server/core/src/kernel/save.c

1998 lines
50 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/*
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include <kernel/config.h>
#include "save.h"
#include "alchemy.h"
#include "alliance.h"
#include "ally.h"
2010-08-08 10:06:34 +02:00
#include "connection.h"
#include "building.h"
#include "faction.h"
#include "group.h"
#include "item.h"
#include "magic.h"
#include "message.h"
#include "move.h"
#include "objtypes.h"
#include "order.h"
#include "pathfinder.h"
#include "plane.h"
#include "race.h"
#include "region.h"
#include "resources.h"
#include "ship.h"
#include "skill.h"
#include "spell.h"
#include "spellbook.h"
2010-08-08 10:06:34 +02:00
#include "terrain.h"
2011-03-07 08:02:35 +01:00
#include "terrainid.h" /* only for conversion code */
2010-08-08 10:06:34 +02:00
#include "unit.h"
#include "version.h"
/* attributes includes */
#include <attributes/key.h>
#include <triggers/timeout.h>
2010-08-08 10:06:34 +02:00
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/event.h>
#include <util/filereader.h>
#include <util/goodies.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/log.h>
#include <util/os.h>
2010-08-08 10:06:34 +02:00
#include <util/parser.h>
#include <quicklist.h>
2010-08-08 10:06:34 +02:00
#include <util/rand.h>
#include <util/resolve.h>
#include <util/rng.h>
#include <util/sql.h>
#include <util/umlaut.h>
#include <util/unicode.h>
#include <storage.h>
#include <binarystore.h>
2010-08-08 10:06:34 +02:00
#include <libxml/encoding.h>
/* libc includes */
#include <string.h>
#include <errno.h>
2010-08-08 10:06:34 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-')
#define ESCAPE_FIX
#define MAXORDERS 256
#define MAXPERSISTENT 128
/* exported symbols symbols */
2011-03-07 08:02:35 +01:00
const char *game_name = "eressea";
2010-08-08 10:06:34 +02:00
int firstx = 0, firsty = 0;
int enc_gamedata = 0;
/* local symbols */
2011-03-07 08:02:35 +01:00
static region *current_region;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
char *rns(FILE * f, char *c, size_t size)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
char *s = c;
2010-08-08 10:06:34 +02:00
do {
2011-03-07 08:02:35 +01:00
*s = (char)getc(f);
} while (*s != '"');
2010-08-08 10:06:34 +02:00
for (;;) {
2011-03-07 08:02:35 +01:00
*s = (char)getc(f);
if (*s == '"')
break;
if (s < c + size)
++s;
2010-08-08 10:06:34 +02:00
}
*s = 0;
return c;
}
2011-03-07 08:02:35 +01:00
extern unsigned int __at_hashkey(const char *s);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static unit *unitorders(FILE * F, int enc, struct faction *f)
2010-08-08 10:06:34 +02:00
{
int i;
unit *u;
2011-03-07 08:02:35 +01:00
if (!f)
return NULL;
2010-08-08 10:06:34 +02:00
i = getid();
u = findunitg(i, NULL);
if (u && u_race(u) == new_race[RC_SPELL])
2011-03-07 08:02:35 +01:00
return NULL;
2010-08-08 10:06:34 +02:00
if (u && u->faction == f) {
2011-03-07 08:02:35 +01:00
order **ordp;
2010-08-08 10:06:34 +02:00
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) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
2010-08-08 10:06:34 +02:00
if (!is_repeated(ord)) {
*ordp = ord->next;
ord->next = NULL;
free_order(ord);
} else {
ordp = &ord->next;
}
}
} else {
free_orders(&u->orders);
}
u->orders = 0;
ordp = &u->orders;
for (;;) {
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
/* Erst wenn wir sicher sind, dass kein Befehl
2011-03-07 08:02:35 +01:00
* eingegeben wurde, checken wir, ob nun eine neue
* Einheit oder ein neuer Spieler drankommt */
2010-08-08 10:06:34 +02:00
s = getbuf(F, enc);
2011-03-07 08:02:35 +01:00
if (s == NULL)
break;
2010-08-08 10:06:34 +02:00
if (s[0]) {
if (s[0]!='@') {
const char *stok = s;
stok = parse_token(&stok);
if (stok) {
bool quit = false;
param_t param = findparam(stok, u->faction->locale);
switch (param) {
case P_UNIT:
case P_REGION:
2010-08-08 10:06:34 +02:00
quit = true;
break;
case P_FACTION:
case P_NEXT:
case P_GAMENAME:
/* these terminate the orders, so we apply extra checking */
if (strlen(stok) >= 3) {
quit = true;
break;
} else {
quit = false;
}
break;
default:
/* TODO: syntax error message */
break;
}
if (quit) {
break;
2011-03-08 08:44:20 +01:00
}
}
2010-08-08 10:06:34 +02:00
}
/* Nun wird der Befehl erzeut und eingeh<65>ngt */
*ordp = parse_order(s, u->faction->locale);
if (*ordp) {
2011-03-07 08:02:35 +01:00
ordp = &(*ordp)->next;
}
2010-08-08 10:06:34 +02:00
}
}
} else {
/* cmistake(?, buf, 160, MSG_EVENT); */
return NULL;
}
return u;
}
2011-03-07 08:02:35 +01:00
static faction *factionorders(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f = NULL;
2010-08-08 10:06:34 +02:00
int fid = getid();
f = findfaction(fid);
2011-03-07 08:02:35 +01:00
if (f != NULL && !is_monsters(f)) {
const char *pass = getstrtoken();
2010-08-08 10:06:34 +02:00
if (!checkpasswd(f, (const char *)pass, true)) {
log_warning("Invalid password for faction %s\n", itoa36(fid));
2010-08-08 10:06:34 +02:00
ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password",
2011-03-07 08:02:35 +01:00
f->no, pass));
2010-08-08 10:06:34 +02:00
return 0;
}
/* Die Partei hat sich zumindest gemeldet, so da<64> sie noch
* nicht als unt<EFBFBD>tig gilt */
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* TODO: +1 ist ein Workaround, weil cturn erst in process_orders
* incrementiert wird. */
2011-03-07 08:02:35 +01:00
f->lastorders = global.data_turn + 1;
2010-08-08 10:06:34 +02:00
} else {
log_warning("orders for invalid faction %s\n", itoa36(fid));
2010-08-08 10:06:34 +02:00
}
return f;
}
/* ------------------------------------------------------------- */
2011-03-07 08:02:35 +01:00
static param_t igetparam(const char *s, const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
return findparam(igetstrtoken(s), lang);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int readorders(const char *filename)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
FILE *F = NULL;
2010-08-08 10:06:34 +02:00
const char *b;
2011-03-07 08:02:35 +01:00
int nfactions = 0;
2010-08-08 10:06:34 +02:00
struct faction *f = NULL;
F = fopen(filename, "rb");
if (!F) {
perror(filename);
return -1;
}
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts(" - lese Befehlsdatei...\n");
2010-08-08 10:06:34 +02:00
/* TODO: recognize UTF8 BOM */
b = getbuf(F, enc_gamedata);
/* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten
* Partei */
while (b) {
2011-03-07 08:02:35 +01:00
const struct locale *lang = f ? f->locale : default_locale;
2010-08-08 10:06:34 +02:00
int p;
switch (igetparam(b, lang)) {
#undef LOCALE_CHANGE
#ifdef LOCALE_CHANGE
case P_LOCALE:
{
const char *s = getstrtoken();
if (f && find_locale(s)) {
f->locale = find_locale(s);
}
2011-03-08 08:44:20 +01:00
}
b = getbuf(F, enc_gamedata);
break;
#endif
2011-03-08 08:44:20 +01:00
case P_GAMENAME:
case P_FACTION:
f = factionorders();
if (f) {
++nfactions;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
b = getbuf(F, enc_gamedata);
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
/* in factionorders wird nur eine zeile gelesen:
* diejenige mit dem passwort. Die befehle der units
* werden geloescht, und die Partei wird als aktiv
* vermerkt. */
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_UNIT:
if (!f || !unitorders(F, enc_gamedata, f))
do {
b = getbuf(F, enc_gamedata);
if (!b)
break;
p = (b[0]=='@') ? NOPARAM : igetparam(b, lang);
2011-03-08 08:44:20 +01:00
} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT
&& p != P_GAMENAME);
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
/* Falls in unitorders() abgebrochen wird, steht dort entweder eine neue
* 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>. */
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_NEXT:
f = NULL;
b = getbuf(F, enc_gamedata);
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
default:
b = getbuf(F, enc_gamedata);
break;
2010-08-08 10:06:34 +02:00
}
}
fclose(F);
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts("\n");
2012-05-16 07:21:59 +02:00
log_printf(stdout, " %d Befehlsdateien gelesen\n", nfactions);
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ------------------------------------------------------------- */
/* #define INNER_WORLD */
/* f<>rs debuggen nur den inneren Teil der Welt laden */
/* -9;-27;-1;-19;Sumpfloch */
2011-03-07 08:02:35 +01:00
int inner_world(region * r)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
static int xy[2] = { 18, -45 };
static int size[2] = { 27, 27 };
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1]
&& r->y < xy[1] + size[1])
2010-08-08 10:06:34 +02:00
return 2;
2011-03-07 08:02:35 +01:00
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)
2010-08-08 10:06:34 +02:00
return 1;
return 0;
}
int maxregions = -1;
int loadplane = 0;
enum {
U_MAN,
U_UNDEAD,
U_ILLUSION,
U_FIREDRAGON,
U_DRAGON,
U_WYRM,
U_SPELL,
U_TAVERNE,
U_MONSTER,
U_BIRTHDAYDRAGON,
U_TREEMAN,
MAXTYPES
};
2011-03-07 08:02:35 +01:00
race_t typus2race(unsigned char typus)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (typus > 0 && typus <= 11)
return (race_t) (typus - 1);
2010-08-08 10:06:34 +02:00
return NORACE;
}
2011-03-07 08:02:35 +01:00
void create_backup(char *file)
2010-08-08 10:06:34 +02:00
{
#ifdef HAVE_LINK
char bfile[MAX_PATH];
int c = 1;
2011-03-07 08:02:35 +01:00
if (access(file, R_OK) == 0)
return;
2010-08-08 10:06:34 +02:00
do {
sprintf(bfile, "%s.backup%d", file, c);
c++;
2011-03-07 08:02:35 +01:00
} while (access(bfile, R_OK) == 0);
2010-08-08 10:06:34 +02:00
link(file, bfile);
#endif
}
2011-03-07 08:02:35 +01:00
void read_items(struct storage *store, item ** ilist)
2010-08-08 10:06:34 +02:00
{
for (;;) {
char ibuf[32];
2011-03-07 08:02:35 +01:00
const item_type *itype;
2010-08-08 10:06:34 +02:00
int i;
READ_STR(store, ibuf, sizeof(ibuf));
2011-03-07 08:02:35 +01:00
if (!strcmp("end", ibuf))
break;
2010-08-08 10:06:34 +02:00
itype = it_find(ibuf);
READ_INT(store, &i);
2011-03-07 08:02:35 +01:00
if (i <= 0) {
log_error("data contains an entry with %d %s\n", i, itype->rtype->_name[1]);
2010-08-08 10:06:34 +02:00
} else {
2011-03-07 08:02:35 +01:00
assert(itype != NULL);
if (itype != NULL) {
2010-08-08 10:06:34 +02:00
i_change(ilist, itype, i);
}
}
}
}
2011-03-07 08:02:35 +01:00
static void read_alliances(struct storage *store)
2010-08-08 10:06:34 +02:00
{
char pbuf[8];
int id, terminator = 0;
if (global.data_version < SAVEALLIANCE_VERSION) {
2011-03-07 08:02:35 +01:00
if (!AllianceRestricted() && !AllianceAuto())
return;
2010-08-08 10:06:34 +02:00
}
if (global.data_version < ALLIANCELEADER_VERSION) {
2010-08-08 10:06:34 +02:00
terminator = atoi36("end");
READ_STR(store, pbuf, sizeof(pbuf));
2010-08-08 10:06:34 +02:00
id = atoi36(pbuf);
} else {
READ_INT(store, &id);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
while (id != terminator) {
2010-08-08 10:06:34 +02:00
char aname[128];
2011-03-07 08:02:35 +01:00
alliance *al;
READ_STR(store, aname, sizeof(aname));
2010-08-08 10:06:34 +02:00
al = makealliance(id, aname);
if (global.data_version >= OWNER_2_VERSION) {
READ_UINT(store, &al->flags);
2010-08-08 10:06:34 +02:00
}
if (global.data_version >= ALLIANCELEADER_VERSION) {
2011-03-07 08:02:35 +01:00
read_reference(&al->_leader, store, read_faction_reference,
resolve_faction);
READ_INT(store, &id);
2011-03-07 08:02:35 +01:00
} else {
READ_STR(store, pbuf, sizeof(pbuf));
2010-08-08 10:06:34 +02:00
id = atoi36(pbuf);
}
}
}
void write_alliances(struct gamedata *data)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
alliance *al = alliances;
2010-08-08 10:06:34 +02:00
while (al) {
if (al->_leader) {
WRITE_INT(data->store, al->id);
WRITE_STR(data->store, al->name);
WRITE_INT(data->store, (int)al->flags);
write_faction_reference(al->_leader, data->store);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
}
al = al->next;
}
WRITE_INT(data->store, 0);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void write_items(struct storage *store, item * ilist)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
item *itm;
for (itm = ilist; itm; itm = itm->next) {
assert(itm->number >= 0);
2010-08-08 10:06:34 +02:00
if (itm->number) {
WRITE_TOK(store, resourcename(itm->type->rtype, 0));
WRITE_INT(store, itm->number);
2010-08-08 10:06:34 +02:00
}
}
WRITE_TOK(store, "end");
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int resolve_owner(variant id, void *address)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region_owner *owner = (region_owner *) address;
2010-08-08 10:06:34 +02:00
int result = 0;
2011-03-07 08:02:35 +01:00
faction *f = NULL;
if (id.i != 0) {
2010-08-08 10:06:34 +02:00
f = findfaction(id.i);
2011-03-07 08:02:35 +01:00
if (f == NULL) {
log_error("region has an invalid owner (%s)\n", itoa36(id.i));
2010-08-08 10:06:34 +02:00
f = get_monsters();
}
}
owner->owner = f;
if (f) {
owner->alliance = f->alliance;
}
return result;
}
static void read_owner(struct gamedata *data, region_owner ** powner)
2010-08-08 10:06:34 +02:00
{
int since_turn;
READ_INT(data->store, &since_turn);
2011-03-07 08:02:35 +01:00
if (since_turn >= 0) {
region_owner *owner = malloc(sizeof(region_owner));
2010-08-08 10:06:34 +02:00
owner->since_turn = since_turn;
READ_INT(data->store, &owner->morale_turn);
if (data->version >= MOURNING_VERSION) {
READ_UINT(data->store, &owner->flags);
2010-08-08 10:06:34 +02:00
} else {
owner->flags = 0;
}
if (data->version >= OWNER_2_VERSION) {
int id;
READ_INT(data->store, &id);
2011-03-07 08:02:35 +01:00
owner->alliance = id ? findalliance(id) : NULL;
2010-08-08 10:06:34 +02:00
} else {
owner->alliance = NULL;
}
read_reference(owner, data->store, &read_faction_reference, &resolve_owner);
2010-08-08 10:06:34 +02:00
*powner = owner;
} else {
*powner = 0;
}
}
static void write_owner(struct gamedata *data, region_owner * owner)
2010-08-08 10:06:34 +02:00
{
if (owner) {
WRITE_INT(data->store, owner->since_turn);
WRITE_INT(data->store, owner->morale_turn);
WRITE_INT(data->store, owner->flags);
WRITE_INT(data->store, owner->alliance ? owner->alliance->id : 0);
write_faction_reference(owner->owner, data->store);
2010-08-08 10:06:34 +02:00
} else {
WRITE_INT(data->store, -1);
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
int current_turn(void)
2010-08-08 10:06:34 +02:00
{
char zText[MAX_PATH];
int cturn = 0;
FILE *F;
2010-08-08 10:06:34 +02:00
sprintf(zText, "%s/turn", basepath());
F = fopen(zText, "r");
if (!F) {
perror(zText);
}
else {
fscanf(F, "%d\n", &cturn);
fclose(F);
2010-08-08 10:06:34 +02:00
}
return cturn;
}
static void
writeorder(struct gamedata *data, const struct order *ord,
2011-03-07 08:02:35 +01:00
const struct locale *lang)
2010-08-08 10:06:34 +02:00
{
char obuf[1024];
write_order(ord, obuf, sizeof(obuf));
2011-03-07 08:02:35 +01:00
if (obuf[0])
WRITE_STR(data->store, obuf);
2010-08-08 10:06:34 +02:00
}
unit *read_unit(struct gamedata *data)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
unit *u;
2010-08-08 10:06:34 +02:00
int number, n, p;
2011-03-07 08:02:35 +01:00
order **orderp;
2010-08-08 10:06:34 +02:00
char obuf[1024];
2011-03-07 08:02:35 +01:00
faction *f;
2010-08-08 10:06:34 +02:00
char rname[32];
READ_INT(data->store, &n);
2011-03-07 08:02:35 +01:00
if (n <= 0)
return NULL;
2010-08-08 10:06:34 +02:00
u = findunit(n);
2011-03-07 08:02:35 +01:00
if (u == NULL) {
2010-08-08 10:06:34 +02:00
u = calloc(sizeof(unit), 1);
u->no = n;
uhash(u);
} else {
2011-03-07 08:02:35 +01:00
while (u->attribs)
a_remove(&u->attribs, u->attribs);
while (u->items)
i_free(i_remove(&u->items, u->items));
2010-08-08 10:06:34 +02:00
free(u->skills);
u->skills = 0;
u->skill_size = 0;
u_setfaction(u, NULL);
}
READ_INT(data->store, &n);
2010-08-08 10:06:34 +02:00
f = findfaction(n);
2011-03-07 08:02:35 +01:00
if (f != u->faction)
u_setfaction(u, f);
2010-08-08 10:06:34 +02:00
READ_STR(data->store, obuf, sizeof(obuf));
u->name = _strdup(obuf);
2010-08-08 10:06:34 +02:00
if (lomem) {
READ_STR(data->store, NULL, 0);
2010-08-08 10:06:34 +02:00
} else {
READ_STR(data->store, obuf, sizeof(obuf));
u->display = _strdup(obuf);
2010-08-08 10:06:34 +02:00
}
READ_INT(data->store, &number);
READ_INT(data->store, &n);
u->age = (short)n;
2011-03-07 08:02:35 +01:00
if (data->version < STORAGE_VERSION) {
2011-03-07 08:02:35 +01:00
char *space;
READ_STR(data->store, rname, sizeof(rname));
2010-08-08 10:06:34 +02:00
space = strchr(rname, ' ');
2011-03-07 08:02:35 +01:00
if (space != NULL) {
char *inc = space + 1;
char *outc = space;
2010-08-08 10:06:34 +02:00
do {
2011-03-07 08:02:35 +01:00
while (*inc == ' ')
++inc;
2010-08-08 10:06:34 +02:00
while (*inc) {
*outc++ = *inc++;
2011-03-07 08:02:35 +01:00
if (*inc == ' ')
break;
2010-08-08 10:06:34 +02:00
}
} while (*inc);
*outc = 0;
}
} else {
READ_TOK(data->store, rname, sizeof(rname));
2010-08-08 10:06:34 +02:00
}
u_setrace(u, rc_find(rname));
if (data->version < STORAGE_VERSION) {
READ_STR(data->store, rname, sizeof(rname));
2010-08-08 10:06:34 +02:00
} else {
READ_TOK(data->store, rname, sizeof(rname));
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (rname[0] && skill_enabled[SK_STEALTH])
u->irace = rc_find(rname);
else
u->irace = NULL;
2010-08-08 10:06:34 +02:00
if (u_race(u)->describe) {
const char *rcdisp = u_race(u)->describe(u, u->faction->locale);
2010-08-08 10:06:34 +02:00
if (u->display && rcdisp) {
/* see if the data file contains old descriptions */
2011-03-07 08:02:35 +01:00
if (strcmp(rcdisp, u->display) == 0) {
2010-08-08 10:06:34 +02:00
free(u->display);
u->display = NULL;
}
}
}
if (u->faction == NULL) {
log_error("unit %s has faction == NULL\n", unitname(u));
2010-08-08 10:06:34 +02:00
u_setfaction(u, get_monsters());
set_number(u, 0);
}
2011-03-07 08:02:35 +01:00
if (count_unit(u) && u->faction)
u->faction->no_units++;
2010-08-08 10:06:34 +02:00
set_number(u, number);
READ_INT(data->store, &n);
if (n > 0) {
building * b = findbuilding(n);
if (b) {
u_set_building(u, b);
if (fval(u, UFL_OWNER)) {
building_set_owner(u);
}
} else {
log_error("read_unit: unit in unkown building '%s'\n", itoa36(n));
}
}
2010-08-08 10:06:34 +02:00
READ_INT(data->store, &n);
if (n > 0) {
ship * sh = findship(n);
if (sh) {
u_set_ship(u, sh);
if (fval(u, UFL_OWNER)) {
ship_set_owner(u);
}
} else {
log_error("read_unit: unit in unkown ship '%s'\n", itoa36(n));
}
}
READ_INT(data->store, &n);
setstatus(u, n);
READ_UINT(data->store, &u->flags);
2010-08-08 10:06:34 +02:00
u->flags &= UFL_SAVEMASK;
2011-03-07 08:02:35 +01:00
if ((u->flags & UFL_ANON_FACTION) && !rule_stealth_faction()) {
2010-08-08 10:06:34 +02:00
/* if this rule is broken, then fix broken units */
u->flags -= UFL_ANON_FACTION;
log_warning("%s was anonymous.\n", unitname(u));
2010-08-08 10:06:34 +02:00
}
/* Persistente Befehle einlesen */
free_orders(&u->orders);
READ_STR(data->store, obuf, sizeof(obuf));
2010-08-08 10:06:34 +02:00
p = n = 0;
orderp = &u->orders;
while (obuf[0]) {
if (!lomem) {
2011-03-07 08:02:35 +01:00
order *ord = parse_order(obuf, u->faction->locale);
if (ord != NULL) {
if (++n < MAXORDERS) {
if (!is_persistent(ord) || ++p < MAXPERSISTENT) {
2010-08-08 10:06:34 +02:00
*orderp = ord;
orderp = &ord->next;
ord = NULL;
2011-03-07 08:02:35 +01:00
} else if (p == MAXPERSISTENT) {
log_warning("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
} else if (n == MAXORDERS) {
log_warning("%s had %d or more orders\n", unitname(u), MAXORDERS);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (ord != NULL)
free_order(ord);
2010-08-08 10:06:34 +02:00
}
}
READ_STR(data->store, obuf, sizeof(obuf));
2010-08-08 10:06:34 +02:00
}
if (data->version < NOLASTORDER_VERSION) {
2011-03-07 08:02:35 +01:00
order *ord;
READ_STR(data->store, obuf, sizeof(obuf));
2010-08-08 10:06:34 +02:00
ord = parse_order(obuf, u->faction->locale);
2011-03-07 08:02:35 +01:00
if (ord != NULL) {
2010-08-08 10:06:34 +02:00
addlist(&u->orders, ord);
}
}
set_order(&u->thisorder, NULL);
assert(u_race(u));
for (;;) {
int n, level, weeks;
skill_t sk;
READ_INT(data->store, &n);
sk = (skill_t)n;
if (sk == NOSKILL) break;
READ_INT(data->store, &level);
READ_INT(data->store, &weeks);
2010-08-08 10:06:34 +02:00
if (level) {
2011-03-07 08:02:35 +01:00
skill *sv = add_skill(u, sk);
2010-08-08 10:06:34 +02:00
sv->level = sv->old = (unsigned char)level;
sv->weeks = (unsigned char)weeks;
}
}
read_items(data->store, &u->items);
READ_INT(data->store, &u->hp);
2010-08-08 10:06:34 +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);
2011-03-07 08:02:35 +01:00
u->hp = u->number;
2010-08-08 10:06:34 +02:00
}
a_read(data->store, &u->attribs, u);
2010-08-08 10:06:34 +02:00
return u;
}
void write_unit(struct gamedata *data, const unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
order *ord;
2010-08-08 10:06:34 +02:00
int i, p = 0;
unsigned int flags = u->flags & UFL_SAVEMASK;
2011-03-07 08:02:35 +01:00
const race *irace = u_irace(u);
write_unit_reference(u, data->store);
write_faction_reference(u->faction, data->store);
WRITE_STR(data->store, (const char *)u->name);
WRITE_STR(data->store, u->display ? (const char *)u->display : "");
WRITE_INT(data->store, u->number);
WRITE_INT(data->store, u->age);
WRITE_TOK(data->store, u_race(u)->_name[0]);
WRITE_TOK(data->store, (irace && irace != u_race(u)) ? irace->_name[0] : "");
write_building_reference(u->building, data->store);
write_ship_reference(u->ship, data->store);
WRITE_INT(data->store, u->status);
if (u->building && u==building_owner(u->building)) flags |= UFL_OWNER;
if (u->ship && u==ship_owner(u->ship)) flags |= UFL_OWNER;
WRITE_INT(data->store, flags);
WRITE_SECTION(data->store);
2011-03-07 08:02:35 +01:00
for (ord = u->old_orders; ord; ord = ord->next) {
if (++p < MAXPERSISTENT) {
writeorder(data, ord, u->faction->locale);
2010-08-08 10:06:34 +02:00
} else {
log_error("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
2010-08-08 10:06:34 +02:00
break;
}
}
2011-03-07 08:02:35 +01:00
for (ord = u->orders; ord; ord = ord->next) {
if (u->old_orders && is_repeated(ord))
continue; /* has new defaults */
2010-08-08 10:06:34 +02:00
if (is_persistent(ord)) {
2011-03-07 08:02:35 +01:00
if (++p < MAXPERSISTENT) {
writeorder(data, ord, u->faction->locale);
2010-08-08 10:06:34 +02:00
} else {
log_error("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
2010-08-08 10:06:34 +02:00
break;
}
}
}
/* write an empty string to terminate the list */
WRITE_STR(data->store, "");
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
assert(u_race(u));
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
assert(sv->weeks <= sv->level * 2 + 1);
if (sv->level > 0) {
WRITE_INT(data->store, sv->id);
WRITE_INT(data->store, sv->level);
WRITE_INT(data->store, sv->weeks);
2010-08-08 10:06:34 +02:00
}
}
WRITE_INT(data->store, -1);
WRITE_SECTION(data->store);
write_items(data->store, u->items);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
if (u->hp == 0) {
log_error("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no));
2011-03-07 08:02:35 +01:00
((unit *) u)->hp = u->number;
2010-08-08 10:06:34 +02:00
}
WRITE_INT(data->store, u->hp);
WRITE_SECTION(data->store);
a_write(data->store, u->attribs, u);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
}
static region *readregion(struct gamedata *data, int x, int y)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region *r = findregion(x, y);
const terrain_type *terrain;
2010-08-08 10:06:34 +02:00
char token[32];
unsigned int uid = 0;
int n;
2010-08-08 10:06:34 +02:00
if (data->version >= UID_VERSION) {
READ_UINT(data->store, &uid);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (r == NULL) {
plane *pl = findplane(x, y);
2010-08-08 10:06:34 +02:00
r = new_region(x, y, pl, uid);
} else {
2011-03-07 08:02:35 +01:00
assert(uid == 0 || r->uid == uid);
2010-08-08 10:06:34 +02:00
current_region = r;
2011-03-07 08:02:35 +01:00
while (r->attribs)
a_remove(&r->attribs, r->attribs);
2010-08-08 10:06:34 +02:00
if (r->land) {
2011-03-07 08:02:35 +01:00
free(r->land); /* mem leak */
r->land->demands = 0; /* mem leak */
2010-08-08 10:06:34 +02:00
}
while (r->resources) {
2011-03-07 08:02:35 +01:00
rawmaterial *rm = r->resources;
2010-08-08 10:06:34 +02:00
r->resources = rm->next;
free(rm);
}
r->land = 0;
}
if (lomem) {
READ_STR(data->store, NULL, 0);
2010-08-08 10:06:34 +02:00
} else {
char info[DISPLAYSIZE];
READ_STR(data->store, info, sizeof(info));
2010-08-08 10:06:34 +02:00
region_setinfo(r, info);
}
2011-03-07 08:02:35 +01:00
if (data->version < TERRAIN_VERSION) {
int ter;
READ_INT(data->store, &ter);
2011-03-07 08:02:35 +01:00
terrain = newterrain((terrain_t) ter);
if (terrain == NULL) {
log_error("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter);
2010-08-08 10:06:34 +02:00
terrain = newterrain(T_PLAIN);
}
} else {
char name[64];
READ_STR(data->store, name, sizeof(name));
2010-08-08 10:06:34 +02:00
terrain = get_terrain(name);
2011-03-07 08:02:35 +01:00
if (terrain == NULL) {
log_error("Unknown terrain '%s'\n", name);
2010-08-08 10:06:34 +02:00
assert(!"unknown terrain");
}
}
r->terrain = terrain;
READ_UINT(data->store, &r->flags);
READ_INT(data->store, &n);
r->age = (unsigned short)n;
2010-08-08 10:06:34 +02:00
if (fval(r->terrain, LAND_REGION)) {
char name[NAMESIZE];
2010-08-08 10:06:34 +02:00
r->land = calloc(1, sizeof(land_region));
READ_STR(data->store, name, sizeof(name));
r->land->name = _strdup(name);
2010-08-08 10:06:34 +02:00
}
if (r->land) {
int i;
2011-03-07 08:02:35 +01:00
rawmaterial **pres = &r->resources;
2010-08-08 10:06:34 +02:00
READ_INT(data->store, &i);
2011-03-07 08:02:35 +01:00
if (i < 0) {
log_error("number of trees in %s is %d.\n", regionname(r, NULL), i);
2011-03-07 08:02:35 +01:00
i = 0;
2010-08-08 10:06:34 +02:00
}
rsettrees(r, 0, i);
READ_INT(data->store, &i);
2011-03-07 08:02:35 +01:00
if (i < 0) {
log_error("number of young trees in %s is %d.\n", regionname(r, NULL), i);
2011-03-07 08:02:35 +01:00
i = 0;
2010-08-08 10:06:34 +02:00
}
rsettrees(r, 1, i);
READ_INT(data->store, &i);
2011-03-07 08:02:35 +01:00
if (i < 0) {
log_error("number of seeds in %s is %d.\n", regionname(r, NULL), i);
2011-03-07 08:02:35 +01:00
i = 0;
2010-08-08 10:06:34 +02:00
}
rsettrees(r, 2, i);
READ_INT(data->store, &i);
2011-03-07 08:02:35 +01:00
rsethorses(r, i);
assert(*pres == NULL);
2010-08-08 10:06:34 +02:00
for (;;) {
2011-03-07 08:02:35 +01:00
rawmaterial *res;
READ_STR(data->store, token, sizeof(token));
2011-03-07 08:02:35 +01:00
if (strcmp(token, "end") == 0)
break;
2010-08-08 10:06:34 +02:00
res = malloc(sizeof(rawmaterial));
res->type = rmt_find(token);
2011-03-07 08:02:35 +01:00
if (res->type == NULL) {
log_error("invalid resourcetype %s in data.\n", token);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
assert(res->type != NULL);
READ_INT(data->store, &n);
res->level = n;
READ_INT(data->store, &n);
res->amount = n;
2010-08-08 10:06:34 +02:00
res->flags = 0;
READ_INT(data->store, &n);
res->startlevel = n;
READ_INT(data->store, &n);
res->base = n;
READ_INT(data->store, &n);
res->divisor = n;
2010-08-08 10:06:34 +02:00
*pres = res;
2011-03-07 08:02:35 +01:00
pres = &res->next;
2010-08-08 10:06:34 +02:00
}
*pres = NULL;
READ_STR(data->store, token, sizeof(token));
2010-08-08 10:06:34 +02:00
if (strcmp(token, "noherb") != 0) {
2011-03-07 08:02:35 +01:00
const resource_type *rtype = rt_find(token);
2010-08-08 10:06:34 +02:00
assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB));
rsetherbtype(r, rtype->itype);
} else {
rsetherbtype(r, NULL);
}
READ_INT(data->store, &n);
rsetherbs(r, (short)n);
READ_INT(data->store, &n);
rsetpeasants(r, n);
READ_INT(data->store, &n);
rsetmoney(r, n);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
assert(r->terrain != NULL);
2010-08-08 10:06:34 +02:00
assert(rhorses(r) >= 0);
assert(rpeasants(r) >= 0);
assert(rmoney(r) >= 0);
if (r->land) {
int n;
2010-08-08 10:06:34 +02:00
for (;;) {
2011-03-07 08:02:35 +01:00
const struct item_type *itype;
READ_STR(data->store, token, sizeof(token));
2011-03-07 08:02:35 +01:00
if (!strcmp(token, "end"))
break;
2010-08-08 10:06:34 +02:00
itype = it_find(token);
assert(itype->rtype->ltype);
READ_INT(data->store, &n);
r_setdemand(r, itype->rtype->ltype, n);
2010-08-08 10:06:34 +02:00
}
if (data->version >= REGIONITEMS_VERSION) {
read_items(data->store, &r->land->items);
2010-08-08 10:06:34 +02:00
}
if (data->version >= REGIONOWNER_VERSION) {
READ_INT(data->store, &n);
r->land->morale = (short)n;
if (r->land->morale < 0) {
2011-03-07 08:02:35 +01:00
r->land->morale = 0;
}
read_owner(data, &r->land->ownership);
2010-08-08 10:06:34 +02:00
}
}
a_read(data->store, &r->attribs, r);
2010-08-08 10:06:34 +02:00
return r;
}
void writeregion(struct gamedata *data, const region * r)
2010-08-08 10:06:34 +02:00
{
WRITE_INT(data->store, r->uid);
WRITE_STR(data->store, region_getinfo(r));
WRITE_TOK(data->store, r->terrain->_name);
WRITE_INT(data->store, r->flags & RF_SAVEMASK);
WRITE_INT(data->store, r->age);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
if (fval(r->terrain, LAND_REGION)) {
const item_type *rht;
2011-03-07 08:02:35 +01:00
struct demand *demand;
rawmaterial *res = r->resources;
WRITE_STR(data->store, (const char *)r->land->name);
2011-03-07 08:02:35 +01:00
assert(rtrees(r, 0) >= 0);
assert(rtrees(r, 1) >= 0);
assert(rtrees(r, 2) >= 0);
WRITE_INT(data->store, rtrees(r, 0));
WRITE_INT(data->store, rtrees(r, 1));
WRITE_INT(data->store, rtrees(r, 2));
WRITE_INT(data->store, rhorses(r));
2010-08-08 10:06:34 +02:00
while (res) {
WRITE_TOK(data->store, res->type->name);
WRITE_INT(data->store, res->level);
WRITE_INT(data->store, res->amount);
WRITE_INT(data->store, res->startlevel);
WRITE_INT(data->store, res->base);
WRITE_INT(data->store, res->divisor);
2010-08-08 10:06:34 +02:00
res = res->next;
}
WRITE_TOK(data->store, "end");
2010-08-08 10:06:34 +02:00
rht = rherbtype(r);
if (rht) {
WRITE_TOK(data->store, resourcename(rht->rtype, 0));
2010-08-08 10:06:34 +02:00
} else {
WRITE_TOK(data->store, "noherb");
2010-08-08 10:06:34 +02:00
}
WRITE_INT(data->store, rherbs(r));
WRITE_INT(data->store, rpeasants(r));
WRITE_INT(data->store, rmoney(r));
2011-03-07 08:02:35 +01:00
if (r->land)
for (demand = r->land->demands; demand; demand = demand->next) {
WRITE_TOK(data->store, resourcename(demand->type->itype->rtype, 0));
WRITE_INT(data->store, demand->value);
2011-03-07 08:02:35 +01:00
}
WRITE_TOK(data->store, "end");
2010-08-08 10:06:34 +02:00
#if RELEASE_VERSION>=REGIONITEMS_VERSION
write_items(data->store, r->land->items);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
#endif
#if RELEASE_VERSION>=REGIONOWNER_VERSION
WRITE_INT(data->store, r->land->morale);
write_owner(data, r->land->ownership);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
#endif
}
a_write(data->store, r->attribs, r);
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static ally **addally(const faction * f, ally ** sfp, int aid, int state)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
struct faction *af = findfaction(aid);
ally *sf;
2010-08-08 10:06:34 +02:00
state &= ~HELP_OBSERVE;
#ifndef REGIONOWNERS
state &= ~HELP_TRAVEL;
#endif
state &= HelpMask();
2011-03-07 08:02:35 +01:00
if (state == 0)
return sfp;
2010-08-08 10:06:34 +02:00
sf = calloc(1, sizeof(ally));
sf->faction = af;
if (!sf->faction) {
variant id;
id.i = aid;
ur_add(id, &sf->faction, resolve_faction);
}
sf->status = state & HELP_ALL;
2011-03-07 08:02:35 +01:00
while (*sfp)
sfp = &(*sfp)->next;
2010-08-08 10:06:34 +02:00
*sfp = sf;
return &sf->next;
}
int get_spell_level_faction(const spell * sp, void * cbdata)
{
static spellbook * common = 0;
spellbook * book;
faction * f = (faction *)cbdata;
spellbook_entry * sbe;
book = get_spellbook(magic_school[f->magiegebiet]);
if (book) {
sbe = spellbook_get(book, sp);
if (sbe) return sbe->level;
}
if (!common) {
common = get_spellbook(magic_school[M_COMMON]);
}
sbe = spellbook_get(common, sp);
if (sbe) {
return sbe->level;
} else {
log_error("read_spellbook: faction '%s' has a spell with unknown level: '%s'", factionname(f), sp->sname);
}
return 0;
}
void read_spellbook(spellbook **bookp, struct storage *store, int(*get_level)(const spell * sp, void *), void * cbdata)
{
for (;;) {
spell *sp = 0;
char spname[64];
int level = 0;
if (global.data_version < SPELLNAME_VERSION) {
int i;
READ_INT(store, &i);
if (i < 0)
break;
if (bookp) {
sp = find_spellbyid((unsigned int) i);
}
} else {
READ_TOK(store, spname, sizeof(spname));
if (strcmp(spname, "end") == 0)
break;
if (bookp) {
sp = find_spell(spname);
if (!sp) {
log_error("read_spells: could not find spell '%s'\n", spname);
}
}
}
if (global.data_version >= SPELLBOOK_VERSION) {
READ_INT(store, &level);
}
if (sp) {
spellbook * sb = *bookp;
if (level<=0 && get_level) {
level = get_level(sp, cbdata);
}
if (!sb) {
*bookp = create_spellbook(0);
sb = *bookp;
}
if (global.data_version >= SPELLBOOK_VERSION || !spellbook_get(sb, sp)) {
spellbook_add(sb, sp, level);
}
}
}
}
void write_spellbook(const struct spellbook *book, struct storage *store)
{
quicklist *ql;
int qi;
if (book) {
for (ql = book->spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi);
WRITE_TOK(store, sbe->sp->sname);
WRITE_INT(store, sbe->level);
}
}
WRITE_TOK(store, "end");
}
2010-08-08 10:06:34 +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(struct gamedata * data)
2010-08-08 10:06:34 +02:00
{
ally **sfp;
int planes, n;
faction *f;
char name[NAMESIZE];
2010-08-08 10:06:34 +02:00
READ_INT(data->store, &n);
f = findfaction(n);
2011-03-07 08:02:35 +01:00
if (f == NULL) {
2010-08-08 10:06:34 +02:00
f = (faction *) calloc(1, sizeof(faction));
f->no = n;
2010-08-08 10:06:34 +02:00
} else {
2011-03-07 08:02:35 +01:00
f->allies = NULL; /* mem leak */
while (f->attribs)
a_remove(&f->attribs, f->attribs);
2010-08-08 10:06:34 +02:00
}
READ_INT(data->store, &f->subscription);
2010-08-08 10:06:34 +02:00
if (alliances || data->version >= OWNER_2_VERSION) {
int allianceid;
READ_INT(data->store, &allianceid);
2011-03-07 08:02:35 +01:00
if (allianceid > 0)
f->alliance = findalliance(allianceid);
2010-08-08 10:06:34 +02:00
if (f->alliance) {
2011-03-07 08:02:35 +01:00
alliance *al = f->alliance;
if (al->flags & ALF_NON_ALLIED) {
assert(!al->members
|| !"non-allied dummy-alliance has more than one member");
2010-08-08 10:06:34 +02:00
}
ql_push(&al->members, f);
2011-03-07 08:02:35 +01:00
} else if (rule_region_owners()) {
2010-08-08 10:06:34 +02:00
/* compat fix for non-allied factions */
2011-03-07 08:02:35 +01:00
alliance *al = makealliance(0, NULL);
2010-08-08 10:06:34 +02:00
setalliance(f, al);
}
if (data->version >= OWNER_2_VERSION) {
READ_INT(data->store, &f->alliance_joindate);
2010-08-08 10:06:34 +02:00
} else {
f->alliance_joindate = turn - 10; /* we're guessing something safe here */
}
}
READ_STR(data->store, name, sizeof(name));
f->name = _strdup(name);
READ_STR(data->store, name, sizeof(name));
f->banner = _strdup(name);
2010-08-08 10:06:34 +02:00
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Lese Partei %s (%s)\n", f->name, factionid(f));
2010-08-08 10:06:34 +02:00
READ_STR(data->store, name, sizeof(name));
if (set_email(&f->email, name) != 0) {
log_warning("Invalid email address for faction %s: %s\n", itoa36(f->no), name);
2010-08-08 10:06:34 +02:00
set_email(&f->email, "");
}
READ_STR(data->store, name, sizeof(name));
f->passw = _strdup(name);
if (data->version >= OVERRIDE_VERSION) {
READ_STR(data->store, name, sizeof(name));
f->override = _strdup(name);
2010-08-08 10:06:34 +02:00
} else {
f->override = _strdup(itoa36(rng_int()));
2010-08-08 10:06:34 +02:00
}
READ_STR(data->store, name, sizeof(name));
f->locale = find_locale(name);
READ_INT(data->store, &f->lastorders);
READ_INT(data->store, &f->age);
READ_STR(data->store, name, sizeof(name));
f->race = rc_find(name);
2010-08-08 10:06:34 +02:00
assert(f->race);
READ_INT(data->store, &n);
f->magiegebiet = (magic_t)n;
2010-08-08 10:06:34 +02:00
if (data->version < FOSS_VERSION) {
2010-08-08 10:06:34 +02:00
/* ignore karma */
READ_INT(data->store, &n);
2010-08-08 10:06:34 +02:00
}
READ_UINT(data->store, &f->flags);
2011-03-07 08:02:35 +01:00
if (f->no == 0) {
2010-08-08 10:06:34 +02:00
f->flags |= FFL_NPC;
}
a_read(data->store, &f->attribs, f);
if (data->version >= CLAIM_VERSION) {
read_items(data->store, &f->items);
2010-08-08 10:06:34 +02:00
}
for (;;) {
READ_TOK(data->store, name, sizeof(name));
if (strcmp("end", name) == 0)
2011-03-07 08:02:35 +01:00
break;
READ_INT(data->store, &n); /* there used to be a level here, which is now ignored */
2011-03-07 08:02:35 +01:00
}
READ_INT(data->store, &planes);
2011-03-07 08:02:35 +01:00
while (--planes >= 0) {
int id, ux, uy;
READ_INT(data->store, &id);
READ_INT(data->store, &ux);
READ_INT(data->store, &uy);
2010-08-08 10:06:34 +02:00
set_ursprung(f, id, ux, uy);
}
f->newbies = 0;
2011-03-07 08:02:35 +01:00
READ_INT(data->store, &n);
f->options = n;
2010-08-08 10:06:34 +02:00
if ((n & (want(O_REPORT) | want(O_COMPUTER))) == 0 && !is_monsters(f)) {
2010-08-08 10:06:34 +02:00
/* Kein Report eingestellt, Fehler */
f->options |= (want(O_REPORT) | want(O_ZUGVORLAGE));
2010-08-08 10:06:34 +02:00
}
sfp = &f->allies;
if (data->version < ALLIANCES_VERSION) {
int p;
READ_INT(data->store, &p);
2010-08-08 10:06:34 +02:00
while (--p >= 0) {
int aid, state;
READ_INT(data->store, &aid);
READ_INT(data->store, &state);
2010-08-08 10:06:34 +02:00
sfp = addally(f, sfp, aid, state);
}
} else {
for (;;) {
int aid = 0;
if (data->version < STORAGE_VERSION) {
READ_TOK(data->store, name, sizeof(name));
if (strcmp(name, "end") != 0) {
aid = atoi36(name);
2010-08-08 10:06:34 +02:00
}
} else {
READ_INT(data->store, &aid);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (aid > 0) {
int state;
READ_INT(data->store, &state);
2010-08-08 10:06:34 +02:00
sfp = addally(f, sfp, aid, state);
} else {
break;
}
}
}
read_groups(data->store, f);
f->spellbook = 0;
if (data->version >= REGIONOWNER_VERSION) {
read_spellbook(FactionSpells() ? &f->spellbook : 0, data->store, get_spell_level_faction, (void *)f);
2010-08-08 10:06:34 +02:00
}
return f;
}
void writefaction(struct gamedata *data, const faction * f)
2010-08-08 10:06:34 +02:00
{
ally *sf;
ursprung *ur;
write_faction_reference(f, data->store);
WRITE_INT(data->store, f->subscription);
2010-08-08 10:06:34 +02:00
if (f->alliance) {
WRITE_INT(data->store, f->alliance->id);
2011-03-07 08:02:35 +01:00
if (f->alliance->flags & ALF_NON_ALLIED) {
assert(f == f->alliance->_leader
|| !"non-allied faction is not leader of its own dummy-alliance.");
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
} else {
WRITE_INT(data->store, 0);
}
WRITE_INT(data->store, f->alliance_joindate);
WRITE_STR(data->store, (const char *)f->name);
WRITE_STR(data->store, (const char *)f->banner);
WRITE_STR(data->store, f->email);
WRITE_TOK(data->store, (const char *)f->passw);
WRITE_TOK(data->store, (const char *)f->override);
WRITE_TOK(data->store, locale_name(f->locale));
WRITE_INT(data->store, f->lastorders);
WRITE_INT(data->store, f->age);
WRITE_TOK(data->store, f->race->_name[0]);
WRITE_SECTION(data->store);
WRITE_INT(data->store, f->magiegebiet);
WRITE_INT(data->store, f->flags & FFL_SAVEMASK);
a_write(data->store, f->attribs, f);
WRITE_SECTION(data->store);
write_items(data->store, f->items);
WRITE_SECTION(data->store);
WRITE_TOK(data->store, "end");
WRITE_SECTION(data->store);
WRITE_INT(data->store, listlen(f->ursprung));
2011-03-07 08:02:35 +01:00
for (ur = f->ursprung; ur; ur = ur->next) {
WRITE_INT(data->store, ur->id);
WRITE_INT(data->store, ur->x);
WRITE_INT(data->store, ur->y);
2010-08-08 10:06:34 +02:00
}
WRITE_SECTION(data->store);
WRITE_INT(data->store, f->options & ~want(O_DEBUG));
WRITE_SECTION(data->store);
2010-08-08 10:06:34 +02:00
for (sf = f->allies; sf; sf = sf->next) {
2011-03-07 08:02:35 +01:00
int no = (sf->faction != NULL) ? sf->faction->no : 0;
2010-08-08 10:06:34 +02:00
int status = alliedfaction(NULL, f, sf->faction, HELP_ALL);
2011-03-07 08:02:35 +01:00
if (status != 0) {
WRITE_INT(data->store, no);
WRITE_INT(data->store, sf->status);
2010-08-08 10:06:34 +02:00
}
}
WRITE_INT(data->store, 0);
WRITE_SECTION(data->store);
write_groups(data->store, f->groups);
write_spellbook(f->spellbook, data->store);
2010-08-08 10:06:34 +02:00
}
int readgame(const char *filename, int backup)
2010-08-08 10:06:34 +02:00
{
int i, n, p;
faction *f, **fp;
region *r;
building *b, **bp;
ship **shp;
unit *u;
int rmax = maxregions;
char path[MAX_PATH];
char name[NAMESIZE];
2011-03-07 08:02:35 +01:00
const struct building_type *bt_lighthouse = bt_find("lighthouse");
gamedata gdata = { 0 };
storage store;
FILE *F;
2011-03-07 08:02:35 +01:00
2012-05-16 07:21:59 +02:00
log_printf(stdout, "- reading game data from %s\n", filename);
sprintf(path, "%s/%s", datapath(), filename);
if (backup) {
2011-03-07 08:02:35 +01:00
create_backup(path);
}
2010-08-08 10:06:34 +02:00
F = fopen(path, "rb");
if (!F) {
perror(path);
2010-08-08 10:06:34 +02:00
return -1;
}
fread(&gdata.version, sizeof(int), 1, F);
if (gdata.version >= INTPAK_VERSION) {
int stream_version;
fread(&stream_version, sizeof(int), 1, F);
assert(stream_version == STREAM_VERSION || !"unsupported data format");
}
assert(gdata.version >= MIN_VERSION || !"unsupported data format");
assert(gdata.version <= RELEASE_VERSION || !"unsupported data format");
2010-08-08 10:06:34 +02:00
gdata.encoding = enc_gamedata;
binstore_init(&store, F);
gdata.store = &store;
global.data_version = gdata.version; /* HACK: attribute::read does not have access to gamedata, only storage */
2010-08-08 10:06:34 +02:00
if (gdata.version >= SAVEXMLNAME_VERSION) {
2010-08-08 10:06:34 +02:00
char basefile[1024];
READ_STR(&store, basefile, sizeof(basefile));
2011-03-07 08:02:35 +01:00
if (strcmp(game_name, basefile) != 0) {
2010-08-08 10:06:34 +02:00
char buffer[64];
2012-05-29 21:17:25 +02:00
strlcpy(buffer, game_name, sizeof(buffer));
strlcat(buffer, ".xml", sizeof(buffer));
2011-03-07 08:02:35 +01:00
if (strcmp(basefile, buffer) != 0) {
log_warning("game mismatch: datafile contains %s, game is %s\n", basefile, game_name);
2010-08-08 10:06:34 +02:00
printf("WARNING: any key to continue, Ctrl-C to stop\n");
getchar();
}
}
}
a_read(&store, &global.attribs, NULL);
READ_INT(&store, &turn);
global.data_turn = turn;
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - reading turn %d\n", turn);
2010-08-08 10:06:34 +02:00
rng_init(turn);
++global.cookie;
READ_INT(&store, &n); /* max_unique_id = ignore */
READ_UINT(&store, &nextborder);
2010-08-08 10:06:34 +02:00
/* Planes */
planes = NULL;
READ_INT(&store, &n);
2011-03-07 08:02:35 +01:00
while (--n >= 0) {
int id;
variant fno;
plane *pl;
READ_INT(&store, &id);
pl = getplanebyid(id);
2011-03-07 08:02:35 +01:00
if (pl == NULL) {
2010-08-08 10:06:34 +02:00
pl = calloc(1, sizeof(plane));
} else {
log_warning("the plane with id=%d already exists.\n", id);
2010-08-08 10:06:34 +02:00
}
pl->id = id;
READ_STR(&store, name, sizeof(name));
pl->name = _strdup(name);
READ_INT(&store, &pl->minx);
READ_INT(&store, &pl->maxx);
READ_INT(&store, &pl->miny);
READ_INT(&store, &pl->maxy);
READ_UINT(&store, &pl->flags);
2010-08-08 10:06:34 +02:00
/* read watchers */
if (gdata.version < FIX_WATCHERS_VERSION) {
char rname[64];
/* before this version, watcher storage was pretty broken. we are incompatible and don't read them */
for (;;) {
READ_TOK(&store, rname, sizeof(rname));
2011-03-07 08:02:35 +01:00
if (strcmp(rname, "end") == 0) {
break; /* this is most likely the end of the list */
} else {
2011-03-07 08:02:35 +01:00
log_error(
("This datafile contains watchers, but we are unable to read them\n"));
}
}
} else {
fno = read_faction_reference(&store);
while (fno.i) {
2011-03-07 08:02:35 +01:00
watcher *w = (watcher *) malloc(sizeof(watcher));
ur_add(fno, &w->faction, resolve_faction);
READ_INT(&store, &n);
w->mode = (unsigned char)n;
w->next = pl->watchers;
pl->watchers = w;
fno = read_faction_reference(&store);
}
2010-08-08 10:06:34 +02:00
}
a_read(&store, &pl->attribs, pl);
2010-08-08 10:06:34 +02:00
addlist(&planes, pl);
}
/* Read factions */
if (gdata.version >= ALLIANCES_VERSION) {
read_alliances(&store);
2010-08-08 10:06:34 +02:00
}
READ_INT(&store, &n);
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Einzulesende Parteien: %d\n", n);
2010-08-08 10:06:34 +02:00
fp = &factions;
2011-03-07 08:02:35 +01:00
while (*fp)
fp = &(*fp)->next;
2010-08-08 10:06:34 +02:00
while (--n >= 0) {
faction *f = readfaction(&gdata);
2010-08-08 10:06:34 +02:00
*fp = f;
fp = &f->next;
fhash(f);
}
*fp = 0;
/* ignore the obsolete list of "used" faction ids */
if (gdata.version < STORAGE_VERSION) {
READ_INT(&store, &i);
2010-08-08 10:06:34 +02:00
while (i--) {
READ_INT(&store, &n);
2010-08-08 10:06:34 +02:00
}
}
/* Regionen */
READ_INT(&store, &n);
2011-03-07 08:02:35 +01:00
assert(n < MAXREGIONS);
if (rmax < 0) {
2011-03-07 08:02:35 +01:00
rmax = n;
}
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Einzulesende Regionen: %d/%d\r", rmax, n);
2010-08-08 10:06:34 +02:00
while (--n >= 0) {
unit **up;
int x, y;
READ_INT(&store, &x);
READ_INT(&store, &y);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y);
2010-08-08 10:06:34 +02:00
}
--rmax;
r = readregion(&gdata, x, y);
2010-08-08 10:06:34 +02:00
/* Burgen */
READ_INT(&store, &p);
2010-08-08 10:06:34 +02:00
bp = &r->buildings;
while (--p >= 0) {
b = (building *) calloc(1, sizeof(building));
READ_INT(&store, &b->no);
2010-08-08 10:06:34 +02:00
*bp = b;
bp = &b->next;
bhash(b);
READ_STR(&store, name, sizeof(name));
b->name = _strdup(name);
2010-08-08 10:06:34 +02:00
if (lomem) {
READ_STR(gdata.store, NULL, 0);
2011-03-07 08:02:35 +01:00
} else {
READ_STR(&store, name, sizeof(name));
b->display = _strdup(name);
2010-08-08 10:06:34 +02:00
}
READ_INT(&store, &b->size);
READ_STR(&store, name, sizeof(name));
b->type = bt_find(name);
2010-08-08 10:06:34 +02:00
b->region = r;
a_read(&store, &b->attribs, b);
2011-03-07 08:02:35 +01:00
if (b->type == bt_lighthouse) {
2010-08-08 10:06:34 +02:00
r->flags |= RF_LIGHTHOUSE;
}
}
/* Schiffe */
READ_INT(&store, &p);
2010-08-08 10:06:34 +02:00
shp = &r->ships;
while (--p >= 0) {
2011-03-07 08:02:35 +01:00
ship *sh = (ship *) calloc(1, sizeof(ship));
2010-08-08 10:06:34 +02:00
sh->region = r;
READ_INT(&store, &sh->no);
2010-08-08 10:06:34 +02:00
*shp = sh;
shp = &sh->next;
shash(sh);
READ_STR(&store, name, sizeof(name));
sh->name = _strdup(name);
2010-08-08 10:06:34 +02:00
if (lomem) {
READ_STR(&store, NULL, 0);
2011-03-07 08:02:35 +01:00
} else {
READ_STR(&store, name, sizeof(name));
sh->display = _strdup(name);
2010-08-08 10:06:34 +02:00
}
READ_STR(&store, name, sizeof(name));
sh->type = st_find(name);
2011-03-07 08:02:35 +01:00
if (sh->type == NULL) {
2010-08-08 10:06:34 +02:00
/* old datafiles */
sh->type = st_find((const char *)locale_string(default_locale, name));
2010-08-08 10:06:34 +02:00
}
assert(sh->type || !"ship_type not registered!");
READ_INT(&store, &sh->size);
READ_INT(&store, &sh->damage);
if (gdata.version >= FOSS_VERSION) {
READ_UINT(&store, &sh->flags);
2010-08-08 10:06:34 +02:00
}
/* Attribute rekursiv einlesen */
READ_INT(&store, &n);
sh->coast = (direction_t)n;
2010-08-08 10:06:34 +02:00
if (sh->type->flags & SFL_NOCOAST) {
sh->coast = NODIRECTION;
}
a_read(&store, &sh->attribs, sh);
2010-08-08 10:06:34 +02:00
}
*shp = 0;
/* Einheiten */
READ_INT(&store, &p);
2010-08-08 10:06:34 +02:00
up = &r->units;
while (--p >= 0) {
unit *u = read_unit(&gdata);
2011-03-07 08:02:35 +01:00
sc_mage *mage;
assert(u->region == NULL);
2010-08-08 10:06:34 +02:00
u->region = r;
*up = u;
up = &u->next;
update_interval(u->faction, u->region);
mage = get_mage(u);
if (mage) {
2011-03-07 08:02:35 +01:00
faction *f = u->faction;
2010-08-08 10:06:34 +02:00
int skl = effskill(u, SK_MAGIC);
2011-03-07 08:02:35 +01:00
if (!is_monsters(f) && f->magiegebiet == M_GRAY) {
log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]);
2010-08-08 10:06:34 +02:00
f->magiegebiet = mage->magietyp;
}
2011-03-07 08:02:35 +01:00
if (f->max_spelllevel < skl) {
2010-08-08 10:06:34 +02:00
f->max_spelllevel = skl;
}
2011-03-07 08:02:35 +01:00
if (mage->spellcount < 0) {
2010-08-08 10:06:34 +02:00
mage->spellcount = 0;
}
}
}
}
2012-05-16 07:21:59 +02:00
log_printf(stdout, "\n");
read_borders(&store);
2010-08-08 10:06:34 +02:00
binstore_done(&store);
2010-08-08 10:06:34 +02:00
/* Unaufgeloeste Zeiger initialisieren */
2012-05-16 07:21:59 +02:00
log_printf(stdout, "fixing unresolved references.\n");
2010-08-08 10:06:34 +02:00
resolve();
2012-05-16 07:21:59 +02:00
log_printf(stdout, "updating area information for lighthouses.\n");
2011-03-07 08:02:35 +01:00
for (r = regions; r; r = r->next) {
2010-08-08 10:06:34 +02:00
if (r->flags & RF_LIGHTHOUSE) {
2011-03-07 08:02:35 +01:00
building *b;
for (b = r->buildings; b; b = b->next)
update_lighthouse(b);
2010-08-08 10:06:34 +02:00
}
}
2012-05-16 07:21:59 +02:00
log_printf(stdout, "marking factions as alive.\n");
2010-08-08 10:06:34 +02:00
for (f = factions; f; f = f->next) {
if (f->flags & FFL_NPC) {
f->alive = 1;
2011-03-07 08:02:35 +01:00
if (f->no == 0) {
int no = 666;
while (findfaction(no))
++no;
log_warning("renum(monsters, %d)\n", no);
2010-08-08 10:06:34 +02:00
renumber_faction(f, no);
}
} else {
for (u = f->units; u; u = u->nextF) {
2011-03-07 08:02:35 +01:00
if (u->number > 0) {
2010-08-08 10:06:34 +02:00
f->alive = 1;
break;
}
}
}
}
2011-03-07 08:02:35 +01:00
if (loadplane || maxregions >= 0) {
2010-08-08 10:06:34 +02:00
remove_empty_factions();
}
2012-05-16 07:21:59 +02:00
log_printf(stdout, "Done loading turn %d.\n", turn);
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
static void clear_monster_orders(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f = get_monsters();
2010-08-08 10:06:34 +02:00
if (f) {
2011-03-07 08:02:35 +01:00
unit *u;
for (u = f->units; u; u = u->nextF) {
2010-08-08 10:06:34 +02:00
free_orders(&u->orders);
}
}
}
int writegame(const char *filename)
2010-08-08 10:06:34 +02:00
{
char *base;
int n;
faction *f;
region *r;
building *b;
ship *sh;
unit *u;
plane *pl;
char path[MAX_PATH];
gamedata gdata;
storage store;
FILE *F;
2010-08-08 10:06:34 +02:00
clear_monster_orders();
sprintf(path, "%s/%s", datapath(), filename);
#ifdef HAVE_UNISTD_H
if (access(path, R_OK) == 0) {
/* make sure we don't overwrite some hardlinkedfile */
unlink(path);
}
#endif
F = fopen(path, "wb");
if (!F) {
/* we might be missing the directory, let's try creating it */
int err = _mkdir(datapath());
if (err) return err;
F = fopen(path, "wb");
if (!F) {
perror(path);
return -1;
}
2010-08-08 10:06:34 +02:00
}
gdata.store = &store;
gdata.encoding = enc_gamedata;
gdata.version = RELEASE_VERSION;
n = STREAM_VERSION;
fwrite(&gdata.version, sizeof(int), 1, F);
fwrite(&n, sizeof(int), 1, F);
binstore_init(&store, F);
2010-08-08 10:06:34 +02:00
/* globale Variablen */
base = strrchr(game_name, '/');
if (base) {
WRITE_STR(&store, base + 1);
2010-08-08 10:06:34 +02:00
} else {
WRITE_STR(&store, game_name);
2010-08-08 10:06:34 +02:00
}
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
a_write(&store, global.attribs, NULL);
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
WRITE_INT(&store, turn);
WRITE_INT(&store, 0 /*max_unique_id */ );
WRITE_INT(&store, nextborder);
2010-08-08 10:06:34 +02:00
/* Write planes */
WRITE_SECTION(&store);
WRITE_INT(&store, listlen(planes));
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
for (pl = planes; pl; pl = pl->next) {
watcher *w;
WRITE_INT(&store, pl->id);
WRITE_STR(&store, pl->name);
WRITE_INT(&store, pl->minx);
WRITE_INT(&store, pl->maxx);
WRITE_INT(&store, pl->miny);
WRITE_INT(&store, pl->maxy);
WRITE_INT(&store, pl->flags);
2010-08-08 10:06:34 +02:00
w = pl->watchers;
while (w) {
if (w->faction) {
write_faction_reference(w->faction, &store);
WRITE_INT(&store, w->mode);
2010-08-08 10:06:34 +02:00
}
w = w->next;
}
write_faction_reference(NULL, &store); /* mark the end of the list */
a_write(&store, pl->attribs, pl);
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
}
/* Write factions */
#if RELEASE_VERSION>=ALLIANCES_VERSION
write_alliances(&gdata);
2010-08-08 10:06:34 +02:00
#endif
n = listlen(factions);
WRITE_INT(&store, n);
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Schreibe %d Parteien...\n", n);
2010-08-08 10:06:34 +02:00
for (f = factions; f; f = f->next) {
writefaction(&gdata, f);
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
}
/* Write regions */
2011-03-07 08:02:35 +01:00
n = listlen(regions);
WRITE_INT(&store, n);
WRITE_SECTION(&store);
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Schreibe Regionen: %d \r", n);
2010-08-08 10:06:34 +02:00
for (r = regions; r; r = r->next, --n) {
/* plus leerzeile */
2011-03-07 08:02:35 +01:00
if ((n % 1024) == 0) { /* das spart extrem Zeit */
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - Schreibe Regionen: %d \r", n);
2010-08-08 10:06:34 +02:00
fflush(stdout);
}
WRITE_SECTION(&store);
WRITE_INT(&store, r->x);
WRITE_INT(&store, r->y);
writeregion(&gdata, r);
2010-08-08 10:06:34 +02:00
WRITE_INT(&store, listlen(r->buildings));
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
for (b = r->buildings; b; b = b->next) {
write_building_reference(b, &store);
WRITE_STR(&store, b->name);
WRITE_STR(&store, b->display ? b->display : "");
WRITE_INT(&store, b->size);
WRITE_TOK(&store, b->type->_name);
WRITE_SECTION(&store);
a_write(&store, b->attribs, b);
WRITE_SECTION(&store);
}
WRITE_INT(&store, listlen(r->ships));
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
for (sh = r->ships; sh; sh = sh->next) {
assert(sh->region == r);
write_ship_reference(sh, &store);
WRITE_STR(&store, (const char *)sh->name);
WRITE_STR(&store, sh->display ? (const char *)sh->display : "");
WRITE_TOK(&store, sh->type->name[0]);
WRITE_INT(&store, sh->size);
WRITE_INT(&store, sh->damage);
WRITE_INT(&store, sh->flags & SFL_SAVEMASK);
2011-03-07 08:02:35 +01:00
assert((sh->type->flags & SFL_NOCOAST) == 0 || sh->coast == NODIRECTION);
WRITE_INT(&store, sh->coast);
WRITE_SECTION(&store);
a_write(&store, sh->attribs, sh);
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
}
WRITE_INT(&store, listlen(r->units));
WRITE_SECTION(&store);
2010-08-08 10:06:34 +02:00
for (u = r->units; u; u = u->next) {
write_unit(&gdata, u);
2010-08-08 10:06:34 +02:00
}
}
WRITE_SECTION(&store);
write_borders(&store);
WRITE_SECTION(&store);
2011-03-07 08:02:35 +01:00
binstore_done(&store);
2010-08-08 10:06:34 +02:00
2012-05-16 07:21:59 +02:00
log_printf(stdout, "\nOk.\n");
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
int a_readint(attrib * a, void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
/* assert(sizeof(int)==sizeof(a->data)); */
READ_INT(store, &a->data.i);
2010-08-08 10:06:34 +02:00
return AT_READ_OK;
}
2011-03-07 08:02:35 +01:00
void a_writeint(const attrib * a, const void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
WRITE_INT(store, a->data.i);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int a_readshorts(attrib * a, void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
int n;
if (global.data_version < ATTRIBREAD_VERSION) {
2010-08-08 10:06:34 +02:00
return a_readint(a, store, owner);
}
READ_INT(store, &n);
a->data.sa[0] = (short)n;
READ_INT(store, &n);
a->data.sa[1] = (short)n;
2010-08-08 10:06:34 +02:00
return AT_READ_OK;
}
2011-03-07 08:02:35 +01:00
void a_writeshorts(const attrib * a, const void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
WRITE_INT(store, a->data.sa[0]);
WRITE_INT(store, a->data.sa[1]);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int a_readchars(attrib * a, void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
int i;
if (global.data_version < ATTRIBREAD_VERSION) {
2010-08-08 10:06:34 +02:00
return a_readint(a, store, owner);
}
2011-03-07 08:02:35 +01:00
for (i = 0; i != 4; ++i) {
int n;
READ_INT(store, &n);
a->data.ca[i] = (char)n;
2010-08-08 10:06:34 +02:00
}
return AT_READ_OK;
}
2011-03-07 08:02:35 +01:00
void a_writechars(const attrib * a, const void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
int i;
2011-03-07 08:02:35 +01:00
for (i = 0; i != 4; ++i) {
WRITE_INT(store, a->data.ca[i]);
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
int a_readvoid(attrib * a, void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
if (global.data_version < ATTRIBREAD_VERSION) {
2010-08-08 10:06:34 +02:00
return a_readint(a, store, owner);
}
return AT_READ_OK;
}
2011-03-07 08:02:35 +01:00
void a_writevoid(const attrib * a, const void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
}
2011-03-07 08:02:35 +01:00
int a_readstring(attrib * a, void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
char buf[DISPLAYSIZE];
char * result = 0;
int e;
size_t len = 0;
do {
e = READ_STR(store, buf, sizeof(buf));
if (result) {
result = realloc(result, len + DISPLAYSIZE - 1);
strcpy(result + len, buf);
len += DISPLAYSIZE - 1;
}
else {
result = _strdup(buf);
}
} while (e == ENOMEM);
a->data.v = result;
2010-08-08 10:06:34 +02:00
return AT_READ_OK;
}
2011-03-07 08:02:35 +01:00
void a_writestring(const attrib * a, const void *owner, struct storage *store)
2010-08-08 10:06:34 +02:00
{
assert(a->data.v);
WRITE_STR(store, (const char *)a->data.v);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void a_finalizestring(attrib * a)
2010-08-08 10:06:34 +02:00
{
free(a->data.v);
}