瀏覽代碼

Converted castle_db.txt to YAML (#6077)

* Converts the Guild Castles Database into YAML.
* Includes CSV2YAML converter.

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Atemo 3 年之前
父節點
當前提交
01a3caf9f9

+ 0 - 62
db/castle_db.txt

@@ -1,62 +0,0 @@
-// Guild Castles Database
-//
-// Structure of Database:
-// CastleID,MapName,CastleName,OnGuildBreakEventName,Flag
-//
-// 01. CastleID                 Unique ID of the castle. Must remain unique across all map-servers.
-// 02. MapName                  Map name to be considered as the castle map.
-// 03. CastleName               Name of the castle (used by scripts and guardian name tags).
-// 04. OnGuildBreakEventName    NPC unique name to invoke ::OnGuildBreak on, when a occupied
-//                              castle is abandoned during guild break.
-
-// WOE FE castle
-0,aldeg_cas01,Neuschwanstein,Agit#aldeg_cas01	// kRO : Noisyubantian
-1,aldeg_cas02,Hohenschwangau,Agit#aldeg_cas02	// kRO : Hohensyubangawoo
-2,aldeg_cas03,Nuernberg,Agit#aldeg_cas03		// kRO : Nyirenverk
-3,aldeg_cas04,Wuerzburg,Agit#aldeg_cas04		// kRO : Byirtsburi
-4,aldeg_cas05,Rothenburg,Agit#aldeg_cas05		// kRO : Rotenburk
-5,gefg_cas01,Repherion,Agit#gefg_cas01			// kRO : Reprion
-6,gefg_cas02,Eeyolbriggar,Agit#gefg_cas02		// kRO : Yolbriger
-7,gefg_cas03,Yesnelph,Agit#gefg_cas03			// kRO : Isinlife
-8,gefg_cas04,Bergel,Agit#gefg_cas04				// kRO : Berigel
-9,gefg_cas05,Mersetzdeitz,Agit#gefg_cas05		// kRO : Melsedetsu
-10,payg_cas01,Bright Arbor,Agit#payg_cas01		// kRO : Mingting
-11,payg_cas02,Scarlet Palace,Agit#payg_cas02	// kRO : Tiantan
-12,payg_cas03,Holy Shadow,Agit#payg_cas03		// kRO : Fuying
-13,payg_cas04,Sacred Altar,Agit#payg_cas04		// kRO : Honglou
-14,payg_cas05,Bamboo Grove Hill,Agit#payg_cas05	// kRO : Zhulinxian
-15,prtg_cas01,Kriemhild,Agit#prtg_cas01			// kRO : Creamhilt
-16,prtg_cas02,Swanhild,Agit#prtg_cas02			// kRO : Sbanhealt
-17,prtg_cas03,Fadhgridh,Agit#prtg_cas03			// kRO : Lazrigees
-18,prtg_cas04,Skoegul,Agit#prtg_cas04			// kRO : Squagul
-19,prtg_cas05,Gondul,Agit#prtg_cas05			// kRO : Guindull
-
-// WOE NGuild castle
-20,nguild_alde,Earth,Agit_N01
-21,nguild_gef,Air,Agit_N02
-22,nguild_pay,Water,Agit_N03
-23,nguild_prt,Fire,Agit_N04
-
-// WOE SE castle
-24,schg_cas01,Himinn,Manager#schg_cas01			// kRO : Himinn
-25,schg_cas02,Andlangr,Manager#schg_cas02		// kRO : Andlangr
-26,schg_cas03,Viblainn,Manager#schg_cas03		// kRO : Viblainn
-27,schg_cas04,Hljod,Manager#schg_cas04			// kRO : Hljod
-28,schg_cas05,Skidbladnir,Manager#schg_cas05	// kRO : Skidbladnir
-29,arug_cas01,Mardol,Manager#arug_cas01			// kRO : Mardol
-30,arug_cas02,Cyr,Manager#arug_cas02			// kRO : Cyr
-31,arug_cas03,Horn,Manager#arug_cas03			// kRO : Horn
-32,arug_cas04,Gefn,Manager#arug_cas04			// kRO : Gefn
-33,arug_cas05,Bandis,Manager#arug_cas05			// kRO : Bandis
-
-// WOE TE castle
-34,te_aldecas1,Kafragarten 1,Manager_TE#Glaris
-35,te_aldecas2,Kafragarten 2,Manager_TE#Defolty
-36,te_aldecas3,Kafragarten 3,Manager_TE#Sorin
-37,te_aldecas4,Kafragarten 4,Manager_TE#Bennit
-38,te_aldecas5,Kafragarten 5,Manager_TE#W
-39,te_prtcas01,Gloria 1,Manager_TE#Gaebolg
-40,te_prtcas02,Gloria 2,Manager_TE#Richard
-41,te_prtcas03,Gloria 3,Manager_TE#Wigner
-42,te_prtcas04,Gloria 4,Manager_TE#Heine
-43,te_prtcas05,Gloria 5,Manager_TE#Nerious

+ 41 - 0
db/castle_db.yml

@@ -0,0 +1,41 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2021 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/>.
+#
+###########################################################################
+# Guild Castles Database
+###########################################################################
+#
+# Guild Castles Settings
+#
+###########################################################################
+# - Id                Unique ID of the castle.
+#   Map               Map name to be considered as the castle map.
+#   Name              Name of the castle (used by scripts and guardian name tags).
+#   Npc               NPC unique name to invoke ::OnGuildBreak on, when a occupied castle is abandoned during guild break.
+###########################################################################
+
+Header:
+  Type: CASTLE_DB
+  Version: 1
+
+Footer:
+  Imports:
+  - Path: db/pre-re/castle_db.yml
+    Mode: Prerenewal
+  - Path: db/re/castle_db.yml
+    Mode: Renewal
+  - Path: db/import/castle_db.yml

+ 0 - 11
db/import-tmpl/castle_db.txt

@@ -1,11 +0,0 @@
-// Guild Castles Database
-//
-// Structure of Database:
-// CastleID,MapName,CastleName,OnGuildBreakEventName,Flag
-//
-// 01. CastleID                 Unique ID of the castle. Must remain unique across all map-servers.
-// 02. MapName                  Map name to be considered as the castle map.
-// 03. CastleName               Name of the castle (used by scripts and guardian name tags).
-// 04. OnGuildBreakEventName    NPC unique name to invoke ::OnGuildBreak on, when a occupied
-//                              castle is abandoned during guild break.
-// 05. Flag                     Switch flag (reserved as of athena-dev mod0796~0801, not used by server).

+ 33 - 0
db/import-tmpl/castle_db.yml

@@ -0,0 +1,33 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2021 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/>.
+#
+###########################################################################
+# Guild Castles Database
+###########################################################################
+#
+# Guild Castles Settings
+#
+###########################################################################
+# - Id                Unique ID of the castle.
+#   Map               Map name to be considered as the castle map.
+#   Name              Name of the castle (used by scripts and guardian name tags).
+#   Npc               NPC unique name to invoke ::OnGuildBreak on, when a occupied castle is abandoned during guild break.
+###########################################################################
+
+Header:
+  Type: CASTLE_DB
+  Version: 1

+ 238 - 0
db/pre-re/castle_db.yml

@@ -0,0 +1,238 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2021 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/>.
+#
+###########################################################################
+# Guild Castles Database
+###########################################################################
+#
+# Guild Castles Settings
+#
+###########################################################################
+# - Id                Unique ID of the castle.
+#   Map               Map name to be considered as the castle map.
+#   Name              Name of the castle (used by scripts and guardian name tags).
+#   Npc               NPC unique name to invoke ::OnGuildBreak on, when a occupied castle is abandoned during guild break.
+###########################################################################
+
+Header:
+  Type: CASTLE_DB
+  Version: 1
+
+Body:
+# WOE FE castle
+  - Id: 0
+    Map: aldeg_cas01
+    Name: Neuschwanstein
+    #Name: Noisyubantian
+    Npc: Agit#aldeg_cas01
+  - Id: 1
+    Map: aldeg_cas02
+    Name: Hohenschwangau
+    #Name: Hohensyubangawoo
+    Npc: Agit#aldeg_cas02
+  - Id: 2
+    Map: aldeg_cas03
+    Name: Nuernberg
+    #Name: Nyirenverk
+    Npc: Agit#aldeg_cas03
+  - Id: 3
+    Map: aldeg_cas04
+    Name: Wuerzburg
+    #Name: Byirtsburi
+    Npc: Agit#aldeg_cas04
+  - Id: 4
+    Map: aldeg_cas05
+    Name: Rothenburg
+    #Name: Rotenburk
+    Npc: Agit#aldeg_cas05
+  - Id: 5
+    Map: gefg_cas01
+    Name: Repherion
+    #Name: Reprion
+    Npc: Agit#gefg_cas01
+  - Id: 6
+    Map: gefg_cas02
+    Name: Eeyolbriggar
+    #Name: Yolbriger
+    Npc: Agit#gefg_cas02
+  - Id: 7
+    Map: gefg_cas03
+    Name: Yesnelph
+    #Name: Isinlife
+    Npc: Agit#gefg_cas03
+  - Id: 8
+    Map: gefg_cas04
+    Name: Bergel
+    #Name: Berigel
+    Npc: Agit#gefg_cas04
+  - Id: 9
+    Map: gefg_cas05
+    Name: Mersetzdeitz
+    #Name: Melsedetsu
+    Npc: Agit#gefg_cas05
+  - Id: 10
+    Map: payg_cas01
+    Name: Bright Arbor
+    #Name: Mingting
+    Npc: Agit#payg_cas01
+  - Id: 11
+    Map: payg_cas02
+    Name: Scarlet Palace
+    #Name: Tiantan
+    Npc: Agit#payg_cas02
+  - Id: 12
+    Map: payg_cas03
+    Name: Holy Shadow
+    #Name: Fuying
+    Npc: Agit#payg_cas03
+  - Id: 13
+    Map: payg_cas04
+    Name: Sacred Altar
+    #Name: Honglou
+    Npc: Agit#payg_cas04
+  - Id: 14
+    Map: payg_cas05
+    Name: Bamboo Grove Hill
+    #Name: Zhulinxian
+    Npc: Agit#payg_cas05
+  - Id: 15
+    Map: prtg_cas01
+    Name: Kriemhild
+    #Name: Creamhilt
+    Npc: Agit#prtg_cas01
+  - Id: 16
+    Map: prtg_cas02
+    Name: Swanhild
+    #Name: Sbanhealt
+    Npc: Agit#prtg_cas02
+  - Id: 17
+    Map: prtg_cas03
+    Name: Fadhgridh
+    #Name: Lazrigees
+    Npc: Agit#prtg_cas03
+  - Id: 18
+    Map: prtg_cas04
+    Name: Skoegul
+    #Name: Squagul
+    Npc: Agit#prtg_cas04
+  - Id: 19
+    Map: prtg_cas05
+    Name: Gondul
+    #Name: Guindull
+    Npc: Agit#prtg_cas05
+
+# WOE NGuild castle
+  - Id: 20
+    Map: nguild_alde
+    Name: Earth
+    Npc: Agit_N01
+  - Id: 21
+    Map: nguild_gef
+    Name: Air
+    Npc: Agit_N02
+  - Id: 22
+    Map: nguild_pay
+    Name: Water
+    Npc: Agit_N03
+  - Id: 23
+    Map: nguild_prt
+    Name: Fire
+    Npc: Agit_N04
+
+# WOE SE castle
+  - Id: 24
+    Map: schg_cas01
+    Name: Himinn
+    Npc: Manager#schg_cas01
+  - Id: 25
+    Map: schg_cas02
+    Name: Andlangr
+    Npc: Manager#schg_cas02
+  - Id: 26
+    Map: schg_cas03
+    Name: Viblainn
+    Npc: Manager#schg_cas03
+  - Id: 27
+    Map: schg_cas04
+    Name: Hljod
+    Npc: Manager#schg_cas04
+  - Id: 28
+    Map: schg_cas05
+    Name: Skidbladnir
+    Npc: Manager#schg_cas05
+  - Id: 29
+    Map: arug_cas01
+    Name: Mardol
+    Npc: Manager#arug_cas01
+  - Id: 30
+    Map: arug_cas02
+    Name: Cyr
+    Npc: Manager#arug_cas02
+  - Id: 31
+    Map: arug_cas03
+    Name: Horn
+    Npc: Manager#arug_cas03
+  - Id: 32
+    Map: arug_cas04
+    Name: Gefn
+    Npc: Manager#arug_cas04
+  - Id: 33
+    Map: arug_cas05
+    Name: Bandis
+    Npc: Manager#arug_cas05
+
+# WOE TE castle
+  - Id: 34
+    Map: te_aldecas1
+    Name: Kafragarten 1
+    Npc: Manager_TE#Glaris
+  - Id: 35
+    Map: te_aldecas2
+    Name: Kafragarten 2
+    Npc: Manager_TE#Defolty
+  - Id: 36
+    Map: te_aldecas3
+    Name: Kafragarten 3
+    Npc: Manager_TE#Sorin
+  - Id: 37
+    Map: te_aldecas4
+    Name: Kafragarten 4
+    Npc: Manager_TE#Bennit
+  - Id: 38
+    Map: te_aldecas5
+    Name: Kafragarten 5
+    Npc: Manager_TE#W
+  - Id: 39
+    Map: te_prtcas01
+    Name: Gloria 1
+    Npc: Manager_TE#Gaebolg
+  - Id: 40
+    Map: te_prtcas02
+    Name: Gloria 2
+    Npc: Manager_TE#Richard
+  - Id: 41
+    Map: te_prtcas03
+    Name: Gloria 3
+    Npc: Manager_TE#Wigner
+  - Id: 42
+    Map: te_prtcas04
+    Name: Gloria 4
+    Npc: Manager_TE#Heine
+  - Id: 43
+    Map: te_prtcas05
+    Name: Gloria 5
+    Npc: Manager_TE#Nerious

+ 238 - 0
db/re/castle_db.yml

@@ -0,0 +1,238 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2021 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/>.
+#
+###########################################################################
+# Guild Castles Database
+###########################################################################
+#
+# Guild Castles Settings
+#
+###########################################################################
+# - Id                Unique ID of the castle.
+#   Map               Map name to be considered as the castle map.
+#   Name              Name of the castle (used by scripts and guardian name tags).
+#   Npc               NPC unique name to invoke ::OnGuildBreak on, when a occupied castle is abandoned during guild break.
+###########################################################################
+
+Header:
+  Type: CASTLE_DB
+  Version: 1
+
+Body:
+# WOE FE castle
+  - Id: 0
+    Map: aldeg_cas01
+    Name: Neuschwanstein
+    #Name: Noisyubantian
+    Npc: Agit#aldeg_cas01
+  - Id: 1
+    Map: aldeg_cas02
+    Name: Hohenschwangau
+    #Name: Hohensyubangawoo
+    Npc: Agit#aldeg_cas02
+  - Id: 2
+    Map: aldeg_cas03
+    Name: Nuernberg
+    #Name: Nyirenverk
+    Npc: Agit#aldeg_cas03
+  - Id: 3
+    Map: aldeg_cas04
+    Name: Wuerzburg
+    #Name: Byirtsburi
+    Npc: Agit#aldeg_cas04
+  - Id: 4
+    Map: aldeg_cas05
+    Name: Rothenburg
+    #Name: Rotenburk
+    Npc: Agit#aldeg_cas05
+  - Id: 5
+    Map: gefg_cas01
+    Name: Repherion
+    #Name: Reprion
+    Npc: Agit#gefg_cas01
+  - Id: 6
+    Map: gefg_cas02
+    Name: Eeyolbriggar
+    #Name: Yolbriger
+    Npc: Agit#gefg_cas02
+  - Id: 7
+    Map: gefg_cas03
+    Name: Yesnelph
+    #Name: Isinlife
+    Npc: Agit#gefg_cas03
+  - Id: 8
+    Map: gefg_cas04
+    Name: Bergel
+    #Name: Berigel
+    Npc: Agit#gefg_cas04
+  - Id: 9
+    Map: gefg_cas05
+    Name: Mersetzdeitz
+    #Name: Melsedetsu
+    Npc: Agit#gefg_cas05
+  - Id: 10
+    Map: payg_cas01
+    Name: Bright Arbor
+    #Name: Mingting
+    Npc: Agit#payg_cas01
+  - Id: 11
+    Map: payg_cas02
+    Name: Scarlet Palace
+    #Name: Tiantan
+    Npc: Agit#payg_cas02
+  - Id: 12
+    Map: payg_cas03
+    Name: Holy Shadow
+    #Name: Fuying
+    Npc: Agit#payg_cas03
+  - Id: 13
+    Map: payg_cas04
+    Name: Sacred Altar
+    #Name: Honglou
+    Npc: Agit#payg_cas04
+  - Id: 14
+    Map: payg_cas05
+    Name: Bamboo Grove Hill
+    #Name: Zhulinxian
+    Npc: Agit#payg_cas05
+  - Id: 15
+    Map: prtg_cas01
+    Name: Kriemhild
+    #Name: Creamhilt
+    Npc: Agit#prtg_cas01
+  - Id: 16
+    Map: prtg_cas02
+    Name: Swanhild
+    #Name: Sbanhealt
+    Npc: Agit#prtg_cas02
+  - Id: 17
+    Map: prtg_cas03
+    Name: Fadhgridh
+    #Name: Lazrigees
+    Npc: Agit#prtg_cas03
+  - Id: 18
+    Map: prtg_cas04
+    Name: Skoegul
+    #Name: Squagul
+    Npc: Agit#prtg_cas04
+  - Id: 19
+    Map: prtg_cas05
+    Name: Gondul
+    #Name: Guindull
+    Npc: Agit#prtg_cas05
+
+# WOE NGuild castle
+  - Id: 20
+    Map: nguild_alde
+    Name: Earth
+    Npc: Agit_N01
+  - Id: 21
+    Map: nguild_gef
+    Name: Air
+    Npc: Agit_N02
+  - Id: 22
+    Map: nguild_pay
+    Name: Water
+    Npc: Agit_N03
+  - Id: 23
+    Map: nguild_prt
+    Name: Fire
+    Npc: Agit_N04
+
+# WOE SE castle
+  - Id: 24
+    Map: schg_cas01
+    Name: Himinn
+    Npc: Manager#schg_cas01
+  - Id: 25
+    Map: schg_cas02
+    Name: Andlangr
+    Npc: Manager#schg_cas02
+  - Id: 26
+    Map: schg_cas03
+    Name: Viblainn
+    Npc: Manager#schg_cas03
+  - Id: 27
+    Map: schg_cas04
+    Name: Hljod
+    Npc: Manager#schg_cas04
+  - Id: 28
+    Map: schg_cas05
+    Name: Skidbladnir
+    Npc: Manager#schg_cas05
+  - Id: 29
+    Map: arug_cas01
+    Name: Mardol
+    Npc: Manager#arug_cas01
+  - Id: 30
+    Map: arug_cas02
+    Name: Cyr
+    Npc: Manager#arug_cas02
+  - Id: 31
+    Map: arug_cas03
+    Name: Horn
+    Npc: Manager#arug_cas03
+  - Id: 32
+    Map: arug_cas04
+    Name: Gefn
+    Npc: Manager#arug_cas04
+  - Id: 33
+    Map: arug_cas05
+    Name: Bandis
+    Npc: Manager#arug_cas05
+
+# WOE TE castle
+  - Id: 34
+    Map: te_aldecas1
+    Name: Kafragarten 1
+    Npc: Manager_TE#Glaris
+  - Id: 35
+    Map: te_aldecas2
+    Name: Kafragarten 2
+    Npc: Manager_TE#Defolty
+  - Id: 36
+    Map: te_aldecas3
+    Name: Kafragarten 3
+    Npc: Manager_TE#Sorin
+  - Id: 37
+    Map: te_aldecas4
+    Name: Kafragarten 4
+    Npc: Manager_TE#Bennit
+  - Id: 38
+    Map: te_aldecas5
+    Name: Kafragarten 5
+    Npc: Manager_TE#W
+  - Id: 39
+    Map: te_prtcas01
+    Name: Gloria 1
+    Npc: Manager_TE#Gaebolg
+  - Id: 40
+    Map: te_prtcas02
+    Name: Gloria 2
+    Npc: Manager_TE#Richard
+  - Id: 41
+    Map: te_prtcas03
+    Name: Gloria 3
+    Npc: Manager_TE#Wigner
+  - Id: 42
+    Map: te_prtcas04
+    Name: Gloria 4
+    Npc: Manager_TE#Heine
+  - Id: 43
+    Map: te_prtcas05
+    Name: Gloria 5
+    Npc: Manager_TE#Nerious

+ 12 - 0
doc/yaml/db/castle_db.yml

@@ -0,0 +1,12 @@
+###########################################################################
+# Guild Castles Database
+###########################################################################
+#
+# Guild Castles Settings
+#
+###########################################################################
+# - Id                Unique ID of the castle.
+#   Map               Map name to be considered as the castle map.
+#   Name              Name of the castle (used by scripts and guardian name tags).
+#   Npc               NPC unique name to invoke ::OnGuildBreak on, when a occupied castle is abandoned during guild break.
+###########################################################################

+ 1 - 1
src/common/mmo.hpp

@@ -723,7 +723,7 @@ struct guild_castle {
 	int castle_id;
 	int mapindex;
 	char castle_name[NAME_LENGTH];
-	char castle_event[EVENT_NAME_LENGTH];
+	char castle_event[NPC_NAME_LENGTH];
 	int guild_id;
 	int economy;
 	int defense;

+ 109 - 119
src/map/guild.cpp

@@ -34,7 +34,8 @@
 using namespace rathena;
 
 static DBMap* guild_db; // int guild_id -> struct guild*
-static DBMap* castle_db; // int castle_id -> struct guild_castle*
+CastleDatabase castle_db;
+
 static DBMap* guild_expcache_db; // uint32 char_id -> struct guild_expcache*
 static DBMap* guild_infoevent_db; // int guild_id -> struct eventlist*
 
@@ -269,25 +270,70 @@ bool guild_check_skill_require( struct guild *g, uint16 id ){
 	return true;
 }
 
-static bool guild_read_castledb(char* str[], int columns, int current) {// <castle id>,<map name>,<castle name>,<castle event>[,<reserved/unused switch flag>]
-	struct guild_castle *gc;
-	int mapindex = mapindex_name2id(str[1]);
-	const int castle_id = atoi(str[0]);
-	
-	if (map_mapindex2mapid(mapindex) < 0) // Map not found or on another map-server
-		return false;
+const std::string CastleDatabase::getDefaultLocation() {
+	return std::string(db_path) + "/castle_db.yml";
+}
+
+uint64 CastleDatabase::parseBodyNode(const YAML::Node &node) {
+	int32 castle_id;
+
+	if (!this->asInt32(node, "Id", castle_id))
+		return 0;
+
+	std::shared_ptr<guild_castle> gc = this->find(castle_id);
+	bool exists = gc != nullptr;
+
+	if (!exists) {
+		if (!this->nodesExist(node, { "Map", "Name", "Npc" }))
+			return 0;
 
-	if ((gc = static_cast<guild_castle*>(idb_get(castle_db, castle_id))) == nullptr) {
-		CREATE(gc, struct guild_castle, 1);
+		gc = std::make_shared<guild_castle>();
+		gc->castle_id = castle_id;
 	}
-	
-	gc->castle_id = castle_id;
-	gc->mapindex = mapindex;
-	safestrncpy(gc->castle_name, trim(str[2]), sizeof(gc->castle_name));
-	safestrncpy(gc->castle_event, trim(str[3]), sizeof(gc->castle_event));
 
-	idb_put(castle_db,gc->castle_id,gc);
-	return true;
+	if (this->nodeExists(node, "Map")) {
+		std::string map_name;
+
+		if (!this->asString(node, "Map", map_name))
+			return 0;
+
+		uint16 mapindex = mapindex_name2idx(map_name.c_str(), nullptr);
+
+		if (map_mapindex2mapid(mapindex) < 0) {
+			this->invalidWarning(node["Map"], "Map %s doesn't exist, skipping.\n", map_name.c_str());
+			return 0;
+		}
+
+		gc->mapindex = mapindex;
+	}
+
+	if (this->nodeExists(node, "Name")) {
+		std::string castle_name;
+
+		if (!this->asString(node, "Name", castle_name))
+			return 0;
+
+		safestrncpy(gc->castle_name, castle_name.c_str(), sizeof(gc->castle_name));
+	}
+
+	if (this->nodeExists(node, "Npc")) {
+		std::string npc_name;
+
+		if (!this->asString(node, "Npc", npc_name))
+			return 0;
+
+		if (npc_name.size() > NPC_NAME_LENGTH) {
+			this->invalidWarning(node["NPC"], "Npc name %s too long, skipping.\n", npc_name.c_str());
+			return 0;
+		}
+
+		safestrncpy(gc->castle_event, npc_name.c_str(), sizeof(gc->castle_event));
+	}
+
+	if (!exists)
+		this->put(castle_id, gc);
+
+	return 1;
 }
 
 /// lookup: guild id -> guild*
@@ -309,28 +355,18 @@ struct guild* guild_searchname(char* str) {
 	return g;
 }
 
-/// lookup: castle id -> castle*
-struct guild_castle* guild_castle_search(int gcid) {
-	return (struct guild_castle*)idb_get(castle_db,gcid);
-}
-
 /// lookup: map index -> castle*
-struct guild_castle* guild_mapindex2gc(short mapindex) {
-	struct guild_castle* gc;
-	DBIterator *iter = db_iterator(castle_db);
-
-	for( gc = (struct guild_castle*)dbi_first(iter); dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter) ) {
-		if( gc->mapindex == mapindex )
-			break;
+std::shared_ptr<guild_castle> CastleDatabase::mapindex2gc(int16 mapindex) {
+	for (const auto &it : castle_db) {
+		if (it.second->mapindex == mapindex)
+			return it.second;
 	}
-	dbi_destroy(iter);
-
-	return gc;
+	return nullptr;
 }
 
 /// lookup: map name -> castle*
-struct guild_castle* guild_mapname2gc(const char* mapname) {
-	return guild_mapindex2gc(mapindex_name2id(mapname));
+std::shared_ptr<guild_castle> CastleDatabase::mapname2gc(const char* mapname) {
+	return castle_db.mapindex2gc(mapindex_name2id(mapname));
 }
 
 struct map_session_data* guild_getavailablesd(struct guild* g) {
@@ -1331,32 +1367,28 @@ int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data) {
 		}
 	}
 	{// update guardians (mobs)
-		DBIterator* iter = db_iterator(castle_db);
-		struct guild_castle* gc;
-		for( gc = (struct guild_castle*)dbi_first(iter) ; dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter) )
-		{
-			if( gc->guild_id != guild_id )
+		for (const auto &it : castle_db) {
+			if( it.second->guild_id != guild_id )
 				continue;
 			// update permanent guardians
-			for( i = 0; i < ARRAYLENGTH(gc->guardian); ++i )
+			for( i = 0; i < ARRAYLENGTH(it.second->guardian); ++i )
 			{
-				TBL_MOB* md = (gc->guardian[i].id ? map_id2md(gc->guardian[i].id) : NULL);
+				TBL_MOB* md = (it.second->guardian[i].id ? map_id2md(it.second->guardian[i].id) : NULL);
 				if( md == NULL || md->guardian_data == NULL )
 					continue;
 				md->guardian_data->emblem_id = emblem_id;
 				clif_guild_emblem_area(&md->bl);
 			}
 			// update temporary guardians
-			for( i = 0; i < gc->temp_guardians_max; ++i )
+			for( i = 0; i < it.second->temp_guardians_max; ++i )
 			{
-				TBL_MOB* md = (gc->temp_guardians[i] ? map_id2md(gc->temp_guardians[i]) : NULL);
+				TBL_MOB* md = (it.second->temp_guardians[i] ? map_id2md(it.second->temp_guardians[i]) : NULL);
 				if( md == NULL || md->guardian_data == NULL )
 					continue;
 				md->guardian_data->emblem_id = emblem_id;
 				clif_guild_emblem_area(&md->bl);
 			}
 		}
-		dbi_destroy(iter);
 	}
 	{// update npcs (flags or other npcs that used flagemblem to attach to this guild)
 		for( i = 0; i < guild_flags_count; i++ ) {
@@ -1845,24 +1877,20 @@ int guild_broken_sub(DBKey key, DBData *data, va_list ap) {
  * Invoked on Castles when a guild is broken. [Skotlex]
  * @see DBApply
  */
-int castle_guild_broken_sub(DBKey key, DBData *data, va_list ap)
-{
-	struct guild_castle *gc = (struct guild_castle *)db_data2ptr(data);
-	int guild_id = va_arg(ap, int);
-
-	nullpo_ret(gc);
-
-	if (gc->guild_id == guild_id) {
-		char name[EVENT_NAME_LENGTH];
-		// We call castle_event::OnGuildBreak of all castles of the guild
-		// You can set all castle_events in the 'db/castle_db.txt'
-		safesnprintf(name, EVENT_NAME_LENGTH, "%s::%s", gc->castle_event, script_config.guild_break_event_name);
-		npc_event_do(name);
-
-		//Save the new 'owner', this should invoke guardian clean up and other such things.
-		guild_castledatasave(gc->castle_id, CD_GUILD_ID, 0);
+void castle_guild_broken_sub(int guild_id) {
+	for (const auto &it : castle_db) {
+		std::shared_ptr<guild_castle> gc = it.second;
+		if (gc->guild_id == guild_id) {
+			char name[EVENT_NAME_LENGTH];
+			// We call castle_event::OnGuildBreak of all castles of the guild
+			// You can set all castle_events in the 'db/castle_db.txt'
+			safesnprintf(name, EVENT_NAME_LENGTH, "%s::%s", gc->castle_event, script_config.guild_break_event_name);
+			npc_event_do(name);
+
+			//Save the new 'owner', this should invoke guardian clean up and other such things.
+			guild_castledatasave(gc->castle_id, CD_GUILD_ID, 0);
+		}
 	}
-	return 0;
 }
 
 //Invoked on /breakguild "Guild name"
@@ -1892,7 +1920,7 @@ int guild_broken(int guild_id,int flag) {
 	}
 
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
-	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
+	castle_guild_broken_sub(guild_id);
 	storage_guild_delete(guild_id);
 	if( channel_config.ally_tmpl.name[0] ) {
 		channel_delete(g->channel,false);
@@ -2066,23 +2094,14 @@ int guild_break(struct map_session_data *sd,char *name) {
  * from char-server.
  */
 void guild_castle_map_init(void) {
-	int num = db_size(castle_db);
-
-	if (num > 0) {
-		struct guild_castle* gc = NULL;
-		int *castle_ids, *cursor;
-		DBIterator* iter = NULL;
-
-		CREATE(castle_ids, int, num);
-		cursor = castle_ids;
-		iter = db_iterator(castle_db);
-		for (gc = (struct guild_castle*)dbi_first(iter); dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter)) {
-			*(cursor++) = gc->castle_id;
-		}
-		dbi_destroy(iter);
-		if (intif_guild_castle_dataload(num, castle_ids))
-			ShowStatus("Requested '" CL_WHITE "%d" CL_RESET "' guild castles from char-server...\n", num);
-		aFree(castle_ids);
+	std::vector<int32> castle_ids;
+
+	for( const auto &it : castle_db ){
+		castle_ids.push_back( it.first );
+	}
+
+	if( !castle_ids.empty() && intif_guild_castle_dataload( castle_ids ) ){
+		ShowStatus( "Requested '" CL_WHITE "%" PRIdPTR CL_RESET "' guild castles from char-server...\n", castle_ids.size() );
 	}
 }
 
@@ -2095,9 +2114,9 @@ void guild_castle_map_init(void) {
  * @param value New value
  */
 int guild_castledatasave(int castle_id, int index, int value) {
-	struct guild_castle *gc = guild_castle_search(castle_id);
+	std::shared_ptr<guild_castle> gc = castle_db.find(castle_id);
 
-	if (gc == NULL) {
+	if (gc == nullptr) {
 		ShowWarning("guild_castledatasave: guild castle '%d' not found\n", castle_id);
 		return 0;
 	}
@@ -2204,8 +2223,9 @@ int guild_castledataloadack(int len, struct guild_castle *gc) {
 		npc_event_doall( script_config.agit_init3_event_name );
 	} else // load received castles into memory, one by one
 	for( i = 0; i < n; i++, gc++ ) {
-		struct guild_castle *c = guild_castle_search(gc->castle_id);
-		if (!c) {
+		std::shared_ptr<guild_castle> c = castle_db.find(gc->castle_id);
+
+		if (c == nullptr) {
 			ShowError("guild_castledataloadack: castle id=%d not found.\n", gc->castle_id);
 			continue;
 		}
@@ -2324,16 +2344,13 @@ bool guild_agit3_end(void){
 
 // How many castles does this guild have?
 int guild_checkcastles(struct guild *g) {
-	int nb_cas = 0;
-	struct guild_castle* gc = NULL;
-	DBIterator *iter = db_iterator(castle_db);
+	nullpo_retr(0, g);
 
-	for (gc = (struct guild_castle*)dbi_first(iter); dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter)) {
-		if (gc->guild_id == g->guild_id) {
+	int nb_cas = 0;
+	for (const auto &it : castle_db) {
+		if (it.second->guild_id == g->guild_id)
 			nb_cas++;
-		}
 	}
-	dbi_destroy(iter);
 	return nb_cas;
 }
 
@@ -2411,17 +2428,6 @@ static int guild_expcache_db_final(DBKey key, DBData *data, va_list ap) {
 	return 0;
 }
 
-/**
- * @see DBApply
- */
-static int guild_castle_db_final(DBKey key, DBData *data, va_list ap) {
-	struct guild_castle* gc = (struct guild_castle *)db_data2ptr(data);
-	if( gc->temp_guardians )
-		aFree(gc->temp_guardians);
-	aFree(gc);
-	return 0;
-}
-
 /* called when scripts are reloaded/unloaded */
 void guild_flags_clear(void) {
 	int i;
@@ -2434,30 +2440,14 @@ void guild_flags_clear(void) {
 }
 
 void do_init_guild(void) {
-	const char* dbsubpath[] = {
-		"",
-		"/" DBIMPORT,
-	};
-	int i;
-	
 	guild_db           = idb_alloc(DB_OPT_RELEASE_DATA);
-	castle_db          = idb_alloc(DB_OPT_BASE);
 	guild_expcache_db  = idb_alloc(DB_OPT_BASE);
 	guild_infoevent_db = idb_alloc(DB_OPT_BASE);
 	expcache_ers = ers_new(sizeof(struct guild_expcache),"guild.cpp::expcache_ers",ERS_OPT_NONE);
 
 	guild_flags_count = 0;
-	
-	for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
-		uint8 n1 = (uint8)(strlen(db_path)+strlen(dbsubpath[i])+1);
-		char* dbsubpath1 = (char*)aMalloc(n1+1);
-		safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
-		
-		sv_readdb(dbsubpath1, "castle_db.txt", ',', 4, 4, -1, &guild_read_castledb, i > 0);
-
-		aFree(dbsubpath1);
-	}
 
+	castle_db.load();
 	guild_skill_tree_db.load();
 
 	add_timer_func_list(guild_payexp_timer,"guild_payexp_timer");
@@ -2476,7 +2466,7 @@ void do_final_guild(void) {
 	dbi_destroy(iter);
 
 	db_destroy(guild_db);
-	castle_db->destroy(castle_db,guild_castle_db_final);
+	castle_db.clear();
 	guild_expcache_db->destroy(guild_expcache_db,guild_expcache_db_final);
 	guild_infoevent_db->destroy(guild_infoevent_db,eventlist_db_final);
 	ers_destroy(expcache_ers);

+ 17 - 5
src/map/guild.hpp

@@ -5,6 +5,7 @@
 #define GUILD_HPP
 
 #include "../common/cbasetypes.hpp"
+#include "../common/database.hpp"
 #include "../common/mmo.hpp"
 
 #include "map.hpp" // NAME_LENGTH
@@ -23,7 +24,7 @@ struct guardian_data {
 	int emblem_id;
 	int guardup_lv; //Level of GD_GUARDUP skill.
 	char guild_name[NAME_LENGTH];
-	struct guild_castle* castle;
+	std::shared_ptr<guild_castle> castle;
 };
 
 uint16 guild_skill_get_max(uint16 id);
@@ -36,10 +37,6 @@ bool guild_isallied(int guild_id, int guild_id2); //Checks alliance based on gui
 void do_init_guild(void);
 struct guild *guild_search(int guild_id);
 struct guild *guild_searchname(char *str);
-struct guild_castle *guild_castle_search(int gcid);
-
-struct guild_castle* guild_mapname2gc(const char* mapname);
-struct guild_castle* guild_mapindex2gc(short mapindex);
 
 struct map_session_data *guild_getavailablesd(struct guild *g);
 int guild_getindex(struct guild *g,uint32 account_id,uint32 char_id);
@@ -119,4 +116,19 @@ void guild_retrieveitembound(uint32 char_id,uint32 account_id,int guild_id);
 
 void do_final_guild(void);
 
+class CastleDatabase : public TypesafeYamlDatabase <int32, guild_castle> {
+public:
+	CastleDatabase() : TypesafeYamlDatabase("CASTLE_DB", 1) {
+
+	}
+
+	const std::string getDefaultLocation();
+	uint64 parseBodyNode(const YAML::Node &node);
+
+	std::shared_ptr<guild_castle> mapname2gc(const char* mapname);
+	std::shared_ptr<guild_castle> mapindex2gc(int16 mapindex);
+};
+
+extern CastleDatabase castle_db;
+
 #endif /* GUILD_HPP */

+ 15 - 9
src/map/intif.cpp

@@ -1152,16 +1152,22 @@ int intif_guild_emblem_version(int guild_id, int emblem_id)
  * @param num Number of castles, size of castle_ids array.
  * @param castle_ids Pointer to array of castle IDs.
  */
-int intif_guild_castle_dataload(int num, int *castle_ids)
-{
-	if (CheckForCharServer())
-		return 0;
-	WFIFOHEAD(inter_fd, 4 + num * sizeof(int));
+bool intif_guild_castle_dataload( const std::vector<int32>& castle_ids ){
+	if( CheckForCharServer() ){
+		return false;
+	}
+
+	uint16 size = (uint16)( 4 + castle_ids.size() * sizeof( int32 ) );
+
+	WFIFOHEAD( inter_fd, size );
 	WFIFOW(inter_fd, 0) = 0x3040;
-	WFIFOW(inter_fd, 2) = 4 + num * sizeof(int);
-	memcpy(WFIFOP(inter_fd, 4), castle_ids, num * sizeof(int));
-	WFIFOSET(inter_fd, WFIFOW(inter_fd, 2));
-	return 1;
+	WFIFOW( inter_fd, 2 ) = size;
+	for( size_t i = 0; i < castle_ids.size(); i++ ){
+		WFIFOL( inter_fd, 4 + i * sizeof( int32 ) ) = castle_ids[i];
+	}
+	WFIFOSET( inter_fd, size );
+
+	return true;
 }
 
 /**

+ 3 - 1
src/map/intif.hpp

@@ -4,6 +4,8 @@
 #ifndef INTIF_HPP
 #define INTIF_HPP
 
+#include <vector>
+
 #include "../common/cbasetypes.hpp"
 #include "../common/mmo.hpp"
 
@@ -64,7 +66,7 @@ int intif_guild_alliance(int guild_id1, int guild_id2, uint32 account_id1, uint3
 int intif_guild_notice(int guild_id, const char *mes1, const char *mes2);
 int intif_guild_emblem(int guild_id, int len, const char *data);
 int intif_guild_emblem_version(int guild_id, int version);
-int intif_guild_castle_dataload(int num, int *castle_ids);
+bool intif_guild_castle_dataload( const std::vector<int32>& castle_ids );
 int intif_guild_castle_datasave(int castle_id, int index, int value);
 #ifdef BOUND_ITEMS
 void intif_itembound_guild_retrieve(uint32 char_id, uint32 account_id, int guild_id);

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

@@ -300,7 +300,7 @@
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\attendance.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\attendance.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\attr_fix.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\attr_fix.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\battleground_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\battleground_db.yml')" />
-    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\castle_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\castle_db.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\castle_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\castle_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\const.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\const.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\create_arrow_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\create_arrow_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\elemental_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\elemental_db.txt')" />

+ 3 - 4
src/map/mob.cpp

@@ -686,7 +686,7 @@ int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, const
 
 		if (mob_id == MOBID_EMPERIUM)
 		{
-			struct guild_castle* gc = guild_mapindex2gc(map_getmapdata(m)->index);
+			std::shared_ptr<guild_castle> gc = castle_db.mapindex2gc(map_getmapdata(m)->index);
 			struct guild* g = (gc) ? guild_search(gc->guild_id) : nullptr;
 			if (gc)
 			{
@@ -827,7 +827,6 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
 	struct mob_data *md=nullptr;
 	struct spawn_data data;
 	struct guild *g=nullptr;
-	struct guild_castle *gc;
 	int16 m;
 	memset(&data, 0, sizeof(struct spawn_data)); //fixme
 	data.num = 1;
@@ -871,8 +870,8 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
 	if (!mob_parse_dataset(&data))
 		return 0;
 
-	gc=guild_mapname2gc(mapname);
-	if (gc == NULL)
+	std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapname);
+	if (gc == nullptr)
 	{
 		ShowError("mob_spawn_guardian: No castle set at map %s\n", mapname);
 		return 0;

+ 1 - 1
src/map/pc.cpp

@@ -6201,7 +6201,7 @@ enum e_setpos pc_setpos(struct map_session_data* sd, unsigned short mapindex, in
 
 	if( sd->status.guild_id > 0 && mapdata->flag[MF_GVG_CASTLE] )
 	{	// Increased guild castle regen [Valaris]
-		struct guild_castle *gc = guild_mapindex2gc(sd->mapindex);
+		std::shared_ptr<guild_castle> gc = castle_db.mapindex2gc(sd->mapindex);
 		if(gc && gc->guild_id == sd->status.guild_id)
 			sd->regen.state.gc = 1;
 	}

+ 4 - 4
src/map/script.cpp

@@ -13261,7 +13261,7 @@ BUILDIN_FUNC(flagemblem)
 BUILDIN_FUNC(getcastlename)
 {
 	const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
-	struct guild_castle* gc = guild_mapname2gc(mapname);
+	std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapname);
 	const char* name = (gc) ? gc->castle_name : "";
 	script_pushstrcopy(st,name);
 	return SCRIPT_CMD_SUCCESS;
@@ -13271,7 +13271,7 @@ BUILDIN_FUNC(getcastledata)
 {
 	const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL);
 	int index = script_getnum(st,3);
-	struct guild_castle *gc = guild_mapname2gc(mapname);
+	std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapname);
 
 	if (gc == NULL) {
 		script_pushint(st,0);
@@ -13315,7 +13315,7 @@ BUILDIN_FUNC(setcastledata)
 	const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL);
 	int index = script_getnum(st,3);
 	int value = script_getnum(st,4);
-	struct guild_castle *gc = guild_mapname2gc(mapname);
+	std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapname);
 
 	if (gc == NULL) {
 		ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname);
@@ -13918,7 +13918,7 @@ BUILDIN_FUNC(guardianinfo)
 	int id = script_getnum(st,3);
 	int type = script_getnum(st,4);
 
-	struct guild_castle* gc = guild_mapname2gc(mapname);
+	std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapname);
 	struct mob_data* gd;
 
 	if( gc == NULL || id < 0 || id >= MAX_GUARDIANS )

+ 2 - 3
src/map/status.cpp

@@ -3516,11 +3516,10 @@ int status_calc_mob_(struct mob_data* md, enum e_status_calc_opt opt)
 	status_calc_misc(&md->bl, status, md->level);
 
 	if(flag&4) { // Strengthen Guardians - custom value +10% / lv
-		struct guild_castle *gc;
 		struct map_data *mapdata = map_getmapdata(md->bl.m);
+		std::shared_ptr<guild_castle> gc = castle_db.mapname2gc(mapdata->name);
 
-		gc=guild_mapname2gc(mapdata->name);
-		if (!gc)
+		if (gc == nullptr)
 			ShowError("status_calc_mob: No castle set at map %s\n", mapdata->name);
 		else if(gc->castle_id < 24 || md->mob_id == MOBID_EMPERIUM) {
 #ifdef RENEWAL

+ 1 - 1
src/map/unit.cpp

@@ -3463,7 +3463,7 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 			}
 
 			if( md->guardian_data ) {
-				struct guild_castle* gc = md->guardian_data->castle;
+				std::shared_ptr<guild_castle> gc = md->guardian_data->castle;
 
 				if( md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS )
 					gc->guardian[md->guardian_data->number].id = 0;

+ 17 - 0
src/tool/csv2yaml.cpp

@@ -354,6 +354,12 @@ int do_init( int argc, char** argv ){
 	})) {
 		return 0;
 	}
+	if (!process("CASTLE_DB", 1, root_paths, "castle_db", [](const std::string &path, const std::string &name_ext) -> bool {
+		return sv_readdb(path.c_str(), name_ext.c_str(), ',', 4, 4, -1, &guild_read_castledb, false);
+	})) {
+		return 0;
+	}
+
 	// TODO: add implementations ;-)
 
 	return 0;
@@ -3709,3 +3715,14 @@ static bool pc_read_statsdb(const char* file) {
 	ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, file);
 	return true;
 }
+
+// Copied and adjusted from guild.cpp
+static bool guild_read_castledb(char* str[], int columns, int current) {
+	body << YAML::BeginMap;
+	body << YAML::Key << "Id" << YAML::Value << str[0];
+	body << YAML::Key << "Map" << YAML::Value << str[1];
+	body << YAML::Key << "Name" << YAML::Value << trim(str[2]);
+	body << YAML::Key << "Npc" << YAML::Value << trim(str[3]);
+	body << YAML::EndMap;
+	return true;
+}

+ 1 - 0
src/tool/csv2yaml.hpp

@@ -424,5 +424,6 @@ static bool mob_readdb_group(char* str[], int columns, int current);
 static bool mob_readdb_group_yaml(void);
 static bool skill_parse_row_createarrowdb(char* fields[], int columns, int current);
 static bool pc_read_statsdb(const char* file);
+static bool guild_read_castledb(char* str[], int columns, int current);
 
 #endif /* CSV2YAML_HPP */