From ca56c060cf3d4c11b0f6da9c5d5b2d8e8e5c3d7e Mon Sep 17 00:00:00 2001 From: Daegaladh Date: Mon, 27 Apr 2020 20:21:22 +0200 Subject: [PATCH] Added independent idle time and settings for homunculus share (#4761) * Follow up to 921b3e2c3e9eae36cbf2ca35bcede6e0d73ba074 --- conf/battle/homunc.conf | 24 ++++++++++++++++++++++-- doc/script_commands.txt | 8 ++++++++ src/map/atcommand.cpp | 2 ++ src/map/battle.cpp | 3 ++- src/map/battle.hpp | 1 + src/map/clif.cpp | 24 ++++++++++++++++++++++++ src/map/mob.cpp | 4 ++-- src/map/pc.hpp | 3 ++- src/map/script.cpp | 12 ++++++++++++ 9 files changed, 75 insertions(+), 6 deletions(-) diff --git a/conf/battle/homunc.conf b/conf/battle/homunc.conf index 8338fe68b2..253e22cce4 100644 --- a/conf/battle/homunc.conf +++ b/conf/battle/homunc.conf @@ -62,15 +62,35 @@ homunculus_S_growth_level: 99 // Official: yes homunculus_autofeed_always: yes -// Is getting exp/item from the homunculus disabled when you're idle? +// Is getting exp/item from the homunculus disabled when their master's idle? // Set to no, or the amount of seconds (NOT milliseconds) that need to pass before considering // a character idle. // Characters in a chat/vending are always considered idle. // A character's idle status is reset upon item use/skill use/attack (auto attack counts too)/movement. -// You will only receive items if 'homunculus_autoloot' is activated, +// Their master will only receive items if 'homunculus_autoloot' is activated, // otherwise they will be dropped on the ground as usual. +// NOTE: This option uses a special timer to track idle time, separated from the normal idle timer. hom_idle_no_share: no +// How the server should measure the homunculus master's idle time? (for homunculus exp share and autoloot ONLY) (Note 3) +// (This will only work if 'hom_idle_no_share' is enabled). +// 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 this features. +// Default: walk (0x1) + useskilltoid (0x2) + useskilltopos (0x4) + useitem (0x8) + attack (0x10) = 0x1F +// NOTE: This allows you to configure different settings for homunculus, separated from normal idle timer and 'idletime_option'. +// It will only apply to homunculus-only kills and it will not affect normal autoloot and party share options. +idletime_hom_option: 0x1F + // The rate at which homunculus gain experience from kills. (Note 2) // Only applies to renewal mode. // Official: 10% diff --git a/doc/script_commands.txt b/doc/script_commands.txt index c8e313893c..49bae2d921 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -3907,6 +3907,14 @@ Name is optional, and defaults to the attached player if omitted. --------------------------------------- +*checkidlehom({""}) + +Returns the time, in seconds, that the specified player has been idle for homunculus item/exp share. +Name is optional, and defaults to the attached player if omitted. +This will only work if 'hom_idle_no_share' and 'idletime_hom_option' are enabled (see '/conf/battle/homunc.conf'). + +--------------------------------------- + *agitcheck() *agitcheck2() *agitcheck3() diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index fb48eabf99..b5d04a12c4 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -10728,6 +10728,8 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message if (battle_config.idletime_option&IDLE_ATCOMMAND) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_ATCOMMAND) + sd->idletime_hom = last_tick; //Clearing these to be used once more. memset(command, '\0', sizeof(command)); diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 7aec469987..208f2e45f3 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -8820,7 +8820,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, }, + { "idletime_option", &battle_config.idletime_option, 0x1F, 0x1, 0xFFF, }, { "spawn_direction", &battle_config.spawn_direction, 0, 0, 1, }, { "arrow_shower_knockback", &battle_config.arrow_shower_knockback, 1, 0, 1, }, { "devotion_rdamage_skill_only", &battle_config.devotion_rdamage_skill_only, 1, 0, 1, }, @@ -8894,6 +8894,7 @@ static const struct _battle_data { { "boss_nopc_idleskill_rate", &battle_config.boss_nopc_idleskill_rate, 100, 0, 100, }, { "boss_nopc_move_rate", &battle_config.boss_nopc_move_rate, 100, 0, 100, }, { "hom_idle_no_share", &battle_config.hom_idle_no_share, 0, 0, INT_MAX, }, + { "idletime_hom_option", &battle_config.idletime_hom_option, 0x1F, 0x1, 0xFFF, }, { "devotion_standup_fix", &battle_config.devotion_standup_fix, 1, 0, 1, }, { "feature.bgqueue", &battle_config.feature_bgqueue, 1, 0, 1, }, { "homunculus_exp_gain", &battle_config.homunculus_exp_gain, 10, 0, 100, }, diff --git a/src/map/battle.hpp b/src/map/battle.hpp index 1ebd060839..17c53d4305 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -672,6 +672,7 @@ struct Battle_Config int boss_nopc_idleskill_rate; int boss_nopc_move_rate; int hom_idle_no_share; + int idletime_hom_option; int devotion_standup_fix; int feature_bgqueue; int homunculus_exp_gain; diff --git a/src/map/clif.cpp b/src/map/clif.cpp index a3d5f2759a..d3a7adbd85 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -10242,6 +10242,8 @@ static bool clif_process_message(struct map_session_data* sd, bool whisperFormat if (battle_config.idletime_option&IDLE_CHAT) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_CHAT) + sd->idletime_hom = last_tick; return true; } @@ -11018,6 +11020,8 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) //Set last idle time... [Skotlex] if (battle_config.idletime_option&IDLE_WALK) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_WALK) + sd->idletime_hom = last_tick; unit_walktoxy(&sd->bl, x, y, 4); } @@ -11232,6 +11236,8 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd) if (battle_config.idletime_option&IDLE_EMOTION) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_EMOTION) + sd->idletime_hom = last_tick; if (sd->state.block_action & PCBLOCK_EMOTION) { clif_skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1); @@ -11316,6 +11322,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, pc_delinvincibletimer(sd); if (battle_config.idletime_option&IDLE_ATTACK) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_ATTACK) + sd->idletime_hom = last_tick; unit_attack(&sd->bl, target_id, action_type != 0); break; case 0x02: // sitdown @@ -11346,6 +11354,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if (battle_config.idletime_option&IDLE_SIT) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_SIT) + sd->idletime_hom = last_tick; pc_setsit(sd); skill_sit(sd, true); @@ -11369,6 +11379,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if (pc_setstand(sd, false)) { if (battle_config.idletime_option&IDLE_SIT) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_SIT) + sd->idletime_hom = last_tick; skill_sit(sd, false); clif_standing(&sd->bl); } @@ -11626,6 +11638,8 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd){ if (battle_config.idletime_option&IDLE_DROPITEM) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_DROPITEM) + sd->idletime_hom = last_tick; return; } @@ -11656,6 +11670,8 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] if (battle_config.idletime_option&IDLE_USEITEM) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_USEITEM) + sd->idletime_hom = last_tick; n = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0])-2; if(n <0 || n >= MAX_INVENTORY) @@ -11703,6 +11719,8 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) if (battle_config.idletime_option&IDLE_USEITEM) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_USEITEM) + sd->idletime_hom = last_tick; //Client doesn't send the position for ammo. if(sd->inventory_data[index]->type == IT_AMMO) @@ -11742,6 +11760,8 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd) if (battle_config.idletime_option&IDLE_USEITEM) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_USEITEM) + sd->idletime_hom = last_tick; pc_unequipitem(sd,index,1); } @@ -12391,6 +12411,8 @@ void clif_parse_skill_toid( struct map_session_data* sd, uint16 skill_id, uint16 // This is done here, because homunculi and mercenaries can be triggered by AI and not by the player itself if (battle_config.idletime_option&IDLE_USESKILLTOID) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_USESKILLTOID) + sd->idletime_hom = last_tick; if( sd->npc_id ){ if( pc_hasprogress( sd, WIP_DISABLE_SKILLITEM ) || !sd->npc_item_flag || !( inf & INF_SELF_SKILL ) ){ @@ -12519,6 +12541,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] if (battle_config.idletime_option&IDLE_USESKILLTOPOS) sd->idletime = last_tick; + if (battle_config.hom_idle_no_share && sd->hd && battle_config.idletime_hom_option&IDLE_USESKILLTOPOS) + sd->idletime_hom = last_tick; if( skill_isNotOk(skill_id, sd) ) return; diff --git a/src/map/mob.cpp b/src/map/mob.cpp index b230aacedf..218cb387dd 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2186,8 +2186,8 @@ static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, str if( sd == NULL ) sd = map_charid2sd(dlist->third_charid); test_autoloot = sd && (drop_rate <= sd->state.autoloot || pc_isautolooting(sd, ditem->item_data.nameid)) - && (battle_config.idle_no_autoloot == 0 || DIFF_TICK(last_tick, sd->idletime) < battle_config.idle_no_autoloot) - && (battle_config.homunculus_autoloot?(battle_config.hom_idle_no_share == 0 || !pc_isidle_hom(sd)):!flag); + && (flag?(battle_config.homunculus_autoloot?(battle_config.hom_idle_no_share == 0 || !pc_isidle_hom(sd)):0): + (battle_config.idle_no_autoloot == 0 || DIFF_TICK(last_tick, sd->idletime) < battle_config.idle_no_autoloot)); #ifdef AUTOLOOT_DISTANCE test_autoloot = test_autoloot && sd->bl.m == md->bl.m && check_distance_blxy(&sd->bl, dlist->x, dlist->y, AUTOLOOT_DISTANCE); diff --git a/src/map/pc.hpp b/src/map/pc.hpp index f18cf6a469..54c74d7718 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -366,6 +366,7 @@ struct map_session_data { int npc_timer_id; //For player attached npc timers. [Skotlex] unsigned int chatID; time_t idletime; + time_t idletime_hom; struct s_progressbar { int npc_id; @@ -910,7 +911,7 @@ extern struct s_job_info job_info[CLASS_COUNT]; #define pc_isdead(sd) ( (sd)->state.dead_sit == 1 ) #define pc_issit(sd) ( (sd)->vd.dead_sit == 2 ) #define pc_isidle_party(sd) ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share ) -#define pc_isidle_hom(sd) ( (sd)->hd && ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.hom_idle_no_share ) ) +#define pc_isidle_hom(sd) ( (sd)->hd && ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime_hom) >= battle_config.hom_idle_no_share ) ) #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)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend ) diff --git a/src/map/script.cpp b/src/map/script.cpp index 6bd04b65d7..388918fbc9 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -17384,6 +17384,17 @@ BUILDIN_FUNC(checkidle) return SCRIPT_CMD_SUCCESS; } +BUILDIN_FUNC(checkidlehom) +{ + TBL_PC *sd = NULL; + + if( script_nick2sd(2,sd) ) + script_pushint(st, DIFF_TICK(last_tick, sd->idletime_hom)); + else + script_pushint(st, 0); + return SCRIPT_CMD_SUCCESS; +} + BUILDIN_FUNC(searchitem) { struct script_data* data = script_getdata(st, 2); @@ -25082,6 +25093,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(checkvending,"?"), BUILDIN_DEF(checkchatting,"?"), BUILDIN_DEF(checkidle,"?"), + BUILDIN_DEF(checkidlehom,"?"), BUILDIN_DEF(openmail,"?"), BUILDIN_DEF(openauction,"?"), BUILDIN_DEF(checkcell,"siii"),