annotate Gear.lua @ 200:6e8838b231d4 v97

Fixed issue with distinguishing different variants of the same item.
author Yellowfive
date Wed, 13 Jan 2021 13:11:54 -0600
parents 4ccc9ff6e824
children
rev   line source
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