From 9a64eca5235da46655ca64ba5916c6fd4d90208a Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sun, 10 May 2020 03:05:29 +0200 Subject: Add skill_enabled_npc battle flag and implement usage --- conf/map/battle/skill.conf | 8 ++++++++ src/map/battle.c | 1 + src/map/battle.h | 2 ++ src/map/clif.c | 18 ++++++++++++------ src/map/pc.h | 1 + src/map/script.c | 5 +++++ src/map/skill.h | 7 +++++++ 7 files changed, 36 insertions(+), 6 deletions(-) diff --git a/conf/map/battle/skill.conf b/conf/map/battle/skill.conf index a40b52124..fe9ca638a 100644 --- a/conf/map/battle/skill.conf +++ b/conf/map/battle/skill.conf @@ -347,3 +347,11 @@ stormgust_knockback: true // 0 : (official) Magic Rod's animation occurs every time it is used. // 1 : Magic Rod's animation would not occur unless a spell was absorbed. (old behavior) magicrod_type: 0 + +// Which skills are allowed to use while interacting with NPC? +// 0 (SKILLENABLEDNPC_NONE) - Don't allow using skills. +// 1 (SKILLENABLEDNPC_SELF) - Allow using non-damaging self skills. +// 2 (SKILLENABLEDNPC_ALL) - Allow using all skills. +// Official RE: 0 (Default value.) +// Official Pre-RE: 1 +skill_enabled_npc: 0 diff --git a/src/map/battle.c b/src/map/battle.c index cf51f4fc5..d99daca14 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7425,6 +7425,7 @@ static const struct battle_data { { "min_item_sell_price", &battle_config.min_item_sell_price, 0, 0, INT_MAX, }, { "display_fake_hp_when_dead", &battle_config.display_fake_hp_when_dead, 1, 0, 1, }, { "magicrod_type", &battle_config.magicrod_type, 0, 0, 1, }, + { "skill_enabled_npc", &battle_config.skill_enabled_npc, 0, 0, INT_MAX, }, { "features/enable_achievement_system", &battle_config.feature_enable_achievement, 1, 0, 1, }, { "ping_timer_inverval", &battle_config.ping_timer_interval, 30, 0, 99999999, }, { "ping_time", &battle_config.ping_time, 20, 0, 99999999, }, diff --git a/src/map/battle.h b/src/map/battle.h index bb907d5b9..55ee32445 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -580,6 +580,8 @@ struct Battle_Config { int magicrod_type; + int skill_enabled_npc; + int feature_enable_achievement; int ping_timer_interval; diff --git a/src/map/clif.c b/src/map/clif.c index 5a090301d..4f0859a4c 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -12832,7 +12832,11 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] pc->update_idle_time(sd, BCIDLE_USESKILLTOID); - if (sd->npc_id || sd->state.workinprogress & 1) { + bool allow_self_skill = ((tmp & INF_SELF_SKILL) != 0 && (skill->get_nk(skill_id) & NK_NO_DAMAGE) != 0); + allow_self_skill = (allow_self_skill && battle_config.skill_enabled_npc == SKILLENABLEDNPC_SELF); + + if ((sd->npc_id != 0 && !allow_self_skill && battle_config.skill_enabled_npc != SKILLENABLEDNPC_ALL) + || (sd->state.workinprogress & 1) != 0) { #if PACKETVER >= 20110308 clif->msgtable(sd, MSG_BUSY); #else @@ -12841,7 +12845,7 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill return; } - if (pc_cant_act(sd) + if (pc_cant_act_except_npc(sd) && skill_id != RK_REFRESH && !(skill_id == SR_GENTLETOUCH_CURE && (sd->sc.opt1 == OPT1_STONE || sd->sc.opt1 == OPT1_FREEZE || sd->sc.opt1 == OPT1_STUN)) && (sd->state.storage_flag != STORAGE_FLAG_CLOSED && !(tmp&INF_SELF_SKILL)) // SELF skills can be used with the storage open, issue: 8027 @@ -12976,7 +12980,8 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin return; } - if (sd->state.workinprogress & 1) { + if ((sd->npc_id != 0 && battle_config.skill_enabled_npc != SKILLENABLEDNPC_ALL) + || (sd->state.workinprogress & 1) != 0) { #if PACKETVER >= 20110308 clif->msgtable(sd, MSG_BUSY); #else @@ -13046,7 +13051,7 @@ static void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd) __attr /// There are various variants of this packet, some of them have padding between fields. static void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd) { - if (pc_cant_act(sd)) + if (pc_cant_act_except_npc(sd)) return; if (pc_issit(sd)) return; @@ -13067,7 +13072,7 @@ static void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd /// There are various variants of this packet, some of them have padding between fields. static void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd) { - if (pc_cant_act(sd)) + if (pc_cant_act_except_npc(sd)) return; if (pc_issit(sd)) return; @@ -13096,7 +13101,8 @@ static void clif_parse_UseSkillMap(int fd, struct map_session_data *sd) return; // It is possible to use teleport with the storage window open issue:8027 - if (pc_cant_act(sd) && (sd->state.storage_flag == STORAGE_FLAG_CLOSED && skill_id != AL_TELEPORT)) { + if ((pc_cant_act_except_npc(sd) && sd->state.storage_flag == STORAGE_FLAG_CLOSED && skill_id != AL_TELEPORT) + || (sd->npc_id != 0 && battle_config.skill_enabled_npc != SKILLENABLEDNPC_ALL)) { clif_menuskill_clear(sd); return; } diff --git a/src/map/pc.h b/src/map/pc.h index 01fd855b7..f9526c248 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -686,6 +686,7 @@ END_ZEROED_BLOCK; #define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading ) #define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1) #define pc_cant_act_except_lapine(sd) ((sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1) +#define pc_cant_act_except_npc(sd) ( (sd)->state.vending != 0 || (sd)->state.buyingstore != 0 || (sd)->chat_id != 0 || ((sd)->sc.opt1 != 0 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading != 0 || (sd)->state.storage_flag != 0 || (sd)->state.prevend != 0 || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1) /* equals pc_cant_act except it doesn't check for chat rooms */ #define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1) diff --git a/src/map/script.c b/src/map/script.c index bda461d5d..7ba9fd276 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -27918,6 +27918,11 @@ static void script_hardcoded_constants(void) script->set_constant("ITEMENABLEDNPC_EQUIP", ITEMENABLEDNPC_EQUIP, false, false); script->set_constant("ITEMENABLEDNPC_CONSUME", ITEMENABLEDNPC_CONSUME, false, false); + script->constdb_comment("NPC allowed skill use constants"); + script->set_constant("SKILLENABLEDNPC_NONE", SKILLENABLEDNPC_NONE, false, false); + script->set_constant("SKILLENABLEDNPC_SELF", SKILLENABLEDNPC_SELF, false, false); + script->set_constant("SKILLENABLEDNPC_ALL", SKILLENABLEDNPC_ALL, false, false); + script->constdb_comment("private airship responds"); script->set_constant("P_AIRSHIP_NONE", P_AIRSHIP_NONE, false, false); script->set_constant("P_AIRSHIP_RETRY", P_AIRSHIP_RETRY, false, false); diff --git a/src/map/skill.h b/src/map/skill.h index 4dbbaf147..e8360c91f 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1733,6 +1733,13 @@ enum autocast_type { AUTOCAST_ITEM, // Used for itemskill() script command. }; +/** Constants for allowed skill use while interacting with NPC. **/ +enum skill_enabled_npc_flags { + SKILLENABLEDNPC_NONE = 0, //!< Don't allow using any skills while interacting with NPC. + SKILLENABLEDNPC_SELF = 1, //!< Allow using non-damaging self skills while interacting with NPC. + SKILLENABLEDNPC_ALL = 2, //!< Allow using all skills while interacting with NPC. +}; + /** * Structures **/ -- cgit v1.2.3-60-g2f50