home *** CD-ROM | disk | FTP | other *** search
/ Gambler 19 / GAMBLERCD19.BIN / UTILS / 3D / BRONIE / DUAL_LAU.ZIP / src / g_save.c < prev    next >
C/C++ Source or Header  |  1997-11-25  |  16KB  |  692 lines

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