Quellcode durchsuchen

mob_chat_db txt to yml (#5976)

* Converted mob_chat_db txt to yml
* mob_skill_db now display a warning when the chat ID doesn't exist

Thanks to @Lemongrass3110 and @aleos89 !
Atemo vor 4 Jahren
Ursprung
Commit
7f71f4c0c3

+ 0 - 5
db/import-tmpl/mob_chat_db.txt

@@ -1,5 +0,0 @@
-// Monster Chat Database
-//
-// Structure of Database:
-// Line_ID#Color_Code#Dialog
-

+ 32 - 0
db/import-tmpl/mob_chat_db.yml

@@ -0,0 +1,32 @@
+# 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/>.
+#
+###########################################################################
+# Monster Chat Database
+###########################################################################
+#
+# Settings
+#
+###########################################################################
+# - Id                      Index of the message.
+#   Color                   Hexadecimal color (Default: 0xFF0000).
+#   Dialog                  Text displayed by the monster.
+###########################################################################
+
+Header:
+  Type: MOB_CHAT_DB
+  Version: 1

+ 0 - 46
db/mob_chat_db.txt

@@ -1,46 +0,0 @@
-// Monster Chat Database
-//
-// Structure of Database:
-// Line_ID#Color_Code#Dialog
-
-1#0xFF0000#Weakling! Challenge me if you have any courage!
-2#0xFF0000#Impressive! I wonder how far your recklessness will take you.
-3#0xFF0000#I almost pity how outmatched you are against me. Now prepare for my attack!
-4#0xFF0000#My loyal servants! Welcome them with a painful death!
-5#0xFF0000#Don't you run away!
-6#0xFF0000#You worthless humans. Your so-called holy powers have no effect on me!
-7#0xFF0000#Useless underlings!...Well, that's fine, I have more weapons to use and dispose.
-8#0xFF0000#Pray to your gods!
-9#0xFF0000#Do you still think you're a match to me?!
-10#0xFF0000#Vanish!
-11#0xFF0000#Let's see how long you can endure my power!
-12#0xFF0000#Is this all you've got?!
-13#0xFF0000#You're tickling me!
-14#0xFF0000#This is how you attack? Watch and learn, weaklings!
-15#0xFF0000#It's time to finish the game!
-16#0xFF0000#Oh, you're stronger than I thought!
-17#0xFF0000#No, this can't be happening! I'm Satan Morocc, Demon King of Destruction!
-18#0xFF0000#I can never die! I'll be coming back for you!
-19#0xFF0000#I was born to conquer this world! None shall stop me!
-20#0xFF0000#Your days are numbered!
-21#0xFF0000#Pulse Strike! My fingers tear steel!
-22#0xFF0000#Hahaha, tell me who I am! I'm Baphomet, the Heir of Hell!
-23#0xFF0000#Enjoy your time on the mortal plane while you can, your hope will soon turn into despair!
-24#0xFF0000#When are you going to learn your lesson? In death?
-25#0xFF0000#No... I can't lose! I won't beg for my life! I'm not running away! I don't accept this as defeat!
-26#0xFF0000#Argh... I... I'm weakening...
-27#0xFF0000#What do you want from me?
-28#0xFF0000#No! I didn't do this! He's the one who planned out all this!
-29#0xFF0000#I just wanted to find peace..!  That's why I have been fleeing away!
-30#0xFF0000#Ahhhh!!! Now, I just have to kill you all!
-31#0xFF0000#Annoying flies!! Get off of me!
-32#0xFF0000#Suffer in Hell!
-33#0xFF0000#Mwahahaha! Taste the anger of the earth!!!
-34#0xFF0000#No... I won't accept this as defeat!
-35#0xFF0000#Will it ease your loneliness to hit me?  Why don't you stay here with me forever, human?
-36#0xFF0000#You will forgot the meaning of time.  I wonder how long can you last in here...
-37#0xFF0000#Is there anyone waiting for you outside of here?  Throw them all away, you are mine now...
-38#0xFF0000#Discard your life and stay confined here.  You will yearn for freedom in captivity !!
-39#0xFF0000#How much will the outside world change if you stay here in solitude for one thousand years?
-40#0xFF0000#Yes! Yearn for your freedom from this confined place, your captivity here will be permanent !!
-

+ 118 - 0
db/mob_chat_db.yml

@@ -0,0 +1,118 @@
+# 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/>.
+#
+###########################################################################
+# Monster Chat Database
+###########################################################################
+#
+# Settings
+#
+###########################################################################
+# - Id                      Index of the message.
+#   Color                   Hexadecimal color (Default: 0xFF0000).
+#   Dialog                  Text displayed by the monster.
+###########################################################################
+
+Header:
+  Type: MOB_CHAT_DB
+  Version: 1
+
+Body:
+  - Id: 1
+    Dialog: Weakling! Challenge me if you have any courage!
+  - Id: 2
+    Dialog: Impressive! I wonder how far your recklessness will take you.
+  - Id: 3
+    Dialog: I almost pity how outmatched you are against me. Now prepare for my attack!
+  - Id: 4
+    Dialog: My loyal servants! Welcome them with a painful death!
+  - Id: 5
+    Dialog: Don't you run away!
+  - Id: 6
+    Dialog: You worthless humans. Your so-called holy powers have no effect on me!
+  - Id: 7
+    Dialog: Useless underlings!...Well, that's fine, I have more weapons to use and dispose.
+  - Id: 8
+    Dialog: Pray to your gods!
+  - Id: 9
+    Dialog: Do you still think you're a match to me?!
+  - Id: 10
+    Dialog: Vanish!
+  - Id: 11
+    Dialog: Let's see how long you can endure my power!
+  - Id: 12
+    Dialog: Is this all you've got?!
+  - Id: 13
+    Dialog: You're tickling me!
+  - Id: 14
+    Dialog: This is how you attack? Watch and learn, weaklings!
+  - Id: 15
+    Dialog: It's time to finish the game!
+  - Id: 16
+    Dialog: Oh, you're stronger than I thought!
+  - Id: 17
+    Dialog: No, this can't be happening! I'm Satan Morocc, Demon King of Destruction!
+  - Id: 18
+    Dialog: I can never die! I'll be coming back for you!
+  - Id: 19
+    Dialog: I was born to conquer this world! None shall stop me!
+  - Id: 20
+    Dialog: Your days are numbered!
+  - Id: 21
+    Dialog: Pulse Strike! My fingers tear steel!
+  - Id: 22
+    Dialog: Hahaha, tell me who I am! I'm Baphomet, the Heir of Hell!
+  - Id: 23
+    Dialog: Enjoy your time on the mortal plane while you can, your hope will soon turn into despair!
+  - Id: 24
+    Dialog: When are you going to learn your lesson? In death?
+  - Id: 25
+    Dialog: No... I can't lose! I won't beg for my life! I'm not running away! I don't accept this as defeat!
+  - Id: 26
+    Dialog: Argh... I... I'm weakening...
+  - Id: 27
+    Dialog: What do you want from me?
+  - Id: 28
+    Dialog: No! I didn't do this! He's the one who planned out all this!
+  - Id: 29
+    Dialog: I just wanted to find peace..!  That's why I have been fleeing away!
+  - Id: 30
+    Dialog: Ahhhh!!! Now, I just have to kill you all!
+  - Id: 31
+    Dialog: Annoying flies!! Get off of me!
+  - Id: 32
+    Dialog: Suffer in Hell!
+  - Id: 33
+    Dialog: Mwahahaha! Taste the anger of the earth!!!
+  - Id: 34
+    Dialog: No... I won't accept this as defeat!
+  - Id: 35
+    Dialog: Will it ease your loneliness to hit me?  Why don't you stay here with me forever, human?
+  - Id: 36
+    Dialog: You will forgot the meaning of time.  I wonder how long can you last in here...
+  - Id: 37
+    Dialog: Is there anyone waiting for you outside of here?  Throw them all away, you are mine now...
+  - Id: 38
+    Dialog: Discard your life and stay confined here.  You will yearn for freedom in captivity !!
+  - Id: 39
+    Dialog: How much will the outside world change if you stay here in solitude for one thousand years?
+  - Id: 40
+    Dialog: Yes! Yearn for your freedom from this confined place, your captivity here will be permanent !!
+
+Footer:
+  Imports:
+  - Path: db/import/mob_chat_db.yml

+ 23 - 11
db/re/mob_skill_db.txt

@@ -10987,17 +10987,29 @@
 2940,Evil Shadow@NPC_DARKSTRIKE,attack,340,1,3000,0,5000,yes,target,always,0,,,,,,,
 2941,Evil Shadow@NPC_CRITICALSLASH,chase,170,1,3000,0,5000,yes,target,always,0,,,,,,,
 2941,Evil Shadow@NPC_PETRIFYATTACK,attack,180,5,3500,0,5000,yes,target,always,0,,,,,,,
-2942,Evil Fanatics@NPC_INVINCIBLE,idle,685,1,10000,0,20000,yes,self,myhpltmaxrate,100,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,100,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,90,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,80,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,70,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,60,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,50,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,40,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,30,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,20,,,,,,,42
-2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,10,,,,,,,42
+2942,Evil Fanatics@NPC_INVINCIBLE,idle,685,1,10000,0,20000,yes,self,myhpltmaxrate,100,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,100,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,90,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,80,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,70,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,60,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,50,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,40,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,30,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,20,,,,,,,
+2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,10,,,,,,,
+// unknown monster chat
+// 2942,Evil Fanatics@NPC_INVINCIBLE,idle,685,1,10000,0,20000,yes,self,myhpltmaxrate,100,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,100,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,90,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,80,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,70,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,60,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,50,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,40,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,30,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,20,,,,,,,42
+// 2942,Evil Fanatics@NPC_INVINCIBLE,attack,685,1,10000,0,20000,yes,self,myhpltmaxrate,10,,,,,,,42
 // 2942,Evil Fanatics@NPC_DANCINGBLADE,attack,713,1,1000,0,15000,yes,self,always,0,,,,,,,
 // 2942,Evil Fanatics@NPC_PULSESTRIKE2,attack,712,1,800,0,15000,yes,self,always,0,,,,,,,
 // 2942,Evil Fanatics@NPC_DARKPIERCING,attack,715,1,2500,0,60000,yes,self,always,0,,,,,,,

+ 11 - 0
doc/yaml/db/mob_chat_db.yml

@@ -0,0 +1,11 @@
+###########################################################################
+# Monster Chat Database
+###########################################################################
+#
+# Settings
+#
+###########################################################################
+# - Id                      Index of the message.
+#   Color                   Hexadecimal color (Default: 0xFF0000).
+#   Dialog                  Text displayed by the monster.
+###########################################################################

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

@@ -339,7 +339,7 @@
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_avail.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_avail.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_boss.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_boss.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_branch.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_branch.txt')" />
-    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_chat_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_chat_db.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_chat_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_chat_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_classchange.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_classchange.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_item_ratio.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_item_ratio.txt')" />

+ 57 - 51
src/map/mob.cpp

@@ -73,12 +73,6 @@ const t_tick MOB_MAX_DELAY = 24 * 3600 * 1000;
 // holds Monster Spawn informations
 std::unordered_map<uint16, std::vector<spawn_info>> mob_spawn_data;
 
-//Dynamic mob chat database
-std::map<short,struct mob_chat> mob_chat_db;
-struct mob_chat *mob_chat(short id) {
-	return util::map_find( mob_chat_db, id );
-}
-
 //Dynamic item drop ratio database for per-item drop ratio modifiers overriding global drop ratios.
 #define MAX_ITEMRATIO_MOBS 10
 struct s_mob_item_drop_ratio {
@@ -112,6 +106,8 @@ struct s_randomsummon_group {
 
 static DBMap *mob_summon_db; /// Random Summon DB. struct s_randomsummon_group -> group_id
 
+MobChatDatabase mob_chat_db;
+
 /*==========================================
  * Local prototype declaration   (only required thing)
  *------------------------------------------*/
@@ -3856,7 +3852,7 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event)
 		}
 		//Skill used. Post-setups...
 		if ( ms[i]->msg_id ){ //Display color message [SnakeDrak]
-			struct mob_chat *mc = mob_chat(ms[i]->msg_id);
+			std::shared_ptr<s_mob_chat> mc = mob_chat_db.find(ms[i]->msg_id);
 
 			if (mc) {
 				std::string name = md->name, output;
@@ -5522,59 +5518,62 @@ static bool mob_readdb_group(char* str[], int columns, int current){
 	return true;
 }
 
-//processes one mob_chat_db entry [SnakeDrak]
-//db struct: Line_ID,Color_Code,Dialog
-static bool mob_parse_row_chatdb(char* fields[], int columns, int current)
-{
-	char* msg;
-	struct mob_chat *ms;
-	int msg_id;
-	size_t len;
+const std::string MobChatDatabase::getDefaultLocation() {
+	return std::string(db_path) + "/mob_chat_db.yml";
+}
 
-	msg_id = atoi(fields[0]);
+/**
+ * Reads and parses an entry from the mob_chat_db.
+ * @param node: YAML node containing the entry.
+ * @return count of successfully parsed rows
+ */
+uint64 MobChatDatabase::parseBodyNode(const YAML::Node &node) {
+	uint16 id;
 
-	if (msg_id <= 0){
-		ShowError("mob_parse_row_chatdb: Invalid chat ID '%d' in line %d\n", msg_id, current);
-		return false;
-	}
+	if (!this->asUInt16(node, "Id", id))
+		return 0;
 
-	ms = mob_chat(msg_id);
+	std::shared_ptr<s_mob_chat> chat = this->find(id);
+	bool exists = chat != nullptr;
 
-	if( ms == NULL ){
-		try{
-			ms = &mob_chat_db[msg_id];
-		}catch( const std::bad_alloc& ){
-			ShowError( "mob_parse_row_chatdb: Memory allocation for chat ID '%d' failed.\n", msg_id );
-			return false;
+	if (!exists) {
+		if (!this->nodesExist(node, { "Dialog" })) {
+			return 0;
 		}
+
+		chat = std::make_shared<s_mob_chat>();
+		chat->msg_id = id;
 	}
 	
-	//MSG ID
-	ms->msg_id=msg_id;
-	//Color
-	ms->color=strtoul(fields[1],NULL,0);
-	//Message
-	msg = fields[2];
-	len = strlen(msg);
+	if (this->nodeExists(node, "Color")) {
+		std::string hex;
 
-	while( len && ( msg[len-1]=='\r' || msg[len-1]=='\n' ) )
-	{// find EOL to strip
-		len--;
-	}
+		if (!this->asString(node, "Color", hex))
+			return 0;
 
-	if(len>(CHAT_SIZE_MAX-1)){
-		ShowError("mob_parse_row_chatdb: Message too long! Line %d, id: %d\n", current, msg_id);
-		return false;
+		chat->color = strtoul(hex.c_str(), nullptr, 0);
+	} else {
+		if (!exists)
+			chat->color = strtoul("0xFF0000", nullptr, 0);
 	}
-	else if( !len ){
-		ShowWarning("mob_parse_row_chatdb: Empty message for id %d.\n", msg_id);
-		return false;
+
+	if (this->nodeExists(node, "Dialog")) {
+		std::string msg;
+
+		if (!this->asString(node, "Dialog", msg))
+			return 0;
+
+		if (msg.length() > (CHAT_SIZE_MAX-1)) {
+			this->invalidWarning(node["Dialog"], "Message too long!\n");
+			return 0;
+		}
+		chat->msg = msg;
 	}
 
-	msg[len] = 0;  // strip previously found EOL
-	safestrncpy(ms->msg, fields[2], CHAT_SIZE_MAX);
+	if (!exists)
+		this->put(id, chat);
 
-	return true;
+	return 1;
 }
 
 /*==========================================
@@ -5810,8 +5809,15 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
 	else
 		ms->emotion = -1;
 
-	if(str[18] != NULL && mob_chat(atoi(str[18]))!=NULL)
-		ms->msg_id = atoi(str[18]);
+	if (*str[18]) {
+		uint16 id = static_cast<uint16>(strtol(str[18], nullptr, 10));
+		if (mob_chat_db.find(id) != nullptr)
+			ms->msg_id = id;
+		else {
+			ms->msg_id = 0;
+			ShowWarning("mob_parse_row_mobskilldb: Unknown chat ID %s for monster %d.\n", str[18], mob_id);
+		}
+	}
 	else
 		ms->msg_id = 0;
 
@@ -6191,6 +6197,8 @@ static void mob_load(void)
 	else
 		mob_db.load();
 
+	mob_chat_db.load();	// load before mob_skill_db
+
 	for(int i = 0; i < ARRAYLENGTH(dbsubpath); i++){	
 		int n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
 		int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
@@ -6207,8 +6215,6 @@ static void mob_load(void)
 			safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]);
 		}
 
-		sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, -1, &mob_parse_row_chatdb, silent);
-
 		if( db_use_sqldbs && i == 0 )
 			mob_read_sqlskilldb();
 		else

+ 14 - 4
src/map/mob.hpp

@@ -189,10 +189,20 @@ struct s_mob_skill {
 	unsigned short msg_id;
 };
 
-struct mob_chat {
-	unsigned short msg_id;
-	unsigned long color;
-	char msg[CHAT_SIZE_MAX];
+struct s_mob_chat {
+	uint16 msg_id;
+	uint32 color;
+	std::string msg;
+};
+
+class MobChatDatabase : public TypesafeYamlDatabase<uint16, s_mob_chat> {
+public:
+	MobChatDatabase() : TypesafeYamlDatabase("MOB_CHAT_DB", 1) {
+
+	}
+
+	const std::string getDefaultLocation();
+	uint64 parseBodyNode(const YAML::Node &node);
 };
 
 struct spawn_info {

+ 44 - 0
src/tool/csv2yaml.cpp

@@ -285,6 +285,12 @@ int do_init( int argc, char** argv ){
 		return 0;
 	}
 
+	if (!process("MOB_CHAT_DB", 1, root_paths, "mob_chat_db", [](const std::string& path, const std::string& name_ext) -> bool {
+		return sv_readdb(path.c_str(), name_ext.c_str(), '#', 3, 3, -1, &mob_parse_row_chatdb, false);
+	})) {
+		return 0;
+	}
+
 	// TODO: add implementations ;-)
 
 	return 0;
@@ -3407,3 +3413,41 @@ static bool mob_readdb_sub(char *fields[], int columns, int current) {
 
 	return true;
 }
+
+// Copied and adjusted from mob.cpp
+static bool mob_parse_row_chatdb(char* fields[], int columns, int current) {
+	int msg_id = atoi(fields[0]);
+
+	if (msg_id <= 0){
+		ShowError("Invalid chat ID '%d' in line %d\n", msg_id, current);
+		return false;
+	}
+
+	char* msg = fields[2];
+	size_t len = strlen(msg);
+
+	while( len && ( msg[len-1] == '\r' || msg[len-1] == '\n' ) ) {// find EOL to strip
+		len--;
+	}
+
+	if (len > (CHAT_SIZE_MAX-1)) {
+		ShowError("Message too long! Line %d, id: %d\n", current, msg_id);
+		return false;
+	}
+	else if (len == 0) {
+		ShowWarning("Empty message for id %d.\n", msg_id);
+		return false;
+	}
+
+	msg[len] = 0;  // strip previously found EOL
+
+	body << YAML::BeginMap;
+	body << YAML::Key << "Id" << YAML::Value << msg_id;
+	if (strcmp(fields[1], "0xFF0000") != 0)	// default color
+		body << YAML::Key << "Color" << YAML::Value << fields[1];
+	body << YAML::Key << "Dialog" << YAML::Value << msg;
+	body << YAML::EndMap;
+
+	return true;
+}
+

+ 1 - 0
src/tool/csv2yaml.hpp

@@ -380,5 +380,6 @@ static bool itemdb_read_randomopt_group(char *str[], int columns, int current);
 static bool itemdb_randomopt_group_yaml(void);
 static bool pc_readdb_levelpenalty(char* fields[], int columns, int current);
 static bool pc_levelpenalty_yaml();
+static bool mob_parse_row_chatdb(char* fields[], int columns, int current);
 
 #endif /* CSV2YAML_HPP */