Implements petautobonus script commands (#7053)

* Fixes #7038.
* Implements script commands: petautobonus, petautobonus2, and petautobonus3.
* This allows pets to utilize the same autobonus features that players can use without having to check for the equipped item position.
Thanks to @EditorFc's suggestion and @Lemongrass3110!
This commit is contained in:
Aleos 2022-09-16 12:46:53 -04:00 committed by GitHub
parent ee5ba2d889
commit f8cd4aa8c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 386 additions and 48 deletions

View File

@ -877,9 +877,9 @@ Body:
.@i = getpetinfo(PETINFO_INTIMATE); .@i = getpetinfo(PETINFO_INTIMATE);
if (.@i >= PET_INTIMATE_LOYAL) { if (.@i >= PET_INTIMATE_LOYAL) {
autobonus "{ bonus2 bSubEle,Ele_Neutral,2; heal 100,0; }",100,5000,BF_SHORT|BF_NORMAL; petautobonus "{ bonus2 bSubEle,Ele_Neutral,2; heal 100,0; }",100,5000,BF_SHORT|BF_NORMAL;
} else if (.@i >= PET_INTIMATE_CORDIAL) { } else if (.@i >= PET_INTIMATE_CORDIAL) {
autobonus "{ bonus2 bSubEle,Ele_Neutral,2; heal 100,0; }",100,3000,BF_SHORT|BF_NORMAL; petautobonus "{ bonus2 bSubEle,Ele_Neutral,2; heal 100,0; }",100,3000,BF_SHORT|BF_NORMAL;
} }
- Mob: MEDUSA - Mob: MEDUSA
TameItem: Splendid_Mirror TameItem: Splendid_Mirror
@ -1511,15 +1511,15 @@ Body:
if (.@i >= PET_INTIMATE_LOYAL) { if (.@i >= PET_INTIMATE_LOYAL) {
bonus bCritical,6; bonus bCritical,6;
bonus bHit,6; bonus bHit,6;
autobonus "{ bonus2 bHPRegenRate,500,1000; bonus2 bSPRegenRate,20,1000; }",30,5000,BF_WEAPON|BF_SHORT; petautobonus "{ bonus2 bHPRegenRate,500,1000; bonus2 bSPRegenRate,20,1000; }",30,5000,BF_WEAPON|BF_SHORT;
} else if (.@i >= PET_INTIMATE_CORDIAL) { } else if (.@i >= PET_INTIMATE_CORDIAL) {
bonus bCritical,5; bonus bCritical,5;
bonus bHit,5; bonus bHit,5;
autobonus "{ bonus2 bHPRegenRate,400,1000; bonus2 bSPRegenRate,10,1000; }",30,5000,BF_WEAPON|BF_SHORT; petautobonus "{ bonus2 bHPRegenRate,400,1000; bonus2 bSPRegenRate,10,1000; }",30,5000,BF_WEAPON|BF_SHORT;
} else if (.@i >= PET_INTIMATE_NEUTRAL) { } else if (.@i >= PET_INTIMATE_NEUTRAL) {
bonus bCritical,4; bonus bCritical,4;
bonus bHit,4; bonus bHit,4;
autobonus "{ bonus2 bHPRegenRate,300,1000; }",20,5000,BF_WEAPON|BF_SHORT; petautobonus "{ bonus2 bHPRegenRate,300,1000; }",20,5000,BF_WEAPON|BF_SHORT;
} else { } else {
bonus bCritical,3; bonus bCritical,3;
bonus bHit,3; bonus bHit,3;
@ -1667,11 +1667,11 @@ Body:
if (.@i >= PET_INTIMATE_LOYAL) { if (.@i >= PET_INTIMATE_LOYAL) {
bonus bCritical,5; bonus bCritical,5;
bonus bHit,5; bonus bHit,5;
autobonus "{ bonus2 bHPRegenRate,400,1000; }",20,5000,BF_WEAPON|BF_SHORT; petautobonus "{ bonus2 bHPRegenRate,400,1000; }",20,5000,BF_WEAPON|BF_SHORT;
} else if (.@i >= PET_INTIMATE_CORDIAL) { } else if (.@i >= PET_INTIMATE_CORDIAL) {
bonus bCritical,4; bonus bCritical,4;
bonus bHit,4; bonus bHit,4;
autobonus "{ bonus2 bHPRegenRate,300,1000; }",20,5000,BF_WEAPON|BF_SHORT; petautobonus "{ bonus2 bHPRegenRate,300,1000; }",20,5000,BF_WEAPON|BF_SHORT;
} else if (.@i >= PET_INTIMATE_NEUTRAL) { } else if (.@i >= PET_INTIMATE_NEUTRAL) {
bonus bCritical,3; bonus bCritical,3;
bonus bHit,3; bonus bHit,3;
@ -1780,10 +1780,10 @@ Body:
if (.@i >= PET_INTIMATE_LOYAL) { if (.@i >= PET_INTIMATE_LOYAL) {
bonus bMaxSP,150; bonus bMaxSP,150;
autobonus "{ bonus2 bSPRegenRate,40,1000; }",30,5000,BF_MAGIC; petautobonus "{ bonus2 bSPRegenRate,40,1000; }",30,5000,BF_MAGIC;
} else if (.@i >= PET_INTIMATE_CORDIAL) { } else if (.@i >= PET_INTIMATE_CORDIAL) {
bonus bMaxSP,150; bonus bMaxSP,150;
autobonus "{ bonus2 bSPRegenRate,30,1000; }",30,5000,BF_MAGIC; petautobonus "{ bonus2 bSPRegenRate,30,1000; }",30,5000,BF_MAGIC;
} else if (.@i >= PET_INTIMATE_NEUTRAL) { } else if (.@i >= PET_INTIMATE_NEUTRAL) {
bonus bMaxSP,100; bonus bMaxSP,100;
} else { } else {

View File

@ -6176,9 +6176,7 @@ kind in 'doc/item_bonus.txt'.
*autobonus3 <bonus script>,<rate>,<duration>,<skill id>,{<other script>}; *autobonus3 <bonus script>,<rate>,<duration>,<skill id>,{<other script>};
*autobonus3 <bonus script>,<rate>,<duration>,"<skill name>",{<other script>}; *autobonus3 <bonus script>,<rate>,<duration>,"<skill name>",{<other script>};
These commands are meant to be used in item scripts. They will probably work These commands are meant to be used in item scripts only! See 'petautobonus' for pet usage.
outside item scripts, but the bonus will not persist for long. They, as
expected, refer only to an invoking character.
What these commands do is 'attach' a script to the player which will get What these commands do is 'attach' a script to the player which will get
executed on attack (or when attacked in the case of autobonus2). executed on attack (or when attacked in the case of autobonus2).
@ -10313,6 +10311,15 @@ Value of 'rate' is between 1 and 100. 100 = 100%
--------------------------------------- ---------------------------------------
*petautobonus <bonus script>,<rate>,<duration>{,<flag>,{<other script>}};
*petautobonus2 <bonus script>,<rate>,<duration>{,<flag>,{<other script>}};
*petautobonus3 <bonus script>,<rate>,<duration>,<skill id>,{<other script>};
*petautobonus3 <bonus script>,<rate>,<duration>,"<skill name>",{<other script>};
See 'autobonus' for more details.
---------------------------------------
=========================== ===========================
|11.- Homunculus commands.| |11.- Homunculus commands.|
=========================== ===========================

View File

@ -31,6 +31,7 @@
using namespace rathena; using namespace rathena;
std::unordered_map<std::string, std::shared_ptr<s_pet_autobonus_wrapper>> pet_autobonuses;
const t_tick MIN_PETTHINKTIME = 100; const t_tick MIN_PETTHINKTIME = 100;
const std::string PetDatabase::getDefaultLocation(){ const std::string PetDatabase::getDefaultLocation(){
@ -2332,6 +2333,113 @@ void pet_evolution(struct map_session_data *sd, int16 pet_id) {
clif_inventorylist(sd); clif_inventorylist(sd);
} }
/**
* Add petautobonus to player when attacking/attacked.
* @param bonus: Bonus
* @param script: Script to execute
* @param rate: Success chance
* @param dur: Duration
* @param flag: Battle flag/skill
* @param other_script: Secondary script to execute
* @param onskill: Skill used to trigger autobonus
* @return True on success or false otherwise
*/
bool pet_addautobonus(std::vector<std::shared_ptr<s_petautobonus>> &bonus, const std::string &script, int16 rate, uint32 dur, uint16 flag, const std::string &other_script, bool onskill) {
if (bonus.size() == MAX_PC_BONUS) {
ShowWarning("pet_addautobonus: Reached max (%d) number of petautobonus per pet!\n", MAX_PC_BONUS);
return false;
}
if (!onskill) {
if (!(flag & BF_RANGEMASK))
flag |= BF_SHORT | BF_LONG; //No range defined? Use both.
if (!(flag & BF_WEAPONMASK))
flag |= BF_WEAPON; //No attack type defined? Use weapon.
if (!(flag & BF_SKILLMASK)) {
if (flag & (BF_MAGIC | BF_MISC))
flag |= BF_SKILL; //These two would never trigger without BF_SKILL
if (flag & BF_WEAPON)
flag |= BF_NORMAL | BF_SKILL;
}
}
if (rate < -10000 || rate > 10000)
ShowWarning("pet_addautobonus: Bonus rate %d exceeds -10000~10000 range, capping.\n", rate);
std::shared_ptr<s_petautobonus> entry = std::make_shared<s_petautobonus>();
entry->rate = cap_value(rate, -10000, 10000);
entry->duration = dur;
entry->timer = INVALID_TIMER;
entry->atk_type = flag;
entry->bonus_script = script;
entry->other_script = other_script;
bonus.push_back(entry);
return true;
}
/**
* Remove a petautobonus from player.
* @param sd: Player data
* @param bonus: Autobonus
* @param restore: Run script on clearing or not
*/
void pet_delautobonus(map_session_data &sd, std::vector<std::shared_ptr<s_petautobonus>> &bonus, bool restore) {
std::vector<std::shared_ptr<s_petautobonus>>::iterator it = bonus.begin();
while (it != bonus.end()) {
std::shared_ptr<s_petautobonus> b = *it;
if (b->timer != INVALID_TIMER && !b->bonus_script.empty() && restore) {
script_run_petautobonus(b->bonus_script, sd);
it = bonus.erase(it);
}
}
}
/**
* Execute petautobonus on player.
* @param sd: Player data
* @param bonus: Bonus vector
* @param autobonus: Autobonus to run
*/
void pet_exeautobonus(map_session_data &sd, std::vector<std::shared_ptr<s_petautobonus>> *bonus, std::shared_ptr<s_petautobonus> &autobonus) {
if (autobonus->timer != INVALID_TIMER)
delete_timer(autobonus->timer, pet_endautobonus);
if (!autobonus->other_script.empty()) {
script_run_petautobonus(autobonus->other_script, sd);
}
autobonus->timer = add_timer(gettick() + autobonus->duration, pet_endautobonus, sd.bl.id, (intptr_t)&bonus);
status_calc_pc(&sd, SCO_FORCE);
}
/**
* Remove petautobonus timer from player.
*/
TIMER_FUNC(pet_endautobonus) {
map_session_data *sd = map_id2sd(id);
std::vector<std::shared_ptr<s_petautobonus>> *bonus = (std::vector<std::shared_ptr<s_petautobonus>> *)data;
nullpo_ret(sd);
nullpo_ret(bonus);
for (std::shared_ptr<s_petautobonus> autobonus : *bonus) {
if (autobonus->timer == tid) {
autobonus->timer = INVALID_TIMER;
break;
}
}
status_calc_pc(sd, SCO_FORCE);
return 0;
}
/** /**
* Initialize pet data. * Initialize pet data.
*/ */
@ -2349,6 +2457,7 @@ void do_init_pet(void)
add_timer_func_list(pet_skill_support_timer, "pet_skill_support_timer"); // [Skotlex] add_timer_func_list(pet_skill_support_timer, "pet_skill_support_timer"); // [Skotlex]
add_timer_func_list(pet_recovery_timer,"pet_recovery_timer"); // [Valaris] add_timer_func_list(pet_recovery_timer,"pet_recovery_timer"); // [Valaris]
add_timer_func_list(pet_heal_timer,"pet_heal_timer"); // [Valaris] add_timer_func_list(pet_heal_timer,"pet_heal_timer"); // [Valaris]
add_timer_func_list(pet_endautobonus, "pet_endautobonus");
add_timer_interval(gettick()+MIN_PETTHINKTIME,pet_ai_hard,0,0,MIN_PETTHINKTIME); add_timer_interval(gettick()+MIN_PETTHINKTIME,pet_ai_hard,0,0,MIN_PETTHINKTIME);
} }
@ -2360,5 +2469,7 @@ void do_final_pet(void)
ers_destroy(item_drop_ers); ers_destroy(item_drop_ers);
ers_destroy(item_drop_list_ers); ers_destroy(item_drop_list_ers);
pet_autobonuses.clear();
pet_db.clear(); pet_db.clear();
} }

View File

@ -144,6 +144,42 @@ public:
extern PetDatabase pet_db; extern PetDatabase pet_db;
TIMER_FUNC(pet_endautobonus);
/// Pet AutoBonus bonus struct
struct s_petautobonus {
int16 rate;
uint16 atk_type;
std::string bonus_script, other_script;
t_tick duration;
int32 timer;
~s_petautobonus() {
if (this->timer != INVALID_TIMER) {
delete_timer(this->timer, pet_endautobonus);
this->timer = INVALID_TIMER;
}
this->bonus_script.clear();
this->other_script.clear();
}
};
/// Pet Autobonus database wrapper
struct s_pet_autobonus_wrapper {
script_code *script;
~s_pet_autobonus_wrapper() {
if (this->script != nullptr) {
script_free_code(this->script);
this->script = nullptr;
}
}
};
extern std::unordered_map<std::string, std::shared_ptr<s_pet_autobonus_wrapper>> pet_autobonuses;
struct pet_data { struct pet_data {
struct block_list bl; struct block_list bl;
struct unit_data ud; struct unit_data ud;
@ -165,6 +201,7 @@ struct pet_data {
struct pet_skill_attack* a_skill; struct pet_skill_attack* a_skill;
struct pet_skill_support* s_skill; struct pet_skill_support* s_skill;
struct pet_loot* loot; struct pet_loot* loot;
std::vector<std::shared_ptr<s_petautobonus>> autobonus, autobonus2, autobonus3;
int masterteleport_timer; int masterteleport_timer;
struct map_session_data *master; struct map_session_data *master;
@ -220,6 +257,10 @@ void pet_clear_support_bonuses(struct map_session_data *sd);
#define pet_stop_walking(pd, type) unit_stop_walking(&(pd)->bl, type) #define pet_stop_walking(pd, type) unit_stop_walking(&(pd)->bl, type)
#define pet_stop_attack(pd) unit_stop_attack(&(pd)->bl) #define pet_stop_attack(pd) unit_stop_attack(&(pd)->bl)
bool pet_addautobonus(std::vector<std::shared_ptr<s_petautobonus>> &bonus, const std::string &script, int16 rate, uint32 dur, uint16 atk_type, const std::string &other_script, bool onskill);
void pet_exeautobonus(map_session_data &sd, std::vector<std::shared_ptr<s_petautobonus>> *bonus, std::shared_ptr<s_petautobonus> &autobonus);
void pet_delautobonus(map_session_data &sd, std::vector<std::shared_ptr<s_petautobonus>> &bonus, bool restore);
void do_init_pet(void); void do_init_pet(void);
void do_final_pet(void); void do_final_pet(void);

View File

@ -4613,6 +4613,27 @@ void script_add_autobonus(const char *autobonus)
} }
} }
void script_run_petautobonus(const std::string &autobonus, map_session_data &sd) {
std::shared_ptr<s_pet_autobonus_wrapper> script = util::umap_find(pet_autobonuses, autobonus);
if (script != nullptr) {
run_script(script->script, 0, sd.bl.id, 0);
}
}
void script_add_petautobonus(const std::string &autobonus) {
if (util::umap_find(pet_autobonuses, autobonus) == nullptr) {
script_code *script = parse_script(autobonus.c_str(), "petautobonus", 0, 0);
if (script != nullptr) {
std::shared_ptr<s_pet_autobonus_wrapper> bonus = std::make_shared<s_pet_autobonus_wrapper>();
bonus->script = script;
pet_autobonuses.emplace(autobonus, bonus);
}
}
}
/// resets a temporary character array variable to given value /// resets a temporary character array variable to given value
void script_cleararray_pc( struct map_session_data* sd, const char* varname ){ void script_cleararray_pc( struct map_session_data* sd, const char* varname ){
@ -10065,6 +10086,96 @@ BUILDIN_FUNC(autobonus3)
return SCRIPT_CMD_SUCCESS; return SCRIPT_CMD_SUCCESS;
} }
BUILDIN_FUNC(petautobonus) {
map_session_data *sd;
if (!script_rid2sd(sd))
return SCRIPT_CMD_FAILURE; // No player attached
const char *command = script_getfuncname(st);
if (sd->pd == nullptr) {
ShowError("buildin_%s: Requires an active pet.\n", command);
return SCRIPT_CMD_FAILURE; // No pet attached to player
}
std::string bonus_script = script_getstr(st, 2);
int16 rate = script_getnum(st, 3);
uint32 dur = script_getnum(st, 4);
if (!rate || !dur || bonus_script.empty())
return SCRIPT_CMD_FAILURE;
uint16 atk_type = 0;
std::string other_script = {};
bool bonus2 = false;
if (strcmpi(command, "petautobonus2") == 0)
bonus2 = true;
if (script_hasdata(st, 5))
atk_type = script_getnum(st, 5);
if (script_hasdata(st, 6))
other_script = script_getstr(st, 6);
if (pet_addautobonus(bonus2 ? sd->pd->autobonus2 : sd->pd->autobonus, bonus_script, rate, dur, atk_type, other_script, false)) {
script_add_petautobonus(bonus_script);
if (!other_script.empty())
script_add_petautobonus(other_script);
}
return SCRIPT_CMD_SUCCESS;
}
BUILDIN_FUNC(petautobonus3) {
map_session_data *sd;
if (!script_rid2sd(sd))
return SCRIPT_CMD_SUCCESS; // No player attached
if (sd->pd == nullptr) {
ShowError("buildin_petautobonus3: Requires an active pet.\n");
return SCRIPT_CMD_FAILURE; // No pet attached to player
}
std::string bonus_script = script_getstr(st, 2);
int16 rate = script_getnum(st, 3);
uint32 dur = script_getnum(st, 4);
if (!rate || !dur || bonus_script.empty())
return SCRIPT_CMD_SUCCESS;
uint16 skill_id = 0;
std::string other_script = {};
if (script_isstring(st, 5)) {
const char *name = script_getstr(st, 5);
if (!(skill_id = skill_name2id(name))) {
ShowError("buildin_petautobonus3: Invalid skill name %s passed to item bonus. Skipping.\n", name);
return SCRIPT_CMD_FAILURE;
}
} else {
skill_id = script_getnum(st, 5);
if (!skill_get_index(skill_id)) {
ShowError("buildin_petautobonus3: Invalid skill ID %d passed to item bonus. Skipping.\n", skill_id);
return SCRIPT_CMD_FAILURE;
}
}
if (script_hasdata(st, 6))
other_script = script_getstr(st, 6);
if (pet_addautobonus(sd->pd->autobonus3, bonus_script, rate, dur, skill_id, other_script, true)) {
script_add_petautobonus(bonus_script);
if (!other_script.empty())
script_add_petautobonus(other_script);
}
return SCRIPT_CMD_SUCCESS;
}
/// Changes the level of a player skill. /// Changes the level of a player skill.
/// <flag> defaults to 1 /// <flag> defaults to 1
/// <flag>=0 : set the level of the skill /// <flag>=0 : set the level of the skill
@ -26578,6 +26689,9 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(autobonus,"sii??"), BUILDIN_DEF(autobonus,"sii??"),
BUILDIN_DEF(autobonus2,"sii??"), BUILDIN_DEF(autobonus2,"sii??"),
BUILDIN_DEF(autobonus3,"siiv?"), BUILDIN_DEF(autobonus3,"siiv?"),
BUILDIN_DEF(petautobonus,"sii??"),
BUILDIN_DEF2(petautobonus,"petautobonus2","sii??"),
BUILDIN_DEF(petautobonus3,"siiv?"),
BUILDIN_DEF(skill,"vi?"), BUILDIN_DEF(skill,"vi?"),
BUILDIN_DEF2(skill,"addtoskill","vi?"), // [Valaris] BUILDIN_DEF2(skill,"addtoskill","vi?"), // [Valaris]
BUILDIN_DEF(guildskill,"vi"), BUILDIN_DEF(guildskill,"vi"),

View File

@ -2169,6 +2169,7 @@ void script_free_state(struct script_state* st);
struct DBMap* script_get_label_db(void); struct DBMap* script_get_label_db(void);
struct DBMap* script_get_userfunc_db(void); struct DBMap* script_get_userfunc_db(void);
void script_run_autobonus(const char *autobonus, struct map_session_data *sd, unsigned int pos); void script_run_autobonus(const char *autobonus, struct map_session_data *sd, unsigned int pos);
void script_run_petautobonus(const std::string &autobonus, map_session_data &sd);
const char* script_get_constant_str(const char* prefix, int64 value); const char* script_get_constant_str(const char* prefix, int64 value);
bool script_get_parameter(const char* name, int64* value); bool script_get_parameter(const char* name, int64* value);

View File

@ -2360,21 +2360,38 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
} }
} }
//Autobonus when attacking // Check for player and pet autobonuses when attacking
if( sd && !sd->autobonus.empty() ) if (sd != nullptr) {
{ // Player
for(auto &it : sd->autobonus) { if (!sd->autobonus.empty()) {
if( it == nullptr ){ for (auto &it : sd->autobonus) {
continue; if (it == nullptr)
} continue;
if (rnd_value(0, 1000) >= it->rate)
continue;
if (!(((it->atk_type) & attack_type) & BF_WEAPONMASK &&
((it->atk_type) & attack_type) & BF_RANGEMASK &&
((it->atk_type) & attack_type) & BF_SKILLMASK))
continue; // one or more trigger conditions were not fulfilled
if (rnd()%1000 >= it->rate) pc_exeautobonus(*sd, &sd->autobonus, it);
continue; }
if (!(((it->atk_type)&attack_type)&BF_WEAPONMASK && }
((it->atk_type)&attack_type)&BF_RANGEMASK &&
((it->atk_type)&attack_type)&BF_SKILLMASK)) // Pet
continue; // one or more trigger conditions were not fulfilled if (sd->pd != nullptr && !sd->pd->autobonus.empty()) {
pc_exeautobonus(*sd, &sd->autobonus, it); for (auto &it : sd->pd->autobonus) {
if (it == nullptr)
continue;
if (rnd_value(0, 1000) >= it->rate)
continue;
if (!(((it->atk_type) & attack_type) & BF_WEAPONMASK &&
((it->atk_type) & attack_type) & BF_RANGEMASK &&
((it->atk_type) & attack_type) & BF_SKILLMASK))
continue; // one or more trigger conditions were not fulfilled
pet_exeautobonus(*sd, &sd->pd->autobonus, it);
}
} }
} }
@ -2461,15 +2478,34 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1
sd->state.autocast = 0; sd->state.autocast = 0;
} }
if( sd && !sd->autobonus3.empty() ) { // Check for player and pet autobonuses when being attacked by skill_id
for (auto &it : sd->autobonus3) { if (sd != nullptr) {
if (it == nullptr) // Player
continue; if (!sd->autobonus3.empty()) {
if (rnd()%1000 >= it->rate) for (auto &it : sd->autobonus3) {
continue; if (it == nullptr)
if (it->atk_type != skill_id) continue;
continue; if (rnd_value(0, 1000) >= it->rate)
pc_exeautobonus(*sd, &sd->autobonus3, it); continue;
if (it->atk_type != skill_id)
continue;
pc_exeautobonus(*sd, &sd->autobonus3, it);
}
}
// Pet
if (sd->pd != nullptr && !sd->pd->autobonus3.empty()) {
for (auto &it : sd->pd->autobonus3) {
if (it == nullptr)
continue;
if (rnd_value(0, 1000) >= it->rate)
continue;
if (it->atk_type != skill_id)
continue;
pet_exeautobonus(*sd, &sd->pd->autobonus3, it);
}
} }
} }
@ -2690,20 +2726,38 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
} }
} }
//Autobonus when attacked // Check for player and pet autobonuses when attacked
if( dstsd && !status_isdead(bl) && !dstsd->autobonus2.empty() && !(skill_id && skill_get_nk(skill_id, NK_NODAMAGE)) ) { if (dstsd != nullptr && !status_isdead(bl) && !(skill_id && skill_get_nk(skill_id, NK_NODAMAGE))) {
for (auto &it : dstsd->autobonus2) { // Player
if( it == nullptr ){ if (!dstsd->autobonus2.empty()) {
continue; for (auto &it : dstsd->autobonus2) {
} if (it == nullptr)
continue;
if (rnd_value(0, 1000) >= it->rate)
continue;
if (!(((it->atk_type) & attack_type) & BF_WEAPONMASK &&
((it->atk_type) & attack_type) & BF_RANGEMASK &&
((it->atk_type) & attack_type) & BF_SKILLMASK))
continue; // one or more trigger conditions were not fulfilled
if (rnd()%1000 >= it->rate) pc_exeautobonus(*dstsd, &dstsd->autobonus2, it);
continue; }
if (!(((it->atk_type)&attack_type)&BF_WEAPONMASK && }
((it->atk_type)&attack_type)&BF_RANGEMASK &&
((it->atk_type)&attack_type)&BF_SKILLMASK)) // Pet
continue; // one or more trigger conditions were not fulfilled if (dstsd->pd != nullptr && !dstsd->pd->autobonus2.empty()) {
pc_exeautobonus(*dstsd, &dstsd->autobonus2, it); for (auto &it : dstsd->pd->autobonus2) {
if (it == nullptr)
continue;
if (rnd_value(0, 1000) >= it->rate)
continue;
if (!(((it->atk_type) & attack_type) & BF_WEAPONMASK &&
((it->atk_type) & attack_type) & BF_RANGEMASK &&
((it->atk_type) & attack_type) & BF_SKILLMASK))
continue; // one or more trigger conditions were not fulfilled
pet_exeautobonus(*dstsd, &dstsd->pd->autobonus2, it);
}
} }
} }

View File

@ -3641,6 +3641,12 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
pc_delautobonus(*sd, sd->autobonus2, true); pc_delautobonus(*sd, sd->autobonus2, true);
pc_delautobonus(*sd, sd->autobonus3, true); pc_delautobonus(*sd, sd->autobonus3, true);
if (sd->pd != nullptr) {
pet_delautobonus(*sd, sd->pd->autobonus, true);
pet_delautobonus(*sd, sd->pd->autobonus2, true);
pet_delautobonus(*sd, sd->pd->autobonus3, true);
}
// Parse equipment // Parse equipment
for (i = 0; i < EQI_MAX; i++) { for (i = 0; i < EQI_MAX; i++) {
current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]

View File

@ -3464,6 +3464,10 @@ int unit_free(struct block_list *bl, clr_type clrtype)
struct pet_data *pd = (struct pet_data*)bl; struct pet_data *pd = (struct pet_data*)bl;
struct map_session_data *sd = pd->master; struct map_session_data *sd = pd->master;
pet_delautobonus(*sd, pd->autobonus, false);
pet_delautobonus(*sd, pd->autobonus2, false);
pet_delautobonus(*sd, pd->autobonus3, false);
pet_hungry_timer_delete(pd); pet_hungry_timer_delete(pd);
pet_clear_support_bonuses(sd); pet_clear_support_bonuses(sd);