From 7e16e015c9522ffb1ad6a8faaaf53f73e7886b63 Mon Sep 17 00:00:00 2001 From: atemo Date: Tue, 15 Jan 2019 21:40:21 +0100 Subject: [PATCH 1/2] Elemental skill + db to yaml --- db/elemental_db.txt | 25 -- db/elemental_db.yml | 273 ++++++++++++++++++ db/elemental_skill_db.txt | 56 ---- db/import-tmpl/elemental_db.yml | 57 ++++ src/map/elemental.cpp | 487 +++++++++++++++++++++++++------- src/map/map-server.vcxproj | 2 +- 6 files changed, 718 insertions(+), 182 deletions(-) delete mode 100644 db/elemental_db.txt create mode 100644 db/elemental_db.yml delete mode 100644 db/elemental_skill_db.txt create mode 100644 db/import-tmpl/elemental_db.yml diff --git a/db/elemental_db.txt b/db/elemental_db.txt deleted file mode 100644 index 380ec5880c5..00000000000 --- a/db/elemental_db.txt +++ /dev/null @@ -1,25 +0,0 @@ -// Elemental Summons Database -// -// Structure of Database: -// ID,Sprite_Name,Name,LV,HP,SP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Speed,aDelay,aMotion,dMotion -// -// Notes: -// Summoned Elemental’s STATs are affected by the Caster’s Base Level and STATs. -// In other words, all values specified will be added to (and will not override) the calculated STATs of the summoned elemental. - -// Monster Elementals -2114,EL_AGNI_S,Agni,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,0,0,83,200,504,1020,360 -2115,EL_AGNI_M,Agni,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,1,0,83,200,504,1020,360 -2116,EL_AGNI_L,Agni,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,2,0,83,200,504,1020,360 - -2117,EL_AQUA_S,Aqua,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,0,0,81,200,504,1020,360 -2118,EL_AQUA_M,Aqua,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,1,0,81,200,504,1020,360 -2119,EL_AQUA_L,Aqua,100,0,1,1,0,0,0,0,1,1,1,1,1,1,5,12,2,0,81,200,504,1020,360 - -2120,EL_VENTUS_S,Ventus,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,0,0,84,200,504,1020,360 -2121,EL_VENTUS_M,Ventus,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,1,0,84,200,504,1020,360 -2122,EL_VENTUS_L,Ventus,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,2,0,84,200,504,1020,360 - -2123,EL_TERA_S,Tera,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,0,0,82,200,504,1020,360 -2124,EL_TERA_M,Tera,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,1,0,82,200,504,1020,360 -2125,EL_TERA_L,Tera,100,0,1,1,0,0,0,0,0,0,0,0,0,0,5,12,2,0,82,200,504,1020,360 diff --git a/db/elemental_db.yml b/db/elemental_db.yml new file mode 100644 index 00000000000..0584271f08a --- /dev/null +++ b/db/elemental_db.yml @@ -0,0 +1,273 @@ +#################################################################### +# +# Structure of Database: +# +#################################################################### +# +#- ID: (int) Elemental ID +# Sprite_Name: (string) Elemental Aegis name +# Name: (string) Elemental displayed name +# Scale: (constant) Elemental size - See doc/item_bonus.txt +# Element: +# Type: (constant) See doc/item_bonus.txt +# Level: (int) +# SpiritMode: +# Passive: +# - SkillID: (constant) +# SkillLevel: (int) (0 to remove the skill on import) +# Defensive: +# - SkillID: (constant) +# SkillLevel: (int) +# Aggressive: +# - SkillID: (constant) +# SkillLevel: (int) +# +# (Optional fields) +# +# LV: (int, default 100) +# HP: (int, default 0) +# SP: (int, default 1) +# Range1: (int, default 1) Elemental basic attaque range +# ATK1: (int, default 0) +# ATK2: (int, default 0) +# DEF: (int, default 0) +# MDEF: (int, default 0) +# STR: (int, default 0) +# AGI: (int, default 0) +# VIT: (int, default 0) +# INT: (int, default 0) +# DEX: (int, default 0) +# LUK: (int, default 0) +# Range2: (int, default 5) Elemental skill attaque range +# Range3: (int, default 12) Elemental visual range +# Race: (constant, default RC_Formless) See doc/item_bonus.txt +# Speed: (int, default 200) +# aDelay: (int, default 504) +# aMotion: (int, default 1020) +# dMotion: (int, default 360) +# +#################################################################### +# +# Notes: +# Summoned Elemental’s STATs are affected by the Caster’s Base Level and STATs. +# In other words, all values specified will be added to (and will not override) the calculated STATs of the summoned elemental. + +# SkillLevel 0 remove the skill +# +#################################################################### + +- ID: 2114 + SpriteName: "EL_AGNI_S" + Name: "Agni" + Scale: Size_Small + Element: + Type: Ele_Fire + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_PYROTECHNIC + SkillLevel: 1 + Defensive: + - SkillID: EL_CIRCLE_OF_FIRE + SkillLevel: 1 + Aggressive: + - SkillID: EL_FIRE_ARROW + SkillLevel: 1 + +- ID: 2115 + SpriteName: "EL_AGNI_M" + Name: "Agni" + Scale: Size_Medium + Element: + Type: Ele_Fire + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_HEATER + SkillLevel: 1 + Defensive: + - SkillID: EL_FIRE_CLOAK + SkillLevel: 1 + Aggressive: + - SkillID: EL_FIRE_BOMB + SkillLevel: 1 + +- ID: 2116 + SpriteName: "EL_AGNI_L" + Name: "Agni" + Scale: Size_Large + Element: + Type: Ele_Fire + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_TROPIC + SkillLevel: 1 + Defensive: + - SkillID: EL_FIRE_MANTLE + SkillLevel: 1 + Aggressive: + - SkillID: EL_FIRE_WAVE + SkillLevel: 1 + +- ID: 2117 + SpriteName: "EL_AQUA_S" + Name: "Aqua" + Scale: Size_Small + Element: + Type: Ele_Water + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_AQUAPLAY + SkillLevel: 1 + Defensive: + - SkillID: EL_WATER_SCREEN + SkillLevel: 1 + Aggressive: + - SkillID: EL_ICE_NEEDLE + SkillLevel: 1 + +- ID: 2118 + SpriteName: "EL_AQUA_M" + Name: "Aqua" + Scale: Size_Medium + Element: + Type: Ele_Water + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_COOLER + SkillLevel: 1 + Defensive: + - SkillID: EL_WATER_DROP + SkillLevel: 1 + Aggressive: + - SkillID: EL_WATER_SCREW + SkillLevel: 1 + +- ID: 2119 + SpriteName: "EL_AQUA_L" + Name: "Aqua" + Scale: Size_Large + Element: + Type: Ele_Water + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_CHILLY_AIR + SkillLevel: 1 + Defensive: + - SkillID: EL_WATER_BARRIER + SkillLevel: 1 + Aggressive: + - SkillID: EL_TIDAL_WEAPON + SkillLevel: 1 + +- ID: 2120 + SpriteName: "EL_VENTUS_S" + Name: "Ventus" + Scale: Size_Small + Element: + Type: Ele_Wind + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_GUST + SkillLevel: 1 + Defensive: + - SkillID: EL_WIND_STEP + SkillLevel: 1 + Aggressive: + - SkillID: EL_WIND_SLASH + SkillLevel: 1 + +- ID: 2121 + SpriteName: "EL_VENTUS_M" + Name: "Ventus" + Scale: Size_Medium + Element: + Type: Ele_Wind + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_BLAST + SkillLevel: 1 + Defensive: + - SkillID: EL_WIND_CURTAIN + SkillLevel: 1 + Aggressive: + - SkillID: EL_HURRICANE + SkillLevel: 1 + +- ID: 2122 + SpriteName: "EL_VENTUS_L" + Name: "Ventus" + Scale: Size_Large + Element: + Type: Ele_Wind + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_WILD_STORM + SkillLevel: 1 + Defensive: + - SkillID: EL_ZEPHYR + SkillLevel: 1 + Aggressive: + - SkillID: EL_TYPOON_MIS + SkillLevel: 1 + +- ID: 2123 + SpriteName: "EL_TERA_S" + Name: "Tera" + Scale: Size_Small + Element: + Type: Ele_Earth + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_PETROLOGY + SkillLevel: 1 + Defensive: + - SkillID: EL_SOLID_SKIN + SkillLevel: 1 + Aggressive: + - SkillID: EL_STONE_HAMMER + SkillLevel: 1 + +- ID: 2124 + SpriteName: "EL_TERA_M" + Name: "Tera" + Scale: Size_Medium + Element: + Type: Ele_Earth + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_CURSED_SOIL + SkillLevel: 1 + Defensive: + - SkillID: EL_STONE_SHIELD + SkillLevel: 1 + Aggressive: + - SkillID: EL_ROCK_CRUSHER + SkillLevel: 1 + +- ID: 2125 + SpriteName: "EL_TERA_L" + Name: "Tera" + Scale: Size_Large + Element: + Type: Ele_Earth + Level: 4 + SpiritMode: + Passive: + - SkillID: EL_UPHEAVAL + SkillLevel: 1 + Defensive: + - SkillID: EL_POWER_OF_GAIA + SkillLevel: 1 + Aggressive: + - SkillID: EL_STONE_RAIN + SkillLevel: 1 diff --git a/db/elemental_skill_db.txt b/db/elemental_skill_db.txt deleted file mode 100644 index f2377e19ea1..00000000000 --- a/db/elemental_skill_db.txt +++ /dev/null @@ -1,56 +0,0 @@ -// Elemental Summons Skill Database -// -// Structure of Database: -// ElementalID,SkillID,SkillLevel,ReqMode -// -// Spirit Modes: -// 1 = Passive, 2 = Defensive, 4 = Aggressive - -// EL_AGNI_S -2114,8413,1,1 //EL_PYROTECHNIC,Pyrotechnic -2114,8401,1,2 //EL_CIRCLE_OF_FIRE,Circle of Fire -2114,8425,1,4 //EL_FIRE_ARROW,Fire Arrow -// EL_AGNI_M -2115,8414,1,1 //EL_HEATER,Heater -2115,8402,1,2 //EL_FIRE_CLOAK,Fire Cloak -2115,8426,1,4 //EL_FIRE_BOMB,Fire Bomb -// EL_AGNI_L -2116,8415,1,1 //EL_TROPIC,Tropic -2116,8403,1,2 //EL_FIRE_MANTLE,Fire Mantle -2116,8428,1,4 //EL_FIRE_WAVE,Fire Wave -// EL_AQUA_S -2117,8416,1,1 //EL_AQUAPLAY,Aqua Play -2117,8404,1,2 //EL_WATER_SCREEN,Water Screen -2117,8430,1,4 //EL_ICE_NEEDLE,Ice Needle -// EL_AQUA_M -2118,8417,1,1 //EL_COOLER,Cooler -2118,8405,1,2 //EL_WATER_DROP,Water Drop -2118,8431,1,4 //EL_WATER_SCREW,Water Screw -// EL_AQUA_L -2119,8418,1,1 //EL_CHILLY_AIR,Cool Air -2119,8406,1,2 //EL_WATER_BARRIER,Water Barrier -2119,8433,1,4 //EL_TIDAL_WEAPON,Tidal Weapon -// EL_VENTUS_S -2120,8419,1,1 //EL_GUST,Gust -2120,8407,1,2 //EL_WIND_STEP,Wind Step -2120,8434,1,4 //EL_WIND_SLASH,Wind Slasher -// EL_VENTUS_M -2121,8420,1,1 //EL_BLAST,Blast -2121,8408,1,2 //EL_WIND_CURTAIN,Wind Curtain -2121,8435,1,4 //EL_HURRICANE,Hurricane Rage -// EL_VENTUS_L -2122,8421,1,1 //EL_WILD_STORM,Wild Storm -2122,8409,1,2 //EL_ZEPHYR,Zephyr -2122,8437,1,4 //EL_TYPOON_MIS,Typhoon Missile -// EL_TERA_S -2123,8422,1,1 //EL_PETROLOGY,Petrology -2123,8410,1,2 //EL_SOLID_SKIN,Solid Skin -2123,8439,1,4 //EL_STONE_HAMMER,Stone Hammer -// EL_TERA_M -2124,8423,1,1 //EL_CURSED_SOIL,Cursed Soil -2124,8411,1,2 //EL_STONE_SHIELD,Stone Shield -2124,8440,1,4 //EL_ROCK_CRUSHER,Rock Launcher -// EL_TERA_L -2125,8424,1,1 //EL_UPHEAVAL,Upheaval -2125,8412,1,2 //EL_POWER_OF_GAIA,Power of Gaia -2125,8442,1,4 //EL_STONE_RAIN,Stone Rain diff --git a/db/import-tmpl/elemental_db.yml b/db/import-tmpl/elemental_db.yml new file mode 100644 index 00000000000..b527a241967 --- /dev/null +++ b/db/import-tmpl/elemental_db.yml @@ -0,0 +1,57 @@ +#################################################################### +# +# Structure of Database: +# +#################################################################### +# +#- ID: (int) Elemental ID +# Sprite_Name: (string) Elemental Aegis name +# Name: (string) Elemental displayed name +# Scale: (constant) Elemental size - See doc/item_bonus.txt +# Element: +# Type: (constant) See doc/item_bonus.txt +# Level: (int) +# SpiritMode: +# Passive: +# - SkillID: (constant) +# SkillLevel: (int) (0 to remove the skill on import) +# Defensive: +# - SkillID: (constant) +# SkillLevel: (int) +# Aggressive: +# - SkillID: (constant) +# SkillLevel: (int) +# +# (Optional fields) +# +# LV: (int, default 100) +# HP: (int, default 0) +# SP: (int, default 1) +# Range1: (int, default 1) Elemental basic attaque range +# ATK1: (int, default 0) +# ATK2: (int, default 0) +# DEF: (int, default 0) +# MDEF: (int, default 0) +# STR: (int, default 0) +# AGI: (int, default 0) +# VIT: (int, default 0) +# INT: (int, default 0) +# DEX: (int, default 0) +# LUK: (int, default 0) +# Range2: (int, default 5) Elemental skill attaque range +# Range3: (int, default 12) Elemental visual range +# Race: (constant, default RC_Formless) See doc/item_bonus.txt +# Speed: (int, default 200) +# aDelay: (int, default 504) +# aMotion: (int, default 1020) +# dMotion: (int, default 360) +# +#################################################################### +# +# Notes: +# Summoned Elemental’s STATs are affected by the Caster’s Base Level and STATs. +# In other words, all values specified will be added to (and will not override) the calculated STATs of the summoned elemental. + +# SkillLevel 0 remove the skill +# +#################################################################### diff --git a/src/map/elemental.cpp b/src/map/elemental.cpp index 4d8c9d4cda8..9ed27f641d2 100644 --- a/src/map/elemental.cpp +++ b/src/map/elemental.cpp @@ -7,6 +7,7 @@ #include //floor #include #include +#include #include "../common/cbasetypes.hpp" #include "../common/malloc.hpp" @@ -756,132 +757,418 @@ static TIMER_FUNC(elemental_ai_timer){ return 0; } +static void yaml_invalid_warning(const char* fmt, const YAML::Node &node, const std::string &file) { + YAML::Emitter out; + out << node; + ShowWarning(fmt, file.c_str()); + ShowMessage("%s\n", out.c_str()); +} + +static bool yaml_assert_exists(const YAML::Node &node, const std::string &key, const std::string &source, const char * func) { + if (!node[key]) { + std::string msg = std::string(func) + ": Missing " + key + " field in '" CL_WHITE "%s" CL_RESET "', skipping.\n"; + yaml_invalid_warning(msg.c_str(), node, source); + return false; + } + return true; +} + +static void yaml_catch_warning(const YAML::Node &node, const std::string &key, const std::string &source, const char * func) { + std::string msg = std::string(func) + ": Node definition with invalid " + key + " field in '" CL_WHITE "%s" CL_RESET "', skipping.\n"; + yaml_invalid_warning(msg.c_str(), node, source); +} + /** -* Reads Elemental DB lines -* ID,Sprite_Name,Name,LV,HP,SP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Speed,aDelay,aMotion,dMotion +* Reads Elemental DB */ -static bool read_elementaldb_sub(char* str[], int columns, int current) { - uint16 class_ = atoi(str[0]), i, ele; +bool read_elementaldb_sub (const YAML::Node &node, int elemental_count, const std::string &source) { struct s_elemental_db *db; struct status_data *status; + std::string spritename, name, scale_constant, ele_type_constant; + int class_, i, scale, ele_type, ele_level; + + const std::string labels[] = { "ID", "SpriteName", "Name", "Scale", "Element" }; + + for (const auto &lab : labels) { + if (!yaml_assert_exists(node, lab, source, "read_elementaldb_sub")) { + return false; + } + } + const YAML::Node &element_list = node["Element"]; + if (!yaml_assert_exists(element_list, "Type", source, "read_elementaldb_sub") || !yaml_assert_exists(element_list, "Level", source, "read_elementaldb_sub")) { + return false; + } - //Find the ID, already exist or not in elemental_db - ARR_FIND(0,elemental_count,i,elemental_db[i].class_ == class_); + try { + class_ = node["ID"].as(); + } catch (...) { + yaml_catch_warning(node, "ID", source, "read_elementaldb_sub"); + return false; + } + try { + spritename = node["SpriteName"].as(); + } catch (...) { + yaml_catch_warning(node, "SpriteName", source, "read_elementaldb_sub"); + return false; + } + try { + name = node["Name"].as(); + } catch (...) { + yaml_catch_warning(node, "Name", source, "read_elementaldb_sub"); + return false; + } + try { + scale_constant = node["Scale"].as(); + } catch (...) { + yaml_catch_warning(node, "Scale", source, "read_elementaldb_sub"); + return false; + } + if (!script_get_constant(scale_constant.c_str(), (int *)&scale)) { + ShowWarning("read_elementaldb_sub: Invalid Scale constant %s for ID %d in \"%s\", skipping.\n", scale_constant.c_str(), class_, source.c_str()); + return false; + } + if (scale < SZ_SMALL || scale > SZ_BIG) { + ShowWarning("read_elementaldb_sub: Invalid scale %d for ID %d in \"%s\" (min: %d, max: %d), skipping.\n", scale, class_, source.c_str(), SZ_SMALL, SZ_BIG); + return false; + } + try { + ele_type_constant = element_list["Type"].as(); + } catch (...) { + yaml_catch_warning(element_list, "Type", source, "read_elementaldb_sub"); + return false; + } + if (!script_get_constant(ele_type_constant.c_str(), (int *)&ele_type)) { + ShowWarning("read_elementaldb_sub: Invalid element Type constant %s for ID %d in \"%s\", skipping.\n", ele_type_constant.c_str(), class_, source.c_str()); + return false; + } + if (ele_type < ELE_NEUTRAL || ele_type > ELE_UNDEAD) { + ShowWarning("read_elementaldb_sub: Invalid element Type %d for ID %d in \"%s\" (min: %d, max: %d), skipping.\n", ele_type, class_, source.c_str(), ELE_NEUTRAL, ELE_UNDEAD); + return false; + } + try { + ele_level = element_list["Level"].as(); + } catch (...) { + yaml_catch_warning(element_list, "Level", source, "read_elementaldb_sub"); + return false; + } + if (!CHK_ELEMENT_LEVEL(ele_level)) { + ShowWarning("read_elementaldb_sub: Elemental %d has invalid element level %d (max is %d) in \"%s\", skipping.\n", class_, ele_level, MAX_ELE_LEVEL, source.c_str()); + return false; + } + + // Find the ID, already exist or not in elemental_db + ARR_FIND(0, elemental_count, i, elemental_db[i].class_ == class_); if (i >= elemental_count) db = &elemental_db[elemental_count]; else db = &elemental_db[i]; - - db->class_ = atoi(str[0]); - safestrncpy(db->sprite, str[1], NAME_LENGTH); - safestrncpy(db->name, str[2], NAME_LENGTH); - db->lv = atoi(str[3]); + db->class_ = class_; + + safestrncpy(db->sprite, spritename.c_str(), NAME_LENGTH); + safestrncpy(db->name, name.c_str(), NAME_LENGTH); status = &db->status; db->vd.class_ = db->class_; + status->size = scale; + status->def_ele = ele_type; + status->ele_lv = ele_level; + + // default value for optional fields + db->lv = 100; + db->range2 = 5; + db->range3 = 12; + status->max_hp = 0; + status->max_sp = 1; + status->rhw.range = 1; - status->max_hp = atoi(str[4]); - status->max_sp = atoi(str[5]); - status->rhw.range = atoi(str[6]); #ifdef RENEWAL - status->rhw.atk = atoi(str[7]); // BaseATK - status->rhw.matk = atoi(str[8]); // BaseMATK + status->rhw.atk = 0; // BaseATK + status->rhw.matk = 0; // BaseMATK #else - status->rhw.atk = atoi(str[7]); // MinATK - status->rhw.atk2 = atoi(str[8]); // MaxATK + status->rhw.atk = 0; // MinATK + status->rhw.atk2 = 0; // MaxATK #endif - status->def = atoi(str[9]); - status->mdef = atoi(str[10]); - status->str = atoi(str[11]); - status->agi = atoi(str[12]); - status->vit = atoi(str[13]); - status->int_ = atoi(str[14]); - status->dex = atoi(str[15]); - status->luk = atoi(str[16]); - db->range2 = atoi(str[17]); - db->range3 = atoi(str[18]); - status->size = atoi(str[19]); - status->race = atoi(str[20]); - - ele = atoi(str[21]); - status->def_ele = ele%20; - status->ele_lv = (unsigned char)floor(ele/20.); - if( !CHK_ELEMENT(status->def_ele) ) { - ShowWarning("read_elementaldb_sub: Elemental %d has invalid element type %d (max element is %d)\n", db->class_, status->def_ele, ELE_ALL - 1); - status->def_ele = ELE_NEUTRAL; - } - if( !CHK_ELEMENT_LEVEL(status->ele_lv) ) { - ShowWarning("read_elementaldb_sub: Elemental %d has invalid element level %d (max is %d)\n", db->class_, status->ele_lv, MAX_ELE_LEVEL); - status->ele_lv = 1; - } + status->def = 0; + status->mdef = 0; + status->str = 0; + status->agi = 0; + status->vit = 0; + status->int_ = 0; + status->dex = 0; + status->luk = 0; + status->race = 0; status->aspd_rate = 1000; - status->speed = atoi(str[22]); - status->adelay = atoi(str[23]); - status->amotion = atoi(str[24]); - status->dmotion = atoi(str[25]); - - if (i >= elemental_count) - elemental_count++; - return true; -} - -void read_elementaldb(void) { - const char *filename[] = { "elemental_db.txt", DBIMPORT"/elemental_db.txt" }; - uint8 i; - - elemental_count = 0; - memset(elemental_db, 0, sizeof(elemental_db)); - for(i = 0; i 0); + status->speed = 200; + status->adelay = 504; + status->amotion = 1020; + status->dmotion = 360; + + char warning_text[512]; + sprintf( warning_text, "read_elementaldb_sub: Invalid elemental %s definition for ID %d in \"%s\", defaulting to %s.\n", "%s", class_, source.c_str(), "%d"); + + if (node["LV"]) { + // catch_value( db->lv, "LV", 100, warning_text ); + try { + db->lv = node["LV"].as(); + } catch (...) { + ShowWarning( warning_text, "LV", 100 ); + db->lv = 100; + } } -} - -/** -* Reads Elemental Skill DB lines -* ElementalID,SkillID,SkillLevel,ReqMode -*/ -static bool read_elemental_skilldb_sub(char* str[], int columns, int current) { - uint16 class_ = atoi(str[0]), skill_id, skill_lv, skillmode; - uint8 i; - struct s_elemental_db *db; - - ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental_db[i].class_); - if( i == MAX_ELEMENTAL_CLASS ) { - ShowError("read_elemental_skilldb_sub: Class not found in elemental_db for skill entry, line %d.\n", current); - return false; + if (node["HP"]) { + try { + status->max_hp = node["HP"].as(); + } catch (...) { + ShowWarning( warning_text, "HP", 0 ); + status->max_hp = 0; + } } - - skill_id = atoi(str[1]); - if( !SKILL_CHK_ELEM(skill_id) ) { - ShowError("read_elemental_skilldb_sub: Invalid Elemental skill '%d'.\n", skill_id); - return false; + if (node["SP"]) { + try { + status->max_sp = node["SP"].as(); + } catch (...) { + ShowWarning( warning_text, "SP", 1 ); + status->max_sp = 1; + } + } + if (node["Range"]) { + try { + status->rhw.range = node["Range"].as(); + } catch (...) { + ShowWarning( warning_text, "Range", 1 ); + status->rhw.range = 1; + } + } + if (node["ATK1"]) { + try { + status->rhw.atk = node["ATK1"].as(); // BaseATK renewal ; MinATK pre-renewal + } catch (...) { + ShowWarning( warning_text, "ATK1", 0 ); + status->rhw.atk = 0; + } + } +#ifdef RENEWAL + if (node["ATK2"]) { + try { + status->rhw.matk = node["ATK2"].as(); + } catch (...) { + ShowWarning( warning_text, "ATK2", 0 ); + status->rhw.matk = 0; + } + } +#else + if (node["ATK2"]) { + try { + status->rhw.atk2 = node["ATK2"].as(); + } catch (...) { + ShowWarning( warning_text, "ATK2", 0 ); + status->rhw.atk2 = 0; + } + } +#endif + if (node["DEF"]) { + try { + status->def = node["DEF"].as(); + } catch (...) { + ShowWarning( warning_text, "DEF", 0 ); + status->def = 0; + } + } + if (node["MDEF"]) { + try { + status->mdef = node["MDEF"].as(); + } catch (...) { + ShowWarning( warning_text, "MDEF", 0 ); + status->mdef = 0; + } + } + if (node["STR"]) { + try { + status->str = node["STR"].as(); + } catch (...) { + ShowWarning( warning_text, "STR", 0 ); + status->str = 0; + } + } + if (node["AGI"]) { + try { + status->agi = node["AGI"].as(); + } catch (...) { + ShowWarning( warning_text, "AGI", 0 ); + status->agi = 0; + } + } + if (node["VIT"]) { + try { + status->vit = node["VIT"].as(); + } catch (...) { + ShowWarning( warning_text, "VIT", 0 ); + status->vit = 0; + } + } + if (node["INT"]) { + try { + status->int_ = node["INT"].as(); + } catch (...) { + ShowWarning( warning_text, "INT", 0 ); + status->int_ = 0; + } + } + if (node["DEX"]) { + try { + status->dex = node["DEX"].as(); + } catch (...) { + ShowWarning( warning_text, "DEX", 0 ); + status->dex = 0; + } + } + if (node["LUK"]) { + try { + status->luk = node["LUK"].as(); + } catch (...) { + ShowWarning( warning_text, "LUK", 0 ); + status->luk = 0; + } + } + if (node["Range2"]) { + try { + db->range2 = node["Range2"].as(); + } catch (...) { + ShowWarning( warning_text, "Range2", 5 ); + db->range2 = 5; + } + } + if (node["Range3"]) { + try { + db->range3 = node["Range3"].as(); + } catch (...) { + ShowWarning( warning_text, "Range3", 12 ); + db->range3 = 12; + } + } + if (node["Race"]) { + try { + std::string race_constant = node["Race"].as(); + int race; + if (!script_get_constant(race_constant.c_str(), (int *)&race)) { + ShowWarning("read_elementaldb_sub: Invalid elemental Race constant %s for ID %d in \"%s\", defaulting to RC_Formless.\n", race_constant.c_str(), class_, source.c_str()); + status->race = 0; + } + else if (race < RC_FORMLESS || race > RC_PLAYER) { + ShowWarning("read_elementaldb_sub: Invalid race %d for ID %d in \"%s\" (min: %d, max: %d), defaulting to RC_Formless.\n", race, class_, source.c_str(), RC_FORMLESS, RC_PLAYER); + status->race = 0; + } + else { + status->race = race; + } + } catch (...) { + ShowWarning("read_elementaldb_sub: Invalid elemental Race definition for ID %d in \"%s\", defaulting to RC_Formless.\n", class_, source.c_str()); + status->race = 0; + } + } + if (node["Speed"]) { + try { + status->speed = node["Speed"].as(); + } catch (...) { + ShowWarning( warning_text, "Speed", 200 ); + status->speed = 200; + } + } + if (node["aDelay"]) { + try { + status->adelay = node["aDelay"].as(); + } catch (...) { + ShowWarning( warning_text, "aDelay", 504 ); + status->adelay = 504; + } + } + if (node["aMotion"]) { + try { + status->amotion = node["aMotion"].as(); + } catch (...) { + ShowWarning( warning_text, "aMotion", 1020 ); + status->amotion = 1020; + } + } + if (node["dMotion"]) { + try { + status->dmotion = node["dMotion"].as(); + } catch (...) { + ShowWarning( warning_text, "dMotion", 360 ); + status->dmotion = 360; + } } - db = &elemental_db[i]; - skill_lv = atoi(str[2]); + // elemental skills + if (node["SpiritMode"]) { + const YAML::Node &spirit_mode = node["SpiritMode"]; + const std::string labels[] = { "Passive", "Defensive", "Aggressive" }; - skillmode = atoi(str[3]); - if( skillmode < EL_SKILLMODE_PASSIVE || skillmode > EL_SKILLMODE_AGGRESSIVE ) { - ShowError("read_elemental_skilldb_sub: Skillmode out of range, line %d.\n",current); - return false; - } - ARR_FIND( 0, MAX_ELESKILLTREE, i, db->skill[i].id == 0 || db->skill[i].id == skill_id ); - if( i == MAX_ELESKILLTREE ) { - ShowWarning("read_elemental_skilldb_sub: Unable to load skill %d into Elemental %d's tree. Maximum number of skills per elemental has been reached.\n", skill_id, class_); - return false; + for (int index = 0; index < ARRAYLENGTH(labels); index++) { + if (!spirit_mode[ labels[index] ]) { + continue; + } + for (const auto &spirit_skill : spirit_mode[ labels[index] ]) { + std::string skill_name; + int skill_id, skill_lv = 1; + uint8 j; + + if (!yaml_assert_exists(spirit_skill, "SkillID", source, "read_elementaldb_sub") || !yaml_assert_exists(spirit_skill, "SkillLevel", source, "read_elementaldb_sub")) { + continue; + } + try { + skill_name = spirit_skill["SkillID"].as(); + } catch (...) { + yaml_catch_warning(spirit_skill, "SkillID", source, "read_elementaldb_sub"); + continue; + } + try { + skill_lv = spirit_skill["SkillLevel"].as(); + } catch (...) { + yaml_catch_warning(spirit_skill, "SkillLevel", source, "read_elementaldb_sub"); + continue; + } + skill_id = skill_name2id( skill_name.c_str() ); + if (!SKILL_CHK_ELEM(skill_id)) { + ShowWarning("read_elementaldb_sub: Invalid Elemental skill '%d' for ID %d in \"%s\", skipping this skill.\n", skill_id, class_, source.c_str()); + continue; + } + ARR_FIND( 0, MAX_ELESKILLTREE, j, db->skill[j].id == 0 || db->skill[j].id == skill_id ); + if (j == MAX_ELESKILLTREE) { + ShowWarning("read_elementaldb_sub: Unable to load skill %d into Elemental %d's tree. Maximum number of skills per elemental has been reached in \"%s\", skipping.\n", skill_id, class_, source.c_str()); + return false; + } + db->skill[j].id = skill_id; + db->skill[j].lv = skill_lv; + db->skill[j].mode = index; + } + } } - db->skill[i].id = skill_id; - db->skill[i].lv = skill_lv; - db->skill[i].mode = skillmode; - return true; + return (i >= elemental_count); } -void read_elemental_skilldb(void) { - const char *filename[] = { "elemental_skill_db.txt", DBIMPORT"/elemental_skill_db.txt" }; - uint8 i; - for(i = 0; i 0); +void read_elementaldb(void) { + std::vector directories = { std::string(db_path) + "/", std::string(db_path) + "/" + std::string(DBIMPORT) + "/" }; + static const std::string file_name("elemental_db.yml"); + memset(elemental_db, 0, sizeof(elemental_db)); + elemental_count = 0; + + for (auto &directory : directories) { + std::string current_file = directory + file_name; + YAML::Node root; + + try { + root = YAML::LoadFile(current_file); + } catch (...) { + ShowError("Failed to read '" CL_WHITE "%s" CL_RESET "'.\n", current_file.c_str()); + continue; + } + for (const auto &node : root) { + if (node.IsDefined() && read_elementaldb_sub(node, elemental_count, current_file)) + elemental_count++; + } + ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_BLUE "%s" CL_RESET "'\n", elemental_count, current_file.c_str()); } } diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index 7348425d09b..f6463866726 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -297,7 +297,7 @@ - + From 2e6a6c47cd8a02f14c0de33c7219425f7efc00e1 Mon Sep 17 00:00:00 2001 From: atemo Date: Tue, 15 Jan 2019 21:47:45 +0100 Subject: [PATCH 2/2] Remove read_elemental_skilldb --- src/map/atcommand.cpp | 1 - src/map/elemental.cpp | 6 ------ 2 files changed, 7 deletions(-) diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index fd39227d997..07c3374fba7 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -3824,7 +3824,6 @@ ACMD_FUNC(reload) { } else if (strstr(command, "skilldb") || strncmp(message, "skilldb", 4) == 0) { skill_reload(); hom_reload_skill(); - reload_elemental_skilldb(); mercenary_read_skilldb(); clif_displaymessage(fd, msg_txt(sd,99)); // Skill database has been reloaded. } else if (strstr(command, "atcommand") || strncmp(message, "atcommand", 4) == 0) { diff --git a/src/map/elemental.cpp b/src/map/elemental.cpp index 9ed27f641d2..ab74cbde529 100644 --- a/src/map/elemental.cpp +++ b/src/map/elemental.cpp @@ -1174,16 +1174,10 @@ void read_elementaldb(void) { void reload_elementaldb(void) { read_elementaldb(); - reload_elemental_skilldb(); -} - -void reload_elemental_skilldb(void) { - read_elemental_skilldb(); } void do_init_elemental(void) { read_elementaldb(); - read_elemental_skilldb(); add_timer_func_list(elemental_ai_timer,"elemental_ai_timer"); add_timer_interval(gettick()+MIN_ELETHINKTIME,elemental_ai_timer,0,0,MIN_ELETHINKTIME);