diff --git a/db/abra_db.txt b/db/abra_db.txt deleted file mode 100644 index d84c815b12..0000000000 --- a/db/abra_db.txt +++ /dev/null @@ -1,227 +0,0 @@ -// Hocus-Pocus (Abracadabra) Castable Skills Database -// -// Structure of Database: -// SkillID,DummyName,ProbabilityPerLvl -// -// 01. SkillID Skill ID to be casted by hocus pocus. -// 02. DummyName Name of the skill (informative, not used by server). -// 03. ProbabilityPerLvl Not a rate! Chance at which the skill is selected compared -// with other entries probabilties -// -// NOTE: -// - The skill is picked at random from the entire database and then tested for rate. If it -// does not succeed at that rate, another skill is picked and tested. This continues -// until a skill succeeds. Abracadabra-specific skills have a different chance to occur -// depending on skill level used. All other skills have an equal chance and appear from -// level 1 onward. -// - To remove entry by importing, put "clear" (without quotes) in DummyName - -5,Bash,500 -6,Provoke,500 -7,Magnum Break,500 -8,Endure,500 - -10,Sight,500 -11,Napalm Beat,500 -12,Safety Wall,500 -13,Soul Strike,500 -14,Cold Bolt,500 -15,Frost Diver,500 -16,Stone Curse,500 -17,Fire Ball,500 -18,Fire Wall,500 -19,Fire Bolt,500 -20,Lightning Bolt,500 -21,Thunder Storm,500 - -24,Ruwach,500 -25,Pneuma,500 -26,Teleport,500 -27,Warp Portal,500 -28,Heal,500 -29,Increase AGI,500 -30,Decrease AGI,500 -31,Aqua Benedicta,500 -32,Signum Crucis,500 -33,Angelus,500 -34,Blessing,500 -35,Cure,500 - -40,Item Appraisal,500 -41,Vending,500 -42,Mammonite,500 - -45,Improve Concentration,500 -46,Double Strafe,500 -47,Arrow Shower,500 - -50,Steal,500 -51,Hiding,500 -52,Envenom,500 -53,Detoxify,500 - -54,Resurrection,500 - -56,Pierce,500 -57,Brandish Spear,500 -58,Spear Stab,500 -59,Spear Boomerang,500 -60,TwoHand Quicken,500 -61,Counter Attack,500 -62,Bowling Bash,500 - -66,Impositio Manus,500 -67,Suffragium,500 -68,Aspersio,500 -69,B.S Sacramenti,500 -70,Sanctuary,500 -71,Slow poison,500 -72,Status Recovery,500 -73,Kyrie Eleison,500 -74,Magnificat,500 -75,Gloria,500 -76,Lex Divina,500 -77,Turn Undead,500 -78,Lex Aeterna,500 -79,Magnus Exorcismus,500 - -80,Fire Pillar,500 -81,Sightrasher,500 -//82,Fire Ivy,500 -83,Meteor Storm,500 -84,Jupitel Thunder,500 -85,Lord of Vermilion,500 -86,Water Ball,500 -87,Ice Wall,500 -88,Frost Nova,500 -89,Storm Gust,500 -90,Earth spike,500 -91,Heaven's Drive,500 -92,Quagmire,500 -93,Sense,500 - -//108,Weapon Repair,500 -110,Hammer Fall,500 -111,Adrenaline Rush,500 -112,Weapon Perfection,500 -113,Power-Thrust,500 -114,Maximize Power,500 - -115,Skid Trap,500 -116,Land Mine,500 -117,Ankle Snare,500 -118,Shockwave Trap,500 -119,Sandman,500 -120,Flasher,500 -121,Freezing Trap,500 -122,Blast Mine,500 -123,Claymore Trap,500 -124,Remove Trap,500 -125,Talkie box,500 -129,Blitz Beat,500 -130,Detect,500 -131,Spring Trap,500 - -135,Cloaking,500 -136,Sonic Blow,500 -137,Grimtooth,500 -138,Enchant Poison,500 -139,Poison React,500 -140,Venom Dust,500 -141,Venom Splasher,500 - -//---EP4.0 Skill--- -211,Mug,500 -212,Back Stab,500 -214,Sightless Raid,500 -215,Divest Weapon,500 -216,Divest Shield,500 -217,Divest Armor,500 -218,Divest Helm,500 -219,Snatch,500 -220,Scribble,500 -//221,Piece,500 -222,Remover,500 - -249,Guard,500 -250,Smite,500 -251,Shield Boomerang,500 -252,Shield Reflect,500 -253,Holy Cross,500 -254,Grand Cross,500 -255,Sacrifice,500 -256,Resistant Souls,500 -257,Defending Aura,500 -258,Spear Quicken,500 - -261,Summon Spirit Sphere,500 -262,Absorb Spirit Sphere,500 -264,Snap,500 -266,Occult Impact,500 -267,Throw Spirit Sphere,500 -268,Mental Strength,500 -269,Root,500 -270,Fury,500 -271,Asura Strike,500 -//272,Raging Quadruple Blow,500 -//273,Raging Thrust,500 - -275,Cast Cancel,500 -276,Magic Rod,500 -277,Spell Break,500 -279,Hindsight,500 -280,Endow Blaze,500 -281,Endow Tsunami,500 -282,Endow Tornado,500 -283,Endow Quake,500 -285,Volcano,500 -286,Deluge,500 -287,Whirlwind,500 -288,Magnetic Earth,500 -289,Dispel,500 - -// Abracadabra Derivation Skill -291,Monocell,250:500:750:1000:1250:1200:1750:2000:2250:2500 -292,Class Change,0:0:0:0:10:10:20:20:30:30 -293,Summon Monster,100:200:300:400:500:600:700:800:900:1000 -294,Grampus Morph,0:0:0:0:0:0:0:10:50:100 -295,Grim Reaper,50:100:150:200:250:300:350:400:450:500 -//296,Gold Digger,50:100:150:200:250:300:350:400:450:500 -//297,Beastly Hypnosis,50:100:150:200:250:300:350:400:450:500 -298,Questioning,1000:800:600:400:200:0:0:0:0:0 -299,Gravity,0:0:0:0:0:0:0:20:50:100 -//300,Leveling,0:0:0:0:0:0:0:0:10:50 -301,Suicide,0:0:0:0:0:0:0:10:50:100 -302,Rejuvination,0:0:0:0:0:0:20:50:100:200 -303,Coma,0:0:0:0:100:200:300:400:500:600 - -// Dancer / Bard commonness -//304,Amp,500 -//305,Encore,500 -//306,Lullaby,500 -//307,Mental Sensing,500 -//308,Down Tempo,500 -//309,Battle Theme,500 -//310,Harmonic Lick,500 -//311,Classical Pluck,500 -//312,Power Chord,500 -//313,Acoustic Rhythm,500 -//314,Ragnarok,500 - -// Bard skill -316,Melody Strike,500 -//317,Unchained Serenade,500 -318,Unbarring Octave,500 -//319,Perfect Tablature,500 -//320,Impressive Riff,500 -//321,Magic Strings,500 -//322,Song of Lutie,500 - -// Dancer skill -324,Slinging Arrow,500 -//325,Hip Shaker,500 -326,Dazzler,500 -//327,Focus Ballet,500 -//328,Slow Grace,500 -//329,Lady Luck,500 -//330,Gypsy's Kiss,500 diff --git a/db/abra_db.yml b/db/abra_db.yml new file mode 100644 index 0000000000..9a189360ce --- /dev/null +++ b/db/abra_db.yml @@ -0,0 +1,324 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +########################################################################### +# Abracadabra Database +########################################################################### +# +# Abracadabra Settings +# +########################################################################### +# - Skill Skill to be casted by Abracadabra. +# Probability: Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%). (Default: 500) +# - Level Skill level. +# Probability Probability at specific skill level (1 = 0.01%, 10000 = 100%). (Default: 0) +########################################################################### + +Header: + Type: ABRA_DB + Version: 1 + +Body: + - Skill: SM_BASH + - Skill: SM_PROVOKE + - Skill: SM_MAGNUM + - Skill: SM_ENDURE + - Skill: MG_SIGHT + - Skill: MG_NAPALMBEAT + - Skill: MG_SAFETYWALL + - Skill: MG_SOULSTRIKE + - Skill: MG_COLDBOLT + - Skill: MG_FROSTDIVER + - Skill: MG_STONECURSE + - Skill: MG_FIREBALL + - Skill: MG_FIREWALL + - Skill: MG_FIREBOLT + - Skill: MG_LIGHTNINGBOLT + - Skill: MG_THUNDERSTORM + - Skill: AL_RUWACH + - Skill: AL_PNEUMA + - Skill: AL_TELEPORT + - Skill: AL_WARP + - Skill: AL_HEAL + - Skill: AL_INCAGI + - Skill: AL_DECAGI + - Skill: AL_HOLYWATER + - Skill: AL_CRUCIS + - Skill: AL_ANGELUS + - Skill: AL_BLESSING + - Skill: AL_CURE + - Skill: MC_IDENTIFY + - Skill: MC_VENDING + - Skill: MC_MAMMONITE + - Skill: AC_CONCENTRATION + - Skill: AC_DOUBLE + - Skill: AC_SHOWER + - Skill: TF_STEAL + - Skill: TF_HIDING + - Skill: TF_POISON + - Skill: TF_DETOXIFY + - Skill: ALL_RESURRECTION + - Skill: KN_PIERCE + - Skill: KN_BRANDISHSPEAR + - Skill: KN_SPEARSTAB + - Skill: KN_SPEARBOOMERANG + - Skill: KN_TWOHANDQUICKEN + - Skill: KN_AUTOCOUNTER + - Skill: KN_BOWLINGBASH + - Skill: PR_IMPOSITIO + - Skill: PR_SUFFRAGIUM + - Skill: PR_ASPERSIO + - Skill: PR_BENEDICTIO + - Skill: PR_SANCTUARY + - Skill: PR_SLOWPOISON + - Skill: PR_STRECOVERY + - Skill: PR_KYRIE + - Skill: PR_MAGNIFICAT + - Skill: PR_GLORIA + - Skill: PR_LEXDIVINA + - Skill: PR_TURNUNDEAD + - Skill: PR_LEXAETERNA + - Skill: PR_MAGNUS + - Skill: WZ_FIREPILLAR + - Skill: WZ_SIGHTRASHER + - Skill: WZ_METEOR + - Skill: WZ_JUPITEL + - Skill: WZ_VERMILION + - Skill: WZ_WATERBALL + - Skill: WZ_ICEWALL + - Skill: WZ_FROSTNOVA + - Skill: WZ_STORMGUST + - Skill: WZ_EARTHSPIKE + - Skill: WZ_HEAVENDRIVE + - Skill: WZ_QUAGMIRE + - Skill: WZ_ESTIMATION + - Skill: BS_HAMMERFALL + - Skill: BS_ADRENALINE + - Skill: BS_WEAPONPERFECT + - Skill: BS_OVERTHRUST + - Skill: BS_MAXIMIZE + - Skill: HT_SKIDTRAP + - Skill: HT_LANDMINE + - Skill: HT_ANKLESNARE + - Skill: HT_SHOCKWAVE + - Skill: HT_SANDMAN + - Skill: HT_FLASHER + - Skill: HT_FREEZINGTRAP + - Skill: HT_BLASTMINE + - Skill: HT_CLAYMORETRAP + - Skill: HT_REMOVETRAP + - Skill: HT_TALKIEBOX + - Skill: HT_BLITZBEAT + - Skill: HT_DETECTING + - Skill: HT_SPRINGTRAP + - Skill: AS_CLOAKING + - Skill: AS_SONICBLOW + - Skill: AS_GRIMTOOTH + - Skill: AS_ENCHANTPOISON + - Skill: AS_POISONREACT + - Skill: AS_VENOMDUST + - Skill: AS_SPLASHER + - Skill: RG_STEALCOIN + - Skill: RG_BACKSTAP + - Skill: RG_RAID + - Skill: RG_STRIPWEAPON + - Skill: RG_STRIPSHIELD + - Skill: RG_STRIPARMOR + - Skill: RG_STRIPHELM + - Skill: RG_INTIMIDATE + - Skill: RG_GRAFFITI + - Skill: RG_CLEANER + - Skill: CR_AUTOGUARD + - Skill: CR_SHIELDCHARGE + - Skill: CR_SHIELDBOOMERANG + - Skill: CR_REFLECTSHIELD + - Skill: CR_HOLYCROSS + - Skill: CR_GRANDCROSS + - Skill: CR_DEVOTION + - Skill: CR_PROVIDENCE + - Skill: CR_DEFENDER + - Skill: CR_SPEARQUICKEN + - Skill: MO_CALLSPIRITS + - Skill: MO_ABSORBSPIRITS + - Skill: MO_BODYRELOCATION + - Skill: MO_INVESTIGATE + - Skill: MO_FINGEROFFENSIVE + - Skill: MO_STEELBODY + - Skill: MO_BLADESTOP + - Skill: MO_EXPLOSIONSPIRITS + - Skill: MO_EXTREMITYFIST + - Skill: SA_CASTCANCEL + - Skill: SA_MAGICROD + - Skill: SA_SPELLBREAKER + - Skill: SA_AUTOSPELL + - Skill: SA_FLAMELAUNCHER + - Skill: SA_FROSTWEAPON + - Skill: SA_LIGHTNINGLOADER + - Skill: SA_SEISMICWEAPON + - Skill: SA_VOLCANO + - Skill: SA_DELUGE + - Skill: SA_VIOLENTGALE + - Skill: SA_LANDPROTECTOR + - Skill: SA_DISPELL + - Skill: SA_MONOCELL + Probability: + - Level: 1 + Probability: 250 + - Level: 2 + Probability: 500 + - Level: 3 + Probability: 750 + - Level: 4 + Probability: 1000 + - Level: 5 + Probability: 1250 + - Level: 6 + Probability: 1200 + - Level: 7 + Probability: 1750 + - Level: 8 + Probability: 2000 + - Level: 9 + Probability: 2250 + - Level: 10 + Probability: 2500 + - Skill: SA_CLASSCHANGE + Probability: + - Level: 5 + Probability: 10 + - Level: 6 + Probability: 10 + - Level: 7 + Probability: 20 + - Level: 8 + Probability: 20 + - Level: 9 + Probability: 30 + - Level: 10 + Probability: 30 + - Skill: SA_SUMMONMONSTER + Probability: + - Level: 1 + Probability: 100 + - Level: 2 + Probability: 200 + - Level: 3 + Probability: 300 + - Level: 4 + Probability: 400 + - Level: 5 + Probability: 500 + - Level: 6 + Probability: 600 + - Level: 7 + Probability: 700 + - Level: 8 + Probability: 800 + - Level: 9 + Probability: 900 + - Level: 10 + Probability: 1000 + - Skill: SA_REVERSEORCISH + Probability: + - Level: 8 + Probability: 10 + - Level: 9 + Probability: 50 + - Level: 10 + Probability: 100 + - Skill: SA_DEATH + Probability: + - Level: 1 + Probability: 50 + - Level: 2 + Probability: 100 + - Level: 3 + Probability: 150 + - Level: 4 + Probability: 200 + - Level: 5 + Probability: 250 + - Level: 6 + Probability: 300 + - Level: 7 + Probability: 350 + - Level: 8 + Probability: 400 + - Level: 9 + Probability: 450 + - Level: 10 + Probability: 500 + - Skill: SA_QUESTION + Probability: + - Level: 1 + Probability: 1000 + - Level: 2 + Probability: 800 + - Level: 3 + Probability: 600 + - Level: 4 + Probability: 400 + - Level: 5 + Probability: 200 + - Skill: SA_GRAVITY + Probability: + - Level: 8 + Probability: 20 + - Level: 9 + Probability: 50 + - Level: 10 + Probability: 100 + - Skill: SA_INSTANTDEATH + Probability: + - Level: 8 + Probability: 10 + - Level: 9 + Probability: 50 + - Level: 10 + Probability: 100 + - Skill: SA_FULLRECOVERY + Probability: + - Level: 7 + Probability: 20 + - Level: 8 + Probability: 50 + - Level: 9 + Probability: 100 + - Level: 10 + Probability: 200 + - Skill: SA_COMA + Probability: + - Level: 5 + Probability: 100 + - Level: 6 + Probability: 200 + - Level: 7 + Probability: 300 + - Level: 8 + Probability: 400 + - Level: 9 + Probability: 500 + - Level: 10 + Probability: 600 + - Skill: BA_MUSICALSTRIKE + - Skill: BA_FROSTJOKER + - Skill: DC_THROWARROW + - Skill: DC_SCREAM + +Footer: + Imports: + - Path: db/import/abra_db.yml diff --git a/db/import-tmpl/abra_db.txt b/db/import-tmpl/abra_db.txt deleted file mode 100644 index f7a7c99a89..0000000000 --- a/db/import-tmpl/abra_db.txt +++ /dev/null @@ -1,17 +0,0 @@ -// Hocus-Pocus (Abracadabra) Castable Skills Database -// -// Structure of Database: -// SkillID,DummyName,ProbabilityPerLvl -// -// 01. SkillID Skill ID to be casted by hocus pocus. -// 02. DummyName Name of the skill (informative, not used by server). -// 03. ProbabilityPerLvl Not a rate! Chance at which the skill is selected compared -// with other entries probabilties -// -// NOTE: -// - The skill is picked at random from the entire database and then tested for rate. If it -// does not succeed at that rate, another skill is picked and tested. This continues -// until a skill succeeds. Abracadabra-specific skills have a different chance to occur -// depending on skill level used. All other skills have an equal chance and appear from -// level 1 onward. -// - To remove entry by importing, put "clear" (without quotes) in DummyName diff --git a/db/import-tmpl/abra_db.yml b/db/import-tmpl/abra_db.yml new file mode 100644 index 0000000000..dfdebec42b --- /dev/null +++ b/db/import-tmpl/abra_db.yml @@ -0,0 +1,33 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +########################################################################### +# Abracadabra Database +########################################################################### +# +# Abracadabra Settings +# +########################################################################### +# - Skill Skill to be casted by Abracadabra. +# Probability: Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%). (Default: 500) +# - Level Skill level. +# Probability Probability at specific skill level (1 = 0.01%, 10000 = 100%). (Default: 0) +########################################################################### + +Header: + Type: ABRA_DB + Version: 1 diff --git a/doc/yaml/db/abra_db.yml b/doc/yaml/db/abra_db.yml new file mode 100644 index 0000000000..c5f0c76666 --- /dev/null +++ b/doc/yaml/db/abra_db.yml @@ -0,0 +1,12 @@ +########################################################################### +# Abracadabra Database +########################################################################### +# +# Abracadabra Settings +# +########################################################################### +# - Skill Skill to be casted by Abracadabra. +# Probability: Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%). (Default: 500) +# - Level Skill level. +# Probability Probability at specific skill level (1 = 0.01%, 10000 = 100%). (Default: 0) +########################################################################### diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index babf974386..dca3993ecb 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -290,7 +290,7 @@ - + diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 6b669fbf68..b403a2914e 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -87,8 +87,7 @@ static unsigned short skill_produce_count; struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; static unsigned short skill_arrow_count; -struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; -unsigned short skill_abra_count; +AbraDatabase abra_db; struct s_skill_improvise_db { uint16 skill_id; @@ -6411,19 +6410,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case SA_ABRACADABRA: - if (!skill_abra_count) { + if (abra_db.size() == 0) { clif_skill_nodamage (src, bl, skill_id, skill_lv, 1); break; } else { - int abra_skill_id = 0, abra_skill_lv, checked = 0, checked_max = MAX_SKILL_ABRA_DB * 3; + int abra_skill_id = 0, abra_skill_lv, checked = 0, checked_max = abra_db.size() * 3; + auto abra_spell = abra_db.begin(); + do { - i = rnd() % MAX_SKILL_ABRA_DB; - abra_skill_id = skill_abra_db[i].skill_id; + std::advance(abra_spell, rnd() % abra_db.size()); + + abra_skill_id = abra_spell->second->skill_id; abra_skill_lv = min(skill_lv, skill_get_max(abra_skill_id)); - } while ( checked++ < checked_max && - (abra_skill_id == 0 || - rnd()%10000 >= skill_abra_db[i].per[max(skill_lv-1,0)]) ); + } while (checked++ < checked_max && rnd() % 10000 >= abra_spell->second->per[max(skill_lv - 1, 0)]); if (!skill_get_index(abra_skill_id)) break; @@ -21585,40 +21585,90 @@ static bool skill_parse_row_nonearnpcrangedb(char* split[], int column, int curr return true; } -/** Reads skill chance by Abracadabra/Hocus Pocus spell - * Structure: SkillID,DummyName,RatePerLvl - */ -static bool skill_parse_row_abradb(char* split[], int columns, int current) -{ - unsigned short i, skill_id = atoi(split[0]); - if (!skill_get_index(skill_id) || !skill_get_max(skill_id)) { - ShowError("skill_parse_row_abradb: Invalid skill ID %d\n", skill_id); - return false; + +const std::string AbraDatabase::getDefaultLocation() { + return std::string(db_path) + "/abra_db.yml"; +} + +/** +* Reads and parses an entry from the abra_db. +* @param node: YAML node containing the entry. +* @return count of successfully parsed rows +*/ +uint64 AbraDatabase::parseBodyNode(const YAML::Node &node) { + std::string skill_name; + + if (!this->asString(node, "Skill", skill_name)) + return 0; + + uint16 skill_id = skill_name2id(skill_name.c_str()); + + if (!skill_id) { + this->invalidWarning(node["Skill"], "Invalid Abra skill name \"%s\", skipping.\n", skill_name.c_str()); + return 0; } + if (!skill_get_inf(skill_id)) { - ShowError("skill_parse_row_abradb: Passive skills cannot be casted (%d/%s)\n", skill_id, skill_get_name(skill_id)); - return false; + this->invalidWarning(node["Skill"], "Passive skill %s cannot be casted by Abra.\n", skill_name.c_str()); + return 0; } - ARR_FIND(0, skill_abra_count, i, skill_abra_db[i].skill_id==skill_id); - if (i >= ARRAYLENGTH(skill_abra_db)) { - ShowError("skill_parse_row_abradb: Maximum db entries reached.\n"); - return false; - } - // Import just for clearing/disabling from original data - if (strcmp(split[1],"clear") == 0) { - memset(&skill_abra_db[i], 0, sizeof(skill_abra_db[i])); - //ShowInfo("skill_parse_row_abradb: Skill %d removed from list.\n", skill_id); - return true; + std::shared_ptr abra = this->find(skill_id); + bool exists = abra != nullptr; + + if (!exists) { + abra = std::make_shared(); + abra->skill_id = skill_id; } - skill_abra_db[i].skill_id = skill_id; - safestrncpy(skill_abra_db[i].name, trim(split[1]), sizeof(skill_abra_db[i].name)); //store dummyname - skill_split_atoi(split[2],skill_abra_db[i].per); - if (i == skill_abra_count) - skill_abra_count++; + if (this->nodeExists(node, "Probability")) { + const YAML::Node probNode = node["Probability"]; + uint16 probability; - return true; + if (probNode.IsScalar()) { + if (!this->asUInt16Rate(probNode, "Probability", probability)) + return 0; + + if (!probability) { + this->invalidWarning(probNode["Probability"], "Probability has to be within the range of 1~10000, skipping.\n"); + return 0; + } + + abra->per.fill(probability); + } else { + abra->per.fill(0); + + for (const YAML::Node &it : probNode) { + uint16 skill_lv; + + if (!this->asUInt16(it, "Level", skill_lv)) + continue; + + if (skill_lv > MAX_SKILL_LEVEL) { + this->invalidWarning(it["Level"], "Probability Level exceeds the maximum skill level of %d, skipping.\n", MAX_SKILL_LEVEL); + return 0; + } + + if (!this->asUInt16Rate(it, "Probability", probability)) + continue; + + if (!probability) { + this->invalidWarning(it["Probability"], "Probability has to be within the range of 1~10000, skipping.\n"); + return 0; + } + + abra->per[skill_lv - 1] = probability; + } + } + } else { + if (!exists) + abra->per.fill(500); + } + + if (!exists) + this->put(skill_id, abra); + + return 1; } /** Reads change material db @@ -21762,7 +21812,6 @@ static void skill_db_destroy(void) { * skill_unit_db.txt * produce_db.txt * create_arrow_db.txt - * abra_db.txt *------------------------------*/ static void skill_readdb(void) { @@ -21782,10 +21831,9 @@ static void skill_readdb(void) memset(skill_produce_db,0,sizeof(skill_produce_db)); memset(skill_arrow_db,0,sizeof(skill_arrow_db)); - memset(skill_abra_db,0,sizeof(skill_abra_db)); memset(skill_spellbook_db,0,sizeof(skill_spellbook_db)); memset(skill_changematerial_db,0,sizeof(skill_changematerial_db)); - skill_produce_count = skill_arrow_count = skill_abra_count = skill_improvise_count = + skill_produce_count = skill_arrow_count = skill_improvise_count = skill_changematerial_count = skill_spellbook_count = 0; for(i=0; i 0); sv_readdb(dbsubpath1, "create_arrow_db.txt" , ',', 1+2, 1+2*MAX_ARROW_RESULT, MAX_SKILL_ARROW_DB, skill_parse_row_createarrowdb, i > 0); - sv_readdb(dbsubpath1, "abra_db.txt" , ',', 3, 3, MAX_SKILL_ABRA_DB, skill_parse_row_abradb, i > 0); sv_readdb(dbsubpath1, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb, i > 0); sv_readdb(dbsubpath1, "skill_copyable_db.txt" , ',', 2, 4, -1, skill_parse_row_copyabledb, i > 0); sv_readdb(dbsubpath1, "skill_improvise_db.txt" , ',', 2, 2, MAX_SKILL_IMPROVISE_DB, skill_parse_row_improvisedb, i > 0); @@ -21823,6 +21870,7 @@ static void skill_readdb(void) aFree(dbsubpath2); } + abra_db.load(); magic_mushroom_db.load(); skill_init_unit_layout(); diff --git a/src/map/skill.hpp b/src/map/skill.hpp index 6bb670a28c..1ff32424bd 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -4,6 +4,8 @@ #ifndef SKILL_HPP #define SKILL_HPP +#include + #include "../common/cbasetypes.hpp" #include "../common/database.hpp" #include "../common/db.hpp" @@ -26,7 +28,6 @@ struct status_change_entry; #define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements #define MAX_SKILL_ARROW_DB 150 /// Max Arrow Creation DB #define MAX_ARROW_RESULT 5 /// Max Arrow results/created -#define MAX_SKILL_ABRA_DB 160 /// Max Skill list of Abracadabra DB #define MAX_SKILL_IMPROVISE_DB 30 /// Max Skill for Improvise #define MAX_SKILL_LEVEL 13 /// Max Skill Level (for skill_db storage) #define MAX_MOBSKILL_LEVEL 100 /// Max monster skill level (on skill usage) @@ -371,11 +372,18 @@ extern struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; /// Abracadabra database struct s_skill_abra_db { uint16 skill_id; /// Skill ID - char name[SKILL_NAME_LENGTH]; /// Shouted skill name - int per[MAX_SKILL_LEVEL]; /// Probability summoned + std::array per; /// Probability summoned +}; + +class AbraDatabase : public TypesafeYamlDatabase { +public: + AbraDatabase() : TypesafeYamlDatabase("ABRA_DB", 1) { + + } + + const std::string getDefaultLocation(); + uint64 parseBodyNode(const YAML::Node& node); }; -extern struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; -extern unsigned short skill_abra_count; void do_init_skill(void); void do_final_skill(void); diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp index 4ccc54942c..f65564beb8 100644 --- a/src/tool/csv2yaml.cpp +++ b/src/tool/csv2yaml.cpp @@ -70,6 +70,7 @@ int getch( void ){ static bool guild_read_guildskill_tree_db( char* split[], int columns, int current ); static size_t pet_read_db( const char* file ); static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current); +static bool skill_parse_row_abradb(char* split[], int columns, int current); // Constants for conversion std::unordered_map aegis_itemnames; @@ -241,6 +242,12 @@ int do_init( int argc, char** argv ){ return 0; } + if (!process("ABRA_DB", 1, root_paths, "abra_db", [](const std::string& path, const std::string& name_ext) -> bool { + return sv_readdb(path.c_str(), name_ext.c_str(), ',', 3, 3, -1, &skill_parse_row_abradb, false); + })) { + return 0; + } + // TODO: add implementations ;-) return 0; @@ -426,6 +433,34 @@ static bool parse_skill_constants( char* split[], int columns, int current ){ return true; } +/** + * Split the string with ':' as separator and put each value for a skilllv + * if no more value found put the last value to fill the array + * @param str: String to split + * @param val: Array of MAX_SKILL_LEVEL to put value into + * @return 0:error, x:number of value assign (should be MAX_SKILL_LEVEL) + */ +int skill_split_atoi(char *str, int *val) { + int i; + + for (i = 0; i < MAX_SKILL_LEVEL; i++) { + if (!str) + break; + val[i] = atoi(str); + str = strchr(str, ':'); + if (str) + *str++ = 0; + } + + if (i == 0) // No data found. + return 0; + + if (i == 1) // Single value, have the whole range have the same value. + return 1; + + return i; +} + // Implementation of the conversion functions // Copied and adjusted from guild.cpp @@ -654,6 +689,7 @@ static size_t pet_read_db( const char* file ){ return entries; } +// Copied and adjusted from skill.cpp static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) { uint16 skill_id = atoi(split[0]); @@ -670,3 +706,43 @@ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int curre return true; } + +// Copied and adjusted from skill.cpp +static bool skill_parse_row_abradb(char* split[], int columns, int current) +{ + uint16 skill_id = atoi(split[0]); + std::string *skill_name = util::umap_find(aegis_skillnames, skill_id); + + if (skill_name == nullptr) { + ShowError("Skill name for Abra skill ID &hu is not known.\n", skill_id); + return false; + } + + body << YAML::BeginMap; + body << YAML::Key << "Skill" << YAML::Value << *skill_name; + + int arr[MAX_SKILL_LEVEL]; + int arr_size = skill_split_atoi(split[2], arr); + + if (arr_size == 1) { + if (arr[0] != 500) + body << YAML::Key << "Probability" << YAML::Value << arr[0]; + } else { + body << YAML::Key << "Probability"; + body << YAML::BeginSeq; + + for (int i = 0; i < arr_size; i++) { + if (arr[i] > 0) { + body << YAML::BeginMap; + body << YAML::Key << "Level" << YAML::Value << i + 1; + body << YAML::Key << "Probability" << YAML::Value << arr[i]; + body << YAML::EndMap; + } + } + + body << YAML::EndSeq; + } + body << YAML::EndMap; + + return true; +}