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 */
InitGame(void)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_READONLY);
168
169 // latched vars
170 sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH_SERVER);
171 gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO|CVAR_LATCH_SERVER);
172 gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO|CVAR_LATCH_SERVER);
173
174 maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH_SERVER);
175 maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
176 deathmatch = gi.cvar ("deathmatch", "0", CVAR_SERVERINFO|CVAR_LATCH_SERVER);
177 coop = gi.cvar ("coop", "0", CVAR_LATCH_SERVER);
178 skill = gi.cvar ("skill", "1", CVAR_LATCH_SERVER);
179 maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH_SERVER);
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 needpass = gi.cvar ("needpass", "0", CVAR_SERVERINFO);
188 filterban = gi.cvar ("filterban", "1", 0);
189
190 g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
191
192 run_pitch = gi.cvar ("run_pitch", "0.002", 0);
193 run_roll = gi.cvar ("run_roll", "0.005", 0);
194 bob_up = gi.cvar ("bob_up", "0.005", 0);
195 bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
196 bob_roll = gi.cvar ("bob_roll", "0.002", 0);
197
198 // flood control
199 flood_msgs = gi.cvar ("flood_msgs", "4", 0);
200 flood_persecond = gi.cvar ("flood_persecond", "4", 0);
201 flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
202
203 // dm map list
204 sv_maplist = gi.cvar ("sv_maplist", "", 0);
205
206 // items
207 InitItems ();
208
209 Q_snprintfz (game.helpmessage1, sizeof(game.helpmessage1), "");
210
211 Q_snprintfz (game.helpmessage2, sizeof(game.helpmessage2), "");
212
213 // initialize all entities for this game
214 game.maxentities = maxentities->floatVal;
215 g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
216 globals.edicts = g_edicts;
217 globals.maxEdicts = game.maxentities;
218
219 // initialize all clients for this game
220 game.maxclients = maxclients->floatVal;
221 game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
222 globals.numEdicts = game.maxclients+1;
223 }
224
225 //=========================================================
226
WriteField1(FILE * f,field_t * field,byte * base)227 void WriteField1 (FILE *f, field_t *field, byte *base)
228 {
229 void *p;
230 int len;
231 int index;
232
233 if (field->flags & FFL_SPAWNTEMP)
234 return;
235
236 p = (void *)(base + field->ofs);
237 switch (field->type)
238 {
239 case F_INT:
240 case F_FLOAT:
241 case F_ANGLEHACK:
242 case F_VECTOR:
243 case F_IGNORE:
244 break;
245
246 case F_LSTRING:
247 case F_GSTRING:
248 if ( *(char **)p )
249 len = strlen(*(char **)p) + 1;
250 else
251 len = 0;
252 *(int *)p = len;
253 break;
254 case F_EDICT:
255 if ( *(edict_t **)p == NULL)
256 index = -1;
257 else
258 index = *(edict_t **)p - g_edicts;
259 *(int *)p = index;
260 break;
261 case F_CLIENT:
262 if ( *(gclient_t **)p == NULL)
263 index = -1;
264 else
265 index = *(gclient_t **)p - game.clients;
266 *(int *)p = index;
267 break;
268 case F_ITEM:
269 if ( *(edict_t **)p == NULL)
270 index = -1;
271 else
272 index = *(gitem_t **)p - itemlist;
273 *(int *)p = index;
274 break;
275
276 //relative to code segment
277 case F_FUNCTION:
278 if (*(byte **)p == NULL)
279 index = 0;
280 else
281 index = *(byte **)p - ((byte *)InitGame);
282 *(int *)p = index;
283 break;
284
285 //relative to data segment
286 case F_MMOVE:
287 if (*(byte **)p == NULL)
288 index = 0;
289 else
290 index = *(byte **)p - (byte *)&mmove_reloc;
291 *(int *)p = index;
292 break;
293
294 default:
295 gi.error ("WriteEdict: unknown field type");
296 }
297 }
298
299
WriteField2(FILE * f,field_t * field,byte * base)300 void WriteField2 (FILE *f, field_t *field, byte *base)
301 {
302 int len;
303 void *p;
304
305 if (field->flags & FFL_SPAWNTEMP)
306 return;
307
308 p = (void *)(base + field->ofs);
309 switch (field->type)
310 {
311 case F_LSTRING:
312 if ( *(char **)p )
313 {
314 len = strlen(*(char **)p) + 1;
315 fwrite (*(char **)p, len, 1, f);
316 }
317 break;
318 }
319 }
320
ReadField(FILE * f,field_t * field,byte * base)321 void ReadField (FILE *f, field_t *field, byte *base)
322 {
323 void *p;
324 int len;
325 int index;
326
327 if (field->flags & FFL_SPAWNTEMP)
328 return;
329
330 p = (void *)(base + field->ofs);
331 switch (field->type)
332 {
333 case F_INT:
334 case F_FLOAT:
335 case F_ANGLEHACK:
336 case F_VECTOR:
337 case F_IGNORE:
338 break;
339
340 case F_LSTRING:
341 len = *(int *)p;
342 if (!len)
343 *(char **)p = NULL;
344 else
345 {
346 *(char **)p = gi.TagMalloc (len, TAG_LEVEL);
347 fread (*(char **)p, len, 1, f);
348 }
349 break;
350 case F_EDICT:
351 index = *(int *)p;
352 if ( index == -1 )
353 *(edict_t **)p = NULL;
354 else
355 *(edict_t **)p = &g_edicts[index];
356 break;
357 case F_CLIENT:
358 index = *(int *)p;
359 if ( index == -1 )
360 *(gclient_t **)p = NULL;
361 else
362 *(gclient_t **)p = &game.clients[index];
363 break;
364 case F_ITEM:
365 index = *(int *)p;
366 if ( index == -1 )
367 *(gitem_t **)p = NULL;
368 else
369 *(gitem_t **)p = &itemlist[index];
370 break;
371
372 //relative to code segment
373 case F_FUNCTION:
374 index = *(int *)p;
375 if ( index == 0 )
376 *(byte **)p = NULL;
377 else
378 *(byte **)p = ((byte *)InitGame) + index;
379 break;
380
381 //relative to data segment
382 case F_MMOVE:
383 index = *(int *)p;
384 if (index == 0)
385 *(byte **)p = NULL;
386 else
387 *(byte **)p = (byte *)&mmove_reloc + index;
388 break;
389
390 default:
391 gi.error ("ReadEdict: unknown field type");
392 }
393 }
394
395 //=========================================================
396
397 /*
398 ==============
399 WriteClient
400
401 All pointer variables (except function pointers) must be handled specially.
402 ==============
403 */
WriteClient(FILE * f,gclient_t * client)404 void WriteClient (FILE *f, gclient_t *client)
405 {
406 field_t *field;
407 gclient_t temp;
408
409 // all of the ints, floats, and vectors stay as they are
410 temp = *client;
411
412 // change the pointers to lengths or indexes
413 for (field=clientfields ; field->name ; field++)
414 {
415 WriteField1 (f, field, (byte *)&temp);
416 }
417
418 // write the block
419 fwrite (&temp, sizeof(temp), 1, f);
420
421 // now write any allocated data following the edict
422 for (field=clientfields ; field->name ; field++)
423 {
424 WriteField2 (f, field, (byte *)client);
425 }
426 }
427
428 /*
429 ==============
430 ReadClient
431
432 All pointer variables (except function pointers) must be handled specially.
433 ==============
434 */
ReadClient(FILE * f,gclient_t * client)435 void ReadClient (FILE *f, gclient_t *client)
436 {
437 field_t *field;
438
439 fread (client, sizeof(*client), 1, f);
440
441 for (field=clientfields ; field->name ; field++)
442 {
443 ReadField (f, field, (byte *)client);
444 }
445 }
446
447 /*
448 ============
449 WriteGame
450
451 This will be called whenever the game goes to a new level,
452 and when the user explicitly saves the game.
453
454 Game information include cross level data, like multi level
455 triggers, help computer info, and all client states.
456
457 A single player death will automatically restore from the
458 last save position.
459 ============
460 */
WriteGame(char * filename,qBool autosave)461 void WriteGame (char *filename, qBool autosave)
462 {
463 FILE *f;
464 int i;
465 char str[16];
466
467 if (!autosave)
468 SaveClientData ();
469
470 f = fopen (filename, "wb");
471 if (!f)
472 gi.error ("Couldn't open %s", filename);
473
474 memset (str, 0, sizeof(str));
475 strcpy (str, __DATE__);
476 fwrite (str, sizeof(str), 1, f);
477
478 game.autosaved = autosave;
479 fwrite (&game, sizeof(game), 1, f);
480 game.autosaved = qFalse;
481
482 for (i=0 ; i<game.maxclients ; i++)
483 WriteClient (f, &game.clients[i]);
484
485 fclose (f);
486 }
487
ReadGame(char * filename)488 void ReadGame (char *filename)
489 {
490 FILE *f;
491 int i;
492 char str[16];
493
494 gi.FreeTags (TAG_GAME);
495
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 WriteEdict
524
525 All pointer variables (except function pointers) must be handled specially.
526 ==============
527 */
WriteEdict(FILE * f,edict_t * ent)528 void WriteEdict (FILE *f, edict_t *ent)
529 {
530 field_t *field;
531 edict_t temp;
532
533 // all of the ints, floats, and vectors stay as they are
534 temp = *ent;
535
536 // change the pointers to lengths or indexes
537 for (field=fields ; field->name ; field++)
538 {
539 WriteField1 (f, field, (byte *)&temp);
540 }
541
542 // write the block
543 fwrite (&temp, sizeof(temp), 1, f);
544
545 // now write any allocated data following the edict
546 for (field=fields ; field->name ; field++)
547 {
548 WriteField2 (f, field, (byte *)ent);
549 }
550
551 }
552
553 /*
554 ==============
555 WriteLevelLocals
556
557 All pointer variables (except function pointers) must be handled specially.
558 ==============
559 */
WriteLevelLocals(FILE * f)560 void WriteLevelLocals (FILE *f)
561 {
562 field_t *field;
563 level_locals_t temp;
564
565 // all of the ints, floats, and vectors stay as they are
566 temp = level;
567
568 // change the pointers to lengths or indexes
569 for (field=levelfields ; field->name ; field++)
570 {
571 WriteField1 (f, field, (byte *)&temp);
572 }
573
574 // write the block
575 fwrite (&temp, sizeof(temp), 1, f);
576
577 // now write any allocated data following the edict
578 for (field=levelfields ; field->name ; field++)
579 {
580 WriteField2 (f, field, (byte *)&level);
581 }
582 }
583
584
585 /*
586 ==============
587 ReadEdict
588
589 All pointer variables (except function pointers) must be handled specially.
590 ==============
591 */
ReadEdict(FILE * f,edict_t * ent)592 void ReadEdict (FILE *f, edict_t *ent)
593 {
594 field_t *field;
595
596 fread (ent, sizeof(*ent), 1, f);
597
598 for (field=fields ; field->name ; field++)
599 {
600 ReadField (f, field, (byte *)ent);
601 }
602 }
603
604 /*
605 ==============
606 ReadLevelLocals
607
608 All pointer variables (except function pointers) must be handled specially.
609 ==============
610 */
ReadLevelLocals(FILE * f)611 void ReadLevelLocals (FILE *f)
612 {
613 field_t *field;
614
615 fread (&level, sizeof(level), 1, f);
616
617 for (field=levelfields ; field->name ; field++)
618 {
619 ReadField (f, field, (byte *)&level);
620 }
621 }
622
623 /*
624 =================
625 WriteLevel
626
627 =================
628 */
WriteLevel(char * filename)629 void WriteLevel (char *filename)
630 {
631 int i;
632 edict_t *ent;
633 FILE *f;
634 void *base;
635
636 f = fopen (filename, "wb");
637 if (!f)
638 gi.error ("Couldn't open %s", filename);
639
640 // write out edict size for checking
641 i = sizeof(edict_t);
642 fwrite (&i, sizeof(i), 1, f);
643
644 // write out a function pointer for checking
645 base = (void *)InitGame;
646 fwrite (&base, sizeof(base), 1, f);
647
648 // write out level_locals_t
649 WriteLevelLocals (f);
650
651 // write out all the entities
652 for (i=0 ; i<globals.numEdicts ; i++)
653 {
654 ent = &g_edicts[i];
655 if (!ent->inUse)
656 continue;
657 fwrite (&i, sizeof(i), 1, f);
658 WriteEdict (f, ent);
659 }
660 i = -1;
661 fwrite (&i, sizeof(i), 1, f);
662
663 fclose (f);
664 }
665
666
667 /*
668 =================
669 ReadLevel
670
671 SpawnEntities will allready have been called on the
672 level the same way it was when the level was saved.
673
674 That is necessary to get the baselines
675 set up identically.
676
677 The server will have cleared all of the world links before
678 calling ReadLevel.
679
680 No clients are connected yet.
681 =================
682 */
ReadLevel(char * filename)683 void ReadLevel (char *filename)
684 {
685 int entNum;
686 FILE *f;
687 int i;
688 void *base;
689 edict_t *ent;
690
691 f = fopen (filename, "rb");
692 if (!f)
693 gi.error ("Couldn't open %s", filename);
694
695 // free any dynamic memory allocated by loading the level
696 // base state
697 gi.FreeTags (TAG_LEVEL);
698
699 // wipe all the entities
700 memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
701 globals.numEdicts = maxclients->floatVal+1;
702
703 // check edict size
704 fread (&i, sizeof(i), 1, f);
705 if (i != sizeof(edict_t))
706 {
707 fclose (f);
708 gi.error ("ReadLevel: mismatched edict size");
709 }
710
711 // check function pointer base address
712 fread (&base, sizeof(base), 1, f);
713 #ifdef _WIN32
714 if (base != (void *)InitGame)
715 {
716 fclose (f);
717 gi.error ("ReadLevel: function pointers have moved");
718 }
719 #else
720 gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
721 #endif
722
723 // load the level locals
724 ReadLevelLocals (f);
725
726 // load all the entities
727 while (1)
728 {
729 if (fread (&entNum, sizeof(entNum), 1, f) != 1)
730 {
731 fclose (f);
732 gi.error ("ReadLevel: failed to read entNum");
733 }
734 if (entNum == -1)
735 break;
736 if (entNum >= globals.numEdicts)
737 globals.numEdicts = entNum+1;
738
739 ent = &g_edicts[entNum];
740 ReadEdict (f, ent);
741
742 // let the server rebuild world links for this ent
743 memset (&ent->area, 0, sizeof(ent->area));
744 gi.linkentity (ent);
745 }
746
747 fclose (f);
748
749 // mark all clients as unconnected
750 for (i=0 ; i<maxclients->floatVal ; i++)
751 {
752 ent = &g_edicts[i+1];
753 ent->client = game.clients + i;
754 ent->client->pers.connected = qFalse;
755 }
756
757 // do any load time things at this point
758 for (i=0 ; i<globals.numEdicts ; i++)
759 {
760 ent = &g_edicts[i];
761
762 if (!ent->inUse)
763 continue;
764
765 // fire any cross-level triggers
766 if (ent->classname)
767 if (strcmp(ent->classname, "target_crosslevel_target") == 0)
768 ent->nextthink = level.time + ent->delay;
769 }
770 }
771