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:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user