123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "g_local.h"
- #define Function(f) {#f, f}
- mmove_t mmove_reloc;
- field_t fields[] = {
- {"classname", FOFS(classname), F_LSTRING},
- {"model", FOFS(model), F_LSTRING},
- {"spawnflags", FOFS(spawnflags), F_INT},
- {"speed", FOFS(speed), F_FLOAT},
- {"accel", FOFS(accel), F_FLOAT},
- {"decel", FOFS(decel), F_FLOAT},
- {"target", FOFS(target), F_LSTRING},
- {"targetname", FOFS(targetname), F_LSTRING},
- {"pathtarget", FOFS(pathtarget), F_LSTRING},
- {"deathtarget", FOFS(deathtarget), F_LSTRING},
- {"killtarget", FOFS(killtarget), F_LSTRING},
- {"combattarget", FOFS(combattarget), F_LSTRING},
- {"message", FOFS(message), F_LSTRING},
- {"team", FOFS(team), F_LSTRING},
- {"wait", FOFS(wait), F_FLOAT},
- {"delay", FOFS(delay), F_FLOAT},
- {"random", FOFS(random), F_FLOAT},
- {"move_origin", FOFS(move_origin), F_VECTOR},
- {"move_angles", FOFS(move_angles), F_VECTOR},
- {"style", FOFS(style), F_INT},
- {"count", FOFS(count), F_INT},
- {"health", FOFS(health), F_INT},
- {"sounds", FOFS(sounds), F_INT},
- {"light", 0, F_IGNORE},
- {"dmg", FOFS(dmg), F_INT},
- {"mass", FOFS(mass), F_INT},
- {"volume", FOFS(volume), F_FLOAT},
- {"attenuation", FOFS(attenuation), F_FLOAT},
- {"map", FOFS(map), F_LSTRING},
- {"origin", FOFS(s.origin), F_VECTOR},
- {"angles", FOFS(s.angles), F_VECTOR},
- {"angle", FOFS(s.angles), F_ANGLEHACK},
- {"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN},
- {"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN},
- {"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN},
- {"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN},
- {"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN},
- {"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN},
- {"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN},
- {"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN},
- {"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN},
- {"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN},
- {"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN},
- {"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN},
- {"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN},
- {"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN},
- {"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN},
- {"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN},
- {"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN},
- {"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN},
- {"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN},
- {"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN},
- {"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN},
- {"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN},
- {"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN},
- {"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN},
- {"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN},
- {"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN},
- {"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN},
- {"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN},
- {"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN},
- {"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN},
- {"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN},
- {"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN},
- // temp spawn vars -- only valid when the spawn function is called
- {"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
- {"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
- {"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
- {"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
- {"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
- {"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
- //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
- {"item", FOFS(item), F_ITEM},
- {"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
- {"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
- {"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
- {"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
- {"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
- {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
- {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
- {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
- {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
- {0, 0, 0, 0}
- };
- field_t levelfields[] =
- {
- {"changemap", LLOFS(changemap), F_LSTRING},
-
- {"sight_client", LLOFS(sight_client), F_EDICT},
- {"sight_entity", LLOFS(sight_entity), F_EDICT},
- {"sound_entity", LLOFS(sound_entity), F_EDICT},
- {"sound2_entity", LLOFS(sound2_entity), F_EDICT},
- {NULL, 0, F_INT}
- };
- field_t clientfields[] =
- {
- {"pers.weapon", CLOFS(pers.weapon), F_ITEM},
- {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
- {"newweapon", CLOFS(newweapon), F_ITEM},
- {NULL, 0, F_INT}
- };
- /*
- ============
- InitGame
- This will be called when the dll is first loaded, which
- only happens when a new game is started or a save game
- is loaded.
- ============
- */
- void InitGame (void)
- {
- gi.dprintf ("==== InitGame ====\n");
- gun_x = gi.cvar ("gun_x", "0", 0);
- gun_y = gi.cvar ("gun_y", "0", 0);
- gun_z = gi.cvar ("gun_z", "0", 0);
- //FIXME: sv_ prefix is wrong for these
- sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
- sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
- sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
- sv_gravity = gi.cvar ("sv_gravity", "800", 0);
- // noset vars
- dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
- // latched vars
- sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
- gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
- gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
- maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
- maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
- deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
- coop = gi.cvar ("coop", "0", CVAR_LATCH);
- skill = gi.cvar ("skill", "1", CVAR_LATCH);
- maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
- // change anytime vars
- dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
- fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
- timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
- password = gi.cvar ("password", "", CVAR_USERINFO);
- spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO);
- filterban = gi.cvar ("filterban", "1", 0);
- g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
- run_pitch = gi.cvar ("run_pitch", "0.002", 0);
- run_roll = gi.cvar ("run_roll", "0.005", 0);
- bob_up = gi.cvar ("bob_up", "0.005", 0);
- bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
- bob_roll = gi.cvar ("bob_roll", "0.002", 0);
- // flood control
- flood_msgs = gi.cvar ("flood_msgs", "4", 0);
- flood_persecond = gi.cvar ("flood_persecond", "4", 0);
- flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
- // dm map list
- sv_maplist = gi.cvar ("sv_maplist", "", 0);
- // items
- InitItems ();
- Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
- Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
- // initialize all entities for this game
- game.maxentities = maxentities->value;
- g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
- globals.edicts = g_edicts;
- globals.max_edicts = game.maxentities;
- // initialize all clients for this game
- game.maxclients = maxclients->value;
- game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
- globals.num_edicts = game.maxclients+1;
- }
- //=========================================================
- void WriteField1 (FILE *f, field_t *field, byte *base)
- {
- void *p;
- int len;
- int index;
- if (field->flags & FFL_SPAWNTEMP)
- return;
- p = (void *)(base + field->ofs);
- switch (field->type)
- {
- case F_INT:
- case F_FLOAT:
- case F_ANGLEHACK:
- case F_VECTOR:
- case F_IGNORE:
- break;
- case F_LSTRING:
- case F_GSTRING:
- if ( *(char **)p )
- len = strlen(*(char **)p) + 1;
- else
- len = 0;
- *(int *)p = len;
- break;
- case F_EDICT:
- if ( *(edict_t **)p == NULL)
- index = -1;
- else
- index = *(edict_t **)p - g_edicts;
- *(int *)p = index;
- break;
- case F_CLIENT:
- if ( *(gclient_t **)p == NULL)
- index = -1;
- else
- index = *(gclient_t **)p - game.clients;
- *(int *)p = index;
- break;
- case F_ITEM:
- if ( *(edict_t **)p == NULL)
- index = -1;
- else
- index = *(gitem_t **)p - itemlist;
- *(int *)p = index;
- break;
- //relative to code segment
- case F_FUNCTION:
- if (*(byte **)p == NULL)
- index = 0;
- else
- index = *(byte **)p - ((byte *)InitGame);
- *(int *)p = index;
- break;
- //relative to data segment
- case F_MMOVE:
- if (*(byte **)p == NULL)
- index = 0;
- else
- index = *(byte **)p - (byte *)&mmove_reloc;
- *(int *)p = index;
- break;
- default:
- gi.error ("WriteEdict: unknown field type");
- }
- }
- void WriteField2 (FILE *f, field_t *field, byte *base)
- {
- int len;
- void *p;
- if (field->flags & FFL_SPAWNTEMP)
- return;
- p = (void *)(base + field->ofs);
- switch (field->type)
- {
- case F_LSTRING:
- if ( *(char **)p )
- {
- len = strlen(*(char **)p) + 1;
- fwrite (*(char **)p, len, 1, f);
- }
- break;
- }
- }
- void ReadField (FILE *f, field_t *field, byte *base)
- {
- void *p;
- int len;
- int index;
- if (field->flags & FFL_SPAWNTEMP)
- return;
- p = (void *)(base + field->ofs);
- switch (field->type)
- {
- case F_INT:
- case F_FLOAT:
- case F_ANGLEHACK:
- case F_VECTOR:
- case F_IGNORE:
- break;
- case F_LSTRING:
- len = *(int *)p;
- if (!len)
- *(char **)p = NULL;
- else
- {
- *(char **)p = gi.TagMalloc (len, TAG_LEVEL);
- fread (*(char **)p, len, 1, f);
- }
- break;
- case F_EDICT:
- index = *(int *)p;
- if ( index == -1 )
- *(edict_t **)p = NULL;
- else
- *(edict_t **)p = &g_edicts[index];
- break;
- case F_CLIENT:
- index = *(int *)p;
- if ( index == -1 )
- *(gclient_t **)p = NULL;
- else
- *(gclient_t **)p = &game.clients[index];
- break;
- case F_ITEM:
- index = *(int *)p;
- if ( index == -1 )
- *(gitem_t **)p = NULL;
- else
- *(gitem_t **)p = &itemlist[index];
- break;
- //relative to code segment
- case F_FUNCTION:
- index = *(int *)p;
- if ( index == 0 )
- *(byte **)p = NULL;
- else
- *(byte **)p = ((byte *)InitGame) + index;
- break;
- //relative to data segment
- case F_MMOVE:
- index = *(int *)p;
- if (index == 0)
- *(byte **)p = NULL;
- else
- *(byte **)p = (byte *)&mmove_reloc + index;
- break;
- default:
- gi.error ("ReadEdict: unknown field type");
- }
- }
- //=========================================================
- /*
- ==============
- WriteClient
- All pointer variables (except function pointers) must be handled specially.
- ==============
- */
- void WriteClient (FILE *f, gclient_t *client)
- {
- field_t *field;
- gclient_t temp;
-
- // all of the ints, floats, and vectors stay as they are
- temp = *client;
- // change the pointers to lengths or indexes
- for (field=clientfields ; field->name ; field++)
- {
- WriteField1 (f, field, (byte *)&temp);
- }
- // write the block
- fwrite (&temp, sizeof(temp), 1, f);
- // now write any allocated data following the edict
- for (field=clientfields ; field->name ; field++)
- {
- WriteField2 (f, field, (byte *)client);
- }
- }
- /*
- ==============
- ReadClient
- All pointer variables (except function pointers) must be handled specially.
- ==============
- */
- void ReadClient (FILE *f, gclient_t *client)
- {
- field_t *field;
- fread (client, sizeof(*client), 1, f);
- for (field=clientfields ; field->name ; field++)
- {
- ReadField (f, field, (byte *)client);
- }
- }
- /*
- ============
- WriteGame
- This will be called whenever the game goes to a new level,
- and when the user explicitly saves the game.
- Game information include cross level data, like multi level
- triggers, help computer info, and all client states.
- A single player death will automatically restore from the
- last save position.
- ============
- */
- void WriteGame (char *filename, qboolean autosave)
- {
- FILE *f;
- int i;
- char str[16];
- if (!autosave)
- SaveClientData ();
- f = fopen (filename, "wb");
- if (!f)
- gi.error ("Couldn't open %s", filename);
- memset (str, 0, sizeof(str));
- strcpy (str, __DATE__);
- fwrite (str, sizeof(str), 1, f);
- game.autosaved = autosave;
- fwrite (&game, sizeof(game), 1, f);
- game.autosaved = false;
- for (i=0 ; i<game.maxclients ; i++)
- WriteClient (f, &game.clients[i]);
- fclose (f);
- }
- void ReadGame (char *filename)
- {
- FILE *f;
- int i;
- char str[16];
- gi.FreeTags (TAG_GAME);
- f = fopen (filename, "rb");
- if (!f)
- gi.error ("Couldn't open %s", filename);
- fread (str, sizeof(str), 1, f);
- if (strcmp (str, __DATE__))
- {
- fclose (f);
- gi.error ("Savegame from an older version.\n");
- }
- g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
- globals.edicts = g_edicts;
- fread (&game, sizeof(game), 1, f);
- game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
- for (i=0 ; i<game.maxclients ; i++)
- ReadClient (f, &game.clients[i]);
- fclose (f);
- }
- //==========================================================
- /*
- ==============
- WriteEdict
- All pointer variables (except function pointers) must be handled specially.
- ==============
- */
- void WriteEdict (FILE *f, edict_t *ent)
- {
- field_t *field;
- edict_t temp;
- // all of the ints, floats, and vectors stay as they are
- temp = *ent;
- // change the pointers to lengths or indexes
- for (field=fields ; field->name ; field++)
- {
- WriteField1 (f, field, (byte *)&temp);
- }
- // write the block
- fwrite (&temp, sizeof(temp), 1, f);
- // now write any allocated data following the edict
- for (field=fields ; field->name ; field++)
- {
- WriteField2 (f, field, (byte *)ent);
- }
- }
- /*
- ==============
- WriteLevelLocals
- All pointer variables (except function pointers) must be handled specially.
- ==============
- */
- void WriteLevelLocals (FILE *f)
- {
- field_t *field;
- level_locals_t temp;
- // all of the ints, floats, and vectors stay as they are
- temp = level;
- // change the pointers to lengths or indexes
- for (field=levelfields ; field->name ; field++)
- {
- WriteField1 (f, field, (byte *)&temp);
- }
- // write the block
- fwrite (&temp, sizeof(temp), 1, f);
- // now write any allocated data following the edict
- for (field=levelfields ; field->name ; field++)
- {
- WriteField2 (f, field, (byte *)&level);
- }
- }
- /*
- ==============
- ReadEdict
- All pointer variables (except function pointers) must be handled specially.
- ==============
- */
- void ReadEdict (FILE *f, edict_t *ent)
- {
- field_t *field;
- fread (ent, sizeof(*ent), 1, f);
- for (field=fields ; field->name ; field++)
- {
- ReadField (f, field, (byte *)ent);
- }
- }
- /*
- ==============
- ReadLevelLocals
- All pointer variables (except function pointers) must be handled specially.
- ==============
- */
- void ReadLevelLocals (FILE *f)
- {
- field_t *field;
- fread (&level, sizeof(level), 1, f);
- for (field=levelfields ; field->name ; field++)
- {
- ReadField (f, field, (byte *)&level);
- }
- }
- /*
- =================
- WriteLevel
- =================
- */
- void WriteLevel (char *filename)
- {
- int i;
- edict_t *ent;
- FILE *f;
- void *base;
- f = fopen (filename, "wb");
- if (!f)
- gi.error ("Couldn't open %s", filename);
- // write out edict size for checking
- i = sizeof(edict_t);
- fwrite (&i, sizeof(i), 1, f);
- // write out a function pointer for checking
- base = (void *)InitGame;
- fwrite (&base, sizeof(base), 1, f);
- // write out level_locals_t
- WriteLevelLocals (f);
- // write out all the entities
- for (i=0 ; i<globals.num_edicts ; i++)
- {
- ent = &g_edicts[i];
- if (!ent->inuse)
- continue;
- fwrite (&i, sizeof(i), 1, f);
- WriteEdict (f, ent);
- }
- i = -1;
- fwrite (&i, sizeof(i), 1, f);
- fclose (f);
- }
- /*
- =================
- ReadLevel
- SpawnEntities will allready have been called on the
- level the same way it was when the level was saved.
- That is necessary to get the baselines
- set up identically.
- The server will have cleared all of the world links before
- calling ReadLevel.
- No clients are connected yet.
- =================
- */
- void ReadLevel (char *filename)
- {
- int entnum;
- FILE *f;
- int i;
- void *base;
- edict_t *ent;
- f = fopen (filename, "rb");
- if (!f)
- gi.error ("Couldn't open %s", filename);
- // free any dynamic memory allocated by loading the level
- // base state
- gi.FreeTags (TAG_LEVEL);
- // wipe all the entities
- memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
- globals.num_edicts = maxclients->value+1;
- // check edict size
- fread (&i, sizeof(i), 1, f);
- if (i != sizeof(edict_t))
- {
- fclose (f);
- gi.error ("ReadLevel: mismatched edict size");
- }
- // check function pointer base address
- fread (&base, sizeof(base), 1, f);
- #ifdef _WIN32
- if (base != (void *)InitGame)
- {
- fclose (f);
- gi.error ("ReadLevel: function pointers have moved");
- }
- #else
- gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
- #endif
- // load the level locals
- ReadLevelLocals (f);
- // load all the entities
- while (1)
- {
- if (fread (&entnum, sizeof(entnum), 1, f) != 1)
- {
- fclose (f);
- gi.error ("ReadLevel: failed to read entnum");
- }
- if (entnum == -1)
- break;
- if (entnum >= globals.num_edicts)
- globals.num_edicts = entnum+1;
- ent = &g_edicts[entnum];
- ReadEdict (f, ent);
- // let the server rebuild world links for this ent
- memset (&ent->area, 0, sizeof(ent->area));
- gi.linkentity (ent);
- }
- fclose (f);
- // mark all clients as unconnected
- for (i=0 ; i<maxclients->value ; i++)
- {
- ent = &g_edicts[i+1];
- ent->client = game.clients + i;
- ent->client->pers.connected = false;
- }
- // do any load time things at this point
- for (i=0 ; i<globals.num_edicts ; i++)
- {
- ent = &g_edicts[i];
- if (!ent->inuse)
- continue;
- // fire any cross-level triggers
- if (ent->classname)
- if (strcmp(ent->classname, "target_crosslevel_target") == 0)
- ent->nextthink = level.time + ent->delay;
- }
- }
|