item_synthesis.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "item_synthesis.hpp"
  4. #include <algorithm>
  5. #include <memory>
  6. #include "../common/nullpo.hpp"
  7. #include "../common/showmsg.hpp"
  8. #include "log.hpp" // e_log_pick_type
  9. ItemSynthesisDatabase item_synthesis_db;
  10. void ItemSynthesisDatabase::clear() {
  11. TypesafeYamlDatabase::clear();
  12. }
  13. const std::string ItemSynthesisDatabase::getDefaultLocation() {
  14. return std::string(db_path) + "/item_synthesis.yml";
  15. }
  16. /**
  17. * Reads and parses an entry from the item_synthesis file.
  18. * @param node: YAML node containing the entry.
  19. * @return count of successfully parsed rows
  20. */
  21. uint64 ItemSynthesisDatabase::parseBodyNode(const YAML::Node &node) {
  22. uint32 id;
  23. if (!this->asUInt32(node, "Id", id))
  24. return 0;
  25. std::shared_ptr<s_item_synthesis_db> entry = this->find(id);
  26. bool exists = entry != nullptr;
  27. if (!exists) {
  28. if (!this->nodeExists(node, "SourceNeeded"))
  29. return 0;
  30. if (!this->nodeExists(node, "SourceItem"))
  31. return 0;
  32. if (!this->nodeExists(node, "Reward"))
  33. return 0;
  34. entry = std::make_shared<s_item_synthesis_db>();
  35. entry->id = id;
  36. }
  37. if (this->nodeExists(node, "SourceNeeded")) {
  38. if (!this->asUInt16(node, "SourceNeeded", entry->source_needed))
  39. return 0;
  40. }
  41. if (this->nodeExists(node, "NeedRefine")) {
  42. const YAML::Node& refineNode = node["NeedRefine"];
  43. if (refineNode.IsScalar()) {
  44. this->asUInt16(node, "NeedRefine", entry->source_refine_min);
  45. }
  46. else {
  47. if (this->nodeExists(refineNode, "Min"))
  48. this->asUInt16(refineNode, "Min", entry->source_refine_min);
  49. if (this->nodeExists(refineNode, "Max"))
  50. this->asUInt16(refineNode, "Max", entry->source_refine_max);
  51. }
  52. }
  53. if (this->nodeExists(node, "SourceItem")) {
  54. const YAML::Node& sourceNode = node["SourceItem"];
  55. if (!entry->sources.empty())
  56. entry->sources.clear();
  57. entry->sources.reserve(entry->source_needed);
  58. for (const YAML::Node &source : sourceNode) {
  59. s_item_synthesis_source source_item = {};
  60. if (!this->asUInt32(source, "Item", source_item.nameid))
  61. continue;
  62. /*if (!itemdb_exists(source_item.nameid)) {
  63. this->invalidWarning(sourceNode, "Unknown item with ID %u.\n", source_item.nameid);
  64. continue;
  65. }*/
  66. if (this->nodeExists(source, "Amount"))
  67. this->asUInt16(source, "Amount", source_item.amount);
  68. entry->sources.push_back(source_item);
  69. }
  70. }
  71. if (this->nodeExists(node, "Reward")) {
  72. std::string script_str;
  73. script_code *code;
  74. if (!this->asString(node, "Reward", script_str) || !(code = parse_script(script_str.c_str(), this->getCurrentFile().c_str(), id, SCRIPT_IGNORE_EXTERNAL_BRACKETS))) {
  75. this->invalidWarning(node["Reward"], "Invalid item script for 'Reward'.\n");
  76. return 0;
  77. }
  78. if (entry->reward)
  79. script_free_code(entry->reward);
  80. entry->reward = code;
  81. }
  82. if (!exists)
  83. this->put(id, entry);
  84. return 1;
  85. }
  86. /*
  87. * Attempt to open synthesis UI for a player
  88. * @param sd Open UI for this player
  89. * @param itemid ID of synthesis UI
  90. * @return True on succes, false on failure
  91. */
  92. bool item_synthesis_open(map_session_data *sd, unsigned int itemid) {
  93. nullpo_retr(false, sd);
  94. if (sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag || sd->state.prevend || sd->state.lapine_ui)
  95. return false;
  96. if (pc_is90overweight(sd) || !pc_inventoryblank(sd)) {
  97. clif_msg(sd, ITEM_CANT_OBTAIN_WEIGHT);
  98. return false;
  99. }
  100. #ifndef ITEMID_INT32_SUPPORTED
  101. if (itemid >= UINT16_MAX) {
  102. ShowError("item_synthesis_open: ID '%u' is not supported by your system. Max ID is %hu.\n", itemid, UINT16_MAX);
  103. return false;
  104. }
  105. #endif
  106. if (!item_synthesis_db.exists(itemid))
  107. return false;
  108. if (clif_synthesisui_open(sd, itemid)) {
  109. sd->last_lapine_box = itemid;
  110. sd->state.lapine_ui = 1;
  111. }
  112. return true;
  113. }
  114. /*
  115. * Proccess synthesis input from player
  116. * @param sd Player who request
  117. * @param itemid ID of synthesis UI
  118. * @param items Item list sent by player
  119. * @return SYNTHESIS_SUCCESS on success. @see e_item_synthesis_result
  120. */
  121. e_item_synthesis_result item_synthesis_submit(map_session_data *sd, unsigned int itemid, const std::vector<s_item_synthesis_list> items) {
  122. nullpo_retr(SYNTHESIS_INVALID_ITEM, sd);
  123. if (!sd->state.lapine_ui || itemid != sd->last_lapine_box) {
  124. sd->state.lapine_ui = sd->last_lapine_box = 0;
  125. return SYNTHESIS_INVALID_ITEM;
  126. }
  127. auto info = item_synthesis_db.find(itemid);
  128. if (!info || !info->checkRequirement(sd, items))
  129. return SYNTHESIS_INSUFFICIENT_AMOUNT;
  130. if (info->reward)
  131. run_script(info->reward, 0, sd->status.account_id, 0);
  132. sd->state.lapine_ui = sd->last_lapine_box = 0;
  133. return SYNTHESIS_SUCCESS;
  134. }
  135. /**
  136. * Loads item_synthesis db
  137. */
  138. void item_synthesis_read_db(void)
  139. {
  140. item_synthesis_db.load();
  141. }
  142. /**
  143. * Reloads the achievement database
  144. */
  145. void item_synthesis_db_reload(void)
  146. {
  147. do_final_item_synthesis();
  148. do_init_item_synthesis();
  149. }
  150. /**
  151. * Initializes the achievement database
  152. */
  153. void do_init_item_synthesis(void)
  154. {
  155. item_synthesis_db.load();
  156. }
  157. /**
  158. * Finalizes the achievement database
  159. */
  160. void do_final_item_synthesis(void) {
  161. item_synthesis_db.clear();
  162. }
  163. /**
  164. * Constructor
  165. */
  166. s_item_synthesis_db::s_item_synthesis_db()
  167. : source_needed(0)
  168. , sources()
  169. , reward(nullptr)
  170. , source_refine_min(0)
  171. , source_refine_max(MAX_REFINE)
  172. {}
  173. /**
  174. * Destructor
  175. */
  176. s_item_synthesis_db::~s_item_synthesis_db()
  177. {
  178. if (this->reward) {
  179. script_free_code(this->reward);
  180. this->reward = nullptr;
  181. }
  182. }
  183. bool s_item_synthesis_db::sourceExists(uint32 source_id)
  184. {
  185. if (this->sources.empty())
  186. return false;
  187. auto source = std::find_if(
  188. this->sources.begin(), this->sources.end(),
  189. [&source_id](const s_item_synthesis_source &source) { return source.nameid == source_id; }
  190. );
  191. return (source != this->sources.end());
  192. }
  193. bool s_item_synthesis_db::checkRequirement(map_session_data *sd, const std::vector<s_item_synthesis_list> items)
  194. {
  195. if (items.empty() || items.size() != this->source_needed)
  196. return false;
  197. item *item = NULL;
  198. item_data *id = NULL;
  199. for (auto &it : items) {
  200. if (it.index >= MAX_INVENTORY)
  201. return false;
  202. if (!(item = &sd->inventory.u.items_inventory[it.index]) || !(id = sd->inventory_data[it.index]))
  203. return false;
  204. if (item->equip || item->expire_time || item->amount < it.amount)
  205. return false;
  206. if (!this->sourceExists(item->nameid))
  207. return false;
  208. if (item->refine < this->source_refine_min)
  209. return false;
  210. if (item->refine > this->source_refine_max)
  211. return false;
  212. if (pc_delitem(sd, it.index, it.amount, 0, 0, LOG_TYPE_OTHER) != 0)
  213. return false;
  214. }
  215. return true;
  216. }
  217. s_item_synthesis_source::s_item_synthesis_source()
  218. : amount(1)
  219. {
  220. }