2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2000
|
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
|
2001-02-03 14:45:35 +01:00
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/reduceproduction.h>
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include <attributes/otherfaction.h>
|
|
|
|
|
#include <attributes/racename.h>
|
2001-02-17 15:47:43 +01:00
|
|
|
|
#include <attributes/gm.h>
|
2001-02-03 14:45:35 +01:00
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "message.h"
|
2002-04-07 10:20:27 +02:00
|
|
|
|
#include "curse.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "spell.h"
|
|
|
|
|
#include "names.h"
|
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "item.h"
|
|
|
|
|
#include "border.h"
|
|
|
|
|
#include "plane.h"
|
|
|
|
|
#include "alchemy.h"
|
|
|
|
|
#include "unit.h"
|
|
|
|
|
#include "save.h"
|
|
|
|
|
#include "magic.h"
|
|
|
|
|
#include "building.h"
|
|
|
|
|
#include "battle.h"
|
|
|
|
|
#include "race.h"
|
|
|
|
|
#include "pool.h"
|
|
|
|
|
#include "region.h"
|
|
|
|
|
#include "unit.h"
|
|
|
|
|
#include "skill.h"
|
|
|
|
|
#include "objtypes.h"
|
|
|
|
|
#include "ship.h"
|
|
|
|
|
#include "karma.h"
|
|
|
|
|
#include "group.h"
|
|
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
|
#include <base36.h>
|
|
|
|
|
#include <event.h>
|
|
|
|
|
#include <umlaut.h>
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
#include <translation.h>
|
|
|
|
|
#include <crmessage.h>
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include <sql.h>
|
|
|
|
|
#include <xml.h>
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
2002-04-28 15:06:27 +02:00
|
|
|
|
#include <modules/xecmd.h>
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2001-05-20 23:47:56 +02:00
|
|
|
|
#include <message.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <time.h>
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include <errno.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* exported variables */
|
2001-02-03 14:45:35 +01:00
|
|
|
|
region *regions;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
faction *factions;
|
|
|
|
|
settings global;
|
2001-02-03 14:45:35 +01:00
|
|
|
|
char buf[BUFSIZE + 1];
|
|
|
|
|
FILE *logfile;
|
2001-12-30 12:27:58 +01:00
|
|
|
|
FILE *updatelog;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const struct race * new_race[MAXRACES];
|
|
|
|
|
|
|
|
|
|
race_t
|
|
|
|
|
old_race(const struct race * rc)
|
|
|
|
|
{
|
|
|
|
|
race_t i;
|
|
|
|
|
for (i=0;i!=MAXRACES;++i) {
|
|
|
|
|
if (new_race[i]==rc) return i;
|
|
|
|
|
}
|
|
|
|
|
return NORACE;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
const char *directions[MAXDIRECTIONS+2] =
|
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
"northwest",
|
|
|
|
|
"northeast",
|
|
|
|
|
"east",
|
|
|
|
|
"southeast",
|
|
|
|
|
"southwest",
|
|
|
|
|
"west",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"",
|
2001-04-16 16:34:19 +02:00
|
|
|
|
"pause"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *gr_prefix[3] = {
|
|
|
|
|
"einem",
|
|
|
|
|
"einer",
|
|
|
|
|
"einem"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *parameters[MAXPARAMS] =
|
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
"LOCALE",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"ALLES",
|
|
|
|
|
"BAUERN",
|
|
|
|
|
"BURG",
|
|
|
|
|
"EINHEIT",
|
|
|
|
|
"PRIVAT",
|
|
|
|
|
"HINTEN",
|
|
|
|
|
"KOMMANDO",
|
|
|
|
|
"KR<EFBFBD>UTER",
|
|
|
|
|
"NICHT",
|
|
|
|
|
"N<EFBFBD>CHSTER",
|
|
|
|
|
"PARTEI",
|
2001-12-10 01:13:39 +01:00
|
|
|
|
"ERESSEA",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"PERSONEN",
|
|
|
|
|
"REGION",
|
|
|
|
|
"SCHIFF",
|
|
|
|
|
"SILBER",
|
2001-02-25 20:31:40 +01:00
|
|
|
|
"STRA<EFBFBD>EN",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"TEMPOR<EFBFBD>RE",
|
|
|
|
|
"FLIEHE",
|
|
|
|
|
"GEB<EFBFBD>UDE",
|
|
|
|
|
"GIB", /* F<>r HELFE */
|
|
|
|
|
"K<EFBFBD>MPFE",
|
|
|
|
|
"BEWACHE",
|
2001-12-10 01:13:39 +01:00
|
|
|
|
"ZAUBER",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"PAUSE",
|
|
|
|
|
"VORNE",
|
2001-04-13 16:39:57 +02:00
|
|
|
|
"AGGRESSIV",
|
|
|
|
|
"DEFENSIV",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"STUFE",
|
|
|
|
|
"HELFE",
|
|
|
|
|
"FREMDES",
|
|
|
|
|
"AURA",
|
|
|
|
|
"UM",
|
|
|
|
|
"BEISTAND",
|
|
|
|
|
"GNADE",
|
|
|
|
|
"HINTER",
|
|
|
|
|
"VOR",
|
|
|
|
|
"ANZAHL",
|
2001-02-25 20:31:40 +01:00
|
|
|
|
"GEGENST<EFBFBD>NDE",
|
2001-12-10 01:13:39 +01:00
|
|
|
|
"TR<EFBFBD>NKE",
|
|
|
|
|
"GRUPPE",
|
|
|
|
|
"PARTEITARNUNG",
|
2002-04-27 21:40:31 +02:00
|
|
|
|
"B<EFBFBD>UME",
|
|
|
|
|
"XEPOTION",
|
|
|
|
|
"XEBALLOON",
|
|
|
|
|
"XELAEN"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char *keywords[MAXKEYWORDS] =
|
|
|
|
|
{
|
|
|
|
|
"//",
|
|
|
|
|
"BANNER",
|
|
|
|
|
"ARBEITEN",
|
|
|
|
|
"ATTACKIEREN",
|
|
|
|
|
"BIETEN",
|
|
|
|
|
"BEKLAUEN",
|
|
|
|
|
"BELAGERE",
|
|
|
|
|
"BENENNEN",
|
|
|
|
|
"BENUTZEN",
|
2002-01-20 13:47:44 +01:00
|
|
|
|
"BESCHREIBEN",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"BETRETEN",
|
|
|
|
|
"BEWACHEN",
|
|
|
|
|
"BOTSCHAFT",
|
|
|
|
|
"ENDE",
|
|
|
|
|
"FAHREN",
|
|
|
|
|
"NUMMER",
|
|
|
|
|
"FOLGEN",
|
|
|
|
|
"FORSCHEN",
|
|
|
|
|
"GIB",
|
|
|
|
|
"HELFEN",
|
|
|
|
|
"K<EFBFBD>MPFEN",
|
|
|
|
|
"KAMPFZAUBER",
|
|
|
|
|
"KAUFEN",
|
2002-01-01 22:47:43 +01:00
|
|
|
|
"KONTAKTIEREN",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"LEHREN",
|
|
|
|
|
"LERNEN",
|
|
|
|
|
"LIEFERE",
|
|
|
|
|
"MACHEN",
|
|
|
|
|
"NACH",
|
|
|
|
|
"PASSWORT",
|
|
|
|
|
"REGION",
|
|
|
|
|
"REKRUTIEREN",
|
|
|
|
|
"RESERVIEREN",
|
|
|
|
|
"ROUTE",
|
|
|
|
|
"SABOTIEREN",
|
|
|
|
|
"OPTION",
|
|
|
|
|
"SPIONIEREN",
|
|
|
|
|
"STIRB",
|
|
|
|
|
"TARNEN",
|
|
|
|
|
"TRANSPORTIEREN",
|
|
|
|
|
"TREIBEN",
|
|
|
|
|
"UNTERHALTEN",
|
2001-12-30 18:48:53 +01:00
|
|
|
|
"VERKAUFEN",
|
|
|
|
|
"VERLASSEN",
|
|
|
|
|
"VERGESSEN",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"ZAUBERE",
|
|
|
|
|
"ZEIGEN",
|
|
|
|
|
"ZERST<EFBFBD>REN",
|
|
|
|
|
"Z<EFBFBD>CHTEN",
|
|
|
|
|
"DEFAULT",
|
|
|
|
|
"REPORT",
|
|
|
|
|
"URSPRUNG",
|
|
|
|
|
"EMAIL",
|
|
|
|
|
"MEINUNG",
|
|
|
|
|
"MAGIEGEBIET",
|
|
|
|
|
"PIRATERIE",
|
|
|
|
|
"NEUSTART",
|
|
|
|
|
"GRUPPE",
|
|
|
|
|
"OPFERE",
|
|
|
|
|
"BETEN",
|
|
|
|
|
"SORTIEREN",
|
2001-01-31 00:16:17 +01:00
|
|
|
|
"JIHAD",
|
2001-04-26 19:41:06 +02:00
|
|
|
|
"GM",
|
2001-04-28 14:01:17 +02:00
|
|
|
|
"INFO",
|
2001-04-29 21:27:42 +02:00
|
|
|
|
#ifdef USE_UGROUPS
|
2001-04-28 14:01:17 +02:00
|
|
|
|
"JOINVERBAND",
|
2001-12-10 01:13:39 +01:00
|
|
|
|
"LEAVEVERBAND",
|
|
|
|
|
#endif
|
|
|
|
|
"PR<EFBFBD>FIX",
|
|
|
|
|
"SYNONYM",
|
|
|
|
|
"PFLANZEN",
|
2002-04-27 21:40:31 +02:00
|
|
|
|
"WERWESEN",
|
|
|
|
|
"XONTORMIA"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *report_options[MAX_MSG] =
|
|
|
|
|
{
|
|
|
|
|
"Kampf",
|
|
|
|
|
"Ereignisse",
|
|
|
|
|
"Bewegung",
|
|
|
|
|
"Einkommen",
|
|
|
|
|
"Handel",
|
|
|
|
|
"Produktion",
|
|
|
|
|
"Orkvermehrung",
|
|
|
|
|
"Zauber",
|
|
|
|
|
"",
|
|
|
|
|
""
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *message_levels[ML_MAX] =
|
|
|
|
|
{
|
|
|
|
|
"Wichtig",
|
|
|
|
|
"Debug",
|
|
|
|
|
"Fehler",
|
|
|
|
|
"Warnungen",
|
|
|
|
|
"Infos"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *options[MAXOPTIONS] =
|
|
|
|
|
{
|
|
|
|
|
"AUSWERTUNG",
|
|
|
|
|
"COMPUTER",
|
|
|
|
|
"ZUGVORLAGE",
|
|
|
|
|
"SILBERPOOL",
|
|
|
|
|
"STATISTIK",
|
|
|
|
|
"DEBUG",
|
|
|
|
|
"ZIPPED",
|
2001-02-28 19:25:25 +01:00
|
|
|
|
"ZEITUNG", /* Option hat Sonderbehandlung! */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
"MATERIALPOOL",
|
|
|
|
|
"ADRESSEN",
|
|
|
|
|
"BZIP2",
|
2002-02-22 20:41:20 +01:00
|
|
|
|
"PUNKTE",
|
|
|
|
|
"SHOWSKCHANGE"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int
|
2002-03-24 12:24:57 +01:00
|
|
|
|
max_skill(const faction * f, skill_t sk)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int m = INT_MAX;
|
|
|
|
|
|
2002-02-15 17:13:30 +01:00
|
|
|
|
switch (sk) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case SK_MAGIC:
|
|
|
|
|
m = MAXMAGICIANS;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(f->race) == RC_ELF) m += 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
m += fspecial(f, FS_MAGOCRACY) * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SK_ALCHEMY:
|
|
|
|
|
m = MAXALCHEMISTS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-03 14:45:35 +01:00
|
|
|
|
char * g_basedir;
|
|
|
|
|
char * g_resourcedir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
basepath(void)
|
|
|
|
|
{
|
|
|
|
|
if (g_basedir) return g_basedir;
|
|
|
|
|
return ".";
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-03 14:45:35 +01:00
|
|
|
|
const char *
|
|
|
|
|
resourcepath(void)
|
|
|
|
|
{
|
|
|
|
|
static char zText[MAX_PATH];
|
|
|
|
|
if (g_resourcedir) return g_resourcedir;
|
|
|
|
|
return strcat(strcpy(zText, basepath()), "/res");
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
count_all_money(const region * r)
|
|
|
|
|
{
|
|
|
|
|
const unit *u;
|
|
|
|
|
int m = rmoney(r);
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
|
|
|
|
m += get_money(u);
|
|
|
|
|
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2002-02-15 17:13:30 +01:00
|
|
|
|
count_skill(faction * f, skill_t sk)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
region *r;
|
|
|
|
|
unit *u;
|
|
|
|
|
region *last = lastregion(f);
|
|
|
|
|
|
|
|
|
|
for (r = firstregion(f); r != last; r = r->next)
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
if (u->faction == f && has_skill(u, sk))
|
|
|
|
|
if (!is_familiar(u)) n += u->number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
shipcapacity (const ship * sh)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
|
|
|
|
/* sonst ist construction:: size nicht ship_type::maxsize */
|
|
|
|
|
assert(!sh->type->construction || sh->type->construction->improvement==NULL);
|
|
|
|
|
|
|
|
|
|
if (sh->type->construction && sh->size!=sh->type->construction->maxsize)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef SHIPDAMAGE
|
2001-12-10 01:13:39 +01:00
|
|
|
|
i = ((sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE)
|
|
|
|
|
* sh->type->cargo / sh->size;
|
|
|
|
|
i += ((sh->size * DAMAGE_SCALE - sh->damage) % DAMAGE_SCALE)
|
|
|
|
|
* sh->type->cargo / (sh->size*DAMAGE_SCALE);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#else
|
|
|
|
|
i = sh->type->cargo;
|
|
|
|
|
#endif
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int max_unique_id;
|
|
|
|
|
int quiet = 0;
|
|
|
|
|
|
|
|
|
|
FILE *debug;
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
shipspeed (ship * sh, const unit * u)
|
|
|
|
|
{
|
|
|
|
|
int k = sh->type->range;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static const curse_type * stormwind_ct, * nodrift_ct;
|
|
|
|
|
static boolean init;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
stormwind_ct = ct_find("stormwind");
|
|
|
|
|
nodrift_ct = ct_find("nodrift");
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +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;
|
|
|
|
|
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if( curse_active(get_curse(sh->attribs, stormwind_ct)))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
k *= 2;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if( curse_active(get_curse(sh->attribs, nodrift_ct)))
|
2001-01-25 10:37:55 +01:00
|
|
|
|
k += 1;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->faction->race) == RC_AQUARIAN
|
|
|
|
|
&& old_race(u->race) == RC_AQUARIAN)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
k += 1;
|
|
|
|
|
#ifdef SHIPSPEED
|
|
|
|
|
k *= SHIPSPEED;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef SHIPDAMAGE
|
|
|
|
|
if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return min (k, MAXSPEED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* erwartete Anzahl Einheiten x 2 */
|
|
|
|
|
#define UMAXHASH 199999
|
|
|
|
|
unit *unithash[UMAXHASH];
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
uhash (unit * u)
|
|
|
|
|
{
|
|
|
|
|
assert(!u->nexthash || !"unit ist bereits gehasht");
|
|
|
|
|
u->nexthash = unithash[u->no % UMAXHASH];
|
|
|
|
|
unithash[u->no % UMAXHASH] = u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
uunhash (unit * u)
|
|
|
|
|
{
|
|
|
|
|
unit ** x = &(unithash[u->no % UMAXHASH]);
|
|
|
|
|
while (*x && *x!=u) x = &(*x)->nexthash;
|
|
|
|
|
assert(*x || !"unit nicht gefunden");
|
|
|
|
|
*x = u->nexthash;
|
|
|
|
|
u->nexthash=NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
ufindhash (int i)
|
|
|
|
|
{
|
|
|
|
|
unit * u = unithash[i % UMAXHASH];
|
|
|
|
|
while (u && u->no!=i) u = u->nexthash;
|
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define FMAXHASH 2047
|
|
|
|
|
faction * factionhash[FMAXHASH];
|
|
|
|
|
|
2001-12-30 09:39:21 +01:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
fhash(faction * f)
|
|
|
|
|
{
|
|
|
|
|
int index = f->no % FMAXHASH;
|
|
|
|
|
f->nexthash = factionhash[index];
|
|
|
|
|
factionhash[index] = f;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 09:39:21 +01:00
|
|
|
|
void
|
2001-01-25 10:37:55 +01:00
|
|
|
|
funhash(faction * f)
|
|
|
|
|
{
|
|
|
|
|
int index = f->no % FMAXHASH;
|
|
|
|
|
faction ** fp = factionhash+index;
|
|
|
|
|
while (*fp && (*fp)!=f) fp = &(*fp)->nexthash;
|
|
|
|
|
*fp = f->nexthash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static faction *
|
|
|
|
|
ffindhash(int no)
|
|
|
|
|
{
|
|
|
|
|
int index = no % FMAXHASH;
|
|
|
|
|
faction * f = factionhash[index];
|
|
|
|
|
while (f && f->no!=no) f = f->nexthash;
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
stripfaction (faction * f)
|
|
|
|
|
{
|
2001-02-24 13:50:51 +01:00
|
|
|
|
#ifdef OLD_MESSAGES
|
2001-01-25 10:37:55 +01:00
|
|
|
|
free_messages(f->msgs);
|
2001-02-24 13:50:51 +01:00
|
|
|
|
#else
|
2002-01-21 02:42:11 +01:00
|
|
|
|
/* TODO: inhalt auch l<>schen */
|
|
|
|
|
if (f->msgs) free(f->msgs);
|
|
|
|
|
if (f->battles) free(f->battles);
|
2001-02-24 13:50:51 +01:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* TODO: free msgs */
|
|
|
|
|
freestrlist(f->mistakes);
|
|
|
|
|
freelist(f->allies);
|
|
|
|
|
free(f->email);
|
|
|
|
|
free(f->banner);
|
|
|
|
|
free(f->passw);
|
2002-03-03 13:53:05 +01:00
|
|
|
|
free(f->override);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
free(f->name);
|
|
|
|
|
#ifndef FAST_REGION
|
|
|
|
|
vset_destroy(&f->regions);
|
|
|
|
|
#endif
|
|
|
|
|
while (f->attribs) a_remove (&f->attribs, f->attribs);
|
|
|
|
|
freelist(f->ursprung);
|
|
|
|
|
funhash(f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
stripunit(unit * u)
|
|
|
|
|
{
|
|
|
|
|
free(u->name);
|
|
|
|
|
free(u->display);
|
|
|
|
|
free(u->thisorder);
|
|
|
|
|
free(u->lastorder);
|
|
|
|
|
freestrlist(u->orders);
|
|
|
|
|
freestrlist(u->botschaften);
|
|
|
|
|
if(u->skills) free(u->skills);
|
|
|
|
|
while (u->items) {
|
|
|
|
|
item * it = u->items->next;
|
|
|
|
|
u->items->next = NULL;
|
|
|
|
|
i_free(u->items);
|
|
|
|
|
u->items = it;
|
|
|
|
|
}
|
|
|
|
|
while (u->attribs) a_remove (&u->attribs, u->attribs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2002-02-03 03:54:47 +01:00
|
|
|
|
verify_data(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
int lf = -1;
|
|
|
|
|
faction *f;
|
|
|
|
|
unit *u;
|
|
|
|
|
int mage, alchemist;
|
|
|
|
|
|
|
|
|
|
puts(" - <20>berpr<70>fe Daten auf Korrektheit...");
|
|
|
|
|
|
|
|
|
|
list_foreach(faction, factions, f) {
|
|
|
|
|
mage = 0;
|
|
|
|
|
alchemist = 0;
|
|
|
|
|
for (u=f->units;u;u=u->nextF) {
|
|
|
|
|
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 > 50000 || u->number < 0) {
|
|
|
|
|
if (lf != f->no) {
|
|
|
|
|
lf = f->no;
|
|
|
|
|
printf("Partei %s:\n", factionid(f));
|
|
|
|
|
}
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (f->no != 0 && ((mage > 3 && old_race(f->race) != RC_ELF) || mage > 4))
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
log_error(("Partei %s hat %d Magier.\n", factionid(f), mage));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (alchemist > 3)
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
list_next(f);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2002-02-03 03:54:47 +01:00
|
|
|
|
distribute(int old, int new_value, int n)
|
2001-01-25 10:37:55 +01: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 (rand() % old < new_value)
|
|
|
|
|
t++;
|
|
|
|
|
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
change_hitpoints (unit * u, int value)
|
|
|
|
|
{
|
|
|
|
|
int hp = u->hp;
|
|
|
|
|
|
|
|
|
|
hp += value;
|
|
|
|
|
|
|
|
|
|
/* Jede Person ben<65>tigt mindestens 1 HP */
|
|
|
|
|
if (hp < u->number){
|
|
|
|
|
if (hp < 0){ /* Einheit tot */
|
|
|
|
|
hp = 0;
|
|
|
|
|
}
|
|
|
|
|
scale_number(u, hp);
|
|
|
|
|
}
|
|
|
|
|
u->hp = hp;
|
|
|
|
|
return hp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2002-02-03 03:54:47 +01:00
|
|
|
|
atoip(const char *s)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
n = atoi (s);
|
|
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
|
n = 0;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
scat (const char *s)
|
|
|
|
|
{
|
|
|
|
|
strncat (buf, s, BUFSIZE - strlen (buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
icat (int n)
|
|
|
|
|
{
|
|
|
|
|
char s[12];
|
|
|
|
|
|
|
|
|
|
sprintf (s, "%d", n);
|
|
|
|
|
scat (s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
region *
|
|
|
|
|
findunitregion (const unit * su)
|
|
|
|
|
{
|
|
|
|
|
#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) {
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This should never happen */
|
|
|
|
|
assert (!"Die unit wurde nicht gefunden");
|
|
|
|
|
|
|
|
|
|
return (region *) NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
effskill(const unit * u, skill_t sk)
|
|
|
|
|
{
|
|
|
|
|
return eff_skill(u, sk, u->region);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
effstealth(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
int e, es;
|
|
|
|
|
|
|
|
|
|
/* Auf dem Ozean keine Tarnung! */
|
|
|
|
|
if (u->region->terrain == T_OCEAN) return 0;
|
|
|
|
|
|
|
|
|
|
e = effskill(u, SK_STEALTH);
|
|
|
|
|
|
|
|
|
|
es = u_geteffstealth(u);
|
|
|
|
|
if (es >=0 && es < e) return es;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
eff_stealth (const unit * u, const region * r)
|
|
|
|
|
{
|
|
|
|
|
int e, es;
|
|
|
|
|
|
|
|
|
|
e = eff_skill (u, SK_STEALTH, r);
|
|
|
|
|
|
|
|
|
|
es = u_geteffstealth(u);
|
|
|
|
|
if (es >=0 && es < e) return es;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
scale_number (unit * u, int n)
|
|
|
|
|
{
|
2002-02-15 17:13:30 +01:00
|
|
|
|
skill_t sk;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
const attrib * a;
|
|
|
|
|
int remain;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (n == u->number) return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (n && u->number) {
|
|
|
|
|
int full;
|
|
|
|
|
remain = ((u->hp%u->number) * (n % u->number)) % u->number;
|
|
|
|
|
|
|
|
|
|
full = u->hp/u->number; /* wieviel kriegt jede person mindestens */
|
|
|
|
|
u->hp = full * n + (u->hp-full*u->number) * n / u->number;
|
|
|
|
|
assert(u->hp>=0);
|
|
|
|
|
if ((rand() % u->number) < remain)
|
|
|
|
|
++u->hp; /* Nachkommastellen */
|
|
|
|
|
} else {
|
|
|
|
|
remain = 0;
|
|
|
|
|
u->hp = 0;
|
|
|
|
|
}
|
|
|
|
|
for (a = a_find(u->attribs, &at_effect);a;a=a->nexttype) {
|
|
|
|
|
effect_data * data = (effect_data *)a->data.v;
|
|
|
|
|
int snew = data->value / u->number * n;
|
|
|
|
|
if (n) {
|
|
|
|
|
remain = data->value - snew / n * u->number;
|
|
|
|
|
snew += remain * n / u->number;
|
|
|
|
|
remain = (remain * n) % u->number;
|
|
|
|
|
if ((rand() % u->number) < remain)
|
|
|
|
|
++snew; /* Nachkommastellen */
|
|
|
|
|
}
|
|
|
|
|
data->value = snew;
|
|
|
|
|
}
|
2002-02-15 17:13:30 +01:00
|
|
|
|
for (sk = 0; sk < MAXSKILLS; sk++) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (n==0 || u->number == 0) {
|
2002-03-11 22:20:31 +01:00
|
|
|
|
remove_skill(u, sk);
|
2002-02-15 17:13:30 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_number(u, n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
unit_has_cursed_item(unit *u)
|
|
|
|
|
{
|
|
|
|
|
item * itm = u->items;
|
|
|
|
|
while (itm) {
|
|
|
|
|
if (fval(itm->type, ITF_CURSED) && itm->number>0) return true;
|
|
|
|
|
itm=itm->next;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-26 16:16:16 +02:00
|
|
|
|
#ifdef ALLIANCES
|
|
|
|
|
int
|
|
|
|
|
allied(const unit * u, const faction * f2, int mode)
|
|
|
|
|
{
|
|
|
|
|
if (u->faction->alliance==f2->alliance) return mode;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
isallied(const plane * pl, const faction * f, const faction * f2, int mode)
|
|
|
|
|
{
|
|
|
|
|
unused(pl);
|
|
|
|
|
if (f->alliance==f2->alliance) return mode;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* f hat zu f2 HELFE mode gesetzt */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
isallied(const plane * pl, const faction * f, const faction * f2, int mode)
|
|
|
|
|
{
|
|
|
|
|
ally *sf;
|
2001-02-17 15:47:43 +01:00
|
|
|
|
attrib * a;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-02-17 15:47:43 +01:00
|
|
|
|
if (f == f2) return mode;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (f2==NULL) return 0;
|
|
|
|
|
|
2001-02-17 15:47:43 +01:00
|
|
|
|
a = a_find(f->attribs, &at_gm);
|
|
|
|
|
while (a) {
|
|
|
|
|
plane * p = (plane*)a->data.v;
|
|
|
|
|
if (p==pl) return mode;
|
|
|
|
|
a=a->next;
|
|
|
|
|
}
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (pl && pl->flags & PFL_FRIENDLY) return mode;
|
|
|
|
|
if (mode != HELP_GIVE && pl && (pl->flags & PFL_NOALLIANCES)) return 0;
|
|
|
|
|
for (sf = f->allies; sf; sf = sf->next)
|
|
|
|
|
if (sf->faction == f2)
|
|
|
|
|
return (sf->status & mode);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-26 16:16:16 +02:00
|
|
|
|
static int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
alliance(const ally * sf, const faction * f, int mode)
|
|
|
|
|
{
|
|
|
|
|
while (sf) {
|
|
|
|
|
if (sf->faction == f)
|
|
|
|
|
return sf->status & mode;
|
|
|
|
|
sf = sf->next;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
allied(const unit * u, const faction * f2, int mode)
|
|
|
|
|
{
|
|
|
|
|
ally * sf;
|
|
|
|
|
const attrib * a;
|
|
|
|
|
plane * pl;
|
|
|
|
|
|
|
|
|
|
if (u->faction == f2) return mode;
|
|
|
|
|
if (u->faction == NULL || f2==NULL) return 0;
|
|
|
|
|
|
|
|
|
|
sf = u->faction->allies;
|
|
|
|
|
pl = getplane(u->region);
|
|
|
|
|
|
|
|
|
|
if (pl && pl->flags & PFL_FRIENDLY) return mode;
|
2001-02-18 13:30:10 +01:00
|
|
|
|
|
|
|
|
|
/* if f2 is a gm in this plane, everyone has an auto-help to it */
|
|
|
|
|
a = a_find(f2->attribs, &at_gm);
|
|
|
|
|
while (a) {
|
|
|
|
|
plane * p = (plane*)a->data.v;
|
|
|
|
|
if (p==pl) return mode;
|
|
|
|
|
a=a->next;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (mode != HELP_GIVE && pl && (pl->flags & PFL_NOALLIANCES))
|
|
|
|
|
return 0;
|
|
|
|
|
a = a_find(u->attribs, &at_group);
|
|
|
|
|
if (a) sf = ((group*)a->data.v)->allies;
|
|
|
|
|
return alliance(sf, f2, mode);
|
|
|
|
|
}
|
2002-08-26 16:16:16 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
boolean
|
2001-12-10 01:13:39 +01:00
|
|
|
|
seefaction(const faction * f, const region * r, const unit * u, int modifier)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
if (((f == u->faction) || !fval(u, FL_PARTEITARNUNG)) && cansee(f, r, u, modifier))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
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 n;
|
|
|
|
|
boolean cansee = false;
|
|
|
|
|
unit *u2;
|
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (u->faction == f || omniscient(f)) {
|
|
|
|
|
return true;
|
|
|
|
|
} else if (old_race(u->race) == RC_SPELL) {
|
|
|
|
|
return false;
|
|
|
|
|
} else if (u->number == 0) {
|
|
|
|
|
attrib *a = a_find(u->attribs, &at_creator);
|
|
|
|
|
if(a) { /* u is an empty temporary unit. In this special case
|
|
|
|
|
we look at the creating unit. */
|
|
|
|
|
u = (unit *)a->data.v;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
n = eff_stealth(u, r) - modifier;
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->faction == f) {
|
|
|
|
|
int o;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (getguard(u) || usiege(u) || u->building || u->ship) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-05-05 18:59:25 +02:00
|
|
|
|
if (invisible(u) >= u->number
|
2002-04-21 19:22:48 +02:00
|
|
|
|
&& !get_item(u2, I_AMULET_OF_TRUE_SEEING))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
o = eff_skill(u2, SK_OBSERVATION, r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#if NIGHTEYES
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (u2->enchanted == SP_NIGHT_EYES && o < NIGHT_EYE_TALENT)
|
|
|
|
|
o = NIGHT_EYE_TALENT;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2002-04-21 19:22:48 +02:00
|
|
|
|
if (o >= n) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cansee;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
boolean
|
|
|
|
|
cansee(faction * f, region * r, 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 */
|
|
|
|
|
{
|
|
|
|
|
boolean cansee = false;
|
|
|
|
|
unit *u2;
|
|
|
|
|
#if FAST_CANSEE
|
|
|
|
|
static region * lastr = NULL;
|
|
|
|
|
static faction * lastf = NULL;
|
|
|
|
|
static int maxskill = INT_MIN;
|
|
|
|
|
#endif
|
|
|
|
|
int n = 0;
|
|
|
|
|
boolean ring = false;
|
2001-04-01 08:58:45 +02:00
|
|
|
|
if (u->faction == f || omniscient(f)) return true;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#if FAST_CANSEE /* buggy */
|
|
|
|
|
if (lastr==r && lastf==f) {
|
|
|
|
|
n = eff_stealth(u, r) - modifier;
|
|
|
|
|
if (n<=maxskill) return true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
lastf=f;
|
|
|
|
|
lastr=r;
|
|
|
|
|
maxskill=INT_MIN;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_SPELL || u->number == 0) return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else {
|
|
|
|
|
boolean xcheck = false;
|
|
|
|
|
int o = INT_MIN;
|
2002-05-05 18:59:25 +02:00
|
|
|
|
ring = (boolean)(ring || (invisible(u) >= u->number));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
n = n || eff_stealth(u, r) - modifier;
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next) {
|
|
|
|
|
if (u2->faction == f) {
|
|
|
|
|
|
|
|
|
|
if (!xcheck && (getguard(u) || usiege(u) || u->building || u->ship)) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
xcheck = true;
|
|
|
|
|
if (ring && !get_item(u2, I_AMULET_OF_TRUE_SEEING))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
o = eff_skill(u2, SK_OBSERVATION, r);
|
|
|
|
|
#if NIGHTEYES
|
|
|
|
|
if (u2->enchanted == SP_NIGHT_EYES && o < NIGHT_EYE_TALENT)
|
|
|
|
|
o = NIGHT_EYE_TALENT;
|
|
|
|
|
#endif
|
|
|
|
|
if (o >= n) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#if FAST_CANSEE
|
|
|
|
|
maxskill = o;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
return cansee;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
boolean
|
2001-12-10 01:13:39 +01:00
|
|
|
|
cansee_durchgezogen(const faction * f, const region * r, const unit * u, int modifier)
|
2001-01-25 10:37:55 +01: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;
|
|
|
|
|
boolean cansee = false;
|
|
|
|
|
unit *u2;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(u->race) == RC_SPELL || u->number == 0) return false;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else if (u->faction == f) cansee = true;
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
|
|
n = eff_stealth(u, r) - modifier;
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next){
|
|
|
|
|
if (u2->faction == f) {
|
|
|
|
|
int o;
|
|
|
|
|
|
|
|
|
|
if (getguard(u) || usiege(u) || u->building || u->ship) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-05-05 18:59:25 +02:00
|
|
|
|
if (invisible(u) >= u->number
|
2001-01-25 10:37:55 +01:00
|
|
|
|
&& !get_item(u2, I_AMULET_OF_TRUE_SEEING))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
o = eff_skill(u2, SK_OBSERVATION, r);
|
|
|
|
|
|
|
|
|
|
#if NIGHTEYES
|
|
|
|
|
if (u2->enchanted == SP_NIGHT_EYES && o < NIGHT_EYE_TALENT)
|
|
|
|
|
o = NIGHT_EYE_TALENT;
|
|
|
|
|
#endif
|
|
|
|
|
if (o >= n) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getguard(u) || usiege(u) || u->building || u->ship) {
|
|
|
|
|
cansee = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cansee;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
const char *
|
|
|
|
|
strcheck (const char *s, size_t maxlen)
|
|
|
|
|
{
|
|
|
|
|
static char buffer[16 * 1024];
|
|
|
|
|
if (strlen(s) > maxlen) {
|
|
|
|
|
assert(maxlen < 16 * 1024);
|
2001-02-12 23:39:57 +01:00
|
|
|
|
log_warning(("[strcheck] String wurde auf %d Zeichen verk<72>rzt:\n%s\n",
|
|
|
|
|
(int)maxlen, s));
|
2002-04-21 12:52:22 +02:00
|
|
|
|
strnzcpy(buffer, s, maxlen);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
attrib_type at_lighthouse = {
|
|
|
|
|
"lighthouse"
|
|
|
|
|
/* Rest ist NULL; tempor<6F>res, nicht alterndes Attribut */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
update_lighthouse(building * lh)
|
|
|
|
|
{
|
|
|
|
|
region * r = lh->region;
|
|
|
|
|
int d = (int)log10(lh->size) + 1;
|
|
|
|
|
int x, y;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
static const struct building_type * bt_lighthouse;
|
|
|
|
|
if (!bt_lighthouse) bt_lighthouse = bt_find("lighthouse");
|
|
|
|
|
assert(bt_lighthouse);
|
|
|
|
|
|
|
|
|
|
if (lh->type!=bt_lighthouse) return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (x=-d;x<=d;++x) {
|
|
|
|
|
for (y=-d;y<=d;++y) {
|
|
|
|
|
attrib * a;
|
|
|
|
|
region * r2 = findregion(x+r->x, y+r->y);
|
|
|
|
|
if (rterrain(r2)!=T_OCEAN) continue;
|
|
|
|
|
if (!r2 || distance(r, r2) > d) continue;
|
|
|
|
|
a = a_find(r2->attribs, &at_lighthouse);
|
|
|
|
|
while (a) {
|
|
|
|
|
building * b = (building*)a->data.v;
|
|
|
|
|
if (b==lh) break;
|
|
|
|
|
a=a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&r2->attribs, a_new(&at_lighthouse));
|
|
|
|
|
a->data.v = (void*)lh;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2001-02-05 08:23:17 +01:00
|
|
|
|
count_all(const faction * f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
unit *u;
|
|
|
|
|
for (u=f->units;u;u=u->nextF)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (playerrace(u->race)) {
|
|
|
|
|
n += u->number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
assert(f==u->faction);
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2001-02-05 08:23:17 +01:00
|
|
|
|
count_maxmigrants(const faction * f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-02-03 14:45:35 +01:00
|
|
|
|
int x = 0;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (old_race(f->race) == RC_HUMAN) {
|
2001-02-05 08:23:17 +01:00
|
|
|
|
x = (int)(log10(count_all(f) / 50.0) * 20);
|
2001-02-03 14:45:35 +01:00
|
|
|
|
if (x < 0) x = 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-02-03 14:45:35 +01:00
|
|
|
|
return x;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/* GET STR, I zur Eingabe von Daten liest diese aus dem Buffer, der beim ersten
|
|
|
|
|
* Aufruf inititialisiert wird? */
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
igetstrtoken (const char *s1)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
static const char *s;
|
2001-02-18 13:20:37 +01:00
|
|
|
|
static char lbuf[DISPLAYSIZE + 1];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (s1) s = s1;
|
|
|
|
|
while (*s == ' ')
|
|
|
|
|
s++;
|
|
|
|
|
i = 0;
|
|
|
|
|
|
2001-02-13 03:58:51 +01:00
|
|
|
|
while (*s && *s != ' ' && i < DISPLAYSIZE) {
|
2001-02-18 13:20:37 +01:00
|
|
|
|
lbuf[i] = (*s);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* Hier wird space_replacement wieder in space zurueck
|
|
|
|
|
* verwandelt, ausser wenn es nach einem escape_char kommt. Im
|
|
|
|
|
* letzteren Fall wird escape_char durch space_replacement
|
|
|
|
|
* ersetzt, statt den aktuellen char einfach dran zu haengen. */
|
|
|
|
|
|
|
|
|
|
if (*s == SPACE_REPLACEMENT) {
|
2001-02-18 13:20:37 +01:00
|
|
|
|
if (i > 0 && lbuf[i - 1] == ESCAPE_CHAR)
|
|
|
|
|
lbuf[--i] = SPACE_REPLACEMENT;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else
|
2002-02-15 17:13:30 +01:00
|
|
|
|
lbuf[i] = ' ';
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
s++;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-18 13:20:37 +01:00
|
|
|
|
lbuf[i] = 0;
|
|
|
|
|
return lbuf;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
getstrtoken (void)
|
|
|
|
|
{
|
|
|
|
|
return igetstrtoken (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
geti (void)
|
|
|
|
|
{
|
|
|
|
|
return atoip (getstrtoken ());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GET KEYWORD, SKILL, ITEM, SPELL benutzen FINDSTR - welche Item um Item eine
|
|
|
|
|
* Liste durchsucht.
|
|
|
|
|
*
|
|
|
|
|
* FIND wird immer von GET aufgerufen. GET braucht keine Parameter, IGET braucht
|
|
|
|
|
* einen String aus dem gelesen wird. In FIND stehen dann listen etc drinnen.
|
|
|
|
|
* FIND kann man auch allein verwenden, wenn der string _nur_ noch das gesuchte
|
|
|
|
|
* object enthaelt. Steht noch weitere info darin, sollte man GET verwenden,
|
|
|
|
|
* bzw. GETI wenn die info am Anfang eines neuen Stringes steht. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
findstr(const char **v, const char *s, unsigned char n)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
size_t ss = strlen(s);
|
|
|
|
|
if (!ss)
|
|
|
|
|
return -1;
|
|
|
|
|
for (i = 0; i != n; i++)
|
|
|
|
|
if (!strncasecmp(s, v[i], ss))
|
|
|
|
|
return i;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
UT_NONE,
|
|
|
|
|
UT_PARAM,
|
|
|
|
|
UT_ITEM,
|
|
|
|
|
UT_BUILDING,
|
|
|
|
|
UT_HERB,
|
|
|
|
|
UT_POTION,
|
|
|
|
|
UT_MAX
|
|
|
|
|
};
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
static struct lstr {
|
|
|
|
|
const struct locale * lang;
|
|
|
|
|
struct tnode tokens[UT_MAX];
|
|
|
|
|
struct tnode skillnames;
|
|
|
|
|
struct tnode keywords;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
struct tnode races;
|
|
|
|
|
struct tnode directions;
|
|
|
|
|
struct tnode options;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
struct lstr * next;
|
|
|
|
|
} * lstrs;
|
|
|
|
|
|
|
|
|
|
static struct lstr *
|
|
|
|
|
get_lnames(const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
static struct lstr * lnames = NULL;
|
|
|
|
|
static const struct locale * lastlang = NULL;
|
|
|
|
|
|
|
|
|
|
if (lastlang!=lang || lnames==NULL) {
|
|
|
|
|
lnames = lstrs;
|
|
|
|
|
while (lnames && lnames->lang!=lang) lnames = lnames->next;
|
|
|
|
|
if (lnames==NULL) {
|
|
|
|
|
lnames = calloc(sizeof(struct lstr), 1);
|
|
|
|
|
lnames->lang = lang;
|
|
|
|
|
lnames->next = lstrs;
|
|
|
|
|
lstrs = lnames;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return lnames;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const struct race *
|
|
|
|
|
findrace(const char * s, const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
|
|
|
|
const struct race * rc;
|
|
|
|
|
|
|
|
|
|
if (findtoken(&lnames->races, s, (void **)&rc)==E_TOK_SUCCESS) {
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
findoption(const char *s, const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
|
|
|
|
int dir;
|
|
|
|
|
|
|
|
|
|
if (findtoken(&lnames->options, s, (void**)&dir)==E_TOK_SUCCESS) {
|
|
|
|
|
return (direction_t)dir;
|
|
|
|
|
}
|
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
skill_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
findskill(const char *s, const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
2001-02-15 03:41:47 +01:00
|
|
|
|
int i;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
|
|
|
|
if (findtoken(&lnames->skillnames, s, (void**)&i)==E_TOK_NOMATCH) return NOSKILL;
|
2001-02-15 03:41:47 +01:00
|
|
|
|
return (skill_t)i;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keyword_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
findkeyword(const char *s, const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
2001-02-15 03:41:47 +01:00
|
|
|
|
int i;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#ifdef AT_PERSISTENT
|
2002-01-13 10:14:13 +01:00
|
|
|
|
if (*s == '@') s++;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findtoken(&lnames->keywords, s, (void**)&i)==E_TOK_NOMATCH) return NOKEYWORD;
|
2001-12-13 22:57:46 +01:00
|
|
|
|
if (global.disabled[i]) return NOKEYWORD;
|
2001-02-15 03:41:47 +01:00
|
|
|
|
return (keyword_t) i;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keyword_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
igetkeyword (const char *s, const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
return findkeyword (igetstrtoken (s), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keyword_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
getkeyword (const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
return findkeyword (getstrtoken (), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
param_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
findparam(const char *s, const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
const building_type * btype;
|
2001-02-15 03:41:47 +01:00
|
|
|
|
|
|
|
|
|
int i;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
if (findtoken(&lnames->tokens[UT_PARAM], s, (void**)&i)==E_TOK_NOMATCH) {
|
|
|
|
|
btype = findbuildingtype(s, lang);
|
2001-02-15 03:41:47 +01:00
|
|
|
|
if (btype!=NULL) return (param_t) P_BUILDING;
|
|
|
|
|
return NOPARAM;
|
|
|
|
|
}
|
|
|
|
|
return (param_t)i;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
param_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
igetparam (const char *s, const struct locale *lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
return findparam (igetstrtoken (s), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
param_t
|
2001-04-16 16:34:19 +02:00
|
|
|
|
getparam (const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
return findparam (getstrtoken (), lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef FUZZY_BASE36
|
|
|
|
|
extern int fuzzy_hits;
|
|
|
|
|
boolean enable_fuzzy = false;
|
|
|
|
|
#endif /* FUZZY_BASE36 */
|
|
|
|
|
|
|
|
|
|
faction *
|
|
|
|
|
findfaction (int n)
|
|
|
|
|
{
|
|
|
|
|
faction * f;
|
|
|
|
|
|
|
|
|
|
f = ffindhash(n);
|
|
|
|
|
if (f) return f;
|
|
|
|
|
for (f = factions; f; f = f->next)
|
|
|
|
|
if (f->no == n) {
|
|
|
|
|
fhash(f);
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
#ifdef FUZZY_BASE36
|
|
|
|
|
if(enable_fuzzy) {
|
|
|
|
|
n = atoi(itoa36(n));
|
|
|
|
|
if (n) {
|
|
|
|
|
f = ffindhash(n);
|
|
|
|
|
if (f) return f;
|
|
|
|
|
for (f = factions; f; f = f->next) {
|
|
|
|
|
if (f->no == n) {
|
|
|
|
|
fhash(f);
|
|
|
|
|
return (f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* FUZZY_BASE36 */
|
2001-12-23 10:23:53 +01:00
|
|
|
|
/* Gibt komische Seiteneffekte hier! */
|
|
|
|
|
/* if (n==MONSTER_FACTION) return makemonsters(); */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
faction *
|
|
|
|
|
getfaction (void)
|
|
|
|
|
{
|
|
|
|
|
return findfaction (getid());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
faction *
|
|
|
|
|
findfaction_unique_id (int unique_id)
|
|
|
|
|
{
|
|
|
|
|
faction *f;
|
|
|
|
|
|
|
|
|
|
for (f = factions; f; f = f->next)
|
|
|
|
|
if (f->unique_id == unique_id) {
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
findunitr (const region * r, int n)
|
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
|
|
|
|
|
/* findunit regional! */
|
|
|
|
|
|
|
|
|
|
for (u = r->units; u; u = u->next)
|
|
|
|
|
if (u->no == n)
|
|
|
|
|
return u;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *findunit(int n)
|
|
|
|
|
{
|
|
|
|
|
return findunitg(n, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
2001-04-26 19:41:06 +02:00
|
|
|
|
findunitg (int n, const region * hint)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Abfangen von Syntaxfehlern. */
|
|
|
|
|
if(n <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* findunit global! */
|
|
|
|
|
hint = 0;
|
|
|
|
|
return ufindhash (n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
2001-04-26 19:41:06 +02:00
|
|
|
|
getnewunit (const region * r, const faction * f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
n = getid();
|
|
|
|
|
|
2001-04-26 19:41:06 +02:00
|
|
|
|
return findnewunit (r, f, n);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2001-04-26 19:41:06 +02:00
|
|
|
|
read_newunitid (const faction * f, const region * r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
unit *u2;
|
|
|
|
|
n = getid();
|
|
|
|
|
if (n == 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
u2 = findnewunit(r, f, n);
|
|
|
|
|
if (u2) return u2->no;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2001-04-26 19:41:06 +02:00
|
|
|
|
read_unitid (const faction * f, const region * r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
s = getstrtoken ();
|
|
|
|
|
|
|
|
|
|
/* 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! */
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
switch (findparam (s, f->locale)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case P_TEMP:
|
|
|
|
|
return read_newunitid(f, r);
|
|
|
|
|
}
|
|
|
|
|
if (!s || *s == 0)
|
|
|
|
|
return -1;
|
|
|
|
|
return atoi36(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* exported symbol */
|
|
|
|
|
boolean getunitpeasants;
|
|
|
|
|
unit *
|
2001-04-26 19:41:06 +02:00
|
|
|
|
getunitg(const region * r, const faction * f)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
getunitpeasants = 0;
|
|
|
|
|
|
|
|
|
|
n = read_unitid(f, r);
|
|
|
|
|
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
getunitpeasants = 1;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n < 0) return 0;
|
|
|
|
|
|
|
|
|
|
return findunit(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
getunit(const region * r, const faction * f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
unit *u2;
|
|
|
|
|
getunitpeasants = 0;
|
|
|
|
|
|
2001-04-26 19:41:06 +02:00
|
|
|
|
n = read_unitid(f, r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
getunitpeasants = 1;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n < 0) return 0;
|
|
|
|
|
|
|
|
|
|
for (u2 = r->units; u2; u2 = u2->next) {
|
2002-03-11 22:20:31 +01:00
|
|
|
|
if (u2->no == n && !fval(u2, UFL_ISNEW)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return u2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* - String Listen --------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
strlist *
|
|
|
|
|
makestrlist (const char *s)
|
|
|
|
|
{
|
|
|
|
|
strlist *S;
|
|
|
|
|
S = malloc(sizeof(strlist));
|
|
|
|
|
S->s = strdup(s);
|
|
|
|
|
S->next = NULL;
|
|
|
|
|
return S;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
addstrlist (strlist ** SP, const char *s)
|
|
|
|
|
{
|
|
|
|
|
addlist(SP, makestrlist(s));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
freestrlist (strlist * s)
|
|
|
|
|
{
|
|
|
|
|
strlist *q, *p = s;
|
|
|
|
|
while (p) {
|
|
|
|
|
q = p->next;
|
|
|
|
|
free(p->s);
|
|
|
|
|
free(p);
|
|
|
|
|
p = q;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* - Meldungen und Fehler ------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
boolean nomsg = false;
|
|
|
|
|
|
|
|
|
|
/* - Namen der Strukturen -------------------------------------- */
|
|
|
|
|
typedef char name[OBJECTIDSIZE + 1];
|
|
|
|
|
static name idbuf[8];
|
|
|
|
|
static int nextbuf = 0;
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
estring(const char *s)
|
|
|
|
|
{
|
|
|
|
|
char *buf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
char *r;
|
|
|
|
|
|
|
|
|
|
strcpy(buf,s);
|
|
|
|
|
r = buf;
|
|
|
|
|
|
|
|
|
|
while(*buf) {
|
|
|
|
|
if(*buf == ' ') {
|
|
|
|
|
*buf = '~';
|
|
|
|
|
}
|
|
|
|
|
buf++;
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
cstring(const char *s)
|
|
|
|
|
{
|
|
|
|
|
char *buf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
char *r;
|
|
|
|
|
|
|
|
|
|
strcpy(buf,s);
|
|
|
|
|
r = buf;
|
|
|
|
|
|
|
|
|
|
while(*buf) {
|
|
|
|
|
if(*buf == '~') {
|
|
|
|
|
*buf = ' ';
|
|
|
|
|
}
|
|
|
|
|
buf++;
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
const char *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
regionid(const region * r)
|
|
|
|
|
{
|
|
|
|
|
char *buf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
|
|
|
|
|
if (!r) {
|
|
|
|
|
strcpy(buf, "(Chaos)");
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(buf, "\\r(%d,%d)", r->x, r->y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
buildingname (const building * b)
|
|
|
|
|
{
|
|
|
|
|
char *buf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
|
|
|
|
|
sprintf(buf, "%s (%s)", strcheck(b->name, NAMESIZE), itoa36(b->no));
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
building *
|
|
|
|
|
largestbuilding (const region * r, boolean img)
|
|
|
|
|
{
|
2002-03-27 22:49:27 +01:00
|
|
|
|
static const building_type * btype = NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
building *b, *best = NULL;
|
2002-03-27 22:49:27 +01:00
|
|
|
|
if (!btype) btype = bt_find("castle"); /* TODO: parameter der funktion? */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* durch die verw. von '>' statt '>=' werden die aelteren burgen
|
|
|
|
|
* bevorzugt. */
|
|
|
|
|
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
|
|
|
|
if (b->type!=btype) {
|
|
|
|
|
if (img) {
|
|
|
|
|
const attrib * a = a_find(b->attribs, &at_icastle);
|
|
|
|
|
if (!a) continue;
|
|
|
|
|
if (a->data.v != btype) continue;
|
|
|
|
|
} else continue;
|
|
|
|
|
}
|
|
|
|
|
if (best==NULL || b->size > best->size)
|
|
|
|
|
best = b;
|
|
|
|
|
}
|
|
|
|
|
return best;
|
|
|
|
|
}
|
|
|
|
|
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
const char *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unitname(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
char *ubuf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
sprintf(ubuf, "%s (%s)", strcheck(u->name, NAMESIZE), itoa36(u->no));
|
|
|
|
|
return ubuf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
xunitid(const unit *u)
|
|
|
|
|
{
|
|
|
|
|
char *buf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
sprintf(buf, "%s in %s", unitname(u), regionid(u->region));
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -- Erschaffung neuer Einheiten ------------------------------ */
|
|
|
|
|
|
|
|
|
|
extern faction * dfindhash(int i);
|
|
|
|
|
|
|
|
|
|
const char* forbidden[] = { "t", "te", "tem", "temp", NULL };
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
forbiddenid(int id)
|
|
|
|
|
{
|
|
|
|
|
static int * forbid = NULL;
|
|
|
|
|
static size_t len;
|
|
|
|
|
size_t i;
|
|
|
|
|
if (id<=0) return 1;
|
|
|
|
|
if (!forbid) {
|
|
|
|
|
while (forbidden[len]) ++len;
|
|
|
|
|
forbid = calloc(len, sizeof(int));
|
|
|
|
|
for (i=0;i!=len;++i) {
|
|
|
|
|
forbid[i] = strtol(forbidden[i], NULL, 36);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (i=0;i!=len;++i) if (id==forbid[i]) return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ID's f<>r Einheiten und Zauber */
|
|
|
|
|
int
|
|
|
|
|
newunitid(void)
|
|
|
|
|
{
|
|
|
|
|
int random_unit_no;
|
|
|
|
|
int start_random_no;
|
|
|
|
|
random_unit_no = 1 + (rand() % 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return random_unit_no;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
newcontainerid(void)
|
|
|
|
|
{
|
|
|
|
|
int random_no;
|
|
|
|
|
int start_random_no;
|
|
|
|
|
|
|
|
|
|
random_no = 1 + (rand() % MAX_CONTAINER_NR);
|
|
|
|
|
start_random_no = random_no;
|
|
|
|
|
|
|
|
|
|
while (findship(random_no) || findbuilding(random_no)) {
|
|
|
|
|
random_no++;
|
|
|
|
|
if (random_no == MAX_CONTAINER_NR + 1) {
|
|
|
|
|
random_no = 1;
|
|
|
|
|
}
|
|
|
|
|
if (random_no == start_random_no) {
|
|
|
|
|
random_no = (int) MAX_CONTAINER_NR + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return random_no;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
void
|
|
|
|
|
createunitid(unit *u, int id)
|
|
|
|
|
{
|
|
|
|
|
if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id))
|
|
|
|
|
u->no = newunitid();
|
|
|
|
|
else
|
|
|
|
|
u->no = id;
|
|
|
|
|
uhash(u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *
|
|
|
|
|
createunit(region * r, faction * f, int number, const struct race * rc)
|
|
|
|
|
{
|
|
|
|
|
return create_unit(r, f, number, rc, 0, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-21 19:22:48 +02:00
|
|
|
|
attrib_type at_creator = {
|
|
|
|
|
"creator"
|
|
|
|
|
/* Rest ist NULL; tempor<6F>res, nicht alterndes Attribut */
|
|
|
|
|
};
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit *
|
2001-12-10 01:13:39 +01:00
|
|
|
|
create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
unit * u = calloc(1, sizeof(unit));
|
|
|
|
|
|
|
|
|
|
assert(f->alive);
|
2001-02-10 15:18:01 +01:00
|
|
|
|
u_setfaction(u, f);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
set_string(&u->thisorder, "");
|
2001-12-23 10:23:53 +01:00
|
|
|
|
set_string(&u->lastorder, LOC(u->faction->locale, "defaultorder"));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
u_seteffstealth(u, -1);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
u->race = urace;
|
|
|
|
|
u->irace = urace;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
set_number(u, number);
|
|
|
|
|
|
|
|
|
|
/* die nummer der neuen einheit muss vor name_unit generiert werden,
|
|
|
|
|
* da der default name immer noch 'Nummer u->no' ist */
|
|
|
|
|
createunitid(u, id);
|
|
|
|
|
|
|
|
|
|
/* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen
|
|
|
|
|
* enthalten */
|
|
|
|
|
move_unit(u, r, NULL);
|
|
|
|
|
|
|
|
|
|
/* u->race muss bereits gesetzt sein, wird f<>r default-hp gebraucht */
|
|
|
|
|
/* u->region auch */
|
|
|
|
|
u->hp = unit_max_hp(u) * number;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (!dname) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
name_unit(u);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
else set_string(&u->name, dname);
|
|
|
|
|
set_string(&u->display, "");
|
|
|
|
|
|
|
|
|
|
/* Nicht zu der Einheitenzahl z<>hlen sollten auch alle Monster. Da
|
|
|
|
|
* aber auf die MAXUNITS nur in MACHE TEMP gepr<EFBFBD>ft wird, ist es egal */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(!fval(u->race, RCF_UNDEAD)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
f->no_units++;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 09:06:02 +01:00
|
|
|
|
if (creator) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
attrib * a;
|
|
|
|
|
|
|
|
|
|
/* erbt Kampfstatus */
|
|
|
|
|
u->status = creator->status;
|
|
|
|
|
|
|
|
|
|
/* erbt Geb<65>ude/Schiff*/
|
|
|
|
|
if (creator->region==r) {
|
|
|
|
|
u->building = creator->building;
|
|
|
|
|
u->ship = creator->ship;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */
|
|
|
|
|
if (fval(creator, FL_PARTEITARNUNG))
|
|
|
|
|
fset(u, FL_PARTEITARNUNG);
|
|
|
|
|
|
|
|
|
|
/* Daemonentarnung */
|
|
|
|
|
set_racename(&u->attribs, get_racename(creator->attribs));
|
2002-05-11 20:22:22 +02:00
|
|
|
|
if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
u->irace = creator->irace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Gruppen */
|
|
|
|
|
a = a_find(creator->attribs, &at_group);
|
|
|
|
|
if (a) {
|
|
|
|
|
group * g = (group*)a->data.v;
|
|
|
|
|
a_add(&u->attribs, a_new(&at_group))->data.v = g;
|
|
|
|
|
}
|
|
|
|
|
a = a_find(creator->attribs, &at_otherfaction);
|
2002-03-24 10:40:50 +01:00
|
|
|
|
if (a) {
|
|
|
|
|
a_add(&u->attribs, make_otherfaction(get_otherfaction(a)));
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2002-04-21 19:22:48 +02:00
|
|
|
|
|
|
|
|
|
a = a_add(&u->attribs, a_new(&at_creator));
|
|
|
|
|
a->data.v = creator;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2001-02-05 08:23:17 +01:00
|
|
|
|
/* Monster sind grunds<64>tzlich parteigetarnt */
|
|
|
|
|
if(f->no <= 0) fset(u, FL_PARTEITARNUNG);
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Setzt Default Befehle -------------------------------------- */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
idle (faction * f)
|
|
|
|
|
{
|
|
|
|
|
return (boolean) (f ? false : true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
maxworkingpeasants(const struct region * r)
|
|
|
|
|
{
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int i = production(r) * MAXPEASANTS_PER_AREA
|
|
|
|
|
- ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE);
|
|
|
|
|
#else
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int i = production(r) * MAXPEASANTS_PER_AREA - rtrees(r) * TREESIZE;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return max(i, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
check_leuchtturm(region * r, faction * f)
|
|
|
|
|
{
|
|
|
|
|
attrib * a;
|
|
|
|
|
|
|
|
|
|
if (rterrain(r) != T_OCEAN) return false;
|
|
|
|
|
|
|
|
|
|
for (a = a_find(r->attribs, &at_lighthouse);a;a=a->nexttype) {
|
|
|
|
|
building *b = (building *)a->data.v;
|
|
|
|
|
region *r2 = b->region;
|
|
|
|
|
|
2002-03-27 22:49:27 +01:00
|
|
|
|
assert(b->type == bt_find("lighthouse"));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (fval(b, BLD_WORKING) && b->size >= 10) {
|
|
|
|
|
int c = 0;
|
|
|
|
|
unit *u;
|
|
|
|
|
int d = 0;
|
|
|
|
|
int maxd = (int)log10(b->size) + 1;
|
|
|
|
|
|
|
|
|
|
for (u = r2->units; u; u = u->next) {
|
|
|
|
|
if (u->building == b) {
|
|
|
|
|
c += u->number;
|
|
|
|
|
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_OBSERVATION, r) >= d * 3) return true;
|
|
|
|
|
}
|
|
|
|
|
} else if (c) break; /* first unit that's no longer in the house ends the search */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
|
|
|
|
lastregion (faction * f)
|
|
|
|
|
{
|
|
|
|
|
region *r = f->last;
|
|
|
|
|
if (!r && f->units) {
|
|
|
|
|
for (r = firstregion(f); r; r = r->next) {
|
2002-05-05 12:26:33 +02:00
|
|
|
|
plane * p = rplane(r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
unit *u;
|
|
|
|
|
attrib *ru;
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
f->last = r->next;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (f->last == r->next)
|
|
|
|
|
continue;
|
|
|
|
|
for (ru = a_find(r->attribs, &at_travelunit); ru; ru = ru->nexttype) {
|
|
|
|
|
u = (unit*)ru->data.v;
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
f->last = r->next;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (f->last == r->next)
|
|
|
|
|
continue;
|
|
|
|
|
if (check_leuchtturm(r, f))
|
|
|
|
|
f->last = r->next;
|
2002-05-05 12:26:33 +02:00
|
|
|
|
if (p && is_watcher(p, f)) {
|
2002-05-05 13:14:47 +02:00
|
|
|
|
f->last = r->next;
|
2002-05-05 12:26:33 +02:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return f->last;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
|
|
|
|
firstregion (faction * f)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
if (f->first || !f->units)
|
|
|
|
|
return f->first;
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
attrib *ru;
|
|
|
|
|
unit *u;
|
2002-05-05 12:26:33 +02:00
|
|
|
|
plane * p = rplane(r);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
f->first = r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (f->first == r->next)
|
|
|
|
|
continue;
|
|
|
|
|
for (ru = a_find(r->attribs, &at_travelunit); ru; ru = ru->nexttype) {
|
|
|
|
|
u = (unit*)ru->data.v;
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
f->first = r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (check_leuchtturm(r, f)) {
|
|
|
|
|
f->first = r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2002-05-05 12:26:33 +02:00
|
|
|
|
if (p && is_watcher(p, f)) {
|
|
|
|
|
f->first = r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
f->first = regions;
|
|
|
|
|
return regions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ** blk_list[1024];
|
|
|
|
|
int list_index;
|
|
|
|
|
int blk_index;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gc_done(void)
|
|
|
|
|
{
|
|
|
|
|
int i, k;
|
|
|
|
|
for (i=0;i!=list_index;++i)
|
|
|
|
|
{
|
|
|
|
|
for (k=0;k!=1024;++k) free(blk_list[i][k]);
|
|
|
|
|
free(blk_list[i]);
|
|
|
|
|
}
|
|
|
|
|
for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]);
|
|
|
|
|
free(blk_list[list_index]);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
gc_add(void * p)
|
|
|
|
|
{
|
|
|
|
|
if (blk_index==0) {
|
|
|
|
|
blk_list[list_index] = (void**)malloc(1024 * sizeof(void*));
|
|
|
|
|
}
|
|
|
|
|
blk_list[list_index][blk_index] = p;
|
|
|
|
|
blk_index = (blk_index+1) % 1024;
|
|
|
|
|
if (!blk_index) ++ list_index;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
findorder(const unit * u, const char * cmd)
|
|
|
|
|
{
|
|
|
|
|
strlist * o;
|
|
|
|
|
char * c;
|
|
|
|
|
for (o=u->orders;o;o=o->next) {
|
|
|
|
|
if (!strcmp(cmd, o->s)) {
|
|
|
|
|
if (o->s==cmd)
|
|
|
|
|
return cmd;
|
|
|
|
|
return o->s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
c = strdup(cmd);
|
|
|
|
|
gc_add(c);
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
use_birthdayamulet(region * r, unit * magician, strlist * cmdstrings)
|
|
|
|
|
{
|
|
|
|
|
region *tr;
|
|
|
|
|
direction_t d;
|
|
|
|
|
|
|
|
|
|
unused(cmdstrings);
|
|
|
|
|
unused(magician);
|
|
|
|
|
|
|
|
|
|
for(d=0;d<MAXDIRECTIONS;d++) {
|
|
|
|
|
tr = rconnect(r, d);
|
|
|
|
|
if(tr) addmessage(tr, 0, "Miiauuuuuu...", MSG_MESSAGE, ML_IMPORTANT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tr = r;
|
|
|
|
|
addmessage(r, 0, "Miiauuuuuu...", MSG_MESSAGE, ML_IMPORTANT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct t_umlaut {
|
|
|
|
|
const char *txt;
|
2001-02-15 03:41:47 +01:00
|
|
|
|
int id;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int typ;
|
|
|
|
|
} t_umlaut;
|
|
|
|
|
|
|
|
|
|
/* Hier sind zum einen Umlaut-Versionen von Schl<68>sselworten, aber auch
|
|
|
|
|
* oftmals Umlaut-umschriebene Worte, weil im "normalen" Source die
|
|
|
|
|
* Umlaut-Version steht, damit die im Report erscheint.
|
|
|
|
|
* WICHTIG: "setenv LANG en_US" sonst ist <EFBFBD> != <EFBFBD>
|
|
|
|
|
*/
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
#if 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static const t_umlaut umlaut[] = {
|
|
|
|
|
/* Parameter */
|
|
|
|
|
{ "Stra<EFBFBD>en", P_ROAD, UT_PARAM },
|
|
|
|
|
/* Gegenst<73>nde - alternative Namen */
|
|
|
|
|
{ "Eisenbarren", I_IRON, UT_ITEM },
|
|
|
|
|
{ "Holzstamm", I_WOOD, UT_ITEM },
|
|
|
|
|
{ "Holzst<EFBFBD>mme", I_WOOD, UT_ITEM },
|
|
|
|
|
{ "St<EFBFBD>mme", I_WOOD, UT_ITEM },
|
|
|
|
|
{ "Stamm", I_WOOD, UT_ITEM },
|
|
|
|
|
{ "Quader", I_STONE, UT_ITEM },
|
|
|
|
|
{ "Steinquader", I_STONE, UT_ITEM },
|
|
|
|
|
{ "Langbogen", I_LONGBOW, UT_ITEM },
|
|
|
|
|
{ "Langb<EFBFBD>gen", I_LONGBOW, UT_ITEM },
|
|
|
|
|
{ "Hemden", I_CHAIN_MAIL, UT_ITEM },
|
|
|
|
|
{ "Panzer", I_PLATE_ARMOR, UT_ITEM },
|
|
|
|
|
{ "Gew<EFBFBD>rze", I_SPICES, UT_ITEM },
|
|
|
|
|
{ "<EFBFBD>le", I_OIL, UT_ITEM },
|
|
|
|
|
{ "Sehens", I_AMULET_OF_TRUE_SEEING, UT_ITEM },
|
|
|
|
|
{ "Heilung", I_AMULET_OF_HEALING, UT_ITEM },
|
|
|
|
|
{ "Unsichtbarkeit", I_RING_OF_INVISIBILITY, UT_ITEM },
|
|
|
|
|
{ "Macht", I_RING_OF_POWER, UT_ITEM },
|
|
|
|
|
#ifdef COMPATIBILITY
|
|
|
|
|
{ "Einhornaugen", I_EYE_OF_HORAX, UT_ITEM },
|
|
|
|
|
{ "Reisekristall", I_TELEPORTCRYSTAL, UT_ITEM },
|
|
|
|
|
{ "Dunkelheit", I_AMULET_OF_DARKNESS, UT_ITEM },
|
|
|
|
|
#endif
|
|
|
|
|
{ "Kopf", I_DRAGONHEAD, UT_ITEM },
|
|
|
|
|
{ "K<EFBFBD>pfe", I_DRAGONHEAD, UT_ITEM },
|
|
|
|
|
{ "Keuschheitsamulett", I_CHASTITY_BELT, UT_ITEM },
|
|
|
|
|
{ "Zweih<EFBFBD>nder", I_GREATSWORD, UT_ITEM },
|
|
|
|
|
{ "Axt", I_AXE, UT_ITEM },
|
|
|
|
|
{ "<EFBFBD>xte", I_AXE, UT_ITEM },
|
|
|
|
|
{ "Treffens", I_AMULETT_DES_TREFFENS, UT_ITEM },
|
|
|
|
|
{ "Flinkfingerring", I_RING_OF_NIMBLEFINGER, UT_ITEM },
|
|
|
|
|
{ NULL, 0, 0 }
|
|
|
|
|
};
|
2001-04-16 16:34:19 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static void
|
|
|
|
|
init_directions(tnode * root, const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
/* mit dieser routine kann man mehrere namen f<>r eine direction geben,
|
|
|
|
|
* das ist f<EFBFBD>r die hexes ideal. */
|
|
|
|
|
const struct {
|
|
|
|
|
const char* name;
|
|
|
|
|
int direction;
|
|
|
|
|
} 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}
|
|
|
|
|
};
|
|
|
|
|
int i;
|
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
|
|
|
|
for (i=0; dirs[i].direction!=NODIRECTION;++i) {
|
|
|
|
|
addtoken(&lnames->directions, LOC(lang, dirs[i].name), (void*)dirs[i].direction);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t
|
|
|
|
|
finddirection(const char *s, const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
|
|
|
|
int dir;
|
|
|
|
|
|
|
|
|
|
if (findtoken(&lnames->directions, s, (void**)&dir)==E_TOK_SUCCESS) {
|
|
|
|
|
return (direction_t)dir;
|
|
|
|
|
}
|
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static void
|
2001-04-16 16:34:19 +02:00
|
|
|
|
init_tokens(const struct locale * lang)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
struct lstr * lnames = get_lnames(lang);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int i;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const struct race * rc;
|
|
|
|
|
|
|
|
|
|
init_directions(&lnames->directions, lang);
|
|
|
|
|
for (rc=races;rc;rc=rc->next) {
|
|
|
|
|
addtoken(&lnames->races, LOC(lang, rc_name(rc, 1)), (void*)rc);
|
2002-01-01 21:51:18 +01:00
|
|
|
|
addtoken(&lnames->races, LOC(lang, rc_name(rc, 0)), (void*)rc);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (i=0;i!=MAXPARAMS;++i)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
addtoken(&lnames->tokens[UT_PARAM], LOC(lang, parameters[i]), (void*)i);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (i=0;i!=MAXSKILLS;++i)
|
2002-02-15 17:13:30 +01:00
|
|
|
|
addtoken(&lnames->skillnames, skillname((skill_t)i, lang), (void*)i);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (i=0;i!=MAXKEYWORDS;++i)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
addtoken(&lnames->keywords, LOC(lang, keywords[i]), (void*)i);
|
|
|
|
|
for (i=0;i!=MAXOPTIONS;++i)
|
|
|
|
|
addtoken(&lnames->options, LOC(lang, options[i]), (void*)i);
|
2001-04-16 16:34:19 +02:00
|
|
|
|
#if 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
for (i=0;umlaut[i].txt;++i)
|
2001-04-16 16:34:19 +02:00
|
|
|
|
addtoken(&lnames->tokens[umlaut[i].typ], umlaut[i].txt, (void*)umlaut[i].id);
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-02-05 17:11:59 +01:00
|
|
|
|
void
|
2001-04-16 16:34:19 +02:00
|
|
|
|
kernel_done(void)
|
2001-02-05 17:11:59 +01: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.
|
|
|
|
|
*/
|
2001-03-01 00:28:55 +01:00
|
|
|
|
translation_done();
|
2001-02-05 17:11:59 +01:00
|
|
|
|
skill_done();
|
|
|
|
|
gc_done();
|
2001-12-10 01:13:39 +01:00
|
|
|
|
sql_done();
|
2001-02-05 17:11:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
static void
|
2001-03-01 00:28:55 +01:00
|
|
|
|
read_strings(FILE * F)
|
|
|
|
|
{
|
|
|
|
|
char rbuf[8192];
|
|
|
|
|
while (fgets(rbuf, sizeof(rbuf), F)) {
|
|
|
|
|
char * b = rbuf;
|
|
|
|
|
locale * lang;
|
|
|
|
|
char * key = b;
|
|
|
|
|
char * language;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
const char * k;
|
2001-03-01 00:28:55 +01:00
|
|
|
|
|
|
|
|
|
if (rbuf[0]=='#') continue;
|
|
|
|
|
rbuf[strlen(rbuf)-1] = 0; /* \n weg */
|
|
|
|
|
while (*b && *b!=';') ++b;
|
|
|
|
|
if (!*b) continue;
|
|
|
|
|
*b++ = 0;
|
|
|
|
|
language = b;
|
|
|
|
|
while (*b && *b!=';') ++b;
|
|
|
|
|
*b++ = 0;
|
|
|
|
|
lang = find_locale(language);
|
|
|
|
|
if (!lang) lang = make_locale(language);
|
2001-04-16 16:34:19 +02:00
|
|
|
|
k = locale_getstring(lang, key);
|
|
|
|
|
if (k) {
|
|
|
|
|
log_warning(("Trying to register %s[%s]=\"%s\", already have \"%s\"\n", key, language, k, b));
|
|
|
|
|
} else locale_setstring(lang, key, b);
|
2001-03-01 00:28:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
const char * messages[] = {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
"%s/%s/strings.xml",
|
2001-04-16 16:34:19 +02:00
|
|
|
|
"%s/%s/messages.xml",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char * strings[] = {
|
|
|
|
|
"%s/%s/strings.txt",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char * locales[] = {
|
|
|
|
|
"de", "en",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
2002-01-05 17:14:38 +01:00
|
|
|
|
static int read_xml(const char * filename, struct xml_stack *stack);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
|
|
|
|
static int
|
2002-01-05 17:14:38 +01:00
|
|
|
|
parse_tagbegin(struct xml_stack *stack)
|
2001-04-16 16:34:19 +02:00
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
const xml_tag * tag = stack->tag;
|
|
|
|
|
if (strcmp(tag->name, "include")==0) {
|
|
|
|
|
const char * filename = xml_value(tag, "file");
|
|
|
|
|
if (filename) {
|
2002-01-05 17:14:38 +01:00
|
|
|
|
return read_xml(filename, stack);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
} else {
|
|
|
|
|
log_printf("required tag 'file' missing from include");
|
|
|
|
|
return XML_USERERROR;
|
|
|
|
|
}
|
2001-12-15 13:26:04 +01:00
|
|
|
|
} else if (strcmp(tag->name, "game")==0) {
|
2001-12-15 15:44:18 +01:00
|
|
|
|
const char * welcome = xml_value(tag, "welcome");
|
2001-12-15 13:26:04 +01:00
|
|
|
|
const char * name = xml_value(tag, "name");
|
|
|
|
|
int maxunits = xml_ivalue(tag, "units");
|
2001-12-15 15:44:18 +01:00
|
|
|
|
if (welcome!=NULL) {
|
|
|
|
|
global.welcomepath = strdup(welcome);
|
|
|
|
|
}
|
2001-12-15 13:26:04 +01:00
|
|
|
|
if (name!=NULL) {
|
|
|
|
|
global.gamename = strdup(name);
|
|
|
|
|
}
|
|
|
|
|
if (maxunits!=0) {
|
|
|
|
|
global.maxunits = maxunits;
|
|
|
|
|
}
|
2001-12-13 22:57:46 +01:00
|
|
|
|
} else if (strcmp(tag->name, "order")==0) {
|
|
|
|
|
const char * name = xml_value(tag, "name");
|
|
|
|
|
if (xml_bvalue(tag, "disable")) {
|
|
|
|
|
int k;
|
|
|
|
|
for (k=0;k!=MAXKEYWORDS;++k) {
|
|
|
|
|
if (strncmp(keywords[k], name, strlen(name))==0) {
|
2002-01-27 11:52:06 +01:00
|
|
|
|
global.disabled[k]=1;
|
2001-12-13 22:57:46 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
return XML_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-05 17:14:38 +01:00
|
|
|
|
static xml_callbacks xml_eressea = {
|
|
|
|
|
parse_tagbegin, NULL, NULL
|
2001-12-10 01:13:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
2002-01-05 17:14:38 +01:00
|
|
|
|
read_xml(const char * filename, xml_stack * stack)
|
2001-12-10 01:13:39 +01:00
|
|
|
|
{
|
|
|
|
|
char zText[80];
|
2001-04-16 16:34:19 +02:00
|
|
|
|
FILE * F;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int i;
|
|
|
|
|
sprintf(zText, "%s/%s", resourcepath(), filename);
|
|
|
|
|
F = fopen(zText, "r+");
|
|
|
|
|
if (F==NULL) {
|
|
|
|
|
log_printf("could not open %s: %s\n", zText, strerror(errno));
|
|
|
|
|
return XML_USERERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-05 17:14:38 +01:00
|
|
|
|
i = xml_read(F, stack);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
fclose(F);
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
init_data(const char * filename)
|
|
|
|
|
{
|
2002-01-05 17:14:38 +01:00
|
|
|
|
int l;
|
|
|
|
|
|
|
|
|
|
xml_register(&xml_eressea, "eressea", 0);
|
|
|
|
|
xml_register(&xml_eressea, "eressea include", XML_CB_IGNORE);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2002-01-05 17:14:38 +01:00
|
|
|
|
l = read_xml(filename, NULL);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (l) return l;
|
|
|
|
|
|
|
|
|
|
/* old stuff, for removal: */
|
2001-04-16 16:34:19 +02:00
|
|
|
|
for (l=0;locales[l];++l) {
|
|
|
|
|
char zText[MAX_PATH];
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0;strings[i];++i) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
FILE * F;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
sprintf(zText, strings[i], resourcepath(), locales[l]);
|
|
|
|
|
F = fopen(zText, "r+");
|
|
|
|
|
if (F) {
|
|
|
|
|
read_strings(F);
|
|
|
|
|
fclose(F);
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(buf, "fopen(%s): ", zText);
|
|
|
|
|
perror(buf);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return 1;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
init_locales(void)
|
|
|
|
|
{
|
|
|
|
|
int l;
|
2001-04-16 16:34:19 +02:00
|
|
|
|
for (l=0;locales[l];++l) {
|
|
|
|
|
const struct locale * lang = find_locale(locales[l]);
|
|
|
|
|
if (lang) init_tokens(lang);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO: soll hier weg */
|
|
|
|
|
extern building_type bt_caldera;
|
|
|
|
|
extern attrib_type at_traveldir_new;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
attrib_type at_germs = {
|
|
|
|
|
"germs",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
DEFAULT_READ,
|
|
|
|
|
ATF_UNIQUE
|
|
|
|
|
};
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
void
|
|
|
|
|
attrib_init(void)
|
|
|
|
|
{
|
|
|
|
|
/* Alle speicherbaren Attribute m<>ssen hier registriert werden */
|
|
|
|
|
at_register(&at_unitdissolve);
|
|
|
|
|
at_register(&at_traveldir_new);
|
|
|
|
|
at_register(&at_familiar);
|
|
|
|
|
at_register(&at_familiarmage);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
at_register(&at_clone);
|
|
|
|
|
at_register(&at_clonemage);
|
2001-04-16 16:34:19 +02:00
|
|
|
|
at_register(&at_eventhandler);
|
|
|
|
|
at_register(&at_stealth);
|
|
|
|
|
at_register(&at_mage);
|
|
|
|
|
at_register(&at_bauernblut);
|
|
|
|
|
at_register(&at_countdown);
|
|
|
|
|
at_register(&at_showitem);
|
|
|
|
|
at_register(&at_curse);
|
|
|
|
|
at_register(&at_cursewall);
|
|
|
|
|
|
|
|
|
|
at_register(&at_seenspell);
|
|
|
|
|
at_register(&at_reportspell);
|
|
|
|
|
at_register(&at_deathcloud);
|
|
|
|
|
|
|
|
|
|
/* neue REGION-Attribute */
|
|
|
|
|
at_register(&at_direction);
|
|
|
|
|
at_register(&at_moveblock);
|
|
|
|
|
#if AT_SALARY
|
|
|
|
|
at_register(&at_salary);
|
|
|
|
|
#endif
|
|
|
|
|
at_register(&at_horseluck);
|
|
|
|
|
at_register(&at_peasantluck);
|
|
|
|
|
at_register(&at_deathcount);
|
|
|
|
|
at_register(&at_chaoscount);
|
|
|
|
|
at_register(&at_woodcount);
|
|
|
|
|
at_register(&at_road);
|
|
|
|
|
|
|
|
|
|
/* neue UNIT-Attribute */
|
|
|
|
|
at_register(&at_alias);
|
|
|
|
|
at_register(&at_siege);
|
|
|
|
|
at_register(&at_target);
|
|
|
|
|
at_register(&at_potion);
|
|
|
|
|
at_register(&at_potionuser);
|
|
|
|
|
at_register(&at_contact);
|
|
|
|
|
at_register(&at_effect);
|
|
|
|
|
at_register(&at_private);
|
|
|
|
|
|
|
|
|
|
at_register(&at_icastle);
|
|
|
|
|
at_register(&at_guard);
|
|
|
|
|
at_register(&at_lighthouse);
|
|
|
|
|
at_register(&at_group);
|
|
|
|
|
at_register(&at_faction_special);
|
|
|
|
|
at_register(&at_prayer_timeout);
|
|
|
|
|
at_register(&at_prayer_effect);
|
|
|
|
|
at_register(&at_wyrm);
|
|
|
|
|
at_register(&at_building_generic_type);
|
|
|
|
|
|
|
|
|
|
/* border-typen */
|
|
|
|
|
register_bordertype(&bt_noway);
|
|
|
|
|
register_bordertype(&bt_fogwall);
|
|
|
|
|
register_bordertype(&bt_wall);
|
|
|
|
|
register_bordertype(&bt_illusionwall);
|
|
|
|
|
register_bordertype(&bt_firewall);
|
|
|
|
|
register_bordertype(&bt_wisps);
|
|
|
|
|
register_bordertype(&bt_road);
|
2002-04-27 16:25:35 +02:00
|
|
|
|
register_bordertype(&bt_questportal);
|
2001-04-16 16:34:19 +02:00
|
|
|
|
|
|
|
|
|
at_register(&at_jihad);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
at_register(&at_skillmod);
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
at_register(&at_germs);
|
|
|
|
|
#endif
|
|
|
|
|
at_register(&at_laen); /* required for old datafiles */
|
2002-04-28 15:06:27 +02:00
|
|
|
|
at_register(&at_xontormiaexpress); /* required for old datafiles */
|
2001-04-16 16:34:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
2001-02-05 17:11:59 +01:00
|
|
|
|
kernel_init(void)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
char zBuffer[MAX_PATH];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
skill_init();
|
|
|
|
|
attrib_init();
|
2001-03-01 00:28:55 +01:00
|
|
|
|
translation_init();
|
2002-01-05 17:14:38 +01:00
|
|
|
|
init_messages();
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!turn) turn = lastturn();
|
2001-02-05 17:11:59 +01:00
|
|
|
|
if (turn == 0)
|
|
|
|
|
srand(time((time_t *) NULL));
|
|
|
|
|
else
|
|
|
|
|
srand(turn);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
|
|
|
|
sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn);
|
|
|
|
|
sql_init(zBuffer);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_guard */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_guard = {
|
|
|
|
|
"guard",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
DEFAULT_READ,
|
|
|
|
|
ATF_UNIQUE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
setguard(unit * u, unsigned int flags)
|
|
|
|
|
{
|
|
|
|
|
/* setzt die guard-flags der Einheit */
|
|
|
|
|
attrib * a = a_find(u->attribs, &at_guard);
|
|
|
|
|
if(flags == GUARD_NONE) {
|
|
|
|
|
if(a) a_remove(&u->attribs, a);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!a) a = a_add(&u->attribs, a_new(&at_guard));
|
|
|
|
|
a->data.i = (int)flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
|
getguard(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
attrib *a;
|
|
|
|
|
|
|
|
|
|
if(u->region->terrain == T_OCEAN) return GUARD_NONE;
|
|
|
|
|
a = a_find(u->attribs, &at_guard);
|
|
|
|
|
if (a) return (unsigned int)a->data.i;
|
|
|
|
|
return GUARD_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_STRDUP
|
|
|
|
|
char *
|
|
|
|
|
strdup(const char *s)
|
|
|
|
|
{
|
|
|
|
|
return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void
|
2002-05-02 01:47:32 +02:00
|
|
|
|
remove_empty_factions(boolean writedropouts)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
faction **fp, *f3;
|
2002-05-02 01:47:32 +02:00
|
|
|
|
FILE *dofp = NULL;
|
2001-01-28 09:50:46 +01:00
|
|
|
|
char zText[MAX_PATH];
|
2002-03-10 09:34:43 +01:00
|
|
|
|
sprintf(zText, "%s/dropouts.%d", basepath(), turn);
|
2001-01-28 09:50:46 +01:00
|
|
|
|
|
2002-05-02 01:47:32 +02:00
|
|
|
|
if (writedropouts) dofp = fopen(zText, "w");
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (fp = &factions; *fp;) {
|
|
|
|
|
faction * f = *fp;
|
|
|
|
|
/* monster (0) werden nicht entfernt. alive kann beim readgame
|
|
|
|
|
* () auf 0 gesetzt werden, wenn monsters keine einheiten mehr
|
|
|
|
|
* haben. */
|
|
|
|
|
if (f->alive == 0 && f->no != MONSTER_FACTION) {
|
2002-03-10 09:34:43 +01:00
|
|
|
|
ursprung * ur = f->ursprung;
|
|
|
|
|
while (ur && ur->id!=0) ur=ur->next;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!quiet) printf("\t%s\n", factionname(f));
|
|
|
|
|
|
|
|
|
|
/* Einfach in eine Datei schreiben und sp<73>ter vermailen */
|
|
|
|
|
|
2002-05-02 01:47:32 +02:00
|
|
|
|
if (dofp) fprintf(dofp, "%s %s %d %d %d\n", f->email, LOC(default_locale, rc_name(f->race, 0)), f->age, ur?ur->x:0, ur?ur->y:0);
|
2001-12-30 12:27:58 +01:00
|
|
|
|
if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
for (f3 = factions; f3; f3 = f3->next) {
|
|
|
|
|
ally * sf;
|
|
|
|
|
group * g;
|
|
|
|
|
ally ** sfp = &f3->allies;
|
|
|
|
|
while (*sfp) {
|
|
|
|
|
sf = *sfp;
|
|
|
|
|
if (sf->faction == f || sf->faction == NULL) {
|
|
|
|
|
*sfp = sf->next;
|
|
|
|
|
free(sf);
|
|
|
|
|
}
|
|
|
|
|
else sfp = &(*sfp)->next;
|
|
|
|
|
}
|
|
|
|
|
for (g = f3->groups; g; g=g->next) {
|
|
|
|
|
sfp = &g->allies;
|
|
|
|
|
while (*sfp) {
|
|
|
|
|
sf = *sfp;
|
|
|
|
|
if (sf->faction == f || sf->faction == NULL) {
|
|
|
|
|
*sfp = sf->next;
|
|
|
|
|
free(sf);
|
|
|
|
|
}
|
|
|
|
|
else sfp = &(*sfp)->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-03 11:51:24 +01:00
|
|
|
|
fprintf(sqlstream, "UPDATE subscriptions set status='DEAD' where "
|
2002-04-20 22:07:35 +02:00
|
|
|
|
"faction='%s' and game=%d\n;", itoa36(f->no), GAME_ID);
|
2002-04-07 02:44:01 +02:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
*fp = f->next;
|
2002-04-07 02:44:01 +02:00
|
|
|
|
/* stripfaction(f);
|
|
|
|
|
* free(f);
|
|
|
|
|
* Wir k<EFBFBD>nnen die nicht l<EFBFBD>schen, weil sie evtl. noch in attributen
|
|
|
|
|
* referenziert sind ! */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
else fp = &(*fp)->next;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-02 01:47:32 +02:00
|
|
|
|
if (dofp) fclose(dofp);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
remove_empty_units_in_region(region *r)
|
|
|
|
|
{
|
|
|
|
|
unit **up = &r->units;
|
|
|
|
|
|
|
|
|
|
while (*up) {
|
|
|
|
|
unit * u = *up;
|
2002-05-23 09:19:54 +02:00
|
|
|
|
#ifdef MAXAGE
|
2002-05-25 08:58:54 +02:00
|
|
|
|
faction * f = u->faction;
|
2002-05-23 09:19:54 +02:00
|
|
|
|
if (f->age > MAXAGE) set_number(u, 0);
|
|
|
|
|
#endif
|
2002-01-27 11:40:40 +01:00
|
|
|
|
if ((u->number <= 0 && u->race != new_race[RC_SPELL])
|
|
|
|
|
|| (u->age <= 0 && u->race == new_race[RC_SPELL])
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|| u->number < 0) {
|
|
|
|
|
destroy_unit(u);
|
|
|
|
|
}
|
|
|
|
|
if (*up==u) up=&u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
remove_empty_units(void)
|
|
|
|
|
{
|
|
|
|
|
region *r;
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
remove_empty_units_in_region(r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int *used_faction_ids = NULL;
|
|
|
|
|
int no_used_faction_ids = 0;
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_cmp_int(const void *i1, const void *i2)
|
|
|
|
|
{
|
|
|
|
|
if(i2==NULL)
|
|
|
|
|
return(*(int*)i1);
|
|
|
|
|
return (*(int*)i1 - *(int *)i2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
register_faction_id(int id)
|
|
|
|
|
{
|
|
|
|
|
no_used_faction_ids++;
|
|
|
|
|
used_faction_ids = realloc(used_faction_ids, no_used_faction_ids*sizeof(int));
|
|
|
|
|
used_faction_ids[no_used_faction_ids-1] = id;
|
|
|
|
|
if(no_used_faction_ids > 1)
|
|
|
|
|
qsort(used_faction_ids, (size_t)no_used_faction_ids, sizeof(int), _cmp_int);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
faction_id_is_unused(int id)
|
2001-04-16 16:34:19 +02:00
|
|
|
|
{
|
2002-08-18 09:14:35 +02:00
|
|
|
|
#if 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(used_faction_ids==NULL)
|
|
|
|
|
return(true);
|
|
|
|
|
return (boolean)(bsearch(&id, used_faction_ids, no_used_faction_ids,
|
|
|
|
|
sizeof(int), _cmp_int) == NULL);
|
2002-08-18 09:14:35 +02:00
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
weight(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
int w, n = 0, in_bag = 0;
|
|
|
|
|
int faerie_level;
|
|
|
|
|
|
|
|
|
|
item * itm;
|
|
|
|
|
for (itm=u->items;itm;itm=itm->next) {
|
|
|
|
|
w = itm->type->weight * itm->number;
|
|
|
|
|
n += w;
|
|
|
|
|
if( !fval(itm->type, ITF_BIG))
|
|
|
|
|
in_bag += w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
faerie_level = fspecial(u->faction, FS_FAERIE);
|
|
|
|
|
if (faerie_level) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
n += (u->number * u->race->weight)/(1+faerie_level);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
n += u->number * u->race->weight;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY;
|
|
|
|
|
if( w > in_bag )
|
|
|
|
|
w = in_bag;
|
|
|
|
|
n -= w;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
init_used_faction_ids(void)
|
|
|
|
|
{
|
|
|
|
|
faction *f;
|
|
|
|
|
|
|
|
|
|
no_used_faction_ids = 0;
|
|
|
|
|
for(f = factions; f; f = f->next) {
|
|
|
|
|
register_faction_id(f->no);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unit *
|
2001-12-10 01:13:39 +01:00
|
|
|
|
make_undead_unit(region * r, faction * f, int n, const struct race * rc)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
unit *u;
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
u = createunit(r, f, n, rc);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
set_string(&u->lastorder, "");
|
|
|
|
|
name_unit(u);
|
2002-03-11 22:20:31 +01:00
|
|
|
|
fset(u, UFL_ISNEW);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
guard(unit * u, unsigned int mask)
|
|
|
|
|
{
|
|
|
|
|
int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX;
|
2002-04-21 19:44:17 +02:00
|
|
|
|
#if GUARD_DISABLES_PRODUCTION == 1
|
|
|
|
|
flags |= GUARD_PRODUCE;
|
|
|
|
|
#endif
|
|
|
|
|
#if GUARD_DISABLES_RECRUIT == 1
|
|
|
|
|
flags |= GUARD_RECRUIT;
|
|
|
|
|
#endif
|
2001-12-10 01:13:39 +01:00
|
|
|
|
switch (old_race(u->race)) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
case RC_ELF:
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (u->faction->race != u->race) break;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* else fallthrough */
|
|
|
|
|
case RC_TREEMAN:
|
|
|
|
|
flags |= GUARD_TREES;
|
|
|
|
|
break;
|
|
|
|
|
case RC_IRONKEEPER:
|
|
|
|
|
flags = GUARD_MINING;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
setguard(u, flags & mask);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
besieged(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
/* belagert kann man in schiffen und burgen werden */
|
|
|
|
|
return (u
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
&& u->building && u->building->besieged
|
2001-01-25 10:37:55 +01:00
|
|
|
|
&& u->building->besieged >= u->building->size * SIEGEFACTOR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
lifestyle(const unit * u)
|
|
|
|
|
{
|
|
|
|
|
static plane * astralspace = NULL;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int need = u->number * u->race->maintenance;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (!astralspace) {
|
|
|
|
|
astralspace = getplanebyname("Astralraum");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Keinen Unterhalt im Astralraum. */
|
|
|
|
|
if (getplane(u->region) == astralspace)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if(u->region->planep && fval(u->region->planep, PFL_NOFEED))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if(fspecial(u->faction, FS_REGENERATION))
|
|
|
|
|
need += 1;
|
|
|
|
|
if(fspecial(u->faction, FS_ADMINISTRATOR))
|
|
|
|
|
need += 1;
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if(fspecial(u->faction, FS_WYRM) && old_race(u->race) == RC_WYRM)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
need *= 500;
|
|
|
|
|
|
|
|
|
|
return need;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
hunger(unit * u, int need)
|
|
|
|
|
{
|
|
|
|
|
region * r = u->region;
|
|
|
|
|
int dead = 0, hpsub = 0;
|
|
|
|
|
int hp = u->hp / u->number;
|
|
|
|
|
int lspp = lifestyle(u)/u->number;
|
|
|
|
|
|
|
|
|
|
if(lspp <= 0) return;
|
|
|
|
|
|
|
|
|
|
while(need > 0) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
int dam = old_race(u->race)==RC_HALFLING?15+rand()%14:(13+rand()%12);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if(dam >= hp) {
|
|
|
|
|
++dead;
|
|
|
|
|
} else {
|
|
|
|
|
hpsub += dam;
|
|
|
|
|
}
|
|
|
|
|
need -= lspp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dead) {
|
2001-02-02 09:40:49 +01:00
|
|
|
|
/* Gestorbene aus der Einheit nehmen,
|
|
|
|
|
* Sie bekommen keine Beerdingung. */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"starvation%u:unit%r:region%i:dead%i:live", u, r, dead, u->number-dead));
|
|
|
|
|
|
|
|
|
|
scale_number(u, u->number - dead);
|
2001-02-02 09:40:49 +01:00
|
|
|
|
deathcounts(r, dead);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
if(hpsub > 0) {
|
|
|
|
|
/* Jetzt die Sch<63>den der nicht gestorbenen abziehen. */
|
|
|
|
|
u->hp -= hpsub;
|
|
|
|
|
/* Meldung nur, wenn noch keine f<>r Tote generiert. */
|
2001-02-02 09:40:49 +01:00
|
|
|
|
if (dead == 0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Durch unzureichende Ern<72>hrung wird %s geschw<68>cht */
|
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction,
|
|
|
|
|
"malnourish%u:unit%r:region", u, r));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(dead || hpsub) {
|
|
|
|
|
fset(u, FL_HUNGER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plagues(region * r, boolean ismagic)
|
|
|
|
|
{
|
|
|
|
|
double prob;
|
|
|
|
|
int peasants;
|
|
|
|
|
int i;
|
|
|
|
|
int gestorben;
|
|
|
|
|
/* Vermeidung von DivByZero */
|
|
|
|
|
double mwp = max(maxworkingpeasants(r), 1);
|
|
|
|
|
|
|
|
|
|
/* Seuchenwahrscheinlichkeit in % */
|
|
|
|
|
|
|
|
|
|
prob = pow((double) rpeasants(r) /
|
|
|
|
|
(mwp * (((double)wage(r,NULL,false)) / 10.0) * 1.3), 4.0)
|
|
|
|
|
* (double) SEUCHE;
|
|
|
|
|
|
|
|
|
|
if (rand() % 100 >= (int)prob && !ismagic) return;
|
|
|
|
|
|
|
|
|
|
peasants = rpeasants(r);
|
|
|
|
|
for (i = peasants; i != 0; i--) {
|
|
|
|
|
if (rand() % 100 < SEUCHENOPFER) {
|
|
|
|
|
if (rand() % 100 < HEILCHANCE && rmoney(r) >= HEILKOSTEN) {
|
|
|
|
|
rsetmoney(r, rmoney(r) - HEILKOSTEN);
|
|
|
|
|
} else {
|
|
|
|
|
peasants--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gestorben = rpeasants(r) - peasants;
|
|
|
|
|
|
|
|
|
|
if (gestorben > 0) {
|
2001-05-20 23:47:56 +02:00
|
|
|
|
message * msg = add_message(&r->msgs, msg_message("pest", "dead", gestorben));
|
|
|
|
|
msg_release(msg);
|
2002-03-17 11:33:47 +01:00
|
|
|
|
deathcounts(r, gestorben);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
rsetpeasants(r, peasants);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Lohn bei den einzelnen Burgstufen f<>r Normale Typen, Orks, Bauern,
|
|
|
|
|
* Modifikation f<EFBFBD>r St<EFBFBD>dter. */
|
|
|
|
|
|
2002-01-20 13:53:35 +01:00
|
|
|
|
#if LARGE_CASTLES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static const int wagetable[7][4] = {
|
2002-01-20 13:53:35 +01:00
|
|
|
|
{10, 10, 11, -7}, /* Baustelle */
|
2001-12-10 01:13:39 +01:00
|
|
|
|
{10, 10, 11, -5}, /* Handelsposten */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{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 */
|
|
|
|
|
};
|
2002-01-20 13:53:35 +01:00
|
|
|
|
#else
|
|
|
|
|
static const int wagetable[7][4] = {
|
|
|
|
|
{10, 10, 11, -5}, /* Baustelle */
|
|
|
|
|
{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 */
|
|
|
|
|
};
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
wage(const region *r, const unit *u, boolean img)
|
|
|
|
|
/* Gibt Arbeitslohn f<>r entsprechende Rasse zur<75>ck, oder f<>r
|
|
|
|
|
* die Bauern wenn ra == NORACE. */
|
|
|
|
|
{
|
|
|
|
|
building *b = largestbuilding(r, img);
|
|
|
|
|
int esize = 0;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
curse * c;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int wage;
|
|
|
|
|
attrib *a;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
static const curse_type * drought_ct, * blessedharvest_ct;
|
|
|
|
|
static boolean init;
|
|
|
|
|
if (!init) {
|
|
|
|
|
init = true;
|
|
|
|
|
drought_ct = ct_find("drought");
|
|
|
|
|
blessedharvest_ct = ct_find("blessedharvest");
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (b) esize = buildingeffsize(b, img);
|
|
|
|
|
|
|
|
|
|
if (u) {
|
2002-02-10 21:02:23 +01:00
|
|
|
|
wage = wagetable[esize][u->race == new_race[RC_ORC] || u->race == new_race[RC_SNOTLING] || u->race == new_race[RC_URUK]];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (fspecial(u->faction, FS_URBAN)) {
|
|
|
|
|
wage += wagetable[esize][3];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
wage = 11;
|
|
|
|
|
} else if (fval(r, RF_ORCIFIED)) {
|
|
|
|
|
wage = wagetable[esize][1];
|
|
|
|
|
} else {
|
|
|
|
|
wage = wagetable[esize][2];
|
|
|
|
|
}
|
2002-05-01 21:08:32 +02:00
|
|
|
|
wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Godcurse: Income -10 */
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
wage = max(0,wage-10);
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Bei einer D<>rre verdient man nur noch ein Viertel */
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (drought_ct) {
|
|
|
|
|
c = get_curse(r->attribs, drought_ct);
|
|
|
|
|
if (curse_active(c)) wage /= curse_geteffect(c);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
a = a_find(r->attribs, &at_reduceproduction);
|
|
|
|
|
if (a) wage = (wage * a->data.sa[0])/100;
|
|
|
|
|
|
|
|
|
|
return wage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
fwage(const region *r, const faction *f, boolean img)
|
|
|
|
|
{
|
|
|
|
|
building *b = largestbuilding(r, img);
|
|
|
|
|
int esize = 0;
|
|
|
|
|
int wage;
|
|
|
|
|
attrib *a;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
curse * c;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
if (b) esize = buildingeffsize(b, img);
|
|
|
|
|
|
|
|
|
|
if (f) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
wage = wagetable[esize][old_race(f->race) == RC_ORC];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (fspecial(f, FS_URBAN)) {
|
|
|
|
|
wage += wagetable[esize][3];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (rterrain(r) == T_OCEAN) {
|
|
|
|
|
wage = 11;
|
|
|
|
|
} else if (fval(r, RF_ORCIFIED)) {
|
|
|
|
|
wage = wagetable[esize][1];
|
|
|
|
|
} else {
|
|
|
|
|
wage = wagetable[esize][2];
|
|
|
|
|
}
|
2002-05-01 21:08:32 +02:00
|
|
|
|
wage += curse_geteffect(get_curse(r->attribs, ct_find("blessedharvest")));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Godcurse: Income -10 */
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
wage = max(0,wage-10);
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* Bei einer D<>rre verdient man nur noch ein Viertel */
|
2002-05-01 21:08:32 +02:00
|
|
|
|
c = get_curse(r->attribs, ct_find("drought"));
|
|
|
|
|
if (curse_active(c)) wage /= curse_geteffect(c);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
a = a_find(r->attribs, &at_reduceproduction);
|
|
|
|
|
if (a) wage = (wage * a->data.sa[0])/100;
|
|
|
|
|
|
|
|
|
|
return wage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
region *
|
2001-01-25 10:37:55 +01:00
|
|
|
|
findspecialdirection(const region *r, char *token)
|
|
|
|
|
{
|
|
|
|
|
attrib *a;
|
|
|
|
|
spec_direction *d;
|
|
|
|
|
|
|
|
|
|
for (a = a_find(r->attribs, &at_direction);a;a=a->nexttype) {
|
|
|
|
|
d = (spec_direction *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
if(strncasecmp(d->keyword, token, strlen(token)) == 0) {
|
|
|
|
|
return findregion(d->x, d->y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
|
|
|
|
movewhere(region * r, const unit *u)
|
|
|
|
|
{
|
|
|
|
|
direction_t d;
|
|
|
|
|
char *token;
|
|
|
|
|
region * r2;
|
|
|
|
|
|
|
|
|
|
token = getstrtoken();
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
d = finddirection(token, u->faction->locale);
|
2001-02-18 13:20:37 +01:00
|
|
|
|
if (d == D_PAUSE)
|
|
|
|
|
return r;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (d == NODIRECTION)
|
|
|
|
|
return findspecialdirection(r, token);
|
|
|
|
|
|
|
|
|
|
#if 0 /* NOT here! make a temporary attribute for this and move it into travel() */
|
|
|
|
|
if (is_cursed(r->attribs, C_REGCONF, 0)) {
|
|
|
|
|
if (rand()%100 < get_curseeffect(r->attribs, C_REGCONF, 0)) {
|
|
|
|
|
if(u->wants < 0) u->wants--;
|
|
|
|
|
else if(u->wants > 0) u->wants++;
|
|
|
|
|
else u->wants = rand()%2==0?1:-1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u->ship && is_cursed(u->ship->attribs, C_DISORIENTATION, 0)) {
|
|
|
|
|
if (rand()%100 < get_curseeffect(r->attribs, C_DISORIENTATION, 0)) {
|
|
|
|
|
if(u->wants < 0) u->wants--;
|
|
|
|
|
else if(u->wants > 0) u->wants++;
|
|
|
|
|
else u->wants = rand()%20?1:-1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
d = (direction_t)((d + u->wants + MAXDIRECTIONS) % MAXDIRECTIONS);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!rconnect(r, d)) {
|
|
|
|
|
#if USE_CREATION
|
|
|
|
|
makeblock(r->x + delta_x[d], r->y + delta_y[d], 1);
|
|
|
|
|
printf("* Fehler! Region (%d,%d) hatte seine Nachbarn "
|
|
|
|
|
"(%d,%d) noch nicht generiert!\n", r->x, r->y,
|
|
|
|
|
r->x + delta_x[d], r->y + delta_y[d]);
|
|
|
|
|
#else
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2001-04-16 16:34:19 +02:00
|
|
|
|
msg_message("moveblocked", "unit direction", u, d));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
r2 = rconnect(r, d);
|
|
|
|
|
|
|
|
|
|
if (!r2) {
|
|
|
|
|
printf("* Fehler! Region (%d,%d) hatte seine Nachbarn "
|
|
|
|
|
"(%d,%d) nicht gefunden!", r->x, r->y,
|
|
|
|
|
r->x + delta_x[d], r->y + delta_y[d]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (move_blocked(u, r, d) == true) {
|
2001-12-10 01:13:39 +01:00
|
|
|
|
add_message(&u->faction->msgs,
|
2001-04-16 16:34:19 +02:00
|
|
|
|
msg_message("moveblocked", "unit direction", u, d));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* r2 enth<74>lt nun die existierende Zielregion - ihre Nachbarn sollen
|
|
|
|
|
* auch schon alle existieren. Dies erleichtert das Umherschauen bei
|
|
|
|
|
* den Reports! */
|
|
|
|
|
|
|
|
|
|
#if USE_CREATION
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; d++)
|
|
|
|
|
if (!rconnect(r2, d))
|
|
|
|
|
makeblock(r2->x + delta_x[d], r2->y + delta_y[d], 1);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return r2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
move_blocked(const unit * u, const region *r, direction_t dir)
|
|
|
|
|
{
|
|
|
|
|
region * r2 = NULL;
|
|
|
|
|
border * b;
|
|
|
|
|
if (dir<MAXDIRECTIONS) r2 = rconnect(r, dir);
|
|
|
|
|
if (r2==NULL) return true;
|
|
|
|
|
b = get_borders(r, r2);
|
|
|
|
|
while (b) {
|
|
|
|
|
if (b->type->block && b->type->block(b, u, r)) return true;
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
add_income(unit * u, int type, int want, int qty)
|
|
|
|
|
{
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
if (want==INT_MAX) want = qty;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
add_message(&u->faction->msgs, new_message(u->faction, "income%u:unit%r:region%i:mode%i:wanted%i:amount",
|
|
|
|
|
u, u->region, type, want, qty));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int weeks_per_month;
|
|
|
|
|
int months_per_year;
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
month(int offset)
|
|
|
|
|
{
|
|
|
|
|
int t = turn - FIRST_TURN + offset;
|
|
|
|
|
int year, r, month;
|
|
|
|
|
|
|
|
|
|
if (t<0) t = turn;
|
|
|
|
|
|
|
|
|
|
year = t/(months_per_year * weeks_per_month) + 1;
|
|
|
|
|
r = t - (year-1) * months_per_year * weeks_per_month;
|
|
|
|
|
month = r/weeks_per_month;
|
|
|
|
|
|
|
|
|
|
return month;
|
|
|
|
|
}
|
2001-04-13 16:39:57 +02:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
reorder_owners(region * r)
|
|
|
|
|
{
|
|
|
|
|
unit ** up=&r->units, ** useek;
|
|
|
|
|
building * b=NULL;
|
|
|
|
|
ship * sh=NULL;
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
size_t len = listlen(r->units);
|
|
|
|
|
#endif
|
|
|
|
|
for (b = r->buildings;b;b=b->next) {
|
|
|
|
|
unit ** ubegin = up;
|
|
|
|
|
unit ** uend = up;
|
|
|
|
|
|
|
|
|
|
useek = up;
|
|
|
|
|
while (*useek) {
|
|
|
|
|
unit * u = *useek;
|
|
|
|
|
if (u->building==b) {
|
|
|
|
|
unit ** insert;
|
|
|
|
|
if (fval(u, FL_OWNER)) {
|
|
|
|
|
unit * nu = *ubegin;
|
|
|
|
|
insert=ubegin;
|
|
|
|
|
if (nu!=u && nu->building==u->building && fval(nu, FL_OWNER)) {
|
|
|
|
|
log_error(("[reorder_owners] %s hat mehrere Besitzer mit FL_OWNER.\n", buildingname(nu->building)));
|
|
|
|
|
freset(nu, FL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else insert = uend;
|
|
|
|
|
if (insert!=useek) {
|
|
|
|
|
*useek = u->next; /* raus aus der liste */
|
|
|
|
|
u->next = *insert;
|
|
|
|
|
*insert = u;
|
|
|
|
|
}
|
|
|
|
|
if (insert==uend) uend=&u->next;
|
|
|
|
|
}
|
|
|
|
|
if (*useek==u) useek = &u->next;
|
|
|
|
|
}
|
|
|
|
|
up = uend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useek=up;
|
|
|
|
|
while (*useek) {
|
|
|
|
|
unit * u = *useek;
|
|
|
|
|
assert(!u->building);
|
|
|
|
|
if (u->ship==NULL) {
|
|
|
|
|
if (fval(u, FL_OWNER)) {
|
|
|
|
|
log_warning(("[reorder_owners] Einheit %s war Besitzer von nichts.\n", unitname(u)));
|
|
|
|
|
freset(u, FL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
if (useek!=up) {
|
|
|
|
|
*useek = u->next; /* raus aus der liste */
|
|
|
|
|
u->next = *up;
|
|
|
|
|
*up = u;
|
|
|
|
|
}
|
|
|
|
|
up = &u->next;
|
|
|
|
|
}
|
|
|
|
|
if (*useek==u) useek = &u->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (sh = r->ships;sh;sh=sh->next) {
|
|
|
|
|
unit ** ubegin = up;
|
|
|
|
|
unit ** uend = up;
|
|
|
|
|
|
|
|
|
|
useek = up;
|
|
|
|
|
while (*useek) {
|
|
|
|
|
unit * u = *useek;
|
|
|
|
|
if (u->ship==sh) {
|
|
|
|
|
unit ** insert;
|
|
|
|
|
if (fval(u, FL_OWNER)) {
|
|
|
|
|
unit * nu = *ubegin;
|
|
|
|
|
insert = ubegin;
|
|
|
|
|
if (nu!=u && nu->ship==u->ship && fval(nu, FL_OWNER)) {
|
|
|
|
|
log_error(("[reorder_owners] %s hat mehrere Besitzer mit FL_OWNER.\n", shipname(nu->ship)));
|
|
|
|
|
freset(nu, FL_OWNER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else insert = uend;
|
|
|
|
|
if (insert!=useek) {
|
|
|
|
|
*useek = u->next; /* raus aus der liste */
|
|
|
|
|
u->next = *insert;
|
|
|
|
|
*insert = u;
|
|
|
|
|
}
|
|
|
|
|
if (insert==uend) uend=&u->next;
|
|
|
|
|
}
|
|
|
|
|
if (*useek==u) useek = &u->next;
|
|
|
|
|
}
|
|
|
|
|
up = uend;
|
|
|
|
|
}
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
assert(len==listlen(r->units));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2002-02-03 03:54:47 +01:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
produceexp(struct unit * u, skill_t sk, int n)
|
|
|
|
|
{
|
|
|
|
|
if (n==0 || !playerrace(u->race)) return 0;
|
2002-02-16 11:37:18 +01:00
|
|
|
|
learn_skill(u, sk, PRODUCEEXP/30.0);
|
2002-02-03 03:54:47 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-15 17:13:30 +01:00
|
|
|
|
boolean
|
|
|
|
|
teure_talente (const struct unit * u)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|