forked from github/server
8cfcffc4aa
make run-turn.sh work without valgrind
865 lines
20 KiB
C
865 lines
20 KiB
C
/*
|
||
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
|
||
Katja Zedel <katze@felidae.kn-bremen.de
|
||
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||
|
||
Permission to use, copy, modify, and/or distribute this software for any
|
||
purpose with or without fee is hereby granted, provided that the above
|
||
copyright notice and this permission notice appear in all copies.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
**/
|
||
|
||
#include <platform.h>
|
||
#include <kernel/config.h>
|
||
|
||
/* kernel includes */
|
||
#include "alliance.h"
|
||
#include "ally.h"
|
||
#include "alchemy.h"
|
||
#include "curse.h"
|
||
#include "connection.h"
|
||
#include "building.h"
|
||
#include "calendar.h"
|
||
#include "direction.h"
|
||
#include "equipment.h"
|
||
#include "faction.h"
|
||
#include "group.h"
|
||
#include "item.h"
|
||
#include "keyword.h"
|
||
#include "messages.h"
|
||
#include "move.h"
|
||
#include "objtypes.h"
|
||
#include "order.h"
|
||
#include "plane.h"
|
||
#include "pool.h"
|
||
#include "race.h"
|
||
#include "reports.h"
|
||
#include "region.h"
|
||
#include "ship.h"
|
||
#include "skill.h"
|
||
#include "terrain.h"
|
||
#include "types.h"
|
||
#include "unit.h"
|
||
|
||
|
||
#include <kernel/spell.h>
|
||
#include <kernel/spellbook.h>
|
||
|
||
/* util includes */
|
||
#include <util/attrib.h>
|
||
#include <util/base36.h>
|
||
#include <util/bsdstring.h>
|
||
#include <util/crmessage.h>
|
||
#include <util/event.h>
|
||
#include <util/language.h>
|
||
#include <util/functions.h>
|
||
#include <util/log.h>
|
||
#include <util/lists.h>
|
||
#include <util/parser.h>
|
||
#include <util/rand.h>
|
||
#include <util/rng.h>
|
||
#include <util/translation.h>
|
||
#include <util/umlaut.h>
|
||
#include <util/xml.h>
|
||
|
||
#include "donations.h"
|
||
#include "guard.h"
|
||
#include "prefix.h"
|
||
|
||
#ifdef USE_LIBXML2
|
||
/* libxml includes */
|
||
#include <libxml/tree.h>
|
||
#include <libxml/xpath.h>
|
||
#endif
|
||
|
||
/* external libraries */
|
||
#include <iniparser.h>
|
||
#include <critbit.h>
|
||
|
||
/* libc includes */
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <assert.h>
|
||
#include <limits.h>
|
||
#include <time.h>
|
||
#include <errno.h>
|
||
#include <sys/stat.h>
|
||
|
||
struct settings global;
|
||
|
||
bool lomem = false;
|
||
int turn = -1;
|
||
|
||
const char *parameters[MAXPARAMS] = {
|
||
"LOCALE",
|
||
"ALLES",
|
||
"JEDEM",
|
||
"BAUERN",
|
||
"BURG",
|
||
"EINHEIT",
|
||
"PRIVAT",
|
||
"HINTEN",
|
||
"KOMMANDO",
|
||
"KRAEUTER",
|
||
"NICHT",
|
||
"NAECHSTER",
|
||
"PARTEI",
|
||
"ERESSEA",
|
||
"PERSONEN",
|
||
"REGION",
|
||
"SCHIFF",
|
||
"SILBER",
|
||
"STRASSEN",
|
||
"TEMP",
|
||
"FLIEHE",
|
||
"GEBAEUDE",
|
||
"GIB", /* F<>r HELFE */
|
||
"KAEMPFE",
|
||
"DURCHREISE",
|
||
"BEWACHE",
|
||
"ZAUBER",
|
||
"PAUSE",
|
||
"VORNE",
|
||
"AGGRESSIV",
|
||
"DEFENSIV",
|
||
"STUFE",
|
||
"HELFE",
|
||
"FREMDES",
|
||
"AURA",
|
||
"HINTER",
|
||
"VOR",
|
||
"ANZAHL",
|
||
"GEGENSTAENDE",
|
||
"TRAENKE",
|
||
"GRUPPE",
|
||
"PARTEITARNUNG",
|
||
"BAEUME",
|
||
"ALLIANZ"
|
||
};
|
||
|
||
FILE *debug;
|
||
|
||
void
|
||
parse(keyword_t kword, int(*dofun) (unit *, struct order *), bool thisorder)
|
||
{
|
||
region *r;
|
||
|
||
for (r = regions; r; r = r->next) {
|
||
unit **up = &r->units;
|
||
while (*up) {
|
||
unit *u = *up;
|
||
order **ordp = &u->orders;
|
||
if (thisorder)
|
||
ordp = &u->thisorder;
|
||
while (*ordp) {
|
||
order *ord = *ordp;
|
||
if (getkeyword(ord) == kword) {
|
||
if (dofun(u, ord) != 0)
|
||
break;
|
||
if (u->orders == NULL)
|
||
break;
|
||
}
|
||
if (thisorder)
|
||
break;
|
||
if (*ordp == ord)
|
||
ordp = &ord->next;
|
||
}
|
||
if (*up == u)
|
||
up = &u->next;
|
||
}
|
||
}
|
||
}
|
||
|
||
int findoption(const char *s, const struct locale *lang)
|
||
{
|
||
void **tokens = get_translations(lang, UT_OPTIONS);
|
||
variant token;
|
||
|
||
if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) {
|
||
return (direction_t)token.i;
|
||
}
|
||
return NODIRECTION;
|
||
}
|
||
|
||
param_t findparam(const char *s, const struct locale * lang)
|
||
{
|
||
param_t result = NOPARAM;
|
||
char buffer[64];
|
||
char * str = s ? transliterate(buffer, sizeof(buffer) - sizeof(int), s) : 0;
|
||
|
||
if (str && *str) {
|
||
int i;
|
||
void * match;
|
||
void **tokens = get_translations(lang, UT_PARAMS);
|
||
critbit_tree *cb = (critbit_tree *)*tokens;
|
||
if (!cb) {
|
||
log_warning("no parameters defined in locale %s", locale_name(lang));
|
||
}
|
||
else if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) {
|
||
cb_get_kv(match, &i, sizeof(int));
|
||
result = (param_t)i;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
param_t findparam_block(const char *s, const struct locale *lang, bool any_locale)
|
||
{
|
||
param_t p;
|
||
if (!s || s[0] == '@') {
|
||
return NOPARAM;
|
||
}
|
||
p = findparam(s, lang);
|
||
if (any_locale && p==NOPARAM) {
|
||
const struct locale *loc;
|
||
for (loc=locales;loc;loc=nextlocale(loc)) {
|
||
if (loc!=lang) {
|
||
p = findparam(s, loc);
|
||
if (p==P_FACTION || p==P_GAMENAME) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return p;
|
||
}
|
||
|
||
param_t findparam_ex(const char *s, const struct locale * lang)
|
||
{
|
||
param_t result = findparam(s, lang);
|
||
|
||
if (result == NOPARAM) {
|
||
const building_type *btype = findbuildingtype(s, lang);
|
||
if (btype != NULL)
|
||
return P_GEBAEUDE;
|
||
}
|
||
return (result == P_BUILDING) ? P_GEBAEUDE : result;
|
||
}
|
||
|
||
bool isparam(const char *s, const struct locale * lang, param_t param)
|
||
{
|
||
assert(s);
|
||
if (s[0] > '@') {
|
||
param_t p = (param == P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang);
|
||
return p == param;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
param_t getparam(const struct locale * lang)
|
||
{
|
||
char token[64];
|
||
const char *s = gettoken(token, sizeof(token));
|
||
return s ? findparam(s, lang) : NOPARAM;
|
||
}
|
||
|
||
unit *getnewunit(const region * r, const faction * f)
|
||
{
|
||
int n;
|
||
n = getid();
|
||
|
||
return findnewunit(r, f, n);
|
||
}
|
||
|
||
|
||
/* -- Erschaffung neuer Einheiten ------------------------------ */
|
||
|
||
static const char *forbidden[] = { "t", "te", "tem", "temp", NULL };
|
||
static int *forbidden_ids;
|
||
|
||
int forbiddenid(int id)
|
||
{
|
||
static size_t len;
|
||
size_t i;
|
||
if (id <= 0)
|
||
return 1;
|
||
if (!forbidden_ids) {
|
||
while (forbidden[len])
|
||
++len;
|
||
forbidden_ids = calloc(len, sizeof(int));
|
||
for (i = 0; i != len; ++i) {
|
||
forbidden_ids[i] = atoi36(forbidden[i]);
|
||
}
|
||
}
|
||
for (i = 0; i != len; ++i)
|
||
if (id == forbidden_ids[i])
|
||
return 1;
|
||
return 0;
|
||
}
|
||
|
||
int newcontainerid(void)
|
||
{
|
||
int random_no;
|
||
int start_random_no;
|
||
|
||
random_no = 1 + (rng_int() % MAX_CONTAINER_NR);
|
||
start_random_no = random_no;
|
||
|
||
while (findship(random_no) || findbuilding(random_no)) {
|
||
random_no++;
|
||
if (random_no == MAX_CONTAINER_NR + 1) {
|
||
random_no = 1;
|
||
}
|
||
if (random_no == start_random_no) {
|
||
random_no = (int)MAX_CONTAINER_NR + 1;
|
||
}
|
||
}
|
||
return random_no;
|
||
}
|
||
|
||
static const char * parameter_key(int i)
|
||
{
|
||
assert(i < MAXPARAMS && i >= 0);
|
||
return parameters[i];
|
||
}
|
||
|
||
void init_parameters(struct locale *lang) {
|
||
init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
|
||
}
|
||
|
||
|
||
void init_terrains_translation(const struct locale *lang) {
|
||
void **tokens;
|
||
const terrain_type *terrain;
|
||
|
||
tokens = get_translations(lang, UT_TERRAINS);
|
||
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
|
||
variant var;
|
||
const char *name;
|
||
var.v = (void *)terrain;
|
||
name = locale_string(lang, terrain->_name, false);
|
||
if (name) {
|
||
addtoken((struct tnode **)tokens, name, var);
|
||
}
|
||
else {
|
||
log_debug("no translation for terrain %s in locale %s", terrain->_name, locale_name(lang));
|
||
}
|
||
}
|
||
}
|
||
|
||
void init_options_translation(const struct locale * lang) {
|
||
void **tokens;
|
||
int i;
|
||
|
||
tokens = get_translations(lang, UT_OPTIONS);
|
||
for (i = 0; i != MAXOPTIONS; ++i) {
|
||
variant var;
|
||
var.i = i;
|
||
if (options[i]) {
|
||
const char *name = locale_string(lang, options[i], false);
|
||
if (name) {
|
||
addtoken((struct tnode **)tokens, name, var);
|
||
}
|
||
else {
|
||
log_debug("no translation for OPTION %s in locale %s", options[i], locale_name(lang));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void init_locale(struct locale *lang)
|
||
{
|
||
variant var;
|
||
int i;
|
||
const struct race *rc;
|
||
void **tokens;
|
||
|
||
tokens = get_translations(lang, UT_MAGIC);
|
||
if (tokens) {
|
||
const char *str = config_get("rules.magic.playerschools");
|
||
char *sstr, *tok;
|
||
if (str == NULL) {
|
||
str = "gwyrrd illaun draig cerddor tybied";
|
||
}
|
||
|
||
sstr = strdup(str);
|
||
tok = strtok(sstr, " ");
|
||
while (tok) {
|
||
const char *name;
|
||
for (i = 0; i != MAXMAGIETYP; ++i) {
|
||
if (strcmp(tok, magic_school[i]) == 0) break;
|
||
}
|
||
assert(i != MAXMAGIETYP);
|
||
var.i = i;
|
||
name = LOC(lang, mkname("school", tok));
|
||
if (name) {
|
||
addtoken((struct tnode **)tokens, name, var);
|
||
}
|
||
else {
|
||
log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang));
|
||
}
|
||
tok = strtok(NULL, " ");
|
||
}
|
||
free(sstr);
|
||
}
|
||
|
||
init_directions(lang);
|
||
init_keywords(lang);
|
||
init_skills(lang);
|
||
|
||
tokens = get_translations(lang, UT_RACES);
|
||
for (rc = races; rc; rc = rc->next) {
|
||
const char *name;
|
||
var.v = (void *)rc;
|
||
name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
|
||
if (name) addtoken((struct tnode **)tokens, name, var);
|
||
name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
|
||
if (name) addtoken((struct tnode **)tokens, name, var);
|
||
}
|
||
|
||
init_parameters(lang);
|
||
|
||
init_options_translation(lang);
|
||
init_terrains_translation(lang);
|
||
}
|
||
|
||
typedef struct param {
|
||
critbit_tree cb;
|
||
} param;
|
||
|
||
size_t pack_keyval(const char *key, const char *value, char *data, size_t len) {
|
||
size_t klen = strlen(key);
|
||
size_t vlen = strlen(value);
|
||
assert(klen + vlen + 2 + sizeof(vlen) <= len);
|
||
memcpy(data, key, klen + 1);
|
||
memcpy(data + klen + 1, value, vlen + 1);
|
||
return klen + vlen + 2;
|
||
}
|
||
|
||
void set_param(struct param **p, const char *key, const char *value)
|
||
{
|
||
struct param *par;
|
||
assert(p);
|
||
|
||
par = *p;
|
||
if (!par && value) {
|
||
*p = par = calloc(1, sizeof(param));
|
||
}
|
||
if (par) {
|
||
void *match;
|
||
size_t klen = strlen(key) + 1;
|
||
if (cb_find_prefix(&par->cb, key, klen, &match, 1, 0) > 0) {
|
||
const char * kv = (const char *)match;
|
||
size_t vlen = strlen(kv + klen) + 1;
|
||
cb_erase(&par->cb, kv, klen + vlen);
|
||
}
|
||
}
|
||
if (value) {
|
||
char data[512];
|
||
size_t sz = pack_keyval(key, value, data, sizeof(data));
|
||
cb_insert(&par->cb, data, sz);
|
||
}
|
||
}
|
||
|
||
void free_params(struct param **pp) {
|
||
param *p = *pp;
|
||
if (p) {
|
||
cb_clear(&p->cb);
|
||
free(p);
|
||
}
|
||
*pp = 0;
|
||
}
|
||
|
||
const char *get_param(const struct param *p, const char *key)
|
||
{
|
||
void *match;
|
||
if (p && cb_find_prefix(&p->cb, key, strlen(key) + 1, &match, 1, 0) > 0) {
|
||
cb_get_kv_ex(match, &match);
|
||
return (const char *)match;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
int get_param_int(const struct param *p, const char *key, int def)
|
||
{
|
||
const char * str = get_param(p, key);
|
||
return str ? atoi(str) : def;
|
||
}
|
||
|
||
int check_param(const struct param *p, const char *key, const char *searchvalue)
|
||
{
|
||
int result = 0;
|
||
const char *value = get_param(p, key);
|
||
char *v, *p_value;
|
||
if (!value) {
|
||
return 0;
|
||
}
|
||
p_value = strdup(value);
|
||
v = strtok(p_value, " ,;");
|
||
|
||
while (v != NULL) {
|
||
if (strcmp(v, searchvalue) == 0) {
|
||
result = 1;
|
||
break;
|
||
}
|
||
v = strtok(NULL, " ,;");
|
||
}
|
||
free(p_value);
|
||
return result;
|
||
}
|
||
|
||
static const char *g_basedir;
|
||
const char *basepath(void)
|
||
{
|
||
if (g_basedir)
|
||
return g_basedir;
|
||
return ".";
|
||
}
|
||
|
||
void set_basepath(const char *path)
|
||
{
|
||
g_basedir = path;
|
||
}
|
||
|
||
#ifdef WIN32
|
||
#define PATH_DELIM '\\'
|
||
#else
|
||
#define PATH_DELIM '/'
|
||
#endif
|
||
|
||
char * join_path(const char *p1, const char *p2, char *dst, size_t len) {
|
||
size_t sz;
|
||
assert(p1 && p2);
|
||
assert(p2 != dst);
|
||
if (dst == p1) {
|
||
sz = strlen(p1);
|
||
}
|
||
else {
|
||
sz = strlcpy(dst, p1, len);
|
||
}
|
||
assert(sz < len);
|
||
dst[sz++] = PATH_DELIM;
|
||
strlcpy(dst + sz, p2, len - sz);
|
||
return dst;
|
||
}
|
||
|
||
static const char * relpath(char *buf, size_t sz, const char *path) {
|
||
if (g_basedir) {
|
||
join_path(g_basedir, path, buf, sz);
|
||
}
|
||
else {
|
||
strlcpy(buf, path, sz);
|
||
}
|
||
return buf;
|
||
}
|
||
|
||
static const char *g_datadir;
|
||
const char *datapath(void)
|
||
{
|
||
static char zText[4096];
|
||
if (g_datadir)
|
||
return g_datadir;
|
||
return relpath(zText, sizeof(zText), "data");
|
||
}
|
||
|
||
void set_datapath(const char *path)
|
||
{
|
||
g_datadir = path;
|
||
}
|
||
|
||
static const char *g_reportdir;
|
||
const char *reportpath(void)
|
||
{
|
||
static char zText[4096];
|
||
if (g_reportdir)
|
||
return g_reportdir;
|
||
return relpath(zText, sizeof(zText), "reports");
|
||
}
|
||
|
||
void set_reportpath(const char *path)
|
||
{
|
||
g_reportdir = path;
|
||
}
|
||
|
||
int create_directories(void) {
|
||
int err;
|
||
err = mkdir(datapath(), 0777);
|
||
if (err) {
|
||
if (errno == EEXIST) errno = 0;
|
||
else return err;
|
||
}
|
||
err = mkdir(reportpath(), 0777);
|
||
if (err && errno == EEXIST) {
|
||
errno = 0;
|
||
}
|
||
return err;
|
||
}
|
||
|
||
double get_param_flt(const struct param *p, const char *key, double def)
|
||
{
|
||
const char *str = p ? get_param(p, key) : NULL;
|
||
return str ? atof(str) : def;
|
||
}
|
||
|
||
void kernel_done(void)
|
||
{
|
||
/* calling this function releases memory assigned to static variables, etc.
|
||
* calling it is optional, e.g. a release server will most likely not do it.
|
||
*/
|
||
#ifdef USE_LIBXML2
|
||
xml_done();
|
||
#endif
|
||
attrib_done();
|
||
item_done();
|
||
message_done();
|
||
equipment_done();
|
||
reports_done();
|
||
curses_done();
|
||
crmessage_done();
|
||
translation_done();
|
||
}
|
||
|
||
bool rule_stealth_other(void)
|
||
{
|
||
static int rule, config;
|
||
if (config_changed(&config)) {
|
||
rule = config_get_int("stealth.faction.other", 1);
|
||
}
|
||
return rule != 0;
|
||
}
|
||
|
||
bool rule_stealth_anon(void)
|
||
{
|
||
static int rule, config;
|
||
if (config_changed(&config)) {
|
||
rule = config_get_int("stealth.faction.anon", 1);
|
||
}
|
||
return rule != 0;
|
||
}
|
||
|
||
bool rule_region_owners(void)
|
||
{
|
||
static int rule, config;
|
||
if (config_changed(&config)) {
|
||
rule = config_get_int("rules.region_owners", 0);
|
||
}
|
||
return rule != 0;
|
||
}
|
||
|
||
int rule_blessed_harvest(void)
|
||
{
|
||
static int rule, config;
|
||
if (config_changed(&config)) {
|
||
rule = config_get_int("rules.blessed_harvest.flags", HARVEST_WORK);
|
||
assert(rule >= 0);
|
||
}
|
||
return rule;
|
||
}
|
||
|
||
int rule_alliance_limit(void)
|
||
{
|
||
static int cache_token;
|
||
static int rule = 0;
|
||
|
||
if (config_changed(&cache_token)) {
|
||
rule = config_get_int("rules.limit.alliance", 0);
|
||
}
|
||
assert(rule >= 0);
|
||
return rule;
|
||
}
|
||
|
||
int rule_faction_limit(void)
|
||
{
|
||
static int cache_token;
|
||
static int rule = 0;
|
||
if (config_changed(&cache_token)) {
|
||
rule = config_get_int("rules.limit.faction", 0);
|
||
}
|
||
assert(rule >= 0);
|
||
return rule;
|
||
}
|
||
|
||
void kernel_init(void)
|
||
{
|
||
register_reports();
|
||
mt_clear();
|
||
translation_init();
|
||
}
|
||
|
||
static order * defaults[MAXLOCALES];
|
||
|
||
order *default_order(const struct locale *lang)
|
||
{
|
||
int i = locale_index(lang);
|
||
order *result = 0;
|
||
assert(i < MAXLOCALES);
|
||
|
||
result = defaults[i];
|
||
if (!result) {
|
||
const char * str;
|
||
keyword_t kwd = NOKEYWORD;
|
||
str = config_get("orders.default");
|
||
if (str) {
|
||
kwd = findkeyword(str);
|
||
}
|
||
if (kwd != NOKEYWORD) {
|
||
result = create_order(kwd, lang, NULL);
|
||
defaults[i] = result;
|
||
}
|
||
}
|
||
return result ? copy_order(result) : 0;
|
||
}
|
||
|
||
int rule_give(void)
|
||
{
|
||
static int config;
|
||
static int rule;
|
||
if (config_changed(&config)) {
|
||
rule = config_get_int("rules.give.flags", GIVE_DEFAULT);
|
||
}
|
||
return rule;
|
||
}
|
||
|
||
static struct param *configuration;
|
||
static int config_cache_key = 1;
|
||
|
||
bool config_changed(int *cache_key) {
|
||
assert(cache_key);
|
||
if (config_cache_key != *cache_key) {
|
||
*cache_key = config_cache_key;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
#define MAXKEYS 16
|
||
void config_set_from(const dictionary *d, const char *valid_keys[])
|
||
{
|
||
int s, nsec = iniparser_getnsec(d);
|
||
for (s=0;s!=nsec;++s) {
|
||
char key[128];
|
||
const char *sec = iniparser_getsecname(d, s);
|
||
int k, nkeys = iniparser_getsecnkeys(d, sec);
|
||
const char *keys[MAXKEYS];
|
||
size_t slen = strlen(sec);
|
||
|
||
assert(nkeys <= MAXKEYS);
|
||
assert(slen<sizeof(key));
|
||
memcpy(key, sec, slen);
|
||
key[slen] = '.';
|
||
iniparser_getseckeys(d, sec, keys);
|
||
for (k=0;k!=nkeys;++k) {
|
||
const char *val, *orig;
|
||
size_t klen = strlen(keys[k]);
|
||
assert(klen+slen+1<sizeof(key));
|
||
memcpy(key+slen+1, keys[k]+slen+1, klen-slen);
|
||
orig = config_get(key);
|
||
val = iniparser_getstring(d, keys[k], NULL);
|
||
if (!orig) {
|
||
if (val) {
|
||
if (valid_keys) {
|
||
int i;
|
||
for (i = 0; valid_keys[i]; ++i) {
|
||
size_t vlen = strlen(valid_keys[i]);
|
||
if (strncmp(key, valid_keys[i], vlen) == 0) break;
|
||
}
|
||
if (!valid_keys[i]) {
|
||
log_error("unknown key in ini-section %s: %s = %s", sec, key+slen+1, val);
|
||
}
|
||
}
|
||
config_set(key, val);
|
||
}
|
||
} else {
|
||
log_debug("not overwriting %s=%s with %s", key, orig, val);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void config_set(const char *key, const char *value) {
|
||
++config_cache_key;
|
||
set_param(&configuration, key, value);
|
||
}
|
||
|
||
const char *config_get(const char *key) {
|
||
return get_param(configuration, key);
|
||
}
|
||
|
||
int config_get_int(const char *key, int def) {
|
||
return get_param_int(configuration, key, def);
|
||
}
|
||
|
||
double config_get_flt(const char *key, double def) {
|
||
return get_param_flt(configuration, key, def);
|
||
}
|
||
|
||
bool config_token(const char *key, const char *tok) {
|
||
return !!check_param(configuration, key, tok);
|
||
}
|
||
|
||
void free_config(void) {
|
||
global.functions.wage = NULL;
|
||
free_params(&configuration);
|
||
++config_cache_key;
|
||
}
|
||
|
||
/** releases all memory associated with the game state.
|
||
* call this function before calling read_game() to load a new game
|
||
* if you have a previously loaded state in memory.
|
||
*/
|
||
void free_gamedata(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i != MAXLOCALES; ++i) {
|
||
if (defaults[i]) {
|
||
free_order(defaults[i]);
|
||
defaults[i] = 0;
|
||
}
|
||
}
|
||
free(forbidden_ids);
|
||
forbidden_ids = NULL;
|
||
|
||
free_donations();
|
||
free_factions();
|
||
free_units();
|
||
free_regions();
|
||
free_borders();
|
||
free_alliances();
|
||
|
||
while (global.attribs) {
|
||
a_remove(&global.attribs, global.attribs);
|
||
}
|
||
|
||
while (planes) {
|
||
plane *pl = planes;
|
||
planes = planes->next;
|
||
free_plane(pl);
|
||
}
|
||
}
|
||
|
||
const char * game_name(void)
|
||
{
|
||
const char * param = config_get("game.name");
|
||
return param ? param : "Eressea";
|
||
}
|
||
|
||
const char * game_mailcmd(void)
|
||
{
|
||
const char *param = config_get("game.mailcmd");
|
||
if (!param) {
|
||
static char result[32]; /* FIXME: static result */
|
||
char *r = result;
|
||
const char *c;
|
||
param = game_name();
|
||
for (c = param; *c && (result + sizeof(result)) > r; ++c) {
|
||
*r++ = (char)toupper(*c);
|
||
}
|
||
*r = '\0';
|
||
log_warning("game.mailcmd configuration is not set, using %s from game.name", result);
|
||
return result;
|
||
}
|
||
return param;
|
||
}
|
||
|
||
int game_id(void) {
|
||
return config_get_int("game.id", 0);
|
||
}
|