2004-08-23 00:15:46 +00:00
/*
Copyright ( C ) 1996 - 1997 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
2005-07-03 15:16:20 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-23 00:15:46 +00:00
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 "qwsvdef.h"
2004-11-29 01:21:00 +00:00
# ifndef CLIENTONLY
2004-08-23 00:15:46 +00:00
extern int total_loading_size , current_loading_size , loading_stage ;
char * T_GetString ( int num ) ;
2005-03-20 02:57:11 +00:00
# define Q2EDICT_NUM(i) (q2edict_t*)((char *)ge->edicts+(i)*ge->edict_size)
2004-08-23 00:15:46 +00:00
server_static_t svs ; // persistant server info
server_t sv ; // local server
char localmodels [ MAX_MODELS ] [ 5 ] ; // inline model names for precache
char localinfo [ MAX_LOCALINFO_STRING + 1 ] ; // local game info
extern cvar_t skill , sv_loadentfiles ;
extern cvar_t sv_cheats ;
2004-11-17 17:49:18 +00:00
extern cvar_t sv_bigcoords ;
2005-03-20 02:57:11 +00:00
extern cvar_t sv_gamespeed ;
extern cvar_t sv_csqcdebug ;
2004-08-23 00:15:46 +00:00
extern qboolean sv_allow_cheats ;
/*
= = = = = = = = = = = = = = = =
SV_ModelIndex
= = = = = = = = = = = = = = = =
*/
int SV_ModelIndex ( char * name )
{
int i ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
if ( ! name | | ! name [ 0 ] )
return 0 ;
2006-02-17 02:51:59 +00:00
for ( i = 1 ; i < MAX_MODELS & & sv . strings . model_precache [ i ] ; i + + )
if ( ! strcmp ( sv . strings . model_precache [ i ] , name ) )
2004-08-23 00:15:46 +00:00
return i ;
2006-02-17 02:51:59 +00:00
if ( i = = MAX_MODELS | | ! sv . strings . model_precache [ i ] )
2004-09-04 17:56:53 +00:00
{
if ( i ! = MAX_MODELS & & sv . state = = ss_loading )
{
2006-02-17 02:51:59 +00:00
Q_strncpyz ( sv . strings . model_precache [ i ] , name , sizeof ( sv . strings . model_precache [ i ] ) ) ;
2004-09-04 17:56:53 +00:00
if ( ! strcmp ( name + strlen ( name ) - 4 , " .bsp " ) )
2006-02-17 02:51:59 +00:00
sv . models [ i ] = Mod_FindName ( sv . strings . model_precache [ i ] ) ;
2006-01-02 22:40:40 +00:00
Con_Printf ( " WARNING: SV_ModelIndex: model %s not precached \n " , name ) ;
2004-09-04 17:56:53 +00:00
}
else
SV_Error ( " SV_ModelIndex: model %s not precached " , name ) ;
}
2004-08-23 00:15:46 +00:00
return i ;
}
2004-11-19 17:45:22 +00:00
int SV_SafeModelIndex ( char * name )
{
int i ;
2005-07-03 15:16:20 +00:00
2004-11-19 17:45:22 +00:00
if ( ! name | | ! name [ 0 ] )
return 0 ;
2006-02-17 02:51:59 +00:00
for ( i = 1 ; i < MAX_MODELS & & sv . strings . model_precache [ i ] ; i + + )
if ( ! strcmp ( sv . strings . model_precache [ i ] , name ) )
2004-11-19 17:45:22 +00:00
return i ;
2006-02-17 02:51:59 +00:00
if ( i = = MAX_MODELS | | ! sv . strings . model_precache [ i ] )
2004-11-19 17:45:22 +00:00
{
return 0 ;
}
return i ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
SV_FlushSignon
Moves to the next signon buffer if needed
= = = = = = = = = = = = = = = =
*/
void SV_FlushSignon ( void )
{
if ( sv . signon . cursize < sv . signon . maxsize - 512 )
return ;
if ( sv . num_signon_buffers = = MAX_SIGNON_BUFFERS - 1 )
SV_Error ( " sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1 " ) ;
sv . signon_buffer_size [ sv . num_signon_buffers - 1 ] = sv . signon . cursize ;
sv . signon . data = sv . signon_buffers [ sv . num_signon_buffers ] ;
sv . num_signon_buffers + + ;
sv . signon . cursize = 0 ;
}
void SV_FlushDemoSignon ( void )
{
if ( sv . demosignon . cursize < sv . demosignon . maxsize - 512 )
return ;
if ( sv . num_demosignon_buffers = = MAX_SIGNON_BUFFERS - 1 )
SV_Error ( " sv.num_demosignon_buffers == MAX_SIGNON_BUFFERS-1 " ) ;
sv . demosignon_buffer_size [ sv . num_demosignon_buffers - 1 ] = sv . demosignon . cursize ;
sv . demosignon . data = sv . demosignon_buffers [ sv . num_demosignon_buffers ] ;
sv . num_demosignon_buffers + + ;
sv . demosignon . cursize = 0 ;
}
/*
= = = = = = = = = = = = = = = =
SV_CreateBaseline
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)
{
int i ;
edict_t * svent ;
2005-07-03 15:16:20 +00:00
int entnum ;
2004-08-23 00:15:46 +00:00
for ( entnum = 0 ; entnum < sv . num_edicts ; entnum + + )
{
svent = EDICT_NUM ( entnum ) ;
if ( svent - > free )
continue ;
// create baselines for all player slots,
// and any other edict that has a visible model
2005-03-28 00:11:59 +00:00
if ( entnum > MAX_CLIENTS & & ! svent - > v - > modelindex )
2004-08-23 00:15:46 +00:00
continue ;
//
// create entity baseline
//
2005-03-28 00:11:59 +00:00
VectorCopy ( svent - > v - > origin , svent - > baseline . origin ) ;
VectorCopy ( svent - > v - > angles , svent - > baseline . angles ) ;
svent - > baseline . frame = svent - > v - > frame ;
svent - > baseline . skinnum = svent - > v - > skin ;
2004-08-23 00:15:46 +00:00
if ( entnum > 0 & & entnum < = MAX_CLIENTS )
{
svent - > baseline . colormap = entnum ;
svent - > baseline . modelindex = SV_ModelIndex ( " progs/player.mdl " ) & 255 ;
}
else
{
svent - > baseline . colormap = 0 ;
svent - > baseline . modelindex =
2005-03-28 00:11:59 +00:00
SV_ModelIndex ( PR_GetString ( svent - > v - > model ) ) & 255 ;
2004-08-23 00:15:46 +00:00
}
# ifdef PEXT_SCALE
svent - > baseline . scale = 1 ;
# endif
# ifdef PEXT_TRANS
svent - > baseline . trans = 1 ;
# endif
//
// flush the signon message out to a seperate buffer if
// nearly full
//
SV_FlushSignon ( ) ;
//
// add to the message
//
2005-07-03 15:16:20 +00:00
MSG_WriteByte ( & sv . signon , svc_spawnbaseline ) ;
2004-08-23 00:15:46 +00:00
MSG_WriteShort ( & sv . signon , entnum ) ;
MSG_WriteByte ( & sv . signon , svent - > baseline . modelindex ) ;
MSG_WriteByte ( & sv . signon , svent - > baseline . frame ) ;
MSG_WriteByte ( & sv . signon , svent - > baseline . colormap ) ;
MSG_WriteByte ( & sv . signon , svent - > baseline . skinnum ) ;
for ( i = 0 ; i < 3 ; i + + )
{
MSG_WriteCoord ( & sv . signon , svent - > baseline . origin [ i ] ) ;
MSG_WriteAngle ( & sv . signon , svent - > baseline . angles [ i ] ) ;
}
}
}
*/
2006-02-27 00:42:25 +00:00
void SV_EdictToEntState ( int num , edict_t * ent , entity_state_t * state )
{
int i ;
state - > number = num ;
state - > flags = 0 ;
VectorCopy ( ent - > v - > origin , state - > origin ) ;
VectorCopy ( ent - > v - > angles , state - > angles ) ;
state - > modelindex = ent - > v - > modelindex ;
state - > frame = ent - > v - > frame ;
state - > colormap = ent - > v - > colormap ;
state - > skinnum = ent - > v - > skin ;
state - > effects = ent - > v - > effects ;
2007-09-02 19:55:17 +00:00
state - > hexen2flags = ent - > xv - > drawflags ;
state - > abslight = ( int ) ( ent - > xv - > abslight * 255 ) & 255 ;
state - > tagentity = ent - > xv - > tag_entity ;
state - > tagindex = ent - > xv - > tag_index ;
state - > light [ 0 ] = ent - > xv - > color [ 0 ] * 255 ;
state - > light [ 1 ] = ent - > xv - > color [ 1 ] * 255 ;
state - > light [ 2 ] = ent - > xv - > color [ 2 ] * 255 ;
state - > light [ 3 ] = ent - > xv - > light_lev ;
state - > lightstyle = ent - > xv - > style ;
state - > lightpflags = ent - > xv - > pflags ;
2006-02-27 00:42:25 +00:00
/* if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass) //hexen2 wierdness.
{
char modname [ MAX_QPATH ] ;
Q_strncpyz ( modname , sv . strings . model_precache [ state - > modelindex ] , sizeof ( modname ) ) ;
if ( strlen ( modname ) > 5 )
{
modname [ strlen ( modname ) - 5 ] = client - > playerclass + ' 0 ' ;
state - > modelindex = SV_ModelIndex ( modname ) ;
}
} */
if ( /*progstype == PROG_H2 &&*/ ent - > v - > solid = = SOLID_BSP )
state - > angles [ 0 ] * = - 1 ;
if ( state - > effects & EF_FULLBRIGHT )
{
state - > hexen2flags | = MLS_FULLBRIGHT ;
}
2007-09-02 19:55:17 +00:00
if ( ! ent - > xv - > alpha )
2006-02-27 00:42:25 +00:00
state - > trans = 255 ;
else
2007-09-02 19:55:17 +00:00
state - > trans = ent - > xv - > alpha * 255 ;
2006-02-27 00:42:25 +00:00
2007-09-02 19:55:17 +00:00
if ( ! ent - > xv - > colormod [ 0 ] & & ! ent - > xv - > colormod [ 1 ] & & ! ent - > xv - > colormod [ 2 ] )
2006-02-27 00:42:25 +00:00
{
state - > colormod [ 0 ] = ( 256 ) / 8 ;
state - > colormod [ 1 ] = ( 256 ) / 8 ;
state - > colormod [ 2 ] = ( 256 ) / 8 ;
}
else
{
2007-09-02 19:55:17 +00:00
i = ent - > xv - > colormod [ 0 ] * ( 256 / 8 ) ; state - > colormod [ 0 ] = bound ( 0 , i , 255 ) ;
i = ent - > xv - > colormod [ 1 ] * ( 256 / 8 ) ; state - > colormod [ 1 ] = bound ( 0 , i , 255 ) ;
i = ent - > xv - > colormod [ 2 ] * ( 256 / 8 ) ; state - > colormod [ 2 ] = bound ( 0 , i , 255 ) ;
2006-02-27 00:42:25 +00:00
}
2007-09-02 19:55:17 +00:00
state - > glowsize = ent - > xv - > glow_size * 0.25 ;
state - > glowcolour = ent - > xv - > glow_color ;
2006-02-27 00:42:25 +00:00
# define RENDER_GLOWTRAIL 2
2007-09-02 19:55:17 +00:00
if ( ent - > xv - > glow_trail )
2006-02-27 00:42:25 +00:00
state - > dpflags | = RENDER_GLOWTRAIL ;
2007-09-02 19:55:17 +00:00
if ( ! ent - > xv - > scale )
2006-02-27 00:42:25 +00:00
state - > scale = 1 * 16 ;
else
2007-09-02 19:55:17 +00:00
state - > scale = ent - > xv - > scale * 16 ;
2006-02-27 00:42:25 +00:00
2007-09-02 19:55:17 +00:00
state - > fatness = ent - > xv - > fatness * 2 ;
2006-02-27 00:42:25 +00:00
}
2004-08-23 00:15:46 +00:00
void SVNQ_CreateBaseline ( void )
{
edict_t * svent ;
2005-07-03 15:16:20 +00:00
int entnum ;
2004-11-19 17:45:22 +00:00
int playermodel = SV_SafeModelIndex ( " progs/player.mdl " ) ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
for ( entnum = 0 ; entnum < sv . num_edicts ; entnum + + )
{
svent = EDICT_NUM ( svprogfuncs , entnum ) ;
memset ( & svent - > baseline , 0 , sizeof ( entity_state_t ) ) ;
svent - > baseline . number = entnum ;
# ifdef PEXT_SCALE
2005-07-01 19:23:00 +00:00
svent - > baseline . scale = 1 * 16 ;
2004-08-23 00:15:46 +00:00
# endif
# ifdef PEXT_TRANS
2005-07-01 19:23:00 +00:00
svent - > baseline . trans = 255 ;
2004-08-23 00:15:46 +00:00
# endif
if ( svent - > isfree )
continue ;
// create baselines for all player slots,
// and any other edict that has a visible model
2005-03-28 00:11:59 +00:00
if ( entnum > sv . allocated_client_slots & & ! svent - > v - > modelindex )
2004-08-23 00:15:46 +00:00
continue ;
//
// create entity baseline
//
2006-02-27 00:42:25 +00:00
SV_EdictToEntState ( entnum , svent , & svent - > baseline ) ;
2004-08-23 00:15:46 +00:00
if ( entnum > 0 & & entnum < = sv . allocated_client_slots )
{
if ( entnum > 0 & & entnum < = 16 )
svent - > baseline . colormap = entnum ;
else
svent - > baseline . colormap = 0 ; //this would crash NQ.
2004-11-19 17:45:22 +00:00
svent - > baseline . modelindex = playermodel ;
2004-08-23 00:15:46 +00:00
}
svent - > baseline . modelindex & = 255 ;
}
}
/*
= = = = = = = = = = = = = = = =
SV_SaveSpawnparms
2005-07-03 15:16:20 +00:00
Grabs the current state of the progs serverinfo flags
2004-08-23 00:15:46 +00:00
and each client for saving across the
transition to another level
= = = = = = = = = = = = = = = =
*/
void SV_SaveSpawnparms ( qboolean dontsave )
{
int i , j ;
if ( ! sv . state )
return ; // no progs loaded yet
if ( ! svprogfuncs )
return ;
// serverflags is the only game related thing maintained
svs . serverflags = pr_global_struct - > serverflags ;
for ( i = 0 , host_client = svs . clients ; i < MAX_CLIENTS ; i + + , host_client + + )
{
if ( host_client - > state ! = cs_spawned )
continue ;
// needs to reconnect
host_client - > state = cs_connected ;
if ( dontsave ) //level restart requires that stats can be reset
continue ;
// call the progs to get default spawn parms for the new client
if ( PR_FindGlobal ( svprogfuncs , " ClientReEnter " , 0 ) )
{ //oooh, evil.
char buffer [ 65536 ] ;
int bufsize = sizeof ( buffer ) ;
char * buf ;
for ( j = 0 ; j < NUM_SPAWN_PARMS ; j + + )
host_client - > spawn_parms [ j ] = 0 ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
buf = svprogfuncs - > saveent ( svprogfuncs , buffer , & bufsize , host_client - > edict ) ;
if ( host_client - > spawninfo )
Z_Free ( host_client - > spawninfo ) ;
host_client - > spawninfo = Z_Malloc ( bufsize + 1 ) ;
memcpy ( host_client - > spawninfo , buf , bufsize ) ;
host_client - > spawninfotime = sv . time ;
}
2007-09-02 19:55:17 +00:00
# ifdef VM_Q1
else if ( svs . gametype = = GT_Q1QVM )
{
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , host_client - > edict ) ;
Q1QVM_SetChangeParms ( ) ;
for ( j = 0 ; j < NUM_SPAWN_PARMS ; j + + )
{
if ( spawnparamglobals [ j ] )
host_client - > spawn_parms [ j ] = * spawnparamglobals [ j ] ;
else
host_client - > spawn_parms [ j ] = 0 ;
}
}
# endif
2004-08-23 00:15:46 +00:00
else if ( pr_nqglobal_struct - > SetChangeParms )
{
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , host_client - > edict ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > SetChangeParms ) ;
for ( j = 0 ; j < NUM_SPAWN_PARMS ; j + + )
2005-06-22 17:10:13 +00:00
{
if ( spawnparamglobals [ j ] )
host_client - > spawn_parms [ j ] = * spawnparamglobals [ j ] ;
2005-07-03 15:16:20 +00:00
else
2005-06-22 17:10:13 +00:00
host_client - > spawn_parms [ j ] = 0 ;
}
2004-08-23 00:15:46 +00:00
}
# ifdef SVRANKING
if ( host_client - > rankid )
{
rankstats_t rs ;
if ( Rank_GetPlayerStats ( host_client - > rankid , & rs ) )
{
rs . timeonserver + = realtime - host_client - > stats_started ;
host_client - > stats_started = realtime ;
rs . kills + = host_client - > kills ;
rs . deaths + = host_client - > deaths ;
host_client - > kills = 0 ;
host_client - > deaths = 0 ;
for ( j = 0 ; j < NUM_SPAWN_PARMS ; j + + )
2005-06-22 17:10:13 +00:00
{
if ( spawnparamglobals [ j ] )
rs . parm [ j ] = * spawnparamglobals [ j ] ;
else
rs . parm [ j ] = 0 ;
}
2004-08-23 00:15:46 +00:00
Rank_SetPlayerStats ( host_client - > rankid , & rs ) ;
}
}
# endif
}
}
/*
= = = = = = = = = = = = = = = =
SV_CalcPHS
Expands the PVS and calculates the PHS
( Potentially Hearable Set )
= = = = = = = = = = = = = = = =
*/
void SV_CalcPHS ( void )
{
int rowbytes , rowwords ;
int i , j , k , l , index , num ;
int bitbyte ;
unsigned * dest , * src ;
qbyte * scan ;
int count , vcount ;
if ( sv . worldmodel - > fromgame = = fg_quake2 | | sv . worldmodel - > fromgame = = fg_quake3 )
{
//PHS calcs are pointless with Q2 bsps
return ;
}
2004-10-18 10:49:19 +00:00
if ( developer . value )
Con_TPrintf ( STL_BUILDINGPHS ) ;
2004-08-23 00:15:46 +00:00
num = sv . worldmodel - > numleafs ;
rowwords = ( num + 31 ) > > 5 ;
rowbytes = rowwords * 4 ;
sv . pvs = Hunk_AllocName ( rowbytes * num , " phs vis " ) ;
scan = sv . pvs ;
vcount = 0 ;
for ( i = 0 ; i < num ; i + + , scan + = rowbytes )
{
2005-08-26 22:56:51 +00:00
memcpy ( scan , sv . worldmodel - > funcs . LeafPVS ( sv . worldmodel , i , NULL ) ,
2004-08-23 00:15:46 +00:00
rowbytes ) ;
if ( i = = 0 )
continue ;
for ( j = 0 ; j < num ; j + + )
{
if ( scan [ j > > 3 ] & ( 1 < < ( j & 7 ) ) )
{
vcount + + ;
}
}
}
sv . phs = Hunk_AllocName ( rowbytes * num , " phs hear " ) ;
count = 0 ;
scan = sv . pvs ;
dest = ( unsigned * ) sv . phs ;
for ( i = 0 ; i < num ; i + + , dest + = rowwords , scan + = rowbytes )
{
memcpy ( dest , scan , rowbytes ) ;
for ( j = 0 ; j < rowbytes ; j + + )
{
bitbyte = scan [ j ] ;
if ( ! bitbyte )
continue ;
for ( k = 0 ; k < 8 ; k + + )
{
if ( ! ( bitbyte & ( 1 < < k ) ) )
continue ;
// or this pvs row into the phs
// +1 because pvs is 1 based
index = ( ( j < < 3 ) + k + 1 ) ;
if ( index > = num )
continue ;
src = ( unsigned * ) sv . pvs + index * rowwords ;
for ( l = 0 ; l < rowwords ; l + + )
dest [ l ] | = src [ l ] ;
}
}
if ( i = = 0 )
continue ;
for ( j = 0 ; j < num ; j + + )
if ( ( ( qbyte * ) dest ) [ j > > 3 ] & ( 1 < < ( j & 7 ) ) )
count + + ;
}
if ( num )
2004-10-18 10:49:19 +00:00
if ( developer . value )
Con_TPrintf ( STL_PHSINFO , vcount / num , count / num , num ) ;
2004-08-23 00:15:46 +00:00
}
unsigned SV_CheckModel ( char * mdl )
{
qbyte stackbuf [ 1024 ] ; // avoid dirtying the cache heap
qbyte * buf ;
unsigned short crc ;
// int len;
buf = ( qbyte * ) COM_LoadStackFile ( mdl , stackbuf , sizeof ( stackbuf ) ) ;
if ( ! buf )
return 0 ;
2005-09-08 22:52:46 +00:00
crc = QCRC_Block ( buf , com_filesize ) ;
2004-08-23 00:15:46 +00:00
// for (len = com_filesize; len; len--, buf++)
// CRC_ProcessByte(&crc, *buf);
return crc ;
}
void SV_UnspawnServer ( void ) //terminate the running server.
{
int i ;
if ( sv . state )
{
Con_TPrintf ( STL_SERVERUNSPAWNED ) ;
SV_FinalMessage ( " Server unspawned \n " ) ;
for ( i = 0 ; i < sv . allocated_client_slots ; i + + )
{
if ( svs . clients [ i ] . state )
SV_DropClient ( svs . clients + i ) ;
}
2005-03-18 06:13:11 +00:00
# ifdef Q2SERVER
SVQ2_ShutdownGameProgs ( ) ;
2009-03-03 01:52:30 +00:00
# endif
# ifdef HLSERVER
SVHL_ShutdownGame ( ) ;
2005-03-18 06:13:11 +00:00
# endif
2004-08-23 00:15:46 +00:00
sv . worldmodel = NULL ;
sv . state = ss_dead ;
* sv . name = ' \0 ' ;
}
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
svs . clients [ i ] . state = 0 ;
2005-05-19 02:53:03 +00:00
* svs . clients [ i ] . namebuf = ' \0 ' ;
svs . clients [ i ] . name = NULL ;
2004-08-23 00:15:46 +00:00
}
NET_CloseServer ( ) ;
}
/*
= = = = = = = = = = = = = = = =
SV_SpawnServer
Change the server to a new map , taking all connected
clients along with it .
This is only called from the SV_Map_f ( ) function .
= = = = = = = = = = = = = = = =
*/
extern cvar_t progs ;
void SV_SpawnServer ( char * server , char * startspot , qboolean noents , qboolean usecinematic )
{
func_t f ;
char * file ;
2005-05-15 18:49:04 +00:00
gametype_e newgametype ;
2005-03-07 08:58:26 +00:00
2004-08-23 00:15:46 +00:00
edict_t * ent ;
# ifdef Q2SERVER
q2edict_t * q2ent ;
# endif
2005-09-14 04:39:36 +00:00
int i , j ;
2004-08-23 00:15:46 +00:00
int spawnflagmask ;
# ifndef SERVERONLY
2005-07-03 15:16:20 +00:00
if ( ! isDedicated & & ( ! qrenderer | | qrenderer = = - 1 ) )
2004-08-23 00:15:46 +00:00
{
2004-09-20 23:25:38 +00:00
R_RestartRenderer_f ( ) ;
2007-05-25 22:16:29 +00:00
if ( ! qrenderer | | qrenderer = = - 1 )
{
Sys_Error ( " No renderer set when map restarted \n " ) ;
return ;
}
2004-08-23 00:15:46 +00:00
}
# endif
Con_DPrintf ( " SpawnServer: %s \n " , server ) ;
svs . spawncount + + ; // any partially connected client will be
// restarted
# ifndef SERVERONLY
total_loading_size = 100 ;
current_loading_size = 0 ;
2009-04-06 00:34:32 +00:00
SCR_SetLoadingStage ( LS_SERVER ) ;
2006-09-17 00:59:22 +00:00
// SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
NET_InitServer ( ) ;
sv . state = ss_dead ;
if ( sv . gamedirchanged )
{
sv . gamedirchanged = false ;
# ifndef SERVERONLY
Wads_Flush ( ) ; //server code is responsable for flushing old state
# endif
2005-11-03 23:40:51 +00:00
# ifdef SVRANKING
2004-08-23 00:15:46 +00:00
Rank_Flush ( ) ;
2005-11-03 23:40:51 +00:00
# endif
2004-08-23 00:15:46 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2005-05-26 12:55:34 +00:00
if ( svs . clients [ i ] . state & & ISQWCLIENT ( & svs . clients [ i ] ) )
2004-08-23 00:15:46 +00:00
ReloadRanking ( & svs . clients [ i ] , svs . clients [ i ] . name ) ;
if ( svs . clients [ i ] . spawninfo ) //don't remember this stuff.
Z_Free ( svs . clients [ i ] . spawninfo ) ;
svs . clients [ i ] . spawninfo = NULL ;
}
T_FreeStrings ( ) ;
}
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
svs . clients [ i ] . nextservertimeupdate = 0 ;
if ( ! svs . clients [ i ] . state ) //bots with the net_preparse module.
svs . clients [ i ] . userinfo [ 0 ] = ' \0 ' ; //clear the userinfo to clear the name
2004-11-17 17:49:18 +00:00
if ( svs . clients [ i ] . netchan . remote_address . type = = NA_LOOPBACK )
{ //forget this client's message buffers, so that any shared client/server network state persists (eg: float coords)
svs . clients [ i ] . num_backbuf = 0 ;
svs . clients [ i ] . datagram . cursize = 0 ;
}
2005-08-03 23:14:59 +00:00
svs . clients [ i ] . csqcactive = false ;
2004-08-23 00:15:46 +00:00
}
2004-11-17 17:49:18 +00:00
if ( sv_bigcoords . value )
2005-06-14 04:52:10 +00:00
{
2004-11-17 17:49:18 +00:00
sizeofcoord = 4 ;
2005-06-14 04:52:10 +00:00
sizeofangle = 2 ;
}
2004-11-17 17:49:18 +00:00
else
2005-06-14 04:52:10 +00:00
{
2004-11-17 17:49:18 +00:00
sizeofcoord = 2 ;
2005-06-14 04:52:10 +00:00
sizeofangle = 1 ;
}
2004-11-27 08:16:25 +00:00
2004-08-23 00:15:46 +00:00
VoteFlushAll ( ) ;
# ifndef SERVERONLY
D_FlushCaches ( ) ;
cl . worldmodel = NULL ;
2006-01-28 19:04:13 +00:00
r_worldentity . model = NULL ;
if ( 0 )
cls . state = ca_connected ;
2004-08-23 00:15:46 +00:00
# endif
2005-09-08 22:52:46 +00:00
# ifdef Q3SERVER
2005-10-05 02:26:54 +00:00
if ( svs . gametype = = GT_QUAKE3 )
2005-09-08 22:52:46 +00:00
SVQ3_ShutdownGame ( ) ; //botlib kinda mandates this. :(
# endif
2004-08-23 00:15:46 +00:00
Mod_ClearAll ( ) ;
Hunk_FreeToLowMark ( host_hunklevel ) ;
2005-05-19 02:53:03 +00:00
if ( svs . gametype = = GT_PROGS )
2004-08-23 00:15:46 +00:00
{
2005-05-19 02:53:03 +00:00
for ( i = 0 ; i < MAX_LIGHTSTYLES ; i + + )
{
2006-02-17 02:51:59 +00:00
if ( sv . strings . lightstyles [ i ] )
Z_Free ( sv . strings . lightstyles [ i ] ) ;
sv . strings . lightstyles [ i ] = NULL ;
2006-03-06 01:41:09 +00:00
sv . strings . lightstylecolours [ i ] = 7 ;
2005-05-19 02:53:03 +00:00
}
2004-08-23 00:15:46 +00:00
}
// wipe the entire per-level structure
memset ( & sv , 0 , sizeof ( sv ) ) ;
sv . datagram . maxsize = sizeof ( sv . datagram_buf ) ;
sv . datagram . data = sv . datagram_buf ;
sv . datagram . allowoverflow = true ;
sv . reliable_datagram . maxsize = sizeof ( sv . reliable_datagram_buf ) ;
sv . reliable_datagram . data = sv . reliable_datagram_buf ;
sv . multicast . maxsize = sizeof ( sv . multicast_buf ) ;
sv . multicast . data = sv . multicast_buf ;
# ifdef NQPROT
sv . nqdatagram . maxsize = sizeof ( sv . nqdatagram_buf ) ;
sv . nqdatagram . data = sv . nqdatagram_buf ;
sv . nqdatagram . allowoverflow = true ;
sv . nqreliable_datagram . maxsize = sizeof ( sv . nqreliable_datagram_buf ) ;
sv . nqreliable_datagram . data = sv . nqreliable_datagram_buf ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
sv . nqmulticast . maxsize = sizeof ( sv . nqmulticast_buf ) ;
sv . nqmulticast . data = sv . nqmulticast_buf ;
# endif
sv . q2datagram . maxsize = sizeof ( sv . q2datagram_buf ) ;
sv . q2datagram . data = sv . q2datagram_buf ;
sv . q2datagram . allowoverflow = true ;
sv . q2reliable_datagram . maxsize = sizeof ( sv . q2reliable_datagram_buf ) ;
sv . q2reliable_datagram . data = sv . q2reliable_datagram_buf ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
sv . q2multicast . maxsize = sizeof ( sv . q2multicast_buf ) ;
sv . q2multicast . data = sv . q2multicast_buf ;
sv . master . maxsize = sizeof ( sv . master_buf ) ;
sv . master . data = sv . master_buf ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
sv . signon . maxsize = sizeof ( sv . signon_buffers [ 0 ] ) ;
sv . signon . data = sv . signon_buffers [ 0 ] ;
sv . num_signon_buffers = 1 ;
sv . numextrastatics = 0 ;
strcpy ( sv . name , server ) ;
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
Cvar_ApplyLatches ( CVAR_LATCH ) ;
2005-08-07 18:08:13 +00:00
//work out the gamespeed
sv . gamespeed = sv_gamespeed . value ;
Info_SetValueForStarKey ( svs . info , " *gamespeed " , va ( " %i " , ( int ) ( sv . gamespeed * 100 ) ) , MAX_SERVERINFO_STRING ) ;
sv . gamespeed = atof ( Info_ValueForKey ( svs . info , " *gamespeed " ) ) / 100 ;
if ( sv . gamespeed < 0.1 | | sv . gamespeed = = 1 )
{
sv . gamespeed = 1 ;
Info_SetValueForStarKey ( svs . info , " *gamespeed " , " " , MAX_SERVERINFO_STRING ) ;
}
//reset the server time.
2004-08-23 00:15:46 +00:00
sv . time = 0.1 ; //some progs don't like time starting at 0.
//cos of spawn funcs like self.nextthink = time...
2005-08-07 18:08:13 +00:00
sv . starttime = Sys_DoubleTime ( ) ;
2004-08-23 00:15:46 +00:00
COM_FlushTempoaryPacks ( ) ;
2006-03-11 03:12:10 +00:00
//This fixes a bug where the server advertises cheats, the internal client connects, and doesn't think cheats are allowed.
//this applies to a few other things too, but cheats is the only special one (because of the *)
if ( sv_cheats . value )
{
sv_allow_cheats = true ;
Info_SetValueForStarKey ( svs . info , " *cheats " , " ON " , MAX_SERVERINFO_STRING ) ;
}
else
{
sv_allow_cheats = false ;
Info_SetValueForStarKey ( svs . info , " *cheats " , " " , MAX_SERVERINFO_STRING ) ;
}
2006-03-11 04:39:16 +00:00
# ifndef SERVERONLY
2006-03-11 03:12:10 +00:00
Q_strncpyz ( cl . serverinfo , svs . info , sizeof ( cl . serverinfo ) ) ;
CL_CheckServerInfo ( ) ;
# endif
2004-08-23 00:15:46 +00:00
if ( usecinematic )
{
strcpy ( sv . name , server ) ;
2004-09-15 03:08:38 +00:00
strcpy ( sv . modelname , " " ) ;
2004-08-23 00:15:46 +00:00
}
else
{
strcpy ( sv . name , server ) ;
sprintf ( sv . modelname , " maps/%s.bsp " , server ) ;
}
sv . state = ss_loading ;
sv . worldmodel = Mod_ForName ( sv . modelname , true ) ;
2007-05-25 22:16:29 +00:00
if ( ! sv . worldmodel | | sv . worldmodel - > needload )
Sys_Error ( " %s is missing or corrupt \n " , sv . modelname ) ;
2005-08-26 22:56:51 +00:00
if ( sv . worldmodel - > type ! = mod_brush & & sv . worldmodel - > type ! = mod_heightmap )
Sys_Error ( " %s is not a bsp model \n " , sv . modelname ) ;
2004-08-23 00:15:46 +00:00
sv . state = ss_dead ;
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
// SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
SV_CalcPHS ( ) ;
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
2004-11-17 17:49:18 +00:00
if ( sv . worldmodel - > fromgame = = fg_doom )
Info_SetValueForStarKey ( svs . info , " *bspversion " , " 1 " , MAX_SERVERINFO_STRING ) ;
else if ( sv . worldmodel - > fromgame = = fg_halflife )
2004-08-23 00:15:46 +00:00
Info_SetValueForStarKey ( svs . info , " *bspversion " , " 30 " , MAX_SERVERINFO_STRING ) ;
else if ( sv . worldmodel - > fromgame = = fg_quake2 )
Info_SetValueForStarKey ( svs . info , " *bspversion " , " 38 " , MAX_SERVERINFO_STRING ) ;
else if ( sv . worldmodel - > fromgame = = fg_quake3 )
Info_SetValueForStarKey ( svs . info , " *bspversion " , " 46 " , MAX_SERVERINFO_STRING ) ;
else
Info_SetValueForStarKey ( svs . info , " *bspversion " , " " , MAX_SERVERINFO_STRING ) ;
if ( startspot )
Info_SetValueForStarKey ( svs . info , " *startspot " , startspot , MAX_SERVERINFO_STRING ) ;
else
Info_SetValueForStarKey ( svs . info , " *startspot " , " " , MAX_SERVERINFO_STRING ) ;
//
// clear physics interaction links
//
SV_ClearWorld ( ) ;
2005-03-10 03:55:18 +00:00
//do we allow csprogs?
# ifdef PEXT_CSQC
file = COM_LoadTempFile ( " csprogs.dat " ) ;
if ( file )
{
char text [ 64 ] ;
2008-05-25 22:23:43 +00:00
sv . csqcchecksum = Com_BlockChecksum ( file , com_filesize ) ;
sprintf ( text , " 0x%x " , sv . csqcchecksum ) ;
2005-03-10 03:55:18 +00:00
Info_SetValueForStarKey ( svs . info , " *csprogs " , text , MAX_SERVERINFO_STRING ) ;
}
else
2008-05-25 22:23:43 +00:00
{
sv . csqcchecksum = 0 ;
2005-03-10 03:55:18 +00:00
Info_SetValueForStarKey ( svs . info , " *csprogs " , " " , MAX_SERVERINFO_STRING ) ;
2008-05-25 22:23:43 +00:00
}
2005-03-20 02:57:11 +00:00
sv . csqcdebug = sv_csqcdebug . value ;
if ( sv . csqcdebug )
Info_SetValueForStarKey ( svs . info , " *csqcdebug " , " 1 " , MAX_SERVERINFO_STRING ) ;
else
Info_RemoveKey ( svs . info , " *csqcdebug " ) ;
2005-03-10 03:55:18 +00:00
# endif
2005-03-20 02:57:11 +00:00
2007-09-02 19:55:17 +00:00
if ( svs . gametype = = GT_PROGS )
2004-08-23 00:15:46 +00:00
{
2007-09-02 19:55:17 +00:00
if ( svprogfuncs ) //we don't want the q1 stuff anymore.
{
CloseProgs ( svprogfuncs ) ;
svprogfuncs = NULL ;
}
2004-08-23 00:15:46 +00:00
}
2005-03-07 08:58:26 +00:00
sv . state = ss_loading ;
2005-05-15 18:49:04 +00:00
newgametype = svs . gametype ;
2009-03-03 01:52:30 +00:00
# ifdef HLSERVER
if ( SVHL_InitGame ( ) )
newgametype = GT_HALFLIFE ;
else
# endif
2005-03-07 08:58:26 +00:00
# ifdef Q3SERVER
if ( SVQ3_InitGame ( ) )
2005-05-15 18:49:04 +00:00
newgametype = GT_QUAKE3 ;
2005-03-07 08:58:26 +00:00
else
# endif
2004-08-23 00:15:46 +00:00
# ifdef Q2SERVER
2005-03-07 08:58:26 +00:00
if ( ( sv . worldmodel - > fromgame = = fg_quake2 | | sv . worldmodel - > fromgame = = fg_quake3 ) & & ! * progs . string & & SVQ2_InitGameProgs ( ) ) //these are the rules for running a q2 server
2005-05-15 18:49:04 +00:00
newgametype = GT_QUAKE2 ; //we loaded the dll
2004-08-23 00:15:46 +00:00
else
2007-09-02 19:55:17 +00:00
# endif
# ifdef VM_Q1
if ( PR_LoadQ1QVM ( ) )
newgametype = GT_Q1QVM ;
else
2004-08-23 00:15:46 +00:00
# endif
{
2005-05-15 18:49:04 +00:00
newgametype = GT_PROGS ; //let's just hope this loads.
2005-03-07 08:58:26 +00:00
Q_InitProgs ( ) ;
}
2004-08-23 00:15:46 +00:00
2005-03-07 08:58:26 +00:00
// if ((sv.worldmodel->fromgame == fg_quake2 || sv.worldmodel->fromgame == fg_quake3) && !*progs.string && SVQ2_InitGameProgs()) //full q2 dll decision in one if statement
2005-05-15 18:49:04 +00:00
if ( newgametype ! = svs . gametype )
2005-03-07 08:58:26 +00:00
{
for ( i = 0 ; i < MAX_CLIENTS ; i + + ) //server type changed, so we need to drop all clients. :(
{
if ( svs . clients [ i ] . state )
SV_DropClient ( & svs . clients [ i ] ) ;
2005-05-19 02:53:03 +00:00
svs . clients [ i ] . namebuf [ 0 ] = ' \0 ' ; //kill all bots
2005-03-07 08:58:26 +00:00
}
2004-08-23 00:15:46 +00:00
}
2005-05-15 18:49:04 +00:00
svs . gametype = newgametype ;
2009-03-03 01:52:30 +00:00
# ifdef HLSERVER
if ( newgametype ! = GT_HALFLIFE )
SVHL_ShutdownGame ( ) ;
# endif
2005-05-15 18:49:04 +00:00
# ifdef Q3SERVER
if ( newgametype ! = GT_QUAKE3 )
SVQ3_ShutdownGame ( ) ;
# endif
# ifdef Q2SERVER
if ( newgametype ! = GT_QUAKE2 ) //we don't want the q2 stuff anymore.
SVQ2_ShutdownGameProgs ( ) ;
# endif
2007-09-02 19:55:17 +00:00
# ifdef VM_Q1
if ( newgametype ! = GT_Q1QVM )
Q1QVM_Shutdown ( ) ;
# endif
2005-05-15 18:49:04 +00:00
2004-08-23 00:15:46 +00:00
2005-03-20 02:57:11 +00:00
sv . models [ 1 ] = sv . worldmodel ;
2007-09-03 22:37:13 +00:00
# ifdef VM_Q1
if ( svs . gametype = = GT_Q1QVM )
{
strcpy ( sv . strings . sound_precache [ 0 ] , " " ) ;
sv . strings . model_precache [ 0 ] = " " ;
sv . strings . model_precache [ 1 ] = sv . modelname ; //the qvm doesn't have access to this array
for ( i = 1 ; i < sv . worldmodel - > numsubmodels ; i + + )
{
sv . strings . model_precache [ 1 + i ] = localmodels [ i ] ;
sv . models [ i + 1 ] = Mod_ForName ( localmodels [ i ] , false ) ;
}
//check player/eyes models for hacks
sv . model_player_checksum = SV_CheckModel ( " progs/player.mdl " ) ;
sv . eyes_player_checksum = SV_CheckModel ( " progs/eyes.mdl " ) ;
}
else
# endif
if ( svs . gametype = = GT_PROGS )
2005-03-20 02:57:11 +00:00
{
2006-02-17 02:51:59 +00:00
strcpy ( sv . strings . sound_precache [ 0 ] , " " ) ;
sv . strings . model_precache [ 0 ] = " " ;
2005-03-20 02:57:11 +00:00
2006-02-17 02:51:59 +00:00
sv . strings . model_precache [ 1 ] = PR_AddString ( svprogfuncs , sv . modelname , 0 ) ;
2005-03-20 02:57:11 +00:00
for ( i = 1 ; i < sv . worldmodel - > numsubmodels ; i + + )
{
2006-02-17 02:51:59 +00:00
sv . strings . model_precache [ 1 + i ] = PR_AddString ( svprogfuncs , localmodels [ i ] , 0 ) ;
2005-03-20 02:57:11 +00:00
sv . models [ i + 1 ] = Mod_ForName ( localmodels [ i ] , false ) ;
}
//check player/eyes models for hacks
sv . model_player_checksum = SV_CheckModel ( " progs/player.mdl " ) ;
sv . eyes_player_checksum = SV_CheckModel ( " progs/eyes.mdl " ) ;
}
2005-07-03 15:16:20 +00:00
# ifdef Q2SERVER
2005-03-20 02:57:11 +00:00
else if ( svs . gametype = = GT_QUAKE2 )
{
2006-04-08 05:43:53 +00:00
extern int map_checksum ;
extern cvar_t sv_airaccelerate ;
2006-02-17 02:51:59 +00:00
memset ( sv . strings . configstring , 0 , sizeof ( sv . strings . configstring ) ) ;
2006-04-08 05:43:53 +00:00
if ( deathmatch . value )
sprintf ( sv . strings . configstring [ Q2CS_AIRACCEL ] , " %g " , sv_airaccelerate . value ) ;
else
strcpy ( sv . strings . configstring [ Q2CS_AIRACCEL ] , " 0 " ) ;
// init map checksum config string but only for Q2/Q3 maps
if ( sv . worldmodel - > fromgame = = fg_quake2 | | sv . worldmodel - > fromgame = = fg_quake3 )
sprintf ( sv . strings . configstring [ Q2CS_MAPCHECKSUM ] , " %i " , map_checksum ) ;
else
strcpy ( sv . strings . configstring [ Q2CS_MAPCHECKSUM ] , " 0 " ) ;
2006-02-17 02:51:59 +00:00
strcpy ( sv . strings . configstring [ Q2CS_MODELS + 1 ] , sv . modelname ) ;
2005-03-20 02:57:11 +00:00
for ( i = 1 ; i < sv . worldmodel - > numsubmodels ; i + + )
{
2006-02-17 02:51:59 +00:00
strcpy ( sv . strings . configstring [ Q2CS_MODELS + 1 + i ] , localmodels [ i ] ) ;
2005-03-20 02:57:11 +00:00
sv . models [ i + 1 ] = Mod_ForName ( localmodels [ i ] , false ) ;
}
}
2005-07-03 15:16:20 +00:00
# endif
2005-03-20 02:57:11 +00:00
2004-08-23 00:15:46 +00:00
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
2005-05-17 02:36:54 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
svs . clients [ i ] . name = svs . clients [ i ] . namebuf ;
svs . clients [ i ] . team = svs . clients [ i ] . teambuf ;
}
2005-03-07 08:58:26 +00:00
switch ( svs . gametype )
2004-08-23 00:15:46 +00:00
{
2007-08-07 19:16:32 +00:00
case GT_MAX :
break ;
2007-09-02 19:55:17 +00:00
case GT_Q1QVM :
2005-03-07 08:58:26 +00:00
case GT_PROGS :
2004-08-23 00:15:46 +00:00
ent = EDICT_NUM ( svprogfuncs , 0 ) ;
ent - > isfree = false ;
2005-07-03 15:16:20 +00:00
2004-08-23 00:15:46 +00:00
// leave slots at start for clients only
// sv.num_edicts = MAX_CLIENTS+1;
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
svs . clients [ i ] . viewent = 0 ;
ent = ED_Alloc ( svprogfuncs ) ; //EDICT_NUM(i+1);
svs . clients [ i ] . edict = ent ;
ent - > isfree = false ;
//ZOID - make sure we update frags right
svs . clients [ i ] . old_frags = 0 ;
if ( ! svs . clients [ i ] . state & & svs . clients [ i ] . name [ 0 ] ) //this is a bot.
svs . clients [ i ] . name [ 0 ] = ' \0 ' ; //make it go away
2005-02-28 07:16:19 +00:00
2007-09-03 22:37:13 +00:00
# ifdef VM_Q1
if ( svs . gametype = = GT_Q1QVM )
{ //we'll fix it up later anyway
svs . clients [ i ] . name = svs . clients [ i ] . namebuf ;
svs . clients [ i ] . team = svs . clients [ i ] . teambuf ;
}
else
# endif
{
svs . clients [ i ] . name = PR_AddString ( svprogfuncs , svs . clients [ i ] . namebuf , sizeof ( svs . clients [ i ] . namebuf ) ) ;
svs . clients [ i ] . team = PR_AddString ( svprogfuncs , svs . clients [ i ] . teambuf , sizeof ( svs . clients [ i ] . teambuf ) ) ;
}
2005-05-17 02:36:54 +00:00
2005-02-28 07:16:19 +00:00
# ifdef PEXT_CSQC
memset ( svs . clients [ i ] . csqcentsequence , 0 , sizeof ( svs . clients [ i ] . csqcentsequence ) ) ;
memset ( svs . clients [ i ] . csqcentversions , 0 , sizeof ( svs . clients [ i ] . csqcentversions ) ) ;
# endif
2004-08-23 00:15:46 +00:00
}
sv . allocated_client_slots = i ;
2005-02-28 07:16:19 +00:00
# ifdef PEXT_CSQC
for ( i = 0 ; i < MAX_EDICTS ; i + + )
sv . csqcentversion [ i ] = 1 ; //force all csqc edicts to start off as version 1
# endif
2005-03-07 08:58:26 +00:00
break ;
case GT_QUAKE2 :
2007-08-07 19:16:32 +00:00
# ifdef Q2SERVER
2004-08-23 00:15:46 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
q2ent = Q2EDICT_NUM ( i + 1 ) ;
q2ent - > s . number = i + 1 ;
svs . clients [ i ] . q2edict = q2ent ;
}
sv . allocated_client_slots = i ;
2005-08-07 18:08:13 +00:00
# endif
2007-08-07 19:16:32 +00:00
break ;
2005-08-07 18:08:13 +00:00
case GT_QUAKE3 :
2007-08-07 19:16:32 +00:00
# ifdef Q3SERVER
2005-08-07 18:08:13 +00:00
sv . allocated_client_slots = 32 ;
2009-03-03 01:52:30 +00:00
# endif
break ;
case GT_HALFLIFE :
# ifdef HLSERVER
SVHL_SetupGame ( ) ;
2004-08-23 00:15:46 +00:00
# endif
2007-08-07 19:16:32 +00:00
break ;
2005-03-07 08:58:26 +00:00
}
2004-08-23 00:15:46 +00:00
2005-05-17 02:36:54 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
Q_strncpyz ( svs . clients [ i ] . name , Info_ValueForKey ( svs . clients [ i ] . userinfo , " name " ) , sizeof ( svs . clients [ i ] . namebuf ) ) ;
Q_strncpyz ( svs . clients [ i ] . team , Info_ValueForKey ( svs . clients [ i ] . userinfo , " team " ) , sizeof ( svs . clients [ i ] . teambuf ) ) ;
}
2004-08-23 00:15:46 +00:00
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
//
// spawn the rest of the entities on the map
2005-07-03 15:16:20 +00:00
//
2004-08-23 00:15:46 +00:00
// precache and static commands can be issued during
// map initialization
sv . state = ss_loading ;
if ( svprogfuncs )
{
2007-09-02 19:55:17 +00:00
//world entity is hackily spawned
2004-08-23 00:15:46 +00:00
extern cvar_t coop , pr_imitatemvdsv ;
eval_t * eval ;
ent = EDICT_NUM ( svprogfuncs , 0 ) ;
ent - > isfree = false ;
2007-09-03 22:37:13 +00:00
# ifdef VM_Q1
if ( svs . gametype ! = GT_Q1QVM ) //we cannot do this with qvm
# endif
ent - > v - > model = PR_NewString ( svprogfuncs , sv . worldmodel - > name , 0 ) ;
2005-03-28 00:11:59 +00:00
ent - > v - > modelindex = 1 ; // world model
ent - > v - > solid = SOLID_BSP ;
ent - > v - > movetype = MOVETYPE_PUSH ;
2004-08-23 00:15:46 +00:00
2008-06-01 22:06:22 +00:00
ED_Spawned ( ent , false ) ;
2005-07-05 23:46:10 +00:00
2004-08-23 00:15:46 +00:00
if ( progstype = = PROG_QW & & pr_imitatemvdsv . value > 0 )
{
2007-09-03 22:37:13 +00:00
# ifdef VM_Q1
if ( svs . gametype ! = GT_Q1QVM ) //we cannot do this with qvm
# endif
{
ent - > v - > targetname = PR_NewString ( svprogfuncs , " mvdsv " , 0 ) ;
ent - > v - > netname = PR_NewString ( svprogfuncs , va ( " %s %f %s, build %d \n Build date: " __DATE__ " , " __TIME__ " " , DISTRIBUTIONLONG , 2.4 , PLATFORM , build_number ( ) ) , 0 ) ;
}
2005-03-28 00:11:59 +00:00
ent - > v - > impulse = 0 ; //QWE_VERNUM;
ent - > v - > items = 103 ;
2004-08-23 00:15:46 +00:00
}
2007-09-03 22:37:13 +00:00
# ifdef VM_Q1
if ( svs . gametype ! = GT_Q1QVM ) //we cannot do this with qvm
# endif
2007-09-13 15:32:23 +00:00
pr_global_struct - > mapname = PR_NewString ( svprogfuncs , sv . name , 0 ) ;
2004-08-23 00:15:46 +00:00
// serverflags are for cross level information (sigils)
pr_global_struct - > serverflags = svs . serverflags ;
pr_global_struct - > time = 0.1 ; //HACK!!!! A few QuakeC mods expect time to be non-zero in spawn funcs - like prydon gate...
if ( progstype = = PROG_H2 )
{
2006-03-23 19:22:12 +00:00
cvar_t * cv ;
2004-08-23 00:15:46 +00:00
if ( coop . value )
{
eval = PR_FindGlobal ( svprogfuncs , " coop " , 0 ) ;
if ( eval ) eval - > _float = coop . value ;
}
else
{
eval = PR_FindGlobal ( svprogfuncs , " deathmatch " , 0 ) ;
if ( eval ) eval - > _float = deathmatch . value ;
}
2006-03-23 19:22:12 +00:00
cv = Cvar_Get ( " randomclass " , " 0 " , CVAR_LATCH , " Hexen2 " ) ;
2004-08-23 00:15:46 +00:00
eval = PR_FindGlobal ( svprogfuncs , " randomclass " , 0 ) ;
2006-03-23 19:22:12 +00:00
if ( eval & & cv ) eval - > _float = cv - > value ;
2004-08-23 00:15:46 +00:00
2006-03-23 19:22:12 +00:00
cv = Cvar_Get ( " cl_playerclass " , " 1 " , CVAR_USERINFO | CVAR_ARCHIVE , " Hexen2 " ) ;
2004-08-23 00:15:46 +00:00
eval = PR_FindGlobal ( svprogfuncs , " cl_playerclass " , 0 ) ;
2006-03-23 19:22:12 +00:00
if ( eval & & cv ) eval - > _float = cv - > value ;
2004-08-23 00:15:46 +00:00
}
else
{
if ( pr_nqglobal_struct - > coop & & coop . value )
pr_global_struct - > coop = coop . value ;
else if ( pr_nqglobal_struct - > deathmatch )
pr_global_struct - > deathmatch = deathmatch . value ;
}
2005-05-17 02:36:54 +00:00
2004-08-23 00:15:46 +00:00
if ( progstype = = PROG_QW )
// run the frame start qc function to let progs check cvars
SV_ProgStartFrame ( ) ; //prydon gate seems to fail because of this allowance
for ( i = 0 ; i < svs . numprogs ; i + + ) //do this AFTER precaches have been played with...
{
f = PR_FindFunction ( svprogfuncs , " initents " , svs . progsnum [ i ] ) ;
if ( f )
{
PR_ExecuteProgram ( svprogfuncs , f ) ;
}
}
}
// load and spawn all other entities
if ( progstype = = PROG_H2 )
{
extern cvar_t coop ;
spawnflagmask = 0 ;
if ( deathmatch . value )
spawnflagmask | = SPAWNFLAG_NOT_H2DEATHMATCH ;
else if ( coop . value )
spawnflagmask | = SPAWNFLAG_NOT_H2COOP ;
else
spawnflagmask | = SPAWNFLAG_NOT_H2SINGLE ;
if ( skill . value < 0.5 )
spawnflagmask | = SPAWNFLAG_NOT_H2EASY ;
else if ( skill . value > 1.5 )
spawnflagmask | = SPAWNFLAG_NOT_H2HARD ;
else
spawnflagmask | = SPAWNFLAG_NOT_H2MEDIUM ;
2006-03-23 19:22:12 +00:00
//don't filter based on player class. we're lame and don't have any real concept of player classes.
2004-08-23 00:15:46 +00:00
}
else if ( ! deathmatch . value ) //decide if we are to inhibit single player game ents instead
{
spawnflagmask = SPAWNFLAG_NOT_DEATHMATCH ;
if ( skill . value < 0.5 )
spawnflagmask = SPAWNFLAG_NOT_EASY ;
else if ( skill . value > 1.5 )
spawnflagmask = SPAWNFLAG_NOT_HARD ;
else
spawnflagmask = SPAWNFLAG_NOT_MEDIUM ;
}
else
spawnflagmask = SPAWNFLAG_NOT_DEATHMATCH ;
//do this and get the precaches/start up the game
if ( sv_loadentfiles . value )
file = COM_LoadMallocFile ( va ( " maps/%s.ent " , server ) ) ;
else
file = NULL ;
if ( file )
{
char crc [ 12 ] ;
2005-09-08 22:52:46 +00:00
sprintf ( crc , " %i " , QCRC_Block ( file , com_filesize ) ) ;
2004-08-23 00:15:46 +00:00
Info_SetValueForStarKey ( svs . info , " *entfile " , crc , MAX_SERVERINFO_STRING ) ;
2005-03-07 08:58:26 +00:00
switch ( svs . gametype )
{
2007-08-07 19:16:32 +00:00
case GT_MAX :
break ;
2007-09-02 19:55:17 +00:00
case GT_Q1QVM :
2005-03-07 08:58:26 +00:00
case GT_PROGS :
2004-08-23 00:15:46 +00:00
pr_edict_size = PR_LoadEnts ( svprogfuncs , file , spawnflagmask ) ;
2005-03-07 08:58:26 +00:00
break ;
case GT_QUAKE2 :
2007-08-07 19:16:32 +00:00
# ifdef Q2SERVER
2004-08-23 00:15:46 +00:00
ge - > SpawnEntities ( sv . name , file , startspot ? startspot : " " ) ;
# endif
2007-08-07 19:16:32 +00:00
break ;
case GT_QUAKE3 :
break ;
2009-03-03 01:52:30 +00:00
case GT_HALFLIFE :
# ifdef HLSERVER
SVHL_SpawnEntities ( file ) ;
# endif
break ;
2005-03-07 08:58:26 +00:00
}
2004-08-23 00:15:46 +00:00
BZ_Free ( file ) ;
}
else
{
Info_SetValueForStarKey ( svs . info , " *entfile " , " " , MAX_SERVERINFO_STRING ) ;
2005-03-07 08:58:26 +00:00
switch ( svs . gametype )
{
2007-08-07 19:16:32 +00:00
case GT_MAX :
break ;
2007-09-02 19:55:17 +00:00
case GT_Q1QVM :
2005-03-07 08:58:26 +00:00
case GT_PROGS :
2004-08-23 00:15:46 +00:00
pr_edict_size = PR_LoadEnts ( svprogfuncs , sv . worldmodel - > entities , spawnflagmask ) ;
2005-03-07 08:58:26 +00:00
break ;
case GT_QUAKE2 :
2007-08-07 19:16:32 +00:00
# ifdef Q2SERVER
2004-08-23 00:15:46 +00:00
ge - > SpawnEntities ( sv . name , sv . worldmodel - > entities , startspot ? startspot : " " ) ;
# endif
2007-08-07 19:16:32 +00:00
break ;
case GT_QUAKE3 :
break ;
2009-03-03 01:52:30 +00:00
case GT_HALFLIFE :
# ifdef HLSERVER
SVHL_SpawnEntities ( sv . worldmodel - > entities ) ;
# endif
break ;
2005-03-07 08:58:26 +00:00
}
2004-08-23 00:15:46 +00:00
}
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
Q_strncpyz ( sv . mapname , sv . name , sizeof ( sv . mapname ) ) ;
if ( svprogfuncs )
{
eval_t * val ;
ent = EDICT_NUM ( svprogfuncs , 0 ) ;
2005-03-28 00:11:59 +00:00
ent - > v - > angles [ 0 ] = ent - > v - > angles [ 1 ] = ent - > v - > angles [ 2 ] = 0 ;
2004-08-23 00:15:46 +00:00
val = svprogfuncs - > GetEdictFieldValue ( svprogfuncs , ent , " message " , NULL ) ;
if ( val )
{
if ( progstype = = PROG_H2 )
2006-05-18 02:24:38 +00:00
snprintf ( sv . mapname , sizeof ( sv . mapname ) , " %s " , T_GetString ( val - > _float - 1 ) ) ;
2004-08-23 00:15:46 +00:00
else
2006-05-18 02:24:38 +00:00
snprintf ( sv . mapname , sizeof ( sv . mapname ) , " %s " , PR_GetString ( svprogfuncs , val - > string ) ) ;
2004-08-23 00:15:46 +00:00
}
2007-09-02 19:55:17 +00:00
else
snprintf ( sv . mapname , sizeof ( sv . mapname ) , " %s " , sv . name ) ;
2005-08-26 22:56:51 +00:00
if ( Cvar_Get ( " sv_readonlyworld " , " 1 " , 0 , " DP compatability " ) - > value )
ent - > readonly = true ; //lock it down!
2004-08-23 00:15:46 +00:00
2005-05-19 02:53:03 +00:00
// look up some model indexes for specialized message compression
SV_FindModelNumbers ( ) ;
}
2004-08-23 00:15:46 +00:00
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
// run two frames to allow everything to settle
realtime + = 0.1 ;
SV_Physics ( ) ;
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
realtime + = 0.1 ;
sv . time + = 0.1 ;
2005-08-07 18:08:13 +00:00
sv . starttime - = 0.1 ;
2004-08-23 00:15:46 +00:00
SV_Physics ( ) ;
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
// save movement vars
SV_SetMoveVars ( ) ;
// create a baseline for more efficient communications
// SV_CreateBaseline ();
2005-05-19 02:53:03 +00:00
if ( svprogfuncs )
SVNQ_CreateBaseline ( ) ;
2004-08-23 00:15:46 +00:00
sv . signon_buffer_size [ sv . num_signon_buffers - 1 ] = sv . signon . cursize ;
2004-09-04 17:56:53 +00:00
// all spawning is completed, any further precache statements
// or prog writes to the signon message are errors
if ( usecinematic )
sv . state = ss_cinematic ;
else
sv . state = ss_active ;
2004-08-23 00:15:46 +00:00
SV_GibFilterInit ( ) ;
SV_FilterImpulseInit ( ) ;
Info_SetValueForKey ( svs . info , " map " , sv . name , MAX_SERVERINFO_STRING ) ;
Con_TPrintf ( STL_SERVERSPAWNED ) ; //misc filenotfounds can be misleading.
if ( ! startspot )
{
SV_FlushLevelCache ( ) ; //to make sure it's caught
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( svs . clients [ i ] . spawninfo )
Z_Free ( svs . clients [ i ] . spawninfo ) ;
svs . clients [ i ] . spawninfo = NULL ;
}
}
if ( svprogfuncs & & startspot )
{
eval_t * eval ;
eval = PR_FindGlobal ( svprogfuncs , " startspot " , 0 ) ;
2005-05-17 02:36:54 +00:00
if ( eval ) eval - > string = PR_NewString ( svprogfuncs , startspot , 0 ) ;
2004-08-23 00:15:46 +00:00
}
if ( Cmd_AliasExist ( " f_svnewmap " , RESTRICT_LOCAL ) )
Cbuf_AddText ( " f_svnewmap \n " , RESTRICT_LOCAL ) ;
# ifndef SERVERONLY
current_loading_size + = 10 ;
2006-09-17 00:59:22 +00:00
//SCR_BeginLoadingPlaque();
SCR_ImageName ( server ) ;
2004-08-23 00:15:46 +00:00
# endif
2005-08-26 22:56:51 +00:00
2007-09-02 19:55:17 +00:00
if ( svs . gametype = = GT_PROGS | | svs . gametype = = GT_Q1QVM )
2005-08-26 22:56:51 +00:00
{
2005-09-14 04:39:36 +00:00
for ( i = 0 ; i < sv . allocated_client_slots ; i + + )
2005-08-26 22:56:51 +00:00
{
host_client = & svs . clients [ i ] ;
if ( host_client - > state = = cs_connected & & host_client - > protocol = = SCP_BAD )
{
sv_player = host_client - > edict ;
SV_ExtractFromUserinfo ( host_client ) ;
// copy spawn parms out of the client_t
2005-09-14 04:39:36 +00:00
for ( j = 0 ; j < NUM_SPAWN_PARMS ; j + + )
2005-08-26 22:56:51 +00:00
{
2005-09-14 04:39:36 +00:00
if ( spawnparamglobals [ j ] )
* spawnparamglobals [ j ] = host_client - > spawn_parms [ j ] ;
2005-08-26 22:56:51 +00:00
}
2005-10-07 16:27:20 +00:00
SV_SetUpClientEdict ( host_client , sv_player ) ;
2007-09-02 19:55:17 +00:00
sv_player - > xv - > clientcolors = atoi ( Info_ValueForKey ( host_client - > userinfo , " topcolor " ) ) * 16 + atoi ( Info_ValueForKey ( host_client - > userinfo , " bottomcolor " ) ) ;
2005-09-14 04:39:36 +00:00
2005-08-26 22:56:51 +00:00
// call the spawn function
2009-03-03 01:52:30 +00:00
pr_global_struct - > time = sv . physicstime ;
2005-08-26 22:56:51 +00:00
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > ClientConnect ) ;
// actually spawn the player
2009-03-03 01:52:30 +00:00
pr_global_struct - > time = sv . physicstime ;
2005-08-26 22:56:51 +00:00
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > PutClientInServer ) ;
// send notification to all clients
host_client - > sendinfo = true ;
host_client - > state = cs_spawned ;
SV_UpdateToReliableMessages ( ) ; //so that we don't flood too much with 31 bots and one player.
}
}
}
2006-11-03 15:53:04 +00:00
SV_MVD_SendInitialGamestate ( NULL ) ;
2004-08-23 00:15:46 +00:00
}
2004-11-29 01:21:00 +00:00
# endif