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