From 932e22bc99c12078a1a101cfc69778dd049d86f6 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Thu, 21 May 2020 08:46:41 +0200 Subject: Make Requirements->Items->Amount can be grouped by levels --- src/map/skill.c | 266 +++++++++++++++++++----- src/map/skill.h | 17 +- src/plugins/HPMHooking/HPMHooking.Defs.inc | 4 +- src/plugins/HPMHooking/HPMHooking_map.Hooks.inc | 12 +- 4 files changed, 236 insertions(+), 63 deletions(-) diff --git a/src/map/skill.c b/src/map/skill.c index 7a46026b1..09165506f 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -369,26 +369,50 @@ static int skill_get_spiritball(int skill_id, int skill_lv) return skill->dbs->db[idx].spiritball[skill_get_lvl_idx(skill_lv)]; } +/** + * Gets a skill's required item's ID by the skill's ID and the item's index. + * + * @param skill_id The skill's ID. + * @param item_idx The item's index. + * @return The skill's required item's ID corresponding to the passed index. Defaults to 0 in case of error. + * + **/ static int skill_get_itemid(int skill_id, int item_idx) { - int idx; if (skill_id == 0) return 0; - idx = skill->get_index(skill_id); - Assert_ret(idx != 0); + Assert_ret(item_idx >= 0 && item_idx < MAX_SKILL_ITEM_REQUIRE); - return skill->dbs->db[idx].itemid[item_idx]; + + int idx = skill->get_index(skill_id); + + Assert_ret(idx != 0); + + return skill->dbs->db[idx].req_items.item[item_idx].id; } -static int skill_get_itemqty(int skill_id, int item_idx) +/** + * Gets a skill's required item's amount by the skill's ID and level and the item's index. + * + * @param skill_id The skill's ID. + * @param item_idx The item's index. + * @param skill_lv The skill's level. + * @return The skill's required item's amount corresponding to the passed index and level. Defaults to 0 in case of error. + * + **/ +static int skill_get_itemqty(int skill_id, int item_idx, int skill_lv) { - int idx; if (skill_id == 0) return 0; - idx = skill->get_index(skill_id); - Assert_ret(idx != 0); + Assert_ret(item_idx >= 0 && item_idx < MAX_SKILL_ITEM_REQUIRE); - return skill->dbs->db[idx].amount[item_idx]; + Assert_ret(skill_lv > 0); + + int idx = skill->get_index(skill_id); + + Assert_ret(idx != 0); + + return skill->dbs->db[idx].req_items.item[item_idx].amount[skill_get_lvl_idx(skill_lv)]; } static int skill_get_zeny(int skill_id, int skill_lv) @@ -3901,8 +3925,8 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill_id, // Requirements for (i = 0; i < MAX_SKILL_ITEM_REQUIRE; i++) { - itemid[i] = skill->dbs->db[idx].itemid[i]; - amount[i] = skill->dbs->db[idx].amount[i]; + itemid[i] = skill->get_itemid(skill_id, i); + amount[i] = skill->get_itemqty(skill_id, i, lv); } hp = skill->dbs->db[idx].hp[lv-1]; sp = skill->dbs->db[idx].sp[lv-1]; @@ -7787,7 +7811,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * map->freeblock_unlock(); return 1; } - if (sd->inventory_data[inventory_idx] == NULL || sd->status.inventory[inventory_idx].amount < skill->get_itemqty(skill_id, item_idx)) { + if (sd->inventory_data[inventory_idx] == NULL || sd->status.inventory[inventory_idx].amount < skill->get_itemqty(skill_id, item_idx, skill_lv)) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0, 0); map->freeblock_unlock(); return 1; @@ -8415,7 +8439,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * if (nameid > 0) { int success; struct item item_tmp = { 0 }; - int amount = skill->get_itemqty(su->group->skill_id, i); + int amount = skill->get_itemqty(su->group->skill_id, i, skill_lv); item_tmp.nameid = nameid; item_tmp.identify = 1; if ((success = pc->additem(sd, &item_tmp, amount, LOG_TYPE_SKILL)) != 0) { @@ -11645,7 +11669,7 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill int bonus; if (inventory_idx == INDEX_NOT_FOUND || item_id <= 0 || sd->inventory_data[inventory_idx] == NULL - || sd->status.inventory[inventory_idx].amount < skill->get_itemqty(skill_id, item_idx) + || sd->status.inventory[inventory_idx].amount < skill->get_itemqty(skill_id, item_idx, skill_lv) ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0, 0); return 1; @@ -15634,11 +15658,11 @@ static struct skill_condition skill_get_requirement(struct map_session_data *sd, continue; break; case AB_ADORAMUS: - if( itemid_isgemstone(skill->dbs->db[idx].itemid[i]) && skill->check_pc_partner(sd,skill_id,&skill_lv, 1, 2) ) + if (itemid_isgemstone(skill->get_itemid(skill_id, i)) && skill->check_pc_partner(sd, skill_id, &skill_lv, 1, 2) != 0) continue; break; case WL_COMET: - if( itemid_isgemstone(skill->dbs->db[idx].itemid[i]) && skill->check_pc_partner(sd,skill_id,&skill_lv, 1, 0) ) + if (itemid_isgemstone(skill->get_itemid(skill_id, i)) && skill->check_pc_partner(sd, skill_id, &skill_lv, 1, 0) != 0) continue; break; case GN_FIRE_EXPANSION: @@ -15664,8 +15688,12 @@ static struct skill_condition skill_get_requirement(struct map_session_data *sd, } } - req.itemid[i] = skill->dbs->db[idx].itemid[i]; - req.amount[i] = skill->dbs->db[idx].amount[i]; + int amount; + + if ((amount = skill->get_itemqty(skill_id, i, skill_lv)) >= 0) { + req.itemid[i] = skill->get_itemid(skill_id, i); + req.amount[i] = amount; + } if (itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN) { if (sd->special_state.no_gemstone) { @@ -15709,8 +15737,8 @@ static struct skill_condition skill_get_requirement(struct map_session_data *sd, case SO_FIRE_INSIGNIA: case SO_WIND_INSIGNIA: case SO_EARTH_INSIGNIA: - req.itemid[skill_lv-1] = skill->dbs->db[idx].itemid[skill_lv-1]; - req.amount[skill_lv-1] = skill->dbs->db[idx].amount[skill_lv-1]; + req.itemid[skill_lv - 1] = skill->get_itemid(skill_id, skill_lv - 1); + req.amount[skill_lv - 1] = skill->get_itemqty(skill_id, skill_lv - 1, skill_lv); break; } if (skill_id == NC_REPAIR) { @@ -22340,6 +22368,53 @@ static void skill_validate_spirit_sphere_cost(struct config_setting_t *conf, str } } +/** + * Validates a skill's required items amounts when reading the skill DB. + * + * @param conf The libconfig settings block which contains the skill's data. + * @param sk The s_skill_db struct where the required items amounts should be set it. + * + **/ +static void skill_validate_item_requirements_sub_item_amount(struct config_setting_t *conf, struct s_skill_db *sk, int item_index) +{ + nullpo_retv(conf); + nullpo_retv(sk); + + for (int i = 0; i < MAX_SKILL_LEVEL; i++) + sk->req_items.item[item_index].amount[i] = 0; + + if (config_setting_is_group(conf)) { + for (int i = 0; i < MAX_SKILL_LEVEL; i++) { + char lv[6]; // Big enough to contain "Lv999" in case of custom MAX_SKILL_LEVEL. + safesnprintf(lv, sizeof(lv), "Lv%d", i + 1); + int amount; + + if (libconfig->setting_lookup_int(conf, lv, &amount) == CONFIG_TRUE) { + if (amount >= 0 && amount <= MAX_AMOUNT) + sk->req_items.item[item_index].amount[i] = amount; + else + ShowWarning("%s: Invalid required item amount %d specified in level %d for skill ID %d in %s! Minimum is 0, maximum is %d. Defaulting to 0...\n", + __func__, amount, i + 1, sk->nameid, conf->file, MAX_AMOUNT); + } else { + // Items is not required for this skill level. (Not even in inventory!) + sk->req_items.item[item_index].amount[i] = -1; + } + } + + return; + } + + int amount = libconfig->setting_get_int(conf); + + if (amount >= 0 && amount <= MAX_AMOUNT) { + for (int i = 0; i < MAX_SKILL_LEVEL; i++) + sk->req_items.item[item_index].amount[i] = amount; + } else { + ShowWarning("%s: Invalid required item amount %d specified for skill ID %d in %s! Minimum is 0, maximum is %d. Defaulting to 0...\n", + __func__, amount, sk->nameid, conf->file, MAX_AMOUNT); + } +} + /** * Validates a skill's required items when reading the skill DB. * @@ -22347,64 +22422,145 @@ static void skill_validate_spirit_sphere_cost(struct config_setting_t *conf, str * @param sk The s_skill_db struct where the required items should be set it. * **/ -static void skill_validate_item_requirements(struct config_setting_t *conf, struct s_skill_db *sk) +static void skill_validate_item_requirements_sub_items(struct config_setting_t *conf, struct s_skill_db *sk) { nullpo_retv(conf); nullpo_retv(sk); - skill->level_set_value(sk->itemid, 0); - skill->level_set_value(sk->amount, 0); + for (int i = 0; i < MAX_SKILL_ITEM_REQUIRE; i++) { + sk->req_items.item[i].id = 0; - struct config_setting_t *t = libconfig->setting_get_member(conf, "Items"); + for (int j = 0; j < MAX_SKILL_LEVEL; j++) + sk->req_items.item[i].amount[j] = 0; + } - if (t != NULL && config_setting_is_group(conf)) { - struct config_setting_t *tt; - int i = -1; + int item_index = 0; + int count = libconfig->setting_length(conf); - while ((tt = libconfig->setting_get_elem(t, ++i)) != NULL && i < MAX_SKILL_ITEM_REQUIRE) { - const char *type = config_setting_name(tt); + for (int i = 0; i < count; i++) { + struct config_setting_t *t = libconfig->setting_get_elem(conf, i); - if (strlen(type) < 2) { - ShowWarning("%s: Invalid required item %s specified for skill ID %d in %s! Skipping item...\n", - __func__, type, sk->nameid, conf->file); + if (t != NULL && strcasecmp(config_setting_name(t), "Any") != 0) { + if (item_index >= MAX_SKILL_ITEM_REQUIRE) { + ShowWarning("%s: Too many required items specified for skill ID %d in %s! Skipping item %s...\n", + __func__, sk->nameid, conf->file, config_setting_name(t)); continue; } - int item_id = 0; + int item_id = skill->validate_requirements_item_name(config_setting_name(t)); - if (type[0] == 'I' && type[1] == 'D') { - item_id = atoi(type + 2); - - if (item_id == 0 || itemdb->exists(item_id) == NULL) { - ShowWarning("%s: Invalid required item %s specified for skill ID %d in %s! Skipping item...\n", - __func__, type, sk->nameid, conf->file); - continue; - } - } else if (!script->get_constant(type, &item_id)) { + if (item_id == 0) { ShowWarning("%s: Invalid required item %s specified for skill ID %d in %s! Skipping item...\n", - __func__, type, sk->nameid, conf->file); + __func__, config_setting_name(t), sk->nameid, conf->file); continue; } - int amount = 0; + int j; - if (config_setting_is_group(tt)) - amount = libconfig->setting_get_int_elem(tt, 0); - else - amount = libconfig->setting_get_int(tt); + ARR_FIND(0, MAX_SKILL_ITEM_REQUIRE, j, sk->req_items.item[j].id == item_id); - if (amount < 0 || amount > MAX_AMOUNT) { - ShowWarning("%s: Invalid required item amount %d specified for skill ID %d in %s! Minimum is 0, maximum is %d. Skipping item...\n", - __func__, amount, sk->nameid, conf->file, MAX_AMOUNT); + if (j < MAX_SKILL_ITEM_REQUIRE) { + ShowWarning("%s: Duplicate required item %s specified for skill ID %d in %s! Skipping item...\n", + __func__, config_setting_name(t), sk->nameid, conf->file); continue; } - sk->itemid[i] = item_id; - sk->amount[i] = amount; + sk->req_items.item[item_index].id = item_id; + skill->validate_item_requirements_sub_item_amount(t, sk, item_index); + item_index++; } } } +/** + * Validates a skill's required items any-flag when reading the skill DB. + * + * @param conf The libconfig settings block which contains the skill's data. + * @param sk The s_skill_db struct where the required items any-flag should be set it. + * + **/ +static void skill_validate_item_requirements_sub_any_flag(struct config_setting_t *conf, struct s_skill_db *sk) +{ + nullpo_retv(conf); + nullpo_retv(sk); + + for (int i = 0; i < MAX_SKILL_LEVEL; i++) + sk->req_items.any[i] = false; + + struct config_setting_t *t = libconfig->setting_get_member(conf, "Any"); + + if (t != NULL && config_setting_is_group(t)) { + for (int i = 0; i < MAX_SKILL_LEVEL; i++) { + char lv[6]; // Big enough to contain "Lv999" in case of custom MAX_SKILL_LEVEL. + safesnprintf(lv, sizeof(lv), "Lv%d", i + 1); + int any_flag; + + if (libconfig->setting_lookup_bool(t, lv, &any_flag) == CONFIG_TRUE) + sk->req_items.any[i] = (any_flag != 0); + } + + return; + } + + int any_flag; + + if (libconfig->setting_lookup_bool(conf, "Any", &any_flag) == CONFIG_TRUE && any_flag != 0) { + for (int i = 0; i < MAX_SKILL_LEVEL; i++) + sk->req_items.any[i] = true; + } +} + +/** + * Validates a skill's required items when reading the skill DB. + * + * @param conf The libconfig settings block which contains the skill's data. + * @param sk The s_skill_db struct where the required items should be set it. + * + **/ +static void skill_validate_item_requirements(struct config_setting_t *conf, struct s_skill_db *sk) +{ + nullpo_retv(conf); + nullpo_retv(sk); + + struct config_setting_t *t = libconfig->setting_get_member(conf, "Items"); + + if (t != NULL && config_setting_is_group(t)) { + skill->validate_item_requirements_sub_any_flag(t, sk); + skill->validate_item_requirements_sub_items(t, sk); + } +} + +/** + * Validates a required item's config setting name when reading the skill DB. + * + * @param name The config setting name to validate. + * @return The corresponding item ID if the passed config setting name is valid, otherwise 0. + * + **/ +static int skill_validate_requirements_item_name(const char *name) +{ + nullpo_ret(name); + + int item_id = 0; + + if (strlen(name) > 2 && name[0] == 'I' && name[1] == 'D') { + if ((item_id = atoi(name + 2)) == 0) + return 0; + + struct item_data *it = itemdb->exists(item_id); + + if (it == NULL) + return 0; + + return it->nameid; + } + + if (!script->get_constant(name, &item_id)) + return 0; + + return item_id; +} + /** * Validates a skill's requirements when reading the skill DB. * @@ -23474,7 +23630,11 @@ void skill_defaults(void) skill->validate_state_sub = skill_validate_state_sub; skill->validate_state = skill_validate_state; skill->validate_spirit_sphere_cost = skill_validate_spirit_sphere_cost; + skill->validate_item_requirements_sub_item_amount = skill_validate_item_requirements_sub_item_amount; + skill->validate_item_requirements_sub_items = skill_validate_item_requirements_sub_items; + skill->validate_item_requirements_sub_any_flag = skill_validate_item_requirements_sub_any_flag; skill->validate_item_requirements = skill_validate_item_requirements; + skill->validate_requirements_item_name = skill_validate_requirements_item_name; skill->validate_requirements = skill_validate_requirements; skill->validate_unit_id_sub = skill_validate_unit_id_sub; skill->validate_unit_id = skill_validate_unit_id; diff --git a/src/map/skill.h b/src/map/skill.h index 2d68e695d..374b76b7f 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1741,6 +1741,15 @@ enum autocast_type { * Structures **/ +/** A container holding all required items. **/ +struct skill_required_item_data { + struct { + int id; + int amount[MAX_SKILL_LEVEL]; + } item[MAX_SKILL_ITEM_REQUIRE]; + bool any[MAX_SKILL_LEVEL]; +}; + struct skill_condition { int weapon,ammo,ammo_qty,hp,sp,zeny,spiritball,mhp,state; int itemid[MAX_SKILL_ITEM_REQUIRE],amount[MAX_SKILL_ITEM_REQUIRE]; @@ -1776,7 +1785,6 @@ struct s_skill_db { int ammo_qty[MAX_SKILL_LEVEL]; int state[MAX_SKILL_LEVEL]; int spiritball[MAX_SKILL_LEVEL]; - int itemid[MAX_SKILL_ITEM_REQUIRE],amount[MAX_SKILL_ITEM_REQUIRE]; int castnodex[MAX_SKILL_LEVEL], delaynodex[MAX_SKILL_LEVEL]; int unit_id[MAX_SKILL_LEVEL][2]; int unit_layout_type[MAX_SKILL_LEVEL]; @@ -1784,6 +1792,7 @@ struct s_skill_db { int unit_interval[MAX_SKILL_LEVEL]; int unit_target[MAX_SKILL_LEVEL]; int unit_flag; + struct skill_required_item_data req_items; }; struct s_skill_unit_layout { @@ -1986,7 +1995,7 @@ struct skill_interface { int (*get_state) (int skill_id, int skill_lv); int (*get_spiritball) (int skill_id, int skill_lv); int (*get_itemid) (int skill_id, int item_idx); - int (*get_itemqty) (int skill_id, int item_idx); + int (*get_itemqty) (int skill_id, int item_idx, int skill_lv); int (*get_zeny) (int skill_id, int skill_lv); int (*get_num) (int skill_id, int skill_lv); int (*get_cast) (int skill_id, int skill_lv); @@ -2171,7 +2180,11 @@ struct skill_interface { int (*validate_state_sub) (const char *state); void (*validate_state) (struct config_setting_t *conf, struct s_skill_db *sk); void (*validate_spirit_sphere_cost) (struct config_setting_t *conf, struct s_skill_db *sk); + void (*validate_item_requirements_sub_item_amount) (struct config_setting_t *conf, struct s_skill_db *sk, int item_index); + void (*validate_item_requirements_sub_items) (struct config_setting_t *conf, struct s_skill_db *sk); + void (*validate_item_requirements_sub_any_flag) (struct config_setting_t *conf, struct s_skill_db *sk); void (*validate_item_requirements) (struct config_setting_t *conf, struct s_skill_db *sk); + int (*validate_requirements_item_name) (const char *name); void (*validate_requirements) (struct config_setting_t *conf, struct s_skill_db *sk); int (*validate_unit_id_sub) (int unit_id); void (*validate_unit_id) (struct config_setting_t *conf, struct s_skill_db *sk); diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index 645afa240..9be0fdae9 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -7264,8 +7264,8 @@ typedef int (*HPMHOOK_pre_skill_get_spiritball) (int *skill_id, int *skill_lv); typedef int (*HPMHOOK_post_skill_get_spiritball) (int retVal___, int skill_id, int skill_lv); typedef int (*HPMHOOK_pre_skill_get_itemid) (int *skill_id, int *item_idx); typedef int (*HPMHOOK_post_skill_get_itemid) (int retVal___, int skill_id, int item_idx); -typedef int (*HPMHOOK_pre_skill_get_itemqty) (int *skill_id, int *item_idx); -typedef int (*HPMHOOK_post_skill_get_itemqty) (int retVal___, int skill_id, int item_idx); +typedef int (*HPMHOOK_pre_skill_get_itemqty) (int *skill_id, int *item_idx, int *skill_lv); +typedef int (*HPMHOOK_post_skill_get_itemqty) (int retVal___, int skill_id, int item_idx, int skill_lv); typedef int (*HPMHOOK_pre_skill_get_zeny) (int *skill_id, int *skill_lv); typedef int (*HPMHOOK_post_skill_get_zeny) (int retVal___, int skill_id, int skill_lv); typedef int (*HPMHOOK_pre_skill_get_num) (int *skill_id, int *skill_lv); diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 1e29af351..1cea69e4a 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -77228,15 +77228,15 @@ int HP_skill_get_itemid(int skill_id, int item_idx) { } return retVal___; } -int HP_skill_get_itemqty(int skill_id, int item_idx) { +int HP_skill_get_itemqty(int skill_id, int item_idx, int skill_lv) { int hIndex = 0; int retVal___ = 0; if (HPMHooks.count.HP_skill_get_itemqty_pre > 0) { - int (*preHookFunc) (int *skill_id, int *item_idx); + int (*preHookFunc) (int *skill_id, int *item_idx, int *skill_lv); *HPMforce_return = false; for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_get_itemqty_pre; hIndex++) { preHookFunc = HPMHooks.list.HP_skill_get_itemqty_pre[hIndex].func; - retVal___ = preHookFunc(&skill_id, &item_idx); + retVal___ = preHookFunc(&skill_id, &item_idx, &skill_lv); } if (*HPMforce_return) { *HPMforce_return = false; @@ -77244,13 +77244,13 @@ int HP_skill_get_itemqty(int skill_id, int item_idx) { } } { - retVal___ = HPMHooks.source.skill.get_itemqty(skill_id, item_idx); + retVal___ = HPMHooks.source.skill.get_itemqty(skill_id, item_idx, skill_lv); } if (HPMHooks.count.HP_skill_get_itemqty_post > 0) { - int (*postHookFunc) (int retVal___, int skill_id, int item_idx); + int (*postHookFunc) (int retVal___, int skill_id, int item_idx, int skill_lv); for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_get_itemqty_post; hIndex++) { postHookFunc = HPMHooks.list.HP_skill_get_itemqty_post[hIndex].func; - retVal___ = postHookFunc(retVal___, skill_id, item_idx); + retVal___ = postHookFunc(retVal___, skill_id, item_idx, skill_lv); } } return retVal___; -- cgit v1.2.3-60-g2f50