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 <lemongrass@kstp.at>
This commit is contained in:
Aleos
2021-10-20 09:04:17 -04:00
committed by GitHub
parent d7b6f39655
commit 31327ade6c
3 changed files with 100 additions and 86 deletions

View File

@@ -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<s_autospell> &spell, short id, short lv, short rate, short flag, unsigned short card_id)
static void pc_bonus_autospell(std::vector<s_autospell> &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<s_autospell> &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<s_autospell> &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<s_autospell> &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<s_autospell> &spell, short src_skill, short id, short lv, short rate, unsigned short card_id)
static void pc_bonus_autospell_onskill(std::vector<s_autospell> &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<s_autospell> &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;

View File

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

View File

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