2009-02-28 14:41:18 +00:00
|
|
|
/*
|
2010-11-26 07:22:46 +00:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* =======================================================================
|
|
|
|
*
|
|
|
|
* Server startup.
|
|
|
|
*
|
|
|
|
* =======================================================================
|
|
|
|
*/
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-25 15:46:36 +00:00
|
|
|
#include "header/server.h"
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
server_static_t svs; /* persistant server info */
|
|
|
|
server_t sv; /* local server */
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
int
|
|
|
|
SV_FindIndex ( char *name, int start, int max, qboolean create )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( !name || !name [ 0 ] )
|
|
|
|
{
|
|
|
|
return ( 0 );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
for ( i = 1; i < max && sv.configstrings [ start + i ] [ 0 ]; i++ )
|
|
|
|
{
|
|
|
|
if ( !strcmp( sv.configstrings [ start + i ], name ) )
|
|
|
|
{
|
|
|
|
return ( i );
|
|
|
|
}
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( !create )
|
|
|
|
{
|
|
|
|
return ( 0 );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( i == max )
|
|
|
|
{
|
|
|
|
Com_Error( ERR_DROP, "*Index: overflow" );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
strncpy( sv.configstrings [ start + i ], name, sizeof ( sv.configstrings [ i ] ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( sv.state != ss_loading )
|
2012-04-29 13:57:33 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
/* 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 );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
return ( i );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
int
|
|
|
|
SV_ModelIndex ( char *name )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
return ( SV_FindIndex( name, CS_MODELS, MAX_MODELS, true ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
int
|
|
|
|
SV_SoundIndex ( char *name )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
return ( SV_FindIndex( name, CS_SOUNDS, MAX_SOUNDS, true ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
int
|
|
|
|
SV_ImageIndex ( char *name )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
return ( SV_FindIndex( name, CS_IMAGES, MAX_IMAGES, true ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-11-26 07:22:46 +00:00
|
|
|
* Entity baselines are used to compress the update messages
|
|
|
|
* to the clients -- only the fields that differ from the
|
|
|
|
* baseline will be transmitted
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SV_CreateBaseline ( void )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
edict_t *svent;
|
|
|
|
int entnum;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
for ( entnum = 1; entnum < ge->num_edicts; entnum++ )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
svent = EDICT_NUM( entnum );
|
|
|
|
|
|
|
|
if ( !svent->inuse )
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2010-11-26 07:22:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( !svent->s.modelindex && !svent->s.sound && !svent->s.effects )
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
continue;
|
2010-11-26 07:22:46 +00:00
|
|
|
}
|
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
svent->s.number = entnum;
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* take current state as baseline */
|
|
|
|
VectorCopy( svent->s.origin, svent->s.old_origin );
|
|
|
|
sv.baselines [ entnum ] = svent->s;
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
void
|
|
|
|
SV_CheckForSavegame ( void )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
char name [ MAX_OSPATH ];
|
|
|
|
FILE *f;
|
|
|
|
int i;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( sv_noreload->value )
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
2010-11-26 07:22:46 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( Cvar_VariableValue( "deathmatch" ) )
|
|
|
|
{
|
2009-02-28 14:41:18 +00:00
|
|
|
return;
|
2010-11-26 07:22:46 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sav", FS_Gamedir(), sv.name );
|
|
|
|
f = fopen( name, "rb" );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( !f )
|
|
|
|
{
|
|
|
|
return; /* no savegame */
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose( f );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
SV_ClearWorld();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* get configstrings and areaportals */
|
|
|
|
SV_ReadLevelFile();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( !sv.loadgame )
|
2012-04-29 13:57:33 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
/* coming back to a level after being in a different
|
|
|
|
level, so run it for ten seconds */
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
server_state_t previousState;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
previousState = sv.state;
|
|
|
|
sv.state = ss_loading;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
for ( i = 0; i < 100; i++ )
|
|
|
|
{
|
|
|
|
ge->RunFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
sv.state = previousState;
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-11-26 07:22:46 +00:00
|
|
|
* Change the server to a new map, taking all connected
|
|
|
|
* clients along with it.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SV_SpawnServer ( char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
int i;
|
|
|
|
unsigned checksum;
|
|
|
|
|
|
|
|
if ( attractloop )
|
|
|
|
{
|
|
|
|
Cvar_Set( "paused", "0" );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_Printf( "------- server initialization ------\n" );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_DPrintf( "SpawnServer: %s\n", server );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( sv.demofile )
|
|
|
|
{
|
|
|
|
FS_FCloseFile( (size_t) sv.demofile );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
svs.spawncount++; /* any partially connected client will be restarted */
|
2009-02-28 14:41:18 +00:00
|
|
|
sv.state = ss_dead;
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_SetServerState( sv.state );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* wipe the entire per-level structure */
|
|
|
|
memset( &sv, 0, sizeof ( sv ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
svs.realtime = 0;
|
|
|
|
sv.loadgame = loadgame;
|
|
|
|
sv.attractloop = attractloop;
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* save name for levels that don't set message */
|
|
|
|
strcpy( sv.configstrings [ CS_NAME ], server );
|
|
|
|
|
|
|
|
if ( Cvar_VariableValue( "deathmatch" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
sprintf( sv.configstrings [ CS_AIRACCEL ], "%g", sv_airaccelerate->value );
|
2009-02-28 14:41:18 +00:00
|
|
|
pm_airaccelerate = sv_airaccelerate->value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
strcpy( sv.configstrings [ CS_AIRACCEL ], "0" );
|
2009-02-28 14:41:18 +00:00
|
|
|
pm_airaccelerate = 0;
|
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
SZ_Init( &sv.multicast, sv.multicast_buf, sizeof ( sv.multicast_buf ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
strcpy( sv.name, server );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* leave slots at start for clients only */
|
|
|
|
for ( i = 0; i < maxclients->value; i++ )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
/* needs to reconnect */
|
|
|
|
if ( svs.clients [ i ].state > cs_connected )
|
|
|
|
{
|
|
|
|
svs.clients [ i ].state = cs_connected;
|
|
|
|
}
|
|
|
|
|
|
|
|
svs.clients [ i ].lastframe = -1;
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sv.time = 1000;
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
strcpy( sv.name, server );
|
|
|
|
strcpy( sv.configstrings [ CS_NAME ], server );
|
|
|
|
|
|
|
|
if ( serverstate != ss_game )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
sv.models [ 1 ] = CM_LoadMap( "", false, &checksum ); /* no real map */
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-04-29 13:57:33 +00:00
|
|
|
Com_sprintf( sv.configstrings [ CS_MODELS + 1 ],
|
2010-11-26 07:22:46 +00:00
|
|
|
sizeof ( sv.configstrings [ CS_MODELS + 1 ] ), "maps/%s.bsp", server );
|
|
|
|
sv.models [ 1 ] = CM_LoadMap( sv.configstrings [ CS_MODELS + 1 ], false, &checksum );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_sprintf( sv.configstrings [ CS_MAPCHECKSUM ], sizeof ( sv.configstrings [ CS_MAPCHECKSUM ] ),
|
|
|
|
"%i", checksum );
|
|
|
|
|
|
|
|
/* clear physics interaction links */
|
|
|
|
SV_ClearWorld();
|
|
|
|
|
|
|
|
for ( i = 1; i < CM_NumInlineModels(); i++ )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_sprintf( sv.configstrings [ CS_MODELS + 1 + i ], sizeof ( sv.configstrings [ CS_MODELS + 1 + i ] ),
|
|
|
|
"*%i", i );
|
|
|
|
sv.models [ i + 1 ] = CM_InlineModel( sv.configstrings [ CS_MODELS + 1 + i ] );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* spawn the rest of the entities on the map */
|
2009-02-28 14:41:18 +00:00
|
|
|
sv.state = ss_loading;
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_SetServerState( sv.state );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* load and spawn all other entities */
|
|
|
|
ge->SpawnEntities( sv.name, CM_EntityString(), spawnpoint );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* run two frames to allow everything to settle */
|
|
|
|
ge->RunFrame();
|
|
|
|
ge->RunFrame();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* verify game didn't clobber important stuff */
|
2012-06-02 07:31:27 +00:00
|
|
|
if ( (int) checksum != (int)strtol( sv.configstrings [ CS_MAPCHECKSUM ], (char **)NULL, 10 ) )
|
2010-11-26 07:22:46 +00:00
|
|
|
{
|
|
|
|
Com_Error( ERR_DROP, "Game DLL corrupted server configstrings" );
|
|
|
|
}
|
2009-03-04 11:13:16 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* all precaches are complete */
|
2009-02-28 14:41:18 +00:00
|
|
|
sv.state = serverstate;
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_SetServerState( sv.state );
|
|
|
|
|
|
|
|
/* create a baseline for more efficient communications */
|
|
|
|
SV_CreateBaseline();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* check for a savegame */
|
|
|
|
SV_CheckForSavegame();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* set serverinfo variable */
|
|
|
|
Cvar_FullSet( "mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET );
|
|
|
|
Cvar_SetValue( "windowed_mouse", 1 );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_Printf( "------------------------------------\n\n" );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-11-26 07:22:46 +00:00
|
|
|
* A brand new game has been started
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SV_InitGame ( void )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
int i;
|
|
|
|
edict_t *ent;
|
|
|
|
char idmaster [ 32 ];
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( svs.initialized )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
/* cause any connected clients to reconnect */
|
|
|
|
SV_Shutdown( "Server restarted\n", true );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-11-26 07:22:46 +00:00
|
|
|
|
2009-03-04 11:13:16 +00:00
|
|
|
#ifndef DEDICATED_ONLY
|
2009-02-28 14:41:18 +00:00
|
|
|
else
|
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
/* make sure the client is down */
|
|
|
|
CL_Drop();
|
|
|
|
SCR_BeginLoadingPlaque();
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2009-03-04 11:13:16 +00:00
|
|
|
#endif
|
2010-11-26 07:22:46 +00:00
|
|
|
|
|
|
|
/* get any latched variable changes (maxclients, etc) */
|
|
|
|
Cvar_GetLatchedVars();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
svs.initialized = true;
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( Cvar_VariableValue( "coop" ) && Cvar_VariableValue( "deathmatch" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
Com_Printf( "Deathmatch and Coop both set, disabling Coop\n" );
|
|
|
|
Cvar_FullSet( "coop", "0", CVAR_SERVERINFO | CVAR_LATCH );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2012-04-29 13:57:33 +00:00
|
|
|
/* dedicated servers can't be single player and are usually DM
|
2010-11-26 07:22:46 +00:00
|
|
|
so unless they explicity set coop, force it to deathmatch */
|
|
|
|
if ( dedicated->value )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( !Cvar_VariableValue( "coop" ) )
|
|
|
|
{
|
|
|
|
Cvar_FullSet( "deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* init clients */
|
|
|
|
if ( Cvar_VariableValue( "deathmatch" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( maxclients->value <= 1 )
|
|
|
|
{
|
|
|
|
Cvar_FullSet( "maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH );
|
|
|
|
}
|
|
|
|
else if ( maxclients->value > MAX_CLIENTS )
|
|
|
|
{
|
|
|
|
Cvar_FullSet( "maxclients", va( "%i", MAX_CLIENTS ), CVAR_SERVERINFO | CVAR_LATCH );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-11-26 07:22:46 +00:00
|
|
|
else if ( Cvar_VariableValue( "coop" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( ( maxclients->value <= 1 ) || ( maxclients->value > 4 ) )
|
|
|
|
{
|
|
|
|
Cvar_FullSet( "maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-11-26 07:22:46 +00:00
|
|
|
else /* non-deathmatch, non-coop is one player */
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
Cvar_FullSet( "maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2012-06-02 09:55:12 +00:00
|
|
|
svs.spawncount = randk();
|
2010-11-26 07:22:46 +00:00
|
|
|
svs.clients = Z_Malloc( sizeof ( client_t ) * maxclients->value );
|
|
|
|
svs.num_client_entities = maxclients->value * UPDATE_BACKUP * 64;
|
|
|
|
svs.client_entities = Z_Malloc( sizeof ( entity_state_t ) * svs.num_client_entities );
|
|
|
|
|
|
|
|
/* init network stuff */
|
|
|
|
NET_Config( ( maxclients->value > 1 ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* heartbeats will always be sent to the id master */
|
|
|
|
svs.last_heartbeat = -99999; /* send immediately */
|
|
|
|
Com_sprintf( idmaster, sizeof ( idmaster ), "192.246.40.37:%i", PORT_MASTER );
|
|
|
|
NET_StringToAdr( idmaster, &master_adr [ 0 ] );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* init game */
|
|
|
|
SV_InitGameProgs();
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
for ( i = 0; i < maxclients->value; i++ )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
ent = EDICT_NUM( i + 1 );
|
|
|
|
ent->s.number = i + 1;
|
|
|
|
svs.clients [ i ].edict = ent;
|
|
|
|
memset( &svs.clients [ i ].lastcmd, 0, sizeof ( svs.clients [ i ].lastcmd ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-11-26 07:22:46 +00:00
|
|
|
* the full syntax is:
|
|
|
|
*
|
|
|
|
* map [*]<map>$<startspot>+<nextserver>
|
|
|
|
*
|
|
|
|
* command from the console or progs.
|
|
|
|
* Map can also be a.cin, .pcx, or .dm2 file
|
|
|
|
* Nextserver is used to allow a cinematic to play, then proceed to
|
|
|
|
* another level:
|
|
|
|
*
|
|
|
|
* map tram.cin+jail_e3
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SV_Map ( qboolean attractloop, char *levelstring, qboolean loadgame )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
char level [ MAX_QPATH ];
|
|
|
|
char *ch;
|
|
|
|
int l;
|
|
|
|
char spawnpoint [ MAX_QPATH ];
|
2009-02-28 14:41:18 +00:00
|
|
|
|
|
|
|
sv.loadgame = loadgame;
|
|
|
|
sv.attractloop = attractloop;
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( ( sv.state == ss_dead ) && !sv.loadgame )
|
|
|
|
{
|
|
|
|
SV_InitGame(); /* the game is just starting */
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
strcpy( level, levelstring );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* if there is a + in the map, set nextserver to the remainder */
|
|
|
|
ch = strstr( level, "+" );
|
|
|
|
|
|
|
|
if ( ch )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
|
|
|
*ch = 0;
|
2010-11-26 07:22:46 +00:00
|
|
|
Cvar_Set( "nextserver", va( "gamemap \"%s\"", ch + 1 ) );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
else
|
2010-11-26 07:22:46 +00:00
|
|
|
{
|
|
|
|
Cvar_Set( "nextserver", "" );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* hack for end game screen in coop mode */
|
|
|
|
if ( Cvar_VariableValue( "coop" ) && !Q_stricmp( level, "victory.pcx" ) )
|
|
|
|
{
|
|
|
|
Cvar_Set( "nextserver", "gamemap \"*base1\"" );
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* if there is a $, use the remainder as a spawnpoint */
|
|
|
|
ch = strstr( level, "$" );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( ch )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
|
|
|
*ch = 0;
|
2010-11-26 07:22:46 +00:00
|
|
|
strcpy( spawnpoint, ch + 1 );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
else
|
2010-11-26 07:22:46 +00:00
|
|
|
{
|
|
|
|
spawnpoint [ 0 ] = 0;
|
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
/* skip the end-of-unit flag if necessary */
|
|
|
|
if ( level [ 0 ] == '*' )
|
|
|
|
{
|
|
|
|
memmove( level, level + 1, strlen( level ) + 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
l = strlen( level );
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
if ( ( l > 4 ) && !strcmp( level + l - 4, ".cin" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2010-11-26 07:22:46 +00:00
|
|
|
#ifndef DEDICATED_ONLY
|
|
|
|
SCR_BeginLoadingPlaque(); /* for local system */
|
2009-03-04 11:13:16 +00:00
|
|
|
#endif
|
2010-11-26 07:22:46 +00:00
|
|
|
SV_BroadcastCommand( "changing\n" );
|
|
|
|
SV_SpawnServer( level, spawnpoint, ss_cinematic, attractloop, loadgame );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-11-26 07:22:46 +00:00
|
|
|
else if ( ( l > 4 ) && !strcmp( level + l - 4, ".dm2" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2009-03-04 11:13:16 +00:00
|
|
|
#ifndef DEDICATED_ONLY
|
2010-11-26 07:22:46 +00:00
|
|
|
SCR_BeginLoadingPlaque(); /* for local system */
|
2009-03-04 11:13:16 +00:00
|
|
|
#endif
|
2010-11-26 07:22:46 +00:00
|
|
|
SV_BroadcastCommand( "changing\n" );
|
|
|
|
SV_SpawnServer( level, spawnpoint, ss_demo, attractloop, loadgame );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-11-26 07:22:46 +00:00
|
|
|
else if ( ( l > 4 ) && !strcmp( level + l - 4, ".pcx" ) )
|
2009-02-28 14:41:18 +00:00
|
|
|
{
|
2009-03-04 11:13:16 +00:00
|
|
|
#ifndef DEDICATED_ONLY
|
2010-11-26 07:22:46 +00:00
|
|
|
SCR_BeginLoadingPlaque(); /* for local system */
|
2009-03-04 11:13:16 +00:00
|
|
|
#endif
|
2010-11-26 07:22:46 +00:00
|
|
|
SV_BroadcastCommand( "changing\n" );
|
|
|
|
SV_SpawnServer( level, spawnpoint, ss_pic, attractloop, loadgame );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-04 11:13:16 +00:00
|
|
|
#ifndef DEDICATED_ONLY
|
2010-11-26 07:22:46 +00:00
|
|
|
SCR_BeginLoadingPlaque(); /* for local system */
|
2009-03-04 11:13:16 +00:00
|
|
|
#endif
|
2010-11-26 07:22:46 +00:00
|
|
|
SV_BroadcastCommand( "changing\n" );
|
|
|
|
SV_SendClientMessages();
|
|
|
|
SV_SpawnServer( level, spawnpoint, ss_game, attractloop, loadgame );
|
|
|
|
Cbuf_CopyToDefer();
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 07:22:46 +00:00
|
|
|
SV_BroadcastCommand( "reconnect\n" );
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|