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