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/script.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/map/script.h') diff --git a/src/map/script.h b/src/map/script.h index 8d7669d68..c981a895d 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -564,6 +564,14 @@ enum mado_type { #endif }; +/** + * Option flags for itemskill() script command. + **/ +enum itemskill_flag { + ISF_NONE = 0x00, + ISF_IGNORECONDITIONS = 0x01, // Ignore skill conditions and don't consume them. +}; + /** * Structures **/ -- 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/script.h') 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/script.h') 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