diff options
-rw-r--r-- | conf/map/battle/items.conf | 12 | ||||
-rw-r--r-- | conf/map/battle/skill.conf | 8 | ||||
-rw-r--r-- | doc/script_commands.txt | 41 | ||||
-rw-r--r-- | src/map/battle.c | 3 | ||||
-rw-r--r-- | src/map/battle.h | 2 | ||||
-rw-r--r-- | src/map/clif.c | 22 | ||||
-rw-r--r-- | src/map/pc.c | 3 | ||||
-rw-r--r-- | src/map/pc.h | 8 | ||||
-rw-r--r-- | src/map/script.c | 77 | ||||
-rw-r--r-- | src/map/skill.h | 7 |
10 files changed, 145 insertions, 38 deletions
diff --git a/conf/map/battle/items.conf b/conf/map/battle/items.conf index 4788d7b30..ef383e19b 100644 --- a/conf/map/battle/items.conf +++ b/conf/map/battle/items.conf @@ -100,10 +100,14 @@ autospell_stacking: false // Default: true (official) item_restricted_consumption_type: true -// Enable all NPC to allow changing of equipments while interacting? (Note 1) -// Script commands 'enable_items/disable_items' will not be override. (see doc/script_commands.txt) -// Default: true (official) -item_enabled_npc: true +// Which item actions are allowed while interacting with NPC? (Note 3) +// Script commands 'enable_items/disable_items' will not be overridden. (See doc/script_commands.txt.) +// 0x0 (ITEMENABLEDNPC_NONE) - Don't allow any item actions. +// 0x1 (ITEMENABLEDNPC_EQUIP) - Allow changing equipment. +// 0x2 (ITEMENABLEDNPC_CONSUME) - Allow consuming usable items. +// Official RE: 0x1 (Default value.) +// Official Pre-RE: 0x3 +item_enabled_npc: 0x1 // Unequip the equipments that has disabled by map_zone_db.conf ? // 0 : disabled equipments and cards are nullify (official) 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/doc/script_commands.txt b/doc/script_commands.txt index 707aab9d6..a585695bd 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -5685,21 +5685,32 @@ Example: --------------------------------------- -*enable_items() -*disable_items() - -These commands enable/disable changing of equipments while an NPC is -running. When disable_items() is run, equipments cannot be changed -during scripts until enable_items() is called or the script has -terminated. To avoid possible exploits, when disable_items() is invoked, -it will only disable changing equips while running that script in -particular. Note that if a different script also calls disable_items(), -it will override the last call (so you may want to call this command at -the start of your script without assuming the effect is still in -effect). -If 'item_enabled_npc' option is set to true in 'conf/map/battle/items.conf' all -NPC are allowing changing of equipment by default except for those have been -set with 'disable_items'. +*enable_items({<flag>}) +*enableitemuse({<flag>}) +*disable_items({<flag>}) +*disableitemuse({<flag>}) + +These commands enable/disable item actions while interacting with a NPC. +When disable_items() is invoked, item actions defined by <flag> are disabled +during scripts until enable_items() is called or the script has terminated. +To avoid possible exploits, when disable_items() is invoked, it will only +disable item actions while running that script in particular. +Note that if a different script also invokes disable_items(), it will override +the last call so you may want to call this command at the start of your +script without assuming the effect is still in effect. +If <flag> is omitted all item actions will be disabled. +The enable_items() command enables item actions defined by <flag> during +scripts until disable_items() is invoked or the script has terminated. +If <flag> is omitted it defaults to 'item_enabled_npc' battle flag. +For a list of supported flags have a look at the description of +'item_enabled_npc' battle flag in 'conf/map/battle/items.conf'. +Unless disable_items() or enable_items() is invoked the script will use +'item_enabled_npc' battle flag by default. + +Example: + + // This will disable changing equipment during this script. + disable_items(ITEMENABLEDNPC_EQUIP); --------------------------------------- diff --git a/src/map/battle.c b/src/map/battle.c index 236ed70b7..611154953 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7378,7 +7378,7 @@ static const struct battle_data { { "item_restricted_consumption_type", &battle_config.item_restricted_consumption_type,1, 0, 1, }, { "unequip_restricted_equipment", &battle_config.unequip_restricted_equipment, 0, 0, 3, }, { "max_walk_path", &battle_config.max_walk_path, 17, 1, MAX_WALKPATH, }, - { "item_enabled_npc", &battle_config.item_enabled_npc, 1, 0, 1, }, + { "item_enabled_npc", &battle_config.item_enabled_npc, 1, 0, INT_MAX, }, { "gm_ignore_warpable_area", &battle_config.gm_ignore_warpable_area, 0, 2, 100, }, { "packet_obfuscation", &battle_config.packet_obfuscation, 1, 0, 3, }, { "client_accept_chatdori", &battle_config.client_accept_chatdori, 0, 0, INT_MAX, }, @@ -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 6d67b5114..409889f90 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -12042,7 +12042,7 @@ static void clif_parse_EquipItem(int fd, struct map_session_data *sd) return; //Out of bounds check. if( sd->npc_id ) { - if ( !sd->npc_item_flag ) + if ((sd->npc_item_flag & ITEMENABLEDNPC_EQUIP) == 0) return; } else if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->sc.opt1) ; //You can equip/unequip stuff while storage is open/under status changes @@ -12087,7 +12087,7 @@ static void clif_parse_UnequipItem(int fd, struct map_session_data *sd) } if( sd->npc_id ) { - if ( !sd->npc_item_flag ) + if ((sd->npc_item_flag & ITEMENABLEDNPC_EQUIP) == 0) return; } else if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->sc.opt1) ; //You can equip/unequip stuff while storage is open/under status changes @@ -12838,7 +12838,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 @@ -12847,7 +12851,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 @@ -12984,7 +12988,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 @@ -13054,7 +13059,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; @@ -13075,7 +13080,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; @@ -13104,7 +13109,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.c b/src/map/pc.c index 4497ef54f..73b41db5a 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5163,7 +5163,8 @@ static int pc_useitem(struct map_session_data *sd, int n) nullpo_ret(sd); Assert_ret(n >= 0 && n < sd->status.inventorySize); - if (sd->npc_id || sd->state.workinprogress & 1) { + if ((sd->npc_id != 0 && (sd->npc_item_flag & ITEMENABLEDNPC_CONSUME) == 0) + || (sd->state.workinprogress & 1) != 0) { #if PACKETVER >= 20110308 clif->msgtable(sd, MSG_BUSY); #else diff --git a/src/map/pc.h b/src/map/pc.h index dfc1f886e..f2e911af3 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -103,6 +103,13 @@ enum pc_checkitem_types { PCCHECKITEM_GSTORAGE = 0x8 }; +/** Bit flags for allowed item actions while interacting with NPC. **/ +enum item_enabled_npc_flags { + ITEMENABLEDNPC_NONE = 0x0, //!< Don't allow any item actions while interacting with NPC. + ITEMENABLEDNPC_EQUIP = 0x1, //!< Allow changing equipment while interacting with NPC. + ITEMENABLEDNPC_CONSUME = 0x2, //!< Allow consuming usable items while interacting with NPC. +}; + struct weapon_data { int atkmods[3]; BEGIN_ZEROED_BLOCK; // all the variables within this block get zero'ed in each call of status_calc_pc @@ -676,6 +683,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 0d04ea31b..763a6c51c 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9135,22 +9135,71 @@ static BUILDIN(delitemidx) return true; } -/*========================================== - * Enables/Disables use of items while in an NPC [Skotlex] - *------------------------------------------*/ +/** + * Enable item actions while interacting with NPC. + * + * @code{.herc} + * enableitemuse({<flag>}); + * enable_items({<flag>}); + * @endcode + * + **/ static BUILDIN(enableitemuse) { + int flag = battle_config.item_enabled_npc; + + if (script_hasdata(st, 2)) { + if (!script_isinttype(st, 2)) + return true; + + flag = script_getnum(st, 2); + } + + if (flag < 0) + return true; + struct map_session_data *sd = script->rid2sd(st); - if (sd != NULL) - st->npc_item_flag = sd->npc_item_flag = 1; + + if (sd == NULL) + return true; + + st->npc_item_flag |= flag; + sd->npc_item_flag |= flag; + return true; } +/** + * Disable item actions while interacting with NPC. + * + * @code{.herc} + * disableitemuse({<flag>}); + * disable_items({<flag>}); + * @endcode + * + **/ static BUILDIN(disableitemuse) { + int flag = battle_config.item_enabled_npc; + + if (script_hasdata(st, 2)) { + if (!script_isinttype(st, 2)) + return true; + + flag = script_getnum(st, 2); + } + + if (flag < 0) + return true; + struct map_session_data *sd = script->rid2sd(st); - if (sd != NULL) - st->npc_item_flag = sd->npc_item_flag = 0; + + if (sd == NULL) + return true; + + st->npc_item_flag &= ~flag; + sd->npc_item_flag &= ~flag; + return true; } @@ -27197,8 +27246,8 @@ static void script_parse_builtin(void) BUILDIN_DEF(delitem,"vi?"), BUILDIN_DEF(delitem2,"viiiiiiii?"), BUILDIN_DEF(delitemidx, "i??"), - BUILDIN_DEF2(enableitemuse,"enable_items",""), - BUILDIN_DEF2(disableitemuse,"disable_items",""), + BUILDIN_DEF2(enableitemuse, "enable_items", "?"), + BUILDIN_DEF2(disableitemuse, "disable_items", "?"), BUILDIN_DEF(cutin,"si"), BUILDIN_DEF(viewpoint,"iiiii"), BUILDIN_DEF(heal,"ii"), @@ -28247,6 +28296,16 @@ static void script_hardcoded_constants(void) script->set_constant("PCBLOCK_COMMANDS", PCBLOCK_COMMANDS, false, false); script->set_constant("PCBLOCK_NPC", PCBLOCK_NPC, false, false); + script->constdb_comment("NPC item action constants"); + script->set_constant("ITEMENABLEDNPC_NONE", ITEMENABLEDNPC_NONE, false, false); + 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 b9178321d..b505412b6 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1737,6 +1737,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 **/ |