server/src/common/kernel/save.c

2165 lines
43 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 "attrib.h"
#include "border.h"
#include "building.h"
2001-01-25 10:37:55 +01:00
#include "faction.h"
#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 "unit.h"
2001-01-25 10:37:55 +01:00
#include "group.h"
#ifdef USE_UGROUPS
#include "ugroup.h"
#include <attributes/ugroup.h>
#endif
/* modules include */
#ifdef ALLIANCES
# include <modules/alliance.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>
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
/* 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();
}
assert(s <= buffer + DISPLAYSIZE + 1);
rc(F);
}
rc(F);
while (nextc != '"') {
if (nextc == EOF) {
assert(s <= buffer + DISPLAYSIZE + 1);
*s = 0;
fprintf(stderr, "Die Datei bricht vorzeitig ab.\n");
abort();
}
*s++ = (char)nextc;
if (s - buffer > DISPLAYSIZE) {
assert(s <= buffer + DISPLAYSIZE + 1);
*s = 0;
log_error(("\nDer String %s wurde nicht terminiert.\n", s));
2001-01-25 10:37:55 +01:00
exit(1);
}
rc(F);
}
rc(F);
assert(s <= buffer + DISPLAYSIZE + 1);
*s = 0;
(*ds) = realloc(*ds, sizeof(char) * (strlen(buffer) + 1));
strcpy(*ds, buffer);
}
#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
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 {
while (bp && !lbuf[MAXLINE-1] && lbuf[MAXLINE-2]!='\n') {
/* wenn die zeile l<>nger als erlaubt war,
* wird der rest weggeworfen: */
bp = (unsigned char *)fgets(buf, 1024, F);
comment = false;
}
bp = (unsigned char *)lbuf;
}
cont = false;
while (cp!=buf+MAXLINE && (char*)bp!=lbuf+MAXLINE && *bp) {
if (isspace(*bp)) {
if (eatwhite)
{
do { ++bp; } while ((char*)bp!=lbuf+MAXLINE && isspace(*bp));
if (!quote && !start && !comment) *(cp++)=' ';
}
else {
do {
if (!comment) *(cp++)=SPACE_REPLACEMENT;
++bp;
} while (cp!=buf+MAXLINE && (char*)bp!=lbuf+MAXLINE && isspace(*bp));
}
}
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;
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 REGIONOWNERS
static void
read_enemies(FILE * F, faction * f)
{
if (global.data_version<REGIONOWNERS_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)
{
#if RELEASE_VERSION>=REGIONOWNERS_VERSION
while (flist) {
fprintf(F, "%s ", itoa36(flist->data->no));
}
fputs("end \n", F);
#endif
}
#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);
if (u && old_race(u->race) == RC_SPELL) return NULL;
if (u && u->faction == f) {
order ** ordp;
free_orders(&u->orders);
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);
ordp = &(*ordp)->next;
}
}
2001-01-25 10:37:55 +01:00
2004-06-21 18:45:27 +02:00
u->botschaften = NULL; /* Sicherheitshalber */
2001-01-25 10:37:55 +01:00
2004-06-21 18:45:27 +02:00
} else {
/* cmistake(?, gc_add(strdup(buf)), 160, MSG_EVENT); */
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
freestrlist(f->mistakes);
f->mistakes = 0;
if (checkpasswd(f, pass, true) == false) {
2004-03-21 22:29:37 +01:00
log_warning(("Invalid password for faction %s\n", fid));
2001-01-25 10:37:55 +01:00
addstrlist(&f->mistakes, "Das Passwort wurde falsch eingegeben");
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;
2001-01-25 10:37:55 +01:00
default:
b = getbuf(F);
}
}
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;
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);
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
#ifdef ALLIANCES
void
read_alliances(FILE * F)
{
char pbuf[32];
2002-09-29 22:36:15 +02:00
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);
}
}
#endif
#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
}
#ifdef ALLIANCES
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);
}
#endif
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;
}
int
read_faction_reference(faction ** f, FILE * F)
{
int id;
if (global.data_version >= BASE36IDS_VERSION) {
char zText[10];
fscanf(F, "%s ", zText);
id = atoi36(zText);
} else {
fscanf(F, "%d ", &id);
}
if (id<0) {
2001-01-25 10:37:55 +01:00
*f = NULL;
return AT_READ_FAIL;
2001-01-25 10:37:55 +01:00
}
*f = findfaction(id);
if (*f==NULL) ur_add((void*)id, (void**)f, resolve_faction);
return AT_READ_OK;
2001-01-25 10:37:55 +01:00
}
void
2001-01-25 10:37:55 +01:00
write_faction_reference(const faction * f, FILE * F)
{
fprintf(F, "%s ", itoa36(f->no));
}
2004-06-21 18:45:27 +02:00
void
fwrite_order(const order * ord, const struct locale * lang, FILE * F)
{
write_order(ord, lang, buf, sizeof(buf));
fputs(buf, F);
}
static void
writeorder(const order * ord, const struct locale * lang, FILE * F)
{
fputc('\"', F);
fwrite_order(ord, lang, F);
fputs("\" ", F);
}
unit *
readunit(FILE * F)
{
skill_t sk;
item_t item;
herb_t herb;
potion_t potion;
unit * u;
int number, n;
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
{
faction * f;
2002-09-02 22:36:12 +02:00
int n = rid(F);
f = findfaction(n);
if (f!=u->faction) u_setfaction(u, f);
}
rds(F, &u->name);
rds(F, &u->display);
number = ri(F);
if (global.data_version<ITEMTYPE_VERSION)
set_money(u, 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 {
rs(F, buf);
if (strcmp(buf, "giant turtle")==0) strcpy(buf, "giantturtle");
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)));
#if 0
abort();
#else
u_setfaction(u, findfaction(MONSTER_FACTION));
set_number(u, 0);
#endif
}
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;
/* Kurze persistente Befehle einlesen */
2004-06-21 18:45:27 +02:00
free_orders(&u->orders);
2002-09-02 22:36:12 +02:00
rs(F, buf);
while(*buf != 0) {
order * ord = parse_order(buf, u->faction->locale);
if (ord!=NULL) addlist(&u->orders, ord);
rs(F, buf);
}
rs(F, buf);
u->lastorder = parse_order(buf, u->faction->locale);
set_order(&u->thisorder, NULL);
assert(u->number >= 0);
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;
}
}
}
if (global.data_version>=ITEMTYPE_VERSION) {
read_items(F, &u->items);
} else {
while ((item = (item_t) ri(F)) >= 0) {
i_change(&u->items, olditemtype[item], ri(F));
}
while ((potion = (potion_t) ri(F)) >= 0) {
i_change(&u->items, oldpotiontype[potion]->itype, ri(F));
}
while ((herb = (herb_t) ri(F)) >= 0) {
i_change(&u->items, oldherbtype[herb]->itype, ri(F));
}
}
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->combatspell[csp] = (spellid_t) i;
mage->combatspelllevel[csp] = ri(F);
csp++;
}
2002-09-02 22:36:12 +02:00
while ((i = ri(F)) != -1) {
addspell(u, (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;
wi36(F, u->no);
wi36(F, u->faction->no);
ws(F, u->name);
ws(F, 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);
for (ord = u->orders; ord; ord=ord->next) {
if (is_persistent(ord)) {
writeorder(ord, u->faction->locale, F);
}
}
ws(F, ""); /* Abschlu<6C> der persistenten Befehle */
2004-06-21 18:45:27 +02:00
writeorder(u->lastorder, u->faction->locale, F);
wnl(F);
assert(u->number >= 0);
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, int x, int y)
{
region * r = findregion(x, y);
int ter;
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;
}
rds(F, &r->display);
ter = ri(F);
if (global.data_version < NOFOREST_VERSION) {
if (ter>T_PLAIN) --ter;
}
rsetterrain(r, (terrain_t)ter);
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;
2002-09-02 22:36:12 +02:00
if (landregion(rterrain(r))) {
r->land = calloc(1, sizeof(land_region));
rds(F, &r->land->name);
}
2002-09-02 22:36:12 +02:00
if (r->land) {
int i;
#if GROWING_TREES
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);
}
#else
i = ri(F); rsettrees(r, i);
#endif
i = ri(F); rsethorses(r, i);
#if NEW_RESOURCEGROWTH
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;
res->startlevel = 1;
for (i=0; i<3; i++) {
if(res->type == terrain[rterrain(r)].rawmaterials[i].type) break;
}
assert(i<=2);
res->base = dice_rand(terrain[rterrain(r)].rawmaterials[i].base);
res->divisor = dice_rand(terrain[rterrain(r)].rawmaterials[i].divisor);
}
*pres = res;
pres=&res->next;
}
}
#else
i = ri(F); rsetiron(r, i);
#endif
if (global.data_version>=ITEMTYPE_VERSION) {
rs(F, buf);
if (strcmp(buf, "noherb") != 0) {
rsetherbtype(r, ht_find(buf));
} else {
rsetherbtype(r, NULL);
}
rsetherbs(r, (short)ri(F));
2002-09-02 22:36:12 +02:00
} else {
int i = ri(F);
terrain_t ter = rterrain(r);
if (ter == T_ICEBERG || ter == T_ICEBERG_SLEEP) ter = T_GLACIER;
if (ter > T_GLACIER || ter == T_OCEAN)
rsetherbtype(r, NULL);
else
rsetherbtype(r, oldherbtype[(i-1)+3*(ter-1)]);
rsetherbs(r, (short)ri(F));
}
rsetpeasants(r, ri(F));
rsetmoney(r, ri(F));
}
assert(rterrain(r) != NOTERRAIN);
assert(rhorses(r) >= 0);
assert(rpeasants(r) >= 0);
assert(rmoney(r) >= 0);
2002-09-02 22:36:12 +02:00
if (r->land) {
if (global.data_version<ITEMTYPE_VERSION) {
int i, p = 0;
for (i = 0; oldluxurytype[i]!=NULL; i++) {
int k = ri(F);
r_setdemand(r, oldluxurytype[i], k);
if (k==0) {
/* Pr<50>fung ob nur ein Luxusgut verkauft wird. */
if (p == 1) {
/* Zuviele ... Wir setzen den Demand. */
r_setdemand(r, oldluxurytype[i], (char) (1 + rand() % 5));
} else ++p;
}
}
} else {
for (;;) {
rs(F, buf);
if (!strcmp(buf, "end")) break;
r_setdemand(r, lt_find(buf), ri(F));
}
}
}
a_read(F, &r->attribs);
return r;
}
void
writeregion(FILE * F, const region * r)
{
ws(F, r->display);
wi(F, rterrain(r));
wi(F, r->flags & RF_SAVEMASK);
wi(F, r->age);
wnl(F);
if (landregion(rterrain(r))) {
const herb_type *rht;
struct demand * demand;
ws(F, r->land->name);
#if GROWING_TREES
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));
#else
wi(F, rtrees(r));
#endif
wi(F, rhorses(r));
#if NEW_RESOURCEGROWTH == 0
wi(F, riron(r));
#elif RELEASE_VERSION>=NEWRESOURCE_VERSION
{
rawmaterial * res = r->resources;
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);
}
#else
assert(!"invalid defines");
#endif
rht = rherbtype(r);
if (rht) {
ws(F, resourcename(rht->itype->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);
}
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
#ifdef ALLIANCES
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
# ifdef ALLIES_ONLY
if (af!=NULL && af->alliance!=f->alliance) state &= ~ALLIES_ONLY;;
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
# else
# endif
2004-05-04 21:34:35 +02:00
if (af!=NULL && af->alliance!=f->alliance) return sfp;
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) ur_add((void*)aid, (void**)&sf->faction, resolve_faction);
sf->status = state;
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);
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);
2002-09-02 22:36:12 +02:00
#ifdef ALLIANCES
if (global.data_version>=ALLIANCES_VERSION) {
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;
}
}
2002-09-02 22:36:12 +02:00
#endif
rds(F, &f->name);
#ifndef AMIGA
if (!quiet) printf(" - Lese Partei %s (%s)\n", f->name, factionid(f));
#endif
rds(F, &f->banner);
rds(F, &f->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);
if (!playerrace(f->race)) {
f->lastorders = turn+1;
}
f->karma = ri(F);
f->flags = ri(F);
freset(f, FFL_OVERRIDE);
a_read(F, &f->attribs);
#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);
int ux = ri(F);
int uy = ri(F);
set_ursprung(f, id, ux, uy);
}
f->newbies = 0;
i = f->options = ri(F);
if ((i & Pow(O_REPORT))==0 && (i & Pow(O_COMPUTER))==0) {
/* 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 REGIONOWNERS
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);
2002-09-02 22:36:12 +02:00
#if defined(ALLIANCES) && RELEASE_VERSION>=ALLIANCES_VERSION
if (f->alliance) wi36(F, f->alliance->id);
else wi36(F, 0);
#endif
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);
#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 REGIONOWNERS
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);
}
#ifndef COMPATIBILITY
if (global.data_version < ITEMTYPE_VERSION) {
fprintf(stderr, "kann keine alten datenfiles einlesen");
exit(-1);
}
#endif
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 = ri(F);
pl->maxx = ri(F);
pl->miny = ri(F);
pl->maxy = 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);
int fno = atoi36(buf);
w->mode = (unsigned char)ri(F);
w->next = pl->watchers;
pl->watchers = w;
ur_add((void*)fno, (void**)&w->faction, resolve_faction);
rs(F, buf);
}
}
a_read(F, &pl->attribs);
addlist(&planes, pl);
}
/* Read factions */
#ifdef ALLIANCES
if (global.data_version>=ALLIANCES_VERSION) {
read_alliances(F);
}
#endif
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);
}
*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);
while (--n >= 0) {
unit **up;
boolean skip = false;
int x = ri(F);
int y = 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);
rds(F, &b->display);
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);
rds(F, &sh->display);
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);
}
}
printf("\n");
if (!dirtyload) {
read_borders(F);
#ifdef USE_UGROUPS
if (global.data_version >= UGROUPS_VERSION) read_ugroups(F);
#endif
}
#ifdef WEATHER
/* Wetter lesen */
weathers = NULL;
if (global.data_version >= 81) {
n = ri(F);
while(--n >= 0) {
weather *w;
w = calloc(1, sizeof(weather));
w->type = ri(F);
w->radius = ri(F);
w->center[0] = ri(F);
w->center[1] = ri(F);
w->move[0] = ri(F);
w->move[1] = ri(F);
addlist(&weathers, w);
}
}
#endif
fclose(F);
#ifdef AMIGA
fputs("Ok.", stderr);
#endif
/* Unaufgeloeste Zeiger initialisieren */
printf("\n - Referenzen initialisieren...\n");
resolve();
resolve_IDs();
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;
}
}
resolve_IDs();
#if 0
/* speziell f<>r Runde 199->200 */
printf("Actions korrigieren...\n");
iuw_fix_rest();
#endif
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 (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
u->faction->alive = 1;
}
}
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 defined(ALLIANCES) && 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);
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);
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;
}