item_upgrade.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "item_upgrade.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. ItemUpgradeDatabase item_upgrade_db;
  10. void ItemUpgradeDatabase::clear() {
  11. TypesafeYamlDatabase::clear();
  12. }
  13. const std::string ItemUpgradeDatabase::getDefaultLocation() {
  14. return std::string(db_path) + "/item_upgrade.yml";
  15. }
  16. /**
  17. * Reads and parses an entry from the item_upgrade file.
  18. * @param node: YAML node containing the entry.
  19. * @return count of successfully parsed rows
  20. */
  21. uint64 ItemUpgradeDatabase::parseBodyNode(const YAML::Node &node) {
  22. uint32 id;
  23. if (!this->asUInt32(node, "Id", id))
  24. return 0;
  25. std::shared_ptr<s_item_upgrade_db> entry = this->find(id);
  26. bool exists = entry != nullptr;
  27. if (!exists) {
  28. if (!this->nodesExist(node, { "TargetItem", "Result" }))
  29. return 0;
  30. entry = std::make_shared<s_item_upgrade_db>();
  31. entry->id = id;
  32. }
  33. if (this->nodeExists(node, "Result")) {
  34. std::string script_str;
  35. script_code *code;
  36. if (!this->asString(node, "Result", script_str))
  37. return 0;
  38. if (!(code = parse_script(script_str.c_str(), this->getCurrentFile().c_str(), id, SCRIPT_IGNORE_EXTERNAL_BRACKETS))) {
  39. this->invalidWarning(node["Result"], "Invalid item script for 'Result'.\n");
  40. return 0;
  41. }
  42. if (entry->result)
  43. script_free_code(entry->result);
  44. entry->result = code;
  45. }
  46. if (this->nodeExists(node, "TargetItem")) {
  47. const YAML::Node& targetNode = node["TargetItem"];
  48. unsigned int itemid;
  49. if (!entry->targets.empty())
  50. entry->targets.clear();
  51. for (const YAML::Node &target : targetNode) {
  52. if (!this->asUInt32(target, "Item", itemid))
  53. continue;
  54. /*if (!itemdb_exists(itemid)) {
  55. this->invalidWarning(target, "Unknown item with ID %u.\n", itemid);
  56. continue;
  57. }*/
  58. entry->targets.push_back(itemid);
  59. }
  60. }
  61. if (this->nodeExists(node, "NeedRefineMin")) {
  62. this->asUInt16(node, "NeedRefineMin", entry->source_refine_min);
  63. }
  64. if (this->nodeExists(node, "NeedOptionNumMin")) {
  65. this->asUInt16(node, "NeedOptionNumMin", entry->source_refine_min);
  66. }
  67. if (this->nodeExists(node, "NotSocketEnchantItem")) {
  68. this->asBool(node, "NotSocketEnchantItem", entry->not_socket_enchant);
  69. }
  70. if (!exists)
  71. this->put(id, entry);
  72. return 1;
  73. }
  74. /*
  75. * Attempt to open synthesis UI for a player
  76. * @param sd Open UI for this player
  77. * @param itemid ID of synthesis UI
  78. * @return True on succes, false on failure
  79. */
  80. bool item_upgrade_open(map_session_data *sd, unsigned int itemid) {
  81. nullpo_retr(false, sd);
  82. if (pc_cant_act(sd))
  83. return false;
  84. if (pc_is90overweight(sd) || !pc_inventoryblank(sd)) {
  85. clif_msg(sd, ITEM_CANT_OBTAIN_WEIGHT);
  86. return false;
  87. }
  88. #ifndef ITEMID_INT32_SUPPORTED
  89. if (itemid >= UINT16_MAX) {
  90. ShowError("item_upgrade_open: ID '%u' is not supported by your system. Max ID is %hu.\n", itemid, UINT16_MAX);
  91. return false;
  92. }
  93. #endif
  94. if (!item_upgrade_db.exists(itemid))
  95. return false;
  96. if (clif_lapine_upgrade_open(sd, itemid)) {
  97. sd->last_lapine_box = itemid;
  98. sd->state.lapine_ui = 2;
  99. }
  100. return true;
  101. }
  102. e_item_upgrade_result item_upgrade_submit(map_session_data *sd, unsigned int source_itemid, uint16 target_index) {
  103. nullpo_retr(LAPINE_UPRAGDE_FAILURE, sd);
  104. if (!sd->state.lapine_ui || source_itemid != sd->last_lapine_box) {
  105. sd->state.lapine_ui = sd->last_lapine_box = 0;
  106. return LAPINE_UPRAGDE_FAILURE;
  107. }
  108. item *it;
  109. if (target_index >= MAX_INVENTORY || !sd->inventory_data[target_index] || !(it = &sd->inventory.u.items_inventory[target_index]))
  110. return LAPINE_UPRAGDE_FAILURE;
  111. if (it->expire_time || it->equip)
  112. return LAPINE_UPRAGDE_FAILURE;
  113. auto info = item_upgrade_db.find(source_itemid);
  114. if (!info || !info->targetExists(it->nameid) || !info->checkRequirement(it, sd->inventory_data[target_index]))
  115. return LAPINE_UPRAGDE_FAILURE;
  116. pc_setparam(sd, SP_LAST_LAPINE_UPGRADE_ITEM, it->nameid);
  117. pc_setparam(sd, SP_LAST_LAPINE_UPGRADE_INDEX, target_index);
  118. pc_setreg(sd, add_str("@last_lapine_id"), it->nameid);
  119. pc_setreg(sd, add_str("@last_lapine_idx"), target_index);
  120. pc_setreg(sd, add_str("@last_lapine_refine"), it->refine);
  121. pc_setreg(sd, add_str("@last_lapine_identify"), it->identify);
  122. pc_setreg(sd, add_str("@last_lapine_attribute"), it->attribute);
  123. pc_setreg(sd, add_str("@last_lapine_card1"), it->card[0]);
  124. pc_setreg(sd, add_str("@last_lapine_card2"), it->card[1]);
  125. pc_setreg(sd, add_str("@last_lapine_card3"), it->card[2]);
  126. pc_setreg(sd, add_str("@last_lapine_card4"), it->card[3]);
  127. pc_setreg(sd, add_str("@last_lapine_expire"), it->expire_time);
  128. pc_setreg(sd, add_str("@last_lapine_bound"), it->bound);
  129. char unique_id[23];
  130. memset(unique_id, '\0', sizeof(unique_id));
  131. snprintf(unique_id, sizeof(unique_id), "%llu", (unsigned long long)it->unique_id);
  132. pc_setregstr(sd, add_str("@last_lapine_uniqueid$"), unique_id);
  133. int key_opt_id = 0, key_opt_value = 0, key_opt_param = 0;
  134. script_cleararray_pc(sd, "@last_lapine_option_id", (void*)0);
  135. script_cleararray_pc(sd, "@last_lapine_option_value", (void*)0);
  136. script_cleararray_pc(sd, "@last_lapine_option_param", (void*)0);
  137. for (int i = 0; i < MAX_ITEM_RDM_OPT; i++) {
  138. script_setarray_pc(sd, "@last_lapine_option_id", i, (void*)(intptr_t)it->option[i].id, &key_opt_id);
  139. script_setarray_pc(sd, "@last_lapine_option_value", i, (void*)(intptr_t)it->option[i].value, &key_opt_value);
  140. script_setarray_pc(sd, "@last_lapine_option_param", i, (void*)(intptr_t)it->option[i].param, &key_opt_param);
  141. }
  142. if (info->delete_target_onsuccess)
  143. pc_delitem(sd, target_index, 1, 0, 0, LOG_TYPE_OTHER);
  144. sd->state.lapine_ui = sd->last_lapine_box = 0;
  145. if (info->result)
  146. run_script(info->result, 0, sd->status.account_id, 0);
  147. return LAPINE_UPRAGDE_SUCCESS;
  148. }
  149. /**
  150. * Loads item_upgrade db
  151. */
  152. void item_upgrade_read_db(void)
  153. {
  154. item_upgrade_db.load();
  155. }
  156. /**
  157. * Reloads the achievement database
  158. */
  159. void item_upgrade_db_reload(void)
  160. {
  161. do_final_item_upgrade();
  162. do_init_item_upgrade();
  163. }
  164. /**
  165. * Initializes the achievement database
  166. */
  167. void do_init_item_upgrade(void)
  168. {
  169. item_upgrade_db.load();
  170. }
  171. /**
  172. * Finalizes the achievement database
  173. */
  174. void do_final_item_upgrade(void) {
  175. item_upgrade_db.clear();
  176. }
  177. /**
  178. * Constructor
  179. */
  180. s_item_upgrade_db::s_item_upgrade_db()
  181. : targets()
  182. , result(nullptr)
  183. , source_refine_min(0)
  184. , need_option_num(0)
  185. , not_socket_enchant(false)
  186. , delete_target_onsuccess(true)
  187. {}
  188. /**
  189. * Destructor
  190. */
  191. s_item_upgrade_db::~s_item_upgrade_db()
  192. {
  193. if (this->result) {
  194. script_free_code(this->result);
  195. this->result = nullptr;
  196. }
  197. }
  198. bool s_item_upgrade_db::targetExists(uint32 target_id)
  199. {
  200. if (this->targets.empty())
  201. return false;
  202. auto target = std::find(this->targets.begin(), this->targets.end(), target_id);
  203. return (target != this->targets.end());
  204. }
  205. bool s_item_upgrade_db::checkRequirement(item * it, item_data *id)
  206. {
  207. if (this->source_refine_min > it->refine)
  208. return false;
  209. if (this->not_socket_enchant) {
  210. for (int i = id->slot; i < MAX_SLOTS; i++) {
  211. if (it->card[i])
  212. return false;
  213. }
  214. }
  215. if (this->need_option_num) {
  216. int c = 0;
  217. for (int i = 0; i < MAX_ITEM_RDM_OPT; i++) {
  218. if (it->option[i].id)
  219. c++;
  220. }
  221. if (c < this->need_option_num)
  222. return false;
  223. }
  224. return true;
  225. }