comparison Loot.lua @ 57:01b63b8ed811 v21

total rewrite to version 21
author yellowfive
date Fri, 05 Jun 2015 11:05:15 -0700
parents
children cf2b6b9a8337
comparison
equal deleted inserted replaced
56:75431c084aa0 57:01b63b8ed811
1 local Amr = LibStub("AceAddon-3.0"):GetAddon("AskMrRobot")
2 local L = LibStub("AceLocale-3.0"):GetLocale("AskMrRobot", true)
3 local AceGUI = LibStub("AceGUI-3.0")
4
5 local _frameLoot
6 local _panelLoot
7 local _selectedIndex
8 local _disenchant = {}
9 local _rankPanels
10 local _lootButtons
11
12 local _widthItemList = 220
13 local _widthRankList = 640
14 local _widthSpacing = 10
15 local _widthRank = 48
16 local _widthRankBar = 195
17 local _widthRollType = 45
18 local _widthColPadding = 8
19 local _widthRollExtraSpacing = 4
20
21 local _rollTypePos = {
22 Need = 1,
23 Off = 2,
24 Greed = 3,
25 Pass = 4
26 }
27
28 -- get the index of the loot item that matches up to the specified item
29 local function getLootIndex(itemIndex)
30
31 local ranking = Amr.db.global.TeamOpt.Rankings[itemIndex]
32 if not ranking then return nil end
33
34 local itemUniqueId = Amr.GetItemUniqueId(ranking.item)
35 for i = 1, GetNumLootItems() do
36 --local texture, item, quantity, quality, locked = GetLootSlotInfo(i)
37 local lootType = GetLootSlotType(i)
38 if lootType == 1 then
39 local link = GetLootSlotLink(i)
40 local lootItem = Amr.ParseItemLink(link)
41 if Amr.GetItemUniqueId(lootItem) == itemUniqueId then
42 return i, link
43 end
44 end
45 end
46 end
47
48 local function getLootCandidateIndex(lootIndex, realm, name)
49 -- remove spaces to ensure proper matches, and make all lower
50 realm = string.gsub(realm, "%s+", "")
51 realm = string.lower(realm)
52 name = string.lower(name)
53
54 local nameMatches = {}
55 for i = 1, 40 do
56 local candidate = GetMasterLootCandidate(lootIndex, i)
57 if candidate then
58 local candidateName = candidate
59 local candidateRealm = GetRealmName()
60
61 -- see if realm is in the name
62 local splitPos = string.find(candidateName, "-")
63 if splitPos ~= nil then
64 candidateRealm = string.sub(candidateName, splitPos + 1)
65 candidateName = string.sub(candidateName, 1, splitPos - 1)
66 end
67
68 -- remove spaces to ensure proper matches, and make all lower
69 candidateRealm = string.gsub(candidateRealm, "%s+", "")
70 candidateRealm = string.lower(candidateRealm)
71 candidateName = string.lower(candidateName)
72
73 -- if perfect match then we are done
74 if candidateRealm == realm and candidateName == name then
75 return i
76 end
77
78 if candidateName == name then
79 table.insert(nameMatches, i)
80 end
81 end
82 end
83
84 -- only one player with same name, must be the player of interest
85 if #nameMatches == 1 then
86 return nameMatches[1]
87 end
88
89 -- could not be found or ambiguous
90 return nil
91 end
92
93 -- helper to send a message telling everyone that an item was just given out
94 local function sendGiveLootMessage(itemLink, unitId, isDisenchant)
95 -- some display info
96 local cls, clsEn = UnitClass(unitId)
97 local name = UnitName(unitId)
98
99 local result = isDisenchant and "Disenchant" or (roll and roll.rollType or nil)
100 if result == nil then result = "??" end
101
102 local msg = string.format("%s\n%d\n%s\n%s\n%s\n%s", Amr.LootMessagePrefixes.Give, _selectedIndex, itemLink, result, clsEn, name)
103 Amr:SendAmrCommMessage(msg)
104 end
105
106 local function onGiveLootClick(widget)
107 local rollIndex = widget:GetUserData("index")
108
109 local rankings = Amr.db.global.TeamOpt.Rankings
110 local ranking = rankings[_selectedIndex]
111 local rank = ranking and ranking.ranks[rollIndex] or nil
112 if rank then
113 local roll = Amr.db.char.TeamOpt.Rolls[_selectedIndex][rollIndex]
114 local isDisenchant = not not _disenchant[_selectedIndex]
115
116 local unitId = Amr:GetUnitId(rank.realm, rank.name)
117 if unitId then
118 -- find the item and loot candidate index
119 local itemIndex, itemLink = getLootIndex(_selectedIndex)
120
121 -- for debugging when don't actually have any loot
122 --itemLink = Amr.CreateItemLink(ranking.item)
123
124 local playerIndex = itemIndex and getLootCandidateIndex(itemIndex, rank.realm, rank.name) or nil
125 if itemIndex and playerIndex then
126 GiveMasterLoot(itemIndex, playerIndex)
127 sendGiveLootMessage(itemLink, unitId, isDisenchant)
128 return
129 end
130
131 end
132 end
133
134 -- if we make it here, we could not give out the item for some reason
135 Amr:Print(L.LootMasterGiveFail)
136 end
137
138 function Amr:OnLootGiveReceived(parts)
139 if not parts or #parts < 6 then return end
140
141 local rankings = Amr.db.global.TeamOpt.Rankings
142
143 -- index of the item that was given, flag it to hide it from the ui now
144 local index = tonumber(parts[2])
145 local ranking = rankings[index]
146 if ranking then
147 ranking.given = true
148 end
149
150 -- change the selected item index to the next ungiven item
151 for i, obj in ipairs(rankings) do
152 if not obj.given then
153 _selectedIndex = i
154 break
155 end
156 end
157
158 -- add a loot history entry
159 local entry = {
160 link = parts[3],
161 result = parts[4],
162 class = parts[5],
163 name = parts[6]
164 }
165 table.insert(Amr.db.char.TeamOpt.History, entry)
166
167 -- redraw any open windows
168 Amr:RefreshTeamUi()
169 Amr:RefreshLootWindow()
170 Amr:RefreshLootRolls()
171
172 -- if this is the master looter, check if all items have been given out
173 if IsMasterLooter() then
174 local allDone = true
175 for i, ranking in ipairs(rankings) do
176 if not ranking.given then
177 allDone = false
178 break
179 end
180 end
181
182 if allDone then
183 -- send a message indicating that looting is done
184 Amr:SendAmrCommMessage(Amr.LootMessagePrefixes.Finish)
185 end
186 end
187
188 end
189
190 local function onDisenchantClick()
191 local val = not _disenchant[_selectedIndex]
192 _disenchant[_selectedIndex] = val
193
194 Amr:RefreshLootWindow()
195 Amr:RefreshLootRolls()
196 end
197
198 local function onRollClick()
199 -- generate a roll for everyone on the current item
200 local rands = {}
201
202 local ranking = Amr.db.global.TeamOpt.Rankings[_selectedIndex]
203 for i, rank in ipairs(ranking.ranks) do
204 local r = math.random(100)
205 rands[i] = r
206 end
207
208 -- transmit the roll data to all group members
209 local msg = string.format("%s\n%d\n%s", Amr.LootMessagePrefixes.Rand, _selectedIndex, Amr:Serialize(rands))
210 Amr:SendAmrCommMessage(msg)
211 end
212
213 function Amr:OnLootRandReceived(parts)
214 if not parts or #parts < 3 then return end
215
216 local index = tonumber(parts[2])
217 local success, rands = Amr:Deserialize(parts[3])
218 if not index or not success then return end
219
220 local rolls = Amr.db.char.TeamOpt.Rolls[index]
221 for i, r in pairs(rands) do
222 local roll = rolls[i]
223 if not roll then
224 roll = {}
225 rolls[i] = roll
226 end
227
228 roll.rand = r
229 end
230
231 Amr:RefreshLootRolls()
232 end
233
234 local function onVetoClick(widget)
235 local rollIndex = widget:GetUserData("rollIndex")
236 local rollType = widget:GetUserData("rollType")
237
238 -- acts like a toggle
239 local roll = Amr.db.char.TeamOpt.Rolls[_selectedIndex][rollIndex]
240 local veto = not roll or not roll.vetoes or not roll.vetoes[rollType]
241
242 -- send a message that a veto has been changed
243 local msg = string.format("%s\n%d\n%d\n%s\n%s", Amr.LootMessagePrefixes.Veto, _selectedIndex, rollIndex, rollType, veto and "t" or "f")
244 Amr:SendAmrCommMessage(msg)
245 end
246
247 function Amr:OnLootVetoReceived(parts)
248 if not parts or #parts < 5 then return end
249
250 local itemIndex = tonumber(parts[2])
251 local rollIndex = tonumber(parts[3])
252 local rollType = parts[4]
253 local veto = parts[5] == "t"
254
255 if itemIndex and rollIndex then
256 local roll = Amr.db.char.TeamOpt.Rolls[itemIndex][rollIndex]
257 if not roll then
258 roll = {}
259 Amr.db.char.TeamOpt.Rolls[itemIndex][rollIndex] = roll
260 end
261
262 if not roll.vetoes then
263 roll.vetoes = {}
264 end
265
266 roll.vetoes[rollType] = veto
267
268 -- if the player chose this option, have to remove it because it has been vetoed
269 if veto and roll.rollType == rollType then
270 roll.rollType = nil
271 end
272
273 Amr:RefreshLootRolls()
274 end
275 end
276
277 -- a user choice for what they want to do on an item
278 local function doRoll(rollType)
279
280 local msg = string.format("%s\n%d\n%s\n%s\n%s", Amr.LootMessagePrefixes.Roll, _selectedIndex, rollType, GetRealmName(), UnitName("player"))
281 Amr:SendAmrCommMessage(msg)
282 end
283
284 function Amr:OnLootRollReceived(parts)
285 local index = tonumber(parts[2])
286 local rollType = parts[3]
287 local realm = parts[4]
288 local name = parts[5]
289
290 -- for now, this code matches up name/realm to one in the rankings
291 -- TODO: more robust handling of players with same name but different realms in the same group on non-english clients
292 local nameMatches = {}
293 local ranking = Amr.db.global.TeamOpt.Rankings[index]
294 for i, rank in ipairs(ranking.ranks) do
295 if name == rank.name and realm == rank.realm then
296 nameMatches = {}
297 break
298 end
299
300 if name == rank.name then
301 table.insert(nameMatches, rank)
302 end
303 end
304 if #nameMatches == 1 then
305 realm = nameMatches[1].realm
306 name = nameMatches[1].name
307 end
308
309 -- find index of the ranking
310 local rankIndex = nil
311 for i, rank in ipairs(ranking.ranks) do
312 if name == rank.name and realm == rank.realm then
313 rankIndex = i
314 break
315 end
316 end
317
318 if rankIndex then
319 local obj = Amr.db.char.TeamOpt.Rolls[index][rankIndex]
320 if not obj then
321 obj = {}
322 Amr.db.char.TeamOpt.Rolls[index][rankIndex] = obj
323 end
324 obj.rollType = rollType
325 end
326
327 Amr:RefreshLootRolls()
328 end
329
330 local function renderRollType(rp, rollType, roll, index)
331
332 local icon = rp:GetUserData(rollType)
333 if not icon and roll then
334 -- create icon if we need one
335 icon = AceGUI:Create("AmrUiTextButton")
336 icon:SetWidth(16)
337 icon:SetHeight(16)
338 local pos = _rollTypePos[rollType]
339 local left = _widthRank + _widthColPadding + _widthRankBar + (pos * _widthColPadding) + ((pos - 1) * _widthRollType) + ((_widthRollType - 16) / 2)
340 icon:SetPoint("LEFT", rp.content, "LEFT", left, 0)
341 rp:AddChild(icon)
342 rp:SetUserData(rollType, icon)
343
344 icon:SetUserData("rollType", rollType)
345 icon:SetUserData("rollIndex", index)
346 icon:SetVisible(false)
347
348 icon:SetCallback("OnClick", onVetoClick)
349 end
350
351 if icon then
352 if roll and roll.rollType == rollType then
353 icon:SetVisible(true)
354 icon:SetBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconCheck")
355 icon:SetHoverBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconCheck")
356 elseif roll and roll.vetoes and roll.vetoes[rollType] then
357 icon:SetVisible(true)
358 icon:SetBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconX")
359 icon:SetHoverBackgroundImage("Interface\\AddOns\\" .. Amr.ADDON_NAME .. "\\Media\\IconX")
360 else
361 icon:SetVisible(false)
362 end
363
364 icon:SetDisabled(not IsMasterLooter())
365 end
366
367 -- update button state for this roll type
368 if _lootButtons and _lootButtons[rollType] then
369 _lootButtons[rollType]:SetDisabled(roll and roll.vetoes and roll.vetoes[rollType])
370 end
371 end
372
373 -- gets the current winner based on rolls and currently selected roll type for each user (returns index into rankings for item, or -1 if no winner yet)
374 local function getWinner(itemIndex)
375
376 local rolls = Amr.db.char.TeamOpt.Rolls[itemIndex]
377 if not rolls then return -1 end
378
379 -- go through and find the highest priority roll type
380 local bestRollType
381 local bestTypePos = 100
382 for i, roll in pairs(rolls) do
383 if roll.rollType then
384 local rollPos = _rollTypePos[roll.rollType]
385 if rollPos < bestTypePos and rollPos < _rollTypePos["Pass"] then
386 bestRollType = roll.rollType
387 bestTypePos = rollPos
388 end
389 end
390 end
391
392 -- nobody has chosen anything yet
393 if not bestRollType then return -1 end
394
395 -- find highest roll in the highest priority roll type
396 local maxRoll = -1
397 local bestRoll = -1
398 for i, roll in pairs(rolls) do
399 if roll.rollType == bestRollType and roll.rand and roll.rand > maxRoll then
400 bestRoll = i
401 maxRoll = roll.rand
402 end
403 end
404
405 return bestRoll
406 end
407
408 function Amr:RefreshLootRolls()
409 if not _rankPanels then return end
410
411 local ranking = Amr.db.global.TeamOpt.Rankings[_selectedIndex]
412 local rolls = Amr.db.char.TeamOpt.Rolls[_selectedIndex]
413 local isDisenchant = _disenchant[_selectedIndex]
414
415 local winnerIndex = getWinner(_selectedIndex)
416
417 for i, rp in pairs(_rankPanels) do
418 local rank = ranking.ranks[i]
419 local roll = rolls[i]
420 if isDisenchant then roll = nil end
421
422 -- clear or set the value of each roll column
423 renderRollType(rp, "Need", roll, i)
424 renderRollType(rp, "Off", roll, i)
425 renderRollType(rp, "Greed", roll, i)
426 renderRollType(rp, "Pass", roll, i)
427
428 -- render the random roll
429 local lbl = rp:GetUserData("randLabel")
430 if roll and roll.rand then
431 if not lbl then
432 lbl = AceGUI:Create("AmrUiLabel")
433 lbl:SetJustifyH("RIGHT")
434
435 local left = _widthRank + _widthColPadding + _widthRankBar + (5 * _widthColPadding) + (5 * _widthRollType)
436 lbl:SetPoint("RIGHT", rp.content, "LEFT", left, 0)
437 rp:AddChild(lbl)
438 rp:SetUserData("randLabel", lbl)
439 end
440
441 -- highlight this roll if winner, otherwise unhighlight
442 if i == winnerIndex then
443 lbl:SetFont(Amr.CreateFont("Bold", 18, Amr.Colors.BrightGreen))
444 else
445 lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
446 end
447
448 lbl:SetText(roll.rand)
449 else
450 if lbl then
451 lbl:SetVisible(false)
452 end
453 end
454
455 -- if this person does not have the addon, show a message (except in DE mode)
456 local hasAddon = true
457 local unitId = Amr:GetUnitId(rank.realm, rank.name)
458 if unitId then
459 local realm, name = Amr:GetRealmAndName(unitId)
460 if realm then
461 local ver = Amr:GetAddonVersion(realm, name)
462 hasAddon = ver >= Amr.MIN_ADDON_VERSION
463 end
464 end
465
466 lbl = rp:GetUserData("noaddonLabel")
467 if not hasAddon and not isDisenchant then
468 if not lbl then
469 lbl = AceGUI:Create("AmrUiLabel")
470 lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.Red))
471 lbl:SetText(L.LootRankLabelNoAddon)
472 lbl:SetPoint("LEFT", rp.content, "LEFT", _widthRank + _widthColPadding + _widthRankBar + _widthColPadding + 5, 0)
473 rp:AddChild(lbl)
474 rp:SetUserData("noaddonLabel", lbl)
475 end
476 else
477 if lbl then
478 lbl:SetVisible(false)
479 end
480 end
481
482 end
483 end
484
485 -- helper to create the column bg and header for rank list
486 local function createLootRankColumn(container, prevColumn, width, txt, txtAlign, extraPadding)
487 extraPadding = extraPadding and extraPadding or 0
488
489 local panel = AceGUI:Create("AmrUiPanel")
490 panel:SetBackgroundColor(Amr.Colors.Black, 0.3)
491 container:AddChild(panel)
492
493 if prevColumn then
494 -- pad a bit to right of previous column
495 panel:SetPoint("TOPLEFT", prevColumn.content, "TOPRIGHT", _widthColPadding + extraPadding, 0)
496 panel:SetPoint("BOTTOMRIGHT", prevColumn.content, "BOTTOMRIGHT", _widthColPadding + extraPadding + width, 0)
497 else
498 -- first column abs position in the main ranking panel
499 panel:SetPoint("TOPLEFT", container.content, "TOPLEFT", _widthItemList + _widthSpacing, -115)
500 panel:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMLEFT", _widthItemList + _widthSpacing + width, 0)
501 end
502
503 lbl = AceGUI:Create("AmrUiLabel")
504 lbl:SetWordWrap(false)
505 lbl:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.TextHeaderDisabled))
506 lbl:SetText(txt)
507 lbl:SetJustifyH(txtAlign)
508 lbl:SetWidth(width)
509 lbl:SetPoint("BOTTOMLEFT", panel.content, "TOPLEFT", 0, 5)
510 container:AddChild(lbl)
511
512 return panel, lbl
513 end
514
515 function Amr:RefreshLootWindow()
516 if not _panelLoot then return end
517
518 -- clear out any children of the main loot frame and re-render
519 _panelLoot:ReleaseChildren()
520 _rankPanels = {}
521 _lootButtons = {}
522
523 local ml = IsMasterLooter()
524 local myUnitId = Amr:GetUnitId(GetRealmName(), UnitName("player"))
525
526 local rankings = Amr.db.global.TeamOpt.Rankings
527 if rankings and #rankings > 0 then
528
529 -- make sure that an item is selected
530 if not _selectedIndex then
531 for i, ranking in ipairs(rankings) do
532 if not ranking.given then
533 _selectedIndex = i
534 break
535 end
536 end
537 end
538
539 -- render list of items
540 local panelItems = AceGUI:Create("AmrUiPanel")
541 panelItems:SetLayout("Fill")
542 panelItems:SetWidth(_widthItemList)
543 panelItems:SetBackgroundColor(Amr.Colors.Black, 0)
544 panelItems:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", 0, 0)
545 panelItems:SetPoint("BOTTOMLEFT", _panelLoot.content, "BOTTOMLEFT")
546 _panelLoot:AddChild(panelItems)
547
548 local scrollItems = AceGUI:Create("AmrUiScrollFrame")
549 scrollItems:SetLayout("List")
550 panelItems:AddChild(scrollItems)
551
552 -- render the divider between items and ranks
553 local divider = AceGUI:Create("AmrUiPanel")
554 divider:SetBackgroundColor(Amr.Colors.Black, 0.5)
555 divider:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList, 0)
556 divider:SetPoint("BOTTOMRIGHT", _panelLoot.content, "BOTTOMLEFT", _widthItemList + 5, 0)
557 _panelLoot:AddChild(divider)
558
559 local btn, btn2, lbl, lbl2, panel, panel2, chk
560
561 local remainingItems = {}
562 for i, ranking in ipairs(rankings) do
563 if not ranking.given then
564 remainingItems[i] = ranking
565 end
566 end
567
568 for i, ranking in pairs(remainingItems) do
569 btn = AceGUI:Create("AmrUiTextButton")
570 btn:SetWidth(_widthItemList)
571 btn:SetHeight(50)
572 btn:SetJustifyH("LEFT")
573 btn:SetJustifyV("TOP")
574 btn:SetTextPadding(9, nil, nil, 2)
575 btn:SetWordWrap(false)
576 btn:SetUserData("index", i)
577
578 local f
579 if _selectedIndex == i then
580 f = Amr.CreateFont("Bold", 16, Amr.Colors.Text)
581 btn:SetBackgroundColor(Amr.Colors.Black, 0.5)
582 btn:SetHoverBackgroundColor(Amr.Colors.Black, 0.5)
583 else
584 f = Amr.CreateFont("Regular", 14, Amr.Colors.Text)
585 btn:SetHoverBackgroundColor(Amr.Colors.Black, 0.2)
586 end
587
588 btn:SetFont(f)
589 btn:SetHoverFont(f)
590
591 scrollItems:AddChild(btn)
592
593 btn:SetCallback("OnClick", function(widget)
594 Amr:SelectLootItem(widget:GetUserData("index"))
595 end)
596
597 local rankLink = Amr.CreateItemLink(ranking.item)
598 Amr.GetItemInfo(rankLink, function(obj, name, link)
599 -- set item name, tooltip
600 obj:SetText(" " .. link:gsub("%[", ""):gsub("%]", ""))
601 Amr:SetItemTooltip(obj, link, "ANCHOR_BOTTOMLEFT", 0, obj.frame:GetHeight())
602 end, btn)
603
604 -- add a label for slot, armor type
605 local slotText = Amr.SlotEnumDisplayText[ranking.itemInfo.slot]
606 if ranking.itemInfo.slot == 'MainHand' then
607 slotText = ranking.itemInfo.subclass == 'TwoHand' and L.TwoHand or L.OneHand
608 elseif ranking.itemInfo.slot == 'OffHand' then
609 slotText = L.OffHand
610 end
611
612 if ranking.itemInfo.armorType == 'None' and ranking.itemInfo.weaponType ~= 'None' then
613 if ranking.itemInfo.weaponType ~= 'OffHand' then
614 slotText = slotText .. ", " .. L.WeaponTypes[ranking.itemInfo.weaponType]
615 end
616 elseif ranking.itemInfo.armorType ~= 'None' then
617 slotText = slotText .. ", " .. L.ArmorTypes[ranking.itemInfo.armorType]
618 end
619
620 btn:SetSubtextFont(Amr.CreateFont("Regular", 13, Amr.Colors.TextGray))
621 btn:SetSubtextJustifyH("LEFT")
622 btn:SetSubtextJustifyV("BOTTOM")
623 btn:SetSubtextPadding(nil, nil, 9, 7)
624 btn:SetSubtextWordWrap(false)
625 btn:SetSubtext(slotText)
626
627
628 local isDisenchant = not not _disenchant[i]
629
630 if _selectedIndex == i then
631
632 -- see if I am in the list
633 local canLoot = false
634 for j, rank in ipairs(ranking.ranks) do
635 local unitId = Amr:GetUnitId(rank.realm, rank.name)
636 if unitId == myUnitId then
637 canLoot = not rank.notRanked or rank.offspec
638 break
639 end
640 end
641
642 -- render loot options
643 if canLoot then
644 btn = AceGUI:Create("AmrUiButton")
645 btn:SetWidth(120)
646 btn:SetHeight(26)
647 btn:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White))
648 btn:SetBackgroundColor(Amr.Colors.Green)
649 btn:SetText(L.TeamLootOptionNeed)
650 btn:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -7)
651 btn:SetCallback("OnClick", function(widget) doRoll("Need") end)
652 _panelLoot:AddChild(btn)
653 _lootButtons["Need"] = btn
654
655 btn2 = AceGUI:Create("AmrUiButton")
656 btn2:SetWidth(120)
657 btn2:SetHeight(26)
658 btn2:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White))
659 btn2:SetBackgroundColor(Amr.Colors.Orange)
660 btn2:SetText(L.TeamLootOptionPass)
661 btn2:SetPoint("TOPLEFT", btn.frame, "BOTTOMLEFT", 0, -15)
662 btn2:SetCallback("OnClick", function(widget) doRoll("Pass") end)
663 _panelLoot:AddChild(btn2)
664 _lootButtons["Pass"] = btn2
665
666 btn = AceGUI:Create("AmrUiButton")
667 btn:SetWidth(120)
668 btn:SetHeight(26)
669 btn:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White))
670 btn:SetBackgroundColor(Amr.Colors.Blue)
671 btn:SetText(L.TeamLootOptionOff)
672 btn:SetPoint("BOTTOMLEFT", btn2.frame, "TOPRIGHT", 15, 15)
673 btn:SetCallback("OnClick", function(widget) doRoll("Off") end)
674 _panelLoot:AddChild(btn)
675 _lootButtons["Off"] = btn
676
677 btn2 = AceGUI:Create("AmrUiButton")
678 btn2:SetWidth(120)
679 btn2:SetHeight(26)
680 btn2:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White))
681 btn2:SetBackgroundColor(Amr.Colors.Blue)
682 btn2:SetText(L.TeamLootOptionGreed)
683 btn2:SetPoint("TOPLEFT", btn.frame, "BOTTOMLEFT", 0, -15)
684 btn2:SetCallback("OnClick", function(widget) doRoll("Greed") end)
685 _panelLoot:AddChild(btn2)
686 _lootButtons["Greed"] = btn2
687 else
688 lbl = AceGUI:Create("AmrUiLabel")
689 lbl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan))
690 lbl:SetText(L.LootIneligible)
691 lbl:SetWidth(255)
692 lbl:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -7)
693 _panelLoot:AddChild(lbl)
694 end
695
696 -- master loot options
697 if ml then
698 chk = AceGUI:Create("AmrUiCheckBox")
699 chk:SetText(L.LootMasterDisenchantText)
700 chk:SetPoint("TOPRIGHT", _panelLoot.content, "TOPRIGHT", -18, -12)
701 chk:SetCallback("OnClick", onDisenchantClick)
702 chk:SetChecked(_disenchant[i])
703 _panelLoot:AddChild(chk)
704
705 lbl = AceGUI:Create("AmrUiLabel")
706 lbl:SetWidth(120)
707 lbl:SetJustifyH("CENTER")
708 lbl:SetText(L.LootMasterDisenchantLabel)
709 lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextTan))
710 lbl:SetPoint("TOP", chk.frame, "BOTTOM", 0, -5)
711 _panelLoot:AddChild(lbl)
712
713 btn2 = AceGUI:Create("AmrUiButton")
714 btn2:SetWidth(120)
715 btn2:SetHeight(26)
716 btn2:SetFont(Amr.CreateFont("Bold", 15, Amr.Colors.White))
717 btn2:SetBackgroundColor(Amr.Colors.Green)
718 btn2:SetText(L.LootMasterRollText)
719 btn2:SetPoint("RIGHT", chk.frame, "LEFT", -50, 0)
720 btn2:SetCallback("OnClick", onRollClick)
721 _panelLoot:AddChild(btn2)
722
723 lbl = AceGUI:Create("AmrUiLabel")
724 lbl:SetWidth(120)
725 lbl:SetJustifyH("CENTER")
726 lbl:SetText(L.LootMasterRollLabel)
727 lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextTan))
728 lbl:SetPoint("TOP", btn2.frame, "BOTTOM", 0, -5)
729 _panelLoot:AddChild(lbl)
730
731 end
732
733 -- backgrounds for the rank list and headers
734 panel = createLootRankColumn(_panelLoot, nil, _widthRank, isDisenchant and "" or L.LootRankHeaderRank, "RIGHT")
735 panel = createLootRankColumn(_panelLoot, panel, _widthRankBar, isDisenchant and L.LootRankHeaderScoreDisenchant or L.LootRankHeaderScore, "LEFT")
736
737 if not isDisenchant then
738 panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderNeed, "CENTER")
739 panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderOff, "CENTER")
740 panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderGreed, "CENTER")
741 panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderPass, "CENTER")
742 panel = createLootRankColumn(_panelLoot, panel, _widthRollType, L.LootRankHeaderRoll, "RIGHT", _widthRollExtraSpacing)
743 end
744
745 -- rank list for selected item
746 panel = AceGUI:Create("AmrUiPanel")
747 panel:SetLayout("Fill")
748 panel:SetBackgroundColor(Amr.Colors.Black, 0)
749 panel:SetPoint("TOPLEFT", _panelLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -115)
750 panel:SetPoint("BOTTOMRIGHT", _panelLoot.content, "BOTTOMRIGHT")
751 _panelLoot:AddChild(panel)
752
753 local scrollRanks = AceGUI:Create("AmrUiScrollFrame")
754 scrollRanks:SetLayout("List")
755 panel:AddChild(scrollRanks)
756
757 -- find min and max value, used for sizing the bars
758 local rankMin = -0.02
759 local rankMax = 0.02
760 for j, rank in ipairs(ranking.ranks) do
761 if rank.score < rankMin then
762 rankMin = rank.score
763 end
764 if rank.score > rankMax then
765 rankMax = rank.score
766 end
767 end
768
769 -- just make min less than max if they are the same, doesn't really matter what it is, would be a wacky case
770 if rankMin == rankMax then
771 rankMin = rankMax - 1
772 end
773
774 local minWidth = 10
775 local maxWidth = _widthRankBar - 36 - 65 - 2 -- reserve 36 for icon, 65 for bar label, and 2 for a border around the bar
776 local rankCount = 0
777
778 for j, rank in ipairs(ranking.ranks) do
779 local unitId = Amr:GetUnitId(rank.realm, rank.name)
780 if unitId then
781 local skip = false
782 if isDisenchant then
783 skip = true
784 if rank.isMasterLooter or (rank.enchantingSkill and rank.enchantingSkill > 0) then
785 skip = false
786 end
787 end
788
789 if not skip then
790 rankCount = rankCount + 1
791
792 local rp = AceGUI:Create("AmrUiPanel")
793 rp:SetLayout("None")
794 rp:SetBackgroundColor(Amr.Colors.Black, 0)
795 rp:SetWidth(_widthRankList)
796 rp:SetHeight(45)
797 scrollRanks:AddChild(rp)
798 _rankPanels[j] = rp
799
800 if not isDisenchant then
801 panel = AceGUI:Create("AmrUiPanel")
802 panel:SetBackgroundColor(Amr.Colors.Black, 1)
803 panel:SetPoint("TOPLEFT", rp.content, "BOTTOMLEFT", 0, 0)
804 panel:SetPoint("BOTTOMRIGHT", rp.content, "BOTTOMRIGHT", -120, -1)
805 rp:AddChild(panel)
806 end
807
808 lbl = AceGUI:Create("AmrUiLabel")
809 lbl:SetFont(Amr.CreateFont("Bold", 32, Amr.Colors.White))
810 lbl:SetText(rankCount)
811 lbl:SetWidth(_widthRank - 6)
812 lbl:SetJustifyH("RIGHT")
813 lbl:SetPoint("BOTTOMLEFT", rp.content, "BOTTOMLEFT", 0, 3)
814 rp:AddChild(lbl)
815
816 local cls, clsEn = UnitClass(unitId)
817 local color = clsEn and Amr.Colors.Classes[clsEn] or Amr.Colors.TextHeaderDisabled
818
819 local icon = AceGUI:Create("AmrUiIcon")
820 icon:SetIconBorderColor(color)
821 icon:SetWidth(36)
822 icon:SetHeight(36)
823 icon:SetIcon("Interface\\Icons\\" .. Amr.SpecIcons[rank.specId])
824 icon:SetPoint("BOTTOMLEFT", rp.content, "BOTTOMLEFT", 48 + 8, 0)
825 rp:AddChild(icon)
826
827 lbl = AceGUI:Create("AmrUiLabel")
828 lbl:SetFont(Amr.CreateFont("Bold", 16, color))
829 lbl:SetText(UnitName(unitId))
830 lbl:SetWidth(_widthRankBar - 36 - 8) -- 4px on left and right side
831 lbl:SetPoint("TOPLEFT", icon.frame, "TOPRIGHT", 4, -2)
832 rp:AddChild(lbl)
833
834 if isDisenchant or rank.notRanked then
835 lbl = AceGUI:Create("AmrUiLabel")
836 lbl:SetFont(Amr.CreateFont("Italic", 13, Amr.Colors.TextHeaderDisabled))
837 lbl:SetWidth(_widthRankBar - 36 - 4) -- 4px on left side
838 lbl:SetWordWrap(false)
839 lbl:SetPoint("BOTTOMLEFT", icon.frame, "BOTTOMRIGHT", 4, 2)
840 rp:AddChild(lbl)
841
842 if isDisenchant then
843 -- will be disenchanter or ML if we are DEing the item
844 lbl:SetText((rank.enchantingSkill and rank.enchantingSkill > 0) and string.format(L.LootRankLabelDisenchant .. " (%d)", rank.enchantingSkill) or L.LootRankLabelMasterLooter)
845 else
846 -- if this is off spec or just a disenchanter, no score bar just description text
847 lbl:SetText(rank.offspec and L.LootRankLabelOff or ((rank.enchantingSkill and rank.enchantingSkill > 0) and string.format(L.LootRankLabelDisenchant .. " (%d)", rank.enchantingSkill) or L.LootRankLabelMasterLooter))
848 end
849 else
850 local scoreText = rank.score .. "%"
851 local val = rank.score;
852 if rank.isEquipped then
853 scoreText = "E"
854 val = 0
855 elseif val >= 0 then
856 scoreText = "+" .. scoreText
857 end
858
859 local per = (val - rankMin) / (rankMax - rankMin);
860 local w = minWidth + (per * (maxWidth - minWidth));
861 color = val > 0 and Amr.Colors.BarHigh or (val == 0 and Amr.Colors.BarMed or Amr.Colors.BarLow)
862
863 panel = AceGUI:Create("AmrUiPanel")
864 panel:SetLayout("None")
865 panel:SetWidth(w + 2)
866 panel:SetHeight(16)
867 panel:SetBackgroundColor(Amr.Colors.Black, 1)
868 panel:SetPoint("BOTTOMLEFT", icon.frame, "BOTTOMRIGHT", 0, -1)
869 rp:AddChild(panel)
870
871 panel2 = AceGUI:Create("AmrUiPanel")
872 panel2:SetLayout("None")
873 panel2:SetWidth(w)
874 panel2:SetHeight(14)
875 panel2:SetBackgroundColor(color, 1)
876 panel2:SetPoint("TOPLEFT", panel.content, "TOPLEFT", 1, -1)
877 panel:AddChild(panel2)
878
879 lbl = AceGUI:Create("AmrUiLabel")
880 lbl:SetFont(Amr.CreateFont("Bold", 13, color))
881 lbl:SetText(scoreText)
882 lbl:SetWidth(63)
883 lbl:SetWordWrap(false)
884 lbl:SetPoint("LEFT", panel.content, "RIGHT", 2, 0)
885 rp:AddChild(lbl)
886 end
887
888 if ml then
889 btn2 = AceGUI:Create("AmrUiButton")
890 btn2:SetHeight(24)
891 btn2:SetFont(Amr.CreateFont("Regular", 13, Amr.Colors.White))
892 btn2:SetBackgroundColor(Amr.Colors.Green)
893
894 if isDisenchant then
895 btn2:SetWidth(200)
896 btn2:SetText(L.LootMasterGiveDisenchant)
897 btn2:SetPoint("LEFT", rp.content, "LEFT", _widthRank + _widthRankBar + (3 * _widthColPadding), 0)
898 else
899 btn2:SetWidth(85)
900 btn2:SetText(L.LootMasterGiveLoot)
901 btn2:SetPoint("RIGHT", rp.content, "RIGHT", -30, 0)
902 end
903
904 btn2:SetUserData("index", j)
905 btn2:SetCallback("OnClick", onGiveLootClick)
906 rp:AddChild(btn2)
907 end
908 end
909
910 end
911 end
912
913 end
914
915 end
916
917 else
918 local lbl = AceGUI:Create("AmrUiLabel")
919 lbl:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan))
920 lbl:SetWidth(800)
921 lbl:SetText(L.LootEmpty)
922 lbl:SetPoint("CENTER", _panelLoot.content, "CENTER")
923 _panelLoot:AddChild(lbl)
924 end
925
926 end
927
928 -- select a particular loot item to display
929 function Amr:SelectLootItem(index)
930 _selectedIndex = index
931 self:RefreshLootWindow()
932 self:RefreshLootRolls()
933 end
934
935 local function onLootFrameClose(widget)
936 AceGUI:Release(widget)
937 _frameLoot = nil
938 _panelLoot = nil
939 _rankPanels = nil
940 _lootButtons = nil
941 end
942
943 function Amr:HideLootWindow()
944 if not _frameLoot then return end
945 _frameLoot:Hide()
946 end
947
948 function Amr:ShowLootWindow()
949 if not _frameLoot then
950 _frameLoot = AceGUI:Create("AmrUiFrame")
951 _frameLoot:SetStatusTable(Amr.db.profile.lootWindow) -- window position is remembered in db
952 _frameLoot:SetCallback("OnClose", onLootFrameClose)
953 _frameLoot:SetLayout("None")
954 _frameLoot:SetWidth(900)
955 _frameLoot:SetHeight(600)
956 _frameLoot:SetBorderColor(Amr.Colors.BorderBlue)
957 _frameLoot:SetBackgroundColor(Amr.Colors.Bg)
958
959 local lbl = AceGUI:Create("AmrUiLabel")
960 lbl:SetWidth(600)
961 lbl:SetFont(Amr.CreateFont("Bold", 28, Amr.Colors.White))
962 lbl:SetText(L.LootTitle)
963 lbl:SetWordWrap(false)
964 lbl:SetJustifyH("CENTER")
965 lbl:SetPoint("TOP", _frameLoot.content, "TOP", 0, 30)
966 _frameLoot:AddChild(lbl)
967
968 lbl:SetCallback("OnMouseDown", function(widget) _frameLoot:StartMove() end)
969 lbl:SetCallback("OnMouseUp", function(widget) _frameLoot:EndMove() end)
970
971 lbl = AceGUI:Create("AmrUiLabel")
972 lbl:SetWidth(_widthItemList)
973 lbl:SetFont(Amr.CreateFont("Regular", 18, Amr.Colors.TextHeaderActive))
974 lbl:SetText(L.LootHelpItems)
975 lbl:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", 0, -10)
976 _frameLoot:AddChild(lbl)
977
978 lbl = AceGUI:Create("AmrUiLabel")
979 lbl:SetWidth(_widthItemList)
980 lbl:SetFont(Amr.CreateFont("Regular", 18, Amr.Colors.TextHeaderActive))
981 lbl:SetText(L.LootHelpRanks)
982 lbl:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", _widthItemList + _widthSpacing, -10)
983 _frameLoot:AddChild(lbl)
984
985 if IsMasterLooter() then
986 lbl = AceGUI:Create("AmrUiLabel")
987 lbl:SetWidth(_widthItemList)
988 lbl:SetFont(Amr.CreateFont("Regular", 18, Amr.Colors.TextHeaderActive))
989 lbl:SetText(L.LootHelpMaster)
990 lbl:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", _widthItemList + _widthSpacing + _widthRank + _widthRankBar + _widthRollType + (_widthColPadding * 3), -10)
991 _frameLoot:AddChild(lbl)
992 end
993
994 _panelLoot = AceGUI:Create("AmrUiPanel")
995 _panelLoot:SetLayout("None")
996 _panelLoot:SetBackgroundColor(Amr.Colors.Black, 0)
997 _panelLoot:SetPoint("TOPLEFT", _frameLoot.content, "TOPLEFT", 0, -40)
998 _panelLoot:SetPoint("BOTTOMRIGHT", _frameLoot.content, "BOTTOMRIGHT", 0, 0)
999 _frameLoot:AddChild(_panelLoot)
1000 else
1001 _frameLoot:Show()
1002 end
1003
1004 _frameLoot:Raise()
1005 end
1006
1007 function Amr:OnStartLootReceived(parts)
1008 local data = {}
1009 for i = 2, #parts do
1010 table.insert(data, parts[i])
1011 end
1012 data = table.concat(data, "\n")
1013
1014 -- reset rankings to the new data sent out by person in control
1015 local rankings = Amr:ParseRankingString(data)
1016 Amr.db.global.TeamOpt.Rankings = rankings
1017
1018 -- reset disenchant state
1019 _disenchant = {}
1020
1021 -- reset roll information when loot is started
1022 local rolls = {}
1023 for i = 1, #rankings do
1024 table.insert(rolls, {})
1025 end
1026 Amr.db.char.TeamOpt.Rolls = rolls
1027
1028 -- select first item by default
1029 _selectedIndex = #rankings > 0 and 1 or nil
1030
1031 -- begin looting
1032 Amr.db.char.TeamOpt.LootInProgress = true
1033
1034 Amr:RefreshTeamUi()
1035 Amr:ShowLootWindow()
1036 Amr:RefreshLootWindow()
1037 end