From 31327ade6c46f4675cbd68141eb81e65d1a88167 Mon Sep 17 00:00:00 2001 From: Aleos Date: Wed, 20 Oct 2021 09:04:17 -0400 Subject: [PATCH] Minor cleanups to AutoSpell item bonuses (#6212) * Fixes #6153. * Fixes variable types to avoid any loss of data. * Fixes AutoSpellOnSkill random level cast being mixed with the target selection flag. * Removes the overloaded use of variables for the autospell bonuses. Thanks to @randell1993 and @Lemongrass3110! Co-authored-by: Lemongrass3110 --- src/map/pc.cpp | 54 +++++++++++--------- src/map/pc.hpp | 6 ++- src/map/skill.cpp | 126 ++++++++++++++++++++++++---------------------- 3 files changed, 100 insertions(+), 86 deletions(-) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 746a1b76e7..1a522770d0 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -2524,10 +2524,13 @@ int pc_disguise(struct map_session_data *sd, int class_) * @param id: Skill to cast * @param lv: Skill level * @param rate: Success chance - * @param flag: Battle flag + * @param battle_flag: Battle flag * @param card_id: Used to prevent card stacking + * @param flag: Flags used for extra arguments + * &1: forces the skill to be casted on target, rather than self + * &2: random skill level in [1..lv] is chosen */ -static void pc_bonus_autospell(std::vector &spell, short id, short lv, short rate, short flag, unsigned short card_id) +static void pc_bonus_autospell(std::vector &spell, uint16 id, uint16 lv, short rate, short battle_flag, t_itemid card_id, uint8 flag) { if (spell.size() == MAX_PC_BONUS) { ShowWarning("pc_bonus_autospell: Reached max (%d) number of autospells per character!\n", MAX_PC_BONUS); @@ -2537,19 +2540,19 @@ static void pc_bonus_autospell(std::vector &spell, short id, short if (!rate) return; - 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; //By default autospells should only trigger on normal weapon attacks. + if (!(battle_flag&BF_RANGEMASK)) + battle_flag |= BF_SHORT | BF_LONG; //No range defined? Use both. + if (!(battle_flag&BF_WEAPONMASK)) + battle_flag |= BF_WEAPON; //No attack type defined? Use weapon. + if (!(battle_flag&BF_SKILLMASK)) { + if (battle_flag&(BF_MAGIC | BF_MISC)) + battle_flag |= BF_SKILL; //These two would never trigger without BF_SKILL + if (battle_flag&BF_WEAPON) + battle_flag |= BF_NORMAL; //By default autospells should only trigger on normal weapon attacks. } for (auto &it : spell) { - if ((it.card_id == card_id || it.rate < 0 || rate < 0) && it.id == id && it.lv == lv && it.flag == flag) { + if ((it.card_id == card_id || it.rate < 0 || rate < 0) && it.id == id && it.lv == lv && it.flag == battle_flag) { if (!battle_config.autospell_stacking && it.rate > 0 && rate > 0) // Stacking disabled return; it.rate = cap_value(it.rate + rate, -10000, 10000); @@ -2565,8 +2568,9 @@ static void pc_bonus_autospell(std::vector &spell, short id, short entry.id = id; entry.lv = lv; entry.rate = cap_value(rate, -10000, 10000); - entry.flag = flag; + entry.battle_flag = battle_flag; entry.card_id = card_id; + entry.flag = flag; spell.push_back(entry); } @@ -2579,8 +2583,11 @@ static void pc_bonus_autospell(std::vector &spell, short id, short * @param lv: Skill level * @param rate: Success chance * @param card_id: Used to prevent card stacking + * @param flag: Flags used for extra arguments + * &1: forces the skill to be casted on self, rather than on the target of skill + * &2: random skill level in [1..lv] is chosen */ -static void pc_bonus_autospell_onskill(std::vector &spell, short src_skill, short id, short lv, short rate, unsigned short card_id) +static void pc_bonus_autospell_onskill(std::vector &spell, uint16 src_skill, uint16 id, uint16 lv, short rate, t_itemid card_id, uint8 flag) { if (spell.size() == MAX_PC_BONUS) { ShowWarning("pc_bonus_autospell_onskill: Reached max (%d) number of autospells per character!\n", MAX_PC_BONUS); @@ -2595,11 +2602,12 @@ static void pc_bonus_autospell_onskill(std::vector &spell, short sr if (rate < -10000 || rate > 10000) ShowWarning("pc_bonus_onskill: Item bonus rate %d exceeds -10000~10000 range, capping.\n", rate); - entry.flag = src_skill; + entry.trigger_skill = src_skill; entry.id = id; entry.lv = lv; entry.rate = cap_value(rate, -10000, 10000); entry.card_id = card_id; + entry.flag = flag; spell.push_back(entry); } @@ -4455,7 +4463,7 @@ void pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val) { int target = skill_get_inf(type2); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !skill_get_inf2(type2, INF2_NOTARGETSELF)); - pc_bonus_autospell(sd->autospell, target?-type2:type2, type3, val, 0, current_equip_card_id); + pc_bonus_autospell(sd->autospell, type2, type3, val, 0, current_equip_card_id, target ? 0 : 1); } break; case SP_AUTOSPELL_WHENHIT: // bonus3 bAutoSpellWhenHit,sk,y,n; @@ -4463,7 +4471,7 @@ void pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val) { int target = skill_get_inf(type2); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !skill_get_inf2(type2, INF2_NOTARGETSELF)); - pc_bonus_autospell(sd->autospell2, target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, current_equip_card_id); + pc_bonus_autospell(sd->autospell2, type2, type3, val, BF_NORMAL|BF_SKILL, current_equip_card_id, target ? 0 : 1); } break; case SP_ADD_MONSTER_DROP_ITEMGROUP: // bonus3 bAddMonsterDropItemGroup,ig,r,n; @@ -4581,12 +4589,12 @@ void pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type switch(type){ case SP_AUTOSPELL: // bonus4 bAutoSpell,sk,y,n,i; if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell, (val&1?type2:-type2), (val&2?-type3:type3), type4, 0, current_equip_card_id); + pc_bonus_autospell(sd->autospell, type2, type3, type4, 0, current_equip_card_id, val); break; case SP_AUTOSPELL_WHENHIT: // bonus4 bAutoSpellWhenHit,sk,y,n,i; if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell2, (val&1?type2:-type2), (val&2?-type3:type3), type4, BF_NORMAL|BF_SKILL, current_equip_card_id); + pc_bonus_autospell(sd->autospell2, type2, type3, type4, BF_NORMAL|BF_SKILL, current_equip_card_id, val); break; case SP_AUTOSPELL_ONSKILL: // bonus4 bAutoSpellOnSkill,sk,x,y,n; @@ -4595,7 +4603,7 @@ void pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type int target = skill_get_inf(type3); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !skill_get_inf2(type3, INF2_NOTARGETSELF)); - pc_bonus_autospell_onskill(sd->autospell3, type2, target?-type3:type3, type4, val, current_equip_card_id); + pc_bonus_autospell_onskill(sd->autospell3, type2, type3, type4, val, current_equip_card_id, target ? 0 : 1); } break; @@ -4664,17 +4672,17 @@ void pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type switch(type){ case SP_AUTOSPELL: // bonus5 bAutoSpell,sk,y,n,bf,i; if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell, (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, current_equip_card_id); + pc_bonus_autospell(sd->autospell, type2, type3, type4, type5, current_equip_card_id, val); break; case SP_AUTOSPELL_WHENHIT: // bonus5 bAutoSpellWhenHit,sk,y,n,bf,i; if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell2, (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, current_equip_card_id); + pc_bonus_autospell(sd->autospell2, type2, type3, type4, type5, current_equip_card_id, val); break; case SP_AUTOSPELL_ONSKILL: // bonus5 bAutoSpellOnSkill,sk,x,y,n,i; if(sd->state.lr_flag != 2) - pc_bonus_autospell_onskill(sd->autospell3, type2, (val&1?-type3:type3), (val&2?-type4:type4), type5, current_equip_card_id); + pc_bonus_autospell_onskill(sd->autospell3, type2, type3, type4, type5, current_equip_card_id, val); break; case SP_ADDEFF_ONSKILL: // bonus5 bAddEffOnSkill,sk,eff,n,y,t; diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 936b891107..189fc6d473 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -194,8 +194,10 @@ struct weapon_data { /// AutoSpell bonus struct struct s_autospell { - short id, lv, rate, flag; - unsigned short card_id; + uint16 id, lv, trigger_skill; + short rate, battle_flag; + t_itemid card_id; + uint8 flag; bool lock; // bAutoSpellOnSkill: blocks autospell from triggering again, while being executed }; diff --git a/src/map/skill.cpp b/src/map/skill.cpp index e69099d5cb..6fa88401bb 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -2168,17 +2168,13 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 // Autospell when attacking if( sd && !status_isdead(bl) && !sd->autospell.empty() ) { - struct block_list *tbl; - struct unit_data *ud; - int autospl_skill_lv, type; - for (const auto &it : sd->autospell) { - if (!(((it.flag)&attack_type)&BF_WEAPONMASK && - ((it.flag)&attack_type)&BF_RANGEMASK && - ((it.flag)&attack_type)&BF_SKILLMASK)) + if (!(((it.battle_flag)&attack_type)&BF_WEAPONMASK && + ((it.battle_flag)&attack_type)&BF_RANGEMASK && + ((it.battle_flag)&attack_type)&BF_SKILLMASK)) continue; // one or more trigger conditions were not fulfilled - skill = (it.id > 0) ? it.id : -it.id; + skill = it.id; sd->state.autocast = 1; if ( skill_isNotOk(skill, sd) ) { @@ -2187,17 +2183,20 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 } sd->state.autocast = 0; - autospl_skill_lv = it.lv?it.lv:1; - if (autospl_skill_lv < 0) autospl_skill_lv = 1+rnd()%(-autospl_skill_lv); + uint16 autospl_skill_lv = it.lv ? it.lv : 1; + + if (it.flag & 2) + autospl_skill_lv = rnd_value( 1, autospl_skill_lv ); rate = (!sd->state.arrow_atk) ? it.rate : it.rate / 2; if (rnd()%1000 >= rate) continue; - tbl = (it.id < 0) ? src : bl; + block_list *tbl = (it.flag & 1) ? bl : src; + e_cast_type type = skill_get_casttype(skill); - if ((type = skill_get_casttype(skill)) == CAST_GROUND) { + if (type == CAST_GROUND) { if (!skill_pos_maxcount_check(src, tbl->x, tbl->y, skill, autospl_skill_lv, BL_PC, false)) continue; } @@ -2229,14 +2228,17 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 break; } sd->state.autocast = 0; + //Set canact delay. [Skotlex] - ud = unit_bl2ud(src); + unit_data *ud = unit_bl2ud(src); + if (ud) { - rate = skill_delayfix(src, skill, autospl_skill_lv); - if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ - ud->canact_tick = i64max(tick + rate, ud->canact_tick); + int delay = skill_delayfix(src, skill, autospl_skill_lv); + + if (DIFF_TICK(ud->canact_tick, tick + delay) < 0){ + ud->canact_tick = i64max(tick + delay, ud->canact_tick); if ( battle_config.display_status_timers && sd ) - clif_status_change(src, EFST_POSTDELAY, 1, rate, 0, 0, 0); + clif_status_change(src, EFST_POSTDELAY, 1, delay, 0, 0, 0); } } } @@ -2270,48 +2272,43 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 } int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint16 skill_id, t_tick tick) { - struct block_list *tbl; - - if( sd == NULL || !skill_id ) + if( sd == nullptr || !skill_id ) return 0; for (auto &it : sd->autospell3) { - int skill, skill_lv, type; - - if (it.flag != skill_id) + if (it.trigger_skill != skill_id) continue; if (it.lock) continue; // autospell already being executed - skill = it.id; + uint16 skill = it.id; + sd->state.autocast = 1; //set this to bypass sd->canskill_tick check - if( skill_isNotOk((skill > 0) ? skill : skill*-1, sd) ) { + if( skill_isNotOk(skill, sd) ) { sd->state.autocast = 0; continue; } sd->state.autocast = 0; - if( skill >= 0 && bl == NULL ) + if( skill > 0 && bl == nullptr ) continue; // No target if( rnd()%1000 >= it.rate ) continue; - skill_lv = it.lv ? it.lv : 1; - if( skill < 0 ) { - tbl = &sd->bl; - skill *= -1; - skill_lv = 1 + rnd()%(-skill_lv); //random skill_lv - } - else - tbl = bl; + block_list *tbl = (it.flag & 1) ? &sd->bl : bl; + uint16 skill_lv = it.lv ? it.lv : 1; + + if (it.flag & 2) + skill_lv = rnd_value( 1, skill_lv ); //random skill_lv + + e_cast_type type = skill_get_casttype(skill); + + if (type == CAST_GROUND && !skill_pos_maxcount_check(&sd->bl, tbl->x, tbl->y, skill_id, skill_lv, BL_PC, false)) + continue; - if ((type = skill_get_casttype(skill)) == CAST_GROUND) { - if (!skill_pos_maxcount_check(&sd->bl, tbl->x, tbl->y, skill_id, skill_lv, BL_PC, false)) - continue; - } if (battle_config.autospell_check_range && !battle_check_range(bl, tbl, skill_get_range2(&sd->bl, skill, skill_lv, true))) continue; @@ -2320,9 +2317,15 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1 it.lock = true; skill_consume_requirement(sd,skill,skill_lv,1); switch( type ) { - case CAST_GROUND: skill_castend_pos2(&sd->bl, tbl->x, tbl->y, skill, skill_lv, tick, 0); break; - case CAST_NODAMAGE: skill_castend_nodamage_id(&sd->bl, tbl, skill, skill_lv, tick, 0); break; - case CAST_DAMAGE: skill_castend_damage_id(&sd->bl, tbl, skill, skill_lv, tick, 0); break; + case CAST_GROUND: + skill_castend_pos2(&sd->bl, tbl->x, tbl->y, skill, skill_lv, tick, 0); + break; + case CAST_NODAMAGE: + skill_castend_nodamage_id(&sd->bl, tbl, skill, skill_lv, tick, 0); + break; + case CAST_DAMAGE: + skill_castend_damage_id(&sd->bl, tbl, skill, skill_lv, tick, 0); + break; } it.lock = false; sd->state.autocast = 0; @@ -2484,21 +2487,19 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if(dstsd && !status_isdead(bl) && !dstsd->autospell2.empty() && !(skill_id && skill_get_nk(skill_id, NK_NODAMAGE))) { - struct block_list *tbl; - struct unit_data *ud; - int autospl_skill_id, autospl_skill_lv, autospl_rate, type; - for (const auto &it : dstsd->autospell2) { - if (!(((it.flag)&attack_type)&BF_WEAPONMASK && - ((it.flag)&attack_type)&BF_RANGEMASK && - ((it.flag)&attack_type)&BF_SKILLMASK)) + if (!(((it.battle_flag)&attack_type)&BF_WEAPONMASK && + ((it.battle_flag)&attack_type)&BF_RANGEMASK && + ((it.battle_flag)&attack_type)&BF_SKILLMASK)) continue; // one or more trigger conditions were not fulfilled - autospl_skill_id = (it.id > 0) ? it.id : -it.id; - autospl_skill_lv = it.lv ? it.lv : 1; - if (autospl_skill_lv < 0) autospl_skill_lv = 1+rnd()%(-autospl_skill_lv); + uint16 autospl_skill_id = it.id, autospl_skill_lv = it.lv ? it.lv : 1; + + if (it.flag & 2) + autospl_skill_lv = rnd_value( 1, autospl_skill_lv ); + + int autospl_rate = it.rate; - autospl_rate = it.rate; //Physical range attacks only trigger autospells half of the time if ((attack_type&(BF_WEAPON|BF_LONG)) == (BF_WEAPON|BF_LONG)) autospl_rate>>=1; @@ -2513,11 +2514,11 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if (rnd()%1000 >= autospl_rate) continue; - tbl = (it.id < 0) ? bl : src; - if ((type = skill_get_casttype(autospl_skill_id)) == CAST_GROUND) { - if (!skill_pos_maxcount_check(bl, tbl->x, tbl->y, autospl_skill_id, autospl_skill_lv, BL_PC, false)) + block_list *tbl = (it.flag & 1) ? src : bl; + e_cast_type type = skill_get_casttype(autospl_skill_id); + + if (type == CAST_GROUND && !skill_pos_maxcount_check(bl, tbl->x, tbl->y, autospl_skill_id, autospl_skill_lv, BL_PC, false)) continue; - } if (!battle_check_range(bl, tbl, skill_get_range2(src, autospl_skill_id, autospl_skill_lv, true)) && battle_config.autospell_check_range) continue; @@ -2536,14 +2537,17 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * break; } dstsd->state.autocast = 0; + //Set canact delay. [Skotlex] - ud = unit_bl2ud(bl); + unit_data *ud = unit_bl2ud(bl); + if (ud) { - autospl_rate = skill_delayfix(bl, autospl_skill_id, autospl_skill_lv); - if (DIFF_TICK(ud->canact_tick, tick + autospl_rate) < 0){ - ud->canact_tick = i64max(tick + autospl_rate, ud->canact_tick); + int delay = skill_delayfix(bl, autospl_skill_id, autospl_skill_lv); + + if (DIFF_TICK(ud->canact_tick, tick + delay) < 0){ + ud->canact_tick = i64max(tick + delay, ud->canact_tick); if ( battle_config.display_status_timers && dstsd ) - clif_status_change(bl, EFST_POSTDELAY, 1, autospl_rate, 0, 0, 0); + clif_status_change(bl, EFST_POSTDELAY, 1, delay, 0, 0, 0); } } }