diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 71201f1f21..44034a896d 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -6278,6 +6278,24 @@ it just removes non-permanent script. --------------------------------------- +*plagiarizeskill ,; + +Enable the player to plagiarize specific skills that are copyable. +Return 1 on success, 0 otherwise. + +--------------------------------------- + +*plagiarizeskillreset ; + +Remove a plagiarized skill from the player. +Return 1 on success, 0 otherwise. + +Flag constants: + 1 - Use for Plagiarism Skill + 2 - Use for Reproduce Skill + +--------------------------------------- + *skill ,{,}; *skill "",{,}; *addtoskill ,{,}; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index d5cdc281ef..03432fc426 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -51,6 +51,7 @@ #include "pc_groups.hpp" #include "pet.hpp" // pet_unlocktarget() #include "quest.hpp" +#include "skill.hpp" // skill_isCopyable() #include "script.hpp" // struct script_reg, struct script_regstr #include "searchstore.hpp" // struct s_search_store_info #include "status.hpp" // OPTION_*, struct weapon_atk @@ -5087,6 +5088,93 @@ bool pc_skill(struct map_session_data* sd, uint16 skill_id, int level, enum e_ad } return true; } + +/** + * Set's a player's plagiarized skill. + * @param sd: Player + * @param skill_id: Skill to be plagiarized + * @param skill_lv: Skill level to be plagiarized + * @return True on success or false otherwise + */ +bool pc_skill_plagiarism(map_session_data &sd, uint16 skill_id, uint16 skill_lv) +{ + skill_id = skill_dummy2skill_id(skill_id); + uint16 idx = skill_get_index(skill_id); + + // Use skill index, avoiding out-of-bound array [Cydh] + if (idx == 0) { + ShowWarning("pc_skill_plagiarism: invalid skill idx 0 for skill %d.\n", skill_id); + return false; + } + + skill_lv = cap_value(skill_lv, 1, skill_get_max(skill_id)); + + int type = skill_isCopyable(&sd, skill_id); + if (type == 1) { + pc_skill_plagiarism_reset(sd, type); + + sd.cloneskill_idx = idx; + pc_setglobalreg(&sd, add_str(SKILL_VAR_PLAGIARISM), skill_id); + pc_setglobalreg(&sd, add_str(SKILL_VAR_PLAGIARISM_LV), skill_lv); + } else if (type == 2) { + pc_skill_plagiarism_reset(sd, type); + + sd.reproduceskill_idx = idx; + pc_setglobalreg(&sd, add_str(SKILL_VAR_REPRODUCE), skill_id); + pc_setglobalreg(&sd, add_str(SKILL_VAR_REPRODUCE_LV), skill_lv); + } else { + ShowWarning("pc_skill_plagiarism: skill %d is not copyable.\n", skill_id); + return false; + } + + sd.status.skill[idx].id = skill_id; + sd.status.skill[idx].lv = skill_lv; + sd.status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; + clif_addskill(&sd, skill_id); + + return true; +} + +/** + * Clear plagiarized skills from a player. + * @param sd: Player + * @param type: 1 for Plagiarism or 2 for Reproduce + * @return True on success or false otherwise + */ +bool pc_skill_plagiarism_reset(map_session_data &sd, uint8 type) +{ + uint16 idx; + if (type == 1) + idx = sd.cloneskill_idx; + else if (type == 2) + idx = sd.reproduceskill_idx; + else { + ShowError("pc_skill_plagiarism_reset: Unknown type %d.\n", type); + return false; + } + + if (sd.status.skill[idx].flag == SKILL_FLAG_PLAGIARIZED) { + uint16 skill_id = sd.status.skill[idx].id; + sd.status.skill[idx].id = 0; + sd.status.skill[idx].lv = 0; + sd.status.skill[idx].flag = SKILL_FLAG_PERMANENT; + clif_deleteskill(&sd, skill_id); + + if (type == 1) { + sd.cloneskill_idx = 0; + pc_setglobalreg(&sd, add_str(SKILL_VAR_PLAGIARISM), 0); + pc_setglobalreg(&sd, add_str(SKILL_VAR_PLAGIARISM_LV), 0); + } + else if (type == 2) { + sd.reproduceskill_idx = 0; + pc_setglobalreg(&sd, add_str(SKILL_VAR_REPRODUCE), 0); + pc_setglobalreg(&sd, add_str(SKILL_VAR_REPRODUCE_LV), 0); + } + } + + return true; +} + /*========================================== * Append a card to an item ? *------------------------------------------*/ @@ -10302,27 +10390,11 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper) } if(sd->cloneskill_idx > 0) { - if( sd->status.skill[sd->cloneskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) { - sd->status.skill[sd->cloneskill_idx].id = 0; - sd->status.skill[sd->cloneskill_idx].lv = 0; - sd->status.skill[sd->cloneskill_idx].flag = SKILL_FLAG_PERMANENT; - clif_deleteskill(sd, static_cast(pc_readglobalreg(sd, add_str(SKILL_VAR_PLAGIARISM)))); - } - sd->cloneskill_idx = 0; - pc_setglobalreg(sd, add_str(SKILL_VAR_PLAGIARISM), 0); - pc_setglobalreg(sd, add_str(SKILL_VAR_PLAGIARISM_LV), 0); + pc_skill_plagiarism_reset(*sd, 1); } if(sd->reproduceskill_idx > 0) { - if( sd->status.skill[sd->reproduceskill_idx].flag == SKILL_FLAG_PLAGIARIZED ) { - sd->status.skill[sd->reproduceskill_idx].id = 0; - sd->status.skill[sd->reproduceskill_idx].lv = 0; - sd->status.skill[sd->reproduceskill_idx].flag = SKILL_FLAG_PERMANENT; - clif_deleteskill(sd, static_cast(pc_readglobalreg(sd, add_str(SKILL_VAR_REPRODUCE)))); - } - sd->reproduceskill_idx = 0; - pc_setglobalreg(sd, add_str(SKILL_VAR_REPRODUCE), 0); - pc_setglobalreg(sd, add_str(SKILL_VAR_REPRODUCE_LV), 0); + pc_skill_plagiarism_reset(*sd, 2); } if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree. diff --git a/src/map/pc.hpp b/src/map/pc.hpp index d7f647bc2f..d2b56b1459 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -1431,6 +1431,8 @@ enum e_addskill_type { }; bool pc_skill(struct map_session_data *sd, uint16 skill_id, int level, enum e_addskill_type type); +bool pc_skill_plagiarism(map_session_data &sd, uint16 skill_id, uint16 skill_lv); +bool pc_skill_plagiarism_reset(map_session_data &sd, uint8 type); int pc_insert_card(struct map_session_data *sd,int idx_card,int idx_equip); diff --git a/src/map/script.cpp b/src/map/script.cpp index df5a491f39..6f1a88aa9a 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -10177,6 +10177,26 @@ BUILDIN_FUNC(petautobonus3) { return SCRIPT_CMD_SUCCESS; } +BUILDIN_FUNC(skill_plagiarism) +{ + TBL_PC *sd; + + if (script_rid2sd(sd)) + script_pushint(st, pc_skill_plagiarism(*sd, script_getnum(st, 2), script_getnum(st, 3))); + + return SCRIPT_CMD_SUCCESS; +} + +BUILDIN_FUNC(skill_plagiarism_reset) +{ + TBL_PC *sd; + + if (!script_rid2sd(sd)) + script_pushint(st, pc_skill_plagiarism_reset(*sd, script_getnum(st, 2))); + + return SCRIPT_CMD_SUCCESS; +} + /// Changes the level of a player skill. /// defaults to 1 /// =0 : set the level of the skill @@ -26808,6 +26828,8 @@ struct script_function buildin_func[] = { BUILDIN_DEF(petautobonus,"sii??"), BUILDIN_DEF2(petautobonus,"petautobonus2","sii??"), BUILDIN_DEF(petautobonus3,"siiv?"), + BUILDIN_DEF(skill_plagiarism, "ii"), + BUILDIN_DEF(skill_plagiarism_reset, "i"), BUILDIN_DEF(skill,"vi?"), BUILDIN_DEF2(skill,"addtoskill","vi?"), // [Valaris] BUILDIN_DEF(guildskill,"vi"), diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 5efa89a084..8518ec00ad 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -799,7 +799,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk * @return 0 - Cannot be copied; 1 - Can be copied by Plagiarism 2 - Can be copied by Reproduce * @author Aru - for previous check; Jobbie for class restriction idea; Cydh expands the copyable skill */ -static int8 skill_isCopyable(struct map_session_data *sd, uint16 skill_id) { +int8 skill_isCopyable(struct map_session_data *sd, uint16 skill_id) { uint16 skill_idx = skill_get_index(skill_id); if (!skill_idx) diff --git a/src/map/skill.hpp b/src/map/skill.hpp index 84c6ef1fd8..6400e57503 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -611,6 +611,7 @@ int skill_autospell(struct map_session_data *md,uint16 skill_id); int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, bool heal); bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce); +int8 skill_isCopyable(struct map_session_data *sd, uint16 skill_id); // Abnormal status bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd);