Räume sv_init.c auf

This commit is contained in:
Yamagi Burmeister 2010-11-26 07:22:46 +00:00
parent c49f21c9d0
commit 6c2ae15351

View file

@ -1,470 +1,505 @@
/* /*
Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
*
This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or modify
modify it under the terms of the GNU General Public License * it under the terms of the GNU General Public License as published by
as published by the Free Software Foundation; either version 2 * the Free Software Foundation; either version 2 of the License, or (at
of the License, or (at your option) any later version. * your option) any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful, but
but WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/ *
* =======================================================================
*
* Server startup.
*
* =======================================================================
*/
#include "header/server.h" #include "header/server.h"
server_static_t svs; // persistant server info server_static_t svs; /* persistant server info */
server_t sv; // local server server_t sv; /* local server */
/* int
================ SV_FindIndex ( char *name, int start, int max, qboolean create )
SV_FindIndex
================
*/
int SV_FindIndex (char *name, int start, int max, qboolean create)
{ {
int i; int i;
if (!name || !name[0])
return 0;
for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++) if ( !name || !name [ 0 ] )
if (!strcmp(sv.configstrings[start+i], name)) {
return i; return ( 0 );
if (!create)
return 0;
if (i == max)
Com_Error (ERR_DROP, "*Index: overflow");
strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
if (sv.state != ss_loading)
{ // send the update to everyone
MSG_WriteChar (&sv.multicast, svc_configstring);
MSG_WriteShort (&sv.multicast, start+i);
MSG_WriteString (&sv.multicast, name);
SV_Multicast (vec3_origin, MULTICAST_ALL_R);
} }
return i; for ( i = 1; i < max && sv.configstrings [ start + i ] [ 0 ]; i++ )
{
if ( !strcmp( sv.configstrings [ start + i ], name ) )
{
return ( i );
}
}
if ( !create )
{
return ( 0 );
}
if ( i == max )
{
Com_Error( ERR_DROP, "*Index: overflow" );
}
strncpy( sv.configstrings [ start + i ], name, sizeof ( sv.configstrings [ i ] ) );
if ( sv.state != ss_loading )
{
/* send the update to everyone */
MSG_WriteChar( &sv.multicast, svc_configstring );
MSG_WriteShort( &sv.multicast, start + i );
MSG_WriteString( &sv.multicast, name );
SV_Multicast( vec3_origin, MULTICAST_ALL_R );
}
return ( i );
} }
int
int SV_ModelIndex (char *name) SV_ModelIndex ( char *name )
{ {
return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true); return ( SV_FindIndex( name, CS_MODELS, MAX_MODELS, true ) );
} }
int SV_SoundIndex (char *name) int
SV_SoundIndex ( char *name )
{ {
return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true); return ( SV_FindIndex( name, CS_SOUNDS, MAX_SOUNDS, true ) );
} }
int SV_ImageIndex (char *name) int
SV_ImageIndex ( char *name )
{ {
return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true); return ( SV_FindIndex( name, CS_IMAGES, MAX_IMAGES, true ) );
} }
/* /*
================ * Entity baselines are used to compress the update messages
SV_CreateBaseline * to the clients -- only the fields that differ from the
* baseline will be transmitted
Entity baselines are used to compress the update messages */
to the clients -- only the fields that differ from the void
baseline will be transmitted SV_CreateBaseline ( void )
================
*/
void SV_CreateBaseline (void)
{ {
edict_t *svent; edict_t *svent;
int entnum; int entnum;
for (entnum = 1; entnum < ge->num_edicts ; entnum++) for ( entnum = 1; entnum < ge->num_edicts; entnum++ )
{ {
svent = EDICT_NUM(entnum); svent = EDICT_NUM( entnum );
if (!svent->inuse)
if ( !svent->inuse )
{
continue; continue;
if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects) }
if ( !svent->s.modelindex && !svent->s.sound && !svent->s.effects )
{
continue; continue;
}
svent->s.number = entnum; svent->s.number = entnum;
// /* take current state as baseline */
// take current state as baseline VectorCopy( svent->s.origin, svent->s.old_origin );
// sv.baselines [ entnum ] = svent->s;
VectorCopy (svent->s.origin, svent->s.old_origin);
sv.baselines[entnum] = svent->s;
} }
} }
void
/* SV_CheckForSavegame ( void )
=================
SV_CheckForSavegame
=================
*/
void SV_CheckForSavegame (void)
{ {
char name[MAX_OSPATH]; char name [ MAX_OSPATH ];
FILE *f; FILE *f;
int i; int i;
if (sv_noreload->value) if ( sv_noreload->value )
{
return; return;
}
if (Cvar_VariableValue ("deathmatch")) if ( Cvar_VariableValue( "deathmatch" ) )
{
return; return;
}
Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name); Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sav", FS_Gamedir(), sv.name );
f = fopen (name, "rb"); f = fopen( name, "rb" );
if (!f)
return; // no savegame
fclose (f); if ( !f )
{
return; /* no savegame */
}
SV_ClearWorld (); fclose( f );
// get configstrings and areaportals SV_ClearWorld();
SV_ReadLevelFile ();
if (!sv.loadgame) /* get configstrings and areaportals */
{ // coming back to a level after being in a different SV_ReadLevelFile();
// level, so run it for ten seconds
// rlava2 was sending too many lightstyles, and overflowing the if ( !sv.loadgame )
// reliable data. temporarily changing the server state to loading {
// prevents these from being passed down. /* coming back to a level after being in a different
server_state_t previousState; // PGM level, so run it for ten seconds */
previousState = sv.state; // PGM server_state_t previousState;
sv.state = ss_loading; // PGM
for (i=0 ; i<100 ; i++)
ge->RunFrame ();
sv.state = previousState; // PGM previousState = sv.state;
sv.state = ss_loading;
for ( i = 0; i < 100; i++ )
{
ge->RunFrame();
}
sv.state = previousState;
} }
} }
/* /*
================ * Change the server to a new map, taking all connected
SV_SpawnServer * clients along with it.
*/
Change the server to a new map, taking all connected void
clients along with it. SV_SpawnServer ( char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame )
================
*/
void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
{ {
int i; int i;
unsigned checksum; unsigned checksum;
if (attractloop) if ( attractloop )
Cvar_Set ("paused", "0"); {
Cvar_Set( "paused", "0" );
}
Com_Printf ("------- server initialization ------\n"); Com_Printf( "------- server initialization ------\n" );
Com_DPrintf ("SpawnServer: %s\n",server); Com_DPrintf( "SpawnServer: %s\n", server );
if (sv.demofile)
FS_FCloseFile ((size_t)sv.demofile);
svs.spawncount++; // any partially connected client will be if ( sv.demofile )
// restarted {
FS_FCloseFile( (size_t) sv.demofile );
}
svs.spawncount++; /* any partially connected client will be restarted */
sv.state = ss_dead; sv.state = ss_dead;
Com_SetServerState (sv.state); Com_SetServerState( sv.state );
// wipe the entire per-level structure /* wipe the entire per-level structure */
memset (&sv, 0, sizeof(sv)); memset( &sv, 0, sizeof ( sv ) );
svs.realtime = 0; svs.realtime = 0;
sv.loadgame = loadgame; sv.loadgame = loadgame;
sv.attractloop = attractloop; sv.attractloop = attractloop;
// save name for levels that don't set message /* save name for levels that don't set message */
strcpy (sv.configstrings[CS_NAME], server); strcpy( sv.configstrings [ CS_NAME ], server );
if (Cvar_VariableValue ("deathmatch"))
if ( Cvar_VariableValue( "deathmatch" ) )
{ {
sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value); sprintf( sv.configstrings [ CS_AIRACCEL ], "%g", sv_airaccelerate->value );
pm_airaccelerate = sv_airaccelerate->value; pm_airaccelerate = sv_airaccelerate->value;
} }
else else
{ {
strcpy(sv.configstrings[CS_AIRACCEL], "0"); strcpy( sv.configstrings [ CS_AIRACCEL ], "0" );
pm_airaccelerate = 0; pm_airaccelerate = 0;
} }
SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); SZ_Init( &sv.multicast, sv.multicast_buf, sizeof ( sv.multicast_buf ) );
strcpy (sv.name, server); strcpy( sv.name, server );
// leave slots at start for clients only /* leave slots at start for clients only */
for (i=0 ; i<maxclients->value ; i++) for ( i = 0; i < maxclients->value; i++ )
{ {
// needs to reconnect /* needs to reconnect */
if (svs.clients[i].state > cs_connected) if ( svs.clients [ i ].state > cs_connected )
svs.clients[i].state = cs_connected; {
svs.clients[i].lastframe = -1; svs.clients [ i ].state = cs_connected;
}
svs.clients [ i ].lastframe = -1;
} }
sv.time = 1000; sv.time = 1000;
strcpy (sv.name, server);
strcpy (sv.configstrings[CS_NAME], server);
if (serverstate != ss_game) strcpy( sv.name, server );
strcpy( sv.configstrings [ CS_NAME ], server );
if ( serverstate != ss_game )
{ {
sv.models[1] = CM_LoadMap ("", false, &checksum); // no real map sv.models [ 1 ] = CM_LoadMap( "", false, &checksum ); /* no real map */
} }
else else
{ {
Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]), Com_sprintf( sv.configstrings [ CS_MODELS + 1 ],
"maps/%s.bsp", server); sizeof ( sv.configstrings [ CS_MODELS + 1 ] ), "maps/%s.bsp", server );
sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum); sv.models [ 1 ] = CM_LoadMap( sv.configstrings [ CS_MODELS + 1 ], false, &checksum );
} }
Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
"%i", checksum);
// Com_sprintf( sv.configstrings [ CS_MAPCHECKSUM ], sizeof ( sv.configstrings [ CS_MAPCHECKSUM ] ),
// clear physics interaction links "%i", checksum );
//
SV_ClearWorld (); /* clear physics interaction links */
SV_ClearWorld();
for (i=1 ; i< CM_NumInlineModels() ; i++)
for ( i = 1; i < CM_NumInlineModels(); i++ )
{ {
Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]), Com_sprintf( sv.configstrings [ CS_MODELS + 1 + i ], sizeof ( sv.configstrings [ CS_MODELS + 1 + i ] ),
"*%i", i); "*%i", i );
sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]); sv.models [ i + 1 ] = CM_InlineModel( sv.configstrings [ CS_MODELS + 1 + i ] );
} }
// /* spawn the rest of the entities on the map */
// spawn the rest of the entities on the map
//
// precache and static commands can be issued during
// map initialization
sv.state = ss_loading; sv.state = ss_loading;
Com_SetServerState (sv.state); Com_SetServerState( sv.state );
// load and spawn all other entities /* load and spawn all other entities */
ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint ); ge->SpawnEntities( sv.name, CM_EntityString(), spawnpoint );
// run two frames to allow everything to settle /* run two frames to allow everything to settle */
ge->RunFrame (); ge->RunFrame();
ge->RunFrame (); ge->RunFrame();
//verify game didn't clobber important stuff /* verify game didn't clobber important stuff */
if ((int)checksum != atoi(sv.configstrings[CS_MAPCHECKSUM])) if ( (int) checksum != atoi( sv.configstrings [ CS_MAPCHECKSUM ] ) )
Com_Error (ERR_DROP, "Game DLL corrupted server configstrings"); {
Com_Error( ERR_DROP, "Game DLL corrupted server configstrings" );
}
// all precaches are complete /* all precaches are complete */
sv.state = serverstate; sv.state = serverstate;
Com_SetServerState (sv.state); Com_SetServerState( sv.state );
// create a baseline for more efficient communications
SV_CreateBaseline ();
// check for a savegame /* create a baseline for more efficient communications */
SV_CheckForSavegame (); SV_CreateBaseline();
// set serverinfo variable /* check for a savegame */
Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); SV_CheckForSavegame();
Cvar_SetValue("windowed_mouse", 1);
Com_Printf ("------------------------------------\n\n"); /* set serverinfo variable */
Cvar_FullSet( "mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET );
Cvar_SetValue( "windowed_mouse", 1 );
Com_Printf( "------------------------------------\n\n" );
} }
/* /*
============== * A brand new game has been started
SV_InitGame */
void
A brand new game has been started SV_InitGame ( void )
==============
*/
void SV_InitGame (void)
{ {
int i; int i;
edict_t *ent; edict_t *ent;
char idmaster[32]; char idmaster [ 32 ];
if (svs.initialized) if ( svs.initialized )
{ {
// cause any connected clients to reconnect /* cause any connected clients to reconnect */
SV_Shutdown ("Server restarted\n", true); SV_Shutdown( "Server restarted\n", true );
} }
#ifndef DEDICATED_ONLY #ifndef DEDICATED_ONLY
else else
{ {
// make sure the client is down /* make sure the client is down */
CL_Drop (); CL_Drop();
SCR_BeginLoadingPlaque (); SCR_BeginLoadingPlaque();
} }
#endif #endif
// get any latched variable changes (maxclients, etc)
Cvar_GetLatchedVars (); /* get any latched variable changes (maxclients, etc) */
Cvar_GetLatchedVars();
svs.initialized = true; svs.initialized = true;
if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch")) if ( Cvar_VariableValue( "coop" ) && Cvar_VariableValue( "deathmatch" ) )
{ {
Com_Printf("Deathmatch and Coop both set, disabling Coop\n"); Com_Printf( "Deathmatch and Coop both set, disabling Coop\n" );
Cvar_FullSet ("coop", "0", CVAR_SERVERINFO | CVAR_LATCH); Cvar_FullSet( "coop", "0", CVAR_SERVERINFO | CVAR_LATCH );
} }
// dedicated servers are can't be single player and are usually DM /* dedicated servers can't be single player and are usually DM
// so unless they explicity set coop, force it to deathmatch so unless they explicity set coop, force it to deathmatch */
if (dedicated->value) if ( dedicated->value )
{ {
if (!Cvar_VariableValue ("coop")) if ( !Cvar_VariableValue( "coop" ) )
Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); {
Cvar_FullSet( "deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH );
}
} }
// init clients /* init clients */
if (Cvar_VariableValue ("deathmatch")) if ( Cvar_VariableValue( "deathmatch" ) )
{ {
if (maxclients->value <= 1) if ( maxclients->value <= 1 )
Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH); {
else if (maxclients->value > MAX_CLIENTS) Cvar_FullSet( "maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH );
Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH); }
else if ( maxclients->value > MAX_CLIENTS )
{
Cvar_FullSet( "maxclients", va( "%i", MAX_CLIENTS ), CVAR_SERVERINFO | CVAR_LATCH );
}
} }
else if (Cvar_VariableValue ("coop")) else if ( Cvar_VariableValue( "coop" ) )
{ {
if (maxclients->value <= 1 || maxclients->value > 4) if ( ( maxclients->value <= 1 ) || ( maxclients->value > 4 ) )
Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); {
Cvar_FullSet( "maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH );
}
} }
else // non-deathmatch, non-coop is one player else /* non-deathmatch, non-coop is one player */
{ {
Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); Cvar_FullSet( "maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH );
} }
svs.spawncount = rand(); svs.spawncount = rand();
svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value); svs.clients = Z_Malloc( sizeof ( client_t ) * maxclients->value );
svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64; svs.num_client_entities = maxclients->value * UPDATE_BACKUP * 64;
svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities); svs.client_entities = Z_Malloc( sizeof ( entity_state_t ) * svs.num_client_entities );
// init network stuff /* init network stuff */
NET_Config ( (maxclients->value > 1) ); NET_Config( ( maxclients->value > 1 ) );
// heartbeats will always be sent to the id master /* heartbeats will always be sent to the id master */
svs.last_heartbeat = -99999; // send immediately svs.last_heartbeat = -99999; /* send immediately */
Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER); Com_sprintf( idmaster, sizeof ( idmaster ), "192.246.40.37:%i", PORT_MASTER );
NET_StringToAdr (idmaster, &master_adr[0]); NET_StringToAdr( idmaster, &master_adr [ 0 ] );
// init game /* init game */
SV_InitGameProgs (); SV_InitGameProgs();
for (i=0 ; i<maxclients->value ; i++)
for ( i = 0; i < maxclients->value; i++ )
{ {
ent = EDICT_NUM(i+1); ent = EDICT_NUM( i + 1 );
ent->s.number = i+1; ent->s.number = i + 1;
svs.clients[i].edict = ent; svs.clients [ i ].edict = ent;
memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); memset( &svs.clients [ i ].lastcmd, 0, sizeof ( svs.clients [ i ].lastcmd ) );
} }
} }
/* /*
====================== * the full syntax is:
SV_Map *
* map [*]<map>$<startspot>+<nextserver>
the full syntax is: *
* command from the console or progs.
map [*]<map>$<startspot>+<nextserver> * Map can also be a.cin, .pcx, or .dm2 file
* Nextserver is used to allow a cinematic to play, then proceed to
command from the console or progs. * another level:
Map can also be a.cin, .pcx, or .dm2 file *
Nextserver is used to allow a cinematic to play, then proceed to * map tram.cin+jail_e3
another level: */
void
map tram.cin+jail_e3 SV_Map ( qboolean attractloop, char *levelstring, qboolean loadgame )
======================
*/
void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
{ {
char level[MAX_QPATH]; char level [ MAX_QPATH ];
char *ch; char *ch;
int l; int l;
char spawnpoint[MAX_QPATH]; char spawnpoint [ MAX_QPATH ];
sv.loadgame = loadgame; sv.loadgame = loadgame;
sv.attractloop = attractloop; sv.attractloop = attractloop;
if (sv.state == ss_dead && !sv.loadgame) if ( ( sv.state == ss_dead ) && !sv.loadgame )
SV_InitGame (); // the game is just starting {
SV_InitGame(); /* the game is just starting */
}
strcpy (level, levelstring); strcpy( level, levelstring );
// if there is a + in the map, set nextserver to the remainder /* if there is a + in the map, set nextserver to the remainder */
ch = strstr(level, "+"); ch = strstr( level, "+" );
if (ch)
if ( ch )
{ {
*ch = 0; *ch = 0;
Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); Cvar_Set( "nextserver", va( "gamemap \"%s\"", ch + 1 ) );
} }
else else
Cvar_Set ("nextserver", ""); {
Cvar_Set( "nextserver", "" );
}
//ZOID special hack for end game screen in coop mode /* hack for end game screen in coop mode */
if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx")) if ( Cvar_VariableValue( "coop" ) && !Q_stricmp( level, "victory.pcx" ) )
Cvar_Set ("nextserver", "gamemap \"*base1\""); {
Cvar_Set( "nextserver", "gamemap \"*base1\"" );
}
// if there is a $, use the remainder as a spawnpoint /* if there is a $, use the remainder as a spawnpoint */
ch = strstr(level, "$"); ch = strstr( level, "$" );
if (ch)
if ( ch )
{ {
*ch = 0; *ch = 0;
strcpy (spawnpoint, ch+1); strcpy( spawnpoint, ch + 1 );
} }
else else
spawnpoint[0] = 0;
// skip the end-of-unit flag if necessary
if (level[0] == '*')
memmove (level, level+1, strlen(level)+1);
l = strlen(level);
if (l > 4 && !strcmp (level+l-4, ".cin") )
{ {
#ifndef DEDICATED_ONLY spawnpoint [ 0 ] = 0;
SCR_BeginLoadingPlaque (); // for local system
#endif
SV_BroadcastCommand ("changing\n");
SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
} }
else if (l > 4 && !strcmp (level+l-4, ".dm2") )
/* skip the end-of-unit flag if necessary */
if ( level [ 0 ] == '*' )
{
memmove( level, level + 1, strlen( level ) + 1 );
}
l = strlen( level );
if ( ( l > 4 ) && !strcmp( level + l - 4, ".cin" ) )
{ {
#ifndef DEDICATED_ONLY #ifndef DEDICATED_ONLY
SCR_BeginLoadingPlaque (); // for local system SCR_BeginLoadingPlaque(); /* for local system */
#endif #endif
SV_BroadcastCommand ("changing\n"); SV_BroadcastCommand( "changing\n" );
SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame); SV_SpawnServer( level, spawnpoint, ss_cinematic, attractloop, loadgame );
} }
else if (l > 4 && !strcmp (level+l-4, ".pcx") ) else if ( ( l > 4 ) && !strcmp( level + l - 4, ".dm2" ) )
{ {
#ifndef DEDICATED_ONLY #ifndef DEDICATED_ONLY
SCR_BeginLoadingPlaque (); // for local system SCR_BeginLoadingPlaque(); /* for local system */
#endif #endif
SV_BroadcastCommand ("changing\n"); SV_BroadcastCommand( "changing\n" );
SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame); SV_SpawnServer( level, spawnpoint, ss_demo, attractloop, loadgame );
}
else if ( ( l > 4 ) && !strcmp( level + l - 4, ".pcx" ) )
{
#ifndef DEDICATED_ONLY
SCR_BeginLoadingPlaque(); /* for local system */
#endif
SV_BroadcastCommand( "changing\n" );
SV_SpawnServer( level, spawnpoint, ss_pic, attractloop, loadgame );
} }
else else
{ {
#ifndef DEDICATED_ONLY #ifndef DEDICATED_ONLY
SCR_BeginLoadingPlaque (); // for local system SCR_BeginLoadingPlaque(); /* for local system */
#endif #endif
SV_BroadcastCommand ("changing\n"); SV_BroadcastCommand( "changing\n" );
SV_SendClientMessages (); SV_SendClientMessages();
SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame); SV_SpawnServer( level, spawnpoint, ss_game, attractloop, loadgame );
Cbuf_CopyToDefer (); Cbuf_CopyToDefer();
} }
SV_BroadcastCommand ("reconnect\n"); SV_BroadcastCommand( "reconnect\n" );
} }