yellowfive@57
|
1 local Amr = LibStub("AceAddon-3.0"):GetAddon("AskMrRobot")
|
yellowfive@57
|
2 local L = LibStub("AceLocale-3.0"):GetLocale("AskMrRobot", true)
|
yellowfive@57
|
3 local AceGUI = LibStub("AceGUI-3.0")
|
yellowfive@57
|
4
|
yellowfive@139
|
5 local _cboSetups
|
yellowfive@139
|
6 local _panelGear
|
yellowfive@139
|
7 local _activeSetupId
|
yellowfive@139
|
8
|
yellowfive@139
|
9 local function getSetupById(id)
|
yellowfive@139
|
10 if not id then
|
yellowfive@139
|
11 id = _activeSetupId
|
yellowfive@139
|
12 end
|
yellowfive@139
|
13 local setup
|
yellowfive@139
|
14 for i,s in ipairs(Amr.db.char.GearSetups) do
|
yellowfive@139
|
15 if s.Id == id then
|
yellowfive@139
|
16 setup = s
|
yellowfive@139
|
17 break
|
yellowfive@139
|
18 end
|
yellowfive@139
|
19 end
|
yellowfive@139
|
20 return setup
|
yellowfive@139
|
21 end
|
yellowfive@57
|
22
|
yellowfive@57
|
23 -- Returns a number indicating how different two items are (0 means the same, higher means more different)
|
yellowfive@57
|
24 local function countItemDifferences(item1, item2)
|
yellowfive@124
|
25 -- both nil, the same
|
yellowfive@124
|
26 if not item1 and not item2 then
|
yellowfive@124
|
27 return 0
|
yellowfive@124
|
28 end
|
yellowfive@124
|
29
|
yellowfive@124
|
30 -- one nil and other not, or different id, totally different
|
yellowfive@124
|
31 if (not item1 and item2) or (item1 and not item2) or item1.id ~= item2.id then
|
yellowfive@191
|
32 return 1000000
|
yellowfive@124
|
33 end
|
yellowfive@124
|
34
|
Yellowfive@200
|
35 --if item1.guid and item2.guid and item1.guid == item2.guid then
|
Yellowfive@200
|
36 -- -- these have the same guid, so even if bonus id or something doesn't match for some reason, they are identical items
|
Yellowfive@200
|
37 --else
|
Yellowfive@200
|
38 -- different versions of same item (id + bonus ids + suffix + drop level, constitutes a different physical drop)
|
Yellowfive@200
|
39 if Amr.GetItemUniqueId(item1, true, true) ~= Amr.GetItemUniqueId(item2, true, true) then
|
Yellowfive@200
|
40 return 100000
|
Yellowfive@200
|
41 end
|
Yellowfive@200
|
42
|
Yellowfive@200
|
43 -- different upgrade levels of the same item
|
Yellowfive@200
|
44 if item1.upgradeId ~= item2.upgradeId then
|
Yellowfive@200
|
45 return 10000
|
Yellowfive@200
|
46 end
|
Yellowfive@200
|
47 --end
|
Yellowfive@200
|
48
|
yellowfive@149
|
49 -- a change that requires reforging is considered more different than a change that does not;
|
yellowfive@149
|
50 -- it is assumed that item1 is how we want the item to be in the end, and item2 is how it currently is
|
yellowfive@149
|
51 local aztReforges = 0
|
yellowfive@149
|
52 local aztSelects = 0
|
yellowfive@149
|
53
|
yellowfive@149
|
54 if item1.id == item2.id and (item1.azerite or item2.azerite) then
|
yellowfive@149
|
55 -- azerite that needs to be reforged
|
yellowfive@149
|
56 if item2.azerite and not item1.azerite then
|
yellowfive@149
|
57 -- kind of a dumb case... but we would need to blank all azerite on item2 to match item1
|
yellowfive@191
|
58 aztReforges = #item2.azerite * 1000
|
yellowfive@149
|
59 elseif item2.azerite then
|
yellowfive@149
|
60 -- count up azerite on item2 but not on item1, these would need to be reforged
|
yellowfive@149
|
61 for i = 1, #item2.azerite do
|
yellowfive@149
|
62 local missing = true
|
yellowfive@149
|
63 for j = 1, #item1.azerite do
|
yellowfive@149
|
64 if item1.azerite[j] == item2.azerite[i] then
|
yellowfive@149
|
65 missing = false
|
yellowfive@149
|
66 end
|
yellowfive@149
|
67 end
|
yellowfive@149
|
68 if missing then
|
yellowfive@191
|
69 aztReforges = aztReforges + 1000
|
yellowfive@149
|
70 end
|
yellowfive@149
|
71 end
|
yellowfive@149
|
72 end
|
yellowfive@149
|
73
|
yellowfive@149
|
74 -- azerite that needs to be selected
|
yellowfive@124
|
75 if item1.azerite and not item2.azerite then
|
yellowfive@149
|
76 -- item2 is blank, so just need to choose all the right ones
|
yellowfive@191
|
77 aztSelects = #item1.azerite * 100
|
yellowfive@149
|
78 elseif item1.azerite then
|
yellowfive@149
|
79 -- count up azerite on item1 but not on item2, these would need to be selected
|
yellowfive@145
|
80 for i = 1, #item1.azerite do
|
yellowfive@145
|
81 local missing = true
|
yellowfive@124
|
82 for j = 1, #item2.azerite do
|
yellowfive@145
|
83 if item2.azerite[j] == item1.azerite[i] then
|
yellowfive@124
|
84 missing = false
|
yellowfive@124
|
85 end
|
yellowfive@124
|
86 end
|
yellowfive@124
|
87 if missing then
|
yellowfive@191
|
88 aztSelects = aztSelects + 100
|
yellowfive@124
|
89 end
|
yellowfive@124
|
90 end
|
yellowfive@149
|
91 end
|
yellowfive@124
|
92 end
|
yellowfive@57
|
93
|
yellowfive@57
|
94 -- different gems
|
yellowfive@57
|
95 local gemDiffs = 0
|
yellowfive@57
|
96 for i = 1, 3 do
|
yellowfive@57
|
97 if item1.gemIds[i] ~= item2.gemIds[i] then
|
yellowfive@191
|
98 gemDiffs = gemDiffs + 10
|
yellowfive@57
|
99 end
|
yellowfive@57
|
100 end
|
yellowfive@57
|
101
|
yellowfive@57
|
102 -- different enchants
|
yellowfive@57
|
103 local enchantDiff = 0
|
yellowfive@57
|
104 if item1.enchantId ~= item2.enchantId then
|
yellowfive@191
|
105 enchantDiff = 10
|
yellowfive@57
|
106 end
|
yellowfive@191
|
107
|
yellowfive@191
|
108 -- different guid
|
yellowfive@191
|
109 local guidDiff = 0
|
yellowfive@191
|
110 if item1.guid and item2.guid and item1.guid ~= item2.guid then
|
yellowfive@191
|
111 guidDiff = 1
|
yellowfive@191
|
112 end
|
yellowfive@191
|
113
|
yellowfive@191
|
114 return aztReforges + aztSelects + gemDiffs + enchantDiff + guidDiff
|
yellowfive@57
|
115 end
|
yellowfive@57
|
116
|
yellowfive@57
|
117 -- given a table of items (keyed or indexed doesn't matter) find closest match to item, or nil if none are a match
|
yellowfive@124
|
118 local function findMatchingItemFromTable(item, list, bestItem, bestDiff, bestLoc, usedItems, tableType)
|
yellowfive@57
|
119 if not list then return nil end
|
yellowfive@57
|
120
|
yellowfive@73
|
121 local found = false
|
yellowfive@129
|
122 for k,listItem in pairs(list) do
|
yellowfive@57
|
123 if listItem then
|
yellowfive@57
|
124 local diff = countItemDifferences(item, listItem)
|
Yellowfive@200
|
125
|
yellowfive@57
|
126 if diff < bestDiff then
|
yellowfive@57
|
127 -- each physical item can only be used once, the usedItems table has items we can't use in this search
|
yellowfive@57
|
128 local key = string.format("%s_%s", tableType, k)
|
yellowfive@57
|
129 if not usedItems[key] then
|
yellowfive@57
|
130 bestItem = listItem
|
yellowfive@57
|
131 bestDiff = diff
|
yellowfive@124
|
132 bestLoc = key
|
yellowfive@57
|
133 end
|
yellowfive@57
|
134 end
|
Yellowfive@200
|
135
|
Yellowfive@200
|
136 if bestDiff == 0 then break end
|
yellowfive@57
|
137 end
|
yellowfive@57
|
138 end
|
yellowfive@57
|
139
|
yellowfive@124
|
140 return bestItem, bestDiff, bestLoc
|
yellowfive@57
|
141 end
|
yellowfive@57
|
142
|
yellowfive@124
|
143 -- search the player's equipped gear, bag, and bank for an item that best matches the specified item
|
yellowfive@57
|
144 function Amr:FindMatchingItem(item, player, usedItems)
|
yellowfive@57
|
145 if not item then return nil end
|
yellowfive@57
|
146
|
yellowfive@57
|
147 local equipped = player.Equipped and player.Equipped[player.ActiveSpec] or nil
|
yellowfive@191
|
148 local bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, equipped, nil, 1000000, nil, usedItems, "equip")
|
yellowfive@124
|
149 bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, player.BagItems, bestItem, bestDiff, bestLoc, usedItems, "bag")
|
yellowfive@124
|
150 if player.BankItems then
|
yellowfive@129
|
151 bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, player.BankItems, bestItem, bestDiff, bestLoc, usedItems, "bank")
|
yellowfive@124
|
152 end
|
yellowfive@57
|
153
|
yellowfive@191
|
154 if bestDiff >= 1000000 then
|
yellowfive@191
|
155 return nil, 1000000
|
yellowfive@57
|
156 else
|
yellowfive@57
|
157 usedItems[bestLoc] = true
|
yellowfive@124
|
158 return bestItem, bestDiff
|
yellowfive@57
|
159 end
|
yellowfive@57
|
160 end
|
yellowfive@57
|
161
|
yellowfive@57
|
162 local function renderEmptyGear(container)
|
yellowfive@57
|
163
|
yellowfive@57
|
164 local panelBlank = AceGUI:Create("AmrUiPanel")
|
yellowfive@57
|
165 panelBlank:SetLayout("None")
|
yellowfive@57
|
166 panelBlank:SetBackgroundColor(Amr.Colors.Black, 0.4)
|
yellowfive@124
|
167 container:AddChild(panelBlank)
|
yellowfive@57
|
168 panelBlank:SetPoint("TOPLEFT", container.content, "TOPLEFT", 6, 0)
|
yellowfive@57
|
169 panelBlank:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT")
|
yellowfive@57
|
170
|
yellowfive@57
|
171 local lbl = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
172 panelBlank:AddChild(lbl)
|
yellowfive@57
|
173 lbl:SetText(L.GearBlank)
|
yellowfive@57
|
174 lbl:SetWidth(700)
|
yellowfive@57
|
175 lbl:SetJustifyH("MIDDLE")
|
yellowfive@57
|
176 lbl:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan))
|
yellowfive@57
|
177 lbl:SetPoint("BOTTOM", panelBlank.content, "CENTER", 0, 20)
|
yellowfive@57
|
178
|
yellowfive@57
|
179 local lbl2 = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
180 panelBlank:AddChild(lbl2)
|
yellowfive@57
|
181 lbl2:SetText(L.GearBlank2)
|
yellowfive@57
|
182 lbl2:SetWidth(700)
|
yellowfive@57
|
183 lbl2:SetJustifyH("MIDDLE")
|
yellowfive@57
|
184 lbl2:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan))
|
yellowfive@57
|
185 lbl2:SetPoint("TOP", lbl.frame, "CENTER", 0, -20)
|
yellowfive@124
|
186 end
|
yellowfive@124
|
187
|
yellowfive@124
|
188 -- helper to create a widget for showing a socket or azerite power
|
yellowfive@124
|
189 local function createSocketWidget(panelMods, prevWidget, prevIsSocket, isEquipped)
|
yellowfive@124
|
190
|
yellowfive@124
|
191 -- highlight for socket that doesn't match
|
yellowfive@124
|
192 local socketBorder = AceGUI:Create("AmrUiPanel")
|
yellowfive@124
|
193 panelMods:AddChild(socketBorder)
|
yellowfive@124
|
194 if not prevIsSocket then
|
yellowfive@124
|
195 socketBorder:SetPoint("LEFT", prevWidget.frame, "RIGHT", 30, 0)
|
yellowfive@124
|
196 else
|
yellowfive@124
|
197 socketBorder:SetPoint("LEFT", prevWidget.frame, "RIGHT", 2, 0)
|
yellowfive@124
|
198 end
|
yellowfive@124
|
199 socketBorder:SetLayout("None")
|
yellowfive@124
|
200 socketBorder:SetBackgroundColor(Amr.Colors.Black, isEquipped and 0 or 1)
|
yellowfive@124
|
201 socketBorder:SetWidth(26)
|
yellowfive@124
|
202 socketBorder:SetHeight(26)
|
yellowfive@124
|
203 if isEquipped then
|
yellowfive@124
|
204 socketBorder:SetAlpha(0.3)
|
yellowfive@124
|
205 end
|
yellowfive@124
|
206
|
yellowfive@124
|
207 local socketBg = AceGUI:Create("AmrUiIcon")
|
yellowfive@124
|
208 socketBorder:AddChild(socketBg)
|
yellowfive@124
|
209 socketBg:SetPoint("TOPLEFT", socketBorder.content, "TOPLEFT", 1, -1)
|
yellowfive@124
|
210 socketBg:SetLayout("None")
|
yellowfive@124
|
211 socketBg:SetBorderWidth(2)
|
yellowfive@124
|
212 socketBg:SetIconBorderColor(Amr.Colors.Green, isEquipped and 0 or 1)
|
yellowfive@124
|
213 socketBg:SetWidth(24)
|
yellowfive@124
|
214 socketBg:SetHeight(24)
|
yellowfive@124
|
215
|
yellowfive@124
|
216 local socketIcon = AceGUI:Create("AmrUiIcon")
|
yellowfive@124
|
217 socketBg:AddChild(socketIcon)
|
yellowfive@124
|
218 socketIcon:SetPoint("CENTER", socketBg.content, "CENTER")
|
yellowfive@124
|
219 socketIcon:SetBorderWidth(1)
|
yellowfive@124
|
220 socketIcon:SetIconBorderColor(Amr.Colors.White)
|
yellowfive@124
|
221 socketIcon:SetWidth(18)
|
yellowfive@124
|
222 socketIcon:SetHeight(18)
|
yellowfive@124
|
223
|
yellowfive@124
|
224 return socketBorder, socketIcon
|
yellowfive@57
|
225 end
|
yellowfive@57
|
226
|
yellowfive@139
|
227 local function renderGear(setupId, container)
|
yellowfive@139
|
228
|
yellowfive@139
|
229 -- release all children that were previously rendered, we gonna redo it now
|
yellowfive@139
|
230 container:ReleaseChildren()
|
yellowfive@57
|
231
|
yellowfive@57
|
232 local player = Amr:ExportCharacter()
|
yellowfive@139
|
233
|
yellowfive@139
|
234 local gear
|
yellowfive@139
|
235 local spec
|
yellowfive@139
|
236 local setupIndex
|
yellowfive@181
|
237 local essences
|
yellowfive@139
|
238 for i, setup in ipairs(Amr.db.char.GearSetups) do
|
yellowfive@139
|
239 if setup.Id == setupId then
|
yellowfive@139
|
240 setupIndex = i
|
yellowfive@139
|
241 gear = setup.Gear
|
yellowfive@139
|
242 spec = setup.SpecSlot
|
yellowfive@165
|
243 essences = setup.Essences
|
yellowfive@139
|
244 break
|
yellowfive@139
|
245 end
|
yellowfive@139
|
246 end
|
yellowfive@139
|
247
|
yellowfive@57
|
248 local equipped = player.Equipped[player.ActiveSpec]
|
yellowfive@185
|
249 --local equippedEssences = player.Essences[player.ActiveSpec]
|
yellowfive@181
|
250
|
yellowfive@57
|
251 if not gear then
|
yellowfive@57
|
252 -- no gear has been imported for this spec so show a message
|
yellowfive@57
|
253 renderEmptyGear(container)
|
yellowfive@57
|
254 else
|
yellowfive@57
|
255 local panelGear = AceGUI:Create("AmrUiPanel")
|
yellowfive@57
|
256 panelGear:SetLayout("None")
|
yellowfive@57
|
257 panelGear:SetBackgroundColor(Amr.Colors.Black, 0.3)
|
yellowfive@124
|
258 container:AddChild(panelGear)
|
yellowfive@57
|
259 panelGear:SetPoint("TOPLEFT", container.content, "TOPLEFT", 6, 0)
|
yellowfive@57
|
260 panelGear:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT", -300, 0)
|
yellowfive@57
|
261
|
yellowfive@57
|
262 local panelMods = AceGUI:Create("AmrUiPanel")
|
yellowfive@57
|
263 panelMods:SetLayout("None")
|
yellowfive@124
|
264 panelMods:SetBackgroundColor(Amr.Colors.Black, 0.3)
|
yellowfive@124
|
265 container:AddChild(panelMods)
|
yellowfive@57
|
266 panelMods:SetPoint("TOPLEFT", panelGear.frame, "TOPRIGHT", 15, 0)
|
yellowfive@57
|
267 panelMods:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT")
|
yellowfive@57
|
268
|
yellowfive@57
|
269 -- spec icon
|
yellowfive@57
|
270 local icon = AceGUI:Create("AmrUiIcon")
|
yellowfive@57
|
271 icon:SetIconBorderColor(Amr.Colors.Classes[player.Class])
|
yellowfive@57
|
272 icon:SetWidth(48)
|
yellowfive@57
|
273 icon:SetHeight(48)
|
yellowfive@57
|
274
|
yellowfive@57
|
275 local iconSpec
|
yellowfive@81
|
276 if player.SubSpecs and player.SubSpecs[spec] then
|
yellowfive@57
|
277 iconSpec = player.SubSpecs[spec]
|
yellowfive@57
|
278 else
|
yellowfive@57
|
279 iconSpec = player.Specs[spec]
|
yellowfive@57
|
280 end
|
yellowfive@57
|
281
|
yellowfive@57
|
282 icon:SetIcon("Interface\\Icons\\" .. Amr.SpecIcons[iconSpec])
|
yellowfive@124
|
283 panelGear:AddChild(icon)
|
yellowfive@57
|
284 icon:SetPoint("TOPLEFT", panelGear.content, "TOPLEFT", 10, -10)
|
yellowfive@57
|
285
|
yellowfive@57
|
286 local btnEquip = AceGUI:Create("AmrUiButton")
|
yellowfive@81
|
287 btnEquip:SetText(L.GearButtonEquip(L.SpecsShort[player.Specs[spec]]))
|
yellowfive@57
|
288 btnEquip:SetBackgroundColor(Amr.Colors.Green)
|
yellowfive@57
|
289 btnEquip:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
|
yellowfive@57
|
290 btnEquip:SetWidth(300)
|
yellowfive@57
|
291 btnEquip:SetHeight(26)
|
yellowfive@57
|
292 btnEquip:SetCallback("OnClick", function(widget)
|
yellowfive@139
|
293 Amr:EquipGearSet(setupIndex)
|
yellowfive@57
|
294 end)
|
yellowfive@57
|
295 panelGear:AddChild(btnEquip)
|
yellowfive@124
|
296 btnEquip:SetPoint("LEFT", icon.frame, "RIGHT", 40, 0)
|
yellowfive@124
|
297 btnEquip:SetPoint("RIGHT", panelGear.content, "RIGHT", -40, 0)
|
yellowfive@57
|
298
|
yellowfive@57
|
299 -- each physical item can only be used once, this tracks ones we have already used
|
yellowfive@57
|
300 local usedItems = {}
|
yellowfive@57
|
301
|
yellowfive@57
|
302 -- gear list
|
yellowfive@57
|
303 local prevElem = icon
|
yellowfive@57
|
304 for slotNum = 1, #Amr.SlotIds do
|
yellowfive@57
|
305 local slotId = Amr.SlotIds[slotNum]
|
yellowfive@57
|
306
|
yellowfive@124
|
307 local equippedItem = equipped and equipped[slotId] or nil
|
yellowfive@133
|
308 --local equippedItemLink = equipped and equipped.link or nil
|
yellowfive@57
|
309 local optimalItem = gear[slotId]
|
yellowfive@57
|
310 local optimalItemLink = Amr.CreateItemLink(optimalItem)
|
yellowfive@57
|
311
|
yellowfive@57
|
312 -- see if item is currently equipped, is false if don't have any item for that slot (e.g. OH for a 2-hander)
|
yellowfive@57
|
313 local isEquipped = false
|
yellowfive@135
|
314 if equippedItem and optimalItem and Amr.GetItemUniqueId(equippedItem, false, true) == Amr.GetItemUniqueId(optimalItem, false, true) then
|
yellowfive@145
|
315
|
yellowfive@191
|
316 if optimalItem.guid then
|
yellowfive@191
|
317 isEquipped = optimalItem.guid == equippedItem.guid
|
yellowfive@191
|
318 else
|
yellowfive@191
|
319 --[[if slotId == 1 or slotId == 3 or slotId == 5 then
|
yellowfive@191
|
320 -- show the item as not equipped if azerite doesn't match... might mean they have to switch to another version of same item
|
yellowfive@191
|
321 local aztDiff = countItemDifferences(optimalItem, equippedItem)
|
yellowfive@191
|
322 if aztDiff < 100 then
|
yellowfive@191
|
323 isEquipped = true
|
yellowfive@191
|
324 end
|
yellowfive@191
|
325 else]]
|
yellowfive@145
|
326 isEquipped = true
|
yellowfive@191
|
327 --end
|
yellowfive@145
|
328 end
|
yellowfive@57
|
329 end
|
yellowfive@124
|
330
|
yellowfive@185
|
331 --local isAzerite = optimalItem and C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItemByID(optimalItem.id)
|
yellowfive@185
|
332 --local isEssence = essences and optimalItem and optimalItem.id == 158075
|
yellowfive@185
|
333 local isAzerite = false
|
yellowfive@185
|
334 local isEssence = false
|
yellowfive@57
|
335
|
yellowfive@57
|
336 -- find the item in the player's inventory that best matches what the optimization wants to use
|
yellowfive@124
|
337 local matchItem = Amr:FindMatchingItem(optimalItem, player, usedItems)
|
yellowfive@57
|
338
|
yellowfive@57
|
339 -- slot label
|
yellowfive@57
|
340 local lbl = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
341 panelGear:AddChild(lbl)
|
yellowfive@124
|
342 lbl:SetPoint("TOPLEFT", prevElem.frame, "BOTTOMLEFT", 0, -12)
|
yellowfive@57
|
343 lbl:SetText(Amr.SlotDisplayText[slotId])
|
yellowfive@57
|
344 lbl:SetWidth(85)
|
yellowfive@57
|
345 lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
|
yellowfive@57
|
346 prevElem = lbl
|
yellowfive@57
|
347
|
yellowfive@57
|
348 -- ilvl label
|
yellowfive@57
|
349 local lblIlvl = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
350 panelGear:AddChild(lblIlvl)
|
yellowfive@124
|
351 lblIlvl:SetPoint("TOPLEFT", lbl.frame, "TOPRIGHT", 0, 0)
|
yellowfive@57
|
352 lblIlvl:SetWidth(45)
|
yellowfive@57
|
353 lblIlvl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan))
|
yellowfive@57
|
354
|
yellowfive@57
|
355 -- equipped label
|
yellowfive@57
|
356 local lblEquipped = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
357 panelGear:AddChild(lblEquipped)
|
yellowfive@124
|
358 lblEquipped:SetPoint("TOPLEFT", lblIlvl.frame, "TOPRIGHT", 0, 0)
|
yellowfive@57
|
359 lblEquipped:SetWidth(20)
|
yellowfive@57
|
360 lblEquipped:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
|
yellowfive@57
|
361 lblEquipped:SetText(isEquipped and "E" or "")
|
yellowfive@57
|
362
|
yellowfive@57
|
363 -- item name/link label
|
yellowfive@57
|
364 local lblItem = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
365 panelGear:AddChild(lblItem)
|
yellowfive@124
|
366 lblItem:SetPoint("TOPLEFT", lblEquipped.frame, "TOPRIGHT", 0, 0)
|
yellowfive@57
|
367 lblItem:SetWordWrap(false)
|
yellowfive@57
|
368 lblItem:SetWidth(345)
|
yellowfive@57
|
369 lblItem:SetFont(Amr.CreateFont(isEquipped and "Regular" or "Bold", isEquipped and 14 or 15, Amr.Colors.White))
|
yellowfive@57
|
370
|
yellowfive@133
|
371 -- fill the name/ilvl labels, which may require asynchronous loading of item information
|
yellowfive@57
|
372 if optimalItemLink then
|
yellowfive@133
|
373 local gameItem = Item:CreateFromItemLink(optimalItemLink)
|
yellowfive@133
|
374 if gameItem then
|
yellowfive@133
|
375 local q = gameItem:GetItemQuality()
|
yellowfive@133
|
376 if q == 6 then
|
yellowfive@133
|
377 -- for artifacts, we consider it equipped if the item id alone matches
|
yellowfive@133
|
378 if equippedItem and equippedItem.id == optimalItem.id then
|
yellowfive@133
|
379 isEquipped = true
|
yellowfive@133
|
380 end
|
yellowfive@133
|
381 lblEquipped:SetText(isEquipped and "E" or "")
|
yellowfive@133
|
382 end
|
yellowfive@124
|
383
|
yellowfive@137
|
384 lblItem:SetFont(Amr.CreateFont(isEquipped and "Regular" or "Bold", isEquipped and 14 or 15, Amr.Colors.Qualities[q] or Amr.Colors.White))
|
yellowfive@133
|
385 lblItem:SetText(gameItem:GetItemName())
|
yellowfive@133
|
386 lblIlvl:SetText(gameItem:GetCurrentItemLevel())
|
yellowfive@133
|
387 Amr:SetItemTooltip(lblItem, gameItem:GetItemLink(), "ANCHOR_TOPRIGHT")
|
yellowfive@133
|
388 end
|
yellowfive@57
|
389 end
|
yellowfive@57
|
390
|
yellowfive@57
|
391 -- modifications
|
yellowfive@57
|
392 if optimalItem then
|
yellowfive@57
|
393
|
yellowfive@165
|
394 -- gems or azerite powers or essences
|
yellowfive@124
|
395 local prevSocket = nil
|
yellowfive@124
|
396
|
yellowfive@124
|
397 if isAzerite then
|
yellowfive@124
|
398 local azt = optimalItem.azerite or {}
|
yellowfive@124
|
399 for i,spellId in ipairs(azt) do
|
yellowfive@124
|
400 if spellId and spellId ~= 0 then
|
yellowfive@135
|
401 local equippedAzt = matchItem and matchItem.azerite or {}
|
yellowfive@124
|
402 local isPowerActive = Amr.Contains(equippedAzt, spellId)
|
yellowfive@124
|
403
|
yellowfive@124
|
404 local socketBorder, socketIcon = createSocketWidget(panelMods, prevSocket or lblItem, prevSocket, isPowerActive)
|
yellowfive@124
|
405
|
yellowfive@124
|
406 -- set icon and tooltip
|
yellowfive@133
|
407 local _, _, spellIcon = GetSpellInfo(spellId)
|
yellowfive@124
|
408 socketIcon:SetIcon(spellIcon)
|
yellowfive@124
|
409 Amr:SetSpellTooltip(socketIcon, spellId, "ANCHOR_TOPRIGHT")
|
yellowfive@124
|
410
|
yellowfive@124
|
411 prevSocket = socketBorder
|
yellowfive@124
|
412 end
|
yellowfive@124
|
413 end
|
yellowfive@165
|
414 elseif isEssence then
|
yellowfive@181
|
415 for i = 1, 4 do
|
yellowfive@181
|
416 if essences and #essences >= i then
|
yellowfive@181
|
417 local essence = essences[i]
|
yellowfive@181
|
418 local equippedEssence = equippedEssences and #equippedEssences >= i and equippedEssences[i] or nil
|
yellowfive@181
|
419 if essence then
|
yellowfive@181
|
420 local essenceInfo = C_AzeriteEssence.GetEssenceInfo(essence[2])
|
yellowfive@181
|
421 if essenceInfo then
|
yellowfive@181
|
422 local isEssenceActive = equippedEssence and equippedEssence[2] == essence[2]
|
yellowfive@181
|
423
|
yellowfive@181
|
424 local socketBorder, socketIcon = createSocketWidget(panelMods, prevSocket or lblItem, prevSocket, isEssenceActive)
|
yellowfive@181
|
425
|
yellowfive@181
|
426 -- set icon and tooltip
|
yellowfive@181
|
427 socketIcon:SetIcon(essenceInfo.icon)
|
yellowfive@181
|
428 Amr:SetEssenceTooltip(socketIcon, string.format("azessence:%d:%d", essence[2], essence[3]) , "ANCHOR_TOPRIGHT")
|
yellowfive@181
|
429
|
yellowfive@181
|
430 --[[
|
yellowfive@181
|
431 if essence[1] and essence[1] > 4 then
|
yellowfive@181
|
432 Amr:SetSpellTooltip(socketIcon, essence[1], "ANCHOR_TOPRIGHT")
|
yellowfive@181
|
433 end]]
|
yellowfive@181
|
434
|
yellowfive@181
|
435 prevSocket = socketBorder
|
yellowfive@181
|
436 end
|
yellowfive@181
|
437 end
|
yellowfive@181
|
438 end
|
yellowfive@181
|
439 end
|
yellowfive@124
|
440 else
|
yellowfive@124
|
441 for i = 1, #optimalItem.gemIds do
|
yellowfive@124
|
442 -- we rely on the fact that the gear sets coming back from the site will almost always have all sockets filled,
|
yellowfive@124
|
443 -- because it's a pain to get the actual number of sockets on an item from within the game
|
yellowfive@57
|
444 local g = optimalItem.gemIds[i]
|
yellowfive@124
|
445 if g == 0 then break end
|
yellowfive@124
|
446
|
yellowfive@124
|
447 local isGemEquipped = matchItem and matchItem.gemIds and matchItem.gemIds[i] == g
|
yellowfive@57
|
448
|
yellowfive@124
|
449 local socketBorder, socketIcon = createSocketWidget(panelMods, prevSocket or lblItem, prevSocket, isGemEquipped)
|
yellowfive@57
|
450
|
yellowfive@57
|
451 -- get icon for optimized gem
|
yellowfive@133
|
452 local gameItem = Item:CreateFromItemID(g)
|
yellowfive@133
|
453 if gameItem then
|
yellowfive@133
|
454 socketIcon:SetIcon(gameItem:GetItemIcon())
|
yellowfive@133
|
455 Amr:SetItemTooltip(socketIcon, gameItem:GetItemLink(), "ANCHOR_TOPRIGHT")
|
yellowfive@133
|
456 end
|
yellowfive@89
|
457
|
yellowfive@89
|
458 prevSocket = socketBorder
|
yellowfive@57
|
459 end
|
yellowfive@57
|
460 end
|
yellowfive@124
|
461
|
yellowfive@57
|
462 -- enchant
|
yellowfive@57
|
463 if optimalItem.enchantId and optimalItem.enchantId ~= 0 then
|
yellowfive@57
|
464 local isEnchantEquipped = matchItem and matchItem.enchantId and matchItem.enchantId == optimalItem.enchantId
|
yellowfive@135
|
465
|
yellowfive@57
|
466 local lblEnchant = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
467 panelMods:AddChild(lblEnchant)
|
yellowfive@124
|
468 lblEnchant:SetPoint("TOPLEFT", lblItem.frame, "TOPRIGHT", 130, 0)
|
yellowfive@57
|
469 lblEnchant:SetWordWrap(false)
|
yellowfive@57
|
470 lblEnchant:SetWidth(170)
|
yellowfive@57
|
471 lblEnchant:SetFont(Amr.CreateFont(isEnchantEquipped and "Regular" or "Bold", 14, isEnchantEquipped and Amr.Colors.TextGray or Amr.Colors.White))
|
yellowfive@57
|
472
|
yellowfive@124
|
473 local enchInfo = Amr.db.char.ExtraEnchantData[optimalItem.enchantId]
|
yellowfive@57
|
474 if enchInfo then
|
yellowfive@57
|
475 lblEnchant:SetText(enchInfo.text)
|
yellowfive@57
|
476
|
yellowfive@133
|
477 local gameItem = Item:CreateFromItemID(enchInfo.itemId)
|
yellowfive@133
|
478 if gameItem then
|
yellowfive@133
|
479 Amr:SetItemTooltip(lblEnchant, gameItem:GetItemLink(), "ANCHOR_TOPRIGHT")
|
yellowfive@133
|
480 end
|
yellowfive@57
|
481 end
|
yellowfive@124
|
482
|
yellowfive@57
|
483 end
|
yellowfive@57
|
484 end
|
yellowfive@57
|
485
|
yellowfive@57
|
486 prevElem = lbl
|
yellowfive@57
|
487 end
|
yellowfive@57
|
488 end
|
yellowfive@57
|
489 end
|
yellowfive@57
|
490
|
yellowfive@139
|
491 local function onSetupChange(widget, eventName, value)
|
yellowfive@139
|
492 _activeSetupId = value
|
yellowfive@139
|
493 renderGear(_activeSetupId, _panelGear)
|
yellowfive@57
|
494 end
|
yellowfive@57
|
495
|
yellowfive@57
|
496 local function onImportClick(widget)
|
yellowfive@57
|
497 Amr:ShowImportWindow()
|
yellowfive@57
|
498 end
|
yellowfive@57
|
499
|
yellowfive@139
|
500 function Amr:PickFirstSetupForSpec()
|
yellowfive@139
|
501 local specSlot = GetSpecialization()
|
yellowfive@139
|
502 for i, setup in ipairs(Amr.db.char.GearSetups) do
|
yellowfive@139
|
503 if setup.SpecSlot == specSlot then
|
yellowfive@139
|
504 _activeSetupId = setup.Id
|
yellowfive@139
|
505 break
|
yellowfive@139
|
506 end
|
yellowfive@139
|
507 end
|
yellowfive@139
|
508 end
|
yellowfive@139
|
509
|
yellowfive@139
|
510 function Amr:GetActiveSetupId()
|
yellowfive@139
|
511 return _activeSetupId
|
yellowfive@139
|
512 end
|
yellowfive@139
|
513
|
yellowfive@139
|
514 function Amr:SetActiveSetupId(setupId)
|
yellowfive@139
|
515 _activeSetupId = setupId
|
yellowfive@139
|
516 end
|
yellowfive@139
|
517
|
yellowfive@139
|
518 function Amr:GetActiveSetupLabel()
|
yellowfive@139
|
519 if not _activeSetupId then
|
yellowfive@139
|
520 return nil
|
yellowfive@139
|
521 end
|
yellowfive@139
|
522 local setup = getSetupById(_activeSetupId)
|
yellowfive@139
|
523 if not setup then
|
yellowfive@139
|
524 return nil
|
yellowfive@139
|
525 else
|
yellowfive@139
|
526 return setup.Label
|
yellowfive@139
|
527 end
|
yellowfive@139
|
528 end
|
yellowfive@139
|
529
|
yellowfive@57
|
530 -- renders the main UI for the Gear tab
|
yellowfive@57
|
531 function Amr:RenderTabGear(container)
|
yellowfive@57
|
532
|
yellowfive@57
|
533 local btnImport = AceGUI:Create("AmrUiButton")
|
yellowfive@57
|
534 btnImport:SetText(L.GearButtonImportText)
|
yellowfive@57
|
535 btnImport:SetBackgroundColor(Amr.Colors.Orange)
|
yellowfive@57
|
536 btnImport:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White))
|
yellowfive@57
|
537 btnImport:SetWidth(120)
|
yellowfive@57
|
538 btnImport:SetHeight(26)
|
yellowfive@57
|
539 btnImport:SetCallback("OnClick", onImportClick)
|
yellowfive@57
|
540 container:AddChild(btnImport)
|
yellowfive@124
|
541 btnImport:SetPoint("TOPLEFT", container.content, "TOPLEFT", 0, -81)
|
yellowfive@57
|
542
|
yellowfive@57
|
543 local lbl = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
544 container:AddChild(lbl)
|
yellowfive@57
|
545 lbl:SetText(L.GearImportNote)
|
yellowfive@57
|
546 lbl:SetWidth(100)
|
yellowfive@57
|
547 lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextTan))
|
yellowfive@57
|
548 lbl:SetJustifyH("MIDDLE")
|
yellowfive@57
|
549 lbl:SetPoint("TOP", btnImport.frame, "BOTTOM", 0, -5)
|
yellowfive@57
|
550
|
yellowfive@57
|
551 local lbl2 = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
552 container:AddChild(lbl2)
|
yellowfive@57
|
553 lbl2:SetText(L.GearTipTitle)
|
yellowfive@57
|
554 lbl2:SetWidth(140)
|
yellowfive@57
|
555 lbl2:SetFont(Amr.CreateFont("Italic", 20, Amr.Colors.Text))
|
yellowfive@57
|
556 lbl2:SetJustifyH("MIDDLE")
|
yellowfive@57
|
557 lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -50)
|
yellowfive@57
|
558
|
yellowfive@57
|
559 lbl = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
560 container:AddChild(lbl)
|
yellowfive@57
|
561 lbl:SetText(L.GearTipText)
|
yellowfive@57
|
562 lbl:SetWidth(140)
|
yellowfive@57
|
563 lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.Text))
|
yellowfive@57
|
564 lbl:SetJustifyH("MIDDLE")
|
yellowfive@57
|
565 lbl:SetPoint("TOP", lbl2.frame, "BOTTOM", 0, -5)
|
yellowfive@57
|
566
|
yellowfive@57
|
567 lbl2 = AceGUI:Create("AmrUiLabel")
|
yellowfive@124
|
568 container:AddChild(lbl2)
|
yellowfive@57
|
569 lbl2:SetText(L.GearTipCommands)
|
yellowfive@57
|
570 lbl2:SetWidth(130)
|
yellowfive@57
|
571 lbl2:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.Text))
|
yellowfive@57
|
572 lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 10, -5)
|
yellowfive@57
|
573
|
yellowfive@139
|
574 _cboSetups = AceGUI:Create("AmrUiDropDown")
|
yellowfive@139
|
575 _cboSetups:SetWidth(300)
|
yellowfive@139
|
576 container:AddChild(_cboSetups)
|
yellowfive@139
|
577 _cboSetups:SetPoint("TOPLEFT", container.content, "TOPLEFT", 150, -27.5)
|
yellowfive@81
|
578
|
yellowfive@139
|
579 _panelGear = AceGUI:Create("AmrUiPanel")
|
yellowfive@139
|
580 _panelGear:SetLayout("None")
|
yellowfive@139
|
581 _panelGear:SetBackgroundColor(Amr.Colors.Bg)
|
yellowfive@139
|
582 container:AddChild(_panelGear)
|
yellowfive@139
|
583 _panelGear:SetPoint("TOPLEFT", container.content, "TOPLEFT", 144, -58)
|
yellowfive@139
|
584 _panelGear:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT")
|
yellowfive@57
|
585
|
yellowfive@61
|
586 local btnShop = AceGUI:Create("AmrUiButton")
|
yellowfive@161
|
587 container:AddChild(btnShop)
|
yellowfive@61
|
588 btnShop:SetText(L.GearButtonShop)
|
yellowfive@61
|
589 btnShop:SetBackgroundColor(Amr.Colors.Blue)
|
yellowfive@61
|
590 btnShop:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
|
yellowfive@161
|
591 btnShop:SetWidth(200)
|
yellowfive@61
|
592 btnShop:SetHeight(26)
|
yellowfive@61
|
593 btnShop:SetCallback("OnClick", function(widget) Amr:ShowShopWindow() end)
|
yellowfive@161
|
594 btnShop:SetPoint("TOPRIGHT", container.content, "TOPRIGHT", -42, -25)
|
yellowfive@161
|
595
|
yellowfive@161
|
596 local btnJunk = AceGUI:Create("AmrUiButton")
|
yellowfive@161
|
597 container:AddChild(btnJunk)
|
yellowfive@161
|
598 btnJunk:SetText(L.GearButtonJunk)
|
yellowfive@161
|
599 btnJunk:SetBackgroundColor(Amr.Colors.Blue)
|
yellowfive@161
|
600 btnJunk:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
|
yellowfive@161
|
601 btnJunk:SetWidth(200)
|
yellowfive@161
|
602 btnJunk:SetHeight(26)
|
yellowfive@161
|
603 btnJunk:SetCallback("OnClick", function(widget) Amr:ShowJunkWindow() end)
|
yellowfive@161
|
604 btnJunk:SetPoint("CENTER", btnShop.frame, "CENTER", 0, 36)
|
yellowfive@139
|
605
|
yellowfive@139
|
606 -- pick a default tab based on player's current spec if none is already specified
|
yellowfive@139
|
607 if not _activeSetupId then
|
yellowfive@139
|
608 Amr:PickFirstSetupForSpec()
|
yellowfive@57
|
609 end
|
yellowfive@139
|
610
|
yellowfive@139
|
611 Amr:RefreshGearDisplay()
|
yellowfive@139
|
612
|
yellowfive@139
|
613 -- set event on dropdown after UI has been initially rendered
|
yellowfive@139
|
614 _cboSetups:SetCallback("OnChange", onSetupChange)
|
yellowfive@57
|
615 end
|
yellowfive@57
|
616
|
yellowfive@57
|
617 function Amr:ReleaseTabGear()
|
yellowfive@139
|
618 _cboSetups = nil
|
yellowfive@139
|
619 _panelGear = nil
|
yellowfive@57
|
620 end
|
yellowfive@57
|
621
|
yellowfive@57
|
622 -- refresh display of the current gear tab
|
yellowfive@139
|
623 function Amr:RefreshGearDisplay()
|
yellowfive@139
|
624
|
yellowfive@139
|
625 if not _panelGear then
|
yellowfive@139
|
626 return
|
yellowfive@139
|
627 end
|
yellowfive@139
|
628
|
yellowfive@139
|
629 -- fill the gear setup picker
|
yellowfive@139
|
630 local setupList = {}
|
yellowfive@139
|
631 for i, setup in ipairs(Amr.db.char.GearSetups) do
|
yellowfive@139
|
632 table.insert(setupList, { text = setup.Label, value = setup.Id })
|
yellowfive@139
|
633 end
|
yellowfive@139
|
634 _cboSetups:SetItems(setupList)
|
yellowfive@139
|
635
|
yellowfive@139
|
636 -- set selected value
|
yellowfive@139
|
637 local prev = _activeSetupId
|
yellowfive@139
|
638 _cboSetups:SelectItem(_activeSetupId)
|
yellowfive@139
|
639
|
yellowfive@139
|
640 if prev == _activeSetupId then
|
yellowfive@139
|
641 -- selecting will trigger the change event if it changed; if it didn't change, do a render now
|
yellowfive@139
|
642 renderGear(_activeSetupId, _panelGear)
|
yellowfive@139
|
643 end
|
yellowfive@57
|
644 end
|
yellowfive@57
|
645
|
yellowfive@57
|
646
|
yellowfive@57
|
647 ------------------------------------------------------------------------------------------------
|
yellowfive@57
|
648 -- Gear Set Management
|
yellowfive@57
|
649 ------------------------------------------------------------------------------------------------
|
yellowfive@57
|
650 local _waitingForSpec = 0
|
yellowfive@124
|
651 local _pendingGearOps = nil
|
yellowfive@124
|
652 local _currentGearOp = nil
|
yellowfive@124
|
653 local _itemLockAction = nil
|
yellowfive@124
|
654 local _gearOpPasses = 0
|
yellowfive@124
|
655 local _gearOpWaiting = nil
|
yellowfive@57
|
656
|
yellowfive@124
|
657 local beginEquipGearSet, processCurrentGearOp, nextGearOp
|
yellowfive@89
|
658
|
yellowfive@57
|
659 -- find the first empty slot in the player's backpack+bags
|
yellowfive@161
|
660 local function findFirstEmptyBagSlot(usedBagSlots)
|
yellowfive@57
|
661
|
yellowfive@57
|
662 local bagIds = {}
|
yellowfive@57
|
663 table.insert(bagIds, BACKPACK_CONTAINER)
|
yellowfive@57
|
664 for bagId = 1, NUM_BAG_SLOTS do
|
yellowfive@57
|
665 table.insert(bagIds, bagId)
|
yellowfive@57
|
666 end
|
yellowfive@57
|
667
|
yellowfive@57
|
668 for i, bagId in ipairs(bagIds) do
|
yellowfive@57
|
669 local numSlots = GetContainerNumSlots(bagId)
|
yellowfive@57
|
670 for slotId = 1, numSlots do
|
yellowfive@161
|
671 if not usedBagSlots or not usedBagSlots[bagId] or not usedBagSlots[bagId][slotId] then
|
yellowfive@161
|
672 local _, _, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId)
|
yellowfive@161
|
673 if not itemLink then
|
yellowfive@161
|
674 -- this prevents repeated calls to this from returning the same bag slot if desired
|
yellowfive@161
|
675 if usedBagSlots then
|
yellowfive@161
|
676 if not usedBagSlots[bagId] then
|
yellowfive@161
|
677 usedBagSlots[bagId] = {}
|
yellowfive@161
|
678 end
|
yellowfive@161
|
679 usedBagSlots[bagId][slotId] = true
|
yellowfive@161
|
680 end
|
yellowfive@161
|
681
|
yellowfive@161
|
682 return bagId, slotId
|
yellowfive@161
|
683 end
|
yellowfive@57
|
684 end
|
yellowfive@57
|
685 end
|
yellowfive@57
|
686 end
|
yellowfive@57
|
687
|
yellowfive@57
|
688 return nil, nil
|
yellowfive@57
|
689 end
|
yellowfive@57
|
690
|
yellowfive@161
|
691
|
yellowfive@161
|
692
|
yellowfive@124
|
693 -- scan a bag for the best matching item
|
yellowfive@124
|
694 local function scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
|
yellowfive@124
|
695 local numSlots = GetContainerNumSlots(bagId)
|
Yellowfive@195
|
696 --local loc = ItemLocation.CreateEmpty()
|
Yellowfive@195
|
697 local blizzItem
|
yellowfive@124
|
698 for slotId = 1, numSlots do
|
yellowfive@124
|
699 local _, _, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId)
|
yellowfive@124
|
700 -- we skip any stackable item, as far as we know, there is no equippable gear that can be stacked
|
yellowfive@124
|
701 if itemLink then
|
yellowfive@124
|
702 local bagItem = Amr.ParseItemLink(itemLink)
|
yellowfive@124
|
703 if bagItem ~= nil then
|
Yellowfive@195
|
704
|
Yellowfive@195
|
705 blizzItem = Item:CreateFromBagAndSlot(bagId, slotId)
|
Yellowfive@195
|
706
|
Yellowfive@195
|
707 -- seems to be of the form Item-1147-0-4000000XXXXXXXXX, so we take just the last 9 digits
|
Yellowfive@195
|
708 bagItem.guid = blizzItem:GetItemGUID()
|
Yellowfive@195
|
709 if bagItem.guid and strlen(bagItem.guid) > 9 then
|
Yellowfive@195
|
710 bagItem.guid = strsub(bagItem.guid, -9)
|
Yellowfive@195
|
711 end
|
Yellowfive@195
|
712
|
yellowfive@149
|
713 -- see if this is an azerite item and read azerite power ids
|
yellowfive@185
|
714 --[[loc:SetBagAndSlot(bagId, slotId)
|
yellowfive@149
|
715 if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(loc) then
|
yellowfive@149
|
716 local powers = Amr.ReadAzeritePowers(loc)
|
yellowfive@149
|
717 if powers then
|
yellowfive@149
|
718 bagItem.azerite = powers
|
yellowfive@149
|
719 end
|
yellowfive@185
|
720 end]]
|
yellowfive@149
|
721
|
yellowfive@124
|
722 local diff = countItemDifferences(item, bagItem)
|
yellowfive@124
|
723 if diff < bestDiff then
|
yellowfive@124
|
724 bestItem = { bag = bagId, slot = slotId }
|
yellowfive@124
|
725 bestDiff = diff
|
yellowfive@124
|
726 bestLink = itemLink
|
yellowfive@124
|
727 end
|
yellowfive@124
|
728 end
|
yellowfive@124
|
729 end
|
yellowfive@57
|
730 end
|
yellowfive@124
|
731 return bestItem, bestDiff, bestLink
|
yellowfive@57
|
732 end
|
yellowfive@57
|
733
|
yellowfive@124
|
734 -- find the item in the player's inventory that best matches the current gear op item, favoring stuff already equipped, then in bags, then in bank
|
yellowfive@124
|
735 local function findCurrentGearOpItem()
|
yellowfive@124
|
736
|
yellowfive@124
|
737 local item = _currentGearOp.items[_currentGearOp.nextSlot]
|
yellowfive@124
|
738
|
yellowfive@57
|
739 local bestItem = nil
|
yellowfive@57
|
740 local bestLink = nil
|
yellowfive@124
|
741 local bestDiff = 10000
|
yellowfive@57
|
742
|
yellowfive@73
|
743 -- inventory
|
yellowfive@73
|
744 bestItem, bestDiff, bestLink = scanBagForItem(item, BACKPACK_CONTAINER, bestItem, bestDiff, bestLink)
|
yellowfive@73
|
745 for bagId = 1, NUM_BAG_SLOTS do
|
yellowfive@73
|
746 bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
|
yellowfive@73
|
747 end
|
yellowfive@73
|
748
|
yellowfive@129
|
749 -- with new approach, the item to use should never be equipped, should be in bags at this point
|
yellowfive@129
|
750 --[[
|
yellowfive@61
|
751 -- equipped items, but skip slots we have just equipped (to avoid e.g. just moving 2 of the same item back and forth between mh oh weapon slots)
|
yellowfive@57
|
752 for slotNum = 1, #Amr.SlotIds do
|
yellowfive@57
|
753 local slotId = Amr.SlotIds[slotNum]
|
yellowfive@124
|
754 if _currentGearOp.slotsRemaining[slotId] then
|
yellowfive@61
|
755 local itemLink = GetInventoryItemLink("player", slotId)
|
yellowfive@61
|
756 if itemLink then
|
yellowfive@61
|
757 local invItem = Amr.ParseItemLink(itemLink)
|
yellowfive@124
|
758 if invItem then
|
yellowfive@61
|
759 local diff = countItemDifferences(item, invItem)
|
yellowfive@61
|
760 if diff < bestDiff then
|
yellowfive@61
|
761 bestItem = { slot = slotId }
|
yellowfive@61
|
762 bestDiff = diff
|
yellowfive@61
|
763 bestLink = itemLink
|
yellowfive@61
|
764 end
|
yellowfive@57
|
765 end
|
yellowfive@57
|
766 end
|
yellowfive@57
|
767 end
|
yellowfive@57
|
768 end
|
yellowfive@129
|
769 ]]
|
yellowfive@129
|
770
|
yellowfive@57
|
771 -- bank
|
yellowfive@124
|
772 if bestDiff > 0 then
|
yellowfive@124
|
773 bestItem, bestDiff, bestLink = scanBagForItem(item, BANK_CONTAINER, bestItem, bestDiff, bestLink)
|
yellowfive@124
|
774 for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
|
yellowfive@124
|
775 bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
|
yellowfive@124
|
776 end
|
yellowfive@57
|
777 end
|
yellowfive@124
|
778
|
yellowfive@124
|
779 return bestItem, bestDiff, bestLink
|
yellowfive@124
|
780 end
|
yellowfive@124
|
781
|
yellowfive@143
|
782 local function createAmrEquipmentSet()
|
yellowfive@133
|
783
|
yellowfive@143
|
784 -- clear any currently ignored slots, ignore shirt and tabard
|
yellowfive@143
|
785 C_EquipmentSet.ClearIgnoredSlotsForSave()
|
yellowfive@133
|
786 C_EquipmentSet.IgnoreSlotForSave(INVSLOT_BODY) -- shirt
|
yellowfive@133
|
787 C_EquipmentSet.IgnoreSlotForSave(INVSLOT_TABARD)
|
yellowfive@133
|
788
|
yellowfive@133
|
789 -- for now use icon of the spec
|
yellowfive@133
|
790 local _, specName, _, setIcon = GetSpecializationInfo(GetSpecialization())
|
yellowfive@57
|
791
|
yellowfive@133
|
792 --[[
|
yellowfive@124
|
793 local item = Amr.ParseItemLink(GetInventoryItemLink("player", INVSLOT_MAINHAND))
|
yellowfive@124
|
794 if not item then
|
yellowfive@124
|
795 item = Amr.ParseItemLink(GetInventoryItemLink("player", INVSLOT_OFFHAND))
|
yellowfive@124
|
796 end
|
yellowfive@124
|
797 if item then
|
yellowfive@133
|
798 local itemObj = Item:CreateFromItemID(item.id)
|
yellowfive@133
|
799 if itemObj then
|
yellowfive@133
|
800 setIcon = itemObj:GetItemIcon()
|
yellowfive@133
|
801 end
|
yellowfive@133
|
802 end
|
yellowfive@133
|
803 ]]
|
yellowfive@133
|
804
|
yellowfive@139
|
805 local setup = getSetupById(_activeSetupId)
|
yellowfive@139
|
806 local setname = setup.Label -- "AMR " .. specName
|
yellowfive@133
|
807 local setid = C_EquipmentSet.GetEquipmentSetID(setname)
|
yellowfive@133
|
808 if setid then
|
yellowfive@145
|
809 local oldName, oldIcon = C_EquipmentSet.GetEquipmentSetInfo(setid)
|
yellowfive@145
|
810 setIcon = oldIcon
|
yellowfive@133
|
811 C_EquipmentSet.SaveEquipmentSet(setid, setIcon)
|
yellowfive@133
|
812 else
|
yellowfive@133
|
813 C_EquipmentSet.CreateEquipmentSet(setname, setIcon)
|
yellowfive@124
|
814 end
|
yellowfive@124
|
815 end
|
yellowfive@124
|
816
|
yellowfive@143
|
817 -- on completion, create an equipment manager set if desired
|
yellowfive@143
|
818 local function onEquipGearSetComplete()
|
yellowfive@143
|
819 if Amr.db.profile.options.disableEm then return end
|
yellowfive@143
|
820
|
yellowfive@143
|
821 -- create an equipment manager set
|
yellowfive@143
|
822 createAmrEquipmentSet()
|
yellowfive@143
|
823
|
yellowfive@143
|
824 -- need to call it twice because on first load the WoW equipment manager just doesn't work
|
yellowfive@143
|
825 Amr.Wait(1, function()
|
yellowfive@143
|
826 createAmrEquipmentSet()
|
yellowfive@143
|
827 end)
|
yellowfive@143
|
828 end
|
yellowfive@143
|
829
|
yellowfive@124
|
830 -- stop any currently in-progress gear swapping operation and clean up
|
yellowfive@124
|
831 local function disposeGearOp()
|
yellowfive@124
|
832 _pendingGearOps = nil
|
yellowfive@124
|
833 _currentGearOp = nil
|
yellowfive@124
|
834 _itemLockAction = nil
|
yellowfive@124
|
835 _gearOpPasses = 0
|
yellowfive@124
|
836 _gearOpWaiting = nil
|
yellowfive@124
|
837
|
yellowfive@124
|
838 -- make sure the gear tab is still in sync
|
yellowfive@139
|
839 Amr:RefreshGearDisplay()
|
yellowfive@124
|
840 end
|
yellowfive@124
|
841
|
yellowfive@124
|
842 -- initialize a gear op to start running it
|
yellowfive@139
|
843 local function initializeGearOp(op, setupId, pos)
|
yellowfive@124
|
844 op.pos = pos
|
yellowfive@139
|
845 op.setupId = setupId
|
yellowfive@124
|
846
|
yellowfive@124
|
847 -- fill the remaining slot list and set the starting slot
|
yellowfive@124
|
848 op.nextSlot = nil
|
yellowfive@124
|
849 op.slotsRemaining = {}
|
yellowfive@124
|
850 op.isWaiting = false
|
yellowfive@124
|
851 for slotId, item in pairs(op.items) do
|
yellowfive@124
|
852 op.slotsRemaining[slotId] = true
|
yellowfive@124
|
853 if not op.nextSlot then
|
yellowfive@124
|
854 op.nextSlot = slotId
|
yellowfive@124
|
855 end
|
yellowfive@124
|
856 end
|
yellowfive@124
|
857 end
|
yellowfive@124
|
858
|
yellowfive@124
|
859 function processCurrentGearOp()
|
yellowfive@124
|
860 if not _currentGearOp then return end
|
yellowfive@124
|
861
|
yellowfive@124
|
862 if _currentGearOp.remove then
|
yellowfive@124
|
863 -- remove the next item
|
yellowfive@124
|
864
|
yellowfive@124
|
865 -- check if the slot is already empty
|
yellowfive@124
|
866 local itemLink = GetInventoryItemLink("player", _currentGearOp.nextSlot)
|
yellowfive@124
|
867 if not itemLink then
|
yellowfive@124
|
868 nextGearOp()
|
yellowfive@124
|
869 return
|
yellowfive@124
|
870 end
|
yellowfive@124
|
871
|
yellowfive@57
|
872 -- find first empty bag slot
|
yellowfive@57
|
873 local invBag, invSlot = findFirstEmptyBagSlot()
|
yellowfive@57
|
874 if not invBag then
|
yellowfive@57
|
875 -- stop if bags are too full
|
yellowfive@57
|
876 Amr:Print(L.GearEquipErrorBagFull)
|
yellowfive@124
|
877 disposeGearOp()
|
yellowfive@57
|
878 return
|
yellowfive@57
|
879 end
|
yellowfive@57
|
880
|
yellowfive@124
|
881 PickupInventoryItem(_currentGearOp.nextSlot)
|
yellowfive@57
|
882 PickupContainerItem(invBag, invSlot)
|
yellowfive@57
|
883
|
yellowfive@124
|
884 -- set an action to happen on ITEM_UNLOCKED, triggered by ClearCursor
|
yellowfive@124
|
885 _itemLockAction = {
|
yellowfive@57
|
886 bagId = invBag,
|
yellowfive@124
|
887 slotId = invSlot,
|
yellowfive@124
|
888 isRemove = true
|
yellowfive@57
|
889 }
|
yellowfive@124
|
890
|
yellowfive@124
|
891 ClearCursor()
|
yellowfive@124
|
892 -- wait for remove to complete
|
yellowfive@124
|
893 else
|
yellowfive@124
|
894 -- equip the next item
|
yellowfive@57
|
895
|
yellowfive@124
|
896 local bestItem, bestDiff, bestLink = findCurrentGearOpItem()
|
yellowfive@124
|
897
|
yellowfive@124
|
898 _itemLockAction = nil
|
yellowfive@57
|
899 ClearCursor()
|
yellowfive@124
|
900
|
yellowfive@124
|
901 if not bestItem then
|
yellowfive@124
|
902 -- stop if we can't find an item
|
yellowfive@124
|
903 Amr:Print(L.GearEquipErrorNotFound)
|
yellowfive@124
|
904 Amr:Print(L.GearEquipErrorNotFound2)
|
yellowfive@124
|
905 disposeGearOp()
|
yellowfive@124
|
906
|
yellowfive@124
|
907 elseif bestItem and bestItem.bag and (bestItem.bag == BANK_CONTAINER or bestItem.bag >= NUM_BAG_SLOTS + 1 and bestItem.bag <= NUM_BAG_SLOTS + NUM_BANKBAGSLOTS) then
|
yellowfive@124
|
908 -- find first empty bag slot
|
yellowfive@124
|
909 local invBag, invSlot = findFirstEmptyBagSlot()
|
yellowfive@124
|
910 if not invBag then
|
yellowfive@124
|
911 -- stop if bags are too full
|
yellowfive@124
|
912 Amr:Print(L.GearEquipErrorBagFull)
|
yellowfive@124
|
913 disposeGearOp()
|
yellowfive@124
|
914 return
|
yellowfive@124
|
915 end
|
yellowfive@124
|
916
|
yellowfive@124
|
917 -- move from bank to bag
|
yellowfive@124
|
918 PickupContainerItem(bestItem.bag, bestItem.slot)
|
yellowfive@124
|
919 PickupContainerItem(invBag, invSlot)
|
yellowfive@124
|
920
|
yellowfive@124
|
921 -- set an action to happen on ITEM_UNLOCKED, triggered by ClearCursor
|
yellowfive@124
|
922 _itemLockAction = {
|
yellowfive@124
|
923 bagId = invBag,
|
yellowfive@124
|
924 slotId = invSlot,
|
yellowfive@124
|
925 isBank = true
|
yellowfive@124
|
926 }
|
yellowfive@124
|
927
|
yellowfive@124
|
928 ClearCursor()
|
yellowfive@124
|
929 -- now we need to wait for game event to continue and try this item again after it is in our bag and unlocked
|
yellowfive@124
|
930
|
yellowfive@124
|
931 elseif (bestItem.bag or bestItem.bag == 0) and not Amr:CanEquip(bestItem.bag, bestItem.slot) then
|
yellowfive@57
|
932 -- if an item is not soulbound, then warn the user and quit
|
yellowfive@57
|
933 Amr:Print(L.GearEquipErrorSoulbound(bestLink))
|
yellowfive@124
|
934 disposeGearOp()
|
yellowfive@124
|
935
|
yellowfive@57
|
936 else
|
yellowfive@124
|
937
|
yellowfive@129
|
938 --print("equipping " .. bestLink .. " in slot " .. _currentGearOp.nextSlot)
|
yellowfive@129
|
939
|
yellowfive@57
|
940 -- an item in the player's bags or already equipped, equip it
|
yellowfive@57
|
941 if bestItem.bag then
|
yellowfive@57
|
942 PickupContainerItem(bestItem.bag, bestItem.slot)
|
yellowfive@57
|
943 else
|
yellowfive@124
|
944 _gearOpWaiting.inventory[bestItem.slot] = true
|
yellowfive@57
|
945 PickupInventoryItem(bestItem.slot)
|
yellowfive@57
|
946 end
|
yellowfive@124
|
947 _gearOpWaiting.inventory[_currentGearOp.nextSlot] = true
|
yellowfive@124
|
948 PickupInventoryItem(_currentGearOp.nextSlot)
|
yellowfive@124
|
949
|
yellowfive@124
|
950 -- don't wait for now, do all equips at once
|
yellowfive@124
|
951 --[[
|
yellowfive@124
|
952 -- set an action to happen on ITEM_UNLOCKED, triggered by ClearCursor
|
yellowfive@124
|
953 _itemLockAction = {
|
yellowfive@124
|
954 bagId = bestItem.bag,
|
yellowfive@124
|
955 slotId = bestItem.slot,
|
yellowfive@124
|
956 invSlot = _currentGearOp.nextSlot,
|
yellowfive@124
|
957 isEquip = true
|
yellowfive@124
|
958 }
|
yellowfive@124
|
959 ]]
|
yellowfive@124
|
960
|
yellowfive@124
|
961 ClearCursor()
|
yellowfive@124
|
962 nextGearOp()
|
yellowfive@124
|
963 end
|
yellowfive@124
|
964
|
yellowfive@124
|
965 end
|
yellowfive@124
|
966 end
|
yellowfive@124
|
967
|
yellowfive@124
|
968 -- when a gear op completes successfully, this will advance to the next op or finish
|
yellowfive@124
|
969 function nextGearOp()
|
yellowfive@124
|
970 if not _currentGearOp then return end
|
yellowfive@124
|
971
|
yellowfive@139
|
972 local setupId = _currentGearOp.setupId
|
yellowfive@124
|
973 local pos = _currentGearOp.pos
|
yellowfive@124
|
974 local passes = _gearOpPasses
|
yellowfive@124
|
975
|
yellowfive@124
|
976 -- mark the slot as done and move to the next
|
yellowfive@124
|
977 if _currentGearOp.nextSlot then
|
yellowfive@124
|
978 _currentGearOp.slotsRemaining[_currentGearOp.nextSlot] = nil
|
yellowfive@124
|
979 _currentGearOp.nextSlot = nil
|
yellowfive@124
|
980 for slotId, item in pairs(_currentGearOp.items) do
|
yellowfive@124
|
981 if _currentGearOp.slotsRemaining[slotId] then
|
yellowfive@124
|
982 _currentGearOp.nextSlot = slotId
|
yellowfive@124
|
983 break
|
yellowfive@124
|
984 end
|
yellowfive@124
|
985 end
|
yellowfive@124
|
986 end
|
yellowfive@124
|
987
|
yellowfive@124
|
988 if not _currentGearOp.nextSlot then
|
yellowfive@124
|
989 -- see if anything is still in progress and we want to wait for it before continuing
|
yellowfive@124
|
990 local inProgress = not Amr.IsEmpty(_gearOpWaiting.inventory)
|
yellowfive@124
|
991
|
yellowfive@124
|
992 if (_currentGearOp.wait or _currentGearOp.remove) and inProgress then
|
yellowfive@124
|
993 -- this will cause the item unlock handler to call nextGearOp again when all in-progress swaps have unlocked related slots
|
yellowfive@124
|
994 _currentGearOp.isWaiting = true
|
yellowfive@124
|
995 else
|
yellowfive@124
|
996 _currentGearOp = _pendingGearOps[pos + 1]
|
yellowfive@124
|
997 if _currentGearOp then
|
yellowfive@124
|
998 -- we have another op, do it
|
yellowfive@139
|
999 initializeGearOp(_currentGearOp, setupId, pos + 1)
|
yellowfive@124
|
1000 processCurrentGearOp()
|
yellowfive@124
|
1001 else
|
yellowfive@124
|
1002 -- we are done
|
yellowfive@124
|
1003 disposeGearOp()
|
yellowfive@124
|
1004
|
yellowfive@124
|
1005 -- this will check if not all items were swapped, and either finish up, try again, or abort if have tried too many times
|
yellowfive@139
|
1006 beginEquipGearSet(setupId, passes + 1)
|
yellowfive@124
|
1007 end
|
yellowfive@124
|
1008 end
|
yellowfive@124
|
1009 else
|
yellowfive@124
|
1010 -- do the next item
|
yellowfive@124
|
1011 processCurrentGearOp()
|
yellowfive@124
|
1012 end
|
yellowfive@124
|
1013
|
yellowfive@124
|
1014 end
|
yellowfive@124
|
1015
|
yellowfive@124
|
1016 local function handleItemUnlocked(bagId, slotId)
|
yellowfive@124
|
1017
|
yellowfive@124
|
1018 -- mark anything that is waiting as unlocked if it is no longer locked
|
yellowfive@124
|
1019 if _currentGearOp and _gearOpWaiting then
|
yellowfive@124
|
1020 for i,s in ipairs(Amr.SlotIds) do
|
yellowfive@124
|
1021 if not IsInventoryItemLocked(s) then
|
yellowfive@124
|
1022 _gearOpWaiting.inventory[s] = nil
|
yellowfive@124
|
1023 end
|
yellowfive@124
|
1024 end
|
yellowfive@124
|
1025 end
|
yellowfive@124
|
1026
|
yellowfive@124
|
1027 if _itemLockAction then
|
yellowfive@124
|
1028 if _itemLockAction.isRemove then
|
yellowfive@124
|
1029 -- waiting for a specific remove op to finish before continuing
|
yellowfive@124
|
1030 if bagId == _itemLockAction.bagId and slotId == _itemLockAction.slotId then
|
yellowfive@124
|
1031 _itemLockAction = nil
|
yellowfive@124
|
1032 nextGearOp()
|
yellowfive@124
|
1033 end
|
yellowfive@124
|
1034 elseif _itemLockAction.isBank then
|
yellowfive@124
|
1035 -- waiting for an item to move from bank into inventory, then reprocess the current op
|
yellowfive@124
|
1036 if bagId == _itemLockAction.bagId and slotId == _itemLockAction.slotId then
|
yellowfive@124
|
1037 _itemLockAction = nil
|
yellowfive@124
|
1038 processCurrentGearOp()
|
yellowfive@124
|
1039 end
|
yellowfive@124
|
1040
|
yellowfive@124
|
1041 elseif _itemLockAction.isEquip then
|
yellowfive@124
|
1042 -- this is not currently used... we do all equips at once usually, but could go back to this if it causes problems
|
yellowfive@124
|
1043
|
yellowfive@124
|
1044 -- waiting for a specific equip op to finish
|
yellowfive@61
|
1045
|
yellowfive@124
|
1046 -- inventory slot we're swapping to is still locked, can't continue yet
|
yellowfive@124
|
1047 if IsInventoryItemLocked(_itemLockAction.invSlot) then return end
|
yellowfive@124
|
1048
|
yellowfive@124
|
1049 if _itemLockAction.bagId then
|
yellowfive@124
|
1050 local _, _, locked = GetContainerItemInfo(_itemLockAction.bagId, _itemLockAction.slotId)
|
yellowfive@124
|
1051 -- the bag slot we're swapping from is still locked, can't continue yet
|
yellowfive@124
|
1052 if locked then return end
|
yellowfive@124
|
1053 else
|
yellowfive@124
|
1054 -- inventory slot we're swapping from is still locked, can't continue yet
|
yellowfive@124
|
1055 if IsInventoryItemLocked(_itemLockAction.slotId) then return end
|
yellowfive@124
|
1056 end
|
yellowfive@124
|
1057
|
yellowfive@124
|
1058 _itemLockAction = nil
|
yellowfive@124
|
1059 nextGearOp()
|
yellowfive@124
|
1060 else
|
yellowfive@124
|
1061 -- unknown... shouldn't happen
|
yellowfive@124
|
1062 _itemLockAction = nil
|
yellowfive@57
|
1063 end
|
yellowfive@124
|
1064 else
|
yellowfive@124
|
1065
|
yellowfive@124
|
1066 -- not waiting on a specific action, check if we are waiting for all locked slots to open up and they are done
|
yellowfive@124
|
1067 if _currentGearOp and _gearOpWaiting and _currentGearOp.isWaiting and Amr.IsEmpty(_gearOpWaiting.inventory) then
|
yellowfive@124
|
1068 nextGearOp()
|
yellowfive@124
|
1069 end
|
yellowfive@57
|
1070 end
|
yellowfive@57
|
1071
|
yellowfive@57
|
1072 end
|
yellowfive@57
|
1073
|
yellowfive@124
|
1074 local function shuffle(tbl)
|
yellowfive@124
|
1075 local size = #tbl
|
yellowfive@124
|
1076 for i = size, 1, -1 do
|
yellowfive@124
|
1077 local rand = math.random(size)
|
yellowfive@124
|
1078 tbl[i], tbl[rand] = tbl[rand], tbl[i]
|
yellowfive@89
|
1079 end
|
yellowfive@124
|
1080 return tbl
|
yellowfive@89
|
1081 end
|
yellowfive@89
|
1082
|
yellowfive@129
|
1083 local _ohFirst = {
|
yellowfive@129
|
1084 [20] = true, -- PaladinProtection
|
yellowfive@129
|
1085 [32] = true, -- WarlockDemonology
|
yellowfive@129
|
1086 [36] = true -- WarriorProtection
|
yellowfive@129
|
1087 }
|
yellowfive@129
|
1088
|
yellowfive@139
|
1089 function beginEquipGearSet(setupId, passes)
|
yellowfive@57
|
1090
|
yellowfive@139
|
1091 local setup = getSetupById(setupId)
|
yellowfive@139
|
1092
|
yellowfive@139
|
1093 if not setup or not setup.Gear then
|
yellowfive@57
|
1094 Amr:Print(L.GearEquipErrorEmpty)
|
yellowfive@57
|
1095 return
|
yellowfive@57
|
1096 end
|
yellowfive@124
|
1097
|
yellowfive@139
|
1098 local gear = setup.Gear
|
yellowfive@139
|
1099 local spec = setup.SpecSlot
|
yellowfive@139
|
1100
|
yellowfive@139
|
1101 -- ensure all our stored data is up to date
|
yellowfive@57
|
1102 local player = Amr:ExportCharacter()
|
yellowfive@129
|
1103 local doOhFirst = _ohFirst[player.Specs[spec]]
|
yellowfive@57
|
1104
|
yellowfive@124
|
1105 local itemsToEquip = {
|
yellowfive@124
|
1106 legendaries = {},
|
yellowfive@124
|
1107 weapons = {},
|
yellowfive@129
|
1108 mh = {},
|
yellowfive@129
|
1109 oh = {},
|
yellowfive@124
|
1110 rings = {},
|
yellowfive@124
|
1111 trinkets = {},
|
yellowfive@124
|
1112 others = {},
|
yellowfive@124
|
1113 blanks = {}
|
yellowfive@124
|
1114 }
|
yellowfive@57
|
1115 local remaining = 0
|
yellowfive@129
|
1116 local usedItems = {}
|
yellowfive@124
|
1117
|
yellowfive@124
|
1118 -- check for items that need to be equipped, do in a random order to try and defeat any unique constraint issues we might hit
|
yellowfive@124
|
1119 local slots = {}
|
yellowfive@124
|
1120 for i,s in ipairs(Amr.SlotIds) do
|
yellowfive@124
|
1121 table.insert(slots, s)
|
yellowfive@124
|
1122 end
|
yellowfive@124
|
1123 shuffle(slots)
|
yellowfive@124
|
1124
|
yellowfive@124
|
1125 for i,slotId in ipairs(slots) do
|
yellowfive@124
|
1126
|
yellowfive@124
|
1127 -- we do stuff in batches that avoids most unique conflicts
|
yellowfive@124
|
1128 local list = itemsToEquip.others
|
yellowfive@129
|
1129 if slotId == 16 then
|
yellowfive@129
|
1130 list = itemsToEquip.mh
|
yellowfive@129
|
1131 elseif slotId == 17 then
|
yellowfive@129
|
1132 list = itemsToEquip.oh
|
yellowfive@124
|
1133 elseif slotId == 11 or slotId == 12 then
|
yellowfive@124
|
1134 list = itemsToEquip.rings
|
yellowfive@124
|
1135 elseif slotId == 13 or slotId == 14 then
|
yellowfive@124
|
1136 list = itemsToEquip.trinkets
|
yellowfive@124
|
1137 end
|
yellowfive@124
|
1138
|
yellowfive@57
|
1139 local old = player.Equipped[spec][slotId]
|
yellowfive@57
|
1140 local new = gear[slotId]
|
yellowfive@124
|
1141 local prevRemaining = remaining
|
yellowfive@69
|
1142 if new then
|
yellowfive@124
|
1143 -- if the new thing is an artifact, only match the item id
|
yellowfive@124
|
1144 local newItem = Item:CreateFromItemID(new.id)
|
yellowfive@124
|
1145 local quality = newItem and newItem:GetItemQuality() or 0
|
yellowfive@124
|
1146 if quality == 6 then
|
yellowfive@124
|
1147 if not old or new.id ~= old.id then
|
yellowfive@124
|
1148 list[slotId] = new
|
yellowfive@129
|
1149 if list == itemsToEquip.mh or list == itemsToEquip.oh then
|
yellowfive@129
|
1150 itemsToEquip.weapons[slotId] = {}
|
yellowfive@129
|
1151 end
|
yellowfive@69
|
1152 remaining = remaining + 1
|
yellowfive@69
|
1153 end
|
yellowfive@129
|
1154 else
|
yellowfive@145
|
1155
|
yellowfive@129
|
1156 -- find the best matching item anywhere in the player's gear
|
yellowfive@129
|
1157 local bestItem, bestDiff = Amr:FindMatchingItem(new, player, usedItems)
|
Yellowfive@195
|
1158
|
yellowfive@129
|
1159 new = bestItem
|
yellowfive@149
|
1160 local diff = countItemDifferences(new, old)
|
yellowfive@124
|
1161
|
Yellowfive@195
|
1162 if diff > 0 then
|
Yellowfive@200
|
1163
|
yellowfive@124
|
1164 list[slotId] = new
|
yellowfive@129
|
1165 if list == itemsToEquip.mh or list == itemsToEquip.oh then
|
yellowfive@129
|
1166 itemsToEquip.weapons[slotId] = {}
|
yellowfive@129
|
1167 end
|
yellowfive@124
|
1168 remaining = remaining + 1
|
yellowfive@124
|
1169 end
|
yellowfive@124
|
1170 end
|
yellowfive@129
|
1171 elseif old then
|
yellowfive@124
|
1172 -- need to remove this item
|
yellowfive@124
|
1173 itemsToEquip.blanks[slotId] = {}
|
yellowfive@124
|
1174 remaining = remaining + 1
|
yellowfive@124
|
1175 end
|
yellowfive@124
|
1176
|
yellowfive@124
|
1177 if remaining > prevRemaining then
|
yellowfive@124
|
1178 -- if we need to swap this slot, see if the old item is a legendary, add a step to remove those first to avoid conflicts
|
yellowfive@124
|
1179 if old then
|
yellowfive@124
|
1180 local oldItem = Item:CreateFromItemID(old.id)
|
yellowfive@124
|
1181 if oldItem and oldItem:GetItemQuality() == 5 then
|
yellowfive@124
|
1182 itemsToEquip.legendaries[slotId] = {}
|
yellowfive@124
|
1183 end
|
yellowfive@57
|
1184 end
|
yellowfive@57
|
1185 end
|
yellowfive@57
|
1186 end
|
yellowfive@124
|
1187
|
yellowfive@124
|
1188 if remaining > 0 then
|
yellowfive@57
|
1189
|
yellowfive@124
|
1190 if passes < 5 then
|
yellowfive@124
|
1191 _pendingGearOps = {}
|
yellowfive@124
|
1192
|
yellowfive@129
|
1193 if not Amr.IsEmpty(itemsToEquip.blanks) then
|
yellowfive@124
|
1194 -- if gear set wants slots to be blank, do that first
|
yellowfive@124
|
1195 table.insert(_pendingGearOps, { items = itemsToEquip.blanks, remove = true, label = "blanks" })
|
yellowfive@129
|
1196 end
|
yellowfive@124
|
1197 if not Amr.IsEmpty(itemsToEquip.weapons) then
|
yellowfive@129
|
1198 -- change weapons first: remove both, wait, then equip each weapon one by one, waiting after each
|
yellowfive@129
|
1199 table.insert(_pendingGearOps, { items = itemsToEquip.weapons, remove = true, label = "remove weapons" })
|
yellowfive@129
|
1200 local thisWeapon = doOhFirst and itemsToEquip.oh or itemsToEquip.mh
|
yellowfive@129
|
1201 if not Amr.IsEmpty(thisWeapon) then
|
yellowfive@129
|
1202 table.insert(_pendingGearOps, { items = thisWeapon, wait = true, label = "equip weapon 1" })
|
yellowfive@129
|
1203 end
|
yellowfive@129
|
1204 thisWeapon = doOhFirst and itemsToEquip.mh or itemsToEquip.oh
|
yellowfive@129
|
1205 if not Amr.IsEmpty(thisWeapon) then
|
yellowfive@129
|
1206 table.insert(_pendingGearOps, { items = thisWeapon, wait = true, label = "equip weapon 2" })
|
yellowfive@129
|
1207 end
|
yellowfive@124
|
1208 end
|
yellowfive@124
|
1209 if not Amr.IsEmpty(itemsToEquip.legendaries) then
|
yellowfive@124
|
1210 -- remove any legendaries, wait
|
yellowfive@124
|
1211 table.insert(_pendingGearOps, { items = itemsToEquip.legendaries, remove = true, label = "remove legendaries" })
|
yellowfive@124
|
1212 end
|
yellowfive@124
|
1213 if not Amr.IsEmpty(itemsToEquip.rings) then
|
yellowfive@124
|
1214 -- remove both rings, wait, then equip new ones
|
yellowfive@124
|
1215 table.insert(_pendingGearOps, { items = itemsToEquip.rings, remove = true, label = "remove rings" })
|
yellowfive@124
|
1216 table.insert(_pendingGearOps, { items = itemsToEquip.rings, wait = true, label = "equip rings" })
|
yellowfive@124
|
1217 end
|
yellowfive@124
|
1218 if not Amr.IsEmpty(itemsToEquip.trinkets) then
|
yellowfive@124
|
1219 -- remove both trinkets, wait, then equip new ones
|
yellowfive@124
|
1220 table.insert(_pendingGearOps, { items = itemsToEquip.trinkets, remove = true, label = "remove trinkets" })
|
yellowfive@124
|
1221 table.insert(_pendingGearOps, { items = itemsToEquip.trinkets, wait = true, label = "equip trinkets" })
|
yellowfive@124
|
1222 end
|
yellowfive@124
|
1223 if not Amr.IsEmpty(itemsToEquip.others) then
|
yellowfive@124
|
1224 -- equip all other items, wait for completion
|
yellowfive@124
|
1225 table.insert(_pendingGearOps, { items = itemsToEquip.others, wait = true, label = "equip others" })
|
yellowfive@124
|
1226 end
|
yellowfive@124
|
1227
|
yellowfive@169
|
1228 if #_pendingGearOps > 0 then
|
yellowfive@169
|
1229 -- make the last operation wait no matter what, before this gets called again to check if everything succeeded
|
yellowfive@169
|
1230 _pendingGearOps[#_pendingGearOps].wait = true
|
yellowfive@124
|
1231
|
yellowfive@169
|
1232 if not _gearOpWaiting then
|
yellowfive@169
|
1233 _gearOpWaiting = { inventory = {} }
|
yellowfive@169
|
1234 end
|
yellowfive@169
|
1235
|
yellowfive@169
|
1236 _gearOpPasses = passes
|
yellowfive@169
|
1237 _currentGearOp = _pendingGearOps[1]
|
yellowfive@169
|
1238 initializeGearOp(_currentGearOp, setupId, 1)
|
yellowfive@169
|
1239
|
yellowfive@169
|
1240 processCurrentGearOp()
|
yellowfive@169
|
1241 else
|
yellowfive@169
|
1242 -- TODO: print message that gear set couldn't be equipped
|
yellowfive@124
|
1243 end
|
yellowfive@169
|
1244
|
yellowfive@124
|
1245 else
|
yellowfive@124
|
1246 -- TODO: print message that gear set couldn't be equipped
|
yellowfive@89
|
1247 end
|
yellowfive@57
|
1248
|
yellowfive@57
|
1249 else
|
yellowfive@89
|
1250 onEquipGearSetComplete()
|
yellowfive@124
|
1251 end
|
yellowfive@57
|
1252 end
|
yellowfive@57
|
1253
|
yellowfive@57
|
1254 local function onActiveTalentGroupChanged()
|
yellowfive@81
|
1255
|
yellowfive@57
|
1256 local auto = Amr.db.profile.options.autoGear
|
yellowfive@81
|
1257 local currentSpec = GetSpecialization()
|
yellowfive@129
|
1258 local waitingSpec = _waitingForSpec
|
yellowfive@129
|
1259 _waitingForSpec = 0
|
yellowfive@57
|
1260
|
yellowfive@139
|
1261 -- when spec changes, change active setup to first one for this spec (does nothing if they have no setups for this spec)
|
yellowfive@139
|
1262 if _activeSetupId then
|
yellowfive@139
|
1263 local currentSetup = getSetupById(_activeSetupId)
|
yellowfive@139
|
1264 if currentSetup.SpecSlot ~= currentSpec then
|
yellowfive@139
|
1265 Amr:PickFirstSetupForSpec()
|
yellowfive@139
|
1266 end
|
yellowfive@139
|
1267 end
|
yellowfive@139
|
1268
|
yellowfive@129
|
1269 if currentSpec == waitingSpec or auto then
|
yellowfive@129
|
1270 -- spec is what we want, now equip the gear but after a short delay because the game auto-swaps artifact weapons
|
yellowfive@129
|
1271 Amr.Wait(2, function()
|
yellowfive@139
|
1272 beginEquipGearSet(_activeSetupId, 0)
|
yellowfive@129
|
1273 end)
|
yellowfive@57
|
1274 end
|
yellowfive@57
|
1275 end
|
yellowfive@57
|
1276
|
yellowfive@81
|
1277 -- activate the specified spec and then equip the saved gear set
|
yellowfive@139
|
1278 function Amr:EquipGearSet(setupIndex)
|
yellowfive@57
|
1279
|
yellowfive@139
|
1280 -- if no argument, then cycle
|
yellowfive@139
|
1281 if not setupIndex then
|
yellowfive@139
|
1282 if not _activeSetupId then
|
yellowfive@139
|
1283 Amr:PickFirstSetupForSpec()
|
yellowfive@139
|
1284 end
|
yellowfive@139
|
1285 for i,setup in ipairs(Amr.db.char.GearSetups) do
|
yellowfive@139
|
1286 if setup.Id == _activeSetupId then
|
yellowfive@139
|
1287 setupIndex = i
|
yellowfive@139
|
1288 break
|
yellowfive@139
|
1289 end
|
yellowfive@139
|
1290 end
|
yellowfive@139
|
1291 if not setupIndex then
|
yellowfive@139
|
1292 setupIndex = 1
|
yellowfive@139
|
1293 else
|
yellowfive@139
|
1294 setupIndex = setupIndex + 1
|
yellowfive@139
|
1295 end
|
yellowfive@57
|
1296 end
|
yellowfive@81
|
1297
|
yellowfive@139
|
1298 setupIndex = tonumber(setupIndex)
|
yellowfive@81
|
1299
|
yellowfive@139
|
1300 if setupIndex > #Amr.db.char.GearSetups then
|
yellowfive@139
|
1301 setupIndex = 1
|
yellowfive@139
|
1302 end
|
yellowfive@139
|
1303
|
yellowfive@57
|
1304 if UnitAffectingCombat("player") then
|
yellowfive@57
|
1305 Amr:Print(L.GearEquipErrorCombat)
|
yellowfive@57
|
1306 return
|
yellowfive@57
|
1307 end
|
yellowfive@57
|
1308
|
yellowfive@139
|
1309 _activeSetupId = Amr.db.char.GearSetups[setupIndex].Id
|
yellowfive@139
|
1310 Amr:RefreshGearDisplay()
|
yellowfive@139
|
1311
|
yellowfive@139
|
1312 local setup = Amr.db.char.GearSetups[setupIndex]
|
yellowfive@81
|
1313 local currentSpec = GetSpecialization()
|
yellowfive@139
|
1314 if currentSpec ~= setup.SpecSlot then
|
yellowfive@139
|
1315 _waitingForSpec = setup.SpecSlot
|
yellowfive@139
|
1316 SetSpecialization(setup.SpecSlot)
|
yellowfive@57
|
1317 else
|
yellowfive@129
|
1318 -- spec is what we want, now equip the gear
|
yellowfive@139
|
1319 beginEquipGearSet(_activeSetupId, 0)
|
yellowfive@57
|
1320 end
|
yellowfive@57
|
1321 end
|
yellowfive@57
|
1322
|
yellowfive@124
|
1323 -- moves any gear in bags to the bank if not part of a gear set
|
yellowfive@57
|
1324 function Amr:CleanBags()
|
yellowfive@57
|
1325 -- TODO: implement
|
yellowfive@57
|
1326 end
|
yellowfive@57
|
1327
|
yellowfive@183
|
1328 --[[
|
yellowfive@81
|
1329 local function testfunc(message)
|
yellowfive@81
|
1330 print(strsub(message, 13))
|
yellowfive@81
|
1331 end
|
yellowfive@183
|
1332 ]]
|
yellowfive@81
|
1333
|
yellowfive@57
|
1334 function Amr:InitializeGear()
|
yellowfive@87
|
1335 Amr:AddEventHandler("ACTIVE_TALENT_GROUP_CHANGED", onActiveTalentGroupChanged)
|
yellowfive@57
|
1336
|
yellowfive@183
|
1337 --Amr:AddEventHandler("CHAT_MSG_CHANNEL", testfunc)
|
yellowfive@81
|
1338
|
yellowfive@57
|
1339 Amr:AddEventHandler("UNIT_INVENTORY_CHANGED", function(unitID)
|
yellowfive@57
|
1340 if unitID and unitID ~= "player" then return end
|
yellowfive@124
|
1341
|
yellowfive@124
|
1342 -- don't update during a gear operation, wait until it is totally finished
|
yellowfive@124
|
1343 if _pendingGearOps then return end
|
yellowfive@124
|
1344
|
yellowfive@139
|
1345 Amr:RefreshGearDisplay()
|
yellowfive@57
|
1346 end)
|
yellowfive@57
|
1347
|
yellowfive@124
|
1348 Amr:AddEventHandler("ITEM_UNLOCKED", handleItemUnlocked)
|
yellowfive@122
|
1349 end
|
yellowfive@161
|
1350
|
yellowfive@161
|
1351
|
yellowfive@161
|
1352 -- export some local methods we need elsewhere
|
yellowfive@161
|
1353 Amr.CountItemDifferences = countItemDifferences
|
yellowfive@161
|
1354 Amr.FindFirstEmptyBagSlot = findFirstEmptyBagSlot
|