Mercurial > wow > askmrrobot
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 |