📄 g_spawn.cpp
字号:
int c2;
c = 0;
c2 = 0;
for( e = active_edicts.next; e != &active_edicts; e = next )
{
assert( e );
assert( e->inuse );
assert( e->entity );
next = e->next;
if ( e == g_edicts )
{
continue;
}
ent = e->entity;
if ( !ent->moveteam.length() )
{
continue;
}
if ( ent->flags & FL_TEAMSLAVE )
{
continue;
}
chain = ent;
ent->teammaster = ent;
c++;
c2++;
for( e2 = next; e2 != &active_edicts; e2 = next2 )
{
assert( e2 );
assert( e2->inuse );
assert( e2->entity );
next2 = e2->next;
ent2 = e2->entity;
if ( !ent2->moveteam.length() )
{
continue;
}
if ( ent2->flags & FL_TEAMSLAVE )
{
continue;
}
if ( ent->moveteam == ent2->moveteam )
{
c2++;
chain->teamchain = ent2;
ent2->teammaster = ent;
chain = ent2;
ent2->flags |= FL_TEAMSLAVE;
}
}
}
gi.dprintf( "%i teams with %i entities\n", c, c2 );
}
/*
==============
G_LevelShutdown
Get rid of anything left over from the last level
==============
*/
void G_LevelShutdown
(
void
)
{
PathManager.SavePaths();
assert( active_edicts.next );
assert( active_edicts.next->prev = &active_edicts );
assert( active_edicts.prev );
assert( active_edicts.prev->next = &active_edicts );
assert( free_edicts.next );
assert( free_edicts.next->prev == &free_edicts );
assert( free_edicts.prev );
assert( free_edicts.prev->next == &free_edicts );
while( active_edicts.next != &active_edicts )
{
assert( active_edicts.next != &free_edicts );
assert( active_edicts.prev != &free_edicts );
assert( active_edicts.next );
assert( active_edicts.next->prev = &active_edicts );
assert( active_edicts.prev );
assert( active_edicts.prev->next = &active_edicts );
assert( free_edicts.next );
assert( free_edicts.next->prev == &free_edicts );
assert( free_edicts.prev );
assert( free_edicts.prev->next == &free_edicts );
if ( active_edicts.next->entity )
{
delete active_edicts.next->entity;
}
else
{
G_FreeEdict( active_edicts.next );
}
}
globals.num_edicts = game.maxclients + 1;
// Reset the gravity paths
gravPathManager.Reset();
// close all the scripts
Director.CloseScript();
// invalidate player readiness
Director.PlayerNotReady();
// clearout any waiting events
G_ClearEventList();
gi.FreeTags( TAG_LEVEL );
}
/*
==============
G_ResetEdicts
==============
*/
void G_ResetEdicts
(
void
)
{
int i;
memset( g_edicts, 0, game.maxentities * sizeof( g_edicts[ 0 ] ) );
// Add all the edicts to the free list
LL_Reset( &free_edicts, next, prev );
LL_Reset( &active_edicts, next, prev );
for( i = 0; i < game.maxentities; i++ )
{
LL_Add( &free_edicts, &g_edicts[ i ], next, prev );
}
for (i=0 ; i<game.maxclients ; i++)
{
// set client fields on player ents
g_edicts[ i + 1 ].client = game.clients + i;
G_InitClientResp (&game.clients[i]);
}
globals.num_edicts = game.maxclients + 1;
}
/*
==============
G_MapInit
Set up for a new map. This is called for loading savegames, so anything done here should
be compatible with G_ReadGame.
==============
*/
void G_MapInit
(
const char *mapname
)
{
G_ClearEventList();
PathManager.Init( mapname );
// init level and console script variables
consoleVars.ClearList();
levelVars.ClearList();
}
/*
==============
G_LevelStart
Does all post-spawning setup. This is NOT called for savegames.
==============
*/
void G_LevelStart
(
void
)
{
ScriptThread *gamescript;
const char *scriptname;
// initialize secrets
levelVars.SetVariable( "total_secrets", level.total_secrets );
levelVars.SetVariable( "found_secrets", level.found_secrets );
G_FindTeams();
// Create the mission computer
consoleManager.CreateMissionComputer();
// call the precache scripts
G_Precache();
//
// start executing the game script
//
scriptname = ScriptLib.GetGameScript();
if ( scriptname && scriptname[ 0 ] )
{
gamescript = Director.CreateThread( scriptname, LEVEL_SCRIPT );
if ( gamescript )
{
// start at the end of this frame
gamescript->Start( 0 );
}
}
}
/*
==============
G_Precache
Calls precache scripts
==============
*/
void G_Precache
(
void
)
{
const char *scriptname;
int i;
//
// load in global0-9.scr
//
for( i = 0; i < 10; i++ )
{
G_LoadAndExecScript( va( "global/global%i.scr", i ) );
}
//
// load in precache0-9.scr
//
if ( precache->value )
{
for( i = 0; i < 10; i++ )
{
G_LoadAndExecScript( va( "global/precache%i.scr", i ) );
}
}
//
// load in players0-9.scr
//
for( i = 0; i< 10; i++ )
{
G_LoadAndExecScript( va( "global/players%i.scr", i ) );
}
//
// load in universal_script.scr
//
G_LoadAndExecScript( "global/universal_script.scr", "precache:" );
//
// precache for the game script
//
scriptname = ScriptLib.GetGameScript();
if ( scriptname && scriptname[ 0 ] )
{
G_LoadAndExecScript( scriptname, "precache:" );
}
}
/*
==============
G_SpawnEntities
Creates a server's entity / program execution context by
parsing textual entity definitions out of an ent file.
==============
*/
void G_SpawnEntities
(
const char *mapname,
const char *entities,
const char *spawnpoint
)
{
int inhibit;
const char *com_token;
float skill_level;
const char *value;
int spawnflags;
qboolean world_spawned;
cvar_t *lowdetail;
int i=0;
#if 0
Class *obj;
Entity *ent;
#endif
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
lowdetail = gi.cvar( "r_lowdetail", "0", CVAR_ARCHIVE );
// Init the level variables
level = level_locals_t();
level.mapname = mapname;
game.spawnpoint = spawnpoint;
if ( !LoadingServer )
{
// Get rid of anything left over from the last level
G_LevelShutdown();
G_ResetEdicts();
// Set up for a new map
G_MapInit( mapname );
}
// Init surface manager & consoles
surfaceManager.Reset();
globals.num_surfaces = 0;
memset (g_surfaces, 0, game.maxsurfaces * sizeof (g_surfaces[0]));
globals.num_consoles = 0;
memset (g_consoles, 0, game.maxconsoles * sizeof (g_consoles[0]));
skill_level = floor( skill->value );
skill_level = bound( skill_level, 0, 3 );
if ( skill->value != skill_level )
{
gi.cvar_forceset( "skill", va( "%f", skill_level ) );
}
gameVars.SetVariable( "skill", skill_level );
// reset out count of the number of game traces
sv_numtraces = 0;
level.playerfrozen = false;
inhibit = 0;
world_spawned = false;
// parse ents
while (1)
{
// parse the opening brace
com_token = COM_Parse (&entities);
if (!entities)
{
break;
}
if (com_token[0] != '{')
{
gi.error ("G_LoadFromFile: found %s when expecting {",com_token);
}
i++;
if ( !( i % 20 ) )
gi.IncrementStatusCount( 20 );
entities = G_ParseEdict (entities);
// remove things (except the world) from different skill levels or deathmatch
value = G_GetSpawnArg( "spawnflags" );
if ( world_spawned && value )
{
spawnflags = atoi( value );
if (deathmatch->value)
{
if ( spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
{
inhibit++;
continue;
}
}
else
{
if (
((skill->value == 0) && (spawnflags & SPAWNFLAG_NOT_EASY)) ||
((skill->value == 1) && (spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
(((skill->value == 2) || (skill->value == 3)) && (spawnflags & SPAWNFLAG_NOT_HARD) ||
( coop->value && (spawnflags & SPAWNFLAG_NOT_COOP) )) ||
( !developer->value && ( spawnflags & SPAWNFLAG_DEVELOPMENT ) ) ||
( lowdetail->value && ( spawnflags & SPAWNFLAG_DETAIL ) )
)
{
inhibit++;
continue;
}
}
}
game.force_entnum = !world_spawned;
game.spawn_entnum = 0;
G_CallSpawn();
world_spawned = true;
#if 0
// have to fix G_CallSpawn so that freed entities are accounted for
if ( obj && obj->isSubclassOf( Entity ) )
{
ent = ( Entity * )obj;
// Sanity check to see if we're expecting a B-Model
assert( !( ( ent->edict->solid == SOLID_BSP ) && !ent->edict->s.modelindex ) );
if ( ( ent->edict->solid == SOLID_BSP ) && !ent->edict->s.modelindex )
{
if ( ent->edict->s.number == 0 )
{
gi.error( "No model for worldspawn!" );
}
else
{
gi.dprintf( "Deleting %s with SOLID_BSP and no model\n", ent->getClassID() );
delete ent;
}
}
}
#endif
}
game.force_entnum = false;
gi.dprintf ("%i entities inhibited\n", inhibit);
G_InitSpawnArguments();
if ( !LoadingServer || game.autosaved )
{
G_LevelStart();
}
}
/*
=================
G_Spawn
Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
edict_t *G_Spawn
(
void
)
{
int i;
edict_t *e;
e = &g_edicts[ ( int )maxclients->value + 1 ];
for ( i = maxclients->value + 1; i < globals.num_edicts; i++, e++ )
{
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if ( !e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
{
assert( e->next );
assert( e->prev );
LL_Remove( e, next, prev );
G_InitEdict( e );
assert( active_edicts.next );
assert( active_edicts.prev );
LL_Add( &active_edicts, e, next, prev );
assert( e->next );
assert( e->prev );
return e;
}
}
if ( i == game.maxentities )
{
gi.error( "G_Spawn: no free edicts" );
}
globals.num_edicts++;
assert( e->next );
assert( e->prev );
LL_Remove( e, next, prev );
G_InitEdict( e );
assert( active_edicts.next );
assert( active_edicts.prev );
LL_Add( &active_edicts, e, next, prev );
assert( e->next );
assert( e->prev );
assert( e->next != &free_edicts );
assert( e->prev != &free_edicts );
return e;
}
/*
=================
G_FreeEdict
Marks the edict as free
=================
*/
void G_FreeEdict
(
edict_t *ed
)
{
gclient_t *client;
assert( ed != &free_edicts );
// unlink from world
gi.unlinkentity ( ed );
assert( ed->next );
assert( ed->prev );
if ( level.next_edict == ed )
{
level.next_edict = ed->next;
}
LL_Remove( ed, next, prev );
assert( ed->next == ed );
assert( ed->prev == ed );
assert( free_edicts.next );
assert( free_edicts.prev );
client = ed->client;
memset( ed, 0, sizeof( *ed ) );
ed->client = client;
ed->freetime = level.time;
ed->inuse = false;
ed->s.number = ed - g_edicts;
assert( free_edicts.next );
assert( free_edicts.prev );
LL_Add( &free_edicts, ed, next, prev );
assert( ed->next );
assert( ed->prev );
}
/*
==============
G_InitClientPersistant
This is only called when the game first initializes in single player,
but is called after each death and level change in deathmatch
==============
*/
void G_InitClientPersistant
(
gclient_t *client
)
{
memset( &client->pers, 0, sizeof( client->pers ) );
client->pers.health = 100;
client->pers.max_health = 100;
}
void G_InitClientResp
(
gclient_t *client
)
{
memset( &client->resp, 0, sizeof( client->resp ) );
client->resp.enterframe = level.framenum;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -