From df7cccaa5638cfb3b94dfce5857ee219da97292e Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Sun, 19 Sep 2021 23:22:43 +0200 Subject: [PATCH] Fixed autobonus on the same equip slot (#6257) Fixes #2079 Thanks to @LunarSHINING for reporting and testing Thanks to @Tokeiburu for the initial report Thanks to @Atemo and @aleos89 for reviewing --- src/map/pc.cpp | 89 +++++++++++++++++++++++++++++++--------------- src/map/pc.hpp | 3 +- src/map/script.cpp | 9 ----- 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 69203de66a..f03e8de2ac 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -2760,6 +2760,23 @@ static void pc_bonus_item_drop(std::vector &drop, t_itemid nameid, u drop.push_back(entry); } +s_autobonus::~s_autobonus(){ + if( this->active != INVALID_TIMER ){ + delete_timer( this->active, pc_endautobonus ); + this->active = INVALID_TIMER; + } + + if( this->bonus_script != nullptr ){ + aFree( this->bonus_script ); + this->bonus_script = nullptr; + } + + if( this->other_script != nullptr ){ + aFree( this->other_script ); + this->other_script = nullptr; + } +} + /** * Add autobonus to player when attacking/attacked * @param bonus: Bonus array @@ -2772,8 +2789,15 @@ static void pc_bonus_item_drop(std::vector &drop, t_itemid nameid, u * @param onskill: Skill used to trigger autobonus * @return True on success or false otherwise */ -bool pc_addautobonus(std::vector &bonus, const char *script, short rate, unsigned int dur, uint16 flag, const char *other_script, unsigned int pos, bool onskill) -{ +bool pc_addautobonus(std::vector &bonus, const char *script, short rate, unsigned int dur, uint16 flag, const char *other_script, unsigned int pos, bool onskill){ + // Check if the same bonus already exists + for( s_autobonus& autobonus : bonus ){ + // Compare based on position and bonus script + if( autobonus.pos == pos && strcmp( script, autobonus.bonus_script ) == 0 ){ + return false; + } + } + if (bonus.size() == MAX_PC_BONUS) { ShowWarning("pc_addautobonus: Reached max (%d) number of autobonus per character!\n", MAX_PC_BONUS); return false; @@ -2825,34 +2849,27 @@ void pc_delautobonus(struct map_session_data* sd, std::vector &bonu while( it != bonus.end() ){ s_autobonus b = *it; - if (b.active != INVALID_TIMER) { - if (restore && (sd->state.autobonus&b.pos) == b.pos) { - if (b.bonus_script) { - unsigned int equip_pos_idx = 0; + if( b.active != INVALID_TIMER && restore && b.bonus_script != nullptr ){ + unsigned int equip_pos_idx = 0; - // Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester] - for (uint8 j = 0; j < EQI_MAX; j++) { - if (sd->equip_index[j] >= 0) - equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip; - } + // Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester] + for (uint8 j = 0; j < EQI_MAX; j++) { + if (sd->equip_index[j] >= 0) + equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip; + } - if ((equip_pos_idx&b.pos) == b.pos) - script_run_autobonus(b.bonus_script, sd, b.pos); - } - - it++; - - continue; - } else { // Logout / Unequipped an item with an activated bonus - delete_timer(b.active, pc_endautobonus); - b.active = INVALID_TIMER; + if( ( equip_pos_idx&b.pos ) == b.pos ){ + script_run_autobonus(b.bonus_script, sd, b.pos); + }else{ + // Not all required items equipped anymore + restore = false; } } - if (b.bonus_script) - aFree(b.bonus_script); - if (b.other_script) - aFree(b.other_script); + if( restore ){ + it++; + continue; + } it = bonus.erase(it); } @@ -2885,7 +2902,6 @@ void pc_exeautobonus(struct map_session_data *sd, std::vector *bonu } autobonus->active = add_timer(gettick()+autobonus->duration, pc_endautobonus, sd->bl.id, (intptr_t)bonus); - sd->state.autobonus |= autobonus->pos; status_calc_pc(sd,SCO_FORCE); } @@ -2902,7 +2918,6 @@ TIMER_FUNC(pc_endautobonus){ for( struct s_autobonus& autobonus : *bonus ){ if( autobonus.active == tid ){ autobonus.active = INVALID_TIMER; - sd->state.autobonus &= ~autobonus.pos; break; } } @@ -10785,6 +10800,21 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswit return true; } +static void pc_deleteautobonus( std::vector& bonus, int position ){ + std::vector::iterator it = bonus.begin(); + + while( it != bonus.end() ){ + s_autobonus b = *it; + + if( ( b.pos & position ) != b.pos ){ + it++; + continue; + } + + it = bonus.erase( it ); + } +} + /** * Recalculate player status on unequip * @param sd: Player data @@ -10796,8 +10826,9 @@ static void pc_unequipitem_sub(struct map_session_data *sd, int n, int flag) { int i, iflag; bool status_calc = false; - if (sd->state.autobonus&sd->inventory.u.items_inventory[n].equip) - sd->state.autobonus &= ~sd->inventory.u.items_inventory[n].equip; //Check for activated autobonus [Inkfish] + pc_deleteautobonus( sd->autobonus, sd->inventory.u.items_inventory[n].equip ); + pc_deleteautobonus( sd->autobonus2, sd->inventory.u.items_inventory[n].equip ); + pc_deleteautobonus( sd->autobonus3, sd->inventory.u.items_inventory[n].equip ); sd->inventory.u.items_inventory[n].equip = 0; if (!(flag & 4)) diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 5a4f24955c..42a56ef566 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -240,6 +240,8 @@ struct s_autobonus { char *bonus_script, *other_script; int active; unsigned int pos; + + ~s_autobonus(); }; /// Timed bonus 'bonus_script' struct [Cydh] @@ -323,7 +325,6 @@ struct map_session_data { t_itemid autolootid[AUTOLOOTITEM_SIZE]; // [Zephyrus] unsigned short autoloottype; unsigned int autolooting : 1; //performance-saver, autolooting state for @alootid - unsigned int autobonus; //flag to indicate if an autobonus is activated. [Inkfish] unsigned int gmaster_flag : 1; unsigned int prevend : 1;//used to flag wheather you've spent 40sp to open the vending or not. unsigned int warping : 1;//states whether you're in the middle of a warp processing diff --git a/src/map/script.cpp b/src/map/script.cpp index 7fd6f6f5b8..7d034bf4e2 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -9636,9 +9636,6 @@ BUILDIN_FUNC(autobonus) else pos = sd->inventory.u.items_inventory[current_equip_item_index].equip; - if((sd->state.autobonus&pos) == pos) - return SCRIPT_CMD_SUCCESS; - rate = script_getnum(st,3); dur = script_getnum(st,4); bonus_script = script_getstr(st,2); @@ -9676,9 +9673,6 @@ BUILDIN_FUNC(autobonus2) else pos = sd->inventory.u.items_inventory[current_equip_item_index].equip; - if((sd->state.autobonus&pos) == pos) - return SCRIPT_CMD_SUCCESS; - rate = script_getnum(st,3); dur = script_getnum(st,4); bonus_script = script_getstr(st,2); @@ -9716,9 +9710,6 @@ BUILDIN_FUNC(autobonus3) else pos = sd->inventory.u.items_inventory[current_equip_item_index].equip; - if((sd->state.autobonus&pos) == pos) - return SCRIPT_CMD_SUCCESS; - rate = script_getnum(st,3); dur = script_getnum(st,4); if (script_isstring(st, 5)) {