From 1098b588625774ca2cf4e05527b00fd4d0187919 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 20 Jan 2020 09:49:23 +0100 Subject: Fixed skill conditions check and parameter in itemskill() script command. * itemskill() script command should check for the skill's conditions and also consumes them. SP are not consumed. * The same applies to Hocus-pocus skill. Conditions should be checked and consumed, SP are not consumed. * This was bugged for more than 6 years now. See linked bug report and commits. Related bug: * https://herc.ws/oldboard/tracker/issue-7210-itemskill-command-does-not-check-for-required-items/ Related commits: * https://github.com/HerculesWS/Hercules/commit/b864056b8d088660fca9129bddad477732ed8df9 * https://github.com/HerculesWS/Hercules/commit/07272f7a16db87970583286db03167ca79604a69 --- src/map/unit.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'src/map/unit.c') diff --git a/src/map/unit.c b/src/map/unit.c index 482440978..923438d78 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1041,11 +1041,19 @@ static int unit_stop_walking(struct block_list *bl, int flag) static int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv) { - return unit->skilluse_id2( - src, target_id, skill_id, skill_lv, - skill->cast_fix(src, skill_id, skill_lv), - skill->get_castcancel(skill_id) - ); + int casttime = skill->cast_fix(src, skill_id, skill_lv); + int castcancel = skill->get_castcancel(skill_id); + 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) { + sd->itemskill_id = 0; + sd->itemskill_lv = 0; + sd->state.itemskill_conditions_checked = 0; + sd->state.itemskill_no_conditions = 0; + } + + return ret; } static int unit_is_walking(struct block_list *bl) @@ -1418,15 +1426,8 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill } } - if (sd) { - /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ -#if 0 - if (sd->skillitem != skill_id && !skill->check_condition_castbegin(sd, skill_id, skill_lv)) -#else - if (!skill->check_condition_castbegin(sd, skill_id, skill_lv)) -#endif - return 0; - } + if (sd != NULL && skill->check_condition_castbegin(sd, skill_id, skill_lv) == 0) + return 0; if (src->type == BL_MOB) { const struct mob_data *src_md = BL_UCCAST(BL_MOB, src); @@ -1678,11 +1679,19 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill static int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv) { - return unit->skilluse_pos2( - src, skill_x, skill_y, skill_id, skill_lv, - skill->cast_fix(src, skill_id, skill_lv), - skill->get_castcancel(skill_id) - ); + int casttime = skill->cast_fix(src, skill_id, skill_lv); + int castcancel = skill->get_castcancel(skill_id); + 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) { + sd->itemskill_id = 0; + sd->itemskill_lv = 0; + sd->state.itemskill_conditions_checked = 0; + sd->state.itemskill_no_conditions = 0; + } + + return ret; } static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel) -- cgit v1.2.3-70-g09d2 From 38a504a04a2c864938ef3e105d0ce22332ff0b7a Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 20 Jan 2020 10:08:00 +0100 Subject: Added a new option flag to itemskill() script command, to be able to cast a skill without cast time. --- src/map/pc.h | 3 ++- src/map/script.c | 3 ++- src/map/script.h | 1 + src/map/unit.c | 13 +++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/map/unit.c') diff --git a/src/map/pc.h b/src/map/pc.h index 4d7a7eef0..1540482c3 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -242,6 +242,7 @@ struct map_session_data { 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_no_conditions : 1; // Used by itemskill() script command, to ignore skill conditions and don't consume them. + unsigned int itemskill_no_casttime : 1; // Used by itemskill() script command, to cast skill instantaneously. } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -647,7 +648,7 @@ END_ZEROED_BLOCK; VECTOR_DECL(int) title_ids; /* - * itemskill_conditions_checked/itemskill_no_conditions abuse prevention. + * itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime 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. diff --git a/src/map/script.c b/src/map/script.c index 470ad9408..acf9fb9ff 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11003,7 +11003,7 @@ static BUILDIN(itemskill) sd->skillitem=id; sd->skillitemlv=lv; - /// itemskill_conditions_checked/itemskill_no_conditions abuse prevention. + /// itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime abuse prevention. /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. sd->itemskill_id = id; sd->itemskill_lv = lv; @@ -11012,6 +11012,7 @@ static BUILDIN(itemskill) 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. sd->state.itemskill_no_conditions = ((flag & ISF_IGNORECONDITIONS) == ISF_IGNORECONDITIONS) ? 1 : 0; /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. + sd->state.itemskill_no_casttime = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST) ? 1 : 0; /// /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. if (sd->state.itemskill_no_conditions == 0) { if (skill->check_condition_castbegin(sd, id, lv) == 0 || skill->check_condition_castend(sd, id, lv) == 0) diff --git a/src/map/script.h b/src/map/script.h index c981a895d..8167a9efd 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -570,6 +570,7 @@ enum mado_type { enum itemskill_flag { ISF_NONE = 0x00, ISF_IGNORECONDITIONS = 0x01, // Ignore skill conditions and don't consume them. + ISF_INSTANTCAST = 0x02, // Cast skill instantaneously. }; /** diff --git a/src/map/unit.c b/src/map/unit.c index 923438d78..ee721bb64 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1051,6 +1051,7 @@ static int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_ sd->itemskill_lv = 0; sd->state.itemskill_conditions_checked = 0; sd->state.itemskill_no_conditions = 0; + sd->state.itemskill_no_casttime = 0; } return ret; @@ -1610,6 +1611,11 @@ 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 && sd->itemskill_id == sd->skillitem + && sd->itemskill_lv == sd->skillitemlv) { + casttime = 0; + } + // in official this is triggered even if no cast time. clif->useskill(src, src->id, target_id, 0,0, skill_id, skill_lv, casttime); if( casttime > 0 || temp ) @@ -1689,6 +1695,7 @@ static int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_ sd->itemskill_lv = 0; sd->state.itemskill_conditions_checked = 0; sd->state.itemskill_no_conditions = 0; + sd->state.itemskill_no_casttime = 0; } return ret; @@ -1816,6 +1823,12 @@ 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 && sd->itemskill_id == sd->skillitem + && sd->itemskill_lv == sd->skillitemlv) { + casttime = 0; + } + // in official this is triggered even if no cast time. clif->useskill(src, src->id, 0, skill_x, skill_y, skill_id, skill_lv, casttime); if( casttime > 0 ) { -- cgit v1.2.3-70-g09d2 From a67dddb0c21be9c6ceeb174db023d3b9db4a9db9 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 20 Jan 2020 10:30:03 +0100 Subject: Added a new option flag to itemskill() script command to be able to forcefully cast skill on on invoking character. --- src/map/clif.c | 8 +++++++- src/map/pc.h | 3 ++- src/map/script.c | 5 +++-- src/map/script.h | 1 + src/map/unit.c | 2 ++ 5 files changed, 15 insertions(+), 4 deletions(-) (limited to 'src/map/unit.c') diff --git a/src/map/clif.c b/src/map/clif.c index 868117a96..50b81d25d 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -6759,10 +6759,16 @@ static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16 nullpo_retv(sd); fd=sd->fd; + + int type = skill->get_inf(skill_id); + + if (sd->state.itemskill_castonself == 1 && sd->itemskill_id == sd->skillitem && sd->itemskill_lv == sd->skillitemlv) + type = INF_SELF_SKILL; + WFIFOHEAD(fd,packet_len(0x147)); WFIFOW(fd, 0)=0x147; WFIFOW(fd, 2)=skill_id; - WFIFOL(fd, 4)=skill->get_inf(skill_id); + WFIFOL(fd, 4) = type; WFIFOW(fd, 8)=skill_lv; WFIFOW(fd,10)=skill->get_sp(skill_id,skill_lv); WFIFOW(fd,12)=skill->get_range2(&sd->bl, skill_id,skill_lv); diff --git a/src/map/pc.h b/src/map/pc.h index 1540482c3..26e33a400 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -243,6 +243,7 @@ struct map_session_data { unsigned int itemskill_conditions_checked : 1; // Used by itemskill() script command, to prevent second check of conditions after target was selected. unsigned int itemskill_no_conditions : 1; // Used by itemskill() script command, to ignore skill conditions and don't 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; @@ -648,7 +649,7 @@ END_ZEROED_BLOCK; VECTOR_DECL(int) title_ids; /* - * itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime abuse prevention. + * 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. diff --git a/src/map/script.c b/src/map/script.c index acf9fb9ff..b51c1a915 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11003,7 +11003,7 @@ static BUILDIN(itemskill) sd->skillitem=id; sd->skillitemlv=lv; - /// itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime abuse prevention. + /// itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention. /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. sd->itemskill_id = id; sd->itemskill_lv = lv; @@ -11013,6 +11013,7 @@ static BUILDIN(itemskill) 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. sd->state.itemskill_no_conditions = ((flag & ISF_IGNORECONDITIONS) == ISF_IGNORECONDITIONS) ? 1 : 0; /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. sd->state.itemskill_no_casttime = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST) ? 1 : 0; /// /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. + sd->state.itemskill_castonself = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF) ? 1 : 0; /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. if (sd->state.itemskill_no_conditions == 0) { if (skill->check_condition_castbegin(sd, id, lv) == 0 || skill->check_condition_castend(sd, id, lv) == 0) @@ -11021,7 +11022,7 @@ static BUILDIN(itemskill) sd->state.itemskill_conditions_checked = 1; /// Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. } - clif->item_skill(sd,id,lv); + clif->item_skill(sd, id, lv); return true; } /*========================================== diff --git a/src/map/script.h b/src/map/script.h index 8167a9efd..857d22c61 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -571,6 +571,7 @@ enum itemskill_flag { ISF_NONE = 0x00, ISF_IGNORECONDITIONS = 0x01, // Ignore skill conditions and don't consume them. ISF_INSTANTCAST = 0x02, // Cast skill instantaneously. + ISF_CASTONSELF = 0x04, // Forcefully cast skill on invoking character without showing the target selection cursor. }; /** diff --git a/src/map/unit.c b/src/map/unit.c index ee721bb64..3ad94d20a 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1052,6 +1052,7 @@ static int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_ sd->state.itemskill_conditions_checked = 0; sd->state.itemskill_no_conditions = 0; sd->state.itemskill_no_casttime = 0; + sd->state.itemskill_castonself = 0; } return ret; @@ -1696,6 +1697,7 @@ static int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_ sd->state.itemskill_conditions_checked = 0; sd->state.itemskill_no_conditions = 0; sd->state.itemskill_no_casttime = 0; + sd->state.itemskill_castonself = 0; } return ret; -- cgit v1.2.3-70-g09d2 From 7b003f2028906218bb6cff68e5e97ec47ad6681e Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sun, 26 Jan 2020 21:52:43 +0100 Subject: Added pc_itemskill_clear() function. --- src/map/clif.c | 1 + src/map/pc.c | 21 +++++++++++++++++++++ src/map/pc.h | 1 + src/map/script.c | 11 +++++------ src/map/skill.c | 5 +++++ src/map/unit.c | 20 ++++---------------- 6 files changed, 37 insertions(+), 22 deletions(-) (limited to 'src/map/unit.c') diff --git a/src/map/clif.c b/src/map/clif.c index 50b81d25d..24de61ec0 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -12932,6 +12932,7 @@ static void clif_parse_UseSkillMap(int fd, struct map_session_data *sd) pc->delinvincibletimer(sd); skill->castend_map(sd,skill_id,map_name); + pc->itemskill_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 a404d93e7..c96e957c7 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5321,6 +5321,26 @@ static int pc_useitem(struct map_session_data *sd, int n) return 1; } +/** + * Sets state flags and helper variables, used by itemskill() script command, to 0. + * + * @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) +{ + nullpo_ret(sd); + + sd->itemskill_id = 0; + sd->itemskill_lv = 0; + sd->state.itemskill_conditions_checked = 0; + sd->state.itemskill_no_conditions = 0; + sd->state.itemskill_no_casttime = 0; + sd->state.itemskill_castonself = 0; + + return 1; +} + /*========================================== * Add item on cart for given index. * Return: @@ -12662,6 +12682,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->skillatk_bonus = pc_skillatk_bonus; pc->skillheal_bonus = pc_skillheal_bonus; diff --git a/src/map/pc.h b/src/map/pc.h index 26e33a400..e940c3310 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -1034,6 +1034,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 (*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 b87a46785..c1eb2e8b7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11007,7 +11007,7 @@ static BUILDIN(itemskill) int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE; - sd->state.itemskill_no_conditions = ((flag & ISF_IGNORECONDITIONS) == ISF_IGNORECONDITIONS) ? 1 : 0; // Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. + sd->state.itemskill_no_conditions = ((flag & ISF_IGNORECONDITIONS) == ISF_IGNORECONDITIONS) ? 1 : 0; // Unset in pc_itemskill_clear(). if (sd->state.itemskill_no_conditions == 0) { if (skill->check_condition_castbegin(sd, sd->skillitem, sd->skillitemlv) == 0 @@ -11015,14 +11015,13 @@ static BUILDIN(itemskill) return true; } - sd->state.itemskill_conditions_checked = 1; // Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. + sd->state.itemskill_conditions_checked = 1; // Unset in pc_itemskill_clear(). } - sd->state.itemskill_no_casttime = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST) ? 1 : 0; // Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. - sd->state.itemskill_castonself = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF) ? 1 : 0; // Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. + 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(). - // itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention. - // Unset in unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. + // 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; diff --git a/src/map/skill.c b/src/map/skill.c index e853bcc1d..6f0cb424b 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -4190,6 +4190,11 @@ 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); } /*========================================== diff --git a/src/map/unit.c b/src/map/unit.c index 3ad94d20a..0a6008247 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1046,14 +1046,8 @@ 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) { - sd->itemskill_id = 0; - sd->itemskill_lv = 0; - sd->state.itemskill_conditions_checked = 0; - sd->state.itemskill_no_conditions = 0; - sd->state.itemskill_no_casttime = 0; - sd->state.itemskill_castonself = 0; - } + if (sd != NULL) + pc->itemskill_clear(sd); return ret; } @@ -1691,14 +1685,8 @@ 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) { - sd->itemskill_id = 0; - sd->itemskill_lv = 0; - sd->state.itemskill_conditions_checked = 0; - sd->state.itemskill_no_conditions = 0; - sd->state.itemskill_no_casttime = 0; - sd->state.itemskill_castonself = 0; - } + if (sd != NULL) + pc->itemskill_clear(sd); return ret; } -- cgit v1.2.3-70-g09d2 From 29dfb34968fe42945bad712ce3ac8806d49ba473 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sun, 26 Jan 2020 23:33:39 +0100 Subject: Added skill_is_item_skill() function. --- src/map/clif.c | 2 +- src/map/skill.c | 23 ++++++++++++++++++++--- src/map/skill.h | 1 + src/map/unit.c | 8 ++------ 4 files changed, 24 insertions(+), 10 deletions(-) (limited to 'src/map/unit.c') diff --git a/src/map/clif.c b/src/map/clif.c index 24de61ec0..23fc3a74d 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -6762,7 +6762,7 @@ static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16 int type = skill->get_inf(skill_id); - if (sd->state.itemskill_castonself == 1 && sd->itemskill_id == sd->skillitem && sd->itemskill_lv == sd->skillitemlv) + if (sd->state.itemskill_castonself == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) type = INF_SELF_SKILL; WFIFOHEAD(fd,packet_len(0x147)); diff --git a/src/map/skill.c b/src/map/skill.c index 6f0cb424b..a8dbefbd7 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -13994,6 +13994,22 @@ 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; @@ -14009,7 +14025,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s return 0; if ((sd->state.itemskill_conditions_checked == 1 || sd->state.itemskill_no_conditions == 1) - && sd->itemskill_id == sd->skillitem && sd->itemskill_lv == sd->skillitemlv) { + && skill->is_item_skill(sd, skill_id, skill_lv)) { return 1; } @@ -14998,7 +15014,7 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski return 0; if ((sd->state.itemskill_conditions_checked == 1 || sd->state.itemskill_no_conditions == 1) - && sd->itemskill_id == sd->skillitem && sd->itemskill_lv == sd->skillitemlv) { + && skill->is_item_skill(sd, skill_id, skill_lv)) { return 1; } @@ -15203,7 +15219,7 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i nullpo_ret(sd); - if (sd->state.itemskill_no_conditions == 1 && sd->itemskill_id == sd->skillitem && sd->itemskill_lv == sd->skillitemlv) + if (sd->state.itemskill_no_conditions == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) return 1; req = skill->get_requirement(sd,skill_id,skill_lv); @@ -21611,6 +21627,7 @@ 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; diff --git a/src/map/skill.h b/src/map/skill.h index 188a1c927..eff9ed7fc 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -2019,6 +2019,7 @@ 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); diff --git a/src/map/unit.c b/src/map/unit.c index 0a6008247..29a01aea7 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1606,10 +1606,8 @@ 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 && sd->itemskill_id == sd->skillitem - && sd->itemskill_lv == sd->skillitemlv) { + if (sd != NULL && sd->state.itemskill_no_casttime == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) casttime = 0; - } // in official this is triggered even if no cast time. clif->useskill(src, src->id, target_id, 0,0, skill_id, skill_lv, casttime); @@ -1814,10 +1812,8 @@ 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 && sd->itemskill_id == sd->skillitem - && sd->itemskill_lv == sd->skillitemlv) { + if (sd != NULL && sd->state.itemskill_no_casttime == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) casttime = 0; - } // in official this is triggered even if no cast time. clif->useskill(src, src->id, 0, skill_x, skill_y, skill_id, skill_lv, casttime); -- cgit v1.2.3-70-g09d2