From 225593f84ecb64036323864f7fd7e7e15ad28287 Mon Sep 17 00:00:00 2001 From: "Guilherme G. Menaldo" Date: Thu, 17 Aug 2023 23:18:46 -0300 Subject: [PATCH] refactor SA_AUTOSPELL spell selection - split spell selection logic into smaller functions - move spell list building to skill.c instead of clif - use config file for autospell list --- src/map/clif.c | 51 ++++---- src/map/clif.h | 2 +- src/map/skill.c | 115 ++++++++++++------ src/map/skill.h | 2 + src/plugins/HPMHooking/HPMHooking.Defs.inc | 8 +- .../HPMHooking_map.HPMHooksCore.inc | 8 ++ .../HPMHooking_map.HookingPoints.inc | 2 + .../HPMHooking/HPMHooking_map.Hooks.inc | 64 +++++++++- 8 files changed, 178 insertions(+), 74 deletions(-) diff --git a/src/map/clif.c b/src/map/clif.c index 3f0b91f2b44..b1c845baaef 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -7998,46 +7998,43 @@ static void clif_pet_food(struct map_session_data *sd, int foodid, int fail) WFIFOSET(fd, sizeof(struct PACKET_ZC_FEED_PET)); } -/// Presents a list of skills that can be auto-spelled (ZC_AUTOSPELLLIST). -/// 01cd { .L }*7 -static void clif_autospell(struct map_session_data *sd, uint16 skill_lv) +/** + * Presents a list of skills that can be auto-spelled (ZC_AUTOSPELLLIST). + * + * 01cd { .L }*7 + * 0afb .W { .L }* + * + * @param sd player who will receive the list + * @param skill_lv autospell skill level + * @param skill_ids_list list of available skills to choose from + * @param list_len length of skill_ids_list + */ +static void clif_autospell(struct map_session_data *sd, uint16 skill_lv, int *skill_ids_list, int list_len) { #if PACKETVER_MAIN_NUM >= 20090406 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO) || PACKETVER_SAK_NUM >= 20080618 nullpo_retv(sd); - int fd = sd->fd; #if PACKETVER_MAIN_NUM >= 20181128 || PACKETVER_RE_NUM >= 20181031 - // reserve space for 7 skills - WFIFOHEAD(fd, sizeof(struct PACKET_ZC_AUTOSPELLLIST) + 4 * 7); + const int len = sizeof(struct PACKET_ZC_AUTOSPELLLIST) + sizeof(int) * list_len; #else - WFIFOHEAD(fd, sizeof(struct PACKET_ZC_AUTOSPELLLIST)); + const int len = sizeof(struct PACKET_ZC_AUTOSPELLLIST); + if (list_len > 7) { + ShowError("%s: AutoSpell list too big for current client. Limit: %d, received: %d. Truncating list...\n", 7, list_len); + list_len = 7; + } #endif + + int fd = sd->fd; + WFIFOHEAD(fd, len); + struct PACKET_ZC_AUTOSPELLLIST *p = WFIFOP(fd, 0); memset(p, 0, sizeof(struct PACKET_ZC_AUTOSPELLLIST)); - p->packetType = HEADER_ZC_AUTOSPELLLIST; - int index = 0; - - if (skill_lv > 0 && pc->checkskill(sd, MG_NAPALMBEAT) > 0) - p->skills[index++] = MG_NAPALMBEAT; - if (skill_lv > 1 && pc->checkskill(sd, MG_COLDBOLT) > 0) - p->skills[index++] = MG_COLDBOLT; - if (skill_lv > 1 && pc->checkskill(sd, MG_FIREBOLT) > 0) - p->skills[index++] = MG_FIREBOLT; - if (skill_lv > 1 && pc->checkskill(sd, MG_LIGHTNINGBOLT) > 0) - p->skills[index++] = MG_LIGHTNINGBOLT; - if (skill_lv > 4 && pc->checkskill(sd, MG_SOULSTRIKE) > 0) - p->skills[index++] = MG_SOULSTRIKE; - if (skill_lv > 7 && pc->checkskill(sd, MG_FIREBALL) > 0) - p->skills[index++] = MG_FIREBALL; - if (skill_lv > 9 && pc->checkskill(sd, MG_FROSTDIVER) > 0) - p->skills[index++] = MG_FROSTDIVER; + p->packetType = HEADER_ZC_AUTOSPELLLIST; #if PACKETVER_MAIN_NUM >= 20181128 || PACKETVER_RE_NUM >= 20181031 - const int len = sizeof(struct PACKET_ZC_AUTOSPELLLIST) + index * 4; p->packetLength = len; -#else - const int len = sizeof(struct PACKET_ZC_AUTOSPELLLIST); #endif + memcpy(p->skills, skill_ids_list, sizeof(int) * list_len); WFIFOSET(fd, len); sd->menuskill_id = SA_AUTOSPELL; diff --git a/src/map/clif.h b/src/map/clif.h index 2f340d4387e..5e9741e2b77 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -1088,7 +1088,7 @@ struct clif_interface { void (*skill_mapinfomessage) (struct map_session_data *sd, int type); void (*skill_produce_mix_list) (struct map_session_data *sd, int skill_id, int trigger); void (*cooking_list) (struct map_session_data *sd, int trigger, uint16 skill_id, int qty, int list_type); - void (*autospell) (struct map_session_data *sd,uint16 skill_lv); + void (*autospell) (struct map_session_data *sd, uint16 skill_lv, int *skill_ids_list, int list_len); void (*combo_delay) (struct block_list *bl,int wait); void (*status_change) (struct block_list *bl, int relevant_bl, int type, int flag, int total_tick, int val1, int val2, int val3); void (*status_change_sub) (struct block_list *bl, int type, int relevant_bl, int flag, int tick, int total_tick, int val1, int val2, int val3); diff --git a/src/map/skill.c b/src/map/skill.c index e4f0ba79a90..9e78e4bcf5d 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -8776,43 +8776,8 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv), skill_id); break; case SA_AUTOSPELL: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(sd){ - sd->state.workinprogress = 3; - clif->autospell(sd,skill_lv); - }else { - int maxlv=1,spellid=0; - static const int spellarray[3] = { MG_COLDBOLT,MG_FIREBOLT,MG_LIGHTNINGBOLT }; - if(skill_lv >= 10) { - spellid = MG_FROSTDIVER; -#if 0 - if (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SA_SAGE) - maxlv = 10; - else -#endif // 0 - maxlv = skill_lv - 9; - } - else if(skill_lv >=8) { - spellid = MG_FIREBALL; - maxlv = skill_lv - 7; - } - else if(skill_lv >=5) { - spellid = MG_SOULSTRIKE; - maxlv = skill_lv - 4; - } - else if(skill_lv >=2) { - int i = rnd() % ARRAYLENGTH(spellarray); - spellid = spellarray[i]; - maxlv = skill_lv - 1; - } - else if(skill_lv > 0) { - spellid = MG_NAPALMBEAT; - maxlv = 3; - } - if(spellid > 0) - sc_start4(src,src,SC_AUTOSPELL,100,skill_lv,spellid,maxlv,0, - skill->get_time(SA_AUTOSPELL, skill_lv), SA_AUTOSPELL); - } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill->autospell_select_spell(src, skill_lv); break; case BS_GREED: @@ -17834,8 +17799,80 @@ static void skill_weaponrefine(struct map_session_data *sd, int idx) } /*========================================== - * + * Auto Spell / Hindsight *------------------------------------------*/ + +/** + * Prepares list and request player to choose the spell they want to use (Auto Spell skill) + * @param sd player casting the skill + * @param skill_lv Auto Spell level + */ +static void skill_autospell_select_spell_pc(struct map_session_data *sd, int skill_lv) +{ + nullpo_retv(sd); + + int *skill_ids; + CREATE(skill_ids, int, MAX_AUTOSPELL_DB); + + int valid_len = 0; + + for (int i = 0; i < MAX_AUTOSPELL_DB; ++i) { + const struct s_autospell_db *sk = &skill->dbs->autospell_db[i]; + if (sk->autospell_level == 0) + break; + + if (skill_lv >= sk->autospell_level && pc->checkskill(sd, sk->skill_id) > 0) { + skill_ids[valid_len] = sk->skill_id; + valid_len++; + } + } + + sd->state.workinprogress = 3; + clif->autospell(sd, skill_lv, skill_ids, valid_len); + + aFree(skill_ids); +} + +/** + * Auto Spell skill spell selection step. + * @param bl unit casting the skill + * @param skill_lv skill level + */ +static void skill_autospell_select_spell(struct block_list *bl, int skill_lv) +{ + nullpo_retv(bl); + + if (bl->type == BL_PC) { + skill->autospell_select_spell_pc(BL_CAST(BL_PC, bl), skill_lv); + return; + } + + int lower_idx = -1; + int upper_idx = 0; + int highest_autospell_tier = 0; + while (upper_idx < MAX_AUTOSPELL_DB + && skill->dbs->autospell_db[upper_idx].autospell_level > 0 + && skill->dbs->autospell_db[upper_idx].autospell_level <= skill_lv) { + if (highest_autospell_tier != skill->dbs->autospell_db[upper_idx].autospell_level) { + lower_idx = upper_idx; + highest_autospell_tier = skill->dbs->autospell_db[upper_idx].autospell_level; + } + + upper_idx++; + } + + if (lower_idx == -1) + return; // No skill available + + int skill_idx = lower_idx; + if ((upper_idx - lower_idx) > 1) + skill_idx += rnd() % (upper_idx - lower_idx); + + const struct s_autospell_db *sk = &skill->dbs->autospell_db[skill_idx]; + sc_start4(bl, bl, SC_AUTOSPELL, 100, skill_lv, sk->skill_id, sk->skill_lv[skill_lv - 1], 0, + skill->get_time(SA_AUTOSPELL, skill_lv), SA_AUTOSPELL); +} + static int skill_autospell(struct map_session_data *sd, uint16 skill_id) { uint16 skill_lv; @@ -25242,6 +25279,8 @@ void skill_defaults(void) skill->repairweapon = skill_repairweapon; skill->identify = skill_identify; skill->weaponrefine = skill_weaponrefine; + skill->autospell_select_spell = skill_autospell_select_spell; + skill->autospell_select_spell_pc = skill_autospell_select_spell_pc; skill->autospell = skill_autospell; skill->calc_heal = skill_calc_heal; skill->check_cloaking = skill_check_cloaking; diff --git a/src/map/skill.h b/src/map/skill.h index 72db5d5fb88..a61f12feed6 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -2168,6 +2168,8 @@ struct skill_interface { void (*repairweapon) (struct map_session_data *sd, int idx); void (*identify) (struct map_session_data *sd,int idx); void (*weaponrefine) (struct map_session_data *sd,int idx); + void (*autospell_select_spell) (struct block_list *bl, int skill_lv); + void (*autospell_select_spell_pc) (struct map_session_data *sd, int skill_lv); int (*autospell) (struct map_session_data *md,uint16 skill_id); int (*calc_heal) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, bool heal); bool (*check_cloaking) (struct block_list *bl, struct status_change_entry *sce); diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index a2cea37d5a3..9ed280799b1 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -1566,8 +1566,8 @@ typedef void (*HPMHOOK_pre_clif_skill_produce_mix_list) (struct map_session_data typedef void (*HPMHOOK_post_clif_skill_produce_mix_list) (struct map_session_data *sd, int skill_id, int trigger); typedef void (*HPMHOOK_pre_clif_cooking_list) (struct map_session_data **sd, int *trigger, uint16 *skill_id, int *qty, int *list_type); typedef void (*HPMHOOK_post_clif_cooking_list) (struct map_session_data *sd, int trigger, uint16 skill_id, int qty, int list_type); -typedef void (*HPMHOOK_pre_clif_autospell) (struct map_session_data **sd, uint16 *skill_lv); -typedef void (*HPMHOOK_post_clif_autospell) (struct map_session_data *sd, uint16 skill_lv); +typedef void (*HPMHOOK_pre_clif_autospell) (struct map_session_data **sd, uint16 *skill_lv, int **skill_ids_list, int *list_len); +typedef void (*HPMHOOK_post_clif_autospell) (struct map_session_data *sd, uint16 skill_lv, int *skill_ids_list, int list_len); typedef void (*HPMHOOK_pre_clif_combo_delay) (struct block_list **bl, int *wait); typedef void (*HPMHOOK_post_clif_combo_delay) (struct block_list *bl, int wait); typedef void (*HPMHOOK_pre_clif_status_change) (struct block_list **bl, int *relevant_bl, int *type, int *flag, int *total_tick, int *val1, int *val2, int *val3); @@ -8466,6 +8466,10 @@ typedef void (*HPMHOOK_pre_skill_identify) (struct map_session_data **sd, int *i typedef void (*HPMHOOK_post_skill_identify) (struct map_session_data *sd, int idx); typedef void (*HPMHOOK_pre_skill_weaponrefine) (struct map_session_data **sd, int *idx); typedef void (*HPMHOOK_post_skill_weaponrefine) (struct map_session_data *sd, int idx); +typedef void (*HPMHOOK_pre_skill_autospell_select_spell) (struct block_list **bl, int *skill_lv); +typedef void (*HPMHOOK_post_skill_autospell_select_spell) (struct block_list *bl, int skill_lv); +typedef void (*HPMHOOK_pre_skill_autospell_select_spell_pc) (struct map_session_data **sd, int *skill_lv); +typedef void (*HPMHOOK_post_skill_autospell_select_spell_pc) (struct map_session_data *sd, int skill_lv); typedef int (*HPMHOOK_pre_skill_autospell) (struct map_session_data **md, uint16 *skill_id); typedef int (*HPMHOOK_post_skill_autospell) (int retVal___, struct map_session_data *md, uint16 skill_id); typedef int (*HPMHOOK_pre_skill_calc_heal) (struct block_list **src, struct block_list **target, uint16 *skill_id, uint16 *skill_lv, bool *heal); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index 420a83fe14a..64aac6c2442 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -6390,6 +6390,10 @@ struct { struct HPMHookPoint *HP_skill_identify_post; struct HPMHookPoint *HP_skill_weaponrefine_pre; struct HPMHookPoint *HP_skill_weaponrefine_post; + struct HPMHookPoint *HP_skill_autospell_select_spell_pre; + struct HPMHookPoint *HP_skill_autospell_select_spell_post; + struct HPMHookPoint *HP_skill_autospell_select_spell_pc_pre; + struct HPMHookPoint *HP_skill_autospell_select_spell_pc_post; struct HPMHookPoint *HP_skill_autospell_pre; struct HPMHookPoint *HP_skill_autospell_post; struct HPMHookPoint *HP_skill_calc_heal_pre; @@ -13931,6 +13935,10 @@ struct { int HP_skill_identify_post; int HP_skill_weaponrefine_pre; int HP_skill_weaponrefine_post; + int HP_skill_autospell_select_spell_pre; + int HP_skill_autospell_select_spell_post; + int HP_skill_autospell_select_spell_pc_pre; + int HP_skill_autospell_select_spell_pc_post; int HP_skill_autospell_pre; int HP_skill_autospell_post; int HP_skill_calc_heal_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 0c5321b2ee3..f0f89781ee6 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -3270,6 +3270,8 @@ struct HookingPointData HookingPoints[] = { { HP_POP(skill->repairweapon, HP_skill_repairweapon) }, { HP_POP(skill->identify, HP_skill_identify) }, { HP_POP(skill->weaponrefine, HP_skill_weaponrefine) }, + { HP_POP(skill->autospell_select_spell, HP_skill_autospell_select_spell) }, + { HP_POP(skill->autospell_select_spell_pc, HP_skill_autospell_select_spell_pc) }, { HP_POP(skill->autospell, HP_skill_autospell) }, { HP_POP(skill->calc_heal, HP_skill_calc_heal) }, { HP_POP(skill->check_cloaking, HP_skill_check_cloaking) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index c12cfd36220..f210b4fa2fc 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -12071,14 +12071,14 @@ void HP_clif_cooking_list(struct map_session_data *sd, int trigger, uint16 skill } return; } -void HP_clif_autospell(struct map_session_data *sd, uint16 skill_lv) { +void HP_clif_autospell(struct map_session_data *sd, uint16 skill_lv, int *skill_ids_list, int list_len) { int hIndex = 0; if (HPMHooks.count.HP_clif_autospell_pre > 0) { - void (*preHookFunc) (struct map_session_data **sd, uint16 *skill_lv); + void (*preHookFunc) (struct map_session_data **sd, uint16 *skill_lv, int **skill_ids_list, int *list_len); *HPMforce_return = false; for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_autospell_pre; hIndex++) { preHookFunc = HPMHooks.list.HP_clif_autospell_pre[hIndex].func; - preHookFunc(&sd, &skill_lv); + preHookFunc(&sd, &skill_lv, &skill_ids_list, &list_len); } if (*HPMforce_return) { *HPMforce_return = false; @@ -12086,13 +12086,13 @@ void HP_clif_autospell(struct map_session_data *sd, uint16 skill_lv) { } } { - HPMHooks.source.clif.autospell(sd, skill_lv); + HPMHooks.source.clif.autospell(sd, skill_lv, skill_ids_list, list_len); } if (HPMHooks.count.HP_clif_autospell_post > 0) { - void (*postHookFunc) (struct map_session_data *sd, uint16 skill_lv); + void (*postHookFunc) (struct map_session_data *sd, uint16 skill_lv, int *skill_ids_list, int list_len); for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_autospell_post; hIndex++) { postHookFunc = HPMHooks.list.HP_clif_autospell_post[hIndex].func; - postHookFunc(sd, skill_lv); + postHookFunc(sd, skill_lv, skill_ids_list, list_len); } } return; @@ -85256,6 +85256,58 @@ void HP_skill_weaponrefine(struct map_session_data *sd, int idx) { } return; } +void HP_skill_autospell_select_spell(struct block_list *bl, int skill_lv) { + int hIndex = 0; + if (HPMHooks.count.HP_skill_autospell_select_spell_pre > 0) { + void (*preHookFunc) (struct block_list **bl, int *skill_lv); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_autospell_select_spell_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_skill_autospell_select_spell_pre[hIndex].func; + preHookFunc(&bl, &skill_lv); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.skill.autospell_select_spell(bl, skill_lv); + } + if (HPMHooks.count.HP_skill_autospell_select_spell_post > 0) { + void (*postHookFunc) (struct block_list *bl, int skill_lv); + for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_autospell_select_spell_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_skill_autospell_select_spell_post[hIndex].func; + postHookFunc(bl, skill_lv); + } + } + return; +} +void HP_skill_autospell_select_spell_pc(struct map_session_data *sd, int skill_lv) { + int hIndex = 0; + if (HPMHooks.count.HP_skill_autospell_select_spell_pc_pre > 0) { + void (*preHookFunc) (struct map_session_data **sd, int *skill_lv); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_autospell_select_spell_pc_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_skill_autospell_select_spell_pc_pre[hIndex].func; + preHookFunc(&sd, &skill_lv); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.skill.autospell_select_spell_pc(sd, skill_lv); + } + if (HPMHooks.count.HP_skill_autospell_select_spell_pc_post > 0) { + void (*postHookFunc) (struct map_session_data *sd, int skill_lv); + for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_autospell_select_spell_pc_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_skill_autospell_select_spell_pc_post[hIndex].func; + postHookFunc(sd, skill_lv); + } + } + return; +} int HP_skill_autospell(struct map_session_data *md, uint16 skill_id) { int hIndex = 0; int retVal___ = 0;