diff options
Diffstat (limited to 'src/map/status.c')
-rw-r--r-- | src/map/status.c | 143 |
1 files changed, 112 insertions, 31 deletions
diff --git a/src/map/status.c b/src/map/status.c index 720a02494..4f1813af6 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -35,6 +35,7 @@ #include "common/strlib.h" #include "common/timer.h" #include "common/utils.h" +#include "common/conf.h" #include <math.h> #include <memory.h> @@ -12278,38 +12279,117 @@ bool status_readdb_sizefix(char* fields[], int columns, int current) return true; } -bool status_readdb_refine(char* fields[], int columns, int current) -{ - int i, bonus_per_level, random_bonus, random_bonus_start_level; - - current = atoi(fields[0]); - - if (current < 0 || current >= REFINE_TYPE_MAX) - return false; - - bonus_per_level = atoi(fields[1]); - random_bonus_start_level = atoi(fields[2]); - random_bonus = atoi(fields[3]); - - for(i = 0; i < MAX_REFINE; i++) - { - char* delim; - - if (!(delim = strchr(fields[4+i], ':'))) - return false; - - *delim = '\0'; - - status->dbs->refine_info[current].chance[i] = atoi(fields[4+i]); +/** + * Processes a refine_db.conf entry. + * + * @param *r 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) + * @param n Ordinal number of the entry, to be displayed in case of + * validation errors. + * @param *source Source of the entry (file name), to be displayed in case of + * validation errors. + * @return # of the validated entry, or 0 in case of failure. + */ +int status_readdb_refine_libconfig_sub(config_setting_t *r, const char *name, const char *source) { + config_setting_t *rate = NULL; + int i=0, type=0, bonus_per_level=0, rnd_bonus_v=0, rnd_bonus_lv=0; + char lv[4]; + + if(!strncmp(name, "Armors", 6)) { + type = 0; + } else if(strncmp(name, "WeaponLevel", 11) || !strspn(&name[strlen(name)-1], "0123456789") || !(type = atoi(strncpy(lv, name+11, 2)))) { + ShowError("status_readdb_refine_libconfig_sub: Invalid key name for entry '%s' in \"%s\", skipping.\n", name, source); + return 0; + } + if(type < REFINE_TYPE_ARMOR || type >= REFINE_TYPE_MAX) { + ShowError("status_readdb_refine_libconfig_sub: Out of range level for entry '%s' in \"%s\", skipping.\n", name, source); + return 0; + } else if(!libconfig->setting_lookup_int(r, "StatsPerLevel", &bonus_per_level)) { + ShowWarning("status_readdb_refine_libconfig_sub: Missing StatsPerLevel for entry '%s' in \"%s\", skipping.\n", name, source); + return 0; + } else if(!libconfig->setting_lookup_int(r, "RandomBonusStartLevel", &rnd_bonus_lv)) { + ShowWarning("status_readdb_refine_libconfig_sub: Missing RandomBonusStartLevel for entry '%s' in \"%s\", skipping.\n", name, source); + return 0; + } else if(!libconfig->setting_lookup_int(r, "RandomBonusValue", &rnd_bonus_v)) { + ShowWarning("status_readdb_refine_libconfig_sub: Missing RandomBonusValue for entry '%s' in \"%s\", skipping.\n", name, source); + return 0; + } - if (i >= random_bonus_start_level - 1) - status->dbs->refine_info[current].randombonus_max[i] = random_bonus * (i - random_bonus_start_level + 2); + if((rate=libconfig->setting_get_member(r, "Rates")) && config_setting_is_group(rate)) { + config_setting_t *t = NULL; + bool duplicate[MAX_REFINE]; + int bonus_[MAX_REFINE], rnd_bonus[MAX_REFINE], chance_[MAX_REFINE]; + + memset(&duplicate,0,sizeof(duplicate)); + memset(&bonus_,0,sizeof(bonus_)); + memset(&rnd_bonus,0,sizeof(rnd_bonus)); + memset(&chance_,0,sizeof(chance_)); + i=0; + while( (t = libconfig->setting_get_elem(rate,i++)) && config_setting_is_group(t) ) { + int level=0, chance=0, bonus=0; + char *rlvl = config_setting_name(t); + memset(&lv,0, sizeof(lv)); + if(!strspn(&rlvl[strlen(rlvl)-1], "0123456789") || (level = atoi(strncpy(lv, rlvl+2, 3))) <= 0) { + ShowError("status_readdb_refine_libconfig_sub: Invalid refine level format '%s' for entry %s in \"%s\"... skipping.\n", rlvl, name, source); + continue; + } else if(level <= 0 || level > MAX_REFINE) { + ShowError("status_readdb_refine_libconfig_sub: Out of range refine level '%s' for entry %s in \"%s\"... skipping.\n", rlvl, name, source); + continue; + } else if(duplicate[level-1]) { + ShowWarning("status_readdb_refine_libconfig_sub: duplicate rate '%s' for entry %s in \"%s\", overwriting previous entry...\n", rlvl, name, source); + } else duplicate[level-1] = true; + level--; + chance_[level] = libconfig->setting_lookup_int(t, "Chance", &chance)?chance:100; + bonus_[level] = bonus_per_level + libconfig->setting_lookup_int(t, "Bonus", &bonus)?bonus:0; + if ( level >= rnd_bonus_lv - 1 ) rnd_bonus[level] = rnd_bonus_v * (level - rnd_bonus_lv + 2); + } + for(i=0; i < MAX_REFINE; i++) { + status->dbs->refine_info[type].chance[i] = chance_[i]?chance_[i]:100; + status->dbs->refine_info[type].randombonus_max[i] = rnd_bonus[i]; + bonus_[i] += i?bonus_[i-1]:0; + status->dbs->refine_info[type].bonus[i] = bonus_[i]?bonus_[i]:0; + } + } else { + ShowWarning("status_readdb_refine_libconfig_sub: Missing refine rates for entry '%s' in \"%s\", skipping.\n", name, source); + return 0; + } + return type+1; +} - status->dbs->refine_info[current].bonus[i] = bonus_per_level + atoi(delim+1); - if (i > 0) - status->dbs->refine_info[current].bonus[i] += status->dbs->refine_info[current].bonus[i-1]; +/** + * Reads from a libconfig-formatted refine_db.conf file. + * + * @param *filename File name, relative to the database path. + * @return The number of found entries. + */ +int status_readdb_refine_libconfig(const char *filename) { + bool duplicate[REFINE_TYPE_MAX]; + config_t refine_db_conf; + config_setting_t *r; + char filepath[256]; + int i = 0, count = 0,type = 0; + + sprintf(filepath, "%s/%s", map->db_path, filename); + memset(&duplicate,0,sizeof(duplicate)); + if( libconfig->read_file(&refine_db_conf, filepath) ) { + ShowError("can't read %s\n", filepath); + return 0; } - return true; + + while((r = libconfig->setting_get_elem(refine_db_conf.root,i++))) { + char *name = config_setting_name(r); + if((type=status->readdb_refine_libconfig_sub(r, name, filename))) { + if( duplicate[type-1] ) { + ShowWarning("status_readdb_refine_libconfig: duplicate entry for %s in \"%s\", overwriting previous entry...\n", name, filename); + } else duplicate[type-1] = true; + count++; + } + } + libconfig->destroy(&refine_db_conf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename); + + return count; } bool status_readdb_scconfig(char* fields[], int columns, int current) { @@ -12372,7 +12452,7 @@ int status_readdb(void) // sv->readdb(map->db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, status->readdb_job2); sv->readdb(map->db_path, DBPATH"size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(status->dbs->atkmods), status->readdb_sizefix); - sv->readdb(map->db_path, DBPATH"refine_db.txt", ',', 4+MAX_REFINE, 4+MAX_REFINE, ARRAYLENGTH(status->dbs->refine_info), status->readdb_refine); + status->readdb_refine_libconfig(DBPATH"refine_db.conf"); sv->readdb(map->db_path, "sc_config.txt", ',', 2, 2, SC_MAX, status->readdb_scconfig); status->read_job_db(); @@ -12547,7 +12627,8 @@ void status_defaults(void) { status->natural_heal_timer = status_natural_heal_timer; status->readdb_job2 = status_readdb_job2; status->readdb_sizefix = status_readdb_sizefix; - status->readdb_refine = status_readdb_refine; + status->readdb_refine_libconfig = status_readdb_refine_libconfig; + status->readdb_refine_libconfig_sub = status_readdb_refine_libconfig_sub; status->readdb_scconfig = status_readdb_scconfig; status->read_job_db = status_read_job_db; status->read_job_db_sub = status_read_job_db_sub; |