From a756b46c8bf302348e2c3a1b2242824e1ef45b8b Mon Sep 17 00:00:00 2001 From: "Guilherme G. Menaldo" Date: Mon, 1 May 2023 14:50:52 -0300 Subject: [PATCH] allow use of item constants in CloneItem field --- db/item_db2.conf | 2 +- db/pre-re/item_db.conf | 2 +- db/re/item_db.conf | 2 +- doc/item_db.txt | 2 +- src/map/itemdb.c | 36 +++++++++++++++++++++++++++++------- src/map/itemdb.h | 6 +++--- src/plugins/db2sql.c | 14 +++++++++----- 7 files changed, 45 insertions(+), 19 deletions(-) diff --git a/db/item_db2.conf b/db/item_db2.conf index b16b1c7af21..129c56bee0e 100644 --- a/db/item_db2.conf +++ b/db/item_db2.conf @@ -37,7 +37,7 @@ item_db: ( AegisName: "Aegis_Name" (string, optional if Inherit: true) Name: "Item Name" (string, optional if Inherit: true) // ================ Optional fields =============================== - CloneItem: ID (int, if specified, copies fields from + CloneItem: ID or "Aegis_Name" (int or string, if specified, copies fields from the other item and overrides with the values specified in this one) Type: Item Type (string, defaults to "IT_ETC") diff --git a/db/pre-re/item_db.conf b/db/pre-re/item_db.conf index 8c91f5fd6d1..3cff5213cdf 100644 --- a/db/pre-re/item_db.conf +++ b/db/pre-re/item_db.conf @@ -37,7 +37,7 @@ item_db: ( AegisName: "Aegis_Name" (string) Name: "Item Name" (string) // ================ Optional fields =============================== - CloneItem: ID (int, if specified, copies fields from + CloneItem: ID or "Aegis_Name" (int or string, if specified, copies fields from the other item and overrides with the values specified in this one) Type: Item Type (string, defaults to "IT_ETC") diff --git a/db/re/item_db.conf b/db/re/item_db.conf index eac95dcac4c..1fffe49e138 100644 --- a/db/re/item_db.conf +++ b/db/re/item_db.conf @@ -37,7 +37,7 @@ item_db: ( AegisName: "Aegis_Name" (string) Name: "Item Name" (string) // ================ Optional fields =============================== - CloneItem: ID (int, if specified, copies fields from + CloneItem: ID or "Aegis_Name" (int or string, if specified, copies fields from the other item and overrides with the values specified in this one) Type: Item Type (string, defaults to "IT_ETC") diff --git a/doc/item_db.txt b/doc/item_db.txt index f681efab7aa..0bf4712acee 100644 --- a/doc/item_db.txt +++ b/doc/item_db.txt @@ -15,7 +15,7 @@ item_db: ( AegisName: "Aegis_Name" (string, optional if Inherit: true) Name: "Item Name" (string, optional if Inherit: true) // =================== Optional fields ================================ - CloneItem: ID (int, if specified, copies fields from + CloneItem: ID or "Aegis_Name" (int or string, if specified, copies fields from the other item and overrides with the values specified in this one) Type: Item Type (string, defaults to "IT_ETC") diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 8f1e75cb455..7f0ac5de9b3 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1970,7 +1970,7 @@ static int itemdb_validate_entry(struct item_data *entry, int n, const char *sou return item->nameid; } -static void itemdb_readdb_additional_fields(int itemid, struct config_setting_t *it, int n, const char *source) +static void itemdb_readdb_additional_fields(int itemid, struct config_setting_t *it, int n, const char *source, struct DBMap *itemconst_db) { // do nothing. plugins can do own work } @@ -2021,7 +2021,7 @@ static void itemdb_readdb_job_sub(struct item_data *id, struct config_setting_t * validation errors. * @return Nameid of the validated entry, or 0 in case of failure. */ -static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const char *source) +static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const char *source, struct DBMap *itemconst_db) { struct item_data id = { 0 }; struct config_setting_t *t = NULL; @@ -2030,6 +2030,7 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const bool inherit = false; nullpo_ret(it); + nullpo_ret(itemconst_db); /* * // Mandatory fields * Id: ID @@ -2105,7 +2106,19 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const bool clone = false; if ((t = libconfig->setting_get_member(it, "CloneItem")) != NULL) { - int clone_id = libconfig->setting_get_int(t); + int clone_id; + + if (t->type == CONFIG_TYPE_STRING) { + const char *clone_name = libconfig->setting_get_string(t); + clone_id = strdb_iget(itemconst_db, clone_name); + + if (clone_id == 0) { + ShowWarning("%s: Could not find item \"%s\" to clone in item %d of \"%s\". Skipping.\n", __func__, clone_name, id.nameid, source); + return 0; + } + } else { + clone_id = libconfig->setting_get_int(t); + } struct item_data *base_entry = itemdb->exists(clone_id); if (base_entry == NULL) { @@ -2403,7 +2416,7 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const * @param filename File name, relative to the database path. * @return The number of found entries. */ -static int itemdb_readdb_libconfig(const char *filename) +static int itemdb_readdb_libconfig(const char *filename, struct DBMap *itemconst_db) { bool duplicate[MAX_ITEMDB]; struct DBMap *duplicate_db; @@ -2413,6 +2426,7 @@ static int itemdb_readdb_libconfig(const char *filename) int i = 0, count = 0; nullpo_ret(filename); + nullpo_ret(itemconst_db); snprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); if (!libconfig->load_file(&item_db_conf, filepath)) @@ -2428,14 +2442,16 @@ static int itemdb_readdb_libconfig(const char *filename) duplicate_db = idb_alloc(DB_OPT_BASE); while( (it = libconfig->setting_get_elem(itdb,i++)) ) { - int nameid = itemdb->readdb_libconfig_sub(it, i-1, filename); + int nameid = itemdb->readdb_libconfig_sub(it, i-1, filename, itemconst_db); if (nameid <= 0 || nameid > MAX_ITEM_ID) continue; - itemdb->readdb_additional_fields(nameid, it, i - 1, filename); + itemdb->readdb_additional_fields(nameid, it, i - 1, filename, itemconst_db); count++; + strdb_iput(itemconst_db, itemdb_name(nameid), nameid); + if (nameid < MAX_ITEMDB) { if (duplicate[nameid]) { ShowWarning("itemdb_readdb:%s: duplicate entry of ID #%d (%s/%s)\n", @@ -2962,8 +2978,14 @@ static void itemdb_read(bool minimal) DBPATH"item_db.conf", "item_db2.conf", }; + + // temporary itemconst db for item cloning because it happens before itemdb->name_constants() + struct DBMap *itemconst_db = strdb_alloc(DB_OPT_BASE, ITEM_NAME_LENGTH); + for (i = 0; i < ARRAYLENGTH(filename); i++) - itemdb->readdb_libconfig(filename[i]); + itemdb->readdb_libconfig(filename[i], itemconst_db); + + db_destroy(itemconst_db); // TODO check duplicate names also in itemdb->other for( i = 0; i < ARRAYLENGTH(itemdb->array); ++i ) { diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 68c774d0f18..42285216c36 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -740,10 +740,10 @@ struct itemdb_interface { int (*gendercheck) (struct item_data *id); int (*validate_entry) (struct item_data *entry, int n, const char *source); void (*readdb_options_additional_fields) (struct itemdb_option *ito, struct config_setting_t *t, const char *source); - void (*readdb_additional_fields) (int itemid, struct config_setting_t *it, int n, const char *source); + void (*readdb_additional_fields) (int itemid, struct config_setting_t *it, int n, const char *source, struct DBMap *itemconst_db); void (*readdb_job_sub) (struct item_data *id, struct config_setting_t *t); - int (*readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source); - int (*readdb_libconfig) (const char *filename); + int (*readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source, struct DBMap *itemconst_db); + int (*readdb_libconfig) (const char *filename, struct DBMap *itemconst_db); uint64 (*unique_id) (struct map_session_data *sd); void (*read) (bool minimal); void (*destroy_item_data) (struct item_data *self, int free_self); diff --git a/src/plugins/db2sql.c b/src/plugins/db2sql.c index 56cb3d4d789..85f428b0116 100644 --- a/src/plugins/db2sql.c +++ b/src/plugins/db2sql.c @@ -69,7 +69,7 @@ bool mobdb2sql_torun = false; static struct Sql *sql_handle = NULL; /// Backup of the original item_db parser function pointer. -int (*itemdb_readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source); +int (*itemdb_readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source, struct DBMap *itemconst_db); /// Backup of the original mob_db parser function pointer. int (*mob_read_db_sub) (struct config_setting_t *it, int n, const char *source); bool (*mob_skill_db_libconfig_sub_skill) (struct config_setting_t *it, int n, int mob_id); @@ -232,11 +232,11 @@ uint64 itemdb2sql_readdb_job_sub(struct config_setting_t *t) * * @see itemdb_readdb_libconfig_sub. */ -int itemdb2sql_sub(struct config_setting_t *entry, int n, const char *source) +int itemdb2sql_sub(struct config_setting_t *entry, int n, const char *source, struct DBMap *itemconst_db) { struct item_data *it = NULL; - if ((it = itemdb->exists(itemdb_readdb_libconfig_sub(entry,n,source)))) { + if ((it = itemdb->exists(itemdb_readdb_libconfig_sub(entry, n, source, itemconst_db)))) { char e_name[ITEM_NAME_LENGTH*2+1]; const char *bonus = NULL; char *str; @@ -470,7 +470,7 @@ int itemdb2sql_sub(struct config_setting_t *entry, int n, const char *source) } else { StrBuf->AppendStr(&buf, "'',"); } - + // rental_unequip_script if (it->rental_end_script && libconfig->setting_lookup_string(entry, "OnRentalEndScript", &bonus)) { hstr(bonus); @@ -582,6 +582,8 @@ void do_itemdb2sql(void) memset(&tosql.buf, 0, sizeof(tosql.buf)); itemdb->clear(false); + struct DBMap *itemconst_db = strdb_alloc(DB_OPT_BASE, ITEM_NAME_LENGTH); + for (i = 0; i < ARRAYLENGTH(files); i++) { if ((tosql.fp = fopen(files[i].destination, "wt+")) == NULL) { ShowError("itemdb_tosql: File not found \"%s\".\n", files[i].destination); @@ -591,11 +593,13 @@ void do_itemdb2sql(void) tosql.db_name = files[i].name; itemdb2sql_tableheader(); - itemdb->readdb_libconfig(files[i].source); + itemdb->readdb_libconfig(files[i].source, itemconst_db); fclose(tosql.fp); } + db_destroy(itemconst_db); + /* unlink */ itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub;