Files
rathena/src/tool/yaml2sql.cpp
2024-04-07 22:14:51 +02:00

959 lines
30 KiB
C++

// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include <fstream>
#include <functional>
#include <iostream>
#include <locale>
#include <unordered_map>
#include <vector>
#ifdef WIN32
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
#include <cstdio>
#endif
#include <yaml-cpp/yaml.h>
#include <ryml_std.hpp>
#include <ryml.hpp>
#include <common/cbasetypes.hpp>
#include <common/core.hpp>
#include <common/malloc.hpp>
#include <common/mmo.hpp>
#include <common/nullpo.hpp>
#include <common/showmsg.hpp>
#include <common/strlib.hpp>
#include <common/utilities.hpp>
#include <common/utils.hpp>
#ifdef WIN32
#include <common/winapi.hpp>
#endif
// Only for constants - do not use functions of it or linking will fail
#define ONLY_CONSTANTS
#include <map/achievement.hpp>
#include <map/battle.hpp>
#include <map/battleground.hpp>
#include <map/cashshop.hpp>
#include <map/channel.hpp>
#include <map/chat.hpp>
#include <map/date.hpp>
#include <map/elemental.hpp>
#include <map/homunculus.hpp>
#include <map/instance.hpp>
#include <map/mercenary.hpp>
#include <map/mob.hpp>
#include <map/npc.hpp>
#include <map/pc.hpp>
#include <map/pet.hpp>
#include <map/quest.hpp>
#include <map/script.hpp>
#include <map/skill.hpp>
#include <map/storage.hpp>
using namespace rathena;
using namespace rathena::server_core;
namespace rathena{
namespace tool_yaml2sql{
class Yaml2SqlTool : public Core{
protected:
bool initialize( int argc, char* argv[] ) override;
public:
Yaml2SqlTool() : Core( e_core_type::TOOL ){
}
};
}
}
using namespace rathena::tool_yaml2sql;
#ifndef WIN32
int getch( void ){
struct termios oldattr, newattr;
int ch;
tcgetattr( STDIN_FILENO, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
return ch;
}
#endif
// Constants for conversion
std::unordered_map<const char *, int64> constants;
// Forward declaration of conversion functions
static bool item_db_yaml2sql(const std::string &file, const std::string &table);
static bool mob_db_yaml2sql(const std::string &file, const std::string &table);
bool fileExists( const std::string& path );
bool askConfirmation( const char* fmt, ... );
YAML::Node inNode;
std::ofstream outFile;
// Implement the function instead of including the original version by linking
void script_set_constant_(const char *name, int64 value, const char *constant_name, bool isparameter, bool deprecated) {
constants[name] = value;
}
const char *constant_lookup(int32 value, const char *prefix) {
if (prefix == nullptr)
return nullptr;
for (auto const &pair : constants) {
// Same prefix group and same value
if (strncasecmp(pair.first, prefix, strlen(prefix)) == 0 && pair.second == value) {
return pair.first;
}
}
return nullptr;
}
int64 constant_lookup_int(const char *constant) {
if (constant == nullptr)
return -100;
for (auto const &pair : constants) {
if (strlen(pair.first) == strlen(constant) && strncasecmp(pair.first, constant, strlen(constant)) == 0) {
return pair.second;
}
}
return -100;
}
void copyFileIfExists( std::ofstream& file,const std::string& name ){
std::string path = "doc/yaml/sql/" + name + ".sql";
if( fileExists( path ) ){
std::ifstream source( path, std::ios::binary );
std::istreambuf_iterator<char> begin_source(source);
std::istreambuf_iterator<char> end_source;
std::ostreambuf_iterator<char> begin_dest( file );
copy( begin_source, end_source, begin_dest );
source.close();
}
}
void prepareHeader(std::ofstream &file, const std::string& name) {
copyFileIfExists( file, name );
file << "\n";
}
template<typename Func>
bool process( const std::string& type, uint32 version, const std::vector<std::string>& paths, const std::string& name, const std::string& to_table, const std::string& table, Func lambda ){
for( const std::string& path : paths ){
const std::string name_ext = name + ".yml";
const std::string from = path + name_ext;
const std::string to = "sql-files/" + to_table + ".sql";
if( fileExists( from ) ){
#ifndef CONVERT_ALL
if( !askConfirmation( "Found the file \"%s\", which can be converted to sql.\nDo you want to convert it now? (Y/N)\n", from.c_str() ) ){
continue;
}
#else
ShowMessage("Found the file \"%s\", converting from yml to sql.\n", from.c_str());
#endif
inNode.reset();
try {
inNode = YAML::LoadFile(from);
} catch (YAML::Exception &e) {
ShowError("%s (Line %d: Column %d)\n", e.msg.c_str(), e.mark.line, e.mark.column);
if (!askConfirmation("Error found in \"%s\" while attempting to load.\nPress any key to continue.\n", from.c_str()))
continue;
}
if (!inNode["Body"].IsDefined())
continue;
#ifndef CONVERT_ALL
if (fileExists(to)) {
if (!askConfirmation("The file \"%s\" already exists.\nDo you want to replace it? (Y/N)\n", to.c_str())) {
continue;
}
}
#endif
outFile.open(to);
if (!outFile.is_open()) {
ShowError("Can not open file \"%s\" for writing.\n", to.c_str());
return false;
}
prepareHeader(outFile, table.compare(to_table) == 0 ? table : to_table);
if( !lambda( path, name_ext, table ) ){
outFile.close();
return false;
}
outFile.close();
}
}
return true;
}
bool Yaml2SqlTool::initialize( int argc, char* argv[] ){
const std::string path_db = std::string( db_path );
const std::string path_db_mode = path_db + "/" + DBPATH;
const std::string path_db_import = path_db + "/" + DBIMPORT + "/";
#ifdef RENEWAL
const std::string item_table_name = "item_db_re";
const std::string item_import_table_name = "item_db2_re";
const std::string mob_table_name = "mob_db_re";
const std::string mob_import_table_name = "mob_db2_re";
#else
const std::string item_table_name = "item_db";
const std::string item_import_table_name = "item_db2";
const std::string mob_table_name = "mob_db";
const std::string mob_import_table_name = "mob_db2";
#endif
std::vector<std::string> item_table_suffixes = {
"usable",
"equip",
"etc"
};
// Load constants
#include <map/script_constants.hpp>
for( const std::string& suffix : item_table_suffixes ){
if (!process("ITEM_DB", 1, { path_db_mode }, "item_db_" + suffix, item_table_name + "_" + suffix, item_table_name, [](const std::string& path, const std::string& name_ext, const std::string& table) -> bool {
return item_db_yaml2sql(path + name_ext, table);
})) {
return false;
}
}
if (!process("ITEM_DB", 1, { path_db_import }, "item_db", item_import_table_name, item_import_table_name, [](const std::string& path, const std::string& name_ext, const std::string& table) -> bool {
return item_db_yaml2sql(path + name_ext, table);
})) {
return false;
}
if (!process("MOB_DB", 1, { path_db_mode }, "mob_db", mob_table_name, mob_table_name, [](const std::string &path, const std::string &name_ext, const std::string &table) -> bool {
return mob_db_yaml2sql(path + name_ext, table);
})) {
return false;
}
if (!process("MOB_DB", 1, { path_db_import }, "mob_db", mob_import_table_name, mob_import_table_name, [](const std::string &path, const std::string &name_ext, const std::string &table) -> bool {
return mob_db_yaml2sql(path + name_ext, table);
})) {
return false;
}
// TODO: add implementations ;-)
return true;
}
bool fileExists( const std::string& path ){
std::ifstream in;
in.open( path );
if( in.is_open() ){
in.close();
return true;
}else{
return false;
}
}
bool askConfirmation( const char* fmt, ... ){
va_list ap;
va_start( ap, fmt );
_vShowMessage( MSG_NONE, fmt, ap );
va_end( ap );
char c = getch();
if( c == 'Y' || c == 'y' ){
return true;
}else{
return false;
}
}
std::string name2Upper(std::string name) {
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
name[0] = toupper(name[0]);
for (size_t i = 0; i < name.size(); i++) {
if (name[i - 1] == '_' || (name[i - 2] == '1' && name[i - 1] == 'h') || (name[i - 2] == '2' && name[i - 1] == 'h'))
name[i] = toupper(name[i]);
}
return name;
}
const std::string WHITESPACE = " \n\r\t\f\v";
std::string ltrim(const std::string &s) {
size_t start = s.find_first_not_of(WHITESPACE);
return (start == std::string::npos) ? "" : s.substr(start);
}
std::string rtrim(const std::string &s) {
size_t end = s.find_last_not_of(WHITESPACE);
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
}
std::string string_trim(const std::string &s) {
return rtrim(ltrim(s));
}
std::string string_escape(const std::string &s) {
size_t n = s.length();
std::string escaped;
escaped.reserve(n * 2);
for (size_t i = 0; i < n; ++i) {
if (s[i] == '\r')
continue;
if (s[i] == '\n' && (i + 1) < n) {
escaped += "\\n";
continue;
}
if (s[i] == '\\' || s[i] == '\'')
escaped += '\\';
escaped += s[i];
}
return escaped;
}
/**
* Append the entry value to the string if the Node exists
* @param node: Node with entry
* @param value: String to store node value to
* @param string: If value is a string or not
*/
static bool appendEntry(const YAML::Node &node, std::string &value, bool string = false) {
if (node.IsDefined()) {
if (string) {
value.append("'");
value.append(string_trim(string_escape(node.as<std::string>())));
value.append("',");
} else {
value.append(string_trim(node.as<std::string>()));
value.append(",");
}
return true;
}
return false;
}
// Implementation of the conversion functions
// Copied and adjusted from itemdb.cpp
static bool item_db_yaml2sql(const std::string &file, const std::string &table) {
size_t entries = 0;
for (const YAML::Node &input : inNode["Body"]) {
std::string column = "", value = "";
if (appendEntry(input["Id"], value))
column.append("`id`,");
if (appendEntry(input["AegisName"], value, true))
column.append("`name_aegis`,");
if (appendEntry(input["Name"], value, true))
column.append("`name_english`,");
if (appendEntry(input["Type"], value, true))
column.append("`type`,");
if (appendEntry(input["SubType"], value, true))
column.append("`subtype`,");
if (appendEntry(input["Buy"], value))
column.append("`price_buy`,");
if (appendEntry(input["Sell"], value))
column.append("`price_sell`,");
if (appendEntry(input["Weight"], value))
column.append("`weight`,");
if (appendEntry(input["Attack"], value))
column.append("`attack`,");
#ifdef RENEWAL
if (appendEntry(input["MagicAttack"], value))
column.append("`magic_attack`,");
#endif
if (appendEntry(input["Defense"], value))
column.append("`defense`,");
if (appendEntry(input["Range"], value))
column.append("`range`,");
if (appendEntry(input["Slots"], value))
column.append("`slots`,");
const YAML::Node &jobs = input["Jobs"];
if (jobs) {
if (appendEntry(jobs["All"], value))
column.append("`job_all`,");
if (appendEntry(jobs["Acolyte"], value))
column.append("`job_acolyte`,");
if (appendEntry(jobs["Alchemist"], value))
column.append("`job_alchemist`,");
if (appendEntry(jobs["Archer"], value))
column.append("`job_archer`,");
if (appendEntry(jobs["Assassin"], value))
column.append("`job_assassin`,");
if (appendEntry(jobs["BardDancer"], value))
column.append("`job_barddancer`,");
if (appendEntry(jobs["Blacksmith"], value))
column.append("`job_blacksmith`,");
if (appendEntry(jobs["Crusader"], value))
column.append("`job_crusader`,");
if (appendEntry(jobs["Gunslinger"], value))
column.append("`job_gunslinger`,");
if (appendEntry(jobs["Hunter"], value))
column.append("`job_hunter`,");
#ifdef RENEWAL
if (appendEntry(jobs["KagerouOboro"], value))
column.append("`job_kagerouoboro`,");
#endif
if (appendEntry(jobs["Knight"], value))
column.append("`job_knight`,");
if (appendEntry(jobs["Mage"], value))
column.append("`job_mage`,");
if (appendEntry(jobs["Merchant"], value))
column.append("`job_merchant`,");
if (appendEntry(jobs["Monk"], value))
column.append("`job_monk`,");
if (appendEntry(jobs["Ninja"], value))
column.append("`job_ninja`,");
if (appendEntry(jobs["Novice"], value))
column.append("`job_novice`,");
if (appendEntry(jobs["Priest"], value))
column.append("`job_priest`,");
#ifdef RENEWAL
if (appendEntry(jobs["Rebellion"], value))
column.append("`job_rebellion`,");
#endif
if (appendEntry(jobs["Rogue"], value))
column.append("`job_rogue`,");
if (appendEntry(jobs["Sage"], value))
column.append("`job_sage`,");
if (appendEntry(jobs["SoulLinker"], value))
column.append("`job_soullinker`,");
#ifdef RENEWAL
if (appendEntry(jobs["Spirit_Handler"], value))
column.append("`job_spirit_handler`,");
#endif
if (appendEntry(jobs["StarGladiator"], value))
column.append("`job_stargladiator`,");
#ifdef RENEWAL
if (appendEntry(jobs["Summoner"], value))
column.append("`job_summoner`,");
#endif
if (appendEntry(jobs["SuperNovice"], value))
column.append("`job_supernovice`,");
if (appendEntry(jobs["Swordman"], value))
column.append("`job_swordman`,");
if (appendEntry(jobs["Taekwon"], value))
column.append("`job_taekwon`,");
if (appendEntry(jobs["Thief"], value))
column.append("`job_thief`,");
if (appendEntry(jobs["Wizard"], value))
column.append("`job_wizard`,");
}
const YAML::Node &classes = input["Classes"];
if (classes) {
std::string str_all_upper;
std::string str_all_baby;
if (classes["All_Upper"].IsDefined())
str_all_upper = string_trim(classes["All_Upper"].as<std::string>());
if (classes["All_Baby"].IsDefined())
str_all_baby = string_trim(classes["All_Baby"].as<std::string>());
if (appendEntry(classes["All"], value))
column.append("`class_all`,");
if (appendEntry(classes["Normal"], value))
column.append("`class_normal`,");
if (appendEntry(classes["Upper"], value))
column.append("`class_upper`,");
else if (!str_all_upper.empty()) {
value.append(str_all_upper);
value.append(",");
column.append("`class_upper`,");
}
if (appendEntry(classes["Baby"], value))
column.append("`class_baby`,");
else if (!str_all_baby.empty()) {
value.append(str_all_baby);
value.append(",");
column.append("`class_baby`,");
}
#ifdef RENEWAL
std::string str_all_third;
if (classes["All_Third"].IsDefined())
str_all_third = string_trim(classes["All_Third"].as<std::string>());
if (appendEntry(classes["Third"], value))
column.append("`class_third`,");
else if (!str_all_third.empty()) {
value.append(str_all_third);
value.append(",");
column.append("`class_third`,");
}
if (appendEntry(classes["Third_Upper"], value))
column.append("`class_third_upper`,");
else if (!str_all_upper.empty() || !str_all_third.empty()) {
if (!str_all_upper.empty())
value.append(str_all_upper);
else
value.append(str_all_third);
value.append(",");
column.append("`class_third_upper`,");
}
if (appendEntry(classes["Third_Baby"], value))
column.append("`class_third_baby`,");
else if (!str_all_baby.empty() || !str_all_third.empty()) {
if (!str_all_baby.empty())
value.append(str_all_baby);
else
value.append(str_all_third);
value.append(",");
column.append("`class_third_baby`,");
}
if (appendEntry(classes["Fourth"], value))
column.append("`class_fourth`,");
#endif
}
if (appendEntry(input["Gender"], value, true))
column.append("`gender`,");
const YAML::Node &locations = input["Locations"];
if (locations) {
if (appendEntry(locations["Head_Top"], value))
column.append("`location_head_top`,");
if (appendEntry(locations["Head_Mid"], value))
column.append("`location_head_mid`,");
if (appendEntry(locations["Head_Low"], value))
column.append("`location_head_low`,");
if (appendEntry(locations["Armor"], value))
column.append("`location_armor`,");
if (locations["Both_Hand"].IsDefined()) {
std::string tmp_value = string_trim(locations["Both_Hand"].as<std::string>());
if (!appendEntry(locations["Left_Hand"], value)) {
value.append(tmp_value);
value.append(",");
}
if (!appendEntry(locations["Right_Hand"], value)) {
value.append(tmp_value);
value.append(",");
}
column.append("`location_left_hand`,");
column.append("`location_right_hand`,");
}
else {
if (appendEntry(locations["Left_Hand"], value))
column.append("`location_left_hand`,");
if (appendEntry(locations["Right_Hand"], value))
column.append("`location_right_hand`,");
}
if (appendEntry(locations["Garment"], value))
column.append("`location_garment`,");
if (appendEntry(locations["Shoes"], value))
column.append("`location_shoes`,");
if (locations["Both_Accessory"].IsDefined()) {
std::string tmp_value = string_trim(locations["Both_Accessory"].as<std::string>());
if (!appendEntry(locations["Right_Accessory"], value)) {
value.append(tmp_value);
value.append(",");
}
if (!appendEntry(locations["Left_Accessory"], value)) {
value.append(tmp_value);
value.append(",");
}
column.append("`location_right_accessory`,");
column.append("`location_left_accessory`,");
}
else {
if (appendEntry(locations["Right_Accessory"], value))
column.append("`location_right_accessory`,");
if (appendEntry(locations["Left_Accessory"], value))
column.append("`location_left_accessory`,");
}
if (appendEntry(locations["Costume_Head_Top"], value))
column.append("`location_costume_head_top`,");
if (appendEntry(locations["Costume_Head_Mid"], value))
column.append("`location_costume_head_Mid`,");
if (appendEntry(locations["Costume_Head_Low"], value))
column.append("`location_costume_head_Low`,");
if (appendEntry(locations["Costume_Garment"], value))
column.append("`location_costume_garment`,");
if (appendEntry(locations["Ammo"], value))
column.append("`location_ammo`,");
if (appendEntry(locations["Shadow_Armor"], value))
column.append("`location_shadow_armor`,");
if (appendEntry(locations["Shadow_Weapon"], value))
column.append("`location_shadow_weapon`,");
if (appendEntry(locations["Shadow_Shield"], value))
column.append("`location_shadow_shield`,");
if (appendEntry(locations["Shadow_Shoes"], value))
column.append("`location_shadow_shoes`,");
if (appendEntry(locations["Shadow_Right_Accessory"], value))
column.append("`location_shadow_right_accessory`,");
if (appendEntry(locations["Shadow_Left_Accessory"], value))
column.append("`location_shadow_left_accessory`,");
}
if (appendEntry(input["WeaponLevel"], value))
column.append("`weapon_level`,");
if (appendEntry(input["ArmorLevel"], value))
column.append("`armor_level`,");
if (appendEntry(input["EquipLevelMin"], value))
column.append("`equip_level_min`,");
if (appendEntry(input["EquipLevelMax"], value))
column.append("`equip_level_max`,");
if (appendEntry(input["Refineable"], value))
column.append("`refineable`,");
if (appendEntry(input["Gradable"], value))
column.append("`gradable`,");
if (appendEntry(input["View"], value))
column.append("`view`,");
if (appendEntry(input["AliasName"], value, true))
column.append("`alias_name`,");
const YAML::Node &flags = input["Flags"];
if (flags) {
if (appendEntry(flags["BuyingStore"], value))
column.append("`flag_buyingstore`,");
if (appendEntry(flags["DeadBranch"], value))
column.append("`flag_deadbranch`,");
if (appendEntry(flags["Container"], value))
column.append("`flag_container`,");
if (appendEntry(flags["UniqueId"], value))
column.append("`flag_uniqueid`,");
if (appendEntry(flags["BindOnEquip"], value))
column.append("`flag_bindonequip`,");
if (appendEntry(flags["DropAnnounce"], value))
column.append("`flag_dropannounce`,");
if (appendEntry(flags["NoConsume"], value))
column.append("`flag_noconsume`,");
if (appendEntry(flags["DropEffect"], value, true))
column.append("`flag_dropeffect`,");
}
const YAML::Node &delay = input["Delay"];
if (delay) {
if (appendEntry(delay["Duration"], value))
column.append("`delay_duration`,");
if (appendEntry(delay["Status"], value, true))
column.append("`delay_status`,");
}
const YAML::Node &stack = input["Stack"];
if (stack) {
if (appendEntry(stack["Amount"], value))
column.append("`stack_amount`,");
if (appendEntry(stack["Inventory"], value))
column.append("`stack_inventory`,");
if (appendEntry(stack["Cart"], value))
column.append("`stack_cart`,");
if (appendEntry(stack["Storage"], value))
column.append("`stack_storage`,");
if (appendEntry(stack["GuildStorage"], value))
column.append("`stack_guildstorage`,");
}
const YAML::Node &nouse = input["NoUse"];
if (nouse) {
if (appendEntry(nouse["Override"], value))
column.append("`nouse_override`,");
if (appendEntry(nouse["Sitting"], value))
column.append("`nouse_sitting`,");
}
const YAML::Node &trade = input["Trade"];
if (trade) {
if (appendEntry(trade["Override"], value))
column.append("`trade_override`,");
if (appendEntry(trade["NoDrop"], value))
column.append("`trade_nodrop`,");
if (appendEntry(trade["NoTrade"], value))
column.append("`trade_notrade`,");
if (appendEntry(trade["TradePartner"], value))
column.append("`trade_tradepartner`,");
if (appendEntry(trade["NoSell"], value))
column.append("`trade_nosell`,");
if (appendEntry(trade["NoCart"], value))
column.append("`trade_nocart`,");
if (appendEntry(trade["NoStorage"], value))
column.append("`trade_nostorage`,");
if (appendEntry(trade["NoGuildStorage"], value))
column.append("`trade_noguildstorage`,");
if (appendEntry(trade["NoMail"], value))
column.append("`trade_nomail`,");
if (appendEntry(trade["NoAuction"], value))
column.append("`trade_noauction`,");
}
if (appendEntry(input["Script"], value, true))
column.append("`script`,");
if (appendEntry(input["EquipScript"], value, true))
column.append("`equip_script`,");
if (appendEntry(input["UnEquipScript"], value, true))
column.append("`unequip_script`,");
column.pop_back(); // Remove last ','
value.pop_back(); // Remove last ','
outFile << "REPLACE INTO `" + table + "` (" + column + ") VALUES (" + value + ");\n";
entries++;
}
ShowStatus("Done converting '" CL_WHITE "%zu" CL_RESET "' items in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
return true;
}
// Copied and adjusted from mob.cpp
static bool mob_db_yaml2sql(const std::string &file, const std::string &table) {
size_t entries = 0;
for (const YAML::Node &input : inNode["Body"]) {
std::string column = "", value = "";
if (appendEntry(input["Id"], value))
column.append("`id`,");
if (appendEntry(input["AegisName"], value, true))
column.append("`name_aegis`,");
if (appendEntry(input["Name"], value, true))
column.append("`name_english`,");
if (appendEntry(input["Name"], value, true))
column.append("`name_japanese`,");
if (appendEntry(input["Level"], value))
column.append("`level`,");
if (appendEntry(input["Hp"], value))
column.append("`hp`,");
if (appendEntry(input["Sp"], value))
column.append("`sp`,");
if (appendEntry(input["BaseExp"], value))
column.append("`base_exp`,");
if (appendEntry(input["JobExp"], value))
column.append("`job_exp`,");
if (appendEntry(input["MvpExp"], value))
column.append("`mvp_exp`,");
if (appendEntry(input["Attack"], value))
column.append("`attack`,");
if (appendEntry(input["Attack2"], value))
column.append("`attack2`,");
if (appendEntry(input["Defense"], value))
column.append("`defense`,");
if (appendEntry(input["MagicDefense"], value))
column.append("`magic_defense`,");
#ifdef RENEWAL
if (appendEntry(input["Resistance"], value))
column.append("`resistance`,");
if (appendEntry(input["MagicResistance"], value))
column.append("`magic_resistance`,");
#endif
if (appendEntry(input["Str"], value))
column.append("`str`,");
if (appendEntry(input["Agi"], value))
column.append("`agi`,");
if (appendEntry(input["Vit"], value))
column.append("`vit`,");
if (appendEntry(input["Int"], value))
column.append("`int`,");
if (appendEntry(input["Dex"], value))
column.append("`dex`,");
if (appendEntry(input["Luk"], value))
column.append("`luk`,");
if (appendEntry(input["AttackRange"], value))
column.append("`attack_range`,");
if (appendEntry(input["SkillRange"], value))
column.append("`skill_range`,");
if (appendEntry(input["ChaseRange"], value))
column.append("`chase_range`,");
if (appendEntry(input["Size"], value, true))
column.append("`size`,");
if (appendEntry(input["Race"], value, true))
column.append("`race`,");
const YAML::Node &racegroups = input["RaceGroups"];
if (racegroups) {
for (uint16 i = 1; i < RC2_MAX; i++) {
std::string constant = constant_lookup(i, "RC2_");
constant.erase(0, 4);
if (appendEntry(racegroups[name2Upper(constant)], value)) {
std::transform(constant.begin(), constant.end(), constant.begin(), ::tolower);
column.append("`racegroup_" + constant + "`,");
}
}
}
if (appendEntry(input["Element"], value, true))
column.append("`element`,");
if (appendEntry(input["ElementLevel"], value))
column.append("`element_level`,");
if (appendEntry(input["WalkSpeed"], value))
column.append("`walk_speed`,");
if (appendEntry(input["AttackDelay"], value))
column.append("`attack_delay`,");
if (appendEntry(input["AttackMotion"], value))
column.append("`attack_motion`,");
if (appendEntry(input["DamageMotion"], value))
column.append("`damage_motion`,");
if (appendEntry(input["DamageTaken"], value))
column.append("`damage_taken`,");
if (appendEntry(input["Ai"], value, true))
column.append("`ai`,");
if (appendEntry(input["Class"], value, true))
column.append("`class`,");
const YAML::Node &modes = input["Modes"];
if (modes) {
if (appendEntry(modes["CanMove"], value))
column.append("`mode_canmove`,");
if (appendEntry(modes["Looter"], value))
column.append("`mode_looter`,");
if (appendEntry(modes["Aggressive"], value))
column.append("`mode_aggressive`,");
if (appendEntry(modes["Assist"], value))
column.append("`mode_assist`,");
if (appendEntry(modes["CastSensorIdle"], value))
column.append("`mode_castsensoridle`,");
if (appendEntry(modes["NoRandomWalk"], value))
column.append("`mode_norandomwalk`,");
if (appendEntry(modes["NoCast"], value))
column.append("`mode_nocast`,");
if (appendEntry(modes["CanAttack"], value))
column.append("`mode_canattack`,");
if (appendEntry(modes["CastSensorChase"], value))
column.append("`mode_castsensorchase`,");
if (appendEntry(modes["ChangeChase"], value))
column.append("`mode_changechase`,");
if (appendEntry(modes["Angry"], value))
column.append("`mode_angry`,");
if (appendEntry(modes["ChangeTargetMelee"], value))
column.append("`mode_changetargetmelee`,");
if (appendEntry(modes["ChangeTargetChase"], value))
column.append("`mode_changetargetchase`,");
if (appendEntry(modes["TargetWeak"], value))
column.append("`mode_targetweak`,");
if (appendEntry(modes["RandomTarget"], value))
column.append("`mode_randomtarget`,");
if (appendEntry(modes["IgnoreMelee"], value))
column.append("`mode_ignoremelee`,");
if (appendEntry(modes["IgnoreMagic"], value))
column.append("`mode_ignoremagic`,");
if (appendEntry(modes["IgnoreRanged"], value))
column.append("`mode_ignoreranged`,");
if (appendEntry(modes["Mvp"], value))
column.append("`mode_mvp`,");
if (appendEntry(modes["IgnoreMisc"], value))
column.append("`mode_ignoremisc`,");
if (appendEntry(modes["KnockBackImmune"], value))
column.append("`mode_knockbackimmune`,");
if (appendEntry(modes["TeleportBlock"], value))
column.append("`mode_teleportblock`,");
if (appendEntry(modes["FixedItemDrop"], value))
column.append("`mode_fixeditemdrop`,");
if (appendEntry(modes["Detector"], value))
column.append("`mode_detector`,");
if (appendEntry(modes["StatusImmune"], value))
column.append("`mode_statusimmune`,");
if (appendEntry(modes["SkillImmune"], value))
column.append("`mode_skillimmune`,");
}
for (uint16 i = 0; i < MAX_MVP_DROP; i++) {
if (!input["MvpDrops"].IsDefined())
continue;
const YAML::Node &mvpdrops = input["MvpDrops"][i];
if (mvpdrops) {
if (appendEntry(mvpdrops["Item"], value, true))
column.append("`mvpdrop" + std::to_string(i + 1) + "_item`,");
if (appendEntry(mvpdrops["Rate"], value))
column.append("`mvpdrop" + std::to_string(i + 1) + "_rate`,");
if (appendEntry(mvpdrops["RandomOptionGroup"], value, true))
column.append("`mvpdrop" + std::to_string(i + 1) + "_option`,");
if (appendEntry(mvpdrops["Index"], value))
column.append("`mvpdrop" + std::to_string(i + 1) + "_index`,");
}
}
for (uint16 i = 0; i < MAX_MOB_DROP; i++) {
if (!input["Drops"].IsDefined())
continue;
const YAML::Node &drops = input["Drops"][i];
if (drops) {
if (appendEntry(drops["Item"], value, true))
column.append("`drop" + std::to_string(i + 1) + "_item`,");
if (appendEntry(drops["Rate"], value))
column.append("`drop" + std::to_string(i + 1) + "_rate`,");
if (appendEntry(drops["StealProtected"], value))
column.append("`drop" + std::to_string(i + 1) + "_nosteal`,");
if (appendEntry(drops["RandomOptionGroup"], value, true))
column.append("`drop" + std::to_string(i + 1) + "_option`,");
if (appendEntry(drops["Index"], value))
column.append("`drop" + std::to_string(i + 1) + "_index`,");
}
}
column.pop_back(); // Remove last ','
value.pop_back(); // Remove last ','
outFile << "REPLACE INTO `" + table + "` (" + column + ") VALUES (" + value + ");\n";
entries++;
}
ShowStatus("Done converting '" CL_WHITE "%zu" CL_RESET "' mobs in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());
return true;
}
int main( int argc, char *argv[] ){
return main_core<Yaml2SqlTool>( argc, argv );
}