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