2015-07-06 19:53:09 +02:00
/*
2015-01-30 22:10:29 +01:00
Copyright ( c ) 1998 - 2015 , Enno Rehling < enno @ eressea . de >
2014-07-23 11:54:51 +02:00
Katja Zedel < katze @ felidae . kn - bremen . de
Christian Schlittchen < corwin @ amber . kn - bremen . de >
2010-08-08 10:06:34 +02:00
Permission to use , copy , modify , and / or distribute this software for any
purpose with or without fee is hereby granted , provided that the above
copyright notice and this permission notice appear in all copies .
THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
* */
# include <platform.h>
# include <kernel/config.h>
# include "save.h"
2014-11-01 12:09:56 +01:00
# include "../buildno.h"
2014-08-14 05:06:36 +02:00
2010-08-08 10:06:34 +02:00
# include "alchemy.h"
# include "alliance.h"
2012-06-30 20:07:28 +02:00
# 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"
2014-06-09 18:54:48 +02:00
# include "messages.h"
2010-08-08 10:06:34 +02:00
# include "move.h"
# include "objtypes.h"
# include "order.h"
# include "pathfinder.h"
# include "plane.h"
# include "race.h"
# include "region.h"
# include "resources.h"
# include "ship.h"
# include "skill.h"
# include "spell.h"
2012-05-24 09:56:54 +02:00
# 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"
2014-12-17 17:22:26 +01:00
# include "lighthouse.h"
2010-08-08 10:06:34 +02:00
# include "version.h"
/* attributes includes */
# include <attributes/key.h>
2012-04-08 03:11:58 +02:00
# 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/parser.h>
2012-05-31 04:55:17 +02:00
# include <quicklist.h>
2010-08-08 10:06:34 +02:00
# include <util/rand.h>
# include <util/resolve.h>
# include <util/rng.h>
# include <util/umlaut.h>
# include <util/unicode.h>
2014-11-03 22:29:04 +01:00
# include <stream.h>
# include <filestream.h>
2013-12-31 10:06:28 +01:00
# include <storage.h>
# include <binarystore.h>
2010-08-08 10:06:34 +02:00
/* libc includes */
# include <string.h>
2013-12-31 10:25:25 +01:00
# 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 */
int firstx = 0 , firsty = 0 ;
2014-06-10 05:14:08 +02:00
int enc_gamedata = ENCODING_UTF8 ;
2010-08-08 10:06:34 +02:00
/* 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
{
2014-07-23 11:54:51 +02:00
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 ;
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
{
2014-07-23 11:54:51 +02:00
int i ;
unit * u ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
if ( ! f )
return NULL ;
i = getid ( ) ;
u = findunitg ( i , NULL ) ;
if ( u & & u_race ( u ) = = get_race ( RC_SPELL ) )
return NULL ;
if ( u & & u - > faction = = f ) {
order * * ordp ;
if ( ! fval ( u , UFL_ORDERS ) ) {
/* alle wiederholbaren, langen befehle werden gesichert: */
fset ( u , UFL_ORDERS ) ;
u - > old_orders = u - > orders ;
ordp = & u - > old_orders ;
while ( * ordp ) {
order * ord = * ordp ;
if ( ! is_repeated ( ord ) ) {
* ordp = ord - > next ;
ord - > next = NULL ;
free_order ( ord ) ;
}
else {
ordp = & ord - > next ;
}
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
}
2014-07-23 11:54:51 +02:00
else {
free_orders ( & u - > orders ) ;
2012-05-19 08:57:20 +02:00
}
2014-07-23 11:54:51 +02:00
u - > orders = 0 ;
ordp = & u - > orders ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
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 */
s = getbuf ( F , enc ) ;
if ( s = = NULL )
break ;
if ( s [ 0 ] ) {
if ( s [ 0 ] ! = ' @ ' ) {
2015-01-04 15:42:36 +01:00
char token [ 128 ] ;
2014-07-23 11:54:51 +02:00
const char * stok = s ;
2015-01-04 15:42:36 +01:00
stok = parse_token ( & stok , token , sizeof ( token ) ) ;
2014-07-23 11:54:51 +02:00
if ( stok ) {
bool quit = false ;
param_t param = findparam ( stok , u - > faction - > locale ) ;
switch ( param ) {
case P_UNIT :
case P_REGION :
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 :
break ;
}
if ( quit ) {
break ;
}
}
}
2015-07-06 19:53:09 +02:00
/* Nun wird der Befehl erzeut und eingehängt */
2014-07-23 11:54:51 +02:00
* ordp = parse_order ( s , u - > faction - > locale ) ;
if ( * ordp ) {
ordp = & ( * ordp ) - > next ;
}
}
}
}
else {
/* cmistake(?, buf, 160, MSG_EVENT); */
return NULL ;
}
return u ;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static faction * factionorders ( void )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
faction * f = NULL ;
int fid = getid ( ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
f = findfaction ( fid ) ;
2011-03-07 08:02:35 +01:00
2014-11-11 16:53:56 +01:00
if ( f ! = NULL & & ! fval ( f , FFL_NPC ) ) {
2014-12-22 14:30:04 +01:00
char token [ 128 ] ;
2014-12-22 16:28:17 +01:00
const char * pass = gettoken ( token , sizeof ( token ) ) ;
2010-08-08 10:06:34 +02:00
2014-12-22 14:30:04 +01:00
if ( ! checkpasswd ( f , ( const char * ) pass ) ) {
2014-07-23 11:54:51 +02:00
log_debug ( " Invalid password for faction %s \n " , itoa36 ( fid ) ) ;
ADDMSG ( & f - > msgs , msg_message ( " wrongpasswd " , " faction password " ,
f - > no , pass ) ) ;
return 0 ;
}
2015-07-06 19:53:09 +02:00
/* Die Partei hat sich zumindest gemeldet, so daß sie noch
* nicht als untätig gilt */
2011-03-07 08:02:35 +01:00
2014-07-23 11:54:51 +02:00
/* TODO: +1 ist ein Workaround, weil cturn erst in process_orders
* incrementiert wird . */
f - > lastorders = global . data_turn + 1 ;
2011-03-07 08:02:35 +01:00
2014-07-23 11:54:51 +02:00
}
else {
2014-08-24 22:54:40 +02:00
log_debug ( " orders for invalid faction %s \n " , itoa36 ( fid ) ) ;
2014-07-23 11:54:51 +02:00
}
return f ;
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
{
2014-07-23 11:54:51 +02:00
FILE * F = NULL ;
const char * b ;
int nfactions = 0 ;
struct faction * f = NULL ;
F = fopen ( filename , " rb " ) ;
if ( ! F ) {
perror ( filename ) ;
return - 1 ;
}
2014-08-11 12:02:16 +02:00
log_info ( " reading orders from %s " , filename ) ;
2014-07-23 11:54:51 +02:00
/* TODO: recognize UTF8 BOM */
b = getbuf ( F , enc_gamedata ) ;
/* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten
* Partei */
while ( b ) {
2014-12-22 14:21:24 +01:00
char token [ 128 ] ;
2014-07-23 11:54:51 +02:00
const struct locale * lang = f ? f - > locale : default_locale ;
2014-12-18 17:47:49 +01:00
param_t p ;
const char * s ;
2014-12-22 14:21:24 +01:00
init_tokens_str ( b ) ;
2014-12-22 16:28:17 +01:00
s = gettoken ( token , sizeof ( token ) ) ;
2014-12-28 22:07:53 +01:00
p = ( s & & s [ 0 ] ! = ' @ ' ) ? findparam ( s , lang ) : NOPARAM ;
2014-12-18 17:47:49 +01:00
switch ( p ) {
2014-07-23 11:54:51 +02:00
case P_GAMENAME :
case P_FACTION :
f = factionorders ( ) ;
if ( f ) {
+ + nfactions ;
}
b = getbuf ( F , enc_gamedata ) ;
break ;
/* in factionorders wird nur eine zeile gelesen:
* diejenige mit dem passwort . Die befehle der units
* werden geloescht , und die Partei wird als aktiv
* vermerkt . */
case P_UNIT :
if ( ! f | | ! unitorders ( F , enc_gamedata , f ) )
do {
2014-12-18 17:47:49 +01:00
b = getbuf ( F , enc_gamedata ) ;
if ( ! b ) {
break ;
}
2014-12-22 14:21:24 +01:00
init_tokens_str ( b ) ;
2014-12-28 22:07:53 +01:00
s = gettoken ( token , sizeof ( token ) ) ;
p = ( s & & s [ 0 ] ! = ' @ ' ) ? findparam ( s , lang ) : NOPARAM ;
2014-07-23 11:54:51 +02:00
} while ( ( p ! = P_UNIT | | ! f ) & & p ! = P_FACTION & & p ! = P_NEXT
& & p ! = P_GAMENAME ) ;
break ;
/* 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
2015-07-06 19:53:09 +02:00
* auf alle Fälle nicht ü berschreiben ! Bei allen anderen Einträgen hier
* muß buf erneut gefüllt werden , da die betreffende Information in nur
* einer Zeile steht , und nun die nächste gelesen werden muß . */
2014-07-23 11:54:51 +02:00
case P_NEXT :
f = NULL ;
b = getbuf ( F , enc_gamedata ) ;
break ;
default :
b = getbuf ( F , enc_gamedata ) ;
2011-03-08 08:44:20 +01:00
break ;
2014-07-23 11:54:51 +02:00
}
}
fclose ( F ) ;
2014-08-11 12:02:16 +02:00
log_info ( " done reading orders for %d factions " , nfactions ) ;
2014-07-23 11:54:51 +02:00
return 0 ;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ------------------------------------------------------------- */
/* #define INNER_WORLD */
2015-07-06 19:53:09 +02:00
/* fürs debuggen nur den inneren Teil der Welt laden */
2010-08-08 10:06:34 +02:00
/* -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
{
2014-07-23 11:54:51 +02:00
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 ;
2010-08-08 10:06:34 +02:00
}
int maxregions = - 1 ;
int loadplane = 0 ;
enum {
2014-07-23 11:54:51 +02:00
U_MAN ,
U_UNDEAD ,
U_ILLUSION ,
U_FIREDRAGON ,
U_DRAGON ,
U_WYRM ,
U_SPELL ,
U_TAVERNE ,
U_MONSTER ,
U_BIRTHDAYDRAGON ,
U_TREEMAN ,
MAXTYPES
2010-08-08 10:06:34 +02:00
} ;
2011-03-07 08:02:35 +01:00
race_t typus2race ( unsigned char typus )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
if ( typus > 0 & & typus < = 11 )
return ( race_t ) ( typus - 1 ) ;
return NORACE ;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void create_backup ( char * file )
2010-08-08 10:06:34 +02:00
{
# ifdef HAVE_LINK
2014-07-23 11:54:51 +02:00
char bfile [ MAX_PATH ] ;
int c = 1 ;
if ( access ( file , R_OK ) = = 0 )
return ;
do {
sprintf ( bfile , " %s.backup%d " , file , c ) ;
c + + ;
} while ( access ( bfile , R_OK ) = = 0 ) ;
link ( file , bfile ) ;
2010-08-08 10:06:34 +02:00
# 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
{
2014-05-25 05:35:00 +02:00
for ( ; ; ) {
char ibuf [ 32 ] ;
2014-12-12 11:28:37 +01:00
const item_type * itype ;
2014-05-25 05:35:00 +02:00
int i ;
READ_STR ( store , ibuf , sizeof ( ibuf ) ) ;
if ( ! strcmp ( " end " , ibuf ) ) {
break ;
}
2014-12-12 11:28:37 +01:00
itype = it_find ( ibuf ) ;
2014-05-25 05:35:00 +02:00
READ_INT ( store , & i ) ;
if ( i < = 0 ) {
2014-12-12 11:28:37 +01:00
log_error ( " data contains an entry with %d %s \n " , i , resourcename ( itype - > rtype , NMF_PLURAL ) ) ;
2014-07-23 11:54:51 +02:00
}
else {
2014-12-12 11:28:37 +01:00
if ( itype & & itype - > rtype ) {
i_change ( ilist , itype , i ) ;
2014-07-23 11:54:51 +02:00
}
else {
2014-05-25 05:35:00 +02:00
log_error ( " data contains unknown item type %s. \n " , ibuf ) ;
}
2014-12-12 11:28:37 +01:00
assert ( itype & & itype - > rtype ) ;
2014-05-25 05:35:00 +02:00
}
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
static void read_alliances ( struct storage * store )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
char pbuf [ 8 ] ;
int id , terminator = 0 ;
if ( global . data_version < ALLIANCELEADER_VERSION ) {
terminator = atoi36 ( " end " ) ;
READ_STR ( store , pbuf , sizeof ( pbuf ) ) ;
id = atoi36 ( pbuf ) ;
}
else {
READ_INT ( store , & id ) ;
}
while ( id ! = terminator ) {
char aname [ 128 ] ;
alliance * al ;
READ_STR ( store , aname , sizeof ( aname ) ) ;
al = makealliance ( id , aname ) ;
if ( global . data_version > = OWNER_2_VERSION ) {
READ_INT ( store , & al - > flags ) ;
}
if ( global . data_version > = ALLIANCELEADER_VERSION ) {
read_reference ( & al - > _leader , store , read_faction_reference ,
resolve_faction ) ;
READ_INT ( store , & id ) ;
}
else {
READ_STR ( store , pbuf , sizeof ( pbuf ) ) ;
id = atoi36 ( pbuf ) ;
}
}
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
void write_alliances ( struct gamedata * data )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
alliance * al = alliances ;
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 ) ;
}
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
{
2014-07-23 11:54:51 +02:00
item * itm ;
for ( itm = ilist ; itm ; itm = itm - > next ) {
assert ( itm - > number > = 0 ) ;
if ( itm - > number ) {
WRITE_TOK ( store , resourcename ( itm - > type - > rtype , 0 ) ) ;
WRITE_INT ( store , itm - > number ) ;
}
}
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
{
2014-07-23 11:54:51 +02:00
region_owner * owner = ( region_owner * ) address ;
int result = 0 ;
faction * f = NULL ;
if ( id . i ! = 0 ) {
f = findfaction ( id . i ) ;
if ( f = = NULL ) {
log_error ( " region has an invalid owner (%s) \n " , itoa36 ( id . i ) ) ;
}
}
owner - > owner = f ;
if ( f ) {
owner - > alliance = f - > alliance ;
}
return result ;
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
static void read_owner ( struct gamedata * data , region_owner * * powner )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
int since_turn ;
READ_INT ( data - > store , & since_turn ) ;
if ( since_turn > = 0 ) {
region_owner * owner = malloc ( sizeof ( region_owner ) ) ;
owner - > since_turn = since_turn ;
READ_INT ( data - > store , & owner - > morale_turn ) ;
if ( data - > version > = MOURNING_VERSION ) {
READ_INT ( data - > store , & owner - > flags ) ;
}
else {
owner - > flags = 0 ;
}
if ( data - > version > = OWNER_2_VERSION ) {
int id ;
READ_INT ( data - > store , & id ) ;
owner - > alliance = id ? findalliance ( id ) : NULL ;
}
else {
owner - > alliance = NULL ;
}
read_reference ( owner , data - > store , & read_faction_reference , & resolve_owner ) ;
* powner = owner ;
}
else {
* powner = 0 ;
}
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
static void write_owner ( struct gamedata * data , region_owner * owner )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +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 ) ;
}
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
{
2014-07-23 11:54:51 +02:00
char zText [ MAX_PATH ] ;
int cturn = 0 ;
FILE * F ;
sprintf ( zText , " %s/turn " , basepath ( ) ) ;
F = fopen ( zText , " r " ) ;
if ( ! F ) {
perror ( zText ) ;
}
else {
fscanf ( F , " %d \n " , & cturn ) ;
fclose ( F ) ;
}
return cturn ;
2010-08-08 10:06:34 +02:00
}
static void
2013-12-31 10:06:28 +01:00
writeorder ( struct gamedata * data , const struct order * ord ,
2014-07-23 11:54:51 +02:00
const struct locale * lang )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
char obuf [ 1024 ] ;
write_order ( ord , obuf , sizeof ( obuf ) ) ;
if ( obuf [ 0 ] )
WRITE_STR ( data - > store , obuf ) ;
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
unit * read_unit ( struct gamedata * data )
2010-08-08 10:06:34 +02:00
{
2014-05-25 05:25:06 +02:00
unit * u ;
int number , n , p ;
order * * orderp ;
char obuf [ DISPLAYSIZE ] ;
faction * f ;
char rname [ 32 ] ;
READ_INT ( data - > store , & n ) ;
if ( n < = 0 ) {
log_error ( " data contains invalid unit %d. \n " , n ) ;
2014-07-23 11:54:51 +02:00
assert ( n > 0 ) ;
2014-05-25 05:25:06 +02:00
return 0 ;
}
u = findunit ( n ) ;
if ( u ) {
log_error ( " reading unit %s that already exists. \n " , unitname ( u ) ) ;
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 ) ;
2014-07-23 11:54:51 +02:00
}
else {
2014-05-25 05:25:06 +02:00
u = calloc ( sizeof ( unit ) , 1 ) ;
u - > no = n ;
uhash ( u ) ;
}
2010-08-08 10:06:34 +02:00
2014-05-25 05:25:06 +02:00
READ_INT ( data - > store , & n ) ;
f = findfaction ( n ) ;
if ( f ! = u - > faction ) {
u_setfaction ( u , f ) ;
}
if ( u - > faction ) {
+ + u - > faction - > no_units ;
2014-07-23 11:54:51 +02:00
}
else {
2014-05-25 05:25:06 +02:00
log_error ( " unit %s has faction == NULL \n " , unitname ( u ) ) ;
assert ( u - > faction ) ;
return 0 ;
}
2010-08-08 10:06:34 +02:00
2013-12-31 10:06:28 +01:00
READ_STR ( data - > store , obuf , sizeof ( obuf ) ) ;
2015-06-12 18:05:56 +02:00
u - > _name = obuf [ 0 ] ? _strdup ( obuf ) : 0 ;
2014-07-23 11:54:51 +02:00
if ( lomem ) {
READ_STR ( data - > store , NULL , 0 ) ;
}
else {
READ_STR ( data - > store , obuf , sizeof ( obuf ) ) ;
2015-06-12 18:05:56 +02:00
u - > display = obuf [ 0 ] ? _strdup ( obuf ) : 0 ;
2014-07-23 11:54:51 +02:00
}
READ_INT ( data - > store , & number ) ;
2014-05-25 05:25:06 +02:00
set_number ( u , number ) ;
2014-07-23 11:54:51 +02:00
READ_INT ( data - > store , & n ) ;
u - > age = ( short ) n ;
2014-12-12 22:52:23 +01:00
READ_TOK ( data - > store , rname , sizeof ( rname ) ) ;
2014-07-23 11:54:51 +02:00
u_setrace ( u , rc_find ( rname ) ) ;
2014-12-12 22:52:23 +01:00
READ_TOK ( data - > store , rname , sizeof ( rname ) ) ;
2014-07-23 11:54:51 +02:00
if ( rname [ 0 ] & & skill_enabled ( SK_STEALTH ) )
u - > irace = rc_find ( rname ) ;
else
u - > irace = NULL ;
if ( u_race ( u ) - > describe ) {
const char * rcdisp = u_race ( u ) - > describe ( u , u - > faction - > locale ) ;
if ( u - > display & & rcdisp ) {
/* see if the data file contains old descriptions */
if ( strcmp ( rcdisp , u - > display ) = = 0 ) {
free ( u - > display ) ;
u - > display = NULL ;
}
2010-08-08 10:06:34 +02:00
}
}
2014-07-23 11:54:51 +02:00
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 ) ) ;
}
}
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 ) ) ;
}
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
READ_INT ( data - > store , & n ) ;
2014-07-23 11:54:51 +02:00
setstatus ( u , n ) ;
READ_INT ( data - > store , & u - > flags ) ;
u - > flags & = UFL_SAVEMASK ;
if ( ( u - > flags & UFL_ANON_FACTION ) & & ! rule_stealth_faction ( ) ) {
/* if this rule is broken, then fix broken units */
u - > flags - = UFL_ANON_FACTION ;
log_warning ( " %s was anonymous. \n " , unitname ( u ) ) ;
}
/* Persistente Befehle einlesen */
free_orders ( & u - > orders ) ;
READ_STR ( data - > store , obuf , sizeof ( obuf ) ) ;
p = n = 0 ;
orderp = & u - > orders ;
while ( obuf [ 0 ] ) {
if ( ! lomem ) {
order * ord = parse_order ( obuf , u - > faction - > locale ) ;
if ( ord ! = NULL ) {
if ( + + n < MAXORDERS ) {
if ( ! is_persistent ( ord ) | | + + p < MAXPERSISTENT ) {
* orderp = ord ;
orderp = & ord - > next ;
ord = NULL ;
}
else if ( p = = MAXPERSISTENT ) {
log_warning ( " %s had %d or more persistent orders \n " , unitname ( u ) , MAXPERSISTENT ) ;
}
}
else if ( n = = MAXORDERS ) {
log_warning ( " %s had %d or more orders \n " , unitname ( u ) , MAXORDERS ) ;
}
if ( ord ! = NULL )
free_order ( ord ) ;
}
}
READ_STR ( data - > store , obuf , sizeof ( obuf ) ) ;
}
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 ) ;
if ( level ) {
skill * sv = add_skill ( u , sk ) ;
sv - > level = sv - > old = ( unsigned char ) level ;
sv - > weeks = ( unsigned char ) weeks ;
}
}
read_items ( data - > store , & u - > items ) ;
READ_INT ( data - > store , & u - > hp ) ;
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 ;
}
a_read ( data - > store , & u - > attribs , u ) ;
return u ;
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
void write_unit ( struct gamedata * data , const unit * u )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
order * ord ;
int i , p = 0 ;
unsigned int flags = u - > flags & UFL_SAVEMASK ;
const race * irace = u_irace ( u ) ;
write_unit_reference ( u , data - > store ) ;
write_faction_reference ( u - > faction , data - > store ) ;
2015-02-11 07:55:35 +01:00
WRITE_STR ( data - > store , u - > _name ) ;
WRITE_STR ( data - > store , u - > display ? u - > display : " " ) ;
2014-07-23 11:54:51 +02:00
WRITE_INT ( data - > store , u - > number ) ;
WRITE_INT ( data - > store , u - > age ) ;
2014-08-24 21:49:55 +02:00
WRITE_TOK ( data - > store , u_race ( u ) - > _name ) ;
WRITE_TOK ( data - > store , ( irace & & irace ! = u_race ( u ) ) ? irace - > _name : " " ) ;
2014-07-23 11:54:51 +02:00
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 ) ;
for ( ord = u - > old_orders ; ord ; ord = ord - > next ) {
if ( + + p < MAXPERSISTENT ) {
writeorder ( data , ord , u - > faction - > locale ) ;
}
else {
log_warning ( " %s had %d or more persistent orders \n " , unitname ( u ) , MAXPERSISTENT ) ;
break ;
}
}
for ( ord = u - > orders ; ord ; ord = ord - > next ) {
if ( u - > old_orders & & is_repeated ( ord ) )
continue ; /* has new defaults */
if ( is_persistent ( ord ) ) {
if ( + + p < MAXPERSISTENT ) {
writeorder ( data , ord , u - > faction - > locale ) ;
}
else {
log_warning ( " %s had %d or more persistent orders \n " , unitname ( u ) , MAXPERSISTENT ) ;
break ;
}
}
}
/* write an empty string to terminate the list */
WRITE_STR ( data - > store , " " ) ;
WRITE_SECTION ( data - > store ) ;
assert ( u_race ( u ) ) ;
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 ) ;
}
}
WRITE_INT ( data - > store , - 1 ) ;
WRITE_SECTION ( data - > store ) ;
write_items ( data - > store , u - > items ) ;
WRITE_SECTION ( data - > store ) ;
if ( u - > hp = = 0 ) {
log_error ( " unit %s has 0 hitpoints, adjusting. \n " , itoa36 ( u - > no ) ) ;
( ( unit * ) u ) - > hp = u - > number ;
}
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
}
2013-12-31 10:06:28 +01:00
static region * readregion ( struct gamedata * data , int x , int y )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
region * r = findregion ( x , y ) ;
const terrain_type * terrain ;
2014-12-12 22:52:23 +01:00
char name [ NAMESIZE ] ;
2014-07-23 11:54:51 +02:00
int uid = 0 ;
int n ;
2014-12-12 22:52:23 +01:00
READ_INT ( data - > store , & uid ) ;
2014-07-23 11:54:51 +02:00
if ( r = = NULL ) {
plane * pl = findplane ( x , y ) ;
r = new_region ( x , y , pl , uid ) ;
}
else {
assert ( uid = = 0 | | r - > uid = = uid ) ;
current_region = r ;
while ( r - > attribs )
a_remove ( & r - > attribs , r - > attribs ) ;
if ( r - > land ) {
free ( r - > land ) ; /* mem leak */
r - > land - > demands = 0 ; /* mem leak */
}
while ( r - > resources ) {
rawmaterial * rm = r - > resources ;
r - > resources = rm - > next ;
free ( rm ) ;
}
r - > land = 0 ;
}
if ( lomem ) {
READ_STR ( data - > store , NULL , 0 ) ;
}
else {
char info [ DISPLAYSIZE ] ;
READ_STR ( data - > store , info , sizeof ( info ) ) ;
region_setinfo ( r , info ) ;
}
2014-12-12 22:52:23 +01:00
READ_STR ( data - > store , name , sizeof ( name ) ) ;
terrain = get_terrain ( name ) ;
if ( terrain = = NULL ) {
log_error ( " Unknown terrain '%s' \n " , name ) ;
assert ( ! " unknown terrain " ) ;
2014-07-23 11:54:51 +02:00
}
r - > terrain = terrain ;
READ_INT ( data - > store , & r - > flags ) ;
2013-12-31 10:06:28 +01:00
READ_INT ( data - > store , & n ) ;
2014-07-23 11:54:51 +02:00
r - > age = ( unsigned short ) n ;
if ( fval ( r - > terrain , LAND_REGION ) ) {
r - > land = calloc ( 1 , sizeof ( land_region ) ) ;
READ_STR ( data - > store , name , sizeof ( name ) ) ;
r - > land - > name = _strdup ( name ) ;
}
if ( r - > land ) {
int i ;
rawmaterial * * pres = & r - > resources ;
READ_INT ( data - > store , & i ) ;
if ( i < 0 ) {
log_error ( " number of trees in %s is %d. \n " , regionname ( r , NULL ) , i ) ;
i = 0 ;
}
rsettrees ( r , 0 , i ) ;
READ_INT ( data - > store , & i ) ;
if ( i < 0 ) {
log_error ( " number of young trees in %s is %d. \n " , regionname ( r , NULL ) , i ) ;
i = 0 ;
}
rsettrees ( r , 1 , i ) ;
READ_INT ( data - > store , & i ) ;
if ( i < 0 ) {
log_error ( " number of seeds in %s is %d. \n " , regionname ( r , NULL ) , i ) ;
i = 0 ;
}
rsettrees ( r , 2 , i ) ;
READ_INT ( data - > store , & i ) ;
rsethorses ( r , i ) ;
assert ( * pres = = NULL ) ;
for ( ; ; ) {
rawmaterial * res ;
2014-12-12 22:52:23 +01:00
READ_STR ( data - > store , name , sizeof ( name ) ) ;
if ( strcmp ( name , " end " ) = = 0 )
2014-07-23 11:54:51 +02:00
break ;
res = malloc ( sizeof ( rawmaterial ) ) ;
2014-12-12 22:52:23 +01:00
res - > type = rmt_find ( name ) ;
2014-07-23 11:54:51 +02:00
if ( res - > type = = NULL ) {
2014-12-12 22:52:23 +01:00
log_error ( " invalid resourcetype %s in data. \n " , name ) ;
2014-07-23 11:54:51 +02:00
}
assert ( res - > type ! = NULL ) ;
READ_INT ( data - > store , & n ) ;
res - > level = n ;
READ_INT ( data - > store , & n ) ;
res - > amount = n ;
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 ;
* pres = res ;
pres = & res - > next ;
}
* pres = NULL ;
2014-12-12 22:52:23 +01:00
READ_STR ( data - > store , name , sizeof ( name ) ) ;
if ( strcmp ( name , " noherb " ) ! = 0 ) {
const resource_type * rtype = rt_find ( name ) ;
2014-07-23 11:54:51 +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
2014-07-23 11:54:51 +02:00
assert ( r - > terrain ! = NULL ) ;
assert ( rhorses ( r ) > = 0 ) ;
assert ( rpeasants ( r ) > = 0 ) ;
assert ( rmoney ( r ) > = 0 ) ;
2010-08-08 10:06:34 +02:00
2014-06-25 07:44:05 +02:00
if ( r - > land ) {
int n ;
for ( ; ; ) {
const struct resource_type * rtype ;
2014-12-12 22:52:23 +01:00
READ_STR ( data - > store , name , sizeof ( name ) ) ;
if ( ! strcmp ( name , " end " ) )
2014-06-25 07:44:05 +02:00
break ;
2014-12-12 22:52:23 +01:00
rtype = rt_find ( name ) ;
2014-06-25 07:44:05 +02:00
assert ( rtype & & rtype - > ltype ) ;
READ_INT ( data - > store , & n ) ;
r_setdemand ( r , rtype - > ltype , n ) ;
}
2014-12-12 22:52:23 +01:00
read_items ( data - > store , & r - > land - > items ) ;
2014-06-25 07:44:05 +02:00
if ( data - > version > = REGIONOWNER_VERSION ) {
READ_INT ( data - > store , & n ) ;
r - > land - > morale = ( short ) n ;
if ( r - > land - > morale < 0 ) {
r - > land - > morale = 0 ;
}
read_owner ( data , & r - > land - > ownership ) ;
}
2010-08-08 10:06:34 +02:00
}
2014-06-25 07:44:05 +02:00
a_read ( data - > store , & r - > attribs , r ) ;
return r ;
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
void writeregion ( struct gamedata * data , const region * r )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +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 ) ;
if ( fval ( r - > terrain , LAND_REGION ) ) {
const item_type * rht ;
struct demand * demand ;
rawmaterial * res = r - > resources ;
2015-07-06 19:53:09 +02:00
assert ( r - > land ) ;
2015-07-06 21:31:27 +02:00
WRITE_STR ( data - > store , ( const char * ) r - > land - > name ) ; //TODO: V595 http://www.viva64.com/en/V595 The 'r->land' pointer was utilized before it was verified against nullptr. Check lines: 993, 1023.
2014-07-23 11:54:51 +02: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 ) ) ;
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 ) ;
res = res - > next ;
}
WRITE_TOK ( data - > store , " end " ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
rht = rherbtype ( r ) ;
if ( rht ) {
WRITE_TOK ( data - > store , resourcename ( rht - > rtype , 0 ) ) ;
}
else {
WRITE_TOK ( data - > store , " noherb " ) ;
}
WRITE_INT ( data - > store , rherbs ( r ) ) ;
WRITE_INT ( data - > store , rpeasants ( r ) ) ;
WRITE_INT ( data - > store , rmoney ( r ) ) ;
2014-12-25 22:38:01 +01:00
if ( r - > land ) {
2014-07-23 11:54:51 +02:00
for ( demand = r - > land - > demands ; demand ; demand = demand - > next ) {
2014-12-18 17:47:49 +01:00
WRITE_TOK ( data - > store , resourcename ( demand - > type - > itype - > rtype , 0 ) ) ;
WRITE_INT ( data - > store , demand - > value ) ;
2014-07-23 11:54:51 +02:00
}
2014-12-25 22:38:01 +01:00
}
2014-07-23 11:54:51 +02:00
WRITE_TOK ( data - > store , " end " ) ;
write_items ( data - > store , r - > land - > items ) ;
WRITE_SECTION ( data - > store ) ;
2010-08-08 10:06:34 +02:00
# if RELEASE_VERSION>=REGIONOWNER_VERSION
2014-07-23 11:54:51 +02:00
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
2014-07-23 11:54:51 +02:00
}
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
{
2014-07-23 11:54:51 +02:00
struct faction * af = findfaction ( aid ) ;
ally * sf ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
state & = ~ HELP_OBSERVE ;
2010-08-08 10:06:34 +02:00
# ifndef REGIONOWNERS
2014-07-23 11:54:51 +02:00
state & = ~ HELP_TRAVEL ;
2010-08-08 10:06:34 +02:00
# endif
2014-07-23 11:54:51 +02:00
state & = HelpMask ( ) ;
if ( state = = 0 )
return sfp ;
2014-10-31 15:52:40 +01:00
while ( * sfp ) {
sfp = & ( * sfp ) - > next ;
}
2014-10-31 15:13:05 +01:00
sf = ally_add ( sfp , af ) ;
2014-07-23 11:54:51 +02:00
if ( ! sf - > faction ) {
variant id ;
id . i = aid ;
ur_add ( id , & sf - > faction , resolve_faction ) ;
}
sf - > status = state & HELP_ALL ;
return & sf - > next ;
2010-08-08 10:06:34 +02:00
}
2012-05-26 23:19:35 +02:00
int get_spell_level_faction ( const spell * sp , void * cbdata )
2012-05-24 09:56:54 +02:00
{
2014-07-23 11:54:51 +02:00
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 ;
2012-05-26 23:19:35 +02:00
}
2013-12-31 10:06:28 +01:00
void read_spellbook ( spellbook * * bookp , struct storage * store , int ( * get_level ) ( const spell * sp , void * ) , void * cbdata )
2012-05-26 23:19:35 +02:00
{
2014-07-23 11:54:51 +02:00
for ( ; ; ) {
spell * sp = 0 ;
char spname [ 64 ] ;
int level = 0 ;
2014-12-12 22:52:23 +01:00
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 ) ;
2014-07-23 11:54:51 +02:00
}
}
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 ;
}
2015-07-02 14:39:13 +02:00
if ( level > 0 & & ( global . data_version > = SPELLBOOK_VERSION | | ! spellbook_get ( sb , sp ) ) ) {
2014-07-23 11:54:51 +02:00
spellbook_add ( sb , sp , level ) ;
}
}
}
2012-05-24 09:56:54 +02:00
}
2012-05-25 07:26:05 +02:00
void write_spellbook ( const struct spellbook * book , struct storage * store )
2012-05-24 09:56:54 +02:00
{
2014-07-23 11:54:51 +02:00
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 ) ;
}
2012-05-24 09:56:54 +02:00
}
2014-07-23 11:54:51 +02:00
WRITE_TOK ( store , " end " ) ;
2012-05-24 09:56:54 +02:00
}
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 .
*/
2013-12-31 10:06:28 +01:00
faction * readfaction ( struct gamedata * data )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
ally * * sfp ;
int planes , n ;
faction * f ;
char name [ DISPLAYSIZE ] ;
READ_INT ( data - > store , & n ) ;
f = findfaction ( n ) ;
if ( f = = NULL ) {
f = ( faction * ) calloc ( 1 , sizeof ( faction ) ) ;
f - > no = n ;
}
else {
f - > allies = NULL ; /* mem leak */
while ( f - > attribs )
a_remove ( & f - > attribs , f - > attribs ) ;
}
READ_INT ( data - > store , & f - > subscription ) ;
if ( alliances | | data - > version > = OWNER_2_VERSION ) {
int allianceid ;
READ_INT ( data - > store , & allianceid ) ;
if ( allianceid > 0 )
f - > alliance = findalliance ( allianceid ) ;
if ( f - > alliance ) {
alliance * al = f - > alliance ;
if ( al - > flags & ALF_NON_ALLIED ) {
assert ( ! al - > members
| | ! " non-allied dummy-alliance has more than one member " ) ;
}
ql_push ( & al - > members , f ) ;
}
else if ( rule_region_owners ( ) ) {
/* compat fix for non-allied factions */
alliance * al = makealliance ( 0 , NULL ) ;
setalliance ( f , al ) ;
}
if ( data - > version > = OWNER_2_VERSION ) {
READ_INT ( data - > store , & f - > alliance_joindate ) ;
}
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 ) ;
log_printf ( stdout , " - Lese Partei %s (%s) \n " , f - > name , factionid ( f ) ) ;
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 ) ;
set_email ( & f - > email , " " ) ;
}
READ_STR ( data - > store , name , sizeof ( name ) ) ;
f - > passw = _strdup ( name ) ;
2014-08-14 05:06:36 +02:00
if ( data - > version < NOOVERRIDE_VERSION ) {
2014-07-23 11:54:51 +02:00
READ_STR ( data - > store , 0 , 0 ) ;
}
READ_STR ( data - > store , name , sizeof ( name ) ) ;
f - > locale = get_locale ( name ) ;
2014-11-23 21:15:09 +01:00
if ( ! f - > locale ) f - > locale = default_locale ;
2014-07-23 11:54:51 +02:00
READ_INT ( data - > store , & f - > lastorders ) ;
READ_INT ( data - > store , & f - > age ) ;
READ_STR ( data - > store , name , sizeof ( name ) ) ;
f - > race = rc_find ( name ) ;
2014-06-01 11:07:22 +02:00
if ( ! f - > race ) {
log_error ( " unknown race in data: %s \n " , name ) ;
}
assert ( f - > race ) ;
2013-12-31 10:06:28 +01:00
READ_INT ( data - > store , & n ) ;
2014-07-23 11:54:51 +02:00
f - > magiegebiet = ( magic_t ) n ;
if ( data - > version < FOSS_VERSION ) {
/* ignore karma */
READ_INT ( data - > store , & n ) ;
}
2010-08-08 10:06:34 +02:00
2014-05-10 18:57:04 +02:00
READ_INT ( data - > store , & f - > flags ) ;
if ( data - > version < INTFLAGS_VERSION ) {
2014-07-23 11:54:51 +02:00
if ( f - > no = = 0 | | f - > no = = 666 ) {
2014-10-16 07:46:08 +02:00
f - > flags = FFL_NPC | FFL_NOIDLEOUT ;
2014-05-10 18:57:04 +02:00
}
}
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
a_read ( data - > store , & f - > attribs , f ) ;
2014-12-12 23:00:30 +01:00
read_items ( data - > store , & f - > items ) ;
2010-08-08 10:06:34 +02:00
for ( ; ; ) {
2013-12-31 10:06:28 +01:00
READ_TOK ( data - > store , name , sizeof ( name ) ) ;
2014-07-23 11:54:51 +02:00
if ( strcmp ( " end " , name ) = = 0 )
break ;
READ_INT ( data - > store , & n ) ; /* there used to be a level here, which is now ignored */
}
READ_INT ( data - > store , & planes ) ;
while ( - - planes > = 0 ) {
int id , ux , uy ;
READ_INT ( data - > store , & id ) ;
READ_INT ( data - > store , & ux ) ;
READ_INT ( data - > store , & uy ) ;
2015-05-19 08:02:32 +02:00
faction_setorigin ( f , id , ux , uy ) ;
2014-07-23 11:54:51 +02:00
}
f - > newbies = 0 ;
READ_INT ( data - > store , & n ) ;
f - > options = n ;
2014-11-11 16:53:56 +01:00
n = want ( O_REPORT ) | want ( O_COMPUTER ) ;
if ( ( f - > options & n ) = = 0 ) {
2014-07-23 11:54:51 +02:00
/* Kein Report eingestellt, Fehler */
2014-11-11 16:53:56 +01:00
f - > options | = n ;
2014-07-23 11:54:51 +02:00
}
2015-03-29 14:03:56 +02:00
if ( data - > version < JSON_REPORT_VERSION ) {
/* mistakes were made in the past*/
f - > options & = ~ want ( O_JSON ) ;
}
2014-07-23 11:54:51 +02:00
sfp = & f - > allies ;
2014-12-12 23:00:30 +01:00
for ( ; ; ) {
int aid = 0 ;
READ_INT ( data - > store , & aid ) ;
if ( aid > 0 ) {
int state ;
2014-07-23 11:54:51 +02:00
READ_INT ( data - > store , & state ) ;
sfp = addally ( f , sfp , aid , state ) ;
}
2014-12-12 23:00:30 +01:00
else {
break ;
2014-07-23 11:54:51 +02:00
}
}
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 ) ;
}
return f ;
2010-08-08 10:06:34 +02:00
}
2013-12-31 10:06:28 +01:00
void writefaction ( struct gamedata * data , const faction * f )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
ally * sf ;
ursprung * ur ;
write_faction_reference ( f , data - > store ) ;
WRITE_INT ( data - > store , f - > subscription ) ;
if ( f - > alliance ) {
WRITE_INT ( data - > store , f - > alliance - > id ) ;
if ( f - > alliance - > flags & ALF_NON_ALLIED ) {
assert ( f = = f - > alliance - > _leader
| | ! " non-allied faction is not leader of its own dummy-alliance. " ) ;
}
}
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 , locale_name ( f - > locale ) ) ;
WRITE_INT ( data - > store , f - > lastorders ) ;
WRITE_INT ( data - > store , f - > age ) ;
2014-08-24 21:49:55 +02:00
WRITE_TOK ( data - > store , f - > race - > _name ) ;
2014-07-23 11:54:51 +02:00
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 ) ) ;
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 ) ;
}
WRITE_SECTION ( data - > store ) ;
WRITE_INT ( data - > store , f - > options & ~ want ( O_DEBUG ) ) ;
WRITE_SECTION ( data - > store ) ;
for ( sf = f - > allies ; sf ; sf = sf - > next ) {
int no = ( sf - > faction ! = NULL ) ? sf - > faction - > no : 0 ;
int status = alliedfaction ( NULL , f , sf - > faction , HELP_ALL ) ;
if ( status ! = 0 ) {
WRITE_INT ( data - > store , no ) ;
WRITE_INT ( data - > store , sf - > status ) ;
}
}
2013-12-31 10:06:28 +01:00
WRITE_INT ( data - > store , 0 ) ;
2014-07-23 11:54:51 +02:00
WRITE_SECTION ( data - > store ) ;
2014-11-03 18:10:05 +01:00
write_groups ( data - > store , f ) ;
2014-07-23 11:54:51 +02:00
write_spellbook ( f - > spellbook , data - > store ) ;
2010-08-08 10:06:34 +02:00
}
2015-05-13 02:18:51 +02:00
int readgame ( const char * filename , bool backup )
2010-08-08 10:06:34 +02:00
{
2014-12-12 22:52:23 +01:00
int n , p , nread ;
2014-07-23 11:54:51 +02:00
faction * f , * * fp ;
region * r ;
building * b , * * bp ;
ship * * shp ;
unit * u ;
int rmax = maxregions ;
char path [ MAX_PATH ] ;
char name [ DISPLAYSIZE ] ;
const struct building_type * bt_lighthouse = bt_find ( " lighthouse " ) ;
gamedata gdata = { 0 } ;
storage store ;
2014-11-03 22:29:04 +01:00
stream strm ;
2014-07-23 11:54:51 +02:00
FILE * F ;
2013-12-31 10:06:28 +01:00
2014-10-29 19:40:09 +01:00
init_locales ( ) ;
2014-07-23 11:54:51 +02:00
log_printf ( stdout , " - reading game data from %s \n " , filename ) ;
sprintf ( path , " %s/%s " , datapath ( ) , filename ) ;
if ( backup ) {
create_backup ( path ) ;
}
F = fopen ( path , " rb " ) ;
if ( ! F ) {
perror ( path ) ;
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 " ) ;
2015-04-19 08:13:40 +02:00
assert ( gdata . version < = MAX_VERSION | | ! " unsupported data format " ) ;
2014-07-23 11:54:51 +02:00
gdata . encoding = enc_gamedata ;
2014-11-03 22:29:04 +01:00
fstream_init ( & strm , F ) ;
binstore_init ( & store , & strm ) ;
2014-07-23 11:54:51 +02:00
gdata . store = & store ;
global . data_version = gdata . version ; /* HACK: attribute::read does not have access to gamedata, only storage */
2014-08-14 05:06:36 +02:00
if ( gdata . version > = BUILDNO_VERSION ) {
int build ;
READ_INT ( & store , & build ) ;
log_debug ( " data in %s created with build %d. " , filename , build ) ;
}
2014-07-23 11:54:51 +02:00
if ( gdata . version > = SAVEGAMEID_VERSION ) {
int gameid ;
READ_INT ( & store , & gameid ) ;
if ( gameid ! = game_id ( ) ) {
log_warning ( " game mismatch: datafile contains game %d, but config is for %d \n " , gameid , game_id ( ) ) ;
printf ( " WARNING: invalid game id. any key to continue, Ctrl-C to stop \n " ) ;
getchar ( ) ;
}
}
2014-12-12 23:00:30 +01:00
else {
READ_STR ( & store , NULL , 0 ) ;
2014-07-23 11:54:51 +02:00
}
a_read ( & store , & global . attribs , NULL ) ;
READ_INT ( & store , & turn ) ;
global . data_turn = turn ;
log_printf ( stdout , " - reading turn %d \n " , turn ) ;
rng_init ( turn ) ;
+ + global . cookie ;
READ_INT ( & store , & nread ) ; /* max_unique_id = ignore */
READ_INT ( & store , & nextborder ) ;
/* Planes */
planes = NULL ;
READ_INT ( & store , & nread ) ;
while ( - - nread > = 0 ) {
int id ;
variant fno ;
plane * pl ;
READ_INT ( & store , & id ) ;
pl = getplanebyid ( id ) ;
if ( pl = = NULL ) {
pl = calloc ( 1 , sizeof ( plane ) ) ;
}
else {
log_warning ( " the plane with id=%d already exists. \n " , id ) ;
}
pl - > id = id ;
2013-12-31 10:06:28 +01:00
READ_STR ( & store , name , sizeof ( name ) ) ;
2014-07-23 11:54:51 +02:00
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_INT ( & store , & pl - > flags ) ;
/* 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 ) ) ;
if ( strcmp ( rname , " end " ) = = 0 ) {
break ; /* this is most likely the end of the list */
}
else {
log_error (
( " This datafile contains watchers, but we are unable to read them \n " ) ) ;
}
}
}
else {
fno = read_faction_reference ( & store ) ;
while ( fno . i ) {
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 ) ;
}
}
a_read ( & store , & pl - > attribs , pl ) ;
2014-09-02 07:24:55 +02:00
if ( pl - > id ! = 1094969858 ) { // Regatta
addlist ( & planes , pl ) ;
}
2014-07-23 11:54:51 +02:00
}
/* Read factions */
2014-12-12 23:00:30 +01:00
read_alliances ( & store ) ;
2014-07-23 11:54:51 +02:00
READ_INT ( & store , & nread ) ;
log_printf ( stdout , " - Einzulesende Parteien: %d \n " , nread ) ;
fp = & factions ;
while ( * fp )
fp = & ( * fp ) - > next ;
while ( - - nread > = 0 ) {
faction * f = readfaction ( & gdata ) ;
* fp = f ;
fp = & f - > next ;
fhash ( f ) ;
}
* fp = 0 ;
/* Regionen */
READ_INT ( & store , & nread ) ;
assert ( nread < MAXREGIONS ) ;
if ( rmax < 0 ) {
rmax = nread ;
}
log_printf ( stdout , " - Einzulesende Regionen: %d/%d \r " , rmax , nread ) ;
while ( - - nread > = 0 ) {
unit * * up ;
int x , y ;
READ_INT ( & store , & x ) ;
READ_INT ( & store , & y ) ;
if ( ( nread & 0x3FF ) = = 0 ) { /* das spart extrem Zeit */
log_printf ( stdout , " - Einzulesende Regionen: %d/%d * %d,%d \r " , rmax , nread , x , y ) ;
}
- - rmax ;
r = readregion ( & gdata , x , y ) ;
/* Burgen */
READ_INT ( & store , & p ) ;
bp = & r - > buildings ;
while ( - - p > = 0 ) {
b = ( building * ) calloc ( 1 , sizeof ( building ) ) ;
READ_INT ( & store , & b - > no ) ;
* bp = b ;
bp = & b - > next ;
bhash ( b ) ;
READ_STR ( & store , name , sizeof ( name ) ) ;
b - > name = _strdup ( name ) ;
if ( lomem ) {
READ_STR ( gdata . store , NULL , 0 ) ;
}
else {
READ_STR ( & store , name , sizeof ( name ) ) ;
b - > display = _strdup ( name ) ;
}
READ_INT ( & store , & b - > size ) ;
READ_STR ( & store , name , sizeof ( name ) ) ;
b - > type = bt_find ( name ) ;
b - > region = r ;
a_read ( & store , & b - > attribs , b ) ;
if ( b - > type = = bt_lighthouse ) {
r - > flags | = RF_LIGHTHOUSE ;
}
}
/* Schiffe */
READ_INT ( & store , & p ) ;
shp = & r - > ships ;
while ( - - p > = 0 ) {
ship * sh = ( ship * ) calloc ( 1 , sizeof ( ship ) ) ;
sh - > region = r ;
READ_INT ( & store , & sh - > no ) ;
* shp = sh ;
shp = & sh - > next ;
shash ( sh ) ;
READ_STR ( & store , name , sizeof ( name ) ) ;
sh - > name = _strdup ( name ) ;
if ( lomem ) {
READ_STR ( & store , NULL , 0 ) ;
}
else {
READ_STR ( & store , name , sizeof ( name ) ) ;
sh - > display = _strdup ( name ) ;
}
READ_STR ( & store , name , sizeof ( name ) ) ;
sh - > type = st_find ( name ) ;
if ( sh - > type = = NULL ) {
/* old datafiles */
2015-01-08 20:55:29 +01:00
sh - > type = st_find ( ( const char * ) LOC ( default_locale , name ) ) ;
2014-07-23 11:54:51 +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_INT ( & store , & sh - > flags ) ;
}
/* Attribute rekursiv einlesen */
READ_INT ( & store , & n ) ;
sh - > coast = ( direction_t ) n ;
if ( sh - > type - > flags & SFL_NOCOAST ) {
sh - > coast = NODIRECTION ;
}
a_read ( & store , & sh - > attribs , sh ) ;
}
* shp = 0 ;
/* Einheiten */
READ_INT ( & store , & p ) ;
up = & r - > units ;
while ( - - p > = 0 ) {
unit * u = read_unit ( & gdata ) ;
sc_mage * mage ;
2015-04-21 12:35:39 +02:00
if ( gdata . version < JSON_REPORT_VERSION ) {
2015-02-11 07:55:35 +01:00
if ( u - > _name & & fval ( u - > faction , FFL_NPC ) ) {
2015-04-21 12:35:39 +02:00
if ( ! u - > _name [ 0 ] | | unit_name_equals_race ( u ) ) {
2014-12-09 07:44:26 +01:00
unit_setname ( u , NULL ) ;
}
}
}
2014-07-23 11:54:51 +02:00
assert ( u - > region = = NULL ) ;
u - > region = r ;
* up = u ;
up = & u - > next ;
update_interval ( u - > faction , u - > region ) ;
mage = get_mage ( u ) ;
if ( mage ) {
faction * f = u - > faction ;
int skl = effskill ( u , SK_MAGIC ) ;
2014-11-11 16:53:56 +01:00
if ( ! fval ( f , FFL_NPC ) & & f - > magiegebiet = = M_GRAY ) {
2014-07-23 11:54:51 +02:00
log_error ( " faction %s had magic=gray, fixing (%s) \n " , factionname ( f ) , magic_school [ mage - > magietyp ] ) ;
f - > magiegebiet = mage - > magietyp ;
}
if ( f - > max_spelllevel < skl ) {
f - > max_spelllevel = skl ;
}
if ( mage - > spellcount < 0 ) {
mage - > spellcount = 0 ;
}
}
}
}
log_printf ( stdout , " \n " ) ;
read_borders ( & store ) ;
binstore_done ( & store ) ;
2014-11-03 22:29:04 +01:00
fstream_done ( & strm ) ;
2014-07-23 11:54:51 +02:00
/* Unaufgeloeste Zeiger initialisieren */
log_printf ( stdout , " fixing unresolved references. \n " ) ;
resolve ( ) ;
log_printf ( stdout , " updating area information for lighthouses. \n " ) ;
for ( r = regions ; r ; r = r - > next ) {
if ( r - > flags & RF_LIGHTHOUSE ) {
building * b ;
for ( b = r - > buildings ; b ; b = b - > next )
update_lighthouse ( b ) ;
}
}
log_printf ( stdout , " marking factions as alive. \n " ) ;
for ( f = factions ; f ; f = f - > next ) {
if ( f - > flags & FFL_NPC ) {
f - > alive = 1 ;
if ( f - > no = = 0 ) {
int no = 666 ;
while ( findfaction ( no ) )
+ + no ;
log_warning ( " renum(monsters, %d) \n " , no ) ;
renumber_faction ( f , no ) ;
}
}
else {
for ( u = f - > units ; u ; u = u - > nextF ) {
if ( u - > number > 0 ) {
f - > alive = 1 ;
break ;
}
}
}
}
if ( loadplane | | maxregions > = 0 ) {
remove_empty_factions ( ) ;
}
log_printf ( stdout , " Done loading turn %d. \n " , turn ) ;
return 0 ;
2010-08-08 10:06:34 +02:00
}
2014-11-11 16:53:56 +01:00
static void clear_npc_orders ( faction * f )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
if ( f ) {
unit * u ;
for ( u = f - > units ; u ; u = u - > nextF ) {
free_orders ( & u - > orders ) ;
}
2010-08-08 10:06:34 +02:00
}
}
2013-12-31 10:06:28 +01:00
int writegame ( const char * filename )
2010-08-08 10:06:34 +02:00
{
2014-07-23 11:54:51 +02:00
int n ;
faction * f ;
region * r ;
building * b ;
ship * sh ;
unit * u ;
plane * pl ;
char path [ MAX_PATH ] ;
gamedata gdata ;
storage store ;
2014-11-03 22:29:04 +01:00
stream strm ;
2014-07-23 11:54:51 +02:00
FILE * F ;
sprintf ( path , " %s/%s " , datapath ( ) , filename ) ;
2010-08-08 10:06:34 +02:00
# ifdef HAVE_UNISTD_H
2014-07-23 11:54:51 +02:00
if ( access ( path , R_OK ) = = 0 ) {
/* make sure we don't overwrite some hardlinkedfile */
unlink ( path ) ;
}
2010-08-08 10:06:34 +02:00
# endif
2013-12-31 10:06:28 +01:00
F = fopen ( path , " wb " ) ;
if ( ! F ) {
2014-07-23 11:54:51 +02:00
/* 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
2014-07-23 11:54:51 +02:00
gdata . store = & store ;
gdata . encoding = enc_gamedata ;
gdata . version = RELEASE_VERSION ;
2015-05-12 18:07:47 +02:00
global . data_version = RELEASE_VERSION ;
2014-07-23 11:54:51 +02:00
n = STREAM_VERSION ;
fwrite ( & gdata . version , sizeof ( int ) , 1 , F ) ;
fwrite ( & n , sizeof ( int ) , 1 , F ) ;
2014-11-03 22:29:04 +01:00
fstream_init ( & strm , F ) ;
binstore_init ( & store , & strm ) ;
2014-07-23 11:54:51 +02:00
/* globale Variablen */
2010-08-08 10:06:34 +02:00
2014-08-14 05:06:36 +02:00
WRITE_INT ( & store , VERSION_BUILD ) ;
2014-07-23 11:54:51 +02:00
WRITE_INT ( & store , game_id ( ) ) ;
2013-12-31 10:06:28 +01:00
WRITE_SECTION ( & store ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
a_write ( & store , global . attribs , NULL ) ;
WRITE_SECTION ( & store ) ;
WRITE_INT ( & store , turn ) ;
WRITE_INT ( & store , 0 /*max_unique_id */ ) ;
WRITE_INT ( & store , nextborder ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
/* Write planes */
WRITE_SECTION ( & store ) ;
WRITE_INT ( & store , listlen ( planes ) ) ;
WRITE_SECTION ( & store ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02: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 ) ;
w = pl - > watchers ;
while ( w ) {
if ( w - > faction ) {
write_faction_reference ( w - > faction , & store ) ;
WRITE_INT ( & store , w - > mode ) ;
}
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
}
2014-07-23 11:54:51 +02:00
/* Write factions */
write_alliances ( & gdata ) ;
n = listlen ( factions ) ;
WRITE_INT ( & store , n ) ;
2013-12-31 10:06:28 +01:00
WRITE_SECTION ( & store ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
log_printf ( stdout , " - Schreibe %d Parteien... \n " , n ) ;
for ( f = factions ; f ; f = f - > next ) {
2014-11-11 16:53:56 +01:00
if ( fval ( f , FFL_NPC ) ) {
clear_npc_orders ( f ) ;
}
2014-07-23 11:54:51 +02:00
writefaction ( & gdata , f ) ;
WRITE_SECTION ( & store ) ;
}
/* Write regions */
n = listlen ( regions ) ;
WRITE_INT ( & store , n ) ;
2013-12-31 10:06:28 +01:00
WRITE_SECTION ( & store ) ;
2014-07-23 11:54:51 +02:00
log_printf ( stdout , " - Schreibe Regionen: %d \r " , n ) ;
for ( r = regions ; r ; r = r - > next , - - n ) {
/* plus leerzeile */
if ( ( n % 1024 ) = = 0 ) { /* das spart extrem Zeit */
log_printf ( stdout , " - Schreibe Regionen: %d \r " , n ) ;
fflush ( stdout ) ;
}
WRITE_SECTION ( & store ) ;
WRITE_INT ( & store , r - > x ) ;
WRITE_INT ( & store , r - > y ) ;
writeregion ( & gdata , r ) ;
WRITE_INT ( & store , listlen ( r - > buildings ) ) ;
WRITE_SECTION ( & store ) ;
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 ) ;
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 ) ;
WRITE_INT ( & store , sh - > size ) ;
WRITE_INT ( & store , sh - > damage ) ;
WRITE_INT ( & store , sh - > flags & SFL_SAVEMASK ) ;
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 ) ;
}
WRITE_INT ( & store , listlen ( r - > units ) ) ;
WRITE_SECTION ( & store ) ;
for ( u = r - > units ; u ; u = u - > next ) {
write_unit ( & gdata , u ) ;
}
}
2013-12-31 10:06:28 +01:00
WRITE_SECTION ( & store ) ;
2014-07-23 11:54:51 +02:00
write_borders ( & store ) ;
2013-12-31 10:06:28 +01:00
WRITE_SECTION ( & store ) ;
2011-03-07 08:02:35 +01:00
2014-07-23 11:54:51 +02:00
binstore_done ( & store ) ;
2014-11-03 22:29:04 +01:00
fstream_done ( & strm ) ;
2010-08-08 10:06:34 +02:00
2014-07-23 11:54:51 +02:00
log_printf ( stdout , " \n Ok. \n " ) ;
return 0 ;
2015-01-30 20:37:14 +01:00
}
2010-08-08 10:06:34 +02:00
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
{
2014-07-23 11:54:51 +02:00
/* assert(sizeof(int)==sizeof(a->data)); */
READ_INT ( store , & a - > data . i ) ;
return AT_READ_OK ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-07-23 11:54:51 +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
{
2014-07-23 11:54:51 +02:00
int n ;
READ_INT ( store , & n ) ;
a - > data . sa [ 0 ] = ( short ) n ;
READ_INT ( store , & n ) ;
a - > data . sa [ 1 ] = ( short ) n ;
return AT_READ_OK ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-07-23 11:54:51 +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
{
2014-07-23 11:54:51 +02:00
int i ;
for ( i = 0 ; i ! = 4 ; + + i ) {
int n ;
READ_INT ( store , & n ) ;
a - > data . ca [ i ] = ( char ) n ;
}
return AT_READ_OK ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-07-23 11:54:51 +02:00
int i ;
2011-03-07 08:02:35 +01:00
2014-07-23 11:54:51 +02: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
{
2014-07-23 11:54:51 +02:00
return AT_READ_OK ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-07-23 11:54:51 +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 ;
return AT_READ_OK ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-07-23 11:54:51 +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
{
2014-07-23 11:54:51 +02:00
free ( a - > data . v ) ;
2010-08-08 10:06:34 +02:00
}