Skip to content

Commit

Permalink
add support to clone an item into another in item_db
Browse files Browse the repository at this point in the history
using the new CloneItem field an item may copy the definition of a
previously, already defined item, into a new item id.

After the copy happens, it may also override specific settings to match
the new items specifics
  • Loading branch information
guilherme-gm committed May 1, 2023
1 parent 21b7f9e commit 6b033b6
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 13 deletions.
3 changes: 3 additions & 0 deletions db/item_db2.conf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ 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
the other item and overrides with the values
specified in this one)
Type: Item Type (string, defaults to "IT_ETC")
Buy: Buy Price (int, defaults to Sell * 2)
Sell: Sell Price (int, defaults to Buy / 2)
Expand Down
3 changes: 3 additions & 0 deletions db/pre-re/item_db.conf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ item_db: (
AegisName: "Aegis_Name" (string)
Name: "Item Name" (string)
// ================ Optional fields ===============================
CloneItem: ID (int, 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")
Buy: Buy Price (int, defaults to Sell * 2)
Sell: Sell Price (int, defaults to Buy / 2)
Expand Down
3 changes: 3 additions & 0 deletions db/re/item_db.conf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ item_db: (
AegisName: "Aegis_Name" (string)
Name: "Item Name" (string)
// ================ Optional fields ===============================
CloneItem: ID (int, 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")
Buy: Buy Price (int, defaults to Sell * 2)
Sell: Sell Price (int, defaults to Buy / 2)
Expand Down
16 changes: 15 additions & 1 deletion doc/item_db.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//===== By: ==================================================
//= Hercules Dev Team
//===== Current Version: =====================================
//= 20211111
//= 20230501
//===== Description: =========================================
//= Explanation of the item_db.conf file and structure.
//============================================================
Expand All @@ -15,6 +15,9 @@ 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
the other item and overrides with the values
specified in this one)
Type: Item Type (string, defaults to "IT_ETC")
Buy: Buy Price (int, defaults to Sell * 2)
Sell: Sell Price (int, defaults to Buy / 2)
Expand Down Expand Up @@ -120,6 +123,17 @@ AegisName: Server name to reference the item in scripts and lookups.

Name: Name in English for displaying as output for @ and script commands.

CloneItem: Clones the definition of another item into this, then override the fields defined in this entry.
The following fields are not cloned: ID and AegisName

Note: You can only clone items that were loaded before the item using CloneItem
field, otherwise an "inexistent item" warning will be shown.
Items are loaded in the same order as they are declared in item_db files, and item_db is loaded
before item_db2.

Note 2: If combined with "Inherit" (item_db2 only), Inherit comes first
(and all fields except for ID and AegisName are replaced by CloneItem)

Type:
IT_HEALING: Healing Item
IT_USABLE: Usable Item
Expand Down
56 changes: 44 additions & 12 deletions src/map/itemdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -2103,8 +2103,30 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const
}
}

if( !libconfig->setting_lookup_string(it, "AegisName", &str) || !*str ) {
if( !inherit ) {
bool clone = false;
if ((t = libconfig->setting_get_member(it, "CloneItem")) != NULL) {
int clone_id = libconfig->setting_get_int(t);

struct item_data *base_entry = itemdb->exists(clone_id);
if (base_entry == NULL) {
ShowWarning("%s: Trying to clone nonexistent item %d in item %d of \"%s\". Skipping.\n", __func__, clone_id, id.nameid, source);
return 0;
}

int new_id = id.nameid;
char existing_name[ITEM_NAME_LENGTH];
strncpy(existing_name, id.name, sizeof(existing_name));

clone = true;
memcpy(&id, base_entry, sizeof(id));

// Restore fields that cloning shouldn't replace. ID and AegisName are unique fields, so should not be cloned.
id.nameid = new_id;
strncpy(id.name, existing_name, sizeof(id.name));
}

if (!libconfig->setting_lookup_string(it, "AegisName", &str) || !*str) {
if (!inherit) {
ShowWarning("itemdb_readdb_libconfig_sub: Missing AegisName in item %d of \"%s\", skipping.\n", id.nameid, source);
return 0;
}
Expand All @@ -2113,7 +2135,7 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const
}

if( !libconfig->setting_lookup_string(it, "Name", &str) || !*str ) {
if( !inherit ) {
if (!inherit && !clone) {
ShowWarning("itemdb_readdb_libconfig_sub: Missing Name in item %d of \"%s\", skipping.\n", id.nameid, source);
return 0;
}
Expand All @@ -2123,7 +2145,7 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const

if (map->setting_lookup_const(it, "Type", &i32))
id.type = i32;
else if (!inherit)
else if (!inherit && !clone)
id.type = IT_ETC;

if (map->setting_lookup_const(it, "Subtype", &i32) && i32 >= 0) {
Expand All @@ -2136,11 +2158,11 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const

if (map->setting_lookup_const(it, "Buy", &i32))
id.value_buy = i32;
else if (!inherit)
else if (!inherit && !clone)
id.value_buy = -1;
if (map->setting_lookup_const(it, "Sell", &i32))
id.value_sell = i32;
else if (!inherit)
else if (!inherit && !clone)
id.value_sell = -1;

if (map->setting_lookup_const(it, "Weight", &i32) && i32 >= 0)
Expand All @@ -2166,7 +2188,7 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const
itemdb->readdb_job_sub(&id, t);
} else if (map->setting_lookup_const(it, "Job", &i32)) { // This is an unsigned value, do not check for >= 0
itemdb->jobmask2mapid(id.class_base, (uint64)i32);
} else if (!inherit) {
} else if (!inherit && !clone) {
itemdb->jobmask2mapid(id.class_base, UINT64_MAX);
}
} else if (!inherit) {
Expand All @@ -2175,12 +2197,12 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const

if (map->setting_lookup_const_mask(it, "Upper", &i32) && i32 >= 0)
id.class_upper = (unsigned int)i32;
else if( !inherit )
else if (!inherit && !clone)
id.class_upper = ITEMUPPER_ALL;

if (map->setting_lookup_const(it, "Gender", &i32) && i32 >= 0)
id.sex = i32;
else if (!inherit)
else if (!inherit && !clone)
id.sex = 2;

if (map->setting_lookup_const_mask(it, "Loc", &i32) && i32 >= 0)
Expand Down Expand Up @@ -2346,20 +2368,30 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const
id.view_id = i32;
}

if( libconfig->setting_lookup_string(it, "Script", &str) )
if (libconfig->setting_lookup_string(it, "Script", &str))
id.script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
else if (clone && id.script != NULL)
id.script = script->clone_script(id.script);

if( libconfig->setting_lookup_string(it, "OnEquipScript", &str) )
if (libconfig->setting_lookup_string(it, "OnEquipScript", &str))
id.equip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
else if (clone && id.equip_script != NULL)
id.equip_script = script->clone_script(id.equip_script);

if( libconfig->setting_lookup_string(it, "OnUnequipScript", &str) )
if (libconfig->setting_lookup_string(it, "OnUnequipScript", &str))
id.unequip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
else if (clone && id.unequip_script != NULL)
id.unequip_script = script->clone_script(id.unequip_script);

if (libconfig->setting_lookup_string(it, "OnRentalStartScript", &str) != CONFIG_FALSE)
id.rental_start_script = (*str != '\0') ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
else if (clone && id.rental_start_script != NULL)
id.rental_start_script = script->clone_script(id.rental_start_script);

if (libconfig->setting_lookup_string(it, "OnRentalEndScript", &str) != CONFIG_FALSE)
id.rental_end_script = (*str != '\0') ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
else if (clone && id.rental_end_script != NULL)
id.rental_end_script = script->clone_script(id.rental_end_script);

return itemdb->validate_entry(&id, n, source);
}
Expand Down
23 changes: 23 additions & 0 deletions src/map/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -3094,6 +3094,28 @@ static struct script_code *parse_script(const char *src, const char *file, int l
return code;
}

/**
* Creates a new script_code instance from an existing one.
* @param original the script code to copy from
* @retval the new script code
*/
static struct script_code *script_clone_script(struct script_code* original)
{
nullpo_retr(NULL, original);
struct script_code* code = NULL;

CREATE(code,struct script_code,1);
VECTOR_INIT(code->script_buf);

VECTOR_ENSURE(code->script_buf, VECTOR_LENGTH(original->script_buf), 1);
VECTOR_PUSHARRAY(code->script_buf, VECTOR_DATA(original->script_buf), VECTOR_LENGTH(original->script_buf));

code->local.vars = NULL;
code->local.arrays = NULL;

return code;
}

/// Returns the player attached to this script, identified by the rid.
/// If there is no player attached, the script is terminated.
static struct map_session_data *script_rid2sd(struct script_state *st)
Expand Down Expand Up @@ -30024,6 +30046,7 @@ void script_defaults(void)
script->warning = script_warning;
script->parse_subexpr = script_parse_subexpr;

script->clone_script = script_clone_script;
script->addScript = script_hp_add;
script->conv_num = conv_num;
script->conv_str = conv_str;
Expand Down
1 change: 1 addition & 0 deletions src/map/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ struct script_interface {
void (*error) (const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos);
void (*warning) (const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos);
/* */
struct script_code* (*clone_script) (struct script_code* original);
bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated);
int (*conv_num) (struct script_state *st,struct script_data *data);
const char* (*conv_str) (struct script_state *st,struct script_data *data);
Expand Down

0 comments on commit 6b033b6

Please sign in to comment.