doc/script_commands.txt | 49 ++++++++++++++++++++++++++----
src/map/clif.c | 6 ++++
src/map/pc.c | 9 ++++--
src/map/pc.h | 15 ++++++++++
src/map/script.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++
src/map/status.c | 4 +++
6 files changed, 155 insertions(+), 7 deletions(-)
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 218bb48..24e64ec 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -5859,12 +5859,11 @@ Examples:
---------------------------------------
-*pcblockmove <id>,<option>;
+*pcblockmove <account ID>,<option>;
-Prevents the given ID from moving when the option != 0, and 0 enables the
-ID to move again. The ID can either be the GID of a monster/NPC or account
-ID of a character, and will run for the attached player if zero is
-supplied.
+Prevents the player from moving when the option > 0, and 0 enables the
+player to move again. The player has to be the account ID of a character,
+and will run for the attached player if zero is supplied.
Examples:
@@ -5874,6 +5873,46 @@ Examples:
// Enables the current char to move again.
pcblockmove getcharid(3),0;
+---------------------------------------
+
+*pcblock <type>,<option>{,<account ID>};
+
+Prevents the player from doing the following actions when the <option> is
+true(1), and false(0) will return the player to original state. If there is
+no account ID given, the script will run for the attached player.
+
+The <type> listed are :-
+ BLOCK_MOVE 1
+ BLOCK_ATTACK 2
+ BLOCK_SKILL 4
+ BLOCK_USEITEM 8
+ BLOCK_CHAT 16
+ BLOCK_IMMUNE 32
+ BLOCK_SITSTAND 64
+
+Examples:
+
+// Make the current attached player invulnerable, same as @monsterignore
+ pcblock BLOCK_IMMUNE, true;
+
+// Prevents the current char from attacking and using skills
+ pcblock BLOCK_ATTACK|BLOCK_SKILL, true, getcharid(3);
+
+---------------------------------------
+
+*checkpcblock({<account ID>})
+
+This command will return the options of the current attached player used by
+'pcblock' command. Additionally, you may insert account ID within the bracket
+to check on another player.
+
+Examples:
+
+ if ( checkpcblock() & BLOCK_IMMUNE )
+ mes "You are invulnerable !";
+
+ if ( checkpcblock() & (BLOCK_ATTACK|BLOCK_SKILL) )
+ mes "You are unable to attack and use any skills.";
---------------------------------------
//=====================================
diff --git a/src/map/clif.c b/src/map/clif.c
index 80703fa..6584b58 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -9963,6 +9963,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
return;
}
+ if( sd->state.blockedsitstand ) // *pcblock script command
+ return;
+
if (sd->ud.skilltimer != INVALID_TIMER || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING ))
break;
@@ -9987,6 +9990,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
return;
}
+ if( sd->state.blockedsitstand ) // *pcblock script command
+ return;
+
if( battle_config.idletime_criteria & BCIDLE_SIT )
sd->idletime = sockt->last_tick;
diff --git a/src/map/pc.c b/src/map/pc.c
index 4d4f415..f198fa3 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -4894,6 +4894,9 @@ int pc_useitem(struct map_session_data *sd,int n) {
if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 )
return 0;
+ if( sd->state.blockeduseitem ) // *pcblock script command
+ return 0;
+
if( !pc->isUseitem(sd,n) )
return 0;
@@ -8890,7 +8893,8 @@ bool pc_can_attack( struct map_session_data *sd, int target_id ) {
(sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) ||
sd->sc.data[SC_BLADESTOP] ||
sd->sc.data[SC_DEEP_SLEEP] ||
- sd->sc.data[SC_FALLENEMPIRE] )
+ sd->sc.data[SC_FALLENEMPIRE] ||
+ sd->state.blockedattack )
return false;
return true;
@@ -8906,7 +8910,8 @@ bool pc_can_talk( struct map_session_data *sd ) {
if( sd->sc.data[SC_BERSERK] ||
(sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) ||
- (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) )
+ (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ||
+ sd->state.blockedchat )
return false;
return true;
diff --git a/src/map/pc.h b/src/map/pc.h
index 2c8b24a..8227ca1 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -172,6 +172,11 @@ struct map_session_data {
unsigned int size :2; // for tiny/large types
unsigned int night :1; //Holds whether or not the player currently has the SI_NIGHT effect on. [Skotlex]
unsigned int blockedmove :1;
+ unsigned int blockedattack :1;
+ unsigned int blockedskill :1;
+ unsigned int blockeduseitem :1;
+ unsigned int blockedchat :1;
+ unsigned int blockedsitstand :1;
unsigned int using_fake_npc :1;
unsigned int rewarp :1; //Signals that a player should warp as soon as he is done loading a map. [Skotlex]
unsigned int killer : 1;
@@ -757,6 +762,16 @@ struct autotrade_vending {
struct hplugin_data_store *hdata; ///< HPM Plugin Data Store
};
+enum pc_block_action {
+ PCBLOCK_MOVE = 0x1,
+ PCBLOCK_ATTACK = 0x2,
+ PCBLOCK_SKILL = 0x4,
+ PCBLOCK_USEITEM = 0x8,
+ PCBLOCK_CHAT = 0x10,
+ PCBLOCK_IMMUNE = 0x20,
+ PCBLOCK_SITSTAND = 0x40,
+};
+
/*=====================================
* Interface : pc.h
* Generated by HerculesInterfaceMaker
diff --git a/src/map/script.c b/src/map/script.c
index 54d8d33..b93eeaa 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -16300,6 +16300,74 @@ BUILDIN(pcblockmove) {
return true;
}
+BUILDIN(pcblock) {
+ int type, flag;
+ TBL_PC *sd = NULL;
+
+ type = script_getnum(st,2);
+ flag = script_getnum(st,3);
+ if ( script_hasdata(st,4) )
+ sd = map->id2sd(script_getnum(st,4));
+ else
+ sd = script->rid2sd(st);
+
+ if ( !sd )
+ return true;
+
+ if ( !type ) {
+ ShowError("buildin_pcblock: Invalid type.\n");
+ return false;
+ }
+
+ if ( type & PCBLOCK_MOVE )
+ sd->state.blockedmove = flag > 0;
+ if ( type & PCBLOCK_ATTACK )
+ sd->state.blockedattack = flag > 0;
+ if ( type & PCBLOCK_SKILL )
+ sd->state.blockedskill = flag > 0;
+ if ( type & PCBLOCK_USEITEM )
+ sd->state.blockeduseitem = flag > 0;
+ if ( type & PCBLOCK_CHAT )
+ sd->state.blockedchat = flag > 0;
+ if ( type & PCBLOCK_IMMUNE )
+ sd->state.monster_ignore = flag > 0;
+ if ( type & PCBLOCK_SITSTAND )
+ sd->state.blockedsitstand = flag > 0;
+
+ return true;
+}
+
+BUILDIN(checkpcblock) {
+ int val = 0;
+ TBL_PC *sd = NULL;
+
+ if ( script_hasdata(st,2) )
+ sd = map->id2sd(script_getnum(st,2));
+ else
+ sd = script->rid2sd(st);
+
+ if ( !sd )
+ return true;
+
+ if ( sd->state.blockedmove )
+ val |= PCBLOCK_MOVE;
+ if ( sd->state.blockedattack )
+ val |= PCBLOCK_ATTACK;
+ if ( sd->state.blockedskill )
+ val |= PCBLOCK_SKILL;
+ if ( sd->state.blockeduseitem )
+ val |= PCBLOCK_USEITEM;
+ if ( sd->state.blockedchat )
+ val |= PCBLOCK_CHAT;
+ if ( sd->state.monster_ignore )
+ val |= PCBLOCK_IMMUNE;
+ if ( sd->state.blockedsitstand )
+ val |= PCBLOCK_SITSTAND;
+
+ script_pushint(st,val);
+ return true;
+}
+
BUILDIN(pcfollow) {
int id, targetid;
TBL_PC *sd = NULL;
@@ -20234,6 +20302,8 @@ void script_parse_builtin(void) {
BUILDIN_DEF(pcfollow,"ii"),
BUILDIN_DEF(pcstopfollow,"i"),
BUILDIN_DEF(pcblockmove,"ii"),
+ BUILDIN_DEF(pcblock,"ii?"),
+ BUILDIN_DEF(checkpcblock,"?"),
// <--- [zBuffer] List of player cont commands
// [zBuffer] List of mob control commands --->
BUILDIN_DEF(unitwalk,"ii?"),
@@ -20509,6 +20579,15 @@ void script_hardcoded_constants(void) {
script->set_constant("BG_AREA_WOS",BG_AREA_WOS,false);
script->set_constant("BG_QUEUE",BG_QUEUE,false);
+ /* pc_block_action */
+ script->set_constant("BLOCK_MOVE",PCBLOCK_MOVE,false);
+ script->set_constant("BLOCK_ATTACK",PCBLOCK_ATTACK,false);
+ script->set_constant("BLOCK_SKILL",PCBLOCK_SKILL,false);
+ script->set_constant("BLOCK_USEITEM",PCBLOCK_USEITEM,false);
+ script->set_constant("BLOCK_CHAT",PCBLOCK_CHAT,false);
+ script->set_constant("BLOCK_IMMUNE",PCBLOCK_IMMUNE,false);
+ script->set_constant("BLOCK_SITSTAND",PCBLOCK_SITSTAND,false);
+
/* Renewal */
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false);
diff --git a/src/map/status.c b/src/map/status.c
index 1a07f74..bf6e23b 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -1600,6 +1600,10 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
if( skill_id ) {
+ if ( src && src->type == BL_PC ) // *pcblock script command
+ if ( ((TBL_PC*)src)->state.blockedskill )
+ return 0;
+
if( src && !(src->type == BL_PC && ((TBL_PC*)src)->skillitem)) { // Items that cast skills using 'itemskill' will not be handled by map_zone_db.
int i;