Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

g_save.c (18283B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 
     21 #include "g_local.h"
     22 
     23 #define Function(f) {#f, f}
     24 
     25 mmove_t mmove_reloc;
     26 
     27 field_t fields[] = {
     28 	{"classname", FOFS(classname), F_LSTRING},
     29 	{"model", FOFS(model), F_LSTRING},
     30 	{"spawnflags", FOFS(spawnflags), F_INT},
     31 	{"speed", FOFS(speed), F_FLOAT},
     32 	{"accel", FOFS(accel), F_FLOAT},
     33 	{"decel", FOFS(decel), F_FLOAT},
     34 	{"target", FOFS(target), F_LSTRING},
     35 	{"targetname", FOFS(targetname), F_LSTRING},
     36 	{"pathtarget", FOFS(pathtarget), F_LSTRING},
     37 	{"deathtarget", FOFS(deathtarget), F_LSTRING},
     38 	{"killtarget", FOFS(killtarget), F_LSTRING},
     39 	{"combattarget", FOFS(combattarget), F_LSTRING},
     40 	{"message", FOFS(message), F_LSTRING},
     41 	{"team", FOFS(team), F_LSTRING},
     42 	{"wait", FOFS(wait), F_FLOAT},
     43 	{"delay", FOFS(delay), F_FLOAT},
     44 	{"random", FOFS(random), F_FLOAT},
     45 	{"move_origin", FOFS(move_origin), F_VECTOR},
     46 	{"move_angles", FOFS(move_angles), F_VECTOR},
     47 	{"style", FOFS(style), F_INT},
     48 	{"count", FOFS(count), F_INT},
     49 	{"health", FOFS(health), F_INT},
     50 	{"sounds", FOFS(sounds), F_INT},
     51 	{"light", 0, F_IGNORE},
     52 	{"dmg", FOFS(dmg), F_INT},
     53 	{"mass", FOFS(mass), F_INT},
     54 	{"volume", FOFS(volume), F_FLOAT},
     55 	{"attenuation", FOFS(attenuation), F_FLOAT},
     56 	{"map", FOFS(map), F_LSTRING},
     57 	{"origin", FOFS(s.origin), F_VECTOR},
     58 	{"angles", FOFS(s.angles), F_VECTOR},
     59 	{"angle", FOFS(s.angles), F_ANGLEHACK},
     60 
     61 	{"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN},
     62 	{"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN},
     63 	{"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN},
     64 	{"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN},
     65 	{"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN},
     66 	{"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN},
     67 	{"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN},
     68 	{"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN},
     69 	{"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN},
     70 	{"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN},
     71 	{"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN},
     72 	{"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN},
     73 	{"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN},
     74 
     75 	{"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN},
     76 	{"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN},
     77 	{"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN},
     78 	{"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN},
     79 	{"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN},
     80 	{"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN},
     81 	{"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN},
     82 
     83 	{"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN},
     84 	{"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN},
     85 	{"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN},
     86 	{"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN},
     87 	{"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN},
     88 	{"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN},
     89 	{"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN},
     90 	{"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN},
     91 	{"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN},
     92 	{"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN},
     93 	{"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN},
     94 
     95 	{"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN},
     96 
     97 	// temp spawn vars -- only valid when the spawn function is called
     98 	{"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
     99 	{"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
    100 	{"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
    101 	{"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
    102 	{"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
    103 	{"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
    104 
    105 //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
    106 	{"item", FOFS(item), F_ITEM},
    107 
    108 	{"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
    109 	{"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
    110 	{"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
    111 	{"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
    112 	{"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
    113 	{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
    114 	{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
    115 	{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
    116 	{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
    117 
    118 	{0, 0, 0, 0}
    119 
    120 };
    121 
    122 field_t		levelfields[] =
    123 {
    124 	{"changemap", LLOFS(changemap), F_LSTRING},
    125                    
    126 	{"sight_client", LLOFS(sight_client), F_EDICT},
    127 	{"sight_entity", LLOFS(sight_entity), F_EDICT},
    128 	{"sound_entity", LLOFS(sound_entity), F_EDICT},
    129 	{"sound2_entity", LLOFS(sound2_entity), F_EDICT},
    130 
    131 	{NULL, 0, F_INT}
    132 };
    133 
    134 field_t		clientfields[] =
    135 {
    136 	{"pers.weapon", CLOFS(pers.weapon), F_ITEM},
    137 	{"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
    138 	{"newweapon", CLOFS(newweapon), F_ITEM},
    139 
    140 	{NULL, 0, F_INT}
    141 };
    142 
    143 /*
    144 ============
    145 InitGame
    146 
    147 This will be called when the dll is first loaded, which
    148 only happens when a new game is started or a save game
    149 is loaded.
    150 ============
    151 */
    152 void InitGame (void)
    153 {
    154 	gi.dprintf ("==== InitGame ====\n");
    155 
    156 	gun_x = gi.cvar ("gun_x", "0", 0);
    157 	gun_y = gi.cvar ("gun_y", "0", 0);
    158 	gun_z = gi.cvar ("gun_z", "0", 0);
    159 
    160 	//FIXME: sv_ prefix is wrong for these
    161 	sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
    162 	sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
    163 	sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
    164 	sv_gravity = gi.cvar ("sv_gravity", "800", 0);
    165 
    166 	// noset vars
    167 	dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
    168 
    169 	// latched vars
    170 	sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
    171 	gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
    172 	gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
    173 
    174 	maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
    175 	maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
    176 	deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
    177 	coop = gi.cvar ("coop", "0", CVAR_LATCH);
    178 	skill = gi.cvar ("skill", "1", CVAR_LATCH);
    179 	maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
    180 
    181 	// change anytime vars
    182 	dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
    183 	fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
    184 	timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
    185 	password = gi.cvar ("password", "", CVAR_USERINFO);
    186 	spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO);
    187 	filterban = gi.cvar ("filterban", "1", 0);
    188 
    189 	g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
    190 
    191 	run_pitch = gi.cvar ("run_pitch", "0.002", 0);
    192 	run_roll = gi.cvar ("run_roll", "0.005", 0);
    193 	bob_up  = gi.cvar ("bob_up", "0.005", 0);
    194 	bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
    195 	bob_roll = gi.cvar ("bob_roll", "0.002", 0);
    196 
    197 	// flood control
    198 	flood_msgs = gi.cvar ("flood_msgs", "4", 0);
    199 	flood_persecond = gi.cvar ("flood_persecond", "4", 0);
    200 	flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
    201 
    202 	// dm map list
    203 	sv_maplist = gi.cvar ("sv_maplist", "", 0);
    204 
    205 	// items
    206 	InitItems ();
    207 
    208 	Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
    209 
    210 	Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
    211 
    212 	// initialize all entities for this game
    213 	game.maxentities = maxentities->value;
    214 	g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
    215 	globals.edicts = g_edicts;
    216 	globals.max_edicts = game.maxentities;
    217 
    218 	// initialize all clients for this game
    219 	game.maxclients = maxclients->value;
    220 	game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
    221 	globals.num_edicts = game.maxclients+1;
    222 }
    223 
    224 //=========================================================
    225 
    226 void WriteField1 (FILE *f, field_t *field, byte *base)
    227 {
    228 	void		*p;
    229 	int			len;
    230 	int			index;
    231 
    232 	if (field->flags & FFL_SPAWNTEMP)
    233 		return;
    234 
    235 	p = (void *)(base + field->ofs);
    236 	switch (field->type)
    237 	{
    238 	case F_INT:
    239 	case F_FLOAT:
    240 	case F_ANGLEHACK:
    241 	case F_VECTOR:
    242 	case F_IGNORE:
    243 		break;
    244 
    245 	case F_LSTRING:
    246 	case F_GSTRING:
    247 		if ( *(char **)p )
    248 			len = strlen(*(char **)p) + 1;
    249 		else
    250 			len = 0;
    251 		*(int *)p = len;
    252 		break;
    253 	case F_EDICT:
    254 		if ( *(edict_t **)p == NULL)
    255 			index = -1;
    256 		else
    257 			index = *(edict_t **)p - g_edicts;
    258 		*(int *)p = index;
    259 		break;
    260 	case F_CLIENT:
    261 		if ( *(gclient_t **)p == NULL)
    262 			index = -1;
    263 		else
    264 			index = *(gclient_t **)p - game.clients;
    265 		*(int *)p = index;
    266 		break;
    267 	case F_ITEM:
    268 		if ( *(edict_t **)p == NULL)
    269 			index = -1;
    270 		else
    271 			index = *(gitem_t **)p - itemlist;
    272 		*(int *)p = index;
    273 		break;
    274 
    275 	//relative to code segment
    276 	case F_FUNCTION:
    277 		if (*(byte **)p == NULL)
    278 			index = 0;
    279 		else
    280 			index = *(byte **)p - ((byte *)InitGame);
    281 		*(int *)p = index;
    282 		break;
    283 
    284 	//relative to data segment
    285 	case F_MMOVE:
    286 		if (*(byte **)p == NULL)
    287 			index = 0;
    288 		else
    289 			index = *(byte **)p - (byte *)&mmove_reloc;
    290 		*(int *)p = index;
    291 		break;
    292 
    293 	default:
    294 		gi.error ("WriteEdict: unknown field type");
    295 	}
    296 }
    297 
    298 
    299 void WriteField2 (FILE *f, field_t *field, byte *base)
    300 {
    301 	int			len;
    302 	void		*p;
    303 
    304 	if (field->flags & FFL_SPAWNTEMP)
    305 		return;
    306 
    307 	p = (void *)(base + field->ofs);
    308 	switch (field->type)
    309 	{
    310 	case F_LSTRING:
    311 		if ( *(char **)p )
    312 		{
    313 			len = strlen(*(char **)p) + 1;
    314 			fwrite (*(char **)p, len, 1, f);
    315 		}
    316 		break;
    317 	}
    318 }
    319 
    320 void ReadField (FILE *f, field_t *field, byte *base)
    321 {
    322 	void		*p;
    323 	int			len;
    324 	int			index;
    325 
    326 	if (field->flags & FFL_SPAWNTEMP)
    327 		return;
    328 
    329 	p = (void *)(base + field->ofs);
    330 	switch (field->type)
    331 	{
    332 	case F_INT:
    333 	case F_FLOAT:
    334 	case F_ANGLEHACK:
    335 	case F_VECTOR:
    336 	case F_IGNORE:
    337 		break;
    338 
    339 	case F_LSTRING:
    340 		len = *(int *)p;
    341 		if (!len)
    342 			*(char **)p = NULL;
    343 		else
    344 		{
    345 			*(char **)p = gi.TagMalloc (len, TAG_LEVEL);
    346 			fread (*(char **)p, len, 1, f);
    347 		}
    348 		break;
    349 	case F_EDICT:
    350 		index = *(int *)p;
    351 		if ( index == -1 )
    352 			*(edict_t **)p = NULL;
    353 		else
    354 			*(edict_t **)p = &g_edicts[index];
    355 		break;
    356 	case F_CLIENT:
    357 		index = *(int *)p;
    358 		if ( index == -1 )
    359 			*(gclient_t **)p = NULL;
    360 		else
    361 			*(gclient_t **)p = &game.clients[index];
    362 		break;
    363 	case F_ITEM:
    364 		index = *(int *)p;
    365 		if ( index == -1 )
    366 			*(gitem_t **)p = NULL;
    367 		else
    368 			*(gitem_t **)p = &itemlist[index];
    369 		break;
    370 
    371 	//relative to code segment
    372 	case F_FUNCTION:
    373 		index = *(int *)p;
    374 		if ( index == 0 )
    375 			*(byte **)p = NULL;
    376 		else
    377 			*(byte **)p = ((byte *)InitGame) + index;
    378 		break;
    379 
    380 	//relative to data segment
    381 	case F_MMOVE:
    382 		index = *(int *)p;
    383 		if (index == 0)
    384 			*(byte **)p = NULL;
    385 		else
    386 			*(byte **)p = (byte *)&mmove_reloc + index;
    387 		break;
    388 
    389 	default:
    390 		gi.error ("ReadEdict: unknown field type");
    391 	}
    392 }
    393 
    394 //=========================================================
    395 
    396 /*
    397 ==============
    398 WriteClient
    399 
    400 All pointer variables (except function pointers) must be handled specially.
    401 ==============
    402 */
    403 void WriteClient (FILE *f, gclient_t *client)
    404 {
    405 	field_t		*field;
    406 	gclient_t	temp;
    407 	
    408 	// all of the ints, floats, and vectors stay as they are
    409 	temp = *client;
    410 
    411 	// change the pointers to lengths or indexes
    412 	for (field=clientfields ; field->name ; field++)
    413 	{
    414 		WriteField1 (f, field, (byte *)&temp);
    415 	}
    416 
    417 	// write the block
    418 	fwrite (&temp, sizeof(temp), 1, f);
    419 
    420 	// now write any allocated data following the edict
    421 	for (field=clientfields ; field->name ; field++)
    422 	{
    423 		WriteField2 (f, field, (byte *)client);
    424 	}
    425 }
    426 
    427 /*
    428 ==============
    429 ReadClient
    430 
    431 All pointer variables (except function pointers) must be handled specially.
    432 ==============
    433 */
    434 void ReadClient (FILE *f, gclient_t *client)
    435 {
    436 	field_t		*field;
    437 
    438 	fread (client, sizeof(*client), 1, f);
    439 
    440 	for (field=clientfields ; field->name ; field++)
    441 	{
    442 		ReadField (f, field, (byte *)client);
    443 	}
    444 }
    445 
    446 /*
    447 ============
    448 WriteGame
    449 
    450 This will be called whenever the game goes to a new level,
    451 and when the user explicitly saves the game.
    452 
    453 Game information include cross level data, like multi level
    454 triggers, help computer info, and all client states.
    455 
    456 A single player death will automatically restore from the
    457 last save position.
    458 ============
    459 */
    460 void WriteGame (char *filename, qboolean autosave)
    461 {
    462 	FILE	*f;
    463 	int		i;
    464 	char	str[16];
    465 
    466 	if (!autosave)
    467 		SaveClientData ();
    468 
    469 	f = fopen (filename, "wb");
    470 	if (!f)
    471 		gi.error ("Couldn't open %s", filename);
    472 
    473 	memset (str, 0, sizeof(str));
    474 	strcpy (str, __DATE__);
    475 	fwrite (str, sizeof(str), 1, f);
    476 
    477 	game.autosaved = autosave;
    478 	fwrite (&game, sizeof(game), 1, f);
    479 	game.autosaved = false;
    480 
    481 	for (i=0 ; i<game.maxclients ; i++)
    482 		WriteClient (f, &game.clients[i]);
    483 
    484 	fclose (f);
    485 }
    486 
    487 void ReadGame (char *filename)
    488 {
    489 	FILE	*f;
    490 	int		i;
    491 	char	str[16];
    492 
    493 	gi.FreeTags (TAG_GAME);
    494 
    495 	f = fopen (filename, "rb");
    496 	if (!f)
    497 		gi.error ("Couldn't open %s", filename);
    498 
    499 	fread (str, sizeof(str), 1, f);
    500 	if (strcmp (str, __DATE__))
    501 	{
    502 		fclose (f);
    503 		gi.error ("Savegame from an older version.\n");
    504 	}
    505 
    506 	g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
    507 	globals.edicts = g_edicts;
    508 
    509 	fread (&game, sizeof(game), 1, f);
    510 	game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
    511 	for (i=0 ; i<game.maxclients ; i++)
    512 		ReadClient (f, &game.clients[i]);
    513 
    514 	fclose (f);
    515 }
    516 
    517 //==========================================================
    518 
    519 
    520 /*
    521 ==============
    522 WriteEdict
    523 
    524 All pointer variables (except function pointers) must be handled specially.
    525 ==============
    526 */
    527 void WriteEdict (FILE *f, edict_t *ent)
    528 {
    529 	field_t		*field;
    530 	edict_t		temp;
    531 
    532 	// all of the ints, floats, and vectors stay as they are
    533 	temp = *ent;
    534 
    535 	// change the pointers to lengths or indexes
    536 	for (field=fields ; field->name ; field++)
    537 	{
    538 		WriteField1 (f, field, (byte *)&temp);
    539 	}
    540 
    541 	// write the block
    542 	fwrite (&temp, sizeof(temp), 1, f);
    543 
    544 	// now write any allocated data following the edict
    545 	for (field=fields ; field->name ; field++)
    546 	{
    547 		WriteField2 (f, field, (byte *)ent);
    548 	}
    549 
    550 }
    551 
    552 /*
    553 ==============
    554 WriteLevelLocals
    555 
    556 All pointer variables (except function pointers) must be handled specially.
    557 ==============
    558 */
    559 void WriteLevelLocals (FILE *f)
    560 {
    561 	field_t		*field;
    562 	level_locals_t		temp;
    563 
    564 	// all of the ints, floats, and vectors stay as they are
    565 	temp = level;
    566 
    567 	// change the pointers to lengths or indexes
    568 	for (field=levelfields ; field->name ; field++)
    569 	{
    570 		WriteField1 (f, field, (byte *)&temp);
    571 	}
    572 
    573 	// write the block
    574 	fwrite (&temp, sizeof(temp), 1, f);
    575 
    576 	// now write any allocated data following the edict
    577 	for (field=levelfields ; field->name ; field++)
    578 	{
    579 		WriteField2 (f, field, (byte *)&level);
    580 	}
    581 }
    582 
    583 
    584 /*
    585 ==============
    586 ReadEdict
    587 
    588 All pointer variables (except function pointers) must be handled specially.
    589 ==============
    590 */
    591 void ReadEdict (FILE *f, edict_t *ent)
    592 {
    593 	field_t		*field;
    594 
    595 	fread (ent, sizeof(*ent), 1, f);
    596 
    597 	for (field=fields ; field->name ; field++)
    598 	{
    599 		ReadField (f, field, (byte *)ent);
    600 	}
    601 }
    602 
    603 /*
    604 ==============
    605 ReadLevelLocals
    606 
    607 All pointer variables (except function pointers) must be handled specially.
    608 ==============
    609 */
    610 void ReadLevelLocals (FILE *f)
    611 {
    612 	field_t		*field;
    613 
    614 	fread (&level, sizeof(level), 1, f);
    615 
    616 	for (field=levelfields ; field->name ; field++)
    617 	{
    618 		ReadField (f, field, (byte *)&level);
    619 	}
    620 }
    621 
    622 /*
    623 =================
    624 WriteLevel
    625 
    626 =================
    627 */
    628 void WriteLevel (char *filename)
    629 {
    630 	int		i;
    631 	edict_t	*ent;
    632 	FILE	*f;
    633 	void	*base;
    634 
    635 	f = fopen (filename, "wb");
    636 	if (!f)
    637 		gi.error ("Couldn't open %s", filename);
    638 
    639 	// write out edict size for checking
    640 	i = sizeof(edict_t);
    641 	fwrite (&i, sizeof(i), 1, f);
    642 
    643 	// write out a function pointer for checking
    644 	base = (void *)InitGame;
    645 	fwrite (&base, sizeof(base), 1, f);
    646 
    647 	// write out level_locals_t
    648 	WriteLevelLocals (f);
    649 
    650 	// write out all the entities
    651 	for (i=0 ; i<globals.num_edicts ; i++)
    652 	{
    653 		ent = &g_edicts[i];
    654 		if (!ent->inuse)
    655 			continue;
    656 		fwrite (&i, sizeof(i), 1, f);
    657 		WriteEdict (f, ent);
    658 	}
    659 	i = -1;
    660 	fwrite (&i, sizeof(i), 1, f);
    661 
    662 	fclose (f);
    663 }
    664 
    665 
    666 /*
    667 =================
    668 ReadLevel
    669 
    670 SpawnEntities will allready have been called on the
    671 level the same way it was when the level was saved.
    672 
    673 That is necessary to get the baselines
    674 set up identically.
    675 
    676 The server will have cleared all of the world links before
    677 calling ReadLevel.
    678 
    679 No clients are connected yet.
    680 =================
    681 */
    682 void ReadLevel (char *filename)
    683 {
    684 	int		entnum;
    685 	FILE	*f;
    686 	int		i;
    687 	void	*base;
    688 	edict_t	*ent;
    689 
    690 	f = fopen (filename, "rb");
    691 	if (!f)
    692 		gi.error ("Couldn't open %s", filename);
    693 
    694 	// free any dynamic memory allocated by loading the level
    695 	// base state
    696 	gi.FreeTags (TAG_LEVEL);
    697 
    698 	// wipe all the entities
    699 	memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
    700 	globals.num_edicts = maxclients->value+1;
    701 
    702 	// check edict size
    703 	fread (&i, sizeof(i), 1, f);
    704 	if (i != sizeof(edict_t))
    705 	{
    706 		fclose (f);
    707 		gi.error ("ReadLevel: mismatched edict size");
    708 	}
    709 
    710 	// check function pointer base address
    711 	fread (&base, sizeof(base), 1, f);
    712 #ifdef _WIN32
    713 	if (base != (void *)InitGame)
    714 	{
    715 		fclose (f);
    716 		gi.error ("ReadLevel: function pointers have moved");
    717 	}
    718 #else
    719 	gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
    720 #endif
    721 
    722 	// load the level locals
    723 	ReadLevelLocals (f);
    724 
    725 	// load all the entities
    726 	while (1)
    727 	{
    728 		if (fread (&entnum, sizeof(entnum), 1, f) != 1)
    729 		{
    730 			fclose (f);
    731 			gi.error ("ReadLevel: failed to read entnum");
    732 		}
    733 		if (entnum == -1)
    734 			break;
    735 		if (entnum >= globals.num_edicts)
    736 			globals.num_edicts = entnum+1;
    737 
    738 		ent = &g_edicts[entnum];
    739 		ReadEdict (f, ent);
    740 
    741 		// let the server rebuild world links for this ent
    742 		memset (&ent->area, 0, sizeof(ent->area));
    743 		gi.linkentity (ent);
    744 	}
    745 
    746 	fclose (f);
    747 
    748 	// mark all clients as unconnected
    749 	for (i=0 ; i<maxclients->value ; i++)
    750 	{
    751 		ent = &g_edicts[i+1];
    752 		ent->client = game.clients + i;
    753 		ent->client->pers.connected = false;
    754 	}
    755 
    756 	// do any load time things at this point
    757 	for (i=0 ; i<globals.num_edicts ; i++)
    758 	{
    759 		ent = &g_edicts[i];
    760 
    761 		if (!ent->inuse)
    762 			continue;
    763 
    764 		// fire any cross-level triggers
    765 		if (ent->classname)
    766 			if (strcmp(ent->classname, "target_crosslevel_target") == 0)
    767 				ent->nextthink = level.time + ent->delay;
    768 	}
    769 }