From 9dd6ee636b783f1cd57b1be3d02fcc9782ebe2c3 Mon Sep 17 00:00:00 2001 From: panikon Date: Thu, 10 Jul 2014 02:02:59 -0300 Subject: Corrected some SC behaviour, special thanks to Rytech - Extracted some methods to check SC blocks - Fixed issue that when players couldn't attack they couldn't talk to NPCs with mob view id either Follow up to ec51176326c6028630835538db67826281d34ffe, fixed minor typo --- src/map/atcommand.c | 2 +- src/map/clif.c | 25 +++++++++++-------------- src/map/pc.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/map/pc.h | 2 ++ src/map/unit.c | 6 ++++++ 5 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 9162d1c45..d36e98c41 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -3933,7 +3933,7 @@ ACMD(mount_peco) return true; } if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER ) { - if( !pc->checkskill(sd,RA_WUGRIDER) > 0 ) { + if( !pc->checkskill(sd,RA_WUGRIDER) ) { sprintf(atcmd_output, msg_txt(213), skill->get_desc(RA_WUGRIDER)); // You need %s to mount! clif->message(fd, atcmd_output); return false; diff --git a/src/map/clif.c b/src/map/clif.c index 8ddae3326..750689816 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9866,7 +9866,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) if( atcommand->exec(fd, sd, message, true) ) return; - 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) ) + if( !pc->can_talk(sd) ) return; if( battle_config.min_chat_delay ) { //[Skotlex] @@ -10113,14 +10113,14 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, return; } - if (sd->sc.count && - (sd->sc.data[SC_TRICKDEAD] || - (sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) || - sd->sc.data[SC_BLADESTOP] || - sd->sc.data[SC_DEEP_SLEEP] || - sd->sc.data[SC__MANHOLE] || - sd->sc.data[SC_CURSEDCIRCLE_ATKER] || - sd->sc.data[SC_CURSEDCIRCLE_TARGET] )) + // Statuses that don't let the player sit / attack / talk with NPCs(targeted) + // (not all are included in pc_can_attack) + if( sd->sc.count && ( + sd->sc.data[SC_TRICKDEAD] || + (sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) || + sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEEP_SLEEP] ) + ) return; pc_stop_walking(sd, 1); @@ -10144,10 +10144,6 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if( sd->sc.option&OPTION_COSTUME ) return; - if( sd->sc.data[SC_BASILICA] || sd->sc.data[SC__SHADOWFORM] || - (sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) ) - return; - if (!battle_config.sdelay_attack_enable && pc->checkskill(sd, SA_FREECAST) <= 0) { if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) { clif->skill_fail(sd, 1, USESKILL_FAIL_SKILLINTERVAL, 0); @@ -10379,7 +10375,8 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) if ( atcommand->exec(fd, sd, message, true) ) return; - 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)) + // Statuses that prevent the player from whispering + if( !pc->can_talk(sd) ) return; if (battle_config.min_chat_delay) { //[Skotlex] diff --git a/src/map/pc.c b/src/map/pc.c index 47744a839..b8b6cda46 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4384,6 +4384,7 @@ int pc_useitem(struct map_session_data *sd,int n) { if (nameid != ITEMID_NAUTHIZ && sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING) return 0; + // Statuses that don't let the player use items if (sd->sc.count && ( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) || @@ -4396,6 +4397,7 @@ int pc_useitem(struct map_session_data *sd,int n) { sd->sc.data[SC_WHITEIMPRISON] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || + sd->sc.data[SC_COLD] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) )) return 0; @@ -8131,6 +8133,49 @@ int pc_setmadogear(TBL_PC* sd, int flag) return 0; } +/** + * Determines whether a player can attack based on status changes + * Why not use status_check_skilluse? + * "src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack." + * Even ground-based attacks should be blocked by these statuses + * Called from unit_attack and unit_attack_timer_sub + * @retval true Can attack + **/ +bool pc_can_attack( struct map_session_data *sd, int target_id ) { + nullpo_retr(false, sd); + + if( sd->sc.data[SC_BASILICA] || + sd->sc.data[SC__SHADOWFORM] || + sd->sc.data[SC__MANHOLE] || + sd->sc.data[SC_CURSEDCIRCLE_ATKER] || + sd->sc.data[SC_CURSEDCIRCLE_TARGET] || + sd->sc.data[SC_COLD] || + sd->sc.data[SC_ALL_RIDING] || // The client doesn't let you, this is to make cheat-safe + sd->sc.data[SC_TRICKDEAD] || + (sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) || + sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEEP_SLEEP] ) + return false; + + return true; +} + +/** + * Determines whether a player can talk/whisper based on status changes + * Called from clif_parse_GlobalMessage and clif_parse_WisMessage + * @retval true Can talk + **/ +bool pc_can_talk( struct map_session_data *sd ) { + nullpo_retr(false, 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) ) + return false; + + return true; +} + /*========================================== * Check if player can drop an item *------------------------------------------*/ @@ -10835,6 +10880,8 @@ void pc_defaults(void) { pc->setstand = pc_setstand; pc->candrop = pc_candrop; + pc->can_talk = pc_can_talk; + pc->can_attack = pc_can_attack; pc->jobid2mapid = pc_jobid2mapid; // Skotlex pc->mapid2jobid = pc_mapid2jobid; // Skotlex diff --git a/src/map/pc.h b/src/map/pc.h index 19e0348d0..1789a8a7b 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -771,6 +771,8 @@ struct pc_interface { //int (*getrefinebonus) (int lv,int type); FIXME: This function does not exist, nor it is ever called bool (*can_give_items) (struct map_session_data *sd); bool (*can_give_bound_items) (struct map_session_data *sd); + bool (*can_talk) (struct map_session_data *sd); + bool (*can_attack) ( struct map_session_data *sd, int target_id ); bool (*can_use_command) (struct map_session_data *sd, const char *command); int (*set_group) (struct map_session_data *sd, int group_id); diff --git a/src/map/unit.c b/src/map/unit.c index 875eb30af..e5c7c45c1 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -909,6 +909,7 @@ int unit_can_move(struct block_list *bl) { )) return 0; //Can't move + // Status changes that block movement if (sc) { if( sc->count && ( @@ -1602,6 +1603,10 @@ int unit_attack(struct block_list *src,int target_id,int continuous) { unit->stop_attack(src); return 0; } + if( !pc->can_attack(sd, target_id) ) { + unit->stop_attack(src); + return 0; + } } if( battle->check_target(src,target,BCT_ENEMY) <= 0 || !status->check_skilluse(src, target, 0, 0) ) { unit->unattackable(src); @@ -1791,6 +1796,7 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick) { #ifdef OFFICIAL_WALKPATH || !path->search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) #endif + || (sd && !pc->can_attack(sd, ud->target) ) ) return 0; // can't attack under these conditions -- cgit v1.2.3-60-g2f50