summaryrefslogtreecommitdiff
path: root/src/map/itemdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/itemdb.c')
-rw-r--r--src/map/itemdb.c610
1 files changed, 493 insertions, 117 deletions
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index bd552dd16..9a43bae14 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -49,7 +49,7 @@ struct itemdb_interface *itemdb;
* name = item alias, so we should find items aliases first. if not found then look for "jname" (full name)
* @see DBApply
*/
-int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap)
+int itemdb_searchname_sub(union DBKey key, struct DBData *data, va_list ap)
{
struct item_data *item = DB->data2ptr(data), **dst, **dst2;
char *str;
@@ -112,7 +112,7 @@ struct item_data* itemdb_name2id(const char *str) {
/**
* @see DBMatcher
*/
-int itemdb_searchname_array_sub(DBKey key, DBData data, va_list ap)
+int itemdb_searchname_array_sub(union DBKey key, struct DBData data, va_list ap)
{
struct item_data *item = DB->data2ptr(&data);
char *str;
@@ -170,10 +170,10 @@ int itemdb_searchname_array(struct item_data** data, int size, const char *str,
// search in the db
if( count < size )
{
- DBData *db_data[MAX_SEARCH];
+ struct DBData *db_data[MAX_SEARCH];
int db_count = 0;
size -= count;
- db_count = itemdb->other->getall(itemdb->other, (DBData**)&db_data, size, itemdb->searchname_array_sub, str);
+ db_count = itemdb->other->getall(itemdb->other, (struct DBData**)&db_data, size, itemdb->searchname_array_sub, str);
for (i = 0; i < db_count; i++)
data[count++] = DB->data2ptr(db_data[i]);
count += db_count;
@@ -321,6 +321,16 @@ struct item_data* itemdb_exists(int nameid)
return item;
}
+/**
+ * Searches for the item_option data.
+ * @param option_index as the index of the item option (client side).
+ * @return pointer to struct item_option data or NULL.
+ */
+struct item_option *itemdb_option_exists(int idx)
+{
+ return (struct item_option *)idb_get(itemdb->options, idx);
+}
+
/// Returns human readable name for given item type.
/// @param type Type id to retrieve name for ( IT_* ).
const char* itemdb_typename(int type)
@@ -342,81 +352,224 @@ const char* itemdb_typename(int type)
return "Unknown Type";
}
-/*==========================================
- * Converts the jobid from the format in itemdb
- * to the format used by the map server. [Skotlex]
- *------------------------------------------*/
-void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask)
+/**
+ * Converts the JobID to the format used by map-server to check item
+ * restriction as per job.
+ *
+ * @param bclass Pointer to the variable containing the new format
+ * @param job_id Variable containing JobID
+ * @param enable Boolean value which (un)set the restriction.
+ *
+ * @author Dastgir
+ */
+void itemdb_jobid2mapid(uint64 *bclass, int job_class, bool enable)
{
+ uint64 mask[3] = { 0 };
int i;
+
nullpo_retv(bclass);
- bclass[0]= bclass[1]= bclass[2]= 0;
+
+ switch (job_class) {
+ // Base Classes
+ case JOB_NOVICE:
+ case JOB_SUPER_NOVICE:
+ mask[0] = 1ULL << MAPID_NOVICE;
+ mask[1] = 1ULL << MAPID_NOVICE;
+ break;
+ case JOB_SWORDMAN:
+ mask[0] = 1ULL << MAPID_SWORDMAN;
+ break;
+ case JOB_MAGE:
+ mask[0] = 1ULL << MAPID_MAGE;
+ break;
+ case JOB_ARCHER:
+ mask[0] = 1ULL << MAPID_ARCHER;
+ break;
+ case JOB_ACOLYTE:
+ mask[0] = 1ULL << MAPID_ACOLYTE;
+ break;
+ case JOB_MERCHANT:
+ mask[0] = 1ULL << MAPID_MERCHANT;
+ break;
+ case JOB_THIEF:
+ mask[0] = 1ULL << MAPID_THIEF;
+ break;
+ // 2-1 Classes
+ case JOB_KNIGHT:
+ mask[1] = 1ULL << MAPID_SWORDMAN;
+ break;
+ case JOB_PRIEST:
+ mask[1] = 1ULL << MAPID_ACOLYTE;
+ break;
+ case JOB_WIZARD:
+ mask[1] = 1ULL << MAPID_MAGE;
+ break;
+ case JOB_BLACKSMITH:
+ mask[1] = 1ULL << MAPID_MERCHANT;
+ break;
+ case JOB_HUNTER:
+ mask[1] = 1ULL << MAPID_ARCHER;
+ break;
+ case JOB_ASSASSIN:
+ mask[1] = 1ULL << MAPID_THIEF;
+ break;
+ // 2-2 Classes
+ case JOB_CRUSADER:
+ mask[2] = 1ULL << MAPID_SWORDMAN;
+ break;
+ case JOB_MONK:
+ mask[2] = 1ULL << MAPID_ACOLYTE;
+ break;
+ case JOB_SAGE:
+ mask[2] = 1ULL << MAPID_MAGE;
+ break;
+ case JOB_ALCHEMIST:
+ mask[2] = 1ULL << MAPID_MERCHANT;
+ break;
+ case JOB_BARD:
+ mask[2] = 1ULL << MAPID_ARCHER;
+ break;
+ case JOB_ROGUE:
+ mask[2] = 1ULL << MAPID_THIEF;
+ break;
+ // Extended Classes
+ case JOB_TAEKWON:
+ mask[0] = 1ULL << MAPID_TAEKWON;
+ break;
+ case JOB_STAR_GLADIATOR:
+ mask[1] = 1ULL << MAPID_TAEKWON;
+ break;
+ case JOB_SOUL_LINKER:
+ mask[2] = 1ULL << MAPID_TAEKWON;
+ break;
+ case JOB_GUNSLINGER:
+ mask[0] = 1ULL << MAPID_GUNSLINGER;
+ mask[1] = 1ULL << MAPID_GUNSLINGER;
+ break;
+ case JOB_NINJA:
+ mask[0] = 1ULL << MAPID_NINJA;
+ mask[1] = 1ULL << MAPID_NINJA;
+ break;
+ case JOB_KAGEROU:
+ case JOB_OBORO:
+ mask[1] = 1ULL << MAPID_NINJA;
+ break;
+ case JOB_REBELLION:
+ mask[1] = 1ULL << MAPID_GUNSLINGER;
+ break;
+ case JOB_SUMMONER:
+ mask[0] = 1ULL << MAPID_SUMMONER;
+ break;
+ // Other Classes
+ case JOB_GANGSI: //Bongun/Munak
+ mask[0] = 1ULL << MAPID_GANGSI;
+ break;
+ case JOB_DEATH_KNIGHT:
+ mask[1] = 1ULL << MAPID_GANGSI;
+ break;
+ case JOB_DARK_COLLECTOR:
+ mask[2] = 1ULL << MAPID_GANGSI;
+ break;
+ }
+
+ for (i = 0; i < ARRAYLENGTH(mask); i++) {
+ if (mask[i] == 0)
+ continue;
+ if (enable)
+ bclass[i] |= mask[i];
+ else
+ bclass[i] &= ~mask[i];
+ }
+}
+
+/**
+ * Converts the JobMask to the format used by map-server to check item
+ * restriction as per job.
+ *
+ * @param bclass Pointer to the variable containing the new format.
+ * @param jobmask Variable containing JobMask.
+ */
+void itemdb_jobmask2mapid(uint64 *bclass, uint64 jobmask)
+{
+ nullpo_retv(bclass);
+ bclass[0] = bclass[1] = bclass[2] = 0;
//Base classes
- if (jobmask & 1<<JOB_NOVICE) {
+ if (jobmask & 1ULL<<JOB_NOVICE) {
//Both Novice/Super-Novice are counted with the same ID
- bclass[0] |= 1<<MAPID_NOVICE;
- bclass[1] |= 1<<MAPID_NOVICE;
- }
- for (i = JOB_NOVICE+1; i <= JOB_THIEF; i++)
- {
- if (jobmask & 1<<i)
- bclass[0] |= 1<<(MAPID_NOVICE+i);
- }
+ bclass[0] |= 1ULL<<MAPID_NOVICE;
+ bclass[1] |= 1ULL<<MAPID_NOVICE;
+ }
+ if (jobmask & 1ULL<<JOB_SWORDMAN)
+ bclass[0] |= 1ULL<<MAPID_SWORDMAN;
+ if (jobmask & 1ULL<<JOB_MAGE)
+ bclass[0] |= 1ULL<<MAPID_MAGE;
+ if (jobmask & 1ULL<<JOB_ARCHER)
+ bclass[0] |= 1ULL<<MAPID_ARCHER;
+ if (jobmask & 1ULL<<JOB_ACOLYTE)
+ bclass[0] |= 1ULL<<MAPID_ACOLYTE;
+ if (jobmask & 1ULL<<JOB_MERCHANT)
+ bclass[0] |= 1ULL<<MAPID_MERCHANT;
+ if (jobmask & 1ULL<<JOB_THIEF)
+ bclass[0] |= 1ULL<<MAPID_THIEF;
//2-1 classes
- if (jobmask & 1<<JOB_KNIGHT)
- bclass[1] |= 1<<MAPID_SWORDMAN;
- if (jobmask & 1<<JOB_PRIEST)
- bclass[1] |= 1<<MAPID_ACOLYTE;
- if (jobmask & 1<<JOB_WIZARD)
- bclass[1] |= 1<<MAPID_MAGE;
- if (jobmask & 1<<JOB_BLACKSMITH)
- bclass[1] |= 1<<MAPID_MERCHANT;
- if (jobmask & 1<<JOB_HUNTER)
- bclass[1] |= 1<<MAPID_ARCHER;
- if (jobmask & 1<<JOB_ASSASSIN)
- bclass[1] |= 1<<MAPID_THIEF;
+ if (jobmask & 1ULL<<JOB_KNIGHT)
+ bclass[1] |= 1ULL<<MAPID_SWORDMAN;
+ if (jobmask & 1ULL<<JOB_PRIEST)
+ bclass[1] |= 1ULL<<MAPID_ACOLYTE;
+ if (jobmask & 1ULL<<JOB_WIZARD)
+ bclass[1] |= 1ULL<<MAPID_MAGE;
+ if (jobmask & 1ULL<<JOB_BLACKSMITH)
+ bclass[1] |= 1ULL<<MAPID_MERCHANT;
+ if (jobmask & 1ULL<<JOB_HUNTER)
+ bclass[1] |= 1ULL<<MAPID_ARCHER;
+ if (jobmask & 1ULL<<JOB_ASSASSIN)
+ bclass[1] |= 1ULL<<MAPID_THIEF;
//2-2 classes
- if (jobmask & 1<<JOB_CRUSADER)
- bclass[2] |= 1<<MAPID_SWORDMAN;
- if (jobmask & 1<<JOB_MONK)
- bclass[2] |= 1<<MAPID_ACOLYTE;
- if (jobmask & 1<<JOB_SAGE)
- bclass[2] |= 1<<MAPID_MAGE;
- if (jobmask & 1<<JOB_ALCHEMIST)
- bclass[2] |= 1<<MAPID_MERCHANT;
- if (jobmask & 1<<JOB_BARD)
- bclass[2] |= 1<<MAPID_ARCHER;
+ if (jobmask & 1ULL<<JOB_CRUSADER)
+ bclass[2] |= 1ULL<<MAPID_SWORDMAN;
+ if (jobmask & 1ULL<<JOB_MONK)
+ bclass[2] |= 1ULL<<MAPID_ACOLYTE;
+ if (jobmask & 1ULL<<JOB_SAGE)
+ bclass[2] |= 1ULL<<MAPID_MAGE;
+ if (jobmask & 1ULL<<JOB_ALCHEMIST)
+ bclass[2] |= 1ULL<<MAPID_MERCHANT;
+ if (jobmask & 1ULL<<JOB_BARD)
+ bclass[2] |= 1ULL<<MAPID_ARCHER;
#if 0 // Bard/Dancer share the same slot now.
- if (jobmask & 1<<JOB_DANCER)
- bclass[2] |= 1<<MAPID_ARCHER;
+ if (jobmask & 1ULL<<JOB_DANCER)
+ bclass[2] |= 1ULL<<MAPID_ARCHER;
#endif // 0
- if (jobmask & 1<<JOB_ROGUE)
- bclass[2] |= 1<<MAPID_THIEF;
+ if (jobmask & 1ULL<<JOB_ROGUE)
+ bclass[2] |= 1ULL<<MAPID_THIEF;
//Special classes that don't fit above.
- if (jobmask & 1<<21) //Taekwon boy
- bclass[0] |= 1<<MAPID_TAEKWON;
- if (jobmask & 1<<22) //Star Gladiator
- bclass[1] |= 1<<MAPID_TAEKWON;
- if (jobmask & 1<<23) //Soul Linker
- bclass[2] |= 1<<MAPID_TAEKWON;
- if (jobmask & 1<<JOB_GUNSLINGER)
- {//Rebellion job can equip Gunslinger equips. [Rytech]
- bclass[0] |= 1<<MAPID_GUNSLINGER;
- bclass[1] |= 1<<MAPID_GUNSLINGER;
- }
- if (jobmask & 1<<JOB_NINJA)
- {bclass[0] |= 1<<MAPID_NINJA;
- bclass[1] |= 1<<MAPID_NINJA;}//Kagerou/Oboro jobs can equip Ninja equips. [Rytech]
- if (jobmask & 1<<26) //Bongun/Munak
- bclass[0] |= 1<<MAPID_GANGSI;
- if (jobmask & 1<<27) //Death Knight
- bclass[1] |= 1<<MAPID_GANGSI;
- if (jobmask & 1<<28) //Dark Collector
- bclass[2] |= 1<<MAPID_GANGSI;
- if (jobmask & 1<<29) //Kagerou / Oboro
- bclass[1] |= 1<<MAPID_NINJA;
- if (jobmask & 1<<30) //Rebellion
- bclass[1] |= 1<<MAPID_GUNSLINGER;
+ if (jobmask & 1ULL<<21) //Taekwon boy
+ bclass[0] |= 1ULL<<MAPID_TAEKWON;
+ if (jobmask & 1ULL<<22) //Star Gladiator
+ bclass[1] |= 1ULL<<MAPID_TAEKWON;
+ if (jobmask & 1ULL<<23) //Soul Linker
+ bclass[2] |= 1ULL<<MAPID_TAEKWON;
+ if (jobmask & 1ULL<<JOB_GUNSLINGER) {
+ //Rebellion job can equip Gunslinger equips. [Rytech]
+ bclass[0] |= 1ULL<<MAPID_GUNSLINGER;
+ bclass[1] |= 1ULL<<MAPID_GUNSLINGER;
+ }
+ if (jobmask & 1ULL<<JOB_NINJA) {
+ //Kagerou/Oboro jobs can equip Ninja equips. [Rytech]
+ bclass[0] |= 1ULL<<MAPID_NINJA;
+ bclass[1] |= 1ULL<<MAPID_NINJA;
+ }
+ if (jobmask & 1ULL<<26) //Bongun/Munak
+ bclass[0] |= 1ULL<<MAPID_GANGSI;
+ if (jobmask & 1ULL<<27) //Death Knight
+ bclass[1] |= 1ULL<<MAPID_GANGSI;
+ if (jobmask & 1ULL<<28) //Dark Collector
+ bclass[2] |= 1ULL<<MAPID_GANGSI;
+ if (jobmask & 1ULL<<29) //Kagerou / Oboro
+ bclass[1] |= 1ULL<<MAPID_NINJA;
+ if (jobmask & 1ULL<<30) //Rebellion
+ bclass[1] |= 1ULL<<MAPID_GUNSLINGER;
+ if (jobmask & 1ULL<<31) //Summoner
+ bclass[0] |= 1ULL<<MAPID_SUMMONER;
}
void create_dummy_data(void)
@@ -637,8 +790,8 @@ int itemdb_isidentified2(struct item_data *data) {
}
void itemdb_read_groups(void) {
- config_t item_group_conf;
- config_setting_t *itg = NULL, *it = NULL;
+ struct config_t item_group_conf;
+ struct config_setting_t *itg = NULL, *it = NULL;
#ifdef RENEWAL
const char *config_filename = "db/re/item_group.conf"; // FIXME hardcoded name
#else
@@ -648,10 +801,8 @@ void itemdb_read_groups(void) {
int i = 0, count = 0, c;
unsigned int *gsize = NULL;
- if (libconfig->read_file(&item_group_conf, config_filename)) {
- ShowError("can't read %s\n", config_filename);
+ if (!libconfig->load_file(&item_group_conf, config_filename))
return;
- }
gsize = aMalloc( libconfig->setting_length(item_group_conf.root) * sizeof(unsigned int) );
@@ -929,8 +1080,8 @@ bool itemdb_read_cached_packages(const char *config_filename) {
return true;
}
void itemdb_read_packages(void) {
- config_t item_packages_conf;
- config_setting_t *itg = NULL, *it = NULL, *t = NULL;
+ struct config_t item_packages_conf;
+ struct config_setting_t *itg = NULL, *it = NULL, *t = NULL;
#ifdef RENEWAL
const char *config_filename = "db/re/item_packages.conf"; // FIXME hardcoded name
#else
@@ -946,10 +1097,8 @@ void itemdb_read_packages(void) {
return;
}
- if (libconfig->read_file(&item_packages_conf, config_filename)) {
- ShowError("can't read %s\n", config_filename);
+ if (!libconfig->load_file(&item_packages_conf, config_filename))
return;
- }
must = aMalloc( libconfig->setting_length(item_packages_conf.root) * sizeof(unsigned int) );
random = aMalloc( libconfig->setting_length(item_packages_conf.root) * sizeof(unsigned int) );
@@ -1160,9 +1309,128 @@ void itemdb_read_packages(void) {
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename);
}
+/**
+ * Processes any (plugin-defined) additional fields for a itemdb_options entry.
+ *
+ * @param[in,out] entry The destination ito entry, already initialized
+ * (item_opt.index, status.mode are expected to be already set).
+ * @param[in] t The libconfig entry.
+ * @param[in] source Source of the entry (file name), to be displayed in
+ * case of validation errors.
+ */
+void itemdb_readdb_options_additional_fields(struct item_option *ito, struct config_setting_t *t, const char *source)
+{
+ // do nothing. plugins can do their own work
+}
+
+/**
+ * Reads the Item Options configuration file.
+ */
+void itemdb_read_options(void)
+{
+ struct config_t item_options_db;
+ struct config_setting_t *ito = NULL, *conf = NULL;
+ int index = 0, count = 0;
+ const char *filepath = "db/item_options.conf";
+ VECTOR_DECL(int) duplicate_id;
+
+ if (!libconfig->load_file(&item_options_db, filepath))
+ return;
+
+#ifdef ENABLE_CASE_CHECK
+ script->parser_current_file = filepath;
+#endif // ENABLE_CASE_CHECK
+
+ if ((ito=libconfig->setting_get_member(item_options_db.root, "item_options_db")) == NULL) {
+ ShowError("itemdb_read_options: '%s' could not be loaded.\n", filepath);
+ libconfig->destroy(&item_options_db);
+ return;
+ }
+
+ VECTOR_INIT(duplicate_id);
+
+ VECTOR_ENSURE(duplicate_id, libconfig->setting_length(ito), 1);
+
+ while ((conf = libconfig->setting_get_elem(ito, index++))) {
+ struct item_option t_opt = { 0 }, *s_opt = NULL;
+ const char *str = NULL;
+ int i = 0;
+
+ /* Id Lookup */
+ if (!libconfig->setting_lookup_int16(conf, "Id", &t_opt.index) || t_opt.index <= 0) {
+ ShowError("itemdb_read_options: Invalid Option Id provided for entry %d in '%s', skipping...\n", t_opt.index, filepath);
+ continue;
+ }
+
+ /* Checking for duplicate entries. */
+ ARR_FIND(0, VECTOR_LENGTH(duplicate_id), i, VECTOR_INDEX(duplicate_id, i) == t_opt.index);
+
+ if (i != VECTOR_LENGTH(duplicate_id)) {
+ ShowError("itemdb_read_options: Duplicate entry for Option Id %d in '%s', skipping...\n", t_opt.index, filepath);
+ continue;
+ }
+
+ VECTOR_PUSH(duplicate_id, t_opt.index);
+
+ /* Name Lookup */
+ if (!libconfig->setting_lookup_string(conf, "Name", &str)) {
+ ShowError("itemdb_read_options: Invalid Option Name '%s' provided for Id %d in '%s', skipping...\n", str, t_opt.index, filepath);
+ continue;
+ }
+
+ /* check for illegal characters in the constant. */
+ {
+ const char *c = str;
+
+ while (ISALNUM(*c) || *c == '_')
+ ++c;
+
+ if (*c != '\0') {
+ ShowError("itemdb_read_options: Invalid characters in Option Name '%s' for Id %d in '%s', skipping...\n", str, t_opt.index, filepath);
+ continue;
+ }
+ }
+
+ /* Set name as a script constant with index as value. */
+ script->set_constant2(str, t_opt.index, false, false);
+
+ /* Script Code Lookup */
+ if (!libconfig->setting_lookup_string(conf, "Script", &str)) {
+ ShowError("itemdb_read_options: Script code not found for entry %s (Id: %d) in '%s', skipping...\n", str, t_opt.index, filepath);
+ continue;
+ }
+
+ /* Set Script */
+ t_opt.script = *str ? script->parse(str, filepath, t_opt.index, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+
+ /* Additional fields through plugins */
+ itemdb->readdb_options_additional_fields(&t_opt, ito, filepath);
+
+ /* Allocate memory and copy contents */
+ CREATE(s_opt, struct item_option, 1);
+
+ *s_opt = t_opt;
+
+ /* Store ptr in the database */
+ idb_put(itemdb->options, t_opt.index, s_opt);
+
+ count++;
+ }
+
+#ifdef ENABLE_CASE_CHECK
+ script->parser_current_file = NULL;
+#endif // ENABLE_CASE_CHECK
+
+ libconfig->destroy(&item_options_db);
+
+ VECTOR_CLEAR(duplicate_id);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+}
+
void itemdb_read_chains(void) {
- config_t item_chain_conf;
- config_setting_t *itc = NULL;
+ struct config_t item_chain_conf;
+ struct config_setting_t *itc = NULL;
#ifdef RENEWAL
const char *config_filename = "db/re/item_chain.conf"; // FIXME hardcoded name
#else
@@ -1170,10 +1438,8 @@ void itemdb_read_chains(void) {
#endif
int i = 0, count = 0;
- if (libconfig->read_file(&item_chain_conf, config_filename)) {
- ShowError("can't read %s\n", config_filename);
+ if (!libconfig->load_file(&item_chain_conf, config_filename))
return;
- }
CREATE(itemdb->chains, struct item_chain, libconfig->setting_length(item_chain_conf.root));
itemdb->chain_count = (unsigned short)libconfig->setting_length(item_chain_conf.root);
@@ -1186,7 +1452,7 @@ void itemdb_read_chains(void) {
struct item_chain_entry *prev = NULL;
const char *name = config_setting_name(itc);
int c = 0;
- config_setting_t *entry = NULL;
+ struct config_setting_t *entry = NULL;
script->set_constant2(name, i-1, false, false);
itemdb->chains[count].qty = (unsigned short)libconfig->setting_length(itc);
@@ -1261,7 +1527,7 @@ void itemdb_read_combos(void)
char filepath[256];
FILE* fp;
- sprintf(filepath, "%s/%s", map->db_path, DBPATH"item_combo_db.txt");
+ snprintf(filepath, 256, "%s/%s", map->db_path, DBPATH"item_combo_db.txt");
if ((fp = fopen(filepath, "r")) == NULL) {
ShowError("itemdb_read_combos: File not found \"%s\".\n", filepath);
@@ -1286,7 +1552,7 @@ void itemdb_read_combos(void)
if (!strchr(p,',')) {
/* is there even a single column? */
- ShowError("itemdb_read_combos: Insufficient columns in line %d of \"%s\", skipping.\n", lines, filepath);
+ ShowError("itemdb_read_combos: Insufficient columns in line %u of \"%s\", skipping.\n", lines, filepath);
continue;
}
@@ -1300,13 +1566,13 @@ void itemdb_read_combos(void)
p++;
if (str[1][0] != '{') {
- ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, filepath);
+ ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %u of \"%s\", skipping.\n", lines, filepath);
continue;
}
/* no ending key anywhere (missing \}\) */
if ( str[1][strlen(str[1])-1] != '}' ) {
- ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, filepath);
+ ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %u of \"%s\", skipping.\n", lines, filepath);
continue;
} else {
int items[MAX_ITEMS_PER_COMBO];
@@ -1314,14 +1580,14 @@ void itemdb_read_combos(void)
struct item_combo *combo = NULL;
if((retcount = itemdb->combo_split_atoi(str[0], items)) < 2) {
- ShowError("itemdb_read_combos: line %d of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, filepath);
+ ShowError("itemdb_read_combos: line %u of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, filepath);
continue;
}
/* validate */
for(v = 0; v < retcount; v++) {
if( !itemdb->exists(items[v]) ) {
- ShowError("itemdb_read_combos: line %d of \"%s\" contains unknown item ID %d, skipping.\n", lines, filepath,items[v]);
+ ShowError("itemdb_read_combos: line %u of \"%s\" contains unknown item ID %d, skipping.\n", lines, filepath, items[v]);
break;
}
}
@@ -1420,6 +1686,30 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
return 0;
}
+ {
+ const char *c = entry->name;
+ while (ISALNUM(*c) || *c == '_')
+ ++c;
+
+ if (*c != '\0') {
+ ShowWarning("itemdb_validate_entry: Invalid characters in the AegisName '%s' for item %d in '%s'. Skipping.\n",
+ entry->name, entry->nameid, source);
+ 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;
+ }
+ }
+
if( entry->type < 0 || entry->type == IT_UNKNOWN || entry->type == IT_UNKNOWN2
|| (entry->type > IT_DELAYCONSUME && entry->type < IT_CASH ) || entry->type >= IT_MAX
) {
@@ -1462,7 +1752,7 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
if (entry->flag.trade_restriction > ITR_ALL) {
ShowWarning("itemdb_validate_entry: Invalid trade restriction flag 0x%x for item %d (%s) in '%s', defaulting to none.\n",
- entry->flag.trade_restriction, entry->nameid, entry->jname, source);
+ (unsigned int)entry->flag.trade_restriction, entry->nameid, entry->jname, source);
entry->flag.trade_restriction = ITR_NONE;
}
@@ -1498,6 +1788,12 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
memset(&entry->stack, '\0', sizeof(entry->stack));
}
+ if (entry->type == IT_WEAPON && (entry->look < 0 || entry->look >= MAX_SINGLE_WEAPON_TYPE)) {
+ ShowWarning("itemdb_validate_entry: Invalid View for weapon items. View value %d for item %d (%s) in '%s', defaulting to 1.\n",
+ entry->look, entry->nameid, entry->jname, source);
+ entry->look = 1;
+ }
+
entry->wlv = cap_value(entry->wlv, REFINE_TYPE_ARMOR, REFINE_TYPE_MAX);
if( !entry->elvmax )
@@ -1507,7 +1803,10 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
if( entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_refine )
entry->flag.no_refine = 1;
-
+
+ if (entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_options)
+ entry->flag.no_options = 1;
+
if (entry->flag.available != 1) {
entry->flag.available = 1;
entry->view_id = 0;
@@ -1535,9 +1834,42 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
return item->nameid;
}
-void itemdb_readdb_additional_fields(int itemid, config_setting_t *it, int n, const char *source)
+void itemdb_readdb_additional_fields(int itemid, struct config_setting_t *it, int n, const char *source)
{
- // do nothing. plugins can do own work
+ // do nothing. plugins can do own work
+}
+
+/**
+ * Processes job names and changes it into mapid format.
+ *
+ * @param id item_data entry.
+ * @param t Libconfig setting entry. It is expected to be valid and it won't
+ * be freed (it is care of the caller to do so if necessary).
+ */
+void itemdb_readdb_job_sub(struct item_data *id, struct config_setting_t *t)
+{
+ int idx = 0;
+ struct config_setting_t *it = NULL;
+ bool enable_all = false;
+
+ id->class_base[0] = id->class_base[1] = id->class_base[2] = 0;
+
+ if (libconfig->setting_lookup_bool_real(t, "All", &enable_all) && enable_all) {
+ itemdb->jobmask2mapid(id->class_base, UINT64_MAX);
+ }
+ while ((it = libconfig->setting_get_elem(t, idx++)) != NULL) {
+ const char *job_name = config_setting_name(it);
+ int job_id;
+
+ if (strcmp(job_name, "All") == 0)
+ continue;
+
+ if ((job_id = pc->check_job_name(job_name)) == -1) {
+ ShowWarning("itemdb_readdb_job_sub: unknown job name '%s'!\n", job_name);
+ } else {
+ itemdb->jobid2mapid(id->class_base, job_id, libconfig->setting_get_bool(it));
+ }
+ }
}
/**
@@ -1553,9 +1885,9 @@ void itemdb_readdb_additional_fields(int itemid, config_setting_t *it, int n, co
* validation errors.
* @return Nameid of the validated entry, or 0 in case of failure.
*/
-int itemdb_readdb_libconfig_sub(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 item_data id = { 0 };
- config_setting_t *t = NULL;
+ struct config_setting_t *t = NULL;
const char *str = NULL;
int i32 = 0;
bool inherit = false;
@@ -1681,10 +2013,17 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source)
if( itemdb->lookup_const(it, "Slots", &i32) && i32 >= 0 )
id.slot = i32;
- if( itemdb->lookup_const(it, "Job", &i32) ) // This is an unsigned value, do not check for >= 0
- itemdb->jobid2mapid(id.class_base, (unsigned int)i32);
- else if( !inherit )
- itemdb->jobid2mapid(id.class_base, UINT_MAX);
+ if ((t = libconfig->setting_get_member(it, "Job")) != NULL) {
+ if (config_setting_is_group(t)) {
+ itemdb->readdb_job_sub(&id, t);
+ } else if (itemdb->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) {
+ itemdb->jobmask2mapid(id.class_base, UINT64_MAX);
+ }
+ } else if (!inherit) {
+ itemdb->jobmask2mapid(id.class_base, UINT64_MAX);
+ }
if( itemdb->lookup_const(it, "Upper", &i32) && i32 >= 0 )
id.class_upper = (unsigned int)i32;
@@ -1715,6 +2054,9 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source)
if( (t = libconfig->setting_get_member(it, "Refine")) )
id.flag.no_refine = libconfig->setting_get_bool(t) ? 0 : 1;
+
+ if ((t = libconfig->setting_get_member(it, "DisableOptions")))
+ id.flag.no_options = libconfig->setting_get_bool(t) ? 1 : 0;
if( itemdb->lookup_const(it, "View", &i32) && i32 >= 0 )
id.look = i32;
@@ -1731,12 +2073,15 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source)
if ((t = libconfig->setting_get_member(it, "KeepAfterUse")))
id.flag.keepafteruse = libconfig->setting_get_bool(t) ? 1 : 0;
+ if ((t = libconfig->setting_get_member(it, "DropAnnounce")))
+ id.flag.drop_announce = libconfig->setting_get_bool(t) ? 1 : 0;
+
if (itemdb->lookup_const(it, "Delay", &i32) && i32 >= 0)
id.delay = i32;
if ( (t = libconfig->setting_get_member(it, "Trade")) ) {
if (config_setting_is_group(t)) {
- config_setting_t *tt = NULL;
+ struct config_setting_t *tt = NULL;
if ((tt = libconfig->setting_get_member(t, "override"))) {
id.gm_lv_trade_override = libconfig->setting_get_int(tt);
@@ -1802,7 +2147,7 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source)
if ((t = libconfig->setting_get_member(it, "Nouse"))) {
if (config_setting_is_group(t)) {
- config_setting_t *nt = NULL;
+ struct config_setting_t *nt = NULL;
if ((nt = libconfig->setting_get_member(t, "override"))) {
id.item_usage.override = libconfig->setting_get_int(nt);
@@ -1850,7 +2195,7 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source)
return itemdb->validate_entry(&id, n, source);
}
-bool itemdb_lookup_const(const config_setting_t *it, const char *name, int *value)
+bool itemdb_lookup_const(const struct config_setting_t *it, const char *name, int *value)
{
nullpo_retr(false, name);
nullpo_retr(false, value);
@@ -1879,19 +2224,24 @@ bool itemdb_lookup_const(const config_setting_t *it, const char *name, int *valu
*/
int itemdb_readdb_libconfig(const char *filename) {
bool duplicate[MAX_ITEMDB];
- config_t item_db_conf;
- config_setting_t *itdb, *it;
+ struct config_t item_db_conf;
+ struct config_setting_t *itdb, *it;
char filepath[256];
int i = 0, count = 0;
nullpo_ret(filename);
+
sprintf(filepath, "%s/%s", map->db_path, filename);
- memset(&duplicate,0,sizeof(duplicate));
- if( libconfig->read_file(&item_db_conf, filepath) || !(itdb = libconfig->setting_get_member(item_db_conf.root, "item_db")) ) {
+ if (!libconfig->load_file(&item_db_conf, filepath))
+ return 0;
+
+ if ((itdb = libconfig->setting_get_member(item_db_conf.root, "item_db")) == NULL) {
ShowError("can't read %s\n", filepath);
return 0;
}
+ memset(&duplicate,0,sizeof(duplicate));
+
while( (it = libconfig->setting_get_elem(itdb,i++)) ) {
int nameid = itemdb->readdb_libconfig_sub(it, i-1, filename);
@@ -1928,7 +2278,7 @@ uint64 itemdb_unique_id(struct map_session_data *sd) {
*/
void itemdb_read(bool minimal) {
int i;
- DBData prev;
+ struct DBData prev;
const char *filename[] = {
DBPATH"item_db.conf",
@@ -1953,6 +2303,7 @@ void itemdb_read(bool minimal) {
itemdb->read_groups();
itemdb->read_chains();
itemdb->read_packages();
+ itemdb->read_options();
}
@@ -2005,7 +2356,7 @@ void destroy_item_data(struct item_data* self, int free_self)
/**
* @see DBApply
*/
-int itemdb_final_sub(DBKey key, DBData *data, va_list ap)
+int itemdb_final_sub(union DBKey key, struct DBData *data, va_list ap)
{
struct item_data *id = DB->data2ptr(data);
@@ -2014,6 +2365,17 @@ int itemdb_final_sub(DBKey key, DBData *data, va_list ap)
return 0;
}
+
+int itemdb_options_final_sub(union DBKey key, struct DBData *data, va_list ap)
+{
+ struct item_option *ito = DB->data2ptr(data);
+
+ if (ito->script != NULL)
+ script->free_code(ito->script);
+
+ return 0;
+}
+
void itemdb_clear(bool total) {
int i;
// clear the previous itemdb data
@@ -2077,6 +2439,7 @@ void itemdb_clear(bool total) {
return;
itemdb->other->clear(itemdb->other, itemdb->final_sub);
+ itemdb->options->clear(itemdb->options, itemdb->options_final_sub);
memset(itemdb->array, 0, sizeof(itemdb->array));
@@ -2127,22 +2490,27 @@ void itemdb_reload(void) {
for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays
pc->setinventorydata(sd);
- if( battle_config.item_check )
- sd->state.itemcheck = 1;
+
+ if (battle->bc->item_check != PCCHECKITEM_NONE) // Check and flag items for inspection.
+ sd->itemcheck = (enum pc_checkitem_types) battle->bc->item_check;
+
/* clear combo bonuses */
- if( sd->combo_count ) {
+ if (sd->combo_count) {
aFree(sd->combos);
sd->combos = NULL;
sd->combo_count = 0;
if( pc->load_combo(sd) > 0 )
status_calc_pc(sd,SCO_FORCE);
}
+
+ // Check for and delete unavailable/disabled items.
pc->checkitem(sd);
}
mapit->free(iter);
}
-void itemdb_name_constants(void) {
- DBIterator *iter = db_iterator(itemdb->names);
+void itemdb_name_constants(void)
+{
+ struct DBIterator *iter = db_iterator(itemdb->names);
struct item_data *data;
#ifdef ENABLE_CASE_CHECK
@@ -2160,6 +2528,7 @@ void do_final_itemdb(void) {
itemdb->clear(true);
itemdb->other->destroy(itemdb->other, itemdb->final_sub);
+ itemdb->options->destroy(itemdb->options, itemdb->options_final_sub);
itemdb->destroy_item_data(&itemdb->dummy, 0);
db_destroy(itemdb->names);
}
@@ -2167,6 +2536,7 @@ void do_final_itemdb(void) {
void do_init_itemdb(bool minimal) {
memset(itemdb->array, 0, sizeof(itemdb->array));
itemdb->other = idb_alloc(DB_OPT_BASE);
+ itemdb->options = idb_alloc(DB_OPT_RELEASE_DATA);
itemdb->names = strdb_alloc(DB_OPT_BASE,ITEM_NAME_LENGTH);
itemdb->create_dummy_data(); //Dummy data item.
itemdb->read(minimal);
@@ -2177,7 +2547,7 @@ void do_init_itemdb(bool minimal) {
clif->cashshop_load();
/** it failed? we disable it **/
- if( !clif->parse_roulette_db() )
+ if (battle_config.feature_roulette == 1 && !clif->parse_roulette_db())
battle_config.feature_roulette = 0;
}
void itemdb_defaults(void) {
@@ -2209,6 +2579,7 @@ void itemdb_defaults(void) {
itemdb->read_groups = itemdb_read_groups;
itemdb->read_chains = itemdb_read_chains;
itemdb->read_packages = itemdb_read_packages;
+ itemdb->read_options = itemdb_read_options;
/* */
itemdb->write_cached_packages = itemdb_write_cached_packages;
itemdb->read_cached_packages = itemdb_read_cached_packages;
@@ -2219,6 +2590,7 @@ void itemdb_defaults(void) {
itemdb->load = itemdb_load;
itemdb->search = itemdb_search;
itemdb->exists = itemdb_exists;
+ itemdb->option_exists = itemdb_option_exists;
itemdb->in_group = itemdb_in_group;
itemdb->group_item = itemdb_searchrandomid;
itemdb->chain_item = itemdb_chain_item;
@@ -2227,6 +2599,7 @@ void itemdb_defaults(void) {
itemdb->searchname_array_sub = itemdb_searchname_array_sub;
itemdb->searchrandomid = itemdb_searchrandomid;
itemdb->typename = itemdb_typename;
+ itemdb->jobmask2mapid = itemdb_jobmask2mapid;
itemdb->jobid2mapid = itemdb_jobid2mapid;
itemdb->create_dummy_data = create_dummy_data;
itemdb->create_item_data = create_item_data;
@@ -2250,13 +2623,16 @@ void itemdb_defaults(void) {
itemdb->read_combos = itemdb_read_combos;
itemdb->gendercheck = itemdb_gendercheck;
itemdb->validate_entry = itemdb_validate_entry;
+ itemdb->readdb_options_additional_fields = itemdb_readdb_options_additional_fields;
itemdb->readdb_additional_fields = itemdb_readdb_additional_fields;
+ itemdb->readdb_job_sub = itemdb_readdb_job_sub;
itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub;
itemdb->readdb_libconfig = itemdb_readdb_libconfig;
itemdb->unique_id = itemdb_unique_id;
itemdb->read = itemdb_read;
itemdb->destroy_item_data = destroy_item_data;
itemdb->final_sub = itemdb_final_sub;
+ itemdb->options_final_sub = itemdb_options_final_sub;
itemdb->clear = itemdb_clear;
itemdb->id2combo = itemdb_id2combo;
itemdb->is_item_usable = itemdb_is_item_usable;