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/pc.h | 11 +++++++++++ src/map/script.c | 25 ++++++++++++++++++------- src/map/script.h | 8 ++++++++ src/map/skill.c | 56 +++++++++++++++++++++++++++++++++----------------------- src/map/unit.c | 47 ++++++++++++++++++++++++++++------------------- 5 files changed, 98 insertions(+), 49 deletions(-) (limited to 'src/map') diff --git a/src/map/pc.h b/src/map/pc.h index a3a3ee48d..4d7a7eef0 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -240,6 +240,8 @@ 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_no_conditions : 1; // Used by itemskill() script command, to ignore skill conditions and don't consume them. } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -643,6 +645,15 @@ END_ZEROED_BLOCK; bool achievements_received; // Title VECTOR_DECL(int) title_ids; + + /* + * itemskill_conditions_checked/itemskill_no_conditions 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 diff --git a/src/map/script.c b/src/map/script.c index b77e6a376..470ad9408 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11000,15 +11000,26 @@ static BUILDIN(itemskill) id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); lv = script_getnum(st,3); -/* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ -#if 0 - if( !script_hasdata(st, 4) ) { - if( !skill->check_condition_castbegin(sd,id,lv) || !skill->check_condition_castend(sd,id,lv) ) - return true; - } -#endif sd->skillitem=id; sd->skillitemlv=lv; + + /// itemskill_conditions_checked/itemskill_no_conditions 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; + + int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE; + + 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. + + if (sd->state.itemskill_no_conditions == 0) { + if (skill->check_condition_castbegin(sd, id, lv) == 0 || skill->check_condition_castend(sd, id, lv) == 0) + return true; + + 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); return true; } 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 **/ diff --git a/src/map/skill.c b/src/map/skill.c index 0f0a72dce..2b4f87a11 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -13997,9 +13997,17 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s nullpo_ret(sd); + if (skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL) + return 0; + if (sd->chat_id != 0) 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) { + 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] sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check. @@ -14041,24 +14049,32 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s if( (i = sd->itemindex) == -1 || sd->status.inventory[i].nameid != sd->itemid || sd->inventory_data[i] == NULL || - !sd->inventory_data[i]->flag.delay_consume || + (sd->inventory_data[i]->flag.delay_consume == 0 && skill_id == WZ_EARTHSPIKE) || // TODO: See below. [Kenpachi] sd->status.inventory[i].amount < 1 ) { //Something went wrong, item exploit? sd->itemid = sd->itemindex = -1; return 0; } + + /** + * [Kenpachi] TODO: + * - No skill casting item should be of type IT_DELAYCONSUME, they are all consumed immediately, even before the skill cursor appears. + * The WZ_EARTHSPIKE check for TK_SPTIME skill should be moved to pc_useitem(), once the type of all skill casting items is updated. + * + * - The consumption of 10 SP when using Earth_Scroll_1_3 or Earth_Scroll_1_5 while SC_EARTHSCROLL is active needs to be implemented. + * + **/ //Consume sd->itemid = sd->itemindex = -1; if( skill_id == WZ_EARTHSPIKE && sc && sc->data[SC_EARTHSCROLL] && rnd()%100 > sc->data[SC_EARTHSCROLL]->val2 ) // [marquis007] ; //Do not consume item. - else if( sd->status.inventory[i].expire_time == 0 ) // Rental usable items are not consumed until expiration + else 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); } - return 1; } - if( pc_is90overweight(sd) ) { + if (pc_is90overweight(sd) && sd->skillitem != skill_id) { /// Skill casting items ignore the overweight restriction. [Kenpachi] clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0); return 0; } @@ -14182,9 +14198,6 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s } } - if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL ) - return 0; - require = skill->get_requirement(sd,skill_id,skill_lv); //Can only update state when weapon/arrow info is checked. @@ -14932,7 +14945,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) { + 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] clif->skill_fail(sd, skill_id, USESKILL_FAIL_SP_INSUFFICIENT, 0, 0); return 0; } @@ -14990,6 +15003,11 @@ 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_no_conditions == 1) + && sd->itemskill_id == sd->skillitem && sd->itemskill_lv == sd->skillitemlv) { + 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] sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check. @@ -15017,14 +15035,8 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski return 0; break; } - /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ -#if 0 - if( sd->state.abra_flag ) // Casting finished (Hocus-Pocus) - return 1; -#endif - if( sd->skillitem == skill_id ) - return 1; - if( pc_is90overweight(sd) ) { + + if (pc_is90overweight(sd) && sd->skillitem != skill_id) { /// Skill casting items ignore the overweight restriction. [Kenpachi] clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0); return 0; } @@ -15197,6 +15209,9 @@ 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) + return 1; + req = skill->get_requirement(sd,skill_id,skill_lv); if (type&1) { @@ -15206,8 +15221,9 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i req.sp = 0; break; default: - if( sd->state.autocast ) + if (sd->state.autocast == 1 || sd->skillitem == skill_id) /// Skill casting items and Hocus-Pocus skills don't consume SP. [Kenpachi] req.sp = 0; + break; } @@ -15285,12 +15301,6 @@ static struct skill_condition skill_get_requirement(struct map_session_data *sd, if( !sd ) return req; -#if 0 /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ - if( sd->state.abra_flag ) -#else // not 0 - if( sd->skillitem == skill_id ) -#endif // 0 - return req; // Hocus-Pocus don't have requirements. sc = &sd->sc; if( !sc->count ) 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') 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') 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 f3fbb0ffa1f88b1b798d97b485306aa4930bf4ec Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 20 Jan 2020 10:59:46 +0100 Subject: Added itemskill option flags to the script constants. --- src/map/script.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/map') diff --git a/src/map/script.c b/src/map/script.c index b51c1a915..08a05004f 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -27851,6 +27851,12 @@ static void script_hardcoded_constants(void) script->set_constant("MADO_ROBOT", MADO_ROBOT, false, false); script->set_constant("MADO_SUITE", MADO_SUITE, false, false); + script->constdb_comment("itemskill option flags"); + script->set_constant("ISF_NONE", ISF_NONE, false, false); + script->set_constant("ISF_IGNORECONDITIONS", ISF_IGNORECONDITIONS, false, false); + script->set_constant("ISF_INSTANTCAST", ISF_INSTANTCAST, false, false); + script->set_constant("ISF_CASTONSELF", ISF_CASTONSELF, false, false); + script->constdb_comment("Renewal"); #ifdef RENEWAL script->set_constant("RENEWAL", 1, false, false); -- cgit v1.2.3-70-g09d2 From 9e8369e0daa596a93934dece1543af2c0a17412c Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 20 Jan 2020 11:22:12 +0100 Subject: Applied code style to BUILDIN(itemskill). --- src/map/script.c | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'src/map') diff --git a/src/map/script.c b/src/map/script.c index 08a05004f..b87a46785 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -10985,46 +10985,52 @@ static BUILDIN(guildopenstorage) return true; } -/*========================================== - * Make player use a skill trought item usage - *------------------------------------------*/ -/// itemskill ,{,flag -/// itemskill "",{,flag +/** + * Makes the attached character use a skill by using an item. + * + * @code{.herc} + * itemskill(, {, }); + * itemskill("", {, }); + * @endcode + * + */ static BUILDIN(itemskill) { - int id; - int lv; struct map_session_data *sd = script->rid2sd(st); + if (sd == NULL || sd->ud.skilltimer != INVALID_TIMER) return true; - id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); - lv = script_getnum(st,3); - sd->skillitem=id; - sd->skillitemlv=lv; - - /// 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; + 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. int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE; - 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. + 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. if (sd->state.itemskill_no_conditions == 0) { - if (skill->check_condition_castbegin(sd, id, lv) == 0 || skill->check_condition_castend(sd, id, lv) == 0) + if (skill->check_condition_castbegin(sd, sd->skillitem, sd->skillitemlv) == 0 + || skill->check_condition_castend(sd, sd->skillitem, sd->skillitemlv) == 0) { 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 unit_skilluse_id()/unit_skilluse_pos() if skill was not aborted while target selection. } - clif->item_skill(sd, id, lv); + 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. + + // 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 = sd->skillitem; + sd->itemskill_lv = sd->skillitemlv; + + clif->item_skill(sd, sd->skillitem, sd->skillitemlv); + return true; } + /*========================================== * Attempt to create an item *------------------------------------------*/ -- cgit v1.2.3-70-g09d2 From 6e2e6a353ba7a0ff1a82b1e8acca6950ae3e47a1 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Fri, 24 Jan 2020 08:15:25 +0100 Subject: Implemented the consumption of 10 SP when using Earth Spike Scroll while SC_EARTHSCROLL is active. --- src/map/skill.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/map') diff --git a/src/map/skill.c b/src/map/skill.c index 2b4f87a11..e8cab751e 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -14062,8 +14062,6 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s * - No skill casting item should be of type IT_DELAYCONSUME, they are all consumed immediately, even before the skill cursor appears. * The WZ_EARTHSPIKE check for TK_SPTIME skill should be moved to pc_useitem(), once the type of all skill casting items is updated. * - * - The consumption of 10 SP when using Earth_Scroll_1_3 or Earth_Scroll_1_5 while SC_EARTHSCROLL is active needs to be implemented. - * **/ //Consume sd->itemid = sd->itemindex = -1; @@ -15219,6 +15217,11 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i case CG_TAROTCARD: // TarotCard will consume sp in skill_cast_nodamage_id [Inkfish] case MC_IDENTIFY: req.sp = 0; + break; + case WZ_EARTHSPIKE: + if (sd->sc.count > 0 && sd->sc.data[SC_EARTHSCROLL] != NULL) // If Earth Spike Scroll is used while SC_EARTHSCROLL is active, 10 SP are consumed. [Kenpachi] + req.sp = 10; + break; default: if (sd->state.autocast == 1 || sd->skillitem == skill_id) /// Skill casting items and Hocus-Pocus skills don't consume SP. [Kenpachi] -- cgit v1.2.3-70-g09d2 From 26eae1d9e811f3171078c675f233be1c0faa4109 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Fri, 24 Jan 2020 09:24:28 +0100 Subject: Moved the WZ_EARTHSPIKE check for TK_SPTIME skill from skill_check_condition_castbegin() to pc_useitem(). --- src/map/itemdb.h | 2 ++ src/map/pc.c | 14 ++++++++++++++ src/map/skill.c | 11 +---------- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'src/map') diff --git a/src/map/itemdb.h b/src/map/itemdb.h index d2592af4e..5f0790b10 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -95,6 +95,8 @@ enum item_itemid { ITEMID_ALOEBERA = 606, ITEMID_SPECTACLES = 611, ITEMID_POISON_BOTTLE = 678, + ITEMID_EARTH_SCROLL_1_3 = 686, + ITEMID_EARTH_SCROLL_1_5 = 687, ITEMID_EMPTY_BOTTLE = 713, ITEMID_EMPERIUM = 714, ITEMID_YELLOW_GEMSTONE = 715, diff --git a/src/map/pc.c b/src/map/pc.c index f6edb5e3c..a404d93e7 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5257,6 +5257,14 @@ static int pc_useitem(struct map_session_data *sd, int n) #endif if( battle_config.item_restricted_consumption_type && sd->status.inventory[n].expire_time == 0 ) { clif->useitemack(sd,n,sd->status.inventory[n].amount-1,true); + + // If Earth Spike Scroll is used while SC_EARTHSCROLL is active, there is a chance to don't consume the scroll. [Kenpachi] + if ((nameid == ITEMID_EARTH_SCROLL_1_3 || nameid == ITEMID_EARTH_SCROLL_1_5) + && sd->sc.count > 0 && sd->sc.data[SC_EARTHSCROLL] != NULL + && rnd() % 100 > sd->sc.data[SC_EARTHSCROLL]->val2) { + return 0; + } + pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME); } return 0; @@ -5302,6 +5310,12 @@ static int pc_useitem(struct map_session_data *sd, int n) script->run_use_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id); script->potion_flag = 0; + // If Earth Spike Scroll is used while SC_EARTHSCROLL is active, there is a chance to don't consume the scroll. [Kenpachi] + if ((nameid == ITEMID_EARTH_SCROLL_1_3 || nameid == ITEMID_EARTH_SCROLL_1_5) && sd->sc.count > 0 + && sd->sc.data[SC_EARTHSCROLL] != NULL && rnd() % 100 > sd->sc.data[SC_EARTHSCROLL]->val2) { + removeItem = false; + } + if (removeItem) pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME); return 1; diff --git a/src/map/skill.c b/src/map/skill.c index e8cab751e..e853bcc1d 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -14049,7 +14049,6 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s if( (i = sd->itemindex) == -1 || sd->status.inventory[i].nameid != sd->itemid || sd->inventory_data[i] == NULL || - (sd->inventory_data[i]->flag.delay_consume == 0 && skill_id == WZ_EARTHSPIKE) || // TODO: See below. [Kenpachi] sd->status.inventory[i].amount < 1 ) { //Something went wrong, item exploit? @@ -14057,17 +14056,9 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s return 0; } - /** - * [Kenpachi] TODO: - * - No skill casting item should be of type IT_DELAYCONSUME, they are all consumed immediately, even before the skill cursor appears. - * The WZ_EARTHSPIKE check for TK_SPTIME skill should be moved to pc_useitem(), once the type of all skill casting items is updated. - * - **/ //Consume sd->itemid = sd->itemindex = -1; - if( skill_id == WZ_EARTHSPIKE && sc && sc->data[SC_EARTHSCROLL] && rnd()%100 > sc->data[SC_EARTHSCROLL]->val2 ) // [marquis007] - ; //Do not consume item. - else if (sd->status.inventory[i].expire_time == 0 && sd->inventory_data[i]->flag.delay_consume == 1) // Rental usable items are not consumed until expiration + 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); } } -- 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') 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') 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 From 1d0bd5baf6364822e48ba64010a52377c6abb776 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sun, 26 Jan 2020 22:55:54 +0100 Subject: Converted packet ZC_AUTORUN_SKILL to structure. --- src/map/clif.c | 27 ++++++++++++++------------- src/map/packets_struct.h | 12 ++++++++++++ 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'src/map') diff --git a/src/map/clif.c b/src/map/clif.c index 23fc3a74d..660c516d7 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -6754,27 +6754,28 @@ static void clif_item_refine_list(struct map_session_data *sd) /// 0147 .W .L .W .W .W .24B .B static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) { - int fd; - nullpo_retv(sd); - fd=sd->fd; + int fd = sd->fd; + + WFIFOHEAD(fd, sizeof(struct PACKET_ZC_AUTORUN_SKILL)); + 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)) type = INF_SELF_SKILL; - WFIFOHEAD(fd,packet_len(0x147)); - WFIFOW(fd, 0)=0x147; - WFIFOW(fd, 2)=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); - safestrncpy(WFIFOP(fd,14),skill->get_name(skill_id),NAME_LENGTH); - WFIFOB(fd,38)=0; - WFIFOSET(fd,packet_len(0x147)); + p->packetType = HEADER_ZC_AUTORUN_SKILL; + p->skill_id = skill_id; + p->skill_type = type; + p->skill_lv = skill_lv; + p->skill_sp = skill->get_sp(skill_id, skill_lv); + p->skill_range = skill->get_range2(&sd->bl, skill_id, skill_lv); + safestrncpy(p->skill_name, skill->get_name(skill_id), NAME_LENGTH); + p->up_flag = 0; + + WFIFOSET(fd, sizeof(struct PACKET_ZC_AUTORUN_SKILL)); } /// Adds an item to character's cart. diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 31b28e831..b604c77b8 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -3873,6 +3873,18 @@ struct PACKET_ZC_STATE_CHANGE { DEFINE_PACKET_HEADER(ZC_STATE_CHANGE, 0x0119); #endif +struct PACKET_ZC_AUTORUN_SKILL { + int16 packetType; + uint16 skill_id; + uint32 skill_type; + uint16 skill_lv; + uint16 skill_sp; + uint16 skill_range; + char skill_name[NAME_LENGTH]; + char up_flag; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(ZC_AUTORUN_SKILL, 0x0147); + #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #pragma pack(pop) #endif // not NetBSD < 6 / Solaris -- cgit v1.2.3-70-g09d2