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