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
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 .
*/
// sv_user.c -- server code for moving users
# include "qwsvdef.h"
# include <ctype.h>
# define Q2EDICT_NUM(i) (q2edict_t*)((char *)ge->edicts+i*ge->edict_size)
# define Q2NUM_FOR_EDICT(ent) (((char *)ent - (char *)ge->edicts) / ge->edict_size)
hull_t * SV_HullForEntity ( edict_t * ent , int hullnum , vec3_t mins , vec3_t maxs , vec3_t offset ) ;
edict_t * sv_player ;
usercmd_t cmd ;
# ifdef SERVERONLY
cvar_t cl_rollspeed = { " cl_rollspeed " , " 200 " } ;
cvar_t cl_rollangle = { " cl_rollangle " , " 2.0 " } ;
# else
extern cvar_t cl_rollspeed ;
extern cvar_t cl_rollangle ;
# endif
cvar_t sv_spectalk = { " sv_spectalk " , " 1 " } ;
cvar_t sv_mapcheck = { " sv_mapcheck " , " 1 " } ;
cvar_t sv_cheatpc = { " sv_cheatpc " , " 125 " } ;
cvar_t sv_cheatspeedchecktime = { " sv_cheatspeedchecktime " , " 30 " } ;
cvar_t sv_playermodelchecks = { " sv_playermodelchecks " , " 1 " } ;
cvar_t sv_cmdlikercon = { " sv_cmdlikercon " , " 0 " } ;
cvar_t sv_nomsec = { " sv_nomsec " , " 0 " } ;
cvar_t sv_edgefriction = { " sv_edgefriction " , " 2 " } ;
2004-10-18 10:48:33 +00:00
cvar_t sv_brokenmovetypes = { " sv_brokenmovetypes " , " 0 " } ;
2004-08-23 00:15:46 +00:00
cvar_t sv_chatfilter = { " sv_chatfilter " , " 0 " } ;
cvar_t votelevel = { " votelevel " , " 0 " } ;
cvar_t voteminimum = { " voteminimum " , " 4 " } ;
cvar_t votepercent = { " votepercent " , " -1 " } ;
cvar_t votetime = { " votetime " , " 10 " } ;
2004-08-31 09:05:42 +00:00
cvar_t pr_allowbutton1 = { " pr_allowbutton1 " , " 1 " , NULL , CVAR_LATCH } ;
2004-08-23 00:15:46 +00:00
2004-08-31 23:58:18 +00:00
2004-08-23 00:15:46 +00:00
extern cvar_t pm_bunnyspeedcap ;
extern cvar_t pm_ktjump ;
extern cvar_t pm_slidefix ;
extern cvar_t pm_airstep ;
char sv_votinggroup [ ] = " server voting " ;
extern char cvargroup_serverpermissions [ ] ;
extern char cvargroup_serverinfo [ ] ;
extern char cvargroup_serverphysics [ ] ;
extern char cvargroup_servercontrol [ ] ;
extern vec3_t player_mins , player_maxs ;
extern int fp_messages , fp_persecond , fp_secondsdead ;
extern char fp_msg [ ] ;
extern cvar_t pausable ;
void SV_PreRunCmd ( void ) ;
void SV_RunCmd ( usercmd_t * ucmd , qboolean recurse ) ;
void SV_PostRunCmd ( void ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
USER STRINGCMD EXECUTION
host_client and sv_player will be valid .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
SV_New_f
Sends the first message from the server to a connected client .
This will be sent on the initial connection and upon each server load .
= = = = = = = = = = = = = = = =
*/
void SV_New_f ( void )
{
char * gamedir ;
int playernum ;
client_t * split ;
if ( host_client - > state = = cs_spawned )
return ;
# ifdef NQPROT
host_client - > nqprot = false ;
# endif
/* splitt delay
host_client - > state = cs_connected ;
host_client - > connection_started = realtime ;
# ifdef SVRANKING
host_client - > stats_started = realtime ;
# endif* /
// send the info about the new client to all connected clients
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
gamedir = Info_ValueForKey ( svs . info , " *gamedir " ) ;
if ( ! gamedir [ 0 ] )
gamedir = " qw " ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf )
{
Con_TPrintf ( STL_BACKBUFSET , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
2004-11-17 17:38:49 +00:00
if ( sizeofcoord > 2 & & ! ( host_client - > fteprotocolextensions & PEXT_FLOATCOORDS ) )
{
SV_ClientPrintf ( host_client , 2 , " \n \n \n \n Sorry, but your client does not appear to support FTE's bigcoords \n FTE users will need to set cl_nopext to 0 and then reconnect, or to upgrade \n " ) ;
Con_Printf ( " %s does not support bigcoords \n " , host_client - > name ) ;
return ;
}
2004-08-23 00:15:46 +00:00
// send the serverdata
MSG_WriteByte ( & host_client - > netchan . message , host_client - > isq2client ? svcq2_serverdata : svc_serverdata ) ;
# ifdef PROTOCOL_VERSION_FTE
if ( host_client - > fteprotocolextensions ) //let the client know
{
MSG_WriteLong ( & host_client - > netchan . message , PROTOCOL_VERSION_FTE ) ;
2004-11-17 17:38:49 +00:00
if ( sizeofcoord = = 2 ) //we're not using float orgs on this level.
MSG_WriteLong ( & host_client - > netchan . message , host_client - > fteprotocolextensions & ~ PEXT_FLOATCOORDS ) ;
else
MSG_WriteLong ( & host_client - > netchan . message , host_client - > fteprotocolextensions ) ;
2004-08-23 00:15:46 +00:00
}
# endif
MSG_WriteLong ( & host_client - > netchan . message , host_client - > isq2client ? host_client - > isq2client : PROTOCOL_VERSION ) ;
MSG_WriteLong ( & host_client - > netchan . message , svs . spawncount ) ;
if ( host_client - > isq2client )
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteString ( & host_client - > netchan . message , gamedir ) ;
for ( split = host_client ; split ; split = split - > controlled )
{
# ifdef Q2SERVER
if ( ! svprogfuncs )
playernum = Q2NUM_FOR_EDICT ( split - > q2edict ) - 1 ;
else
# endif
playernum = NUM_FOR_EDICT ( svprogfuncs , split - > edict ) - 1 ;
if ( sv . demostate )
playernum = ( MAX_CLIENTS - 1 ) | 128 ;
else if ( split - > spectator )
playernum | = 128 ;
if ( sv . state = = ss_cinematic )
playernum = - 1 ;
if ( host_client - > isq2client )
MSG_WriteShort ( & host_client - > netchan . message , playernum ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , playernum ) ;
split - > state = cs_connected ;
split - > connection_started = realtime ;
# ifdef SVRANKING
split - > stats_started = realtime ;
# endif
}
if ( host_client - > fteprotocolextensions & PEXT_SPLITSCREEN )
MSG_WriteByte ( & host_client - > netchan . message , 128 ) ;
// send full levelname
MSG_WriteString ( & host_client - > netchan . message , sv . mapname ) ;
//
// game server
//
# ifdef Q2SERVER
if ( host_client - > isq2client )
{
if ( sv . state ! = ss_cinematic )
{
// host_client->q2edict = Q2NUM_FOR_EDICT(split->q2edict)-1;
memset ( & host_client - > lastcmd , 0 , sizeof ( host_client - > lastcmd ) ) ;
// begin fetching configstrings
MSG_WriteByte ( & host_client - > netchan . message , svcq2_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd configstrings %i 0 \n " , svs . spawncount ) ) ;
}
return ;
}
# endif
// send the movevars
MSG_WriteFloat ( & host_client - > netchan . message , movevars . gravity ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . stopspeed ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . maxspeed ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . spectatormaxspeed ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . accelerate ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . airaccelerate ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . wateraccelerate ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . friction ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . waterfriction ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . entgravity ) ;
// send server info string
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " fullserverinfo \" %s \" \n " , svs . info ) ) ;
// send music
MSG_WriteByte ( & host_client - > netchan . message , svc_cdtrack ) ;
if ( svprogfuncs )
MSG_WriteByte ( & host_client - > netchan . message , sv . edicts - > v . sounds ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
# define NQ_PROTOCOL_VERSION 15
# define GAME_DEATHMATCH 0
# define GAME_COOP 1
void SVNQ_New_f ( void )
{
extern cvar_t coop ;
char message [ 2048 ] ;
int i ;
# ifdef NQPROT
host_client - > nqprot = true ;
# endif
MSG_WriteByte ( & host_client - > netchan . message , svc_print ) ;
# ifdef DISTRIBUTION
sprintf ( message , " %c \n " DISTRIBUTION " QuakeWorld version %4.2f server \n " , 2 , VERSION ) ;
# else
sprintf ( message , " %c \n QUAKEWORLD VERSION %4.2f SERVER \n " , 2 , VERSION ) ;
# endif
MSG_WriteString ( & host_client - > netchan . message , message ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_serverdata ) ;
MSG_WriteLong ( & host_client - > netchan . message , NQ_PROTOCOL_VERSION ) ;
MSG_WriteByte ( & host_client - > netchan . message , 16 ) ;
if ( ! coop . value & & deathmatch . value )
MSG_WriteByte ( & host_client - > netchan . message , GAME_DEATHMATCH ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , GAME_COOP ) ;
strcpy ( message , sv . mapname ) ;
MSG_WriteString ( & host_client - > netchan . message , message ) ;
for ( i = 1 ; * sv . model_precache [ i ] ; i + + )
MSG_WriteString ( & host_client - > netchan . message , sv . model_precache [ i ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
for ( i = 1 ; * sv . sound_precache [ i ] ; i + + )
MSG_WriteString ( & host_client - > netchan . message , sv . sound_precache [ i ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// send music
MSG_WriteByte ( & host_client - > netchan . message , svc_cdtrack ) ;
MSG_WriteByte ( & host_client - > netchan . message , sv . edicts - > v . sounds ) ;
MSG_WriteByte ( & host_client - > netchan . message , sv . edicts - > v . sounds ) ;
// set view
MSG_WriteByte ( & host_client - > netchan . message , svc_setview ) ;
MSG_WriteShort ( & host_client - > netchan . message , NUM_FOR_EDICT ( svprogfuncs , host_client - > edict ) ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_signonnum ) ;
MSG_WriteByte ( & host_client - > netchan . message , 1 ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_setpause ) ;
MSG_WriteByte ( & host_client - > netchan . message , sv . paused ) ;
// host_client->sendsignon = true;
// host_client->spawned = false; // need prespawn, spawn, etc
}
# ifdef Q2SERVER
void SVQ2_ConfigStrings_f ( void )
{
extern int map_checksum ;
int start ;
Con_DPrintf ( " Configstrings() from %s \n " , host_client - > name ) ;
if ( host_client - > state ! = cs_connected )
{
Con_DPrintf ( " configstrings not valid -- already spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_DPrintf ( " SV_Configstrings_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
start = atoi ( Cmd_Argv ( 2 ) ) ;
2004-10-28 21:13:52 +00:00
if ( start < 0 )
{
Con_Printf ( " SV_Configstrings_f: %s tried crashing us \n " , host_client - > name ) ;
host_client - > drop = true ;
return ;
}
2004-08-23 00:15:46 +00:00
// write a packet full of data
while ( host_client - > netchan . message . cursize < MAX_QWMSGLEN / 2
& & start < Q2MAX_CONFIGSTRINGS )
{
//choose range to grab from.
if ( start < Q2CS_CDTRACK )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , sv . name ) ;
/* if (svprogfuncs)
MSG_WriteString ( & host_client - > netchan . message , va ( " %s " , PR_GetString ( svprogfuncs , sv . edicts - > v . message ) ) ) ;
else
MSG_WriteString ( & host_client - > netchan . message , " LEVEL NAME " ) ;
*/ }
else if ( start < Q2CS_SKY )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
if ( svprogfuncs )
MSG_WriteString ( & host_client - > netchan . message , va ( " %i " , sv . edicts - > v . sounds ) ) ;
else
MSG_WriteString ( & host_client - > netchan . message , " 0 " ) ;
}
else if ( start < Q2CS_SKYAXIS )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , " unit1_ " ) ;
}
else if ( start < Q2CS_SKYROTATE )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , " 0 " ) ;
}
else if ( start < Q2CS_STATUSBAR )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , " 0 " ) ;
}
else if ( start < Q2CS_AIRACCEL )
{ //show status bar
if ( start = = Q2CS_STATUSBAR )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , sv . statusbar ) ;
}
}
else if ( start < Q2CS_MAXCLIENTS )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " %i " , ( int ) 1 ) ) ;
}
else if ( start < Q2CS_MAPCHECKSUM )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " %i " , ( int ) 32 ) ) ;
}
else if ( start < Q2CS_MODELS )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " %i " , map_checksum ) ) ;
}
else if ( start < Q2CS_SOUNDS )
{
if ( * sv . model_precache [ start - Q2CS_MODELS ] )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , sv . model_precache [ start - Q2CS_MODELS ] ) ;
}
}
else if ( start < Q2CS_IMAGES )
{
if ( * sv . sound_precache [ start - Q2CS_SOUNDS ] )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , sv . sound_precache [ start - Q2CS_SOUNDS ] ) ;
}
}
else if ( start < Q2CS_LIGHTS )
{
if ( * sv . image_precache [ start - Q2CS_IMAGES ] )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , sv . image_precache [ start - Q2CS_IMAGES ] ) ;
}
}
else if ( start < Q2CS_ITEMS )
{
if ( start - Q2CS_LIGHTS < MAX_LIGHTSTYLES & & sv . lightstyles [ start - Q2CS_LIGHTS ] )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_configstring ) ;
MSG_WriteShort ( & host_client - > netchan . message , start ) ;
MSG_WriteString ( & host_client - > netchan . message , sv . lightstyles [ start - Q2CS_LIGHTS ] ) ;
}
}
else if ( start < Q2CS_PLAYERSKINS )
{
// MSG_WriteByte (&host_client->netchan.message, svcq2_configstring);
// MSG_WriteShort (&host_client->netchan.message, start);
// MSG_WriteString (&host_client->netchan.message, sv.configstrings[start-Q2CS_ITEMS]);
}
else if ( start < Q2CS_GENERAL )
{
// MSG_WriteByte (&host_client->netchan.message, svcq2_configstring);
// MSG_WriteShort (&host_client->netchan.message, start);
// MSG_WriteString (&host_client->netchan.message, sv.configstrings[start]);
}
else
{
// MSG_WriteByte (&host_client->netchan.message, svcq2_configstring);
// MSG_WriteShort (&host_client->netchan.message, start);
// MSG_WriteString (&host_client->netchan.message, sv.configstrings[start]);
}
start + + ;
}
// send next command
if ( start = = Q2MAX_CONFIGSTRINGS )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd baselines %i 0 \n " , svs . spawncount ) ) ;
}
else
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd configstrings %i %i \n " , svs . spawncount , start ) ) ;
}
}
# endif
# ifdef Q2SERVER
void SVQ2_BaseLines_f ( void )
{
int start ;
q2entity_state_t nullstate ;
q2entity_state_t * base ;
extern q2entity_state_t sv_baselines [ Q2MAX_EDICTS ] ;
Con_DPrintf ( " Baselines() from %s \n " , host_client - > name ) ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " baselines not valid -- already spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_Printf ( " SV_Baselines_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
start = atoi ( Cmd_Argv ( 2 ) ) ;
memset ( & nullstate , 0 , sizeof ( nullstate ) ) ;
// write a packet full of data
while ( host_client - > netchan . message . cursize < MAX_QWMSGLEN / 2
& & start < Q2MAX_EDICTS )
{
base = & sv_baselines [ start ] ;
if ( base - > modelindex | | base - > sound | | base - > effects )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_spawnbaseline ) ;
MSGQ2_WriteDeltaEntity ( & nullstate , base , & host_client - > netchan . message , true , true ) ;
}
start + + ;
}
// send next command
if ( start = = Q2MAX_EDICTS )
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " precache %i \n " , svs . spawncount ) ) ;
}
else
{
MSG_WriteByte ( & host_client - > netchan . message , svcq2_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd baselines %i %i \n " , svs . spawncount , start ) ) ;
}
}
2004-08-27 00:45:34 +00:00
void SVQ2_NextServer_f ( void )
{
if ( ! * sv . modelname & & atoi ( Cmd_Argv ( 1 ) ) = = svs . spawncount )
{
cvar_t * nsv = Cvar_FindVar ( " nextserver " ) ;
if ( ! nsv | | ! * nsv - > string )
return ;
svs . spawncount + + ; // make sure another doesn't sneak in
Cbuf_AddText ( nsv - > string , RESTRICT_LOCAL ) ;
Cbuf_AddText ( " \n " , RESTRICT_LOCAL ) ;
Cvar_Set ( nsv , " " ) ;
}
}
2004-08-23 00:15:46 +00:00
# endif
2004-11-17 17:38:49 +00:00
void SV_PK3List_f ( void )
{
int crc ;
char * name ;
int n , i ;
if ( host_client - > state ! = cs_connected )
{ //fixme: send prints instead
Con_Printf ( " pk3list not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount & & ! sv . msgfromdemo )
{
Con_Printf ( " SV_PK3List_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
i = atoi ( Cmd_Argv ( 2 ) ) ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_Soundlist] Back buffered (%d), clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
if ( i < 0 )
{
Con_Printf ( " SV_PK3List_f: %s tried to crash us \n " , host_client - > name ) ;
SV_DropClient ( host_client ) ;
return ;
}
for ( i ; ; i + + )
{
if ( host_client - > netchan . message . cursize < ( MAX_QWMSGLEN / 2 ) )
{ //user's buffer was too small
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd pk3list %i %i \n " , svs . spawncount , 0 ) ) ;
return ; //and stop before we flood them
}
name = COM_GetPathInfo ( i , & crc ) ;
if ( name & & * name )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " echo packfile %s \n " , name ) ) ;
continue ; //okay, that was all we could find.
}
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " soundlist %i 0 \n " , svs . spawncount ) ) ;
return ;
}
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_Soundlist_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Soundlist_f ( void )
{
int i ;
//char **s;
int n ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " soundlist not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount & & ! sv . msgfromdemo )
{
Con_Printf ( " SV_Soundlist_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
n = atoi ( Cmd_Argv ( 2 ) ) ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_Soundlist] Back buffered (%d), clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
2004-11-17 17:38:49 +00:00
if ( n < 0 )
{
Con_Printf ( " SV_Soundlist_f: %s tried to crash us \n " , host_client - > name ) ;
SV_DropClient ( host_client ) ;
return ;
}
2004-08-23 00:15:46 +00:00
MSG_WriteByte ( & host_client - > netchan . message , svc_soundlist ) ;
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
if ( sv . democausesreconnect ) //read the list from somewhere else
{
for ( i = 1 + n ;
* sv . demsound_precache [ i ] & & host_client - > netchan . message . cursize < ( MAX_QWMSGLEN / 2 ) ;
i + + , n + + )
MSG_WriteString ( & host_client - > netchan . message , sv . demsound_precache [ i ] ) ;
}
else
{
for ( i = 1 + n ;
* sv . sound_precache [ i ] & & host_client - > netchan . message . cursize < ( MAX_QWMSGLEN / 2 ) ;
i + + , n + + )
MSG_WriteString ( & host_client - > netchan . message , sv . sound_precache [ i ] ) ;
}
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// next msg
if ( * sv . sound_precache [ i ] )
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Modellist_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Modellist_f ( void )
{
int i ;
int n ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " modellist not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount & & ! sv . msgfromdemo )
{
Con_Printf ( " SV_Modellist_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
n = atoi ( Cmd_Argv ( 2 ) ) ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_Modellist] Back buffered (%d), clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
2004-11-17 17:38:49 +00:00
if ( n < 0 )
{
Con_Printf ( " SV_Modellist_f: %s tried to crash us \n " , host_client - > name ) ;
SV_DropClient ( host_client ) ;
return ;
}
2004-08-23 00:15:46 +00:00
if ( n > = 255 )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_modellistshort ) ;
MSG_WriteShort ( & host_client - > netchan . message , n ) ;
}
else
{
MSG_WriteByte ( & host_client - > netchan . message , svc_modellist ) ;
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
}
if ( sv . democausesreconnect ) //read the list from somewhere else
{
for ( i = 1 + n ;
* sv . demmodel_precache [ i ] & & ( ( n & 255 ) = = 0 | | host_client - > netchan . message . cursize < ( MAX_QWMSGLEN / 2 ) ) ;
i + + , n + + )
MSG_WriteString ( & host_client - > netchan . message , sv . demmodel_precache [ i ] ) ;
}
else
{
for ( i = 1 + n ;
* sv . model_precache [ i ] & & ( ( ( n & 255 ) = = 0 ) | | ( host_client - > netchan . message . cursize < ( MAX_QWMSGLEN / 2 ) ) ) ; //make sure we don't send a 0 next...
i + + , n + + )
MSG_WriteString ( & host_client - > netchan . message , sv . model_precache [ i ] ) ;
}
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// next msg
if ( ( sv . democausesreconnect & & * sv . demmodel_precache [ i ] ) | | ( ! sv . democausesreconnect & & * sv . model_precache [ i ] ) )
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_PreSpawn_f
= = = = = = = = = = = = = = = = = =
*/
void SV_PreSpawn_f ( void )
{
unsigned buf , bufs ;
unsigned check ;
unsigned statics ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " prespawn not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount & & ! sv . msgfromdemo )
{
Con_Printf ( " SV_PreSpawn_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
if ( sv . democausesreconnect )
bufs = sv . num_demosignon_buffers ;
else
bufs = sv . num_signon_buffers ;
statics = sv . numextrastatics ;
buf = atoi ( Cmd_Argv ( 2 ) ) ;
if ( buf > = bufs + statics + sv . num_edicts + 255 )
buf = 0 ;
2004-11-17 17:38:49 +00:00
if ( buf < 0 )
buf = 0 ;
2004-08-23 00:15:46 +00:00
if ( ! buf )
{
// should be three numbers following containing checksums
check = atoi ( Cmd_Argv ( 3 ) ) ;
// Con_DPrintf("Client check = %d\n", check);
if ( sv_mapcheck . value & & check ! = sv . worldmodel - > checksum & &
check ! = sv . worldmodel - > checksum2 )
if ( ! sv . demofile | | ( sv . demofile & & ! sv . democausesreconnect ) ) //demo playing causes no check. If it's the return level, check anyway to avoid that loophole.
{
SV_ClientTPrintf ( host_client , PRINT_HIGH ,
STL_MAPCHEAT ,
sv . modelname , check , sv . worldmodel - > checksum , sv . worldmodel - > checksum2 ) ;
SV_DropClient ( host_client ) ;
return ;
}
host_client - > checksum = check ;
}
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_PreSpawn] Back buffered (%d), clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
if ( buf > = bufs )
{
int i ;
entity_state_t from ;
entity_state_t * state ;
edict_t * ent ;
svcustomtents_t * ctent ;
memset ( & from , 0 , sizeof ( from ) ) ;
while ( host_client - > netchan . message . cursize < ( host_client - > netchan . message . maxsize / 2 ) ) //static entities
{
if ( buf - bufs > = sv . numextrastatics )
break ;
state = & sv . extendedstatics [ buf - bufs ] ;
if ( host_client - > fteprotocolextensions & PEXT_SPAWNSTATIC2 )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnstatic2 ) ;
SV_WriteDelta ( & from , state , & host_client - > netchan . message , true , host_client - > fteprotocolextensions ) ;
}
else
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnstatic ) ;
MSG_WriteByte ( & host_client - > netchan . message , state - > modelindex & 255 ) ;
MSG_WriteByte ( & host_client - > netchan . message , state - > frame ) ;
MSG_WriteByte ( & host_client - > netchan . message , ( int ) state - > colormap ) ;
MSG_WriteByte ( & host_client - > netchan . message , ( int ) state - > skinnum ) ;
for ( i = 0 ; i < 3 ; i + + )
{
MSG_WriteCoord ( & host_client - > netchan . message , state - > origin [ i ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , state - > angles [ i ] ) ;
}
}
buf + + ;
}
while ( host_client - > netchan . message . cursize < ( host_client - > netchan . message . maxsize / 2 ) ) //baselines
{
if ( buf - bufs - sv . numextrastatics > = sv . num_edicts )
break ;
ent = EDICT_NUM ( svprogfuncs , buf - bufs - sv . numextrastatics ) ;
2004-10-10 06:32:29 +00:00
if ( ent - > tagent )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_setattachment ) ;
MSG_WriteShort ( & host_client - > netchan . message , ent - > entnum ) ;
MSG_WriteShort ( & host_client - > netchan . message , ent - > tagent ) ;
MSG_WriteShort ( & host_client - > netchan . message , ent - > tagindex ) ;
}
state = & ent - > baseline ;
2004-08-23 00:15:46 +00:00
if ( ! state - > number | | ! state - > modelindex )
{ //ent doesn't have a baseline
buf + + ;
continue ;
}
if ( ! ent )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnbaseline ) ;
MSG_WriteShort ( & host_client - > netchan . message , buf - bufs - sv . numextrastatics ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
for ( i = 0 ; i < 3 ; i + + )
{
MSG_WriteCoord ( & host_client - > netchan . message , 0 ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
}
}
else if ( host_client - > fteprotocolextensions & PEXT_SPAWNSTATIC2 )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnbaseline2 ) ;
SV_WriteDelta ( & from , state , & host_client - > netchan . message , true , host_client - > fteprotocolextensions ) ;
}
else
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnbaseline ) ;
MSG_WriteShort ( & host_client - > netchan . message , buf - bufs - sv . numextrastatics ) ;
MSG_WriteByte ( & host_client - > netchan . message , state - > modelindex & 255 ) ;
MSG_WriteByte ( & host_client - > netchan . message , state - > frame ) ;
MSG_WriteByte ( & host_client - > netchan . message , ( int ) state - > colormap ) ;
MSG_WriteByte ( & host_client - > netchan . message , ( int ) state - > skinnum ) ;
for ( i = 0 ; i < 3 ; i + + )
{
MSG_WriteCoord ( & host_client - > netchan . message , state - > origin [ i ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , state - > angles [ i ] ) ;
}
}
buf + + ;
}
while ( host_client - > netchan . message . cursize < ( host_client - > netchan . message . maxsize / 2 ) )
{
i = buf - bufs - sv . numextrastatics - sv . num_edicts ;
if ( i > = 255 )
break ;
ctent = & sv . customtents [ i ] ;
buf + + ;
if ( ! * ctent - > particleeffecttype )
{ //effect isn't registered.
continue ;
}
if ( host_client - > fteprotocolextensions & PEXT_CUSTOMTEMPEFFECTS )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_customtempent ) ;
MSG_WriteByte ( & host_client - > netchan . message , 255 ) ;
MSG_WriteByte ( & host_client - > netchan . message , i ) ;
MSG_WriteByte ( & host_client - > netchan . message , ctent - > netstyle ) ;
MSG_WriteString ( & host_client - > netchan . message , ctent - > particleeffecttype ) ;
if ( ctent - > netstyle & CTE_STAINS )
{
MSG_WriteChar ( & host_client - > netchan . message , ctent - > stain [ 0 ] ) ;
MSG_WriteChar ( & host_client - > netchan . message , ctent - > stain [ 0 ] ) ;
MSG_WriteChar ( & host_client - > netchan . message , ctent - > stain [ 0 ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , ctent - > radius ) ;
}
if ( ctent - > netstyle & CTE_GLOWS )
{
MSG_WriteByte ( & host_client - > netchan . message , ctent - > dlightrgb [ 0 ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , ctent - > dlightrgb [ 1 ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , ctent - > dlightrgb [ 2 ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , ctent - > dlightradius ) ;
MSG_WriteByte ( & host_client - > netchan . message , ctent - > dlighttime ) ;
}
}
}
}
else
{
if ( sv . democausesreconnect )
SZ_Write ( & host_client - > netchan . message ,
sv . demosignon_buffers [ buf ] ,
sv . demosignon_buffer_size [ buf ] ) ;
else
SZ_Write ( & host_client - > netchan . message ,
sv . signon_buffers [ buf ] ,
sv . signon_buffer_size [ buf ] ) ;
buf + + ;
}
if ( buf = = bufs + sv . numextrastatics + sv . num_edicts + 255 )
{ // all done prespawning
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd spawn %i \n " , svs . spawncount ) ) ;
}
else
{ // need to prespawn more
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message ,
va ( " cmd prespawn %i %i \n " , svs . spawncount , buf ) ) ;
}
}
2004-10-29 06:11:33 +00:00
static void SetUpClientEdict ( client_t * cl , edict_t * ent ) ;
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_Spawn_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Spawn_f ( void )
{
int i ;
client_t * client , * split ;
edict_t * ent ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " Spawn not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount & & ! sv . msgfromdemo )
{
Con_Printf ( " SV_Spawn_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
// send all current names, colors, and frag counts
// FIXME: is this a good thing?
SZ_Clear ( & host_client - > netchan . message ) ;
// send current status of all other players
// normally this could overflow, but no need to check due to backbuf
for ( i = 0 , client = svs . clients ; i < MAX_CLIENTS ; i + + , client + + )
SV_FullClientUpdateToClient ( client , host_client ) ;
// send all current light styles
for ( i = 0 ; i < MAX_LIGHTSTYLES ; i + + )
{
if ( sv . democausesreconnect )
{
ClientReliableWrite_Begin ( host_client , svc_lightstyle ,
3 + ( sv . demolightstyles [ i ] ? strlen ( sv . demolightstyles [ i ] ) : 1 ) ) ;
ClientReliableWrite_Byte ( host_client , ( char ) i ) ;
ClientReliableWrite_String ( host_client , sv . demolightstyles [ i ] ) ;
}
else
# ifdef PEXT_LIGHTSTYLECOL
if ( host_client - > fteprotocolextensions & PEXT_LIGHTSTYLECOL & & sv . lightstylecolours [ i ] ! = 7 )
{
ClientReliableWrite_Begin ( host_client , svc_lightstylecol ,
3 + ( sv . lightstyles [ i ] ? strlen ( sv . lightstyles [ i ] ) : 1 ) ) ;
ClientReliableWrite_Byte ( host_client , ( char ) i ) ;
ClientReliableWrite_Char ( host_client , sv . lightstylecolours [ i ] ) ;
ClientReliableWrite_String ( host_client , sv . lightstyles [ i ] ) ;
}
else
# endif
{
ClientReliableWrite_Begin ( host_client , svc_lightstyle ,
3 + ( sv . lightstyles [ i ] ? strlen ( sv . lightstyles [ i ] ) : 1 ) ) ;
ClientReliableWrite_Byte ( host_client , ( char ) i ) ;
ClientReliableWrite_String ( host_client , sv . lightstyles [ i ] ) ;
}
}
// set up the edict
for ( split = host_client ; split ; split = split - > controlled )
{
ent = split - > edict ;
if ( split - > istobeloaded ) //minimal setup
{
split - > entgravity = ent - > v . gravity ;
split - > maxspeed = ent - > v . maxspeed ;
}
else
{
2004-10-29 06:11:33 +00:00
SetUpClientEdict ( split , ent ) ;
2004-08-23 00:15:46 +00:00
}
//
// force stats to be updated
//
memset ( host_client - > stats , 0 , sizeof ( host_client - > stats ) ) ;
}
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALSECRETS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > total_secrets ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALMONSTERS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > total_monsters ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_SECRETS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > found_secrets ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_MONSTERS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > killed_monsters ) ;
// get the client to check and download skins
// when that is completed, a begin command will be issued
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " skins \n " ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_SpawnSpectator
= = = = = = = = = = = = = = = = = =
*/
void SV_SpawnSpectator ( void )
{
int i ;
edict_t * e ;
VectorCopy ( vec3_origin , sv_player - > v . origin ) ;
VectorCopy ( vec3_origin , sv_player - > v . view_ofs ) ;
sv_player - > v . view_ofs [ 2 ] = DEFAULT_VIEWHEIGHT ;
sv_player - > v . movetype = MOVETYPE_NOCLIP ;
// search for an info_playerstart to spawn the spectator at
2004-10-26 15:33:33 +00:00
for ( i = MAX_CLIENTS + 1 ; i < sv . num_edicts ; i + + )
2004-08-23 00:15:46 +00:00
{
e = EDICT_NUM ( svprogfuncs , i ) ;
if ( ! strcmp ( PR_GetString ( svprogfuncs , e - > v . classname ) , " info_player_start " ) )
{
VectorCopy ( e - > v . origin , sv_player - > v . origin ) ;
return ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Begin_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Begin_f ( void )
{
client_t * split , * oh ;
unsigned pmodel = 0 , emodel = 0 ;
int i ;
qboolean sendangles = false ;
if ( host_client - > state = = cs_spawned )
return ; // don't begin again
for ( split = host_client ; split ; split = split - > controlled )
split - > state = cs_spawned ;
2004-11-17 17:38:49 +00:00
2004-08-23 00:15:46 +00:00
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount & & ! sv . msgfromdemo )
{
Con_Printf ( " SV_Begin_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
for ( split = host_client ; split ; split = split - > controlled )
{
if ( split - > istobeloaded )
{
sendangles = true ;
split - > istobeloaded = false ;
}
else
{
if ( split - > spectator )
{
SV_SpawnSpectator ( ) ;
if ( SpectatorConnect )
{
// copy spawn parms out of the client_t
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
( & pr_global_struct - > parm1 ) [ i ] = split - > spawn_parms [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , split - > edict ) ;
PR_ExecuteProgram ( svprogfuncs , SpectatorConnect ) ;
}
}
else
{
if ( svprogfuncs )
{
eval_t * eval , * eval2 ;
eval = PR_FindGlobal ( svprogfuncs , " ClientReEnter " , 0 ) ;
if ( eval & & split - > spawninfo )
{
globalvars_t * pr_globals = PR_globals ( svprogfuncs , PR_CURRENT ) ;
int j ;
edict_t * ent ;
ent = split - > edict ;
j = strlen ( split - > spawninfo ) ;
SV_UnlinkEdict ( ent ) ;
svprogfuncs - > restoreent ( svprogfuncs , split - > spawninfo , & j , ent ) ;
eval2 = svprogfuncs - > GetEdictFieldValue ( svprogfuncs , ent , " stats_restored " , NULL ) ;
if ( eval2 )
eval2 - > _float = 1 ;
for ( j = 0 ; j < NUM_SPAWN_PARMS ; j + + )
( & pr_global_struct - > parm1 ) [ j ] = split - > spawn_parms [ j ] ;
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , ent ) ;
G_FLOAT ( OFS_PARM0 ) = sv . time - split - > spawninfotime ;
PR_ExecuteProgram ( svprogfuncs , eval - > function ) ;
}
else
{
// copy spawn parms out of the client_t
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
( & pr_global_struct - > parm1 ) [ i ] = split - > spawn_parms [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , split - > edict ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > ClientConnect ) ;
// actually spawn the player
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , split - > edict ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > PutClientInServer ) ;
oh = host_client ;
SV_PreRunCmd ( ) ;
{
usercmd_t cmd ;
2004-10-10 06:32:29 +00:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2004-08-23 00:15:46 +00:00
cmd . msec = 0 ;
# define ANGLE2SHORT(x) (x) * (65536 / 360.0)
cmd . angles [ 0 ] = ANGLE2SHORT ( split - > edict - > v . v_angle [ 0 ] ) ;
cmd . angles [ 1 ] = ANGLE2SHORT ( split - > edict - > v . v_angle [ 1 ] ) ;
cmd . angles [ 2 ] = ANGLE2SHORT ( split - > edict - > v . v_angle [ 2 ] ) ;
SV_RunCmd ( & cmd , false ) ;
}
SV_PostRunCmd ( ) ;
host_client = oh ;
}
}
# ifdef Q2SERVER
else
{
ge - > ClientBegin ( split - > q2edict ) ;
}
# endif
}
}
}
// clear the net statistics, because connecting gives a bogus picture
host_client - > netchan . frame_latency = 0 ;
host_client - > netchan . frame_rate = 0 ;
host_client - > netchan . drop_count = 0 ;
host_client - > netchan . good_count = 0 ;
//check he's not cheating
if ( progstype = = PROG_QW )
{
pmodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " pmodel " ) ) ;
emodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " emodel " ) ) ;
if ( pmodel ! = sv . model_player_checksum | |
emodel ! = sv . eyes_player_checksum )
SV_BroadcastTPrintf ( PRINT_HIGH , STL_POSSIBLEMODELCHEAT , host_client - > name ) ;
}
// if we are paused, tell the client
if ( sv . paused )
{
if ( ! host_client - > isq2client )
{
ClientReliableWrite_Begin ( host_client , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( host_client , sv . paused ) ;
}
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_SERVERPAUSED ) ;
}
if ( sendangles )
{
//
// send a fixangle over the reliable channel to make sure it gets there
// Never send a roll angle, because savegames can catch the server
// in a state where it is expecting the client to correct the angle
// and it won't happen if the game was just loaded, so you wind up
// with a permanent head tilt
MSG_WriteByte ( & host_client - > netchan . message , svc_setangle ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
MSG_WriteAngle ( & host_client - > netchan . message , host_client - > edict - > v . angles [ 1 ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
}
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = =
SV_NextDownload_f
= = = = = = = = = = = = = = = = = =
*/
void SV_NextDownload_f ( void )
{
qbyte buffer [ 1024 ] ;
int r ;
int percent ;
int size ;
if ( ! host_client - > download )
return ;
r = host_client - > downloadsize - host_client - > downloadcount ;
/*
# ifdef PEXT_ZLIBDL
if ( host_client - > protocolextensions & PEXT_ZLIBDL )
{
if ( r > 1024 ) //expect a little more.
r = 1024 ;
}
else
# endif
*/
if ( r > 768 )
r = 768 ;
r = fread ( buffer , 1 , r , host_client - > download ) ;
ClientReliableWrite_Begin ( host_client , host_client - > isq2client ? svcq2_download : svc_download , 6 + r ) ;
ClientReliableWrite_Short ( host_client , r ) ;
host_client - > downloadcount + = r ;
size = host_client - > downloadsize ;
if ( ! size )
size = 1 ;
percent = host_client - > downloadcount * 100 / size ;
# ifdef PEXT_ZLIBDL
if ( host_client - > fteprotocolextensions & PEXT_ZLIBDL )
{
ClientReliableWrite_Byte ( host_client , percent + 101 ) ;
ClientReliableWrite_ZLib ( host_client , buffer , r ) ;
}
else
# endif
{
ClientReliableWrite_Byte ( host_client , percent ) ;
ClientReliableWrite_SZ ( host_client , buffer , r ) ;
}
if ( host_client - > downloadcount ! = host_client - > downloadsize )
return ;
fclose ( host_client - > download ) ;
host_client - > download = NULL ;
}
void VARGS OutofBandPrintf ( netadr_t where , char * fmt , . . . )
{
va_list argptr ;
char send [ 1024 ] ;
send [ 0 ] = 0xff ;
send [ 1 ] = 0xff ;
send [ 2 ] = 0xff ;
send [ 3 ] = 0xff ;
send [ 4 ] = A2C_PRINT ;
va_start ( argptr , fmt ) ;
vsprintf ( send + 5 , fmt , argptr ) ;
va_end ( argptr ) ;
NET_SendPacket ( NS_SERVER , strlen ( send ) + 1 , send , where ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_NextUpload
= = = = = = = = = = = = = = = = = =
*/
void SV_NextUpload ( void )
{
int percent ;
int size ;
if ( ! * host_client - > uploadfn )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_UPLOADDENIED ) ;
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " stopul " ) ;
// suck out rest of packet
size = MSG_ReadShort ( ) ; MSG_ReadByte ( ) ;
msg_readcount + = size ;
return ;
}
size = MSG_ReadShort ( ) ;
percent = MSG_ReadByte ( ) ;
if ( ! host_client - > upload )
{
host_client - > upload = fopen ( host_client - > uploadfn , " wb " ) ;
if ( ! host_client - > upload )
{
Sys_Printf ( " Can't create %s \n " , host_client - > uploadfn ) ;
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " stopul " ) ;
* host_client - > uploadfn = 0 ;
return ;
}
Con_Printf ( " Receiving %s from %d... \n " , host_client - > uploadfn , host_client - > userid ) ;
if ( host_client - > remote_snap )
OutofBandPrintf ( host_client - > snap_from , " Server receiving %s from %d... \n " , host_client - > uploadfn , host_client - > userid ) ;
}
fwrite ( net_message . data + msg_readcount , 1 , size , host_client - > upload ) ;
msg_readcount + = size ;
Con_DPrintf ( " UPLOAD: %d received \n " , size ) ;
if ( percent ! = 100 )
{
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " nextul \n " ) ;
}
else
{
fclose ( host_client - > upload ) ;
host_client - > upload = NULL ;
Con_Printf ( " %s upload completed. \n " , host_client - > uploadfn ) ;
if ( host_client - > remote_snap )
{
char * p ;
if ( ( p = strchr ( host_client - > uploadfn , ' / ' ) ) ! = NULL )
p + + ;
else
p = host_client - > uploadfn ;
OutofBandPrintf ( host_client - > snap_from , " %s upload completed. \n To download, enter: \n download %s \n " ,
host_client - > uploadfn , p ) ;
}
}
}
2004-09-20 23:25:38 +00:00
//Use of this function is on name only.
//Be aware that the maps directory should be restricted based on weather the file was from a pack file
//this is to preserve copyright - please do not breach due to a bug.
2004-08-23 00:15:46 +00:00
qboolean SV_AllowDownload ( char * name )
{
extern cvar_t allow_download ;
extern cvar_t allow_download_skins ;
extern cvar_t allow_download_models ;
extern cvar_t allow_download_sounds ;
extern cvar_t allow_download_demos ;
2004-09-20 23:25:38 +00:00
extern cvar_t allow_download_maps ;
extern cvar_t allow_download_textures ;
extern cvar_t allow_download_pk3s ;
extern cvar_t allow_download_wads ;
2004-08-23 00:15:46 +00:00
extern cvar_t allow_download_root ;
2004-09-20 23:25:38 +00:00
// extern int file_from_pak; // ZOID did file come from pak?
//allowed at all?
if ( ! allow_download . value )
return false ;
2004-08-23 00:15:46 +00:00
2004-09-20 23:25:38 +00:00
//no subdirs?
if ( strstr ( name , " .. " ) ) //no under paths.
return false ;
if ( * name = = ' . ' ) //relative is pointless
return false ;
if ( * name = = ' / ' ) //no absolute.
2004-08-23 00:15:46 +00:00
return false ;
2004-09-20 23:25:38 +00:00
if ( strchr ( name , ' \\ ' ) ) //no windows paths - grow up lame windows users.
return false ;
if ( strncmp ( name , " maps/ " , 5 ) = = 0 & & ( allow_download_maps . value ) )
return true ;
//skins?
if ( strncmp ( name , " skins/ " , 6 ) = = 0 & & allow_download_skins . value )
return true ;
//models
if ( ( strncmp ( name , " progs/ " , 6 ) = = 0 | |
strncmp ( name , " models/ " , 7 ) = = 0 ) & & allow_download_models . value )
return true ;
//sound
if ( strncmp ( name , " sound/ " , 6 ) = = 0 & & allow_download_sounds . value )
return true ;
//demos
if ( strncmp ( name , " demos/ " , 6 ) = = 0 & & allow_download_demos . value )
return true ;
//textures
if ( strncmp ( name , " texures/ " , 8 ) = = 0 & & allow_download_textures . value )
return true ;
//wads
if ( strncmp ( name , " wads/ " , 5 ) = = 0 & & allow_download_wads . value )
return true ;
if ( ! strcmp ( " .wad " , COM_FileExtension ( name ) ) & & allow_download_wads . value )
return true ;
//pk3s.
if ( ! strcmp ( " .pk3 " , COM_FileExtension ( name ) ) & & allow_download_pk3s . value )
if ( strnicmp ( name , " pak " , 3 ) ) //don't give out q3 pk3 files.
return true ;
//root of gamedir
if ( strchr ( name , ' / ' ) & & ! allow_download_root . value )
return false ;
//any other subdirs are allowed
2004-08-23 00:15:46 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_BeginDownload_f
= = = = = = = = = = = = = = = = = =
*/
void SV_BeginDownload_f ( void )
{
char * name ;
extern cvar_t allow_download_anymap ;
extern int file_from_pak ; // ZOID did file come from pak?
name = Cmd_Argv ( 1 ) ;
// hacked by zoid to allow more conrol over download
if ( ! SV_AllowDownload ( name ) )
{ // don't allow anything with .. path
ClientReliableWrite_Begin ( host_client , host_client - > isq2client ? svcq2_download : svc_download , 4 ) ;
ClientReliableWrite_Short ( host_client , - 1 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
return ;
}
if ( host_client - > download )
{
fclose ( host_client - > download ) ;
host_client - > download = NULL ;
}
// lowercase name (needed for casesen file systems)
{
char * p ;
for ( p = name ; * p ; p + + )
* p = ( char ) tolower ( * p ) ;
}
host_client - > downloadsize = COM_FOpenFile ( name , & host_client - > download ) ;
host_client - > downloadcount = 0 ;
if ( ! host_client - > download
// special check for maps, if it came from a pak file, don't allow
// download ZOID
| | ( ! allow_download_anymap . value & & strncmp ( name , " maps/ " , 5 ) = = 0 & & file_from_pak ) )
{
if ( host_client - > download )
{
fclose ( host_client - > download ) ;
host_client - > download = NULL ;
}
Sys_Printf ( " Couldn't download %s to %s \n " , name , host_client - > name ) ;
ClientReliableWrite_Begin ( host_client , host_client - > isq2client ? svcq2_download : svc_download , 4 ) ;
ClientReliableWrite_Short ( host_client , - 1 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
return ;
}
SV_NextDownload_f ( ) ;
SV_EndRedirect ( ) ;
Con_Printf ( " Downloading %s to %s \n " , name , host_client - > name ) ;
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = =
SV_SayOne_f
= = = = = = = = = = = = = = = = = =
*/
void SV_SayOne_f ( void )
{
char text [ 1024 ] ;
client_t * to ;
int i ;
char * s , * s2 ;
int clnum = - 1 ;
if ( Cmd_Argc ( ) < 3 )
return ;
while ( ( to = SV_GetClientForString ( Cmd_Argv ( 1 ) , & clnum ) ) )
{
if ( host_client - > spectator )
{
if ( ! sv_spectalk . value | | to - > spectator )
sprintf ( text , " [SPEC] {%s}: " , host_client - > name ) ;
else
continue ;
}
else
sprintf ( text , " {%s}: " , host_client - > name ) ;
if ( host_client - > ismuted )
{
SV_ClientTPrintf ( host_client , PRINT_CHAT ,
STL_YOUAREMUTED ) ;
return ;
}
for ( i = 2 ; ; i + + )
{
s = Cmd_Argv ( i ) ;
if ( ! * s )
break ;
if ( strlen ( text ) + strlen ( s ) + 2 > = sizeof ( text ) - 1 )
break ;
strcat ( text , " " ) ;
strcat ( text , s ) ;
}
//filter out '\n' and '\r'
s = text ;
s2 = text ;
while ( * s2 )
{
if ( * s2 = = ' \r ' | | * s2 = = ' \n ' )
{
s2 + + ;
continue ;
}
* s = * s2 ;
s + + ;
s2 + + ;
}
* s = ' \0 ' ;
strcat ( text , " \n " ) ;
SV_ClientPrintf ( to , PRINT_CHAT , " %s " , text ) ;
}
if ( clnum = = - 1 ) //none found
{
SV_ClientTPrintf ( host_client , PRINT_CHAT , STL_NAMEDCLIENTDOESNTEXIST ) ;
return ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Say
= = = = = = = = = = = = = = = = = =
*/
void SV_Say ( qboolean team )
{
client_t * client ;
int j , tmp ;
char * p ;
char text [ 1024 ] ;
char t1 [ 32 ] , * t2 ;
int cls = 0 ;
qboolean sent [ MAX_CLIENTS ] ; //so we don't send to the same splitscreen connection twice. (it's ugly)
int cln ;
char * s , * s2 ;
if ( Cmd_Argc ( ) < 2 )
return ;
Sys_ServerActivity ( ) ;
memset ( sent , 0 , sizeof ( sent ) ) ;
if ( team )
{
Q_strncpyz ( t1 , Info_ValueForKey ( host_client - > userinfo , " team " ) , sizeof ( t1 ) ) ;
}
if ( host_client - > spectator & & ( ! sv_spectalk . value | | team ) )
sprintf ( text , " [SPEC] %s: " , host_client - > name ) ;
else if ( team )
sprintf ( text , " (%s): " , host_client - > name ) ;
else
sprintf ( text , " %s: " , host_client - > name ) ;
if ( host_client - > ismuted )
{
SV_ClientTPrintf ( host_client , PRINT_CHAT ,
STL_MUTEDCHAT ) ;
return ;
}
if ( fp_messages )
{
if ( ! sv . paused & & realtime < host_client - > lockedtill )
{
SV_ClientTPrintf ( host_client , PRINT_CHAT ,
STL_FLOODPROTTIME ,
( int ) ( host_client - > lockedtill - realtime ) ) ;
return ;
}
tmp = host_client - > whensaidhead - fp_messages + 1 ;
if ( tmp < 0 )
tmp = 10 + tmp ;
if ( ! sv . paused & &
host_client - > whensaid [ tmp ] & & ( realtime - host_client - > whensaid [ tmp ] < fp_persecond ) )
{
host_client - > lockedtill = realtime + fp_secondsdead ;
if ( fp_msg [ 0 ] )
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" FloodProt: %s \n " , fp_msg ) ;
else
SV_ClientTPrintf ( host_client , PRINT_CHAT ,
STL_FLOODPROTACTIVE , fp_secondsdead ) ;
return ;
}
host_client - > whensaidhead + + ;
if ( host_client - > whensaidhead > 9 )
host_client - > whensaidhead = 0 ;
host_client - > whensaid [ host_client - > whensaidhead ] = realtime ;
}
p = Cmd_Args ( ) ;
if ( * p = = ' " ' )
{
p + + ;
p [ Q_strlen ( p ) - 1 ] = 0 ;
}
if ( strlen ( text ) + strlen ( p ) + 2 > = sizeof ( text ) - 10 )
{
SV_ClientTPrintf ( host_client , PRINT_CHAT , STL_BUFFERPROTECTION ) ;
return ;
}
if ( svprogfuncs )
if ( PR_QCChat ( p , team ) ) //true if handled.
return ;
Q_strcat ( text , p ) ;
//filter out '\n' and '\r'
if ( sv_chatfilter . value )
{
s = text ;
s2 = text ;
while ( * s2 )
{
if ( * s2 = = ' \r ' | | * s2 = = ' \n ' )
{
s2 + + ;
continue ;
}
* s = * s2 ;
s + + ;
s2 + + ;
}
* s = ' \0 ' ;
}
Q_strcat ( text , " \n " ) ;
Sys_Printf ( " %s " , text ) ;
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + )
{
if ( client - > state ! = cs_spawned & & client - > state ! = cs_connected )
continue ;
if ( host_client - > spectator & & ! sv_spectalk . value )
if ( ! client - > spectator )
continue ;
if ( team )
{
// the spectator team
if ( host_client - > spectator ) {
if ( ! client - > spectator )
continue ;
} else {
t2 = Info_ValueForKey ( client - > userinfo , " team " ) ;
if ( strcmp ( t1 , t2 ) | | client - > spectator )
continue ; // on different teams
}
}
cls | = 1 < < j ;
//make sure we don't send the say to the same client 20 times due to splitscreen
if ( client - > controller )
cln = client - > controller - svs . clients ;
else
cln = client - svs . clients ;
if ( sent [ cln ] )
continue ;
else
sent [ cln ] = true ;
SV_ClientPrintf ( client , PRINT_CHAT , " %s " , text ) ;
}
if ( ! sv . mvdrecording | | ! cls )
return ;
// non-team messages should be seen allways, even if not tracking any player
if ( ! team & & ( ( host_client - > spectator & & sv_spectalk . value ) | | ! host_client - > spectator ) )
{
MVDWrite_Begin ( dem_all , 0 , strlen ( text ) + 3 ) ;
}
else
MVDWrite_Begin ( dem_multiple , cls , strlen ( text ) + 3 ) ;
MSG_WriteByte ( ( sizebuf_t * ) demo . dbuf , svc_print ) ;
MSG_WriteByte ( ( sizebuf_t * ) demo . dbuf , PRINT_CHAT ) ;
MSG_WriteString ( ( sizebuf_t * ) demo . dbuf , text ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Say_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Say_f ( void )
{
SV_Say ( false ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Say_Team_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Say_Team_f ( void )
{
SV_Say ( true ) ;
}
//============================================================================
/*
= = = = = = = = = = = = = = = = =
SV_Pings_f
The client is showing the scoreboard , so send new ping times for all
clients
= = = = = = = = = = = = = = = = =
*/
void SV_Pings_f ( void )
{
client_t * client ;
int j ;
if ( sv . demofile )
{
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + )
{
if ( ! * sv . recordedplayer [ j ] . userinfo )
continue ;
ClientReliableWrite_Begin ( host_client , svc_updateping , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
ClientReliableWrite_Short ( host_client , sv . recordedplayer [ j ] . ping ) ;
ClientReliableWrite_Begin ( host_client , svc_updatepl , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
ClientReliableWrite_Byte ( host_client , sv . recordedplayer [ j ] . pl ) ;
}
return ;
}
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + )
{
if ( client - > state ! = cs_spawned )
continue ;
ClientReliableWrite_Begin ( host_client , svc_updateping , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
ClientReliableWrite_Short ( host_client , SV_CalcPing ( client ) ) ;
ClientReliableWrite_Begin ( host_client , svc_updatepl , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
ClientReliableWrite_Byte ( host_client , client - > lossage ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Kill_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Kill_f ( void )
{
if ( sv_player - > v . health < = 0 )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_NOSUISIDEWHENDEAD ) ;
return ;
}
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > ClientKill ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_TogglePause
= = = = = = = = = = = = = = = = = =
*/
void SV_TogglePause ( void )
{
int i ;
client_t * cl ;
sv . paused ^ = 1 ;
// send notification to all clients
for ( i = 0 , cl = svs . clients ; i < MAX_CLIENTS ; i + + , cl + + )
{
if ( ! cl - > state )
continue ;
2004-11-17 17:38:49 +00:00
if ( ! cl - > isq2client & & ! cl - > controller )
2004-08-23 00:15:46 +00:00
{
ClientReliableWrite_Begin ( cl , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( cl , sv . paused ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Pause_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Pause_f ( void )
{
if ( ! pausable . value )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_CANTPAUSE ) ;
return ;
}
if ( host_client - > spectator & & ! svs . demoplayback )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_CANTPAUSESPEC ) ;
return ;
}
SV_TogglePause ( ) ;
if ( sv . paused )
SV_BroadcastTPrintf ( PRINT_HIGH , STL_CLIENTPAUSED , host_client - > name ) ;
else
SV_BroadcastTPrintf ( PRINT_HIGH , STL_CLIENTUNPAUSED , host_client - > name ) ;
}
/*
= = = = = = = = = = = = = = = = =
SV_Drop_f
The client is going to disconnect , so remove the connection immediately
= = = = = = = = = = = = = = = = =
*/
void SV_Drop_f ( void )
{
SV_EndRedirect ( ) ;
if ( ! host_client - > spectator )
SV_BroadcastTPrintf ( PRINT_HIGH , STL_CLIENTDROPPED , host_client - > name ) ;
SV_DropClient ( host_client ) ;
}
/*
= = = = = = = = = = = = = = = = =
SV_PTrack_f
Change the bandwidth estimate for a client
= = = = = = = = = = = = = = = = =
*/
void SV_PTrack_f ( void )
{
int i ;
edict_t * ent , * tent ;
if ( ! host_client - > spectator & & ! sv . demofile )
return ;
if ( Cmd_Argc ( ) ! = 2 )
{
// turn off tracking
host_client - > spec_track = 0 ;
ent = EDICT_NUM ( svprogfuncs , host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( svprogfuncs , 0 ) ;
ent - > v . goalentity = EDICT_TO_PROG ( svprogfuncs , tent ) ;
return ;
}
i = atoi ( Cmd_Argv ( 1 ) ) ;
if ( * sv . recordedplayer [ i ] . userinfo )
{
host_client - > spec_track = i + 1 ;
return ;
}
if ( i < 0 | | i > = MAX_CLIENTS | | svs . clients [ i ] . state ! = cs_spawned | |
svs . clients [ i ] . spectator )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_INVALIDTRACKCLIENT ) ;
host_client - > spec_track = 0 ;
ent = EDICT_NUM ( svprogfuncs , host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( svprogfuncs , 0 ) ;
ent - > v . goalentity = EDICT_TO_PROG ( svprogfuncs , tent ) ;
return ;
}
host_client - > spec_track = i + 1 ; // now tracking
ent = EDICT_NUM ( svprogfuncs , host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( svprogfuncs , i + 1 ) ;
ent - > v . goalentity = EDICT_TO_PROG ( svprogfuncs , tent ) ;
}
/*
= = = = = = = = = = = = = = = = =
SV_Rate_f
Change the bandwidth estimate for a client
= = = = = = = = = = = = = = = = =
*/
void SV_Rate_f ( void )
{
2004-10-19 16:10:14 +00:00
extern cvar_t sv_maxrate ;
2004-08-23 00:15:46 +00:00
int rate ;
if ( Cmd_Argc ( ) ! = 2 )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_CURRENTRATE ,
2004-10-19 16:10:14 +00:00
host_client - > rate ) ;
2004-08-23 00:15:46 +00:00
return ;
}
rate = atoi ( Cmd_Argv ( 1 ) ) ;
if ( rate < 500 )
rate = 500 ;
2004-10-19 16:10:14 +00:00
if ( rate > sv_maxrate . value )
rate = sv_maxrate . value ;
2004-08-23 00:15:46 +00:00
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_RATESETTO , rate ) ;
2004-10-19 16:10:14 +00:00
host_client - > rate = rate ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = = =
SV_Msg_f
Change the message level for a client
= = = = = = = = = = = = = = = = =
*/
void SV_Msg_f ( void )
{
if ( Cmd_Argc ( ) ! = 2 )
{
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_CURRENTMSGLEVEL ,
host_client - > messagelevel ) ;
return ;
}
host_client - > messagelevel = atoi ( Cmd_Argv ( 1 ) ) ;
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_MSGLEVELSET , host_client - > messagelevel ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_SetInfo_f
Allow clients to change userinfo
= = = = = = = = = = = = = = = = = =
*/
void SV_SetInfo_f ( void )
{
int i ;
char oldval [ MAX_INFO_STRING ] ;
if ( Cmd_Argc ( ) = = 1 )
{
Con_Printf ( " User info settings: \n " ) ;
Info_Print ( host_client - > userinfo ) ;
return ;
}
if ( Cmd_Argc ( ) ! = 3 )
{
Con_Printf ( " usage: setinfo [ <key> <value> ] \n " ) ;
return ;
}
if ( Cmd_Argv ( 1 ) [ 0 ] = = ' * ' )
return ; // don't set priveledged values
strcpy ( oldval , Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) ) ;
Info_SetValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) , Cmd_Argv ( 2 ) , MAX_INFO_STRING ) ;
// name is extracted below in ExtractFromUserInfo
// strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
// , sizeof(host_client->name)-1);
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
if ( ! strcmp ( Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) , oldval ) )
return ; // key hasn't changed
// process any changed values
SV_ExtractFromUserinfo ( host_client ) ;
if ( progstype ! = PROG_QW & & ! strcmp ( Cmd_Argv ( 1 ) , " bottomcolor " ) )
{
sv_player - > v . team = atoi ( Cmd_Argv ( 2 ) ) + 1 ;
}
PR_ClientUserInfoChanged ( Cmd_Argv ( 1 ) , oldval , Cmd_Argv ( 2 ) ) ;
if ( * Cmd_Argv ( 1 ) = = ' _ ' )
return ;
i = host_client - svs . clients ;
MSG_WriteByte ( & sv . reliable_datagram , svc_setinfo ) ;
MSG_WriteByte ( & sv . reliable_datagram , i ) ;
MSG_WriteString ( & sv . reliable_datagram , Cmd_Argv ( 1 ) ) ;
MSG_WriteString ( & sv . reliable_datagram , Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_ShowServerinfo_f
Dumps the serverinfo info string
= = = = = = = = = = = = = = = = = =
*/
void SV_ShowServerinfo_f ( void )
{
Info_Print ( svs . info ) ;
}
void SV_NoSnap_f ( void )
{
if ( * host_client - > uploadfn ) {
* host_client - > uploadfn = 0 ;
SV_BroadcastTPrintf ( PRINT_HIGH , STL_SNAPREFUSED , host_client - > name ) ;
}
}
//3 votes per player.
typedef struct voteinfo_s {
struct voteinfo_s * next ;
float timeout ;
int clientid ;
char command [ 1 ] ;
} voteinfo_t ;
voteinfo_t * voteinfo ;
void VoteAdd ( char * cmd , int id )
{
voteinfo_t * vote ;
vote = Z_Malloc ( sizeof ( voteinfo_t ) + strlen ( cmd ) ) ; //null term is part of voteinfo_t
strcpy ( vote - > command , cmd ) ;
vote - > clientid = id ;
vote - > timeout = realtime + votetime . value * 60 ;
vote - > next = voteinfo ;
voteinfo = vote ;
}
void VoteRemoveCommands ( char * command , int id ) //all of one command
{
voteinfo_t * vote , * prev ;
prev = NULL ;
for ( vote = voteinfo ; vote ; vote = vote - > next )
{
if ( ( ! command | | ! strcmp ( vote - > command , command ) ) & & ( vote - > clientid = = id | | id = = - 1 ) )
{
if ( prev )
prev - > next = vote - > next ;
else
voteinfo = vote - > next ;
Z_Free ( vote ) ;
VoteRemoveCommands ( command , id ) ;
return ;
}
else
prev = vote ;
}
}
void VoteFlushAll ( void )
{
VoteRemoveCommands ( NULL , - 1 ) ;
}
int VoteCount ( char * command , int id ) //all of one command
{
voteinfo_t * vote ;
int num = 0 ;
for ( vote = voteinfo ; vote ; vote = vote - > next )
{
if ( ! command | | ! strcmp ( vote - > command , command ) )
{
if ( vote - > clientid = = id | | id = = - 1 )
num + + ;
}
}
return num ;
}
void VoteCheckTimes ( void )
{
voteinfo_t * vote , * prev ;
prev = NULL ;
for ( vote = voteinfo ; vote ; vote = vote - > next )
{
if ( vote - > timeout < realtime )
{
if ( prev )
prev - > next = vote - > next ;
else
voteinfo = vote - > next ;
Z_Free ( vote ) ;
}
else
prev = vote ;
}
}
void SV_Vote_f ( void )
{
char * command = Cmd_Args ( ) ;
char * base ;
int id = host_client - > userid ;
int num ;
int totalusers = 0 ;
qboolean passes ;
if ( ! votelevel . value )
{
Con_TPrintf ( STL_NOVOTING ) ;
return ;
}
if ( host_client - > ismuted )
{
Con_TPrintf ( STL_MUTEDVOTE ) ;
return ;
}
Cmd_ExecLevel = votelevel . value ;
base = command ;
while ( * base > ' ' )
base + + ;
if ( * base )
* base = ' \0 ' ;
else
base = NULL ;
if ( strchr ( command , ' ; ' ) | | ! strcmp ( command , " if " ) )
{
Con_TPrintf ( STL_BADVOTE ) ;
return ;
}
num = Cmd_Level ( command ) ;
if ( base )
* base = ' ' ;
if ( num ! = Cmd_ExecLevel )
{
Con_TPrintf ( STL_BADVOTE ) ;
return ;
}
VoteCheckTimes ( ) ;
for ( num = 0 ; num < sv . allocated_client_slots ; num + + )
if ( svs . clients [ num ] . state = = cs_spawned )
totalusers + + ;
if ( VoteCount ( command , id ) )
{
VoteRemoveCommands ( command , id ) ;
Con_TPrintf ( STL_OLDVOTEREMOVED ) ;
return ;
}
if ( VoteCount ( NULL , id ) > = 3 )
{
VoteRemoveCommands ( NULL , id ) ;
Con_TPrintf ( STL_VOTESREMOVED ) ;
}
num = VoteCount ( command , - 1 ) + 1 ;
passes = true ;
if ( votepercent . value < 0 & & ( float ) ( totalusers - num ) > = 0.5 * totalusers )
passes = false ;
if ( votepercent . value > = 0 & & num < = totalusers * votepercent . value / 100 )
passes = false ;
if ( num < voteminimum . value )
passes = false ;
if ( passes ) //>min number of votes, and meets the percent required
{
SV_BroadcastTPrintf ( PRINT_HIGH , STL_FINALVOTE , host_client - > name , command ) ;
VoteRemoveCommands ( command , - 1 ) ;
Cbuf_AddText ( command , votelevel . value ) ;
//Cmd_ExecuteString (command, votelevel.value);
return ;
}
else //otherwise, try later.
{
SV_BroadcastTPrintf ( PRINT_HIGH , STL_VOTE , host_client - > name , command ) ;
VoteAdd ( command , id ) ;
}
}
extern qboolean sv_allow_cheats ;
//Sets client to godmode
void Cmd_God_f ( void )
{
if ( ( int ) ( sv_player - > v . flags = ( int ) sv_player - > v . flags ^ FL_NOTARGET ) & FL_NOTARGET )
SV_ClientPrintf ( host_client , PRINT_HIGH , " notarget ON \n " ) ;
else
SV_ClientPrintf ( host_client , PRINT_HIGH , " notarget OFF \n " ) ;
if ( ! sv_allow_cheats )
{
Con_Printf ( " Cheats are not allowed on this server \n " ) ;
return ;
}
if ( ( int ) ( sv_player - > v . flags = ( int ) sv_player - > v . flags ^ FL_GODMODE ) & FL_GODMODE )
SV_ClientPrintf ( host_client , PRINT_HIGH , " godmode ON \n " ) ;
else
SV_ClientPrintf ( host_client , PRINT_HIGH , " godmode OFF \n " ) ;
}
void Cmd_Give_f ( void )
{
char * t ;
int v ;
if ( ! sv_allow_cheats )
{
Con_Printf ( " Cheats are not allowed on this server \n " ) ;
return ;
}
t = Cmd_Argv ( 1 ) ;
v = atoi ( Cmd_Argv ( 2 ) ) ;
if ( strlen ( t ) = = 1 & & ( Cmd_Argc ( ) = = 3 | | ( * t > = ' 0 ' & & * t < = ' 9 ' ) ) )
{
switch ( t [ 0 ] )
{
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
sv_player - > v . items = ( int ) sv_player - > v . items | IT_SHOTGUN < < ( t [ 0 ] - ' 2 ' ) ;
break ;
case ' s ' :
sv_player - > v . ammo_shells = v ;
break ;
case ' n ' :
sv_player - > v . ammo_nails = v ;
break ;
case ' r ' :
sv_player - > v . ammo_rockets = v ;
break ;
case ' h ' :
sv_player - > v . health = v ;
break ;
case ' c ' :
sv_player - > v . ammo_cells = v ;
break ;
}
}
else if ( host_client - > netchan . remote_address . type = = NA_LOOPBACK ) //we don't want clients doing nasty things... like setting movetype 3123
{
int oldself ;
oldself = pr_global_struct - > self ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
Con_Printf ( " Result: %s \n " , svprogfuncs - > EvaluateDebugString ( svprogfuncs , Cmd_Args ( ) ) ) ;
pr_global_struct - > self = oldself ;
}
}
void Cmd_Noclip_f ( void )
{
if ( ! sv_allow_cheats )
{
Con_Printf ( " Cheats are not allowed on this server \n " ) ;
return ;
}
if ( sv_player - > v . movetype ! = MOVETYPE_NOCLIP )
{
sv_player - > v . movetype = MOVETYPE_NOCLIP ;
sv_player - > v . solid = SOLID_TRIGGER ;
SV_ClientPrintf ( host_client , PRINT_HIGH , " noclip ON \n " ) ;
}
else
{
sv_player - > v . movetype = MOVETYPE_WALK ;
if ( sv_player - > v . health > 0 )
sv_player - > v . solid = SOLID_SLIDEBOX ;
else
sv_player - > v . solid = SOLID_NOT ;
SV_ClientPrintf ( host_client , PRINT_HIGH , " noclip OFF \n " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = =
Host_SetPos_f UDC
By Alex Shadowalker
= = = = = = = = = = = = = = = = = = = =
*/
void Cmd_SetPos_f ( void )
{
if ( ! sv_allow_cheats )
{
Con_Printf ( " Cheats are not allowed on this server \n " ) ;
return ;
}
if ( Cmd_Argc ( ) ! = 4 )
{
Con_Printf ( " setpos %i %i %i \n " , ( int ) sv_player - > v . origin [ 0 ] , ( int ) sv_player - > v . origin [ 1 ] , ( int ) sv_player - > v . origin [ 2 ] ) ;
return ;
}
if ( sv_player - > v . movetype ! = MOVETYPE_NOCLIP )
{
sv_player - > v . movetype = MOVETYPE_NOCLIP ;
Con_Printf ( " noclip on \n " ) ;
}
sv_player - > v . origin [ 0 ] = atof ( Cmd_Argv ( 1 ) ) ;
sv_player - > v . origin [ 1 ] = atof ( Cmd_Argv ( 2 ) ) ;
sv_player - > v . origin [ 2 ] = atof ( Cmd_Argv ( 3 ) ) ;
SV_LinkEdict ( sv_player , false ) ;
}
void ED_ClearEdict ( progfuncs_t * progfuncs , edict_t * e ) ;
static void SetUpClientEdict ( client_t * cl , edict_t * ent )
{
2004-10-29 06:11:33 +00:00
extern int pr_teamfield ;
2004-08-23 00:15:46 +00:00
ED_ClearEdict ( svprogfuncs , ent ) ;
2004-10-29 06:11:33 +00:00
ED_Spawned ( ent ) ;
2004-08-23 00:15:46 +00:00
ent - > isfree = false ;
ent - > v . colormap = NUM_FOR_EDICT ( svprogfuncs , ent ) ;
ent - > v . netname = PR_SetString ( svprogfuncs , cl - > name ) ;
2004-10-29 06:11:33 +00:00
if ( pr_teamfield )
2004-11-17 17:38:49 +00:00
( ( string_t * ) & ent - > v ) [ pr_teamfield ] = ( string_t ) PR_SetString ( svprogfuncs , cl - > team ) ;
2004-10-29 06:11:33 +00:00
2004-08-23 00:15:46 +00:00
ent - > v . gravity = cl - > entgravity = 1.0 ;
ent - > v . maxspeed = cl - > maxspeed = sv_maxspeed . value ;
ent - > v . movetype = MOVETYPE_NOCLIP ;
}
/*
= = = = = = = = = = = = = = = = = =
Cmd_Join_f
Set client to player mode without reconnecting
= = = = = = = = = = = = = = = = = =
*/
void Cmd_Join_f ( void )
{
int i ;
client_t * cl ;
int numclients ;
extern cvar_t maxclients ;
if ( host_client - > state ! = cs_spawned )
return ;
if ( ! host_client - > spectator )
return ; // already a player
if ( ! ( host_client - > zquake_extensions & Z_EXT_JOIN_OBSERVE ) ) {
Con_Printf ( " Your QW client doesn't support this command \n " ) ;
return ;
}
if ( password . string [ 0 ] & & stricmp ( password . string , " none " ) ) {
Con_Printf ( " This server requires a %s password. Please disconnect, set the password and reconnect as %s. \n " , " player " , " player " ) ;
return ;
}
// count players already on server
numclients = 0 ;
for ( i = 0 , cl = svs . clients ; i < sv . allocated_client_slots ; i + + , cl + + ) {
if ( cl - > state ! = cs_free & & ! cl - > spectator )
numclients + + ;
}
if ( numclients > = maxclients . value ) {
Con_Printf ( " Can't join, all player slots full \n " ) ;
return ;
}
// call the prog function for removing a client
// this will set the body to a dead frame, among other things
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
if ( SpectatorDisconnect )
PR_ExecuteProgram ( svprogfuncs , SpectatorDisconnect ) ;
host_client - > old_frags = 0 ;
SetUpClientEdict ( host_client , host_client - > edict ) ;
// turn the spectator into a player
host_client - > spectator = false ;
Info_RemoveKey ( host_client - > userinfo , " *spectator " ) ;
// FIXME, bump the client's userid?
// call the progs to get default spawn parms for the new client
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > SetNewParms ) ;
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
host_client - > spawn_parms [ i ] = ( & pr_global_struct - > parm1 ) [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > ClientConnect ) ;
// actually spawn the player
pr_global_struct - > time = sv . time ;
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 ;
}
/*
= = = = = = = = = = = = = = = = = =
Cmd_Observe_f
Set client to spectator mode without reconnecting
= = = = = = = = = = = = = = = = = =
*/
void Cmd_Observe_f ( void )
{
int i ;
client_t * cl ;
int numspectators ;
extern cvar_t maxspectators , spectator_password ;
if ( host_client - > state ! = cs_spawned )
return ;
if ( host_client - > spectator )
return ; // already a spectator
if ( ! ( host_client - > zquake_extensions & Z_EXT_JOIN_OBSERVE ) ) {
Con_Printf ( " Your QW client doesn't support this command \n " ) ;
return ;
}
if ( spectator_password . string [ 0 ] & & stricmp ( spectator_password . string , " none " ) ) {
Con_Printf ( " This server requires a %s password. Please disconnect, set the password and reconnect as %s. \n " , " spectator " , " spectator " ) ;
return ;
}
// count spectators already on server
numspectators = 0 ;
for ( i = 0 , cl = svs . clients ; i < sv . allocated_client_slots ; i + + , cl + + ) {
if ( cl - > state ! = cs_free & & cl - > spectator )
numspectators + + ;
}
if ( numspectators > = maxspectators . value ) {
Con_Printf ( " Can't join, all spectator slots full \n " ) ;
return ;
}
// call the prog function for removing a client
// this will set the body to a dead frame, among other things
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > ClientDisconnect ) ;
host_client - > old_frags = 0 ;
SetUpClientEdict ( host_client , host_client - > edict ) ;
// turn the player into a spectator
host_client - > spectator = true ;
Info_SetValueForStarKey ( host_client - > userinfo , " *spectator " , " 1 " , MAX_INFO_STRING ) ;
// FIXME, bump the client's userid?
// call the progs to get default spawn parms for the new client
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > SetNewParms ) ;
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
host_client - > spawn_parms [ i ] = ( & pr_global_struct - > parm1 ) [ i ] ;
SV_SpawnSpectator ( ) ;
// call the spawn function
if ( SpectatorConnect ) {
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , SpectatorConnect ) ;
}
// send notification to all clients
host_client - > sendinfo = true ;
}
void SV_MVDList_f ( void ) ;
void SV_MVDInfo_f ( void ) ;
typedef struct
{
char * name ;
void ( * func ) ( void ) ;
} ucmd_t ;
ucmd_t ucmds [ ] =
{
{ " new " , SV_New_f } ,
2004-11-17 17:38:49 +00:00
{ " pk3list " , SV_PK3List_f } ,
2004-08-23 00:15:46 +00:00
{ " modellist " , SV_Modellist_f } ,
{ " soundlist " , SV_Soundlist_f } ,
{ " prespawn " , SV_PreSpawn_f } ,
{ " spawn " , SV_Spawn_f } ,
{ " begin " , SV_Begin_f } ,
{ " join " , Cmd_Join_f } ,
{ " observe " , Cmd_Observe_f } ,
{ " drop " , SV_Drop_f } ,
{ " disconnect " , SV_Drop_f } ,
{ " pings " , SV_Pings_f } ,
// issued by hand at client consoles
{ " rate " , SV_Rate_f } ,
{ " kill " , SV_Kill_f } ,
{ " pause " , SV_Pause_f } ,
{ " msg " , SV_Msg_f } ,
{ " sayone " , SV_SayOne_f } ,
{ " say " , SV_Say_f } ,
{ " say_team " , SV_Say_Team_f } ,
{ " setinfo " , SV_SetInfo_f } ,
{ " serverinfo " , SV_ShowServerinfo_f } ,
{ " download " , SV_BeginDownload_f } ,
{ " nextdl " , SV_NextDownload_f } ,
{ " ptrack " , SV_PTrack_f } , //ZOID - used with autocam
{ " snap " , SV_NoSnap_f } ,
{ " vote " , SV_Vote_f } ,
# ifdef SVRANKING
{ " topten " , Rank_ListTop10_f } ,
# endif
{ " god " , Cmd_God_f } ,
{ " give " , Cmd_Give_f } ,
{ " noclip " , Cmd_Noclip_f } ,
{ " setpos " , Cmd_SetPos_f } ,
// {"stopdownload", SV_StopDownload_f},
{ " demolist " , SV_MVDList_f } ,
{ " demoinfo " , SV_MVDInfo_f } ,
{ NULL , NULL }
} ;
# ifdef Q2SERVER
ucmd_t ucmdsq2 [ ] = {
{ " new " , SV_New_f } ,
{ " configstrings " , SVQ2_ConfigStrings_f } ,
{ " baselines " , SVQ2_BaseLines_f } ,
{ " begin " , SV_Begin_f } ,
{ " setinfo " , SV_SetInfo_f } ,
{ " serverinfo " , SV_ShowServerinfo_f } ,
{ " download " , SV_BeginDownload_f } ,
{ " nextdl " , SV_NextDownload_f } ,
2004-08-27 00:45:34 +00:00
{ " nextserver " , SVQ2_NextServer_f } ,
2004-08-23 00:15:46 +00:00
{ " vote " , SV_Vote_f } ,
# ifdef SVRANKING
{ " topten " , Rank_ListTop10_f } ,
# endif
{ " drop " , SV_Drop_f } ,
{ " disconnect " , SV_Drop_f } ,
{ NULL , NULL }
} ;
# endif
/*
= = = = = = = = = = = = = = = = = =
SV_ExecuteUserCommand
= = = = = = = = = = = = = = = = = =
*/
void SV_ExecuteUserCommand ( char * s , qboolean fromQC )
{
ucmd_t * u ;
client_t * oldhost = host_client ;
Cmd_TokenizeString ( s ) ;
sv_player = host_client - > edict ;
Cmd_ExecLevel = 1 ;
SV_BeginRedirect ( RD_CLIENT ) ;
if ( atoi ( Cmd_Argv ( 0 ) ) > 0 ) //now see if it's meant to be from a slave client
{
int pnum = atoi ( Cmd_Argv ( 0 ) ) ;
client_t * s ;
for ( s = host_client ; s ; s = s - > controlled )
{
if ( ! - - pnum )
{
host_client = s ;
break ;
}
}
sv_player = host_client - > edict ;
Cmd_ShiftArgs ( 1 ) ;
}
# ifdef Q2SERVER
if ( host_client - > isq2client )
u = ucmdsq2 ;
else
# endif
u = ucmds ;
for ( ; u - > name ; u + + )
if ( ! strcmp ( Cmd_Argv ( 0 ) , u - > name ) )
{
u - > func ( ) ;
break ;
}
if ( ! u - > name )
{
if ( ! fromQC )
if ( PR_UserCmd ( s ) )
2004-08-27 00:45:34 +00:00
{
host_client = oldhost ;
SV_EndRedirect ( ) ;
2004-08-23 00:15:46 +00:00
return ;
2004-08-27 00:45:34 +00:00
}
2004-08-23 00:15:46 +00:00
if ( sv_cmdlikercon . value & & host_client - > rankid )
{
char remaining [ 1024 ] ;
int i ;
rankstats_t stats ;
if ( ! Rank_GetPlayerStats ( host_client - > rankid , & stats ) )
{
host_client = oldhost ;
SV_EndRedirect ( ) ;
return ;
}
Con_Printf ( " cmd from %s: \n %s \n "
, host_client - > name , net_message . data + 4 ) ;
SV_BeginRedirect ( RD_PACKET ) ;
remaining [ 0 ] = 0 ;
for ( i = 0 ; i < Cmd_Argc ( ) ; i + + )
{
if ( strlen ( remaining ) + strlen ( Cmd_Argv ( i ) ) > = sizeof ( remaining ) - 1 )
{
Con_Printf ( " cmd was too long \n " ) ;
host_client = oldhost ;
SV_EndRedirect ( ) ;
Con_Printf ( " cmd from %s: \n %s \n "
, NET_AdrToString ( net_from ) , " Was too long - possible buffer overflow attempt " ) ;
return ;
}
strcat ( remaining , Cmd_Argv ( i ) ) ;
strcat ( remaining , " " ) ;
}
Cmd_ExecuteString ( remaining , stats . trustlevel ) ;
host_client = oldhost ;
SV_EndRedirect ( ) ;
return ;
}
Con_Printf ( " Bad user command: %s \n " , Cmd_Argv ( 0 ) ) ;
}
host_client = oldhost ;
SV_EndRedirect ( ) ;
}
# ifdef NQPROT
void SVNQ_Spawn_f ( void )
{
int i ;
client_t * client ;
edict_t * ent ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " spawn not valid -- allready spawned \n " ) ;
return ;
}
// send all current names, colors, and frag counts
// FIXME: is this a good thing?
SZ_Clear ( & host_client - > netchan . message ) ;
// send current status of all other players
// normally this could overflow, but no need to check due to backbuf
for ( i = 0 , client = svs . clients ; i < sv . allocated_client_slots ; i + + , client + + )
SV_FullClientUpdateToClient ( client , host_client ) ;
// send all current light styles
for ( i = 0 ; i < MAX_LIGHTSTYLES ; i + + )
{
ClientReliableWrite_Begin ( host_client , svc_lightstyle ,
3 + ( sv . lightstyles [ i ] ? strlen ( sv . lightstyles [ i ] ) : 1 ) ) ;
ClientReliableWrite_Byte ( host_client , ( char ) i ) ;
ClientReliableWrite_String ( host_client , sv . lightstyles [ i ] ) ;
}
// set up the edict
ent = host_client - > edict ;
if ( host_client - > istobeloaded ) //minimal setup
{
host_client - > entgravity = ent - > v . gravity ;
host_client - > maxspeed = ent - > v . maxspeed ;
}
else
{
memset ( & ent - > v , 0 , pr_edict_size - svprogparms . edictsize ) ;
2004-08-31 23:58:18 +00:00
ED_Spawned ( ent ) ;
2004-08-23 00:15:46 +00:00
ent - > v . colormap = NUM_FOR_EDICT ( svprogfuncs , ent ) ;
ent - > v . team = 0 ; // FIXME
ent - > v . netname = PR_SetString ( svprogfuncs , host_client - > name ) ;
host_client - > entgravity = ent - > v . gravity = 1.0 ;
host_client - > maxspeed = ent - > v . maxspeed = sv_maxspeed . value ;
}
//
// force stats to be updated
//
memset ( host_client - > stats , 0 , sizeof ( host_client - > stats ) ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestat , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALSECRETS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > total_secrets ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestat , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALMONSTERS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > total_monsters ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestat , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_SECRETS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > found_secrets ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestat , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_MONSTERS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > killed_monsters ) ;
SZ_Write ( & host_client - > netchan . message , sv . signon . data , sv . signon . cursize ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_signonnum ) ;
MSG_WriteByte ( & host_client - > netchan . message , 3 ) ;
host_client - > send_message = true ;
}
void SVNQ_Begin_f ( void )
{
unsigned pmodel = 0 , emodel = 0 ;
int i ;
qboolean sendangles = false ;
if ( host_client - > state = = cs_spawned )
return ; // don't begin again
host_client - > state = cs_spawned ;
if ( host_client - > istobeloaded )
{
sendangles = true ;
host_client - > istobeloaded = false ;
}
else
{
if ( host_client - > spectator )
{
SV_SpawnSpectator ( ) ;
if ( SpectatorConnect )
{
// copy spawn parms out of the client_t
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
( & pr_global_struct - > parm1 ) [ i ] = host_client - > spawn_parms [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , SpectatorConnect ) ;
}
}
else
{
// copy spawn parms out of the client_t
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
( & pr_global_struct - > parm1 ) [ i ] = host_client - > spawn_parms [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > ClientConnect ) ;
// actually spawn the player
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > PutClientInServer ) ;
}
}
// clear the net statistics, because connecting gives a bogus picture
host_client - > netchan . frame_latency = 0 ;
host_client - > netchan . frame_rate = 0 ;
host_client - > netchan . drop_count = 0 ;
host_client - > netchan . good_count = 0 ;
//check he's not cheating
if ( sv_playermodelchecks . value )
{
pmodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " pmodel " ) ) ;
emodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " emodel " ) ) ;
if ( pmodel ! = sv . model_player_checksum | |
emodel ! = sv . eyes_player_checksum )
SV_BroadcastTPrintf ( PRINT_HIGH , STL_POSSIBLEMODELCHEAT , host_client - > name ) ;
}
// if we are paused, tell the client
if ( sv . paused )
{
if ( ! host_client - > isq2client )
{
ClientReliableWrite_Begin ( host_client , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( host_client , sv . paused ) ;
}
SV_ClientTPrintf ( host_client , PRINT_HIGH , STL_SERVERPAUSED ) ;
}
if ( sendangles )
{
//
// send a fixangle over the reliable channel to make sure it gets there
// Never send a roll angle, because savegames can catch the server
// in a state where it is expecting the client to correct the angle
// and it won't happen if the game was just loaded, so you wind up
// with a permanent head tilt
MSG_WriteByte ( & host_client - > netchan . message , svc_setangle ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
MSG_WriteAngle ( & host_client - > netchan . message , host_client - > edict - > v . angles [ 1 ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
}
SZ_Write ( & host_client - > netchan . message , sv . signon . data , sv . signon . cursize ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_signonnum ) ;
MSG_WriteByte ( & host_client - > netchan . message , 4 ) ;
host_client - > send_message = true ;
}
void SVNQ_PreSpawn_f ( void )
{
edict_t * ent ;
entity_state_t * state ;
int i , e ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " prespawn not valid -- allready spawned \n " ) ;
return ;
}
for ( e = 1 ; e < sv . num_edicts ; e + + )
{
ent = EDICT_NUM ( svprogfuncs , e ) ;
state = & ent - > baseline ;
if ( ! state - > number | | ! state - > modelindex )
{ //ent doesn't have a baseline
continue ;
}
if ( ! ent )
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnbaseline ) ;
MSG_WriteShort ( & host_client - > netchan . message , e ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
for ( i = 0 ; i < 3 ; i + + )
{
MSG_WriteCoord ( & host_client - > netchan . message , 0 ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
}
}
else
{
MSG_WriteByte ( & host_client - > netchan . message , svc_spawnbaseline ) ;
MSG_WriteShort ( & host_client - > netchan . message , e ) ;
MSG_WriteByte ( & host_client - > netchan . message , state - > modelindex & 255 ) ;
MSG_WriteByte ( & host_client - > netchan . message , state - > frame ) ;
MSG_WriteByte ( & host_client - > netchan . message , ( int ) state - > colormap ) ;
MSG_WriteByte ( & host_client - > netchan . message , ( int ) state - > skinnum ) ;
for ( i = 0 ; i < 3 ; i + + )
{
MSG_WriteCoord ( & host_client - > netchan . message , state - > origin [ i ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , state - > angles [ i ] ) ;
}
}
}
for ( i = 0 ; i < sv . num_signon_buffers ; i + + )
SZ_Write ( & host_client - > netchan . message , sv . signon_buffers [ i ] , sv . signon_buffer_size [ i ] ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_signonnum ) ;
MSG_WriteByte ( & host_client - > netchan . message , 2 ) ;
host_client - > send_message = true ;
}
void SVNQ_NQInfo_f ( void )
{
Cmd_TokenizeString ( va ( " setinfo \" %s \" \" %s \" \n " , Cmd_Argv ( 0 ) , Cmd_Argv ( 1 ) ) ) ;
SV_SetInfo_f ( ) ;
}
void SVNQ_NQColour_f ( void )
{
int top ;
int bottom ;
int playercolor ;
if ( Cmd_Argc ( ) = = 2 )
top = bottom = atoi ( Cmd_Argv ( 1 ) ) ;
else
{
top = atoi ( Cmd_Argv ( 1 ) ) ;
bottom = atoi ( Cmd_Argv ( 2 ) ) ;
}
top & = 15 ;
if ( top > 13 )
top = 13 ;
bottom & = 15 ;
if ( bottom > 13 )
bottom = 13 ;
playercolor = top * 16 + bottom ;
if ( progstype ! = PROG_QW )
host_client - > edict - > v . team = bottom + 1 ;
Info_SetValueForKey ( host_client - > userinfo , " topcolor " , va ( " %i " , top ) , MAX_INFO_STRING ) ;
Info_SetValueForKey ( host_client - > userinfo , " bottomcolor " , va ( " %i " , bottom ) , MAX_INFO_STRING ) ;
switch ( bottom )
{
case 4 :
Info_SetValueForKey ( host_client - > userinfo , " team " , " red " , MAX_INFO_STRING ) ;
break ;
case 14 :
Info_SetValueForKey ( host_client - > userinfo , " team " , " blue " , MAX_INFO_STRING ) ;
break ;
default :
Info_SetValueForKey ( host_client - > userinfo , " team " , va ( " t%i " , bottom + 1 ) , MAX_INFO_STRING ) ;
break ;
}
SV_ExtractFromUserinfo ( host_client ) ;
MSG_WriteByte ( & sv . reliable_datagram , svc_setinfo ) ;
MSG_WriteByte ( & sv . reliable_datagram , host_client - svs . clients ) ;
MSG_WriteString ( & sv . reliable_datagram , " topcolor " ) ;
MSG_WriteString ( & sv . reliable_datagram , Info_ValueForKey ( host_client - > userinfo , " topcolor " ) ) ;
MSG_WriteByte ( & sv . reliable_datagram , svc_setinfo ) ;
MSG_WriteByte ( & sv . reliable_datagram , host_client - svs . clients ) ;
MSG_WriteString ( & sv . reliable_datagram , " bottomcolor " ) ;
MSG_WriteString ( & sv . reliable_datagram , Info_ValueForKey ( host_client - > userinfo , " bottomcolor " ) ) ;
MSG_WriteByte ( & sv . reliable_datagram , svc_setinfo ) ;
MSG_WriteByte ( & sv . reliable_datagram , host_client - svs . clients ) ;
MSG_WriteString ( & sv . reliable_datagram , " team " ) ;
MSG_WriteString ( & sv . reliable_datagram , Info_ValueForKey ( host_client - > userinfo , " team " ) ) ;
MSG_WriteByte ( & sv . nqreliable_datagram , svc_updatecolors ) ;
MSG_WriteByte ( & sv . nqreliable_datagram , host_client - svs . clients ) ;
MSG_WriteByte ( & sv . nqreliable_datagram , playercolor ) ;
}
ucmd_t nqucmds [ ] =
{
{ " status " , NULL } ,
{ " god " , Cmd_God_f } ,
{ " give " , Cmd_Give_f } ,
{ " notarget " , NULL } ,
{ " fly " , NULL } ,
{ " noclip " , Cmd_Noclip_f } ,
{ " name " , SVNQ_NQInfo_f } ,
{ " say " , SV_Say_f } ,
{ " say_team " , SV_Say_Team_f } ,
{ " tell " , SV_SayOne_f } ,
{ " color " , SVNQ_NQColour_f } ,
{ " kill " , SV_Kill_f } ,
{ " pause " , SV_Pause_f } ,
{ " spawn " , SVNQ_Spawn_f } ,
{ " begin " , SVNQ_Begin_f } ,
{ " prespawn " , SVNQ_PreSpawn_f } ,
{ " kick " , NULL } ,
{ " ping " , NULL } ,
{ " ban " , NULL } ,
{ " vote " , SV_Vote_f } ,
# ifdef SVRANKING
{ " topten " , Rank_ListTop10_f } ,
# endif
{ NULL , NULL }
} ;
void SVNQ_ExecuteUserCommand ( char * s )
{
ucmd_t * u ;
Cmd_TokenizeString ( s ) ;
sv_player = host_client - > edict ;
Cmd_ExecLevel = 1 ;
SV_BeginRedirect ( RD_CLIENT ) ;
for ( u = nqucmds ; u - > name ; u + + )
{
if ( ! strcmp ( Cmd_Argv ( 0 ) , u - > name ) )
{
if ( ! u - > func )
{
Con_Printf ( " Command was disabled \n " ) ;
}
else
u - > func ( ) ;
break ;
}
}
SV_EndRedirect ( ) ;
if ( ! u - > name )
Con_Printf ( " %s tried to \" %s \" \n " , host_client - > name , s ) ;
}
# endif
int implevels [ 256 ] ;
qboolean SV_FiltureImpulse ( int imp , int level )
{
if ( imp < 0 | | imp > 255 )
return true ; //erm
if ( implevels [ imp ] > level )
return false ;
return true ;
}
void SV_FilterImpulseInit ( void )
{
char buffer [ 1024 ] ;
char * s ;
int lev ;
int imp ;
memset ( implevels , 0 , sizeof ( implevels ) ) ;
s = COM_LoadStackFile ( " impfiltr.cfg " , buffer , sizeof ( buffer ) ) ;
if ( ! s )
Con_Printf ( " impfiltr.cfg not found. Impulse filters are disabled \n " ) ;
while ( s )
{
s = COM_Parse ( s ) ;
if ( ! s )
return ;
imp = atoi ( com_token ) ;
s = COM_Parse ( s ) ;
if ( ! s )
{
Con_Printf ( " Unexpected eof in impfiltr.cfg \n " ) ;
return ;
}
lev = atoi ( com_token ) ;
if ( imp > 255 | | imp < 0 | | lev < 0 | | lev > RESTRICT_MAX )
Con_Printf ( " impfiltr.cfg - bad paramters \n " ) ;
else
implevels [ imp ] = lev ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
USER CMD EXECUTION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# ifdef SERVERONLY
/*
= = = = = = = = = = = = = = =
V_CalcRoll
Used by view and sv_user
= = = = = = = = = = = = = = =
*/
float V_CalcRoll ( vec3_t angles , vec3_t velocity )
{
vec3_t forward , right , up ;
float sign ;
float side ;
float value ;
AngleVectors ( angles , forward , right , up ) ;
side = DotProduct ( velocity , right ) ;
sign = side < 0 ? - 1 : 1 ;
side = fabs ( side ) ;
value = cl_rollangle . value ;
if ( side < cl_rollspeed . value )
side = side * value / cl_rollspeed . value ;
else
side = value ;
return side * sign ;
}
# endif
//============================================================================
vec3_t pmove_mins , pmove_maxs ;
/*
= = = = = = = = = = = = = = = = = = = =
AddLinksToPmove
= = = = = = = = = = = = = = = = = = = =
*/
void AddLinksToPmove ( areanode_t * node )
{
int Q1_HullPointContents ( hull_t * hull , int num , vec3_t p ) ;
link_t * l , * next ;
edict_t * check ;
int pl ;
int i ;
physent_t * pe ;
float os , omt ;
hull_t * hull ;
vec3_t offset ;
pl = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
// touch linked edicts
for ( l = node - > solid_edicts . next ; l ! = & node - > solid_edicts ; l = next )
{
next = l - > next ;
check = EDICT_FROM_AREA ( l ) ;
if ( check - > v . owner = = pl )
continue ; // player's own missile
if ( check - > v . solid = = SOLID_BSP
| | check - > v . solid = = SOLID_BBOX
| | check - > v . solid = = SOLID_SLIDEBOX )
{
if ( check = = sv_player )
continue ;
for ( i = 0 ; i < 3 ; i + + )
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
break ;
if ( i ! = 3 )
continue ;
2004-09-04 18:01:53 +00:00
2004-08-23 00:15:46 +00:00
if ( pmove . numphysent = = MAX_PHYSENTS )
break ;
pe = & pmove . physents [ pmove . numphysent ] ;
2004-09-04 18:01:53 +00:00
pe - > notouch = ! ( ( int ) sv_player - > v . dimension_solid & ( int ) check - > v . dimension_hit ) ;
if ( ! ( ( int ) sv_player - > v . dimension_hit & ( int ) check - > v . dimension_solid ) )
continue ;
2004-08-23 00:15:46 +00:00
pmove . numphysent + + ;
VectorCopy ( check - > v . origin , pe - > origin ) ;
VectorCopy ( check - > v . angles , pe - > angles ) ;
pe - > info = NUM_FOR_EDICT ( svprogfuncs , check ) ;
if ( check - > v . solid = = SOLID_BSP )
2004-11-17 17:38:49 +00:00
{
if ( progstype ! = PROG_H2 )
pe - > angles [ 0 ] * = - 1 ; //quake is wierd. I guess someone fixed it hexen2... or my code is buggy or something...
2004-08-23 00:15:46 +00:00
pe - > model = sv . models [ ( int ) ( check - > v . modelindex ) ] ;
2004-11-17 17:38:49 +00:00
}
2004-08-23 00:15:46 +00:00
else
{
pe - > model = NULL ;
VectorCopy ( check - > v . mins , pe - > mins ) ;
VectorCopy ( check - > v . maxs , pe - > maxs ) ;
}
}
}
if ( sv_player - > v . mins [ 2 ] ! = 24 ) //crouching/dead
for ( l = node - > trigger_edicts . next ; l ! = & node - > trigger_edicts ; l = next )
{
next = l - > next ;
check = EDICT_FROM_AREA ( l ) ;
if ( check - > v . owner = = pl )
continue ; // player's own missile
if ( ( progstype ! = PROG_H2 & & check - > v . solid = = SOLID_LADDERQ1 ) | | check - > v . solid = = SOLID_LADDER )
{
for ( i = 0 ; i < 3 ; i + + )
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
break ;
if ( i ! = 3 )
continue ;
2004-09-04 18:01:53 +00:00
if ( ! ( ( int ) sv_player - > v . dimension_hit & ( int ) check - > v . dimension_solid ) )
2004-08-31 23:58:18 +00:00
continue ;
2004-08-23 00:15:46 +00:00
// check->v.model = "a";
os = check - > v . solid ;
omt = check - > v . movetype ;
check - > v . solid = SOLID_BSP ;
check - > v . movetype = MOVETYPE_PUSH ;
hull = SV_HullForEntity ( check , 0 , sv_player - > v . mins , sv_player - > v . maxs , offset ) ;
check - > v . movetype = omt ;
check - > v . solid = os ;
// test the point
if ( hull - > funcs . HullPointContents ( hull , sv_player - > v . origin ) = = FTECONTENTS_SOLID )
sv_player - > v . fteflags = ( int ) sv_player - > v . fteflags | FF_LADDER ; //touch that ladder!
}
}
// recurse down both sides
if ( node - > axis = = - 1 )
return ;
if ( pmove_maxs [ node - > axis ] > node - > dist )
AddLinksToPmove ( node - > children [ 0 ] ) ;
if ( pmove_mins [ node - > axis ] < node - > dist )
AddLinksToPmove ( node - > children [ 1 ] ) ;
}
/*
= = = = = = = = = = = = = = = =
AddAllEntsToPmove
For debugging
= = = = = = = = = = = = = = = =
*/
void AddAllEntsToPmove ( void )
{
int e ;
edict_t * check ;
int i ;
physent_t * pe ;
int pl ;
pl = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
for ( e = 1 ; e < sv . num_edicts ; e + + )
{
check = EDICT_NUM ( svprogfuncs , e ) ;
if ( check - > isfree )
continue ;
if ( check - > v . owner = = pl )
continue ;
if ( check - > v . solid = = SOLID_BSP
| | check - > v . solid = = SOLID_BBOX
| | check - > v . solid = = SOLID_SLIDEBOX )
{
if ( check = = sv_player )
continue ;
for ( i = 0 ; i < 3 ; i + + )
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
break ;
if ( i ! = 3 )
continue ;
pe = & pmove . physents [ pmove . numphysent ] ;
VectorCopy ( check - > v . origin , pe - > origin ) ;
VectorCopy ( check - > v . angles , pe - > angles ) ;
pmove . physents [ pmove . numphysent ] . info = e ;
if ( check - > v . solid = = SOLID_BSP )
pe - > model = sv . models [ ( int ) ( check - > v . modelindex ) ] ;
else
{
pe - > angles [ 0 ] = pe - > angles [ 1 ] = pe - > angles [ 2 ] = 0 ;
pe - > model = NULL ;
VectorCopy ( check - > v . mins , pe - > mins ) ;
VectorCopy ( check - > v . maxs , pe - > maxs ) ;
}
if ( + + pmove . numphysent = = MAX_PHYSENTS )
break ;
}
}
}
int SV_PMTypeForClient ( client_t * cl )
{
if ( cl - > edict - > v . movetype = = MOVETYPE_NOCLIP )
{
if ( cl - > zquake_extensions & Z_EXT_PM_TYPE_NEW )
return PM_SPECTATOR ;
return PM_OLD_SPECTATOR ;
}
if ( cl - > edict - > v . movetype = = MOVETYPE_FLY )
return PM_FLY ;
if ( cl - > edict - > v . movetype = = MOVETYPE_NONE )
2004-10-18 10:48:33 +00:00
{
if ( sv_brokenmovetypes . value )
return PM_NORMAL ;
2004-08-23 00:15:46 +00:00
return PM_NONE ;
2004-10-18 10:48:33 +00:00
}
2004-08-23 00:15:46 +00:00
if ( cl - > edict - > v . health < = 0 )
return PM_DEAD ;
return PM_NORMAL ;
}
/*
= = = = = = = = = = =
SV_PreRunCmd
= = = = = = = = = = =
Done before running a player command . Clears the touch array
*/
qbyte playertouch [ ( MAX_EDICTS + 7 ) / 8 ] ;
void SV_PreRunCmd ( void )
{
memset ( playertouch , 0 , sizeof ( playertouch ) ) ;
}
/*
= = = = = = = = = = =
SV_RunCmd
= = = = = = = = = = =
*/
void SV_RunCmd ( usercmd_t * ucmd , qboolean recurse )
{
edict_t * ent ;
int i , n ;
int oldmsec ;
double tmp_time ;
qboolean jumpable ;
# ifdef Q2SERVER
if ( ! svprogfuncs )
{
ge - > ClientThink ( host_client - > q2edict , ucmd ) ;
return ;
}
# endif
// DMW copied this KK hack copied from QuakeForge anti-cheat
// (also extra inside parm on all SV_RunCmds that follow)
// To prevent a infinite loop
if ( ! recurse ) {
host_client - > msecs + = ucmd - > msec ;
if ( ( tmp_time = realtime - host_client - > last_check ) > = sv_cheatspeedchecktime . value ) {
tmp_time = tmp_time * 1000.0 * sv_cheatpc . value / 100.0 ;
if ( host_client - > msecs > tmp_time ) {
host_client - > msec_cheating + + ;
SV_BroadcastTPrintf ( PRINT_HIGH ,
STL_SPEEDCHEATPOSSIBLE ,
host_client - > msecs , tmp_time ,
host_client - > msec_cheating , host_client - > name ) ;
if ( host_client - > msec_cheating > = 2 ) {
SV_BroadcastTPrintf ( PRINT_HIGH ,
STL_SPEEDCHEATKICKED ,
host_client - > name , NET_AdrToString ( host_client - > netchan . remote_address ) ) ;
SV_DropClient ( host_client ) ;
}
}
host_client - > msecs = 0 ;
host_client - > last_check = realtime ;
}
}
// end KK hack copied from QuakeForge anti-cheat
//it's amazing how code get's copied around...
cmd = * ucmd ;
// chop up very long commands
if ( cmd . msec > 50 )
{
oldmsec = ucmd - > msec ;
cmd . msec = oldmsec / 2 ;
SV_RunCmd ( & cmd , true ) ;
cmd . msec = oldmsec / 2 + ( oldmsec & 1 ) ; //give them back thier msec.
cmd . impulse = 0 ;
SV_RunCmd ( & cmd , true ) ;
return ;
}
host_frametime = ucmd - > msec * 0.001 ;
if ( host_frametime > 0.1 )
host_frametime = 0.1 ;
# ifdef SVCHAT
if ( SV_ChatMove ( ucmd - > impulse ) )
{
ucmd - > buttons = 0 ;
ucmd - > impulse = 0 ;
ucmd - > forwardmove = ucmd - > sidemove = ucmd - > upmove = 0 ;
}
# endif
if ( ! sv_player - > v . fixangle )
{
sv_player - > v . v_angle [ 0 ] = SHORT2ANGLE ( ucmd - > angles [ 0 ] ) ;
sv_player - > v . v_angle [ 1 ] = SHORT2ANGLE ( ucmd - > angles [ 1 ] ) ;
sv_player - > v . v_angle [ 2 ] = SHORT2ANGLE ( ucmd - > angles [ 2 ] ) ;
}
if ( progstype = = PROG_H2 )
sv_player - > v . light_level = 128 ; //hmm... HACK!!!
sv_player - > v . button0 = ucmd - > buttons & 1 ;
2004-09-04 18:01:53 +00:00
sv_player - > v . button2 = ( ucmd - > buttons > > 1 ) & 1 ;
2004-08-31 09:05:42 +00:00
if ( pr_allowbutton1 . value ) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
2004-09-04 18:01:53 +00:00
sv_player - > v . button1 = ( ( ucmd - > buttons > > 2 ) & 1 ) ;
// DP_INPUTBUTTONS
sv_player - > v . button3 = ( ( ucmd - > buttons > > 2 ) & 1 ) ;
sv_player - > v . button4 = ( ( ucmd - > buttons > > 3 ) & 1 ) ;
sv_player - > v . button5 = ( ( ucmd - > buttons > > 4 ) & 1 ) ;
sv_player - > v . button6 = ( ( ucmd - > buttons > > 5 ) & 1 ) ;
sv_player - > v . button7 = ( ( ucmd - > buttons > > 6 ) & 1 ) ;
sv_player - > v . button8 = ( ( ucmd - > buttons > > 7 ) & 1 ) ;
2004-08-23 00:15:46 +00:00
if ( ucmd - > impulse & & SV_FiltureImpulse ( ucmd - > impulse , host_client - > trustlevel ) )
sv_player - > v . impulse = ucmd - > impulse ;
if ( host_client - > iscuffed )
{
sv_player - > v . impulse = 0 ;
sv_player - > v . button0 = 0 ;
}
sv_player - > v . movement [ 0 ] = ucmd - > forwardmove * host_frametime ;
sv_player - > v . movement [ 1 ] = ucmd - > sidemove * host_frametime ;
sv_player - > v . movement [ 2 ] = ucmd - > upmove * host_frametime ;
SV_CheckVelocity ( sv_player ) ;
//
// angles
// show 1/3 the pitch angle and all the roll angle
if ( sv_player - > v . health > 0 )
{
if ( ! sv_player - > v . fixangle )
{
sv_player - > v . angles [ PITCH ] = - sv_player - > v . v_angle [ PITCH ] / 3 ;
sv_player - > v . angles [ YAW ] = sv_player - > v . v_angle [ YAW ] ;
}
sv_player - > v . angles [ ROLL ] =
V_CalcRoll ( sv_player - > v . angles , sv_player - > v . velocity ) * 4 ;
}
if ( ! host_client - > spectator )
{
vec_t oldvz ;
pr_global_struct - > frametime = host_frametime ;
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
oldvz = sv_player - > v . velocity [ 2 ] ;
if ( progstype ! = PROG_QW )
{
# define FL_JUMPRELEASED 4096
jumpable = ( int ) sv_player - > v . flags & FL_JUMPRELEASED ;
pmove . waterjumptime = sv_player - > v . teleport_time ;
if ( pmove . waterjumptime > sv . time )
sv_player - > v . flags = ( int ) sv_player - > v . flags | FL_WATERJUMP ;
sv_player - > v . teleport_time = sv . time + pmove . waterjumptime ;
}
else
jumpable = false ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > PlayerPreThink ) ;
if ( progstype ! = PROG_QW )
{
if ( sv_player - > v . velocity [ 2 ] = = 225 & & sv_player - > v . teleport_time > sv . time )
{
sv_player - > v . velocity [ 2 ] = oldvz ;
// Con_Printf("Waterjump detected\n");
}
sv_player - > v . flags = ( int ) sv_player - > v . flags & ~ FL_WATERJUMP ;
sv_player - > v . teleport_time = pmove . waterjumptime ;
if ( jumpable & & ! ( ( int ) sv_player - > v . flags & FL_JUMPRELEASED ) ) //hmm... a jump was hit.
sv_player - > v . velocity [ 2 ] - = 270 ;
}
SV_RunThink ( sv_player ) ;
}
// memset(&pmove, 0, sizeof(pmove));
// memset(&movevars, 0, sizeof(movevars));
player_mins [ 0 ] = sv_player - > v . mins [ 0 ] ;
player_mins [ 1 ] = sv_player - > v . mins [ 1 ] ;
player_mins [ 2 ] = sv_player - > v . mins [ 2 ] ;
player_maxs [ 0 ] = sv_player - > v . maxs [ 0 ] ;
player_maxs [ 1 ] = sv_player - > v . maxs [ 1 ] ;
player_maxs [ 2 ] = sv_player - > v . maxs [ 2 ] ;
for ( i = 0 ; i < 3 ; i + + )
pmove . origin [ i ] = sv_player - > v . origin [ i ] ; // + (sv_player->v.mins[i] - player_mins[i]);
VectorCopy ( sv_player - > v . velocity , pmove . velocity ) ;
VectorCopy ( sv_player - > v . v_angle , pmove . angles ) ;
pmove . pm_type = SV_PMTypeForClient ( host_client ) ;
pmove . jump_held = host_client - > jump_held ;
pmove . jump_msec = 0 ;
if ( progstype ! = PROG_QW ) //this is just annoying.
pmove . waterjumptime = sv_player - > v . teleport_time - sv . time ;
else
pmove . waterjumptime = sv_player - > v . teleport_time ;
pmove . numphysent = 1 ;
pmove . physents [ 0 ] . model = sv . worldmodel ;
pmove . cmd = * ucmd ;
if ( sv . worldmodel - > fromgame = = fg_quake2 | | sv . worldmodel - > fromgame = = fg_quake3 )
pmove . hullnum = ( ( int ) sv_player - > v . fteflags & FF_CROUCHING ) ? 3 : 1 ;
else
pmove . hullnum = SV_HullNumForPlayer ( sv_player - > v . hull , sv_player - > v . mins , sv_player - > v . maxs ) ;
movevars . entgravity = host_client - > entgravity ;
movevars . maxspeed = host_client - > maxspeed ;
movevars . bunnyspeedcap = pm_bunnyspeedcap . value ;
movevars . ktjump = pm_ktjump . value ;
movevars . slidefix = ( pm_slidefix . value ! = 0 ) ;
movevars . airstep = ( pm_airstep . value ! = 0 ) ;
if ( sv_player - > v . hasted )
movevars . maxspeed * = sv_player - > v . hasted ;
for ( i = 0 ; i < 3 ; i + + )
{
pmove_mins [ i ] = pmove . origin [ i ] - 256 ;
pmove_maxs [ i ] = pmove . origin [ i ] + 256 ;
}
sv_player - > v . fteflags = ( int ) sv_player - > v . fteflags & ~ FF_LADDER ; //assume not touching ladder trigger
# if 1
AddLinksToPmove ( sv_areanodes ) ;
# else
AddAllEntsToPmove ( ) ;
# endif
if ( ( int ) sv_player - > v . fteflags & FF_LADDER )
pmove . onladder = true ;
else
pmove . onladder = false ;
#if 0
{
int before , after ;
before = PM_TestPlayerPosition ( pmove . origin ) ;
PlayerMove ( ) ;
after = PM_TestPlayerPosition ( pmove . origin ) ;
if ( sv_player - > v . health > 0 & & before & & ! after )
Con_Printf ( " player %s got stuck in playermove!!!! \n " , host_client - > name ) ;
}
# else
PM_PlayerMove ( ) ;
# endif
host_client - > jump_held = pmove . jump_held ;
if ( progstype ! = PROG_QW ) //this is just annoying.
sv_player - > v . teleport_time = pmove . waterjumptime + sv . time ;
else
sv_player - > v . teleport_time = pmove . waterjumptime ;
sv_player - > v . waterlevel = pmove . waterlevel ;
if ( pmove . watertype & FTECONTENTS_SOLID )
sv_player - > v . watertype = Q1CONTENTS_SOLID ;
else if ( pmove . watertype & FTECONTENTS_SKY )
sv_player - > v . watertype = Q1CONTENTS_SKY ;
else if ( pmove . watertype & FTECONTENTS_LAVA )
sv_player - > v . watertype = Q1CONTENTS_LAVA ;
else if ( pmove . watertype & FTECONTENTS_SLIME )
sv_player - > v . watertype = Q1CONTENTS_SLIME ;
else if ( pmove . watertype & FTECONTENTS_WATER )
sv_player - > v . watertype = Q1CONTENTS_WATER ;
else
sv_player - > v . watertype = Q1CONTENTS_EMPTY ;
if ( pmove . onground )
{
sv_player - > v . flags = ( int ) sv_player - > v . flags | FL_ONGROUND ;
sv_player - > v . groundentity = EDICT_TO_PROG ( svprogfuncs , EDICT_NUM ( svprogfuncs , pmove . physents [ pmove . groundent ] . info ) ) ;
}
else
sv_player - > v . flags = ( int ) sv_player - > v . flags & ~ FL_ONGROUND ;
for ( i = 0 ; i < 3 ; i + + )
sv_player - > v . origin [ i ] = pmove . origin [ i ] ; // - (sv_player->v.mins[i] - player_mins[i]);
#if 0
// truncate velocity the same way the net protocol will
for ( i = 0 ; i < 3 ; i + + )
sv_player - > v . velocity [ i ] = ( int ) pmove . velocity [ i ] ;
# else
VectorCopy ( pmove . velocity , sv_player - > v . velocity ) ;
# endif
VectorCopy ( pmove . angles , sv_player - > v . v_angle ) ;
player_mins [ 0 ] = - 16 ;
player_mins [ 1 ] = - 16 ;
player_mins [ 2 ] = - 24 ;
player_maxs [ 0 ] = 16 ;
player_maxs [ 1 ] = 16 ;
player_maxs [ 2 ] = 32 ;
if ( ! host_client - > spectator )
{
// link into place and touch triggers
SV_LinkEdict ( sv_player , true ) ;
2004-09-04 18:01:53 +00:00
/* for (i = 0; i < pmove.numphysent; i++)
{
}
*/
2004-08-23 00:15:46 +00:00
// touch other objects
for ( i = 0 ; i < pmove . numtouch ; i + + )
{
2004-09-04 18:01:53 +00:00
if ( pmove . physents [ pmove . touchindex [ i ] ] . notouch )
continue ;
2004-08-23 00:15:46 +00:00
n = pmove . physents [ pmove . touchindex [ i ] ] . info ;
ent = EDICT_NUM ( svprogfuncs , n ) ;
if ( ! ent - > v . touch | | ( playertouch [ n / 8 ] & ( 1 < < ( n % 8 ) ) ) )
continue ;
2004-09-04 18:01:53 +00:00
2004-08-23 00:15:46 +00:00
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , ent ) ;
pr_global_struct - > other = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , ent - > v . touch ) ;
playertouch [ n / 8 ] | = 1 < < ( n % 8 ) ;
}
}
}
/*
= = = = = = = = = = =
SV_PostRunCmd
= = = = = = = = = = =
Done after running a player command .
*/
void SV_PostRunCmd ( void )
{
// run post-think
if ( ! svprogfuncs )
return ;
if ( ! host_client - > spectator ) {
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , pr_global_struct - > PlayerPostThink ) ;
SV_RunNewmis ( ) ;
} else if ( SpectatorThink ) {
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , SpectatorThink ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
SV_ExecuteClientMessage
The current net_message is parsed for the given client
= = = = = = = = = = = = = = = = = = =
*/
void SV_ClientThink ( void ) ;
void SV_ExecuteClientMessage ( client_t * cl )
{
client_t * split ;
int c ;
char * s ;
usercmd_t oldest , oldcmd , newcmd ;
client_frame_t * frame ;
vec3_t o ;
qboolean move_issued = false ; //only allow one move command
int checksumIndex ;
qbyte checksum , calculatedChecksum ;
int seq_hash ;
// calc ping time
if ( cl - > frames )
{ //split screen doesn't always have frames.
frame = & cl - > frames [ cl - > netchan . incoming_acknowledged & UPDATE_MASK ] ;
frame - > ping_time = realtime - frame - > senttime ;
}
else
return ; //shouldn't happen...
// make sure the reply sequence number matches the incoming
// sequence number
if ( cl - > netchan . incoming_sequence > = cl - > netchan . outgoing_sequence )
cl - > netchan . outgoing_sequence = cl - > netchan . incoming_sequence ;
else
cl - > send_message = false ; // don't reply, sequences have slipped
// save time for ping calculations
if ( cl - > frames )
{ //split screen doesn't always have frames.
cl - > frames [ cl - > netchan . outgoing_sequence & UPDATE_MASK ] . senttime = realtime ;
cl - > frames [ cl - > netchan . outgoing_sequence & UPDATE_MASK ] . ping_time = - 1 ;
}
host_client = cl ;
sv_player = host_client - > edict ;
seq_hash = cl - > netchan . incoming_sequence ;
// mark time so clients will know how much to predict
// other players
cl - > localtime = sv . time ;
cl - > delta_sequence = - 1 ; // no delta unless requested
while ( 1 )
{
if ( msg_badread )
{
Con_Printf ( " SV_ReadClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
}
c = MSG_ReadByte ( ) ;
2004-09-04 18:01:53 +00:00
haveannothergo :
2004-08-23 00:15:46 +00:00
if ( c = = - 1 )
break ;
switch ( c )
{
default :
Con_Printf ( " SV_ReadClientMessage: unknown command char %i \n " , c ) ;
SV_DropClient ( cl ) ;
return ;
case clc_nop :
break ;
case clc_delta :
cl - > delta_sequence = MSG_ReadByte ( ) ;
break ;
case clc_move :
if ( move_issued )
return ; // someone is trying to cheat...
move_issued = true ;
checksumIndex = MSG_GetReadCount ( ) ;
checksum = ( qbyte ) MSG_ReadByte ( ) ;
// read loss percentage
cl - > lossage = MSG_ReadByte ( ) ;
for ( split = cl ; cl ; cl = cl - > controlled ) //FIXME
{
host_client = cl ;
cl - > localtime = sv . time ;
sv_player = cl - > edict ;
MSG_ReadDeltaUsercmd ( & nullcmd , & oldest ) ;
MSG_ReadDeltaUsercmd ( & oldest , & oldcmd ) ;
MSG_ReadDeltaUsercmd ( & oldcmd , & newcmd ) ;
2004-09-04 18:01:53 +00:00
if ( cl - > state = = cs_spawned )
2004-08-23 00:15:46 +00:00
{
2004-09-04 18:01:53 +00:00
if ( split = = cl )
2004-08-23 00:15:46 +00:00
{
2004-09-04 18:01:53 +00:00
// if the checksum fails, ignore the rest of the packet
calculatedChecksum = COM_BlockSequenceCRCByte (
net_message . data + checksumIndex + 1 ,
MSG_GetReadCount ( ) - checksumIndex - 1 ,
seq_hash ) ;
2004-08-23 00:15:46 +00:00
2004-09-04 18:01:53 +00:00
if ( calculatedChecksum ! = checksum )
2004-08-23 00:15:46 +00:00
{
2004-09-04 18:01:53 +00:00
Con_DPrintf ( " Failed command checksum for %s(%d) (%d != %d) \n " ,
cl - > name , cl - > netchan . incoming_sequence , checksum , calculatedChecksum ) ;
for ( ; cl ; cl = cl - > controlled ) //FIXME
{
MSG_ReadDeltaUsercmd ( & nullcmd , & oldest ) ;
MSG_ReadDeltaUsercmd ( & oldest , & oldcmd ) ;
MSG_ReadDeltaUsercmd ( & oldcmd , & newcmd ) ;
}
break ; ;
2004-08-23 00:15:46 +00:00
}
}
2004-09-04 18:01:53 +00:00
if ( cl - > iscrippled )
{
cl - > lastcmd . forwardmove = 0 ; //hmmm.... does this work well enough?
oldest . forwardmove = 0 ;
newcmd . forwardmove = 0 ;
2004-08-23 00:15:46 +00:00
2004-09-04 18:01:53 +00:00
cl - > lastcmd . sidemove = 0 ;
oldest . sidemove = 0 ;
newcmd . sidemove = 0 ;
2004-08-23 00:15:46 +00:00
2004-09-04 18:01:53 +00:00
cl - > lastcmd . upmove = 0 ;
oldest . upmove = 0 ;
newcmd . upmove = 0 ;
}
2004-08-23 00:15:46 +00:00
2004-09-04 18:01:53 +00:00
if ( ! sv . paused )
2004-08-23 00:15:46 +00:00
{
2004-09-04 18:01:53 +00:00
if ( sv_nomsec . value | | SV_PlayerPhysicsQC )
2004-08-23 00:15:46 +00:00
{
2004-09-04 18:01:53 +00:00
if ( ! sv_player - > v . fixangle )
{
sv_player - > v . v_angle [ 0 ] = newcmd . angles [ 0 ] * ( 360.0 / 65536 ) ;
sv_player - > v . v_angle [ 1 ] = newcmd . angles [ 1 ] * ( 360.0 / 65536 ) ;
sv_player - > v . v_angle [ 2 ] = newcmd . angles [ 2 ] * ( 360.0 / 65536 ) ;
}
if ( newcmd . impulse ) // && SV_FiltureImpulse(newcmd.impulse, host_client->trustlevel))
sv_player - > v . impulse = newcmd . impulse ;
2004-10-10 06:32:29 +00:00
2004-09-04 18:01:53 +00:00
sv_player - > v . button0 = newcmd . buttons & 1 ;
2004-10-10 06:32:29 +00:00
sv_player - > v . button2 = ( newcmd . buttons > > 1 ) & 1 ;
if ( pr_allowbutton1 . value ) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
sv_player - > v . button1 = ( ( newcmd . buttons > > 2 ) & 1 ) ;
// DP_INPUTBUTTONS
sv_player - > v . button3 = ( ( newcmd . buttons > > 2 ) & 1 ) ;
sv_player - > v . button4 = ( ( newcmd . buttons > > 3 ) & 1 ) ;
sv_player - > v . button5 = ( ( newcmd . buttons > > 4 ) & 1 ) ;
sv_player - > v . button6 = ( ( newcmd . buttons > > 5 ) & 1 ) ;
sv_player - > v . button7 = ( ( newcmd . buttons > > 6 ) & 1 ) ;
sv_player - > v . button8 = ( ( newcmd . buttons > > 7 ) & 1 ) ;
2004-09-04 18:01:53 +00:00
cl - > lastcmd = newcmd ;
cl - > lastcmd . buttons = 0 ; // avoid multiple fires on lag
2004-10-03 22:52:02 +00:00
if ( msg_badread )
{
Con_Printf ( " SV_ReadClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
}
c = MSG_ReadByte ( ) ;
if ( c ! = clc_move )
{
host_client = cl = split ;
sv_player = cl - > edict ;
goto haveannothergo ;
}
2004-09-04 18:01:53 +00:00
continue ;
2004-08-23 00:15:46 +00:00
}
2004-09-04 18:01:53 +00:00
SV_PreRunCmd ( ) ;
2004-08-23 00:15:46 +00:00
2004-09-04 18:01:53 +00:00
if ( net_drop < 20 )
2004-08-23 00:15:46 +00:00
{
2004-09-04 18:01:53 +00:00
while ( net_drop > 2 )
{
SV_RunCmd ( & cl - > lastcmd , false ) ;
net_drop - - ;
}
if ( net_drop > 1 )
SV_RunCmd ( & oldest , false ) ;
if ( net_drop > 0 )
SV_RunCmd ( & oldcmd , false ) ;
2004-08-23 00:15:46 +00:00
}
2004-09-04 18:01:53 +00:00
SV_RunCmd ( & newcmd , false ) ;
SV_PostRunCmd ( ) ;
2004-10-28 21:13:52 +00:00
2004-08-23 00:15:46 +00:00
}
2004-09-04 18:01:53 +00:00
cl - > lastcmd = newcmd ;
cl - > lastcmd . buttons = 0 ; // avoid multiple fires on lag
2004-08-23 00:15:46 +00:00
}
2004-09-04 18:01:53 +00:00
if ( msg_badread )
{
Con_Printf ( " SV_ReadClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
}
2004-08-23 00:15:46 +00:00
2004-09-04 18:01:53 +00:00
c = MSG_ReadByte ( ) ;
if ( c ! = clc_move )
{
host_client = cl = split ;
sv_player = cl - > edict ;
goto haveannothergo ;
}
2004-08-23 00:15:46 +00:00
}
host_client = cl = split ;
sv_player = cl - > edict ;
break ;
case clc_stringcmd :
s = MSG_ReadString ( ) ;
SV_ExecuteUserCommand ( s , false ) ;
host_client = cl ;
sv_player = cl - > edict ;
break ;
case clc_tmove :
o [ 0 ] = MSG_ReadCoord ( ) ;
o [ 1 ] = MSG_ReadCoord ( ) ;
o [ 2 ] = MSG_ReadCoord ( ) ;
// only allowed by spectators
if ( host_client - > spectator ) {
VectorCopy ( o , sv_player - > v . origin ) ;
SV_LinkEdict ( sv_player , false ) ;
}
break ;
case clc_upload :
SV_NextUpload ( ) ;
break ;
}
}
host_client = NULL ;
sv_player = NULL ;
}
# ifdef Q2SERVER
void SVQ2_ExecuteClientMessage ( client_t * cl )
{
enum clcq2_ops_e c ;
char * s ;
usercmd_t oldest , oldcmd , newcmd ;
q2client_frame_t * frame ;
qboolean move_issued = false ; //only allow one move command
int checksumIndex ;
qbyte checksum , calculatedChecksum ;
int seq_hash ;
int lastframe ;
// calc ping time
frame = & cl - > q2frames [ cl - > netchan . incoming_acknowledged & Q2UPDATE_MASK ] ;
// make sure the reply sequence number matches the incoming
// sequence number
if ( cl - > netchan . incoming_sequence > = cl - > netchan . outgoing_sequence )
cl - > netchan . outgoing_sequence = cl - > netchan . incoming_sequence ;
else
cl - > send_message = false ; // don't reply, sequences have slipped
// save time for ping calculations
2004-08-27 00:45:34 +00:00
cl - > q2frames [ cl - > netchan . outgoing_sequence & Q2UPDATE_MASK ] . senttime = realtime ;
2004-08-23 00:15:46 +00:00
// cl->q2frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
host_client = cl ;
sv_player = host_client - > edict ;
seq_hash = cl - > netchan . incoming_sequence ;
// mark time so clients will know how much to predict
// other players
cl - > localtime = sv . time ;
cl - > delta_sequence = - 1 ; // no delta unless requested
while ( 1 )
{
if ( msg_badread )
{
Con_Printf ( " SVQ2_ExecuteClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
}
c = MSG_ReadByte ( ) ;
if ( c = = - 1 )
break ;
switch ( c )
{
default :
Con_Printf ( " SV_ReadClientMessage: unknown command char %i \n " , c ) ;
SV_DropClient ( cl ) ;
return ;
case clcq2_nop :
break ;
case clcq2_move :
if ( move_issued )
return ; // someone is trying to cheat...
move_issued = true ;
checksumIndex = MSG_GetReadCount ( ) ;
checksum = ( qbyte ) MSG_ReadByte ( ) ;
lastframe = MSG_ReadLong ( ) ;
if ( lastframe ! = host_client - > delta_sequence ) {
cl - > delta_sequence = lastframe ;
}
MSGQ2_ReadDeltaUsercmd ( & nullcmd , & oldest ) ;
MSGQ2_ReadDeltaUsercmd ( & oldest , & oldcmd ) ;
MSGQ2_ReadDeltaUsercmd ( & oldcmd , & newcmd ) ;
if ( cl - > state ! = cs_spawned )
break ;
// if the checksum fails, ignore the rest of the packet
calculatedChecksum = Q2COM_BlockSequenceCRCByte (
net_message . data + checksumIndex + 1 ,
MSG_GetReadCount ( ) - checksumIndex - 1 ,
seq_hash ) ;
if ( calculatedChecksum ! = checksum )
{
Con_DPrintf ( " Failed command checksum for %s(%d) (%d != %d) \n " ,
cl - > name , cl - > netchan . incoming_sequence , checksum , calculatedChecksum ) ;
return ;
}
if ( cl - > iscrippled )
{
cl - > lastcmd . forwardmove = 0 ; //hmmm.... does this work well enough?
oldest . forwardmove = 0 ;
newcmd . forwardmove = 0 ;
cl - > lastcmd . sidemove = 0 ;
oldest . sidemove = 0 ;
newcmd . sidemove = 0 ;
cl - > lastcmd . upmove = 0 ;
oldest . upmove = 0 ;
newcmd . upmove = 0 ;
}
if ( ! sv . paused )
{
2004-09-22 15:29:33 +00:00
/*if (sv_nomsec.value)
2004-08-23 00:15:46 +00:00
{
cmd = newcmd ;
SV_ClientThink ( ) ;
cl - > lastcmd = newcmd ;
cl - > lastcmd . buttons = 0 ; // avoid multiple fires on lag
break ;
2004-09-22 15:29:33 +00:00
} */
2004-08-23 00:15:46 +00:00
SV_PreRunCmd ( ) ;
if ( net_drop < 20 )
{
while ( net_drop > 2 )
{
SV_RunCmd ( & cl - > lastcmd , false ) ;
net_drop - - ;
}
if ( net_drop > 1 )
SV_RunCmd ( & oldest , false ) ;
if ( net_drop > 0 )
SV_RunCmd ( & oldcmd , false ) ;
}
SV_RunCmd ( & newcmd , false ) ;
SV_PostRunCmd ( ) ;
}
cl - > lastcmd = newcmd ;
cl - > lastcmd . buttons = 0 ; // avoid multiple fires on lag
break ;
case clcq2_userinfo :
s = MSG_ReadString ( ) ;
break ;
case clcq2_stringcmd :
s = MSG_ReadString ( ) ;
SV_ExecuteUserCommand ( s , false ) ;
if ( cl - > state = = cs_zombie )
return ; // disconnect command
break ;
}
}
}
# endif
# ifdef NQPROT
void SVNQ_ReadClientMove ( usercmd_t * move )
{
int i ;
int bits ;
MSG_ReadFloat ( ) ; //message time (nq uses it to time pings - qw ignores it)
// read current angles
for ( i = 0 ; i < 3 ; i + + )
2004-11-20 00:52:49 +00:00
{
host_client - > edict - > v . v_angle [ i ] = MSG_ReadAngle ( ) ;
2004-08-23 00:15:46 +00:00
2004-11-20 00:52:49 +00:00
move - > angles [ i ] = ( host_client - > edict - > v . v_angle [ i ] * 256 * 256 ) / 360 ;
}
2004-08-23 00:15:46 +00:00
// read movement
move - > forwardmove = MSG_ReadShort ( ) ;
move - > sidemove = MSG_ReadShort ( ) ;
move - > upmove = MSG_ReadShort ( ) ;
move - > msec = 100 ;
// read buttons
bits = MSG_ReadByte ( ) ;
move - > buttons = bits ;
i = MSG_ReadByte ( ) ;
if ( i )
move - > impulse = i ;
2004-11-20 00:52:49 +00:00
if ( i & & SV_FiltureImpulse ( i , host_client - > trustlevel ) )
host_client - > edict - > v . impulse = i ;
host_client - > edict - > v . button0 = bits & 1 ;
host_client - > edict - > v . button2 = ( bits > > 1 ) & 1 ;
if ( pr_allowbutton1 . value ) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
host_client - > edict - > v . button1 = ( ( bits > > 2 ) & 1 ) ;
// DP_INPUTBUTTONS
host_client - > edict - > v . button3 = ( ( bits > > 2 ) & 1 ) ;
host_client - > edict - > v . button4 = ( ( bits > > 3 ) & 1 ) ;
host_client - > edict - > v . button5 = ( ( bits > > 4 ) & 1 ) ;
host_client - > edict - > v . button6 = ( ( bits > > 5 ) & 1 ) ;
host_client - > edict - > v . button7 = ( ( bits > > 6 ) & 1 ) ;
host_client - > edict - > v . button8 = ( ( bits > > 7 ) & 1 ) ;
2004-08-23 00:15:46 +00:00
}
void SVNQ_ExecuteClientMessage ( client_t * cl )
{
int c ;
char * s ;
client_frame_t * frame ;
int seq_hash ;
MSG_BeginReading ( ) ;
// calc ping time
frame = & cl - > frames [ cl - > netchan . incoming_acknowledged & UPDATE_MASK ] ;
frame - > ping_time = realtime - frame - > senttime ;
// make sure the reply sequence number matches the incoming
// sequence number
if ( cl - > netchan . incoming_sequence > = cl - > netchan . outgoing_sequence )
cl - > netchan . outgoing_sequence = cl - > netchan . incoming_sequence ;
else
cl - > send_message = false ; // don't reply, sequences have slipped
// save time for ping calculations
cl - > frames [ cl - > netchan . outgoing_sequence & UPDATE_MASK ] . senttime = realtime ;
cl - > frames [ cl - > netchan . outgoing_sequence & UPDATE_MASK ] . ping_time = - 1 ;
host_client = cl ;
sv_player = host_client - > edict ;
seq_hash = cl - > netchan . incoming_sequence ;
// mark time so clients will know how much to predict
// other players
cl - > localtime = sv . time ;
cl - > delta_sequence = - 1 ; // no delta unless requested
while ( 1 )
{
if ( msg_badread )
{
Con_Printf ( " SV_ReadClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
}
c = MSG_ReadByte ( ) ;
if ( c = = - 1 )
break ;
switch ( c )
{
default :
Con_Printf ( " SV_ReadClientMessage: unknown command char %i \n " , c ) ;
SV_DropClient ( cl ) ;
return ;
case clc_disconnect :
SV_DropClient ( cl ) ;
break ;
case clc_nop :
break ;
case clc_delta :
cl - > delta_sequence = MSG_ReadByte ( ) ;
break ;
case clc_move :
SVNQ_ReadClientMove ( & host_client - > lastcmd ) ;
// cmd = host_client->lastcmd;
// SV_ClientThink();
break ;
case clc_stringcmd :
s = MSG_ReadString ( ) ;
SVNQ_ExecuteUserCommand ( s ) ;
break ;
}
}
}
# endif
/*
= = = = = = = = = = = = = =
SV_UserInit
= = = = = = = = = = = = = =
*/
void SV_UserInit ( void )
{
# ifdef SERVERONLY
Cvar_Register ( & cl_rollspeed , " Prediction stuff " ) ;
Cvar_Register ( & cl_rollangle , " Prediction stuff " ) ;
# endif
Cvar_Register ( & sv_chatfilter , cvargroup_serverpermissions ) ;
Cvar_Register ( & sv_spectalk , cvargroup_servercontrol ) ;
Cvar_Register ( & sv_mapcheck , cvargroup_servercontrol ) ;
Cvar_Register ( & sv_cheatpc , cvargroup_servercontrol ) ;
Cvar_Register ( & sv_cheatspeedchecktime , cvargroup_servercontrol ) ;
Cvar_Register ( & sv_playermodelchecks , cvargroup_servercontrol ) ;
Cvar_Register ( & sv_cmdlikercon , cvargroup_serverpermissions ) ;
Cvar_Register ( & votelevel , sv_votinggroup ) ;
Cvar_Register ( & voteminimum , sv_votinggroup ) ;
Cvar_Register ( & votepercent , sv_votinggroup ) ;
Cvar_Register ( & votetime , sv_votinggroup ) ;
2004-10-18 10:48:33 +00:00
Cvar_Register ( & sv_brokenmovetypes , " " ) ;
2004-08-23 00:15:46 +00:00
Cvar_Register ( & sv_edgefriction , " netquake compatability " ) ;
}
static vec3_t forward , right , up , wishdir ;
static float * origin , * velocity , * angles ;
static float wishspeed ;
extern cvar_t sv_accelerate , sv_friction ;
static qboolean onground ;
/*
= = = = = = = = = = = = = = = = = =
SV_UserFriction
= = = = = = = = = = = = = = = = = =
*/
void SV_UserFriction ( void )
{
extern cvar_t sv_stopspeed ;
float * vel ;
float speed , newspeed , control ;
vec3_t start , stop ;
float friction ;
trace_t trace ;
vel = velocity ;
speed = sqrt ( vel [ 0 ] * vel [ 0 ] + vel [ 1 ] * vel [ 1 ] ) ;
if ( ! speed )
return ;
// if the leading edge is over a dropoff, increase friction
start [ 0 ] = stop [ 0 ] = origin [ 0 ] + vel [ 0 ] / speed * 16 ;
start [ 1 ] = stop [ 1 ] = origin [ 1 ] + vel [ 1 ] / speed * 16 ;
start [ 2 ] = origin [ 2 ] + sv_player - > v . mins [ 2 ] ;
stop [ 2 ] = start [ 2 ] - 34 ;
trace = SV_Move ( start , vec3_origin , vec3_origin , stop , true , sv_player ) ;
if ( trace . fraction = = 1.0 )
friction = sv_friction . value * sv_edgefriction . value ;
else
friction = sv_friction . value ;
// val = GetEdictFieldValue(sv_player, "friction", &frictioncache);
// if (val && val->_float)
// friction *= val->_float;
// apply friction
control = speed < sv_stopspeed . value ? sv_stopspeed . value : speed ;
newspeed = speed - host_frametime * control * friction ;
if ( newspeed < 0 )
newspeed = 0 ;
newspeed / = speed ;
vel [ 0 ] = vel [ 0 ] * newspeed ;
vel [ 1 ] = vel [ 1 ] * newspeed ;
vel [ 2 ] = vel [ 2 ] * newspeed ;
}
void SV_Accelerate ( void )
{
int i ;
float addspeed , accelspeed , currentspeed ;
currentspeed = DotProduct ( velocity , wishdir ) ;
addspeed = wishspeed - currentspeed ;
if ( addspeed < = 0 )
return ;
accelspeed = sv_accelerate . value * host_frametime * wishspeed ;
if ( accelspeed > addspeed )
accelspeed = addspeed ;
for ( i = 0 ; i < 3 ; i + + )
velocity [ i ] + = accelspeed * wishdir [ i ] ;
}
void SV_AirAccelerate ( vec3_t wishveloc )
{
int i ;
float addspeed , wishspd , accelspeed , currentspeed ;
wishspd = VectorNormalize ( wishveloc ) ;
if ( wishspd > 30 )
wishspd = 30 ;
currentspeed = DotProduct ( velocity , wishveloc ) ;
addspeed = wishspd - currentspeed ;
if ( addspeed < = 0 )
return ;
// accelspeed = sv_accelerate.value * host_frametime;
accelspeed = sv_accelerate . value * wishspeed * host_frametime ;
if ( accelspeed > addspeed )
accelspeed = addspeed ;
for ( i = 0 ; i < 3 ; i + + )
velocity [ i ] + = accelspeed * wishveloc [ i ] ;
}
/*
= = = = = = = = = = = = = = = = = = =
SV_AirMove
= = = = = = = = = = = = = = = = = = =
*/
void SV_AirMove ( void )
{
int i ;
vec3_t wishvel ;
float fmove , smove ;
float scale , maxspeed ;
AngleVectors ( sv_player - > v . angles , forward , right , up ) ;
fmove = cmd . forwardmove ;
smove = cmd . sidemove ;
// hack to not let you back into teleporter
if ( sv . time < sv_player - > v . teleport_time & & fmove < 0 )
fmove = 0 ;
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
if ( ( int ) sv_player - > v . movetype ! = MOVETYPE_WALK )
wishvel [ 2 ] = cmd . upmove ;
else
wishvel [ 2 ] = 0 ;
VectorCopy ( wishvel , wishdir ) ;
wishspeed = VectorNormalize ( wishdir ) ;
// val = GetEdictFieldValue(sv_player, "scale", &scalecache);
// if (!val || !val->_float)
scale = 1 ;
// else
// scale = val->_float;
maxspeed = sv_player - > v . maxspeed ; //FIXME: This isn't fully compatable code...
if ( wishspeed > maxspeed * scale )
{
VectorScale ( wishvel , maxspeed / wishspeed , wishvel ) ;
wishspeed = maxspeed * scale ;
}
if ( sv_player - > v . movetype = = MOVETYPE_NOCLIP )
{ // noclip
VectorCopy ( wishvel , velocity ) ;
}
else if ( onground )
{
SV_UserFriction ( ) ;
SV_Accelerate ( ) ;
}
else
{ // not on ground, so little effect on velocity
SV_AirAccelerate ( wishvel ) ;
}
}
void SV_WaterMove ( void )
{
int i ;
vec3_t wishvel ;
float speed , newspeed , wishspeed , addspeed , accelspeed ;
float scale ;
float maxspeed ;
//
// user intentions
//
AngleVectors ( sv_player - > v . v_angle , forward , right , up ) ;
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * cmd . forwardmove + right [ i ] * cmd . sidemove ;
if ( ! cmd . forwardmove & & ! cmd . sidemove & & ! cmd . upmove )
wishvel [ 2 ] - = 60 ; // drift towards bottom
else
wishvel [ 2 ] + = cmd . upmove ;
wishspeed = Length ( wishvel ) ;
// val = GetEdictFieldValue(sv_player, "scale", &scalecache);
// if (!val || !val->_float)
scale = 1 ;
// else
// scale = val->_float;
// val = GetEdictFieldValue(sv_player, "maxspeed", &maxspeedcache);
// if (val && val->_float)
// maxspeed = sv_maxspeed.value*val->_float;
// else
maxspeed = host_client - > maxspeed ;
if ( wishspeed > maxspeed * scale )
{
VectorScale ( wishvel , maxspeed / wishspeed , wishvel ) ;
wishspeed = maxspeed * scale ;
}
wishspeed * = 0.7 ;
//
// water friction
//
speed = Length ( velocity ) ;
if ( speed )
{
// val = GetEdictFieldValue(sv_player, "friction", &frictioncache);
// if (val&&val->_float)
// newspeed = speed - host_frametime * speed * sv_friction.value*val->_float;
// else
newspeed = speed - host_frametime * speed * sv_friction . value ;
if ( newspeed < 0 )
newspeed = 0 ;
VectorScale ( velocity , newspeed / speed , velocity ) ;
}
else
newspeed = 0 ;
//
// water acceleration
//
if ( ! wishspeed )
return ;
addspeed = wishspeed - newspeed ;
if ( addspeed < = 0 )
return ;
VectorNormalize ( wishvel ) ;
accelspeed = sv_accelerate . value * wishspeed * host_frametime ;
if ( accelspeed > addspeed )
accelspeed = addspeed ;
for ( i = 0 ; i < 3 ; i + + )
velocity [ i ] + = accelspeed * wishvel [ i ] ;
}
void SV_WaterJump ( void )
{
if ( sv . time > sv_player - > v . teleport_time
| | ! sv_player - > v . waterlevel )
{
sv_player - > v . flags = ( int ) sv_player - > v . flags & ~ FL_WATERJUMP ;
sv_player - > v . teleport_time = 0 ;
}
sv_player - > v . velocity [ 0 ] = sv_player - > v . movedir [ 0 ] ;
sv_player - > v . velocity [ 1 ] = sv_player - > v . movedir [ 1 ] ;
}
void SV_ClientThink ( void )
{
vec3_t v_angle ;
2004-09-22 15:29:33 +00:00
cmd = host_client - > lastcmd ;
sv_player = host_client - > edict ;
2004-09-07 23:12:46 +00:00
sv_player - > v . movement [ 0 ] = cmd . forwardmove ;
sv_player - > v . movement [ 1 ] = cmd . sidemove ;
sv_player - > v . movement [ 2 ] = cmd . upmove ;
2004-08-23 00:15:46 +00:00
2004-09-07 23:12:46 +00:00
if ( SV_PlayerPhysicsQC )
2004-08-23 00:15:46 +00:00
{
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , sv_player ) ;
PR_ExecuteProgram ( svprogfuncs , SV_PlayerPhysicsQC ) ;
return ;
}
2004-09-07 23:12:46 +00:00
2004-08-23 00:15:46 +00:00
if ( sv_player - > v . movetype = = MOVETYPE_NONE )
return ;
onground = ( int ) sv_player - > v . flags & FL_ONGROUND ;
origin = sv_player - > v . origin ;
velocity = sv_player - > v . velocity ;
// DropPunchAngle ();
//
// if dead, behave differently
//
if ( sv_player - > v . health < = 0 )
return ;
//
// angles
// show 1/3 the pitch angle and all the roll angle
angles = sv_player - > v . angles ;
VectorCopy ( sv_player - > v . v_angle , v_angle ) ;
// VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle);
angles [ ROLL ] = V_CalcRoll ( sv_player - > v . angles , sv_player - > v . velocity ) * 4 ;
if ( ! sv_player - > v . fixangle )
{
angles [ PITCH ] = - v_angle [ PITCH ] / 3 ;
angles [ YAW ] = v_angle [ YAW ] ;
}
if ( ( int ) sv_player - > v . flags & FL_WATERJUMP )
{
SV_WaterJump ( ) ;
return ;
}
//
// walk
//
if ( ( sv_player - > v . waterlevel > = 2 )
& & ( sv_player - > v . movetype ! = MOVETYPE_NOCLIP ) )
{
SV_WaterMove ( ) ;
return ;
}
SV_AirMove ( ) ;
}