summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2013-11-08 07:18:40 +0100
committerHaru <haru@dotalux.com>2013-11-14 20:15:28 +0100
commited72a947a6c97804c1eef5b80bfa49d99f7d7586 (patch)
treef9196c943010e26c13c12d38c7a622d43301a4cd /src
parent7d0a63b72f93c05b302c08cfb19d5651cef1cdb8 (diff)
downloadhercules-ed72a947a6c97804c1eef5b80bfa49d99f7d7586.tar.gz
hercules-ed72a947a6c97804c1eef5b80bfa49d99f7d7586.tar.bz2
hercules-ed72a947a6c97804c1eef5b80bfa49d99f7d7586.tar.xz
hercules-ed72a947a6c97804c1eef5b80bfa49d99f7d7586.zip
Item DB overhaul
http://hercules.ws/board/topic/2954-item-db-file-structure-overhaul - Item db was changed to libconfig format. - This new format is larger than the original format, but it's less subject to conflicts when some items are edited and the file gets updated. - It is no longer necessary to specify fields with no value, and only the actually used fields are specified. - Items scripts (especially the long ones) are made more readable by splitting them into multiple lines, with proper indentation. - A converter perl script is provided in the tools directory (and a link to the web-based version of the same script canbe found in the above forum topic) - All of this was made possible thanks to Ind, Yommy. Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src')
-rw-r--r--src/map/itemdb.c539
-rw-r--r--src/map/itemdb.h18
-rw-r--r--src/map/pc.c22
3 files changed, 310 insertions, 269 deletions
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 82f316828..dff0207c7 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -1532,171 +1532,294 @@ int itemdb_gendercheck(struct item_data *id)
return (battle_config.ignore_items_gender) ? 2 : id->sex;
}
-/**
- * [RRInd]
- * For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot
- * We use a ':' delimiter which, if not found, assumes the weapon does not provide any matk.
- **/
-void itemdb_re_split_atoi(char *str, int *atk, int *matk) {
- int i, val[2];
+int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
+ struct item_data *item;
+
+ if( entry->nameid <= 0 || entry->nameid >= MAX_ITEMDB ) {
+ ShowWarning("itemdb_validate_entry: Invalid item ID %d in entry %d of '%s', allowed values 0 < ID < %d (MAX_ITEMDB), skipping.\n",
+ entry->nameid, n, source, MAX_ITEMDB);
+ if (entry->script) {
+ script->free_code(entry->script);
+ entry->script = NULL;
+ }
+ if (entry->equip_script) {
+ script->free_code(entry->equip_script);
+ entry->equip_script = NULL;
+ }
+ if (entry->unequip_script) {
+ script->free_code(entry->unequip_script);
+ entry->unequip_script = NULL;
+ }
+ return 0;
+ }
- for (i=0; i<2; i++) {
- if (!str) break;
- val[i] = atoi(str);
- str = strchr(str,':');
- if (str)
- *str++=0;
+ if( entry->type < 0 || entry->type == IT_UNKNOWN || entry->type == IT_UNKNOWN2
+ || (entry->type > IT_DELAYCONSUME && entry->type < IT_CASH ) || entry->type >= IT_MAX
+ ) {
+ // catch invalid item types
+ ShowWarning("itemdb_validate_entry: Invalid item type %d for item %d. IT_ETC will be used.\n", entry->type, entry->nameid);
+ entry->type = IT_ETC;
+ } else if( entry->type == IT_DELAYCONSUME ) {
+ //Items that are consumed only after target confirmation
+ entry->type = IT_USABLE;
+ entry->flag.delay_consume = 1;
}
- if( i == 0 ) {
- *atk = *matk = 0;
- return;//no data found
+
+ //When a particular price is not given, we should base it off the other one
+ //(it is important to make a distinction between 'no price' and 0z)
+ if( entry->value_buy < 0 && entry->value_sell < 0 ) {
+ entry->value_buy = entry->value_sell = 0;
+ } else if( entry->value_buy < 0 ) {
+ entry->value_buy = entry->value_sell * 2;
+ } else if( entry->value_sell < 0 ) {
+ entry->value_sell = entry->value_buy / 2;
}
- if( i == 1 ) {//Single Value, we assume it's the ATK
- *atk = val[0];
- *matk = 0;
- return;
+ if( entry->value_buy/124. < entry->value_sell/75. ) {
+ ShowWarning("itemdb_validate_entry: Buying/Selling [%d/%d] price of item %d (%s) allows Zeny making exploit through buying/selling at discounted/overcharged prices!\n",
+ entry->value_buy, entry->value_sell, entry->nameid, entry->jname);
}
- //We assume we have 2 values.
- *atk = val[0];
- *matk = val[1];
- return;
+
+ if( entry->slot > MAX_SLOTS ) {
+ ShowWarning("itemdb_validate_entry: Item %d (%s) specifies %d slots, but the server only supports up to %d. Using %d slots.\n",
+ entry->nameid, entry->jname, entry->slot, MAX_SLOTS, MAX_SLOTS);
+ entry->slot = MAX_SLOTS;
+ }
+
+ if (!entry->equip && itemdb->isequip2(entry)) {
+ ShowWarning("itemdb_validate_entry: Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", entry->nameid, entry->jname);
+ entry->type = IT_ETC;
+ }
+
+ entry->wlv = cap_value(entry->wlv, REFINE_TYPE_ARMOR, REFINE_TYPE_MAX);
+
+ if( !entry->elvmax )
+ entry->elvmax = MAX_LEVEL;
+ else if( entry->elvmax > entry->elv )
+ entry->elvmax = entry->elv;
+
+ if( entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_refine )
+ entry->flag.no_refine = 1;
+
+ entry->flag.available = 1;
+ entry->view_id = 0;
+ entry->sex = itemdb->gendercheck(entry); //Apply gender filtering.
+
+ // Validated. Finally insert it
+ item = itemdb->load(entry->nameid);
+
+ if (item->script) {
+ script->free_code(item->script);
+ item->script = NULL;
+ }
+ if (item->equip_script) {
+ script->free_code(item->equip_script);
+ item->equip_script = NULL;
+ }
+ if (item->unequip_script) {
+ script->free_code(item->unequip_script);
+ item->unequip_script = NULL;
+ }
+
+ *item = *entry;
+ return item->nameid;
}
/*==========================================
* processes one itemdb entry
*------------------------------------------*/
-int itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt) {
+int itemdb_readdb_sql_sub(Sql *handle, int n, const char *source) {
+ struct item_data id = { 0 };
+ char *data = NULL;
+
/*
- +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
- | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
- +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
- | id | name_english | name_japanese | type | price_buy | price_sell | weight | attack | defence | range | slots | equip_jobs | equip_upper | equip_genders | equip_locations | weapon_level | equip_level | refineable | view | script | equip_script | unequip_script |
- +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
- */
- int nameid;
- struct item_data* id;
- unsigned char offset = 0;
-
- nameid = atoi(str[0]);
- if( nameid <= 0 ) {
- ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", skipping.\n", nameid, line, source);
+ * `id` smallint(5) unsigned NOT NULL DEFAULT '0'
+ * `name_english` varchar(50) NOT NULL DEFAULT ''
+ * `name_japanese` varchar(50) NOT NULL DEFAULT ''
+ * `type` tinyint(2) unsigned NOT NULL DEFAULT '0'
+ * `price_buy` mediumint(10) DEFAULT NULL
+ * `price_sell` mediumint(10) DEFAULT NULL
+ * `weight` smallint(5) unsigned DEFAULT NULL
+ * `atk` smallint(5) unsigned DEFAULT NULL
+ * `matk` smallint(5) unsigned DEFAULT NULL
+ * `defence` smallint(5) unsigned DEFAULT NULL
+ * `range` tinyint(2) unsigned DEFAULT NULL
+ * `slots` tinyint(2) unsigned DEFAULT NULL
+ * `equip_jobs` int(12) unsigned DEFAULT NULL
+ * `equip_upper` tinyint(8) unsigned DEFAULT NULL
+ * `equip_genders` tinyint(2) unsigned DEFAULT NULL
+ * `equip_locations` smallint(4) unsigned DEFAULT NULL
+ * `weapon_level` tinyint(2) unsigned DEFAULT NULL
+ * `equip_level_min` smallint(5) unsigned DEFAULT NULL
+ * `equip_level_max` smallint(5) unsigned DEFAULT NULL
+ * `refineable` tinyint(1) unsigned DEFAULT NULL
+ * `view` smallint(3) unsigned DEFAULT NULL
+ * `script` text
+ * `equip_script` text
+ * `unequip_script` text
+ */
+ SQL->GetData(handle, 0, &data, NULL); id.nameid = (uint16)atoi(data);
+ SQL->GetData(handle, 1, &data, NULL); safestrncpy(id.name, data, sizeof(id.name));
+ SQL->GetData(handle, 2, &data, NULL); safestrncpy(id.jname, data, sizeof(id.jname));
+ SQL->GetData(handle, 3, &data, NULL); id.type = atoi(data);
+ SQL->GetData(handle, 4, &data, NULL); id.value_buy = data ? atoi(data) : -1; // Using invalid price -1 when missing, it'll be validated later
+ SQL->GetData(handle, 5, &data, NULL); id.value_sell = data ? atoi(data) : -1;
+ SQL->GetData(handle, 6, &data, NULL); id.weight = data ? atoi(data) : 0;
+ SQL->GetData(handle, 7, &data, NULL); id.atk = data ? atoi(data) : 0;
+ SQL->GetData(handle, 8, &data, NULL); id.matk = data ? atoi(data) : 0;
+ SQL->GetData(handle, 9, &data, NULL); id.def = data ? atoi(data) : 0;
+ SQL->GetData(handle, 10, &data, NULL); id.range = data ? atoi(data) : 0;
+ SQL->GetData(handle, 11, &data, NULL); id.slot = data ? atoi(data) : 0;
+ SQL->GetData(handle, 12, &data, NULL); itemdb->jobid2mapid(id.class_base, data ? (unsigned int)strtoul(data,NULL,0) : UINT_MAX);
+ SQL->GetData(handle, 13, &data, NULL); id.class_upper = data ? (unsigned int)atoi(data) : ITEMUPPER_ALL;
+ SQL->GetData(handle, 14, &data, NULL); id.sex = data ? atoi(data) : 2;
+ SQL->GetData(handle, 15, &data, NULL); id.equip = data ? atoi(data) : 0;
+ SQL->GetData(handle, 16, &data, NULL); id.wlv = data ? atoi(data) : 0;
+ SQL->GetData(handle, 17, &data, NULL); id.elv = data ? atoi(data) : 0;
+ SQL->GetData(handle, 18, &data, NULL); id.elvmax = data ? atoi(data) : 0;
+ SQL->GetData(handle, 19, &data, NULL); id.flag.no_refine = data && atoi(data) ? 0 : 1;
+ SQL->GetData(handle, 20, &data, NULL); id.look = data ? atoi(data) : 0;
+ SQL->GetData(handle, 21, &data, NULL); id.script = *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL;
+ SQL->GetData(handle, 22, &data, NULL); id.equip_script = *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL;
+ SQL->GetData(handle, 23, &data, NULL); id.unequip_script = *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL;
+
+ return itemdb->validate_entry(&id, n, source);
+}
+
+int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) {
+ struct item_data id = { 0 };
+ config_setting_t *t = NULL;
+ const char *str = NULL;
+ uint32 ui32 = 0;
+ int i32 = 0;
+
+ /*
+ * // Mandatory fields
+ * Id: ID
+ * AegisName: "Aegis_Name"
+ * Name: "Item Name"
+ * // Optional fields
+ * Type: Item Type
+ * Buy: Buy Price
+ * Sell: Sell Price
+ * Weight: Item Weight
+ * Atk: Attack
+ * Matk: Attack
+ * Def: Defense
+ * Range: Attack Range
+ * Slots: Slots
+ * Job: Job mask
+ * Upper: Upper mask
+ * Gender: Gender
+ * Loc: Equip location
+ * WeaponLv: Weapon Level
+ * EquipLv: Equip required level
+ * Refine: Refineable
+ * View: View ID
+ * Script: <"
+ * Script
+ * (it can be multi-line)
+ * ">
+ * OnEquipScript: <" OnEquip Script ">
+ * OnUnequipScript: <" OnUnequip Script ">
+ */
+ if( !config_setting_lookup_int(it, "Id", &i32) ) {
+ ShowWarning("itemdb_readdb_libconfig_sub: Invalid or missing id in \"%s\", entry #%d, skipping.\n", source, n);
+ return 0;
+ }
+ id.nameid = (uint16)i32;
+
+ if( !config_setting_lookup_string(it, "AegisName", &str) || !*str ) {
+ ShowWarning("itemdb_readdb_libconfig_sub: Missing AegisName in item %d of \"%s\", skipping.\n", id.nameid, source);
return 0;
- } else if ( nameid >= MAX_ITEMDB ) {
- ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", beyond MAX_ITEMDB, skipping.\n", nameid, line, source);
+ }
+ safestrncpy(id.name, str, sizeof(id.name));
+
+ if( !config_setting_lookup_string(it, "Name", &str) || !*str ) {
+ ShowWarning("itemdb_readdb_libconfig_sub: Missing Name in item %d of \"%s\", skipping.\n", id.nameid, source);
return 0;
}
+ safestrncpy(id.jname, str, sizeof(id.jname));
- //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View
- id = itemdb->load(nameid);
- safestrncpy(id->name, str[1], sizeof(id->name));
- safestrncpy(id->jname, str[2], sizeof(id->jname));
+ if( config_setting_lookup_int(it, "Type", &i32) )
+ id.type = i32;
+ else
+ id.type = IT_UNKNOWN;
- id->type = atoi(str[3]);
+ if( config_setting_lookup_int(it, "Buy", &i32) )
+ id.value_buy = i32;
+ else
+ id.value_buy = -1;
+ if( config_setting_lookup_int(it, "Sell", &i32) )
+ id.value_sell = i32;
+ else
+ id.value_sell = -1;
- if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_CASH ) || id->type >= IT_MAX )
- {// catch invalid item types
- ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid);
- id->type = IT_ETC;
- }
+ if( config_setting_lookup_int(it, "Weight", &i32) && i32 >= 0 )
+ id.weight = i32;
- if (id->type == IT_DELAYCONSUME)
- { //Items that are consumed only after target confirmation
- id->type = IT_USABLE;
- id->flag.delay_consume = 1;
- } else //In case of an itemdb reload and the item type changed.
- id->flag.delay_consume = 0;
+ if( config_setting_lookup_int(it, "Atk", &i32) && i32 >= 0 )
+ id.atk = i32;
- //When a particular price is not given, we should base it off the other one
- //(it is important to make a distinction between 'no price' and 0z)
- if ( str[4][0] )
- id->value_buy = atoi(str[4]);
+ if( config_setting_lookup_int(it, "Matk", &i32) && i32 >= 0 )
+ id.matk = i32;
+
+ if( config_setting_lookup_int(it, "Def", &i32) && i32 >= 0 )
+ id.def = i32;
+
+ if( config_setting_lookup_int(it, "Range", &i32) && i32 >= 0 )
+ id.range = i32;
+
+ if( config_setting_lookup_int(it, "Slot", &i32) && i32 >= 0 )
+ id.slot = i32;
+
+ if( config_setting_lookup_int(it, "Job", &i32) ) // This is an unsigned value, do not check for >= 0
+ ui32 = (unsigned int)i32;
else
- id->value_buy = atoi(str[5]) * 2;
+ ui32 = UINT_MAX;
+ itemdb->jobid2mapid(id.class_base, ui32);
- if ( str[5][0] )
- id->value_sell = atoi(str[5]);
+ if( config_setting_lookup_int(it, "Upper", &i32) && i32 >= 0 )
+ id.class_upper = (unsigned int)i32;
else
- id->value_sell = id->value_buy / 2;
- /*
- if ( !str[4][0] && !str[5][0])
- {
- ShowWarning("itemdb_parse_dbrow: No buying/selling price defined for item %d (%s), using 20/10z\n", nameid, id->jname);
- id->value_buy = 20;
- id->value_sell = 10;
- } else
- */
- if (id->value_buy/124. < id->value_sell/75.)
- ShowWarning("itemdb_parse_dbrow: Buying/Selling [%d/%d] price of item %d (%s) allows Zeny making exploit through buying/selling at discounted/overcharged prices!\n",
- id->value_buy, id->value_sell, nameid, id->jname);
-
- id->weight = atoi(str[6]);
-#ifdef RENEWAL
- if( map->db_use_sql_item_db ) {
- id->atk = atoi(str[7]);
- id->matk = atoi(str[8]);
- offset += 1;
- } else
- itemdb->re_split_atoi(str[7],&id->atk,&id->matk);
-#else
- id->atk = atoi(str[7]);
-#endif
- id->def = atoi(str[8+offset]);
- id->range = atoi(str[9+offset]);
- id->slot = atoi(str[10+offset]);
+ id.class_upper = ITEMUPPER_ALL;
- if (id->slot > MAX_SLOTS) {
- ShowWarning("itemdb_parse_dbrow: Item %d (%s) specifies %d slots, but the server only supports up to %d. Using %d slots.\n", nameid, id->jname, id->slot, MAX_SLOTS, MAX_SLOTS);
- id->slot = MAX_SLOTS;
- }
+ if( config_setting_lookup_int(it, "Gender", &i32) && i32 >= 0 )
+ id.sex = i32;
+ else
+ id.sex = 2;
+
+ if( config_setting_lookup_int(it, "Loc", &i32) && i32 >= 0 )
+ id.equip = i32;
- itemdb->jobid2mapid(id->class_base, (unsigned int)strtoul(str[11+offset],NULL,0));
- id->class_upper = atoi(str[12+offset]);
- id->sex = atoi(str[13+offset]);
- id->equip = atoi(str[14+offset]);
+ if( config_setting_lookup_int(it, "WeaponLv", &i32) && i32 >= 0 )
+ id.wlv = i32;
- if (!id->equip && itemdb->isequip2(id)) {
- ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname);
- id->type = IT_ETC;
+ if( (t = config_setting_get_member(it, "EquipLv")) ) {
+ if( config_setting_is_aggregate(t) ) {
+ if( config_setting_length(t) >= 2 )
+ id.elvmax = config_setting_get_int_elem(t, 1);
+ if( config_setting_length(t) >= 1 )
+ id.elv = config_setting_get_int_elem(t, 0);
+ } else {
+ id.elv = config_setting_get_int(t);
+ }
}
- id->wlv = cap_value(atoi(str[15+offset]), REFINE_TYPE_ARMOR, REFINE_TYPE_MAX);
-#ifdef RENEWAL
- if( map->db_use_sql_item_db ) {
- id->elv = atoi(str[16+offset]);
- id->elvmax = atoi(str[17+offset]);
- offset += 1;
- } else
- itemdb->re_split_atoi(str[16],&id->elv,&id->elvmax);
-#else
- id->elv = atoi(str[16]);
-#endif
- id->flag.no_refine = atoi(str[17+offset]) ? 0 : 1; //FIXME: verify this
- id->look = atoi(str[18+offset]);
+ if( (t = config_setting_get_member(it, "Refine")) )
+ id.flag.no_refine = config_setting_get_bool(t) ? 0 : 1;
- id->flag.available = 1;
- id->view_id = 0;
- id->sex = itemdb->gendercheck(id); //Apply gender filtering.
+ if( config_setting_lookup_int(it, "View", &i32) && i32 >= 0 )
+ id.look = i32;
- if (id->script) {
- script->free_code(id->script);
- id->script = NULL;
- }
- if (id->equip_script) {
- script->free_code(id->equip_script);
- id->equip_script = NULL;
- }
- if (id->unequip_script) {
- script->free_code(id->unequip_script);
- id->unequip_script = NULL;
- }
+ if( config_setting_lookup_string(it, "Script", &str) && *str )
+ id.script = script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS);
+
+ if( config_setting_lookup_string(it, "OnEquipScript", &str) && *str )
+ id.equip_script = script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS);
- if (*str[19+offset])
- id->script = script->parse(str[19+offset], source, line, scriptopt);
- if (*str[20+offset])
- id->equip_script = script->parse(str[20+offset], source, line, scriptopt);
- if (*str[21+offset])
- id->unequip_script = script->parse(str[21+offset], source, line, scriptopt);
+ if( config_setting_lookup_string(it, "OnUnequipScript", &str) && *str )
+ id.unequip_script = script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS);
- return id->nameid;
+ return itemdb->validate_entry(&id, n, source);
}
/*==========================================
@@ -1705,131 +1828,48 @@ int itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt)
*------------------------------------------*/
int itemdb_readdb(void) {
const char* filename[] = {
- DBPATH"item_db.txt",
- "item_db2.txt" };
+ DBPATH"item_db.conf",
+ "item_db2.conf",
+ };
bool duplicate[MAX_ITEMDB];
int fi;
+ config_t item_db_conf;
+ config_setting_t *itdb, *it;
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) {
- uint32 lines = 0, count = 0;
- char line[1024];
-
char filepath[256];
- FILE* fp;
-
+ int i = 0, count = 0;
sprintf(filepath, "%s/%s", map->db_path, filename[fi]);
- fp = fopen(filepath, "r");
- if( fp == NULL ) {
- ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", filepath);
+ memset(&duplicate,0,sizeof(duplicate));
+ if( conf_read_file(&item_db_conf, filepath) || !(itdb = config_setting_get_member(item_db_conf.root, "item_db")) ) {
+ ShowError("can't read %s\n", filepath);
continue;
}
- memset(&duplicate,0,sizeof(duplicate));
-
- // process rows one by one
- while(fgets(line, sizeof(line), fp))
- {
- char *str[32], *p;
- int i, id = 0;
- lines++;
- if(line[0] == '/' && line[1] == '/')
- continue;
- memset(str, 0, sizeof(str));
-
- p = line;
- while( ISSPACE(*p) )
- ++p;
- if( *p == '\0' )
- continue;// empty line
- for( i = 0; i < 19; ++i ) {
- str[i] = p;
- p = strchr(p,',');
- if( p == NULL )
- break;// comma not found
- *p = '\0';
- ++p;
- }
-
- if( p == NULL ) {
- ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
- continue;
- }
-
- // Script
- if( *p != '{' ) {
- ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
- continue;
- }
- str[19] = p;
- p = strstr(p+1,"},");
- if( p == NULL ) {
- ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
- continue;
- }
- p[1] = '\0';
- p += 2;
+ while( (it = config_setting_get_elem(itdb,i++)) ) {
+ int nameid = itemdb->readdb_libconfig_sub(it, i-1, filename[fi]);
- // OnEquip_Script
- if( *p != '{' ) {
- ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
- continue;
- }
- str[20] = p;
- p = strstr(p+1,"},");
- if( p == NULL ) {
- ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
+ if( !nameid )
continue;
- }
- p[1] = '\0';
- p += 2;
- // OnUnequip_Script (last column)
- if( *p != '{' ) {
- ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
- continue;
- }
- str[21] = p;
-
- if ( str[21][strlen(str[21])-2] != '}' ) {
- /* lets count to ensure it's not something silly e.g. a extra space at line ending */
- int v, lcurly = 0, rcurly = 0;
-
- for( v = 0; v < strlen(str[21]); v++ ) {
- if( str[21][v] == '{' )
- lcurly++;
- else if ( str[21][v] == '}' )
- rcurly++;
- }
-
- if( lcurly != rcurly ) {
- ShowError("itemdb_readdb: Mismatching curly braces in line %d of \"%s\" (item with id %d), skipping.\n", lines, filepath, atoi(str[0]));
- continue;
- }
- }
+ count++;
- if (!(id = itemdb->parse_dbrow(str, filepath, lines, 0)))
- continue;
-
- if( duplicate[id] ) {
- ShowWarning("itemdb_readdb:%s: duplicate entry of ID #%d (%s/%s)\n",filename[fi],id,itemdb_name(id),itemdb_jname(id));
+ if( duplicate[nameid] ) {
+ ShowWarning("itemdb_readdb:%s: duplicate entry of ID #%d (%s/%s)\n",
+ filename[fi], nameid, itemdb_name(nameid), itemdb_jname(nameid));
} else
- duplicate[id] = true;
-
- count++;
+ duplicate[nameid] = true;
}
-
- fclose(fp);
-
+ config_destroy(&item_db_conf);
ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]);
}
-
+
return 0;
}
/*======================================
* item_db table reading
*======================================*/
int itemdb_read_sqldb(void) {
-
const char* item_db_name[] = {
#ifdef RENEWAL
map->item_db_re_db,
@@ -1840,6 +1880,7 @@ int itemdb_read_sqldb(void) {
int fi;
for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi ) {
+ int i = 0;
uint32 count = 0;
// retrieve all rows from the item database
@@ -1849,20 +1890,9 @@ int itemdb_read_sqldb(void) {
}
// process rows one by one
- while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) {// wrap the result into a TXT-compatible format
- char* str[ITEMDB_SQL_COLUMNS];
- char* dummy = "";
- int i;
- for( i = 0; i < ITEMDB_SQL_COLUMNS; ++i ) {
- SQL->GetData(map->mysql_handle, i, &str[i], NULL);
- if( str[i] == NULL )
- str[i] = dummy; // get rid of NULL columns
- }
-
- if (!itemdb->parse_dbrow(str, item_db_name[fi], -(atoi(str[0])), SCRIPT_IGNORE_EXTERNAL_BRACKETS))
- continue;
-
- ++count;
+ while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) {
+ if( itemdb->readdb_sql_sub(map->mysql_handle, i++, item_db_name[fi]) )
+ count++;
}
// free the query result
@@ -2218,7 +2248,6 @@ void itemdb_defaults(void) {
itemdb->search_name_array = itemdb_searchname_array;
itemdb->load = itemdb_load;
itemdb->search = itemdb_search;
- itemdb->parse_dbrow = itemdb_parse_dbrow;
itemdb->exists = itemdb_exists;
itemdb->in_group = itemdb_in_group;
itemdb->group_item = itemdb_searchrandomid;
@@ -2256,7 +2285,9 @@ void itemdb_defaults(void) {
itemdb->combo_split_atoi = itemdb_combo_split_atoi;
itemdb->read_combos = itemdb_read_combos;
itemdb->gendercheck = itemdb_gendercheck;
- itemdb->re_split_atoi = itemdb_re_split_atoi;
+ itemdb->validate_entry = itemdb_validate_entry;
+ itemdb->readdb_sql_sub = itemdb_readdb_sql_sub;
+ itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub;
itemdb->readdb = itemdb_readdb;
itemdb->read_sqldb = itemdb_read_sqldb;
itemdb->unique_id = itemdb_unique_id;
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 80d2fd0ce..870ecce58 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -105,6 +105,17 @@ enum e_chain_cache {
ECC_MAX,
};
+enum item_class_upper {
+ ITEMUPPER_NONE = 0x00,
+ ITEMUPPER_NORMAL = 0x01,
+ ITEMUPPER_UPPER = 0x02,
+ ITEMUPPER_BABY = 0x04,
+ ITEMUPPER_THIRD = 0x08,
+ ITEMUPPER_THURDUPPER = 0x10,
+ ITEMUPPER_THIRDBABY = 0x20,
+ ITEMUPPER_ALL = 0x3f, // Sum of all the above
+};
+
struct item_data {
uint16 nameid;
char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH];
@@ -125,10 +136,8 @@ struct item_data {
int elv;
int wlv;
int view_id;
-#ifdef RENEWAL
int matk;
int elvmax;/* maximum level for this item */
-#endif
int delay;
//Lupus: I rearranged order of these fields due to compatibility with ITEMINFO script command
@@ -300,7 +309,6 @@ struct itemdb_interface {
int (*search_name_array) (struct item_data** data, int size, const char *str, int flag);
struct item_data* (*load)(int nameid);
struct item_data* (*search)(int nameid);
- int (*parse_dbrow) (char** str, const char* source, int line, int scriptopt);
struct item_data* (*exists) (int nameid);
bool (*in_group) (struct item_group *group, int nameid);
int (*group_item) (struct item_group *group);
@@ -338,7 +346,9 @@ struct itemdb_interface {
int (*combo_split_atoi) (char *str, int *val);
void (*read_combos) ();
int (*gendercheck) (struct item_data *id);
- void (*re_split_atoi) (char *str, int *atk, int *matk);
+ int (*validate_entry) (struct item_data *entry, int n, const char *source);
+ int (*readdb_sql_sub) (Sql *handle, int n, const char *source);
+ int (*readdb_libconfig_sub) (config_setting_t *it, int n, const char *source);
int (*readdb) (void);
int (*read_sqldb) (void);
uint64 (*unique_id) (int8 flag, int64 value);
diff --git a/src/map/pc.c b/src/map/pc.c
index 7a04f1fb8..d597ccf9f 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -983,10 +983,10 @@ int pc_isequip(struct map_session_data *sd,int n)
return 0;
//Not usable by upper class. [Inkfish]
while( 1 ) {
- if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
- if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
- if( item->class_upper&4 && sd->class_&JOBL_BABY ) break;
- if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break;
+ if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
+ if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
+ if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY ) break;
+ if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD ) break;
return 0;
}
@@ -4338,22 +4338,22 @@ int pc_isUseitem(struct map_session_data *sd,int n)
//Not usable by upper class. [Haru]
while( 1 ) {
// Normal classes (no upper, no baby, no third classes)
- if( item->class_upper&0x01 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
+ if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
#ifdef RENEWAL
// Upper classes (no third classes)
- if( item->class_upper&0x02 && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_THIRD) ) break;
+ if( item->class_upper&ITEMUPPER_UPPER && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_THIRD) ) break;
#else
//pre-re has no use for the extra, so we maintain the previous for backwards compatibility
- if( item->class_upper&0x02 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
+ if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
#endif
// Baby classes (no third classes)
- if( item->class_upper&0x04 && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD) ) break;
+ if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD) ) break;
// Third classes (no upper, no baby classes)
- if( item->class_upper&0x08 && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY)) ) break;
+ if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY)) ) break;
// Upper third classes
- if( item->class_upper&0x10 && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER ) break;
+ if( item->class_upper&ITEMUPPER_THURDUPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER ) break;
// Baby third classes
- if( item->class_upper&0x20 && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY ) break;
+ if( item->class_upper&ITEMUPPER_THIRDBABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY ) break;
return 0;
}