summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2020-04-05 21:05:27 +0200
committerGitHub <noreply@github.com>2020-04-05 21:05:27 +0200
commit024c9c48d4a1d064ac9d37d997d3983fb1bff40f (patch)
tree0eae933a4a69c220f98dacfe17b9df2cc5b877ec /src
parent02a84aa9870422bddb7b631dd09bb45c1e5e6856 (diff)
parent876cfa678d5e9a43d1ce419bd9d8300d9c8c6b36 (diff)
downloadhercules-024c9c48d4a1d064ac9d37d997d3983fb1bff40f.tar.gz
hercules-024c9c48d4a1d064ac9d37d997d3983fb1bff40f.tar.bz2
hercules-024c9c48d4a1d064ac9d37d997d3983fb1bff40f.tar.xz
hercules-024c9c48d4a1d064ac9d37d997d3983fb1bff40f.zip
Merge pull request #2657 from Kenpachi2k13/autocast_clean_up
Clean up auto-cast related code
Diffstat (limited to 'src')
-rw-r--r--src/map/atcommand.c2
-rw-r--r--src/map/battle.c20
-rw-r--r--src/map/clif.c48
-rw-r--r--src/map/pc.c29
-rw-r--r--src/map/pc.h30
-rw-r--r--src/map/script.c36
-rw-r--r--src/map/skill.c181
-rw-r--r--src/map/skill.h11
-rw-r--r--src/map/status.c6
-rw-r--r--src/map/unit.c20
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Defs.inc6
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc12
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc3
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc43
14 files changed, 221 insertions, 226 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 410cd7af7..d3368c3b0 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -5671,6 +5671,8 @@ ACMD(useskill)
return false;
}
+ pc->autocast_clear(sd);
+
if (skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL
&& sd->hd && homun_alive(sd->hd)) // (If used with @useskill, put the homunc as dest)
bl = &sd->hd->bl;
diff --git a/src/map/battle.c b/src/map/battle.c
index 985d2bca4..6519b1f37 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -5928,21 +5928,21 @@ static void battle_reflect_damage(struct block_list *target, struct block_list *
delay += 100;/* gradual increase so the numbers don't clip in the client */
}
if( sc->data[SC_LG_REFLECTDAMAGE] && rnd()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) {
- bool change = false;
-
NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100);
trdamage -= rdamage;/* wont count towards total */
- if( sd && !sd->state.autocast ) {
- change = true;
- sd->state.autocast = 1;
+ enum autocast_type ac_type;
+
+ if (sd != NULL) {
+ ac_type = sd->autocast.type;
+ sd->autocast.type = AUTOCAST_TEMP;
}
map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,delay,wd->dmotion,rdamage,status_get_race(target));
- if( change )
- sd->state.autocast = 0;
+ if (sd != NULL)
+ sd->autocast.type = ac_type;
delay += 150;/* gradual increase so the numbers don't clip in the client */
@@ -6132,7 +6132,7 @@ static int battle_damage_area(struct block_list *bl, va_list ap)
else
status_fix_damage(src,bl,damage,0);
clif->damage(bl,bl,amotion,dmotion,damage,1,BDT_ENDURE,0);
- if (src->type != BL_PC || !BL_UCCAST(BL_PC, src)->state.autocast)
+ if (src->type != BL_PC || BL_UCCAST(BL_PC, src)->autocast.type != AUTOCAST_TEMP)
skill->additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
map->freeblock_unlock();
}
@@ -6456,10 +6456,10 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_
}
}
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(sd,r_skill,r_lv,3);
skill->castend_type(type, src, target, r_skill, r_lv, tick, flag);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
sd->ud.canact_tick = tick + skill->delay_fix(src, r_skill, r_lv);
clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1);
}
diff --git a/src/map/clif.c b/src/map/clif.c
index a7d9c71e5..83f5751ba 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -6766,7 +6766,7 @@ static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16
struct PACKET_ZC_AUTORUN_SKILL *p = WFIFOP(fd, 0);
int type = skill->get_inf(skill_id);
- if (sd->state.itemskill_castonself == 1 && skill->is_item_skill(sd, skill_id, skill_lv))
+ if (sd->autocast.itemskill_cast_on_self && sd->autocast.type == AUTOCAST_ITEM)
type = INF_SELF_SKILL;
p->packetType = HEADER_ZC_AUTORUN_SKILL;
@@ -12707,6 +12707,14 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
{
int64 tick = timer->gettick();
+ /**
+ * According to Skotlex' comment below, the client sometimes passes 0 for the skill level.
+ * Even though this seems to only affect guild skills, sd->autocast.skill_lv is used
+ * for the auto-cast data validation if skill_lv is 0.
+ *
+ **/
+ skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv);
+
if (skill_lv < 1)
skill_lv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex]
@@ -12760,7 +12768,7 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
if (skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST)
return;
} else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) {
- if (sd->skillitem != skill_id) {
+ if (sd->autocast.type == AUTOCAST_NONE) {
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0);
return;
}
@@ -12778,16 +12786,16 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
} else if (sd->menuskill_id != SA_AUTOSPELL)
return; //Can't use skills while a menu is open.
}
- if (sd->skillitem == skill_id) {
- if (skill_lv != sd->skillitemlv)
- skill_lv = sd->skillitemlv;
+ if (sd->autocast.type != AUTOCAST_NONE) {
+ if (skill_lv != sd->autocast.skill_lv)
+ skill_lv = sd->autocast.skill_lv;
if (!(tmp&INF_SELF_SKILL))
pc->delinvincibletimer(sd); // Target skills through items cancel invincibility. [Inkfish]
unit->skilluse_id(&sd->bl, target_id, skill_id, skill_lv);
return;
}
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
if (skill_id >= GD_SKILLBASE && skill_id < GD_MAX) {
if (sd->state.gmaster_flag)
@@ -12848,6 +12856,16 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
int64 tick = timer->gettick();
nullpo_retv(sd);
+
+ /**
+ * When using clif_item_skill() to initiate the execution of ground skills,
+ * the client sometimes passes 0 for the skill level in packet 0x0af4.
+ * In that case sd->autocast.skill_lv is used for the auto-cast data validation,
+ * since clif_item_skill() is only used for auto-cast skills.
+ *
+ **/
+ skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv);
+
if( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) )
return; //Using a target skill on the ground? WRONG.
@@ -12888,7 +12906,7 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
return;
if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) {
- if( sd->skillitem != skill_id ) {
+ if (sd->autocast.type == AUTOCAST_NONE) {
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0);
return;
}
@@ -12909,13 +12927,13 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
pc->delinvincibletimer(sd);
- if( sd->skillitem == skill_id ) {
- if( skill_lv != sd->skillitemlv )
- skill_lv = sd->skillitemlv;
+ if (sd->autocast.type != AUTOCAST_NONE) {
+ if (skill_lv != sd->autocast.skill_lv)
+ skill_lv = sd->autocast.skill_lv;
unit->skilluse_pos(&sd->bl, x, y, skill_id, skill_lv);
} else {
int lv;
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
if( (lv = pc->checkskill(sd, skill_id)) > 0 ) {
if( skill_lv > lv )
skill_lv = lv;
@@ -12986,9 +13004,15 @@ static void clif_parse_UseSkillMap(int fd, struct map_session_data *sd)
return;
}
+ /**
+ * Since no skill level was passed use 0 to notify skill_validate_autocast_data() of this special case.
+ *
+ **/
+ skill->validate_autocast_data(sd, skill_id, 0);
+
pc->delinvincibletimer(sd);
skill->castend_map(sd,skill_id,map_name);
- pc->itemskill_clear(sd);
+ pc->autocast_clear(sd);
}
static void clif_parse_RequestMemo(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
diff --git a/src/map/pc.c b/src/map/pc.c
index da53b2606..6dba997ef 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -5295,10 +5295,6 @@ static int pc_useitem(struct map_session_data *sd, int n)
if(sd->catch_target_class != -1) //Abort pet catching.
sd->catch_target_class = -1;
- // Removes abracadabra/randomize spell flag for delayed consume items or item doesn't get consumed
- if (sd->inventory_data[n]->flag.delay_consume)
- sd->state.abra_flag = 0;
-
amount = sd->status.inventory[n].amount;
//Check if the item is to be consumed immediately [Skotlex]
if (sd->inventory_data[n]->flag.delay_consume || sd->inventory_data[n]->flag.keepafteruse)
@@ -5337,21 +5333,22 @@ static int pc_useitem(struct map_session_data *sd, int n)
}
/**
- * Sets state flags and helper variables, used by itemskill() script command, to 0.
+ * Unsets a character's auto-cast related data.
*
* @param sd The character's session data.
* @return 0 if parameter sd is NULL, otherwise 1.
*/
-static int pc_itemskill_clear(struct map_session_data *sd)
+static int pc_autocast_clear(struct map_session_data *sd)
{
nullpo_ret(sd);
- sd->itemskill_id = 0;
- sd->itemskill_lv = 0;
- sd->state.itemskill_conditions_checked = 0;
- sd->state.itemskill_check_conditions = 0;
- sd->state.itemskill_no_casttime = 0;
- sd->state.itemskill_castonself = 0;
+ sd->autocast.type = AUTOCAST_NONE;
+ sd->autocast.skill_id = 0;
+ sd->autocast.skill_lv = 0;
+ sd->autocast.itemskill_conditions_checked = false;
+ sd->autocast.itemskill_check_conditions = false;
+ sd->autocast.itemskill_instant_cast = false;
+ sd->autocast.itemskill_cast_on_self = false;
return 1;
}
@@ -8122,9 +8119,9 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
clif->party_dead_notification(sd);
- //Reset menu skills/item skills
- if (sd->skillitem)
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd); // Unset auto-cast data.
+
+ // Reset menu skills.
if (sd->menuskill_id)
sd->menuskill_id = sd->menuskill_val = 0;
//Reset ticks.
@@ -12730,7 +12727,7 @@ void pc_defaults(void)
pc->unequipitem_pos = pc_unequipitem_pos;
pc->checkitem = pc_checkitem;
pc->useitem = pc_useitem;
- pc->itemskill_clear = pc_itemskill_clear;
+ pc->autocast_clear = pc_autocast_clear;
pc->skillatk_bonus = pc_skillatk_bonus;
pc->skillheal_bonus = pc_skillheal_bonus;
diff --git a/src/map/pc.h b/src/map/pc.h
index 8d1ae3607..6f932c447 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -173,6 +173,17 @@ struct pc_combos {
int id; /* this combo id */
};
+/** Auto-cast related data. **/
+struct autocast_data {
+ enum autocast_type type; // The auto-cast type.
+ int skill_id; // The auto-cast skill ID.
+ int skill_lv; // The auto-cast skill level.
+ bool itemskill_conditions_checked; // Used by itemskill() script command, to prevent second check of conditions after target was selected.
+ bool itemskill_check_conditions; // Used by itemskill() script command, to check skill conditions and consume them.
+ bool itemskill_instant_cast; // Used by itemskill() script command, to cast skill instantaneously.
+ bool itemskill_cast_on_self; // Used by itemskill() script command, to forcefully cast skill on invoking character.
+};
+
struct map_session_data {
struct block_list bl;
struct unit_data ud;
@@ -181,6 +192,7 @@ struct map_session_data {
struct status_change sc;
struct regen_data regen;
struct regen_data_sub sregen, ssregen;
+ struct autocast_data autocast;
//NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in
//status_calc_pc, while special_state is recalculated in each call. [Skotlex]
struct {
@@ -194,8 +206,6 @@ struct map_session_data {
unsigned int rest : 1;
unsigned int storage_flag : 2; // @see enum storage_flag
unsigned int snovice_dead_flag : 1; //Explosion spirits on death: 0 off, 1 used.
- unsigned int abra_flag : 2; // Abracadabra bugfix by Aru
- unsigned int autocast : 1; // Autospell flag [Inkfish]
unsigned int autotrade : 2; //By Fantik
unsigned int showdelay :1;
unsigned int showexp :1;
@@ -240,10 +250,6 @@ struct map_session_data {
unsigned int refine_ui : 1;
unsigned int npc_unloaded : 1; ///< The player is talking with an unloaded NPCs (respawned tombstones)
unsigned int lapine_ui : 1;
- unsigned int itemskill_conditions_checked : 1; // Used by itemskill() script command, to prevent second check of conditions after target was selected.
- unsigned int itemskill_check_conditions : 1; // Used by itemskill() script command, to check skill conditions and consume them.
- unsigned int itemskill_no_casttime : 1; // Used by itemskill() script command, to cast skill instantaneously.
- unsigned int itemskill_castonself : 1; // Used by itemskill() script command, to forcefully cast skill on invoking character.
} state;
struct {
unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;
@@ -298,7 +304,6 @@ struct map_session_data {
int followtimer; // [MouseJstr]
int followtarget;
time_t emotionlasttime; // to limit flood with emotion packets
- int skillitem,skillitemlv;
uint16 skill_id_old,skill_lv_old;
uint16 skill_id_dance,skill_lv_dance;
short cook_mastery; // range: [0,1999] [Inkfish]
@@ -647,15 +652,6 @@ END_ZEROED_BLOCK;
bool achievements_received;
// Title
VECTOR_DECL(int) title_ids;
-
- /*
- * itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention.
- * If a skill, casted by itemskill() script command, is aborted while target selection,
- * the map server gets no notification where these states could be unset.
- * Thus we need this helper variables to prevent abusing these states for next skill cast.
- */
- int itemskill_id;
- int itemskill_lv;
};
#define EQP_WEAPON EQP_HAND_R
@@ -1034,7 +1030,7 @@ END_ZEROED_BLOCK; /* End */
void (*unequipitem_pos) (struct map_session_data *sd, int n, int pos);
int (*checkitem) (struct map_session_data *sd);
int (*useitem) (struct map_session_data *sd,int n);
- int (*itemskill_clear) (struct map_session_data *sd);
+ int (*autocast_clear) (struct map_session_data *sd);
int (*skillatk_bonus) (struct map_session_data *sd, uint16 skill_id);
int (*skillheal_bonus) (struct map_session_data *sd, uint16 skill_id);
diff --git a/src/map/script.c b/src/map/script.c
index c644e9b75..d575c5925 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -11001,33 +11001,29 @@ static BUILDIN(itemskill)
if (sd == NULL || sd->ud.skilltimer != INVALID_TIMER)
return true;
- pc->itemskill_clear(sd);
- sd->skillitem = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
- sd->skillitemlv = script_getnum(st, 3);
- sd->state.itemskill_conditions_checked = 0; // Skill casting items will check the conditions prior to the target selection in AEGIS. Thus we need a flag to prevent checking them twice.
+ pc->autocast_clear(sd);
+ sd->autocast.type = AUTOCAST_ITEM;
+ sd->autocast.skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
+ sd->autocast.skill_lv = script_getnum(st, 3);
int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE;
- sd->state.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS) ? 1 : 0; // Unset in pc_itemskill_clear().
+ sd->autocast.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS);
- if (sd->state.itemskill_check_conditions == 1) {
- if (skill->check_condition_castbegin(sd, sd->skillitem, sd->skillitemlv) == 0
- || skill->check_condition_castend(sd, sd->skillitem, sd->skillitemlv) == 0) {
- pc->itemskill_clear(sd);
+ if (sd->autocast.itemskill_check_conditions) {
+ if (skill->check_condition_castbegin(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0
+ || skill->check_condition_castend(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0) {
+ pc->autocast_clear(sd);
return true;
}
- sd->state.itemskill_conditions_checked = 1; // Unset in pc_itemskill_clear().
+ sd->autocast.itemskill_conditions_checked = true;
}
- sd->state.itemskill_no_casttime = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST) ? 1 : 0; // Unset in pc_itemskill_clear().
- sd->state.itemskill_castonself = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF) ? 1 : 0; // Unset in pc_itemskill_clear().
+ sd->autocast.itemskill_instant_cast = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST);
+ sd->autocast.itemskill_cast_on_self = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF);
- // itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention. Unset in pc_itemskill_clear().
- sd->itemskill_id = sd->skillitem;
- sd->itemskill_lv = sd->skillitemlv;
-
- clif->item_skill(sd, sd->skillitem, sd->skillitemlv);
+ clif->item_skill(sd, sd->autocast.skill_id, sd->autocast.skill_lv);
return true;
}
@@ -21429,7 +21425,10 @@ static BUILDIN(unitskilluseid)
} else {
status_calc_npc(nd, SCO_NONE);
}
+ } else if (bl->type == BL_PC) {
+ pc->autocast_clear(BL_UCAST(BL_PC, bl));
}
+
unit->skilluse_id(bl, target_id, skill_id, skill_lv);
}
@@ -21465,7 +21464,10 @@ static BUILDIN(unitskillusepos)
} else {
status_calc_npc(nd, SCO_NONE);
}
+ } else if (bl->type == BL_PC) {
+ pc->autocast_clear(BL_UCAST(BL_PC, bl));
}
+
unit->skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv);
}
diff --git a/src/map/skill.c b/src/map/skill.c
index 176ce7b58..3dccf7a9e 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -1012,14 +1012,14 @@ static int skillnotok(uint16 skill_id, struct map_session_data *sd)
if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL))
return 0; // can do any damn thing they want
- if( skill_id == AL_TELEPORT && sd->skillitem == skill_id && sd->skillitemlv > 2 )
- return 0; // Teleport lv 3 bypasses this check.[Inkfish]
+ if (skill_id == AL_TELEPORT && sd->autocast.type == AUTOCAST_ITEM && sd->autocast.skill_lv > 2)
+ return 0; // Teleport level 3 and higher bypasses this check if cast by itemskill() script commands.
// Epoque:
// This code will compare the player's attack motion value which is influenced by ASPD before
// allowing a skill to be cast. This is to prevent no-delay ACT files from spamming skills such as
// AC_DOUBLE which do not have a skill delay and are not regarded in terms of attack motion.
- if( !sd->state.autocast && sd->skillitem != skill_id && sd->canskill_tick &&
+ if (sd->autocast.type == AUTOCAST_NONE && sd->canskill_tick != 0 &&
DIFF_TICK(timer->gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100) )
{// attempted to cast a skill before the attack motion has finished
return 1;
@@ -1034,7 +1034,7 @@ static int skillnotok(uint16 skill_id, struct map_session_data *sd)
* It has been confirmed on a official server (thanks to Yommy) that item-cast skills bypass all the restrictions below
* Also, without this check, an exploit where an item casting + healing (or any other kind buff) isn't deleted after used on a restricted map
**/
- if( sd->skillitem == skill_id )
+ if (sd->autocast.type == AUTOCAST_ITEM)
return 0;
if( sd->sc.data[SC_ALL_RIDING] )
@@ -1179,6 +1179,31 @@ static int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md)
return skill->not_ok(skill_id, md->master);
}
+/**
+ * Validates the plausibility of auto-cast related data and calls pc_autocast_clear() if necessary.
+ *
+ * @param sd The character who cast the skill.
+ * @param skill_id The cast skill's ID.
+ * @param skill_lv The cast skill's level. (clif_parse_UseSkillMap() passes 0.)
+ *
+ **/
+static void skill_validate_autocast_data(struct map_session_data *sd, int skill_id, int skill_lv)
+{
+ nullpo_retv(sd);
+
+ // Determine if called by clif_parse_UseSkillMap().
+ bool use_skill_map = (skill_lv == 0 && (skill_id == AL_WARP || skill_id == AL_TELEPORT));
+
+ if (sd->autocast.type == AUTOCAST_NONE)
+ pc->autocast_clear(sd); // No auto-cast type set. Preventively unset all auto-cast related data.
+ else if (sd->autocast.type == AUTOCAST_TEMP)
+ pc->autocast_clear(sd); // AUTOCAST_TEMP should have been unset straight after usage.
+ else if (sd->autocast.skill_id == 0 || skill_id == 0 || sd->autocast.skill_id != skill_id)
+ pc->autocast_clear(sd); // Implausible skill ID.
+ else if (sd->autocast.skill_lv == 0 || (!use_skill_map && (skill_lv == 0 || sd->autocast.skill_lv != skill_lv)))
+ pc->autocast_clear(sd); // Implausible skill level.
+}
+
static struct s_skill_unit_layout *skill_get_unit_layout(uint16 skill_id, uint16 skill_lv, struct block_list *src, int x, int y)
{
int pos = skill->get_unit_layout_type(skill_id,skill_lv);
@@ -2067,9 +2092,9 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl
temp = (sd->autospell[i].id > 0) ? sd->autospell[i].id : -sd->autospell[i].id;
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
notok = skill->not_ok(temp, sd);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
if ( notok )
continue;
@@ -2120,11 +2145,12 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl
else if (temp == PF_SPIDERWEB) //Special case, due to its nature of coding.
type = CAST_GROUND;
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(sd,temp,auto_skill_lv,1);
skill->toggle_magicpower(src, temp);
skill->castend_type(type, src, tbl, temp, auto_skill_lv, tick, 0);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
+
//Set canact delay. [Skotlex]
ud = unit->bl2ud(src);
if (ud) {
@@ -2193,6 +2219,9 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl
if( sd == NULL || !skill_id )
return 0;
+ // Preserve auto-cast type if bAutoSpellOnSkill was triggered by a skill which was cast by Abracadabra, Improvised Song or an item.
+ enum autocast_type ac_type = sd->autocast.type;
+
for( i = 0; i < ARRAYLENGTH(sd->autospell3) && sd->autospell3[i].flag; i++ ) {
if( sd->autospell3[i].flag != skill_id )
continue;
@@ -2202,9 +2231,9 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl
temp = (sd->autospell3[i].id > 0) ? sd->autospell3[i].id : -sd->autospell3[i].id;
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
notok = skill->not_ok(temp, sd);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
if ( notok )
continue;
@@ -2250,14 +2279,16 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl
!battle->check_range(&sd->bl, tbl, skill->get_range2(&sd->bl, temp,skill_lv) + (temp == RG_CLOSECONFINE?0:1)) )
continue;
- sd->state.autocast = 1;
sd->autospell3[i].lock = true;
+ sd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(sd,temp,skill_lv,1);
skill->castend_type(type, &sd->bl, tbl, temp, skill_lv, tick, 0);
+ sd->autocast.type = AUTOCAST_NONE;
sd->autospell3[i].lock = false;
- sd->state.autocast = 0;
}
+ sd->autocast.type = ac_type;
+
if (sd->autobonus3[0].rate) {
for( i = 0; i < ARRAYLENGTH(sd->autobonus3); i++ ) {
if( rnd()%1000 >= sd->autobonus3[i].rate )
@@ -2404,6 +2435,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
struct unit_data *ud;
int i, auto_skill_id, auto_skill_lv, type, notok;
+ // Preserve auto-cast type if bAutoSpellWhenHit was triggered during cast of a skill which was cast by Abracadabra, Improvised Song or an item.
+ enum autocast_type ac_type = dstsd->autocast.type;
+
for (i = 0; i < ARRAYLENGTH(dstsd->autospell2) && dstsd->autospell2[i].id; i++) {
if(!(dstsd->autospell2[i].flag&attack_type&BF_WEAPONMASK &&
@@ -2419,9 +2453,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
if (attack_type&BF_LONG)
rate>>=1;
- dstsd->state.autocast = 1;
+ dstsd->autocast.type = AUTOCAST_TEMP;
notok = skill->not_ok(auto_skill_id, dstsd);
- dstsd->state.autocast = 0;
+ dstsd->autocast.type = AUTOCAST_NONE;
if ( notok )
continue;
@@ -2462,10 +2496,11 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
if( !battle->check_range(src, tbl, skill->get_range2(src, auto_skill_id,auto_skill_lv) + (auto_skill_id == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range )
continue;
- dstsd->state.autocast = 1;
+ dstsd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(dstsd,auto_skill_id,auto_skill_lv,1);
skill->castend_type(type, bl, tbl, auto_skill_id, auto_skill_lv, tick, 0);
- dstsd->state.autocast = 0;
+ dstsd->autocast.type = AUTOCAST_NONE;
+
// Set canact delay. [Skotlex]
ud = unit->bl2ud(bl);
if (ud) {
@@ -2477,6 +2512,8 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
}
}
}
+
+ dstsd->autocast.type = ac_type;
}
//Autobonus when attacked
@@ -4199,11 +4236,6 @@ static void skill_castend_type(int type, struct block_list *src, struct block_li
skill->castend_damage_id(src, bl, skill_id, skill_lv, tick, flag);
break;
}
-
- struct map_session_data *sd = BL_CAST(BL_PC, src);
-
- if (sd != NULL)
- pc->itemskill_clear(sd);
}
/*==========================================
@@ -5794,7 +5826,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH)
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); // Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish]
if (sd) { // Cooldown application
int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv);
@@ -5863,7 +5895,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
}
if( sd && ud->skill_id != SA_ABRACADABRA && ud->skill_id != WM_RANDOMIZESPELL ) // they just set the data so leave it as it is.[Inkfish]
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
if (ud->skilltimer == INVALID_TIMER) {
if(md) md->skill_idx = -1;
@@ -5912,14 +5944,14 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
}
}
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick;
ud->skill_id = ud->skill_lv = ud->skilltarget = 0;
//You can't place a skill failed packet here because it would be
//sent in ALL cases, even cases where skill_check_condition fails
//which would lead to double 'skill failed' messages u.u [Skotlex]
if(sd)
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
else if(md)
md->skill_idx = -1;
return 0;
@@ -6301,9 +6333,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
if (sd) {
// player-casted
- sd->state.abra_flag = 1;
- sd->skillitem = abra_skill_id;
- sd->skillitemlv = abra_skill_lv;
+ sd->autocast.type = AUTOCAST_ABRA;
+ sd->autocast.skill_id = abra_skill_id;
+ sd->autocast.skill_lv = abra_skill_lv;
clif->item_skill(sd, abra_skill_id, abra_skill_lv);
} else {
// mob-casted
@@ -7432,7 +7464,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
map->freeblock_unlock();
return 1;
}
- if( sd->skillitem != skill_id )
+ if (sd->autocast.type == AUTOCAST_NONE)
status_zap(src, 0, skill->get_sp(skill_id, skill_lv)); // consume sp only if succeeded
}
break;
@@ -7469,7 +7501,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
break;
}
- if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1 ) || skill_lv == 3 )
+ if (sd->autocast.type == AUTOCAST_TEMP || ((sd->autocast.skill_id == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1) || skill_lv == 3)
{
if( skill_lv == 1 )
pc->randomwarp(sd,CLR_TELEPORT);
@@ -10043,9 +10075,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
clif->skill_nodamage (src, bl, skill_id, skill_lv, 1);
if (sd != NULL) {
- sd->state.abra_flag = 2;
- sd->skillitem = improv_skill_id;
- sd->skillitemlv = improv_skill_lv;
+ sd->autocast.type = AUTOCAST_IMPROVISE;
+ sd->autocast.skill_id = improv_skill_id;
+ sd->autocast.skill_lv = improv_skill_lv;
clif->item_skill(sd, improv_skill_id, improv_skill_lv);
} else {
struct unit_data *ud = unit->bl2ud(src);
@@ -10814,7 +10846,7 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
if (ud->walktimer != INVALID_TIMER)
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv);
if (sd) { //Cooldown application
int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv);
@@ -10843,8 +10875,8 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
map->freeblock_lock();
skill->castend_pos2(src,ud->skillx,ud->skilly,ud->skill_id,ud->skill_lv,tick,0);
- if( sd && sd->skillitem != AL_WARP ) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish]
- sd->skillitem = sd->skillitemlv = 0;
+ if (sd != NULL && sd->autocast.skill_id != AL_WARP) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish]
+ pc->autocast_clear(sd);
unit->set_dir(src, map->calc_dir(src, ud->skillx, ud->skilly));
@@ -10858,11 +10890,11 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
return 1;
} while(0);
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick;
ud->skill_id = ud->skill_lv = 0;
if(sd)
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
else if(md)
md->skill_idx = -1;
return 0;
@@ -10992,7 +11024,7 @@ static int skill_castend_map(struct map_session_data *sd, uint16 skill_id, const
}
}
- lv = sd->skillitem==skill_id?sd->skillitemlv:pc->checkskill(sd,skill_id);
+ lv = (sd->autocast.type > AUTOCAST_TEMP) ? sd->autocast.skill_lv : pc->checkskill(sd, skill_id);
wx = sd->menuskill_val>>16;
wy = sd->menuskill_val&0xffff;
@@ -11015,7 +11047,7 @@ static int skill_castend_map(struct map_session_data *sd, uint16 skill_id, const
}
skill->consume_requirement(sd,sd->menuskill_id,lv,2);
- sd->skillitem = sd->skillitemlv = 0; // Clear data that's skipped in 'skill_castend_pos' [Inkfish]
+ pc->autocast_clear(sd); // Clear data which was skipped in skill_castend_pos().
if((group=skill->unitsetting(&sd->bl,skill_id,lv,wx,wy,0))==NULL) {
skill_failed(sd);
@@ -14014,22 +14046,6 @@ static bool skill_is_combo(int skill_id)
return false;
}
-/**
- * Checks if a skill is casted by an item (itemskill() script command).
- *
- * @param sd The charcater's session data.
- * @param skill_id The skill's ID.
- * @param skill_lv The skill's level.
- * @return true if skill is casted by an item, otherwise false.
- */
-static bool skill_is_item_skill(struct map_session_data *sd, int skill_id, int skill_lv)
-{
- nullpo_retr(false, sd);
-
- return (sd->skillitem == skill_id && sd->skillitemlv == skill_lv
- && sd->itemskill_id == skill_id && sd->itemskill_lv == skill_lv);
-}
-
static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv)
{
struct status_data *st;
@@ -14044,13 +14060,13 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
if (sd->chat_id != 0)
return 0;
- if ((sd->state.itemskill_conditions_checked == 1 || sd->state.itemskill_check_conditions == 0)
- && skill->is_item_skill(sd, skill_id, skill_lv)) {
+ if (((sd->autocast.itemskill_conditions_checked || !sd->autocast.itemskill_check_conditions)
+ && sd->autocast.type == AUTOCAST_ITEM) || sd->autocast.type == AUTOCAST_IMPROVISE) {
return 1;
}
- if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id) {
- //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
+ if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->autocast.type != AUTOCAST_ITEM) {
+ // GMs don't override the AUTOCAST_ITEM check, otherwise they can use items without them being consumed!
sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check.
sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
return 1;
@@ -14081,30 +14097,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
if( !sc->count )
sc = NULL;
- if( sd->skillitem == skill_id ) {
- if( sd->state.abra_flag ) // Hocus-Pocus was used. [Inkfish]
- sd->state.abra_flag = 0;
- else {
- int i;
- // When a target was selected, consume items that were skipped in pc_use_item [Skotlex]
- if( (i = sd->itemindex) == -1 ||
- sd->status.inventory[i].nameid != sd->itemid ||
- sd->inventory_data[i] == NULL ||
- sd->status.inventory[i].amount < 1
- ) {
- //Something went wrong, item exploit?
- sd->itemid = sd->itemindex = -1;
- return 0;
- }
-
- //Consume
- sd->itemid = sd->itemindex = -1;
- if (sd->status.inventory[i].expire_time == 0 && sd->inventory_data[i]->flag.delay_consume == 1) // Rental usable items are not consumed until expiration
- pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME);
- }
- }
-
- if (pc_is90overweight(sd) && sd->skillitem != skill_id) { /// Skill casting items ignore the overweight restriction. [Kenpachi]
+ if (pc_is90overweight(sd) && sd->autocast.type != AUTOCAST_ITEM) { // Skill casting items ignore the overweight restriction.
clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0);
return 0;
}
@@ -14975,7 +14968,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
return 0;
}
- if (require.sp > 0 && st->sp < (unsigned int)require.sp && sd->skillitem != skill_id) { /// Skill casting items and Hocus-Pocus skills don't consume SP. [Kenpachi]
+ if (require.sp > 0 && st->sp < (unsigned int)require.sp && sd->autocast.type == AUTOCAST_NONE) { // Auto-cast skills don't consume SP.
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SP_INSUFFICIENT, 0, 0);
return 0;
}
@@ -15033,13 +15026,13 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski
if (sd->chat_id != 0)
return 0;
- if ((sd->state.itemskill_conditions_checked == 1 || sd->state.itemskill_check_conditions == 0)
- && skill->is_item_skill(sd, skill_id, skill_lv)) {
+ if (((sd->autocast.itemskill_conditions_checked || !sd->autocast.itemskill_check_conditions)
+ && sd->autocast.type == AUTOCAST_ITEM) || sd->autocast.type == AUTOCAST_IMPROVISE) {
return 1;
}
- if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) {
- //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
+ if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->autocast.type != AUTOCAST_ITEM) {
+ // GMs don't override the AUTOCAST_ITEM check, otherwise they can use items without them being consumed!
sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check.
sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
return 1;
@@ -15066,7 +15059,7 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski
break;
}
- if (pc_is90overweight(sd) && sd->skillitem != skill_id) { /// Skill casting items ignore the overweight restriction. [Kenpachi]
+ if (pc_is90overweight(sd) && sd->autocast.type != AUTOCAST_ITEM) { // Skill casting items ignore the overweight restriction.
clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0);
return 0;
}
@@ -15237,8 +15230,10 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i
nullpo_ret(sd);
- if (sd->state.itemskill_check_conditions == 0 && skill->is_item_skill(sd, skill_id, skill_lv))
+ if ((!sd->autocast.itemskill_check_conditions && sd->autocast.type == AUTOCAST_ITEM)
+ || sd->autocast.type == AUTOCAST_IMPROVISE) {
return 1;
+ }
req = skill->get_requirement(sd,skill_id,skill_lv);
@@ -15254,7 +15249,7 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i
break;
default:
- if (sd->state.autocast == 1 || sd->skillitem == skill_id) /// Skill casting items and Hocus-Pocus skills don't consume SP. [Kenpachi]
+ if (sd->autocast.type != AUTOCAST_NONE) // Auto-cast skills don't consume SP.
req.sp = 0;
break;
@@ -21640,7 +21635,6 @@ void skill_defaults(void)
skill->cast_fix_sc = skill_castfix_sc;
skill->vf_cast_fix = skill_vfcastfix;
skill->delay_fix = skill_delay_fix;
- skill->is_item_skill = skill_is_item_skill;
skill->check_condition_castbegin = skill_check_condition_castbegin;
skill->check_condition_castend = skill_check_condition_castend;
skill->consume_requirement = skill_consume_requirement;
@@ -21666,6 +21660,7 @@ void skill_defaults(void)
skill->not_ok_hom = skillnotok_hom;
skill->not_ok_hom_unknown = skillnotok_hom_unknown;
skill->not_ok_mercenary = skillnotok_mercenary;
+ skill->validate_autocast_data = skill_validate_autocast_data;
skill->chastle_mob_changetarget = skill_chastle_mob_changetarget;
skill->can_produce_mix = skill_can_produce_mix;
skill->produce_mix = skill_produce_mix;
diff --git a/src/map/skill.h b/src/map/skill.h
index c65547181..65195dc75 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -1724,6 +1724,15 @@ enum {
UNT_MAX = 0x190
};
+/** Constants to identify the auto-cast type. **/
+enum autocast_type {
+ AUTOCAST_NONE = 0,
+ AUTOCAST_TEMP, // Used when type is only required during the execution of the calling instance. (For example bAutoSpell* skills.)
+ AUTOCAST_ABRA, // Used for Abracadabra (Hocus pocus).
+ AUTOCAST_IMPROVISE, // Used for Improvised Song.
+ AUTOCAST_ITEM, // Used for itemskill() script command.
+};
+
/**
* Structures
**/
@@ -2020,7 +2029,6 @@ struct skill_interface {
int (*cast_fix_sc) ( struct block_list *bl, int time);
int (*vf_cast_fix) ( struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv);
int (*delay_fix) ( struct block_list *bl, uint16 skill_id, uint16 skill_lv);
- bool (*is_item_skill) (struct map_session_data *sd, int skill_id, int skill_lv);
int (*check_condition_castbegin) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
int (*check_condition_castend) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
int (*consume_requirement) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, short type);
@@ -2046,6 +2054,7 @@ struct skill_interface {
int (*not_ok_hom) (uint16 skill_id, struct homun_data *hd);
int (*not_ok_hom_unknown) (uint16 skill_id, struct homun_data *hd);
int (*not_ok_mercenary) (uint16 skill_id, struct mercenary_data *md);
+ void (*validate_autocast_data) (struct map_session_data *sd, int skill_id, int skill_lv);
int (*chastle_mob_changetarget) (struct block_list *bl,va_list ap);
int (*can_produce_mix) ( struct map_session_data *sd, int nameid, int trigger, int qty);
int (*produce_mix) ( struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty );
diff --git a/src/map/status.c b/src/map/status.c
index 3b7658769..4e7094569 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -1591,7 +1591,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ
}
if( skill_id ) {
- if (src != NULL && (sd == NULL || sd->skillitem == 0)) {
+ if (src != NULL && (sd == NULL || sd->autocast.type != AUTOCAST_ITEM)) {
// Items that cast skills using 'itemskill' will not be handled by map_zone_db.
int i;
@@ -1635,7 +1635,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ
if (src != NULL
&& map->getcell(src->m, src, src->x, src->y, CELL_CHKLANDPROTECTOR)
&& !(st->mode&MD_BOSS)
- && (src->type != BL_PC || sd->skillitem != skill_id))
+ && (src->type != BL_PC || sd->autocast.type != AUTOCAST_ITEM))
return 0;
break;
default:
@@ -1714,7 +1714,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ
return 0; //Can't amp out of Wand of Hermode :/ [Skotlex]
}
- if (skill_id != 0 /* Do not block item-casted skills.*/ && (src->type != BL_PC || sd->skillitem != skill_id)) {
+ if (skill_id != 0 /* Do not block item-casted skills.*/ && (src->type != BL_PC || sd->autocast.type != AUTOCAST_ITEM)) {
//Skills blocked through status changes...
if (!flag && ( //Blocked only from using the skill (stuff like autospell may still go through
sc->data[SC_SILENCE] ||
diff --git a/src/map/unit.c b/src/map/unit.c
index a879a125f..56ddb5917 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -1148,8 +1148,10 @@ static int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_
int ret = unit->skilluse_id2(src, target_id, skill_id, skill_lv, casttime, castcancel);
struct map_session_data *sd = BL_CAST(BL_PC, src);
- if (sd != NULL && (ret == 0 || !skill->is_item_skill(sd, skill_id, skill_lv)))
- pc->itemskill_clear(sd);
+ if (sd != NULL && ret == 0)
+ pc->autocast_clear(sd); // Error in unit_skilluse_id2().
+ else if (sd != NULL && ret != 0 && skill_id != SA_ABRACADABRA && skill_id != WM_RANDOMIZESPELL)
+ skill->validate_autocast_data(sd, skill_id, skill_lv);
return ret;
}
@@ -1708,7 +1710,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
if (!ud->state.running) //need TK_RUN or WUGDASH handler to be done before that, see bugreport:6026
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);// even though this is not how official works but this will do the trick. bugreport:6829
- if (sd != NULL && sd->state.itemskill_no_casttime == 1 && skill->is_item_skill(sd, skill_id, skill_lv))
+ if (sd != NULL && sd->autocast.itemskill_instant_cast && sd->autocast.type == AUTOCAST_ITEM)
casttime = 0;
// in official this is triggered even if no cast time.
@@ -1746,7 +1748,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
if( casttime <= 0 )
ud->state.skillcastcancel = 0;
- if( !sd || sd->skillitem != skill_id || skill->get_cast(skill_id,skill_lv) )
+ if (sd == NULL || sd->autocast.type < AUTOCAST_ABRA || skill->get_cast(skill_id, skill_lv) != 0)
ud->canact_tick = tick + casttime + 100;
if( sd )
{
@@ -1785,8 +1787,10 @@ static int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_
int ret = unit->skilluse_pos2(src, skill_x, skill_y, skill_id, skill_lv, casttime, castcancel);
struct map_session_data *sd = BL_CAST(BL_PC, src);
- if (sd != NULL && (ret == 0 || !skill->is_item_skill(sd, skill_id, skill_lv)))
- pc->itemskill_clear(sd);
+ if (sd != NULL && ret == 0)
+ pc->autocast_clear(sd); // Error in unit_skilluse_pos2().
+ else if (sd != NULL && ret != 0 && skill_id != SA_ABRACADABRA && skill_id != WM_RANDOMIZESPELL)
+ skill->validate_autocast_data(sd, skill_id, skill_lv);
return ret;
}
@@ -1883,7 +1887,7 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill
}
ud->state.skillcastcancel = castcancel&&casttime>0?1:0;
- if( !sd || sd->skillitem != skill_id || skill->get_cast(skill_id,skill_lv) )
+ if (sd == NULL || sd->autocast.type < AUTOCAST_ABRA || skill->get_cast(skill_id, skill_lv) != 0)
ud->canact_tick = tick + casttime + 100;
#if 0
if (sd) {
@@ -1914,7 +1918,7 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);
- if (sd != NULL && sd->state.itemskill_no_casttime == 1 && skill->is_item_skill(sd, skill_id, skill_lv))
+ if (sd != NULL && sd->autocast.itemskill_instant_cast && sd->autocast.type == AUTOCAST_ITEM)
casttime = 0;
// in official this is triggered even if no cast time.
diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc
index f01d0250d..dc516c355 100644
--- a/src/plugins/HPMHooking/HPMHooking.Defs.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc
@@ -6188,8 +6188,8 @@ typedef int (*HPMHOOK_pre_pc_checkitem) (struct map_session_data **sd);
typedef int (*HPMHOOK_post_pc_checkitem) (int retVal___, struct map_session_data *sd);
typedef int (*HPMHOOK_pre_pc_useitem) (struct map_session_data **sd, int *n);
typedef int (*HPMHOOK_post_pc_useitem) (int retVal___, struct map_session_data *sd, int n);
-typedef int (*HPMHOOK_pre_pc_itemskill_clear) (struct map_session_data **sd);
-typedef int (*HPMHOOK_post_pc_itemskill_clear) (int retVal___, struct map_session_data *sd);
+typedef int (*HPMHOOK_pre_pc_autocast_clear) (struct map_session_data **sd);
+typedef int (*HPMHOOK_post_pc_autocast_clear) (int retVal___, struct map_session_data *sd);
typedef int (*HPMHOOK_pre_pc_skillatk_bonus) (struct map_session_data **sd, uint16 *skill_id);
typedef int (*HPMHOOK_post_pc_skillatk_bonus) (int retVal___, struct map_session_data *sd, uint16 skill_id);
typedef int (*HPMHOOK_pre_pc_skillheal_bonus) (struct map_session_data **sd, uint16 *skill_id);
@@ -7336,8 +7336,6 @@ typedef int (*HPMHOOK_pre_skill_vf_cast_fix) (struct block_list **bl, double *ti
typedef int (*HPMHOOK_post_skill_vf_cast_fix) (int retVal___, struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv);
typedef int (*HPMHOOK_pre_skill_delay_fix) (struct block_list **bl, uint16 *skill_id, uint16 *skill_lv);
typedef int (*HPMHOOK_post_skill_delay_fix) (int retVal___, struct block_list *bl, uint16 skill_id, uint16 skill_lv);
-typedef bool (*HPMHOOK_pre_skill_is_item_skill) (struct map_session_data **sd, int *skill_id, int *skill_lv);
-typedef bool (*HPMHOOK_post_skill_is_item_skill) (bool retVal___, struct map_session_data *sd, int skill_id, int skill_lv);
typedef int (*HPMHOOK_pre_skill_check_condition_castbegin) (struct map_session_data **sd, uint16 *skill_id, uint16 *skill_lv);
typedef int (*HPMHOOK_post_skill_check_condition_castbegin) (int retVal___, struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
typedef int (*HPMHOOK_pre_skill_check_condition_castend) (struct map_session_data **sd, uint16 *skill_id, uint16 *skill_lv);
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index 24635d7e3..5047ae64d 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -4768,8 +4768,8 @@ struct {
struct HPMHookPoint *HP_pc_checkitem_post;
struct HPMHookPoint *HP_pc_useitem_pre;
struct HPMHookPoint *HP_pc_useitem_post;
- struct HPMHookPoint *HP_pc_itemskill_clear_pre;
- struct HPMHookPoint *HP_pc_itemskill_clear_post;
+ struct HPMHookPoint *HP_pc_autocast_clear_pre;
+ struct HPMHookPoint *HP_pc_autocast_clear_post;
struct HPMHookPoint *HP_pc_skillatk_bonus_pre;
struct HPMHookPoint *HP_pc_skillatk_bonus_post;
struct HPMHookPoint *HP_pc_skillheal_bonus_pre;
@@ -5860,8 +5860,6 @@ struct {
struct HPMHookPoint *HP_skill_vf_cast_fix_post;
struct HPMHookPoint *HP_skill_delay_fix_pre;
struct HPMHookPoint *HP_skill_delay_fix_post;
- struct HPMHookPoint *HP_skill_is_item_skill_pre;
- struct HPMHookPoint *HP_skill_is_item_skill_post;
struct HPMHookPoint *HP_skill_check_condition_castbegin_pre;
struct HPMHookPoint *HP_skill_check_condition_castbegin_post;
struct HPMHookPoint *HP_skill_check_condition_castend_pre;
@@ -11647,8 +11645,8 @@ struct {
int HP_pc_checkitem_post;
int HP_pc_useitem_pre;
int HP_pc_useitem_post;
- int HP_pc_itemskill_clear_pre;
- int HP_pc_itemskill_clear_post;
+ int HP_pc_autocast_clear_pre;
+ int HP_pc_autocast_clear_post;
int HP_pc_skillatk_bonus_pre;
int HP_pc_skillatk_bonus_post;
int HP_pc_skillheal_bonus_pre;
@@ -12739,8 +12737,6 @@ struct {
int HP_skill_vf_cast_fix_post;
int HP_skill_delay_fix_pre;
int HP_skill_delay_fix_post;
- int HP_skill_is_item_skill_pre;
- int HP_skill_is_item_skill_post;
int HP_skill_check_condition_castbegin_pre;
int HP_skill_check_condition_castbegin_post;
int HP_skill_check_condition_castend_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index cc8d59844..4c3b1b720 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -2442,7 +2442,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(pc->unequipitem_pos, HP_pc_unequipitem_pos) },
{ HP_POP(pc->checkitem, HP_pc_checkitem) },
{ HP_POP(pc->useitem, HP_pc_useitem) },
- { HP_POP(pc->itemskill_clear, HP_pc_itemskill_clear) },
+ { HP_POP(pc->autocast_clear, HP_pc_autocast_clear) },
{ HP_POP(pc->skillatk_bonus, HP_pc_skillatk_bonus) },
{ HP_POP(pc->skillheal_bonus, HP_pc_skillheal_bonus) },
{ HP_POP(pc->skillheal2_bonus, HP_pc_skillheal2_bonus) },
@@ -2999,7 +2999,6 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(skill->cast_fix_sc, HP_skill_cast_fix_sc) },
{ HP_POP(skill->vf_cast_fix, HP_skill_vf_cast_fix) },
{ HP_POP(skill->delay_fix, HP_skill_delay_fix) },
- { HP_POP(skill->is_item_skill, HP_skill_is_item_skill) },
{ HP_POP(skill->check_condition_castbegin, HP_skill_check_condition_castbegin) },
{ HP_POP(skill->check_condition_castend, HP_skill_check_condition_castend) },
{ HP_POP(skill->consume_requirement, HP_skill_consume_requirement) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index a9ed12c31..af3f355b3 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -63411,14 +63411,14 @@ int HP_pc_useitem(struct map_session_data *sd, int n) {
}
return retVal___;
}
-int HP_pc_itemskill_clear(struct map_session_data *sd) {
+int HP_pc_autocast_clear(struct map_session_data *sd) {
int hIndex = 0;
int retVal___ = 0;
- if (HPMHooks.count.HP_pc_itemskill_clear_pre > 0) {
+ if (HPMHooks.count.HP_pc_autocast_clear_pre > 0) {
int (*preHookFunc) (struct map_session_data **sd);
*HPMforce_return = false;
- for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_itemskill_clear_pre; hIndex++) {
- preHookFunc = HPMHooks.list.HP_pc_itemskill_clear_pre[hIndex].func;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_autocast_clear_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_pc_autocast_clear_pre[hIndex].func;
retVal___ = preHookFunc(&sd);
}
if (*HPMforce_return) {
@@ -63427,12 +63427,12 @@ int HP_pc_itemskill_clear(struct map_session_data *sd) {
}
}
{
- retVal___ = HPMHooks.source.pc.itemskill_clear(sd);
+ retVal___ = HPMHooks.source.pc.autocast_clear(sd);
}
- if (HPMHooks.count.HP_pc_itemskill_clear_post > 0) {
+ if (HPMHooks.count.HP_pc_autocast_clear_post > 0) {
int (*postHookFunc) (int retVal___, struct map_session_data *sd);
- for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_itemskill_clear_post; hIndex++) {
- postHookFunc = HPMHooks.list.HP_pc_itemskill_clear_post[hIndex].func;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_autocast_clear_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_pc_autocast_clear_post[hIndex].func;
retVal___ = postHookFunc(retVal___, sd);
}
}
@@ -78215,33 +78215,6 @@ int HP_skill_delay_fix(struct block_list *bl, uint16 skill_id, uint16 skill_lv)
}
return retVal___;
}
-bool HP_skill_is_item_skill(struct map_session_data *sd, int skill_id, int skill_lv) {
- int hIndex = 0;
- bool retVal___ = false;
- if (HPMHooks.count.HP_skill_is_item_skill_pre > 0) {
- bool (*preHookFunc) (struct map_session_data **sd, int *skill_id, int *skill_lv);
- *HPMforce_return = false;
- for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_is_item_skill_pre; hIndex++) {
- preHookFunc = HPMHooks.list.HP_skill_is_item_skill_pre[hIndex].func;
- retVal___ = preHookFunc(&sd, &skill_id, &skill_lv);
- }
- if (*HPMforce_return) {
- *HPMforce_return = false;
- return retVal___;
- }
- }
- {
- retVal___ = HPMHooks.source.skill.is_item_skill(sd, skill_id, skill_lv);
- }
- if (HPMHooks.count.HP_skill_is_item_skill_post > 0) {
- bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int skill_id, int skill_lv);
- for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_is_item_skill_post; hIndex++) {
- postHookFunc = HPMHooks.list.HP_skill_is_item_skill_post[hIndex].func;
- retVal___ = postHookFunc(retVal___, sd, skill_id, skill_lv);
- }
- }
- return retVal___;
-}
int HP_skill_check_condition_castbegin(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) {
int hIndex = 0;
int retVal___ = 0;