diff --git a/conf/battle/player.conf b/conf/battle/player.conf index f71b2b5e75..5c8c4cd19c 100644 --- a/conf/battle/player.conf +++ b/conf/battle/player.conf @@ -229,3 +229,19 @@ fame_pharmacy_3: 1 fame_pharmacy_5: 3 fame_pharmacy_7: 10 fame_pharmacy_10: 50 + +// How the server should measure the character's idle time? (Note 3) +// 0x001 - Walk Request +// 0x002 - UseSkillToID Request (Targetted skill use attempt) +// 0x004 - UseSkillToPos Request (AoE skill use attempt) +// 0x008 - UseItem Request (Including equip/unequip) +// 0x010 - Attack Request +// 0x020 - Chat Request (Whisper, Party, Guild, Battlegrounds, etc) +// 0x040 - Sit/Standup Request +// 0x080 - Emotion Request +// 0x100 - DropItem Request +// 0x200 - @/#Command Request +// Please note that at least 1 option has to be enabled. +// Be mindful that the more options used, the easier it becomes to cheat features that rely on idletime (e.g. checkidle()). +// Default: walk (0x1) + useskilltoid (0x2) + useskilltopos (0x4) + useitem (0x8) + attack (0x10) = 0x1F +idletime_option: 0x1F diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 15edb0507e..3846c0543c 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -10160,6 +10160,9 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message sprintf(atcmd_msg, "%s", message); } + if (battle_config.idletime_option&IDLE_ATCOMMAND) + sd->idletime = last_tick; + //Clearing these to be used once more. memset(command, '\0', sizeof(command)); memset(params, '\0', sizeof(params)); diff --git a/src/map/battle.c b/src/map/battle.c index 37a7a0b9c1..e47e51cb26 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7783,6 +7783,7 @@ static const struct _battle_data { { "fame_pharmacy_10", &battle_config.fame_pharmacy_10, 50, 0, INT_MAX, }, { "mail_delay", &battle_config.mail_delay, 1000, 1000, INT_MAX, }, { "at_monsterignore", &battle_config.autotrade_monsterignore, 0, 0, 1, }, + { "idletime_option", &battle_config.idletime_option, 0x25, 1, INT_MAX, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index 9ee56d1b31..673e619843 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -565,6 +565,7 @@ extern struct Battle_Config int revive_onwarp; int mail_delay; int autotrade_monsterignore; + int idletime_option; } battle_config; void do_init_battle(void); diff --git a/src/map/clif.c b/src/map/clif.c index 9eafe83c3a..c0184ca322 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9708,9 +9708,6 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) // Notify everyone that this char logged in [Skotlex]. map_foreachpc(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 1); - // Set the initial idle time - sd->idletime = last_tick; - if (!sd->state.autotrade) { // Don't trigger NPC event or opening vending/buyingstore will be failed //Login Event npc_script_event(sd, NPCE_LOGIN); @@ -10010,7 +10007,8 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) RFIFOPOS(fd, packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0], &x, &y, NULL); //Set last idle time... [Skotlex] - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_WALK) + sd->idletime = last_tick; unit_walktoxy(&sd->bl, x, y, 4); } @@ -10124,6 +10122,9 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } + if (battle_config.idletime_option&IDLE_CHAT) + sd->idletime = last_tick; + if( sd->gcbind ) { channel_send(sd->gcbind,sd,message); return; @@ -10158,9 +10159,6 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) map_foreachinrange(npc_chat_sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl); #endif - // Reset idle time when using normal chat. - sd->idletime = last_tick; - // Chat logging type 'O' / Global Chat log_chat(LOG_CHAT_GLOBAL, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, message); } @@ -10256,6 +10254,9 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd) } sd->emotionlasttime = time(NULL); + if (battle_config.idletime_option&IDLE_EMOTION) + sd->idletime = last_tick; + if(battle_config.client_reshuffle_dice && emoticon>=E_DICE1 && emoticon<=E_DICE6) {// re-roll dice emoticon = rnd()%6+E_DICE1; } @@ -10332,7 +10333,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, } pc_delinvincibletimer(sd); - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_ATTACK) + sd->idletime = last_tick; unit_attack(&sd->bl, target_id, action_type != 0); break; case 0x02: // sitdown @@ -10356,7 +10358,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, )) //No sitting during these states either. break; - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_SIT) + sd->idletime = last_tick; + skill_sit(sd, 1); pc_setsit(sd); clif_sitting(&sd->bl); @@ -10374,7 +10378,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, return; } - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_SIT) + sd->idletime = last_tick; + pc_setstand(sd); skill_sit(sd, 0); clif_standing(&sd->bl); @@ -10458,8 +10464,8 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - // Reset idle time when using whisper/main chat. - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_CHAT) + sd->idletime = last_tick; // Chat logging type 'W' / Whisper log_chat(LOG_CHAT_WHISPER, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, target, message); @@ -10647,6 +10653,9 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd){ if (!pc_dropitem(sd, item_index, item_amount)) break; + if (battle_config.idletime_option&IDLE_DROPITEM) + sd->idletime = last_tick; + return; } @@ -10672,7 +10681,8 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) return; //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_USEITEM) + sd->idletime = last_tick; n = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-2; if(n <0 || n >= MAX_INVENTORY) @@ -10718,6 +10728,9 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) return; } + if (battle_config.idletime_option&IDLE_USEITEM) + sd->idletime = last_tick; + //Client doesn't send the position for ammo. if(sd->inventory_data[index]->type == IT_AMMO) pc_equipitem(sd,index,EQP_AMMO); @@ -10754,6 +10767,9 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd) index = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-2; + if (battle_config.idletime_option&IDLE_USEITEM) + sd->idletime = last_tick; + pc_unequipitem(sd,index,1); } @@ -11311,7 +11327,8 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_USESKILLTOID) + sd->idletime = last_tick; if( sd->npc_id ){ #ifdef RENEWAL @@ -11411,7 +11428,8 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin } //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_USESKILLTOPOS) + sd->idletime = last_tick; if( skill_isNotOk(skill_id, sd) ) return; @@ -12191,8 +12209,8 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd){ sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - // Reset idle time when using party chat. - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_CHAT) + sd->idletime = last_tick; party_send_message(sd, text, textlen); } @@ -12787,8 +12805,8 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd){ sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - // Reset idle time when using guild chat. - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_CHAT) + sd->idletime = last_tick; if( sd->bg_id ) bg_send_message(sd, text, textlen); @@ -15789,8 +15807,8 @@ void clif_parse_BattleChat(int fd, struct map_session_data* sd){ sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - // Reset idle time when using battleground chat. - sd->idletime = last_tick; + if (battle_config.idletime_option&IDLE_CHAT) + sd->idletime = last_tick; bg_send_message(sd, text, textlen); } diff --git a/src/map/pc.c b/src/map/pc.c index 896d3f1d2c..96bec5844e 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1151,6 +1151,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->cantalk_tick = tick; sd->canskill_tick = tick; sd->cansendmail_tick = tick; + sd->idletime = last_tick; for(i = 0; i < MAX_SPIRITBALL; i++) sd->spirit_timer[i] = INVALID_TIMER; diff --git a/src/map/pc.h b/src/map/pc.h index 32a223022b..8346608d77 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -666,6 +666,19 @@ enum ammo_type { A_THROWWEAPON //9 }; +enum idletime_option { + IDLE_WALK = 0x001, + IDLE_USESKILLTOID = 0x002, + IDLE_USESKILLTOPOS = 0x004, + IDLE_USEITEM = 0x008, + IDLE_ATTACK = 0x010, + IDLE_CHAT = 0x020, + IDLE_SIT = 0x040, + IDLE_EMOTION = 0x080, + IDLE_DROPITEM = 0x100, + IDLE_ATCOMMAND = 0x200, +}; + struct { unsigned int base_hp[MAX_LEVEL], base_sp[MAX_LEVEL]; //Storage for the first calculation with hp/sp factor and multiplicator int hp_factor, hp_multiplicator, sp_factor; diff --git a/src/map/unit.c b/src/map/unit.c index dbf0cc4462..68eb283db1 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2181,7 +2181,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t } if(ud->state.attack_continue) { - if( src->type == BL_PC ) + if (src->type == BL_PC && battle_config.idletime_option&IDLE_ATTACK) ((TBL_PC*)src)->idletime = last_tick; ud->attacktimer = add_timer(ud->attackabletime,unit_attack_timer,src->id,0); }