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
This commit is contained in:
Lemongrass3110 2021-09-19 23:22:43 +02:00 committed by GitHub
parent 54c2689bbd
commit df7cccaa56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 39 deletions

View File

@ -2760,6 +2760,23 @@ static void pc_bonus_item_drop(std::vector<s_add_drop> &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<s_add_drop> &drop, t_itemid nameid, u
* @param onskill: Skill used to trigger autobonus
* @return True on success or false otherwise
*/
bool pc_addautobonus(std::vector<s_autobonus> &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<s_autobonus> &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,9 +2849,7 @@ void pc_delautobonus(struct map_session_data* sd, std::vector<s_autobonus> &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) {
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]
@ -2836,23 +2858,18 @@ void pc_delautobonus(struct map_session_data* sd, std::vector<s_autobonus> &bonu
equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
}
if ((equip_pos_idx&b.pos) == b.pos)
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( restore ){
it++;
continue;
} else { // Logout / Unequipped an item with an activated bonus
delete_timer(b.active, pc_endautobonus);
b.active = INVALID_TIMER;
}
}
if (b.bonus_script)
aFree(b.bonus_script);
if (b.other_script)
aFree(b.other_script);
it = bonus.erase(it);
}
@ -2885,7 +2902,6 @@ void pc_exeautobonus(struct map_session_data *sd, std::vector<s_autobonus> *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<s_autobonus>& bonus, int position ){
std::vector<s_autobonus>::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))

View File

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

View File

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