Bläddra i källkod

Converted Abra Database to YAML (#4480)

* Removed useless skill name usage in the database.
Aleos 5 år sedan
förälder
incheckning
2fc7472001
9 ändrade filer med 546 tillägg och 289 borttagningar
  1. 0 227
      db/abra_db.txt
  2. 324 0
      db/abra_db.yml
  3. 0 17
      db/import-tmpl/abra_db.txt
  4. 33 0
      db/import-tmpl/abra_db.yml
  5. 12 0
      doc/yaml/db/abra_db.yml
  6. 1 1
      src/map/map-server.vcxproj
  7. 87 39
      src/map/skill.cpp
  8. 13 5
      src/map/skill.hpp
  9. 76 0
      src/tool/csv2yaml.cpp

+ 0 - 227
db/abra_db.txt

@@ -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

+ 324 - 0
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 <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# 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

+ 0 - 17
db/import-tmpl/abra_db.txt

@@ -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

+ 33 - 0
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 <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# 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

+ 12 - 0
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)
+###########################################################################

+ 1 - 1
src/map/map-server.vcxproj

@@ -290,7 +290,7 @@
     <Copy SourceFiles="$(SolutionDir)conf\msg_conf\import-tmpl\map_msg_rus_conf.txt" DestinationFolder="$(SolutionDir)conf\msg_conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\msg_conf\import\map_msg_rus_conf.txt')" />
     <Copy SourceFiles="$(SolutionDir)conf\msg_conf\import-tmpl\map_msg_spn_conf.txt" DestinationFolder="$(SolutionDir)conf\msg_conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\msg_conf\import\map_msg_spn_conf.txt')" />
     <Copy SourceFiles="$(SolutionDir)conf\msg_conf\import-tmpl\map_msg_tha_conf.txt" DestinationFolder="$(SolutionDir)conf\msg_conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\msg_conf\import\map_msg_tha_conf.txt')" />
-    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\abra_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\abra_db.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\abra_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\abra_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\achievement_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\achievement_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\achievement_level_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\achievement_level_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\attendance.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\attendance.yml')" />

+ 87 - 39
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;
+	std::shared_ptr<s_skill_abra_db> abra = this->find(skill_id);
+	bool exists = abra != nullptr;
+
+	if (!exists) {
+		abra = std::make_shared<s_skill_abra_db>();
+		abra->skill_id = skill_id;
 	}
-	// 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;
+
+	if (this->nodeExists(node, "Probability")) {
+		const YAML::Node probNode = node["Probability"];
+		uint16 probability;
+
+		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);
 	}
 
-	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 (!exists)
+		this->put(skill_id, abra);
 
-	return true;
+	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<ARRAYLENGTH(dbsubpath); i++){
@@ -21811,7 +21859,6 @@ static void skill_readdb(void)
 
 		sv_readdb(dbsubpath2, "produce_db.txt"        , ',',   5,  5+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb, 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();

+ 13 - 5
src/map/skill.hpp

@@ -4,6 +4,8 @@
 #ifndef SKILL_HPP
 #define SKILL_HPP
 
+#include <array>
+
 #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<uint16, MAX_SKILL_LEVEL> per; /// Probability summoned
+};
+
+class AbraDatabase : public TypesafeYamlDatabase<uint16, s_skill_abra_db> {
+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);

+ 76 - 0
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<uint16, std::string> 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;
+}