9
3

Recipe.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. /*
  2. EQ2Emulator: Everquest II Server Emulator
  3. Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
  4. This file is part of EQ2Emulator.
  5. EQ2Emulator is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. EQ2Emulator is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <assert.h>
  17. #include "../../common/debug.h"
  18. #include "../../common/Log.h"
  19. #include "../../common/database.h"
  20. #include "Recipe.h"
  21. #include "../../common/ConfigReader.h"
  22. #include "../Items/Items.h"
  23. #include "../World.h"
  24. extern ConfigReader configReader;
  25. extern MasterItemList master_item_list;
  26. extern World world;
  27. Recipe::Recipe() {
  28. id = 0;
  29. book_id = 0;
  30. memset(name, 0, sizeof(name));
  31. memset(book_name, 0, sizeof(book_name));
  32. memset(book, 0, sizeof(book));
  33. memset(device, 0, sizeof(device));
  34. level = 0;
  35. tier = 0;
  36. icon = 0;
  37. skill = 0;
  38. technique = 0;
  39. knowledge = 0;
  40. classes = 0;
  41. unknown2 = 0;
  42. unknown3 = 0;
  43. unknown4 = 0;
  44. }
  45. Recipe::~Recipe() {
  46. map<int8, RecipeProducts*>::iterator itr;
  47. for (itr = products.begin(); itr != products.end(); itr++)
  48. safe_delete(itr->second);
  49. }
  50. Recipe::Recipe(Recipe *in){
  51. assert(in);
  52. id = in->GetID();
  53. soe_id = in->GetSoeID();
  54. book_id = in->GetBookID();
  55. strncpy(name, in->GetName(), sizeof(name));
  56. strncpy(description, in->GetDescription(), sizeof(description));
  57. strncpy(book_name, in->GetBookName(), sizeof(book_name));
  58. strncpy(book, in->GetBook(), sizeof(book));
  59. strncpy(device, in->GetDevice(), sizeof(device));
  60. level = in->GetLevel();
  61. tier = in->GetTier();
  62. icon = in->GetIcon();
  63. skill = in->GetSkill();
  64. technique = in->GetTechnique();
  65. knowledge = in->GetKnowledge();
  66. device_sub_type = in->GetDevice_Sub_Type();
  67. classes = in->GetClasses();
  68. unknown1 = in->GetUnknown1();
  69. unknown2 = in->GetUnknown2();
  70. unknown3 = in->GetUnknown3();
  71. unknown4 = in->GetUnknown4();
  72. product_item_id = in->GetProductID();
  73. strncpy(product_name, in->product_name, sizeof(product_name));
  74. product_qty = in->GetProductQuantity();
  75. strncpy(primary_build_comp_title, in->primary_build_comp_title, sizeof(primary_build_comp_title));
  76. strncpy(build1_comp_title, in->build1_comp_title, sizeof(build1_comp_title));
  77. strncpy(build2_comp_title, in->build2_comp_title, sizeof(build2_comp_title));
  78. strncpy(build3_comp_title, in->build3_comp_title, sizeof(build3_comp_title));
  79. strncpy(build4_comp_title, in->build4_comp_title, sizeof(build4_comp_title));
  80. strncpy(fuel_comp_title, in->fuel_comp_title, sizeof(fuel_comp_title));
  81. build1_comp_qty = in->GetBuild1ComponentQuantity();
  82. build2_comp_qty = in->GetBuild2ComponentQuantity();
  83. build3_comp_qty = in->GetBuild3ComponentQuantity();
  84. build4_comp_qty = in->GetBuild4ComponentQuantity();
  85. fuel_comp_qty = in->GetFuelComponentQuantity();
  86. primary_comp_qty = in->GetPrimaryComponentQuantity();
  87. highestStage = in->GetHighestStage();
  88. std::map<int8, RecipeProducts*>::iterator itr;
  89. for (itr = in->products.begin(); itr != in->products.end(); itr++) {
  90. RecipeProducts* rp = new RecipeProducts;
  91. rp->product_id = itr->second->product_id;
  92. rp->byproduct_id = itr->second->byproduct_id;
  93. rp->product_qty = itr->second->product_qty;
  94. rp->byproduct_qty = itr->second->byproduct_qty;
  95. products.insert(make_pair(itr->first, rp));
  96. }
  97. std::map<int8, vector<int32>>::iterator itr2;
  98. for (itr2 = in->components.begin(); itr2 != in->components.end(); itr2++) {
  99. std::vector<int32> recipe_component;
  100. std::copy(itr2->second.begin(), itr2->second.end(),
  101. std::back_inserter(recipe_component));
  102. components.insert(make_pair(itr2->first, recipe_component));
  103. }
  104. }
  105. MasterRecipeList::MasterRecipeList() {
  106. m_recipes.SetName("MasterRecipeList::recipes");
  107. }
  108. MasterRecipeList::~MasterRecipeList() {
  109. ClearRecipes();
  110. }
  111. bool MasterRecipeList::AddRecipe(Recipe *recipe) {
  112. bool ret = false;
  113. int32 id;
  114. assert(recipe);
  115. id = recipe->GetID();
  116. m_recipes.writelock(__FUNCTION__, __LINE__);
  117. if (recipes.count(id) == 0) {
  118. recipes[id] = recipe;
  119. recipes_crc[recipe->GetSoeID()] = recipe;
  120. ret = true;
  121. }
  122. m_recipes.releasewritelock(__FUNCTION__, __LINE__);
  123. return ret;
  124. }
  125. Recipe* MasterRecipeList::GetRecipe(int32 recipe_id) {
  126. Recipe *ret = 0;
  127. m_recipes.readlock(__FUNCTION__, __LINE__);
  128. if (recipes.count(recipe_id) > 0)
  129. ret = recipes[recipe_id];
  130. m_recipes.releasereadlock(__FUNCTION__, __LINE__);
  131. return ret;
  132. }
  133. Recipe* MasterRecipeList::GetRecipeByCRC(int32 recipe_crc) {
  134. Recipe *ret = 0;
  135. m_recipes.readlock(__FUNCTION__, __LINE__);
  136. if (recipes_crc.count(recipe_crc) > 0)
  137. ret = recipes_crc[recipe_crc];
  138. m_recipes.releasereadlock(__FUNCTION__, __LINE__);
  139. return ret;
  140. }
  141. Recipe* MasterRecipeList::GetRecipeByName(const char* name) {
  142. Recipe* ret = 0;
  143. map<int32, Recipe*>::iterator itr;
  144. m_recipes.readlock(__FUNCTION__, __LINE__);
  145. for (itr = recipes.begin(); itr != recipes.end(); itr++) {
  146. if (::ToLower(string(name)) == ::ToLower(string(itr->second->GetName()))) {
  147. ret = itr->second;
  148. break;
  149. }
  150. }
  151. m_recipes.releasereadlock(__FUNCTION__, __LINE__);
  152. return ret;
  153. }
  154. void MasterRecipeList::ClearRecipes() {
  155. map<int32, Recipe *>::iterator itr;
  156. m_recipes.writelock(__FUNCTION__, __LINE__);
  157. for (itr = recipes.begin(); itr != recipes.end(); itr++)
  158. safe_delete(itr->second);
  159. recipes.clear();
  160. recipes_crc.clear();
  161. m_recipes.releasewritelock(__FUNCTION__, __LINE__);
  162. }
  163. int32 MasterRecipeList::Size() {
  164. int32 ret;
  165. m_recipes.readlock(__FUNCTION__, __LINE__);
  166. ret = (int32)recipes.size();
  167. m_recipes.releasereadlock(__FUNCTION__, __LINE__);
  168. return ret;
  169. }
  170. vector<Recipe*> MasterRecipeList::GetRecipes(const char* book_name) {
  171. vector<Recipe*> ret;
  172. map<int32, Recipe *>::iterator itr;
  173. m_recipes.writelock(__FUNCTION__, __LINE__);
  174. for (itr = recipes.begin(); itr != recipes.end(); itr++) {
  175. if (::ToLower(string(book_name)) == ::ToLower(string(itr->second->GetBook())))
  176. ret.push_back(itr->second);
  177. }
  178. m_recipes.releasewritelock(__FUNCTION__, __LINE__);
  179. return ret;
  180. }
  181. PlayerRecipeList::PlayerRecipeList(){
  182. }
  183. PlayerRecipeList::~PlayerRecipeList(){
  184. ClearRecipes();
  185. }
  186. bool PlayerRecipeList::AddRecipe(Recipe *recipe){
  187. std::unique_lock lock(player_recipe_mutex);
  188. assert(recipe);
  189. if(recipes.count(recipe->GetID()) == 0){
  190. recipes[recipe->GetID()] = recipe;
  191. return true;
  192. }
  193. return false;
  194. }
  195. Recipe * PlayerRecipeList::GetRecipe(int32 recipe_id){
  196. std::shared_lock lock(player_recipe_mutex);
  197. if (recipes.count(recipe_id) > 0)
  198. return recipes[recipe_id];
  199. return 0;
  200. }
  201. void PlayerRecipeList::ClearRecipes(){
  202. std::unique_lock lock(player_recipe_mutex);
  203. map<int32, Recipe *>::iterator itr;
  204. for (itr = recipes.begin(); itr != recipes.end(); itr++)
  205. safe_delete(itr->second);
  206. recipes.clear();
  207. }
  208. bool PlayerRecipeList::RemoveRecipe(int32 recipe_id) {
  209. std::unique_lock lock(player_recipe_mutex);
  210. bool ret = false;
  211. if (recipes.count(recipe_id) > 0) {
  212. recipes.erase(recipe_id);
  213. ret = true;
  214. }
  215. return ret;
  216. }
  217. int32 PlayerRecipeList::Size() {
  218. std::unique_lock lock(player_recipe_mutex);
  219. return recipes.size();
  220. }
  221. MasterRecipeBookList::MasterRecipeBookList(){
  222. m_recipeBooks.SetName("MasterRecipeBookList::recipeBooks");
  223. }
  224. MasterRecipeBookList::~MasterRecipeBookList(){
  225. ClearRecipeBooks();
  226. }
  227. bool MasterRecipeBookList::AddRecipeBook(Recipe *recipe){
  228. bool ret = false;
  229. int32 id = 0;
  230. assert(recipe);
  231. id = recipe->GetBookID();
  232. m_recipeBooks.writelock(__FUNCTION__, __LINE__);
  233. if(recipeBooks.count(id) == 0){
  234. recipeBooks[id] = recipe;
  235. ret = true;
  236. }
  237. m_recipeBooks.releasewritelock(__FUNCTION__, __LINE__);
  238. return ret;
  239. }
  240. Recipe * MasterRecipeBookList::GetRecipeBooks(int32 recipebook_id){
  241. Recipe *ret = 0;
  242. m_recipeBooks.readlock(__FUNCTION__, __LINE__);
  243. if (recipeBooks.count(recipebook_id) > 0)
  244. ret = recipeBooks[recipebook_id];
  245. m_recipeBooks.releasereadlock(__FUNCTION__, __LINE__);
  246. return ret;
  247. }
  248. void MasterRecipeBookList::ClearRecipeBooks(){
  249. map<int32, Recipe *>::iterator itr;
  250. m_recipeBooks.writelock(__FUNCTION__, __LINE__);
  251. for (itr = recipeBooks.begin(); itr != recipeBooks.end(); itr++)
  252. safe_delete(itr->second);
  253. recipeBooks.clear();
  254. m_recipeBooks.releasewritelock(__FUNCTION__, __LINE__);
  255. }
  256. int32 MasterRecipeBookList::Size(){
  257. int32 ret = 0;
  258. m_recipeBooks.readlock(__FUNCTION__, __LINE__);
  259. ret = (int32)recipeBooks.size();
  260. m_recipeBooks.releasereadlock(__FUNCTION__, __LINE__);
  261. return ret;
  262. }
  263. EQ2Packet* MasterRecipeList::GetRecipePacket(int32 recipe_id, Client* client, bool display, int8 packet_type){
  264. Recipe *recipe = GetRecipe(recipe_id);
  265. if(recipe){
  266. LogWrite(TRADESKILL__DEBUG, 5, "Recipes", "Recipe ID: %u Recipe Name: %s", recipe->GetID(), recipe->GetName());
  267. return recipe->SerializeRecipe(client, recipe, display, packet_type);
  268. }
  269. return 0;
  270. }
  271. PlayerRecipeBookList::PlayerRecipeBookList(){
  272. }
  273. PlayerRecipeBookList::~PlayerRecipeBookList(){
  274. ClearRecipeBooks();
  275. }
  276. bool PlayerRecipeBookList::AddRecipeBook(Recipe *recipe){
  277. assert(recipe);
  278. if(recipeBooks.count(recipe->GetBookID()) == 0){
  279. recipeBooks[recipe->GetBookID()] = recipe;
  280. return true;
  281. }
  282. return false;
  283. }
  284. Recipe * PlayerRecipeBookList::GetRecipeBook(int32 recipebook_id){
  285. if(recipeBooks.count(recipebook_id) > 0)
  286. return recipeBooks[recipebook_id];
  287. return 0;
  288. }
  289. bool PlayerRecipeBookList::HasRecipeBook(int32 book_id) {
  290. if (recipeBooks.count(book_id) > 0)
  291. return true;
  292. return false;
  293. }
  294. void PlayerRecipeBookList::ClearRecipeBooks(){
  295. map<int32, Recipe*>::iterator itr;
  296. for(itr = recipeBooks.begin(); itr != recipeBooks.end(); itr++)
  297. safe_delete(itr->second);
  298. recipeBooks.clear();
  299. }
  300. EQ2Packet * Recipe::SerializeRecipe(Client *client, Recipe *recipe, bool display, int8 packet_type, int8 subpacket_type, const char *struct_name){
  301. int16 version = 1;
  302. Item* item = 0;
  303. RecipeProducts* rp = 0;
  304. vector<int32>::iterator itr;
  305. vector<RecipeComp> comp_list;
  306. int8 i = 0;
  307. int32 firstID = 0;
  308. int32 primary_comp_id = 0;
  309. if(client)
  310. version = client->GetVersion();
  311. if(!struct_name)
  312. struct_name = "WS_ExamineRecipeInfo";
  313. PacketStruct *packet = configReader.getStruct(struct_name, version);
  314. if(display)
  315. packet->setSubstructDataByName("info_header", "show_name", 1);
  316. else
  317. packet->setSubstructDataByName("info_header", "show_popup", 1);
  318. if(client->GetVersion() <= 561) {
  319. packet->setSubstructDataByName("info_header", "packettype", 0x02);
  320. }
  321. else if(packet_type > 0)
  322. packet->setSubstructDataByName("info_header", "packettype", GetItemPacketType(packet->GetVersion()));
  323. else
  324. if(version == 1096)
  325. packet->setSubstructDataByName("info_header", "packettype",0x35FE);
  326. if (version == 1208)
  327. packet->setSubstructDataByName("info_header", "packettype", 0x45FE);
  328. if(version >= 57048)
  329. packet->setSubstructDataByName("info_header", "packettype",0x48FE);
  330. if(subpacket_type == 0)
  331. subpacket_type = 0x02;
  332. packet->setSubstructDataByName("info_header", "packetsubtype", subpacket_type);
  333. packet->setSubstructDataByName("recipe_info", "id", recipe->GetID());
  334. packet->setSubstructDataByName("recipe_info", "unknown", 3);
  335. packet->setSubstructDataByName("recipe_info", "level", recipe->GetLevel());
  336. packet->setSubstructDataByName("recipe_info", "technique", recipe->GetTechnique());
  337. packet->setSubstructDataByName("recipe_info", "skill_level", 50); //50
  338. packet->setSubstructDataByName("recipe_info", "knowledge", recipe->GetKnowledge());
  339. packet->setSubstructDataByName("recipe_info", "device", recipe->GetDevice());
  340. packet->setSubstructDataByName("recipe_info", "icon", recipe->GetIcon());
  341. packet->setSubstructDataByName("recipe_info", "unknown3", 1);
  342. packet->setSubstructDataByName("recipe_info", "adventure_id", 0xFF);
  343. packet->setSubstructDataByName("recipe_info", "tradeskill_id", client ? client->GetPlayer()->GetTradeskillClass() : 0);
  344. packet->setSubstructDataByName("recipe_info", "unknown4a", 100);
  345. packet->setSubstructDataByName("recipe_info", "unknown4aa", 1);
  346. packet->setSubstructDataByName("recipe_info", "unknown5a", 20);//level *10
  347. packet->setSubstructDataByName("recipe_info", "product_classes", recipe->GetClasses());
  348. int32 HS = 0;
  349. if (client->GetPlayer()->GetRecipeList()->GetRecipe(recipe->GetID()) == NULL)
  350. HS = 0;
  351. else
  352. HS = client->GetPlayer()->GetRecipeList()->GetRecipe(recipe->GetID())->highestStage;
  353. packet->setSubstructDataByName("recipe_info", "show_previous", HS);// recipe->highestStage);
  354. rp = recipe->products[1];
  355. if (rp->product_id > 0) {
  356. item = 0;
  357. item = master_item_list.GetItem(rp->product_id);
  358. if (item) {
  359. packet->setSubstructDataByName("recipe_info", "previous1_icon", item->GetIcon(client->GetVersion()));
  360. packet->setSubstructDataByName("recipe_info", "previous1_name", "previous1_name");
  361. packet->setSubstructDataByName("recipe_info", "previous1_qty", recipe->products[1]->product_qty);
  362. packet->setSubstructDataByName("recipe_info", "previous1_item_id", recipe->products[1]->product_id);
  363. packet->setSubstructDataByName("recipe_info", "previous1_item_crc", -853046774);
  364. packet->setSubstructDataByName("recipe_info", "firstbar_icon", item->GetIcon(client->GetVersion()));
  365. packet->setSubstructDataByName("recipe_info", "firstbar_name", "firstbar_name");
  366. packet->setSubstructDataByName("recipe_info", "firstbar_qty", recipe->products[1]->product_qty);
  367. packet->setSubstructDataByName("recipe_info", "firstbar_item_id", recipe->products[2]->product_id);
  368. packet->setSubstructDataByName("recipe_info", "firstbar_item_crc", -853046774);
  369. }
  370. }
  371. rp = recipe->products[2];
  372. if (rp->product_id > 0) {
  373. item = 0;
  374. item = master_item_list.GetItem(rp->product_id);
  375. if (item) {
  376. packet->setSubstructDataByName("recipe_info", "previous2_icon", item->GetIcon(client->GetVersion()));
  377. packet->setSubstructDataByName("recipe_info", "previous2_name", "previous2_name");
  378. packet->setSubstructDataByName("recipe_info", "previous2_qty", recipe->products[2]->product_qty);
  379. packet->setSubstructDataByName("recipe_info", "previous2_item_id", recipe->products[2]->product_id);
  380. packet->setSubstructDataByName("recipe_info", "previous2_item_crc", -853046774);
  381. packet->setSubstructDataByName("recipe_info", "secondbar_icon", item->GetIcon(client->GetVersion()));
  382. packet->setSubstructDataByName("recipe_info", "secondbar_name", "secondbar_name");
  383. packet->setSubstructDataByName("recipe_info", "secondbar_qty", recipe->products[2]->product_qty);
  384. packet->setSubstructDataByName("recipe_info", "secondbar_item_id", recipe->products[2]->product_id);
  385. packet->setSubstructDataByName("recipe_info", "secondbar_item_crc", -853046774);
  386. }
  387. }
  388. rp = recipe->products[3];
  389. if (rp->product_id > 0) {
  390. item = 0;
  391. item = master_item_list.GetItem(rp->product_id);
  392. if (item) {
  393. packet->setSubstructDataByName("recipe_info", "previous3_icon", item->GetIcon(client->GetVersion()));
  394. packet->setSubstructDataByName("recipe_info", "previous3_name", "previous3_name");
  395. packet->setSubstructDataByName("recipe_info", "previous3_qty", recipe->products[3]->product_qty);
  396. packet->setSubstructDataByName("recipe_info", "previous3_item_id", recipe->products[3]->product_id);
  397. packet->setSubstructDataByName("recipe_info", "previous3_item_crc", -853046774);
  398. packet->setSubstructDataByName("recipe_info", "thirdbar_icon", item->GetIcon(client->GetVersion()));
  399. packet->setSubstructDataByName("recipe_info", "thirdbar_name", "thirdbar_name");
  400. packet->setSubstructDataByName("recipe_info", "thirdbar_qty", recipe->products[3]->product_qty);
  401. packet->setSubstructDataByName("recipe_info", "thirdbar_item_id", recipe->products[3]->product_id);
  402. packet->setSubstructDataByName("recipe_info", "thirdbar_item_crc", -2065846136);
  403. }
  404. }
  405. //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
  406. item = master_item_list.GetItem(recipe->GetProductID());
  407. if(item) {
  408. packet->setSubstructDataByName("recipe_info", "product_icon", item->GetIcon(client->GetVersion())); //item->details.icon);
  409. packet->setSubstructDataByName("recipe_info", "product_name", item->name.c_str()); //item->name);
  410. packet->setSubstructDataByName("recipe_info", "product_qty", 1);
  411. packet->setSubstructDataByName("recipe_info", "product_item_id", item->details.item_id); //item->details.item_id);
  412. packet->setSubstructDataByName("recipe_info", "product_item_crc", 0); //item->details.item_crc);
  413. }
  414. rp = recipe->products[0];
  415. if (rp->byproduct_id > 0) {
  416. item = 0;
  417. item = master_item_list.GetItem(rp->byproduct_id);
  418. if (item) {
  419. packet->setSubstructDataByName("recipe_info", "byproduct_icon", item->GetIcon(client->GetVersion()));//11
  420. packet->setSubstructDataByName("recipe_info", "byproduct_id", item->details.item_id);
  421. }
  422. }
  423. rp = recipe->products[1];
  424. if (rp->product_id > 0) {
  425. item = 0;
  426. item = master_item_list.GetItem(rp->product_id);
  427. if (item) {
  428. packet->setSubstructDataByName("recipe_info", "byproduct_icon", item->GetIcon(client->GetVersion()));//11
  429. packet->setSubstructDataByName("recipe_info", "byproduct_id", item->details.item_id);
  430. }
  431. }
  432. item = 0;
  433. // Check to see if we have a primary component (slot = 0)
  434. vector<Item*> itemss;
  435. if (recipe->components.count(0) > 0) {
  436. if(client->GetVersion() <= 561) {
  437. packet->setSubstructDataByName("recipe_info", "primary_count", 1);
  438. }
  439. int16 have_qty = 0;
  440. vector<int32> rc = recipe->components[0];
  441. for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
  442. item = master_item_list.GetItem(*itr);
  443. packet->setSubstructDataByName("recipe_info", "primary_comp", recipe->primary_build_comp_title);
  444. packet->setSubstructDataByName("recipe_info", "primary_qty", recipe->GetPrimaryComponentQuantity());
  445. item = 0;
  446. itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
  447. if (itemss.size() > 0) {
  448. int16 needed_qty = recipe->GetPrimaryComponentQuantity();
  449. for (int8 i = 0; i < itemss.size(); i++) {
  450. have_qty += itemss[i]->details.count;
  451. }
  452. }
  453. }
  454. packet->setSubstructDataByName("recipe_info", "primary_qty_avail", have_qty);
  455. }
  456. int8 total_build_components = recipe->GetTotalBuildComponents();
  457. int8 index = 0;
  458. int8 count = 0;
  459. if (total_build_components > 0) {
  460. packet->setSubstructArrayLengthByName("recipe_info", "num_comps", total_build_components);
  461. for (index = 0; index < 4; index++) {
  462. if (recipe->components.count(index + 1) == 0)
  463. continue;
  464. count++;
  465. vector<int32> rc = recipe->components[index + 1];
  466. int16 have_qty = 0;
  467. string comp_title;
  468. int8 comp_qty;
  469. for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
  470. if (index == 0) {
  471. comp_title = recipe->build1_comp_title;
  472. comp_qty = recipe->build1_comp_qty;
  473. }
  474. else if (index == 1) {
  475. comp_title = recipe->build2_comp_title;
  476. comp_qty = recipe->build2_comp_qty;
  477. }
  478. else if (index == 2) {
  479. comp_title = recipe->build3_comp_title;
  480. comp_qty = recipe->build3_comp_qty;
  481. }
  482. else if (index == 3) {
  483. comp_title = recipe->build4_comp_title;
  484. comp_qty = recipe->build4_comp_qty;
  485. }
  486. itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
  487. for (int8 j = 0; j < itemss.size(); j++) {
  488. have_qty += itemss[j]->details.count;
  489. }
  490. }
  491. packet->setArrayDataByName("build_comp", comp_title.c_str(), index);
  492. packet->setArrayDataByName("build_comp_qty", comp_qty, index);
  493. packet->setArrayDataByName("build_comp_qty_avail", have_qty, index);
  494. }
  495. }
  496. if(client->GetVersion() <= 561) {
  497. packet->setSubstructDataByName("recipe_info", "fuel_count", 1);
  498. packet->setSubstructDataByName("recipe_info", "fuel_comp", recipe->fuel_comp_title);
  499. packet->setSubstructDataByName("recipe_info", "fuel_comp_qty", recipe->fuel_comp_qty);
  500. }
  501. // Check to see if we have a fuel component (slot = 5)
  502. else if (recipe->components.count(5) > 0) {
  503. vector<int32> rc = recipe->components[5];
  504. for (itr = rc.begin(); itr != rc.end(); itr++, i++) {
  505. item = master_item_list.GetItem(*itr);
  506. packet->setSubstructDataByName("recipe_info", "fuel_comp", recipe->fuel_comp_title);
  507. packet->setSubstructDataByName("recipe_info", "fuel_comp_qty", recipe->fuel_comp_qty);
  508. item = 0;
  509. itemss = client->GetPlayer()->item_list.GetAllItemsFromID((*itr));
  510. if (itemss.size() > 0) {
  511. int16 have_qty = 0;
  512. for (int8 i = 0; i < itemss.size(); i++) {
  513. have_qty += itemss[i]->details.count;
  514. }
  515. packet->setSubstructDataByName("recipe_info", "fuel_comp_qty_avail", have_qty);
  516. break;
  517. }
  518. }
  519. }
  520. packet->setSubstructDataByName("recipe_info", "build_comp_qty_avail_flag", 1);
  521. packet->setSubstructDataByName("recipe_info", "unknown6", 4, 0);
  522. packet->setSubstructDataByName("recipe_info", "min_product", 1);
  523. packet->setSubstructDataByName("recipe_info", "max_product", 1);
  524. packet->setSubstructDataByName("recipe_info", "available_flag", 4);
  525. packet->setSubstructDataByName("recipe_info", "not_commissionable", 1);
  526. packet->setSubstructDataByName("recipe_info", "recipe_name", recipe->GetName());
  527. packet->setSubstructDataByName("recipe_info", "recipe_description", recipe->GetDescription());
  528. //packet->PrintPacket();
  529. EQ2Packet* data = packet->serialize();
  530. EQ2Packet* app = new EQ2Packet(OP_ClientCmdMsg, data->pBuffer, data->size);
  531. safe_delete(packet);
  532. safe_delete(data);
  533. //DumpPacket(app);
  534. return app;
  535. }
  536. void Recipe::AddBuildComp(int32 itemID, int8 slot, bool preffered) {
  537. if (preffered)
  538. components[slot].insert(components[slot].begin(), itemID);
  539. else
  540. components[slot].push_back(itemID);
  541. }
  542. int8 Recipe::GetTotalBuildComponents() {
  543. int8 total_build_components = 0;
  544. for(int i=1;i<=4;i++) {
  545. if (components.count(i) > 0)
  546. total_build_components++;
  547. }
  548. return total_build_components;
  549. }
  550. bool Recipe::ProvidedAllRequiredComponents(Client* client, vector<Item*>* player_components, vector<pair<int32,int16>>* player_component_pair_qty) {
  551. vector<int32>::iterator itr;
  552. std::vector<pair<int32,int16>> player_comp_itr;
  553. // Check to see if we have a fuel component (slot = 5)
  554. bool matched = false;
  555. bool hasfuel = false;
  556. if (components.count(5) > 0) {
  557. vector<int32> rc = components[5];
  558. for (itr = rc.begin(); itr != rc.end(); itr++) {
  559. hasfuel = true;
  560. LogWrite(TRADESKILL__INFO, 5, "Recipes", "Recipe ID: %u Recipe Name: %s, item %s (%u), fuel quantity required %u", GetID(), GetName(), fuel_comp_title, (*itr), fuel_comp_qty);
  561. if(PlayerHasComponentByItemID(client, player_components, player_component_pair_qty, (*itr), fuel_comp_qty)) {
  562. matched = true;
  563. break;
  564. }
  565. }
  566. }
  567. if(hasfuel && !matched) {
  568. LogWrite(TRADESKILL__ERROR, 0, "Recipes", "Recipe ID: %u Recipe Name: %s, item %s (%u), lacking fuel quantity required %u", GetID(), GetName(), fuel_comp_title, (*itr), fuel_comp_qty);
  569. return false;
  570. }
  571. for (int8 index = 0; index < GetTotalBuildComponents(); index++) {
  572. if (components.count(index + 1) == 0)
  573. continue;
  574. vector<int32> rc = components[index + 1];
  575. string comp_title;
  576. int8 comp_qty;
  577. matched = false;
  578. for (itr = rc.begin(); itr != rc.end(); itr++) {
  579. if (index == 0) {
  580. comp_title = build1_comp_title;
  581. comp_qty = build1_comp_qty;
  582. }
  583. else if (index == 1) {
  584. comp_title = build2_comp_title;
  585. comp_qty = build2_comp_qty;
  586. }
  587. else if (index == 2) {
  588. comp_title = build3_comp_title;
  589. comp_qty = build3_comp_qty;
  590. }
  591. else if (index == 3) {
  592. comp_title = build4_comp_title;
  593. comp_qty = build4_comp_qty;
  594. }
  595. LogWrite(TRADESKILL__INFO, 5, "Recipes", "Recipe ID: %u Recipe Name: %s, item %s (%u), index %u quantity required %u", GetID(), GetName(), comp_title.c_str(), (*itr), index, comp_qty);
  596. if(PlayerHasComponentByItemID(client, player_components, player_component_pair_qty, (*itr), comp_qty)) {
  597. matched = true;
  598. break;
  599. }
  600. }
  601. if(!matched) {
  602. return false;
  603. }
  604. }
  605. return true;
  606. }
  607. bool Recipe::PlayerHasComponentByItemID(Client* client, vector<Item*>* player_components, vector<pair<int32,int16>>* player_component_pair_qty, int32 item_id, int8 required_qty) {
  608. vector<Item*>::iterator itr;
  609. int16 have_qty = 0;
  610. for(itr = player_components->begin(); itr != player_components->end(); itr++) {
  611. LogWrite(TRADESKILL__DEBUG, 0, "Recipes", "PlayerHasComponentByItemID %u to match %u, qty %u, qtyreq: %u", (*itr)->details.item_id, item_id, (*itr)->details.count, required_qty);
  612. if((*itr) && (*itr)->details.item_id == item_id && (*itr)->details.count >= required_qty) {
  613. return true;
  614. }
  615. }
  616. vector<Item*> itemss = client->GetPlayer()->item_list.GetAllItemsFromID(item_id);
  617. if (itemss.size() > 0) {
  618. for (int8 i = 0; i < itemss.size(); i++) {
  619. have_qty += itemss[i]->details.count;
  620. }
  621. }
  622. int16 track_req_qty = required_qty;
  623. if(have_qty >= required_qty) {
  624. LogWrite(TRADESKILL__DEBUG, 0, "Recipes", "PlayerHasComponentByItemID OVERRIDE! Inventory has item id %u, more than required for quantity %u, have %u", item_id, required_qty, have_qty);
  625. have_qty = 0;
  626. for (int8 i = 0; i < itemss.size(); i++) {
  627. have_qty += itemss[i]->details.count;
  628. int8 cur_qty = itemss[i]->details.count;
  629. if(cur_qty > track_req_qty)
  630. cur_qty = track_req_qty;
  631. track_req_qty -= cur_qty;
  632. itemss[i]->details.item_locked = true;
  633. player_component_pair_qty->push_back({itemss[i]->details.unique_id, cur_qty});
  634. player_components->push_back(itemss[i]);
  635. if(have_qty >= required_qty)
  636. break;
  637. }
  638. return true;
  639. }
  640. return false;
  641. }
  642. int8 Recipe::GetItemRequiredQuantity(int32 item_id) {
  643. vector<int32>::iterator itr;
  644. int8 comp_qty = 0, qty = 0;
  645. for (int8 index = 0; index < GetTotalBuildComponents(); index++) {
  646. if (components.count(index + 1) == 0)
  647. continue;
  648. vector<int32> rc = components[index + 1];
  649. string comp_title;
  650. int8 comp_qty;
  651. bool matched = false;
  652. for (itr = rc.begin(); itr != rc.end(); itr++) {
  653. if (index == 0) {
  654. comp_qty = build1_comp_qty;
  655. }
  656. else if (index == 1) {
  657. comp_qty = build2_comp_qty;
  658. }
  659. else if (index == 2) {
  660. comp_qty = build3_comp_qty;
  661. }
  662. else if (index == 3) {
  663. comp_qty = build4_comp_qty;
  664. }
  665. if((*itr) == item_id)
  666. qty += comp_qty;
  667. }
  668. }
  669. return qty;
  670. }