2000-05-10 20:33:16 +00:00
/*
2000-05-11 16:03:29 +00:00
sv_user . c
2000-05-10 20:33:16 +00:00
2000-05-22 07:46:47 +00:00
server code for moving users
2000-05-10 20:33:16 +00:00
2000-05-11 16:03:29 +00:00
Copyright ( C ) 1996 - 1997 Id Software , Inc .
2000-05-10 20:33:16 +00:00
2000-05-11 16:03:29 +00:00
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 .
2000-05-10 20:33:16 +00:00
2000-05-11 16:03:29 +00:00
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 .
2000-05-10 20:33:16 +00:00
2000-05-11 16:03:29 +00:00
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to :
Free Software Foundation , Inc .
59 Temple Place - Suite 330
Boston , MA 02111 - 1307 , USA
$ Id $
2000-05-10 20:33:16 +00:00
*/
2000-05-22 07:46:47 +00:00
2000-05-17 10:03:19 +00:00
# ifdef HAVE_CONFIG_H
2000-12-08 06:51:37 +00:00
# include "config.h"
2000-05-17 10:03:19 +00:00
# endif
2000-05-21 08:24:45 +00:00
2000-05-14 19:29:57 +00:00
# include <math.h>
2000-12-30 02:16:36 +00:00
# ifdef HAVE_STRING_H
2000-05-21 08:24:45 +00:00
# include <string.h>
2000-12-30 02:16:36 +00:00
# endif
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
2000-05-21 08:24:45 +00:00
# include <stdarg.h>
# include <stdlib.h>
# include <ctype.h>
2000-05-10 11:29:38 +00:00
2000-12-30 02:16:36 +00:00
# include "bothdefs.h"
# include "checksum.h"
# include "cmd.h"
# include "cvar.h"
# include "msg.h"
# include "pmove.h"
# include "quakefs.h"
# include "server.h"
# include "sys.h"
# include "va.h"
# include "world.h"
2000-12-08 06:51:37 +00:00
edict_t * sv_player ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
usercmd_t cmd ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
cvar_t * cl_rollspeed ;
cvar_t * cl_rollangle ;
cvar_t * sv_spectalk ;
2000-05-16 04:47:41 +00:00
2000-12-08 06:51:37 +00:00
cvar_t * sv_mapcheck ;
2000-05-16 04:47:41 +00:00
2000-12-08 06:51:37 +00:00
cvar_t * sv_timekick ;
cvar_t * sv_timekick_fuzz ;
cvar_t * sv_timekick_interval ;
2000-05-14 19:29:57 +00:00
2000-12-08 06:51:37 +00:00
extern cvar_t * sv_maxrate ;
2000-11-26 12:43:49 +00:00
2000-12-08 06:51:37 +00:00
extern vec3_t player_mins ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
extern int fp_messages , fp_persecond , fp_secondsdead ;
2000-05-10 11:29:38 +00:00
extern char fp_msg [ ] ;
2000-05-16 04:47:41 +00:00
extern cvar_t * pausable ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
void SV_FullClientUpdateToClient ( client_t * client , client_t * cl ) ;
2000-05-10 20:33:16 +00:00
2000-05-10 11:29:38 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 .
= = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_New_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
char * gamedir ;
int playernum ;
cvar_t * r_skyname ;
2000-05-10 11:29:38 +00:00
if ( host_client - > state = = cs_spawned )
return ;
host_client - > state = cs_connected ;
host_client - > connection_started = realtime ;
// send the info about the new client to all connected clients
2000-12-08 06:51:37 +00:00
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
2000-05-10 11:29:38 +00:00
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 ) {
2000-12-08 06:51:37 +00:00
Con_Printf ( " WARNING %s: [SV_New] Back buffered (%d0, clearing " ,
host_client - > name , host_client - > netchan . message . cursize ) ;
2000-05-10 11:29:38 +00:00
host_client - > num_backbuf = 0 ;
2000-12-08 06:51:37 +00:00
SZ_Clear ( & host_client - > netchan . message ) ;
2000-05-10 11:29:38 +00:00
}
// send the serverdata
MSG_WriteByte ( & host_client - > netchan . message , svc_serverdata ) ;
MSG_WriteLong ( & host_client - > netchan . message , PROTOCOL_VERSION ) ;
MSG_WriteLong ( & host_client - > netchan . message , svs . spawncount ) ;
MSG_WriteString ( & host_client - > netchan . message , gamedir ) ;
2000-12-31 07:43:09 +00:00
playernum = NUM_FOR_EDICT ( & sv_progs , host_client - > edict ) - 1 ;
2000-05-10 11:29:38 +00:00
if ( host_client - > spectator )
playernum | = 128 ;
MSG_WriteByte ( & host_client - > netchan . message , playernum ) ;
// send full levelname
2000-12-08 06:51:37 +00:00
MSG_WriteString ( & host_client - > netchan . message ,
2000-12-31 07:43:09 +00:00
PR_GetString ( & sv_progs , sv . edicts - > v . message ) ) ;
2000-05-10 11:29:38 +00:00
// send the movevars
2000-12-08 06:51:37 +00:00
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 ) ;
2000-05-10 11:29:38 +00:00
// send music
MSG_WriteByte ( & host_client - > netchan . message , svc_cdtrack ) ;
MSG_WriteByte ( & host_client - > netchan . message , sv . edicts - > v . sounds ) ;
// send server info string
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
2000-12-08 06:51:37 +00:00
MSG_WriteString ( & host_client - > netchan . message ,
va ( " fullserverinfo \" %s \" \n " , svs . info ) ) ;
2000-05-19 03:06:05 +00:00
// Send our current skybox
r_skyname = Cvar_FindVar ( " r_skyname " ) ;
2000-12-08 06:51:37 +00:00
if ( r_skyname ! = NULL ) {
2000-05-19 03:06:05 +00:00
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
2000-12-08 06:51:37 +00:00
MSG_WriteString ( & host_client - > netchan . message , va ( " r_skyname %s " ,
r_skyname - > string ) ) ;
2000-05-19 03:06:05 +00:00
}
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
SV_Soundlist_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Soundlist_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
char * * s ;
unsigned n ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( host_client - > state ! = cs_connected ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " soundlist not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
2000-12-08 06:51:37 +00:00
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " SV_Soundlist_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-12-08 06:51:37 +00:00
n = atoi ( Cmd_Argv ( 2 ) ) ;
2000-11-21 00:45:36 +00:00
if ( n > = MAX_SOUNDS ) {
Con_Printf ( " SV_Soundlist_f: Invalid soundlist index \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-05-10 11:29:38 +00:00
//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 ) {
2000-12-08 06:51:37 +00:00
Con_Printf ( " WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing " ,
host_client - > name , host_client - > netchan . message . cursize ) ;
2000-05-10 11:29:38 +00:00
host_client - > num_backbuf = 0 ;
2000-12-08 06:51:37 +00:00
SZ_Clear ( & host_client - > netchan . message ) ;
2000-05-10 11:29:38 +00:00
}
MSG_WriteByte ( & host_client - > netchan . message , svc_soundlist ) ;
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
2000-12-08 06:51:37 +00:00
for ( s = sv . sound_precache + 1 + n ;
* s & & host_client - > netchan . message . cursize < ( MAX_MSGLEN / 2 ) ;
s + + , n + + ) MSG_WriteString ( & host_client - > netchan . message , * s ) ;
2000-05-10 11:29:38 +00:00
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// next msg
if ( * s )
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Modellist_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Modellist_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
char * * s ;
unsigned n ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( host_client - > state ! = cs_connected ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " modellist not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
2000-12-08 06:51:37 +00:00
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " SV_Modellist_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-12-08 06:51:37 +00:00
n = atoi ( Cmd_Argv ( 2 ) ) ;
2000-11-21 00:45:36 +00:00
if ( n > = MAX_MODELS ) {
Con_Printf ( " SV_Modellist_f: Invalid modellist index \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-05-10 11:29:38 +00:00
//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 ) {
2000-12-08 06:51:37 +00:00
Con_Printf ( " WARNING %s: [SV_Modellist] Back buffered (%d0, clearing " ,
host_client - > name , host_client - > netchan . message . cursize ) ;
2000-05-10 11:29:38 +00:00
host_client - > num_backbuf = 0 ;
2000-12-08 06:51:37 +00:00
SZ_Clear ( & host_client - > netchan . message ) ;
2000-05-10 11:29:38 +00:00
}
MSG_WriteByte ( & host_client - > netchan . message , svc_modellist ) ;
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
2000-12-08 06:51:37 +00:00
for ( s = sv . model_precache + 1 + n ;
* s & & host_client - > netchan . message . cursize < ( MAX_MSGLEN / 2 ) ;
s + + , n + + ) MSG_WriteString ( & host_client - > netchan . message , * s ) ;
2000-05-10 11:29:38 +00:00
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// next msg
if ( * s )
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_PreSpawn_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_PreSpawn_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
unsigned int buf ;
unsigned int check ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( host_client - > state ! = cs_connected ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " prespawn not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
2000-12-08 06:14:26 +00:00
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " SV_PreSpawn_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-12-08 06:51:37 +00:00
buf = atoi ( Cmd_Argv ( 2 ) ) ;
2000-05-10 11:29:38 +00:00
if ( buf > = sv . num_signon_buffers )
buf = 0 ;
if ( ! buf ) {
// should be three numbers following containing checksums
2000-12-08 06:51:37 +00:00
check = atoi ( Cmd_Argv ( 3 ) ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
// Con_DPrintf("Client check = %d\n", check);
2000-05-10 11:29:38 +00:00
2000-10-17 03:17:42 +00:00
if ( sv_mapcheck - > int_val & & check ! = sv . worldmodel - > checksum & &
2000-05-10 11:29:38 +00:00
check ! = sv . worldmodel - > checksum2 ) {
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH ,
" Map model file does not match (%s), %i != %i/%i. \n "
" You may need a new version of the map, or the proper install files. \n " ,
sv . modelname , check , sv . worldmodel - > checksum ,
sv . worldmodel - > checksum2 ) ;
SV_DropClient ( host_client ) ;
2000-05-10 11:29:38 +00:00
return ;
}
host_client - > checksum = check ;
}
2000-12-08 06:51:37 +00:00
// NOTE: This doesn't go through ClientReliableWrite since it's before
// the user
2000-12-08 06:14:26 +00:00
// spawns. These functions are written to not overflow
2000-05-10 11:29:38 +00:00
if ( host_client - > num_backbuf ) {
2000-12-08 06:51:37 +00:00
Con_Printf ( " WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing " ,
host_client - > name , host_client - > netchan . message . cursize ) ;
2000-05-10 11:29:38 +00:00
host_client - > num_backbuf = 0 ;
2000-12-08 06:51:37 +00:00
SZ_Clear ( & host_client - > netchan . message ) ;
2000-05-10 11:29:38 +00:00
}
2000-12-08 06:51:37 +00:00
SZ_Write ( & host_client - > netchan . message ,
sv . signon_buffers [ buf ] , sv . signon_buffer_size [ buf ] ) ;
2000-05-10 11:29:38 +00:00
buf + + ;
2000-12-08 06:14:26 +00:00
if ( buf = = sv . num_signon_buffers ) { // all done prespawning
2000-05-10 11:29:38 +00:00
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
2000-12-08 06:51:37 +00:00
MSG_WriteString ( & host_client - > netchan . message ,
va ( " cmd spawn %i 0 \n " , svs . spawncount ) ) ;
} else { // need to prespawn more
2000-05-10 11:29:38 +00:00
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
2000-12-08 06:51:37 +00:00
MSG_WriteString ( & host_client - > netchan . message ,
va ( " cmd prespawn %i %i \n " , svs . spawncount , buf ) ) ;
2000-05-10 11:29:38 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Spawn_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Spawn_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
int i ;
client_t * client ;
edict_t * ent ;
eval_t * val ;
int n ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:14:26 +00:00
if ( host_client - > state ! = cs_connected ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " Spawn not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
2000-12-08 06:14:26 +00:00
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " SV_Spawn_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-12-08 06:14:26 +00:00
n = atoi ( Cmd_Argv ( 2 ) ) ;
2000-05-10 20:33:16 +00:00
// make sure n is valid
2000-12-08 06:14:26 +00:00
if ( n < 0 | | n > MAX_CLIENTS ) {
2000-05-10 20:33:16 +00:00
Con_Printf ( " SV_Spawn_f invalid client start \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-12-08 06:14:26 +00:00
// send all current names, colors, and frag counts
2000-05-10 11:29:38 +00:00
// FIXME: is this a good thing?
SZ_Clear ( & host_client - > netchan . message ) ;
2000-12-08 06:14:26 +00:00
// send current status of all other players
2000-05-10 11:29:38 +00:00
// normally this could overflow, but no need to check due to backbuf
2000-12-08 06:51:37 +00:00
for ( i = n , client = svs . clients + n ; i < MAX_CLIENTS ; i + + , client + + )
2000-05-10 11:29:38 +00:00
SV_FullClientUpdateToClient ( client , host_client ) ;
2000-12-08 06:51:37 +00:00
2000-12-08 06:14:26 +00:00
// send all current light styles
for ( i = 0 ; i < MAX_LIGHTSTYLES ; i + + ) {
2000-12-08 06:51:37 +00:00
ClientReliableWrite_Begin ( host_client , svc_lightstyle ,
3 +
( sv .
lightstyles [ i ] ? strlen ( sv .
lightstyles [ i ] ) :
1 ) ) ;
ClientReliableWrite_Byte ( host_client , ( char ) i ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_String ( host_client , sv . lightstyles [ i ] ) ;
}
// set up the edict
ent = host_client - > edict ;
2000-12-31 07:43:09 +00:00
memset ( & ent - > v , 0 , sv_progs . progs - > entityfields * 4 ) ;
ent - > v . colormap = NUM_FOR_EDICT ( & sv_progs , ent ) ;
2000-12-08 06:51:37 +00:00
ent - > v . team = 0 ; // FIXME
2000-12-31 07:43:09 +00:00
ent - > v . netname = PR_SetString ( & sv_progs , host_client - > name ) ;
2000-05-10 11:29:38 +00:00
host_client - > entgravity = 1.0 ;
2000-12-31 07:43:09 +00:00
val = GetEdictFieldValue ( & sv_progs , ent , " gravity " ) ;
2000-05-10 11:29:38 +00:00
if ( val )
val - > _float = 1.0 ;
2000-05-16 04:47:41 +00:00
host_client - > maxspeed = sv_maxspeed - > value ;
2000-12-31 07:43:09 +00:00
val = GetEdictFieldValue ( & sv_progs , ent , " maxspeed " ) ;
2000-05-10 11:29:38 +00:00
if ( val )
2000-05-16 04:47:41 +00:00
val - > _float = sv_maxspeed - > value ;
2000-05-10 11:29:38 +00:00
//
// force stats to be updated
//
2000-12-08 06:51:37 +00:00
memset ( host_client - > stats , 0 , sizeof ( host_client - > stats ) ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALSECRETS ) ;
2000-12-31 07:43:09 +00:00
ClientReliableWrite_Long ( host_client , sv_progs . pr_global_struct - > total_secrets ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALMONSTERS ) ;
2000-12-31 07:43:09 +00:00
ClientReliableWrite_Long ( host_client , sv_progs . pr_global_struct - > total_monsters ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_SECRETS ) ;
2000-12-31 07:43:09 +00:00
ClientReliableWrite_Long ( host_client , sv_progs . pr_global_struct - > found_secrets ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_MONSTERS ) ;
2000-12-31 07:43:09 +00:00
ClientReliableWrite_Long ( host_client , sv_progs . pr_global_struct - > killed_monsters ) ;
2000-05-10 11:29:38 +00:00
// 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 ) ;
2000-12-08 06:51:37 +00:00
ClientReliableWrite_String ( host_client , " skins \n " ) ;
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
SV_SpawnSpectator
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_SpawnSpectator ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
int i ;
edict_t * e ;
2000-05-10 11:29:38 +00:00
VectorCopy ( vec3_origin , sv_player - > v . origin ) ;
VectorCopy ( vec3_origin , sv_player - > v . view_ofs ) ;
sv_player - > v . view_ofs [ 2 ] = 22 ;
// search for an info_playerstart to spawn the spectator at
2000-12-08 06:51:37 +00:00
for ( i = MAX_CLIENTS - 1 ; i < sv . num_edicts ; i + + ) {
2000-12-31 07:43:09 +00:00
e = EDICT_NUM ( & sv_progs , i ) ;
if ( ! strcmp ( PR_GetString ( & sv_progs , e - > v . classname ) , " info_player_start " ) ) {
2000-05-10 11:29:38 +00:00
VectorCopy ( e - > v . origin , sv_player - > v . origin ) ;
return ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Begin_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Begin_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-09-22 09:08:08 +00:00
unsigned int pmodel = 0 , emodel = 0 ;
2000-12-08 06:51:37 +00:00
int i ;
2000-05-10 11:29:38 +00:00
if ( host_client - > state = = cs_spawned )
2000-12-08 06:51:37 +00:00
return ; // don't begin again
2000-05-10 11:29:38 +00:00
host_client - > state = cs_spawned ;
2000-12-08 06:51:37 +00:00
2000-05-10 11:29:38 +00:00
// handle the case of a level changing while a client was connecting
2000-12-08 06:14:26 +00:00
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " SV_Begin_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
2000-12-08 06:14:26 +00:00
if ( host_client - > spectator ) {
2000-05-10 11:29:38 +00:00
SV_SpawnSpectator ( ) ;
if ( SpectatorConnect ) {
// copy spawn parms out of the client_t
2000-12-08 06:14:26 +00:00
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
2000-12-31 07:43:09 +00:00
( & sv_progs . pr_global_struct - > parm1 ) [ i ] = host_client - > spawn_parms [ i ] ;
2000-12-08 06:51:37 +00:00
2000-05-10 11:29:38 +00:00
// call the spawn function
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , SpectatorConnect ) ;
2000-05-10 11:29:38 +00:00
}
2000-12-08 06:14:26 +00:00
} else {
2000-05-10 11:29:38 +00:00
// copy spawn parms out of the client_t
2000-12-08 06:14:26 +00:00
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
2000-12-31 07:43:09 +00:00
( & sv_progs . pr_global_struct - > parm1 ) [ i ] = host_client - > spawn_parms [ i ] ;
2000-05-10 11:29:38 +00:00
// call the spawn function
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , sv_progs . pr_global_struct - > ClientConnect ) ;
2000-05-10 11:29:38 +00:00
// actually spawn the player
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , sv_progs . pr_global_struct - > PutClientInServer ) ;
2000-05-10 11:29:38 +00:00
}
// clear the net statistics, because connecting gives a bogus picture
2000-12-08 06:14:26 +00:00
host_client - > last_check = - 1 ;
2000-05-10 11:29:38 +00:00
host_client - > netchan . frame_latency = 0 ;
host_client - > netchan . frame_rate = 0 ;
host_client - > netchan . drop_count = 0 ;
host_client - > netchan . good_count = 0 ;
2000-12-08 06:14:26 +00:00
// check he's not cheating
pmodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " pmodel " ) ) ;
emodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " emodel " ) ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:14:26 +00:00
if ( pmodel ! = sv . model_player_checksum | | emodel ! = sv . eyes_player_checksum )
2000-12-08 06:51:37 +00:00
SV_BroadcastPrintf ( PRINT_HIGH ,
" %s WARNING: non standard player/eyes model detected \n " ,
host_client - > name ) ;
2000-05-10 11:29:38 +00:00
// if we are paused, tell the client
if ( sv . paused ) {
ClientReliableWrite_Begin ( host_client , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( host_client , sv . paused ) ;
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Server is paused. \n " ) ;
2000-05-10 11:29:38 +00:00
}
#if 0
//
// 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
2000-12-31 07:43:09 +00:00
ent = EDICT_NUM ( & sv_progs , 1 + ( host_client - svs . clients ) ) ;
2000-05-10 11:29:38 +00:00
MSG_WriteByte ( & host_client - > netchan . message , svc_setangle ) ;
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 2 ; i + + )
MSG_WriteAngle ( & host_client - > netchan . message , ent - > v . angles [ i ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
2000-05-10 11:29:38 +00:00
# endif
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = =
SV_NextDownload_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_NextDownload_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
byte buffer [ 1024 ] ;
int r ;
int percent ;
int size ;
2000-05-10 11:29:38 +00:00
if ( ! host_client - > download )
return ;
r = host_client - > downloadsize - host_client - > downloadcount ;
if ( r > 768 )
r = 768 ;
2000-09-27 19:44:26 +00:00
r = Qread ( host_client - > download , buffer , r ) ;
2000-12-08 06:51:37 +00:00
ClientReliableWrite_Begin ( host_client , svc_download , 6 + r ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Short ( host_client , r ) ;
host_client - > downloadcount + = r ;
size = host_client - > downloadsize ;
if ( ! size )
size = 1 ;
2000-12-08 06:51:37 +00:00
percent = host_client - > downloadcount * 100 / size ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Byte ( host_client , percent ) ;
ClientReliableWrite_SZ ( host_client , buffer , r ) ;
if ( host_client - > downloadcount ! = host_client - > downloadsize )
return ;
2000-09-27 19:44:26 +00:00
Qclose ( host_client - > download ) ;
2000-05-10 11:29:38 +00:00
host_client - > download = NULL ;
}
2000-05-10 20:33:16 +00:00
2000-12-08 06:51:37 +00:00
void
OutofBandPrintf ( netadr_t where , char * fmt , . . . )
2000-05-10 20:33:16 +00:00
{
2000-12-08 06:51:37 +00:00
va_list argptr ;
char send [ 1024 ] ;
2000-05-10 20:33:16 +00:00
send [ 0 ] = 0xff ;
send [ 1 ] = 0xff ;
send [ 2 ] = 0xff ;
send [ 3 ] = 0xff ;
send [ 4 ] = A2C_PRINT ;
va_start ( argptr , fmt ) ;
2000-12-08 06:51:37 +00:00
vsnprintf ( send + 5 , sizeof ( send - 5 ) , fmt , argptr ) ;
2000-05-10 20:33:16 +00:00
va_end ( argptr ) ;
2000-12-08 06:51:37 +00:00
NET_SendPacket ( strlen ( send ) + 1 , send , where ) ;
2000-05-10 20:33:16 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
SV_NextUpload
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_NextUpload ( void )
2000-05-10 20:33:16 +00:00
{
2000-12-08 06:51:37 +00:00
int percent ;
int size ;
2000-05-10 20:33:16 +00:00
if ( ! * host_client - > uploadfn ) {
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Upload denied \n " ) ;
2000-05-10 20:33:16 +00:00
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " stopul " ) ;
// suck out rest of packet
2000-12-08 06:51:37 +00:00
size = MSG_ReadShort ( ) ;
MSG_ReadByte ( ) ;
2000-05-10 20:33:16 +00:00
msg_readcount + = size ;
return ;
}
size = MSG_ReadShort ( ) ;
percent = MSG_ReadByte ( ) ;
2000-12-08 06:51:37 +00:00
if ( ! host_client - > upload ) {
host_client - > upload = Qopen ( host_client - > uploadfn , " wb " ) ;
2000-05-10 20:33:16 +00:00
if ( ! host_client - > upload ) {
2001-01-05 19:52:50 +00:00
Con_Printf ( " Can't create %s \n " , host_client - > uploadfn ) ;
2000-05-10 20:33:16 +00:00
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " stopul " ) ;
* host_client - > uploadfn = 0 ;
return ;
}
2001-01-05 19:52:50 +00:00
Con_Printf ( " Receiving %s from %d... \n " , host_client - > uploadfn ,
2000-12-08 06:51:37 +00:00
host_client - > userid ) ;
2000-05-10 20:33:16 +00:00
if ( host_client - > remote_snap )
2000-12-08 06:51:37 +00:00
OutofBandPrintf ( host_client - > snap_from ,
" Server receiving %s from %d... \n " ,
host_client - > uploadfn , host_client - > userid ) ;
2000-05-10 20:33:16 +00:00
}
2000-09-27 19:44:26 +00:00
Qwrite ( host_client - > upload , net_message . data + msg_readcount , size ) ;
2000-05-10 20:33:16 +00:00
msg_readcount + = size ;
2000-12-08 06:51:37 +00:00
Con_DPrintf ( " UPLOAD: %d received \n " , size ) ;
2000-05-10 20:33:16 +00:00
if ( percent ! = 100 ) {
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " nextul \n " ) ;
} else {
2000-09-27 19:44:26 +00:00
Qclose ( host_client - > upload ) ;
2000-05-10 20:33:16 +00:00
host_client - > upload = NULL ;
2001-01-05 19:52:50 +00:00
Con_Printf ( " %s upload completed. \n " , host_client - > uploadfn ) ;
2000-05-10 20:33:16 +00:00
if ( host_client - > remote_snap ) {
2000-12-08 06:51:37 +00:00
char * p ;
2000-05-10 20:33:16 +00:00
2000-12-08 06:51:37 +00:00
if ( ( p = strchr ( host_client - > uploadfn , ' / ' ) ) ! = NULL )
2000-05-10 20:33:16 +00:00
p + + ;
else
p = host_client - > uploadfn ;
2000-12-08 06:51:37 +00:00
OutofBandPrintf ( host_client - > snap_from ,
" %s upload completed. \n To download, enter: \n download %s \n " ,
host_client - > uploadfn , p ) ;
2000-05-10 20:33:16 +00:00
}
}
}
2000-05-10 11:29:38 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_BeginDownload_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_BeginDownload_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
char * name ;
QFile * file ;
int size ;
char realname [ MAX_OSPATH ] ;
int zip ;
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_maps ;
extern int file_from_pak ; // ZOID did file come from pak?
name = Cmd_Argv ( 1 ) ;
2000-05-10 11:29:38 +00:00
// hacked by zoid to allow more conrol over download
2000-12-08 06:51:37 +00:00
// first off, no .. or global allow check
2000-10-17 03:17:42 +00:00
if ( strstr ( name , " .. " ) | | ! allow_download - > int_val
2000-05-10 11:29:38 +00:00
// leading dot is no good
2000-12-08 06:51:37 +00:00
| | * name = = ' . '
2000-05-10 11:29:38 +00:00
// leading slash bad as well, must be in subdir
| | * name = = ' / '
// next up, skin check
2000-12-08 06:51:37 +00:00
| | ( strncmp ( name , " skins/ " , 6 ) = = 0 & & ! allow_download_skins - > int_val )
2000-05-10 11:29:38 +00:00
// now models
2000-12-08 06:51:37 +00:00
| | ( strncmp ( name , " progs/ " , 6 ) = = 0 & & ! allow_download_models - > int_val )
2000-05-10 11:29:38 +00:00
// now sounds
2000-12-08 06:51:37 +00:00
| | ( strncmp ( name , " sound/ " , 6 ) = = 0 & & ! allow_download_sounds - > int_val )
2000-05-10 11:29:38 +00:00
// now maps (note special case for maps, must not be in pak)
2000-12-08 06:51:37 +00:00
| | ( strncmp ( name , " maps/ " , 6 ) = = 0 & & ! allow_download_maps - > int_val )
// MUST be in a subdirectory
| | ! strstr ( name , " / " ) ) { // don't allow anything with .. path
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_download , 4 ) ;
ClientReliableWrite_Short ( host_client , - 1 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
return ;
}
if ( host_client - > download ) {
2000-09-27 19:44:26 +00:00
Qclose ( host_client - > download ) ;
2000-05-10 11:29:38 +00:00
host_client - > download = NULL ;
}
// lowercase name (needed for casesen file systems)
{
2000-12-08 06:51:37 +00:00
char * p ;
2000-05-10 11:29:38 +00:00
for ( p = name ; * p ; p + + )
2000-12-08 06:51:37 +00:00
* p = tolower ( ( int ) * p ) ;
2000-05-10 11:29:38 +00:00
}
2000-12-08 06:51:37 +00:00
zip = strchr ( Info_ValueForKey ( host_client - > userinfo , " *cap " ) , ' z ' ) ! = 0 ;
2000-09-28 06:11:55 +00:00
2000-09-28 13:35:59 +00:00
size = _COM_FOpenFile ( name , & file , realname , ! zip ) ;
2000-05-23 22:43:36 +00:00
2000-09-28 06:11:55 +00:00
host_client - > download = file ;
host_client - > downloadsize = size ;
2000-05-10 11:29:38 +00:00
host_client - > downloadcount = 0 ;
if ( ! host_client - > download
// special check for maps, if it came from a pak file, don't allow
// download ZOID
2000-12-08 06:51:37 +00:00
| | ( strncmp ( name , " maps/ " , 5 ) = = 0 & & file_from_pak ) ) {
2000-05-10 11:29:38 +00:00
if ( host_client - > download ) {
2000-12-08 06:51:37 +00:00
Qclose ( host_client - > download ) ;
2000-05-10 11:29:38 +00:00
host_client - > download = NULL ;
}
2001-01-05 19:52:50 +00:00
Con_Printf ( " Couldn't download %s to %s \n " , name , host_client - > name ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_download , 4 ) ;
ClientReliableWrite_Short ( host_client , - 1 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
return ;
}
2000-09-28 06:11:55 +00:00
if ( zip & & strcmp ( realname , name ) ) {
2001-01-05 19:52:50 +00:00
Con_Printf ( " download renamed to %s \n " , realname ) ;
2000-09-28 06:11:55 +00:00
ClientReliableWrite_Begin ( host_client , svc_download ,
2000-12-08 06:51:37 +00:00
strlen ( realname ) + 5 ) ;
2000-09-28 06:11:55 +00:00
ClientReliableWrite_Short ( host_client , - 2 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
ClientReliableWrite_String ( host_client , realname ) ;
ClientReliable_FinishWrite ( host_client ) ;
}
2000-05-10 11:29:38 +00:00
SV_NextDownload_f ( ) ;
2001-01-05 19:52:50 +00:00
Con_Printf ( " Downloading %s to %s \n " , name , host_client - > name ) ;
2000-05-10 11:29:38 +00:00
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = =
SV_Say
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Say ( qboolean team )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
client_t * client ;
int j , tmp ;
char * p ;
char text [ 2048 ] ;
char t1 [ 32 ] , * t2 ;
2000-05-10 11:29:38 +00:00
if ( Cmd_Argc ( ) < 2 )
return ;
2000-12-08 06:51:37 +00:00
if ( team ) {
2000-05-10 11:29:38 +00:00
strncpy ( t1 , Info_ValueForKey ( host_client - > userinfo , " team " ) , 31 ) ;
t1 [ 31 ] = 0 ;
}
2000-10-17 03:17:42 +00:00
if ( host_client - > spectator & & ( ! sv_spectalk - > int_val | | team ) )
2000-12-08 06:51:37 +00:00
snprintf ( text , sizeof ( text ) , " [SPEC] %s: " , host_client - > name ) ;
2000-05-10 11:29:38 +00:00
else if ( team )
2000-12-08 06:51:37 +00:00
snprintf ( text , sizeof ( text ) , " (%s): " , host_client - > name ) ;
2000-05-10 11:29:38 +00:00
else {
2000-12-08 06:51:37 +00:00
snprintf ( text , sizeof ( text ) , " %s: " , host_client - > name ) ;
2000-05-10 11:29:38 +00:00
}
if ( fp_messages ) {
2000-12-08 06:51:37 +00:00
if ( ! sv . paused & & realtime < host_client - > lockedtill ) {
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" You can't talk for %d more seconds \n " ,
( int ) ( host_client - > lockedtill - realtime ) ) ;
2000-05-10 11:29:38 +00:00
return ;
}
tmp = host_client - > whensaidhead - fp_messages + 1 ;
if ( tmp < 0 )
2000-12-08 06:51:37 +00:00
tmp = 10 + tmp ;
2000-05-10 11:29:38 +00:00
if ( ! sv . paused & &
2000-12-08 06:51:37 +00:00
host_client - > whensaid [ tmp ]
& & ( realtime - host_client - > whensaid [ tmp ] < fp_persecond ) ) {
2000-05-10 11:29:38 +00:00
host_client - > lockedtill = realtime + fp_secondsdead ;
if ( fp_msg [ 0 ] )
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" FloodProt: %s \n " , fp_msg ) ;
2000-05-10 11:29:38 +00:00
else
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" FloodProt: You can't talk for %d seconds. \n " ,
fp_secondsdead ) ;
2000-05-10 11:29:38 +00:00
return ;
}
host_client - > whensaidhead + + ;
if ( host_client - > whensaidhead > 9 )
host_client - > whensaidhead = 0 ;
host_client - > whensaid [ host_client - > whensaidhead ] = realtime ;
}
2000-12-08 06:51:37 +00:00
p = Cmd_Args ( ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( * p = = ' " ' ) {
2000-05-10 11:29:38 +00:00
p + + ;
2000-12-08 06:51:37 +00:00
p [ strlen ( p ) - 1 ] = 0 ;
2000-05-10 11:29:38 +00:00
}
2000-12-08 06:51:37 +00:00
strncat ( text , p , sizeof ( text ) - strlen ( text ) ) ;
strncat ( text , " \n " , sizeof ( text ) - strlen ( text ) ) ;
2000-05-10 11:29:38 +00:00
2001-01-05 19:52:50 +00:00
Con_Printf ( " %s " , text ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + ) {
2000-05-10 11:29:38 +00:00
if ( client - > state ! = cs_spawned )
continue ;
2000-10-17 03:17:42 +00:00
if ( host_client - > spectator & & ! sv_spectalk - > int_val )
2000-05-10 11:29:38 +00:00
if ( ! client - > spectator )
continue ;
2000-12-08 06:51:37 +00:00
if ( team ) {
2000-05-10 11:29:38 +00:00
// the spectator team
if ( host_client - > spectator ) {
if ( ! client - > spectator )
continue ;
} else {
t2 = Info_ValueForKey ( client - > userinfo , " team " ) ;
2000-12-08 06:51:37 +00:00
if ( strcmp ( t1 , t2 ) | | client - > spectator )
continue ; // on different teams
2000-05-10 11:29:38 +00:00
}
}
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( client , PRINT_CHAT , " %s " , text ) ;
2000-05-10 11:29:38 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Say_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Say_f ( void )
2000-05-10 11:29:38 +00:00
{
SV_Say ( false ) ;
}
2000-12-08 06:51:37 +00:00
2000-05-10 11:29:38 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_Say_Team_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Say_Team_f ( void )
2000-05-10 11:29:38 +00:00
{
SV_Say ( true ) ;
}
//============================================================================
/*
= = = = = = = = = = = = = = = = =
SV_Pings_f
The client is showing the scoreboard , so send new ping times for all
clients
= = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Pings_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
client_t * client ;
int j ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + ) {
2000-05-10 11:29:38 +00:00
if ( client - > state ! = cs_spawned )
continue ;
ClientReliableWrite_Begin ( host_client , svc_updateping , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
2000-12-08 06:51:37 +00:00
ClientReliableWrite_Short ( host_client , SV_CalcPing ( client ) ) ;
2000-05-10 11:29:38 +00:00
ClientReliableWrite_Begin ( host_client , svc_updatepl , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
ClientReliableWrite_Byte ( host_client , client - > lossage ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Kill_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Kill_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
if ( sv_player - > v . health < = 0 ) {
SV_ClientPrintf ( host_client , PRINT_HIGH ,
" Can't suicide -- allready dead! \n " ) ;
2000-05-10 11:29:38 +00:00
return ;
}
2000-12-08 06:51:37 +00:00
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , sv_progs . pr_global_struct - > ClientKill ) ;
2000-05-10 11:29:38 +00:00
}
2000-05-10 20:33:16 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_TogglePause
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_TogglePause ( const char * msg )
2000-05-10 20:33:16 +00:00
{
2000-12-08 06:51:37 +00:00
int i ;
client_t * cl ;
2000-05-10 20:33:16 +00:00
sv . paused ^ = 1 ;
if ( msg )
SV_BroadcastPrintf ( PRINT_HIGH , " %s " , msg ) ;
// send notification to all clients
2000-12-08 06:51:37 +00:00
for ( i = 0 , cl = svs . clients ; i < MAX_CLIENTS ; i + + , cl + + ) {
2000-05-10 20:33:16 +00:00
if ( ! cl - > state )
continue ;
ClientReliableWrite_Begin ( cl , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( cl , sv . paused ) ;
}
}
2000-05-10 11:29:38 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_Pause_f
= = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Pause_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-08-13 14:21:21 +00:00
static double lastpausetime ;
2000-12-08 06:51:37 +00:00
double currenttime ;
char st [ sizeof ( host_client - > name ) + 32 ] ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
currenttime = Sys_DoubleTime ( ) ;
2000-08-13 14:21:21 +00:00
2000-12-08 06:51:37 +00:00
if ( lastpausetime + 1 > currenttime ) {
2000-08-13 14:21:21 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Pause flood not allowed. \n " ) ;
return ;
2000-12-08 06:51:37 +00:00
}
2000-08-13 14:21:21 +00:00
2000-12-08 06:51:37 +00:00
lastpausetime = currenttime ;
2000-08-13 14:21:21 +00:00
2000-10-17 03:17:42 +00:00
if ( ! pausable - > int_val ) {
2000-05-10 11:29:38 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Pause not allowed. \n " ) ;
return ;
}
if ( host_client - > spectator ) {
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH ,
" Spectators can not pause. \n " ) ;
2000-05-10 11:29:38 +00:00
return ;
2000-05-10 20:33:16 +00:00
}
2000-10-16 03:12:03 +00:00
if ( ! sv . paused )
2000-12-08 06:51:37 +00:00
snprintf ( st , sizeof ( st ) , " %s paused the game \n " , host_client - > name ) ;
2000-05-10 20:33:16 +00:00
else
2000-12-08 06:51:37 +00:00
snprintf ( st , sizeof ( st ) , " %s unpaused the game \n " , host_client - > name ) ;
2000-05-10 20:33:16 +00:00
2000-12-08 06:51:37 +00:00
SV_TogglePause ( st ) ;
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = = = = = = = =
SV_Drop_f
The client is going to disconnect , so remove the connection immediately
= = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_Drop_f ( void )
2000-05-10 11:29:38 +00:00
{
SV_EndRedirect ( ) ;
if ( ! host_client - > spectator )
SV_BroadcastPrintf ( PRINT_HIGH , " %s dropped \n " , host_client - > name ) ;
2000-12-08 06:51:37 +00:00
SV_DropClient ( host_client ) ;
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = = = = = = = =
SV_PTrack_f
Change the bandwidth estimate for a client
= = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_PTrack_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
int i ;
edict_t * ent , * tent ;
2000-05-10 11:29:38 +00:00
if ( ! host_client - > spectator )
return ;
2000-12-08 06:51:37 +00:00
if ( Cmd_Argc ( ) ! = 2 ) {
2000-05-10 11:29:38 +00:00
// turn off tracking
host_client - > spec_track = 0 ;
2000-12-31 07:43:09 +00:00
ent = EDICT_NUM ( & sv_progs , host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( & sv_progs , 0 ) ;
2001-01-02 03:22:46 +00:00
ent - > v . goalentity = EDICT_TO_PROG ( & sv_progs , tent ) ;
2000-05-10 11:29:38 +00:00
return ;
}
2000-12-08 06:51:37 +00:00
i = atoi ( Cmd_Argv ( 1 ) ) ;
2000-05-10 11:29:38 +00:00
if ( i < 0 | | i > = MAX_CLIENTS | | svs . clients [ i ] . state ! = cs_spawned | |
svs . clients [ i ] . spectator ) {
SV_ClientPrintf ( host_client , PRINT_HIGH , " Invalid client to track \n " ) ;
host_client - > spec_track = 0 ;
2000-12-31 07:43:09 +00:00
ent = EDICT_NUM ( & sv_progs , host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( & sv_progs , 0 ) ;
2001-01-02 03:22:46 +00:00
ent - > v . goalentity = EDICT_TO_PROG ( & sv_progs , tent ) ;
2000-05-10 11:29:38 +00:00
return ;
}
2000-12-08 06:51:37 +00:00
host_client - > spec_track = i + 1 ; // now tracking
2000-05-10 11:29:38 +00:00
2000-12-31 07:43:09 +00:00
ent = EDICT_NUM ( & sv_progs , host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( & sv_progs , i + 1 ) ;
2001-01-02 03:22:46 +00:00
ent - > v . goalentity = EDICT_TO_PROG ( & sv_progs , tent ) ;
2000-05-10 11:29:38 +00:00
}
/*
2000-11-26 12:43:49 +00:00
SV_Rate_f
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
Change the bandwidth estimate for a client
2000-05-10 11:29:38 +00:00
*/
2000-11-26 12:43:49 +00:00
void
SV_Rate_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
int rate ;
2000-11-26 12:43:49 +00:00
if ( Cmd_Argc ( ) ! = 2 ) {
2000-05-10 11:29:38 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Current rate is %i \n " ,
2000-12-08 06:51:37 +00:00
( int ) ( 1.0 / host_client - > netchan . rate + 0.5 ) ) ;
2000-05-10 11:29:38 +00:00
return ;
}
2000-12-08 06:51:37 +00:00
2000-11-26 12:43:49 +00:00
rate = atoi ( Cmd_Argv ( 1 ) ) ;
if ( ( sv_maxrate - > int_val ) & & ( rate > sv_maxrate - > int_val ) ) {
rate = bound ( 500 , rate , sv_maxrate - > int_val ) ;
} else {
rate = bound ( 500 , rate , 10000 ) ;
}
2000-05-10 11:29:38 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Net rate set to %i \n " , rate ) ;
2000-11-26 12:43:49 +00:00
host_client - > netchan . rate = 1.0 / rate ;
2000-05-10 11:29:38 +00:00
}
/*
2000-11-26 12:43:49 +00:00
SV_Msg_f
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
Change the message level for a client
2000-05-10 11:29:38 +00:00
*/
2000-11-26 12:43:49 +00:00
void
SV_Msg_f ( void )
2000-12-08 06:51:37 +00:00
{
if ( Cmd_Argc ( ) ! = 2 ) {
2000-05-10 11:29:38 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Current msg level is %i \n " ,
2000-12-08 06:51:37 +00:00
host_client - > messagelevel ) ;
2000-05-10 11:29:38 +00:00
return ;
}
2000-12-08 06:51:37 +00:00
2000-11-26 12:43:49 +00:00
host_client - > messagelevel = atoi ( Cmd_Argv ( 1 ) ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
SV_ClientPrintf ( host_client , PRINT_HIGH , " Msg level set to %i \n " ,
host_client - > messagelevel ) ;
2000-05-10 11:29:38 +00:00
}
/*
2000-11-26 12:43:49 +00:00
SV_SetInfo_f
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
Allow clients to change userinfo
2000-05-10 11:29:38 +00:00
*/
2000-11-26 12:43:49 +00:00
void
SV_SetInfo_f ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
int i ;
char oldval [ MAX_INFO_STRING ] ;
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
if ( Cmd_Argc ( ) = = 1 ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " User info settings: \n " ) ;
Info_Print ( host_client - > userinfo ) ;
return ;
}
2000-11-26 12:43:49 +00:00
if ( Cmd_Argc ( ) ! = 3 ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " usage: setinfo [ <key> <value> ] \n " ) ;
return ;
}
2000-11-26 12:43:49 +00:00
if ( Cmd_Argv ( 1 ) [ 0 ] = = ' * ' )
2000-12-08 06:51:37 +00:00
return ; // don't set priveledged values
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
strcpy ( oldval , Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
Info_SetValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) , Cmd_Argv ( 2 ) ,
MAX_INFO_STRING ) ;
2000-05-10 11:29:38 +00:00
// name is extracted below in ExtractFromUserInfo
2000-12-08 06:51:37 +00:00
// 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;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( strequal
2000-12-14 07:46:17 +00:00
( Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) , oldval ) )
return ; // key hasn't changed
2000-05-10 11:29:38 +00:00
// process any changed values
SV_ExtractFromUserinfo ( host_client ) ;
i = host_client - svs . clients ;
MSG_WriteByte ( & sv . reliable_datagram , svc_setinfo ) ;
MSG_WriteByte ( & sv . reliable_datagram , i ) ;
2000-12-08 06:51:37 +00:00
MSG_WriteString ( & sv . reliable_datagram , Cmd_Argv ( 1 ) ) ;
MSG_WriteString ( & sv . reliable_datagram ,
Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) ) ;
2000-05-10 11:29:38 +00:00
}
/*
2000-11-26 12:43:49 +00:00
SV_ShowServerinfo_f
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
Dump serverinfo into a string
2000-05-10 11:29:38 +00:00
*/
2000-11-26 12:43:49 +00:00
void
SV_ShowServerinfo_f ( void )
2000-05-10 11:29:38 +00:00
{
Info_Print ( svs . info ) ;
2000-05-10 20:33:16 +00:00
}
2000-11-26 12:43:49 +00:00
void
SV_NoSnap_f ( void )
2000-05-10 20:33:16 +00:00
{
if ( * host_client - > uploadfn ) {
* host_client - > uploadfn = 0 ;
2000-12-08 06:51:37 +00:00
SV_BroadcastPrintf ( PRINT_HIGH , " %s refused remote screenshot \n " ,
host_client - > name ) ;
2000-05-10 20:33:16 +00:00
}
}
2000-05-10 11:29:38 +00:00
2000-11-26 12:43:49 +00:00
typedef struct {
2000-12-08 06:51:37 +00:00
char * name ;
void ( * func ) ( void ) ;
2001-01-08 06:23:10 +00:00
int no_redirect ;
2000-05-10 11:29:38 +00:00
} ucmd_t ;
2000-12-08 06:51:37 +00:00
ucmd_t ucmds [ ] = {
2000-05-10 11:29:38 +00:00
{ " new " , SV_New_f } ,
{ " modellist " , SV_Modellist_f } ,
{ " soundlist " , SV_Soundlist_f } ,
{ " prespawn " , SV_PreSpawn_f } ,
{ " spawn " , SV_Spawn_f } ,
2001-01-08 06:23:10 +00:00
{ " begin " , SV_Begin_f , 1 } ,
2000-05-10 11:29:38 +00:00
{ " drop " , SV_Drop_f } ,
{ " pings " , SV_Pings_f } ,
2000-12-08 06:51:37 +00:00
// issued by hand at client consoles
2000-05-10 11:29:38 +00:00
{ " rate " , SV_Rate_f } ,
{ " kill " , SV_Kill_f } ,
{ " pause " , SV_Pause_f } ,
{ " msg " , SV_Msg_f } ,
2001-01-08 06:23:10 +00:00
{ " say " , SV_Say_f , 1 } ,
{ " say_team " , SV_Say_Team_f , 1 } ,
2000-05-10 11:29:38 +00:00
{ " setinfo " , SV_SetInfo_f } ,
{ " serverinfo " , SV_ShowServerinfo_f } ,
{ " download " , SV_BeginDownload_f } ,
2000-05-10 20:33:16 +00:00
{ " nextdl " , SV_NextDownload_f } ,
2000-12-08 06:51:37 +00:00
{ " ptrack " , SV_PTrack_f } , // ZOID - used with autocam
2000-05-10 20:33:16 +00:00
2000-05-10 11:29:38 +00:00
{ " snap " , SV_NoSnap_f } ,
2000-12-08 06:51:37 +00:00
2000-05-10 11:29:38 +00:00
} ;
2001-01-08 06:23:10 +00:00
static int
ucmds_compare ( const void * _a , const void * _b )
{
ucmd_t * a = ( ucmd_t * ) _a ;
ucmd_t * b = ( ucmd_t * ) _b ;
return strcmp ( a - > name , b - > name ) ;
}
2000-05-10 11:29:38 +00:00
/*
2000-11-26 12:43:49 +00:00
SV_ExecuteUserCommand
Uhh . . . execute user command . : )
2000-05-10 11:29:38 +00:00
*/
2000-11-26 12:43:49 +00:00
void
SV_ExecuteUserCommand ( char * s )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
ucmd_t * u ;
2001-01-08 06:23:10 +00:00
ucmd_t cmd ;
2000-12-08 06:51:37 +00:00
2000-05-10 11:29:38 +00:00
Cmd_TokenizeString ( s ) ;
sv_player = host_client - > edict ;
2001-01-08 06:23:10 +00:00
cmd . name = Cmd_Argv ( 0 ) ;
2000-05-10 11:29:38 +00:00
2001-01-08 06:23:10 +00:00
u = ( ucmd_t * ) bsearch ( & cmd , ucmds , sizeof ( ucmds ) / sizeof ( ucmds [ 0 ] ) ,
sizeof ( ucmds [ 0 ] ) , ucmds_compare ) ;
2000-05-10 11:29:38 +00:00
2001-01-08 06:23:10 +00:00
if ( ! u ) {
SV_BeginRedirect ( RD_CLIENT ) ;
2000-11-26 12:43:49 +00:00
Con_Printf ( " Bad user command: %s \n " , Cmd_Argv ( 0 ) ) ;
2001-01-06 07:15:42 +00:00
SV_EndRedirect ( ) ;
2001-01-08 06:23:10 +00:00
} else {
if ( ! u - > no_redirect )
SV_BeginRedirect ( RD_CLIENT ) ;
u - > func ( ) ;
if ( ! u - > no_redirect )
SV_EndRedirect ( ) ;
}
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
USER CMD EXECUTION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
2000-06-09 19:06:50 +00:00
SV_CalcRoll
2000-05-10 11:29:38 +00:00
Used by view and sv_user
= = = = = = = = = = = = = = =
*/
2000-11-26 12:43:49 +00:00
float
SV_CalcRoll ( vec3_t angles , vec3_t velocity )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
vec3_t forward , right , up ;
float sign ;
float side ;
float value ;
2000-05-10 11:29:38 +00:00
AngleVectors ( angles , forward , right , up ) ;
side = DotProduct ( velocity , right ) ;
sign = side < 0 ? - 1 : 1 ;
2000-12-08 06:51:37 +00:00
side = fabs ( side ) ;
2000-05-16 04:47:41 +00:00
value = cl_rollangle - > value ;
if ( side < cl_rollspeed - > value )
side = side * value / cl_rollspeed - > value ;
2000-05-10 11:29:38 +00:00
else
side = value ;
2000-12-08 06:51:37 +00:00
return side * sign ;
2000-05-10 11:29:38 +00:00
}
//============================================================================
2000-12-08 06:51:37 +00:00
vec3_t pmove_mins , pmove_maxs ;
2000-05-10 11:29:38 +00:00
/*
= = = = = = = = = = = = = = = = = = = =
AddLinksToPmove
= = = = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
AddLinksToPmove ( areanode_t * node )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
link_t * l , * next ;
edict_t * check ;
int pl ;
int i ;
physent_t * pe ;
2000-05-10 11:29:38 +00:00
2001-01-02 03:22:46 +00:00
pl = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-05-10 11:29:38 +00:00
// touch linked edicts
2000-12-08 06:51:37 +00:00
for ( l = node - > solid_edicts . next ; l ! = & node - > solid_edicts ; l = next ) {
2000-05-10 11:29:38 +00:00
next = l - > next ;
2000-12-08 06:51:37 +00:00
check = EDICT_FROM_AREA ( l ) ;
2000-05-10 11:29:38 +00:00
if ( check - > v . owner = = pl )
2000-12-08 06:51:37 +00:00
continue ; // player's own missile
if ( check - > v . solid = = SOLID_BSP
| | check - > v . solid = = SOLID_BBOX | | check - > v . solid = = SOLID_SLIDEBOX ) {
2000-05-10 11:29:38 +00:00
if ( check = = sv_player )
continue ;
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 3 ; i + + )
2000-05-10 11:29:38 +00:00
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
2000-12-08 06:51:37 +00:00
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
2000-05-10 11:29:38 +00:00
break ;
if ( i ! = 3 )
continue ;
if ( pmove . numphysent = = MAX_PHYSENTS )
return ;
pe = & pmove . physents [ pmove . numphysent ] ;
pmove . numphysent + + ;
VectorCopy ( check - > v . origin , pe - > origin ) ;
2000-12-31 07:43:09 +00:00
pe - > info = NUM_FOR_EDICT ( & sv_progs , check ) ;
2000-11-26 12:43:49 +00:00
if ( check - > v . solid = = SOLID_BSP ) {
2000-12-08 06:51:37 +00:00
pe - > model = sv . models [ ( int ) ( check - > v . modelindex ) ] ;
2000-11-26 12:43:49 +00:00
} else {
2000-05-10 11:29:38 +00:00
pe - > model = NULL ;
VectorCopy ( check - > v . mins , pe - > mins ) ;
VectorCopy ( check - > v . maxs , pe - > maxs ) ;
}
}
}
2000-12-08 06:51:37 +00:00
2000-11-26 12:43:49 +00:00
// recurse down both sides
2000-05-10 11:29:38 +00:00
if ( node - > axis = = - 1 )
return ;
2000-11-26 12:43:49 +00:00
if ( pmove_maxs [ node - > axis ] > node - > dist )
AddLinksToPmove ( node - > children [ 0 ] ) ;
if ( pmove_mins [ node - > axis ] < node - > dist )
AddLinksToPmove ( node - > children [ 1 ] ) ;
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = = = = = = =
AddAllEntsToPmove
For debugging
= = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
AddAllEntsToPmove ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
int e ;
edict_t * check ;
int i ;
physent_t * pe ;
int pl ;
2001-01-02 03:22:46 +00:00
pl = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
check = NEXT_EDICT ( & sv_progs , sv . edicts ) ;
for ( e = 1 ; e < sv . num_edicts ; e + + , check = NEXT_EDICT ( & sv_progs , check ) ) {
2000-05-10 11:29:38 +00:00
if ( check - > free )
continue ;
if ( check - > v . owner = = pl )
continue ;
2000-12-08 06:51:37 +00:00
if ( check - > v . solid = = SOLID_BSP
| | check - > v . solid = = SOLID_BBOX | | check - > v . solid = = SOLID_SLIDEBOX ) {
2000-05-10 11:29:38 +00:00
if ( check = = sv_player )
continue ;
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 3 ; i + + )
2000-05-10 11:29:38 +00:00
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
2000-12-08 06:51:37 +00:00
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
2000-05-10 11:29:38 +00:00
break ;
if ( i ! = 3 )
continue ;
pe = & pmove . physents [ pmove . numphysent ] ;
VectorCopy ( check - > v . origin , pe - > origin ) ;
pmove . physents [ pmove . numphysent ] . info = e ;
if ( check - > v . solid = = SOLID_BSP )
2000-12-08 06:51:37 +00:00
pe - > model = sv . models [ ( int ) ( check - > v . modelindex ) ] ;
else {
2000-05-10 11:29:38 +00:00
pe - > model = NULL ;
VectorCopy ( check - > v . mins , pe - > mins ) ;
VectorCopy ( check - > v . maxs , pe - > maxs ) ;
}
if ( + + pmove . numphysent = = MAX_PHYSENTS )
break ;
}
}
}
/*
= = = = = = = = = = =
SV_PreRunCmd
= = = = = = = = = = =
Done before running a player command . Clears the touch array
*/
2000-12-08 06:51:37 +00:00
byte playertouch [ ( MAX_EDICTS + 7 ) / 8 ] ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
void
SV_PreRunCmd ( void )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
memset ( playertouch , 0 , sizeof ( playertouch ) ) ;
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = =
SV_RunCmd
= = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
extern qboolean nouse ; // 1999-10-29 +USE fix by Maddes
2000-08-20 19:17:44 +00:00
2000-11-26 12:43:49 +00:00
void
SV_RunCmd ( usercmd_t * ucmd , qboolean inside )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
edict_t * ent ;
int i , n , oldmsec ;
double tmp_time ;
int tmp_time1 ;
2000-09-25 02:02:58 +00:00
2000-12-08 06:51:37 +00:00
if ( ! inside ) { // prevent infinite loop
2000-09-25 02:02:58 +00:00
host_client - > msecs + = ucmd - > msec ;
2000-11-25 14:20:04 +00:00
if ( ( sv_timekick - > int_val )
2000-12-08 06:51:37 +00:00
& & ( ( tmp_time = realtime - host_client - > last_check ) > =
sv_timekick_interval - > value ) ) {
2000-11-25 14:20:04 +00:00
tmp_time1 = tmp_time * ( 1000 + sv_timekick_fuzz - > value ) ;
2000-12-08 06:51:37 +00:00
if ( ( host_client - > last_check ! = - 1 ) // don't do it if new player
& & ( host_client - > msecs > tmp_time1 ) ) {
2000-09-25 02:02:58 +00:00
host_client - > msec_cheating + + ;
2000-11-25 14:20:04 +00:00
SV_BroadcastPrintf ( PRINT_HIGH ,
2000-12-08 06:51:37 +00:00
va
( " %s thinks there are %d ms in %d seconds (Strike %d/%d) \n " ,
host_client - > name , host_client - > msecs ,
( int ) tmp_time , host_client - > msec_cheating ,
sv_timekick - > int_val ) ) ;
2000-09-25 02:02:58 +00:00
2000-10-17 03:17:42 +00:00
if ( host_client - > msec_cheating > = sv_timekick - > int_val ) {
2000-12-08 06:14:26 +00:00
SV_BroadcastPrintf ( PRINT_HIGH , va ( " Strike %d for %s!! \n " ,
2000-12-08 06:51:37 +00:00
host_client - >
msec_cheating ,
host_client - > name ) ) ;
SV_BroadcastPrintf ( PRINT_HIGH ,
" Please see http://www.quakeforge.net/speed_cheat.php for infomation on QuakeForge's time cheat protection, and to explain how some may be cheating without knowing it. \n " ) ;
2000-12-08 06:14:26 +00:00
SV_DropClient ( host_client ) ;
2000-09-25 02:02:58 +00:00
}
}
2000-05-14 19:29:57 +00:00
2000-09-25 02:02:58 +00:00
host_client - > msecs = 0 ;
host_client - > last_check = realtime ;
}
}
2000-05-14 19:29:57 +00:00
2000-09-25 02:02:58 +00:00
cmd = * ucmd ;
// chop up very long commands
if ( cmd . msec > 50 ) {
oldmsec = ucmd - > msec ;
2000-12-08 06:51:37 +00:00
cmd . msec = oldmsec / 2 ;
2000-09-25 02:02:58 +00:00
SV_RunCmd ( & cmd , 1 ) ;
2000-12-08 06:51:37 +00:00
cmd . msec = oldmsec / 2 ;
2000-09-25 02:02:58 +00:00
cmd . impulse = 0 ;
SV_RunCmd ( & cmd , 1 ) ;
return ;
}
2000-05-14 19:29:57 +00:00
2000-09-25 02:02:58 +00:00
if ( ! sv_player - > v . fixangle )
VectorCopy ( ucmd - > angles , sv_player - > v . v_angle ) ;
2000-05-14 19:29:57 +00:00
2000-09-25 02:02:58 +00:00
sv_player - > v . button0 = ucmd - > buttons & 1 ;
2000-08-20 19:17:44 +00:00
// 1999-10-29 +USE fix by Maddes start
2000-12-08 06:51:37 +00:00
if ( ! nouse ) {
sv_player - > v . button1 = ( ucmd - > buttons & 4 ) > > 2 ;
2000-08-20 19:17:44 +00:00
}
// 1999-10-29 +USE fix by Maddes end
2000-12-08 06:51:37 +00:00
sv_player - > v . button2 = ( ucmd - > buttons & 2 ) > > 1 ;
2000-09-25 02:02:58 +00:00
if ( ucmd - > impulse )
sv_player - > v . impulse = ucmd - > impulse ;
2000-05-10 11:29:38 +00:00
//
// angles
2000-05-14 19:29:57 +00:00
// show 1/3 the pitch angle and all the roll angle
2000-09-25 02:02:58 +00:00
if ( sv_player - > v . health > 0 ) {
if ( ! sv_player - > v . fixangle ) {
2000-12-08 06:51:37 +00:00
sv_player - > v . angles [ PITCH ] = - sv_player - > v . v_angle [ PITCH ] / 3 ;
2000-09-25 02:02:58 +00:00
sv_player - > v . angles [ YAW ] = sv_player - > v . v_angle [ YAW ] ;
}
sv_player - > v . angles [ ROLL ] =
2000-12-08 06:51:37 +00:00
SV_CalcRoll ( sv_player - > v . angles , sv_player - > v . velocity ) * 4 ;
2000-09-25 02:02:58 +00:00
}
2000-05-14 19:29:57 +00:00
2000-12-08 06:51:37 +00:00
sv_frametime = min ( 0.1 , ucmd - > msec * 0.001 ) ;
2000-09-25 02:02:58 +00:00
if ( ! host_client - > spectator ) {
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > frametime = sv_frametime ;
2000-05-14 19:29:57 +00:00
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , sv_progs . pr_global_struct - > PlayerPreThink ) ;
2000-05-14 19:29:57 +00:00
2000-09-25 02:02:58 +00:00
SV_RunThink ( sv_player ) ;
}
2000-05-14 19:29:57 +00:00
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 3 ; i + + )
pmove . origin [ i ] =
sv_player - > v . origin [ i ] + ( sv_player - > v . mins [ i ] - player_mins [ i ] ) ;
2000-09-25 02:02:58 +00:00
VectorCopy ( sv_player - > v . velocity , pmove . velocity ) ;
VectorCopy ( sv_player - > v . v_angle , pmove . angles ) ;
pmove . flying = sv_player - > v . movetype = = MOVETYPE_FLY ;
pmove . spectator = host_client - > spectator ;
pmove . waterjumptime = sv_player - > v . teleport_time ;
pmove . numphysent = 1 ;
pmove . physents [ 0 ] . model = sv . worldmodel ;
pmove . cmd = * ucmd ;
pmove . dead = sv_player - > v . health < = 0 ;
pmove . oldbuttons = host_client - > oldbuttons ;
movevars . entgravity = host_client - > entgravity ;
movevars . maxspeed = host_client - > maxspeed ;
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
2000-09-25 02:02:58 +00:00
pmove_mins [ i ] = pmove . origin [ i ] - 256 ;
pmove_maxs [ i ] = pmove . origin [ i ] + 256 ;
}
2000-05-10 11:29:38 +00:00
# if 1
2000-11-26 12:43:49 +00:00
AddLinksToPmove ( sv_areanodes ) ;
2000-05-10 11:29:38 +00:00
# else
2000-09-25 02:02:58 +00:00
AddAllEntsToPmove ( ) ;
2000-05-10 11:29:38 +00:00
# endif
#if 0
2000-12-08 06:51:37 +00:00
{
int before , after ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
before = PM_TestPlayerPosition ( pmove . origin ) ;
PlayerMove ( ) ;
after = PM_TestPlayerPosition ( pmove . origin ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( sv_player - > v . health > 0 & & before & & ! after )
Con_Printf ( " player %s got stuck in playermove!!!! \n " ,
host_client - > name ) ;
}
2000-05-10 11:29:38 +00:00
# else
2000-09-25 02:02:58 +00:00
PlayerMove ( ) ;
2000-05-10 11:29:38 +00:00
# endif
2000-09-25 02:02:58 +00:00
host_client - > oldbuttons = pmove . oldbuttons ;
sv_player - > v . teleport_time = pmove . waterjumptime ;
sv_player - > v . waterlevel = waterlevel ;
sv_player - > v . watertype = watertype ;
if ( onground ! = - 1 ) {
2000-12-08 06:51:37 +00:00
sv_player - > v . flags = ( int ) sv_player - > v . flags | FL_ONGROUND ;
sv_player - > v . groundentity =
2001-01-02 03:22:46 +00:00
EDICT_TO_PROG ( & sv_progs , EDICT_NUM ( & sv_progs , pmove . physents [ onground ] . info ) ) ;
2000-09-25 02:02:58 +00:00
} else {
2000-12-08 06:51:37 +00:00
sv_player - > v . flags = ( int ) sv_player - > v . flags & ~ FL_ONGROUND ;
2000-09-25 02:02:58 +00:00
}
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 3 ; i + + )
sv_player - > v . origin [ i ] =
pmove . origin [ i ] - ( sv_player - > v . mins [ i ] - player_mins [ i ] ) ;
2000-05-10 11:29:38 +00:00
#if 0
2000-09-25 02:02:58 +00:00
// truncate velocity the same way the net protocol will
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < 3 ; i + + )
sv_player - > v . velocity [ i ] = ( int ) pmove . velocity [ i ] ;
2000-05-10 11:29:38 +00:00
# else
2000-09-25 02:02:58 +00:00
VectorCopy ( pmove . velocity , sv_player - > v . velocity ) ;
2000-05-10 11:29:38 +00:00
# endif
2000-09-25 02:02:58 +00:00
VectorCopy ( pmove . angles , sv_player - > v . v_angle ) ;
if ( ! host_client - > spectator ) {
// link into place and touch triggers
SV_LinkEdict ( sv_player , true ) ;
// touch other objects
2000-12-08 06:51:37 +00:00
for ( i = 0 ; i < pmove . numtouch ; i + + ) {
2000-09-25 02:02:58 +00:00
n = pmove . physents [ pmove . touchindex [ i ] ] . info ;
2000-12-31 07:43:09 +00:00
ent = EDICT_NUM ( & sv_progs , n ) ;
2000-12-08 06:51:37 +00:00
if ( ! ent - > v . touch | | ( playertouch [ n / 8 ] & ( 1 < < ( n % 8 ) ) ) )
2000-09-25 02:02:58 +00:00
continue ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , ent ) ;
sv_progs . pr_global_struct - > other = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , ent - > v . touch ) ;
2000-12-08 06:51:37 +00:00
playertouch [ n / 8 ] | = 1 < < ( n % 8 ) ;
2000-09-25 02:02:58 +00:00
}
}
2000-05-10 11:29:38 +00:00
}
/*
= = = = = = = = = = =
SV_PostRunCmd
= = = = = = = = = = =
Done after running a player command .
*/
2000-12-08 06:51:37 +00:00
void
SV_PostRunCmd ( void )
2000-05-10 11:29:38 +00:00
{
// run post-think
if ( ! host_client - > spectator ) {
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , sv_progs . pr_global_struct - > PlayerPostThink ) ;
2000-05-10 11:29:38 +00:00
SV_RunNewmis ( ) ;
} else if ( SpectatorThink ) {
2000-12-31 07:43:09 +00:00
sv_progs . pr_global_struct - > time = sv . time ;
2001-01-02 03:22:46 +00:00
sv_progs . pr_global_struct - > self = EDICT_TO_PROG ( & sv_progs , sv_player ) ;
2000-12-31 07:43:09 +00:00
PR_ExecuteProgram ( & sv_progs , SpectatorThink ) ;
2000-05-10 11:29:38 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = = =
SV_ExecuteClientMessage
The current net_message is parsed for the given client
= = = = = = = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_ExecuteClientMessage ( client_t * cl )
2000-05-10 11:29:38 +00:00
{
2000-12-08 06:51:37 +00:00
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 ;
byte checksum , calculatedChecksum ;
int seq_hash ;
2000-05-10 11:29:38 +00:00
// 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
2000-12-08 06:51:37 +00:00
cl - > send_message = false ; // don't reply, sequences have
// slipped
2000-05-10 11:29:38 +00:00
// 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 ;
2000-05-10 20:33:16 +00:00
2000-12-08 06:51:37 +00:00
// seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
2000-05-10 20:33:16 +00:00
seq_hash = cl - > netchan . incoming_sequence ;
2000-12-08 06:51:37 +00:00
2000-05-10 11:29:38 +00:00
// mark time so clients will know how much to predict
// other players
2000-12-08 06:51:37 +00:00
cl - > localtime = sv . time ;
cl - > delta_sequence = - 1 ; // no delta unless requested
while ( 1 ) {
if ( msg_badread ) {
2000-05-10 11:29:38 +00:00
Con_Printf ( " SV_ReadClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
2000-12-08 06:51:37 +00:00
}
2000-05-10 11:29:38 +00:00
c = MSG_ReadByte ( ) ;
if ( c = = - 1 )
2000-12-08 06:51:37 +00:00
return ; // Ender: Patched :)
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
switch ( c ) {
default :
Con_Printf ( " SV_ReadClientMessage: unknown command char \n " ) ;
SV_DropClient ( cl ) ;
return ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
case clc_nop :
break ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
case clc_delta :
cl - > delta_sequence = MSG_ReadByte ( ) ;
break ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
case clc_move :
if ( move_issued )
return ; // someone is trying to cheat...
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
move_issued = true ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
checksumIndex = MSG_GetReadCount ( ) ;
checksum = ( byte ) MSG_ReadByte ( ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
// read loss percentage
cl - > lossage = MSG_ReadByte ( ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
MSG_ReadDeltaUsercmd ( & nullcmd , & oldest ) ;
MSG_ReadDeltaUsercmd ( & oldest , & oldcmd ) ;
MSG_ReadDeltaUsercmd ( & oldcmd , & newcmd ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( cl - > state ! = cs_spawned )
break ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +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 ) ;
if ( calculatedChecksum ! = checksum ) {
Con_DPrintf
( " Failed command checksum for %s(%d) (%d != %d) \n " ,
cl - > name , cl - > netchan . incoming_sequence , checksum ,
calculatedChecksum ) ;
return ;
}
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
if ( ! sv . paused ) {
SV_PreRunCmd ( ) ;
if ( net_drop < 20 ) {
while ( net_drop > 2 ) {
SV_RunCmd ( & cl - > lastcmd , 0 ) ;
net_drop - - ;
}
if ( net_drop > 1 )
SV_RunCmd ( & oldest , 0 ) ;
if ( net_drop > 0 )
SV_RunCmd ( & oldcmd , 0 ) ;
2000-05-10 11:29:38 +00:00
}
2000-12-08 06:51:37 +00:00
SV_RunCmd ( & newcmd , 0 ) ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
SV_PostRunCmd ( ) ;
}
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
cl - > lastcmd = newcmd ;
cl - > lastcmd . buttons = 0 ; // avoid multiple fires on lag
break ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
case clc_stringcmd :
s = MSG_ReadString ( ) ;
SV_ExecuteUserCommand ( s ) ;
break ;
2000-05-10 11:29:38 +00:00
2000-12-08 06:51:37 +00:00
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 ;
2000-05-10 20:33:16 +00:00
2000-12-08 06:51:37 +00:00
case clc_upload :
SV_NextUpload ( ) ;
break ;
2000-05-10 11:29:38 +00:00
}
}
}
/*
= = = = = = = = = = = = = =
SV_UserInit
= = = = = = = = = = = = = =
*/
2000-12-08 06:51:37 +00:00
void
SV_UserInit ( void )
2000-05-10 11:29:38 +00:00
{
2001-01-08 06:23:10 +00:00
qsort ( ucmds , sizeof ( ucmds ) / sizeof ( ucmds [ 0 ] ) , sizeof ( ucmds [ 0 ] ) ,
ucmds_compare ) ;
2000-12-31 04:46:04 +00:00
cl_rollspeed = Cvar_Get ( " cl_rollspeed " , " 200 " , CVAR_NONE , " How quickly a player straightens out after strafing " ) ;
cl_rollangle = Cvar_Get ( " cl_rollangle " , " 2 " , CVAR_NONE , " How much a player's screen tilts when strafing " ) ;
sv_spectalk = Cvar_Get ( " sv_spectalk " , " 1 " , CVAR_NONE , " Toggles the ability of spectators to talk to players " ) ;
sv_mapcheck = Cvar_Get ( " sv_mapcheck " , " 1 " , CVAR_NONE ,
" Toggle the use of map checksumming to check for players who edit maps to cheat " ) ;
2000-05-10 11:29:38 +00:00
}