Преглед на файлове

Splitted guild_skill_tree.txt into re and pre-re (#3841)

Converted Guild Skill Tree database to YAML

Please run csv2yaml to convert your existing databases if necessary.

Thanks to @aleos89, @Atemo and @Lemongrass3110
Daegaladh преди 6 години
родител
ревизия
cbe0d6b271

+ 0 - 30
db/guild_skill_tree.txt

@@ -1,30 +0,0 @@
-// Guild Skill Tree Database
-//
-// Structure of Database:
-// SkillID,MaxLv,Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5	//GUILD SKILLNAME#Skill Name#
-//
-// 01. SkillID                  Skill ID of the guild skill.
-// 02. MaxLv                    Maximum level of the guild skill.
-// 03. Prerequisite SkillID     Guild skill required for the skill to become available.
-// 04. Prerequisite SkillLv     Level of the required guild skill.
-// ...
-//
-// NOTE: MAX_GUILD_SKILL_REQUIRE (typically 5) ID/Lv pairs must be specified.
-
-
-10000,1,0,0,0,0,0,0,0,0,0,0	//GD_APPROVAL#Official Guild Approval#
-10001,1,10000,1,0,0,0,0,0,0,0,0	//GD_KAFRACONTRACT#Contract with Kafra#
-10002,1,10000,1,0,0,0,0,0,0,0,0	//GD_GUARDRESEARCH#Guardian Research#
-10003,3,0,0,0,0,0,0,0,0,0,0	//GD_GUARDUP#Strengthen Guardians#
-10004,10,0,0,0,0,0,0,0,0,0,0	//GD_EXTENSION#Guild Extension#
-10005,0,0,0,0,0,0,0,0,0,0,0	//GD_GLORYGUILD#Guilds Glory#
-10006,5,0,0,0,0,0,0,0,0,0,0	//GD_LEADERSHIP#Great Leadership#
-10007,5,0,0,0,0,0,0,0,0,0,0	//GD_GLORYWOUNDS#Glorious Wounds#
-10008,5,10007,1,0,0,0,0,0,0,0,0	//GD_SOULCOLD#Cold Heart#
-10009,5,10006,1,0,0,0,0,0,0,0,0	//GD_HAWKEYES#Sharp Gaze#
-10010,1,10000,1,10004,2,0,0,0,0,0,0	//GD_BATTLEORDER#Battle Command#
-10011,3,10000,1,10004,5,10010,1,0,0,0,0	//GD_REGENERATION#Regeneration#
-10012,1,10011,1,0,0,0,0,0,0,0,0	//GD_RESTORE#Restoration#
-10013,1,10000,1,10002,1,10004,5,10010,1,10011,1	//GD_EMERGENCYCALL#Urgent Call#
-10014,1,0,0,0,0,0,0,0,0,0,0	//GD_DEVELOPMENT#Permanent Development#
-10016,5,0,0,0,0,0,0,0,0,0,0	//GD_GUILD_STORAGE#Guild Storage Expansion#

+ 44 - 0
db/guild_skill_tree.yml

@@ -0,0 +1,44 @@
+# 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/>.
+#
+###########################################################################
+# Guild Skill Database
+###########################################################################
+#
+# Guild Skill Settings
+#
+###########################################################################
+# Id - Skill ID of the guild skill.
+###########################################################################
+# MaxLevel - Maximum level of the guild skill.
+###########################################################################
+# Required - A list of required skills for the skill to become available.
+#   Id: Skill ID of the required guild skill.
+#   Level: Level of the required guild skill.
+###########################################################################
+
+Header:
+  Type: GUILD_SKILL_TREE_DB
+  Version: 1
+
+Footer:
+  Imports:
+  - Path: db/pre-re/guild_skill_tree.yml
+    Mode: Prerenewal
+  - Path: db/re/guild_skill_tree.yml
+    Mode: Renewal
+  - Path: db/import/guild_skill_tree.yml

+ 0 - 13
db/import-tmpl/guild_skill_tree.txt

@@ -1,13 +0,0 @@
-// Guild Skill Tree Database
-//
-// Structure of Database:
-// SkillID,MaxLv,Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5	//GUILD SKILLNAME#Skill Name#
-//
-// 01. SkillID                  Skill ID of the guild skill.
-// 02. MaxLv                    Maximum level of the guild skill.
-// 03. Prerequisite SkillID     Guild skill required for the skill to become available.
-// 04. Prerequisite SkillLv     Level of the required guild skill.
-// ...
-//
-// NOTE: MAX_GUILD_SKILL_REQUIRE (typically 5) ID/Lv pairs must be specified.
-

+ 36 - 0
db/import-tmpl/guild_skill_tree.yml

@@ -0,0 +1,36 @@
+# 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/>.
+#
+###########################################################################
+# Custom Guild Skill Database
+###########################################################################
+#
+# Guild Skill Settings
+#
+###########################################################################
+# Id - Skill ID of the guild skill.
+###########################################################################
+# MaxLevel - Maximum level of the guild skill.
+###########################################################################
+# Required - A list of required skills for the skill to become available.
+#   Id: Skill ID of the required guild skill.
+#   Level: Level of the required guild skill.
+###########################################################################
+
+Header:
+  Type: GUILD_SKILL_TREE_DB
+  Version: 1

+ 123 - 0
db/pre-re/guild_skill_tree.yml

@@ -0,0 +1,123 @@
+# 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/>.
+#
+###########################################################################
+# Pre-Renewal Guild Skill Database
+###########################################################################
+#
+# Guild Skill Settings
+#
+###########################################################################
+# Id - Skill ID of the guild skill.
+###########################################################################
+# MaxLevel - Maximum level of the guild skill.
+###########################################################################
+# Required - A list of required skills for the skill to become available.
+#   Id: Skill ID of the required guild skill.
+#   Level: Level of the required guild skill.
+###########################################################################
+
+Header:
+  Type: GUILD_SKILL_TREE_DB
+  Version: 1
+
+Body:
+  - Id: GD_APPROVAL
+    MaxLevel: 1
+
+  - Id: GD_KAFRACONTRACT
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+
+  - Id: GD_GUARDRESEARCH
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+
+  - Id: GD_GUARDUP
+    MaxLevel: 3
+
+  - Id: GD_EXTENSION
+    MaxLevel: 10
+
+  - Id: GD_GLORYGUILD
+    MaxLevel: 0
+
+  - Id: GD_LEADERSHIP
+    MaxLevel: 5
+
+  - Id: GD_GLORYWOUNDS
+    MaxLevel: 5
+
+  - Id: GD_SOULCOLD
+    MaxLevel: 5
+    Required:
+    - Id: GD_GLORYWOUNDS
+      Level: 1
+
+  - Id: GD_HAWKEYES
+    MaxLevel: 5
+    Required:
+    - Id: GD_LEADERSHIP
+      Level: 1
+
+  - Id: GD_BATTLEORDER
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+    - Id: GD_EXTENSION
+      Level: 2
+
+  - Id: GD_REGENERATION
+    MaxLevel: 3
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+    - Id: GD_EXTENSION
+      Level: 5
+    - Id: GD_BATTLEORDER
+      Level: 1
+
+  - Id: GD_RESTORE
+    MaxLevel: 1
+    Required:
+    - Id: GD_REGENERATION
+      Level: 1
+
+  - Id: GD_EMERGENCYCALL
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+    - Id: GD_GUARDRESEARCH
+      Level: 1
+    - Id: GD_EXTENSION
+      Level: 5
+    - Id: GD_BATTLEORDER
+      Level: 1
+    - Id: GD_REGENERATION
+      Level: 1
+
+  - Id: GD_DEVELOPMENT
+    MaxLevel: 1
+
+#  - Id: GD_GUILD_STORAGE
+#    MaxLevel: 5

+ 123 - 0
db/re/guild_skill_tree.yml

@@ -0,0 +1,123 @@
+# 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/>.
+#
+###########################################################################
+# Renewal Guild Skill Database
+###########################################################################
+#
+# Guild Skill Settings
+#
+###########################################################################
+# Id - Skill ID of the guild skill.
+###########################################################################
+# MaxLevel - Maximum level of the guild skill.
+###########################################################################
+# Required - A list of required skills for the skill to become available.
+#   Id: Skill ID of the required guild skill.
+#   Level: Level of the required guild skill.
+###########################################################################
+
+Header:
+  Type: GUILD_SKILL_TREE_DB
+  Version: 1
+
+Body:
+  - Id: GD_APPROVAL
+    MaxLevel: 1
+
+  - Id: GD_KAFRACONTRACT
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+
+  - Id: GD_GUARDRESEARCH
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+
+  - Id: GD_GUARDUP
+    MaxLevel: 3
+
+  - Id: GD_EXTENSION
+    MaxLevel: 10
+
+  - Id: GD_GLORYGUILD
+    MaxLevel: 0
+
+  - Id: GD_LEADERSHIP
+    MaxLevel: 5
+
+  - Id: GD_GLORYWOUNDS
+    MaxLevel: 5
+
+  - Id: GD_SOULCOLD
+    MaxLevel: 5
+    Required:
+    - Id: GD_GLORYWOUNDS
+      Level: 1
+
+  - Id: GD_HAWKEYES
+    MaxLevel: 5
+    Required:
+    - Id: GD_LEADERSHIP
+      Level: 1
+
+  - Id: GD_BATTLEORDER
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+    - Id: GD_EXTENSION
+      Level: 2
+
+  - Id: GD_REGENERATION
+    MaxLevel: 3
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+    - Id: GD_EXTENSION
+      Level: 5
+    - Id: GD_BATTLEORDER
+      Level: 1
+
+  - Id: GD_RESTORE
+    MaxLevel: 1
+    Required:
+    - Id: GD_REGENERATION
+      Level: 1
+
+  - Id: GD_EMERGENCYCALL
+    MaxLevel: 1
+    Required:
+    - Id: GD_APPROVAL
+      Level: 1
+    - Id: GD_GUARDRESEARCH
+      Level: 1
+    - Id: GD_EXTENSION
+      Level: 5
+    - Id: GD_BATTLEORDER
+      Level: 1
+    - Id: GD_REGENERATION
+      Level: 1
+
+  - Id: GD_DEVELOPMENT
+    MaxLevel: 1
+
+  - Id: GD_GUILD_STORAGE
+    MaxLevel: 5

+ 162 - 56
src/map/guild.cpp

@@ -4,8 +4,10 @@
 #include "guild.hpp"
 
 #include <stdlib.h>
+#include <yaml-cpp/yaml.h>
 
 #include "../common/cbasetypes.hpp"
+#include "../common/database.hpp"
 #include "../common/ers.hpp"
 #include "../common/malloc.hpp"
 #include "../common/mapindex.hpp"
@@ -13,6 +15,7 @@
 #include "../common/showmsg.hpp"
 #include "../common/strlib.hpp"
 #include "../common/timer.hpp"
+#include "../common/utilities.hpp"
 #include "../common/utils.hpp"
 
 #include "battle.hpp"
@@ -28,6 +31,8 @@
 #include "storage.hpp"
 #include "trade.hpp"
 
+using namespace rathena;
+
 static DBMap* guild_db; // int guild_id -> struct guild*
 static DBMap* castle_db; // int castle_id -> struct guild_castle*
 static DBMap* guild_expcache_db; // uint32 char_id -> struct guild_expcache*
@@ -50,15 +55,139 @@ struct guild_expcache {
 };
 static struct eri *expcache_ers; //For handling of guild exp payment.
 
-#define MAX_GUILD_SKILL_REQUIRE 5
-struct s_guild_skill_tree {
-	int id;
-	int max;
-	struct{
-		short id;
-		short lv;
-	}need[MAX_GUILD_SKILL_REQUIRE];
-} guild_skill_tree[MAX_GUILDSKILL];
+struct s_guild_skill_requirement{
+	uint16 id;
+	uint16 lv;
+};
+
+struct s_guild_skill_tree{
+	uint16 id;
+	uint16 max;
+	std::unordered_map<uint16,std::shared_ptr<s_guild_skill_requirement>> need;
+};
+
+class GuildSkillTreeDatabase : public TypesafeYamlDatabase<uint16, s_guild_skill_tree>{
+public:
+	GuildSkillTreeDatabase() : TypesafeYamlDatabase( "GUILD_SKILL_TREE_DB", 1 ){
+
+	}
+
+	const std::string getDefaultLocation();
+	uint64 parseBodyNode( const YAML::Node& node );
+};
+
+const std::string GuildSkillTreeDatabase::getDefaultLocation(){
+	return std::string(db_path) + "/guild_skill_tree.yml";
+}
+
+uint64 GuildSkillTreeDatabase::parseBodyNode( const YAML::Node &node ){
+	std::string name;
+
+	if( !this->asString( node, "Id", name ) ){
+		return 0;
+	}
+
+	uint16 skill_id;
+
+	if( !( skill_id = skill_name2id( name.c_str() ) ) ){
+		this->invalidWarning( node["Id"], "Invalid guild skill name \"%s\", skipping.\n", name.c_str() );
+		return 0;
+	}
+
+	if( !SKILL_CHK_GUILD( skill_id ) ){
+		this->invalidWarning( node["Id"], "Guild skill \"%s\" with Id %u is out of the guild skill range [%u-%u], skipping.\n", name.c_str(), skill_id, GD_SKILLBASE, GD_MAX );
+		return 0;
+	}
+
+	std::shared_ptr<s_guild_skill_tree> skill = this->find( skill_id );
+	bool exists = skill != nullptr;
+
+	if( !exists ){
+		if( !this->nodeExists( node, "MaxLevel" ) ){
+			this->invalidWarning( node, "Missing node \"MaxLevel\", skipping.\n" );
+			return 0;
+		}
+
+		skill = std::make_shared<s_guild_skill_tree>();
+		skill->id = skill_id;
+	}
+
+	if( this->nodeExists( node, "MaxLevel" ) ){
+		uint16 level;
+
+		if( !this->asUInt16( node, "MaxLevel", level ) ){
+			return 0;
+		}
+
+		// Enable Guild's Glory when required for emblems
+		if( skill_id == GD_GLORYGUILD && battle_config.require_glory_guild && level == 0 ){
+			level = 1;
+		}
+
+		skill->max = level;
+	}
+
+	if( this->nodeExists( node, "Required" ) ){
+		for( const YAML::Node& requiredNode : node["Required"] ){
+			std::string requiredName;
+
+			if( !this->asString( requiredNode, "Id", requiredName ) ){
+				return 0;
+			}
+
+			uint16 requiredSkillId;
+
+			if( !( requiredSkillId = skill_name2id( requiredName.c_str() ) ) ){
+				this->invalidWarning( requiredNode["Id"], "Invalid required guild skill name \"%s\", skipping.\n", requiredName.c_str() );
+				return 0;
+			}
+
+			if( !SKILL_CHK_GUILD( requiredSkillId ) ){
+				this->invalidWarning( requiredNode["Id"], "Required guild skill \"%s\" with Id %u is out of the guild skill range [%u-%u], skipping.\n", requiredName.c_str(), requiredSkillId, GD_SKILLBASE, GD_MAX );
+				return 0;
+			}
+
+			std::shared_ptr<s_guild_skill_requirement> requirement = util::umap_find( skill->need, requiredSkillId );
+			bool requirement_exists = requirement != nullptr;
+
+			if( !requirement_exists ){
+				if( !this->nodeExists( requiredNode, "Level" ) ){
+					this->invalidWarning( requiredNode, "Missing node \"Level\", skipping.\n" );
+					return 0;
+				}
+
+				requirement = std::make_shared<s_guild_skill_requirement>();
+				requirement->id = requiredSkillId;
+			}
+
+			if( this->nodeExists( requiredNode, "Level" ) ){
+				uint16 requiredLevel;
+
+				if( !this->asUInt16( requiredNode, "Level", requiredLevel ) ){
+					return 0;
+				}
+
+				if( requiredLevel == 0 ){
+					continue;
+				}
+
+				requirement->lv = requiredLevel;
+			}
+
+			if( !requirement_exists ){
+				skill->need[requiredSkillId] = requirement;
+			}
+		}
+	}
+
+	if( !exists ){
+		this->put( skill_id, skill );
+	}
+
+	return 1;
+}
+
+GuildSkillTreeDatabase guild_skill_tree_db;
 
 TIMER_FUNC(guild_payexp_timer);
 static TIMER_FUNC(guild_send_xy_timer);
@@ -68,7 +197,7 @@ struct npc_data **guild_flags;
 unsigned short guild_flags_count;
 
 /**
- * Get guild skill index in guild_skill_tree
+ * Get guild skill index in guild structure of mmo.hpp
  * @param skill_id
  * @return Index in skill_tree or -1
  **/
@@ -100,10 +229,14 @@ static TBL_PC* guild_sd_check(int guild_id, uint32 account_id, uint32 char_id) {
 }
 
 // Modified [Komurka]
-int guild_skill_get_max (int id) {
-	if ((id = guild_skill_get_index(id)) < 0)
+uint16 guild_skill_get_max( uint16 id ){
+	std::shared_ptr<s_guild_skill_tree> skill = guild_skill_tree_db.find( id );
+
+	if( skill == nullptr ){
 		return 0;
-	return guild_skill_tree[id].max;
+	}
+
+	return skill->max;
 }
 
 // Retrieve skill_lv learned by guild
@@ -114,54 +247,28 @@ int guild_checkskill(struct guild *g, int id) {
 }
 
 /*==========================================
- * guild_skill_tree.txt reading - from jA [Komurka]
+ * Guild skill check - from jA [Komurka]
  *------------------------------------------*/
-static bool guild_read_guildskill_tree_db(char* split[], int columns, int current) {// <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>
-	int k, skill_id = atoi(split[0]);
-	short idx = -1;
-
-	if ((idx = guild_skill_get_index(skill_id)) < 0) {
-		ShowError("guild_read_guildskill_tree_db: Invalid Guild skill '%s'.\n", split[1]);
+bool guild_check_skill_require( struct guild *g, uint16 id ){
+	if( g == nullptr ){
 		return false;
 	}
 
-	guild_skill_tree[idx].id = skill_id;
-	guild_skill_tree[idx].max = atoi(split[1]);
+	std::shared_ptr<s_guild_skill_tree> skill = guild_skill_tree_db.find( id );
 
-	if( guild_skill_tree[idx].id == GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[idx].max == 0 ) 	{// enable guild's glory when required for emblems
-		guild_skill_tree[idx].max = 1;
+	if( skill == nullptr ){
+		return false;
 	}
 
-	for( k = 0; k < MAX_GUILD_SKILL_REQUIRE; k++ ) 	{
-		guild_skill_tree[idx].need[k].id = atoi(split[k*2+2]);
-		guild_skill_tree[idx].need[k].lv = atoi(split[k*2+3]);
+	for( const auto& pair : skill->need ){
+		if( pair.second->lv > guild_checkskill( g, pair.second->id ) ){
+			return false;
+		}
 	}
 
 	return true;
 }
 
-/*==========================================
- * Guild skill check - from jA [Komurka]
- *------------------------------------------*/
-int guild_check_skill_require(struct guild *g,int id) {
-	uint8 i;
-	short idx = -1;
-
-	if(g == NULL)
-		return 0;
-
-	if ((idx = guild_skill_get_index(id)) < 0)
-		return 0;
-
-	for(i=0;i<MAX_GUILD_SKILL_REQUIRE;i++)
-	{
-		if(guild_skill_tree[idx].need[i].id == 0) break;
-		if(guild_skill_tree[idx].need[i].lv > guild_checkskill(g,guild_skill_tree[idx].need[i].id))
-			return 0;
-	}
-	return 1;
-}
-
 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]);
@@ -2314,20 +2421,19 @@ void do_init_guild(void) {
 	expcache_ers = ers_new(sizeof(struct guild_expcache),"guild.cpp::expcache_ers",ERS_OPT_NONE);
 
 	guild_flags_count = 0;
-
-	memset(guild_skill_tree,0,sizeof(guild_skill_tree));
 	
 	for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
-		int n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
+		uint8 n1 = (uint8)(strlen(db_path)+strlen(dbsubpath[i])+1);
 		char* dbsubpath1 = (char*)aMalloc(n1+1);
-		safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);
+		safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
 		
 		sv_readdb(dbsubpath1, "castle_db.txt", ',', 4, 4, -1, &guild_read_castledb, i > 0);
-		sv_readdb(dbsubpath1, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, &guild_read_guildskill_tree_db, i > 0); //guild skill tree [Komurka]
-		
+
 		aFree(dbsubpath1);
 	}
-	
+
+	guild_skill_tree_db.load();
+
 	add_timer_func_list(guild_payexp_timer,"guild_payexp_timer");
 	add_timer_func_list(guild_send_xy_timer, "guild_send_xy_timer");
 	add_timer_interval(gettick()+GUILD_PAYEXP_INTERVAL,guild_payexp_timer,0,0,GUILD_PAYEXP_INTERVAL);

+ 2 - 2
src/map/guild.hpp

@@ -26,10 +26,10 @@ struct guardian_data {
 	struct guild_castle* castle;
 };
 
-int guild_skill_get_max(int id);
+uint16 guild_skill_get_max(uint16 id);
 
 int guild_checkskill(struct guild *g,int id);
-int guild_check_skill_require(struct guild *g,int id); // [Komurka]
+bool guild_check_skill_require(struct guild *g,uint16 id); // [Komurka]
 int guild_checkcastles(struct guild *g); // [MouseJstr]
 bool guild_isallied(int guild_id, int guild_id2); //Checks alliance based on guild Ids. [Skotlex]
 

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

@@ -301,7 +301,7 @@
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\elemental_skill_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\elemental_skill_db.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\exp_guild.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\exp_guild.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\exp_homun.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\exp_homun.txt')" />
-    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\guild_skill_tree.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\guild_skill_tree.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\guild_skill_tree.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\guild_skill_tree.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\homun_skill_tree.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homun_skill_tree.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\homunculus_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homunculus_db.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\instance_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\instance_db.txt')" />

+ 50 - 1
src/tool/csv2yaml.cpp

@@ -36,12 +36,19 @@ int getch( void ){
 }
 #endif
 
+// Required constant and structure definitions
+#define MAX_GUILD_SKILL_REQUIRE 5
+
+// Forward declaration of conversion functions
+static bool guild_read_guildskill_tree_db( char* split[], int columns, int current );
+
 bool fileExists( const std::string& path );
 bool writeToFile( const YAML::Node& node, const std::string& path );
 void prepareHeader( YAML::Node& node, const std::string& type, uint32 version );
 bool askConfirmation( const char* fmt, ... );
 
 YAML::Node body;
+size_t counter;
 
 template<typename Func>
 bool process( const std::string& type, uint32 version, const std::vector<std::string>& paths, const std::string& name, Func lambda ){
@@ -59,7 +66,7 @@ bool process( const std::string& type, uint32 version, const std::vector<std::st
 
 			prepareHeader( root, type, version );
 			body.reset();
-
+			counter = 0;
 			
 			if( !lambda( path, name_ext ) ){
 				return false;
@@ -91,6 +98,17 @@ int do_init( int argc, char** argv ){
 	const std::string path_db_mode = path_db + "/" + DBPATH;
 	const std::string path_db_import = path_db + "/" + DBIMPORT;
 
+	std::vector<std::string> guild_skill_tree_paths = {
+		path_db,
+		path_db_import
+	};
+
+	if( process( "GUILD_SKILL_TREE_DB", 1, guild_skill_tree_paths, "guild_skill_tree", []( const std::string& path, const std::string& name_ext ) -> bool {
+		return sv_readdb( path.c_str(), name_ext.c_str(), ',', 2 + MAX_GUILD_SKILL_REQUIRE * 2, 2 + MAX_GUILD_SKILL_REQUIRE * 2, -1, &guild_read_guildskill_tree_db, false );
+	} ) ){
+		return 0;
+	}
+
 	// TODO: add implementations ;-)
 
 	return 0;
@@ -163,3 +181,34 @@ bool askConfirmation( const char* fmt, ... ){
 		return false;
 	}
 }
+
+// Implementation of the conversion functions
+
+// Copied and adjusted from guild.cpp
+// <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>
+static bool guild_read_guildskill_tree_db( char* split[], int columns, int current ){
+	YAML::Node node;
+
+	node["Id"] = (uint16)atoi(split[0]);
+	node["MaxLevel"] = (uint16)atoi(split[1]);
+
+	for( int i = 0, j = 0; i < MAX_GUILD_SKILL_REQUIRE; i++ ){
+		uint16 skill_id = atoi( split[i * 2 + 2] );
+		uint16 skill_level = atoi( split[i * 2 + 3] );
+
+		if( skill_id == 0 || skill_level == 0 ){
+			continue;
+		}
+
+		YAML::Node req;
+
+		req["Id"] = skill_id;
+		req["Level"] = skill_level;
+
+		node["Required"][j++] = req;
+	}
+
+	body[counter++] = node;
+
+	return true;
+}