| contrebasse@98 | 1 local addonName, A = ... | 
| contrebasse@98 | 2 | 
| contrebasse@98 | 3 -- @todo clean the A table | 
| contrebasse@98 | 4 -- @todo check local copy of globals functions | 
| contrebasse@98 | 5 -- @todo add support for dez ? | 
| contrebasse@107 | 6 -- @todo add support for hidden recipes, removing filtering => save the reagent count to be able to compute the number of craftable items | 
| contrebasse@98 | 7 -- @todo add support for cross tradeskill, like mining + forge/ingé | 
| contrebasse@98 | 8 -- @todo when a reagent can not be crafted and the recipe has many reagents, do like ReverseEngeneering and go to this recipe (with a one step return button) | 
| contrebasse@98 | 9 -- @todo scroll to the selected recipe on opening (usefull also for the previous todo) | 
| contrebasse@98 | 10 -- @todo shift+clic on a reagent name while the serachbar is focused fills the serachbar with the reagent name (idem with the crafted item) | 
| contrebasse@98 | 11 -- @todo add a button to clear search | 
| contrebasse@98 | 12 -- @todo add a button to cast a campfire when coocking | 
| contrebasse@98 | 13 | 
| contrebasse@98 | 14 --------------------------------------------------- | 
| contrebasse@98 | 15 -- Variables | 
| contrebasse@98 | 16 --------------------------------------------------- | 
| contrebasse@98 | 17 -- Used by findglobals | 
| contrebasse@98 | 18 -- GLOBALS: _G, CreateFrame, DEFAULT_CHAT_FRAME | 
| contrebasse@98 | 19 | 
| contrebasse@98 | 20 -- Lua functions | 
| contrebasse@98 | 21 | 
| contrebasse@98 | 22 -- Wow functions | 
| contrebasse@98 | 23 | 
| contrebasse@98 | 24 -- constant vars | 
| contrebasse@98 | 25 | 
| contrebasse@98 | 26 --------------------------------------------------- | 
| contrebasse@98 | 27 -- Manage events | 
| contrebasse@98 | 28 --------------------------------------------------- | 
| contrebasse@98 | 29 A.EventsFrame = CreateFrame("Frame") | 
| contrebasse@98 | 30 | 
| contrebasse@98 | 31 local SCAN_DELAY = 0.2 | 
| contrebasse@98 | 32 local t_throttle = SCAN_DELAY | 
| contrebasse@98 | 33 local function throttleScan(self, t_elapsed) | 
| contrebasse@98 | 34 	t_throttle = t_throttle - t_elapsed | 
| contrebasse@98 | 35 	if t_throttle<0 then | 
| contrebasse@98 | 36 		self:SetScript("OnUpdate", nil) | 
| contrebasse@98 | 37 | 
| contrebasse@98 | 38 		-- Close the external window if the tradeskill changed | 
| contrebasse@98 | 39 		if A.currentTradeSkill ~= GetTradeSkillLine() then | 
| contrebasse@98 | 40 			A.MenuFrame:Hide() | 
| contrebasse@98 | 41 		end | 
| contrebasse@98 | 42 		if IsTradeSkillGuild() or IsTradeSkillLinked() then | 
| contrebasse@98 | 43 			A.MenuFrame:Hide() | 
| contrebasse@98 | 44 			return | 
| contrebasse@98 | 45 		end | 
| contrebasse@98 | 46 | 
| contrebasse@98 | 47 		-- Scan availabe recipes | 
| contrebasse@98 | 48 		-- Rescan in case of problem | 
| contrebasse@98 | 49 		if not A:ScanSimpleRecipes() then | 
| contrebasse@98 | 50 			t_throttle = SCAN_DELAY | 
| contrebasse@98 | 51 			self:SetScript("OnUpdate", throttleScan) | 
| contrebasse@98 | 52 		end | 
| contrebasse@98 | 53 | 
| contrebasse@98 | 54 		-- Show makables reagents | 
| contrebasse@98 | 55 		A.updateCounts(GetTradeSkillSelectionIndex()) | 
| contrebasse@98 | 56 	end | 
| contrebasse@98 | 57 end | 
| contrebasse@98 | 58 A.EventsFrame:SetScript("OnEvent", function(self, event) | 
| contrebasse@98 | 59 	if event == "TRADE_SKILL_UPDATE" then | 
| contrebasse@98 | 60 		t_throttle = SCAN_DELAY | 
| contrebasse@98 | 61 		self:SetScript("OnUpdate", throttleScan) | 
| contrebasse@101 | 62 		A.ManageCampFireBtn() | 
| contrebasse@101 | 63 | 
| contrebasse@101 | 64 	elseif event == "PLAYER_REGEN_DISABLED" then | 
| contrebasse@101 | 65 		A.HideCampFireBtn() | 
| contrebasse@101 | 66 	elseif event == "PLAYER_REGEN_ENABLED" then | 
| contrebasse@101 | 67 		A.ManageCampFireBtn() | 
| contrebasse@98 | 68 | 
| contrebasse@98 | 69 	elseif event == "TRADE_SKILL_SHOW" then | 
| contrebasse@98 | 70 		A:Initialize() | 
| contrebasse@98 | 71 		A.EventsFrame:UnregisterEvent("TRADE_SKILL_SHOW") | 
| contrebasse@98 | 72 	end -- if | 
| contrebasse@98 | 73 end) -- function | 
| contrebasse@98 | 74 A.EventsFrame:RegisterEvent("TRADE_SKILL_SHOW") | 
| contrebasse@98 | 75 A.EventsFrame:RegisterEvent("TRADE_SKILL_UPDATE") | 
| contrebasse@98 | 76 A.EventsFrame:RegisterEvent("PLAYER_REGEN_ENABLED") | 
| contrebasse@98 | 77 A.EventsFrame:RegisterEvent("PLAYER_REGEN_DISABLED") | 
| contrebasse@98 | 78 | 
| contrebasse@98 | 79 --------------------------------------------------- | 
| contrebasse@98 | 80 -- Initialize | 
| contrebasse@98 | 81 --------------------------------------------------- | 
| contrebasse@98 | 82 function A:Initialize() | 
| contrebasse@98 | 83 | 
| contrebasse@98 | 84 	-- Register clics on reagent's buttons | 
| contrebasse@98 | 85 	for i=1,7 do | 
| contrebasse@98 | 86 		local btn = _G["TradeSkillReagent"..i] | 
| contrebasse@98 | 87 		btn:HookScript("OnDoubleClick", A.ProcessReagent) | 
| contrebasse@98 | 88 		btn:HookScript("OnEnter", A.btnEntered) | 
| contrebasse@98 | 89 		btn:HookScript("OnLeave", A.btnLeft) | 
| contrebasse@98 | 90 		btn.SplitStack = A.SplitStack | 
| contrebasse@98 | 91 | 
| contrebasse@98 | 92 		local textureHighlight = btn:CreateTexture() | 
| contrebasse@98 | 93 		textureHighlight:Hide() | 
| contrebasse@98 | 94 		textureHighlight:SetTexture("Interface\\BUTTONS\\CheckButtonHilight") | 
| contrebasse@98 | 95 		textureHighlight:SetBlendMode("ADD") | 
| contrebasse@98 | 96 		textureHighlight:SetAllPoints("TradeSkillReagent"..i.."IconTexture") | 
| contrebasse@98 | 97 		btn.textureHighlight = textureHighlight | 
| contrebasse@98 | 98 | 
| contrebasse@98 | 99 		local label = btn:CreateFontString(nil,"ARTWORK","GameFontHighlight") | 
| contrebasse@98 | 100 		label:SetSize(100,20) | 
| contrebasse@98 | 101 		label:SetPoint("TOPLEFT",btn,"TOPLEFT",4,-4) | 
| contrebasse@98 | 102 		label:SetJustifyH("LEFT") | 
| contrebasse@98 | 103 		label:SetJustifyV("TOP") | 
| contrebasse@98 | 104 		label:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE") | 
| contrebasse@98 | 105 		btn.label = label | 
| contrebasse@98 | 106 	end -- for | 
| contrebasse@98 | 107 | 
| contrebasse@98 | 108 	-- Secondary Tooltip | 
| contrebasse@98 | 109 	A.tooltipRecipe = CreateFrame("GameTooltip", "ReagentMaker_tooltipRecipe",UIParent, "GameTooltipTemplate") | 
| contrebasse@98 | 110 	A.tooltipRecipe:SetFrameStrata("TOOLTIP") | 
| contrebasse@98 | 111 	A.tooltipRecipe:Hide() | 
| contrebasse@101 | 112 | 
| contrebasse@98 | 113 	-- Button for enchanting directy on a scroll | 
| contrebasse@98 | 114 	A.LoadEnchantOnScroll() | 
| contrebasse@98 | 115 end -- function | 
| contrebasse@98 | 116 | 
| contrebasse@98 | 117 -- Function run after selecting a item in the tradeskill window | 
| contrebasse@98 | 118 function A.ProcessReagent(btn, ...) | 
| contrebasse@108 | 119 	--SPELL_FAILED_REAGENTS = "Missing reagent: %s"; | 
| contrebasse@108 | 120 	--ERR_SPELL_FAILED_REAGENTS_GENERIC = "Missing reagent"; | 
| contrebasse@108 | 121 	--ERR_INTERNAL_BAG_ERROR = "Internal Bag Error"; | 
| contrebasse@108 | 122 	--SPELL_FAILED_ERROR = "Internal error"; | 
| contrebasse@98 | 123 | 
| contrebasse@98 | 124 	-- Do not manage guild tradeskill | 
| contrebasse@98 | 125 	if IsTradeSkillGuild() or IsTradeSkillLinked() then return end | 
| contrebasse@98 | 126 | 
| contrebasse@98 | 127 	-- We want no modifiers, or shift to choose the number of reagent to craft | 
| contrebasse@98 | 128 	if IsModifierKeyDown() and not IsShiftKeyDown() then return end | 
| contrebasse@98 | 129 	local chooseNumberToCraft = IsShiftKeyDown() | 
| contrebasse@98 | 130 | 
| contrebasse@98 | 131 	-- Index of the reagent in the recipe, taken from the button name | 
| contrebasse@98 | 132 	local reagentRecipeIndex = A.buttonNumber(btn) | 
| contrebasse@98 | 133 | 
| contrebasse@98 | 134 	-- ID of the reagent we want to craft | 
| contrebasse@98 | 135 	local recipeIndex = GetTradeSkillSelectionIndex() | 
| contrebasse@98 | 136 	local reagentID = A.link2ID(GetTradeSkillReagentItemLink(recipeIndex, reagentRecipeIndex)) | 
| contrebasse@98 | 137 | 
| contrebasse@98 | 138 	-- Continue only if the reagent is known | 
| contrebasse@98 | 139 	if not reagentID or not A.data[reagentID] then return end | 
| contrebasse@98 | 140 | 
| contrebasse@98 | 141 	-- If only one recipe is known for the reagent, use it | 
| contrebasse@98 | 142 	if #(A.data[reagentID]) == 1 and not A.data[reagentID][1].macro then | 
| contrebasse@98 | 143 		if A.data[reagentID][1].spellName and A.data[reagentID][1].spellName ~= GetTradeSkillLine() then | 
| contrebasse@98 | 144 			A.Error(A.L["The recipe to make this reagent is in another tradeskill. Currently ReagentMaker can not manage such a case, sorry."]) | 
| contrebasse@98 | 145 			return | 
| contrebasse@98 | 146 		end | 
| contrebasse@98 | 147 | 
| contrebasse@108 | 148 		local reagentIndex = A.findSkillIndex(reagentID) -- finds only the first recipe that creates the reagent, should check recipe name too | 
| contrebasse@98 | 149 | 
| contrebasse@98 | 150 		-- Try to show the recipe by removing filters once if it was not found | 
| contrebasse@98 | 151 		if not reagentIndex then | 
| contrebasse@98 | 152 			A.SaveActiveFilters(A.data[reagentID][1].header) | 
| contrebasse@108 | 153 			reagentIndex = A.findSkillIndex(reagentID) | 
| contrebasse@108 | 154 		end | 
| contrebasse@108 | 155 		if not reagentIndex then | 
| contrebasse@108 | 156 			A.Error(A.L["The recipe to make the reagent seems to be hidden, it is not makable. Try to remove the filters on the recipes."]) | 
| contrebasse@108 | 157 			A.RestoreActiveFilters() | 
| contrebasse@108 | 158 			return | 
| contrebasse@98 | 159 		end | 
| contrebasse@98 | 160 | 
| contrebasse@108 | 161 		local numMakable = A.numMakable(reagentID) | 
| contrebasse@98 | 162 		if not numMakable then | 
| contrebasse@108 | 163 			A.Error(A.L["There was a problem while retrieving informations, please retry."]) | 
| contrebasse@107 | 164 			A.RestoreActiveFilters() | 
| contrebasse@98 | 165 			return | 
| contrebasse@98 | 166 		end | 
| contrebasse@98 | 167 		if numMakable>0 then | 
| contrebasse@98 | 168 			A.craft(recipeIndex,reagentRecipeIndex,reagentIndex,numMakable,chooseNumberToCraft) | 
| contrebasse@107 | 169 			A.RestoreActiveFilters() | 
| contrebasse@98 | 170 			return | 
| contrebasse@98 | 171 		end | 
| contrebasse@98 | 172 | 
| contrebasse@98 | 173 		-- If we can make the item needed to make the reagent, open a window to make it | 
| contrebasse@98 | 174 		-- one step recursion, enables to mill to create an ink | 
| contrebasse@98 | 175 		if A.data[reagentID][1][1] and A.data[A.data[reagentID][1][1]] then | 
| contrebasse@98 | 176 			if A.externalCraftWindow(A.data[reagentID][1][1],reagentID) ~= false then | 
| contrebasse@107 | 177 				A.RestoreActiveFilters() | 
| contrebasse@98 | 178 				return | 
| contrebasse@98 | 179 			end | 
| contrebasse@98 | 180 		end | 
| contrebasse@98 | 181 | 
| contrebasse@98 | 182 		A.Error(A.L["You do not have enough reagents to craft [%s]"]:format(GetItemInfo(reagentID) or "item #"..reagentID)) | 
| contrebasse@107 | 183 		A.RestoreActiveFilters() | 
| contrebasse@98 | 184 		return | 
| contrebasse@98 | 185 	else | 
| contrebasse@98 | 186 		A.externalCraftWindow(reagentID) | 
| contrebasse@98 | 187 	end -- if | 
| contrebasse@98 | 188 	--A.RestoreActiveFilters() | 
| contrebasse@98 | 189 end -- function | 
| contrebasse@98 | 190 | 
| contrebasse@98 | 191 | 
| contrebasse@98 | 192 --------------------------------------------------- | 
| contrebasse@98 | 193 -- Craft items | 
| contrebasse@98 | 194 --------------------------------------------------- | 
| contrebasse@98 | 195 -- function used after choosing the number of reagent to craft | 
| contrebasse@98 | 196 function A.SplitStack(owner,split) | 
| contrebasse@98 | 197 	DoTradeSkill(owner.ReagentMaker_reagentIndex,tonumber(split)) | 
| contrebasse@98 | 198 	owner.ReagentMaker_reagentIndex = nil | 
| contrebasse@98 | 199 end | 
| contrebasse@98 | 200 | 
| contrebasse@98 | 201 -- Craft the reagent of an item, given it's position in the recipe | 
| contrebasse@98 | 202 function A.craft(recipeIndex,reagentRecipeIndex,reagentIndex,numReagentMakable,chooseNumber) | 
| contrebasse@98 | 203 	-- Look at how many we need to make one item for the selected recipe | 
| contrebasse@98 | 204 	local numToMake = 1 | 
| contrebasse@98 | 205 	local _, _, reagentCount, playerReagentCount = GetTradeSkillReagentInfo(recipeIndex, reagentRecipeIndex) | 
| contrebasse@98 | 206 	-- make enough reagents to craft one more item | 
| contrebasse@98 | 207 	numToMake = math.min(math.floor(playerReagentCount/reagentCount+1)*reagentCount-playerReagentCount,numReagentMakable) | 
| contrebasse@98 | 208 | 
| contrebasse@98 | 209 	-- take into account that some recipe craft more than one item | 
| contrebasse@98 | 210 	-- use the mean between min and max, but make at least one... | 
| contrebasse@98 | 211 	local minMade, maxMade = GetTradeSkillNumMade(reagentIndex) | 
| contrebasse@98 | 212 	numToMake = math.max(math.floor(2*numToMake/(maxMade+minMade)),1) | 
| contrebasse@101 | 213 | 
| contrebasse@98 | 214 	-- Choose number or craft directly | 
| contrebasse@98 | 215 	if chooseNumber then | 
| contrebasse@98 | 216 		-- the dialog window is linked to the reagent button | 
| contrebasse@98 | 217 		local btn = _G["TradeSkillReagent"..reagentRecipeIndex] | 
| contrebasse@98 | 218 | 
| contrebasse@98 | 219 		-- Store info to be able to run the function later | 
| contrebasse@98 | 220 		btn.ReagentMaker_reagentIndex = reagentIndex | 
| contrebasse@98 | 221 | 
| contrebasse@98 | 222 		-- Open dialog | 
| contrebasse@98 | 223 		OpenStackSplitFrame(numReagentMakable, btn, "TOP", "BOTTOM") | 
| contrebasse@98 | 224 | 
| contrebasse@98 | 225 		-- Fill in the number to make | 
| contrebasse@98 | 226 		numToMake = tostring(numToMake) | 
| contrebasse@98 | 227 		for i = 1,numToMake:len() do | 
| contrebasse@98 | 228 			StackSplitFrame_OnChar(StackSplitFrame,numToMake:gsub(i,i)) | 
| contrebasse@98 | 229 		end | 
| contrebasse@98 | 230 		StackSplitFrame.typing = 0 -- reinit the frame so tha the entered value will be erased on text entry | 
| contrebasse@98 | 231 	else | 
| contrebasse@98 | 232 		DoTradeSkill(reagentIndex,numToMake) | 
| contrebasse@98 | 233 	end -- if | 
| contrebasse@98 | 234 end -- function | 
| contrebasse@98 | 235 | 
| contrebasse@98 | 236 | 
| contrebasse@98 | 237 -- Button hovering | 
| contrebasse@98 | 238 function A.btnEntered(btn) | 
| contrebasse@98 | 239 	-- Do not manage guild tradeskill | 
| contrebasse@98 | 240 	if IsTradeSkillGuild() or IsTradeSkillLinked() then return end | 
| contrebasse@98 | 241 | 
| contrebasse@98 | 242 	-- Index of the reagent in the recipe, taken from the button name | 
| contrebasse@98 | 243 	local reagentRecipeIndex = A.buttonNumber(btn) | 
| contrebasse@98 | 244 | 
| contrebasse@98 | 245 	-- ID of the reagent we want to craft | 
| contrebasse@98 | 246 	local reagentLink = GetTradeSkillReagentItemLink(GetTradeSkillSelectionIndex(), reagentRecipeIndex) | 
| contrebasse@98 | 247 	local reagentID = A.link2ID(reagentLink) | 
| contrebasse@98 | 248 | 
| contrebasse@98 | 249 	-- Continue only if the reagent is known | 
| contrebasse@98 | 250 	if not reagentID or not A.data[reagentID] then return end | 
| contrebasse@98 | 251 | 
| contrebasse@98 | 252 	btn.textureHighlight:Show() | 
| contrebasse@98 | 253 | 
| contrebasse@98 | 254 	-- Check if the item is made by only one recipe. If not, return | 
| contrebasse@98 | 255 	if not A.isRecipeUnique(A.data[reagentID]) then return end | 
| contrebasse@98 | 256 | 
| contrebasse@98 | 257 	-- Tooltips | 
| contrebasse@98 | 258 	local link = A.data[reagentID][1].spellLink | 
| contrebasse@98 | 259 	if link then | 
| contrebasse@98 | 260 		A.tooltipRecipe:SetOwner(btn) | 
| contrebasse@98 | 261 		A.tooltipRecipe:SetHyperlink(link) | 
| contrebasse@98 | 262 		A.tooltipRecipe:Show() | 
| contrebasse@98 | 263 		A.tooltipRecipe:ClearAllPoints() | 
| contrebasse@98 | 264 		A.tooltipRecipe:SetPoint("BOTTOMLEFT",GameTooltip,"BOTTOMRIGHT") | 
| contrebasse@98 | 265 	end | 
| contrebasse@98 | 266 end | 
| contrebasse@98 | 267 | 
| contrebasse@98 | 268 function A.btnLeft(btn) | 
| contrebasse@98 | 269 	btn.textureHighlight:Hide() | 
| contrebasse@98 | 270 	A.tooltipRecipe:Hide() | 
| contrebasse@98 | 271 end -- function | 
| contrebasse@98 | 272 | 
| contrebasse@98 | 273 function A.updateCounts(recipeIndex) | 
| contrebasse@98 | 274 	-- Needs an argument | 
| contrebasse@98 | 275 	if not recipeIndex then return end | 
| contrebasse@98 | 276 | 
| contrebasse@98 | 277 	-- Do not manage guild tradeskill | 
| contrebasse@98 | 278 	if IsTradeSkillGuild() or IsTradeSkillLinked() then | 
| contrebasse@98 | 279 		for reagentRecipeIndex = 1,GetTradeSkillNumReagents(recipeIndex) do | 
| contrebasse@98 | 280 			-- If the normal tradeskill hasn't been opened yet, the field 'label' doesn't exists yet | 
| contrebasse@98 | 281 			local label = _G["TradeSkillReagent"..reagentRecipeIndex].label | 
| contrebasse@98 | 282 			if label then | 
| contrebasse@98 | 283 				label:Hide() | 
| contrebasse@98 | 284 			end | 
| contrebasse@98 | 285 		end | 
| contrebasse@98 | 286 		return | 
| contrebasse@98 | 287 	end | 
| contrebasse@98 | 288 | 
| contrebasse@98 | 289 	-- Count makable items and show it | 
| contrebasse@98 | 290 	for reagentRecipeIndex = 1,GetTradeSkillNumReagents(recipeIndex) do | 
| contrebasse@98 | 291 		-- ID of the reagent we want to craft | 
| contrebasse@98 | 292 		local reagentLink = GetTradeSkillReagentItemLink(recipeIndex, reagentRecipeIndex) | 
| contrebasse@98 | 293 		local reagentID = A.link2ID(reagentLink) | 
| contrebasse@98 | 294 | 
| contrebasse@98 | 295 		local label = _G["TradeSkillReagent"..reagentRecipeIndex].label | 
| contrebasse@98 | 296 		if not label then break end -- Shouldn't happen... | 
| contrebasse@98 | 297 | 
| contrebasse@98 | 298 		-- Continue only if the reagent is known | 
| contrebasse@98 | 299 		if not reagentID or not A.data[reagentID] then | 
| contrebasse@98 | 300 			label:Hide() | 
| contrebasse@98 | 301 		else | 
| contrebasse@98 | 302 			-- Count and show | 
| contrebasse@98 | 303 			local numMakable = A.numMakable(reagentID) | 
| contrebasse@108 | 304 			--if not numMakable or #(A.data[reagentID]) ~= 1 or A.data[reagentID][1].macro then | 
| contrebasse@108 | 305 			if not numMakable then | 
| contrebasse@98 | 306 				label:SetText("?") | 
| contrebasse@98 | 307 				label:SetTextColor(0, 0.5, 1, 1) -- blue | 
| contrebasse@98 | 308 			else | 
| contrebasse@98 | 309 				label:SetText(numMakable) | 
| contrebasse@98 | 310 				if numMakable==0 then | 
| contrebasse@98 | 311 					label:SetTextColor(1, 0, 0, 1) -- red | 
| contrebasse@98 | 312 				else | 
| contrebasse@98 | 313 					label:SetTextColor(0, 1, 0, 1) -- green | 
| contrebasse@98 | 314 				end | 
| contrebasse@98 | 315 			end -- if | 
| contrebasse@98 | 316 			label:Show() | 
| contrebasse@98 | 317 		end -- if | 
| contrebasse@98 | 318 	end -- for | 
| contrebasse@98 | 319 end -- function | 
| contrebasse@98 | 320 hooksecurefunc("SelectTradeSkill",A.updateCounts) |