diff options
author | Haru <haru@dotalux.com> | 2013-11-08 07:18:40 +0100 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2013-11-14 20:15:28 +0100 |
commit | ed72a947a6c97804c1eef5b80bfa49d99f7d7586 (patch) | |
tree | f9196c943010e26c13c12d38c7a622d43301a4cd /src/map | |
parent | 7d0a63b72f93c05b302c08cfb19d5651cef1cdb8 (diff) | |
download | hercules-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/map')
-rw-r--r-- | src/map/itemdb.c | 539 | ||||
-rw-r--r-- | src/map/itemdb.h | 18 | ||||
-rw-r--r-- | src/map/pc.c | 22 |
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; } |