From 81e7d8ef890ee24b53e05c855f01996bd90b4424 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Sat, 21 Nov 2020 01:05:07 +0100 Subject: [PATCH] Converted penalty db to YAML (#5562) Fixes #5463 Added penalty for MVP exp and MVP drops Removed penalty support for monster classes Thanks to @attackjom and @aleos89 --- db/import-tmpl/level_penalty.txt | 14 --- db/import-tmpl/level_penalty.yml | 33 ++++++ db/level_penalty.yml | 39 +++++++ db/re/level_penalty.txt | 60 ---------- db/re/level_penalty.yml | 99 +++++++++++++++++ doc/yaml/db/level_penalty.yml | 12 ++ src/map/atcommand.cpp | 14 ++- src/map/map-server.vcxproj | 2 +- src/map/mob.cpp | 23 +++- src/map/party.cpp | 2 +- src/map/pc.cpp | 185 +++++++++++++++++++++---------- src/map/pc.hpp | 29 ++++- src/map/script_constants.hpp | 6 + src/tool/csv2yaml.cpp | 81 ++++++++++++++ 14 files changed, 455 insertions(+), 144 deletions(-) delete mode 100644 db/import-tmpl/level_penalty.txt create mode 100644 db/import-tmpl/level_penalty.yml create mode 100644 db/level_penalty.yml delete mode 100644 db/re/level_penalty.txt create mode 100644 db/re/level_penalty.yml create mode 100644 doc/yaml/db/level_penalty.yml diff --git a/db/import-tmpl/level_penalty.txt b/db/import-tmpl/level_penalty.txt deleted file mode 100644 index 026114e12f..0000000000 --- a/db/import-tmpl/level_penalty.txt +++ /dev/null @@ -1,14 +0,0 @@ -// Experience & Drop Rate Modifier Database -// -// Structure of Database: -// Type,Class,Level difference,Rate -// -// TYPE: -// 1=experience, 2=item drop -// CLASS: -// 0=Normal monsters, 1=Boss monsters, 2=Guardians -// -// Note: RENEWAL_DROP and/or RENEWAL_EXP must be enabled. - -// EXP modifiers due to level difference - diff --git a/db/import-tmpl/level_penalty.yml b/db/import-tmpl/level_penalty.yml new file mode 100644 index 0000000000..46402607a7 --- /dev/null +++ b/db/import-tmpl/level_penalty.yml @@ -0,0 +1,33 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +########################################################################### +# Level Penalty Database +########################################################################### +# +# Level Penalty Settings +# +########################################################################### +# - Type: Type of Penalty (Exp, Drop, Mvp_Exp, Mvp_Drop) +# LevelDifferences: List of level difference between player and monster +# - Difference: Level difference between player and monster +# Rate: Rate applied to original exp or drop rate (0-10000) +########################################################################### + +Header: + Type: PENALTY_DB + Version: 1 diff --git a/db/level_penalty.yml b/db/level_penalty.yml new file mode 100644 index 0000000000..24a6fb5756 --- /dev/null +++ b/db/level_penalty.yml @@ -0,0 +1,39 @@ +# 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 . +# +########################################################################### +# Level Penalty Database +########################################################################### +# +# Level Penalty Settings +# +########################################################################### +# - Type: Type of Penalty (Exp, Drop, Mvp_Exp, Mvp_Drop) +# LevelDifferences: List of level difference between player and monster +# - Difference: Level difference between player and monster +# Rate: Rate applied to original exp or drop rate (0-10000) +########################################################################### + +Header: + Type: PENALTY_DB + Version: 1 + +Footer: + Imports: + - Path: db/re/level_penalty.yml + Mode: Renewal + - Path: db/import/level_penalty.yml diff --git a/db/re/level_penalty.txt b/db/re/level_penalty.txt deleted file mode 100644 index 3d93079401..0000000000 --- a/db/re/level_penalty.txt +++ /dev/null @@ -1,60 +0,0 @@ -// Experience & Drop Rate Modifier Database -// -// Structure of Database: -// Type,Class,Level difference,Rate -// -// TYPE: -// 1=experience, 2=item drop -// CLASS: -// 0=Normal monsters, 1=Boss monsters, 2=Guardians -// -// Note: RENEWAL_DROP and/or RENEWAL_EXP must be enabled. - -// EXP modifiers due to level difference -1,CLASS_NORMAL,16,40 -1,CLASS_NORMAL,15,115 -1,CLASS_NORMAL,14,120 -1,CLASS_NORMAL,13,125 -1,CLASS_NORMAL,12,130 -1,CLASS_NORMAL,11,135 -1,CLASS_NORMAL,10,140 -1,CLASS_NORMAL,9,135 -1,CLASS_NORMAL,8,130 -1,CLASS_NORMAL,7,125 -1,CLASS_NORMAL,6,120 -1,CLASS_NORMAL,5,115 -1,CLASS_NORMAL,4,110 -1,CLASS_NORMAL,3,105 -1,CLASS_NORMAL,0,100 -1,CLASS_NORMAL,-1,100 -1,CLASS_NORMAL,-6,95 -1,CLASS_NORMAL,-11,90 -1,CLASS_NORMAL,-16,85 -1,CLASS_NORMAL,-21,60 -1,CLASS_NORMAL,-26,35 -1,CLASS_NORMAL,-31,10 - -// Boss Type -1,CLASS_BOSS,0,100 - -// Guardian Type -1,CLASS_GUARDIAN,0,100 - -// Drop rate modifiers due to level difference -2,CLASS_NORMAL,16,50 -2,CLASS_NORMAL,13,60 -2,CLASS_NORMAL,10,70 -2,CLASS_NORMAL,7,80 -2,CLASS_NORMAL,4,90 -2,CLASS_NORMAL,0,100 -2,CLASS_NORMAL,-4,90 -2,CLASS_NORMAL,-7,80 -2,CLASS_NORMAL,-10,70 -2,CLASS_NORMAL,-13,60 -2,CLASS_NORMAL,-16,50 - -// Boss Type -2,CLASS_BOSS,0,100 - -// Guardian Type -2,CLASS_GUARDIAN,0,100 diff --git a/db/re/level_penalty.yml b/db/re/level_penalty.yml new file mode 100644 index 0000000000..9d8bf09357 --- /dev/null +++ b/db/re/level_penalty.yml @@ -0,0 +1,99 @@ +# 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 . +# +########################################################################### +# Level Penalty Database +########################################################################### +# +# Level Penalty Settings +# +########################################################################### +# - Type: Type of Penalty (Exp, Drop, Mvp_Exp, Mvp_Drop) +# LevelDifferences: List of level difference between player and monster +# - Difference: Level difference between player and monster +# Rate: Rate applied to original exp or drop rate (0-10000) +########################################################################### + +Header: + Type: PENALTY_DB + Version: 1 + +Body: + - Type: Exp + LevelDifferences: + - Difference: 16 + Rate: 40 + - Difference: 15 + Rate: 115 + - Difference: 14 + Rate: 120 + - Difference: 13 + Rate: 125 + - Difference: 12 + Rate: 130 + - Difference: 11 + Rate: 135 + - Difference: 10 + Rate: 140 + - Difference: 9 + Rate: 135 + - Difference: 8 + Rate: 130 + - Difference: 7 + Rate: 125 + - Difference: 6 + Rate: 120 + - Difference: 5 + Rate: 115 + - Difference: 4 + Rate: 110 + - Difference: 3 + Rate: 105 + - Difference: -6 + Rate: 95 + - Difference: -11 + Rate: 90 + - Difference: -16 + Rate: 85 + - Difference: -21 + Rate: 60 + - Difference: -26 + Rate: 35 + - Difference: -31 + Rate: 10 + - Type: Drop + LevelDifferences: + - Difference: 16 + Rate: 50 + - Difference: 13 + Rate: 60 + - Difference: 10 + Rate: 70 + - Difference: 7 + Rate: 80 + - Difference: 4 + Rate: 90 + - Difference: -4 + Rate: 90 + - Difference: -7 + Rate: 80 + - Difference: -10 + Rate: 70 + - Difference: -13 + Rate: 60 + - Difference: -16 + Rate: 50 diff --git a/doc/yaml/db/level_penalty.yml b/doc/yaml/db/level_penalty.yml new file mode 100644 index 0000000000..01f528c606 --- /dev/null +++ b/doc/yaml/db/level_penalty.yml @@ -0,0 +1,12 @@ +########################################################################### +# Level Penalty Database +########################################################################### +# +# Level Penalty Settings +# +########################################################################### +# - Type: Type of Penalty (Exp, Drop, Mvp_Exp, Mvp_Drop) +# LevelDifferences: List of level difference between player and monster +# - Difference: Level difference between player and monster +# Rate: Rate applied to original exp or drop rate (0-10000) +########################################################################### diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index d98703cea1..35b245f64f 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -7389,8 +7389,10 @@ ACMD_FUNC(mobinfo) } #ifdef RENEWAL_EXP if( battle_config.atcommand_mobinfo_type ) { - base_exp = base_exp * pc_level_penalty_mod(mob->lv - sd->status.base_level, mob->status.class_, mob->status.mode, 1) / 100; - job_exp = job_exp * pc_level_penalty_mod(mob->lv - sd->status.base_level, mob->status.class_, mob->status.mode, 1) / 100; + int penalty = pc_level_penalty_mod( sd, PENALTY_EXP, mob ); + + base_exp = base_exp * penalty / 100; + job_exp = job_exp * penalty / 100; } #endif // stats @@ -7415,6 +7417,10 @@ ACMD_FUNC(mobinfo) clif_displaymessage(fd, msg_txt(sd,1245)); // Drops: strcpy(atcmd_output, " "); j = 0; +#ifdef RENEWAL_DROP + int penalty = pc_level_penalty_mod( sd, PENALTY_DROP, mob ); +#endif + for (i = 0; i < MAX_MOB_DROP_TOTAL; i++) { int droprate; if (mob->dropitem[i].nameid == 0 || mob->dropitem[i].rate < 1 || (item_data = itemdb_exists(mob->dropitem[i].nameid)) == NULL) @@ -7423,7 +7429,7 @@ ACMD_FUNC(mobinfo) #ifdef RENEWAL_DROP if( battle_config.atcommand_mobinfo_type ) { - droprate = droprate * pc_level_penalty_mod(mob->lv - sd->status.base_level, mob->status.class_, mob->status.mode, 2) / 100; + droprate = droprate * penalty / 100; if (droprate <= 0 && !battle_config.drop_rate0item) droprate = 1; } @@ -7962,7 +7968,7 @@ ACMD_FUNC(whodrops) #ifdef RENEWAL_DROP if( battle_config.atcommand_mobinfo_type ) - dropchance = dropchance * pc_level_penalty_mod(mob_db(item_data->mob[j].id)->lv - sd->status.base_level, mob_db(item_data->mob[j].id)->status.class_, mob_db(item_data->mob[j].id)->status.mode, 2) / 100; + dropchance = dropchance * pc_level_penalty_mod( sd, PENALTY_DROP, mob_db( item_data->mob[j].id ) ) / 100; #endif if (pc_isvip(sd)) // Display item rate increase for VIP dropchance += (dropchance * battle_config.vip_drop_increase) / 100; diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index 5b455e0272..985b5d1143 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -330,7 +330,7 @@ - + diff --git a/src/map/mob.cpp b/src/map/mob.cpp index b760de598b..932895b4d9 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2713,7 +2713,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if(base_exp || job_exp) { if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) { #ifdef RENEWAL_EXP - int rate = pc_level_penalty_mod(md->level - tmpsd[i]->status.base_level, md->status.class_, md->status.mode, 1); + int rate = pc_level_penalty_mod( tmpsd[i], PENALTY_EXP, nullptr, md ); if (rate != 100) { if (base_exp) base_exp = (unsigned int)cap_value(apply_rate(base_exp, rate), 1, UINT_MAX); @@ -2748,10 +2748,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) struct item_data* it = NULL; int drop_rate; #ifdef RENEWAL_DROP - int drop_modifier = mvp_sd ? pc_level_penalty_mod(md->level - mvp_sd->status.base_level, md->status.class_, md->status.mode, 2) : - second_sd ? pc_level_penalty_mod(md->level - second_sd->status.base_level, md->status.class_, md->status.mode, 2): - third_sd ? pc_level_penalty_mod(md->level - third_sd->status.base_level, md->status.class_, md->status.mode, 2) : - 100; // No player was attached, we don't use any modifier (100 = rates are not touched) + int drop_modifier = pc_level_penalty_mod( mvp_sd != nullptr ? mvp_sd : second_sd != nullptr ? second_sd : third_sd, PENALTY_DROP, nullptr, md ); #endif dlist->m = md->bl.m; dlist->x = md->bl.x; @@ -2931,6 +2928,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) exp =1; else { exp = md->db->mexp; + +#if defined(RENEWAL_EXP) + int penalty = pc_level_penalty_mod( mvp_sd, PENALTY_MVP_EXP, nullptr, md ); + + exp = cap_value( apply_rate( exp, penalty ), 0, MAX_EXP ); +#endif + if (count > 1) exp += exp*(battle_config.exp_bonus_attacker*(count-1))/100.; //[Gengar] } @@ -2968,6 +2972,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } } +#if defined(RENEWAL_DROP) + int penalty = pc_level_penalty_mod( mvp_sd, PENALTY_MVP_DROP, nullptr, md ); +#endif + for(i = 0; i < MAX_MVP_DROP_TOTAL; i++) { struct item_data *i_data; @@ -2975,6 +2983,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) continue; temp = mdrop[i].rate; + +#if defined(RENEWAL_DROP) + temp = cap_value( apply_rate( temp, penalty ), 0, 10000 ); +#endif + if (temp != 10000) { if(temp <= 0 && !battle_config.drop_rate0item) temp = 1; diff --git a/src/map/party.cpp b/src/map/party.cpp index 30afb9c8ca..3e4b922dbe 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -1115,7 +1115,7 @@ void party_exp_share(struct party_data* p, struct block_list* src, unsigned int #ifdef RENEWAL_EXP uint32 base_gained = base_exp, job_gained = job_exp; if (base_exp || job_exp) { - int rate = pc_level_penalty_mod(md->level - sd[i]->status.base_level, md->db->status.class_, md->db->status.mode, 1); + int rate = pc_level_penalty_mod( sd[i], PENALTY_EXP, nullptr, md ); if (rate != 100) { if (base_exp) base_gained = (unsigned int)cap_value(apply_rate(base_exp, rate), 1, UINT_MAX); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 865eec74f3..24b1739759 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -67,9 +67,6 @@ static inline bool pc_attendance_rewarded_today( struct map_session_data* sd ); #define PVP_CALCRANK_INTERVAL 1000 // PVP calculation interval static unsigned int statp[MAX_LEVEL+1]; -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -static unsigned int level_penalty[3][CLASS_MAX][MAX_LEVEL*2+1]; -#endif // h-files are for declarations, not for implementations... [Shinomori] struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE]; @@ -267,6 +264,105 @@ uint64 AttendanceDatabase::parseBodyNode(const YAML::Node &node){ AttendanceDatabase attendance_db; +const std::string PenaltyDatabase::getDefaultLocation(){ + return std::string( db_path ) + "/level_penalty.yml"; +} + +uint64 PenaltyDatabase::parseBodyNode( const YAML::Node& node ){ + std::string type_constant; + + if( !this->asString( node, "Type", type_constant ) ){ + return 0; + } + + int64 constant_value; + + if( !script_get_constant( ( "PENALTY_" + type_constant ).c_str(), &constant_value ) ){ + this->invalidWarning( node["Type"], "Unknown penalty type \"%s\".\n", type_constant.c_str() ); + return 0; + } + + if( constant_value < PENALTY_NONE || constant_value > PENALTY_MAX ){ + this->invalidWarning( node["Type"], "Invalid penalty type \"%s\".\n", type_constant.c_str() ); + return 0; + } + + e_penalty_type type = static_cast( constant_value ); + + std::shared_ptr penalty = this->find( type ); + bool exists = penalty != nullptr; + + if( !exists ){ + penalty = std::make_shared(); + penalty->type = type; + + for( int i = 0, max = ARRAYLENGTH( penalty->rate ); i < max; i++ ){ + penalty->rate[i] = UINT16_MAX; + } + } + + if( this->nodeExists( node, "LevelDifferences" ) ){ + for( const YAML::Node& levelNode : node["LevelDifferences"] ){ + if( !this->nodesExist( levelNode, { "Difference", "Rate" } ) ){ + return 0; + } + + int32 difference; + + if( !this->asInt32( levelNode, "Difference", difference ) ){ + return 0; + } + + if( std::abs( difference ) > MAX_LEVEL ){ + this->invalidWarning( levelNode["Difference"], "Level difference %d is bigger than maximum level %d.\n", difference, MAX_LEVEL ); + return 0; + } + + uint16 rate; + + if( !this->asUInt16Rate( levelNode, "Rate", rate ) ){ + return 0; + } + + penalty->rate[difference + MAX_LEVEL - 1] = rate; + } + } + + if( !exists ){ + this->put( type, penalty ); + } + + return 1; +} + +void PenaltyDatabase::loadingFinished(){ + for( const auto& pair : *this ){ + for( int i = MAX_LEVEL - 1, max = ARRAYLENGTH( pair.second->rate ), last_rate = 100; i < max; i++ ){ + uint16 rate = pair.second->rate[i]; + + // Check if it has been defined + if( rate == UINT16_MAX ){ + pair.second->rate[i] = last_rate; + }else{ + last_rate = rate; + } + } + + for( int i = MAX_LEVEL - 1, last_rate = 100; i >= 0; i-- ){ + uint16 rate = pair.second->rate[i]; + + // Check if it has been defined + if( rate == UINT16_MAX ){ + pair.second->rate[i] = last_rate; + }else{ + last_rate = rate; + } + } + } +} + +PenaltyDatabase penalty_db; + #define MOTD_LINE_SIZE 128 static char motd_text[MOTD_LINE_SIZE][CHAT_SIZE_MAX]; // Message of the day buffer [Valaris] @@ -11727,20 +11823,36 @@ void pc_delspiritcharm(struct map_session_data *sd, int count, int type) * @param type: 1 - EXP, 2 - Item Drop * @return Penalty rate */ -int pc_level_penalty_mod(int level_diff, uint32 mob_class, enum e_mode mode, int type) -{ - int rate = 100; +uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, struct mob_db* mob, mob_data* md ){ + // No player was attached, we don't use any modifier (100 = rates are not touched) + if( sd == nullptr ){ + return 100; + } - if (type == 2 && (mode&MD_FIXED_ITEMDROP)) - return rate; + int monster_level; - if (level_diff < 0) - level_diff = MAX_LEVEL + (~level_diff + 1); + if( md != nullptr ){ + monster_level = md->level; + mob = md->db; + }else if( mob != nullptr ){ + monster_level = mob->lv; + }else{ + return 100; + } - if ((rate = level_penalty[type][mob_class][level_diff]) > 0) // Monster class found, return rate - return rate; + if( ( type == PENALTY_DROP || type == PENALTY_MVP_DROP ) && status_has_mode( &mob->status, MD_FIXED_ITEMDROP ) ){ + return 100; + } - return 100; // Penalty not found, return default + int level_difference = monster_level - sd->status.base_level; + + std::shared_ptr penalty = penalty_db.find( type ); + + if( penalty != nullptr ){ + return penalty->rate[ level_difference + MAX_LEVEL - 1 ]; + }else{ + return 100; + } } #endif @@ -11897,35 +12009,6 @@ static bool pc_readdb_skilltree(char* fields[], int columns, int current) } return true; } -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) -{ - int type, class_, diff; - - type = atoi(fields[0]); //1=experience, 2=item drop - class_ = atoi(fields[1]); - diff = atoi(fields[2]); - - if( type != 1 && type != 2 ){ - ShowWarning("pc_readdb_levelpenalty: Invalid type %d specified.\n", type); - return false; - } - - if( !CHK_CLASS(class_) ){ - ShowWarning("pc_readdb_levelpenalty: Invalid class %d specified.\n", class_); - return false; - } - - diff = min(diff, MAX_LEVEL); - - if( diff < 0 ) - diff = min(MAX_LEVEL + ( ~(diff) + 1 ), MAX_LEVEL*2); - - level_penalty[type][class_][diff] = atoi(fields[3]); - - return true; -} -#endif /** [Cydh] * Calculates base hp of player. Reference: http://irowiki.org/wiki/Max_HP @@ -12303,22 +12386,7 @@ void pc_readdb(void) { memset(job_info,0,sizeof(job_info)); // job_info table #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) - sv_readdb(db_path, DBPATH "level_penalty.txt", ',', 4, 4, -1, &pc_readdb_levelpenalty, 0); - sv_readdb(db_path, DBIMPORT"/level_penalty.txt", ',', 4, 4, -1, &pc_readdb_levelpenalty, 1); - for( k=1; k < 3; k++ ){ // fill in the blanks - int j; - for( j = 0; j < CLASS_ALL; j++ ){ - int tmp = 0; - for( i = 0; i < MAX_LEVEL*2; i++ ){ - if( i == MAX_LEVEL+1 ) - tmp = level_penalty[k][j][0];// reset - if( level_penalty[k][j][i] > 0 ) - tmp = level_penalty[k][j][i]; - else - level_penalty[k][j][i] = tmp; - } - } - } + penalty_db.load(); #endif // reset then read statspoint @@ -13576,6 +13644,7 @@ void do_final_pc(void) { ers_destroy(str_reg_ers); attendance_db.clear(); + penalty_db.clear(); } void do_init_pc(void) { diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 26be10ef76..7201a16e61 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -7,6 +7,8 @@ #include #include +#include "../common/cbasetypes.hpp" +#include "../common/database.hpp" #include "../common/mmo.hpp" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus #include "../common/strlib.hpp"// StringBuf #include "../common/timer.hpp" @@ -895,6 +897,31 @@ enum item_check { ITMCHK_ALL = ITMCHK_INVENTORY|ITMCHK_CART|ITMCHK_STORAGE, }; +enum e_penalty_type : uint16{ + PENALTY_NONE, + PENALTY_EXP, + PENALTY_DROP, + PENALTY_MVP_EXP, + PENALTY_MVP_DROP, + PENALTY_MAX +}; + +struct s_penalty{ + e_penalty_type type; + uint16 rate[MAX_LEVEL * 2 - 1]; +}; + +class PenaltyDatabase : public TypesafeYamlDatabase { +public: + PenaltyDatabase() : TypesafeYamlDatabase( "PENALTY_DB", 1 ){ + + } + + const std::string getDefaultLocation(); + uint64 parseBodyNode(const YAML::Node& node); + void loadingFinished(); +}; + struct s_job_info { unsigned int base_hp[MAX_LEVEL], base_sp[MAX_LEVEL]; //Storage for the first calculation with hp/sp factor and multiplicator int hp_factor, hp_multiplicator, sp_factor; @@ -1420,7 +1447,7 @@ void pc_show_questinfo_reinit(struct map_session_data *sd); bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv); #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -int pc_level_penalty_mod(int level_diff, uint32 mob_class, enum e_mode mode, int type); +uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, struct mob_db* mob, mob_data* md = nullptr ); #endif bool pc_attendance_enabled(); diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 43a3832f78..bde50acda5 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -7981,6 +7981,12 @@ export_constant(DROPEFFECT_ORANGE_PILLAR); export_constant(DROPEFFECT_MAX); + /* penalty types */ + export_constant(PENALTY_EXP); + export_constant(PENALTY_DROP); + export_constant(PENALTY_MVP_EXP); + export_constant(PENALTY_MVP_DROP); + #undef export_constant #undef export_constant2 #undef export_parameter diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp index d639028ad1..ee4750f30c 100644 --- a/src/tool/csv2yaml.cpp +++ b/src/tool/csv2yaml.cpp @@ -87,6 +87,8 @@ std::unordered_map skill_unit; std::unordered_map skill_copyable; std::unordered_map skill_nearnpc; +static unsigned int level_penalty[3][CLASS_MAX][MAX_LEVEL * 2 + 1]; + struct s_item_flag_csv2yaml { bool buyingstore, dead_branch, group, guid, broadcast, bindOnEquip, delay_consume; e_item_drop_effect dropEffect; @@ -215,6 +217,8 @@ static bool itemdb_read_db(const char *file); static bool itemdb_read_randomopt(const char* file); 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(); // Constants for conversion std::unordered_map aegis_itemnames; @@ -537,6 +541,22 @@ int do_init( int argc, char** argv ){ return 0; } +#ifdef RENEWAL + memset( level_penalty, 0, sizeof( level_penalty ) ); + if (!process("PENALTY_DB", 1, { path_db_mode }, "level_penalty", [](const std::string& path, const std::string& name_ext) -> bool { + return sv_readdb(path.c_str(), name_ext.c_str(), ',', 4, 4, -1, &pc_readdb_levelpenalty, false) && pc_levelpenalty_yaml(); + })) { + return 0; + } + + memset( level_penalty, 0, sizeof( level_penalty ) ); + if (!process("PENALTY_DB", 1, { path_db_import }, "level_penalty", [](const std::string& path, const std::string& name_ext) -> bool { + return sv_readdb(path.c_str(), name_ext.c_str(), ',', 4, 4, -1, &pc_readdb_levelpenalty, false) && pc_levelpenalty_yaml(); + })) { + return 0; + } +#endif + // TODO: add implementations ;-) return 0; @@ -3538,6 +3558,67 @@ static bool itemdb_randomopt_group_yaml(void) { return true; } +static bool pc_readdb_levelpenalty( char* fields[], int columns, int current ){ + // 1=experience, 2=item drop + int type = atoi( fields[0] ); + + if( type != 1 && type != 2 ){ + ShowWarning( "pc_readdb_levelpenalty: Invalid type %d specified.\n", type ); + return false; + } + + int64 val = constant_lookup_int( fields[1] ); + + if( val == -100 ){ + ShowWarning("pc_readdb_levelpenalty: Unknown class constant %s specified.\n", fields[1] ); + return false; + } + + int class_ = atoi( fields[1] ); + + if( !CHK_CLASS( class_ ) ){ + ShowWarning( "pc_readdb_levelpenalty: Invalid class %d specified.\n", class_ ); + return false; + } + + int diff = atoi( fields[2] ); + + if( std::abs( diff ) > MAX_LEVEL ){ + ShowWarning( "pc_readdb_levelpenalty: Level difference %d is too high.\n", diff ); + return false; + } + + diff += MAX_LEVEL - 1; + + level_penalty[type][class_][diff] = atoi(fields[3]); + + return true; +} + +void pc_levelpenalty_yaml_sub( int type, const std::string& name ){ + body << YAML::BeginMap; + body << YAML::Key << "Type" << YAML::Value << name; + body << YAML::Key << "LevelDifferences"; + body << YAML::BeginSeq; + for( int i = ARRAYLENGTH( level_penalty[type][CLASS_NORMAL] ); i >= 0; i-- ){ + if( level_penalty[type][CLASS_NORMAL][i] > 0 && level_penalty[type][CLASS_NORMAL][i] != 100 ){ + body << YAML::BeginMap; + body << YAML::Key << "Difference" << YAML::Value << ( i - MAX_LEVEL + 1 ); + body << YAML::Key << "Rate" << YAML::Value << level_penalty[type][CLASS_NORMAL][i]; + body << YAML::EndMap; + } + } + body << YAML::EndSeq; + body << YAML::EndMap; +} + +bool pc_levelpenalty_yaml(){ + pc_levelpenalty_yaml_sub( 1, "Exp" ); + pc_levelpenalty_yaml_sub( 2, "Drop" ); + + return true; +} + // Initialize Random Option constants void init_random_option_constants() { #define export_constant2(a, b) script_set_constant_(a, b, a, false, false)