Quantcast

Modified the way recipes are stored to be more memory-efficient. Alpha code. You have been warned.

pschifferer [11-24-09 - 02:49]
Modified the way recipes are stored to be more memory-efficient.  Alpha code.  You have been warned.
Filename
CauldronMain.lua
CauldronMainUI.lua
CauldronQueue.lua
CauldronTradeskill.lua
diff --git a/CauldronMain.lua b/CauldronMain.lua
index ac0e6da..dedf76d 100644
--- a/CauldronMain.lua
+++ b/CauldronMain.lua
@@ -40,6 +40,7 @@ function Cauldron:OnInitialize()
 		},
 		global = {
 			difficulty = {}, -- Stores at what level difficulty is changed for all recipes.
+			recipes = {}, -- Stores the global list of recipes.
 		}
 	}

@@ -169,6 +170,69 @@ function Cauldron:InitPlayer()
 		end
 	end

+	-- check if the skill database needs to be moved to the new location
+	if not self.db.global.recipes then
+		self.db.global.recipes = {};
+	end
+	-- iterate over each skill for this character
+	for skillName,skillList in pairs(self.db.realm.userdata[self.vars.playername].skills) do
+		-- skip linked tradeskills
+		if not (string.find(skillName, "Linked-")) then
+			-- create the table for the skill
+			if not self.db.global.recipes[skillName] then
+				self.db.global.recipes[skillName] = {};
+			end
+
+			-- iterate over each recipe in the skill
+			for recipeName,recipeInfo in pairs(skillList.recipes) do
+				-- check if the recipe is in not the global list
+				if not self.db.global.recipes[skillName][recipeName] then
+					if recipeInfo.itemLink then
+						-- copy it to the global list
+						self.db.global.recipes[skillName][recipeName] = CopyTable(recipeInfo);
+
+						-- check if we need to reduce this recipe info to character-specific only
+						skillList.recipes[recipeName] = {
+							["index"] = recipeInfo.index,
+							["tradeskill"] = recipeInfo.tradeskill,
+							["difficulty"] = recipeInfo.difficulty,
+							["categories"] = recipeInfo.categories or "",
+							["minMade"] = recipeInfo.minMade,
+							["maxMade"] = recipeInfo.maxMade,
+							["available"] = recipeInfo.available,
+							["reagents"] = {},
+						};
+
+						-- copy reagent skill indexes
+						for _,r in ipairs(recipeInfo.reagents) do
+							table.insert(skillList.recipes[recipeName].reagents, {
+								skillIndex = r.skillIndex,
+							});
+						end
+					end
+				end
+			end
+		end
+	end
+
+	if not self.db.global.reagentMap then
+		self.db.global.reagentMap = {};
+	end
+	-- iterate over the reagent map for this character
+	if self.db.realm.userdata[self.vars.playername].reagentMap then
+		for recipeName,reagentList in pairs(self.db.realm.userdata[self.vars.playername].reagentMap) do
+			if not self.db.global.reagentMap[recipeName] then
+				self.db.global.reagentMap[recipeName] = {};
+			end
+			for _,info in ipairs(reagentList) do
+				-- add to the global table
+				table.insert(self.db.global.reagentMap[recipeName], info);
+			end
+		end
+		-- remove the character-local reagent map
+		self.db.realm.userdata[self.vars.playername].reagentMap = nil;
+	end
+
 --@alpha@
 	self:debug("InitPlayer exit");
 --@end-alpha@
@@ -624,6 +688,7 @@ function Cauldron:GetSelectedSkill()
 --@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
+	local baseSkillName = skillName;
 	if IsTradeSkillLinked() then
 		skillName = "Linked-"..skillName;
 	end
@@ -637,7 +702,7 @@ function Cauldron:GetSelectedSkill()

 	for name, info in pairs(self.db.realm.userdata[self.vars.playername].skills[skillName].recipes) do
 		if selected == info.index then
-			return info;
+			return self.db.global.recipes[baseSkillName][name];
 		end
 	end

@@ -654,9 +719,10 @@ function Cauldron:QueueAllTradeSkillItem()
 --@end-alpha@

 	local skillInfo = Cauldron:GetSelectedSkill();
+	local skillData = Cauldron:GetSkillDataForSkill(skillInfo);

-	if skillInfo then
-		local amount = skillInfo.available;
+	if skillInfo and skillData then
+		local amount = skillData.available;
 		local potential = Cauldron:GetPotentialCraftCount(skillInfo);
 		local queueAmount = 0;

@@ -722,10 +788,11 @@ function Cauldron:CreateAllTradeSkillItem()
 		CauldronAmountInputBox:ClearFocus();

 		local skillInfo = Cauldron:GetSelectedSkill();
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);

-		CauldronAmountInputBox:SetNumber(skillInfo.available);
+		CauldronAmountInputBox:SetNumber(skillData.available);

-		DoTradeSkill(skillInfo.index, skillInfo.available);
+		DoTradeSkill(skillData.index, skillData.available);
 	end

 --@alpha@
@@ -743,8 +810,9 @@ function Cauldron:CreateTradeSkillItem()

 		local skillInfo = Cauldron:GetSelectedSkill();
 		local amount = CauldronAmountInputBox:GetNumber();
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);

-		DoTradeSkill(skillInfo.index, amount);
+		DoTradeSkill(skillData.index, amount);
 	end

 --@alpha@
@@ -778,11 +846,12 @@ function Cauldron:ProcessQueue()
 		queueInfo = queue[1];
 		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
 		skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
 		self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));

-		if skillInfo.available > 0 then
-			self:debug("First item in main queue can be made "..skillInfo.available.." times");
-			self:SubmitItemToProcess(queueInfo, skillInfo, math.min(skillInfo.available, queueInfo.amount));
+		if skillData.available > 0 then
+			self:debug("First item in main queue can be made "..skillData.available.." times");
+			self:SubmitItemToProcess(queueInfo, skillInfo, math.min(skillData.available, queueInfo.amount));
 			return;
 --[[		else
 			-- see if queue contains other items that can be made if the first can't be
@@ -792,7 +861,7 @@ function Cauldron:ProcessQueue()
 					skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
 					self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));

-					if skillInfo.available > 0 then
+					if skillData.available > 0 then
 						-- present dialog to user to move item to top of queue
 						Cauldron:ConfirmDialog(L["Confirm"], L["message"],
 							L["Okay"],
@@ -885,7 +954,8 @@ function Cauldron:ProcessItem(skillInfo, queueInfo, amount)
 		self:Print(string.format(L["Crafting %1$d of %2$s..."], amount, self.makingItem));

 		-- do it
-		DoTradeSkill(skillInfo.index, amount);
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
+		DoTradeSkill(skillData.index, amount);
 	else
 		-- TODO: notify player?
 	end
@@ -1023,16 +1093,17 @@ function Cauldron:AddToTooltip(tooltip, id)
 					favInfo = " ";
 				end
 				local skillInfo = Cauldron:GetSkillInfoForLink(skillLink);
+				local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
 				local color;
 				if TradeSkillTypeColor then
-					color = TradeSkillTypeColor[skillInfo.difficulty];
+					color = TradeSkillTypeColor[skillData.difficulty];
 				else
 					local colorMap = {
 						optimal = {r=1.0, g=0.5, b=0.25},
 						medium = {r=1.0, g=1.0, b=0.0},
 						easy = {r=0.25, g=0.75, b=0.25},
 					};
-					color = colorMap[skillInfo.difficulty];
+					color = colorMap[skillData.difficulty];
 				end
 				local colorStr = "|r";
 				if color then
@@ -1059,9 +1130,10 @@ function Cauldron:AddToTooltip(tooltip, id)
 					levelInfo = " ";
 				end
 				local skillInfo = Cauldron:GetSkillInfoForLink(skillLink);
+				local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
 				local color;
 				if TradeSkillTypeColor then
-					color = TradeSkillTypeColor[skillInfo.difficulty];
+					color = TradeSkillTypeColor[skillData.difficulty];
 --				else
 --					color = {r=1.0, g=1.0, b=1.0};
 				end
@@ -1119,9 +1191,10 @@ function filterSkillups(skillList)
 	for i,skill in ipairs(skillList) do
 		local skillName, skillLink = string.split(";", skill, 2);
 		local skillInfo = Cauldron:GetSkillInfoForLink(skillLink);
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);

-		if skillInfo then
-			if difficulty[skillInfo.difficulty] > 1 then
+		if skillInfo and skillData then
+			if difficulty[skillData.difficulty] > 1 then
 				table.insert(skillups, skill);
 			end
 		end
@@ -1350,6 +1423,8 @@ end
 			["<reagent name>"] = <amount>,
 		},
 	},
+	["global"] = {
+	},

 --]]

diff --git a/CauldronMainUI.lua b/CauldronMainUI.lua
index a0306f0..58b5bc6 100644
--- a/CauldronMainUI.lua
+++ b/CauldronMainUI.lua
@@ -274,6 +274,8 @@ function Cauldron:UpdateSkillList()
 		--@alpha@
 		self:debug("UpdateSkillList: i="..i);
 		--@end-alpha@
+
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);

 		local skillFrame = _G["CauldronSkillItem"..i];

@@ -317,10 +319,10 @@ function Cauldron:UpdateSkillList()
 		end

 		skillFrame:SetID(i);
-		skillFrame.skillIndex = skillInfo.index;
+		skillFrame.skillIndex = skillData.index;

 		-- set selection
-		if self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected == skillInfo.index then
+		if self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected == skillData.index then
 			_G["CauldronSkillItem"..i.."Selection"]:Show();
 		else
 			_G["CauldronSkillItem"..i.."Selection"]:Hide();
@@ -333,10 +335,10 @@ function Cauldron:UpdateSkillList()
 		frame = _G["CauldronSkillItem"..i.."SkillName"];
 		local nameText = skillInfo.name;
 		local potentialCount = Cauldron:GetPotentialCraftCount(skillInfo);
-		if (potentialCount > 0) and (potentialCount > skillInfo.available) then
-			nameText = nameText.." ["..skillInfo.available.."/"..potentialCount.."]";
-		elseif skillInfo.available > 0 then
-			nameText = nameText.." ["..skillInfo.available.."]";
+		if (potentialCount > 0) and (potentialCount > skillData.available) then
+			nameText = nameText.." ["..skillData.available.."/"..potentialCount.."]";
+		elseif skillData.available > 0 then
+			nameText = nameText.." ["..skillData.available.."]";
 		end
 		local achievements = Cauldron:GetAchievementsForSkill(skillInfo);
 		if achievements and #achievements > 0 then
@@ -344,7 +346,7 @@ function Cauldron:UpdateSkillList()
 		end
 		frame:SetText(nameText);
 		if TradeSkillTypeColor then
-			local color = TradeSkillTypeColor[skillInfo.difficulty];
+			local color = TradeSkillTypeColor[skillData.difficulty];
 			if color then
 				frame:SetFontObject(color.font);
 				frame.r = color.r;
@@ -367,10 +369,11 @@ function Cauldron:UpdateSkillList()
 		frame = _G["CauldronSkillItem"..i.."FavoriteButton"];
 		frame:SetChecked(self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite);
 		frame.skillInfo = skillInfo;
+		frame.skillData = skillData;

 		-- set cooldown
 		frame = _G["CauldronSkillItem"..i.."SkillCooldown"];
-		local cooldown = GetTradeSkillCooldown(skillInfo.index);
+		local cooldown = GetTradeSkillCooldown(skillData.index);
 		if cooldown then
 			if not frame:IsVisible() then
 				frame:Show();
@@ -386,7 +389,7 @@ function Cauldron:UpdateSkillList()
 		frame = _G["CauldronSkillItem"..i.."SkillIcon"];
 		frame:SetNormalTexture(skillInfo.icon);
 		frame.itemLink = skillInfo.link;
-		frame.skillIndex = skillInfo.index;
+		frame.skillIndex = skillData.index;

 		--[[
 		frame = _G["CauldronSkillItem"..i.."SkillNameTooltipFrame"];
@@ -395,7 +398,7 @@ function Cauldron:UpdateSkillList()

 		-- set the craft count
 		frame = _G["CauldronSkillItem"..i.."SkillIconCount"];
-		local minMade, maxMade = skillInfo.minMade, skillInfo.maxMade;
+		local minMade, maxMade = skillData.minMade, skillData.maxMade;
 		if maxMade > 1 then
 			if minMade == maxMade then
 				frame:SetText(minMade);
@@ -412,33 +415,34 @@ function Cauldron:UpdateSkillList()
 		-- set the disclosure button texture
 		frame = _G["CauldronSkillItem"..i.."DiscloseButton"];
 		frame.skillInfo = skillInfo;
---@alpha@
+		frame.skillData = skillData;
+		--@alpha@
 		self:debug("UpdateSkillList: skillInfo.name="..skillInfo.name);
---@end-alpha@
+		--@end-alpha@
 		local reagentsExpanded = self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
---@alpha@
+		--@alpha@
 		self:debug("UpdateSkillList: reagentsExpanded="..tostring(reagentsExpanded));
---@end-alpha@
+		--@end-alpha@
 		if reagentsExpanded then
 			frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");

 			_G["CauldronSkillItem"..i.."Reagents"]:Show();

 			-- fill in the tools info
-			local spellFocus = BuildColoredListString(GetTradeSkillTools(skillInfo.index));
+			local spellFocus = BuildColoredListString(GetTradeSkillTools(skillData.index));
 			local toolsFrame = _G["CauldronSkillItem"..i.."ReagentsToolsInfo"];
 			if spellFocus then
---@alpha@
+				--@alpha@
 				self:debug("UpdateSkillList: skill has a spell focus");
---@end-alpha@
+				--@end-alpha@

 				toolsFrame:Show();
 				toolsFrame:SetText(L["Requires"]..": "..spellFocus);
 				toolsFrame:SetHeight(15);
 			else
---@alpha@
+				--@alpha@
 				self:debug("UpdateSkillList: skill doesn't have a spell focus");
---@end-alpha@
+				--@end-alpha@

 				toolsFrame:Hide();
 				toolsFrame:SetText("");
@@ -460,7 +464,7 @@ function Cauldron:UpdateSkillList()
 				else
 					local reagentInfo = reagents[j];

-					reagentFrame.skillIndex = skillInfo.index;
+					reagentFrame.skillIndex = skillData.index;
 					reagentFrame.reagentIndex = reagentInfo.index;
 					reagentFrame.link = reagentInfo.link;

@@ -713,6 +717,7 @@ function Cauldron:UpdateQueue()
 		_G["CauldronQueueItem"..i.."AddToShoppingList"]:SetScale(0.5);

 		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
 		if not skillInfo then
 			-- the skill isn't available (character doesn't know it?)
 			self:warn("No skill available for "..queueInfo.name.." ("..queueInfo.tradeskill..")");
@@ -727,12 +732,12 @@ function Cauldron:UpdateQueue()
 		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
 		--@end-alpha@
 		local nameText = queueInfo.name;
-		if skillInfo and (skillInfo.available > 0) then
-			nameText = nameText.." ["..skillInfo.available.."]";
+		if skillInfo and (skillData.available > 0) then
+			nameText = nameText.." ["..skillData.available.."]";
 		end
 		frame:SetText(nameText);
-		if skillInfo then
-			local color = TradeSkillTypeColor[skillInfo.difficulty];
+		if skillInfo and skillData then
+			local color = TradeSkillTypeColor[skillData.difficulty];
 			if color then
 				frame:SetFontObject(color.font);
 				frame:SetTextColor(color.r, color.g, color.b, 1.0);
@@ -758,31 +763,31 @@ function Cauldron:UpdateQueue()

 		-- set the icon
 		frame = _G["CauldronQueueItem"..i.."Icon"];
---@alpha@
+		--@alpha@
 		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
---@end-alpha@
+		--@end-alpha@
 		frame:SetNormalTexture(queueInfo.icon);
 		frame.link = queueInfo.link;

 		-- set the amount
 		frame = _G["CauldronQueueItem"..i.."IconCount"];
---@alpha@
+		--@alpha@
 		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
---@end-alpha@
+		--@end-alpha@
 		frame:SetText(queueInfo.amount);

 		-- place the frame in the scroll view
 		if i > 1 then
 			-- anchor to the frame above
---@alpha@
+			--@alpha@
 			self:debug("UpdateQueue: anchor frame to top left of frame above");
---@end-alpha@
+			--@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueItem"..(i-1)], "BOTTOMLEFT", 0, 0);
 		else
 			-- anchor to the parent
---@alpha@
+			--@alpha@
 			self:debug("UpdateQueue: anchor frame to parent");
---@end-alpha@
+			--@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsMainItems, "TOPLEFT", 0, 0);
 		end

@@ -790,9 +795,9 @@ function Cauldron:UpdateQueue()
 --		self:debug("UpdateQueue: height="..height);

 		-- show the frame
---@alpha@
+		--@alpha@
 		self:debug("UpdateQueue: show the frame");
---@end-alpha@
+		--@end-alpha@
 		queueItemFrame:Show();
 	end

@@ -825,9 +830,9 @@ function Cauldron:UpdateQueue()

 	-- display intermediate queue, maybe
 	if #intQueue == 0 then
---@alpha@
+		--@alpha@
 		self:debug("UpdateQueue: intermediate queue is empty, hide header and item frames");
---@end-alpha@
+		--@end-alpha@
 		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:SetHeight(1);
 		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeaderText:SetText("");
 		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(1);
@@ -840,9 +845,9 @@ function Cauldron:UpdateQueue()
 		local intHeight = 0;

 		for i, queueInfo in ipairs(intQueue) do
---@alpha@
+			--@alpha@
 			self:debug("intQueue: name="..queueInfo.name);
---@end-alpha@
+			--@end-alpha@

 			local queueItemFrame = _G["CauldronQueueIntItem"..i];

@@ -878,6 +883,7 @@ function Cauldron:UpdateQueue()
 			_G["CauldronQueueIntItem"..i.."AddToShoppingList"]:SetScale(0.5);

 			local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+			local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
 			if not skillInfo then
 				-- the skill isn't available (character doesn't know it?)
 				-- TODO
@@ -892,13 +898,13 @@ function Cauldron:UpdateQueue()
 			-- set name and difficulty color
 			frame = _G["CauldronQueueIntItem"..i.."ItemName"];
 			local nameText = queueInfo.name;
-			if skillInfo then
-				if (skillInfo.available > 0) then
-					nameText = nameText.." ["..skillInfo.available.."]";
+			if skillInfo and skillData then
+				if (skillData.available > 0) then
+					nameText = nameText.." ["..skillData.available.."]";
 				end
 				frame:SetText(nameText);

-				local color = TradeSkillTypeColor[skillInfo.difficulty];
+				local color = TradeSkillTypeColor[skillData.difficulty];
 				if color then
 					frame:SetFontObject(color.font);
 					frame:SetTextColor(color.r, color.g, color.b, 1.0);
@@ -943,15 +949,15 @@ function Cauldron:UpdateQueue()
 			-- place the frame in the scroll view
 			if i > 1 then
 				-- anchor to the frame above
---@alpha@
+				--@alpha@
 				self:debug("UpdateQueue: anchor frame to top left of frame above");
---@end-alpha@
+				--@end-alpha@
 				queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueIntItem"..(i-1)], "BOTTOMLEFT", 0, 0);
 			else
 				-- anchor to the parent
---@alpha@
+				--@alpha@
 				self:debug("UpdateQueue: anchor frame to parent");
---@end-alpha@
+				--@end-alpha@
 				queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems, "TOPLEFT", 0, 0);
 			end

@@ -961,9 +967,9 @@ function Cauldron:UpdateQueue()
 --			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(intHeight);

 			-- show the frame
---@alpha@
+			--@alpha@
 			self:debug("UpdateQueue: show the frame");
---@end-alpha@
+			--@end-alpha@
 			queueItemFrame:Show();
 		end
 	end
@@ -996,9 +1002,9 @@ function Cauldron:UpdateQueue()
 	local reagentHeight = 0;

 	for i, queueInfo in ipairs(reagentList) do
---@alpha@
+		--@alpha@
 		self:debug("reagentList: "..queueInfo.name);
---@end-alpha@
+		--@end-alpha@

 		local queueItemFrame = _G["CauldronQueueReagentItem"..i];

@@ -1040,6 +1046,7 @@ function Cauldron:UpdateQueue()
 		_G["CauldronQueueReagentItem"..i.."AddToShoppingList"]:SetScale(0.5);

 		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
 		if not skillInfo then
 			-- TODO
 		end
@@ -1092,15 +1099,15 @@ function Cauldron:UpdateQueue()
 		-- place the frame in the scroll view
 		if i > 1 then
 			-- anchor to the frame above
---@alpha@
+			--@alpha@
 			self:debug("UpdateQueue: anchor frame to top left of frame above");
---@end-alpha@
+			--@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueReagentItem"..(i-1)], "BOTTOMLEFT", 0, 0);
 		else
 			-- anchor to the parent
---@alpha@
+			--@alpha@
 			self:debug("UpdateQueue: anchor frame to parent");
---@end-alpha@
+			--@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsReagents, "TOPLEFT", 0, 0);
 		end

@@ -1110,9 +1117,9 @@ function Cauldron:UpdateQueue()
 --		CauldronQueueFrameScrollFrameQueueSectionsReagents:SetHeight(reagentHeight);

 		-- show the frame
---@alpha@
+		--@alpha@
 		self:debug("UpdateQueue: show the frame");
---@end-alpha@
+		--@end-alpha@
 		queueItemFrame:Show();
 	end

@@ -1146,27 +1153,27 @@ function Cauldron:UpdateQueue()
 	CauldronQueueFrameScrollFrameQueueSections:SetHeight(h);
 	CauldronQueueFrameScrollFrame:UpdateScrollChildRect();

---@alpha@
+	--@alpha@
 	self:debug("UpdateQueue exit");
---@end-alpha@
+	--@end-alpha@
 end

 function Cauldron:SaveFramePosition()
---@alpha@
+	--@alpha@
  	self:debug("SaveFramePosition enter");
---@end-alpha@
+	--@end-alpha@

 -- TODO

---@alpha@
+	--@alpha@
  	self:debug("SaveFramePosition exit");
---@end-alpha@
+	--@end-alpha@
 end

 function Cauldron:OnCauldronUpdate()
---@alpha@
+	--@alpha@
 	self:debug("OnCauldronUpdate enter");
---@end-alpha@
+	--@end-alpha@

 	--[[
 --	self:Search();
@@ -1178,15 +1185,15 @@ function Cauldron:OnCauldronUpdate()
  	end
  	--]]

---@alpha@
+	--@alpha@
 	self:debug("OnCauldronUpdate exit");
---@end-alpha@
+	--@end-alpha@
 end

 function Cauldron:FilterDropDown_OnLoad(dropdown)
---@alpha@
+	--@alpha@
 	self:debug("FilterDropDown_OnLoad enter");
---@end-alpha@
+	--@end-alpha@

 --[[
 	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
@@ -1197,9 +1204,9 @@ function Cauldron:FilterDropDown_OnLoad(dropdown)
 	UIDropDownMenu_Initialize(dropdown, Cauldron.FilterDropDown_Initialize);
 	UIDropDownMenu_SetText(CauldronFiltersFilterDropDown, L["Filters"]);

---@alpha@
+	--@alpha@
 	self:debug("FilterDropDown_OnLoad exit");
---@end-alpha@
+	--@end-alpha@
 end

 function Cauldron:InvSlotDropDown_OnLoad(dropdown)
@@ -2071,9 +2078,10 @@ function Cauldron:CollapseItemButton_OnClick(button)
 	end

 	local skillInfo = button.skillInfo;
+	local skillData = Cauldron:GetSkillDataForSkill(skillInfo);

 	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = skillInfo.index;
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = skillData.index;

 	-- update the UI
 	Cauldron:UpdateSkillList();
diff --git a/CauldronQueue.lua b/CauldronQueue.lua
index 8059500..0c7eac3 100644
--- a/CauldronQueue.lua
+++ b/CauldronQueue.lua
@@ -104,7 +104,8 @@ function CauldronQueue:GetIntermediates(queue)
 --		else
 			local t = CopyTable(item);
 			local skillInfo = Cauldron:GetSkillInfo(t.tradeskill, t.name);
-			if skillInfo and (skillInfo.available > 0) then
+			local skillData = Cauldron:GetSkillDataForSkill(skillInfo);
+			if skillInfo and skillData and (skillData.available > 0) then
 				-- increase the priority of items that can be crafted, so that they appear at the top of the list
 				t.priority = t.priority + 1000;
 			end
@@ -229,14 +230,15 @@ function CauldronQueue:CalculateRequiredItems(queue, skillInfo, amount, priority
 			if amount > 0 then
 				-- adjust the amount if the item produces more than one per execution
 				local intSkillInfo = Cauldron:GetSkillInfoForItem(reagent.name);
-				if intSkillInfo then
-					if intSkillInfo.minMade > 1 then
+				local intSkillData = Cauldron:GetSkillDataForSkill(intSkillInfo);
+				if intSkillInfo and intSkillData then
+					if intSkillData.minMade > 1 then
 						-- we ignore maxMade, since if it is greater than minMade, then the amount
 						-- produced is variable, so we err on the side of caution and account for
 						-- only ever making the minimum possible; besides, each execution of the
 						-- skill will cause the reagent list to be reassessed, so producing more
 						-- will be handled appropriately
-						amount = math.ceil(amount / intSkillInfo.minMade);
+						amount = math.ceil(amount / intSkillData.minMade);
 					end
 				end

diff --git a/CauldronTradeskill.lua b/CauldronTradeskill.lua
index d415267..840e984 100644
--- a/CauldronTradeskill.lua
+++ b/CauldronTradeskill.lua
@@ -33,6 +33,9 @@ function Cauldron:UpdateSkills()
 	if not self.db.realm.userdata[self.vars.playername].reagentMap then
 		self.db.realm.userdata[self.vars.playername].reagentMap = {};
 	end
+	if not self.db.global.reagentMap then
+		self.db.global.reagentMap = {};
+	end

 	-- save the skill entry in a local var
 	local skillDB = self.db.realm.userdata[self.vars.playername].skills[skillName];
@@ -40,6 +43,14 @@ function Cauldron:UpdateSkills()
 		skillDB.recipes = {};
 	end

+	-- initialize the global recipe list
+	if not self.db.global.recipes then
+		self.db.global.recipes = {};
+	end
+	if not self.db.global.recipes[baseSkillName] then
+		self.db.global.recipes[baseSkillName] = {};
+	end
+
 	-- initialize window information, if necessary
 	if not skillDB.window then
 		skillDB.window = {
@@ -97,8 +108,12 @@ function Cauldron:UpdateSkills()
 				skillDB.recipes[name].maxMade = maxMade;

 				-- update reagent skill index
-				for _,r in ipairs(skillDB.recipes[name].reagents) do
-					r.skillIndex = i;
+				if skillDB.recipes[name].reagents then
+					for _,r in ipairs(skillDB.recipes[name].reagents) do
+						r.skillIndex = i;
+					end
+				else
+					Cauldron:error("No reagent list found for recipe: "..name.."!");
 				end
 			else
 				-- add the recipe info and other miscellaneous info
@@ -107,19 +122,31 @@ function Cauldron:UpdateSkills()
 				local _, _, _, _, _, _, _, _, slot, _ = GetItemInfo(itemLink);

 				local keywords = name;
-
-				-- fill in the db entry
+
+				-- fill in the character db entry
 				skillDB.recipes[name] = {
 					['index'] = i,
-					['name'] = name,
-					['itemLink'] = itemLink,
-					['recipeLink'] = recipeLink,
-					['icon'] = GetTradeSkillIcon(i),
 					['tradeskill'] = baseSkillName,
 					['difficulty'] = difficulty,
 					['available'] = avail,
 					['minMade'] = minMade,
 					['maxMade'] = maxMade,
+					['categories'] = "",
+					['reagents'] = {},
+				};
+
+				-- fill in the global db entry
+				self.db.global.recipes[baseSkillName][name] = {
+--					['index'] = i,
+					['name'] = name,
+					['itemLink'] = itemLink,
+					['recipeLink'] = recipeLink,
+					['icon'] = GetTradeSkillIcon(i),
+					['tradeskill'] = baseSkillName,
+--					['difficulty'] = difficulty,
+--					['available'] = avail,
+--					['minMade'] = minMade,
+--					['maxMade'] = maxMade,

 					-- filter information
 					['slot'] = slot,
@@ -129,7 +156,7 @@ function Cauldron:UpdateSkills()
 				};

 				-- set the action verb for this skill
-				skillDB.recipes[name].verb = verb;
+				self.db.global.recipes[baseSkillName][name].verb = verb;

 				-- make sure the skill window info is initialized
 				if not skillDB.window.skills[name] then
@@ -192,22 +219,27 @@ function Cauldron:UpdateSkills()
 						["key"] = key,
 					};

-					table.insert(skillDB.recipes[name].reagents, r);
+					-- add to the global reagent table
+					table.insert(self.db.global.recipes[baseSkillName][name].reagents, r);
+					-- add to the local reagent table
+					table.insert(skillDB.recipes[name].reagents, {
+						skillIndex = j,
+					});

 					-- add the reagent to the reagent map

 					if rName then
-						if not self.db.realm.userdata[self.vars.playername].reagentMap[rName] then
-							self.db.realm.userdata[self.vars.playername].reagentMap[rName] = {};
+						if not self.db.global.reagentMap[rName] then
+							self.db.global.reagentMap[rName] = {};
 						end
-						table.insert(self.db.realm.userdata[self.vars.playername].reagentMap[rName], skillName..";"..recipeLink);
+						table.insert(self.db.global.reagentMap[rName], skillName..";"..recipeLink);

 						keywords = keywords..","..rName;
 					end
 				end

 				-- fill in the keywords db entry
-				skillDB.recipes[name].keywords = keywords;
+				self.db.global.recipes[baseSkillName][name].keywords = keywords;
 			end
 	    else
 	    	-- save the header name
@@ -300,6 +332,9 @@ function Cauldron:GetSkillList(playername, skillName)

 	for name, recipe in pairs(self.db.realm.userdata[playername].skills[skillName].recipes) do
 		self:debug("GetSkillList: name="..name);
+
+		-- get the details of the recipe from the global list
+		local recipeInfo = self.db.global.recipes[skillName][name];

 		local add = true;

@@ -327,7 +362,7 @@ function Cauldron:GetSkillList(playername, skillName)
 				minLevel = tonumber(minLevel) or 0;
 				maxLevel = tonumber(maxLevel) or 0;

-				local _,_,_,itemLevel,reqLevel,_,_,_,_,_ = GetItemInfo(recipe.itemLink);
+				local _,_,_,itemLevel,reqLevel,_,_,_,_,_ = GetItemInfo(recipeInfo.itemLink);
 				if itemLevel and (matchItemLevel == "i") then
 					itemLevel = tonumber(itemLevel) or 0;
 					self:debug("GetSkillList: match by item level");
@@ -346,8 +381,8 @@ function Cauldron:GetSkillList(playername, skillName)
 			else
 				-- match name or reagents
 				self:debug("GetSkillList: match by name or reagents");
-				if not string.find(string.lower(recipe.keywords or ""), string.lower(search)) then
-					self:debug("skipping recipe: "..name.." (keywords: "..tostring(recipe.keywords)..")");
+				if not string.find(string.lower(recipeInfo.keywords or ""), string.lower(search)) then
+					self:debug("skipping recipe: "..name.." (keywords: "..tostring(recipeInfo.keywords)..")");
 					add = false;
 				end
 			end
@@ -361,9 +396,9 @@ function Cauldron:GetSkillList(playername, skillName)
 		end

 		-- check categories
-		local catInfo = self.db.realm.userdata[playername].skills[skillName].window.categories[recipe.defaultCategory];
+		local catInfo = self.db.realm.userdata[playername].skills[skillName].window.categories[recipeInfo.defaultCategory];
 		if catInfo and (not catInfo.shown) then
-			self:debug("skipping recipe: "..name.." (category: "..recipe.defaultCategory..")");
+			self:debug("skipping recipe: "..name.." (category: "..recipeInfo.defaultCategory..")");
 			add = false;
 		end

@@ -387,7 +422,7 @@ function Cauldron:GetSkillList(playername, skillName)
 			end
 		elseif self.db.realm.userdata[playername].skills[skillName].window.filter.haveKeyReagents then
 			-- check if the reagent count for key reagents is 0
-			for _, rinfo in ipairs(recipe.reagents) do
+			for _, rinfo in ipairs(recipeInfo.reagents) do
 				-- check possession count
 				if (GetItemCount(rinfo.link, false) < rinfo.numRequired) and (rinfo.key) then
 					add = false;
@@ -396,7 +431,7 @@ function Cauldron:GetSkillList(playername, skillName)
 		elseif self.db.realm.userdata[playername].skills[skillName].window.filter.haveAnyReagents then
 			-- check if the reagent count for any reagent is > 0
 			add = false;
-			for _, rinfo in ipairs(recipe.reagents) do
+			for _, rinfo in ipairs(recipeInfo.reagents) do
 				-- check possession count
 				if GetItemCount(rinfo.link, false) > 0 then
 					add = true;
@@ -406,9 +441,9 @@ function Cauldron:GetSkillList(playername, skillName)

 		-- check favorites filter
 		if self.db.realm.userdata[playername].skills[skillName].window.filter.favorites then
-			if not self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].favorite then
+			if not self.db.realm.userdata[playername].skills[skillName].window.skills[recipeInfo.name].favorite then
 				--@alpha@
-				self:debug("skipping recipe: "..name.." (favorite: "..tostring(self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].favorite)..")");
+				self:debug("skipping recipe: "..name.." (favorite: "..tostring(self.db.realm.userdata[playername].skills[skillName].window.skills[recipeInfo.name].favorite)..")");
 				--@end-alpha@
 				add = false;
 			end
@@ -416,10 +451,10 @@ function Cauldron:GetSkillList(playername, skillName)

 		-- check achievements filter
 		if self.db.realm.userdata[playername].skills[skillName].window.filter.achievements then
-			local achievements = Cauldron:GetAchievementsForSkill(recipe);
+			local achievements = Cauldron:GetAchievementsForSkill(recipeInfo);
 			if (not achievements) or (#achievements == 0) then
 				--@alpha@
-				self:debug("skipping recipe: "..name.." (achievements: "..tostring(self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].achievements)..")");
+				self:debug("skipping recipe: "..name.." (achievements: "..tostring(self.db.realm.userdata[playername].skills[skillName].window.skills[recipeInfo.name].achievements)..")");
 				--@end-alpha@
 				add = false;
 			end
@@ -427,7 +462,7 @@ function Cauldron:GetSkillList(playername, skillName)

 		-- we got here, add the recipe to the list
 		if add then
-			table.insert(skills, recipe);
+			table.insert(skills, recipeInfo);
 		end
 	end

@@ -444,7 +479,9 @@ function Cauldron:GetSkillList(playername, skillName)
 				--@alpha@
 				self:debug("GetSkillList: sorting by default (skill index)");
 				--@end-alpha@
-				return r1.index < r2.index;
+				local r1v = self.db.realm.userdata[playername].skills[skillName].recipes[r1.name].index;
+				local r2v = self.db.realm.userdata[playername].skills[skillName].recipes[r2.name].index;
+				return r1v < r2v;
 			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortAlpha then
 				--@alpha@
 				self:debug("GetSkillList: sorting by alpha");
@@ -461,11 +498,13 @@ function Cauldron:GetSkillList(playername, skillName)
 					trivial = 1,
 				};

+				local r1v = self.db.realm.userdata[playername].skills[skillName].recipes[r1.name].difficulty;
+				local r2v = self.db.realm.userdata[playername].skills[skillName].recipes[r2.name].difficulty;
 				--@alpha@
-				self:debug("GetSkillList: r1.difficulty="..r1.difficulty);
-				self:debug("GetSkillList: r2.difficulty="..r2.difficulty);
+				self:debug("GetSkillList: r1.difficulty="..r1v);
+				self:debug("GetSkillList: r2.difficulty="..r2v);
 				--@end-alpha@
-				return difficulty[r1.difficulty] > difficulty[r2.difficulty];
+				return difficulty[r1v] > difficulty[r2v];
 			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortItemLevel then
 				--@alpha@
 				self:debug("GetSkillList: sorting by item level");
@@ -491,8 +530,8 @@ function Cauldron:GetSkillList(playername, skillName)
 				self:debug("GetSkillList: sorting by favorites");
 				--@end-alpha@

-				local r1f = r1.favorite and 100 or 1;
-				local r2f = r2.favorite and 100 or 1;
+				local r1f = self.db.realm.userdata[playername].skills[skillName].window.skills[r1.name].favorite and 100 or 1;
+				local r2f = self.db.realm.userdata[playername].skills[skillName].window.skills[r2.name].favorite and 100 or 1;

 				return r2f < r1f;
 			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortBenefit then
@@ -527,11 +566,12 @@ function Cauldron:GetSkillInfo(tradeskill, skill)
 		return nil;
 	end

-	local skillInfo = self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes[skill];
+	local skillInfo = self.db.global.recipes[tradeskill][skill];
+--	local skillInfo = self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes[skill];
 	if not skillInfo then
 		-- couldn't find a skill with the item name, so scan the list for skills that craft
 		-- the item
-		for _, recipe in pairs(self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes) do
+		for _, recipe in pairs(self.db.global.recipes[tradeskill]) do
 			local name, _ = GetItemInfo(recipe.itemLink);
 			if name == skill then
 				return recipe;
@@ -554,7 +594,8 @@ function Cauldron:GetSkillInfoForItem(item)
 	for tradeskill, list in pairs(self.db.realm.userdata[self.vars.playername].skills) do
 		-- skip linked skills
 		if not (string.find(tradeskill, "Linked-")) then
-			for _, recipeInfo in pairs(list.recipes) do
+			for recipeName, recipe in pairs(list.recipes) do
+				local recipeInfo = self.db.global.recipes[tradeskill][recipeName];
 				local name, _ = GetItemInfo(recipeInfo.itemLink);
 				if name == item then
 					return recipeInfo;
@@ -576,7 +617,8 @@ function Cauldron:GetSkillInfoForLink(recipeLink)
 	for tradeskill, list in pairs(self.db.realm.userdata[self.vars.playername].skills) do
 		-- skip linked skills
 		if not (string.find(tradeskill, "Linked-")) then
-			for _, recipeInfo in pairs(list.recipes) do
+			for recipeName, recipe in pairs(list.recipes) do
+				local recipeInfo = self.db.global.recipes[tradeskill][recipeName];
 				local id = Cauldron:GetIdFromLink(recipeLink);
 				local recipeId = Cauldron:GetIdFromLink(recipeInfo.recipeLink);
 				if id == recipeId then
@@ -599,8 +641,10 @@ function Cauldron:GetSkillInfoByIndex(itemIndex)
 	for tradeskill, list in pairs(self.db.realm.userdata[self.vars.playername].skills) do
 		-- skip linked skills
 		if not (string.find(tradeskill, "Linked-")) then
-			for _, recipeInfo in pairs(list.recipes) do
-				if recipeInfo.index == itemIndex then
+			for recipeName, recipe in pairs(list.recipes) do
+				local recipeInfo = self.db.global.recipes[tradeskill][recipeName];
+				local recipeData = Cauldron:GetSkillDataForSkill(recipeInfo);
+				if recipeData.index == itemIndex then
 					return recipeInfo;
 				end
 			end
@@ -631,6 +675,31 @@ function Cauldron:GetReagentInfoByIndex(item, reagentIndex)
 	return nil;
 end

+function Cauldron:GetSkillDataForSkill(skillInfo)
+
+	if not skillInfo then
+		return nil;
+	end
+
+	local skillData = nil;
+
+	if self.db.realm.userdata[self.vars.playername].skills[skillInfo.tradeskill] and
+	   self.db.realm.userdata[self.vars.playername].skills[skillInfo.tradeskill].recipes[skillInfo.name] then
+	   	skillData = self.db.realm.userdata[self.vars.playername].skills[skillInfo.tradeskill].recipes[skillInfo.name];
+	else
+		skillData = {
+			index = 0,
+			difficulty = "unknown",
+			available = 0,
+			minMade = 0,
+			maxMade = 0,
+			categories = "",
+		};
+	end
+
+	return skillData;
+end
+
 function Cauldron:GetRequiredItems(skillInfo, amount)

 	local intermediates = {};
@@ -779,12 +848,12 @@ function Cauldron:GetSkillsForReagent(id)
 	local itemName,itemInfo,_ = GetItemInfo(id);
 	local skillList = {};

-	if not Cauldron.db.realm.userdata[Cauldron.vars.playername].reagentMap then
+	if not Cauldron.db.global.reagentMap then
 		return {};
 	end

 	-- find the reagent in the map
-	local reagentMap = Cauldron.db.realm.userdata[Cauldron.vars.playername].reagentMap[itemName];
+	local reagentMap = Cauldron.db.global.reagentMap[itemName];
 	if reagentMap then
 		for _,skill in ipairs(reagentMap) do
 			table.insert(skillList, skill);