Browse Source

Tradeskill Update

Many tradeskill updates, the following issues should be resolved
- Counter successes/fails don't seem to have any effect on durability/progress more than a regular tick.
- Every recipe has the description "The art of sculpting metal into a candelabra." in the mouseover tooltip.
- Materials and fuels stored in bank are counted for use in recipes.
- Recipes with a primary component that is not owned in inventory (or bank) show as "Primary Component: [0]" in the recipe tooltip when hovering the recipe icon in the recipe window, instead of red-colored text "Primary Component: Bronze Cluster [0]". This is only with primary components. Build components and fuel components don't have this same behavior.
- Recipes can be crafted from recipe window, without having a crafting station selected or even being near one.
- T1 rawhide leather pelts harvested from dens are not the same pelts needed for any recipe that requires rawhide leather pelts:
    Alder, Bronze, Sackcloth, Tranquil Sackcloth, Waxed Leather, Woven Waxed, Elm, Rawhide Leather, Woven Rawhide, Threadbare, Tranquil Threadbare, Tin (probably more)
- examine recipe windows fixed, including showing total amounts of components in your inventory and previously created stage now displays as intended
- when in the craft recipe screen (prior to pressing begin) you may now select components to craft with, all available will be listed that can be used
Robert Allen 1 year ago
parent
commit
12a348199a

+ 28 - 1
EQ2/source/WorldServer/Items/Items.cpp

@@ -3180,7 +3180,34 @@ bool PlayerItemList::GetFirstFreeSlot(sint32* bag_id, sint16* slot) {
 	MPlayerItems.releasereadlock(__FUNCTION__, __LINE__);
 	return ret;
 }
-
+vector<Item*> PlayerItemList::GetAllItemsFromID(int32 id, bool include_bank, bool lock) {
+	//first check for an exact count match
+	map<sint32, map<int8, map<int16, Item*>> >::iterator itr;
+	map<int16, Item*>::iterator slot_itr;
+	vector<Item*> ret ;
+	if (lock)
+		MPlayerItems.readlock(__FUNCTION__, __LINE__);
+	for (itr = items.begin(); itr != items.end(); itr++) {
+		if (include_bank || (!include_bank && itr->first >= 0)) {
+			for (int8 i = 0; i < MAX_EQUIPMENT; i++)
+			{
+				for (slot_itr = itr->second[i].begin(); slot_itr != itr->second[i].end(); slot_itr++) {
+					if (slot_itr->second && slot_itr->second->details.item_id == id) {
+						if (lock)
+							MPlayerItems.releasereadlock(__FUNCTION__, __LINE__);
+						int32 yyy = 0;
+						ret.push_back(slot_itr->second);
+						
+						//return slot_itr->second;
+					}
+				}
+				
+			}
+			
+		}
+	}
+	return ret;
+}
 Item* PlayerItemList::CanStack(Item* item, bool include_bank){
 	if(!item || item->stack_count < 2)
 		return 0;

+ 2 - 1
EQ2/source/WorldServer/Items/Items.h

@@ -1042,6 +1042,7 @@ public:
 
 	Item* GetItem(int32 id);
 	Item* GetItemByName(const char *name);
+	Item* GetAllItemsByClassification(const char* name);
 	ItemStatsValues* CalculateItemBonuses(int32 item_id, Entity* entity = 0);
 	ItemStatsValues* CalculateItemBonuses(Item* desc, Entity* entity = 0, ItemStatsValues* values = 0);
 	vector<Item*>* GetItems(string name, int64 itype, int64 ltype, int64 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass);
@@ -1092,7 +1093,7 @@ public:
 	bool  HasFreeBagSlot();
 	void DestroyItem(int16 index);
 	Item* CanStack(Item* item, bool include_bank = false);
-	
+	vector<Item*> GetAllItemsFromID(int32 item, bool include_bank = false, bool lock = false);
 	void RemoveItem(Item* item, bool delete_item = false);
 	bool AddItem(Item* item);
 

+ 114 - 229
EQ2/source/WorldServer/Recipes/Recipe.cpp

@@ -28,6 +28,7 @@
 extern ConfigReader configReader;
 extern MasterItemList master_item_list;
 
+
 Recipe::Recipe() {
 	id = 0;
 	book_id = 0;
@@ -304,7 +305,7 @@ EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display
 	RecipeProducts* rp = 0;
 	vector<int32>::iterator itr;
 	vector<RecipeComp> comp_list;
-
+	
 	int8 i = 0;
 	int32 firstID = 0;
 	int32 primary_comp_id = 0;
@@ -341,43 +342,69 @@ EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display
 	packet->setSubstructDataByName("recipe_info", "unknown3", 1);
 	packet->setSubstructDataByName("recipe_info", "adventure_id", 0xFF);
 	packet->setSubstructDataByName("recipe_info", "tradeskill_id", client ? client->GetPlayer()->GetTradeskillClass() : 0);
-	packet->setSubstructDataByName("recipe_info", "unknown4", 100);
+	packet->setSubstructDataByName("recipe_info", "unknown4a", 100);
 	packet->setSubstructDataByName("recipe_info", "unknown4aa", 1);
-	packet->setSubstructDataByName("recipe_info", "unknown5a", 20);
+	packet->setSubstructDataByName("recipe_info", "unknown5a", 20);//level *10
 	packet->setSubstructDataByName("recipe_info", "product_classes", recipe->GetClasses());
-	packet->setSubstructDataByName("recipe_info", "show_previous", 15);
-	packet->setSubstructDataByName("recipe_info", "previous1_icon", 186);
-	packet->setSubstructDataByName("recipe_info", "previous1_name", "previous1_name");
-	packet->setSubstructDataByName("recipe_info", "previous1_qty", 1);
-	packet->setSubstructDataByName("recipe_info", "previous1_item_id", 4142);
-	packet->setSubstructDataByName("recipe_info", "previous1_item_crc", -853046774);
-	packet->setSubstructDataByName("recipe_info", "previous2_icon", 186);
-	packet->setSubstructDataByName("recipe_info", "previous2_name", "previous2_name");
-	packet->setSubstructDataByName("recipe_info", "previous2_qty", 1);
-	packet->setSubstructDataByName("recipe_info", "previous2_item_id", 4142);
-	packet->setSubstructDataByName("recipe_info", "previous2_item_crc", -853046774);
-	packet->setSubstructDataByName("recipe_info", "previous3_icon", 186);
-	packet->setSubstructDataByName("recipe_info", "previous3_name", "previous3_name");
-	packet->setSubstructDataByName("recipe_info", "previous3_qty", 1);
-	packet->setSubstructDataByName("recipe_info", "previous3_item_id", 4142);
-	packet->setSubstructDataByName("recipe_info", "previous3_item_crc", -853046774);
-	packet->setSubstructDataByName("recipe_info", "firstbar_icon", 186);
-	packet->setSubstructDataByName("recipe_info", "firstbar_name", "firstbar_name");
-	packet->setSubstructDataByName("recipe_info", "firstbar_qty", 1);
-	packet->setSubstructDataByName("recipe_info", "firstbar_item_id", 4142);
-	packet->setSubstructDataByName("recipe_info", "firstbar_item_crc", -853046774);
-	packet->setSubstructDataByName("recipe_info", "secondbar_icon", 186);
-	packet->setSubstructDataByName("recipe_info", "secondbar_name", "secondbar_name");
-	packet->setSubstructDataByName("recipe_info", "secondbar_qty", 1);
-	packet->setSubstructDataByName("recipe_info", "secondbar_item_id", 4142);
-	packet->setSubstructDataByName("recipe_info", "secondbar_item_crc", -853046774);
-	packet->setSubstructDataByName("recipe_info", "thirdbar_icon", 198);
-	packet->setSubstructDataByName("recipe_info", "thirdbar_name", "thirdbar_name");
-	packet->setSubstructDataByName("recipe_info", "thirdbar_qty", 1);
-	packet->setSubstructDataByName("recipe_info", "thirdbar_item_id", 12098);
-
-	packet->setSubstructDataByName("recipe_info", "thirdbar_item_crc", -2065846136);
-	item = master_item_list.GetItemByName(recipe->GetName());
+	packet->setSubstructDataByName("recipe_info", "show_previous", client->GetPlayer()->GetRecipeList()->GetRecipe(recipe->GetID())->highestStage);//     recipe->highestStage);
+
+
+	rp = recipe->products[1];
+	if (rp->product_id > 0) {
+		item = 0;
+		item = master_item_list.GetItem(rp->product_id);
+		if (item) {
+			packet->setSubstructDataByName("recipe_info", "previous1_icon", item->details.icon);
+			packet->setSubstructDataByName("recipe_info", "previous1_name", "previous1_name");
+			packet->setSubstructDataByName("recipe_info", "previous1_qty", recipe->products[1]->product_qty);
+			packet->setSubstructDataByName("recipe_info", "previous1_item_id", recipe->products[1]->product_id);
+			packet->setSubstructDataByName("recipe_info", "previous1_item_crc", -853046774);
+			packet->setSubstructDataByName("recipe_info", "firstbar_icon", item->details.icon);
+			packet->setSubstructDataByName("recipe_info", "firstbar_name", "firstbar_name");
+			packet->setSubstructDataByName("recipe_info", "firstbar_qty", recipe->products[1]->product_qty);
+			packet->setSubstructDataByName("recipe_info", "firstbar_item_id", recipe->products[2]->product_id);
+			packet->setSubstructDataByName("recipe_info", "firstbar_item_crc", -853046774);
+		}
+	}
+	rp = recipe->products[2];
+	if (rp->product_id > 0) {
+		item = 0;
+		item = master_item_list.GetItem(rp->product_id);
+		if (item) {
+			packet->setSubstructDataByName("recipe_info", "previous2_icon", item->details.icon);
+			packet->setSubstructDataByName("recipe_info", "previous2_name", "previous2_name");
+			packet->setSubstructDataByName("recipe_info", "previous2_qty", recipe->products[2]->product_qty);
+			packet->setSubstructDataByName("recipe_info", "previous2_item_id", recipe->products[2]->product_id);
+			packet->setSubstructDataByName("recipe_info", "previous2_item_crc", -853046774);
+			packet->setSubstructDataByName("recipe_info", "secondbar_icon", item->details.icon);
+			packet->setSubstructDataByName("recipe_info", "secondbar_name", "secondbar_name");
+			packet->setSubstructDataByName("recipe_info", "secondbar_qty", recipe->products[2]->product_qty);
+			packet->setSubstructDataByName("recipe_info", "secondbar_item_id", recipe->products[2]->product_id);
+			packet->setSubstructDataByName("recipe_info", "secondbar_item_crc", -853046774);
+		}
+	}
+	rp = recipe->products[3];
+	if (rp->product_id > 0) {
+		item = 0;
+		item = master_item_list.GetItem(rp->product_id);
+		if (item) {
+			packet->setSubstructDataByName("recipe_info", "previous3_icon", item->details.icon);
+			packet->setSubstructDataByName("recipe_info", "previous3_name", "previous3_name");
+			packet->setSubstructDataByName("recipe_info", "previous3_qty", recipe->products[3]->product_qty);
+			packet->setSubstructDataByName("recipe_info", "previous3_item_id", recipe->products[3]->product_id);
+			packet->setSubstructDataByName("recipe_info", "previous3_item_crc", -853046774);
+			packet->setSubstructDataByName("recipe_info", "thirdbar_icon", item->details.icon);
+			packet->setSubstructDataByName("recipe_info", "thirdbar_name", "thirdbar_name");
+			packet->setSubstructDataByName("recipe_info", "thirdbar_qty", recipe->products[3]->product_qty);
+			packet->setSubstructDataByName("recipe_info", "thirdbar_item_id", recipe->products[3]->product_id);
+			packet->setSubstructDataByName("recipe_info", "thirdbar_item_crc", -2065846136);
+		}
+	}
+	
+	
+	
+	
+	item = master_item_list.GetItemByName(recipe->GetName());// TODO: MJ we should be getting item by item number in case of multiple items with same name
 	if(item) {
 		packet->setSubstructDataByName("recipe_info", "product_icon", item->details.icon); //item->details.icon);
 		packet->setSubstructDataByName("recipe_info", "product_name", item->name.c_str()); //item->name);
@@ -385,6 +412,7 @@ EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display
 		packet->setSubstructDataByName("recipe_info", "product_item_id", item->details.item_id); //item->details.item_id);
 		packet->setSubstructDataByName("recipe_info", "product_item_crc", 0); //item->details.item_crc);
 	}
+
 	rp = recipe->products[0];
 	if (rp->byproduct_id > 0) {
 		item = 0;
@@ -393,48 +421,46 @@ EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display
 			packet->setSubstructDataByName("recipe_info", "byproduct_icon", item->details.icon);//11
 			packet->setSubstructDataByName("recipe_info", "byproduct_id", item->details.item_id);
 		}
+
 	}
-	
-	
-	//string xxx = recipe->
-	//item = master_item_list.GetItemByName   (recipe->GetBuild1ComponentTitle());
-	// Reset item to 0
+	rp = recipe->products[1];
+	if (rp->product_id > 0) {
+		item = 0;
+		item = master_item_list.GetItem(rp->product_id);
+		if (item) {
+			packet->setSubstructDataByName("recipe_info", "byproduct_icon", item->details.icon);//11
+			packet->setSubstructDataByName("recipe_info", "byproduct_id", item->details.item_id);
+		}
+
+	}
+		
 	item = 0;
 
 	// Check to see if we have a primary component (slot = 0)
+	vector<Item*> itemss;
 	if (recipe->components.count(0) > 0) {
+		
 		vector<int32> rc = recipe->components[0];
 		for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
-			if (firstID == 0)
-				firstID = *itr;
-
 			item = master_item_list.GetItem(*itr);
+			packet->setSubstructDataByName("recipe_info", "primary_comp", recipe->primary_build_comp_title);
+			packet->setSubstructDataByName("recipe_info", "primary_qty", recipe->GetPrimaryComponentQuantity());
 			item = 0;
 			item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-			if (item) {
-				packet->setSubstructDataByName("recipe_info", "primary_qty_avail", item->details.count);
-				packet->setSubstructDataByName("recipe_info", "primary_comp", recipe->primary_build_comp_title);
+			itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+			if (itemss.size() > 0) {
+				int16 needed_qty = recipe->GetPrimaryComponentQuantity();
+				int16 have_qty = 0;
+				for (int8 i = 0; i < itemss.size(); i++) {
+					have_qty += itemss[i]->details.count;
+				}
+				packet->setSubstructDataByName("recipe_info", "primary_qty_avail", have_qty);
 				break;
-					}
-		}
-		// store the id of the primary comp
-		primary_comp_id = firstID;
-		// Set the default item id to the first component id
-		item = 0;
-		item = client->GetPlayer()->item_list.GetItemFromID(firstID);
-		if (item) {
-			
+			}
 		}
-		// Reset the variables we will reuse
-		i = 0;
-		firstID = 0;
-		item = 0;
-	}
-	else {
-		LogWrite(TRADESKILL__ERROR, 0, "Recipes", "Recipe has no primary component");
-		
 	}
 	
+	
 
 	int8 total_build_components = 0;
 	if (recipe->components.count(1) > 0)
@@ -450,205 +476,64 @@ EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display
 	if (total_build_components > 0) {
 		packet->setSubstructArrayLengthByName("recipe_info", "num_comps", total_build_components);
 		for (int8 index = 0; index < 4; index++) {
-
 			if (recipe->components.count(index + 1) == 0)
 				continue;
 
-			//packet->setArrayDataByName("build_slot", index, index);
-
 			vector<int32> rc = recipe->components[index + 1];
-
-			//packet->setSubArrayLengthByName("num_build_choices", rc.size(), index);
+			int16 have_qty = 0;
+			string comp_title;
+			int8 comp_qty;
 			for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
-				if (firstID == 0)
-					firstID = *itr;
-				string comp_title;
-				int8 comp_qty;
+
+				
 				if (index == 0) {
 					comp_title = recipe->build1_comp_title;
-					comp_qty = recipe->build_comp_qty;
-					item = master_item_list.GetItem(*itr);
-					packet->setArrayDataByName("build_comp", comp_title.c_str(), index );
-					packet->setArrayDataByName("build_comp_qty", comp_qty, index );
-					item = master_item_list.GetItem(*itr);
-					item = 0;
-					item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-					if (item) {
-						packet->setArrayDataByName("build_comp_qty_avail", item->details.count, index );
-
-					}
+					comp_qty = recipe->build1_comp_qty;
 				}
 				else if (index == 1) {
 					comp_title = recipe->build2_comp_title;
 					comp_qty = recipe->build2_comp_qty;
-					item = master_item_list.GetItem(*itr);
-					packet->setArrayDataByName("build_comp", comp_title.c_str(), index );
-					packet->setArrayDataByName("build_comp_qty", comp_qty, index );
-					item = master_item_list.GetItem(*itr);
-					item = 0;
-					item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-					if (item) {
-						packet->setArrayDataByName("build_comp_qty_avail", item->details.count, index );
-						break;
-					}
 				}
 				else if (index == 2) {
 					comp_title = recipe->build3_comp_title;
 					comp_qty = recipe->build3_comp_qty;
-					item = master_item_list.GetItem(*itr);
-					packet->setArrayDataByName("build_comp", comp_title.c_str(), index );
-					packet->setArrayDataByName("build_comp_qty", comp_qty, index );
-					item = master_item_list.GetItem(*itr);
-					item = 0;
-					item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-					if (item) {
-						packet->setArrayDataByName("build_comp_qty_avail", item->details.count, index );
-						break;
-					}
 				}
 				else if (index == 3) {
 					comp_title = recipe->build4_comp_title;
 					comp_qty = recipe->build4_comp_qty;
-					item = master_item_list.GetItem(*itr);
-					packet->setArrayDataByName("build_comp", comp_title.c_str(), index );
-					packet->setArrayDataByName("build_comp_qty", comp_qty, index );
-					item = master_item_list.GetItem(*itr);
-					item = 0;
-					item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-					if (item) {
-						packet->setArrayDataByName("build_comp_qty_avail", item->details.count, index );
-						break;
-					}
 				}
-
-				
-					//item = master_item_list.GetItem(*itr);
-					//packet->setArrayDataByName("build_comp", comp_title.c_str(), index -1);
-					//packet->setArrayDataByName("build_comp_qty", comp_qty, index - 1);
-					//item = master_item_list.GetItem(*itr);
-					//item = 0;
-					//item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-					//if (item) {
-					//	packet->setArrayDataByName("build_comp_qty_avail", item->details.count, index - 1);
-					
-					//}
-									   					 			
-
-					item = 0;
-					item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-					if (item) {
-						//packet->setSubArrayDataByName("build_total_quantity", item->details.count, index, i);
-					}
-				}
-
-				// Set the default item id to the first component id
-				//packet->setArrayDataByName("build_item_selected", 1, index);
-				//packet->setArrayDataByName("build_selected_item_id", firstID, index);
-				item = 0;
-				item = client->GetPlayer()->item_list.GetItemFromID(firstID);
-				int8 qty = 0;
-				if (item) {
-					qty = (int8)item->details.count;
-					if (qty > 0 && firstID == primary_comp_id)
-						qty -= 1;
+				item = master_item_list.GetItem(*itr);
+				itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+				for (int8 j = 0; j < itemss.size(); j++) {
+					have_qty += itemss[j]->details.count;
 				}
-
-				if (index == 0) {
-					//	packet->setArrayDataByName("build_title", recipe->GetBuild1ComponentTitle(), index);
-						//packet->setArrayDataByName("build_qty", recipe->GetBuild1ComponentQuantity(), index);
-					if (item) {
-						//	packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild1ComponentQuantity()), index);
-					}
-				}
-				else if (index == 1) {
-					//	packet->setArrayDataByName("build_title", recipe->GetBuild2ComponentTitle(), index);
-					//	packet->setArrayDataByName("build_qty", recipe->GetBuild2ComponentQuantity(), index);
-					if (item) {
-						//	packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild2ComponentQuantity()), index);
-					}
-				}
-				else if (index == 2) {
-					//	packet->setArrayDataByName("build_title", recipe->GetBuild3ComponentTitle(), index);
-					//	packet->setArrayDataByName("build_qty", recipe->GetBuild3ComponentQuantity(), index);
-					if (item) {
-						//	packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild3ComponentQuantity()), index);
-					}
-				}
-				else {
-					//	packet->setArrayDataByName("build_title", recipe->GetBuild4ComponentTitle(), index);
-					//	packet->setArrayDataByName("build_qty", recipe->GetBuild4ComponentQuantity(), index);
-					if (item) {
-						//packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild4ComponentQuantity()), index);
-					}
-				}
-
-				// Reset the variables we will reuse
-				i = 0;
-				firstID = 0;
-				item = 0;
 			}
+				packet->setArrayDataByName("build_comp", comp_title.c_str(), index);
+				packet->setArrayDataByName("build_comp_qty", comp_qty, index);
+				packet->setArrayDataByName("build_comp_qty_avail", have_qty, index);
+		}
 		
 	}
-
-
-
-
-	//packet->setArrayDataByName("build_comp", "build_comp1", 0);
-	//packet->setArrayDataByName("build_comp_qty", 1, 0);
-	//packet->setArrayDataByName("build_comp_qty_avail", 24, 0);
-
-	//packet->setArrayDataByName("build_comp", "build_comp2", 1);
-	//packet->setArrayDataByName("build_comp_qty", 1, 1);
-	//packet->setArrayDataByName("build_comp_qty_avail", 16, 1);
-
-	//packet->setArrayDataByName("build_comp", "build_comp3", 2);
-	//packet->setArrayDataByName("build_comp_qty", 1, 2);
-	//packet->setArrayDataByName("build_comp_qty_avail", 15, 2);
-
 	// Check to see if we have a fuel component (slot = 5)
 	if (recipe->components.count(5) > 0) {
 		vector<int32> rc = recipe->components[5];
-		//packet->setArrayLengthByName("num_fuel_choices", rc.size());
 		for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
-			if (firstID == 0)
-				firstID = *itr;
-
 			item = master_item_list.GetItem(*itr);
-			//packet->setSubstructDataByName("recipe_info", "fuel_comp_qty_avail", item->details.count);
+			packet->setSubstructDataByName("recipe_info", "fuel_comp", recipe->fuel_comp_title);
+			packet->setSubstructDataByName("recipe_info", "fuel_comp_qty", recipe->fuel_comp_qty);
 			item = 0;
 			item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-			if (item) {
-				packet->setSubstructDataByName("recipe_info", "fuel_comp_qty_avail", item->details.count);
+			itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+			if (itemss.size() > 0) {
+				int16 have_qty = 0;
+				for (int8 i = 0; i < itemss.size(); i++) {
+					have_qty += itemss[i]->details.count;
 				}
+				packet->setSubstructDataByName("recipe_info", "fuel_comp_qty_avail", have_qty);
+				break;
 			}
-
-		// Set the default item id to the first component id
-		//packet->setDataByName("fuel_selected_item_id", firstID);
-		//packet->setDataByName("fuel_item_selected", 1);
-		item = 0;
-		item = client->GetPlayer()->item_list.GetItemFromID(firstID);
-		if (item) {
-			//	packet->setDataByName("fuel_selected_item_qty", min(recipe->GetFuelComponentQuantity(), (int8)item->details.count));
 		}
-			//packet->setDataByName("fuel_title", recipe->GetFuelComponentTitle());
-		//packet->setDataByName("fuel_qty", recipe->GetFuelComponentQuantity());
-
-		// Reset the variables we will reuse
-		i = 0;
-		firstID = 0;
-		item = 0;
-	}
-	else {
-		LogWrite(TRADESKILL__ERROR, 0, "Recipes", "Recipe has no fuel component");
-		
 	}
-
-
-
-
-	packet->setSubstructDataByName("recipe_info", "fuel_comp", recipe->fuel_comp_title);
-	packet->setSubstructDataByName("recipe_info", "fuel_comp_qty", recipe->fuel_comp_qty);
-	//packet->setSubstructDataByName("recipe_info", "fuel_comp_qty_avail", 10);
 	packet->setSubstructDataByName("recipe_info", "build_comp_qty_avail_flag", 1);
 	packet->setSubstructDataByName("recipe_info", "unknown6", 4, 0);
 	packet->setSubstructDataByName("recipe_info", "min_product", 1);
@@ -656,7 +541,7 @@ EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display
 	packet->setSubstructDataByName("recipe_info", "available_flag", 4);
 	packet->setSubstructDataByName("recipe_info", "not_commissionable", 1);
 	packet->setSubstructDataByName("recipe_info", "recipe_name", recipe->GetName());
-	packet->setSubstructDataByName("recipe_info", "recipe_description", "The art of sculpting metal into a candelabra.");
+	packet->setSubstructDataByName("recipe_info", "recipe_description", recipe->GetDescription());
 	//packet->PrintPacket();
 	EQ2Packet* data = packet->serialize();
 	EQ2Packet* app = new EQ2Packet(OP_ClientCmdMsg, data->pBuffer, data->size);

+ 22 - 13
EQ2/source/WorldServer/Recipes/Recipe.h

@@ -53,6 +53,7 @@ public:
 	void SetID(int32 id) {this->id = id;}
 	void SetBookID(int32 book_id) {this->book_id = book_id;}
 	void SetName(const char *name) {strncpy(this->name, name, sizeof(this->name));}
+	void SetDescription(const char* description) { strncpy(this->description, description, sizeof(this->description)); }
 	void SetBookName(const char *book_name) {strncpy(this->book_name, book_name, sizeof(this->book_name));}
 	void SetBook(const char *book) {strncpy(this->book, book, sizeof(this->book));}
 	void SetDevice(const char *device) {strncpy(this->device, device, sizeof(this->device));}
@@ -64,27 +65,30 @@ public:
 	void SetKnowledge(int32 knowledge) {this->knowledge = knowledge;}
 	void SetClasses(int32 classes) {this->classes = classes;}
 	void SetDevice_Sub_Type(int8 device_sub_type) {this->device_sub_type = device_sub_type;}
+	void SetUnknown1(int8 unknown1) {this->unknown1 = unknown1;}
 	void SetUnknown2(int32 unknown2) {this->unknown2 = unknown2;}
 	void SetUnknown3(int32 unknown3) {this->unknown3 = unknown3;}
 	void SetUnknown4(int32 unknown4) {this->unknown4 = unknown4;}
 	void SetProductID(int32 itemID) { product_item_id = itemID; }
 	void SetProductQuantity(int8 qty) { product_qty = qty; }
 	void SetProductName(const char* productName) { strncpy(product_name, productName, sizeof(product_name)); }
-	void SetBuildComponentTitle(const char* title) { strncpy(build1_comp_title, title, sizeof(build1_comp_title)); }
+	void SetBuild1ComponentTitle(const char* title) { strncpy(build1_comp_title, title, sizeof(build1_comp_title)); }
 	void SetBuild2ComponentTitle(const char* title) { strncpy(build2_comp_title, title, sizeof(build2_comp_title)); }
 	void SetBuild3ComponentTitle(const char* title) { strncpy(build3_comp_title, title, sizeof(build3_comp_title)); }
 	void SetBuild4ComponentTitle(const char* title) { strncpy(build4_comp_title, title, sizeof(build4_comp_title)); }
 	void SetFuelComponentTitle(const char* title) { strncpy(fuel_comp_title, title, sizeof(fuel_comp_title)); }
 	void SetPrimaryComponentTitle(const char* title) { strncpy(primary_build_comp_title, title, sizeof(primary_build_comp_title)); }
-	void SetBuild1ComponentQuantity(int8 qty) { build_comp_qty = qty; }
+	void SetBuild1ComponentQuantity(int8 qty) { build1_comp_qty = qty; }
 	void SetBuild2ComponentQuantity(int8 qty) { build2_comp_qty = qty; }
 	void SetBuild3ComponentQuantity(int8 qty) { build3_comp_qty = qty; }
 	void SetBuild4ComponentQuantity(int8 qty) { build4_comp_qty = qty; }
 	void SetFuelComponentQuantity(int8 qty) { fuel_comp_qty = qty; }
+	void SetPrimaryComponentQuantity(int8 qty) { primary_comp_qty = qty; }
 
 	int32 GetID() {return id;}
 	int32 GetBookID() {return book_id;}
 	const char * GetName() {return name;}
+	const char* GetDescription() { return description; }
 	const char * GetBookName() {return book_name;}
 	const char * GetBook() {return book;}
 	const char * GetDevice() {return device;}
@@ -106,6 +110,7 @@ public:
 	return item->generic_info.tradeskill_classes < 4 || (1 << class_id) & item->generic_info.tradeskill_classes;
 	}
 	int8 GetDevice_Sub_Type() {return device_sub_type;}
+	int8 GetUnknown1() {return unknown1;}
 	int32 GetUnknown2() {return unknown2;}
 	int32 GetUnknown3() {return unknown3;}
 	int32 GetUnknown4() {return unknown4;}
@@ -119,17 +124,18 @@ public:
 	const char* GetBuild3ComponentTitle() { return build3_comp_title; }
 	const char* GetBuild4ComponentTitle() { return build4_comp_title; }
 	const char* GetFuelComponentTitle() { return fuel_comp_title; }
-	int8 GetBuild1ComponentQuantity() { return build_comp_qty; }
-	int8 GetBuild2ComponentQuantity() { return build2_comp_qty; }
-	int8 GetBuild3ComponentQuantity() { return build3_comp_qty; }
-	int8 GetBuild4ComponentQuantity() { return build4_comp_qty; }
-	int8 GetFuelComponentQuantity() { return fuel_comp_qty; }
+	int16 GetBuild1ComponentQuantity() { return build1_comp_qty; }
+	int16 GetBuild2ComponentQuantity() { return build2_comp_qty; }
+	int16 GetBuild3ComponentQuantity() { return build3_comp_qty; }
+	int16 GetBuild4ComponentQuantity() { return build4_comp_qty; }
+	int16 GetFuelComponentQuantity() { return fuel_comp_qty; }
+	int16 GetPrimaryComponentQuantity() { return primary_comp_qty; }
 
 	///<summary>Add a build component to this recipe</summary>
 	///<param name="itemID">Item id of the component</param>
 	///<param name="slot">Slot id for this component</param>
 	void AddBuildComp(int32 itemID, int8 slot, bool preferred = 0);
-
+	
 	// int8 = slot, vector = itemid
 	map<int8, vector<int32> > components;
 
@@ -143,6 +149,7 @@ private:
 	int32 id;
 	int32 book_id;
 	char name[256];
+	char description[256];
 	char book_name[256];
 	char book[256];
 	char device[30];
@@ -154,6 +161,7 @@ private:
 	int32 knowledge;
 	int8 device_sub_type;
 	int32 classes;
+	int8  unknown1;
 	int32 unknown2;
 	int32 unknown3;
 	int32 unknown4;
@@ -167,11 +175,12 @@ private:
 	char	build3_comp_title[256];
 	char	build4_comp_title[256];
 	char	fuel_comp_title[256];
-	int8	build_comp_qty;
-	int8	build2_comp_qty;
-	int8	build3_comp_qty;
-	int8	build4_comp_qty;
-	int8	fuel_comp_qty;
+	int16	build1_comp_qty;
+	int16	build2_comp_qty;
+	int16	build3_comp_qty;
+	int16	build4_comp_qty;
+	int16	fuel_comp_qty;
+	int16	primary_comp_qty;
 	int8	highestStage;
 	
 };

+ 11 - 8
EQ2/source/WorldServer/Recipes/RecipeDB.cpp

@@ -29,13 +29,14 @@
 
 extern MasterRecipeList master_recipe_list;
 extern MasterRecipeBookList master_recipebook_list;
+extern MasterItemList master_item_list;
 
 void WorldDatabase::LoadRecipes() {
 	DatabaseResult res;
 
 	bool status = database_new.Select(&res, 
-		"SELECT r.`id`,r.`level`,r.`icon`,r.`skill_level`,r.`technique`,r.`knowledge`,r.`name`,i.`name` as `book`,r.`bench`,ipc.`adventure_classes`, "
-		"r.`stage4_id`, r.`name`, r.`stage4_qty`, pcl.`name` as primary_comp_title, fcl.name as `fuel_comp_title`, r.fuel_comp_qty, "
+		"SELECT r.`id`,r.`level`,r.`icon`,r.`skill_level`,r.`technique`,r.`knowledge`,r.`name`,r.`description`,i.`name` as `book`,r.`bench`,ipc.`adventure_classes`, "
+		"r.`stage4_id`, r.`name`, r.`stage4_qty`, pcl.`name` as primary_comp_title,r.primary_comp_qty, fcl.name as `fuel_comp_title`, r.fuel_comp_qty, "
 		"bc.`name` AS build_comp_title, bc.qty AS build_comp_qty, bc2.`name` AS build2_comp_title, bc2.qty AS build2_comp_qty, "
 		"bc3.`name` AS build3_comp_title, bc3.qty AS build3_comp_qty, bc4.`name` AS build4_comp_title, bc4.qty AS build4_comp_qty,\n"
 		"r.stage0_id, r.stage1_id, r.stage2_id, r.stage3_id, r.stage4_id, r.stage0_qty, r.stage1_qty, r.stage2_qty, r.stage3_qty, r.stage4_qty,\n"
@@ -66,6 +67,7 @@ void WorldDatabase::LoadRecipes() {
 		recipe->SetTechnique(res.GetInt32(i++));
 		recipe->SetKnowledge(res.GetInt32(i++));
 		recipe->SetName(res.GetString(i++));
+		recipe->SetDescription(res.GetString(i++));
 		recipe->SetBook(res.GetString(i++));
 
 		//Convert the device string
@@ -86,17 +88,18 @@ void WorldDatabase::LoadRecipes() {
 		recipe->SetProductName(res.GetString(i++));
 		recipe->SetProductQuantity(res.GetInt8(i++));
 		recipe->SetPrimaryComponentTitle(res.GetString(i++));
+		recipe->SetPrimaryComponentQuantity(res.GetInt16(i++));
 		recipe->SetFuelComponentTitle(res.GetString(i++));
-		recipe->SetFuelComponentQuantity(res.GetInt8(i++));
+		recipe->SetFuelComponentQuantity(res.GetInt16(i++));
 
-		recipe->SetBuildComponentTitle(res.GetString(i++));
-		recipe->SetBuild1ComponentQuantity(res.GetInt8(i++));
+		recipe->SetBuild1ComponentTitle(res.GetString(i++));
+		recipe->SetBuild1ComponentQuantity(res.GetInt16(i++));
 		recipe->SetBuild2ComponentTitle(res.GetString(i++));
-		recipe->SetBuild2ComponentQuantity(res.GetInt8(i++));
+		recipe->SetBuild2ComponentQuantity(res.GetInt16(i++));
 		recipe->SetBuild3ComponentTitle(res.GetString(i++));
-		recipe->SetBuild3ComponentQuantity(res.GetInt8(i++));
+		recipe->SetBuild3ComponentQuantity(res.GetInt16(i++));
 		recipe->SetBuild4ComponentTitle(res.GetString(i++));
-		recipe->SetBuild4ComponentQuantity(res.GetInt8(i++));
+		recipe->SetBuild4ComponentQuantity(res.GetInt16(i++));
 
 		LogWrite(TRADESKILL__DEBUG, 7, "Recipes", "Loading recipe: %s (%u)", recipe->GetName(), recipe->GetID());
 

+ 31 - 33
EQ2/source/WorldServer/Tradeskills/Tradeskills.cpp

@@ -233,7 +233,7 @@ void TradeskillMgr::Process() {
 	m_tradeskills.releasewritelock(__FUNCTION__, __LINE__);
 }
 
-void TradeskillMgr::BeginCrafting(Client* client, vector<int32> components) {
+void TradeskillMgr::BeginCrafting(Client* client, vector<pair<int32,int8>> components) {
 	Recipe* recipe = master_recipe_list.GetRecipe(client->GetPlayer()->GetCurrentRecipe());
 
 	if (!recipe) {
@@ -243,13 +243,13 @@ void TradeskillMgr::BeginCrafting(Client* client, vector<int32> components) {
 	}
 
 	// TODO: use the vecotr to lock inventory slots
-	vector<int32>::iterator itr;
+	vector<pair<int32, int8>>::iterator itr;
 	bool missingItem = false;
 	int32 itemid = 0;
 	vector<Item*> tmpItems;
 	for (itr = components.begin(); itr != components.end(); itr++) {
-		itemid = *itr;
-		Item* item = client->GetPlayer()->item_list.GetItemFromID(itemid);
+		itemid = itr->first;
+		Item* item = client->GetPlayer()->item_list.GetItemFromUniqueID(itemid);
 
 		if(!item)
 		{
@@ -317,7 +317,7 @@ void TradeskillMgr::StopCrafting(Client* client, bool lock) {
 	int32 dur = tradeskill->currentDurability;
 	int32 progress = tradeskill->currentProgress;
 	Recipe* recipe = tradeskill->recipe;
-	vector<int32>::iterator itr;
+	vector<pair<int32, int8>>::iterator itr;
 	Item* item = 0;
 	int32 item_id = 0;
 	int8 i = 0;
@@ -336,23 +336,12 @@ void TradeskillMgr::StopCrafting(Client* client, bool lock) {
 	bool updateInvReq = false;
 	// cycle through the list of used items and remove them
 	for (itr = tradeskill->usedComponents.begin(); itr != tradeskill->usedComponents.end(); itr++, i++) {
-		// get the quantity to remove, first item in the vectore is always the primary, last is always the fuel
-		if (i == 0)
-			qty = 1;
-		else if (i == 1 && i != tradeskill->usedComponents.size() - 1)
-			qty = recipe->GetBuild1ComponentQuantity();
-		else if (i == 2 && i != tradeskill->usedComponents.size() - 1)
-			qty = recipe->GetBuild2ComponentQuantity();
-		else if (i == 3 && i != tradeskill->usedComponents.size() - 1)
-			qty = recipe->GetBuild3ComponentQuantity();
-		else if (i == 4 && i != tradeskill->usedComponents.size() - 1)
-			qty = recipe->GetBuild4ComponentQuantity();
-		else if (i == 5 || i == tradeskill->usedComponents.size() - 1)
-			qty = recipe->GetFuelComponentQuantity();
-
+		
+		
 		// Get the item in the players inventory and remove or reduce the quantity
-		int32 itmid = *itr;
-		item = client->GetPlayer()->item_list.GetItemFromID(itmid);
+		int32 itmid = itr->first;
+		qty = itr->second;
+		item = client->GetPlayer()->item_list.GetItemFromUniqueID(itmid);
 		if (item && item->details.count <= qty)
 		{
 			item->details.item_locked = false;
@@ -381,10 +370,13 @@ void TradeskillMgr::StopCrafting(Client* client, bool lock) {
 	item = 0;
 	qty = recipe->GetFuelComponentQuantity();	
 	item_id = recipe->components[5][0];
+	int8 HS = playerRecipe->GetHighestStage();
 	if (progress >= 400 && progress < 600) {
-		if (playerRecipe->GetHighestStage() < 1) {
-			playerRecipe->SetHighestStage(1);
-			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), 1);
+		if (HS & (1 << (1 - 1))) {
+		}
+		else {
+			playerRecipe->SetHighestStage(HS + 1 );
+			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), playerRecipe->GetHighestStage());
 		}
 		if (recipe->products.count(1) > 0) {
 			item_id = recipe->products[1]->product_id;
@@ -392,9 +384,11 @@ void TradeskillMgr::StopCrafting(Client* client, bool lock) {
 		}
 	}
 	else if ((dur < 200 && progress >= 600) || (dur >= 200 && progress >= 600 && progress < 800)) {
-		if (playerRecipe->GetHighestStage() < 2) {
-			playerRecipe->SetHighestStage(2);
-			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), 2);
+		if (HS & (1 << (2 - 1))) {
+		}
+		else {
+			playerRecipe->SetHighestStage(HS + 2);
+			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), playerRecipe->GetHighestStage());
 		}
 		if (recipe->products.count(2) > 0) {
 			item_id = recipe->products[2]->product_id;
@@ -402,9 +396,11 @@ void TradeskillMgr::StopCrafting(Client* client, bool lock) {
 		}
 	}
 	else if ((dur >= 200 && dur < 800 && progress >= 800) || (dur >= 800 && progress >= 800 && progress < 1000)) {
-		if (playerRecipe->GetHighestStage() < 3) {
-			playerRecipe->SetHighestStage(3);
-			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), 3);
+		if (HS & (1 << (3 - 1))) {
+		}
+		else {
+			playerRecipe->SetHighestStage(HS + 4);
+			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), playerRecipe->GetHighestStage());
 		}
 		if (recipe->products.count(3) > 0) {
 			item_id = recipe->products[3]->product_id;
@@ -412,9 +408,11 @@ void TradeskillMgr::StopCrafting(Client* client, bool lock) {
 		}
 	}
 	else if (dur >= 800 && progress >= 1000) {
-		if (playerRecipe->GetHighestStage() < 4) {
-			playerRecipe->SetHighestStage(4);
-			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), 4);
+		if (HS & (1 << (4 - 1))) {
+		}
+		else {
+			playerRecipe->SetHighestStage(HS + 8);
+			database.UpdatePlayerRecipe(client->GetPlayer(), recipe->GetID(), playerRecipe->GetHighestStage());
 		}
 		if (recipe->products.count(4) > 0) {
 			item_id = recipe->products[4]->product_id;

+ 2 - 2
EQ2/source/WorldServer/Tradeskills/Tradeskills.h

@@ -54,7 +54,7 @@ struct Tradeskill
 	int32			currentProgress;
 	int32			currentDurability;
 	int32			nextUpdateTime;
-	vector<int32>	usedComponents;
+	vector<pair<int32, int8>>	usedComponents;
 	TradeskillEvent* CurrentEvent;
 	bool			eventChecked;
 	bool			eventCountered;
@@ -72,7 +72,7 @@ public:
 	/// <summary>Starts the actual crafting process</summary>
 	/// <param name='client'>Client that is crafting</param>
 	/// <param name='components'>List of items the player is using to craft</param>
-	void BeginCrafting(Client* client, vector<int32> components);
+	void BeginCrafting(Client* client, vector<pair<int32, int8>> components);
 
 	/// <summary>Stops the crafting process</summary>
 	/// <param name='client'>Client that stopped crafting</param>

+ 220 - 79
EQ2/source/WorldServer/Tradeskills/TradeskillsPackets.cpp

@@ -64,61 +64,123 @@ void ClientPacketFunctions::SendCreateFromRecipe(Client* client, int32 recipeID)
 		return;
 	}
 	vector<int32>::iterator itr;
+	vector<Item*> itemss;
 	int8 i = 0;
+	int8 k = 0;
 	int32 firstID = 0;
+	int32 IDcount = 0;
 	int32 primary_comp_id = 0;
+	Item* first_item = 0;
 	Item* item = 0;
+	Item* item_player = 0;
+	Spawn* target = 0;
+	if (!(target = client->GetPlayer()->GetTarget())) {
+
+		client->Message(CHANNEL_COLOR_YELLOW, "You must be at a  %s in order to crafte this recipe", recipe->GetDevice());
+		return;
+	}
 
 	// Recipe and crafting table info
 	packet->setDataByName("crafting_station", recipe->GetDevice());
 	packet->setDataByName("recipe_name", recipe->GetName());
 	packet->setDataByName("tier", recipe->GetTier());
-
+	// Mass Production
+	int32 mpq = 1; 
+	int32 mp = 5;
+	vector<int> v{ 1,2,4,6,11,21 };
+	// mpq will eventually be retrieved from achievement for mass production
+	mpq = v[mp];
+	
+	packet->setArrayLengthByName("num_mass_production_choices",mpq);
+	packet->setArrayDataByName("mass_qty", 1, 0);
+	for (int x = 1; x < mpq; x++) {
+		packet->setArrayDataByName("mass_qty", x * 5, x);
+	}
 	// Product info
 	item = master_item_list.GetItem(recipe->GetProductID());
 	packet->setDataByName("product_name", item->name.c_str());
 	packet->setDataByName("icon", item->details.icon);
 	packet->setDataByName("product_qty", recipe->GetProductQuantity());
 	packet->setDataByName("primary_title", recipe->GetPrimaryBuildComponentTitle());
-	packet->setDataByName("primary_qty", 1);
-
+	packet->setDataByName("primary_qty_needed", recipe->GetPrimaryComponentQuantity());
+	packet->setDataByName("unknown6", 11);
+	packet->setDataByName("unknown3", 18);
 	// Reset item to 0
-	item = 0;
-
+	item, item_player = 0;
+	
 	// Check to see if we have a primary component (slot = 0)
 	if (recipe->components.count(0) > 0) {
 		vector<int32> rc = recipe->components[0];
-		packet->setArrayLengthByName("num_primary_choices", rc.size());
+			vector <pair<int32, int16>> selected_items;
 		for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
 			if (firstID == 0)
 				firstID = *itr;
 
 			item = master_item_list.GetItem(*itr);
-			if(!item)
+			if (!item)
 			{
 				LogWrite(TRADESKILL__ERROR, 0, "Recipes", "Error creating packet to client missing item %u", *itr);
 				client->Message(CHANNEL_COLOR_RED, "Error producing create recipe packet!  Recipe is trying to find item %u, but it is missing!", *itr);
 				safe_delete(packet);
 				return;
 			}
-			packet->setArrayDataByName("primary_component", item->name.c_str(), i);
-			packet->setArrayDataByName("primary_item_id", (*itr), i);
-			packet->setArrayDataByName("primary_icon", item->details.icon, i);
-			item = 0;
-			item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-			if (item)
-				packet->setArrayDataByName("primary_total_quantity", item->details.count, i);
+			item_player = 0;
+			item_player = client->GetPlayer()->item_list.GetItemFromID((*itr));
+
+			itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+			packet->setArrayLengthByName("num_primary_choices", itemss.size());
+			if (itemss.size() > 0) {
+				
+				int16 needed_qty = recipe->GetPrimaryComponentQuantity();
+				int16 have_qty = 0;
+				if (firstID == 0)
+					firstID = *itr;
+				for (int8 i = 0; i < itemss.size(); i++) {
+					IDcount++;
+					if (have_qty < needed_qty) {
+
+						int16 stack_count = itemss[i]->details.count;
+						int16 min_qty = min(stack_count, int16(needed_qty - have_qty));
+						selected_items.push_back(make_pair(int32(itemss[i]->details.unique_id), min_qty));
+						have_qty += min_qty;
+					}
+					packet->setArrayDataByName("primary_component", itemss[i]->name.c_str(), i);
+					packet->setArrayDataByName("primary_item_id", itemss[i]->details.unique_id, i);
+					packet->setArrayDataByName("primary_icon", itemss[i]->details.icon, i);
+					packet->setArrayDataByName("primary_total_quantity", itemss[i]->details.count, i);
+					//packet->setArrayDataByName("primary_supply_depot", itemss[i]->details.count, i);  // future need
+					//packet->setArrayDataByName("primary_unknown3a",);      // future need
+				}
+				packet->setDataByName("primary_id", itemss[0]->details.unique_id);
+				packet->setDataByName("primary_default_selected_id", itemss[0]->details.unique_id);
+				for (int8 i = 0; i < selected_items.size(); i++) {
+
+
+
+
+
+				}
+				int16 qty = 0;
+				if (item) {
+					qty = (int8)item->details.count;
+					if (qty > 0 && firstID == primary_comp_id)
+						qty -= 1;
+				}
+			}
+			else
+				packet->setDataByName("primary_id",*itr);
 		}
 		// store the id of the primary comp
 		primary_comp_id = firstID;
+		
 		// Set the default item id to the first component id
-		packet->setDataByName("primary_item_selected", 1);
-		packet->setDataByName("primary_default_selected_id", firstID);
-		item = 0;
-		item = client->GetPlayer()->item_list.GetItemFromID(firstID);
-		if (item)
-			packet->setDataByName("primary_selected_item_qty", min((int8)1, (int8)item->details.count));
+		packet->setArrayLengthByName("num_primary_items_selected", selected_items.size());
+		for (int8 i = 0; i < selected_items.size(); i++) {
+			packet->setArrayDataByName("primary_selected_item_qty", selected_items[i].second,i  );
+			packet->setArrayDataByName("primary_selected_item_id", selected_items[i].first,i);
 
+		}
+				
 		// Reset the variables we will reuse
 		i = 0;
 		firstID = 0;
@@ -131,7 +193,7 @@ void ClientPacketFunctions::SendCreateFromRecipe(Client* client, int32 recipeID)
 
 	// Check to see if we have build components (slot = 1 - 4)
 	int8 total_build_components = 0;
-	if (recipe->components.count(1) > 0)
+	if (recipe->components.count(1) > 0) 
 		total_build_components++;
 	if (recipe->components.count(2))
 		total_build_components++;
@@ -139,107 +201,187 @@ void ClientPacketFunctions::SendCreateFromRecipe(Client* client, int32 recipeID)
 		total_build_components++;
 	if (recipe->components.count(4))
 		total_build_components++;
-
+	//--------------------------------------------------------------Start Build Components-------------------------------------------------------------
 	if (total_build_components > 0) {
 		packet->setArrayLengthByName("num_build_components", total_build_components);
+		LogWrite(TRADESKILL__ERROR, 0, "Recipes", "num_build_components ", total_build_components);
 		for (int8 index = 0; index < 4; index++) {
-
 			if (recipe->components.count(index + 1) == 0)
 				continue;
-
 			packet->setArrayDataByName("build_slot", index, index);
-
 			vector<int32> rc = recipe->components[index + 1];
-
-			packet->setSubArrayLengthByName("num_build_choices", rc.size(), index);
-			for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
-				if (firstID == 0)
-					firstID = *itr;
-
+			int32 total_component_items = 0;
+			int8 hasComp = 0;
+			vector <pair<int32, int16>> selected_items;
+			for (itr = rc.begin(); itr != rc.end(); itr++) {
+				itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+				if (itemss.size() > 0)
+					total_component_items += itemss.size();
+			}
+			packet->setSubArrayLengthByName("num_build_choices", total_component_items, index);// get # build choces first
+			hasComp = 0;
+			char msgbuf[200] = "";
+			for (itr = rc.begin(); itr != rc.end(); itr++) {// iterates through each recipe component to find the stacks in inventory
 				item = master_item_list.GetItem(*itr);
-			
-				packet->setSubArrayDataByName("build_component", item->name.c_str(), index, i);
-				packet->setSubArrayDataByName("build_item_id", (*itr), index, i);
-				packet->setSubArrayDataByName("build_icon", item->details.icon, index, i);
-
-				item = 0;
-				item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-				if (item)
-					packet->setSubArrayDataByName("build_total_quantity", item->details.count, index, i);
+				itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+				sprintf(msgbuf, "k=%d hascomp=%d \n", k, hasComp);
+				OutputDebugString(msgbuf);
+				if (itemss.size() > 0) { 
+					int16 needed_qty = 0;
+					int16 have_qty = 0;
+					if (index == 0) {
+						needed_qty = recipe->GetBuild1ComponentQuantity();
+						have_qty = 0;
+					}
+					else if (index == 1) {
+						needed_qty = recipe->GetBuild2ComponentQuantity();
+						have_qty = 0;
+					}
+					else if (index == 2) {
+						needed_qty = recipe->GetBuild3ComponentQuantity();
+						have_qty = 0;
+					}
+					else if (index == 3) {
+						needed_qty = recipe->GetBuild4ComponentQuantity();
+						have_qty = 0;
+					}
+					if (firstID == 0)
+						firstID = *itr;
+					if (hasComp == 0) {
+						hasComp = 100 + k;
+					}
+					for (int8 j = 0; j < itemss.size(); j++, k++) { // go through each stack of a compnent
+						if (have_qty < needed_qty) {
+
+							int16 stack_count = itemss[j]->details.count;
+							int16 min_qty = min(stack_count, int16(needed_qty - have_qty));
+							selected_items.push_back(make_pair(int32(itemss[j]->details.unique_id), min_qty));
+							have_qty += min_qty;
+						}
+						item = master_item_list.GetItem(itemss[j]->details.item_id);
+						packet->setSubArrayDataByName("build_component", itemss[j]->name.c_str(), index, k);
+						packet->setSubArrayDataByName("build_item_id", itemss[j]->details.unique_id, index, k);
+						packet->setSubArrayDataByName("build_icon", itemss[j]->details.icon, index, k);
+						packet->setSubArrayDataByName("build_total_quantity", itemss[j]->details.count, index, k);
+						//packet->setSubArrayDataByName("build_supply_depot",);  // future need
+						//packet->setSubArrayDataByName("build_unknown3",);      // future need
+
+					}
+				}
 			}
+			packet->setArrayLengthByName("num_build_items_selected", selected_items.size());
+			for (int8 i = 0; i < selected_items.size(); i++) {
+				packet->setArrayDataByName("build_selected_item_qty", selected_items[i].second, i);
+				packet->setArrayDataByName("build_selected_id", selected_items[i].first, i);
 
-			// Set the default item id to the first component id
-			packet->setArrayDataByName("build_item_selected", 1, index);
-			packet->setArrayDataByName("build_selected_item_id", firstID, index);
-			item = 0;
-			item = client->GetPlayer()->item_list.GetItemFromID(firstID);
-			int8 qty = 0;
+			}
+			int16 qty = 0;
 			if (item) {
-				qty = (int8)item->details.count;
+				qty = (int16)item->details.count;
 				if (qty > 0 && firstID == primary_comp_id)
 					qty -= 1;
 			}
-
 			if (index == 0) {
 				packet->setArrayDataByName("build_title", recipe->GetBuild1ComponentTitle(), index);
-				packet->setArrayDataByName("build_qty", recipe->GetBuild1ComponentQuantity(), index);
+				packet->setArrayDataByName("build_qty_needed", recipe->GetBuild1ComponentQuantity(), index);
 				if (item)
-					packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild1ComponentQuantity()), index);
+					packet->setArrayDataByName("build_selected_item_qty_have", min(qty, recipe->GetBuild1ComponentQuantity()), index);
 			}
 			else if (index == 1) {
 				packet->setArrayDataByName("build_title", recipe->GetBuild2ComponentTitle(), index);
-				packet->setArrayDataByName("build_qty", recipe->GetBuild2ComponentQuantity(), index);
+				packet->setArrayDataByName("build_qty_needed", recipe->GetBuild2ComponentQuantity(), index);
 				if (item)
-					packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild2ComponentQuantity()), index);
+					packet->setArrayDataByName("build_selected_item_qty_have", min(qty, recipe->GetBuild2ComponentQuantity()), index);
 			}
 			else if (index == 2) {
 				packet->setArrayDataByName("build_title", recipe->GetBuild3ComponentTitle(), index);
-				packet->setArrayDataByName("build_qty", recipe->GetBuild3ComponentQuantity(), index);
+				packet->setArrayDataByName("build_qty_needed", recipe->GetBuild3ComponentQuantity(), index);
 				if (item)
-					packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild3ComponentQuantity()), index);
+					packet->setArrayDataByName("build_selected_item_qty_have", min(qty, recipe->GetBuild3ComponentQuantity()), index);
 			}
 			else {
 				packet->setArrayDataByName("build_title", recipe->GetBuild4ComponentTitle(), index);
-				packet->setArrayDataByName("build_qty", recipe->GetBuild4ComponentQuantity(), index);
+				packet->setArrayDataByName("build_qty_needed", recipe->GetBuild4ComponentQuantity(), index);
 				if (item)
-					packet->setArrayDataByName("build_selected_item_qty", min(qty, recipe->GetBuild4ComponentQuantity()), index);
+					packet->setArrayDataByName("build_selected_item_qty_have", min(qty, recipe->GetBuild4ComponentQuantity()), index);
 			}
 
 			// Reset the variables we will reuse
 			i = 0;
 			firstID = 0;
 			item = 0;
-		}
+			k = 0;
+			}
+		
+		
+		int32 xxx = 0;
 	}
 
+
 	// Check to see if we have a fuel component (slot = 5)
 	if (recipe->components.count(5) > 0) {
 		vector<int32> rc = recipe->components[5];
-		packet->setArrayLengthByName("num_fuel_choices", rc.size());
+		vector <pair<int32, int16>> selected_items;
 		for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
 			if (firstID == 0)
 				firstID = *itr;
-
 			item = master_item_list.GetItem(*itr);
-
-			packet->setArrayDataByName("fuel_component", item->name.c_str(), i);
-			packet->setArrayDataByName("fuel_item_id", (*itr), i);
-			packet->setArrayDataByName("fuel_icon", item->details.icon, i);
-			item = 0;
-			item = client->GetPlayer()->item_list.GetItemFromID((*itr));
-			if (item)
-				packet->setArrayDataByName("fuel_total_quantity", item->details.count, i);
+			if (!item)
+			{
+				LogWrite(TRADESKILL__ERROR, 0, "Recipes", "Error creating packet to client missing item %u", *itr);
+				client->Message(CHANNEL_COLOR_RED, "Error producing create recipe packet!  Recipe is trying to find item %u, but it is missing!", *itr);
+				safe_delete(packet);
+				return;
+			}
+			item_player = 0;
+			item_player = client->GetPlayer()->item_list.GetItemFromID((*itr));
+
+			itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
+			packet->setArrayLengthByName("num_fuel_choices", itemss.size());
+			if (itemss.size() > 0) {
+				int16 needed_qty = recipe->GetFuelComponentQuantity();
+				int16 have_qty = 0;
+				if (firstID == 0)
+					firstID = *itr;
+				for (int8 i = 0; i < itemss.size(); i++) {
+					IDcount++;
+					if (have_qty < needed_qty) {
+
+						int16 stack_count = itemss[i]->details.count;
+						int16 min_qty = min(stack_count, int16(needed_qty - have_qty));
+						selected_items.push_back(make_pair(int32(itemss[i]->details.unique_id), min_qty));
+						have_qty += min_qty;
+					}
+					packet->setArrayDataByName("fuel_component", itemss[i]->name.c_str(), i);
+					packet->setArrayDataByName("fuel_item_id", itemss[i]->details.unique_id, i);
+					packet->setArrayDataByName("fuel_icon", itemss[i]->details.icon, i);
+					packet->setArrayDataByName("fuel_total_quantity", itemss[i]->details.count, i);
+					//packet->setArrayDataByName("fuel_supply_depot", itemss[i]->details.count, i);  // future need
+					//packet->setArrayDataByName("primary_unknown3a",);      // future need
+				}
+				packet->setDataByName("fuel_selected_item_id", itemss[0]->details.unique_id);
+				int16 qty = 0;
+				if (item) {
+					qty = (int8)item->details.count;
+					if (qty > 0 && firstID == primary_comp_id)
+						qty -= 1;
+				}
+			}
+			else
+				packet->setDataByName("primary_vvv", *itr);
 		}
+		// store the id of the primary comp
+		primary_comp_id = firstID;
 
 		// Set the default item id to the first component id
-		packet->setDataByName("fuel_selected_item_id", firstID);
-		packet->setDataByName("fuel_item_selected", 1);
-		item = 0;
-		item = client->GetPlayer()->item_list.GetItemFromID(firstID);
-		if (item)
-			packet->setDataByName("fuel_selected_item_qty", min(recipe->GetFuelComponentQuantity(), (int8)item->details.count));
-		packet->setDataByName("fuel_title",recipe->GetFuelComponentTitle());
-		packet->setDataByName("fuel_qty",recipe->GetFuelComponentQuantity());
+		packet->setArrayLengthByName("num_fuel_items_selected", selected_items.size());
+		for (int8 i = 0; i < selected_items.size(); i++) {
+			packet->setArrayDataByName("fuel_selected_item_qty", selected_items[i].second, i);
+			packet->setArrayDataByName("fuel_selected_item_id", selected_items[i].first, i);
+		}
+		packet->setDataByName("fuel_title", recipe->GetFuelComponentTitle());
+		packet->setDataByName("fuel_qty_needed", recipe->GetFuelComponentQuantity());
+
 
 		// Reset the variables we will reuse
 		i = 0;
@@ -251,10 +393,9 @@ void ClientPacketFunctions::SendCreateFromRecipe(Client* client, int32 recipeID)
 		return;
 	}
 
-	packet->setDataByName("unknown1", recipeID);
-	packet->setDataByName("unknown8", 1); // Possible array for amount you can craft
-	packet->setDataByName("unknown8", 1, 1); // amounts you can craft
-	//packet->PrintPacket();
+	packet->setDataByName("recipe_id", recipeID);
+	
+	packet->PrintPacket();
 	// Send the packet
 	client->QueuePacket(packet->serialize());
 	safe_delete(packet);

+ 41 - 18
EQ2/source/WorldServer/client.cpp

@@ -1682,27 +1682,49 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 		if (packet) {
 			packet->LoadPacketData(app->pBuffer, app->size);
 			int32 item = 0;
-			vector<int32> items;
-			char tmp_item_id[20];
-			item = packet->getType_int32_ByName("primary_component_id");
-			if (item > 0)
-				items.push_back(item);
-			item = 0;
+			int8 qty = 0;
+			vector<pair<int32, int8>> items;
+			char tmp_item_id[30];
+			int8 num_primary_selected_items = packet->getType_int8_ByName("num_primary_selected_items");
+			for (int8 i = 0; i < num_primary_selected_items; i++) {
+				memset(tmp_item_id, 0, 30);
+				sprintf(tmp_item_id, "primary_selected_item_id_%i", i);
+				item = packet->getType_int32_ByName(tmp_item_id);
+				sprintf(tmp_item_id, "primary_selected_item_qty_%i", i);
+				qty = packet->getType_int8_ByName(tmp_item_id);
+				if (item > 0)
+					items.push_back(make_pair(item,qty));
+				item = 0;
+			}
 			int8 build_components = packet->getType_int8_ByName("num_build_components");
 			for (int8 i = 0; i < build_components; i++) {
-				memset(tmp_item_id, 0, 20);
-				sprintf(tmp_item_id, "component_id_%i", i);
+				memset(tmp_item_id, 0, 30);
+				sprintf(tmp_item_id, "num_selected_items_%i", i);
+				int8 num_selected_items = packet->getType_int8_ByName(tmp_item_id);
+				for (int8 j = 0; j < num_selected_items; j++) {
+					memset(tmp_item_id, 0, 30);
+					sprintf(tmp_item_id, "selected_id%i_%i", i,j);
+					item = packet->getType_int32_ByName(tmp_item_id);
+					sprintf(tmp_item_id, "selected_qty%i_%i", i, j);
+					qty = packet->getType_int8_ByName(tmp_item_id);
+					if (item > 0)
+						items.push_back(make_pair(item, qty));
+
+					item = 0;
+				}
+			}
+			int8 num_fuel_items = packet->getType_int8_ByName("num_fuel_items");
+			for (int8 i = 0; i < num_fuel_items; i++) {
+				memset(tmp_item_id, 0, 30);
+				sprintf(tmp_item_id, "selected_id_%i", i);
 				item = packet->getType_int32_ByName(tmp_item_id);
+				sprintf(tmp_item_id, "selected_qty_%i", i);
+				qty = packet->getType_int8_ByName(tmp_item_id);
 				if (item > 0)
-					items.push_back(item);
-
+					items.push_back(make_pair(item, qty));
 				item = 0;
 			}
-
-			item = packet->getType_int32_ByName("fuel_id");
-			if (item > 0)
-				items.push_back(item);
-
+			
 			GetCurrentZone()->GetTradeskillMgr()->BeginCrafting(this, items);
 
 			safe_delete(packet);
@@ -2848,7 +2870,8 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 	if (type == 3) {
 		Spell* spell = 0;
 		bool trait_display;
-		request = configReader.getStruct("WS_ExamineInfoRequest", GetVersion());
+		
+		request = configReader.getStruct("WS_ExamineInfoRequestMsg", GetVersion());
 		if (!request) {
 			return;
 		}
@@ -3039,7 +3062,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		}
 	}
 	else if (type == 5) { // recipe info
-		request = configReader.getStruct("WS_ExamineInfoRequest", GetVersion());
+	request = configReader.getStruct("WS_ExamineInfoRequestMsg", GetVersion());
 		if (!request)
 			return;
 		request->LoadPacketData(app->pBuffer, app->size);
@@ -3056,7 +3079,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		Spell* spell = 0;
 		//Spell* spell2 = 0;
 		//AltAdvanceData* data = 0;
-		request = configReader.getStruct("WS_ExamineInfoRequest", GetVersion());
+		request = configReader.getStruct("WS_ExamineInfoRequestMsg", GetVersion());
 		if (!request)
 			return;
 		request->LoadPacketData(app->pBuffer, app->size);

+ 57 - 49
server/WorldStructs.xml

@@ -6405,19 +6405,19 @@ to zero and treated like placeholders." />
 <Data ElementName="unique_id" Type="int32" />
 <Data ElementName="unknown5" Type="int16" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequest" ClientVersion="1" >
+<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="1" OpcodeName="OP_ExamineInfoRequestMsg">
 <Data ElementName="type" Type="int8" Size="1" />
 <Data ElementName="id" Type="int32" />
 <Data ElementName="display" Type="int8" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequest" ClientVersion="546" >
+<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="546" OpcodeName="OP_ExamineInfoRequestMsg">
 <Data ElementName="type" Type="int8" Size="1" />
 <Data ElementName="unique_id" Type="int32" />
 <Data ElementName="id" Type="int32" />
 <Data ElementName="unknown5" Type="int8" />
 <Data ElementName="display" Type="int8" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequest" ClientVersion="860" >
+<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="860" OpcodeName="OP_ExamineInfoRequestMsg">
 <Data ElementName="type" Type="int8" Size="1" />
 <Data ElementName="unknown_id" Type="int32" />
 <Data ElementName="unknown" Type="int32" />
@@ -6425,7 +6425,7 @@ to zero and treated like placeholders." />
 <Data ElementName="id" Type="int32" />
 <Data ElementName="unknown5" Type="int16" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequest" ClientVersion="1188" >
+<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="1188" OpcodeName="OP_ExamineInfoRequestMsg">
 <Data ElementName="type" Type="int8" Size="1" />
 <Data ElementName="unknown_id" Type="int32" />
 <Data ElementName="unknown2" Type="int32" />
@@ -6434,7 +6434,7 @@ to zero and treated like placeholders." />
 <Data ElementName="id" Type="int32" />
 <Data ElementName="unknown6" Type="int16" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequest" ClientVersion="60114" >
+<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="60114" OpcodeName="OP_ExamineInfoRequestMsg">
 <Data ElementName="type" Type="int8" Size="1" />
 <Data ElementName="unknown_id" Type="int32" />
 <Data ElementName="unknown2" Type="int32" />
@@ -6443,7 +6443,7 @@ to zero and treated like placeholders." />
 <Data ElementName="id" Type="int32" />
 <Data ElementName="unknown6" Type="int16" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequest" ClientVersion="63119" >
+<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="63119" OpcodeName="OP_ExamineInfoRequestMsg">
 <Data ElementName="type" Type="int8" Size="1" />
 <Data ElementName="id" Type="int32" />
 <Data ElementName="unique_id" Type="int32" />
@@ -16026,7 +16026,7 @@ to zero and treated like placeholders." />
 </Struct>
 <Struct Name="WS_CreateFromRecipe" ClientVersion="57048" OpcodeName="OP_ShowCreateFromRecipeUIMsg">
 <Data ElementName="crafting_station" Type="EQ2_16Bit_String" />
-<Data ElementName="unknown1" Type="int32" Size="1" />
+<Data ElementName="recipe_id" Type="int32" Size="1" />
 <Data ElementName="recipe_name" Type="EQ2_16Bit_String" />
 <Data ElementName="tier" Type="int8" Size="1" />
 <Data ElementName="unknown3" Type="int32" Size="1" />
@@ -16036,29 +16036,35 @@ to zero and treated like placeholders." />
 <Data ElementName="unknown5" Type="int16" Size="1" />
 <Data ElementName="unknown6" Type="int8" Size="1" />
 <Data ElementName="unknown7" Type="int16" Size="1" />
-<Data ElementName="unknown8" Type="int8" Size="3" />
+<Data ElementName="num_mass_production_choices" Type="int8" Size="1" />
+<Data ElementName="mass_array" Type="Array" ArraySizeVariable="num_mass_production_choices">
+	<Data ElementName="mass_qty" Type="int16" Size="1" />
+</Data>
 <Data ElementName="primary_title" Type="EQ2_16Bit_String" />
 <Data ElementName="unknown9" Type="int8" Size="1" />
 <Data ElementName="primary_id" Type="int32" Size="1" />
 <Data ElementName="unknown10" Type="int8" Size="6" />
-<Data ElementName="primary_qty" Type="int16" Size="1" />
+<Data ElementName="primary_qty_needed" Type="int16" Size="1" />
 <Data ElementName="num_primary_choices" Type="int8" />
 <Data ElementName="primary_array" Type="Array" ArraySizeVariable="num_primary_choices">
   <Data ElementName="primary_component" Type="EQ2_16Bit_String" />
   <Data ElementName="primary_item_id" Type="int32" Size="1" />
   <Data ElementName="primary_icon" Type="int16" Size="1" />
   <Data ElementName="primary_total_quantity" Type="int16" Size="1" />
-  <Data ElementName="primary_supply_depot" Type="int8" Size="1" />
-  <Data ElementName="primary_unknown3" Type="int8" Size="4" />
+  <Data ElementName="primary_unknown3" Type="int8" Size="2" />
+	<Data ElementName="primary_supply_depot" Type="int8" Size="1" />
+  <Data ElementName="primary_unknown3a" Type="int8" Size="2" />
 </Data>
-<Data ElementName="primary_item_selected" Type="int8" />
-<Data ElementName="primary_default_selected_id" Type="int32" Size="1" />
-<Data ElementName="primary_selected_item_qty" Type="int16" Size="1" />
+<Data ElementName="num_primary_items_selected" Type="int8" />
+<Data ElementName="primary_items_selected_array" Type="Array" ArraySizeVariable="num_primary_items_selected">
+	<Data ElementName="primary_selected_item_id" Type="int32" Size="1" />
+	<Data ElementName="primary_selected_item_qty" Type="int16" Size="1" />
+</Data>	
 <Data ElementName="num_build_components" Type="int8" />
 <Data ElementName="build_array" Type="Array" ArraySizeVariable="num_build_components">
   <Data ElementName="build_slot" Type="int32" />
   <Data ElementName="build_title" Type="EQ2_16Bit_String" />
-  <Data ElementName="build_qty" Type="int16" />
+  <Data ElementName="build_qty_needed" Type="int16" />
   <Data ElementName="build_unknown1" Type="int32" Size="1" />
   <Data ElementName="num_build_choices" Type="int8" Size="1" />
   <Data ElementName="build_components_array" Type="Array" ArraySizeVariable="num_build_choices">
@@ -16066,29 +16072,35 @@ to zero and treated like placeholders." />
     <Data ElementName="build_item_id" Type="int32" Size="1" />
     <Data ElementName="build_icon" Type="int16" Size="1" />
     <Data ElementName="build_total_quantity" Type="int16" Size="1" />
-    <Data ElementName="build_supply_depot" Type="int8" Size="1" />
-    <Data ElementName="build_unknown6" Type="int8" Size="3" />
+		<Data ElementName="build_unknown6" Type="int8" Size="2" />
+		<Data ElementName="build_supply_depot" Type="int8" Size="1" />
+    <Data ElementName="build_unknown6a" Type="int8" Size="1" />
   </Data>
-  <Data ElementName="build_item_selected" Type="int8" Size="1" />
-  <Data ElementName="build_selected_item_id" Type="int32" Size="1" />
-  <Data ElementName="build_selected_item_qty" Type="int8" Size="1" />
-  <Data ElementName="unknown" Type="int8" Size="1" />
+  <Data ElementName="num_build_items_selected" Type="int8" />
+	<Data ElementName="build_items_selected_array" Type="Array" ArraySizeVariable="num_build_items_selected">
+		<Data ElementName="build_selected_item_id" Type="int32" Size="1" />
+		<Data ElementName="build_selected_item_qty" Type="int8" Size="1" />
+		<Data ElementName="unknown" Type="int8" Size="1" />
+	</Data>
 </Data>
 
 <Data ElementName="fuel_title" Type="EQ2_16Bit_String" />
-<Data ElementName="fuel_qty" Type="int16" />
+<Data ElementName="fuel_qty_needed" Type="int16" />
 <Data ElementName="num_fuel_choices" Type="int8" Size="1" />
 <Data ElementName="fuel_component_array" Type="Array" ArraySizeVariable="num_fuel_choices">
   <Data ElementName="fuel_component" Type="EQ2_16Bit_String" />
   <Data ElementName="fuel_item_id" Type="int32" Size="1" />
   <Data ElementName="fuel_icon" Type="int16" />
   <Data ElementName="fuel_total_quantity" Type="int16" Size="1" />
+  <Data ElementName="fuel_unknown4" Type="int8" Size="2" />
   <Data ElementName="fuel_supply_depot" Type="int8" Size="1" />
-  <Data ElementName="fuel_unknown4" Type="int8" Size="3" />
+  <Data ElementName="fuel_unknown4a" Type="int8" Size="1" />
+</Data>
+<Data ElementName="num_fuel_items_selected" Type="int8" />
+<Data ElementName="fuel_items_selected_array" Type="Array" ArraySizeVariable="num_fuel_items_selected">
+	<Data ElementName="fuel_selected_item_id" Type="int32" Size="1" />
+	<Data ElementName="fuel_selected_item_qty" Type="int16" Size="1" />
 </Data>
-<Data ElementName="fuel_item_selected" Type="int8" Size="1" />
-<Data ElementName="fuel_selected_item_id" Type="int32" Size="1" />
-<Data ElementName="fuel_selected_item_qty" Type="int16" Size="1" />
 </Struct>
 <Struct Name="WS_CreateFromRecipe" ClientVersion="63119" OpcodeName="OP_ShowCreateFromRecipeUIMsg">
 <Data ElementName="crafting_station" Type="EQ2_16Bit_String" />
@@ -16202,19 +16214,26 @@ to zero and treated like placeholders." />
 <Data ElementName="fuel_qty" Type="int16" Size="1" />
 </Struct>
 <Struct Name="WS_BeginItemCreation" ClientVersion="1199" OpcodeName="OP_BeginItemCreationMsg">
-<Data ElementName="unknown1" Type="int8" Size="11" />
-<Data ElementName="primary_component_id" Type="int32" Size="1" />
-<Data ElementName="primary_component_qty" Type="int16" Size="1" />
+<Data ElementName="unknown1" Type="int8" Size="10" />
+<Data ElementName="num_primary_selected_items" Type="int8" Size="1" />
+<Data ElementName="primary_selected_items_array" Type="Array" ArraySizeVariable="num_primary_selected_items">
+  <Data ElementName="primary_selected_item_id" Type="int32" Size="1" />
+  <Data ElementName="primary_selected_item_qty" Type="int16" Size="1" />
+</Data>
 <Data ElementName="num_build_components" Type="int8" Size="1" />
 <Data ElementName="component_array" Type="Array" ArraySizeVariable="num_build_components">
-  <Data ElementName="component_num" Type="int32" Size="1" />
-  <Data ElementName="component_unknown" Type="int8" Size="1" />
-  <Data ElementName="component_id" Type="int32" Size="1" />
-  <Data ElementName="component_qty" Type="int16" Size="1" />
-</Data>
-<Data ElementName="unknown2" Type="int8" Size="1" />
-<Data ElementName="fuel_id" Type="int32" Size="1" />
-<Data ElementName="fuel_qty" Type="int16" Size="1" />
+	<Data ElementName="unknown" Type="int32" Size="1" />
+		<Data ElementName="num_selected_items" Type="int8" Size="1" />
+		<Data ElementName="selected_item_array" Type="Array" ArraySizeVariable="num_selected_items">
+			<Data ElementName="selected_id" Type="int32" Size="1" />
+			<Data ElementName="selected_qty" Type="int16" Size="1" />
+		</Data>	
+	</Data>
+<Data ElementName="num_fuel_items" Type="int8" Size="1" />
+<Data ElementName="fuel_item_array" Type="Array" ArraySizeVariable="num_fuel_items">
+	<Data ElementName="fuel_id" Type="int32" Size="1" />
+	<Data ElementName="fuel_qty" Type="int16" Size="1" />
+	</Data>
 </Struct>
 <Struct Name="WS_RecipeList" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_RecipeList">
 <Data ElementName="unknown" Type="int8" Size="1" />
@@ -16504,7 +16523,7 @@ to zero and treated like placeholders." />
 <Data ElementName="bag_name" Type="EQ2_8Bit_String" Size="1" />
 </Struct>
 <Struct Name="WS_SupplyDepot" ClientVersion="1096" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_SupplyDepot">
- <Data ElementName="unknown1" Type="int8" Size="4" />
+ <Data ElementName="depot_id" Type="int32" Size="1" />
  <Data ElementName="depot_name" Type="EQ2_16Bit_String" />
  <Data ElementName="num_items" Type="int16" Size="1" />
  <Data ElementName="max_items" Type="int16" Size="1" />
@@ -18349,17 +18368,6 @@ to zero and treated like placeholders." />
   <Data ElementName="unknown3" Type="int8" />
   <Data ElementName="unknown4" Type="int8" />
 </Struct>
-<Struct Name="WS_ExamineInfoRequestMsg" ClientVersion="50000" OpcodeName="OP_ExamineInfoRequestMsg">
-  <Data ElementName="unknown" Type="int32" />
-  <Data ElementName="unknown1" Type="int32" />
-  <Data ElementName="unknown2" Type="int32" />
-  <Data ElementName="unknown3" Type="int32" />
-  <Data ElementName="unknown4" Type="int32" />
-  <Data ElementName="item_crc" Type="int32" />
-  <Data ElementName="unknown5" Type="int32" />
-  <Data ElementName="item_id" Type="int32" />
-  <Data ElementName="unknown6" Type="int16" />
-</Struct>
 <Struct Name="WS_PredictionUpdateMsg" ClientVersion="1" OpcodeName="OP_PredictionUpdateMsg">
 </Struct>
 <Struct Name="WS_QuestJournalInspectMsg" ClientVersion="1" OpcodeName="OP_QuestJournalInspectMsg">