rpgxef/code/cgame/cg_servercmds.c
Walter Julius Hennecke a39565b783 Integrated RPG-X2 rpgxEF edition into the rpgxEF repo
... not quite content with where the project files lie but it is ok for
now.
... compiling works fine so far (only tested mingw32 right now)
2012-08-04 12:54:37 +02:00

927 lines
22 KiB
C

// Copyright (C) 1999-2000 Id Software, Inc.
//
// cg_servercmds.c -- reliably sequenced text commands sent by the server
// these are processed at snapshot transition time, so there will definately
// be a valid snapshot this frame
#include "cg_local.h"
#define MAX_LOCAL_ENTITIES 512
extern localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
/*
=================
CG_ParseScores
=================
*/
static void CG_ParseScores( void ) {
int i, powerups, eliminated;
cg.numScores = atoi( CG_Argv( 1 ) );
if ( cg.numScores > MAX_CLIENTS ) {
cg.numScores = MAX_CLIENTS;
}
cg.teamScores[0] = atoi( CG_Argv( 2 ) );
cg.teamScores[1] = atoi( CG_Argv( 3 ) );
memset( cg.scores, 0, sizeof( cg.scores ) );
for ( i = 0 ; i < cg.numScores ; i++ ) {
cg.scores[i].client = atoi( CG_Argv( i * 11+ 4 ) );
cg.scores[i].score = atoi( CG_Argv( i * 11+ 5 ) );
cg.scores[i].ping = atoi( CG_Argv( i * 11+ 6 ) );
cg.scores[i].time = atoi( CG_Argv( i * 11+ 7 ) );
cg.scores[i].scoreFlags = atoi( CG_Argv( i * 11+ 8 ) );
powerups = atoi( CG_Argv( i * 11+ 9 ) );
// cg.scores[i].faveTarget = atoi( CG_Argv( i * 12+ 10) );
// cg.scores[i].faveTargetKills = atoi( CG_Argv( i * 12+ 11) );
cg.scores[i].worstEnemy = atoi( CG_Argv( i * 11+ 10) );
cg.scores[i].worstEnemyKills= atoi( CG_Argv( i * 11+ 11) );
cg.scores[i].faveWeapon = atoi( CG_Argv( i * 11+ 12) );
cg.scores[i].killedCnt = atoi( CG_Argv( i * 11+ 13) );
eliminated = atoi( CG_Argv( i * 11+ 14) );
if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
cg.scores[i].client = 0;
}
cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
cgs.clientinfo[ cg.scores[i].client ].eliminated = eliminated;
}
}
/*
=================
CG_ParseTeamInfo
=================
*/
static void CG_ParseTeamInfo( void ) {
int i;
int client;
numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
client = atoi( CG_Argv( i * 2 + 2 ) ); //6
sortedTeamPlayers[i] = client;
cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 2 + 3 ) ); //6 +
/*cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );*/
}
}
/*
=================
CG_ParseHealthInfo
=================
*/
static void CG_ParseHealthInfo( void ) {
int i;
int client;
int numHealthInfoClients = 0;
numHealthInfoClients = atoi( CG_Argv( 1 ) );
for ( i = 0 ; i < numHealthInfoClients ; i++ ) {
client = atoi( CG_Argv( i * 2 + 2 ) );
cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 2 + 3 ) );
}
}
/*
================
CG_ParseServerinfo
This is called explicitly when the gamestate is first received,
and whenever the server updates any serverinfo flagged cvars
================
*/
void CG_ParseServerinfo( void ) {
const char *info;
char *mapname;
info = CG_ConfigString( CS_SERVERINFO );
cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
cgs.pModAssimilation = atoi( Info_ValueForKey( info, "g_pModAssimilation" ) );
cgs.pModDisintegration = atoi( Info_ValueForKey( info, "g_pModDisintegration" ) );
cgs.pModActionHero = atoi( Info_ValueForKey( info, "g_pModActionHero" ) );
cgs.pModSpecialties = atoi( Info_ValueForKey( info, "g_pModSpecialties" ) );
cgs.pModElimination = atoi( Info_ValueForKey( info, "g_pModElimination" ) );
cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
cgs.ForceClassColor = atoi( Info_ValueForKey( info, "rpg_forceClassColor" ) );
mapname = Info_ValueForKey( info, "mapname" );
Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
//RPG-X: TiM - new Rankset
Q_strncpyz( cgs.rankSet, Info_ValueForKey( info, "rpg_rankSet"), sizeof(cgs.rankSet) );
//RPG-X: TiM - new Class set
Q_strncpyz( cgs.classSet, Info_ValueForKey( info, "rpg_classSet" ), sizeof( cgs.classSet ) );
//scannable panels
cgs.scannablePanels = atoi( Info_ValueForKey( info, "rpg_scannablePanels" ) );
}
/*
==================
CG_ParseWarmup
==================
*/
static void CG_ParseWarmup( void ) {
const char *info;
int warmup;
info = CG_ConfigString( CS_WARMUP );
warmup = atoi( info );
cg.warmupCount = -1;
if ( warmup == 0 && cg.warmup ) {
} else if ( warmup > 0 && cg.warmup <= 0 ) {
trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
}
cg.warmup = warmup;
}
/*
================
CG_SetConfigValues
Called on load to set the initial values from configure strings
================
*/
void CG_SetConfigValues( void ) {
const char *s;
cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
s = CG_ConfigString( CS_FLAGSTATUS );
cgs.redflag = s[0] - '0';
cgs.blueflag = s[1] - '0';
cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
}
/*
=====================
CG_ClientShakeCamera
TiM: Parses the cam shake
config string, and inputs the useful
data.
=====================
*/
void CG_ClientShakeCamera ( void ) {
float intensity;
int duration;
char *str;
str = (char *)CG_ConfigString( CS_CAMERA_SHAKE );
intensity = (float)atoi( COM_Parse( &str ) )/10.0f;
duration = atoi( COM_Parse( &str ) ); //This is an offset so if a player somehow received
//the string halfway thru the cycle (ie just connected etc)
//This way, it'll only do it as much as is left for the rest of the players
cg.shake_serverIndex = duration; //Back up the index for later
duration -= ( cg.time - cgs.levelStartTime ); //This is the actual duration, based off of length, and the time the command was received
CG_CameraShake( intensity, duration, qtrue );
}
/*
==================
CG_ParseClassData
==================
*/
/*void CG_ParseClassData( void )
{
char *str;
int i;
char *val;
char *lineChar;
char *lineCharEnd;
int colorBits;
int classBits;
str = (char *)CG_ConfigString( CS_CLASS_DATA );
if ( !str[0] )
return;
memset( &cgs.classData, 0, sizeof( cgs.classData ) );
for ( i = 0; i < MAX_CLASSES; i++ ) {
val = Info_ValueForKey( str, va( "c%i", i ) );
if (!val[0])
break;
//First slash = consoleName, so skip that
lineChar = strstr( val, "|");
lineChar++;
//next line should be formal name
lineCharEnd = strstr( lineChar, "|" );
lineCharEnd--;
val = lineChar;
val[ strlen(lineChar) - strlen(lineCharEnd) + 1] = '\0';
Q_strncpyz( cgs.classData[i].formalName, val, sizeof( cgs.classData[i].formalName ) );
//CG_Printf( S_COLOR_RED "%s\n", cgs.classData[i].formalName );
//--Next is color
lineChar = lineChar + (strlen(lineChar) - strlen(lineCharEnd))+2;
lineCharEnd = strstr( lineChar, "|" );
lineCharEnd--;
val = lineChar;
val[ strlen(lineChar) - strlen(lineCharEnd)+1] = '\0';
colorBits=atoi( val );
cgs.classData[i].radarColor[0] = colorBits & 255;
cgs.classData[i].radarColor[1] = (colorBits >> 8) & 255;
cgs.classData[i].radarColor[2] = (colorBits >> 16) & 255;
//CG_Printf( S_COLOR_RED "%i\n", colorBits );
//cgs.classData[i].showRanks = (colorBits >> 25) & 1;
//--Next is Rank Icon Color
lineChar = lineCharEnd+2;
classBits = atoi( lineChar );
cgs.classData[i].isMedic = ( classBits >> 1 ) & 1;
cgs.classData[i].showRanks = ( classBits >> 2 ) & 1;
cgs.classData[i].iconColor = ( classBits >> 4 ) & 15;
//CG_Printf( S_COLOR_RED "%i\n", classBits );
}
}*/
/*
================
CG_ConfigStringModified
================
*/
static void CG_ConfigStringModified( void ) {
const char *str;
int num;
num = atoi( CG_Argv( 1 ) );
// get the gamestate from the client system, which will have the
// new configstring already integrated
trap_GetGameState( &cgs.gameState );
// look up the individual string that was modified
str = CG_ConfigString( num );
// do something with it if necessary
if ( num == CS_MUSIC ) {
CG_StartMusic();
} else if ( num == CS_CAMERA_SHAKE ) { //RPG-X : TiM - Camera Shake
CG_ClientShakeCamera();
} else if ( num == CS_SERVERINFO ) {
CG_ParseServerinfo();
} else if ( num == CS_WARMUP ) {
CG_ParseWarmup();
} else if ( num == CS_SCORES1 ) {
cgs.scores1 = atoi( str );
} else if ( num == CS_SCORES2 ) {
cgs.scores2 = atoi( str );
} else if ( num == CS_WARMUP ) {
CG_ParseWarmup();
} else if ( num == CS_LEVEL_START_TIME ) {
cgs.levelStartTime = atoi( str );
} else if ( num == CS_VOTE_TIME ) {
cgs.voteTime = atoi( str );
cgs.voteModified = qtrue;
} else if ( num == CS_VOTE_YES ) {
cgs.voteYes = atoi( str );
cgs.voteModified = qtrue;
} else if ( num == CS_VOTE_NO ) {
cgs.voteNo = atoi( str );
cgs.voteModified = qtrue;
} else if ( num == CS_VOTE_STRING ) {
Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
} else if ( num == CS_INTERMISSION ) {
cg.intermissionStarted = atoi( str );
} else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
} else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
if ( str[0] != '*' ) { // player specific sounds don't register here
cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str );
}
} else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
CG_NewClientInfo( num - CS_PLAYERS );
} else if ( num >= CS_DECOYS && num < CS_DECOYS+MAX_DECOYS ) {
CG_NewDecoyInfo( num - CS_DECOYS );
} else if ( num == CS_FLAGSTATUS ) {
// format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
cgs.redflag = str[0] - '0';
cgs.blueflag = str[1] - '0';
}
else if(num == CS_SHADERSTATE) {
CG_ShaderStateChanged();
}
}
/*
=======================
CG_AddToTeamChat
=======================
*/
static void CG_AddToTeamChat( const char *str ) {
int len;
char *p, *ls;
int lastcolor;
int chatHeight;
if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
chatHeight = cg_teamChatHeight.integer;
} else {
chatHeight = TEAMCHAT_HEIGHT;
}
if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
// team chat disabled, dump into normal chat
cgs.teamChatPos = cgs.teamLastChatPos = 0;
return;
}
len = 0;
p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
*p = 0;
lastcolor = '7';
ls = NULL;
while (*str) {
if (len > TEAMCHAT_WIDTH - 1) {
if (ls) {
str -= (p - ls);
str++;
p -= (p - ls);
}
*p = 0;
cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
cgs.teamChatPos++;
p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
*p = 0;
*p++ = Q_COLOR_ESCAPE;
*p++ = lastcolor;
len = 0;
ls = NULL;
}
if ( Q_IsColorString( str ) ) {
*p++ = *str++;
lastcolor = *str;
*p++ = *str++;
continue;
}
if (*str == ' ') {
ls = p;
}
*p++ = *str++;
len++;
}
*p = 0;
cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
cgs.teamChatPos++;
if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
}
/*
===============
CG_MapRestart
The server has issued a map_restart, so the next snapshot
is completely new and should not be interpolated to.
A tournement restart will clear everything, but doesn't
require a reload of all the media
===============
*/
static void CG_MapRestart( void ) {
if ( cg_showmiss.integer ) {
CG_Printf( "CG_MapRestart\n" );
}
CG_InitLocalEntities();
CG_InitMarkPolys();
// make sure the "3 frags left" warnings play again
cg.fraglimitWarnings = 0;
cg.timelimitWarnings = 0;
cg.intermissionStarted = qfalse;
cgs.voteTime = 0;
CG_StartMusic();
// we really should clear more parts of cg here and stop sounds
// play the "fight" sound if this is a restart without warmup
if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */)
{
trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
}
}
/***********************
CG_EncodeIDFile
The server detected that
we have a pure copy of
the ID, so it's sent us
the IP it received so we
can byte encrypt it into
an ID and save it to file
***********************/
static void CG_EncodeIDFile( void )
{
unsigned int playerID;
char *IP;
char strSubnet[3];
int intSubnet[4];
int i, j;
memset(strSubnet, 0, sizeof(strSubnet));
IP = (char *)CG_Argv( 1 );
//IP = "143.163.12.2";
//TiM - Scooter's IP List
//Double-check we're not spawning an ID off of these
if( Q_stricmp( IP, "localhost" ) //localhost
&& Q_strncmp( IP, "10.", 3 ) //class A
&& Q_strncmp( IP, "172.16.", 7 ) //class B
&& Q_strncmp( IP, "192.168.", 8 ) //class C
&& Q_strncmp( IP, "127.", 4 ) //loopback
&& Q_strncmp( IP, "169.254.", 8 ) //link-local
)
{
return;
}
//check we don't already have an ID
if ( (unsigned)atoul( sv_securityCode.string ) != SECURITY_PID )
return;
i = 0;
j = 0;
while ( *IP )
{
if( *IP != '.' )
{
if ( i < 3 )
strSubnet[i++] = *IP;
}
else
{
if ( j < 4 )
intSubnet[j++] = atoi( strSubnet );
i=0;
memset( strSubnet, 0, 3 );
}
IP++;
}
//the final cell
intSubnet[j++] = atoi( strSubnet );
//calculate the key
playerID = ( intSubnet[3] << 24 ) | ( intSubnet[2] << 16 ) | ( intSubnet[1] << 8 ) | intSubnet[0];
//CG_Printf( "%i %i %i %i - %u\n", intSubnet[0], intSubnet[1], intSubnet[2], intSubnet[3], playerID );
//encode the information into the id key file
{
fileHandle_t f;
//unsigned char buffer[SECURITY_SIZE];
int fileLen;
rpgxSecurityFile_t sF;
fileLen = trap_FS_FOpenFile( SECURITY_FILE, &f, FS_READ );
if ( !f || fileLen != SECURITY_SIZE )
{
CG_Error( "ERROR: Could not validate %s file.\n", SECURITY_FILE );
return;
}
trap_FS_Read( &sF, SECURITY_SIZE, f );
trap_FS_FCloseFile( f );
if ( !sF.ID || sF.ID != SECURITY_ID )
{
CG_Error( "ERROR: %s was loaded, but it wasn't valid.\n", SECURITY_FILE );
return;
}
//ensure the hash is valid
if ( sF.hash != atoul( sv_securityHash.string ) )
{
CG_Error( "ERROR: %s was loaded, but the hash wasn't valid.\n", SECURITY_FILE );
return;
}
//okay, reopen the file for writing, and input the new ID
f = 0;
fileLen = trap_FS_FOpenFile( SECURITY_FILE, &f, FS_WRITE );
if ( !f )
{
CG_Error( "ERROR: Could not validate %s file for writing.\n", SECURITY_FILE );
return;
}
//copy over the new key
sF.playerID = playerID;
trap_FS_Write( &sF, SECURITY_SIZE, f );
trap_FS_FCloseFile( f );
}
trap_Cvar_Set( "sv_SecurityCode", va( "%u", playerID ) );
}
/*
==================
ConcatArgs
==================
*/
char *ConcatArgs2( int start ) {
int i, c, tlen;
static char line[MAX_STRING_CHARS];
int len;
char arg[MAX_STRING_CHARS];
len = 0;
c = trap_Argc();
for ( i = start ; i < c ; i++ ) {
trap_Argv( i, arg, sizeof( arg ) );
tlen = strlen( arg );
if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
break;
}
memcpy( line + len, arg, tlen );
len += tlen;
if ( i != c - 1 ) {
line[len] = ' ';
len++;
}
}
line[len] = 0;
return line;
}
/*
=====================
CG_ShaderStateChanged
=====================
*/
void CG_ShaderStateChanged(void) {
char originalShader[MAX_QPATH];
char newShader[MAX_QPATH];
char timeOffset[16];
const char *o;
char *n,*t;
o = CG_ConfigString( CS_SHADERSTATE );
if(!o) return;
while (o && *o) {
n = strstr(o, "=");
if (n && *n) {
strncpy(originalShader, o, n-o);
originalShader[n-o] = 0;
n++;
t = strstr(n, ":");
if (t && *t) {
strncpy(newShader, n, t-n);
newShader[t-n] = 0;
} else {
break;
}
t++;
o = strstr(t, "@");
if (o) {
strncpy(timeOffset, t, o-t);
timeOffset[o-t] = 0;
o++;
trap_R_RemapShader( originalShader, newShader, timeOffset );
}
} else {
break;
}
}
}
/*
=================
CG_ServerCommand
The string has been tokenized and can be retrieved with
Cmd_Argc() / Cmd_Argv()
=================
*/
static void CG_ServerCommand( void ) {
const char *cmd;
cmd = CG_Argv(0);
if ( !cmd[0] ) {
// server claimed the command
return;
}
//RPG-X | Phenix | 13/02/2005
// Play a insult to the n00b when moved into n00b class
if ( !strcmp( cmd, "playN00bInsult") ) {
trap_S_StartLocalSound( cgs.media.N00bSound[(rand()%N00bSoundCount)], CHAN_LOCAL_SOUND );
CG_CenterPrint( "Welcome to the n00b Class", SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
return;
}
// RPG-X | Phenix | 08/06/05
if ( !strcmp( cmd, "servermsg") ) {
trap_S_StartLocalSound( cgs.media.AdminMsgSound, CHAN_LOCAL_SOUND );
cg.adminMsgTime = cg.time + 10000;
Q_strncpyz( cg.adminMsgMsg, ConcatArgs2(1), sizeof( cg.adminMsgMsg ) );
//CG_CenterPrint( cg.adminMsgMsg, SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
return;
}
if( !strcmp( cmd, "servercprint") ) {
trap_S_StartLocalSound( cgs.media.AdminMsgSound, CHAN_LOCAL_SOUND );
//cg.adminMsgTime = cg.time + 10000;
Q_strncpyz( cg.adminMsgMsg, ConcatArgs2(1), sizeof( cg.adminMsgMsg ) );
CG_CenterPrint( cg.adminMsgMsg, SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
return;
}
if ( !strcmp( cmd, "cp" ) ) {
CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
return;
}
if ( !strcmp( cmd, "cs" ) ) {
CG_ConfigStringModified();
return;
}
if ( !strcmp( cmd, "print" ) ) {
CG_Printf( "%s", CG_Argv(1) );
return;
}
if ( !strcmp( cmd, "chat" ) ) {
trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
CG_Printf( "%s\n", CG_Argv(1) );
return;
}
if ( !strcmp( cmd, "pc" ) ) {
trap_Cvar_Set("ui_playerClass", CG_Argv(1));
return;
}
if ( !strcmp( cmd, "prank" ) ) {
trap_Cvar_Set("ui_playerRank", CG_Argv(1));
return;
}
/*if ( !strcmp( cmd, "cr" ) ) {
trap_Cvar_VariableStringBuffer( "ui_playerclass", pClass, sizeof(pClass) );
trap_Cvar_VariableStringBuffer( "ui_playerrank", pRank, sizeof(pRank) );
if ( !strcmp( pClass, "maker" ) || !strcmp( pClass, "alphaomega22" ) ) {
trap_SendClientCommand( "class command" );
trap_SendClientCommand( va( "rank %s", pRank) );
}
trap_SendClientCommand( va( "class %s", pClass) );
trap_SendClientCommand( va( "rank %s", pRank) );
return;
}*/
if ( !strcmp( cmd, "tchat" ) ) {
trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
CG_AddToTeamChat( CG_Argv(1) );
CG_Printf( "%s\n", CG_Argv(1) );
return;
}
if ( !strcmp( cmd, "scores" ) ) {
CG_ParseScores();
return;
}
if ( !strcmp( cmd, "awards" ) ) {
AW_SPPostgameMenu_f();
return;
}
if ( !strcmp( cmd, "tinfo" ) ) {
CG_ParseTeamInfo();
return;
}
if ( !strcmp( cmd, "hinfo" ) ) {
CG_ParseHealthInfo();
return;
}
if ( !strcmp( cmd, "map_restart" ) ) {
CG_MapRestart();
return;
}
//TiM: Purge all active effects
if ( !strcmp( cmd, "cg_flushFX" ) ) {
int i;
for ( i = 0; i < MAX_LOCAL_ENTITIES; i ++ ) {
cg_localEntities[i].endTime = cg.time;
}
return;
}
/*if ( !strcmp( cmd, "cg_flushAngles" ) ) {
//CG_ResetPlayerEntity( &cg.predictedPlayerEntity ); //&cg_entities[ cg.predictedPlayerState.clientNum ]
cg_entities[cg.predictedPlayerState.clientNum].pe.torso.yawAngle = cg_entities[cg.predictedPlayerState.clientNum].lerpAngles[YAW];
cg_entities[cg.predictedPlayerState.clientNum].pe.legs.yawAngle = cg_entities[cg.predictedPlayerState.clientNum].lerpAngles[YAW];
return;
}*/
// loaddeferred can be both a servercmd and a consolecmd
if ( !strcmp( cmd, "loaddeferred" ) ) { // FIXME: spelled wrong, but not changing for demo
CG_LoadDeferredPlayers();
return;
}
// clientLevelShot is sent before taking a special screenshot for
// the menu system during development
if ( !strcmp( cmd, "clientLevelShot" ) ) {
cg.levelShot = qtrue;
return;
}
//TiM - client received a command from a turbolift ent
//Show the decks UI
if ( !strcmp( cmd, "lift" ) ) {
trap_SendConsoleCommand( va( "ui_turbolift %i", CG_Argv( 1 ) ) );
return;
}
//The server motd thingzor
//RPG-X | Marcin | 15/12/2008
if ( !strcmp( cmd, "motd" ) ) {
trap_SendConsoleCommand( "ui_motd_reset\n" );
trap_SendConsoleCommand( "ui_motd\n" );
return;
}
//RPG-X | Marcin | 15/12/2008
if ( !strcmp( cmd, "motd_line" ) ) {
trap_SendConsoleCommand( va( "ui_motd_line \"%s\"\n", CG_Argv( 1 ) ) );
return;
}
if ( !strcmp( cmd, "configID" ) )
{
CG_EncodeIDFile();
return;
}
if ( !strcmp( cmd, "changeClientInfo" ) )
{
//create local copy of the args
//due to the way CG_Argv works
char arg1[64];
char arg2[64];
Q_strncpyz( arg1, CG_Argv(1), sizeof(arg1) );
Q_strncpyz( arg2, CG_Argv(2), sizeof(arg2) );
trap_Cvar_Set( arg1, arg2 );
return;
}
if ( !strcmp( cmd, "playSnd" ) )
{
trap_SendConsoleCommand( va( "play %s", CG_Argv(1) ) );
return;
}
if ( !strcmp( cmd, "cg_connect" ) ) {
trap_SendConsoleCommand( va( "connect %s", CG_Argv(1) ) );
return;
}
if ( Q_stricmp (cmd, "remapShader") == 0 )
{
if (trap_Argc() == 4)
{
char shader1[MAX_QPATH];
char shader2[MAX_QPATH];
char shader3[MAX_QPATH];
Q_strncpyz(shader1, CG_Argv(1), sizeof(shader1));
Q_strncpyz(shader2, CG_Argv(2), sizeof(shader2));
Q_strncpyz(shader3, CG_Argv(3), sizeof(shader3));
trap_R_RemapShader(shader1, shader2, shader3);
}
return;
}
if(!strcmp(cmd, "ui_transporter")) {
trap_SendConsoleCommand(va("ui_transporter %s", CG_Argv(1)));
return;
}
if(!strcmp(cmd, "ui_trdata")) {
trap_SendConsoleCommand(va("ui_trdata \"%s\"", CG_Argv(1)));
return;
}
if(!strcmp(cmd, "holo_data")) {
trap_SendConsoleCommand(va("holo_data \"%s\"", CG_Argv(1)));
return;
}
if(!strcmp(cmd, "ui_holodeck")) {
trap_SendClientCommand(va("ui_holodeck %i", CG_Argv(1)));
return;
}
/* TODO remove me? */
if(!strcmp(cmd, "sqlkey")) {
trap_SendClientCommand(va("sqlkey %i", CG_Argv(1)));
return;
}
CG_Printf( "Unknown client game command: %s\n", cmd );
}
/*
====================
CG_ExecuteNewServerCommands
Execute all of the server commands that were received along
with this this snapshot.
====================
*/
void CG_ExecuteNewServerCommands( int latestSequence ) {
while ( cgs.serverCommandSequence < latestSequence ) {
if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
CG_ServerCommand();
}
}
}