From c84f47d877caad7756cc48f14829dcea8560f77b Mon Sep 17 00:00:00 2001 From: csnv Date: Sun, 14 Apr 2024 05:06:40 +0200 Subject: [PATCH] Fixed Rogue's plagiarize losing skills when copying skills from its own skill tree --- .gitignore | 1 + src/map/clif.c | 11 +++- src/map/pc.c | 62 ++++++++++++++----- src/map/pc.h | 1 + src/map/skill.c | 33 +++++++++- src/map/status.c | 6 +- src/plugins/HPMHooking/HPMHooking.Defs.inc | 2 + .../HPMHooking_map.HPMHooksCore.inc | 4 ++ .../HPMHooking_map.HookingPoints.inc | 1 + .../HPMHooking/HPMHooking_map.Hooks.inc | 27 ++++++++ 10 files changed, 127 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 283e134a8..17ece337e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .ycm_extra_conf.py* Thumbs.db .vscode +enc_temp_folder # / /*.exe diff --git a/src/map/clif.c b/src/map/clif.c index 73c05deb8..12e3116ae 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -5729,8 +5729,15 @@ static void clif_skillup(struct map_session_data *sd, uint16 skill_id, int skill WFIFOW(fd, 0) = 0x10e; WFIFOW(fd, 2) = skill_id; WFIFOW(fd, 4) = skill_lv; - WFIFOW(fd, 6) = skill->get_sp(skill_id, skill_lv); - WFIFOW(fd, 8) = (flag)?skill->get_range2(&sd->bl, skill_id, skill_lv) : skill->get_range(skill_id, skill_lv); + + if (skill_lv > 0) { + WFIFOW(fd, 6) = skill->get_sp(skill_id, skill_lv); + WFIFOW(fd, 8) = (flag)?skill->get_range2(&sd->bl, skill_id, skill_lv) : skill->get_range(skill_id, skill_lv); + } else { + WFIFOW(fd, 6) = 0; + WFIFOW(fd, 8) = 0; + } + if( flag ) WFIFOB(fd,10) = (skill_lv < skill->tree_get_max(skill_id, sd->status.class)) ? 1 : 0; else diff --git a/src/map/pc.c b/src/map/pc.c index 6324b8fb8..f0f51c62a 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1481,7 +1481,7 @@ static int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_li *------------------------------------------*/ static int pc_reg_received(struct map_session_data *sd) { - int i, idx = 0; + int i, idx = 0, knownlv = 0; nullpo_ret(sd); sd->vars_ok = true; @@ -1520,21 +1520,31 @@ static int pc_reg_received(struct map_session_data *sd) if ((i = pc->checkskill(sd,RG_PLAGIARISM)) > 0) { sd->cloneskill_id = pc_readglobalreg(sd,script->add_variable("CLONE_SKILL")); if (sd->cloneskill_id > 0 && (idx = skill->get_index(sd->cloneskill_id)) > 0) { + knownlv = sd->status.skill[idx].lv; sd->status.skill[idx].id = sd->cloneskill_id; sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_variable("CLONE_SKILL_LV")); if (sd->status.skill[idx].lv > i) sd->status.skill[idx].lv = i; - sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; + + if (knownlv > 0 && sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) + sd->status.skill[idx].flag = knownlv + SKILL_FLAG_REPLACED_LV_0; + else + sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; } } if ((i = pc->checkskill(sd,SC_REPRODUCE)) > 0) { sd->reproduceskill_id = pc_readglobalreg(sd,script->add_variable("REPRODUCE_SKILL")); if( sd->reproduceskill_id > 0 && (idx = skill->get_index(sd->reproduceskill_id)) > 0) { + knownlv = sd->status.skill[idx].lv; sd->status.skill[idx].id = sd->reproduceskill_id; sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_variable("REPRODUCE_SKILL_LV")); - if( i < sd->status.skill[idx].lv) + if (sd->status.skill[idx].lv > i) sd->status.skill[idx].lv = i; - sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; + + if (knownlv > 0 && sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) + sd->status.skill[idx].flag = knownlv + SKILL_FLAG_REPLACED_LV_0; + else + sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; } } @@ -1644,8 +1654,22 @@ static void pc_calc_skilltree_clear(struct map_session_data *sd) nullpo_retv(sd); for (i = 0; i < MAX_SKILL_DB; i++) { - if (sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED) //Don't touch these - sd->status.skill[i].id = 0; //First clear skills. + // Don't touch these + if (sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED + || sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED + || (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0 + && (sd->status.skill[i].id == sd->cloneskill_id || sd->status.skill[i].id == sd->reproduceskill_id)) + ) + continue; + + sd->status.skill[i].id = 0; //First clear skills. + + if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { // Plagiarized skills were already ignored + // Restore original level of skills after deleting earned skills. + sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; + sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; + } + /* permanent skills that must be re-checked */ if (sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) { switch (skill->dbs->db[i].nameid) { @@ -1678,14 +1702,6 @@ static int pc_calc_skilltree(struct map_session_data *sd) pc->calc_skilltree_clear(sd); - for (int i = 0; i < MAX_SKILL_DB; i++) { - if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { - // Restore original level of skills after deleting earned skills. - sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; - sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; - } - } - //Enable Bard/Dancer spirit linked skills. skill->add_bard_dancer_soullink_songs(sd); @@ -1905,7 +1921,7 @@ static int pc_clean_skilltree(struct map_session_data *sd) sd->status.skill[i].flag = 0; } else if (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; - sd->status.skill[i].flag = 0; + sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } } @@ -7279,6 +7295,21 @@ static int pc_statusup2(struct map_session_data *sd, int type, int val) return val; } +/** + * Check skill_id is part of character's own skill tree + */ +static bool pc_isownskill(struct map_session_data *sd, uint16 skill_id) +{ + nullpo_ret(sd); + + int class_idx = pc->class2idx(sd->status.class); + int i; + + ARR_FIND(0, MAX_SKILL_TREE, i, pc->skill_tree[class_idx][i].id == 0 || pc->skill_tree[class_idx][i].id == skill_id); + + return i < MAX_SKILL_TREE && pc->skill_tree[class_idx][i].id == skill_id; +} + /*========================================== * Update skill_lv for player sd * Skill point allocation @@ -12829,6 +12860,7 @@ void pc_defaults(void) pc->maxparameterincrease = pc_maxparameterincrease; pc->statusup = pc_statusup; pc->statusup2 = pc_statusup2; + pc->isownskill = pc_isownskill; pc->skillup = pc_skillup; pc->allskillup = pc_allskillup; pc->resetlvl = pc_resetlvl; diff --git a/src/map/pc.h b/src/map/pc.h index 25ca09daf..9ca106297 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -1074,6 +1074,7 @@ END_ZEROED_BLOCK; /* End */ int (*maxparameterincrease) (struct map_session_data* sd, int type); bool (*statusup) (struct map_session_data *sd, int type, int increase); int (*statusup2) (struct map_session_data *sd,int type,int val); + bool (*isownskill) (struct map_session_data* sd, uint16 skill_id); int (*skillup) (struct map_session_data *sd,uint16 skill_id); int (*allskillup) (struct map_session_data *sd); int (*resetlvl) (struct map_session_data *sd,int type); diff --git a/src/map/skill.c b/src/map/skill.c index f4c398870..fc11e0bcf 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -3662,11 +3662,16 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li break; } - int cidx, idx, lv = 0; + int cidx, idx, knownlv, lv = 0; cidx = skill->get_index(copy_skill); switch(can_copy(tsd, copy_skill)) { case 1: // Plagiarism { + + knownlv = pc->checkskill(tsd, copy_skill); + if (knownlv >= skill_lv) + break; + if (tsd->cloneskill_id) { idx = skill->get_index(tsd->cloneskill_id); if (tsd->status.skill[idx].flag == SKILL_FLAG_PLAGIARIZED) { @@ -3674,6 +3679,14 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li tsd->status.skill[idx].lv = 0; tsd->status.skill[idx].flag = 0; clif->deleteskill(tsd, tsd->cloneskill_id, false); +#if PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918 + if (pc->isownskill(tsd, tsd->cloneskill_id)) + clif->skillup(tsd, tsd->cloneskill_id, 0, 1); +#endif + } else if (tsd->status.skill[idx].flag >= SKILL_FLAG_REPLACED_LV_0) { + tsd->status.skill[idx].lv = tsd->status.skill[idx].flag - SKILL_FLAG_REPLACED_LV_0; + tsd->status.skill[idx].flag = SKILL_FLAG_PERMANENT; + clif->addskill(tsd, tsd->cloneskill_id); } } @@ -3685,13 +3698,18 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li tsd->status.skill[cidx].id = copy_skill; tsd->status.skill[cidx].lv = lv; - tsd->status.skill[cidx].flag = SKILL_FLAG_PLAGIARIZED; + tsd->status.skill[cidx].flag = knownlv > 0 ? knownlv + SKILL_FLAG_REPLACED_LV_0 : SKILL_FLAG_PLAGIARIZED; clif->addskill(tsd, copy_skill); } break; case 2: // Reproduce { + knownlv = pc->checkskill(tsd, copy_skill); lv = sc ? sc->data[SC__REPRODUCE]->val1 : 1; + + if (knownlv >= lv) + break; + if (tsd->reproduceskill_id) { idx = skill->get_index(tsd->reproduceskill_id); if (tsd->status.skill[idx].flag == SKILL_FLAG_PLAGIARIZED) { @@ -3699,8 +3717,17 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li tsd->status.skill[idx].lv = 0; tsd->status.skill[idx].flag = 0; clif->deleteskill(tsd, tsd->reproduceskill_id, false); +#if PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918 + if (pc->isownskill(tsd, tsd->reproduceskill_id)) + clif->skillup(tsd, tsd->reproduceskill_id, 0, 1); +#endif + } else if (tsd->status.skill[idx].flag >= SKILL_FLAG_REPLACED_LV_0) { + tsd->status.skill[idx].lv = tsd->status.skill[idx].flag - SKILL_FLAG_REPLACED_LV_0; + tsd->status.skill[idx].flag = SKILL_FLAG_PERMANENT; + clif->addskill(tsd, tsd->reproduceskill_id); } } + lv = min(lv, skill->get_max(copy_skill)); tsd->reproduceskill_id = copy_skill; @@ -3709,7 +3736,7 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li tsd->status.skill[cidx].id = copy_skill; tsd->status.skill[cidx].lv = lv; - tsd->status.skill[cidx].flag = SKILL_FLAG_PLAGIARIZED; + tsd->status.skill[cidx].flag = knownlv > 0 ? knownlv + SKILL_FLAG_REPLACED_LV_0 : SKILL_FLAG_PLAGIARIZED; clif->addskill(tsd, copy_skill); } break; diff --git a/src/map/status.c b/src/map/status.c index e44ad58c7..93b9d31e3 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2395,8 +2395,12 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o // Client doesn't delete unavailable skills even if we refresh // the skill tree, individually delete them. for (i = 0; i < MAX_SKILL_DB; i++) { - if (b_skill[i].id != 0 && sd->status.skill[i].id == 0) + if (b_skill[i].id != 0 && sd->status.skill[i].id == 0) { clif->deleteskill(sd, b_skill[i].id, true); + // Skills that belong to the skill tree need to be "downgraded" + if (pc->isownskill(sd, b_skill[i].id)) + clif->skillup(sd, b_skill[i].id, 0, 1); + } } #endif clif->skillinfoblock(sd); diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index e21e5b969..ed4d159ef 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -7198,6 +7198,8 @@ typedef bool (*HPMHOOK_pre_pc_statusup) (struct map_session_data **sd, int *type typedef bool (*HPMHOOK_post_pc_statusup) (bool retVal___, struct map_session_data *sd, int type, int increase); typedef int (*HPMHOOK_pre_pc_statusup2) (struct map_session_data **sd, int *type, int *val); typedef int (*HPMHOOK_post_pc_statusup2) (int retVal___, struct map_session_data *sd, int type, int val); +typedef bool (*HPMHOOK_pre_pc_isownskill) (struct map_session_data **sd, uint16 *skill_id); +typedef bool (*HPMHOOK_post_pc_isownskill) (bool retVal___, struct map_session_data *sd, uint16 skill_id); typedef int (*HPMHOOK_pre_pc_skillup) (struct map_session_data **sd, uint16 *skill_id); typedef int (*HPMHOOK_post_pc_skillup) (int retVal___, struct map_session_data *sd, uint16 skill_id); typedef int (*HPMHOOK_pre_pc_allskillup) (struct map_session_data **sd); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index e1d4f6610..fba206261 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -5176,6 +5176,8 @@ struct { struct HPMHookPoint *HP_pc_statusup_post; struct HPMHookPoint *HP_pc_statusup2_pre; struct HPMHookPoint *HP_pc_statusup2_post; + struct HPMHookPoint *HP_pc_isownskill_pre; + struct HPMHookPoint *HP_pc_isownskill_post; struct HPMHookPoint *HP_pc_skillup_pre; struct HPMHookPoint *HP_pc_skillup_post; struct HPMHookPoint *HP_pc_allskillup_pre; @@ -12733,6 +12735,8 @@ struct { int HP_pc_statusup_post; int HP_pc_statusup2_pre; int HP_pc_statusup2_post; + int HP_pc_isownskill_pre; + int HP_pc_isownskill_post; int HP_pc_skillup_pre; int HP_pc_skillup_post; int HP_pc_allskillup_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 1af289b53..0693be6cd 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -2653,6 +2653,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pc->maxparameterincrease, HP_pc_maxparameterincrease) }, { HP_POP(pc->statusup, HP_pc_statusup) }, { HP_POP(pc->statusup2, HP_pc_statusup2) }, + { HP_POP(pc->isownskill, HP_pc_isownskill) }, { HP_POP(pc->skillup, HP_pc_skillup) }, { HP_POP(pc->allskillup, HP_pc_allskillup) }, { HP_POP(pc->resetlvl, HP_pc_resetlvl) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 5879feb9e..10a28c50c 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -68816,6 +68816,33 @@ int HP_pc_statusup2(struct map_session_data *sd, int type, int val) { } return retVal___; } +bool HP_pc_isownskill(struct map_session_data *sd, uint16 skill_id) { + int hIndex = 0; + bool retVal___ = false; + if (HPMHooks.count.HP_pc_isownskill_pre > 0) { + bool (*preHookFunc) (struct map_session_data **sd, uint16 *skill_id); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_isownskill_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pc_isownskill_pre[hIndex].func; + retVal___ = preHookFunc(&sd, &skill_id); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.pc.isownskill(sd, skill_id); + } + if (HPMHooks.count.HP_pc_isownskill_post > 0) { + bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, uint16 skill_id); + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_isownskill_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pc_isownskill_post[hIndex].func; + retVal___ = postHookFunc(retVal___, sd, skill_id); + } + } + return retVal___; +} int HP_pc_skillup(struct map_session_data *sd, uint16 skill_id) { int hIndex = 0; int retVal___ = 0;