diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index e6b5386769..c18b8353ac 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -857,7 +857,10 @@ 793: Usage @camerainfo range rotation latitude -//794-899 free +// pcblock command +794: This action is currently blocked. + +//795-899 free //------------------------------------ // More atcommands message diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 0d9c427887..191fcdaf09 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -6133,6 +6133,55 @@ Examples: --------------------------------------- +*setpcblock {,}; +*getpcblock {}; + +'setpcblock' command prevents/allows the player from doing the given of action +during the player session (note: @reloadscript also removes all ). +The values are bit-masks, multiples of can be added to change the player action. + +'getpcblock' command return the bit-mask value of the currently +enabled block flags. + +The available are: + PCBLOCK_MOVE + PCBLOCK_ATTACK + PCBLOCK_SKILL + PCBLOCK_USEITEM + PCBLOCK_CHAT + PCBLOCK_IMMUNE + PCBLOCK_SITSTAND + PCBLOCK_COMMANDS + PCBLOCK_NPCCLICK + PCBLOCK_EMOTION + PCBLOCK_ALL + +Examples: + +// Make the attached player invulnerable to monster (same as @monsterignore) + setpcblock (getpcblock() & PCBLOCK_IMMUNE); + +// Prevents the attached player from attacking and using skills + setpcblock (getpcblock() & (PCBLOCK_ATTACK|PCBLOCK_SKILL)); + +// Re-enables attack, skills and item use + setpcblock (getpcblock() & ~(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM)); + +// getpcblock related checks + if (getpcblock() & PCBLOCK_IMMUNE) + mes "You are invulnerable!"; + + if (getpcblock() & (PCBLOCK_MOVE|PCBLOCK_SITSTAND)) + mes "You can't walk or sit."; + + if ((getpcblock() & (PCBLOCK_ATTACK|PCBLOCK_SKILL)) == 0) + mes "You can attack and use skills."; + + if (getpcblock() & PCBLOCK_CHAT) + mes "You can't chat."; + +--------------------------------------- + ================================== |5.- Mob / NPC -related commands.| ================================== diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 8bed1a91c2..4573ee85f7 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -3917,6 +3917,7 @@ ACMD_FUNC(reload) { for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ){ pc_close_npc(pl_sd,1); clif_cutin(pl_sd, "", 255); + pl_sd->state.block_action = 0; } mapit_free(iter); @@ -5972,7 +5973,7 @@ ACMD_FUNC(autotrade) { sd->state.autotrade = 1; if (battle_config.autotrade_monsterignore) - sd->state.monster_ignore = 1; + sd->state.block_action |= PCBLOCK_IMMUNE; if( sd->state.vending ){ if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", vendings_table, sd->vender_id ) != SQL_SUCCESS ){ @@ -6629,7 +6630,7 @@ ACMD_FUNC(npctalk) bool ifcolor=(*(command + 8) != 'c' && *(command + 8) != 'C')?0:1; unsigned long color=0; - if (sd->sc.cant.chat) + if (sd->sc.cant.chat || (sd->state.block_action & PCBLOCK_CHAT)) return -1; //no "chatting" while muted. if(!ifcolor) { @@ -6678,7 +6679,7 @@ ACMD_FUNC(pettalk) return -1; } - if (sd->sc.cant.chat) + if (sd->sc.cant.chat || (sd->state.block_action & PCBLOCK_CHAT)) return -1; //no "chatting" while muted. if (!message || !*message || sscanf(message, "%99[^\n]", mes) < 1) { @@ -7562,7 +7563,7 @@ ACMD_FUNC(homtalk) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - if (sd->sc.cant.chat) + if (sd->sc.cant.chat || (sd->state.block_action & PCBLOCK_CHAT)) return -1; //no "chatting" while muted. if ( !hom_is_active(sd->hd) ) { @@ -7970,7 +7971,7 @@ ACMD_FUNC(me) memset(tempmes, '\0', sizeof(tempmes)); memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (sd->sc.cant.chat) + if (sd->sc.cant.chat || (sd->state.block_action & PCBLOCK_CHAT)) return -1; //no "chatting" while muted. if (!message || !*message || sscanf(message, "%255[^\n]", tempmes) < 0) { @@ -8090,12 +8091,12 @@ ACMD_FUNC(monsterignore) { nullpo_retr(-1, sd); - if (!sd->state.monster_ignore) { - sd->state.monster_ignore = 1; - clif_displaymessage(sd->fd, msg_txt(sd,1305)); // You are now immune to attacks. - } else { - sd->state.monster_ignore = 0; + if (sd->state.block_action & PCBLOCK_IMMUNE) { + sd->state.block_action &= ~PCBLOCK_IMMUNE; clif_displaymessage(sd->fd, msg_txt(sd,1306)); // Returned to normal state. + } else { + sd->state.block_action |= PCBLOCK_IMMUNE; + clif_displaymessage(sd->fd, msg_txt(sd,1305)); // You are now immune to attacks. } return 0; @@ -10559,6 +10560,12 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message if( sscanf(atcmd_msg, "%255s %255[^\n]", command, params) < 2 ) params[0] = '\0'; + if (type == 1 && (sd->state.block_action & PCBLOCK_COMMANDS)) { + sprintf(output,msg_txt(sd,154), command); // %s failed. + clif_displaymessage(fd, output); + return true; + } + // @commands (script based) if((type == 1 || type == 3) && atcmd_binding_count > 0) { struct atcmd_binding_data *binding = get_atcommandbind_byname(command); diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 472dece863..b934cc39a3 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -7756,7 +7756,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f sd = BL_CAST(BL_PC, t_bl); sc = status_get_sc(t_bl); - if( (sd->state.monster_ignore || (sc->data[SC_KINGS_GRACE] && s_bl->type != BL_PC)) && flag&BCT_ENEMY ) + if( ((sd->state.block_action & PCBLOCK_IMMUNE) || (sc->data[SC_KINGS_GRACE] && s_bl->type != BL_PC)) && flag&BCT_ENEMY ) return 0; // Global immunity only to Attacks if( sd->status.karma && s_bl->type == BL_PC && ((TBL_PC*)s_bl)->status.karma ) state |= BCT_ENEMY; // Characters with bad karma may fight amongst them diff --git a/src/map/buyingstore.cpp b/src/map/buyingstore.cpp index 8a92aded9c..e79b4137be 100644 --- a/src/map/buyingstore.cpp +++ b/src/map/buyingstore.cpp @@ -700,7 +700,10 @@ void do_init_buyingstore_autotrade( void ) { CREATE(at->sd, struct map_session_data, 1); pc_setnewpc(at->sd, at->account_id, at->char_id, 0, gettick(), at->sex, 0); at->sd->state.autotrade = 1|4; - at->sd->state.monster_ignore = (battle_config.autotrade_monsterignore); + if (battle_config.autotrade_monsterignore) + at->sd->state.block_action |= PCBLOCK_IMMUNE; + else + at->sd->state.block_action &= ~PCBLOCK_IMMUNE; chrif_authreq(at->sd, true); uidb_put(buyingstore_autotrader_db, at->char_id, at); } diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 64b74c77c7..7b4713740f 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -10112,7 +10112,7 @@ static bool clif_process_message(struct map_session_data* sd, bool whisperFormat if( is_atcommand( fd, sd, out_message, 1 ) ) return false; - if (sd->sc.cant.chat) + if (sd->sc.cant.chat || (sd->state.block_action & PCBLOCK_CHAT)) return false; //no "chatting" while muted. if( battle_config.min_chat_delay ) { //[Skotlex] @@ -11099,6 +11099,11 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd) if (battle_config.idletime_option&IDLE_EMOTION) sd->idletime = last_tick; + if (sd->state.block_action & PCBLOCK_EMOTION) { + clif_skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1); + return; + } + if(battle_config.client_reshuffle_dice && emoticon>=ET_DICE1 && emoticon<=ET_DICE6) {// re-roll dice emoticon = rnd()%6+ET_DICE1; } @@ -11199,6 +11204,11 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, )) //No sitting during these states either. break; + if (sd->state.block_action & PCBLOCK_SITSTAND) { + clif_displaymessage(sd->fd, msg_txt(sd,794)); // This action is currently blocked. + break; + } + if (battle_config.idletime_option&IDLE_SIT) sd->idletime = last_tick; @@ -11216,6 +11226,11 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if (sd->sc.opt1 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING) break; + if (sd->state.block_action & PCBLOCK_SITSTAND) { + clif_displaymessage(sd->fd, msg_txt(sd,794)); // This action is currently blocked. + break; + } + if (pc_setstand(sd, false)) { if (battle_config.idletime_option&IDLE_SIT) sd->idletime = last_tick; @@ -11498,7 +11513,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) return; } - if ( (!sd->npc_id && pc_istrading(sd)) || sd->chatID ) + if ( (!sd->npc_id && pc_istrading(sd)) || sd->chatID || (sd->state.block_action & PCBLOCK_USEITEM) ) return; //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] @@ -12212,6 +12227,9 @@ void clif_parse_skill_toid( struct map_session_data* sd, uint16 skill_id, uint16 if (inf&INF_GROUND_SKILL || !inf) return; //Using a ground/passive skill on a target? WRONG. + if (sd->state.block_action & PCBLOCK_SKILL) + return; + if( SKILL_CHK_HOMUN(skill_id) ) { clif_parse_UseSkillToId_homun(sd->hd, sd, tick, skill_id, skill_lv, target_id); return; @@ -12325,6 +12343,9 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin if( !(skill_get_inf(skill_id)&INF_GROUND_SKILL) ) return; //Using a target skill on the ground? WRONG. + if (sd->state.block_action & PCBLOCK_SKILL) + return; + if( SKILL_CHK_HOMUN(skill_id) ) { clif_parse_UseSkillToPos_homun(sd->hd, sd, tick, skill_id, skill_lv, x, y, skillmoreinfo); return; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 170a129c4b..6c8f4b5a55 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -984,6 +984,9 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y) //if(sd->npc_id) // return 1; + if (sd->state.block_action & PCBLOCK_NPCCLICK) + return 0; + struct map_data *mapdata = map_getmapdata(m); for(i=0;inpc_num;i++) @@ -1284,7 +1287,12 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) //Hidden/Disabled npc. if (nd->class_ < 0 || nd->sc.option&(OPTION_INVISIBLE|OPTION_HIDE)) return 1; - + + if (sd->state.block_action & PCBLOCK_NPCCLICK) { + clif_msg(sd, WORK_IN_PROGRESS); + return 1; + } + switch(nd->subtype) { case NPCTYPE_SHOP: clif_npcbuysell(sd,nd->bl.id); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index c217692521..f252190ab3 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -9319,6 +9319,9 @@ bool pc_can_attack( struct map_session_data *sd, int target_id ) { if( pc_is90overweight(sd) || pc_isridingwug(sd) ) return false; + if (sd->state.block_action & PCBLOCK_ATTACK) + return false; + if( sd->sc.data[SC_BASILICA] || sd->sc.data[SC__SHADOWFORM] || sd->sc.data[SC_CURSEDCIRCLE_ATKER] || diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 1f038745ac..f6c0a65dcc 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -251,7 +251,6 @@ struct map_session_data { unsigned int noask :1; // [LuzZza] unsigned int trading :1; //[Skotlex] is 1 only after a trade has started. unsigned int deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE - unsigned int monster_ignore :1; // for monsters to ignore a character [Valaris] [zzo] 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 using_fake_npc :1; @@ -289,6 +288,7 @@ struct map_session_data { bool mail_writing; // Whether the player is currently writing a mail in RODEX or not bool cashshop_open; bool sale_open; + unsigned int block_action : 1; } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; diff --git a/src/map/script.cpp b/src/map/script.cpp index be5bebe74c..cb4ec9fd1d 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -17234,6 +17234,27 @@ BUILDIN_FUNC(pcblockskill) return SCRIPT_CMD_SUCCESS; } +BUILDIN_FUNC(setpcblock) +{ + TBL_PC *sd; + + if (script_mapid2sd(3, sd)) + sd->state.block_action |= (e_pcblock_action_flag)script_getnum(st, 2); + + return SCRIPT_CMD_SUCCESS; +} + +BUILDIN_FUNC(getpcblock) +{ + TBL_PC *sd; + + if (script_mapid2sd(2, sd)) + script_pushint(st, sd->state.block_action); + else + script_pushint(st, 0); + return SCRIPT_CMD_SUCCESS; +} + BUILDIN_FUNC(pcfollow) { TBL_PC *sd; @@ -24494,6 +24515,8 @@ struct script_function buildin_func[] = { BUILDIN_DEF2(pcblockmove,"unitblockmove","ii"), BUILDIN_DEF(pcblockskill,"ii"), BUILDIN_DEF2(pcblockskill,"unitblockskill","ii"), + BUILDIN_DEF(setpcblock, "i?"), + BUILDIN_DEF(getpcblock, "?"), // <--- [zBuffer] List of player cont commands // [zBuffer] List of unit control commands ---> BUILDIN_DEF(unitexists,"i"), diff --git a/src/map/script.hpp b/src/map/script.hpp index 9a06555fa4..1b19d1594f 100644 --- a/src/map/script.hpp +++ b/src/map/script.hpp @@ -1898,6 +1898,23 @@ enum e_hat_effects { HAT_EF_MAX }; +/** + * Player blocking actions related flags. + */ +enum e_pcblock_action_flag { + PCBLOCK_MOVE = 0x001, + PCBLOCK_ATTACK = 0x002, + PCBLOCK_SKILL = 0x004, + PCBLOCK_USEITEM = 0x008, + PCBLOCK_CHAT = 0x010, + PCBLOCK_IMMUNE = 0x020, + PCBLOCK_SITSTAND = 0x040, + PCBLOCK_COMMANDS = 0x080, + PCBLOCK_NPCCLICK = 0x100, + PCBLOCK_EMOTION = 0x200, + PCBLOCK_ALL = 0x3FF, +}; + /** * used to generate quick script_array entries **/ diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 2da78757a6..2b56d9791b 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -7193,6 +7193,19 @@ /* timer related */ export_constant(INFINITE_TICK); + /* block action */ + export_constant(PCBLOCK_MOVE); + export_constant(PCBLOCK_ATTACK); + export_constant(PCBLOCK_SKILL); + export_constant(PCBLOCK_USEITEM); + export_constant(PCBLOCK_CHAT); + export_constant(PCBLOCK_IMMUNE); + export_constant(PCBLOCK_SITSTAND); + export_constant(PCBLOCK_COMMANDS); + export_constant(PCBLOCK_NPCCLICK); + export_constant(PCBLOCK_EMOTION); + export_constant(PCBLOCK_ALL); + #undef export_constant #undef export_constant2 #undef export_parameter diff --git a/src/map/unit.cpp b/src/map/unit.cpp index 3305283d91..fcc9e8eae1 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -1376,7 +1376,7 @@ int unit_can_move(struct block_list *bl) { if (DIFF_TICK(ud->canmove_tick, gettick()) > 0) return 0; - if ((sd && (pc_issit(sd) || sd->state.vending || sd->state.buyingstore)) || ud->state.blockedmove) + if ((sd && (pc_issit(sd) || sd->state.vending || sd->state.buyingstore || (sd->state.block_action & PCBLOCK_MOVE))) || ud->state.blockedmove) return 0; // Can't move // Status changes that block movement diff --git a/src/map/vending.cpp b/src/map/vending.cpp index 73df92f89a..f2232be490 100755 --- a/src/map/vending.cpp +++ b/src/map/vending.cpp @@ -599,7 +599,10 @@ void do_init_vending_autotrade(void) CREATE(at->sd, struct map_session_data, 1); pc_setnewpc(at->sd, at->account_id, at->char_id, 0, gettick(), at->sex, 0); at->sd->state.autotrade = 1|2; - at->sd->state.monster_ignore = (battle_config.autotrade_monsterignore); + if (battle_config.autotrade_monsterignore) + at->sd->state.block_action |= PCBLOCK_IMMUNE; + else + at->sd->state.block_action &= ~PCBLOCK_IMMUNE; chrif_authreq(at->sd, true); uidb_put(vending_autotrader_db, at->char_id, at); }