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