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;
+}