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>
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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"
|
2012-06-30 20:07:28 +02:00
|
|
|
|
#include "ally.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include "alchemy.h"
|
2014-12-25 18:16:24 +01:00
|
|
|
|
#include "curse.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include "connection.h"
|
|
|
|
|
#include "building.h"
|
|
|
|
|
#include "calendar.h"
|
2014-06-16 03:34:39 +02:00
|
|
|
|
#include "direction.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "group.h"
|
|
|
|
|
#include "item.h"
|
2014-06-16 17:01:59 +02:00
|
|
|
|
#include "keyword.h"
|
2014-06-09 18:54:48 +02:00
|
|
|
|
#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"
|
2014-07-06 05:14:11 +02:00
|
|
|
|
#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"
|
2014-11-01 12:09:56 +01:00
|
|
|
|
#include "types.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include "unit.h"
|
|
|
|
|
|
2015-09-12 23:38:31 +02:00
|
|
|
|
|
2014-06-17 07:19:19 +02:00
|
|
|
|
#include <kernel/spell.h>
|
|
|
|
|
#include <kernel/spellbook.h>
|
2014-11-01 12:09:56 +01:00
|
|
|
|
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* util includes */
|
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
#include <util/base36.h>
|
2011-02-25 16:23:02 +01:00
|
|
|
|
#include <util/bsdstring.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/crmessage.h>
|
|
|
|
|
#include <util/event.h>
|
|
|
|
|
#include <util/language.h>
|
2014-06-10 05:14:08 +02:00
|
|
|
|
#include <util/functions.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/log.h>
|
|
|
|
|
#include <util/lists.h>
|
|
|
|
|
#include <util/parser.h>
|
2012-05-31 04:55:17 +02:00
|
|
|
|
#include <quicklist.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/rand.h>
|
|
|
|
|
#include <util/rng.h>
|
|
|
|
|
#include <util/translation.h>
|
2011-02-25 16:23:02 +01:00
|
|
|
|
#include <util/unicode.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/umlaut.h>
|
|
|
|
|
#include <util/xml.h>
|
|
|
|
|
|
2015-09-09 15:45:20 +02:00
|
|
|
|
#include "donations.h"
|
2015-09-12 23:38:31 +02:00
|
|
|
|
#include "guard.h"
|
2015-09-12 12:29:42 +02:00
|
|
|
|
#include "prefix.h"
|
2015-09-09 15:45:20 +02:00
|
|
|
|
|
2014-06-10 05:14:08 +02:00
|
|
|
|
#ifdef USE_LIBXML2
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* libxml includes */
|
|
|
|
|
#include <libxml/tree.h>
|
|
|
|
|
#include <libxml/xpath.h>
|
2014-06-10 05:14:08 +02:00
|
|
|
|
#endif
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2012-05-31 04:17:08 +02:00
|
|
|
|
/* external libraries */
|
2014-12-13 22:08:57 +01:00
|
|
|
|
#include <storage.h>
|
2012-05-31 04:17:08 +02:00
|
|
|
|
#include <iniparser.h>
|
2014-06-16 03:34:39 +02:00
|
|
|
|
#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 = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"Eressea", /* gamename */
|
2010-08-08 10:06:34 +02:00
|
|
|
|
};
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-05-04 22:49:06 +02:00
|
|
|
|
bool lomem = false;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
FILE *logfile;
|
2012-06-24 07:41:07 +02:00
|
|
|
|
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)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int value = -1;
|
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
if (value < 0 || gamecookie != global.cookie) {
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
value = get_param_int(global.parameters, "NewbieImmunity", 0);
|
|
|
|
|
}
|
|
|
|
|
return value;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool IsImmune(const faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool ExpensiveMigrants(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int value = -1;
|
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
if (value < 0 || gamecookie != global.cookie) {
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
value = get_param_int(global.parameters, "study.expensivemigrants", 0);
|
|
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
|
return value != 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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int value = -1;
|
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
if (value < 0 || gamecookie != global.cookie) {
|
|
|
|
|
const char *str = get_param(global.parameters, "alliance.auto");
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int rule = -1;
|
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
const char *str = get_param(global.parameters, "rules.help.mask");
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int rule = -1;
|
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
const char *str = get_param(global.parameters, "alliance.restricted");
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
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)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (u != NULL) {
|
|
|
|
|
if (!fval(u, UFL_HUNGER))
|
|
|
|
|
return false;
|
|
|
|
|
if (u_race(u) == get_race(RC_DAEMON))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
rule = get_param_int(global.parameters, "hunger.long", 0);
|
|
|
|
|
}
|
|
|
|
|
return rule;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int SkillCap(skill_t sk)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return rule;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int NMRTimeout(void)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
rule = get_param_int(global.parameters, "nmr.timeout", 0);
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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[] = {
|
2015-01-30 20:37:14 +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
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 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
|
|
|
|
{
|
2014-08-24 22:54:40 +02:00
|
|
|
|
static char zText[32]; // FIXME: static return value
|
2014-07-23 11:54:51 +02:00
|
|
|
|
char *zPtr = zText;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
/* the english names are all in ASCII, so we don't need to worry about UTF8 */
|
2015-10-30 11:41:59 +01:00
|
|
|
|
strlcpy(zText, (const char *)LOC(get_locale("en"), rc_name_s(rc, NAME_SINGULAR)), sizeof(zText));
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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] = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"LOCALE",
|
|
|
|
|
"ALLES",
|
|
|
|
|
"JEDEM",
|
|
|
|
|
"BAUERN",
|
|
|
|
|
"BURG",
|
|
|
|
|
"EINHEIT",
|
|
|
|
|
"PRIVAT",
|
|
|
|
|
"HINTEN",
|
|
|
|
|
"KOMMANDO",
|
|
|
|
|
"KRAEUTER",
|
|
|
|
|
"NICHT",
|
|
|
|
|
"NAECHSTER",
|
|
|
|
|
"PARTEI",
|
|
|
|
|
"ERESSEA",
|
|
|
|
|
"PERSONEN",
|
|
|
|
|
"REGION",
|
|
|
|
|
"SCHIFF",
|
|
|
|
|
"SILBER",
|
|
|
|
|
"STRASSEN",
|
2014-08-17 14:24:19 +02:00
|
|
|
|
"TEMP",
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"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] = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"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] = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"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] = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
a->data.i = MAXMAGICIANS;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static attrib_type at_maxmagicians = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int m =
|
|
|
|
|
get_param_int(global.parameters, "rules.maxskills.magic", MAXMAGICIANS);
|
|
|
|
|
attrib *a;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-07-23 11:54:51 +02: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
|
|
|
|
}
|
|
|
|
|
|
2014-06-21 08:59:04 +02:00
|
|
|
|
static void init_npcfaction(struct attrib *a)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
a->data.i = 1;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-21 08:59:04 +02:00
|
|
|
|
static attrib_type at_npcfaction = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"npcfaction",
|
|
|
|
|
init_npcfaction,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
a_writeint,
|
|
|
|
|
a_readint,
|
|
|
|
|
ATF_UNIQUE
|
2014-06-21 08:59:04 +02:00
|
|
|
|
};
|
|
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int i;
|
|
|
|
|
int t;
|
|
|
|
|
assert(new_value <= old);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (old == 0)
|
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return t;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-10 23:04:54 +01:00
|
|
|
|
bool unit_has_cursed_item(const unit * u)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (f_get_alliance(sf) != NULL && AllianceAuto()) {
|
|
|
|
|
if (sf->alliance == f2->alliance)
|
|
|
|
|
return AllianceAuto();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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,
|
2014-07-23 11:54:51 +02:00
|
|
|
|
const struct faction *f2, const struct ally *sf, int mode)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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,
|
2014-07-23 11:54:51 +02:00
|
|
|
|
const struct faction *f2, int mode)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
ally *sf;
|
|
|
|
|
int automode;
|
|
|
|
|
|
2015-08-02 21:17:21 +02:00
|
|
|
|
assert(u);
|
|
|
|
|
assert(f2);
|
2014-07-23 11:54:51 +02: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);
|
|
|
|
|
/* helps the owner of the region */
|
|
|
|
|
if (owner == f2) {
|
|
|
|
|
return HELP_FIGHT;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
pl = rplane(u->region);
|
|
|
|
|
automode = mode & autoalliance(pl, u->faction, f2);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (pl != NULL && (pl->flags & PFL_NOALLIANCES))
|
|
|
|
|
mode = (mode & automode) | (mode & HELP_GIVE);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-25 05:25:06 +02:00
|
|
|
|
int count_faction(const faction * f, int flags)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-04-26 21:24:51 +02:00
|
|
|
|
unit *u;
|
2014-05-25 05:25:06 +02:00
|
|
|
|
int n = 0;
|
2014-04-26 21:24:51 +02:00
|
|
|
|
for (u = f->units; u; u = u->nextF) {
|
2014-05-25 05:25:06 +02:00
|
|
|
|
const race *rc = u_race(u);
|
|
|
|
|
int x = (flags&COUNT_UNITS) ? 1 : u->number;
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (f->race != rc) {
|
2014-05-25 05:25:06 +02:00
|
|
|
|
if (!playerrace(rc)) {
|
|
|
|
|
if (flags&COUNT_MONSTERS) {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
n += x;
|
2014-05-25 05:25:06 +02:00
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
}
|
|
|
|
|
else if (flags&COUNT_MIGRANTS) {
|
2014-05-25 05:25:06 +02:00
|
|
|
|
if (!is_cursed(u->attribs, C_SLAVE, 0)) {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
n += x;
|
2014-05-25 05:25:06 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
}
|
|
|
|
|
else if (flags&COUNT_DEFAULT) {
|
|
|
|
|
n += x;
|
2014-04-26 21:24:51 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-25 05:25:06 +02:00
|
|
|
|
return n;
|
2014-04-26 21:24:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int count_units(const faction * f)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return count_faction(f, COUNT_ALL | COUNT_UNITS);
|
2014-05-25 05:25:06 +02:00
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
2014-05-25 05:25:06 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int migrants = -1;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (migrants < 0) {
|
2015-09-11 10:04:08 +02:00
|
|
|
|
migrants = get_param_int(global.parameters, "rules.migrants.max", INT_MAX);
|
2014-07-23 11:54:51 +02:00
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return migrants;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
void **tokens = get_translations(lang, UT_RACES);
|
|
|
|
|
variant token;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
void **tokens = get_translations(lang, UT_OPTIONS);
|
|
|
|
|
variant token;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-03 06:17:31 +02:00
|
|
|
|
param_t result = NOPARAM;
|
|
|
|
|
char buffer[64];
|
2014-08-23 09:17:58 +02:00
|
|
|
|
char * str = s ? transliterate(buffer, sizeof(buffer) - sizeof(int), s) : 0;
|
2014-07-23 11:54:51 +02:00
|
|
|
|
|
2014-07-03 06:17:31 +02:00
|
|
|
|
if (str && *str) {
|
|
|
|
|
int i;
|
2015-07-12 10:35:09 +02:00
|
|
|
|
void * match;
|
2014-07-03 06:17:31 +02:00
|
|
|
|
void **tokens = get_translations(lang, UT_PARAMS);
|
|
|
|
|
critbit_tree *cb = (critbit_tree *)*tokens;
|
|
|
|
|
if (!cb) {
|
2014-08-11 12:02:16 +02:00
|
|
|
|
log_error("no parameters defined in locale %s", locale_name(lang));
|
2014-07-03 06:17:31 +02:00
|
|
|
|
}
|
|
|
|
|
else if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) {
|
|
|
|
|
cb_get_kv(match, &i, sizeof(int));
|
|
|
|
|
result = (param_t)i;
|
|
|
|
|
}
|
2012-05-16 21:06:44 +02:00
|
|
|
|
}
|
2014-07-03 06:17:31 +02:00
|
|
|
|
return result;
|
2012-05-16 21:06:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
param_t findparam_ex(const char *s, const struct locale * lang)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
param_t result = findparam(s, lang);
|
2012-05-16 21:06:44 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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)
|
2012-05-16 21:06:44 +02:00
|
|
|
|
{
|
2014-08-23 09:17:58 +02:00
|
|
|
|
assert(s);
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (s[0] > '@') {
|
|
|
|
|
param_t p = (param == P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang);
|
|
|
|
|
return p == param;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2012-05-16 21:06:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
param_t getparam(const struct locale * lang)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-22 16:28:17 +01:00
|
|
|
|
char token[64];
|
|
|
|
|
const char *s = gettoken(token, sizeof(token));
|
2014-09-21 16:43:17 +02:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int n;
|
|
|
|
|
n = getid();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int n;
|
|
|
|
|
unit *u2;
|
|
|
|
|
n = getid();
|
|
|
|
|
if (n == 0)
|
|
|
|
|
return -1;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
u2 = findnewunit(r, f, n);
|
|
|
|
|
if (u2)
|
|
|
|
|
return u2->no;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-12-24 15:55:55 +01:00
|
|
|
|
char token[16];
|
2014-12-22 16:28:17 +01:00
|
|
|
|
const char *s = gettoken(token, sizeof(token));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2015-09-05 19:48:25 +02:00
|
|
|
|
if (!s || *s == 0 || !isalnum(*s)) {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2014-12-12 20:53:39 +01:00
|
|
|
|
int getunit(const region * r, const faction * f, unit **uresult)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-14 15:23:28 +01:00
|
|
|
|
unit *u2 = NULL;
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int n = read_unitid(f, r);
|
2014-12-12 21:55:44 +01:00
|
|
|
|
int result = GET_NOTFOUND;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (n == 0) {
|
2014-12-12 21:55:44 +01:00
|
|
|
|
result = GET_PEASANTS;
|
2014-07-23 11:54:51 +02:00
|
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
|
else if (n > 0) {
|
2014-12-12 21:55:44 +01:00
|
|
|
|
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;
|
2014-12-12 21:06:47 +01:00
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
}
|
2014-12-12 21:06:47 +01:00
|
|
|
|
if (uresult) {
|
|
|
|
|
*uresult = u2;
|
|
|
|
|
}
|
2014-12-12 21:55:44 +01:00
|
|
|
|
return result;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* - Namen der Strukturen -------------------------------------- */
|
2014-12-09 05:55:16 +01:00
|
|
|
|
char *untilde(char *ibuf)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
char *p = ibuf;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
while (*p) {
|
|
|
|
|
if (*p == '~') {
|
|
|
|
|
*p = ' ';
|
|
|
|
|
}
|
|
|
|
|
++p;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-07-23 11:54:51 +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,
|
2014-07-23 11:54:51 +02:00
|
|
|
|
bool imaginary)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
building *b, *best = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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 };
|
2015-09-05 19:25:55 +02:00
|
|
|
|
// 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
|
|
|
|
{
|
2014-07-23 11:54:51 +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) {
|
2015-05-15 19:08:44 +02:00
|
|
|
|
forbid[i] = atoi36(forbidden[i]);
|
2014-07-23 11:54:51 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int random_no;
|
|
|
|
|
int start_random_no;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
random_no = 1 + (rng_int() % MAX_CONTAINER_NR);
|
|
|
|
|
start_random_no = random_no;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-09-18 12:10:42 +02:00
|
|
|
|
int size = production(r);
|
|
|
|
|
int treespace = (rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE;
|
2015-01-30 20:37:14 +01:00
|
|
|
|
return _max(size - treespace, _min(size / 10, 200));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-22 02:45:54 +02:00
|
|
|
|
static const char * parameter_key(int i)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
assert(i < MAXPARAMS && i >= 0);
|
|
|
|
|
return parameters[i];
|
2012-05-22 02:45:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-05 12:19:17 +02:00
|
|
|
|
void init_parameters(struct locale *lang) {
|
|
|
|
|
init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-17 00:45:45 +02:00
|
|
|
|
|
|
|
|
|
void init_terrains_translation(const struct locale *lang) {
|
|
|
|
|
void **tokens;
|
|
|
|
|
const terrain_type *terrain;
|
2014-07-23 11:54:51 +02:00
|
|
|
|
|
2014-07-17 00:45:45 +02:00
|
|
|
|
tokens = get_translations(lang, UT_TERRAINS);
|
|
|
|
|
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
|
|
|
|
|
variant var;
|
|
|
|
|
const char *name;
|
|
|
|
|
var.v = (void *)terrain;
|
2015-01-08 20:55:29 +01:00
|
|
|
|
name = locale_string(lang, terrain->_name, false);
|
2014-07-17 00:45:45 +02:00
|
|
|
|
if (name) {
|
|
|
|
|
addtoken(tokens, name, var);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2015-01-08 20:55:29 +01:00
|
|
|
|
log_debug("no translation for terrain %s in locale %s", terrain->_name, locale_name(lang));
|
2014-07-17 00:45:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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]) {
|
2015-01-08 20:55:29 +01:00
|
|
|
|
const char *name = locale_string(lang, options[i], false);
|
2014-07-17 00:45:45 +02:00
|
|
|
|
if (name) {
|
|
|
|
|
addtoken(tokens, name, var);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2015-01-08 20:55:29 +01:00
|
|
|
|
log_debug("no translation for OPTION %s in locale %s", options[i], locale_name(lang));
|
2014-07-17 00:45:45 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-29 21:19:07 +02:00
|
|
|
|
void init_locale(struct locale *lang)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-06-14 16:52:32 +02:00
|
|
|
|
variant var;
|
|
|
|
|
int i;
|
|
|
|
|
const struct race *rc;
|
|
|
|
|
void **tokens;
|
|
|
|
|
|
|
|
|
|
tokens = get_translations(lang, UT_MAGIC);
|
|
|
|
|
if (tokens) {
|
|
|
|
|
const char *str = get_param(global.parameters, "rules.magic.playerschools");
|
|
|
|
|
char *sstr, *tok;
|
|
|
|
|
if (str == NULL) {
|
|
|
|
|
str = "gwyrrd illaun draig cerddor tybied";
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-06-14 16:52:32 +02:00
|
|
|
|
sstr = _strdup(str);
|
|
|
|
|
tok = strtok(sstr, " ");
|
|
|
|
|
while (tok) {
|
2014-07-17 00:45:45 +02:00
|
|
|
|
const char *name;
|
2014-06-14 16:52:32 +02:00
|
|
|
|
for (i = 0; i != MAXMAGIETYP; ++i) {
|
|
|
|
|
if (strcmp(tok, magic_school[i]) == 0) break;
|
|
|
|
|
}
|
|
|
|
|
assert(i != MAXMAGIETYP);
|
|
|
|
|
var.i = i;
|
2014-07-17 00:45:45 +02:00
|
|
|
|
name = LOC(lang, mkname("school", tok));
|
|
|
|
|
if (name) {
|
|
|
|
|
addtoken(tokens, name, var);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2015-06-19 13:17:01 +02:00
|
|
|
|
log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang));
|
2014-07-17 00:45:45 +02:00
|
|
|
|
}
|
2014-06-14 16:52:32 +02:00
|
|
|
|
tok = strtok(NULL, " ");
|
|
|
|
|
}
|
|
|
|
|
free(sstr);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-16 03:34:39 +02:00
|
|
|
|
init_directions(lang);
|
2014-06-16 17:01:59 +02:00
|
|
|
|
init_keywords(lang);
|
2014-06-21 23:39:56 +02:00
|
|
|
|
init_skills(lang);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-06-14 16:52:32 +02:00
|
|
|
|
tokens = get_translations(lang, UT_RACES);
|
|
|
|
|
for (rc = races; rc; rc = rc->next) {
|
2014-07-17 00:45:45 +02:00
|
|
|
|
const char *name;
|
2014-06-14 16:52:32 +02:00
|
|
|
|
var.v = (void *)rc;
|
2015-01-08 20:55:29 +01:00
|
|
|
|
name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
|
2014-07-17 00:45:45 +02:00
|
|
|
|
if (name) addtoken(tokens, name, var);
|
2015-01-08 20:55:29 +01:00
|
|
|
|
name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
|
2014-07-17 00:45:45 +02:00
|
|
|
|
if (name) addtoken(tokens, name, var);
|
2014-06-14 16:52:32 +02:00
|
|
|
|
}
|
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
|
|
|
|
|
2014-07-17 00:45:45 +02:00
|
|
|
|
init_options_translation(lang);
|
|
|
|
|
init_terrains_translation(lang);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct param {
|
2015-11-20 15:48:09 +01:00
|
|
|
|
critbit_tree cb;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
} param;
|
|
|
|
|
|
2015-11-20 15:48:09 +01:00
|
|
|
|
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) {
|
2015-11-20 15:48:09 +01:00
|
|
|
|
param *p = *pp;
|
|
|
|
|
if (p) {
|
|
|
|
|
cb_clear(&p->cb);
|
2015-09-05 18:14:28 +02:00
|
|
|
|
free(p);
|
|
|
|
|
}
|
2015-11-20 15:48:09 +01:00
|
|
|
|
*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
|
|
|
|
{
|
2015-11-20 15:48:09 +01: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
|
|
|
|
}
|
|
|
|
|
|
2014-08-08 13:29:26 +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;
|
2014-08-08 13:29:26 +02:00
|
|
|
|
const char *value = get_param(p, key);
|
|
|
|
|
if (!value) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-12-31 01:00:10 +01:00
|
|
|
|
char *p_value = _strdup(value);
|
2014-08-08 13:29:26 +02:00
|
|
|
|
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;
|
2014-08-08 13:29:26 +02:00
|
|
|
|
}
|
|
|
|
|
v = strtok(NULL, delimiter);
|
|
|
|
|
}
|
2014-12-31 01:00:10 +01:00
|
|
|
|
free(p_value);
|
|
|
|
|
return result;
|
2014-08-08 13:29:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-30 11:39:47 +01:00
|
|
|
|
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
|
|
|
|
{
|
2014-08-24 22:54:40 +02:00
|
|
|
|
static char zText[MAX_PATH]; // FIXME: static return value
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (g_datadir)
|
|
|
|
|
return g_datadir;
|
2015-10-30 11:39:47 +01:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-08-24 22:54:40 +02:00
|
|
|
|
static char zText[MAX_PATH]; // FIXME: static return value
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (g_reportdir)
|
|
|
|
|
return g_reportdir;
|
2015-10-30 11:39:47 +01:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
g_basedir = path;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-12 16:38:39 +02:00
|
|
|
|
double get_param_flt(const struct param *p, const char *key, double def)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-06-25 16:25:54 +02:00
|
|
|
|
const char *str = get_param(p, key);
|
2015-09-12 16:38:39 +02:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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();
|
2014-12-31 01:17:49 +01:00
|
|
|
|
free_attribs();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_germs = {
|
2014-07-23 11:54:51 +02:00
|
|
|
|
"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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
2013-12-29 14:38:58 +01:00
|
|
|
|
char *_strdup(const char *s)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return strcpy((char *)malloc(sizeof(char) * (strlen(s) + 1)), s);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool faction_id_is_unused(int id)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool has_horses(const struct unit * u)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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] = {
|
2015-01-30 20:37:14 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool is_owner_building(const struct building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
faction *f = region_get_owner(b->region);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return -1;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-09 13:36:52 +01:00
|
|
|
|
bool rule_stealth_other(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
2015-11-09 13:36:52 +01:00
|
|
|
|
rule = get_param_int(global.parameters, "stealth.faction.other", 1);
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
|
|
|
|
return rule != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rule_stealth_anon(void)
|
|
|
|
|
{
|
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule = get_param_int(global.parameters, "stealth.faction.anon", 1);
|
2014-07-23 11:54:51 +02:00
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
2015-09-11 10:04:08 +02:00
|
|
|
|
return rule!=0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-11 10:04:08 +02:00
|
|
|
|
bool rule_region_owners(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule = get_param_int(global.parameters, "rules.region_owners", 0);
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
2015-09-11 10:04:08 +02:00
|
|
|
|
return rule!=0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-09 13:36:52 +01:00
|
|
|
|
bool rule_auto_taxation(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule =
|
2015-11-09 13:36:52 +01:00
|
|
|
|
get_param_int(global.parameters, "rules.economy.taxation", 0);
|
2014-07-23 11:54:51 +02:00
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
|
|
|
|
return rule;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rule_blessed_harvest(void)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule =
|
2015-09-11 10:04:08 +02:00
|
|
|
|
get_param_int(global.parameters, "rules.blessed_harvest.flags",
|
2014-07-23 11:54:51 +02:00
|
|
|
|
HARVEST_WORK);
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
|
|
|
|
return rule;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rule_alliance_limit(void)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule = get_param_int(global.parameters, "rules.limit.alliance", 0);
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
|
|
|
|
return rule;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rule_faction_limit(void)
|
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule = get_param_int(global.parameters, "rules.limit.faction", 0);
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
|
|
|
|
return rule;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-11 10:04:08 +02:00
|
|
|
|
bool rule_transfermen(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int gamecookie = -1;
|
|
|
|
|
static int rule = -1;
|
|
|
|
|
if (rule < 0 || gamecookie != global.cookie) {
|
|
|
|
|
rule = get_param_int(global.parameters, "rules.transfermen", 1);
|
|
|
|
|
gamecookie = global.cookie;
|
|
|
|
|
assert(rule >= 0);
|
|
|
|
|
}
|
2015-09-11 10:04:08 +02:00
|
|
|
|
return rule!=0;
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool has_limited_skills(const struct unit * u)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
}
|
|
|
|
|
|
2014-12-13 22:08:57 +01: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
|
|
|
|
{
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
at_register(&at_seenspell);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
at_register(&at_icastle);
|
|
|
|
|
at_register(&at_guard);
|
|
|
|
|
at_register(&at_group);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
at_register(&at_building_generic_type);
|
|
|
|
|
at_register(&at_maxmagicians);
|
|
|
|
|
at_register(&at_npcfaction);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2015-11-03 13:24:58 +01:00
|
|
|
|
register_function((pf_generic)minimum_wage, "minimum_wage");
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
at_register(&at_germs);
|
2012-06-17 20:08:48 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */
|
2014-12-13 22:08:57 +01:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-06 05:14:11 +02:00
|
|
|
|
register_reports();
|
2015-08-17 19:35:07 +02:00
|
|
|
|
mt_clear();
|
2014-07-06 05:14:11 +02:00
|
|
|
|
attrib_init();
|
|
|
|
|
translation_init();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-16 22:07:28 +02:00
|
|
|
|
static order * defaults[MAXLOCALES];
|
2015-08-05 00:03:30 +02:00
|
|
|
|
keyword_t default_keyword = NOKEYWORD;
|
|
|
|
|
|
|
|
|
|
void set_default_order(int kwd) {
|
|
|
|
|
default_keyword = (keyword_t)kwd;
|
|
|
|
|
}
|
2012-05-16 22:07:28 +02:00
|
|
|
|
|
2015-10-14 12:51:45 +02:00
|
|
|
|
// 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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
static int usedefault = 1;
|
|
|
|
|
int i = locale_index(lang);
|
|
|
|
|
order *result = 0;
|
|
|
|
|
assert(i < MAXLOCALES);
|
2015-08-05 00:03:30 +02:00
|
|
|
|
|
|
|
|
|
if (default_keyword!=NOKEYWORD) {
|
|
|
|
|
return create_order(default_keyword, lang, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
result = defaults[i];
|
|
|
|
|
if (!result && usedefault) {
|
2015-01-08 20:55:29 +01:00
|
|
|
|
const char * str = LOC(lang, "defaultorder");
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (str) {
|
|
|
|
|
result = defaults[i] = parse_order(str, lang);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
usedefault = 0;
|
|
|
|
|
}
|
2012-05-16 22:07:28 +02:00
|
|
|
|
}
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
double n;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
if (is_cursed(r->attribs, C_DEPRESSION, 0)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
n = rmoney(r) / ENTERTAINFRACTION;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-07-23 11:54:51 +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
|
|
|
|
|
2014-07-23 11:54:51 +02:00
|
|
|
|
return (int)n;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rule_give(void)
|
|
|
|
|
{
|
2015-11-09 13:36:52 +01:00
|
|
|
|
return get_param_int(global.parameters, "rules.give.flags", GIVE_DEFAULT);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-09 13:36:52 +01:00
|
|
|
|
bool markets_module(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-10-16 07:34:09 +02:00
|
|
|
|
return get_param_int(global.parameters, "modules.markets", 0);
|
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
|
|
|
|
{
|
2014-07-23 11:54:51 +02:00
|
|
|
|
int i;
|
2015-09-09 15:45:20 +02:00
|
|
|
|
free_donations();
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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();
|
2014-07-23 11:54:51 +02:00
|
|
|
|
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 = get_param(global.parameters, "game.name");
|
|
|
|
|
return param ? param : global.gamename;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int game_id(void) {
|
2014-08-03 20:37:05 +02:00
|
|
|
|
return get_param_int(global.parameters, "game.id", 0);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|