| 
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@57
 | 
     5 local _gearTabs
 | 
| 
yellowfive@57
 | 
     6 local _activeTab
 | 
| 
yellowfive@57
 | 
     7 
 | 
| 
yellowfive@57
 | 
     8 -- Returns a number indicating how different two items are (0 means the same, higher means more different)
 | 
| 
yellowfive@57
 | 
     9 local function countItemDifferences(item1, item2)
 | 
| 
yellowfive@124
 | 
    10 	-- both nil, the same
 | 
| 
yellowfive@124
 | 
    11 	if not item1 and not item2 then 
 | 
| 
yellowfive@124
 | 
    12 		return 0 
 | 
| 
yellowfive@124
 | 
    13 	end 
 | 
| 
yellowfive@124
 | 
    14 	
 | 
| 
yellowfive@124
 | 
    15 	-- one nil and other not, or different id, totally different
 | 
| 
yellowfive@124
 | 
    16 	if (not item1 and item2) or (item1 and not item2) or item1.id ~= item2.id then 
 | 
| 
yellowfive@124
 | 
    17 		return 10000 
 | 
| 
yellowfive@124
 | 
    18 	end
 | 
| 
yellowfive@124
 | 
    19 	
 | 
| 
yellowfive@124
 | 
    20     -- different versions of same item (id + bonus ids + suffix + drop level, constitutes a different physical drop)
 | 
| 
yellowfive@57
 | 
    21     if Amr.GetItemUniqueId(item1, true) ~= Amr.GetItemUniqueId(item2, true) then
 | 
| 
yellowfive@57
 | 
    22 		return 1000
 | 
| 
yellowfive@57
 | 
    23     end
 | 
| 
yellowfive@57
 | 
    24     
 | 
| 
yellowfive@81
 | 
    25     -- different upgrade levels of the same item
 | 
| 
yellowfive@57
 | 
    26     if item1.upgradeId ~= item2.upgradeId then
 | 
| 
yellowfive@57
 | 
    27         return 100
 | 
| 
yellowfive@124
 | 
    28 	end
 | 
| 
yellowfive@124
 | 
    29 	
 | 
| 
yellowfive@124
 | 
    30 	-- different azerite powers
 | 
| 
yellowfive@124
 | 
    31 	local aztDiffs = 0
 | 
| 
yellowfive@124
 | 
    32 	if item1.azerite or item2.azerite then
 | 
| 
yellowfive@124
 | 
    33 		if item1.azerite and not item2.azerite then
 | 
| 
yellowfive@124
 | 
    34 			aztDiffs = #item1.azerite * 10
 | 
| 
yellowfive@124
 | 
    35 		elseif item2.azerite and not item1.azerite then
 | 
| 
yellowfive@124
 | 
    36 			aztDiffs = #item2.azerite * 10
 | 
| 
yellowfive@124
 | 
    37 		else
 | 
| 
yellowfive@124
 | 
    38 			-- count up number in item1 but missing from item2
 | 
| 
yellowfive@124
 | 
    39 			for i = 1, #item1.azerite do
 | 
| 
yellowfive@124
 | 
    40 				local missing = false
 | 
| 
yellowfive@124
 | 
    41 				for j = 1, #item2.azerite do
 | 
| 
yellowfive@124
 | 
    42 					if item2[j] == item1[i] then
 | 
| 
yellowfive@124
 | 
    43 						missing = false
 | 
| 
yellowfive@124
 | 
    44 					end
 | 
| 
yellowfive@124
 | 
    45 				end
 | 
| 
yellowfive@124
 | 
    46 				if missing then
 | 
| 
yellowfive@124
 | 
    47 					aztDiffs = aztDiffs + 10
 | 
| 
yellowfive@124
 | 
    48 				end
 | 
| 
yellowfive@124
 | 
    49 			end
 | 
| 
yellowfive@124
 | 
    50 			-- count up number in item2 but missing from item1
 | 
| 
yellowfive@124
 | 
    51 			for i = 1, #item2.azerite do
 | 
| 
yellowfive@124
 | 
    52 				local missing = false
 | 
| 
yellowfive@124
 | 
    53 				for j = 1, #item1.azerite do
 | 
| 
yellowfive@124
 | 
    54 					if item1[j] == item2[i] then
 | 
| 
yellowfive@124
 | 
    55 						missing = false
 | 
| 
yellowfive@124
 | 
    56 					end
 | 
| 
yellowfive@124
 | 
    57 				end
 | 
| 
yellowfive@124
 | 
    58 				if missing then
 | 
| 
yellowfive@124
 | 
    59 					aztDiffs = aztDiffs + 10
 | 
| 
yellowfive@124
 | 
    60 				end
 | 
| 
yellowfive@124
 | 
    61 			end
 | 
| 
yellowfive@124
 | 
    62 		end
 | 
| 
yellowfive@124
 | 
    63 	end
 | 
| 
yellowfive@57
 | 
    64     
 | 
| 
yellowfive@57
 | 
    65     -- different gems
 | 
| 
yellowfive@57
 | 
    66     local gemDiffs = 0
 | 
| 
yellowfive@57
 | 
    67     for i = 1, 3 do
 | 
| 
yellowfive@57
 | 
    68         if item1.gemIds[i] ~= item2.gemIds[i] then
 | 
| 
yellowfive@57
 | 
    69             gemDiffs = gemDiffs + 1
 | 
| 
yellowfive@57
 | 
    70         end
 | 
| 
yellowfive@57
 | 
    71     end
 | 
| 
yellowfive@57
 | 
    72     
 | 
| 
yellowfive@57
 | 
    73 	-- different enchants
 | 
| 
yellowfive@57
 | 
    74     local enchantDiff = 0
 | 
| 
yellowfive@57
 | 
    75     if item1.enchantId ~= item2.enchantId then
 | 
| 
yellowfive@57
 | 
    76         enchantDiff = 1
 | 
| 
yellowfive@57
 | 
    77     end
 | 
| 
yellowfive@57
 | 
    78     
 | 
| 
yellowfive@124
 | 
    79     return aztDiffs + gemDiffs + enchantDiff
 | 
| 
yellowfive@57
 | 
    80 end
 | 
| 
yellowfive@57
 | 
    81 
 | 
| 
yellowfive@57
 | 
    82 -- 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
 | 
    83 local function findMatchingItemFromTable(item, list, bestItem, bestDiff, bestLoc, usedItems, tableType)
 | 
| 
yellowfive@57
 | 
    84 	if not list then return nil end
 | 
| 
yellowfive@57
 | 
    85 	
 | 
| 
yellowfive@73
 | 
    86 	local found = false
 | 
| 
yellowfive@124
 | 
    87 	for k,listItem in pairs(list) do
 | 
| 
yellowfive@57
 | 
    88 		if listItem then
 | 
| 
yellowfive@57
 | 
    89 			local diff = countItemDifferences(item, listItem)
 | 
| 
yellowfive@57
 | 
    90 			if diff < bestDiff then
 | 
| 
yellowfive@57
 | 
    91 				-- each physical item can only be used once, the usedItems table has items we can't use in this search
 | 
| 
yellowfive@57
 | 
    92 				local key = string.format("%s_%s", tableType, k)
 | 
| 
yellowfive@57
 | 
    93 				if not usedItems[key] then
 | 
| 
yellowfive@57
 | 
    94 					bestItem = listItem
 | 
| 
yellowfive@57
 | 
    95 					bestDiff = diff
 | 
| 
yellowfive@124
 | 
    96 					bestLoc = key
 | 
| 
yellowfive@73
 | 
    97 					found = true
 | 
| 
yellowfive@57
 | 
    98 				end
 | 
| 
yellowfive@57
 | 
    99 			end
 | 
| 
yellowfive@73
 | 
   100 			if found then break end
 | 
| 
yellowfive@57
 | 
   101 		end
 | 
| 
yellowfive@57
 | 
   102 	end
 | 
| 
yellowfive@57
 | 
   103 	
 | 
| 
yellowfive@124
 | 
   104 	return bestItem, bestDiff, bestLoc
 | 
| 
yellowfive@57
 | 
   105 end
 | 
| 
yellowfive@57
 | 
   106 
 | 
| 
yellowfive@124
 | 
   107 -- search the player's equipped gear, bag, and bank for an item that best matches the specified item
 | 
| 
yellowfive@57
 | 
   108 function Amr:FindMatchingItem(item, player, usedItems)
 | 
| 
yellowfive@57
 | 
   109 	if not item then return nil end
 | 
| 
yellowfive@57
 | 
   110 
 | 
| 
yellowfive@57
 | 
   111 	local equipped = player.Equipped and player.Equipped[player.ActiveSpec] or nil
 | 
| 
yellowfive@124
 | 
   112 	local bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, equipped, nil, 10000, nil, usedItems, "equip")
 | 
| 
yellowfive@124
 | 
   113 	bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, player.BagItems, bestItem, bestDiff, bestLoc, usedItems, "bag")
 | 
| 
yellowfive@124
 | 
   114 	if player.BankItems then
 | 
| 
yellowfive@124
 | 
   115 		for bagId,bagList in pairs(player.BankItems) do
 | 
| 
yellowfive@124
 | 
   116 			bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, bagList, bestItem, bestDiff, bestLoc, usedItems, "bank" .. bagId)
 | 
| 
yellowfive@124
 | 
   117 		end
 | 
| 
yellowfive@124
 | 
   118 	end	
 | 
| 
yellowfive@57
 | 
   119 
 | 
| 
yellowfive@124
 | 
   120 	if bestDiff >= 10000 then
 | 
| 
yellowfive@124
 | 
   121 		return nil, 10000
 | 
| 
yellowfive@57
 | 
   122 	else
 | 
| 
yellowfive@57
 | 
   123 		usedItems[bestLoc] = true
 | 
| 
yellowfive@124
 | 
   124 		return bestItem, bestDiff
 | 
| 
yellowfive@57
 | 
   125 	end
 | 
| 
yellowfive@57
 | 
   126 end
 | 
| 
yellowfive@57
 | 
   127 
 | 
| 
yellowfive@57
 | 
   128 local function renderEmptyGear(container)
 | 
| 
yellowfive@57
 | 
   129 
 | 
| 
yellowfive@57
 | 
   130 	local panelBlank = AceGUI:Create("AmrUiPanel")
 | 
| 
yellowfive@57
 | 
   131 	panelBlank:SetLayout("None")
 | 
| 
yellowfive@57
 | 
   132 	panelBlank:SetBackgroundColor(Amr.Colors.Black, 0.4)
 | 
| 
yellowfive@124
 | 
   133 	container:AddChild(panelBlank)
 | 
| 
yellowfive@57
 | 
   134 	panelBlank:SetPoint("TOPLEFT", container.content, "TOPLEFT", 6, 0)
 | 
| 
yellowfive@57
 | 
   135 	panelBlank:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT")
 | 
| 
yellowfive@57
 | 
   136 	
 | 
| 
yellowfive@57
 | 
   137 	local lbl = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   138 	panelBlank:AddChild(lbl)
 | 
| 
yellowfive@57
 | 
   139 	lbl:SetText(L.GearBlank)
 | 
| 
yellowfive@57
 | 
   140 	lbl:SetWidth(700)
 | 
| 
yellowfive@57
 | 
   141 	lbl:SetJustifyH("MIDDLE")
 | 
| 
yellowfive@57
 | 
   142 	lbl:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan))		
 | 
| 
yellowfive@57
 | 
   143 	lbl:SetPoint("BOTTOM", panelBlank.content, "CENTER", 0, 20)
 | 
| 
yellowfive@57
 | 
   144 	
 | 
| 
yellowfive@57
 | 
   145 	local lbl2 = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   146 	panelBlank:AddChild(lbl2)
 | 
| 
yellowfive@57
 | 
   147 	lbl2:SetText(L.GearBlank2)
 | 
| 
yellowfive@57
 | 
   148 	lbl2:SetWidth(700)
 | 
| 
yellowfive@57
 | 
   149 	lbl2:SetJustifyH("MIDDLE")
 | 
| 
yellowfive@57
 | 
   150 	lbl2:SetFont(Amr.CreateFont("Italic", 16, Amr.Colors.TextTan))		
 | 
| 
yellowfive@57
 | 
   151 	lbl2:SetPoint("TOP", lbl.frame, "CENTER", 0, -20)
 | 
| 
yellowfive@124
 | 
   152 end
 | 
| 
yellowfive@124
 | 
   153 
 | 
| 
yellowfive@124
 | 
   154 -- helper to create a widget for showing a socket or azerite power
 | 
| 
yellowfive@124
 | 
   155 local function createSocketWidget(panelMods, prevWidget, prevIsSocket, isEquipped)
 | 
| 
yellowfive@124
 | 
   156 
 | 
| 
yellowfive@124
 | 
   157 	-- highlight for socket that doesn't match
 | 
| 
yellowfive@124
 | 
   158 	local socketBorder = AceGUI:Create("AmrUiPanel")
 | 
| 
yellowfive@124
 | 
   159 	panelMods:AddChild(socketBorder)
 | 
| 
yellowfive@124
 | 
   160 	if not prevIsSocket then
 | 
| 
yellowfive@124
 | 
   161 		socketBorder:SetPoint("LEFT", prevWidget.frame, "RIGHT", 30, 0)
 | 
| 
yellowfive@124
 | 
   162 	else
 | 
| 
yellowfive@124
 | 
   163 		socketBorder:SetPoint("LEFT", prevWidget.frame, "RIGHT", 2, 0)
 | 
| 
yellowfive@124
 | 
   164 	end
 | 
| 
yellowfive@124
 | 
   165 	socketBorder:SetLayout("None")
 | 
| 
yellowfive@124
 | 
   166 	socketBorder:SetBackgroundColor(Amr.Colors.Black, isEquipped and 0 or 1)
 | 
| 
yellowfive@124
 | 
   167 	socketBorder:SetWidth(26)
 | 
| 
yellowfive@124
 | 
   168 	socketBorder:SetHeight(26)
 | 
| 
yellowfive@124
 | 
   169 	if isEquipped then
 | 
| 
yellowfive@124
 | 
   170 		socketBorder:SetAlpha(0.3)
 | 
| 
yellowfive@124
 | 
   171 	end					
 | 
| 
yellowfive@124
 | 
   172 
 | 
| 
yellowfive@124
 | 
   173 	local socketBg = AceGUI:Create("AmrUiIcon")
 | 
| 
yellowfive@124
 | 
   174 	socketBorder:AddChild(socketBg)
 | 
| 
yellowfive@124
 | 
   175 	socketBg:SetPoint("TOPLEFT", socketBorder.content, "TOPLEFT", 1, -1)
 | 
| 
yellowfive@124
 | 
   176 	socketBg:SetLayout("None")
 | 
| 
yellowfive@124
 | 
   177 	socketBg:SetBorderWidth(2)
 | 
| 
yellowfive@124
 | 
   178 	socketBg:SetIconBorderColor(Amr.Colors.Green, isEquipped and 0 or 1)
 | 
| 
yellowfive@124
 | 
   179 	socketBg:SetWidth(24)
 | 
| 
yellowfive@124
 | 
   180 	socketBg:SetHeight(24)
 | 
| 
yellowfive@124
 | 
   181 
 | 
| 
yellowfive@124
 | 
   182 	local socketIcon = AceGUI:Create("AmrUiIcon")
 | 
| 
yellowfive@124
 | 
   183 	socketBg:AddChild(socketIcon)
 | 
| 
yellowfive@124
 | 
   184 	socketIcon:SetPoint("CENTER", socketBg.content, "CENTER")
 | 
| 
yellowfive@124
 | 
   185 	socketIcon:SetBorderWidth(1)
 | 
| 
yellowfive@124
 | 
   186 	socketIcon:SetIconBorderColor(Amr.Colors.White)
 | 
| 
yellowfive@124
 | 
   187 	socketIcon:SetWidth(18)
 | 
| 
yellowfive@124
 | 
   188 	socketIcon:SetHeight(18)
 | 
| 
yellowfive@124
 | 
   189 	
 | 
| 
yellowfive@124
 | 
   190 	return socketBorder, socketIcon
 | 
| 
yellowfive@57
 | 
   191 end
 | 
| 
yellowfive@57
 | 
   192 
 | 
| 
yellowfive@57
 | 
   193 local function renderGear(spec, container)
 | 
| 
yellowfive@57
 | 
   194 
 | 
| 
yellowfive@57
 | 
   195 	local player = Amr:ExportCharacter()
 | 
| 
yellowfive@57
 | 
   196 	local gear = Amr.db.char.GearSets[spec]
 | 
| 
yellowfive@57
 | 
   197 	local equipped = player.Equipped[player.ActiveSpec]
 | 
| 
yellowfive@57
 | 
   198 		
 | 
| 
yellowfive@57
 | 
   199 	if not gear then
 | 
| 
yellowfive@57
 | 
   200 		-- no gear has been imported for this spec so show a message
 | 
| 
yellowfive@57
 | 
   201 		renderEmptyGear(container)
 | 
| 
yellowfive@57
 | 
   202 	else
 | 
| 
yellowfive@57
 | 
   203 		local panelGear = AceGUI:Create("AmrUiPanel")
 | 
| 
yellowfive@57
 | 
   204 		panelGear:SetLayout("None")
 | 
| 
yellowfive@57
 | 
   205 		panelGear:SetBackgroundColor(Amr.Colors.Black, 0.3)
 | 
| 
yellowfive@124
 | 
   206 		container:AddChild(panelGear)
 | 
| 
yellowfive@57
 | 
   207 		panelGear:SetPoint("TOPLEFT", container.content, "TOPLEFT", 6, 0)
 | 
| 
yellowfive@57
 | 
   208 		panelGear:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT", -300, 0)
 | 
| 
yellowfive@57
 | 
   209 		
 | 
| 
yellowfive@57
 | 
   210 		local panelMods = AceGUI:Create("AmrUiPanel")
 | 
| 
yellowfive@57
 | 
   211 		panelMods:SetLayout("None")
 | 
| 
yellowfive@124
 | 
   212 		panelMods:SetBackgroundColor(Amr.Colors.Black, 0.3)
 | 
| 
yellowfive@124
 | 
   213 		container:AddChild(panelMods)
 | 
| 
yellowfive@57
 | 
   214 		panelMods:SetPoint("TOPLEFT", panelGear.frame, "TOPRIGHT", 15, 0)
 | 
| 
yellowfive@57
 | 
   215 		panelMods:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT")
 | 
| 
yellowfive@57
 | 
   216 		
 | 
| 
yellowfive@57
 | 
   217 		-- spec icon
 | 
| 
yellowfive@57
 | 
   218 		local icon = AceGUI:Create("AmrUiIcon")	
 | 
| 
yellowfive@57
 | 
   219 		icon:SetIconBorderColor(Amr.Colors.Classes[player.Class])
 | 
| 
yellowfive@57
 | 
   220 		icon:SetWidth(48)
 | 
| 
yellowfive@57
 | 
   221 		icon:SetHeight(48)
 | 
| 
yellowfive@57
 | 
   222 		
 | 
| 
yellowfive@57
 | 
   223 		local iconSpec
 | 
| 
yellowfive@81
 | 
   224 		if player.SubSpecs and player.SubSpecs[spec] then
 | 
| 
yellowfive@57
 | 
   225 			iconSpec = player.SubSpecs[spec]
 | 
| 
yellowfive@57
 | 
   226 		else
 | 
| 
yellowfive@57
 | 
   227 			iconSpec = player.Specs[spec]
 | 
| 
yellowfive@57
 | 
   228 		end
 | 
| 
yellowfive@57
 | 
   229 
 | 
| 
yellowfive@57
 | 
   230 		icon:SetIcon("Interface\\Icons\\" .. Amr.SpecIcons[iconSpec])
 | 
| 
yellowfive@124
 | 
   231 		panelGear:AddChild(icon)
 | 
| 
yellowfive@57
 | 
   232 		icon:SetPoint("TOPLEFT", panelGear.content, "TOPLEFT", 10, -10)
 | 
| 
yellowfive@57
 | 
   233 		
 | 
| 
yellowfive@57
 | 
   234 		local btnEquip = AceGUI:Create("AmrUiButton")
 | 
| 
yellowfive@81
 | 
   235 		btnEquip:SetText(L.GearButtonEquip(L.SpecsShort[player.Specs[spec]]))
 | 
| 
yellowfive@57
 | 
   236 		btnEquip:SetBackgroundColor(Amr.Colors.Green)
 | 
| 
yellowfive@57
 | 
   237 		btnEquip:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
 | 
| 
yellowfive@57
 | 
   238 		btnEquip:SetWidth(300)
 | 
| 
yellowfive@57
 | 
   239 		btnEquip:SetHeight(26)
 | 
| 
yellowfive@57
 | 
   240 		btnEquip:SetCallback("OnClick", function(widget)
 | 
| 
yellowfive@57
 | 
   241 			Amr:EquipGearSet(spec)			
 | 
| 
yellowfive@57
 | 
   242 		end)
 | 
| 
yellowfive@57
 | 
   243 		panelGear:AddChild(btnEquip)
 | 
| 
yellowfive@124
 | 
   244 		btnEquip:SetPoint("LEFT", icon.frame, "RIGHT", 40, 0)
 | 
| 
yellowfive@124
 | 
   245 		btnEquip:SetPoint("RIGHT", panelGear.content, "RIGHT", -40, 0)
 | 
| 
yellowfive@57
 | 
   246 		
 | 
| 
yellowfive@57
 | 
   247 		-- each physical item can only be used once, this tracks ones we have already used
 | 
| 
yellowfive@57
 | 
   248 		local usedItems = {}
 | 
| 
yellowfive@57
 | 
   249 		
 | 
| 
yellowfive@57
 | 
   250 		-- gear list
 | 
| 
yellowfive@57
 | 
   251 		local prevElem = icon
 | 
| 
yellowfive@57
 | 
   252 		for slotNum = 1, #Amr.SlotIds do
 | 
| 
yellowfive@57
 | 
   253 			local slotId = Amr.SlotIds[slotNum]
 | 
| 
yellowfive@57
 | 
   254 			
 | 
| 
yellowfive@124
 | 
   255 			local equippedItem = equipped and equipped[slotId] or nil
 | 
| 
yellowfive@124
 | 
   256 			local equippedItemLink = equipped and equipped.link or nil
 | 
| 
yellowfive@57
 | 
   257 			local optimalItem = gear[slotId]			
 | 
| 
yellowfive@57
 | 
   258 			local optimalItemLink = Amr.CreateItemLink(optimalItem)
 | 
| 
yellowfive@57
 | 
   259 			
 | 
| 
yellowfive@57
 | 
   260 			-- 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
 | 
   261 			local isEquipped = false			
 | 
| 
yellowfive@57
 | 
   262 			if equippedItem and optimalItem and Amr.GetItemUniqueId(equippedItem) == Amr.GetItemUniqueId(optimalItem) then
 | 
| 
yellowfive@57
 | 
   263 				isEquipped = true
 | 
| 
yellowfive@57
 | 
   264 			end
 | 
| 
yellowfive@124
 | 
   265 
 | 
| 
yellowfive@124
 | 
   266 			local isAzerite = optimalItem and C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItemByID(optimalItem.id)
 | 
| 
yellowfive@57
 | 
   267 			
 | 
| 
yellowfive@57
 | 
   268 			-- find the item in the player's inventory that best matches what the optimization wants to use
 | 
| 
yellowfive@124
 | 
   269 			local matchItem = Amr:FindMatchingItem(optimalItem, player, usedItems)
 | 
| 
yellowfive@57
 | 
   270 			
 | 
| 
yellowfive@57
 | 
   271 			-- slot label
 | 
| 
yellowfive@57
 | 
   272 			local lbl = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   273 			panelGear:AddChild(lbl)
 | 
| 
yellowfive@124
 | 
   274 			lbl:SetPoint("TOPLEFT", prevElem.frame, "BOTTOMLEFT", 0, -12) 
 | 
| 
yellowfive@57
 | 
   275 			lbl:SetText(Amr.SlotDisplayText[slotId])
 | 
| 
yellowfive@57
 | 
   276 			lbl:SetWidth(85)
 | 
| 
yellowfive@57
 | 
   277 			lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))		
 | 
| 
yellowfive@57
 | 
   278 			prevElem = lbl
 | 
| 
yellowfive@57
 | 
   279 			
 | 
| 
yellowfive@57
 | 
   280 			-- ilvl label
 | 
| 
yellowfive@57
 | 
   281 			local lblIlvl = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   282 			panelGear:AddChild(lblIlvl)
 | 
| 
yellowfive@124
 | 
   283 			lblIlvl:SetPoint("TOPLEFT", lbl.frame, "TOPRIGHT", 0, 0) 
 | 
| 
yellowfive@57
 | 
   284 			lblIlvl:SetWidth(45)
 | 
| 
yellowfive@57
 | 
   285 			lblIlvl:SetFont(Amr.CreateFont("Italic", 14, Amr.Colors.TextTan))		
 | 
| 
yellowfive@57
 | 
   286 			
 | 
| 
yellowfive@57
 | 
   287 			-- equipped label
 | 
| 
yellowfive@57
 | 
   288 			local lblEquipped = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   289 			panelGear:AddChild(lblEquipped)
 | 
| 
yellowfive@124
 | 
   290 			lblEquipped:SetPoint("TOPLEFT", lblIlvl.frame, "TOPRIGHT", 0, 0) 
 | 
| 
yellowfive@57
 | 
   291 			lblEquipped:SetWidth(20)
 | 
| 
yellowfive@57
 | 
   292 			lblEquipped:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
 | 
| 
yellowfive@57
 | 
   293 			lblEquipped:SetText(isEquipped and "E" or "")
 | 
| 
yellowfive@57
 | 
   294 			
 | 
| 
yellowfive@57
 | 
   295 			-- item name/link label
 | 
| 
yellowfive@57
 | 
   296 			local lblItem = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   297 			panelGear:AddChild(lblItem)
 | 
| 
yellowfive@124
 | 
   298 			lblItem:SetPoint("TOPLEFT", lblEquipped.frame, "TOPRIGHT", 0, 0) 
 | 
| 
yellowfive@57
 | 
   299 			lblItem:SetWordWrap(false)
 | 
| 
yellowfive@57
 | 
   300 			lblItem:SetWidth(345)
 | 
| 
yellowfive@57
 | 
   301 			lblItem:SetFont(Amr.CreateFont(isEquipped and "Regular" or "Bold", isEquipped and 14 or 15, Amr.Colors.White))		
 | 
| 
yellowfive@57
 | 
   302 			
 | 
| 
yellowfive@57
 | 
   303 			-- fill the name/ilvl labels, which may require asynchronous loading of item information
 | 
| 
yellowfive@57
 | 
   304 			if optimalItemLink then
 | 
| 
yellowfive@57
 | 
   305 				Amr.GetItemInfo(optimalItemLink, function(obj, name, link, quality, iLevel)					
 | 
| 
yellowfive@57
 | 
   306 					-- set item name, tooltip, and ilvl
 | 
| 
yellowfive@57
 | 
   307 					obj.nameLabel:SetText(link:gsub("%[", ""):gsub("%]", ""))
 | 
| 
yellowfive@100
 | 
   308 					
 | 
| 
yellowfive@100
 | 
   309 					if quality == 6 then
 | 
| 
yellowfive@124
 | 
   310 						-- not quite right but whatever... close enough, artifacts are a thing of the past
 | 
| 
yellowfive@124
 | 
   311 						local tmprel = obj.optimalItem.relicBonusIds
 | 
| 
yellowfive@124
 | 
   312 						obj.optimalItem.relicBonusIds = nil
 | 
| 
yellowfive@124
 | 
   313 						link = Amr.CreateItemLink(obj.optimalItem)
 | 
| 
yellowfive@124
 | 
   314 						obj.optimalItem.relicBonusIds = tmprel
 | 
| 
yellowfive@124
 | 
   315 
 | 
| 
yellowfive@124
 | 
   316 						-- for artifacts, we consider it equipped if the item id alone matches
 | 
| 
yellowfive@124
 | 
   317 						if obj.equippedItem and obj.equippedItem.id == obj.optimalItem.id then
 | 
| 
yellowfive@124
 | 
   318 							obj.isEquipped = true
 | 
| 
yellowfive@124
 | 
   319 						end
 | 
| 
yellowfive@124
 | 
   320 						obj.equipLabel:SetText(obj.isEquipped and "E" or "")
 | 
| 
yellowfive@100
 | 
   321 					end
 | 
| 
yellowfive@100
 | 
   322 					
 | 
| 
yellowfive@124
 | 
   323 					Amr:SetItemTooltip(obj.nameLabel, link, "ANCHOR_TOPRIGHT")
 | 
| 
yellowfive@89
 | 
   324 					
 | 
| 
yellowfive@124
 | 
   325 					local itemObj = Item:CreateFromItemLink(link)
 | 
| 
yellowfive@124
 | 
   326 					if itemObj then
 | 
| 
yellowfive@124
 | 
   327 						-- game's GetItemInfo method returns the wrong ilvl sometimes, so use the new item api to get it
 | 
| 
yellowfive@124
 | 
   328 						iLevel = itemObj:GetCurrentItemLevel()
 | 
| 
yellowfive@124
 | 
   329 					end
 | 
| 
yellowfive@124
 | 
   330 					obj.ilvlLabel:SetText(iLevel)					
 | 
| 
yellowfive@124
 | 
   331 
 | 
| 
yellowfive@124
 | 
   332 				end, { 
 | 
| 
yellowfive@124
 | 
   333 					ilvlLabel = lblIlvl, 
 | 
| 
yellowfive@124
 | 
   334 					nameLabel = lblItem, 
 | 
| 
yellowfive@124
 | 
   335 					equipLabel = lblEquipped,
 | 
| 
yellowfive@124
 | 
   336 					optimalItem = optimalItem,
 | 
| 
yellowfive@124
 | 
   337 					equippedItem = equippedItem,
 | 
| 
yellowfive@124
 | 
   338 					isEquipped = isEquipped
 | 
| 
yellowfive@124
 | 
   339 				})
 | 
| 
yellowfive@57
 | 
   340 			end
 | 
| 
yellowfive@57
 | 
   341 						
 | 
| 
yellowfive@57
 | 
   342 			-- modifications
 | 
| 
yellowfive@57
 | 
   343 			if optimalItem then
 | 
| 
yellowfive@57
 | 
   344 
 | 
| 
yellowfive@124
 | 
   345 				-- gems or azerite powers
 | 
| 
yellowfive@124
 | 
   346 				local prevSocket = nil
 | 
| 
yellowfive@124
 | 
   347 
 | 
| 
yellowfive@124
 | 
   348 				if isAzerite then
 | 
| 
yellowfive@124
 | 
   349 					local azt = optimalItem.azerite or {}
 | 
| 
yellowfive@124
 | 
   350 					for i,spellId in ipairs(azt) do
 | 
| 
yellowfive@124
 | 
   351 						if spellId and spellId ~= 0 then
 | 
| 
yellowfive@124
 | 
   352 							local equippedAzt = equippedItem and equippedItem.azerite or {}
 | 
| 
yellowfive@124
 | 
   353 							local isPowerActive = Amr.Contains(equippedAzt, spellId)
 | 
| 
yellowfive@124
 | 
   354 
 | 
| 
yellowfive@124
 | 
   355 							local socketBorder, socketIcon = createSocketWidget(panelMods, prevSocket or lblItem, prevSocket, isPowerActive)
 | 
| 
yellowfive@124
 | 
   356 							
 | 
| 
yellowfive@124
 | 
   357 							-- set icon and tooltip
 | 
| 
yellowfive@124
 | 
   358 							local spellName, _, spellIcon = GetSpellInfo(spellId)
 | 
| 
yellowfive@124
 | 
   359 							socketIcon:SetIcon(spellIcon)
 | 
| 
yellowfive@124
 | 
   360 							Amr:SetSpellTooltip(socketIcon, spellId, "ANCHOR_TOPRIGHT")
 | 
| 
yellowfive@124
 | 
   361 							
 | 
| 
yellowfive@124
 | 
   362 							prevSocket = socketBorder
 | 
| 
yellowfive@124
 | 
   363 						end
 | 
| 
yellowfive@124
 | 
   364 					end
 | 
| 
yellowfive@124
 | 
   365 				else
 | 
| 
yellowfive@124
 | 
   366 					for i = 1, #optimalItem.gemIds do
 | 
| 
yellowfive@124
 | 
   367 						-- we rely on the fact that the gear sets coming back from the site will almost always have all sockets filled,
 | 
| 
yellowfive@124
 | 
   368 						-- because it's a pain to get the actual number of sockets on an item from within the game
 | 
| 
yellowfive@57
 | 
   369 						local g = optimalItem.gemIds[i]
 | 
| 
yellowfive@124
 | 
   370 						if g == 0 then break end
 | 
| 
yellowfive@124
 | 
   371 
 | 
| 
yellowfive@124
 | 
   372 						local isGemEquipped = matchItem and matchItem.gemIds and matchItem.gemIds[i] == g
 | 
| 
yellowfive@57
 | 
   373 						
 | 
| 
yellowfive@124
 | 
   374 						local socketBorder, socketIcon = createSocketWidget(panelMods, prevSocket or lblItem, prevSocket, isGemEquipped)
 | 
| 
yellowfive@57
 | 
   375 						
 | 
| 
yellowfive@57
 | 
   376 						-- get icon for optimized gem
 | 
| 
yellowfive@124
 | 
   377 						Amr.GetItemInfo(g, function(obj, name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture)					
 | 
| 
yellowfive@124
 | 
   378 							-- set icon and a tooltip
 | 
| 
yellowfive@124
 | 
   379 							obj:SetIcon(texture)
 | 
| 
yellowfive@124
 | 
   380 							Amr:SetItemTooltip(obj, link, "ANCHOR_TOPRIGHT")
 | 
| 
yellowfive@124
 | 
   381 						end, socketIcon)
 | 
| 
yellowfive@89
 | 
   382 						
 | 
| 
yellowfive@89
 | 
   383 						prevSocket = socketBorder
 | 
| 
yellowfive@57
 | 
   384 					end
 | 
| 
yellowfive@57
 | 
   385 				end
 | 
| 
yellowfive@124
 | 
   386 
 | 
| 
yellowfive@57
 | 
   387 				-- enchant
 | 
| 
yellowfive@57
 | 
   388 				if optimalItem.enchantId and optimalItem.enchantId ~= 0 then
 | 
| 
yellowfive@57
 | 
   389 					local isEnchantEquipped = matchItem and matchItem.enchantId and matchItem.enchantId == optimalItem.enchantId
 | 
| 
yellowfive@57
 | 
   390 					
 | 
| 
yellowfive@57
 | 
   391 					local lblEnchant = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   392 					panelMods:AddChild(lblEnchant)
 | 
| 
yellowfive@124
 | 
   393 					lblEnchant:SetPoint("TOPLEFT", lblItem.frame, "TOPRIGHT", 130, 0)
 | 
| 
yellowfive@57
 | 
   394 					lblEnchant:SetWordWrap(false)
 | 
| 
yellowfive@57
 | 
   395 					lblEnchant:SetWidth(170)
 | 
| 
yellowfive@57
 | 
   396 					lblEnchant:SetFont(Amr.CreateFont(isEnchantEquipped and "Regular" or "Bold", 14, isEnchantEquipped and Amr.Colors.TextGray or Amr.Colors.White))
 | 
| 
yellowfive@57
 | 
   397 					
 | 
| 
yellowfive@124
 | 
   398 					local enchInfo = Amr.db.char.ExtraEnchantData[optimalItem.enchantId]
 | 
| 
yellowfive@57
 | 
   399 					if enchInfo then
 | 
| 
yellowfive@57
 | 
   400 						lblEnchant:SetText(enchInfo.text)
 | 
| 
yellowfive@57
 | 
   401 						
 | 
| 
yellowfive@57
 | 
   402 						Amr.GetItemInfo(enchInfo.itemId, function(obj, name, link)					
 | 
| 
yellowfive@124
 | 
   403 							Amr:SetItemTooltip(obj, link, "ANCHOR_TOPRIGHT")
 | 
| 
yellowfive@57
 | 
   404 						end, lblEnchant)						
 | 
| 
yellowfive@57
 | 
   405 						--Amr:SetSpellTooltip(lblEnchant, enchInfo.spellId)
 | 
| 
yellowfive@57
 | 
   406 					end
 | 
| 
yellowfive@124
 | 
   407 					
 | 
| 
yellowfive@57
 | 
   408 				end
 | 
| 
yellowfive@57
 | 
   409 			end
 | 
| 
yellowfive@57
 | 
   410 			
 | 
| 
yellowfive@57
 | 
   411 			prevElem = lbl
 | 
| 
yellowfive@57
 | 
   412 		end
 | 
| 
yellowfive@57
 | 
   413 	end
 | 
| 
yellowfive@57
 | 
   414 end
 | 
| 
yellowfive@57
 | 
   415 
 | 
| 
yellowfive@57
 | 
   416 local function onGearTabSelected(container, event, group)
 | 
| 
yellowfive@57
 | 
   417 	container:ReleaseChildren()
 | 
| 
yellowfive@57
 | 
   418 	_activeTab = group
 | 
| 
yellowfive@57
 | 
   419 	renderGear(tonumber(group), container)
 | 
| 
yellowfive@57
 | 
   420 end
 | 
| 
yellowfive@57
 | 
   421 
 | 
| 
yellowfive@57
 | 
   422 local function onImportClick(widget)
 | 
| 
yellowfive@57
 | 
   423 	Amr:ShowImportWindow()
 | 
| 
yellowfive@57
 | 
   424 end
 | 
| 
yellowfive@57
 | 
   425 
 | 
| 
yellowfive@57
 | 
   426 -- renders the main UI for the Gear tab
 | 
| 
yellowfive@57
 | 
   427 function Amr:RenderTabGear(container)
 | 
| 
yellowfive@57
 | 
   428 
 | 
| 
yellowfive@57
 | 
   429 	local btnImport = AceGUI:Create("AmrUiButton")
 | 
| 
yellowfive@57
 | 
   430 	btnImport:SetText(L.GearButtonImportText)
 | 
| 
yellowfive@57
 | 
   431 	btnImport:SetBackgroundColor(Amr.Colors.Orange)
 | 
| 
yellowfive@57
 | 
   432 	btnImport:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White))
 | 
| 
yellowfive@57
 | 
   433 	btnImport:SetWidth(120)
 | 
| 
yellowfive@57
 | 
   434 	btnImport:SetHeight(26)
 | 
| 
yellowfive@57
 | 
   435 	btnImport:SetCallback("OnClick", onImportClick)
 | 
| 
yellowfive@57
 | 
   436 	container:AddChild(btnImport)	
 | 
| 
yellowfive@124
 | 
   437 	btnImport:SetPoint("TOPLEFT", container.content, "TOPLEFT", 0, -81)
 | 
| 
yellowfive@57
 | 
   438 	
 | 
| 
yellowfive@57
 | 
   439 	local lbl = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   440 	container:AddChild(lbl)
 | 
| 
yellowfive@57
 | 
   441 	lbl:SetText(L.GearImportNote)
 | 
| 
yellowfive@57
 | 
   442 	lbl:SetWidth(100)
 | 
| 
yellowfive@57
 | 
   443 	lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.TextTan))
 | 
| 
yellowfive@57
 | 
   444 	lbl:SetJustifyH("MIDDLE")
 | 
| 
yellowfive@57
 | 
   445 	lbl:SetPoint("TOP", btnImport.frame, "BOTTOM", 0, -5)
 | 
| 
yellowfive@57
 | 
   446 	
 | 
| 
yellowfive@57
 | 
   447 	local lbl2 = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   448 	container:AddChild(lbl2)
 | 
| 
yellowfive@57
 | 
   449 	lbl2:SetText(L.GearTipTitle)
 | 
| 
yellowfive@57
 | 
   450 	lbl2:SetWidth(140)
 | 
| 
yellowfive@57
 | 
   451 	lbl2:SetFont(Amr.CreateFont("Italic", 20, Amr.Colors.Text))
 | 
| 
yellowfive@57
 | 
   452 	lbl2:SetJustifyH("MIDDLE")
 | 
| 
yellowfive@57
 | 
   453 	lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -50)
 | 
| 
yellowfive@57
 | 
   454 	
 | 
| 
yellowfive@57
 | 
   455 	lbl = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   456 	container:AddChild(lbl)
 | 
| 
yellowfive@57
 | 
   457 	lbl:SetText(L.GearTipText)
 | 
| 
yellowfive@57
 | 
   458 	lbl:SetWidth(140)
 | 
| 
yellowfive@57
 | 
   459 	lbl:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.Text))
 | 
| 
yellowfive@57
 | 
   460 	lbl:SetJustifyH("MIDDLE")
 | 
| 
yellowfive@57
 | 
   461 	lbl:SetPoint("TOP", lbl2.frame, "BOTTOM", 0, -5)
 | 
| 
yellowfive@57
 | 
   462 	
 | 
| 
yellowfive@57
 | 
   463 	lbl2 = AceGUI:Create("AmrUiLabel")
 | 
| 
yellowfive@124
 | 
   464 	container:AddChild(lbl2)
 | 
| 
yellowfive@57
 | 
   465 	lbl2:SetText(L.GearTipCommands)
 | 
| 
yellowfive@57
 | 
   466 	lbl2:SetWidth(130)
 | 
| 
yellowfive@57
 | 
   467 	lbl2:SetFont(Amr.CreateFont("Italic", 12, Amr.Colors.Text))
 | 
| 
yellowfive@57
 | 
   468 	lbl2:SetPoint("TOP", lbl.frame, "BOTTOM", 10, -5)
 | 
| 
yellowfive@57
 | 
   469 	
 | 
| 
yellowfive@57
 | 
   470 	local t =  AceGUI:Create("AmrUiTabGroup")
 | 
| 
yellowfive@57
 | 
   471 	t:SetLayout("None")
 | 
| 
yellowfive@81
 | 
   472 	
 | 
| 
yellowfive@81
 | 
   473 	local tabz = {}
 | 
| 
yellowfive@81
 | 
   474 	for pos = 1, 4 do
 | 
| 
yellowfive@81
 | 
   475         local specId = GetSpecializationInfo(pos)
 | 
| 
yellowfive@81
 | 
   476         if specId then
 | 
| 
yellowfive@81
 | 
   477             table.insert(tabz, { text = L.SpecsShort[Amr.SpecIds[specId]], value = pos .. "", style = "bold" })
 | 
| 
yellowfive@81
 | 
   478         end
 | 
| 
yellowfive@81
 | 
   479 	end
 | 
| 
yellowfive@81
 | 
   480 	
 | 
| 
yellowfive@81
 | 
   481 	t:SetTabs(tabz)
 | 
| 
yellowfive@57
 | 
   482 	t:SetCallback("OnGroupSelected", onGearTabSelected)
 | 
| 
yellowfive@124
 | 
   483 	container:AddChild(t)	
 | 
| 
yellowfive@57
 | 
   484 	t:SetPoint("TOPLEFT", container.content, "TOPLEFT", 144, -30)
 | 
| 
yellowfive@57
 | 
   485 	t:SetPoint("BOTTOMRIGHT", container.content, "BOTTOMRIGHT")
 | 
| 
yellowfive@57
 | 
   486 	_gearTabs = t;
 | 
| 
yellowfive@57
 | 
   487 	
 | 
| 
yellowfive@61
 | 
   488 	local btnShop = AceGUI:Create("AmrUiButton")
 | 
| 
yellowfive@61
 | 
   489 	btnShop:SetText(L.GearButtonShop)
 | 
| 
yellowfive@61
 | 
   490 	btnShop:SetBackgroundColor(Amr.Colors.Blue)
 | 
| 
yellowfive@61
 | 
   491 	btnShop:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.White))
 | 
| 
yellowfive@61
 | 
   492 	btnShop:SetWidth(245)
 | 
| 
yellowfive@61
 | 
   493 	btnShop:SetHeight(26)
 | 
| 
yellowfive@61
 | 
   494 	btnShop:SetCallback("OnClick", function(widget) Amr:ShowShopWindow() end)
 | 
| 
yellowfive@61
 | 
   495 	container:AddChild(btnShop)
 | 
| 
yellowfive@124
 | 
   496 	btnShop:SetPoint("TOPRIGHT", container.content, "TOPRIGHT", -20, -25)
 | 
| 
yellowfive@61
 | 
   497 	
 | 
| 
yellowfive@57
 | 
   498 	if not _activeTab then
 | 
| 
yellowfive@81
 | 
   499 		_activeTab = tostring(GetSpecialization())
 | 
| 
yellowfive@57
 | 
   500 	end
 | 
| 
yellowfive@57
 | 
   501 	
 | 
| 
yellowfive@57
 | 
   502 	t:SelectTab(_activeTab)
 | 
| 
yellowfive@57
 | 
   503 end
 | 
| 
yellowfive@57
 | 
   504 
 | 
| 
yellowfive@57
 | 
   505 -- do cleanup when the gear tab is released
 | 
| 
yellowfive@57
 | 
   506 function Amr:ReleaseTabGear()
 | 
| 
yellowfive@57
 | 
   507 	_gearTabs = nil
 | 
| 
yellowfive@57
 | 
   508 end
 | 
| 
yellowfive@57
 | 
   509 
 | 
| 
yellowfive@57
 | 
   510 -- show and update the gear tab for the specified spec
 | 
| 
yellowfive@57
 | 
   511 function Amr:ShowGearTab(spec)
 | 
| 
yellowfive@57
 | 
   512 	if not _gearTabs then return end
 | 
| 
yellowfive@57
 | 
   513 	
 | 
| 
yellowfive@57
 | 
   514 	_activeTab = tostring(spec)
 | 
| 
yellowfive@57
 | 
   515 	_gearTabs:SelectTab(_activeTab)
 | 
| 
yellowfive@57
 | 
   516 end
 | 
| 
yellowfive@57
 | 
   517 
 | 
| 
yellowfive@57
 | 
   518 -- refresh display of the current gear tab
 | 
| 
yellowfive@57
 | 
   519 function Amr:RefreshGearTab()
 | 
| 
yellowfive@57
 | 
   520 	if not _gearTabs then return end
 | 
| 
yellowfive@57
 | 
   521 	_gearTabs:SelectTab(_activeTab)
 | 
| 
yellowfive@57
 | 
   522 end
 | 
| 
yellowfive@57
 | 
   523 
 | 
| 
yellowfive@57
 | 
   524 
 | 
| 
yellowfive@57
 | 
   525 ------------------------------------------------------------------------------------------------
 | 
| 
yellowfive@57
 | 
   526 -- Gear Set Management
 | 
| 
yellowfive@57
 | 
   527 ------------------------------------------------------------------------------------------------
 | 
| 
yellowfive@57
 | 
   528 local _waitingForSpec = 0
 | 
| 
yellowfive@124
 | 
   529 local _pendingGearOps = nil
 | 
| 
yellowfive@124
 | 
   530 local _currentGearOp = nil
 | 
| 
yellowfive@124
 | 
   531 local _itemLockAction = nil
 | 
| 
yellowfive@124
 | 
   532 local _gearOpPasses = 0
 | 
| 
yellowfive@124
 | 
   533 local _gearOpWaiting = nil
 | 
| 
yellowfive@57
 | 
   534 
 | 
| 
yellowfive@124
 | 
   535 local beginEquipGearSet, processCurrentGearOp, nextGearOp
 | 
| 
yellowfive@89
 | 
   536 
 | 
| 
yellowfive@57
 | 
   537 -- find the first empty slot in the player's backpack+bags
 | 
| 
yellowfive@57
 | 
   538 local function findFirstEmptyBagSlot()
 | 
| 
yellowfive@57
 | 
   539 	
 | 
| 
yellowfive@57
 | 
   540 	local bagIds = {}
 | 
| 
yellowfive@57
 | 
   541 	table.insert(bagIds, BACKPACK_CONTAINER)
 | 
| 
yellowfive@57
 | 
   542 	for bagId = 1, NUM_BAG_SLOTS do
 | 
| 
yellowfive@57
 | 
   543 		table.insert(bagIds, bagId)
 | 
| 
yellowfive@57
 | 
   544 	end
 | 
| 
yellowfive@57
 | 
   545 	
 | 
| 
yellowfive@57
 | 
   546 	for i, bagId in ipairs(bagIds) do
 | 
| 
yellowfive@57
 | 
   547 		local numSlots = GetContainerNumSlots(bagId)
 | 
| 
yellowfive@57
 | 
   548 		for slotId = 1, numSlots do
 | 
| 
yellowfive@57
 | 
   549 			local _, _, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId)
 | 
| 
yellowfive@57
 | 
   550 			if not itemLink then
 | 
| 
yellowfive@57
 | 
   551 				return bagId, slotId
 | 
| 
yellowfive@57
 | 
   552 			end
 | 
| 
yellowfive@57
 | 
   553 		end
 | 
| 
yellowfive@57
 | 
   554 	end
 | 
| 
yellowfive@57
 | 
   555 	
 | 
| 
yellowfive@57
 | 
   556 	return nil, nil
 | 
| 
yellowfive@57
 | 
   557 end
 | 
| 
yellowfive@57
 | 
   558 
 | 
| 
yellowfive@124
 | 
   559 -- scan a bag for the best matching item
 | 
| 
yellowfive@124
 | 
   560 local function scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
 | 
| 
yellowfive@124
 | 
   561 	local numSlots = GetContainerNumSlots(bagId)
 | 
| 
yellowfive@124
 | 
   562 	for slotId = 1, numSlots do
 | 
| 
yellowfive@124
 | 
   563 		local _, _, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId)
 | 
| 
yellowfive@124
 | 
   564         -- we skip any stackable item, as far as we know, there is no equippable gear that can be stacked
 | 
| 
yellowfive@124
 | 
   565 		if itemLink then
 | 
| 
yellowfive@124
 | 
   566 			local bagItem = Amr.ParseItemLink(itemLink)
 | 
| 
yellowfive@124
 | 
   567 			if bagItem ~= nil then
 | 
| 
yellowfive@124
 | 
   568 				local diff = countItemDifferences(item, bagItem)
 | 
| 
yellowfive@124
 | 
   569 				if diff < bestDiff then
 | 
| 
yellowfive@124
 | 
   570 					bestItem = { bag = bagId, slot = slotId }
 | 
| 
yellowfive@124
 | 
   571 					bestDiff = diff
 | 
| 
yellowfive@124
 | 
   572 					bestLink = itemLink
 | 
| 
yellowfive@124
 | 
   573 				end
 | 
| 
yellowfive@124
 | 
   574             end
 | 
| 
yellowfive@124
 | 
   575 		end
 | 
| 
yellowfive@57
 | 
   576 	end
 | 
| 
yellowfive@124
 | 
   577 	return bestItem, bestDiff, bestLink
 | 
| 
yellowfive@57
 | 
   578 end
 | 
| 
yellowfive@57
 | 
   579 
 | 
| 
yellowfive@124
 | 
   580 -- 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
 | 
   581 local function findCurrentGearOpItem()
 | 
| 
yellowfive@124
 | 
   582 
 | 
| 
yellowfive@124
 | 
   583 	local item = _currentGearOp.items[_currentGearOp.nextSlot]
 | 
| 
yellowfive@124
 | 
   584 
 | 
| 
yellowfive@57
 | 
   585 	local bestItem = nil
 | 
| 
yellowfive@57
 | 
   586 	local bestLink = nil
 | 
| 
yellowfive@124
 | 
   587 	local bestDiff = 10000
 | 
| 
yellowfive@57
 | 
   588 	
 | 
| 
yellowfive@73
 | 
   589 	-- inventory
 | 
| 
yellowfive@73
 | 
   590 	bestItem, bestDiff, bestLink = scanBagForItem(item, BACKPACK_CONTAINER, bestItem, bestDiff, bestLink)
 | 
| 
yellowfive@73
 | 
   591 	for bagId = 1, NUM_BAG_SLOTS do
 | 
| 
yellowfive@73
 | 
   592 		bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
 | 
| 
yellowfive@73
 | 
   593 	end
 | 
| 
yellowfive@73
 | 
   594 
 | 
| 
yellowfive@61
 | 
   595 	-- 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
 | 
   596 	for slotNum = 1, #Amr.SlotIds do
 | 
| 
yellowfive@57
 | 
   597 		local slotId = Amr.SlotIds[slotNum]
 | 
| 
yellowfive@124
 | 
   598 		if _currentGearOp.slotsRemaining[slotId] then
 | 
| 
yellowfive@61
 | 
   599 			local itemLink = GetInventoryItemLink("player", slotId)
 | 
| 
yellowfive@61
 | 
   600 			if itemLink then
 | 
| 
yellowfive@61
 | 
   601 				local invItem = Amr.ParseItemLink(itemLink)
 | 
| 
yellowfive@124
 | 
   602 				if invItem then
 | 
| 
yellowfive@61
 | 
   603 					local diff = countItemDifferences(item, invItem)
 | 
| 
yellowfive@61
 | 
   604 					if diff < bestDiff then
 | 
| 
yellowfive@61
 | 
   605 						bestItem = { slot = slotId }
 | 
| 
yellowfive@61
 | 
   606 						bestDiff = diff
 | 
| 
yellowfive@61
 | 
   607 						bestLink = itemLink
 | 
| 
yellowfive@61
 | 
   608 					end
 | 
| 
yellowfive@57
 | 
   609 				end
 | 
| 
yellowfive@57
 | 
   610 			end
 | 
| 
yellowfive@57
 | 
   611 		end
 | 
| 
yellowfive@57
 | 
   612 	end
 | 
| 
yellowfive@57
 | 
   613 	
 | 
| 
yellowfive@57
 | 
   614 	-- bank
 | 
| 
yellowfive@124
 | 
   615 	if bestDiff > 0 then
 | 
| 
yellowfive@124
 | 
   616 		bestItem, bestDiff, bestLink = scanBagForItem(item, BANK_CONTAINER, bestItem, bestDiff, bestLink)
 | 
| 
yellowfive@124
 | 
   617 		for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
 | 
| 
yellowfive@124
 | 
   618 			bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
 | 
| 
yellowfive@124
 | 
   619 		end
 | 
| 
yellowfive@57
 | 
   620 	end
 | 
| 
yellowfive@124
 | 
   621 
 | 
| 
yellowfive@124
 | 
   622 	return bestItem, bestDiff, bestLink
 | 
| 
yellowfive@124
 | 
   623 end
 | 
| 
yellowfive@124
 | 
   624 
 | 
| 
yellowfive@124
 | 
   625 -- on completion, create an equipment manager set if desired
 | 
| 
yellowfive@124
 | 
   626 local function onEquipGearSetComplete()
 | 
| 
yellowfive@124
 | 
   627 	if Amr.db.profile.options.disableEm then return end
 | 
| 
yellowfive@57
 | 
   628 	
 | 
| 
yellowfive@124
 | 
   629 	-- create an equipment manager set
 | 
| 
yellowfive@124
 | 
   630 	local specId, specName = GetSpecializationInfo(GetSpecialization())
 | 
| 
yellowfive@57
 | 
   631 	
 | 
| 
yellowfive@124
 | 
   632 	local item = Amr.ParseItemLink(GetInventoryItemLink("player", INVSLOT_MAINHAND))
 | 
| 
yellowfive@124
 | 
   633 	if not item then
 | 
| 
yellowfive@124
 | 
   634 		item = Amr.ParseItemLink(GetInventoryItemLink("player", INVSLOT_OFFHAND))
 | 
| 
yellowfive@124
 | 
   635 	end
 | 
| 
yellowfive@124
 | 
   636 	if item then
 | 
| 
yellowfive@124
 | 
   637 		Amr.GetItemInfo(item.id, function(customArg, name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture)
 | 
| 
yellowfive@124
 | 
   638 			local setname = "AMR " .. specName
 | 
| 
yellowfive@124
 | 
   639 			local setid = C_EquipmentSet.GetEquipmentSetID(setname)
 | 
| 
yellowfive@124
 | 
   640 			if setid then
 | 
| 
yellowfive@124
 | 
   641 				C_EquipmentSet.SaveEquipmentSet(setid, texture)
 | 
| 
yellowfive@124
 | 
   642 			else
 | 
| 
yellowfive@124
 | 
   643 				C_EquipmentSet.CreateEquipmentSet(setname, texture)
 | 
| 
yellowfive@124
 | 
   644 			end
 | 
| 
yellowfive@124
 | 
   645 		end)
 | 
| 
yellowfive@124
 | 
   646 	end
 | 
| 
yellowfive@124
 | 
   647 end
 | 
| 
yellowfive@124
 | 
   648 
 | 
| 
yellowfive@124
 | 
   649 -- stop any currently in-progress gear swapping operation and clean up
 | 
| 
yellowfive@124
 | 
   650 local function disposeGearOp()
 | 
| 
yellowfive@124
 | 
   651 	_pendingGearOps = nil
 | 
| 
yellowfive@124
 | 
   652 	_currentGearOp = nil
 | 
| 
yellowfive@124
 | 
   653 	_itemLockAction = nil
 | 
| 
yellowfive@124
 | 
   654 	_gearOpPasses = 0
 | 
| 
yellowfive@124
 | 
   655 	_gearOpWaiting = nil
 | 
| 
yellowfive@124
 | 
   656 
 | 
| 
yellowfive@124
 | 
   657 	-- make sure the gear tab is still in sync
 | 
| 
yellowfive@124
 | 
   658 	Amr:RefreshGearTab()
 | 
| 
yellowfive@124
 | 
   659 end
 | 
| 
yellowfive@124
 | 
   660 
 | 
| 
yellowfive@124
 | 
   661 -- initialize a gear op to start running it
 | 
| 
yellowfive@124
 | 
   662 local function initializeGearOp(op, spec, pos)
 | 
| 
yellowfive@124
 | 
   663 	op.pos = pos
 | 
| 
yellowfive@124
 | 
   664 	op.spec = spec
 | 
| 
yellowfive@124
 | 
   665 
 | 
| 
yellowfive@124
 | 
   666 	-- fill the remaining slot list and set the starting slot
 | 
| 
yellowfive@124
 | 
   667 	op.nextSlot = nil
 | 
| 
yellowfive@124
 | 
   668 	op.slotsRemaining = {}	
 | 
| 
yellowfive@124
 | 
   669 	op.isWaiting = false
 | 
| 
yellowfive@124
 | 
   670 	for slotId, item in pairs(op.items) do
 | 
| 
yellowfive@124
 | 
   671 		op.slotsRemaining[slotId] = true
 | 
| 
yellowfive@124
 | 
   672 		if not op.nextSlot then
 | 
| 
yellowfive@124
 | 
   673 			op.nextSlot = slotId
 | 
| 
yellowfive@124
 | 
   674 		end			
 | 
| 
yellowfive@124
 | 
   675 	end
 | 
| 
yellowfive@124
 | 
   676 end
 | 
| 
yellowfive@124
 | 
   677 
 | 
| 
yellowfive@124
 | 
   678 function processCurrentGearOp()
 | 
| 
yellowfive@124
 | 
   679 	if not _currentGearOp then return end
 | 
| 
yellowfive@124
 | 
   680 
 | 
| 
yellowfive@124
 | 
   681 	if _currentGearOp.remove then
 | 
| 
yellowfive@124
 | 
   682 		-- remove the next item
 | 
| 
yellowfive@124
 | 
   683 
 | 
| 
yellowfive@124
 | 
   684 		-- check if the slot is already empty
 | 
| 
yellowfive@124
 | 
   685 		local itemLink = GetInventoryItemLink("player", _currentGearOp.nextSlot)
 | 
| 
yellowfive@124
 | 
   686 		if not itemLink then
 | 
| 
yellowfive@124
 | 
   687 			nextGearOp()
 | 
| 
yellowfive@124
 | 
   688 			return
 | 
| 
yellowfive@124
 | 
   689 		end
 | 
| 
yellowfive@124
 | 
   690 
 | 
| 
yellowfive@57
 | 
   691 		-- find first empty bag slot
 | 
| 
yellowfive@57
 | 
   692 		local invBag, invSlot = findFirstEmptyBagSlot()
 | 
| 
yellowfive@57
 | 
   693 		if not invBag then
 | 
| 
yellowfive@57
 | 
   694 			-- stop if bags are too full
 | 
| 
yellowfive@57
 | 
   695 			Amr:Print(L.GearEquipErrorBagFull)
 | 
| 
yellowfive@124
 | 
   696 			disposeGearOp()
 | 
| 
yellowfive@57
 | 
   697 			return
 | 
| 
yellowfive@57
 | 
   698 		end
 | 
| 
yellowfive@57
 | 
   699 
 | 
| 
yellowfive@124
 | 
   700 		PickupInventoryItem(_currentGearOp.nextSlot)
 | 
| 
yellowfive@57
 | 
   701 		PickupContainerItem(invBag, invSlot)
 | 
| 
yellowfive@57
 | 
   702 
 | 
| 
yellowfive@124
 | 
   703 		-- set an action to happen on ITEM_UNLOCKED, triggered by ClearCursor
 | 
| 
yellowfive@124
 | 
   704 		_itemLockAction = {
 | 
| 
yellowfive@57
 | 
   705 			bagId = invBag,
 | 
| 
yellowfive@124
 | 
   706 			slotId = invSlot,
 | 
| 
yellowfive@124
 | 
   707 			isRemove = true			
 | 
| 
yellowfive@57
 | 
   708 		}
 | 
| 
yellowfive@124
 | 
   709 
 | 
| 
yellowfive@124
 | 
   710 		ClearCursor()
 | 
| 
yellowfive@124
 | 
   711 		-- wait for remove to complete
 | 
| 
yellowfive@124
 | 
   712 	else
 | 
| 
yellowfive@124
 | 
   713 		-- equip the next item
 | 
| 
yellowfive@57
 | 
   714 		
 | 
| 
yellowfive@124
 | 
   715 		local bestItem, bestDiff, bestLink = findCurrentGearOpItem()
 | 
| 
yellowfive@124
 | 
   716 		
 | 
| 
yellowfive@124
 | 
   717 		_itemLockAction = nil
 | 
| 
yellowfive@57
 | 
   718 		ClearCursor()
 | 
| 
yellowfive@124
 | 
   719 	
 | 
| 
yellowfive@124
 | 
   720 		if not bestItem then
 | 
| 
yellowfive@124
 | 
   721 			-- stop if we can't find an item
 | 
| 
yellowfive@124
 | 
   722 			Amr:Print(L.GearEquipErrorNotFound)
 | 
| 
yellowfive@124
 | 
   723 			Amr:Print(L.GearEquipErrorNotFound2)
 | 
| 
yellowfive@124
 | 
   724 			disposeGearOp()
 | 
| 
yellowfive@124
 | 
   725 			
 | 
| 
yellowfive@124
 | 
   726 		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
 | 
   727 			-- find first empty bag slot
 | 
| 
yellowfive@124
 | 
   728 			local invBag, invSlot = findFirstEmptyBagSlot()
 | 
| 
yellowfive@124
 | 
   729 			if not invBag then
 | 
| 
yellowfive@124
 | 
   730 				-- stop if bags are too full
 | 
| 
yellowfive@124
 | 
   731 				Amr:Print(L.GearEquipErrorBagFull)
 | 
| 
yellowfive@124
 | 
   732 				disposeGearOp()
 | 
| 
yellowfive@124
 | 
   733 				return
 | 
| 
yellowfive@124
 | 
   734 			end
 | 
| 
yellowfive@124
 | 
   735 	
 | 
| 
yellowfive@124
 | 
   736 			-- move from bank to bag
 | 
| 
yellowfive@124
 | 
   737 			PickupContainerItem(bestItem.bag, bestItem.slot)
 | 
| 
yellowfive@124
 | 
   738 			PickupContainerItem(invBag, invSlot)
 | 
| 
yellowfive@124
 | 
   739 	
 | 
| 
yellowfive@124
 | 
   740 			-- set an action to happen on ITEM_UNLOCKED, triggered by ClearCursor
 | 
| 
yellowfive@124
 | 
   741 			_itemLockAction = {
 | 
| 
yellowfive@124
 | 
   742 				bagId = invBag,
 | 
| 
yellowfive@124
 | 
   743 				slotId = invSlot,
 | 
| 
yellowfive@124
 | 
   744 				isBank = true			
 | 
| 
yellowfive@124
 | 
   745 			}
 | 
| 
yellowfive@124
 | 
   746 			
 | 
| 
yellowfive@124
 | 
   747 			ClearCursor()			
 | 
| 
yellowfive@124
 | 
   748 			-- 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
 | 
   749 
 | 
| 
yellowfive@124
 | 
   750 		elseif (bestItem.bag or bestItem.bag == 0) and not Amr:CanEquip(bestItem.bag, bestItem.slot) then
 | 
| 
yellowfive@57
 | 
   751 			-- if an item is not soulbound, then warn the user and quit
 | 
| 
yellowfive@57
 | 
   752 			Amr:Print(L.GearEquipErrorSoulbound(bestLink))
 | 
| 
yellowfive@124
 | 
   753 			disposeGearOp()
 | 
| 
yellowfive@124
 | 
   754 
 | 
| 
yellowfive@57
 | 
   755 		else
 | 
| 
yellowfive@124
 | 
   756 
 | 
| 
yellowfive@57
 | 
   757 			-- an item in the player's bags or already equipped, equip it
 | 
| 
yellowfive@57
 | 
   758 			if bestItem.bag then
 | 
| 
yellowfive@57
 | 
   759 				PickupContainerItem(bestItem.bag, bestItem.slot)
 | 
| 
yellowfive@57
 | 
   760 			else
 | 
| 
yellowfive@124
 | 
   761 				_gearOpWaiting.inventory[bestItem.slot] = true
 | 
| 
yellowfive@57
 | 
   762 				PickupInventoryItem(bestItem.slot)
 | 
| 
yellowfive@57
 | 
   763 			end
 | 
| 
yellowfive@124
 | 
   764 			_gearOpWaiting.inventory[_currentGearOp.nextSlot] = true
 | 
| 
yellowfive@124
 | 
   765 			PickupInventoryItem(_currentGearOp.nextSlot)
 | 
| 
yellowfive@124
 | 
   766 
 | 
| 
yellowfive@124
 | 
   767 			-- don't wait for now, do all equips at once
 | 
| 
yellowfive@124
 | 
   768 			--[[
 | 
| 
yellowfive@124
 | 
   769 			-- set an action to happen on ITEM_UNLOCKED, triggered by ClearCursor
 | 
| 
yellowfive@124
 | 
   770 			_itemLockAction = {
 | 
| 
yellowfive@124
 | 
   771 				bagId = bestItem.bag,
 | 
| 
yellowfive@124
 | 
   772 				slotId = bestItem.slot,
 | 
| 
yellowfive@124
 | 
   773 				invSlot = _currentGearOp.nextSlot,
 | 
| 
yellowfive@124
 | 
   774 				isEquip = true
 | 
| 
yellowfive@124
 | 
   775 			}
 | 
| 
yellowfive@124
 | 
   776 			]]
 | 
| 
yellowfive@124
 | 
   777 
 | 
| 
yellowfive@124
 | 
   778 			ClearCursor()			
 | 
| 
yellowfive@124
 | 
   779 			nextGearOp()			
 | 
| 
yellowfive@124
 | 
   780 		end
 | 
| 
yellowfive@124
 | 
   781 
 | 
| 
yellowfive@124
 | 
   782 	end
 | 
| 
yellowfive@124
 | 
   783 end
 | 
| 
yellowfive@124
 | 
   784 
 | 
| 
yellowfive@124
 | 
   785 -- when a gear op completes successfully, this will advance to the next op or finish
 | 
| 
yellowfive@124
 | 
   786 function nextGearOp()
 | 
| 
yellowfive@124
 | 
   787 	if not _currentGearOp then return end
 | 
| 
yellowfive@124
 | 
   788 
 | 
| 
yellowfive@124
 | 
   789 	local spec = _currentGearOp.spec
 | 
| 
yellowfive@124
 | 
   790 	local pos = _currentGearOp.pos
 | 
| 
yellowfive@124
 | 
   791 	local passes = _gearOpPasses	
 | 
| 
yellowfive@124
 | 
   792 
 | 
| 
yellowfive@124
 | 
   793 	-- mark the slot as done and move to the next
 | 
| 
yellowfive@124
 | 
   794 	if _currentGearOp.nextSlot then
 | 
| 
yellowfive@124
 | 
   795 		_currentGearOp.slotsRemaining[_currentGearOp.nextSlot] = nil
 | 
| 
yellowfive@124
 | 
   796 		_currentGearOp.nextSlot = nil
 | 
| 
yellowfive@124
 | 
   797 		for slotId, item in pairs(_currentGearOp.items) do
 | 
| 
yellowfive@124
 | 
   798 			if _currentGearOp.slotsRemaining[slotId] then
 | 
| 
yellowfive@124
 | 
   799 				_currentGearOp.nextSlot = slotId
 | 
| 
yellowfive@124
 | 
   800 				break
 | 
| 
yellowfive@124
 | 
   801 			end
 | 
| 
yellowfive@124
 | 
   802 		end
 | 
| 
yellowfive@124
 | 
   803 	end
 | 
| 
yellowfive@124
 | 
   804 
 | 
| 
yellowfive@124
 | 
   805 	if not _currentGearOp.nextSlot then
 | 
| 
yellowfive@124
 | 
   806 		-- see if anything is still in progress and we want to wait for it before continuing		
 | 
| 
yellowfive@124
 | 
   807 		local inProgress = not Amr.IsEmpty(_gearOpWaiting.inventory)
 | 
| 
yellowfive@124
 | 
   808 
 | 
| 
yellowfive@124
 | 
   809 		if (_currentGearOp.wait or _currentGearOp.remove) and inProgress then
 | 
| 
yellowfive@124
 | 
   810 			-- this will cause the item unlock handler to call nextGearOp again when all in-progress swaps have unlocked related slots
 | 
| 
yellowfive@124
 | 
   811 			_currentGearOp.isWaiting = true
 | 
| 
yellowfive@124
 | 
   812 		else
 | 
| 
yellowfive@124
 | 
   813 			_currentGearOp = _pendingGearOps[pos + 1]
 | 
| 
yellowfive@124
 | 
   814 			if _currentGearOp then
 | 
| 
yellowfive@124
 | 
   815 				-- we have another op, do it
 | 
| 
yellowfive@124
 | 
   816 				initializeGearOp(_currentGearOp, spec, pos + 1)
 | 
| 
yellowfive@124
 | 
   817 				processCurrentGearOp()
 | 
| 
yellowfive@124
 | 
   818 			else
 | 
| 
yellowfive@124
 | 
   819 				-- we are done
 | 
| 
yellowfive@124
 | 
   820 				disposeGearOp()
 | 
| 
yellowfive@124
 | 
   821 
 | 
| 
yellowfive@124
 | 
   822 				-- this will check if not all items were swapped, and either finish up, try again, or abort if have tried too many times
 | 
| 
yellowfive@124
 | 
   823 				beginEquipGearSet(spec, passes + 1)
 | 
| 
yellowfive@124
 | 
   824 			end
 | 
| 
yellowfive@124
 | 
   825 		end
 | 
| 
yellowfive@124
 | 
   826 	else
 | 
| 
yellowfive@124
 | 
   827 		-- do the next item
 | 
| 
yellowfive@124
 | 
   828 		processCurrentGearOp()
 | 
| 
yellowfive@124
 | 
   829 	end
 | 
| 
yellowfive@124
 | 
   830 
 | 
| 
yellowfive@124
 | 
   831 end
 | 
| 
yellowfive@124
 | 
   832 
 | 
| 
yellowfive@124
 | 
   833 local function handleItemUnlocked(bagId, slotId)
 | 
| 
yellowfive@124
 | 
   834 
 | 
| 
yellowfive@124
 | 
   835 	-- mark anything that is waiting as unlocked if it is no longer locked
 | 
| 
yellowfive@124
 | 
   836 	if _currentGearOp and _gearOpWaiting then
 | 
| 
yellowfive@124
 | 
   837 		for i,s in ipairs(Amr.SlotIds) do
 | 
| 
yellowfive@124
 | 
   838 			if not IsInventoryItemLocked(s) then
 | 
| 
yellowfive@124
 | 
   839 				_gearOpWaiting.inventory[s] = nil
 | 
| 
yellowfive@124
 | 
   840 			end
 | 
| 
yellowfive@124
 | 
   841 		end
 | 
| 
yellowfive@124
 | 
   842 	end
 | 
| 
yellowfive@124
 | 
   843 
 | 
| 
yellowfive@124
 | 
   844 	if _itemLockAction then
 | 
| 
yellowfive@124
 | 
   845 		if _itemLockAction.isRemove then
 | 
| 
yellowfive@124
 | 
   846 			-- waiting for a specific remove op to finish before continuing
 | 
| 
yellowfive@124
 | 
   847 			if bagId == _itemLockAction.bagId and slotId == _itemLockAction.slotId then
 | 
| 
yellowfive@124
 | 
   848 				_itemLockAction = nil
 | 
| 
yellowfive@124
 | 
   849 				nextGearOp()
 | 
| 
yellowfive@124
 | 
   850 			end
 | 
| 
yellowfive@124
 | 
   851 		elseif _itemLockAction.isBank then
 | 
| 
yellowfive@124
 | 
   852 			-- waiting for an item to move from bank into inventory, then reprocess the current op
 | 
| 
yellowfive@124
 | 
   853 			if bagId == _itemLockAction.bagId and slotId == _itemLockAction.slotId then
 | 
| 
yellowfive@124
 | 
   854 				_itemLockAction = nil
 | 
| 
yellowfive@124
 | 
   855 				processCurrentGearOp()
 | 
| 
yellowfive@124
 | 
   856 			end
 | 
| 
yellowfive@124
 | 
   857 
 | 
| 
yellowfive@124
 | 
   858 		elseif _itemLockAction.isEquip then
 | 
| 
yellowfive@124
 | 
   859 			-- this is not currently used... we do all equips at once usually, but could go back to this if it causes problems
 | 
| 
yellowfive@124
 | 
   860 
 | 
| 
yellowfive@124
 | 
   861 			-- waiting for a specific equip op to finish
 | 
| 
yellowfive@61
 | 
   862 			
 | 
| 
yellowfive@124
 | 
   863 			-- inventory slot we're swapping to is still locked, can't continue yet
 | 
| 
yellowfive@124
 | 
   864 			if IsInventoryItemLocked(_itemLockAction.invSlot) then return end
 | 
| 
yellowfive@124
 | 
   865 
 | 
| 
yellowfive@124
 | 
   866 			if _itemLockAction.bagId then
 | 
| 
yellowfive@124
 | 
   867 				local _, _, locked = GetContainerItemInfo(_itemLockAction.bagId, _itemLockAction.slotId)
 | 
| 
yellowfive@124
 | 
   868 				-- the bag slot we're swapping from is still locked, can't continue yet
 | 
| 
yellowfive@124
 | 
   869 				if locked then return end
 | 
| 
yellowfive@124
 | 
   870 			else
 | 
| 
yellowfive@124
 | 
   871 				-- inventory slot we're swapping from is still locked, can't continue yet
 | 
| 
yellowfive@124
 | 
   872 				if IsInventoryItemLocked(_itemLockAction.slotId) then return end
 | 
| 
yellowfive@124
 | 
   873 			end
 | 
| 
yellowfive@124
 | 
   874 			
 | 
| 
yellowfive@124
 | 
   875 			_itemLockAction = nil
 | 
| 
yellowfive@124
 | 
   876 			nextGearOp()
 | 
| 
yellowfive@124
 | 
   877 		else
 | 
| 
yellowfive@124
 | 
   878 			-- unknown... shouldn't happen
 | 
| 
yellowfive@124
 | 
   879 			_itemLockAction = nil
 | 
| 
yellowfive@57
 | 
   880 		end
 | 
| 
yellowfive@124
 | 
   881 	else
 | 
| 
yellowfive@124
 | 
   882 		
 | 
| 
yellowfive@124
 | 
   883 		-- not waiting on a specific action, check if we are waiting for all locked slots to open up and they are done
 | 
| 
yellowfive@124
 | 
   884 		if _currentGearOp and _gearOpWaiting and _currentGearOp.isWaiting and Amr.IsEmpty(_gearOpWaiting.inventory) then
 | 
| 
yellowfive@124
 | 
   885 			nextGearOp()
 | 
| 
yellowfive@124
 | 
   886 		end	
 | 
| 
yellowfive@57
 | 
   887 	end
 | 
| 
yellowfive@57
 | 
   888 	
 | 
| 
yellowfive@57
 | 
   889 end
 | 
| 
yellowfive@57
 | 
   890 
 | 
| 
yellowfive@124
 | 
   891 local function shuffle(tbl)
 | 
| 
yellowfive@124
 | 
   892 	local size = #tbl
 | 
| 
yellowfive@124
 | 
   893 	for i = size, 1, -1 do
 | 
| 
yellowfive@124
 | 
   894 		local rand = math.random(size)
 | 
| 
yellowfive@124
 | 
   895 		tbl[i], tbl[rand] = tbl[rand], tbl[i]
 | 
| 
yellowfive@89
 | 
   896 	end
 | 
| 
yellowfive@124
 | 
   897 	return tbl
 | 
| 
yellowfive@89
 | 
   898 end
 | 
| 
yellowfive@89
 | 
   899 
 | 
| 
yellowfive@124
 | 
   900 function beginEquipGearSet(spec, passes)
 | 
| 
yellowfive@57
 | 
   901 
 | 
| 
yellowfive@57
 | 
   902 	local gear = Amr.db.char.GearSets[spec]
 | 
| 
yellowfive@57
 | 
   903 	if not gear then 
 | 
| 
yellowfive@57
 | 
   904 		Amr:Print(L.GearEquipErrorEmpty)
 | 
| 
yellowfive@57
 | 
   905 		return
 | 
| 
yellowfive@57
 | 
   906 	end
 | 
| 
yellowfive@124
 | 
   907 
 | 
| 
yellowfive@124
 | 
   908 	-- ensure all our stored data is up to date
 | 
| 
yellowfive@57
 | 
   909 	local player = Amr:ExportCharacter()
 | 
| 
yellowfive@57
 | 
   910 
 | 
| 
yellowfive@124
 | 
   911 	local itemsToEquip = {
 | 
| 
yellowfive@124
 | 
   912 		legendaries = {},
 | 
| 
yellowfive@124
 | 
   913 		weapons = {},
 | 
| 
yellowfive@124
 | 
   914 		rings = {},
 | 
| 
yellowfive@124
 | 
   915 		trinkets = {},
 | 
| 
yellowfive@124
 | 
   916 		others = {},
 | 
| 
yellowfive@124
 | 
   917 		blanks = {}
 | 
| 
yellowfive@124
 | 
   918 	}
 | 
| 
yellowfive@57
 | 
   919 	local remaining = 0
 | 
| 
yellowfive@124
 | 
   920 	local usedItems = {}	
 | 
| 
yellowfive@124
 | 
   921 
 | 
| 
yellowfive@124
 | 
   922 	-- 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
 | 
   923 	local slots = {}
 | 
| 
yellowfive@124
 | 
   924 	for i,s in ipairs(Amr.SlotIds) do
 | 
| 
yellowfive@124
 | 
   925 		table.insert(slots, s)
 | 
| 
yellowfive@124
 | 
   926 	end
 | 
| 
yellowfive@124
 | 
   927 	shuffle(slots)
 | 
| 
yellowfive@124
 | 
   928 
 | 
| 
yellowfive@124
 | 
   929 	for i,slotId in ipairs(slots) do
 | 
| 
yellowfive@124
 | 
   930 
 | 
| 
yellowfive@124
 | 
   931 		-- we do stuff in batches that avoids most unique conflicts
 | 
| 
yellowfive@124
 | 
   932 		local list = itemsToEquip.others
 | 
| 
yellowfive@124
 | 
   933 		if slotId == 16 or slotId == 17 then
 | 
| 
yellowfive@124
 | 
   934 			list = itemsToEquip.weapons
 | 
| 
yellowfive@124
 | 
   935 		elseif slotId == 11 or slotId == 12 then
 | 
| 
yellowfive@124
 | 
   936 			list = itemsToEquip.rings
 | 
| 
yellowfive@124
 | 
   937 		elseif slotId == 13 or slotId == 14 then
 | 
| 
yellowfive@124
 | 
   938 			list = itemsToEquip.trinkets
 | 
| 
yellowfive@124
 | 
   939 		end
 | 
| 
yellowfive@124
 | 
   940 
 | 
| 
yellowfive@57
 | 
   941 		local old = player.Equipped[spec][slotId]
 | 
| 
yellowfive@57
 | 
   942 		local new = gear[slotId]
 | 
| 
yellowfive@124
 | 
   943 		local prevRemaining = remaining
 | 
| 
yellowfive@69
 | 
   944 		if new then
 | 
| 
yellowfive@124
 | 
   945 			-- if the new thing is an artifact, only match the item id
 | 
| 
yellowfive@124
 | 
   946 			local newItem = Item:CreateFromItemID(new.id)
 | 
| 
yellowfive@124
 | 
   947 			local quality = newItem and newItem:GetItemQuality() or 0
 | 
| 
yellowfive@124
 | 
   948 			if quality == 6 then
 | 
| 
yellowfive@124
 | 
   949 				if not old or new.id ~= old.id then
 | 
| 
yellowfive@124
 | 
   950 					list[slotId] = new
 | 
| 
yellowfive@69
 | 
   951 					remaining = remaining + 1
 | 
| 
yellowfive@69
 | 
   952 				end
 | 
| 
yellowfive@124
 | 
   953 			else				
 | 
| 
yellowfive@124
 | 
   954 				local diff = countItemDifferences(old, new)
 | 
| 
yellowfive@124
 | 
   955 				if diff > 0 and diff < 1000 then
 | 
| 
yellowfive@124
 | 
   956 					-- same item, see if inventory has one that is closer (e.g. a duplicate item with correct enchants/gems)
 | 
| 
yellowfive@124
 | 
   957 					local bestItem, bestDiff = Amr:FindMatchingItem(new, player, usedItems)
 | 
| 
yellowfive@124
 | 
   958 					if bestDiff and bestDiff < diff then
 | 
| 
yellowfive@124
 | 
   959 						new = bestItem
 | 
| 
yellowfive@124
 | 
   960 						diff = bestDiff
 | 
| 
yellowfive@124
 | 
   961 					end
 | 
| 
yellowfive@124
 | 
   962 				end
 | 
| 
yellowfive@124
 | 
   963 
 | 
| 
yellowfive@124
 | 
   964 				if diff > 0 then
 | 
| 
yellowfive@124
 | 
   965 					list[slotId] = new
 | 
| 
yellowfive@124
 | 
   966 					remaining = remaining + 1
 | 
| 
yellowfive@124
 | 
   967 				end
 | 
| 
yellowfive@124
 | 
   968 			end
 | 
| 
yellowfive@124
 | 
   969 		else
 | 
| 
yellowfive@124
 | 
   970 			-- need to remove this item
 | 
| 
yellowfive@124
 | 
   971 			itemsToEquip.blanks[slotId] = {}
 | 
| 
yellowfive@124
 | 
   972 			remaining = remaining + 1
 | 
| 
yellowfive@124
 | 
   973 		end
 | 
| 
yellowfive@124
 | 
   974 
 | 
| 
yellowfive@124
 | 
   975 		if remaining > prevRemaining then
 | 
| 
yellowfive@124
 | 
   976 			-- 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
 | 
   977 			if old then
 | 
| 
yellowfive@124
 | 
   978 				local oldItem = Item:CreateFromItemID(old.id)
 | 
| 
yellowfive@124
 | 
   979 				if oldItem and oldItem:GetItemQuality() == 5 then				
 | 
| 
yellowfive@124
 | 
   980 					itemsToEquip.legendaries[slotId] = {}
 | 
| 
yellowfive@124
 | 
   981 				end
 | 
| 
yellowfive@57
 | 
   982 			end
 | 
| 
yellowfive@57
 | 
   983 		end
 | 
| 
yellowfive@57
 | 
   984 	end
 | 
| 
yellowfive@124
 | 
   985 	
 | 
| 
yellowfive@124
 | 
   986 	if remaining > 0 then
 | 
| 
yellowfive@57
 | 
   987 
 | 
| 
yellowfive@124
 | 
   988 		if passes < 5 then
 | 
| 
yellowfive@124
 | 
   989 			_pendingGearOps = {}
 | 
| 
yellowfive@124
 | 
   990 
 | 
| 
yellowfive@124
 | 
   991 			if not Amr.IsEmpty(itemsToEquip.blanks) then
 | 
| 
yellowfive@124
 | 
   992 				-- if gear set wants slots to be blank, do that first
 | 
| 
yellowfive@124
 | 
   993 				table.insert(_pendingGearOps, { items = itemsToEquip.blanks, remove = true, label = "blanks" }) 
 | 
| 
yellowfive@124
 | 
   994 			end
 | 
| 
yellowfive@124
 | 
   995 			if not Amr.IsEmpty(itemsToEquip.weapons) then
 | 
| 
yellowfive@124
 | 
   996 				-- change weapons first: remove both, wait, then equip new ones
 | 
| 
yellowfive@124
 | 
   997 				table.insert(_pendingGearOps, { items = itemsToEquip.weapons, remove = true, label = "remove weapons" })				
 | 
| 
yellowfive@124
 | 
   998 				table.insert(_pendingGearOps, { items = itemsToEquip.weapons, wait = true, label = "equip weapons" })
 | 
| 
yellowfive@124
 | 
   999 			end
 | 
| 
yellowfive@124
 | 
  1000 			if not Amr.IsEmpty(itemsToEquip.legendaries) then 
 | 
| 
yellowfive@124
 | 
  1001 				-- remove any legendaries, wait
 | 
| 
yellowfive@124
 | 
  1002 				table.insert(_pendingGearOps, { items = itemsToEquip.legendaries, remove = true, label = "remove legendaries" }) 
 | 
| 
yellowfive@124
 | 
  1003 			end
 | 
| 
yellowfive@124
 | 
  1004 			if not Amr.IsEmpty(itemsToEquip.rings) then 
 | 
| 
yellowfive@124
 | 
  1005 				-- remove both rings, wait, then equip new ones
 | 
| 
yellowfive@124
 | 
  1006 				table.insert(_pendingGearOps, { items = itemsToEquip.rings, remove = true, label = "remove rings" })
 | 
| 
yellowfive@124
 | 
  1007 				table.insert(_pendingGearOps, { items = itemsToEquip.rings, wait = true, label = "equip rings" })
 | 
| 
yellowfive@124
 | 
  1008 			end
 | 
| 
yellowfive@124
 | 
  1009 			if not Amr.IsEmpty(itemsToEquip.trinkets) then 
 | 
| 
yellowfive@124
 | 
  1010 				-- remove both trinkets, wait, then equip new ones
 | 
| 
yellowfive@124
 | 
  1011 				table.insert(_pendingGearOps, { items = itemsToEquip.trinkets, remove = true, label = "remove trinkets" })
 | 
| 
yellowfive@124
 | 
  1012 				table.insert(_pendingGearOps, { items = itemsToEquip.trinkets, wait = true, label = "equip trinkets" })
 | 
| 
yellowfive@124
 | 
  1013 			end
 | 
| 
yellowfive@124
 | 
  1014 			if not Amr.IsEmpty(itemsToEquip.others) then 
 | 
| 
yellowfive@124
 | 
  1015 				-- equip all other items, wait for completion
 | 
| 
yellowfive@124
 | 
  1016 				table.insert(_pendingGearOps, { items = itemsToEquip.others, wait = true, label = "equip others" }) 
 | 
| 
yellowfive@124
 | 
  1017 			end
 | 
| 
yellowfive@124
 | 
  1018 
 | 
| 
yellowfive@124
 | 
  1019 			-- make the last operation wait no matter what, before this gets called again to check if everything succeeded
 | 
| 
yellowfive@124
 | 
  1020 			_pendingGearOps[#_pendingGearOps].wait = true
 | 
| 
yellowfive@124
 | 
  1021 
 | 
| 
yellowfive@124
 | 
  1022 			if not _gearOpWaiting then
 | 
| 
yellowfive@124
 | 
  1023 				_gearOpWaiting = { inventory = {} }
 | 
| 
yellowfive@124
 | 
  1024 			end
 | 
| 
yellowfive@124
 | 
  1025 
 | 
| 
yellowfive@124
 | 
  1026 			_gearOpPasses = passes
 | 
| 
yellowfive@124
 | 
  1027 			_currentGearOp = _pendingGearOps[1]
 | 
| 
yellowfive@124
 | 
  1028 			initializeGearOp(_currentGearOp, spec, 1)
 | 
| 
yellowfive@124
 | 
  1029 
 | 
| 
yellowfive@124
 | 
  1030 			processCurrentGearOp()
 | 
| 
yellowfive@124
 | 
  1031 		else
 | 
| 
yellowfive@124
 | 
  1032 			-- TODO: print message that gear set couldn't be equipped
 | 
| 
yellowfive@89
 | 
  1033 		end
 | 
| 
yellowfive@57
 | 
  1034 
 | 
| 
yellowfive@57
 | 
  1035 	else
 | 
| 
yellowfive@89
 | 
  1036 		onEquipGearSetComplete()
 | 
| 
yellowfive@124
 | 
  1037 	end	
 | 
| 
yellowfive@57
 | 
  1038 end
 | 
| 
yellowfive@57
 | 
  1039 
 | 
| 
yellowfive@57
 | 
  1040 local function onActiveTalentGroupChanged()
 | 
| 
yellowfive@81
 | 
  1041 
 | 
| 
yellowfive@57
 | 
  1042 	local auto = Amr.db.profile.options.autoGear
 | 
| 
yellowfive@81
 | 
  1043 	local currentSpec = GetSpecialization()
 | 
| 
yellowfive@57
 | 
  1044 	
 | 
| 
yellowfive@57
 | 
  1045 	if currentSpec == _waitingForSpec or auto then
 | 
| 
yellowfive@57
 | 
  1046 		-- spec is what we want, now equip the gear
 | 
| 
yellowfive@124
 | 
  1047 		beginEquipGearSet(currentSpec, 0)
 | 
| 
yellowfive@57
 | 
  1048 	end
 | 
| 
yellowfive@57
 | 
  1049 	
 | 
| 
yellowfive@57
 | 
  1050 	_waitingForSpec = 0
 | 
| 
yellowfive@57
 | 
  1051 end
 | 
| 
yellowfive@57
 | 
  1052 
 | 
| 
yellowfive@81
 | 
  1053 -- activate the specified spec and then equip the saved gear set
 | 
| 
yellowfive@57
 | 
  1054 function Amr:EquipGearSet(spec)
 | 
| 
yellowfive@57
 | 
  1055 	
 | 
| 
yellowfive@81
 | 
  1056 	-- if no argument, then cycle spec
 | 
| 
yellowfive@57
 | 
  1057 	if not spec then
 | 
| 
yellowfive@81
 | 
  1058 		spec = GetSpecialization() + 1
 | 
| 
yellowfive@57
 | 
  1059 	end
 | 
| 
yellowfive@81
 | 
  1060 
 | 
| 
yellowfive@57
 | 
  1061 	-- allow some flexibility in the arguments
 | 
| 
yellowfive@81
 | 
  1062 	if spec == "1" or spec == "2" or spec == "3" or spec == "4" then spec = tonumber(spec) end
 | 
| 
yellowfive@81
 | 
  1063 
 | 
| 
yellowfive@81
 | 
  1064 	local specId = GetSpecializationInfo(spec)
 | 
| 
yellowfive@81
 | 
  1065 	if not specId then spec = 1 end
 | 
| 
yellowfive@57
 | 
  1066 	
 | 
| 
yellowfive@57
 | 
  1067 	if UnitAffectingCombat("player") then
 | 
| 
yellowfive@57
 | 
  1068 		Amr:Print(L.GearEquipErrorCombat)
 | 
| 
yellowfive@57
 | 
  1069 		return
 | 
| 
yellowfive@57
 | 
  1070 	end
 | 
| 
yellowfive@57
 | 
  1071 	
 | 
| 
yellowfive@57
 | 
  1072 	_waitingForSpec = spec
 | 
| 
yellowfive@57
 | 
  1073 	
 | 
| 
yellowfive@81
 | 
  1074 	local currentSpec = GetSpecialization()
 | 
| 
yellowfive@57
 | 
  1075 	if currentSpec ~= spec then
 | 
| 
yellowfive@81
 | 
  1076 		SetSpecialization(spec)
 | 
| 
yellowfive@57
 | 
  1077 	else
 | 
| 
yellowfive@57
 | 
  1078 		onActiveTalentGroupChanged()
 | 
| 
yellowfive@57
 | 
  1079 	end
 | 
| 
yellowfive@57
 | 
  1080 end
 | 
| 
yellowfive@57
 | 
  1081 
 | 
| 
yellowfive@124
 | 
  1082 -- moves any gear in bags to the bank if not part of a gear set
 | 
| 
yellowfive@57
 | 
  1083 function Amr:CleanBags()
 | 
| 
yellowfive@57
 | 
  1084 	-- TODO: implement
 | 
| 
yellowfive@57
 | 
  1085 end
 | 
| 
yellowfive@57
 | 
  1086 
 | 
| 
yellowfive@81
 | 
  1087 --[[
 | 
| 
yellowfive@81
 | 
  1088 local function testfunc(message)
 | 
| 
yellowfive@81
 | 
  1089 	print(strsub(message, 13))
 | 
| 
yellowfive@81
 | 
  1090 end
 | 
| 
yellowfive@81
 | 
  1091 ]]
 | 
| 
yellowfive@81
 | 
  1092 
 | 
| 
yellowfive@57
 | 
  1093 function Amr:InitializeGear()
 | 
| 
yellowfive@87
 | 
  1094 	Amr:AddEventHandler("ACTIVE_TALENT_GROUP_CHANGED", onActiveTalentGroupChanged)
 | 
| 
yellowfive@57
 | 
  1095 
 | 
| 
yellowfive@81
 | 
  1096 	--Amr:AddEventHandler("CHAT_MSG_CHANNEL", testfunc)
 | 
| 
yellowfive@81
 | 
  1097 	
 | 
| 
yellowfive@57
 | 
  1098 	Amr:AddEventHandler("UNIT_INVENTORY_CHANGED", function(unitID)
 | 
| 
yellowfive@57
 | 
  1099 		if unitID and unitID ~= "player" then return end
 | 
| 
yellowfive@124
 | 
  1100 		
 | 
| 
yellowfive@124
 | 
  1101 		-- don't update during a gear operation, wait until it is totally finished
 | 
| 
yellowfive@124
 | 
  1102 		if _pendingGearOps then return end
 | 
| 
yellowfive@124
 | 
  1103 
 | 
| 
yellowfive@57
 | 
  1104 		Amr:RefreshGearTab()
 | 
| 
yellowfive@57
 | 
  1105 	end)
 | 
| 
yellowfive@57
 | 
  1106 
 | 
| 
yellowfive@124
 | 
  1107 	Amr:AddEventHandler("ITEM_UNLOCKED", handleItemUnlocked)
 | 
| 
yellowfive@122
 | 
  1108 end
 |