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
This commit is contained in:
Lemongrass3110 2020-11-21 01:05:07 +01:00 committed by GitHub
parent c349c82f60
commit 81e7d8ef89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 455 additions and 144 deletions

View File

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

View File

@ -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 <http://www.gnu.org/licenses/>.
#
###########################################################################
# 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

39
db/level_penalty.yml Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#
###########################################################################
# 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

View File

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

99
db/re/level_penalty.yml Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#
###########################################################################
# 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

View File

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

View File

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

View File

@ -330,7 +330,7 @@
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\job_exp.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\job_exp.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\job_noenter_map.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\job_noenter_map.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\job_param_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\job_param_db.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\level_penalty.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\level_penalty.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\level_penalty.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\level_penalty.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\magicmushroom_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\magicmushroom_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\map_cache.dat" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\map_cache.dat')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\map_index.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\map_index.txt')" />

View File

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

View File

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

View File

@ -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<e_penalty_type>( constant_value );
std::shared_ptr<s_penalty> penalty = this->find( type );
bool exists = penalty != nullptr;
if( !exists ){
penalty = std::make_shared<s_penalty>();
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<s_penalty> 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) {

View File

@ -7,6 +7,8 @@
#include <memory>
#include <vector>
#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<uint16, s_penalty> {
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();

View File

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

View File

@ -87,6 +87,8 @@ std::unordered_map<uint16, s_skill_unit_csv> skill_unit;
std::unordered_map<uint16, s_skill_copyable> skill_copyable;
std::unordered_map<uint16, s_skill_db> 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<t_itemid, std::string> 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)