server/src/common/kernel/save.c

2162 lines
45 KiB
C
Raw Normal View History

2001-01-25 10:37:55 +01:00
/* vi: set ts=2:
*
* Eressea PB(E)M host Copyright (C) 1998-2003
2001-01-25 10:37:55 +01:00
* 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"
#include "save.h"
2004-06-21 18:45:27 +02:00
#include "alchemy.h"
#include "alliance.h"
2004-06-21 18:45:27 +02:00
#include "attrib.h"
#include "border.h"
#include "building.h"
2001-01-25 10:37:55 +01:00
#include "faction.h"
#include "group.h"
2001-01-25 10:37:55 +01:00
#include "item.h"
2004-06-21 18:45:27 +02:00
#include "karma.h"
#include "magic.h"
#include "message.h"
2001-01-25 10:37:55 +01:00
#include "movement.h"
2004-06-21 18:45:27 +02:00
#include "objtypes.h"
#include "order.h"
#include "pathfinder.h"
#include "plane.h"
#include "race.h"
2001-01-25 10:37:55 +01:00
#include "region.h"
#include "resources.h"
2001-01-25 10:37:55 +01:00
#include "ship.h"
2004-06-21 18:45:27 +02:00
#include "skill.h"
#include "spell.h"
#include "terrain.h"
#include "terrainid.h" /* only for conversion code */
2004-06-21 18:45:27 +02:00
#include "unit.h"
2001-01-25 10:37:55 +01:00
#ifdef USE_UGROUPS
#include "ugroup.h"
#include <attributes/ugroup.h>
#endif
2001-01-25 10:37:55 +01:00
/* attributes includes */
#include <attributes/key.h>
/* util includes */
#include <attrib.h>
#include <base36.h>
#include <event.h>
#include <util/goodies.h>
2001-01-25 10:37:55 +01:00
#include <resolve.h>
#include <sql.h>
#include <rand.h>
#include <umlaut.h>
2001-01-25 10:37:55 +01:00
/* libc includes */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-')
2001-01-25 10:37:55 +01:00
#define COMMENT_CHAR ';'
#define ESCAPE_FIX
#define MAXORDERS 256
2005-07-28 15:20:36 +02:00
#define MAXPERSISTENT 128
2001-01-25 10:37:55 +01:00
/* exported symbols symbols */
const char * xmlfile = "eressea.xml";
2001-01-25 10:37:55 +01:00
const char * g_datadir;
int firstx = 0, firsty = 0;
/* local symbols */
static region * current_region;
2001-01-25 10:37:55 +01:00
#if RESOURCE_CONVERSION
int laen_read(attrib * a, FILE * F)
{
int laen;
fscanf(F, "%d", &laen);
read_laen(current_region, laen);
return AT_READ_FAIL;
}
#endif
2001-01-25 10:37:55 +01:00
char *
rns(FILE * f, char *c, size_t size)
{
char * s = c;
do {
*s = (char) getc(f);
} while (*s!='"');
for (;;) {
*s = (char) getc(f);
if (*s=='"') break;
if (s<c+size) ++s;
}
*s = 0;
return c;
}
extern unsigned int __at_hashkey(const char* s);
FILE *
cfopen(const char *filename, const char *mode)
{
FILE * F = fopen(filename, mode);
if (F == 0) {
perror(filename);
return NULL;
}
setvbuf(F, 0, _IOFBF, 32 * 1024); /* 32 kb buffer size */
return F;
}
/* ------------------------------------------------------------- */
/* Dummy-Funktion f<>r die Kompatibilit<69>t */
#define rid(F) ri36(F)
2001-01-25 10:37:55 +01:00
static int nextc;
2001-01-25 10:37:55 +01:00
#define rc(F) (nextc = getc(F))
2002-12-01 12:23:17 +01:00
#undef CONVERT_DBLINK
#ifdef CONVERT_DBLINK
typedef struct uniquenode {
struct uniquenode * next;
int id;
faction * f;
} uniquenode;
#define HASHSIZE 2039
static uniquenode * uniquehash[HASHSIZE];
static faction *
uniquefaction(int id)
{
uniquenode * node = uniquehash[id%HASHSIZE];
while (node && node->id!=id) node=node->next;
return node?node->f:NULL;
}
static void
addunique(int id, faction * f)
{
uniquenode * fnode = calloc(1, sizeof(uniquenode));
fnode->f = f;
fnode->id = id;
fnode->next = uniquehash[id%HASHSIZE];
uniquehash[id%HASHSIZE] = fnode;
}
typedef struct mapnode {
struct mapnode * next;
int fno;
int subscription;
} mapnode;
static mapnode * subscriptions[HASHSIZE];
void
convertunique(faction * f)
{
int unique = f->subscription;
static FILE * F = NULL;
mapnode * mnode;
addunique(unique, f);
if (F==NULL) {
static char zText[MAX_PATH];
strcat(strcpy(zText, basepath()), "/subscriptions");
F = fopen(zText, "r");
if (F==NULL) {
log_warning(("could not open %s.\n", zText));
abort();
}
for (;;) {
char zFaction[5];
int subscription, fno;
2002-11-03 14:40:17 +01:00
if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break;
mnode = calloc(1, sizeof(mapnode));
fno = atoi36(zFaction);
mnode->next = subscriptions[fno%HASHSIZE];
mnode->fno = fno;
mnode->subscription = subscription;
subscriptions[fno%HASHSIZE] = mnode;
}
}
mnode = subscriptions[f->no%HASHSIZE];
while (mnode!=NULL && mnode->fno!=f->no) mnode = mnode->next;
2002-11-02 16:50:51 +01:00
if (mnode) f->subscription = mnode->subscription;
else {
2002-11-02 18:38:43 +01:00
log_printf("%s %s %s %s\n",
2002-11-02 16:50:51 +01:00
itoa36(f->no), f->email, f->override, dbrace(f->race));
}
}
#endif
2001-01-25 10:37:55 +01:00
void
rds(FILE * F, char **ds)
{
static char buffer[DISPLAYSIZE + 1]; /*Platz f<>r null-char nicht vergessen!*/
char *s = &buffer[0];
while (nextc != '"') {
if (nextc == EOF) {
*s = 0;
fprintf(stderr, "Die Datei bricht vorzeitig ab.\n");
abort();
}
rc(F);
}
rc(F);
while (nextc != '"') {
if (nextc == EOF) {
*s = 0;
fprintf(stderr, "Die Datei bricht vorzeitig ab.\n");
abort();
}
2005-06-17 20:12:58 +02:00
if (s - buffer < DISPLAYSIZE) {
*s++ = (char)nextc;
}
2001-01-25 10:37:55 +01:00
rc(F);
}
rc(F);
*s = 0;
if (ds) {
2005-06-17 20:12:58 +02:00
*ds = realloc(*ds, sizeof(char) * (strlen(buffer) + 1));
strcpy(*ds, buffer);
}
2001-01-25 10:37:55 +01:00
}
#define rcf(F) (getc(F));
void
rsf(FILE * F, char *s, size_t len)
{
char * begin = s;
int nextc;
do {
nextc = rcf(F);
if (nextc == EOF) {
puts("Die Datei bricht vorzeitig ab.");
abort();
}
} while (nextc != '"');
for (;;) {
nextc = rcf(F);
if (nextc == '"') break;
else if (nextc == EOF) {
puts("Die Datei bricht vorzeitig ab.");
abort();
}
if (s-begin<(int)len-1)
*s++ = (char)nextc;
}
*s = 0;
}
static void
rs(FILE * F, char *s)
{
boolean apos = false;
while (isspace(nextc)) rc(F);
if (nextc=='"') {
apos=true;
2001-01-25 10:37:55 +01:00
rc(F);
}
for (;;) {
if (nextc=='"') {
rc(F);
break;
} else if (!apos && isspace(nextc)) break;
2001-01-25 10:37:55 +01:00
*s++ = (char)nextc;
rc(F);
}
*s = 0;
}
static int
ri(FILE * F)
{
int i = 0, vz = 1;
while (!xisdigit(nextc)) {
if (nextc == EOF) {
puts("Die Datei bricht vorzeitig ab.");
abort();
}
rc(F);
}
while (xisdigit(nextc)) {
if (nextc == '-')
vz = -1;
else
i = 10 * i + (nextc - '0');
rc(F);
}
return i * vz;
}
static int
ri36(FILE * F)
{
char buf[64];
int i = 0;
rc(F);
while (!isalnum(nextc)) rc(F);
while (isalnum(nextc)) {
buf[i++]=(char)nextc;
rc(F);
}
buf[i]=0;
i = atoi36(buf);
return i;
}
#define MAXLINE 4096*16
static char *
2001-01-25 10:37:55 +01:00
getbuf(FILE * F)
{
char lbuf[MAXLINE];
boolean cont = false;
boolean quote = false;
boolean comment = false;
char * cp = buf;
lbuf[MAXLINE-1] = '@';
do {
boolean eatwhite = true;
boolean start = true;
unsigned char * end;
unsigned char * bp = (unsigned char * )fgets(lbuf, MAXLINE, F);
comment = (boolean)(comment && cont);
if (!bp) return NULL;
end = bp + strlen((const char *)bp);
if (*(end-1)=='\n') *(--end) = 0;
else {
2004-10-15 00:37:16 +02:00
/* wenn die zeile l<>nger als erlaubt war, ist sie ung<6E>ltig,
* und wird mit dem rest weggeworfen: */
for (;;) {
2004-10-15 00:37:16 +02:00
bp = (unsigned char *)fgets(lbuf, MAXLINE, F);
if (bp==NULL) break;
2004-10-15 00:37:16 +02:00
end = bp + strlen((const char *)bp);
if (*(end-1)=='\n') break;
lbuf[MAXLINE-1] = 0;
}
2004-10-15 00:37:16 +02:00
comment = false;
bp = NULL;
}
2001-01-25 10:37:55 +01:00
cont = false;
2004-10-15 00:37:16 +02:00
while (bp!=NULL && *bp && cp!=buf+MAXLINE && (char*)bp!=lbuf+MAXLINE) {
2001-01-25 10:37:55 +01:00
if (isspace(*bp)) {
if (eatwhite) {
2001-01-25 10:37:55 +01:00
do { ++bp; } while ((char*)bp!=lbuf+MAXLINE && isspace(*bp));
if (!quote && !start && !comment) *(cp++)=' ';
}
else {
if (!comment) *(cp++)=*(bp++);
while (cp!=buf+MAXLINE && (char*)bp!=lbuf+MAXLINE && isspace(*bp)) {
if (!comment) *(cp++)=*bp;
2001-01-25 10:37:55 +01:00
++bp;
}
if (*bp==0) --cp;
2001-01-25 10:37:55 +01:00
}
}
else if (iscntrl(*bp)) {
*(cp++) = '?';
++bp;
} else {
cont = false;
if (*bp==COMMENT_CHAR && !quote) {
/* bp = max(end-1, bp+1); */
2001-01-25 10:37:55 +01:00
comment=true;
}
else {
if (*bp=='"') {
quote = (boolean)!quote;
*cp++ = *bp;
2001-01-25 10:37:55 +01:00
eatwhite=true;
}
else if (*bp=='\\') cont=true;
else {
if (!comment) *(cp++) = *bp;
eatwhite = (boolean)!quote;
}
}
++bp;
2001-01-25 10:37:55 +01:00
}
start = false;
}
if (cp==buf+MAXLINE) {
--cp;
}
*cp=0;
} while (cont || cp==buf);
return buf;
}
#ifdef ENEMIES
static void
read_enemies(FILE * F, faction * f)
{
if (global.data_version<ENEMIES_VERSION) return;
f->enemies = NULL;
for (;;) {
char zText[32];
fscanf(F, "%s", zText);
if (strcmp(zText, "end")==0) break;
else {
int fno = atoi36(zText);
faction_list * flist = malloc(sizeof(faction_list));
flist->next = f->enemies;
f->enemies = flist;
ur_add((void*)fno, (void**)&flist->data, resolve_faction);
}
}
}
static void
write_enemies(FILE * F, const faction_list * flist)
{
while (flist) {
fprintf(F, "%s ", itoa36(flist->data->no));
}
fputs("end \n", F);
}
#endif
2001-01-25 10:37:55 +01:00
static unit *
unitorders(FILE * F, struct faction * f)
2001-01-25 10:37:55 +01:00
{
2004-06-21 18:45:27 +02:00
int i;
unit *u;
if (!f) return NULL;
i = getid();
u = findunitg(i, NULL);
2005-05-27 23:04:13 +02:00
if (u && u->race == new_race[RC_SPELL]) return NULL;
2004-06-21 18:45:27 +02:00
if (u && u->faction == f) {
order ** ordp;
if (!quiet) {
printf(",_%4s_", itoa36(u->no));
fflush(stdout);
}
if (!fval(u, UFL_ORDERS)) {
/* alle wiederholbaren, langen befehle werden gesichert: */
fset(u, UFL_ORDERS);
u->old_orders = u->orders;
ordp = &u->old_orders;
while (*ordp) {
order * ord = *ordp;
if (!is_repeated(ord)) {
2005-05-01 13:38:06 +02:00
*ordp = ord->next;
2005-05-01 15:33:34 +02:00
ord->next = NULL;
free_order(ord);
} else {
ordp = &ord->next;
}
}
} else {
free_orders(&u->orders);
}
2004-06-21 18:45:27 +02:00
u->orders = 0;
ordp = &u->orders;
for (;;) {
const char * s;
/* Erst wenn wir sicher sind, dass kein Befehl
* eingegeben wurde, checken wir, ob nun eine neue
* Einheit oder ein neuer Spieler drankommt */
if (!getbuf(F)) break;
init_tokens_str(buf);
s = getstrtoken();
if (findkeyword(s, u->faction->locale) == NOKEYWORD) {
boolean quit = false;
switch (findparam(s, u->faction->locale)) {
case P_UNIT:
case P_REGION:
2004-06-21 18:45:27 +02:00
case P_FACTION:
case P_NEXT:
case P_GAMENAME:
quit = true;
}
if (quit) break;
}
if (buf[0]) {
/* Nun wird der Befehl erzeut und eingeh<65>ngt */
*ordp = parse_order(buf, u->faction->locale);
if (*ordp) ordp = &(*ordp)->next;
2004-06-21 18:45:27 +02:00
}
}
2001-01-25 10:37:55 +01:00
2004-06-21 18:45:27 +02:00
} else {
/* cmistake(?, buf, 160, MSG_EVENT); */
2004-06-21 18:45:27 +02:00
return NULL;
}
return u;
2001-01-25 10:37:55 +01:00
}
static faction *
factionorders(void)
2001-01-25 10:37:55 +01:00
{
char b[16];
char * fid = strnzcpy(b, getstrtoken(), 15);
const char * pass = getstrtoken();
2001-01-25 10:37:55 +01:00
faction *f;
f = findfaction(atoi36(fid));
2001-01-25 10:37:55 +01:00
if (f!=NULL) {
/* Kontrolliere, ob das Passwort richtig eingegeben wurde. Es
* mu<EFBFBD> in "G<EFBFBD>nsef<EFBFBD><EFBFBD>chen" stehen!! */
/* War vorher in main.c:getgarbage() */
if (!quiet) {
2001-02-17 16:02:50 +01:00
printf(" %4s;", factionid(f));
fflush(stdout);
2001-02-17 16:02:50 +01:00
}
2001-01-25 10:37:55 +01:00
if (checkpasswd(f, pass, true) == false) {
2004-03-21 22:29:37 +01:00
log_warning(("Invalid password for faction %s\n", fid));
2005-05-08 01:53:23 +02:00
ADDMSG(&f->msgs, msg_message("msg_errors", "string",
"Das Passwort wurde falsch eingegeben"));
2001-01-25 10:37:55 +01:00
return 0;
}
/* Die Partei hat sich zumindest gemeldet, so da<64> sie noch
* nicht als unt<EFBFBD>tig gilt */
2003-12-28 16:30:43 +01:00
/* TODO: +1 ist ein Workaround, weil turn erst in process_orders
* incrementiert wird. */
f->lastorders = global.data_turn+1;
2001-01-25 10:37:55 +01:00
} else
log_warning(("Befehle f<>r die ung<6E>ltige Partei %s\n", fid));
2001-01-25 10:37:55 +01:00
return f;
}
double
version(void)
{
return RELEASE_VERSION * 0.1;
}
/* ------------------------------------------------------------- */
2004-06-21 18:45:27 +02:00
static param_t
igetparam (const char *s, const struct locale *lang)
{
return findparam (igetstrtoken (s), lang);
}
2001-01-25 10:37:55 +01:00
int
readorders(const char *filename)
{
FILE * F = NULL;
2001-01-25 10:37:55 +01:00
char *b;
2001-02-17 16:02:50 +01:00
int nfactions=0;
struct faction *f = NULL;
2001-01-25 10:37:55 +01:00
if (filename) F = cfopen(filename, "rt");
2001-01-25 10:37:55 +01:00
if (F==NULL) return 0;
2001-02-17 16:02:50 +01:00
puts(" - lese Befehlsdatei...\n");
2001-01-25 10:37:55 +01:00
b = getbuf(F);
/* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten
* Partei */
while (b) {
const struct locale * lang = f?f->locale:default_locale;
2001-02-17 16:02:50 +01:00
int p;
const char * s;
switch (igetparam(b, lang)) {
case P_LOCALE:
s = getstrtoken();
2004-05-09 12:18:09 +02:00
#undef LOCALE_CHANGE
#ifdef LOCALE_CHANGE
if (f && find_locale(s)) {
f->locale = find_locale(s);
}
#endif
2001-02-17 16:02:50 +01:00
b = getbuf(F);
break;
case P_GAMENAME:
2001-01-25 10:37:55 +01:00
case P_FACTION:
f = factionorders();
if (f) {
++nfactions;
}
2001-01-25 10:37:55 +01:00
b = getbuf(F);
break;
/* in factionorders wird nur eine zeile gelesen:
2001-01-25 10:37:55 +01:00
* diejenige mit dem passwort. Die befehle der units
* werden geloescht, und die Partei wird als aktiv
* vermerkt. */
case P_UNIT:
if (!f || !unitorders(F, f)) do {
2001-01-25 10:37:55 +01:00
b = getbuf(F);
if (!b) break;
p = igetparam(b, lang);
} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT && p != P_GAMENAME);
2001-01-25 10:37:55 +01:00
break;
/* Falls in unitorders() abgebrochen wird, steht dort entweder eine neue
2001-01-25 10:37:55 +01:00
* Partei, eine neue Einheit oder das File-Ende. Das switch() wird erneut
* durchlaufen, und die entsprechende Funktion aufgerufen. Man darf buf
* auf alle F<EFBFBD>lle nicht <EFBFBD>berschreiben! Bei allen anderen Eintr<EFBFBD>gen hier
* mu<EFBFBD> buf erneut gef<EFBFBD>llt werden, da die betreffende Information in nur
* einer Zeile steht, und nun die n<EFBFBD>chste gelesen werden mu<EFBFBD>. */
case P_NEXT:
f = NULL;
b = getbuf(F);
break;
default:
2001-01-25 10:37:55 +01:00
b = getbuf(F);
break;
2001-01-25 10:37:55 +01:00
}
}
fclose(F);
2001-02-17 16:02:50 +01:00
puts("\n");
log_printf(" %d Befehlsdateien gelesen\n", nfactions);
return 0;
2001-01-25 10:37:55 +01:00
}
/* ------------------------------------------------------------- */
/* #define INNER_WORLD */
/* f<>rs debuggen nur den inneren Teil der Welt laden */
/* -9;-27;-1;-19;Sumpfloch */
int
inner_world(region * r)
{
static int xy[2] =
{18, -45};
static int size[2] =
{27, 27};
if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1])
return 2;
if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9)
return 1;
return 0;
}
int maxregions = -1;
int loadplane = 0;
boolean dirtyload = false;
2005-01-03 22:28:57 +01:00
boolean incomplete_data = false;
2001-01-25 10:37:55 +01:00
enum {
U_MAN,
U_UNDEAD,
U_ILLUSION,
U_FIREDRAGON,
U_DRAGON,
U_WYRM,
U_SPELL,
U_TAVERNE,
U_MONSTER,
U_BIRTHDAYDRAGON,
U_TREEMAN,
MAXTYPES
};
race_t
typus2race(unsigned char typus)
{
if (typus>0 && typus <=11) return (race_t)(typus-1);
return NORACE;
}
void
create_backup(char *file)
{
#if defined(HAVE_ACCESS)
char bfile[MAX_PATH];
char command[MAX_PATH*2+10];
2001-01-25 10:37:55 +01:00
int c = 1;
do {
sprintf(bfile, "%s.backup%d", file, c);
c++;
} while(access(bfile, R_OK) == 0);
sprintf(command, "cp %s %s", file, bfile);
system(command);
#endif
}
const char *
2001-01-25 10:37:55 +01:00
datapath(void)
{
static char zText[MAX_PATH];
2001-01-25 10:37:55 +01:00
if (g_datadir) return g_datadir;
return strcat(strcpy(zText, basepath()), "/data");
}
2001-01-25 10:37:55 +01:00
void
read_items(FILE *F, item **ilist)
{
for (;;) {
2003-12-14 11:10:30 +01:00
const item_type * itype;
2001-01-25 10:37:55 +01:00
rs(F, buf);
if (!strcmp("end", buf)) break;
2003-12-14 11:10:30 +01:00
itype = it_find(buf);
assert(itype!=NULL);
if (itype!=NULL) {
i_change(ilist, itype, ri(F));
}
2001-01-25 10:37:55 +01:00
}
}
#if RESOURCE_CONVERSION
2002-05-02 23:19:45 +02:00
struct attrib_type at_resources = {
"resources", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE
};
2002-05-02 23:19:45 +02:00
void
read_iron(struct region * r, int iron)
{
attrib * a = a_find(r->attribs, &at_resources);
assert(iron>=0);
if (a==NULL) {
a = a_add(&r->attribs, a_new(&at_resources));
a->data.sa[1] = -1;
}
a->data.sa[0] = (short)iron;
}
2002-05-02 23:19:45 +02:00
void
read_laen(struct region * r, int laen)
{
attrib * a = a_find(r->attribs, &at_resources);
assert(laen>=0);
if (a==NULL) {
a = a_add(&r->attribs, a_new(&at_resources));
a->data.sa[0] = -1;
}
a->data.sa[1] = (short)laen;
}
#endif
#ifdef USE_UGROUPS
void
read_ugroups(FILE *file)
{
int i;
faction *f;
ugroup *ug;
int fno, ugid, ugmem;
while(1) {
fno = ri(file);
if(fno == -1) break;
f = findfaction(fno);
while(1) {
ugid = ri(file);
if(ugid == -1) break;
ugmem = ri(file);
ug = malloc(sizeof(ugroup));
ug->id = ugid;
ug->members = ugmem;
ug->unit_array = malloc(ug->members * sizeof(unit *));
for(i=0; i<ugmem; i++) {
unit *u = findunitg(ri36(file), NULL);
ug->unit_array[i] = u;
a_add(&u->attribs, a_new(&at_ugroup))->data.i = ugid;
}
ug->next = f->ugroups;
f->ugroups = ug;
}
}
}
#endif
static void
read_alliances(FILE * F)
{
char pbuf[32];
if (global.data_version<SAVEALLIANCE_VERSION) {
if (!AllianceRestricted() && !AllianceAuto()) return;
}
rs(F, pbuf);
while (strcmp(pbuf, "end")!=0) {
rs(F, buf);
makealliance(atoi36(pbuf), buf);
2002-09-29 22:36:15 +02:00
rs(F, pbuf);
}
}
#define wc(F, c) putc(c, F);
#define wnl(F) putc('\n', F);
#define whs(F, s) fputs(s, F); putc(' ', F)
2001-01-25 10:37:55 +01:00
void
wsn(FILE * F, const char *s)
{
if (!s)
return;
while (*s)
wc(F, *s++);
}
void
ws(FILE * F, const char *s)
{
fputc('"', F);
2001-01-25 10:37:55 +01:00
wsn(F, s);
fputs("\" ", F);
2001-01-25 10:37:55 +01:00
}
static void
2001-01-25 10:37:55 +01:00
wi(FILE * F, int n)
{
fprintf(F, "%d ", n);
2001-01-25 10:37:55 +01:00
}
static void
wi36(FILE * F, int n)
2001-01-25 10:37:55 +01:00
{
fprintf(F, "%s ", itoa36(n));
2001-01-25 10:37:55 +01:00
}
void
write_alliances(FILE * F)
{
alliance * al = alliances;
while (al) {
2002-09-02 22:36:12 +02:00
wi36(F, al->id);
ws(F, al->name);
al = al->next;
wnl(F);
}
fprintf(F, "end ");
wnl(F);
}
2001-01-25 10:37:55 +01:00
void
write_items(FILE *F, item *ilist)
{
item * itm;
for (itm=ilist;itm;itm=itm->next) if (itm->number) {
fprintf(F, "%s %i ", resourcename(itm->type->rtype, 0), itm->number);
2001-01-25 10:37:55 +01:00
}
2002-02-24 14:06:05 +01:00
fputs("end ", F);
2001-01-25 10:37:55 +01:00
}
#ifdef USE_UGROUPS
void
write_ugroups(FILE *file)
{
faction *f;
ugroup *ug;
int i;
for(f=factions; f; f=f->next) if(f->ugroups) {
wi(file, f->no);
for(ug = f->ugroups; ug; ug=ug->next) {
wi(file, ug->id);
wi(file, ug->members);
for(i=0; i<ug->members; i++) {
wi36(file, ug->unit_array[i]->no);
}
}
fputs("-1\n", file);
}
fputs("-1\n", file);
}
#endif
#ifdef USE_PLAYERS
2001-04-26 19:41:06 +02:00
static void
export_players(const char * path)
{
FILE * F;
player * p = get_players();
if (p==NULL) return;
F = cfopen(path, "w");
if (F==NULL) return;
fputs("name;email;passwd;faction;info\n", F);
while (p) {
/* name */
fputc('\"', F);
if (p->name) fputs(p->name, F);
2001-04-26 19:41:06 +02:00
/* email */
fputs("\";\"", F);
if (p->email) fputs(p->email, F);
else if (p->faction) fputs(p->faction->email, F);
2001-04-26 19:41:06 +02:00
fputs("\";\"", F);
/* passwd */
fputs("\";\"", F);
if (p->faction) fputs(p->faction->passw, F);
/* faction */
fputs("\";\"", F);
if (p->faction) fputs(itoa36(p->faction->no), F);
/* info */
fputs("\";\"", F);
if (p->info) fputs(p->info, F);
else if (p->faction) fputs(p->faction->banner, F);
2001-04-26 19:41:06 +02:00
fputs("\"\n", F);
p = next_player(p);
}
fclose(F);
}
#endif
2001-04-26 19:41:06 +02:00
2001-01-25 10:37:55 +01:00
int
lastturn(void)
{
int turn = 0;
#ifdef HAVE_READDIR
DIR *data_dir = NULL;
struct dirent *entry = NULL;
const char * dir = datapath();
data_dir = opendir(dir);
if (data_dir != NULL) {
entry = readdir(data_dir);
}
if (data_dir != NULL && entry != NULL) {
turn = 0;
do {
int i = atoi(entry->d_name);
if (i > turn)
turn = i;
entry = readdir(data_dir);
} while (entry != NULL);
#ifdef HAVE_CLOSEDIR
closedir(data_dir);
#endif
}
#else
# error "requires dirent.h or an equivalent to compile!"
#endif
return turn;
}
2004-06-21 18:45:27 +02:00
void
fwriteorder(FILE * F, const order * ord, const struct locale * lang)
2004-06-21 18:45:27 +02:00
{
write_order(ord, lang, buf, sizeof(buf));
if (buf[0]) fwritestr(F, buf);
2004-06-21 18:45:27 +02:00
}
unit *
readunit(FILE * F)
{
skill_t sk;
unit * u;
int number, n, p;
order ** orderp;
n = rid(F);
u = findunit(n);
if (u==NULL) {
u = calloc(sizeof(unit), 1);
u->no = n;
uhash(u);
} else {
while (u->attribs) a_remove(&u->attribs, u->attribs);
while (u->items) i_free(i_remove(&u->items, u->items));
free(u->skills);
u->skills = 0;
u->skill_size = 0;
u_setfaction(u, NULL);
}
2002-09-02 22:36:12 +02:00
{
int n = rid(F);
faction * f = findfaction(n);
if (f!=u->faction) u_setfaction(u, f);
}
rds(F, &u->name);
if (lomem) rds(F, 0);
else rds(F, &u->display);
#ifndef NDEBUG
if (strlen(u->name)>=NAMESIZE) u->name[NAMESIZE] = 0;
if (u->display && strlen(u->display)>=DISPLAYSIZE) u->display[DISPLAYSIZE] = 0;
#endif
number = ri(F);
u->age = (short)ri(F);
if (global.data_version<NEWRACE_VERSION) {
u->race = new_race[(race_t)ri(F)];
u->irace = new_race[(race_t)ri(F)];
} else {
char * space;
rs(F, buf);
space = strchr(buf, ' ');
while (space!=NULL) {
strcpy(space, space+1);
space=strchr(space, ' ');
}
/* if (strcmp(buf, "giant turtle")==0) strcpy(buf, "giantturtle");
if (strcmp(buf, "young dragon")==0) strcpy(buf, "youngdragon");
if (strcmp(buf, "young dragon")==0) strcpy(buf, "youngdragon"); */
u->race = rc_find(buf);
assert(u->race);
rs(F, buf);
if (strlen(buf)) u->irace = rc_find(buf);
else u->irace = u->race;
}
if (u->faction == NULL) {
log_error(("unit %s has faction == NULL\n", unitname(u)));
u_setfaction(u, findfaction(MONSTER_FACTION));
set_number(u, 0);
}
if (playerrace(u->race)) {
u->faction->no_units++;
}
set_number(u, number);
2002-09-02 22:36:12 +02:00
u->building = findbuilding(rid(F));
u->ship = findship(rid(F));
if (global.data_version <= 73) {
if (ri(F)) {
fset(u, UFL_OWNER);
} else {
freset(u, UFL_OWNER);
}
}
u->status = (status_t) ri(F);
if (global.data_version < NEWSTATUS_VERSION) {
switch (u->status) {
case 0: u->status = ST_FIGHT; break;
case 1: u->status = ST_BEHIND; break;
case 2: u->status = ST_AVOID; break;
case 3: u->status = ST_FLEE; break;
default: assert(0);
}
}
if (global.data_version <= 73) {
if (ri(F)) {
guard(u, GUARD_ALL);
} else {
guard(u, GUARD_NONE);
}
} else {
u->flags = ri(F) & ~UFL_DEBUG;
u->flags &= UFL_SAVEMASK;
}
/* Persistente Befehle einlesen */
2004-06-21 18:45:27 +02:00
free_orders(&u->orders);
freadstr(F, buf, sizeof(buf));
p = n = 0;
orderp = &u->orders;
2004-07-03 21:16:17 +02:00
while (*buf != 0) {
order * ord = parse_order(buf, u->faction->locale);
if (ord!=NULL) {
if (++n<MAXORDERS) {
if (!is_persistent(ord) || ++p<MAXPERSISTENT) {
*orderp = ord;
orderp = &ord->next;
} else if (p==MAXPERSISTENT) {
log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT));
}
} else if (n==MAXORDERS) {
log_error(("%s had %d or more orders\n", unitname(u), MAXORDERS));
}
}
freadstr(F, buf, sizeof(buf));
}
if (global.data_version<NOLASTORDER_VERSION) {
order * ord;
freadstr(F, buf, sizeof(buf));
ord = parse_order(buf, u->faction->locale);
if (ord!=NULL) {
#ifdef LASTORDER
set_order(&u->lastorder, ord);
#else
addlist(&u->orders, ord);
#endif
}
}
set_order(&u->thisorder, NULL);
assert(u->number <= UNIT_MAXSIZE);
assert(u->race);
if (global.data_version<NEWSKILL_VERSION) {
/* convert old data */
while ((sk = (skill_t) ri(F)) != NOSKILL) {
int days = ri(F) / u->number;
int lvl = level(days);
int weeks = lvl + 1 - (days - level_days(lvl))/30;
assert(weeks>0 && weeks<=lvl+1);
if (lvl) {
skill * sv = add_skill(u, sk);
sv->level = sv->old = (unsigned char)lvl;
sv->weeks = (unsigned char)weeks;
}
}
} else {
while ((sk = (skill_t) ri(F)) != NOSKILL) {
int level = ri(F);
int weeks = ri(F);
if (level) {
skill * sv = add_skill(u, sk);
sv->level = sv->old = (unsigned char)level;
sv->weeks = (unsigned char)weeks;
}
}
}
read_items(F, &u->items);
u->hp = ri(F);
2002-10-20 10:57:37 +02:00
if (u->hp < u->number) {
log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no),
u->number, u->hp));
u->hp=u->number;
}
if (global.data_version < MAGE_ATTRIB_VERSION) {
2002-09-02 22:36:12 +02:00
int i = ri(F);
if (i != -1){
attrib * a;
int csp = 0;
sc_mage * mage = calloc(1, sizeof(sc_mage));
mage->magietyp = (magic_t) i;
mage->spellpoints = ri(F);
mage->spchange = ri(F);
while ((i = ri(F)) != -1) {
mage->combatspells[csp].sp = find_spellbyid((spellid_t)i);
mage->combatspells[csp].level = ri(F);
2002-09-02 22:36:12 +02:00
csp++;
}
2002-09-02 22:36:12 +02:00
while ((i = ri(F)) != -1) {
add_spell(mage, find_spellbyid((spellid_t)i));
}
2002-09-02 22:36:12 +02:00
mage->spellcount = 0;
a = a_add(&u->attribs, a_new(&at_mage));
a->data.v = mage;
}
}
a_read(F, &u->attribs);
return u;
}
void
writeunit(FILE * F, const unit * u)
{
2004-06-21 18:45:27 +02:00
order * ord;
int i, p = 0;
wi36(F, u->no);
wi36(F, u->faction->no);
ws(F, u->name);
ws(F, u->display?u->display:"");
wi(F, u->number);
wi(F, u->age);
ws(F, u->race->_name[0]);
ws(F, u->irace!=u->race?u->irace->_name[0]:"");
if (u->building)
wi36(F, u->building->no);
else
wi(F, 0);
2002-09-02 22:36:12 +02:00
if (u->ship) wi36(F, u->ship->no);
else wi36(F, 0);
wi(F, u->status);
wi(F, u->flags & UFL_SAVEMASK);
2004-06-21 18:45:27 +02:00
wnl(F);
#ifndef LASTORDER
for (ord = u->old_orders; ord; ord=ord->next) {
if (++p<MAXPERSISTENT) {
fwriteorder(F, ord, u->faction->locale);
fputc(' ', F);
} else {
log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT));
break;
}
}
#endif
for (ord = u->orders; ord; ord=ord->next) {
if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */
if (is_persistent(ord)) {
if (++p<MAXPERSISTENT) {
fwriteorder(F, ord, u->faction->locale);
fputc(' ', F);
} else {
log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT));
break;
}
}
}
2004-07-03 21:16:17 +02:00
/* write an empty string to terminate the list */
fputs("\"\"", F);
wnl(F);
#if RELEASE_VERSION<NOLASTORDER_VERSION
2004-07-03 21:16:17 +02:00
/* the current default order */
fwriteorder(F, u->lastorder, u->faction->locale);
wnl(F);
#endif
assert(u->number <= UNIT_MAXSIZE);
assert(u->race);
for (i=0;i!=u->skill_size;++i) {
skill * sv = u->skills+i;
2002-03-03 16:26:17 +01:00
assert(sv->weeks<=sv->level*2+1);
if (sv->level>0) {
wi(F, sv->id);
wi(F, sv->level);
wi(F, sv->weeks);
}
}
wi(F, -1);
wnl(F);
write_items(F, u->items);
wnl(F);
if (u->hp == 0) {
log_error(("Einheit %s hat 0 Trefferpunkte\n", itoa36(u->no)));
((unit*)u)->hp = 1;
}
wi(F, u->hp);
wnl(F);
a_write(F, u->attribs);
wnl(F);
}
region *
readregion(FILE * F, short x, short y)
{
region * r = findregion(x, y);
const terrain_type * terrain;
if (r==NULL) {
r = new_region(x, y);
} else {
current_region = r;
while (r->attribs) a_remove(&r->attribs, r->attribs);
if (r->land) {
free(r->land); /* mem leak */
2002-03-03 16:26:17 +01:00
r->land->demands = 0; /* mem leak */
}
while (r->resources) {
rawmaterial * rm = r->resources;
r->resources = rm->next;
free(rm);
}
r->land = 0;
}
if (lomem) rds(F, 0);
else rds(F, &r->display);
if (global.data_version < TERRAIN_VERSION) {
int ter = ri(F);
if (global.data_version < NOFOREST_VERSION) {
if (ter>T_PLAIN) --ter;
}
terrain = newterrain((terrain_t)ter);
} else {
char name[64];
rs(F, name);
terrain = get_terrain(name);
}
r->terrain = terrain;
2002-09-02 22:36:12 +02:00
r->flags = (char) ri(F);
if (global.data_version >= REGIONAGE_VERSION)
r->age = (unsigned short) ri(F);
else
r->age = 0;
if (fval(r->terrain, LAND_REGION)) {
r->land = calloc(1, sizeof(land_region));
rds(F, &r->land->name);
#ifndef NDEBUG
if (strlen(r->land->name)>=NAMESIZE) r->land->name[NAMESIZE] = 0;
#endif
}
2002-09-02 22:36:12 +02:00
if (r->land) {
int i;
if(global.data_version < GROWTREE_VERSION) {
i = ri(F); rsettrees(r, 2, i);
} else {
i = ri(F);
if (i<0) {
log_error(("number of trees in %s is %d.\n",
regionname(r, NULL), i));
i=0;
}
rsettrees(r, 0, i);
i = ri(F);
if (i<0) {
log_error(("number of young trees in %s is %d.\n",
regionname(r, NULL), i));
i=0;
}
rsettrees(r, 1, i);
i = ri(F);
if (i<0) {
log_error(("number of seeds in %s is %d.\n",
regionname(r, NULL), i));
i=0;
}
rsettrees(r, 2, i);
}
i = ri(F); rsethorses(r, i);
if (global.data_version < NEWRESOURCE_VERSION) {
2002-05-02 23:19:45 +02:00
i = ri(F);
#if RESOURCE_CONVERSION
if (i!=0) read_iron(r, i);
#endif
} else {
rawmaterial ** pres = &r->resources;
assert(*pres==NULL);
for (;;) {
rawmaterial * res;
rs(F, buf);
if (strcmp(buf, "end")==0) break;
res = calloc(sizeof(rawmaterial), 1);
res->type = rmt_find(buf);
assert(res->type!=NULL);
res->level = ri(F);
res->amount = ri(F);
if(global.data_version >= RANDOMIZED_RESOURCES_VERSION) {
res->startlevel = ri(F);
res->base = ri(F);
res->divisor = ri(F);
} else {
int i;
for (i=0;r->terrain->production[i].type;++i) {
if (res->type->rtype == r->terrain->production[i].type) break;
}
res->base = dice_rand(r->terrain->production[i].base);
res->divisor = dice_rand(r->terrain->production[i].divisor);
res->startlevel = 1;
}
*pres = res;
pres=&res->next;
}
}
rs(F, buf);
if (strcmp(buf, "noherb") != 0) {
const resource_type * rtype = rt_find(buf);
assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB));
rsetherbtype(r, rtype->itype);
2002-09-02 22:36:12 +02:00
} else {
rsetherbtype(r, NULL);
}
rsetherbs(r, (short)ri(F));
rsetpeasants(r, ri(F));
rsetmoney(r, ri(F));
}
assert(r->terrain!=NULL);
assert(rhorses(r) >= 0);
assert(rpeasants(r) >= 0);
assert(rmoney(r) >= 0);
2002-09-02 22:36:12 +02:00
if (r->land) {
for (;;) {
const struct item_type * itype;
rs(F, buf);
if (!strcmp(buf, "end")) break;
itype = it_find(buf);
assert(itype->rtype->ltype);
r_setdemand(r, itype->rtype->ltype, ri(F));
}
if (global.data_version>=REGIONITEMS_VERSION) {
read_items(F, &r->land->items);
}
}
a_read(F, &r->attribs);
return r;
}
void
writeregion(FILE * F, const region * r)
{
ws(F, r->display?r->display:"");
ws(F, r->terrain->_name);
wi(F, r->flags & RF_SAVEMASK);
wi(F, r->age);
wnl(F);
if (fval(r->terrain, LAND_REGION)) {
const item_type *rht;
struct demand * demand;
rawmaterial * res = r->resources;
ws(F, r->land->name);
assert(rtrees(r,0)>=0);
assert(rtrees(r,1)>=0);
assert(rtrees(r,2)>=0);
wi(F, rtrees(r,0));
wi(F, rtrees(r,1));
wi(F, rtrees(r,2));
wi(F, rhorses(r));
while (res) {
ws(F, res->type->name);
wi(F, res->level);
wi(F, res->amount);
wi(F, res->startlevel);
wi(F, res->base);
wi(F, res->divisor);
res = res->next;
}
fputs("end ", F);
rht = rherbtype(r);
if (rht) {
ws(F, resourcename(rht->rtype, 0));
} else {
ws(F, "noherb");
}
wi(F, rherbs(r));
wi(F, rpeasants(r));
wi(F, rmoney(r));
if (r->land) for (demand=r->land->demands; demand; demand=demand->next) {
ws(F, resourcename(demand->type->itype->rtype, 0));
wi(F, demand->value);
}
fputs("end \n", F);
#if RELEASE_VERSION>=REGIONITEMS_VERSION
write_items(F, r->land->items);
wnl(F);
#endif
}
a_write(F, r->attribs);
wnl(F);
}
static ally **
2002-09-02 22:36:12 +02:00
addally(const faction * f, ally ** sfp, int aid, int state)
{
struct faction * af = findfaction(aid);
ally * sf;
state &= ~HELP_OBSERVE;
magicskillboost -- implementiert. Kann nur einmal pro Partei verwendet werden, und nur von einem Magier. Müssen wir erklären. Amulett des wahren Sehens und Ring der Unsichtbarkeit geben lediglich einen Bonus auf Wahrnehmung (+2) und Tarnung (+4). -- das define war nicht aktiviert Halblinge haben Armbrustschiessen +0 (statt +1). -- spearates Rassenfile für WDW Es gibt spezielle Regeln für Allianzen, und der HELFE und KONTAKTIERE Befehl sind eingeschränkt. Konkret kann kein HELP_FIGHT HELP_GUARD HELP_FSTEALTH HELP_MONEY gegeben werden (die anderen sind erlaubt). -- mit #defeine ALLIES_ONLY definiert Jede Allianz kann bis zu 15 Magier und 15 Alchemisten haben. Jede einzelne Partei der Allianz kann dabei nicht mehr als 15/Anzahl_Parteien (aufgerundet) Magier bzw. Alchemisten haben, und die Gesamtsumme darf 15 nicht übersteigen. -- mit #define ALLIANCE_LIMITS gemacht. Die Startgeschenke (Personen, Silber, ...) werden pro Allianz, nicht pro Spieler verteilt. Größere Allianzen bekommen also weniger pro Spieler. -- Nochmal geändert: Die Allianzen kriegen jede 168 Personen zum Start, weil sich das gut aufteilen lässt. Das wird auf 28 Einheiten pro Partei gesplittet, jede Einheit hat eines der Talente, außer der Starteinheit, die hat den magicskillboost. Einige Skills kommen öfter vor als andere, das ist nicht einfach vermeidbar. Sollte aber auch wurscht sein, es geht primär darum, lehren zu können. Es gibt ein Einheitenlimit von 1000 Einheiten pro Allianz. -- die Regel sparen wir uns einfach mal.
2003-12-14 22:45:47 +01:00
#ifndef REGIONOWNERS
state &= ~HELP_TRAVEL;
2002-09-02 22:36:12 +02:00
#endif
2004-05-04 21:34:35 +02:00
if (state==0) return sfp;
magicskillboost -- implementiert. Kann nur einmal pro Partei verwendet werden, und nur von einem Magier. Müssen wir erklären. Amulett des wahren Sehens und Ring der Unsichtbarkeit geben lediglich einen Bonus auf Wahrnehmung (+2) und Tarnung (+4). -- das define war nicht aktiviert Halblinge haben Armbrustschiessen +0 (statt +1). -- spearates Rassenfile für WDW Es gibt spezielle Regeln für Allianzen, und der HELFE und KONTAKTIERE Befehl sind eingeschränkt. Konkret kann kein HELP_FIGHT HELP_GUARD HELP_FSTEALTH HELP_MONEY gegeben werden (die anderen sind erlaubt). -- mit #defeine ALLIES_ONLY definiert Jede Allianz kann bis zu 15 Magier und 15 Alchemisten haben. Jede einzelne Partei der Allianz kann dabei nicht mehr als 15/Anzahl_Parteien (aufgerundet) Magier bzw. Alchemisten haben, und die Gesamtsumme darf 15 nicht übersteigen. -- mit #define ALLIANCE_LIMITS gemacht. Die Startgeschenke (Personen, Silber, ...) werden pro Allianz, nicht pro Spieler verteilt. Größere Allianzen bekommen also weniger pro Spieler. -- Nochmal geändert: Die Allianzen kriegen jede 168 Personen zum Start, weil sich das gut aufteilen lässt. Das wird auf 28 Einheiten pro Partei gesplittet, jede Einheit hat eines der Talente, außer der Starteinheit, die hat den magicskillboost. Einige Skills kommen öfter vor als andere, das ist nicht einfach vermeidbar. Sollte aber auch wurscht sein, es geht primär darum, lehren zu können. Es gibt ein Einheitenlimit von 1000 Einheiten pro Allianz. -- die Regel sparen wir uns einfach mal.
2003-12-14 22:45:47 +01:00
sf = calloc(1, sizeof(ally));
sf->faction = af;
if (!sf->faction) {
variant id;
id.i = aid;
ur_add(id, (void**)&sf->faction, resolve_faction);
}
sf->status = state & HELP_ALL;
2002-09-02 22:36:12 +02:00
while (*sfp) sfp=&(*sfp)->next;
*sfp = sf;
2004-05-04 21:34:35 +02:00
return &sf->next;
2002-09-02 22:36:12 +02:00
}
/** Reads a faction from a file.
* This function requires no context, can be called in any state. The
* faction may not already exist, however.
*/
faction *
readfaction(FILE * F)
{
ally **sfp;
int planes;
int i = rid(F);
faction * f = findfaction(i);
2004-08-22 11:54:39 +02:00
char * email = NULL;
if (f==NULL) {
f = (faction *) calloc(1, sizeof(faction));
f->no = i;
} else {
#ifdef MSG_LEVELS
f->warnings = NULL; /* mem leak */
#endif
f->allies = NULL; /* mem leak */
while (f->attribs) a_remove(&f->attribs, f->attribs);
}
f->subscription = ri(F);
if (alliances!=NULL) {
int allianceid = rid(F);
if (allianceid!=0) f->alliance = findalliance(allianceid);
if (f->alliance) {
faction_list * flist = malloc(sizeof(faction_list));
flist->data = f;
flist->next = f->alliance->members;
f->alliance->members = flist;
}
}
rds(F, &f->name);
rds(F, &f->banner);
#ifndef NDEBUG
if (strlen(f->name)>=NAMESIZE) f->name[NAMESIZE] = 0;
if (strlen(f->banner)>=DISPLAYSIZE) f->banner[DISPLAYSIZE] = 0;
#endif
if (!quiet) printf(" - Lese Partei %s (%s)\n", f->name, factionid(f));
rds(F, &email);
if (set_email(&f->email, email)!=0) {
log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email));
set_email(&f->email, "");
}
free(email);
rds(F, &f->passw);
if (global.data_version >= OVERRIDE_VERSION) {
rds(F, &f->override);
} else {
f->override = strdup(itoa36(rand()));
}
if (global.data_version < LOCALE_VERSION) {
f->locale = find_locale("de");
} else {
rs(F, buf);
f->locale = find_locale(buf);
}
f->lastorders = ri(F);
f->age = ri(F);
if (global.data_version < NEWRACE_VERSION) {
race_t rc = (char) ri(F);
f->race = new_race[rc];
} else {
rs(F, buf);
f->race = rc_find(buf);
assert(f->race);
}
2002-11-02 16:50:51 +01:00
#ifdef CONVERT_DBLINK
convertunique(f);
2002-11-02 16:50:51 +01:00
#endif
f->magiegebiet = (magic_t)ri(F);
f->karma = ri(F);
f->flags = ri(F);
freset(f, FFL_OVERRIDE);
a_read(F, &f->attribs);
if (global.data_version>=CLAIM_VERSION) {
read_items(F, &f->items);
}
#ifdef MSG_LEVELS
read_msglevels(&f->warnings, F);
#else
for (;;) {
int level;
fscanf(F, "%s", buf);
if (strcmp("end", buf)==0) break;
fscanf(F, "%d ", &level);
}
#endif
planes = ri(F);
while(--planes >= 0) {
int id = ri(F);
short ux = (short)ri(F);
short uy = (short)ri(F);
set_ursprung(f, id, ux, uy);
}
f->newbies = 0;
i = f->options = ri(F);
if ((i & ((1<<O_REPORT)|(1<<O_COMPUTER)))==0 && f->no!=MONSTER_FACTION) {
/* Kein Report eingestellt, Fehler */
f->options = f->options | Pow(O_REPORT) | Pow(O_ZUGVORLAGE);
}
if (global.data_version < TYPES_VERSION) {
int sk = ri(F); /* f->seenspell <20>berspringen */
spell_list * slist;
for (slist=spells;slist!=NULL;slist=slist->next) {
spell * sp = slist->data;
if (sp->magietyp==f->magiegebiet && sp->level<=sk) {
a_add(&f->attribs, a_new(&at_seenspell))->data.i = sp->id;
}
}
}
sfp = &f->allies;
if (global.data_version<ALLIANCES_VERSION) {
int p = ri(F);
while (--p >= 0) {
int aid = rid(F);
int state = ri(F);
sfp = addally(f, sfp, aid, state);
}
} else {
for (;;) {
rs(F, buf);
if (strcmp(buf, "end")==0) break;
else {
int aid = atoi36(buf);
int state = ri(F);
sfp = addally(f, sfp, aid, state);
}
}
}
read_groups(F, f);
#ifdef ENEMIES
read_enemies(F, f);
#endif
return f;
}
void
writefaction(FILE * F, const faction * f)
{
ally *sf;
ursprung *ur;
wi36(F, f->no);
wi(F, f->subscription);
if (alliances!=NULL) {
if (f->alliance) wi36(F, f->alliance->id);
else wi36(F, 0);
}
2002-09-02 22:36:12 +02:00
ws(F, f->name);
ws(F, f->banner);
ws(F, f->email);
ws(F, f->passw);
ws(F, f->override);
ws(F, locale_name(f->locale));
wi(F, f->lastorders);
wi(F, f->age);
ws(F, f->race->_name[0]);
wnl(F);
wi(F, f->magiegebiet);
wi(F, f->karma);
wi(F, f->flags);
a_write(F, f->attribs);
wnl(F);
#if RELEASE_VERSION>=CLAIM_VERSION
write_items(F, f->items);
wnl(F);
#endif
#ifdef MSG_LEVELS
write_msglevels(f->warnings, F);
#else
fputs("end ", F);
#endif
wnl(F);
wi(F, listlen(f->ursprung));
for(ur = f->ursprung;ur;ur=ur->next) {
wi(F, ur->id);
wi(F, ur->x);
wi(F, ur->y);
}
wnl(F);
wi(F, f->options & ~Pow(O_DEBUG));
wnl(F);
for (sf = f->allies; sf; sf = sf->next) {
int no = (sf->faction!=NULL)?sf->faction->no:0;
2002-09-02 22:36:12 +02:00
int status = alliedfaction(NULL, f, sf->faction, HELP_ALL);
if (status!=0) {
wi36(F, no);
wi(F, sf->status);
}
}
fprintf(F, "end ");
wnl(F);
write_groups(F, f->groups);
#ifdef ENEMIES
write_enemies(F, f->enemies);
#endif
2002-03-03 16:26:17 +01:00
}
int
readgame(const char * filename, int backup)
{
int i, n, p;
faction *f, **fp;
region *r;
building *b, **bp;
ship *sh, **shp;
unit *u;
FILE * F;
int rmax = maxregions;
sprintf(buf, "%s/%s", datapath(), filename);
log_printf("- reading game data from %s\n", filename);
if (backup) create_backup(buf);
F = cfopen(buf, "r");
if (F==NULL) {
log_error(("Keine Spieldaten gefunden.\n"));
return -1;
}
rc(F);
/* globale Variablen */
global.data_version = ri(F);
assert(global.data_version>=MIN_VERSION || !"unsupported data format");
assert(global.data_version<=RELEASE_VERSION || !"unsupported data format");
assert(global.data_version >= NEWSOURCE_VERSION);
if(global.data_version >= SAVEXMLNAME_VERSION) {
char basefile[1024];
const char *basearg = "(null)";
rs(F, basefile);
assert(xmlfile != NULL);
basearg = strrchr(xmlfile, '/');
if (basearg==NULL) {
basearg = xmlfile;
} else {
++basearg;
}
if (strcmp(basearg, basefile)!=0) {
log_warning(("xmlfile mismatch: datafile contains %s, argument/default is %s\n", basefile, basearg));
printf("WARNING: any key to continue, Ctrl-C to stop\n");
getchar();
}
}
if (global.data_version >= GLOBAL_ATTRIB_VERSION) {
a_read(F, &global.attribs);
}
global.data_turn = turn = ri(F);
ri(F); /* max_unique_id = */
nextborder = ri(F);
/* Planes */
planes = NULL;
n = ri(F);
while(--n >= 0) {
plane *pl = calloc(1, sizeof(plane));
pl->id = ri(F);
rds(F, &pl->name);
pl->minx = (short)ri(F);
pl->maxx = (short)ri(F);
pl->miny = (short)ri(F);
pl->maxy = (short)ri(F);
pl->flags = ri(F);
if (global.data_version>WATCHERS_VERSION) {
rs(F, buf);
while (strcmp(buf, "end")!=0) {
watcher * w = calloc(sizeof(watcher),1);
variant fno;
fno.i = atoi36(buf);
w->mode = (unsigned char)ri(F);
w->next = pl->watchers;
pl->watchers = w;
ur_add(fno, (void**)&w->faction, resolve_faction);
rs(F, buf);
}
}
a_read(F, &pl->attribs);
addlist(&planes, pl);
}
/* Read factions */
if (global.data_version>=ALLIANCES_VERSION) {
read_alliances(F);
}
n = ri(F);
printf(" - Einzulesende Parteien: %d\n", n);
fp = &factions;
while (*fp) fp=&(*fp)->next;
/* fflush (stdout); */
while (--n >= 0) {
faction * f = readfaction(F);
addlist2(fp, f);
fhash(f);
}
*fp = 0;
/* Benutzte Faction-Ids */
no_used_faction_ids = ri(F);
/* used_faction_ids = gc_add(malloc(no_used_faction_ids*sizeof(int))); */
used_faction_ids = malloc(no_used_faction_ids*sizeof(int));
for(i=0; i < no_used_faction_ids; i++) {
used_faction_ids[i] = ri(F);
}
/* Regionen */
n = ri(F);
if (rmax<0) rmax = n;
printf(" - Einzulesende Regionen: %d/%d\r", rmax, n);
2005-01-03 22:28:57 +01:00
if (loadplane || dirtyload || firstx || firsty || maxregions>=0) {
incomplete_data = true;
}
while (--n >= 0) {
unit **up;
boolean skip = false;
short x = (short)ri(F);
short y = (short)ri(F);
plane * pl = findplane(x, y);
if (firstx || firsty) {
if (x!=firstx || y!=firsty) {
skip = true;
} else {
firstx=0;
firsty=0;
if (rmax>0) rmax = min(n, rmax)-1;
}
}
if (loadplane && (!pl || pl->id!=loadplane)) skip = true;
if (rmax==0) {
if (dirtyload) break;
skip = true;
}
if ((n%1024)==0) { /* das spart extrem Zeit */
printf(" - Einzulesende Regionen: %d/%d ", rmax, n);
printf("* %d,%d \r", x, y);
}
if (skip) {
char * r;
do {
r = fgets(buf, BUFSIZE, F); /* skip region */
} while (r && buf[0]!='\n');
continue;
}
--rmax;
r = readregion(F, x, y);
/* Burgen */
p = ri(F);
bp = &r->buildings;
while (--p >= 0) {
b = (building *) calloc(1, sizeof(building));
b->no = rid(F);
bhash(b);
rds(F, &b->name);
if (lomem) rds(F, 0);
else rds(F, &b->display);
#ifndef NDEBUG
if (strlen(b->name)>=NAMESIZE) b->name[NAMESIZE] = 0;
if (b->display && strlen(b->display)>=DISPLAYSIZE) b->display[DISPLAYSIZE] = 0;
#endif
b->size = ri(F);
if (global.data_version < TYPES_VERSION) {
assert(!"data format is no longer supported");
/* b->type = oldbuildings[ri(F)]; */
}
else {
rs(F, buf);
b->type = bt_find(buf);
}
b->region = r;
a_read(F, &b->attribs);
addlist2(bp, b);
}
/* Schiffe */
p = ri(F);
shp = &r->ships;
while (--p >= 0) {
sh = (ship *) calloc(1, sizeof(ship));
sh->region = r;
sh->no = rid(F);
shash(sh);
rds(F, &sh->name);
if (lomem) rds(F, 0);
else rds(F, &sh->display);
#ifndef NDEBUG
if (sh->name && strlen(sh->name)>=NAMESIZE) sh->name[NAMESIZE] = 0;
if (sh->display && strlen(sh->display)>=DISPLAYSIZE) sh->display[DISPLAYSIZE] = 0;
#endif
rs(F, buf);
sh->type = st_find(buf);
assert(sh->type || !"ship_type not registered!");
sh->size = ri(F);
sh->damage = ri(F);
/* Attribute rekursiv einlesen */
sh->coast = (direction_t)ri(F);
a_read(F, &sh->attribs);
addlist2(shp, sh);
}
*shp = 0;
/* Einheiten */
p = ri(F);
up = &r->units;
while (--p >= 0) {
unit * u = readunit(F);
assert(u->region==NULL);
u->region = r;
addlist2(up,u);
update_interval(u->faction, u->region);
}
}
printf("\n");
if (!dirtyload) {
read_borders(F);
#ifdef USE_UGROUPS
if (global.data_version >= UGROUPS_VERSION) read_ugroups(F);
#endif
}
fclose(F);
/* Unaufgeloeste Zeiger initialisieren */
printf("\n - Referenzen initialisieren...\n");
resolve();
printf("\n - Leere Gruppen l<>schen...\n");
for (f=factions; f; f=f->next) {
group ** gp = &f->groups;
while (*gp) {
group * g = *gp;
if (g->members==0) {
*gp = g->next;
free_group(g);
} else
gp = &g->next;
}
}
for (r=regions;r;r=r->next) {
building * b;
for (b=r->buildings;b;b=b->next) update_lighthouse(b);
}
printf(" - Regionen initialisieren & verbinden...\n");
for (f = factions; f; f = f->next) {
for (u = f->units; u; u = u->nextF) {
if (u->number>0) {
f->alive = 1;
break;
}
}
}
if (findfaction(0)) {
findfaction(0)->alive = 1;
}
if (loadplane || maxregions>=0) {
remove_empty_factions(false);
}
return 0;
}
int
writegame(const char *filename, char quiet)
{
char *base;
int i,n;
faction *f;
region *r;
building *b;
ship *sh;
unit *u;
plane *pl;
FILE * F;
#ifdef USE_PLAYERS
char playerfile[MAX_PATH];
#endif
#ifdef USE_PLAYERS
sprintf(buf, "%s/%d.players", datapath(), turn);
export_players(playerfile);
#endif
sprintf(buf, "%s/%s", datapath(), filename);
F = cfopen(buf, "w");
if (F==NULL)
return -1;
if (!quiet)
printf("Schreibe die %d. Runde...\n", turn);
/* globale Variablen */
wi(F, RELEASE_VERSION);
wnl(F);
base = strrchr(xmlfile, '/');
if(base) {
ws(F, base+1);
} else {
ws(F, xmlfile);
}
wnl(F);
a_write(F, global.attribs);
wnl(F);
wi(F, turn);
wi(F, 0/*max_unique_id*/);
wi(F, nextborder);
/* Write planes */
wnl(F);
wi(F, listlen(planes));
wnl(F);
for(pl = planes; pl; pl=pl->next) {
watcher * w;
wi(F, pl->id);
ws(F, pl->name);
wi(F, pl->minx);
wi(F, pl->maxx);
wi(F, pl->miny);
wi(F, pl->maxy);
wi(F, pl->flags);
w = pl->watchers;
while (w) {
if (w->faction) {
wi36(F, w->faction->no);
wi(F, w->mode);
}
w = w->next;
}
fputs("end ", F);
a_write(F, pl->attribs);
wnl(F);
}
/* Write factions */
#if RELEASE_VERSION>=ALLIANCES_VERSION
write_alliances(F);
#endif
n = listlen(factions);
wi(F, n);
wnl(F);
printf(" - Schreibe %d Parteien...\n",n);
for (f = factions; f; f = f->next) {
writefaction(F, f);
}
wi(F, no_used_faction_ids);
wnl(F);
for(i=0; i<no_used_faction_ids; i++) {
wi(F, used_faction_ids[i]);
wnl(F);
}
wnl(F);
/* Write regions */
n=listlen(regions);
wi(F, n);
wnl(F);
printf(" - Schreibe Regionen: %d \r", n);
for (r = regions; r; r = r->next, --n) {
/* plus leerzeile */
if ((n%1024)==0) { /* das spart extrem Zeit */
printf(" - Schreibe Regionen: %d \r", n);
fflush(stdout);
}
wnl(F);
wi(F, r->x);
wi(F, r->y);
writeregion(F, r);
wi(F, listlen(r->buildings));
wnl(F);
for (b = r->buildings; b; b = b->next) {
wi36(F, b->no);
ws(F, b->name);
ws(F, b->display?b->display:"");
wi(F, b->size);
ws(F, b->type->_name);
wnl(F);
a_write(F, b->attribs);
wnl(F);
}
wi(F, listlen(r->ships));
wnl(F);
for (sh = r->ships; sh; sh = sh->next) {
assert(sh->region == r);
wi36(F, sh->no);
ws(F, sh->name);
ws(F, sh->display?sh->display:"");
ws(F, sh->type->name[0]);
wi(F, sh->size);
wi(F, sh->damage);
wi(F, sh->coast);
wnl(F);
a_write(F, sh->attribs);
wnl(F);
}
wi(F, listlen(r->units));
wnl(F);
for (u = r->units; u; u = u->next) {
writeunit(F, u);
}
}
wnl(F);
write_borders(F);
wnl(F);
#if RELEASE_VERSION >= UGROUPS_VERSION
write_ugroups(F);
wnl(F);
#endif
fclose(F);
printf("\nOk.\n");
return 0;
}