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