server/src/kernel/config.c

1639 lines
38 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/*
2015-01-30 22:10:29 +01:00
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
2010-08-08 10:06:34 +02:00
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>
/* attributes includes */
#include <attributes/reduceproduction.h>
/* kernel includes */
#include "alliance.h"
#include "ally.h"
2010-08-08 10:06:34 +02:00
#include "alchemy.h"
#include "curse.h"
2010-08-08 10:06:34 +02:00
#include "connection.h"
#include "building.h"
#include "calendar.h"
#include "direction.h"
2010-08-08 10:06:34 +02:00
#include "faction.h"
#include "group.h"
#include "item.h"
#include "keyword.h"
#include "messages.h"
2010-08-08 10:06:34 +02:00
#include "move.h"
#include "objtypes.h"
#include "order.h"
#include "plane.h"
#include "pool.h"
#include "race.h"
#include "reports.h"
2010-08-08 10:06:34 +02:00
#include "region.h"
#include "save.h"
#include "ship.h"
#include "skill.h"
#include "terrain.h"
#include "types.h"
2010-08-08 10:06:34 +02:00
#include "unit.h"
#include <kernel/spell.h>
#include <kernel/spellbook.h>
2010-08-08 10:06:34 +02:00
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
2010-08-08 10:06:34 +02:00
#include <util/crmessage.h>
#include <util/event.h>
#include <util/language.h>
#include <util/functions.h>
2010-08-08 10:06:34 +02:00
#include <util/log.h>
#include <util/lists.h>
#include <util/parser.h>
#include <quicklist.h>
2010-08-08 10:06:34 +02:00
#include <util/rand.h>
#include <util/rng.h>
#include <util/translation.h>
#include <util/unicode.h>
2010-08-08 10:06:34 +02:00
#include <util/umlaut.h>
#include <util/xml.h>
#include "donations.h"
#include "guard.h"
#include "prefix.h"
#ifdef USE_LIBXML2
2010-08-08 10:06:34 +02:00
/* libxml includes */
#include <libxml/tree.h>
#include <libxml/xpath.h>
#endif
2010-08-08 10:06:34 +02:00
/* external libraries */
#include <storage.h>
#include <iniparser.h>
#include <critbit.h>
2010-08-08 10:06:34 +02:00
/* libc includes */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <math.h>
#include <limits.h>
#include <time.h>
#include <errno.h>
struct settings global = {
"Eressea", /* gamename */
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
bool lomem = false;
2011-03-07 08:02:35 +01:00
FILE *logfile;
bool battledebug = false;
2014-04-25 07:47:23 +02:00
int turn = -1;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
int NewbieImmunity(void)
{
return config_get_int("NewbieImmunity", 0);
2010-08-08 10:06:34 +02:00
}
bool IsImmune(const faction * f)
2010-08-08 10:06:34 +02:00
{
return !fval(f, FFL_NPC) && f->age < NewbieImmunity();
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int ally_flag(const char *s, int help_mask)
{
if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0)
return HELP_MONEY;
if ((help_mask & HELP_FIGHT) && strcmp(s, "fight") == 0)
return HELP_FIGHT;
if ((help_mask & HELP_GIVE) && strcmp(s, "give") == 0)
return HELP_GIVE;
if ((help_mask & HELP_GUARD) && strcmp(s, "guard") == 0)
return HELP_GUARD;
if ((help_mask & HELP_FSTEALTH) && strcmp(s, "stealth") == 0)
return HELP_FSTEALTH;
if ((help_mask & HELP_TRAVEL) && strcmp(s, "travel") == 0)
return HELP_TRAVEL;
return 0;
2010-08-08 10:06:34 +02:00
}
bool ExpensiveMigrants(void)
2010-08-08 10:06:34 +02:00
{
return config_get_int("study.expensivemigrants", 0) != 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/** Specifies automatic alliance modes.
* If this returns a value then the bits set are immutable between alliance
* partners (faction::alliance) and cannot be changed with the HELP command.
*/
2011-03-07 08:02:35 +01:00
int AllianceAuto(void)
2010-08-08 10:06:34 +02:00
{
int value;
const char *str = config_get("alliance.auto");
value = 0;
if (str != NULL) {
char *sstr = _strdup(str);
char *tok = strtok(sstr, " ");
while (tok) {
value |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
return value & HelpMask();
2010-08-08 10:06:34 +02:00
}
/** Limits the available help modes
* The bitfield returned by this function specifies the available help modes
* in this game (so you can, for example, disable HELP GIVE globally).
* Disabling a status will disable the command sequence entirely (order parsing
* uses this function).
*/
2011-03-07 08:02:35 +01:00
int HelpMask(void)
2010-08-08 10:06:34 +02:00
{
const char *str = config_get("rules.help.mask");
int rule = 0;
if (str != NULL) {
char *sstr = _strdup(str);
char *tok = strtok(sstr, " ");
while (tok) {
rule |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
else {
rule = HELP_ALL;
}
return rule;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int AllianceRestricted(void)
2010-08-08 10:06:34 +02:00
{
const char *str = config_get("alliance.restricted");
int rule = 0;
if (str != NULL) {
char *sstr = _strdup(str);
char *tok = strtok(sstr, " ");
while (tok) {
rule |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
rule &= HelpMask();
return rule;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int LongHunger(const struct unit *u)
{
if (u != NULL) {
if (!fval(u, UFL_HUNGER))
return false;
if (u_race(u) == get_race(RC_DAEMON))
return false;
}
return config_get_int("hunger.long", 0);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int SkillCap(skill_t sk)
{
if (sk == SK_MAGIC) return 0; /* no caps on magic */
return config_get_int("skill.maxlevel", 0);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int NMRTimeout(void)
{
return config_get_int("nmr.timeout", 0);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
race_t old_race(const struct race * rc)
2010-08-08 10:06:34 +02:00
{
race_t i;
for (i = 0; i != MAXRACES; ++i) {
if (get_race(i) == rc) return i;
}
return NORACE;
2010-08-08 10:06:34 +02:00
}
helpmode helpmodes[] = {
{ "all", HELP_ALL }
,
{ "money", HELP_MONEY }
,
{ "fight", HELP_FIGHT }
,
{ "observe", HELP_OBSERVE }
,
{ "give", HELP_GIVE }
,
{ "guard", HELP_GUARD }
,
{ "stealth", HELP_FSTEALTH }
,
{ "travel", HELP_TRAVEL }
,
{ NULL, 0 }
2010-08-08 10:06:34 +02:00
};
/** Returns the English name of the race, which is what the database uses.
*/
2011-03-07 08:02:35 +01:00
const char *dbrace(const struct race *rc)
2010-08-08 10:06:34 +02:00
{
static char zText[32]; // FIXME: static return value
char *zPtr = zText;
2010-08-08 10:06:34 +02:00
/* the english names are all in ASCII, so we don't need to worry about UTF8 */
strlcpy(zText, (const char *)LOC(get_locale("en"), rc_name_s(rc, NAME_SINGULAR)), sizeof(zText));
while (*zPtr) {
*zPtr = (char)(toupper(*zPtr));
++zPtr;
}
return zText;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
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"
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
const char *report_options[MAX_MSG] = {
"Kampf",
"Ereignisse",
"Bewegung",
"Einkommen",
"Handel",
"Produktion",
"Orkvermehrung",
"Zauber",
"",
""
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
const char *message_levels[ML_MAX] = {
"Wichtig",
"Debug",
"Fehler",
"Warnungen",
"Infos"
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
const char *options[MAXOPTIONS] = {
"AUSWERTUNG",
"COMPUTER",
"ZUGVORLAGE",
NULL,
"STATISTIK",
"DEBUG",
"ZIPPED",
"ZEITUNG", /* Option hat Sonderbehandlung! */
NULL,
"ADRESSEN",
"BZIP2",
"PUNKTE",
"SHOWSKCHANGE"
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
static void init_maxmagicians(struct attrib *a)
2010-08-08 10:06:34 +02:00
{
a->data.i = MAXMAGICIANS;
2010-08-08 10:06:34 +02:00
}
static attrib_type at_maxmagicians = {
"maxmagicians",
init_maxmagicians,
NULL,
NULL,
a_writeint,
a_readint,
ATF_UNIQUE
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
int max_magicians(const faction * f)
2010-08-08 10:06:34 +02:00
{
int m = config_get_int("rules.maxskills.magic", MAXMAGICIANS);
attrib *a;
2011-03-07 08:02:35 +01:00
if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) {
m = a->data.i;
}
if (f->race == get_race(RC_ELF))
++m;
return m;
2010-08-08 10:06:34 +02:00
}
static void init_npcfaction(struct attrib *a)
2010-08-08 10:06:34 +02:00
{
a->data.i = 1;
2010-08-08 10:06:34 +02:00
}
static attrib_type at_npcfaction = {
"npcfaction",
init_npcfaction,
NULL,
NULL,
a_writeint,
a_readint,
ATF_UNIQUE
};
2010-08-08 10:06:34 +02:00
FILE *debug;
/* ----------------------------------------------------------------------- */
2011-03-07 08:02:35 +01:00
int distribute(int old, int new_value, int n)
2010-08-08 10:06:34 +02:00
{
int i;
int t;
assert(new_value <= old);
2010-08-08 10:06:34 +02:00
if (old == 0)
return 0;
2010-08-08 10:06:34 +02:00
t = (n / old) * new_value;
for (i = (n % old); i; i--)
if (rng_int() % old < new_value)
t++;
2010-08-08 10:06:34 +02:00
return t;
2010-08-08 10:06:34 +02:00
}
bool unit_has_cursed_item(const unit * u)
2010-08-08 10:06:34 +02:00
{
item *itm = u->items;
while (itm) {
if (fval(itm->type, ITF_CURSED) && itm->number > 0)
return true;
itm = itm->next;
}
return false;
2010-08-08 10:06:34 +02:00
}
static int
autoalliance(const plane * pl, const faction * sf, const faction * f2)
{
if (pl && (pl->flags & PFL_FRIENDLY))
2011-03-07 08:02:35 +01:00
return HELP_ALL;
2010-08-08 10:06:34 +02:00
if (f_get_alliance(sf) != NULL && AllianceAuto()) {
if (sf->alliance == f2->alliance)
return AllianceAuto();
}
2010-08-08 10:06:34 +02:00
return 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int ally_mode(const ally * sf, int mode)
2010-08-08 10:06:34 +02:00
{
if (sf == NULL)
return 0;
return sf->status & mode;
2010-08-08 10:06:34 +02:00
}
int
2011-03-07 08:02:35 +01:00
alliedgroup(const struct plane *pl, const struct faction *f,
const struct faction *f2, const struct ally *sf, int mode)
2010-08-08 10:06:34 +02:00
{
while (sf && sf->faction != f2)
sf = sf->next;
if (sf == NULL) {
mode = mode & autoalliance(pl, f, f2);
2010-08-08 10:06:34 +02:00
}
mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2));
if (AllianceRestricted()) {
if (a_findc(f->attribs, &at_npcfaction)) {
return mode;
}
if (a_findc(f2->attribs, &at_npcfaction)) {
return mode;
}
if (f->alliance != f2->alliance) {
mode &= ~AllianceRestricted();
}
2010-08-08 10:06:34 +02:00
}
return mode;
2010-08-08 10:06:34 +02:00
}
int
2011-03-07 08:02:35 +01:00
alliedfaction(const struct plane *pl, const struct faction *f,
const struct faction *f2, int mode)
2010-08-08 10:06:34 +02:00
{
return alliedgroup(pl, f, f2, f->allies, mode);
2010-08-08 10:06:34 +02:00
}
/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */
2011-03-07 08:02:35 +01:00
int alliedunit(const unit * u, const faction * f2, int mode)
2010-08-08 10:06:34 +02:00
{
ally *sf;
int automode;
assert(u);
assert(f2);
assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */
if (u->faction == f2)
return mode;
if (u->faction != NULL && f2 != NULL) {
plane *pl;
if (mode & HELP_FIGHT) {
if ((u->flags & UFL_DEFENDER) || (u->faction->flags & FFL_DEFENDER)) {
faction *owner = region_get_owner(u->region);
/* helps the owner of the region */
if (owner == f2) {
return HELP_FIGHT;
}
}
2010-08-08 10:06:34 +02:00
}
pl = rplane(u->region);
automode = mode & autoalliance(pl, u->faction, f2);
2010-08-08 10:06:34 +02:00
if (pl != NULL && (pl->flags & PFL_NOALLIANCES))
mode = (mode & automode) | (mode & HELP_GIVE);
2010-08-08 10:06:34 +02:00
sf = u->faction->allies;
if (fval(u, UFL_GROUP)) {
const attrib *a = a_findc(u->attribs, &at_group);
if (a != NULL)
sf = ((group *)a->data.v)->allies;
}
return alliedgroup(pl, u->faction, f2, sf, mode);
2010-08-08 10:06:34 +02:00
}
return 0;
2010-08-08 10:06:34 +02:00
}
int count_faction(const faction * f, int flags)
2010-08-08 10:06:34 +02:00
{
unit *u;
int n = 0;
for (u = f->units; u; u = u->nextF) {
const race *rc = u_race(u);
int x = (flags&COUNT_UNITS) ? 1 : u->number;
if (f->race != rc) {
if (!playerrace(rc)) {
if (flags&COUNT_MONSTERS) {
n += x;
}
}
else if (flags&COUNT_MIGRANTS) {
if (!is_cursed(u->attribs, C_SLAVE, 0)) {
n += x;
}
}
}
else if (flags&COUNT_DEFAULT) {
n += x;
}
}
return n;
}
int count_units(const faction * f)
{
return count_faction(f, COUNT_ALL | COUNT_UNITS);
}
int count_all(const faction * f)
{
return count_faction(f, COUNT_ALL);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int count_migrants(const faction * f)
2010-08-08 10:06:34 +02:00
{
return count_faction(f, COUNT_MIGRANTS);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int count_maxmigrants(const faction * f)
2010-08-08 10:06:34 +02:00
{
static int migrants = -1;
2010-08-08 10:06:34 +02:00
if (migrants < 0) {
migrants = config_get_int("rules.migrants.max", INT_MAX);
}
if (migrants == INT_MAX) {
int x = 0;
if (f->race == get_race(RC_HUMAN)) {
int nsize = count_all(f);
if (nsize > 0) {
x = (int)(log10(nsize / 50.0) * 20);
if (x < 0)
x = 0;
}
}
return x;
2010-08-08 10:06:34 +02:00
}
return migrants;
2010-08-08 10:06:34 +02:00
}
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;
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
const struct race *findrace(const char *s, const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
void **tokens = get_translations(lang, UT_RACES);
variant token;
2010-08-08 10:06:34 +02:00
assert(lang);
if (tokens && findtoken(*tokens, s, &token) == E_TOK_SUCCESS) {
return (const struct race *)token.v;
}
return NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int findoption(const char *s, const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
void **tokens = get_translations(lang, UT_OPTIONS);
variant token;
2010-08-08 10:06:34 +02:00
if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) {
return (direction_t)token.i;
}
return NODIRECTION;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
param_t findparam(const char *s, const struct locale * lang)
2010-08-08 10:06:34 +02:00
{
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_error("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_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;
2010-08-08 10:06:34 +02:00
}
2012-06-24 08:04:12 +02:00
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;
}
2011-03-07 08:02:35 +01:00
param_t getparam(const struct locale * lang)
2010-08-08 10:06:34 +02:00
{
char token[64];
const char *s = gettoken(token, sizeof(token));
return s ? findparam(s, lang) : NOPARAM;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
faction *getfaction(void)
2010-08-08 10:06:34 +02:00
{
return findfaction(getid());
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
unit *getnewunit(const region * r, const faction * f)
2010-08-08 10:06:34 +02:00
{
int n;
n = getid();
2010-08-08 10:06:34 +02:00
return findnewunit(r, f, n);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int read_newunitid(const faction * f, const region * r)
2010-08-08 10:06:34 +02:00
{
int n;
unit *u2;
n = getid();
if (n == 0)
return -1;
2010-08-08 10:06:34 +02:00
u2 = findnewunit(r, f, n);
if (u2)
return u2->no;
2010-08-08 10:06:34 +02:00
return -1;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int read_unitid(const faction * f, const region * r)
2010-08-08 10:06:34 +02:00
{
char token[16];
const char *s = gettoken(token, sizeof(token));
2010-08-08 10:06:34 +02:00
/* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der
* paramliste. machen wir das nicht, dann wird getnewunit in s nach der
* nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */
2010-08-08 10:06:34 +02:00
if (!s || *s == 0 || !isalnum(*s)) {
return -1;
}
if (isparam(s, f->locale, P_TEMP)) {
return read_newunitid(f, r);
}
return atoi36((const char *)s);
2010-08-08 10:06:34 +02:00
}
int getunit(const region * r, const faction * f, unit **uresult)
2010-08-08 10:06:34 +02:00
{
unit *u2 = NULL;
int n = read_unitid(f, r);
int result = GET_NOTFOUND;
2010-08-08 10:06:34 +02:00
if (n == 0) {
result = GET_PEASANTS;
}
else if (n > 0) {
u2 = findunit(n);
if (u2 != NULL && u2->region == r) {
/* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition
* here, but it got removed because of a bug that made units disappear:
* http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172
*/
result = GET_UNIT;
}
else {
u2 = NULL;
}
}
if (uresult) {
*uresult = u2;
}
return result;
2010-08-08 10:06:34 +02:00
}
/* - Namen der Strukturen -------------------------------------- */
char *untilde(char *ibuf)
2010-08-08 10:06:34 +02:00
{
char *p = ibuf;
2010-08-08 10:06:34 +02:00
while (*p) {
if (*p == '~') {
*p = ' ';
}
++p;
2010-08-08 10:06:34 +02:00
}
return ibuf;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
building *largestbuilding(const region * r, cmp_building_cb cmp_gt,
bool imaginary)
2010-08-08 10:06:34 +02:00
{
building *b, *best = NULL;
2010-08-08 10:06:34 +02:00
for (b = rbuildings(r); b; b = b->next) {
if (cmp_gt(b, best) <= 0)
continue;
if (!imaginary) {
const attrib *a = a_find(b->attribs, &at_icastle);
if (a)
continue;
}
best = b;
2010-08-08 10:06:34 +02:00
}
return best;
2010-08-08 10:06:34 +02:00
}
/* -- Erschaffung neuer Einheiten ------------------------------ */
2011-03-07 08:02:35 +01:00
extern faction *dfindhash(int i);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static const char *forbidden[] = { "t", "te", "tem", "temp", NULL };
// PEASANT: "b", "ba", "bau", "baue", "p", "pe", "pea", "peas"
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
int forbiddenid(int id)
2010-08-08 10:06:34 +02:00
{
static int *forbid = NULL;
static size_t len;
size_t i;
if (id <= 0)
return 1;
if (!forbid) {
while (forbidden[len])
++len;
forbid = calloc(len, sizeof(int));
for (i = 0; i != len; ++i) {
forbid[i] = atoi36(forbidden[i]);
}
}
for (i = 0; i != len; ++i)
if (id == forbid[i])
return 1;
return 0;
2010-08-08 10:06:34 +02:00
}
/* ID's f<>r Einheiten und Zauber */
2011-03-07 08:02:35 +01:00
int newunitid(void)
2010-08-08 10:06:34 +02:00
{
int random_unit_no;
int start_random_no;
random_unit_no = 1 + (rng_int() % MAX_UNIT_NR);
start_random_no = random_unit_no;
while (ufindhash(random_unit_no) || dfindhash(random_unit_no)
|| cfindhash(random_unit_no)
|| forbiddenid(random_unit_no)) {
random_unit_no++;
if (random_unit_no == MAX_UNIT_NR + 1) {
random_unit_no = 1;
}
if (random_unit_no == start_random_no) {
random_unit_no = (int)MAX_UNIT_NR + 1;
}
2010-08-08 10:06:34 +02:00
}
return random_unit_no;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int newcontainerid(void)
2010-08-08 10:06:34 +02:00
{
int random_no;
int start_random_no;
2010-08-08 10:06:34 +02:00
random_no = 1 + (rng_int() % MAX_CONTAINER_NR);
start_random_no = random_no;
2010-08-08 10:06:34 +02:00
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;
}
2010-08-08 10:06:34 +02:00
}
return random_no;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int maxworkingpeasants(const struct region *r)
2010-08-08 10:06:34 +02:00
{
int size = production(r);
int treespace = (rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE;
return _max(size - treespace, _min(size / 10, 200));
2010-08-08 10:06:34 +02:00
}
static const char * parameter_key(int i)
{
assert(i < MAXPARAMS && i >= 0);
return parameters[i];
}
2015-08-05 12:19:17 +02:00
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(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(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)
2010-08-08 10:06:34 +02:00
{
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";
}
2010-08-08 10:06:34 +02:00
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(tokens, name, var);
}
else {
log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang));
}
tok = strtok(NULL, " ");
}
free(sstr);
2010-08-08 10:06:34 +02:00
}
init_directions(lang);
init_keywords(lang);
init_skills(lang);
2010-08-08 10:06:34 +02:00
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(tokens, name, var);
name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
if (name) addtoken(tokens, name, var);
}
2010-08-08 10:06:34 +02:00
2015-08-05 12:19:17 +02:00
init_parameters(lang);
2010-08-08 10:06:34 +02:00
init_options_translation(lang);
init_terrains_translation(lang);
2010-08-08 10:06:34 +02:00
}
typedef struct param {
critbit_tree cb;
2010-08-08 10:06:34 +02:00
} 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);
++global.cookie;
}
}
if (value) {
char data[512];
size_t sz = pack_keyval(key, value, data, sizeof(data));
if (cb_insert(&par->cb, data, sz) == CB_SUCCESS) {
++global.cookie;
}
}
}
2015-09-05 18:14:28 +02:00
void free_params(struct param **pp) {
param *p = *pp;
if (p) {
cb_clear(&p->cb);
2015-09-05 18:14:28 +02:00
free(p);
}
*pp = 0;
2015-09-05 18:14:28 +02:00
}
2011-03-07 08:02:35 +01:00
const char *get_param(const struct param *p, const char *key)
2010-08-08 10:06:34 +02:00
{
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;
2014-06-25 16:22:39 +02:00
}
return NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int get_param_int(const struct param *p, const char *key, int def)
2010-08-08 10:06:34 +02:00
{
2014-06-25 16:22:39 +02:00
const char * str = get_param(p, key);
return str ? atoi(str) : def;
2010-08-08 10:06:34 +02:00
}
int check_param(const struct param *p, const char *key, const char *searchvalue)
{
2014-12-31 01:00:10 +01:00
int result = 0;
const char *value = get_param(p, key);
if (!value) {
return 0;
}
2014-12-31 01:00:10 +01:00
char *p_value = _strdup(value);
const char *delimiter = " ,;";
char *v = strtok(p_value, delimiter);
while (v != NULL) {
2014-12-31 01:00:10 +01:00
if (strcmp(v, searchvalue) == 0) {
result = 1;
break;
}
v = strtok(NULL, delimiter);
}
2014-12-31 01:00:10 +01:00
free(p_value);
return result;
}
const char * relpath(char *buf, size_t sz, const char *path) {
strlcpy(buf, basepath(), sz);
strlcat(buf, path, sz);
return buf;
}
2011-03-07 08:02:35 +01:00
static const char *g_datadir;
const char *datapath(void)
2010-08-08 10:06:34 +02:00
{
static char zText[MAX_PATH]; // FIXME: static return value
if (g_datadir)
return g_datadir;
return relpath(zText, sizeof(zText), "/data");
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void set_datapath(const char *path)
2010-08-08 10:06:34 +02:00
{
g_datadir = path;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static const char *g_reportdir;
const char *reportpath(void)
2010-08-08 10:06:34 +02:00
{
static char zText[MAX_PATH]; // FIXME: static return value
if (g_reportdir)
return g_reportdir;
return relpath(zText, sizeof(zText), "/reports");
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void set_reportpath(const char *path)
2010-08-08 10:06:34 +02:00
{
g_reportdir = path;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static const char *g_basedir;
const char *basepath(void)
2010-08-08 10:06:34 +02:00
{
if (g_basedir)
return g_basedir;
return ".";
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void set_basepath(const char *path)
2010-08-08 10:06:34 +02:00
{
g_basedir = path;
2010-08-08 10:06:34 +02:00
}
double get_param_flt(const struct param *p, const char *key, double def)
2010-08-08 10:06:34 +02:00
{
const char *str = get_param(p, key);
return str ? atof(str) : def;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void kernel_done(void)
2010-08-08 10:06:34 +02:00
{
/* 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.
*/
translation_done();
free_attribs();
2010-08-08 10:06:34 +02:00
}
attrib_type at_germs = {
"germs",
DEFAULT_INIT,
DEFAULT_FINALIZE,
DEFAULT_AGE,
a_writeshorts,
a_readshorts,
ATF_UNIQUE
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
void setstatus(struct unit *u, int status)
2010-08-08 10:06:34 +02:00
{
assert(status >= ST_AGGRO && status <= ST_FLEE);
if (u->status != status) {
u->status = (status_t)status;
}
2010-08-08 10:06:34 +02:00
}
#ifndef HAVE_STRDUP
char *_strdup(const char *s)
2010-08-08 10:06:34 +02:00
{
return strcpy((char *)malloc(sizeof(char) * (strlen(s) + 1)), s);
2010-08-08 10:06:34 +02:00
}
#endif
bool faction_id_is_unused(int id)
2010-08-08 10:06:34 +02:00
{
return findfaction(id) == NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int besieged(const unit * u)
2010-08-08 10:06:34 +02:00
{
/* belagert kann man in schiffen und burgen werden */
return (u && !keyword_disabled(K_BESIEGE)
&& u->building && u->building->besieged
&& u->building->besieged >= u->building->size * SIEGEFACTOR);
2010-08-08 10:06:34 +02:00
}
bool has_horses(const struct unit * u)
2010-08-08 10:06:34 +02:00
{
item *itm = u->items;
for (; itm; itm = itm->next) {
if (itm->type->flags & ITF_ANIMAL)
return true;
}
return false;
2010-08-08 10:06:34 +02:00
}
/* Lohn bei den einzelnen Burgstufen f<>r Normale Typen, Orks, Bauern,
* Modifikation f<EFBFBD>r St<EFBFBD>dter. */
static const int wagetable[7][4] = {
{ 10, 10, 11, -7 }, /* Baustelle */
{ 10, 10, 11, -5 }, /* Handelsposten */
{ 11, 11, 12, -3 }, /* Befestigung */
{ 12, 11, 13, -1 }, /* Turm */
{ 13, 12, 14, 0 }, /* Burg */
{ 14, 12, 15, 1 }, /* Festung */
{ 15, 13, 16, 2 } /* Zitadelle */
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
int cmp_wage(const struct building *b, const building * a)
2010-08-08 10:06:34 +02:00
{
const struct building_type *bt_castle = bt_find("castle");
if (b->type == bt_castle) {
if (!a)
return 1;
if (b->size > a->size)
return 1;
if (b->size == a->size)
return 0;
}
return -1;
2010-08-08 10:06:34 +02:00
}
bool is_owner_building(const struct building * b)
2010-08-08 10:06:34 +02:00
{
region *r = b->region;
if (b->type->taxes && r->land && r->land->ownership) {
unit *u = building_owner(b);
return u && u->faction == r->land->ownership->owner;
}
return false;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int cmp_taxes(const building * b, const building * a)
2010-08-08 10:06:34 +02:00
{
faction *f = region_get_owner(b->region);
if (b->type->taxes) {
unit *u = building_owner(b);
if (!u) {
2011-03-07 08:02:35 +01:00
return -1;
2010-08-08 10:06:34 +02:00
}
else if (a) {
int newsize = buildingeffsize(b, false);
double newtaxes = b->type->taxes(b, newsize);
int oldsize = buildingeffsize(a, false);
double oldtaxes = a->type->taxes(a, oldsize);
if (newtaxes < oldtaxes)
return -1;
else if (newtaxes > oldtaxes)
return 1;
else if (b->size < a->size)
return -1;
else if (b->size > a->size)
return 1;
else {
if (u && u->faction == f) {
u = building_owner(a);
if (u && u->faction == f)
return -1;
return 1;
}
}
}
else {
return 1;
}
2010-08-08 10:06:34 +02:00
}
return -1;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int cmp_current_owner(const building * b, const building * a)
2010-08-08 10:06:34 +02:00
{
faction *f = region_get_owner(b->region);
2010-08-08 10:06:34 +02:00
assert(rule_region_owners());
if (f && b->type->taxes) {
unit *u = building_owner(b);
if (!u || u->faction != f)
return -1;
if (a) {
int newsize = buildingeffsize(b, false);
double newtaxes = b->type->taxes(b, newsize);
int oldsize = buildingeffsize(a, false);
double oldtaxes = a->type->taxes(a, oldsize);
if (newtaxes != oldtaxes)
return (newtaxes > oldtaxes) ? 1 : -1;
if (newsize != oldsize)
return newsize - oldsize;
return (b->size - a->size);
}
else {
return 1;
}
2010-08-08 10:06:34 +02:00
}
return -1;
2010-08-08 10:06:34 +02:00
}
bool rule_stealth_other(void)
2010-08-08 10:06:34 +02:00
{
int rule = config_get_int("stealth.faction.other", 1);
return rule != 0;
}
bool rule_stealth_anon(void)
{
int rule = config_get_int("stealth.faction.anon", 1);
return rule != 0;
2010-08-08 10:06:34 +02:00
}
bool rule_region_owners(void)
2010-08-08 10:06:34 +02:00
{
int rule = config_get_int("rules.region_owners", 0);
return rule != 0;
2010-08-08 10:06:34 +02:00
}
int rule_blessed_harvest(void)
{
int rule = config_get_int("rules.blessed_harvest.flags",
HARVEST_WORK);
assert(rule >= 0);
return rule;
2010-08-08 10:06:34 +02:00
}
int rule_alliance_limit(void)
{
int rule = config_get_int("rules.limit.alliance", 0);
assert(rule >= 0);
return rule;
2010-08-08 10:06:34 +02:00
}
int rule_faction_limit(void)
{
int rule = config_get_int("rules.limit.faction", 0);
assert(rule >= 0);
return rule;
2010-08-08 10:06:34 +02:00
}
static int
2011-03-07 08:02:35 +01:00
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
2010-08-08 10:06:34 +02:00
{
building *b = largestbuilding(r, &cmp_wage, false);
int esize = 0;
curse *c;
double wage;
attrib *a;
const building_type *artsculpture_type = bt_find("artsculpture");
static const curse_type *drought_ct, *blessedharvest_ct;
static bool init;
2010-08-08 10:06:34 +02:00
if (!init) {
init = true;
drought_ct = ct_find("drought");
blessedharvest_ct = ct_find("blessedharvest");
}
if (b != NULL) {
/* TODO: this reveals imaginary castles */
esize = buildingeffsize(b, false);
}
2010-08-08 10:06:34 +02:00
if (f != NULL) {
int index = 0;
if (rc == get_race(RC_ORC) || rc == get_race(RC_SNOTLING)) {
index = 1;
}
wage = wagetable[esize][index];
}
else {
if (is_mourning(r, in_turn)) {
wage = 10;
}
else if (fval(r->terrain, SEA_REGION)) {
wage = 11;
}
else if (fval(r, RF_ORCIFIED)) {
wage = wagetable[esize][1];
}
else {
wage = wagetable[esize][2];
}
if (rule_blessed_harvest() == HARVEST_WORK) {
/* E1 rules */
wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct));
}
}
/* Artsculpture: Income +5 */
for (b = r->buildings; b; b = b->next) {
if (b->type == artsculpture_type) {
wage += 5;
}
}
/* Godcurse: Income -10 */
if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) {
wage = _max(0, wage - 10);
}
/* Bei einer D<>rre verdient man nur noch ein Viertel */
if (drought_ct) {
c = get_curse(r->attribs, drought_ct);
if (curse_active(c))
wage /= curse_geteffect(c);
}
a = a_find(r->attribs, &at_reduceproduction);
if (a)
wage = (wage * a->data.sa[0]) / 100;
return (int)wage;
2010-08-08 10:06:34 +02:00
}
static int
2011-03-07 08:02:35 +01:00
minimum_wage(const region * r, const faction * f, const race * rc, int in_turn)
2010-08-08 10:06:34 +02:00
{
if (f && rc) {
return rc->maintenance;
}
return default_wage(r, f, rc, in_turn);
2010-08-08 10:06:34 +02:00
}
/* Gibt Arbeitslohn f<>r entsprechende Rasse zur<75>ck, oder f<>r
* die Bauern wenn f == NULL. */
2011-03-07 08:02:35 +01:00
int wage(const region * r, const faction * f, const race * rc, int in_turn)
2010-08-08 10:06:34 +02:00
{
if (global.functions.wage) {
return global.functions.wage(r, f, rc, in_turn);
}
return default_wage(r, f, rc, in_turn);
2010-08-08 10:06:34 +02:00
}
#define MAINTENANCE 10
2011-03-07 08:02:35 +01:00
int maintenance_cost(const struct unit *u)
2010-08-08 10:06:34 +02:00
{
if (u == NULL)
return MAINTENANCE;
if (global.functions.maintenance) {
int retval = global.functions.maintenance(u);
if (retval >= 0)
return retval;
}
return u_race(u)->maintenance * u->number;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int lovar(double xpct_x2)
2010-08-08 10:06:34 +02:00
{
int n = (int)(xpct_x2 * 500) + 1;
if (n == 0)
return 0;
return (rng_int() % n + rng_int() % n) / 1000;
2010-08-08 10:06:34 +02:00
}
bool has_limited_skills(const struct unit * u)
2010-08-08 10:06:34 +02:00
{
if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) ||
has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) ||
has_skill(u, SK_SPY)) {
return true;
}
else {
return false;
}
2010-08-08 10:06:34 +02:00
}
static int read_ext(attrib * a, void *owner, struct storage *store)
{
int len;
READ_INT(store, &len);
store->api->r_bin(store->handle, NULL, (size_t)len);
return AT_READ_OK;
}
2011-03-07 08:02:35 +01:00
void attrib_init(void)
2010-08-08 10:06:34 +02:00
{
/* Alle speicherbaren Attribute m<>ssen hier registriert werden */
at_register(&at_shiptrail);
at_register(&at_familiar);
at_register(&at_familiarmage);
at_register(&at_clone);
at_register(&at_clonemage);
at_register(&at_eventhandler);
at_register(&at_mage);
at_register(&at_countdown);
at_register(&at_curse);
2010-08-08 10:06:34 +02:00
at_register(&at_seenspell);
2010-08-08 10:06:34 +02:00
/* neue REGION-Attribute */
at_register(&at_moveblock);
at_register(&at_deathcount);
at_register(&at_woodcount);
2010-08-08 10:06:34 +02:00
/* neue UNIT-Attribute */
at_register(&at_siege);
at_register(&at_effect);
at_register(&at_private);
2010-08-08 10:06:34 +02:00
at_register(&at_icastle);
at_register(&at_guard);
at_register(&at_group);
2010-08-08 10:06:34 +02:00
at_register(&at_building_generic_type);
at_register(&at_maxmagicians);
at_register(&at_npcfaction);
2010-08-08 10:06:34 +02:00
/* connection-typen */
register_bordertype(&bt_noway);
register_bordertype(&bt_fogwall);
register_bordertype(&bt_wall);
register_bordertype(&bt_illusionwall);
register_bordertype(&bt_road);
2010-08-08 10:06:34 +02:00
register_function((pf_generic)minimum_wage, "minimum_wage");
2010-08-08 10:06:34 +02:00
at_register(&at_germs);
at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */
at_deprecate("lua", read_ext); /* required for old datafiles */
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void kernel_init(void)
2010-08-08 10:06:34 +02:00
{
register_reports();
mt_clear();
attrib_init();
translation_init();
2010-08-08 10:06:34 +02:00
}
static order * defaults[MAXLOCALES];
keyword_t default_keyword = NOKEYWORD;
void set_default_order(int kwd) {
default_keyword = (keyword_t)kwd;
}
// TODO: outside of tests, default_keyword is never used, why is this here?
// see also test_long_order_hungry
2011-03-07 08:02:35 +01:00
order *default_order(const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
static int usedefault = 1;
int i = locale_index(lang);
order *result = 0;
assert(i < MAXLOCALES);
if (default_keyword != NOKEYWORD) {
return create_order(default_keyword, lang, 0);
}
result = defaults[i];
if (!result && usedefault) {
const char * str = LOC(lang, "defaultorder");
if (str) {
result = defaults[i] = parse_order(str, lang);
}
else {
usedefault = 0;
}
}
return result ? copy_order(result) : 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int entertainmoney(const region * r)
2010-08-08 10:06:34 +02:00
{
double n;
2010-08-08 10:06:34 +02:00
if (is_cursed(r->attribs, C_DEPRESSION, 0)) {
return 0;
}
2010-08-08 10:06:34 +02:00
n = rmoney(r) / ENTERTAINFRACTION;
2010-08-08 10:06:34 +02:00
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
n *= get_curseeffect(r->attribs, C_GENEROUS, 0);
}
2010-08-08 10:06:34 +02:00
return (int)n;
2010-08-08 10:06:34 +02:00
}
int rule_give(void)
{
return config_get_int("rules.give.flags", GIVE_DEFAULT);
2010-08-08 10:06:34 +02:00
}
bool markets_module(void)
2010-08-08 10:06:34 +02:00
{
return config_get_int("modules.markets", 0);
2010-08-08 10:06:34 +02:00
}
void config_set(const char *key, const char *value) {
set_param(&global.parameters, key, value);
}
const char *config_get(const char *key) {
return get_param(global.parameters, key);
}
int config_get_int(const char *key, int def) {
return get_param_int(global.parameters, key, def);
}
double config_get_flt(const char *key, double def) {
return get_param_flt(global.parameters, key, def);
}
2010-08-08 10:06:34 +02:00
/** 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.
*/
2011-03-07 08:02:35 +01:00
void free_gamedata(void)
2010-08-08 10:06:34 +02:00
{
int i;
free_donations();
free_units();
free_regions();
free_borders();
for (i = 0; i != MAXLOCALES; ++i) {
if (defaults[i]) {
free_order(defaults[i]);
defaults[i] = 0;
}
}
2014-12-09 14:43:11 +01:00
free_alliances();
while (factions) {
faction *f = factions;
factions = f->next;
funhash(f);
free_faction(f);
free(f);
}
while (planes) {
plane *pl = planes;
planes = planes->next;
free(pl->name);
free(pl);
}
while (global.attribs) {
a_remove(&global.attribs, global.attribs);
}
++global.cookie; /* readgame() already does this, but sjust in case */
}
const char * game_name(void) {
const char * param = config_get("game.name");
return param ? param : global.gamename;
}
int game_id(void) {
return config_get_int("game.id", 0);
2010-08-08 10:06:34 +02:00
}