server/src/kernel/config.c

3154 lines
67 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/*
Copyright (c) 1998-2010, 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>
/* attributes includes */
#include <attributes/reduceproduction.h>
#include <attributes/gm.h>
/* kernel includes */
#include "alliance.h"
#include "alchemy.h"
#include "battle.h"
#include "connection.h"
#include "building.h"
#include "calendar.h"
#include "curse.h"
#include "faction.h"
#include "group.h"
#include "item.h"
#include "magic.h"
#include "message.h"
#include "move.h"
#include "names.h"
#include "objtypes.h"
#include "order.h"
#include "plane.h"
#include "pool.h"
#include "race.h"
#include "region.h"
#include "save.h"
#include "ship.h"
#include "skill.h"
#include "terrain.h"
#include "unit.h"
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <critbit.h>
2010-08-08 10:06:34 +02:00
#include <util/crmessage.h>
#include <util/event.h>
#include <util/functions.h>
#include <util/language.h>
#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/sql.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>
/* libxml includes */
#include <libxml/tree.h>
#include <libxml/xpath.h>
/* external libraries */
#include <iniparser.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 = {
2011-03-07 08:02:35 +01:00
"Eressea", /* gamename */
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
FILE *logfile;
FILE *updatelog;
const struct race *new_race[MAXRACES];
bool sqlpatch = false;
bool battledebug = false;
2010-08-08 10:06:34 +02:00
int turn = 0;
2011-03-07 08:02:35 +01:00
int NewbieImmunity(void)
{
2010-08-08 10:06:34 +02:00
static int value = -1;
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (value < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "NewbieImmunity", 0);
}
return value;
}
bool IsImmune(const faction * f)
2010-08-08 10:06:34 +02:00
{
return !fval(f, FFL_NPC) && f->age < NewbieImmunity();
}
2011-03-07 08:02:35 +01:00
static int MaxAge(void)
{
2010-08-08 10:06:34 +02:00
static int value = -1;
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (value < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "MaxAge", 0);
}
return value;
}
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;
2010-08-08 10:06:34 +02:00
return 0;
}
bool ExpensiveMigrants(void)
2010-08-08 10:06:34 +02:00
{
static int value = -1;
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (value < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "study.expensivemigrants", 0);
}
return value;
}
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
{
static int value = -1;
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (value < 0 || gamecookie != global.cookie) {
const char *str = get_param(global.parameters, "alliance.auto");
gamecookie = global.cookie;
2010-08-08 10:06:34 +02:00
value = 0;
2011-03-07 08:02:35 +01:00
if (str != NULL) {
char *sstr = strdup(str);
char *tok = strtok(sstr, " ");
2010-08-08 10:06:34 +02:00
while (tok) {
value |= ally_flag(tok, -1);
tok = strtok(NULL, " ");
}
free(sstr);
}
}
return value & HelpMask();
}
/** 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
{
static int rule = -1;
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
const char *str = get_param(global.parameters, "rules.help.mask");
gamecookie = global.cookie;
rule = 0;
2011-03-07 08:02:35 +01:00
if (str != NULL) {
char *sstr = strdup(str);
char *tok = strtok(sstr, " ");
2010-08-08 10:06:34 +02:00
while (tok) {
rule |= ally_flag(tok, -1);
2010-08-08 10:06:34 +02:00
tok = strtok(NULL, " ");
}
free(sstr);
} else {
rule = HELP_ALL;
2010-08-08 10:06:34 +02:00
}
}
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
{
static int rule = -1;
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
const char *str = get_param(global.parameters, "alliance.restricted");
gamecookie = global.cookie;
rule = 0;
2011-03-07 08:02:35 +01:00
if (str != NULL) {
char *sstr = strdup(str);
char *tok = strtok(sstr, " ");
2010-08-08 10:06:34 +02:00
while (tok) {
rule |= ally_flag(tok, -1);
2010-08-08 10:06:34 +02:00
tok = strtok(NULL, " ");
}
free(sstr);
}
rule &= HelpMask();
2010-08-08 10:06:34 +02:00
}
return rule;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int LongHunger(const struct unit *u)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (u != NULL) {
if (!fval(u, UFL_HUNGER))
return false;
2010-08-08 10:06:34 +02:00
#ifdef NEW_DAEMONHUNGER_RULE
2011-03-07 08:02:35 +01:00
if (u->race == new_race[RC_DAEMON])
return false;
2010-08-08 10:06:34 +02:00
#endif
}
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
rule = get_param_int(global.parameters, "hunger.long", 0);
2010-08-08 10:06:34 +02:00
}
return rule;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int SkillCap(skill_t sk)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (sk == SK_MAGIC)
return 0; /* no caps on magic */
if (rule < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
rule = get_param_int(global.parameters, "skill.maxlevel", 0);
2010-08-08 10:06:34 +02:00
}
return rule;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int NMRTimeout(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
rule = get_param_int(global.parameters, "nmr.timeout", 0);
2010-08-08 10:06:34 +02:00
}
return rule;
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;
2011-03-07 08:02:35 +01:00
for (i = 0; i != MAXRACES; ++i) {
if (new_race[i] == rc)
return i;
2010-08-08 10:06:34 +02:00
}
return NORACE;
}
helpmode helpmodes[] = {
2011-03-07 08:02:35 +01:00
{"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
};
2011-03-07 08:02:35 +01:00
const char *directions[MAXDIRECTIONS + 2] = {
2010-08-08 10:06:34 +02:00
"northwest",
"northeast",
"east",
"southeast",
"southwest",
"west",
"",
"pause"
};
/** 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];
2011-03-07 08:02:35 +01:00
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 */
2011-03-07 08:02:35 +01:00
strcpy(zText, (const char *)LOC(find_locale("en"), rc_name(rc, 0)));
2010-08-08 10:06:34 +02:00
while (*zPtr) {
*zPtr = (char)(toupper(*zPtr));
++zPtr;
}
return zText;
}
2011-03-07 08:02:35 +01:00
const char *parameters[MAXPARAMS] = {
2010-08-08 10:06:34 +02:00
"LOCALE",
"ALLES",
"JEDEM",
"BAUERN",
"BURG",
"EINHEIT",
"PRIVAT",
"HINTEN",
"KOMMANDO",
"KRAEUTER",
"NICHT",
"NAECHSTER",
"PARTEI",
"ERESSEA",
"PERSONEN",
"REGION",
"SCHIFF",
"SILBER",
"STRASSEN",
"TEMPORAERE",
"FLIEHE",
"GEBAEUDE",
2011-03-07 08:02:35 +01:00
"GIB", /* F<>r HELFE */
2010-08-08 10:06:34 +02:00
"KAEMPFE",
"DURCHREISE",
"BEWACHE",
"ZAUBER",
"PAUSE",
"VORNE",
"AGGRESSIV",
"DEFENSIV",
"STUFE",
"HELFE",
"FREMDES",
"AURA",
"UM",
"BEISTAND",
"GNADE",
"HINTER",
"VOR",
"ANZAHL",
"GEGENSTAENDE",
"TRAENKE",
"GRUPPE",
"PARTEITARNUNG",
"BAEUME",
"XEPOTION",
"XEBALLOON",
"XELAEN",
"ALLIANZ"
};
2011-03-07 08:02:35 +01:00
const char *keywords[MAXKEYWORDS] = {
2010-08-08 10:06:34 +02:00
"//",
"BANNER",
"ARBEITEN",
"ATTACKIEREN",
"BEKLAUEN",
"BELAGERE",
"BENENNEN",
"BENUTZEN",
"BESCHREIBEN",
"BETRETEN",
"BEWACHEN",
"BOTSCHAFT",
"ENDE",
"FAHREN",
"NUMMER",
"FOLGEN",
"FORSCHEN",
"GIB",
"HELFEN",
"KAEMPFEN",
"KAMPFZAUBER",
"KAUFEN",
"KONTAKTIEREN",
"LEHREN",
"LERNEN",
"LIEFERE",
"MACHEN",
"NACH",
"PASSWORT",
"REKRUTIEREN",
"RESERVIEREN",
"ROUTE",
"SABOTIEREN",
"OPTION",
"SPIONIEREN",
"STIRB",
"TARNEN",
"TRANSPORTIEREN",
"TREIBEN",
"UNTERHALTEN",
"VERKAUFEN",
"VERLASSEN",
"VERGESSEN",
"ZAUBERE",
"ZEIGEN",
"ZERSTOEREN",
"ZUECHTEN",
"DEFAULT",
"URSPRUNG",
"EMAIL",
"PIRATERIE",
"GRUPPE",
"SORTIEREN",
"GM",
"INFO",
"PRAEFIX",
"PFLANZEN",
"ALLIANZ",
"BEANSPRUCHEN",
"PROMOTION",
"BEZAHLEN",
};
2011-03-07 08:02:35 +01:00
const char *report_options[MAX_MSG] = {
2010-08-08 10:06:34 +02:00
"Kampf",
"Ereignisse",
"Bewegung",
"Einkommen",
"Handel",
"Produktion",
"Orkvermehrung",
"Zauber",
"",
""
};
2011-03-07 08:02:35 +01:00
const char *message_levels[ML_MAX] = {
2010-08-08 10:06:34 +02:00
"Wichtig",
"Debug",
"Fehler",
"Warnungen",
"Infos"
};
2011-03-07 08:02:35 +01:00
const char *options[MAXOPTIONS] = {
2010-08-08 10:06:34 +02:00
"AUSWERTUNG",
"COMPUTER",
"ZUGVORLAGE",
NULL,
"STATISTIK",
"DEBUG",
"ZIPPED",
2011-03-07 08:02:35 +01:00
"ZEITUNG", /* Option hat Sonderbehandlung! */
2010-08-08 10:06:34 +02:00
NULL,
"ADRESSEN",
"BZIP2",
"PUNKTE",
"SHOWSKCHANGE",
"XML"
};
2011-03-07 08:02:35 +01:00
static int allied_skillcount(const faction * f, skill_t sk)
2010-08-08 10:06:34 +02:00
{
int num = 0;
2011-03-07 08:02:35 +01:00
alliance *a = f_get_alliance(f);
quicklist *members = a->members;
int qi;
2011-03-07 08:02:35 +01:00
for (qi = 0; members; ql_advance(&members, &qi, 1)) {
faction *m = (faction *) ql_get(members, qi);
num += count_skill(m, sk);
2010-08-08 10:06:34 +02:00
}
return num;
}
2011-03-07 08:02:35 +01:00
static int allied_skilllimit(const faction * f, skill_t sk)
2010-08-08 10:06:34 +02:00
{
static int value = -1;
2011-03-07 08:02:35 +01:00
if (value < 0) {
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "alliance.skilllimit", 0);
}
return value;
}
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;
}
static attrib_type at_maxmagicians = {
"maxmagicians",
init_maxmagicians,
NULL,
NULL,
a_writeint,
a_readint,
ATF_UNIQUE
};
2011-03-07 08:02:35 +01:00
static void init_npcfaction(struct attrib *a)
2010-08-08 10:06:34 +02:00
{
a->data.i = 1;
}
static attrib_type at_npcfaction = {
"npcfaction",
init_npcfaction,
NULL,
NULL,
a_writeint,
a_readint,
ATF_UNIQUE
};
2011-03-07 08:02:35 +01:00
int max_magicians(const faction * f)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
int m =
get_param_int(global.parameters, "rules.maxskills.magic", MAXMAGICIANS);
attrib *a;
2010-08-08 10:06:34 +02:00
if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) {
m = a->data.i;
}
2011-03-07 08:02:35 +01:00
if (f->race == new_race[RC_ELF])
++m;
2010-08-08 10:06:34 +02:00
return m;
}
2011-03-07 08:02:35 +01:00
int skill_limit(faction * f, skill_t sk)
2010-08-08 10:06:34 +02:00
{
int m = INT_MAX;
int al = allied_skilllimit(f, sk);
2011-03-07 08:02:35 +01:00
if (al > 0) {
if (sk != SK_ALCHEMY && sk != SK_MAGIC)
return INT_MAX;
2010-08-08 10:06:34 +02:00
if (f_get_alliance(f)) {
2011-03-07 08:02:35 +01:00
int ac = listlen(f->alliance->members); /* number of factions */
int fl = (al + ac - 1) / ac; /* faction limit, rounded up */
2010-08-08 10:06:34 +02:00
/* the faction limit may not be achievable because it would break the alliance-limit */
int sc = al - allied_skillcount(f, sk);
2011-03-07 08:02:35 +01:00
if (sc <= 0)
return 0;
2010-08-08 10:06:34 +02:00
return fl;
}
}
2011-03-08 08:44:20 +01:00
if (sk == SK_MAGIC) {
m = max_magicians(f);
} else if (sk == SK_ALCHEMY) {
m = get_param_int(global.parameters, "rules.maxskills.alchemy",
MAXALCHEMISTS);
2010-08-08 10:06:34 +02:00
}
return m;
}
2011-03-07 08:02:35 +01:00
int count_skill(faction * f, skill_t sk)
2010-08-08 10:06:34 +02:00
{
int n = 0;
unit *u;
for (u = f->units; u; u = u->nextF) {
if (has_skill(u, sk)) {
2011-03-08 08:44:20 +01:00
if (!is_familiar(u)) {
2011-03-07 08:02:35 +01:00
n += u->number;
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
}
}
return n;
}
2012-05-16 07:21:59 +02:00
int verbosity = 1;
2010-08-08 10:06:34 +02:00
FILE *debug;
2011-03-07 08:02:35 +01:00
static int ShipSpeedBonus(const unit * u)
2010-08-08 10:06:34 +02:00
{
static int level = -1;
2011-03-07 08:02:35 +01:00
if (level == -1) {
level =
get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (level > 0) {
ship *sh = u->ship;
2010-08-08 10:06:34 +02:00
int skl = effskill(u, SK_SAILING);
2011-03-07 08:02:35 +01:00
int minsk = (sh->type->cptskill + 1) / 2;
return (skl - minsk) / level;
2010-08-08 10:06:34 +02:00
}
return 0;
}
2011-03-07 08:02:35 +01:00
int shipspeed(const ship * sh, const unit * u)
2010-08-08 10:06:34 +02:00
{
double k = sh->type->range;
2011-03-07 08:02:35 +01:00
static const curse_type *stormwind_ct, *nodrift_ct;
static bool init;
2010-08-08 10:06:34 +02:00
attrib *a;
2011-03-07 08:02:35 +01:00
curse *c;
2010-08-08 10:06:34 +02:00
if (!init) {
init = true;
stormwind_ct = ct_find("stormwind");
nodrift_ct = ct_find("nodrift");
}
2011-03-07 08:02:35 +01:00
assert(u->ship == sh);
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
if (sh->size != sh->type->construction->maxsize)
return 0;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (curse_active(get_curse(sh->attribs, stormwind_ct)))
k *= 2;
if (curse_active(get_curse(sh->attribs, nodrift_ct)))
k += 1;
2010-08-08 10:06:34 +02:00
if (u->faction->race == u->race) {
/* race bonus for this faction? */
if (fval(u->race, RCF_SHIPSPEED)) {
k += 1;
}
}
k += ShipSpeedBonus(u);
a = a_find(sh->attribs, &at_speedup);
2011-03-07 08:02:35 +01:00
while (a != NULL && a->type == &at_speedup) {
2010-08-08 10:06:34 +02:00
k += a->data.sa[0];
a = a->next;
}
c = get_curse(sh->attribs, ct_find("shipspeedup"));
2011-03-07 08:02:35 +01:00
while (c) {
2010-08-08 10:06:34 +02:00
k += curse_geteffect(c);
2011-03-07 08:02:35 +01:00
c = c->nexthash;
2010-08-08 10:06:34 +02:00
}
#ifdef SHIPSPEED
k *= SHIPSPEED;
#endif
#ifdef SHIPDAMAGE
2011-03-07 08:02:35 +01:00
if (sh->damage)
k =
(k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE -
1) / (sh->size * DAMAGE_SCALE);
2010-08-08 10:06:34 +02:00
#endif
return (int)k;
}
#define FMAXHASH 2039
2011-03-07 08:02:35 +01:00
faction *factionhash[FMAXHASH];
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
void fhash(faction * f)
2010-08-08 10:06:34 +02:00
{
int index = f->no % FMAXHASH;
f->nexthash = factionhash[index];
factionhash[index] = f;
}
2011-03-07 08:02:35 +01:00
void funhash(faction * f)
2010-08-08 10:06:34 +02:00
{
int index = f->no % FMAXHASH;
2011-03-07 08:02:35 +01:00
faction **fp = factionhash + index;
while (*fp && (*fp) != f)
fp = &(*fp)->nexthash;
2010-08-08 10:06:34 +02:00
*fp = f->nexthash;
}
2011-03-07 08:02:35 +01:00
static faction *ffindhash(int no)
2010-08-08 10:06:34 +02:00
{
int index = no % FMAXHASH;
2011-03-07 08:02:35 +01:00
faction *f = factionhash[index];
while (f && f->no != no)
f = f->nexthash;
2010-08-08 10:06:34 +02:00
return f;
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ----------------------------------------------------------------------- */
2011-03-07 08:02:35 +01:00
void verify_data(void)
2010-08-08 10:06:34 +02:00
{
#ifndef NDEBUG
int lf = -1;
faction *f;
unit *u;
int mage, alchemist;
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts(" - <20>berpr<70>fe Daten auf Korrektheit...");
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (f = factions; f; f = f->next) {
2010-08-08 10:06:34 +02:00
mage = 0;
alchemist = 0;
2011-03-07 08:02:35 +01:00
for (u = f->units; u; u = u->nextF) {
2010-08-08 10:06:34 +02:00
if (eff_skill(u, SK_MAGIC, u->region)) {
mage += u->number;
}
if (eff_skill(u, SK_ALCHEMY, u->region))
alchemist += u->number;
if (u->number > UNIT_MAXSIZE) {
if (lf != f->no) {
lf = f->no;
2012-05-16 07:21:59 +02:00
log_printf(stdout, "Partei %s:\n", factionid(f));
2010-08-08 10:06:34 +02:00
}
log_warning("Einheit %s hat %d Personen\n", unitid(u), u->number);
2010-08-08 10:06:34 +02:00
}
}
if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4))
log_error("Partei %s hat %d Magier.\n", factionid(f), mage);
2010-08-08 10:06:34 +02:00
if (alchemist > 3)
log_error("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist);
2010-08-08 10:06:34 +02:00
}
#endif
}
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);
if (old == 0)
return 0;
t = (n / old) * new_value;
for (i = (n % old); i; i--)
if (rng_int() % old < new_value)
t++;
return t;
}
2011-03-07 08:02:35 +01:00
int change_hitpoints(unit * u, int value)
2010-08-08 10:06:34 +02:00
{
int hp = u->hp;
hp += value;
/* Jede Person ben<65>tigt mindestens 1 HP */
2011-03-07 08:02:35 +01:00
if (hp < u->number) {
if (hp < 0) { /* Einheit tot */
2010-08-08 10:06:34 +02:00
hp = 0;
}
scale_number(u, hp);
}
u->hp = hp;
return hp;
}
2011-03-07 08:02:35 +01:00
unsigned int atoip(const char *s)
2010-08-08 10:06:34 +02:00
{
int n;
2011-03-07 08:02:35 +01:00
n = atoi(s);
2010-08-08 10:06:34 +02:00
if (n < 0)
n = 0;
return n;
}
2011-03-07 08:02:35 +01:00
region *findunitregion(const unit * su)
2010-08-08 10:06:34 +02:00
{
#ifndef SLOW_REGION
return su->region;
#else
region *r;
const unit *u;
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
if (su == u) {
2011-03-07 08:02:35 +01:00
return r;
2010-08-08 10:06:34 +02:00
}
}
}
/* This should never happen */
2011-03-07 08:02:35 +01:00
assert(!"Die unit wurde nicht gefunden");
2010-08-08 10:06:34 +02:00
return (region *) NULL;
#endif
}
2011-03-07 08:02:35 +01:00
int effskill(const unit * u, skill_t sk)
2010-08-08 10:06:34 +02:00
{
return eff_skill(u, sk, u->region);
}
2011-03-07 08:02:35 +01:00
int eff_stealth(const unit * u, const region * r)
2010-08-08 10:06:34 +02:00
{
int e = 0;
/* Auf Schiffen keine Tarnung! */
if (!u->ship && skill_enabled[SK_STEALTH]) {
2011-03-07 08:02:35 +01:00
e = eff_skill(u, SK_STEALTH, r);
2010-08-08 10:06:34 +02:00
if (fval(u, UFL_STEALTH)) {
int es = u_geteffstealth(u);
2011-03-07 08:02:35 +01:00
if (es >= 0 && es < e)
return es;
2010-08-08 10:06:34 +02:00
}
}
return e;
}
bool unit_has_cursed_item(unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item *itm = u->items;
2010-08-08 10:06:34 +02:00
while (itm) {
2011-03-07 08:02:35 +01:00
if (fval(itm->type, ITF_CURSED) && itm->number > 0)
return true;
itm = itm->next;
2010-08-08 10:06:34 +02:00
}
return false;
}
2011-03-07 08:02:35 +01:00
static void init_gms(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (f = factions; f; f = f->next) {
const attrib *a = a_findc(f->attribs, &at_gm);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (a != NULL)
fset(f, FFL_GM);
2010-08-08 10:06:34 +02:00
}
}
static int
autoalliance(const plane * pl, const faction * sf, const faction * f2)
{
static bool init = false;
2010-08-08 10:06:34 +02:00
if (!init) {
init_gms();
init = true;
}
2011-03-07 08:02:35 +01:00
if (pl && (pl->flags & PFL_FRIENDLY))
return HELP_ALL;
2010-08-08 10:06:34 +02:00
/* if f2 is a gm in this plane, everyone has an auto-help to it */
if (fval(f2, FFL_GM)) {
2011-03-07 08:02:35 +01:00
attrib *a = a_find(f2->attribs, &at_gm);
2010-08-08 10:06:34 +02:00
while (a) {
2011-03-07 08:02:35 +01:00
const plane *p = (const plane *)a->data.v;
if (p == pl)
return HELP_ALL;
a = a->next;
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01: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;
}
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
{
2011-03-07 08:02:35 +01:00
if (sf == NULL)
return 0;
2010-08-08 10:06:34 +02:00
return sf->status & mode;
}
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
{
2011-03-07 08:02:35 +01:00
while (sf && sf->faction != f2)
sf = sf->next;
if (sf == NULL) {
2010-08-08 10:06:34 +02:00
mode = mode & autoalliance(pl, f, f2);
}
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;
}
2011-03-07 08:02:35 +01:00
if (f->alliance != f2->alliance) {
2010-08-08 10:06:34 +02:00
mode &= ~AllianceRestricted();
}
}
return mode;
}
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);
}
/* 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
{
2011-03-07 08:02:35 +01:00
ally *sf;
2010-08-08 10:06:34 +02:00
int automode;
2011-03-07 08:02:35 +01:00
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);
2010-08-08 10:06:34 +02:00
/* helps the owner of the region */
2011-03-07 08:02:35 +01:00
if (owner == f2) {
2010-08-08 10:06:34 +02:00
return HELP_FIGHT;
}
}
}
pl = rplane(u->region);
automode = mode & autoalliance(pl, u->faction, f2);
2011-03-07 08:02:35 +01:00
if (pl != NULL && (pl->flags & PFL_NOALLIANCES))
2010-08-08 10:06:34 +02:00
mode = (mode & automode) | (mode & HELP_GIVE);
sf = u->faction->allies;
if (fval(u, UFL_GROUP)) {
2011-03-07 08:02:35 +01:00
const attrib *a = a_findc(u->attribs, &at_group);
if (a != NULL)
sf = ((group *) a->data.v)->allies;
2010-08-08 10:06:34 +02:00
}
return alliedgroup(pl, u->faction, f2, sf, mode);
}
return 0;
}
bool
2010-08-08 10:06:34 +02:00
seefaction(const faction * f, const region * r, const unit * u, int modifier)
{
2011-03-07 08:02:35 +01:00
if (((f == u->faction) || !fval(u, UFL_ANON_FACTION))
&& cansee(f, r, u, modifier))
2010-08-08 10:06:34 +02:00
return true;
return false;
}
bool
2010-08-08 10:06:34 +02:00
cansee(const faction * f, const region * r, const unit * u, int modifier)
/* r kann != u->region sein, wenn es um durchreisen geht */
/* und es muss niemand aus f in der region sein, wenn sie vom Turm
* erblickt wird */
{
int stealth, rings;
unit *u2 = r->units;
2011-03-07 08:02:35 +01:00
static const item_type *itype_grail;
static bool init;
2010-08-08 10:06:34 +02:00
if (!init) {
init = true;
itype_grail = it_find("grail");
}
if (u->faction == f || omniscient(f)) {
return true;
} else if (fval(u->race, RCF_INVISIBLE)) {
return false;
} else if (u->number == 0) {
attrib *a = a_find(u->attribs, &at_creator);
2011-03-07 08:02:35 +01:00
if (a) { /* u is an empty temporary unit. In this special case
we look at the creating unit. */
u = (unit *) a->data.v;
2010-08-08 10:06:34 +02:00
} else {
return false;
}
}
2011-03-07 08:02:35 +01:00
if (leftship(u))
return true;
if (itype_grail != NULL && i_get(u->items, itype_grail))
return true;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
while (u2 && u2->faction != f)
u2 = u2->next;
if (u2 == NULL)
return false;
2010-08-08 10:06:34 +02:00
/* simple visibility, just gotta have a unit in the region to see 'em */
2011-03-07 08:02:35 +01:00
if (is_guard(u, GUARD_ALL) != 0 || usiege(u) || u->building || u->ship) {
2010-08-08 10:06:34 +02:00
return true;
}
rings = invisible(u, NULL);
stealth = eff_stealth(u, r) - modifier;
while (u2) {
2011-03-07 08:02:35 +01:00
if (rings < u->number || invisible(u, u2) < u->number) {
2010-08-08 10:06:34 +02:00
if (skill_enabled[SK_PERCEPTION]) {
int observation = eff_skill(u2, SK_PERCEPTION, r);
if (observation >= stealth) {
return true;
}
} else {
return true;
}
}
/* find next unit in our faction */
do {
2011-03-07 08:02:35 +01:00
u2 = u2->next;
2010-08-08 10:06:34 +02:00
} while (u2 && u2->faction != f);
}
return false;
}
bool cansee_unit(const unit * u, const unit * target, int modifier)
2010-08-08 10:06:34 +02:00
/* target->region kann != u->region sein, wenn es um durchreisen geht */
{
2011-03-07 08:02:35 +01:00
if (fval(target->race, RCF_INVISIBLE) || target->number == 0)
return false;
else if (target->faction == u->faction)
return true;
2010-08-08 10:06:34 +02:00
else {
int n, rings, o;
2011-03-07 08:02:35 +01:00
if (is_guard(target, GUARD_ALL) != 0 || usiege(target) || target->building
|| target->ship) {
2010-08-08 10:06:34 +02:00
return true;
}
n = eff_stealth(target, target->region) - modifier;
rings = invisible(target, NULL);
2011-03-07 08:02:35 +01:00
if (rings == 0 && n <= 0) {
2010-08-08 10:06:34 +02:00
return true;
}
if (rings && invisible(target, u) >= target->number) {
return false;
}
if (skill_enabled[SK_PERCEPTION]) {
o = eff_skill(u, SK_PERCEPTION, target->region);
if (o >= n) {
return true;
}
} else {
return true;
}
}
return false;
}
bool
2011-03-07 08:02:35 +01:00
cansee_durchgezogen(const faction * f, const region * r, const unit * u,
int modifier)
2010-08-08 10:06:34 +02:00
/* r kann != u->region sein, wenn es um durchreisen geht */
/* und es muss niemand aus f in der region sein, wenn sie vom Turm
* erblickt wird */
{
int n;
unit *u2;
2011-03-07 08:02:35 +01:00
if (fval(u->race, RCF_INVISIBLE) || u->number == 0)
return false;
else if (u->faction == f)
return true;
2010-08-08 10:06:34 +02:00
else {
int rings;
2011-03-07 08:02:35 +01:00
if (is_guard(u, GUARD_ALL) != 0 || usiege(u) || u->building || u->ship) {
2010-08-08 10:06:34 +02:00
return true;
}
n = eff_stealth(u, r) - modifier;
rings = invisible(u, NULL);
2011-03-07 08:02:35 +01:00
if (rings == 0 && n <= 0) {
2010-08-08 10:06:34 +02:00
return true;
}
2011-03-07 08:02:35 +01:00
for (u2 = r->units; u2; u2 = u2->next) {
2010-08-08 10:06:34 +02:00
if (u2->faction == f) {
int o;
2011-03-07 08:02:35 +01:00
if (rings && invisible(u, u2) >= u->number)
continue;
2010-08-08 10:06:34 +02:00
o = eff_skill(u2, SK_PERCEPTION, r);
if (o >= n) {
return true;
}
}
}
}
return false;
}
#ifndef NDEBUG
2011-03-07 08:02:35 +01:00
const char *strcheck(const char *s, size_t maxlen)
2010-08-08 10:06:34 +02:00
{
static char buffer[16 * 1024];
if (strlen(s) > maxlen) {
assert(maxlen < 16 * 1024);
log_warning("[strcheck] String wurde auf %d Zeichen verk<72>rzt:\n%s\n", (int)maxlen, s);
2010-08-08 10:06:34 +02:00
strlcpy(buffer, s, maxlen);
return buffer;
}
return s;
}
#endif
static attrib_type at_lighthouse = {
"lighthouse"
2011-03-07 08:02:35 +01:00
/* Rest ist NULL; tempor<6F>res, nicht alterndes Attribut */
2010-08-08 10:06:34 +02:00
};
/* update_lighthouse: call this function whenever the size of a lighthouse changes
* it adds temporary markers to the surrounding regions.
* The existence of markers says nothing about the quality of the observer in
* the lighthouse, for this may change more frequently.
*/
2011-03-07 08:02:35 +01:00
void update_lighthouse(building * lh)
2010-08-08 10:06:34 +02:00
{
static bool init_lighthouse = false;
2011-03-07 08:02:35 +01:00
static const struct building_type *bt_lighthouse = 0;
2010-08-08 10:06:34 +02:00
if (!init_lighthouse) {
bt_lighthouse = bt_find("lighthouse");
2011-03-07 08:02:35 +01:00
if (bt_lighthouse == NULL)
return;
2010-08-08 10:06:34 +02:00
init_lighthouse = true;
}
2011-03-07 08:02:35 +01:00
if (lh->type == bt_lighthouse) {
region *r = lh->region;
2010-08-08 10:06:34 +02:00
int d = (int)log10(lh->size) + 1;
int x;
2011-03-07 08:02:35 +01:00
if (lh->size > 0) {
2010-08-08 10:06:34 +02:00
r->flags |= RF_LIGHTHOUSE;
}
2011-03-07 08:02:35 +01:00
for (x = -d; x <= d; ++x) {
2010-08-08 10:06:34 +02:00
int y;
2011-03-07 08:02:35 +01:00
for (y = -d; y <= d; ++y) {
attrib *a;
region *r2;
int px = r->x + x, py = r->y + y;
2010-08-08 10:06:34 +02:00
pnormalize(&px, &py, rplane(r));
r2 = findregion(px, py);
2011-03-07 08:02:35 +01:00
if (r2 == NULL)
continue;
if (!fval(r2->terrain, SEA_REGION))
continue;
if (distance(r, r2) > d)
continue;
2010-08-08 10:06:34 +02:00
a = a_find(r2->attribs, &at_lighthouse);
2011-03-07 08:02:35 +01:00
while (a && a->type == &at_lighthouse) {
building *b = (building *) a->data.v;
if (b == lh)
break;
2010-08-08 10:06:34 +02:00
a = a->next;
}
if (!a) {
a = a_add(&r2->attribs, a_new(&at_lighthouse));
2011-03-07 08:02:35 +01:00
a->data.v = (void *)lh;
2010-08-08 10:06:34 +02:00
}
}
}
}
}
2011-03-07 08:02:35 +01:00
int count_all(const faction * f)
2010-08-08 10:06:34 +02:00
{
#ifndef NDEBUG
int n = 0;
unit *u;
2011-03-07 08:02:35 +01:00
for (u = f->units; u; u = u->nextF) {
2010-08-08 10:06:34 +02:00
if (playerrace(u->race)) {
n += u->number;
2011-03-07 08:02:35 +01:00
assert(f == u->faction);
2010-08-08 10:06:34 +02:00
}
}
if (f->num_people != n) {
log_error("# of people in %s is != num_people: %d should be %d.\n", factionid(f), f->num_people, n);
2010-08-08 10:06:34 +02:00
}
#endif
return f->num_people;
}
2011-03-07 08:02:35 +01:00
int count_migrants(const faction * f)
2010-08-08 10:06:34 +02:00
{
unit *u = f->units;
int n = 0;
while (u) {
assert(u->faction == f);
2011-03-07 08:02:35 +01:00
if (u->race != f->race && u->race != new_race[RC_ILLUSION]
&& u->race != new_race[RC_SPELL]
&& !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) {
2010-08-08 10:06:34 +02:00
n += u->number;
}
u = u->nextF;
}
return n;
}
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;
2011-03-07 08:02:35 +01:00
if (migrants < 0) {
2010-08-08 10:06:34 +02:00
migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX);
}
2011-03-07 08:02:35 +01:00
if (migrants == INT_MAX) {
2010-08-08 10:06:34 +02:00
int x = 0;
if (f->race == new_race[RC_HUMAN]) {
int nsize = count_all(f);
2011-03-07 08:02:35 +01:00
if (nsize > 0) {
2010-08-08 10:06:34 +02:00
x = (int)(log10(nsize / 50.0) * 20);
2011-03-07 08:02:35 +01:00
if (x < 0)
x = 0;
2010-08-08 10:06:34 +02:00
}
}
return x;
}
return migrants;
}
void
parse(keyword_t kword, int (*dofun) (unit *, struct order *), bool thisorder)
2010-08-08 10:06:34 +02:00
{
region *r;
for (r = regions; r; r = r->next) {
unit **up = &r->units;
while (*up) {
2011-03-07 08:02:35 +01:00
unit *u = *up;
order **ordp = &u->orders;
if (thisorder)
ordp = &u->thisorder;
2010-08-08 10:06:34 +02:00
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
2010-08-08 10:06:34 +02:00
if (get_keyword(ord) == kword) {
2011-03-07 08:02:35 +01:00
if (dofun(u, ord) != 0)
break;
if (u->orders == NULL)
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (thisorder)
break;
if (*ordp == ord)
ordp = &ord->next;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (*up == u)
up = &u->next;
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
const char *igetstrtoken(const char *initstr)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (initstr != NULL) {
2010-08-08 10:06:34 +02:00
init_tokens_str(initstr, NULL);
}
return getstrtoken();
}
2011-03-07 08:02:35 +01:00
unsigned int getuint(void)
2010-08-08 10:06:34 +02:00
{
return atoip((const char *)getstrtoken());
}
2011-03-07 08:02:35 +01:00
int getint(void)
2010-08-08 10:06:34 +02:00
{
return atoi((const char *)getstrtoken());
}
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);
2010-08-08 10:06:34 +02:00
variant token;
assert(lang);
if (tokens && findtoken(*tokens, s, &token) == E_TOK_SUCCESS) {
2010-08-08 10:06:34 +02:00
return (const struct race *)token.v;
}
return NULL;
}
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);
2010-08-08 10:06:34 +02:00
variant token;
if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) {
2011-03-07 08:02:35 +01:00
return (direction_t) token.i;
2010-08-08 10:06:34 +02:00
}
return NODIRECTION;
}
skill_t findskill(const char *s, const struct locale * lang)
2010-08-08 10:06:34 +02:00
{
param_t result = NOSKILL;
char buffer[64];
char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s);
2010-08-08 10:06:34 +02:00
if (str) {
int i;
const void * match;
void **tokens = get_translations(lang, UT_SKILLS);
critbit_tree *cb = (critbit_tree *)*tokens;
if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) {
cb_get_kv(match, &i, sizeof(int));
result = (skill_t)i;
2010-08-08 10:06:34 +02:00
}
}
return result;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
keyword_t findkeyword(const char *s, const struct locale * lang)
2010-08-08 10:06:34 +02:00
{
2012-05-22 03:09:30 +02:00
keyword_t result = NOKEYWORD;
char buffer[64];
while (*s == '@') ++s;
if (*s) {
char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s);
2010-08-08 10:06:34 +02:00
2012-05-22 03:09:30 +02:00
if (str) {
int i;
const void * match;
void **tokens = get_translations(lang, UT_KEYWORDS);
critbit_tree *cb = (critbit_tree *)*tokens;
if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) {
cb_get_kv(match, &i, sizeof(int));
result = (keyword_t)i;
return global.disabled[result] ? NOKEYWORD : result;
}
}
}
return NOKEYWORD;
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 = transliterate(buffer, sizeof(buffer)-sizeof(int), s);
if (str && *str) {
int i;
const void * match;
void **tokens = get_translations(lang, UT_PARAMS);
critbit_tree *cb = (critbit_tree *)*tokens;
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) {
2011-03-07 08:02:35 +01:00
const building_type *btype = findbuildingtype(s, lang);
if (btype != NULL)
return P_GEBAEUDE;
2010-08-08 10:06:34 +02:00
}
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)
{
if (s[0]>'@') {
param_t p = (param==P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang);
return p==param;
}
2012-06-24 08:04:12 +02:00
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
{
2011-03-07 08:02:35 +01:00
return findparam(getstrtoken(), lang);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
faction *findfaction(int n)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f = ffindhash(n);
2010-08-08 10:06:34 +02:00
return f;
}
2011-03-07 08:02:35 +01:00
faction *getfaction(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return findfaction(getid());
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
unit *findunitr(const region * r, int n)
2010-08-08 10:06:34 +02:00
{
unit *u;
/* findunit regional! */
for (u = r->units; u; u = u->next)
if (u->no == n)
return u;
return 0;
}
unit *findunit(int n)
{
if (n <= 0) {
return NULL;
}
return ufindhash(n);
}
2011-03-07 08:02:35 +01:00
unit *findunitg(int n, const region * hint)
2010-08-08 10:06:34 +02:00
{
/* Abfangen von Syntaxfehlern. */
if (n <= 0)
return NULL;
/* findunit global! */
hint = 0;
return ufindhash(n);
}
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();
2011-03-07 08:02:35 +01: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;
u2 = findnewunit(r, f, n);
2011-03-07 08:02:35 +01:00
if (u2)
return u2->no;
2010-08-08 10:06:34 +02:00
return -1;
}
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
{
2011-03-07 08:02:35 +01:00
const char *s = getstrtoken();
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! */
if (!s || *s == 0) {
return -1;
}
if (isparam(s, f->locale, P_TEMP)) {
2011-03-08 08:44:20 +01:00
return read_newunitid(f, r);
2010-08-08 10:06:34 +02:00
}
return atoi36((const char *)s);
}
/* exported symbol */
bool getunitpeasants;
2011-03-07 08:02:35 +01:00
unit *getunitg(const region * r, const faction * f)
2010-08-08 10:06:34 +02:00
{
int n = read_unitid(f, r);
if (n == 0) {
getunitpeasants = 1;
return NULL;
}
getunitpeasants = 0;
2011-03-07 08:02:35 +01:00
if (n < 0)
return 0;
2010-08-08 10:06:34 +02:00
return findunit(n);
}
2011-03-07 08:02:35 +01:00
unit *getunit(const region * r, const faction * f)
2010-08-08 10:06:34 +02:00
{
int n = read_unitid(f, r);
unit *u2;
if (n == 0) {
getunitpeasants = 1;
return NULL;
}
getunitpeasants = 0;
2011-03-07 08:02:35 +01:00
if (n < 0)
return 0;
2010-08-08 10:06:34 +02:00
u2 = findunit(n);
2011-03-07 08:02:35 +01:00
if (u2 != NULL && u2->region == r) {
2010-08-08 10:06:34 +02:00
/* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition
2011-03-07 08:02:35 +01:00
* 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
*/
2010-08-08 10:06:34 +02:00
return u2;
}
return NULL;
}
/* - String Listen --------------------------------------------- */
2011-03-07 08:02:35 +01:00
void addstrlist(strlist ** SP, const char *s)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
strlist *slist = malloc(sizeof(strlist));
2010-08-08 10:06:34 +02:00
slist->next = NULL;
slist->s = strdup(s);
addlist(SP, slist);
}
2011-03-07 08:02:35 +01:00
void freestrlist(strlist * s)
2010-08-08 10:06:34 +02:00
{
strlist *q, *p = s;
while (p) {
q = p->next;
free(p->s);
free(p);
p = q;
}
}
/* - Meldungen und Fehler ------------------------------------------------- */
bool lomem = false;
2010-08-08 10:06:34 +02:00
/* - Namen der Strukturen -------------------------------------- */
2011-03-07 08:02:35 +01:00
typedef char name[OBJECTIDSIZE + 1];
2010-08-08 10:06:34 +02:00
static name idbuf[8];
static int nextbuf = 0;
2011-03-07 08:02:35 +01:00
char *estring_i(char *ibuf)
2010-08-08 10:06:34 +02:00
{
char *p = ibuf;
while (*p) {
2011-03-07 08:02:35 +01:00
if (isxspace(*(unsigned *)p) == ' ') {
2010-08-08 10:06:34 +02:00
*p = '~';
}
++p;
}
return ibuf;
}
2011-03-07 08:02:35 +01:00
char *estring(const char *s)
2010-08-08 10:06:34 +02:00
{
char *ibuf = idbuf[(++nextbuf) % 8];
strlcpy(ibuf, s, sizeof(name));
return estring_i(ibuf);
}
2011-03-07 08:02:35 +01:00
char *cstring_i(char *ibuf)
2010-08-08 10:06:34 +02:00
{
char *p = ibuf;
while (*p) {
if (*p == '~') {
*p = ' ';
}
++p;
}
return ibuf;
}
2011-03-07 08:02:35 +01:00
char *cstring(const char *s)
2010-08-08 10:06:34 +02:00
{
char *ibuf = idbuf[(++nextbuf) % 8];
strlcpy(ibuf, s, sizeof(name));
return cstring_i(ibuf);
}
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;
for (b = rbuildings(r); b; b = b->next) {
2011-03-07 08:02:35 +01:00
if (cmp_gt(b, best) <= 0)
continue;
2010-08-08 10:06:34 +02:00
if (!imaginary) {
2011-03-07 08:02:35 +01:00
const attrib *a = a_find(b->attribs, &at_icastle);
if (a)
continue;
2010-08-08 10:06:34 +02:00
}
best = b;
}
return best;
}
2011-03-07 08:02:35 +01:00
char *write_unitname(const unit * u, char *buffer, size_t size)
2010-08-08 10:06:34 +02:00
{
2012-05-29 21:17:25 +02:00
slprintf(buffer, size, "%s (%s)", (const char *)u->name, itoa36(u->no));
2011-03-07 08:02:35 +01:00
buffer[size - 1] = 0;
2010-08-08 10:06:34 +02:00
return buffer;
}
2011-03-07 08:02:35 +01:00
const char *unitname(const unit * u)
2010-08-08 10:06:34 +02:00
{
char *ubuf = idbuf[(++nextbuf) % 8];
return write_unitname(u, ubuf, sizeof(name));
}
/* -- 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 };
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
{
2011-03-07 08:02:35 +01:00
static int *forbid = NULL;
2010-08-08 10:06:34 +02:00
static size_t len;
size_t i;
2011-03-07 08:02:35 +01:00
if (id <= 0)
return 1;
2010-08-08 10:06:34 +02:00
if (!forbid) {
2011-03-07 08:02:35 +01:00
while (forbidden[len])
++len;
2010-08-08 10:06:34 +02:00
forbid = calloc(len, sizeof(int));
2011-03-07 08:02:35 +01:00
for (i = 0; i != len; ++i) {
2010-08-08 10:06:34 +02:00
forbid[i] = strtol(forbidden[i], NULL, 36);
}
}
2011-03-07 08:02:35 +01:00
for (i = 0; i != len; ++i)
if (id == forbid[i])
return 1;
2010-08-08 10:06:34 +02:00
return 0;
}
/* 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)
2011-03-07 08:02:35 +01:00
|| cfindhash(random_unit_no)
|| forbiddenid(random_unit_no)) {
2010-08-08 10:06:34 +02:00
random_unit_no++;
if (random_unit_no == MAX_UNIT_NR + 1) {
random_unit_no = 1;
}
if (random_unit_no == start_random_no) {
2011-03-07 08:02:35 +01:00
random_unit_no = (int)MAX_UNIT_NR + 1;
2010-08-08 10:06:34 +02:00
}
}
return random_unit_no;
}
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;
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) {
2011-03-07 08:02:35 +01:00
random_no = (int)MAX_CONTAINER_NR + 1;
2010-08-08 10:06:34 +02:00
}
}
return random_no;
}
2011-03-07 08:02:35 +01:00
unit *createunit(region * r, faction * f, int number, const struct race * rc)
2010-08-08 10:06:34 +02:00
{
assert(rc);
return create_unit(r, f, number, rc, 0, NULL, NULL);
}
bool idle(faction * f)
2010-08-08 10:06:34 +02:00
{
return (bool) (f ? false : true);
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 i = production(r) * MAXPEASANTS_PER_AREA
2011-03-07 08:02:35 +01:00
- ((rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE);
2010-08-08 10:06:34 +02:00
return MAX(i, 0);
}
2011-03-07 08:02:35 +01:00
int lighthouse_range(const building * b, const faction * f)
2010-08-08 10:06:34 +02:00
{
int d = 0;
if (fval(b, BLD_WORKING) && b->size >= 10) {
int maxd = (int)log10(b->size) + 1;
if (skill_enabled[SK_PERCEPTION]) {
2011-03-07 08:02:35 +01:00
region *r = b->region;
2010-08-08 10:06:34 +02:00
int c = 0;
unit *u;
for (u = r->units; u; u = u->next) {
if (u->building == b) {
c += u->number;
2011-03-07 08:02:35 +01:00
if (c > buildingcapacity(b))
break;
if (f == NULL || u->faction == f) {
2010-08-08 10:06:34 +02:00
int sk = eff_skill(u, SK_PERCEPTION, r) / 3;
d = MAX(d, sk);
d = MIN(maxd, d);
2011-03-07 08:02:35 +01:00
if (d == maxd)
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
} else if (c)
break; /* first unit that's no longer in the house ends the search */
2010-08-08 10:06:34 +02:00
}
} else {
/* E3A rule: no perception req'd */
return maxd;
}
}
return d;
}
bool check_leuchtturm(region * r, faction * f)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib *a;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (!fval(r->terrain, SEA_REGION))
return false;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse;
a = a->next) {
building *b = (building *) a->data.v;
2010-08-08 10:06:34 +02:00
assert(b->type == bt_find("lighthouse"));
if (fval(b, BLD_WORKING) && b->size >= 10) {
int maxd = (int)log10(b->size) + 1;
if (skill_enabled[SK_PERCEPTION]) {
region *r2 = b->region;
unit *u;
int c = 0;
int d = 0;
for (u = r2->units; u; u = u->next) {
if (u->building == b) {
c += u->number;
2011-03-07 08:02:35 +01:00
if (c > buildingcapacity(b))
break;
if (f == NULL || u->faction == f) {
if (!d)
d = distance(r, r2);
if (maxd < d)
break;
if (eff_skill(u, SK_PERCEPTION, r) >= d * 3)
return true;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
} else if (c)
break; /* first unit that's no longer in the house ends the search */
2010-08-08 10:06:34 +02:00
}
} else {
/* E3A rule: no perception req'd */
return maxd;
}
}
}
return false;
}
2011-03-07 08:02:35 +01:00
region *lastregion(faction * f)
2010-08-08 10:06:34 +02:00
{
#ifdef SMART_INTERVALS
2011-03-07 08:02:35 +01:00
unit *u = f->units;
2010-08-08 10:06:34 +02:00
region *r = f->last;
2011-03-07 08:02:35 +01:00
if (u == NULL)
return NULL;
if (r != NULL)
return r->next;
2010-08-08 10:06:34 +02:00
/* it is safe to start in the region of the first unit. */
f->last = u->region;
/* if regions have indices, we can skip ahead: */
2011-03-07 08:02:35 +01:00
for (u = u->nextF; u != NULL; u = u->nextF) {
2010-08-08 10:06:34 +02:00
r = u->region;
2011-03-07 08:02:35 +01:00
if (r->index > f->last->index)
f->last = r;
2010-08-08 10:06:34 +02:00
}
/* we continue from the best region and look for travelthru etc. */
for (r = f->last->next; r; r = r->next) {
2011-03-07 08:02:35 +01:00
plane *p = rplane(r);
2010-08-08 10:06:34 +02:00
/* search the region for travelthru-attributes: */
if (fval(r, RF_TRAVELUNIT)) {
2011-03-07 08:02:35 +01:00
attrib *ru = a_find(r->attribs, &at_travelunit);
while (ru && ru->type == &at_travelunit) {
u = (unit *) ru->data.v;
2010-08-08 10:06:34 +02:00
if (u->faction == f) {
f->last = r;
break;
}
ru = ru->next;
}
}
2011-03-07 08:02:35 +01:00
if (f->last == r)
continue;
2010-08-08 10:06:34 +02:00
if (check_leuchtturm(r, f))
f->last = r;
if (p && is_watcher(p, f)) {
f->last = r;
}
}
return f->last->next;
#else
return NULL;
#endif
}
2011-03-07 08:02:35 +01:00
region *firstregion(faction * f)
2010-08-08 10:06:34 +02:00
{
#ifdef SMART_INTERVALS
region *r = f->first;
2011-03-07 08:02:35 +01:00
if (f->units == NULL)
return NULL;
if (r != NULL)
return r;
2010-08-08 10:06:34 +02:00
return f->first = regions;
#else
return regions;
#endif
}
2011-03-07 08:02:35 +01:00
void **blk_list[1024];
2010-08-08 10:06:34 +02:00
int list_index;
int blk_index;
2011-03-07 08:02:35 +01:00
static void gc_done(void)
2010-08-08 10:06:34 +02:00
{
int i, k;
2011-03-07 08:02:35 +01:00
for (i = 0; i != list_index; ++i) {
for (k = 0; k != 1024; ++k)
free(blk_list[i][k]);
2010-08-08 10:06:34 +02:00
free(blk_list[i]);
}
2011-03-07 08:02:35 +01:00
for (k = 0; k != blk_index; ++k)
free(blk_list[list_index][k]);
2010-08-08 10:06:34 +02:00
free(blk_list[list_index]);
}
2011-03-07 08:02:35 +01:00
void *gc_add(void *p)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (blk_index == 0) {
blk_list[list_index] = (void **)malloc(1024 * sizeof(void *));
2010-08-08 10:06:34 +02:00
}
blk_list[list_index][blk_index] = p;
2011-03-07 08:02:35 +01:00
blk_index = (blk_index + 1) % 1024;
if (!blk_index)
++list_index;
2010-08-08 10:06:34 +02:00
return p;
}
static void init_directions(void ** root, const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
/* mit dieser routine kann man mehrere namen f<>r eine direction geben,
* das ist f<EFBFBD>r die hexes ideal. */
const struct {
2011-03-07 08:02:35 +01:00
const char *name;
2010-08-08 10:06:34 +02:00
int direction;
2011-03-07 08:02:35 +01:00
} dirs[] = {
{
"dir_ne", D_NORTHEAST}, {
"dir_nw", D_NORTHWEST}, {
"dir_se", D_SOUTHEAST}, {
"dir_sw", D_SOUTHWEST}, {
"dir_east", D_EAST}, {
"dir_west", D_WEST}, {
"northeast", D_NORTHEAST}, {
"northwest", D_NORTHWEST}, {
"southeast", D_SOUTHEAST}, {
"southwest", D_SOUTHWEST}, {
"east", D_EAST}, {
"west", D_WEST}, {
"PAUSE", D_PAUSE}, {
NULL, NODIRECTION}
2010-08-08 10:06:34 +02:00
};
int i;
void **tokens = get_translations(lang, UT_DIRECTIONS);
2011-03-07 08:02:35 +01:00
for (i = 0; dirs[i].direction != NODIRECTION; ++i) {
2010-08-08 10:06:34 +02:00
variant token;
token.i = dirs[i].direction;
addtoken(tokens, LOC(lang, dirs[i].name), token);
}
}
2011-03-07 08:02:35 +01:00
direction_t finddirection(const char *s, const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
void **tokens = get_translations(lang, UT_DIRECTIONS);
2010-08-08 10:06:34 +02:00
variant token;
if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) {
2011-03-07 08:02:35 +01:00
return (direction_t) token.i;
2010-08-08 10:06:34 +02:00
}
return NODIRECTION;
}
2012-06-24 07:36:17 +02:00
direction_t getdirection(const struct locale * lang)
{
return finddirection(getstrtoken(), lang);
}
static void init_translations(const struct locale *lang, int ut, const char * (*string_cb)(int i), int maxstrings)
{
char buffer[256];
void **tokens;
int i;
assert(string_cb);
assert(maxstrings>0);
tokens = get_translations(lang, ut);
for (i = 0; i != maxstrings; ++i) {
const char * s = string_cb(i);
const char * key = s ? locale_string(lang, s) : 0;
if (key) {
char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), key);
if (str) {
critbit_tree * cb = (critbit_tree *)*tokens;
size_t len = strlen(str);
if (!cb) {
*tokens = cb = (critbit_tree *)calloc(1, sizeof(critbit_tree *));
}
len = cb_new_kv(str, len, &i, sizeof(int), buffer);
cb_insert(cb, buffer, len);
} else {
log_error("could not transliterate '%s'\n", key);
}
}
}
}
2012-05-22 03:09:30 +02:00
static const char * keyword_key(int i)
{
assert(i<MAXKEYWORDS&& i>=0);
return keywords[i];
}
static const char * parameter_key(int i)
{
assert(i<MAXPARAMS && i>=0);
return parameters[i];
}
static const char * skill_key(int sk)
{
assert(sk<MAXPARAMS && sk>=0);
return skill_enabled[sk] ? mkname("skill", skillnames[sk]) : 0;
}
2011-03-07 08:02:35 +01:00
static void init_locale(const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
variant var;
int i;
2011-03-07 08:02:35 +01:00
const struct race *rc;
const terrain_type *terrain;
void **tokens;
2010-08-08 10:06:34 +02:00
tokens = get_translations(lang, UT_MAGIC);
if (tokens) {
2011-03-07 08:02:35 +01:00
const char *str = get_param(global.parameters, "rules.magic.playerschools");
char *sstr, *tok;
if (str == NULL) {
2010-08-08 10:06:34 +02:00
str = "gwyrrd illaun draig cerddor tybied";
}
sstr = strdup(str);
tok = strtok(sstr, " ");
while (tok) {
2011-03-07 08:02:35 +01:00
for (i = 0; i != MAXMAGIETYP; ++i) {
if (strcmp(tok, magic_school[i]) == 0)
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
assert(i != MAXMAGIETYP);
2010-08-08 10:06:34 +02:00
var.i = i;
addtoken(tokens, LOC(lang, mkname("school", tok)), var);
tok = strtok(NULL, " ");
}
free(sstr);
}
tokens = get_translations(lang, UT_DIRECTIONS);
init_directions(tokens, lang);
tokens = get_translations(lang, UT_RACES);
2011-03-07 08:02:35 +01:00
for (rc = races; rc; rc = rc->next) {
var.v = (void *)rc;
2010-08-08 10:06:34 +02:00
addtoken(tokens, LOC(lang, rc_name(rc, 1)), var);
addtoken(tokens, LOC(lang, rc_name(rc, 0)), var);
}
init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
init_translations(lang, UT_SKILLS, skill_key, MAXSKILLS);
2012-05-22 03:09:30 +02:00
init_translations(lang, UT_KEYWORDS, keyword_key, MAXKEYWORDS);
2010-08-08 10:06:34 +02:00
tokens = get_translations(lang, UT_OPTIONS);
2011-03-07 08:02:35 +01:00
for (i = 0; i != MAXOPTIONS; ++i) {
2010-08-08 10:06:34 +02:00
var.i = i;
2011-03-07 08:02:35 +01:00
if (options[i])
addtoken(tokens, LOC(lang, options[i]), var);
2010-08-08 10:06:34 +02:00
}
tokens = get_translations(lang, UT_TERRAINS);
2011-03-07 08:02:35 +01:00
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
var.v = (void *)terrain;
2010-08-08 10:06:34 +02:00
addtoken(tokens, LOC(lang, terrain->_name), var);
}
}
typedef struct param {
2011-03-07 08:02:35 +01:00
struct param *next;
char *name;
char *data;
2010-08-08 10:06:34 +02:00
} param;
2011-03-07 08:02:35 +01:00
int getid(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *str = (const char *)getstrtoken();
2010-08-08 10:06:34 +02:00
int i = atoi36(str);
2011-03-07 08:02:35 +01:00
if (i < 0) {
2010-08-08 10:06:34 +02:00
return -1;
}
return i;
}
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
{
2011-03-07 08:02:35 +01:00
while (p != NULL) {
if (strcmp(p->name, key) == 0)
return p->data;
2010-08-08 10:06:34 +02:00
p = p->next;
}
return NULL;
}
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
{
2011-03-07 08:02:35 +01:00
while (p != NULL) {
if (strcmp(p->name, key) == 0)
return atoi(p->data);
2010-08-08 10:06:34 +02:00
p = p->next;
}
return def;
}
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];
2011-03-07 08:02:35 +01:00
if (g_datadir)
return g_datadir;
2010-08-08 10:06:34 +02:00
return strcat(strcpy(zText, basepath()), "/data");
}
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;
}
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];
2011-03-07 08:02:35 +01:00
if (g_reportdir)
return g_reportdir;
2010-08-08 10:06:34 +02:00
return strcat(strcpy(zText, basepath()), "/reports");
}
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;
}
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
{
2011-03-07 08:02:35 +01:00
if (g_basedir)
return g_basedir;
2010-08-08 10:06:34 +02:00
return ".";
}
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;
}
2011-03-07 08:02:35 +01:00
float get_param_flt(const struct param *p, const char *key, float def)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (p != NULL) {
if (strcmp(p->name, key) == 0)
return (float)atof(p->data);
2010-08-08 10:06:34 +02:00
p = p->next;
}
return def;
}
2011-03-07 08:02:35 +01:00
void set_param(struct param **p, const char *key, const char *data)
2010-08-08 10:06:34 +02:00
{
++global.cookie;
2011-03-07 08:02:35 +01:00
while (*p != NULL) {
if (strcmp((*p)->name, key) == 0) {
2010-08-08 10:06:34 +02:00
free((*p)->data);
(*p)->data = strdup(data);
return;
}
2011-03-07 08:02:35 +01:00
p = &(*p)->next;
2010-08-08 10:06:34 +02:00
}
*p = malloc(sizeof(param));
(*p)->name = strdup(key);
(*p)->data = strdup(data);
(*p)->next = NULL;
}
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();
gc_done();
sql_done();
}
2011-03-07 08:02:35 +01:00
const char *localenames[] = {
2010-08-08 10:06:34 +02:00
"de", "en",
NULL
};
2011-03-07 08:02:35 +01:00
void init_locales(void)
2010-08-08 10:06:34 +02:00
{
int l;
2011-03-07 08:02:35 +01:00
for (l = 0; localenames[l]; ++l) {
const struct locale *lang = find_locale(localenames[l]);
if (lang)
init_locale(lang);
2010-08-08 10:06:34 +02:00
}
}
/* TODO: soll hier weg */
extern struct attrib_type at_shiptrail;
attrib_type at_germs = {
"germs",
DEFAULT_INIT,
DEFAULT_FINALIZE,
DEFAULT_AGE,
a_writeshorts,
a_readshorts,
ATF_UNIQUE
};
/*********************/
/* at_guard */
/*********************/
attrib_type at_guard = {
"guard",
DEFAULT_INIT,
DEFAULT_FINALIZE,
DEFAULT_AGE,
a_writeint,
a_readint,
ATF_UNIQUE
};
2011-03-07 08:02:35 +01:00
void setstatus(struct unit *u, int status)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01: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
}
}
2011-03-07 08:02:35 +01:00
void setguard(unit * u, unsigned int flags)
2010-08-08 10:06:34 +02:00
{
/* setzt die guard-flags der Einheit */
2011-03-07 08:02:35 +01:00
attrib *a = NULL;
assert(flags == 0 || !fval(u, UFL_MOVED));
assert(flags == 0 || u->status < ST_FLEE);
2010-08-08 10:06:34 +02:00
if (fval(u, UFL_GUARD)) {
a = a_find(u->attribs, &at_guard);
}
if (flags == GUARD_NONE) {
freset(u, UFL_GUARD);
2011-03-07 08:02:35 +01:00
if (a)
a_remove(&u->attribs, a);
2010-08-08 10:06:34 +02:00
return;
}
fset(u, UFL_GUARD);
fset(u->region, RF_GUARDED);
2011-03-07 08:02:35 +01:00
if ((int)flags == guard_flags(u)) {
if (a)
a_remove(&u->attribs, a);
2010-08-08 10:06:34 +02:00
} else {
2011-03-07 08:02:35 +01:00
if (!a)
a = a_add(&u->attribs, a_new(&at_guard));
2010-08-08 10:06:34 +02:00
a->data.i = (int)flags;
}
}
2011-03-07 08:02:35 +01:00
unsigned int getguard(const unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib *a;
assert(fval(u, UFL_GUARD) || (u->building && u==building_owner(u->building))
2011-03-07 08:02:35 +01:00
|| !"you're doing it wrong! check is_guard first");
2010-08-08 10:06:34 +02:00
a = a_find(u->attribs, &at_guard);
if (a) {
return (unsigned int)a->data.i;
}
return guard_flags(u);
}
#ifndef HAVE_STRDUP
2011-03-07 08:02:35 +01:00
char *strdup(const char *s)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return strcpy((char *)malloc(sizeof(char) * (strlen(s) + 1)), s);
2010-08-08 10:06:34 +02:00
}
#endif
2011-03-07 08:02:35 +01:00
void remove_empty_factions(void)
2010-08-08 10:06:34 +02:00
{
faction **fp, *f3;
for (fp = &factions; *fp;) {
2011-03-07 08:02:35 +01:00
faction *f = *fp;
2010-08-08 10:06:34 +02:00
/* monster (0) werden nicht entfernt. alive kann beim readgame
* () auf 0 gesetzt werden, wenn monsters keine einheiten mehr
* haben. */
2011-03-07 08:02:35 +01:00
if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) {
ursprung *ur = f->ursprung;
while (ur && ur->id != 0)
ur = ur->next;
if (verbosity >= 2)
2012-05-16 07:21:59 +02:00
log_printf(stdout, "\t%s\n", factionname(f));
2010-08-08 10:06:34 +02:00
/* Einfach in eine Datei schreiben und sp<73>ter vermailen */
2011-03-07 08:02:35 +01:00
if (updatelog)
fprintf(updatelog, "dropout %s\n", itoa36(f->no));
2010-08-08 10:06:34 +02:00
for (f3 = factions; f3; f3 = f3->next) {
2011-03-07 08:02:35 +01:00
ally *sf;
group *g;
ally **sfp = &f3->allies;
2010-08-08 10:06:34 +02:00
while (*sfp) {
sf = *sfp;
if (sf->faction == f || sf->faction == NULL) {
*sfp = sf->next;
free(sf);
2011-03-07 08:02:35 +01:00
} else
sfp = &(*sfp)->next;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
for (g = f3->groups; g; g = g->next) {
2010-08-08 10:06:34 +02:00
sfp = &g->allies;
while (*sfp) {
sf = *sfp;
if (sf->faction == f || sf->faction == NULL) {
*sfp = sf->next;
free(sf);
2011-03-07 08:02:35 +01:00
} else
sfp = &(*sfp)->next;
2010-08-08 10:06:34 +02:00
}
}
}
if (f->subscription) {
sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n",
2011-03-07 08:02:35 +01:00
f->subscription));
2010-08-08 10:06:34 +02:00
}
*fp = f->next;
funhash(f);
free_faction(f);
free(f);
2011-03-07 08:02:35 +01:00
} else
fp = &(*fp)->next;
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
void remove_empty_units_in_region(region * r)
2010-08-08 10:06:34 +02:00
{
unit **up = &r->units;
while (*up) {
2011-03-07 08:02:35 +01:00
unit *u = *up;
2010-08-08 10:06:34 +02:00
if (u->number) {
2011-03-07 08:02:35 +01:00
faction *f = u->faction;
if (f == NULL || !f->alive) {
2010-08-08 10:06:34 +02:00
set_number(u, 0);
}
2011-03-07 08:02:35 +01:00
if (MaxAge() > 0) {
2010-08-08 10:06:34 +02:00
if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) {
set_number(u, 0);
}
}
}
2011-03-07 08:02:35 +01:00
if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0
&& u->race == new_race[RC_SPELL])) {
2010-08-08 10:06:34 +02:00
remove_unit(up, u);
}
2011-03-07 08:02:35 +01:00
if (*up == u)
up = &u->next;
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
void remove_empty_units(void)
2010-08-08 10:06:34 +02:00
{
region *r;
for (r = regions; r; r = r->next) {
remove_empty_units_in_region(r);
}
}
bool faction_id_is_unused(int id)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return findfaction(id) == NULL;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int weight(const unit * u)
2010-08-08 10:06:34 +02:00
{
int w, n = 0, in_bag = 0;
2011-03-07 08:02:35 +01:00
item *itm;
for (itm = u->items; itm; itm = itm->next) {
2010-08-08 10:06:34 +02:00
w = itm->type->weight * itm->number;
n += w;
2011-03-07 08:02:35 +01:00
if (!fval(itm->type, ITF_BIG))
2010-08-08 10:06:34 +02:00
in_bag += w;
}
n += u->number * u->race->weight;
w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY;
2011-03-07 08:02:35 +01:00
if (w > in_bag)
2010-08-08 10:06:34 +02:00
w = in_bag;
n -= w;
return n;
}
2011-03-07 08:02:35 +01:00
void make_undead_unit(unit * u)
2010-08-08 10:06:34 +02:00
{
free_orders(&u->orders);
name_unit(u);
fset(u, UFL_ISNEW);
}
2011-03-07 08:02:35 +01:00
unsigned int guard_flags(const unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
unsigned int flags =
GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX;
2010-08-08 10:06:34 +02:00
#if GUARD_DISABLES_PRODUCTION == 1
flags |= GUARD_PRODUCE;
#endif
#if GUARD_DISABLES_RECRUIT == 1
flags |= GUARD_RECRUIT;
#endif
switch (old_race(u->race)) {
2011-03-08 08:44:20 +01:00
case RC_ELF:
if (u->faction->race != u->race)
2011-03-07 08:02:35 +01:00
break;
2011-03-08 08:44:20 +01:00
/* else fallthrough */
case RC_TREEMAN:
flags |= GUARD_TREES;
break;
case RC_IRONKEEPER:
flags = GUARD_MINING;
break;
default:
/* TODO: This should be configuration variables, all of it */
break;
2010-08-08 10:06:34 +02:00
}
return flags;
}
2011-03-07 08:02:35 +01:00
void guard(unit * u, unsigned int mask)
2010-08-08 10:06:34 +02:00
{
unsigned int flags = guard_flags(u);
setguard(u, flags & mask);
}
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 && !global.disabled[K_BESIEGE]
2011-03-07 08:02:35 +01:00
&& u->building && u->building->besieged
&& u->building->besieged >= u->building->size * SIEGEFACTOR);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int lifestyle(const unit * u)
2010-08-08 10:06:34 +02:00
{
int need;
2011-03-07 08:02:35 +01:00
plane *pl;
2010-08-08 10:06:34 +02:00
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (gamecookie != global.cookie) {
2010-08-08 10:06:34 +02:00
gamecookie = global.cookie;
}
2011-03-07 08:02:35 +01:00
if (is_monsters(u->faction))
return 0;
2010-08-08 10:06:34 +02:00
need = maintenance_cost(u);
pl = rplane(u->region);
if (pl && fval(pl, PFL_NOFEED))
return 0;
return need;
}
bool has_horses(const struct unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item *itm = u->items;
for (; itm; itm = itm->next) {
if (itm->type->flags & ITF_ANIMAL)
return true;
2010-08-08 10:06:34 +02:00
}
return false;
}
bool hunger(int number, unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region *r = u->region;
2010-08-08 10:06:34 +02:00
int dead = 0, hpsub = 0;
int hp = u->hp / u->number;
2011-03-07 08:02:35 +01:00
static const char *damage = 0;
static const char *rcdamage = 0;
static const race *rc = 0;
2010-08-08 10:06:34 +02:00
if (!damage) {
damage = get_param(global.parameters, "hunger.damage");
2011-03-07 08:02:35 +01:00
if (damage == NULL)
damage = "1d12+12";
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (rc != u->race) {
2010-08-08 10:06:34 +02:00
rcdamage = get_param(u->race->parameters, "hunger.damage");
rc = u->race;
}
while (number--) {
2011-03-07 08:02:35 +01:00
int dam = dice_rand(rcdamage ? rcdamage : damage);
2010-08-08 10:06:34 +02:00
if (dam >= hp) {
++dead;
} else {
hpsub += dam;
}
}
if (dead) {
/* Gestorbene aus der Einheit nehmen,
* Sie bekommen keine Beerdingung. */
ADDMSG(&u->faction->msgs, msg_message("starvation",
2011-03-07 08:02:35 +01:00
"unit region dead live", u, r, dead, u->number - dead));
2010-08-08 10:06:34 +02:00
scale_number(u, u->number - dead);
deathcounts(r, dead);
}
if (hpsub > 0) {
/* Jetzt die Sch<63>den der nicht gestorbenen abziehen. */
u->hp -= hpsub;
/* Meldung nur, wenn noch keine f<>r Tote generiert. */
if (dead == 0) {
/* Durch unzureichende Ern<72>hrung wird %s geschw<68>cht */
2011-03-07 08:02:35 +01:00
ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r));
2010-08-08 10:06:34 +02:00
}
}
return (dead || hpsub);
}
void plagues(region * r, bool ismagic)
2010-08-08 10:06:34 +02:00
{
int peasants;
int i;
int dead = 0;
/* Seuchenwahrscheinlichkeit in % */
if (!ismagic) {
double mwp = MAX(maxworkingpeasants(r), 1);
2011-03-07 08:02:35 +01:00
double prob =
pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0)
* PLAGUE_CHANCE;
if (rng_double() >= prob)
return;
2010-08-08 10:06:34 +02:00
}
peasants = rpeasants(r);
dead = (int)(0.5F + PLAGUE_VICTIMS * peasants);
for (i = dead; i != 0; i--) {
if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) {
rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST);
--dead;
}
}
if (dead > 0) {
2011-03-07 08:02:35 +01:00
message *msg = add_message(&r->msgs, msg_message("pest", "dead", dead));
2010-08-08 10:06:34 +02:00
msg_release(msg);
deathcounts(r, dead);
rsetpeasants(r, peasants - dead);
}
}
/* Lohn bei den einzelnen Burgstufen f<>r Normale Typen, Orks, Bauern,
* Modifikation f<EFBFBD>r St<EFBFBD>dter. */
static const int wagetable[7][4] = {
2011-03-07 08:02:35 +01:00
{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
{
2011-03-07 08:02:35 +01:00
static const struct building_type *bt_castle;
if (!bt_castle)
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;
2010-08-08 10:06:34 +02:00
}
return -1;
}
bool is_owner_building(const struct building * b)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region *r = b->region;
2010-08-08 10:06:34 +02:00
if (b->type->taxes && r->land && r->land->ownership) {
2011-03-07 08:02:35 +01:00
unit *u = building_owner(b);
2010-08-08 10:06:34 +02:00
return u && u->faction == r->land->ownership->owner;
}
return false;
}
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
{
2011-03-07 08:02:35 +01:00
faction *f = region_get_owner(b->region);
2010-08-08 10:06:34 +02:00
if (b->type->taxes) {
2011-03-07 08:02:35 +01:00
unit *u = building_owner(b);
2010-08-08 10:06:34 +02:00
if (!u) {
return -1;
} 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);
2011-03-07 08:02:35 +01:00
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;
2010-08-08 10:06:34 +02:00
else {
2011-03-07 08:02:35 +01:00
if (u && u->faction == f) {
2010-08-08 10:06:34 +02:00
u = building_owner(a);
2011-03-07 08:02:35 +01:00
if (u && u->faction == f)
return -1;
2010-08-08 10:06:34 +02:00
return 1;
}
}
} else {
return 1;
}
}
return -1;
}
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
{
2011-03-07 08:02:35 +01: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) {
2011-03-07 08:02:35 +01:00
unit *u = building_owner(b);
if (!u || u->faction != f)
return -1;
2010-08-08 10:06:34 +02:00
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);
2011-03-07 08:02:35 +01:00
if (newtaxes != oldtaxes)
return (newtaxes > oldtaxes) ? 1 : -1;
if (newsize != oldsize)
return newsize - oldsize;
return (b->size - a->size);
2010-08-08 10:06:34 +02:00
} else {
return 1;
}
}
return -1;
}
int rule_stealth_faction(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
rule = get_param_int(global.parameters, "rules.stealth.faction", 0xFF);
2010-08-08 10:06:34 +02:00
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
int rule_region_owners(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
2010-08-08 10:06:34 +02:00
rule = get_param_int(global.parameters, "rules.region_owners", 0);
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
int rule_auto_taxation(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
rule =
get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER);
2010-08-08 10:06:34 +02:00
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
int rule_blessed_harvest(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
rule =
get_param_int(global.parameters, "rules.magic.blessed_harvest",
HARVEST_WORK);
2010-08-08 10:06:34 +02:00
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
int rule_alliance_limit(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
2010-08-08 10:06:34 +02:00
rule = get_param_int(global.parameters, "rules.limit.alliance", 0);
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
int rule_faction_limit(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
2010-08-08 10:06:34 +02:00
rule = get_param_int(global.parameters, "rules.limit.faction", 0);
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
int rule_transfermen(void)
{
static int gamecookie = -1;
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0 || gamecookie != global.cookie) {
2010-08-08 10:06:34 +02:00
rule = get_param_int(global.parameters, "rules.transfermen", 1);
gamecookie = global.cookie;
2011-03-07 08:02:35 +01:00
assert(rule >= 0);
2010-08-08 10:06:34 +02:00
}
return rule;
}
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);
2011-03-07 08:02:35 +01:00
int esize = 0;
curse *c;
2010-08-08 10:06:34 +02:00
double wage;
2011-03-07 08:02:35 +01:00
attrib *a;
2010-08-08 10:06:34 +02:00
const building_type *artsculpture_type = bt_find("artsculpture");
2011-03-07 08:02:35 +01:00
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");
}
2011-03-07 08:02:35 +01:00
if (b != NULL) {
2010-08-08 10:06:34 +02:00
/* TODO: this reveals imaginary castles */
esize = buildingeffsize(b, false);
}
2011-03-07 08:02:35 +01:00
if (f != NULL) {
2010-08-08 10:06:34 +02:00
int index = 0;
2011-03-07 08:02:35 +01:00
if (rc == new_race[RC_ORC] || rc == new_race[RC_SNOTLING]) {
2010-08-08 10:06:34 +02:00
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];
}
2011-03-07 08:02:35 +01:00
if (rule_blessed_harvest() == HARVEST_WORK) {
2010-08-08 10:06:34 +02:00
/* E1 rules */
wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct));
}
}
/* Artsculpture: Income +5 */
2011-03-07 08:02:35 +01:00
for (b = r->buildings; b; b = b->next) {
if (b->type == artsculpture_type) {
2010-08-08 10:06:34 +02:00
wage += 5;
}
}
/* Godcurse: Income -10 */
if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) {
2011-03-07 08:02:35 +01:00
wage = MAX(0, wage - 10);
2010-08-08 10:06:34 +02:00
}
/* Bei einer D<>rre verdient man nur noch ein Viertel */
if (drought_ct) {
c = get_curse(r->attribs, drought_ct);
2011-03-07 08:02:35 +01:00
if (curse_active(c))
wage /= curse_geteffect(c);
2010-08-08 10:06:34 +02:00
}
a = a_find(r->attribs, &at_reduceproduction);
2011-03-07 08:02:35 +01:00
if (a)
wage = (wage * a->data.sa[0]) / 100;
2010-08-08 10:06:34 +02:00
return (int)wage;
}
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);
}
/* 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);
}
#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
{
2011-03-07 08:02:35 +01:00
if (u == NULL)
return MAINTENANCE;
2010-08-08 10:06:34 +02:00
if (global.functions.maintenance) {
int retval = global.functions.maintenance(u);
2011-03-07 08:02:35 +01:00
if (retval >= 0)
return retval;
2010-08-08 10:06:34 +02:00
}
return u->race->maintenance * u->number;
}
2011-03-07 08:02:35 +01:00
message *movement_error(unit * u, const char *token, order * ord,
int error_code)
2010-08-08 10:06:34 +02:00
{
direction_t d;
switch (error_code) {
2011-03-08 08:44:20 +01:00
case E_MOVE_BLOCKED:
d = finddirection(token, u->faction->locale);
return msg_message("moveblocked", "unit direction", u, d);
case E_MOVE_NOREGION:
return msg_feedback(u, ord, "unknowndirection", "dirname", token);
2010-08-08 10:06:34 +02:00
}
return NULL;
}
2011-03-07 08:02:35 +01:00
int movewhere(const unit * u, const char *token, region * r, region ** resultp)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region *r2;
2010-08-08 10:06:34 +02:00
direction_t d;
if (*token == '\0') {
*resultp = NULL;
return E_MOVE_OK;
}
d = finddirection(token, u->faction->locale);
switch (d) {
2011-03-08 08:44:20 +01:00
case D_PAUSE:
*resultp = r;
break;
case NODIRECTION:
r2 = find_special_direction(r, token, u->faction->locale);
if (r2 == NULL) {
return E_MOVE_NOREGION;
}
*resultp = r2;
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
default:
r2 = rconnect(r, d);
if (r2 == NULL || move_blocked(u, r, r2)) {
return E_MOVE_BLOCKED;
}
*resultp = r2;
2010-08-08 10:06:34 +02:00
}
return E_MOVE_OK;
}
bool move_blocked(const unit * u, const region * r, const region * r2)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
connection *b;
curse *c;
static const curse_type *fogtrap_ct = NULL;
if (r2 == NULL)
return true;
2010-08-08 10:06:34 +02:00
b = get_borders(r, r2);
while (b) {
2011-03-07 08:02:35 +01:00
if (b->type->block && b->type->block(b, u, r))
return true;
2010-08-08 10:06:34 +02:00
b = b->next;
}
2011-03-07 08:02:35 +01:00
if (fogtrap_ct == NULL)
fogtrap_ct = ct_find("fogtrap");
2010-08-08 10:06:34 +02:00
c = get_curse(r->attribs, fogtrap_ct);
2011-03-07 08:02:35 +01:00
if (curse_active(c))
return true;
2010-08-08 10:06:34 +02:00
return false;
}
2011-03-07 08:02:35 +01:00
void add_income(unit * u, int type, int want, int qty)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (want == INT_MAX)
want = qty;
ADDMSG(&u->faction->msgs, msg_message("income",
"unit region mode wanted amount", u, u->region, type, want, qty));
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int produceexp(struct unit *u, skill_t sk, int n)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (global.producexpchance > 0.0F) {
if (n == 0 || !playerrace(u->race))
return 0;
2010-08-08 10:06:34 +02:00
learn_skill(u, sk, global.producexpchance);
}
return 0;
}
2011-03-07 08:02:35 +01:00
int lovar(double xpct_x2)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01: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;
}
}
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_stealth);
at_register(&at_mage);
at_register(&at_countdown);
at_register(&at_curse);
at_register(&at_seenspell);
/* neue REGION-Attribute */
at_register(&at_direction);
at_register(&at_moveblock);
at_register(&at_deathcount);
at_register(&at_chaoscount);
at_register(&at_woodcount);
/* neue UNIT-Attribute */
at_register(&at_siege);
at_register(&at_effect);
at_register(&at_private);
at_register(&at_icastle);
at_register(&at_guard);
at_register(&at_group);
at_register(&at_building_generic_type);
at_register(&at_maxmagicians);
at_register(&at_npcfaction);
/* connection-typen */
register_bordertype(&bt_noway);
register_bordertype(&bt_fogwall);
register_bordertype(&bt_wall);
register_bordertype(&bt_illusionwall);
register_bordertype(&bt_road);
register_bordertype(&bt_questportal);
2011-03-07 08:02:35 +01: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 */
2010-08-08 10:06:34 +02:00
at_register(&at_speedup);
at_register(&at_building_action);
}
2011-03-07 08:02:35 +01:00
void kernel_init(void)
2010-08-08 10:06:34 +02:00
{
char zBuffer[MAX_PATH];
attrib_init();
translation_init();
if (sqlpatch) {
sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn);
sql_init(zBuffer);
}
}
static order * defaults[MAXLOCALES];
2011-03-07 08:02:35 +01:00
order *default_order(const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
int i = locale_index(lang);
order *result = 0;
assert(i<MAXLOCALES);
result = defaults[i];
if (!result) {
const char * str = locale_string(lang, "defaultorder");
if (str) {
result = defaults[i] = parse_order(str, lang);
}
}
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;
if (is_cursed(r->attribs, C_DEPRESSION, 0)) {
return 0;
}
n = rmoney(r) / ENTERTAINFRACTION;
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
n *= get_curseeffect(r->attribs, C_GENEROUS, 0);
}
return (int)n;
}
int rule_give(void)
{
static int value = -1;
2011-03-07 08:02:35 +01:00
if (value < 0) {
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT);
}
return value;
}
int markets_module(void)
{
static int value = -1;
2011-03-07 08:02:35 +01:00
if (value < 0) {
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "modules.markets", 0);
}
return value;
}
/** 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;
2010-08-08 10:06:34 +02:00
free_units();
free_regions();
free_borders();
for (i=0;i!=MAXLOCALES;++i) {
if (defaults[i]) {
free_order(defaults[i]);
defaults[i] = 0;
}
}
2010-08-08 10:06:34 +02:00
while (alliances) {
2011-03-07 08:02:35 +01:00
alliance *al = alliances;
2010-08-08 10:06:34 +02:00
alliances = al->next;
free_alliance(al);
}
while (factions) {
2011-03-07 08:02:35 +01:00
faction *f = factions;
2010-08-08 10:06:34 +02:00
factions = f->next;
funhash(f);
free_faction(f);
free(f);
}
while (planes) {
2011-03-07 08:02:35 +01:00
plane *pl = planes;
2010-08-08 10:06:34 +02:00
planes = planes->next;
free(pl->name);
free(pl);
}
while (global.attribs) {
a_remove(&global.attribs, global.attribs);
}
2011-03-07 08:02:35 +01:00
++global.cookie; /* readgame() already does this, but sjust in case */
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void load_inifile(dictionary * d)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *reportdir = reportpath();
const char *datadir = datapath();
const char *basedir = basepath();
const char *str;
2010-08-08 10:06:34 +02:00
assert(d);
str = iniparser_getstring(d, "eressea:base", basedir);
2011-03-07 08:02:35 +01:00
if (str != basedir)
set_basepath(str);
2010-08-08 10:06:34 +02:00
str = iniparser_getstring(d, "eressea:report", reportdir);
2011-03-07 08:02:35 +01:00
if (str != reportdir)
set_reportpath(str);
2010-08-08 10:06:34 +02:00
str = iniparser_getstring(d, "eressea:data", datadir);
2011-03-07 08:02:35 +01:00
if (str != datadir)
set_datapath(str);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
lomem = iniparser_getint(d, "eressea:lomem", lomem) ? 1 : 0;
2010-08-08 10:06:34 +02:00
str = iniparser_getstring(d, "eressea:encoding", NULL);
2011-03-07 08:02:35 +01:00
if (str)
enc_gamedata = xmlParseCharEncoding(str);
2010-08-08 10:06:34 +02:00
verbosity = iniparser_getint(d, "eressea:verbose", 2);
sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false);
2011-03-07 08:02:35 +01:00
battledebug = iniparser_getint(d, "eressea:debug", battledebug) ? 1 : 0;
2010-08-08 10:06:34 +02:00
str = iniparser_getstring(d, "eressea:locales", "de,en");
make_locales(str);
/* excerpt from [config] (the rest is used in bindings.c) */
game_name = iniparser_getstring(d, "config:game", game_name);
global.inifile = d;
}