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