Files
rathena/src/map/item_synthesis.cpp
aleos 93cfc55118 Converts item ID to item name
* Converts the databases to utilize item names instead of their ID.
* Updates header of YAML files.
* Enables some 32bit items.
* Updates item names to match kRO.
* Removes some items that got duplicated during the merge to master.
* Fixes some minor left overs for t_itemid usage.
2020-09-14 14:15:12 -04:00

345 lines
8.4 KiB
C++

// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "item_synthesis.hpp"
#include <algorithm>
#include <memory>
#include "../common/nullpo.hpp"
#include "../common/showmsg.hpp"
#include "log.hpp" // e_log_pick_type
ItemSynthesisDatabase item_synthesis_db;
void ItemSynthesisDatabase::clear() {
TypesafeYamlDatabase::clear();
}
const std::string ItemSynthesisDatabase::getDefaultLocation() {
return std::string(db_path) + "/item_synthesis.yml";
}
/**
* Reads and parses an entry from the item_synthesis file.
* @param node: YAML node containing the entry.
* @return count of successfully parsed rows
*/
uint64 ItemSynthesisDatabase::parseBodyNode(const YAML::Node &node) {
std::string synthesis_item_name;
if (!this->asString(node, "Item", synthesis_item_name))
return 0;
item_data *item = itemdb_search_aegisname(synthesis_item_name.c_str());
if (item == nullptr) {
this->invalidWarning(node["Item"], "Item name for Synthesis Box %s does not exist.\n", synthesis_item_name.c_str());
return 0;
}
std::shared_ptr<s_item_synthesis_db> entry = this->find(item->nameid);
bool exists = entry != nullptr;
if (!exists) {
if (!this->nodesExist(node, { "SourceItem", "Reward" }))
return 0;
entry = std::make_shared<s_item_synthesis_db>();
entry->id = item->nameid;
}
if (this->nodeExists(node, "SourceNeeded")) {
if (!this->asUInt16(node, "SourceNeeded", entry->source_needed))
return 0;
}
if (this->nodeExists(node, "NeedRefineMin")) {
if (!this->asUInt16(node, "NeedRefineMin", entry->source_refine_min))
return 0;
}
if (this->nodeExists(node, "NeedRefineMax")) {
if (!this->asUInt16(node, "NeedRefineMax", entry->source_refine_max))
return 0;
}
if (exists && this->nodeExists(node, "ClearSourceItem")) {
ShowNotice("item_synthesis: Cleared all items in SourceItem. Synthesis: %s (%u)\n", item->name, item->nameid);
if (!entry->sources.empty())
entry->sources.clear();
}
if (this->nodeExists(node, "SourceItem")) {
const YAML::Node& sourceNode = node["SourceItem"];
if (!exists)
entry->sources.reserve(entry->source_needed);
for (const YAML::Node &source : sourceNode) {
std::string source_item_name;
if (!this->asString(source, "Item", source_item_name))
continue;
item_data *source_it = itemdb_search_aegisname(source_item_name.c_str());
if (source_it == nullptr) {
this->invalidWarning(node["SourceItem"], "Source item name %s does not exist, skipping.\n", source_item_name.c_str());
continue;
}
s_item_synthesis_source source_item = {};
source_item.nameid = source_it->nameid;
if (exists && this->nodeExists(source, "Remove")) {
entry->sources.erase(std::remove_if(entry->sources.begin(), entry->sources.end(), [&source_item](const s_item_synthesis_source &x) { return x.nameid == source_item.nameid; }));
ShowNotice("item_synthesis: Removed %s (%u) from SourceItem. Synthesis: %s (%u)\n", source_it->name, source_item.nameid, item->name, item->nameid);
continue;
}
if (this->nodeExists(source, "Amount"))
this->asUInt16(source, "Amount", source_item.amount);
if (entry->sources.end() == std::find_if(
entry->sources.begin(), entry->sources.end(), [&source_item](s_item_synthesis_source &x)
{
if (x.nameid == source_item.nameid) {
x.amount = source_item.amount;
return true;
}
return false;
}
))
entry->sources.push_back(source_item);
}
}
if (this->nodeExists(node, "Reward")) {
std::string script_str;
script_code *code;
if (!this->asString(node, "Reward", script_str))
return 0;
if (!(code = parse_script(script_str.c_str(), this->getCurrentFile().c_str(), item->nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS))) {
this->invalidWarning(node["Reward"], "Invalid Reward item script.\n");
return 0;
}
if (entry->reward)
script_free_code(entry->reward);
entry->reward = code;
}
if (!exists)
this->put(item->nameid, entry);
return 1;
}
/**
* Attempt to open synthesis UI for a player
* @param sd: Open UI for this player
* @param itemid: ID of synthesis UI
* @return True on succes, false on failure
*/
bool item_synthesis_open(map_session_data *sd, t_itemid itemid) {
nullpo_retr(false, sd);
if (pc_cant_act2(sd) || (sd)->chatID)
return false;
if (pc_is90overweight(sd) || !pc_inventoryblank(sd)) {
clif_msg(sd, ITEM_CANT_OBTAIN_WEIGHT);
return false;
}
if (!item_synthesis_db.exists(itemid))
return false;
if (clif_synthesisui_open(sd, itemid)) {
sd->last_lapine_box = itemid;
sd->state.lapine_ui = 1;
}
return true;
}
/**
* Process synthesis input from player
* @param sd: Player who request
* @param itemid: ID of synthesis UI
* @param items: Item list sent by player
* @return SYNTHESIS_SUCCESS on success. @see e_item_synthesis_result
*/
e_item_synthesis_result item_synthesis_submit(map_session_data *sd, t_itemid itemid, const std::vector<s_item_synthesis_list> items) {
nullpo_retr(SYNTHESIS_INVALID_ITEM, sd);
if (!sd->state.lapine_ui || itemid != sd->last_lapine_box) {
sd->state.lapine_ui = sd->last_lapine_box = 0;
return SYNTHESIS_INVALID_ITEM;
}
auto info = item_synthesis_db.find(itemid);
if (!info || !info->checkRequirement(sd, items))
return SYNTHESIS_INSUFFICIENT_AMOUNT;
if (!info->deleteRequirement(sd, items))
return SYNTHESIS_INSUFFICIENT_AMOUNT;
if (info->reward)
run_script(info->reward, 0, sd->status.account_id, 0);
sd->state.lapine_ui = sd->last_lapine_box = 0;
return SYNTHESIS_SUCCESS;
}
/**
* Loads lapine synthesis database
*/
void item_synthesis_read_db(void)
{
item_synthesis_db.load();
}
/**
* Reloads the lapine synthesis database
*/
void item_synthesis_db_reload(void)
{
do_final_item_synthesis();
do_init_item_synthesis();
}
/**
* Initializes the lapine synthesis database
*/
void do_init_item_synthesis(void)
{
item_synthesis_db.load();
}
/**
* Finalizes the lapine synthesis database
*/
void do_final_item_synthesis(void) {
item_synthesis_db.clear();
}
/**
* Constructor
*/
s_item_synthesis_db::s_item_synthesis_db()
: source_needed(1)
, sources()
, reward(nullptr)
, source_refine_min(0)
, source_refine_max(MAX_REFINE)
{}
/**
* Destructor
*/
s_item_synthesis_db::~s_item_synthesis_db()
{
if (this->reward) {
script_free_code(this->reward);
this->reward = nullptr;
}
}
/**
* Check if the source for synthesis item is exists
* @param source_id: Item ID of source item
* @return true if source exists, false if doesn't
*/
bool s_item_synthesis_db::sourceExists(t_itemid source_id)
{
if (this->sources.empty())
return false;
auto source = std::find_if(
this->sources.begin(), this->sources.end(),
[&source_id](const s_item_synthesis_source &source) { return source.nameid == source_id; }
);
return (source != this->sources.end());
}
/**
* Check all submitted items are valid
* @param sd: Player
* @param items: Submitted items by player
* @return True if all items are valid
*/
bool s_item_synthesis_db::checkRequirement(map_session_data *sd, const std::vector<s_item_synthesis_list> items)
{
if (items.empty() || items.size() != this->source_needed)
return false;
item *item = nullptr;
item_data *id = nullptr;
std::vector<int> indexes(this->source_needed);
for (auto &it : items) {
if (it.index >= MAX_INVENTORY)
return false;
if (!(item = &sd->inventory.u.items_inventory[it.index]) || !(id = sd->inventory_data[it.index]))
return false;
if (item->equip || item->expire_time || item->amount < it.amount || item->identify != 1)
return false;
if (!this->sourceExists(item->nameid))
return false;
if (item->refine < this->source_refine_min)
return false;
if (item->refine > this->source_refine_max)
return false;
if (std::find(indexes.begin(), indexes.end(), it.index) != indexes.end())
return false;
indexes.push_back(it.index);
}
return true;
}
/**
* Delete all submitted items for synthesis
* @param sd: Player
* @param items: Submitted items by player
* @return True if all items are deleted
*/
bool s_item_synthesis_db::deleteRequirement(map_session_data *sd, const std::vector<s_item_synthesis_list> items)
{
if (items.empty() || items.size() != this->source_needed)
return false;
for (auto &it : items) {
if (it.index >= MAX_INVENTORY)
return false;
if (pc_delitem(sd, it.index, it.amount, 0, 0, LOG_TYPE_OTHER) != 0)
return false;
}
return true;
}
/**
* Synthesis items constructor.
* Set default amount to 1
*/
s_item_synthesis_source::s_item_synthesis_source()
: amount(1)
{
}