summaryrefslogtreecommitdiff
path: root/src/game/g_cmds.c.orig
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_cmds.c.orig')
-rw-r--r--src/game/g_cmds.c.orig3588
1 files changed, 0 insertions, 3588 deletions
diff --git a/src/game/g_cmds.c.orig b/src/game/g_cmds.c.orig
deleted file mode 100644
index 5a30f7b..0000000
--- a/src/game/g_cmds.c.orig
+++ /dev/null
@@ -1,3588 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2009 Darklegion Development
-
-This file is part of Tremulous.
-
-Tremulous 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.
-
-Tremulous is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "g_local.h"
-
-/*
-==================
-G_SanitiseString
-
-Remove color codes and non-alphanumeric characters from a string
-==================
-*/
-void G_SanitiseString( char *in, char *out, int len )
-{
- len--;
-
- while( *in && len > 0 )
- {
- if( Q_IsColorString( in ) )
- {
- in += 2; // skip color code
- continue;
- }
-
- if( isalnum( *in ) )
- {
- *out++ = tolower( *in );
- len--;
- }
- in++;
- }
- *out = 0;
-}
-
-/*
-==================
-G_ClientNumberFromString
-
-Returns a player number for either a number or name string
-Returns -1 and optionally sets err if invalid or not exactly 1 match
-err will have a trailing \n if set
-==================
-*/
-int G_ClientNumberFromString( char *s, char *err, int len )
-{
- gclient_t *cl;
- int i, found = 0, m = -1;
- char s2[ MAX_NAME_LENGTH ];
- char n2[ MAX_NAME_LENGTH ];
- char *p = err;
- int l, l2 = len;
-
- if( !s[ 0 ] )
- {
- if( p )
- Q_strncpyz( p, "no player name or slot # provided\n", len );
-
- return -1;
- }
-
- // numeric values are just slot numbers
- for( i = 0; s[ i ] && isdigit( s[ i ] ); i++ );
- if( !s[ i ] )
- {
- i = atoi( s );
-
- if( i < 0 || i >= level.maxclients )
- return -1;
-
- cl = &level.clients[ i ];
-
- if( cl->pers.connected == CON_DISCONNECTED )
- {
- if( p )
- Q_strncpyz( p, "no player connected in that slot #\n", len );
-
- return -1;
- }
-
- return i;
- }
-
- G_SanitiseString( s, s2, sizeof( s2 ) );
- if( !s2[ 0 ] )
- {
- if( p )
- Q_strncpyz( p, "no player name provided\n", len );
-
- return -1;
- }
-
- if( p )
- {
- Q_strncpyz( p, "more than one player name matches. "
- "be more specific or use the slot #:\n", l2 );
- l = strlen( p );
- p += l;
- l2 -= l;
- }
-
- // check for a name match
- for( i = 0, cl = level.clients; i < level.maxclients; i++, cl++ )
- {
- if( cl->pers.connected == CON_DISCONNECTED )
- continue;
-
- G_SanitiseString( cl->pers.netname, n2, sizeof( n2 ) );
-
- if( !strcmp( n2, s2 ) )
- return i;
-
- if( strstr( n2, s2 ) )
- {
- if( p )
- {
- l = Q_snprintf( p, l2, "%-2d - %s^7\n", i, cl->pers.netname );
- p += l;
- l2 -= l;
- }
-
- found++;
- m = i;
- }
- }
-
- if( found == 1 )
- return m;
-
- if( found == 0 && err )
- Q_strncpyz( err, "no connected player by that name or slot #\n", len );
-
- return -1;
-}
-
-/*
-==================
-G_ClientNumbersFromString
-
-Sets plist to an array of integers that represent client numbers that have
-names that are a partial match for s.
-
-Returns number of matching clientids up to max.
-==================
-*/
-int G_ClientNumbersFromString( char *s, int *plist, int max )
-{
- gclient_t *p;
- int i, found = 0;
- char *endptr;
- char n2[ MAX_NAME_LENGTH ] = {""};
- char s2[ MAX_NAME_LENGTH ] = {""};
-
- if( max == 0 )
- return 0;
-
- if( !s[ 0 ] )
- return 0;
-
- // if a number is provided, it is a clientnum
- i = strtol( s, &endptr, 10 );
- if( *endptr == '\0' )
- {
- if( i >= 0 && i < level.maxclients )
- {
- p = &level.clients[ i ];
- if( p->pers.connected != CON_DISCONNECTED )
- {
- *plist = i;
- return 1;
- }
- }
- // we must assume that if only a number is provided, it is a clientNum
- return 0;
- }
-
- // now look for name matches
- G_SanitiseString( s, s2, sizeof( s2 ) );
- if( !s2[ 0 ] )
- return 0;
- for( i = 0; i < level.maxclients && found < max; i++ )
- {
- p = &level.clients[ i ];
- if( p->pers.connected == CON_DISCONNECTED )
- {
- continue;
- }
- G_SanitiseString( p->pers.netname, n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- *plist++ = i;
- found++;
- }
- }
- return found;
-}
-
-/*
-==================
-ScoreboardMessage
-
-==================
-*/
-void ScoreboardMessage( gentity_t *ent )
-{
- char entry[ 1024 ];
- char string[ 1400 ];
- int stringlength;
- int i, j;
- gclient_t *cl;
- int numSorted;
- weapon_t weapon = WP_NONE;
- upgrade_t upgrade = UP_NONE;
-
- // send the latest information on all clients
- string[ 0 ] = 0;
- stringlength = 0;
-
- numSorted = level.numConnectedClients;
-
- for( i = 0; i < numSorted; i++ )
- {
- int ping;
-
- cl = &level.clients[ level.sortedClients[ i ] ];
-
- if( cl->pers.connected == CON_CONNECTING )
- ping = -1;
- else
- ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
-
- if( cl->sess.spectatorState == SPECTATOR_NOT &&
- ( ent->client->pers.teamSelection == TEAM_NONE ||
- cl->pers.teamSelection == ent->client->pers.teamSelection ) )
- {
- weapon = cl->ps.weapon;
-
- if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, cl->ps.stats ) )
- upgrade = UP_BATTLESUIT;
- else if( BG_InventoryContainsUpgrade( UP_JETPACK, cl->ps.stats ) )
- upgrade = UP_JETPACK;
- else if( BG_InventoryContainsUpgrade( UP_BATTPACK, cl->ps.stats ) )
- upgrade = UP_BATTPACK;
- else if( BG_InventoryContainsUpgrade( UP_HELMET_MK1, cl->ps.stats ) )
- upgrade = UP_HELMET_MK1;
- else if( BG_InventoryContainsUpgrade( UP_HELMET_MK2, cl->ps.stats ) )
- upgrade = UP_HELMET_MK2;
- else if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, cl->ps.stats ) )
- upgrade = UP_LIGHTARMOUR;
- else
- upgrade = UP_NONE;
- }
- else
- {
- weapon = WP_NONE;
- upgrade = UP_NONE;
- }
-
- Com_sprintf( entry, sizeof( entry ),
- " %d %d %d %d %d %d", level.sortedClients[ i ], cl->ps.persistant[ PERS_SCORE ],
- ping, ( level.time - cl->pers.enterTime ) / 60000, weapon, upgrade );
-
- j = strlen( entry );
-
- if( stringlength + j >= 1024 )
- break;
-
- strcpy( string + stringlength, entry );
- stringlength += j;
- }
-
- trap_SendServerCommand( ent-g_entities, va( "scores %i %i%s",
- level.alienKills, level.humanKills, string ) );
-}
-
-
-/*
-==================
-ConcatArgs
-==================
-*/
-char *ConcatArgs( 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( len == MAX_STRING_CHARS - 1 )
- break;
-
- if( i != c - 1 )
- {
- line[ len ] = ' ';
- len++;
- }
- }
-
- line[ len ] = 0;
-
- return line;
-}
-
-/*
-==================
-ConcatArgsPrintable
-Duplicate of concatargs but enquotes things that need to be
-Used to log command arguments in a way that preserves user intended tokenizing
-==================
-*/
-char *ConcatArgsPrintable( int start )
-{
- int i, c, tlen;
- static char line[ MAX_STRING_CHARS ];
- int len;
- char arg[ MAX_STRING_CHARS + 2 ];
- char *printArg;
-
- len = 0;
- c = trap_Argc( );
-
- for( i = start; i < c; i++ )
- {
- printArg = arg;
- trap_Argv( i, arg, sizeof( arg ) );
- if( strchr( arg, ' ' ) )
- printArg = va( "\"%s\"", arg );
- tlen = strlen( printArg );
-
- if( len + tlen >= MAX_STRING_CHARS - 1 )
- break;
-
- memcpy( line + len, printArg, tlen );
- len += tlen;
-
- if( len == MAX_STRING_CHARS - 1 )
- break;
-
- if( i != c - 1 )
- {
- line[ len ] = ' ';
- len++;
- }
- }
-
- line[ len ] = 0;
-
- return line;
-}
-
-
-/*
-==================
-Cmd_Give_f
-
-Give items to a client
-==================
-*/
-void Cmd_Give_f( gentity_t *ent )
-{
- char *name;
- qboolean give_all = qfalse;
-
- if( trap_Argc( ) < 2 )
- {
- ADMP( "usage: give [what]\n" );
- ADMP( "usage: valid choices are: all, health, funds [amount], stamina, "
- "poison, gas, ammo\n" );
- return;
- }
-
- name = ConcatArgs( 1 );
- if( Q_stricmp( name, "all" ) == 0 )
- give_all = qtrue;
-
- if( give_all || Q_stricmp( name, "health" ) == 0 )
- {
- ent->health = ent->client->ps.stats[ STAT_MAX_HEALTH ];
- BG_AddUpgradeToInventory( UP_MEDKIT, ent->client->ps.stats );
- }
-
- if( give_all || Q_stricmpn( name, "funds", 5 ) == 0 )
- {
- float credits;
-
- if( give_all || trap_Argc( ) < 3 )
- credits = 30000.0f;
- else
- {
- credits = atof( name + 6 ) *
- ( ent->client->pers.teamSelection ==
- TEAM_ALIENS ? ALIEN_CREDITS_PER_KILL : 1.0f );
-
- // clamp credits manually, as G_AddCreditToClient() expects a short int
- if( credits > SHRT_MAX )
- credits = 30000.0f;
- else if( credits < SHRT_MIN )
- credits = -30000.0f;
- }
-
- G_AddCreditToClient( ent->client, (short)credits, qtrue );
- }
-
- if( give_all || Q_stricmp( name, "stamina" ) == 0 )
- ent->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
-
- if( Q_stricmp( name, "poison" ) == 0 )
- {
- if( ent->client->pers.teamSelection == TEAM_HUMANS )
- {
- ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
- ent->client->lastPoisonTime = level.time;
- ent->client->lastPoisonClient = ent;
- }
- else
- {
- ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- ent->client->boostedTime = level.time;
- }
- }
-
- if( Q_stricmp( name, "gas" ) == 0 )
- {
- ent->client->ps.eFlags |= EF_POISONCLOUDED;
- ent->client->lastPoisonCloudedTime = level.time;
- trap_SendServerCommand( ent->client->ps.clientNum,
- "poisoncloud" );
- }
-
- if( give_all || Q_stricmp( name, "ammo" ) == 0 )
- {
- gclient_t *client = ent->client;
-
- if( client->ps.weapon != WP_ALEVEL3_UPG &&
- BG_Weapon( client->ps.weapon )->infiniteAmmo )
- return;
-
- client->ps.ammo = BG_Weapon( client->ps.weapon )->maxAmmo;
- client->ps.clips = BG_Weapon( client->ps.weapon )->maxClips;
-
- if( BG_Weapon( client->ps.weapon )->usesEnergy &&
- BG_InventoryContainsUpgrade( UP_BATTPACK, client->ps.stats ) )
- client->ps.ammo = (int)( (float)client->ps.ammo * BATTPACK_MODIFIER );
- }
-
- if( give_all || Q_stricmp( name, "fuel" ) == 0 )
- {
- if( BG_InventoryContainsUpgrade( UP_JETPACK, ent->client->ps.stats ) )
- ent->client->ps.stats[ STAT_FUEL ] = JETPACK_FUEL_FULL;
- }
-}
-
-
-/*
-==================
-Cmd_God_f
-
-Sets client to godmode
-
-argv(0) god
-==================
-*/
-void Cmd_God_f( gentity_t *ent )
-{
- char *msg;
-
- ent->flags ^= FL_GODMODE;
-
- if( !( ent->flags & FL_GODMODE ) )
- msg = "godmode OFF\n";
- else
- msg = "godmode ON\n";
-
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
-}
-
-
-/*
-==================
-Cmd_Notarget_f
-
-Sets client to notarget
-
-argv(0) notarget
-==================
-*/
-void Cmd_Notarget_f( gentity_t *ent )
-{
- char *msg;
-
- ent->flags ^= FL_NOTARGET;
-
- if( !( ent->flags & FL_NOTARGET ) )
- msg = "notarget OFF\n";
- else
- msg = "notarget ON\n";
-
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
-}
-
-
-/*
-==================
-Cmd_Noclip_f
-
-argv(0) noclip
-==================
-*/
-void Cmd_Noclip_f( gentity_t *ent )
-{
- char *msg;
-
- if( ent->client->noclip )
- msg = "noclip OFF\n";
- else
- msg = "noclip ON\n";
-
- ent->client->noclip = !ent->client->noclip;
-
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
-}
-
-
-/*
-==================
-Cmd_LevelShot_f
-
-This is just to help generate the level pictures
-for the menus. It goes to the intermission immediately
-and sends over a command to the client to resize the view,
-hide the scoreboard, and take a special screenshot
-==================
-*/
-void Cmd_LevelShot_f( gentity_t *ent )
-{
- BeginIntermission( );
- trap_SendServerCommand( ent - g_entities, "clientLevelShot" );
-}
-
-/*
-=================
-Cmd_Kill_f
-=================
-*/
-void Cmd_Kill_f( gentity_t *ent )
-{
- if( g_cheats.integer )
- {
- ent->flags &= ~FL_GODMODE;
- ent->client->ps.stats[ STAT_HEALTH ] = ent->health = 0;
- player_die( ent, ent, ent, 100000, MOD_SUICIDE );
- }
- else
- {
- if( ent->suicideTime == 0 )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You will suicide in 20 seconds\n\"" );
- ent->suicideTime = level.time + 20000;
- }
- else if( ent->suicideTime > level.time )
- {
- trap_SendServerCommand( ent-g_entities, "print \"Suicide cancelled\n\"" );
- ent->suicideTime = 0;
- }
- }
-}
-
-/*
-=================
-Cmd_Team_f
-=================
-*/
-void Cmd_Team_f( gentity_t *ent )
-{
- team_t team;
- team_t oldteam = ent->client->pers.teamSelection;
- char s[ MAX_TOKEN_CHARS ];
- qboolean force = G_admin_permission( ent, ADMF_FORCETEAMCHANGE );
- int aliens = level.numAlienClients;
- int humans = level.numHumanClients;
-
- if( oldteam == TEAM_ALIENS )
- aliens--;
- else if( oldteam == TEAM_HUMANS )
- humans--;
-
- // stop team join spam
- if( ent->client->pers.teamChangeTime &&
- level.time - ent->client->pers.teamChangeTime < 1000 )
- return;
-
- // stop switching teams for gameplay exploit reasons by enforcing a long
- // wait before they can come back
- if( !force && !g_cheats.integer && ent->client->pers.aliveSeconds &&
- level.time - ent->client->pers.teamChangeTime < 30000 )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"You must wait another %d seconds before changing teams again\n\"",
- (int) ( ( 30000 - ( level.time - ent->client->pers.teamChangeTime ) ) / 1000.f ) ) );
- return;
- }
-
- // disallow joining teams during warmup
- if( g_doWarmup.integer && ( ( level.warmupTime - level.time ) / 1000 ) > 0 )
- {
- G_TriggerMenu( ent - g_entities, MN_WARMUP );
- return;
- }
-
- trap_Argv( 1, s, sizeof( s ) );
-
- if( !s[ 0 ] )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"team: %s\n\"",
- BG_TeamName( oldteam ) ) );
- return;
- }
-
- if( !Q_stricmp( s, "auto" ) )
- {
- if( level.humanTeamLocked && level.alienTeamLocked )
- team = TEAM_NONE;
- else if( level.humanTeamLocked || humans > aliens )
- team = TEAM_ALIENS;
-
- else if( level.alienTeamLocked || aliens > humans )
- team = TEAM_HUMANS;
- else
- team = TEAM_ALIENS + rand( ) / ( RAND_MAX / 2 + 1 );
- }
- else switch( G_TeamFromString( s ) )
- {
- case TEAM_NONE:
- team = TEAM_NONE;
- break;
-
- case TEAM_ALIENS:
- if( level.alienTeamLocked )
- {
- G_TriggerMenu( ent - g_entities, MN_A_TEAMLOCKED );
- return;
- }
- else if( level.humanTeamLocked )
- force = qtrue;
-
- if( !force && g_teamForceBalance.integer && aliens > humans )
- {
- G_TriggerMenu( ent - g_entities, MN_A_TEAMFULL );
- return;
- }
-
- team = TEAM_ALIENS;
- break;
-
- case TEAM_HUMANS:
- if( level.humanTeamLocked )
- {
- G_TriggerMenu( ent - g_entities, MN_H_TEAMLOCKED );
- return;
- }
- else if( level.alienTeamLocked )
- force = qtrue;
-
- if( !force && g_teamForceBalance.integer && humans > aliens )
- {
- G_TriggerMenu( ent - g_entities, MN_H_TEAMFULL );
- return;
- }
-
- team = TEAM_HUMANS;
- break;
-
- default:
- trap_SendServerCommand( ent-g_entities,
- va( "print \"Unknown team: %s\n\"", s ) );
- return;
- }
-
- // stop team join spam
- if( oldteam == team )
- return;
-
- if( team != TEAM_NONE && g_maxGameClients.integer &&
- level.numPlayingClients >= g_maxGameClients.integer )
- {
- G_TriggerMenu( ent - g_entities, MN_PLAYERLIMIT );
- return;
- }
-
- // Apply the change
- G_ChangeTeam( ent, team );
-}
-
-/*
-==================
-G_CensorString
-==================
-*/
-static char censors[ 20000 ];
-static int numcensors;
-
-void G_LoadCensors( void )
-{
- char *text_p, *token;
- char text[ 20000 ];
- char *term;
- int len;
- fileHandle_t f;
-
- numcensors = 0;
-
- if( !g_censorship.string[ 0 ] )
- return;
-
- len = trap_FS_FOpenFile( g_censorship.string, &f, FS_READ );
- if( len < 0 )
- {
- Com_Printf( S_COLOR_RED "ERROR: Censors file %s doesn't exist\n",
- g_censorship.string );
- return;
- }
- if( len == 0 || len >= sizeof( text ) - 1 )
- {
- trap_FS_FCloseFile( f );
- Com_Printf( S_COLOR_RED "ERROR: Censors file %s is %s\n",
- g_censorship.string, len == 0 ? "empty" : "too long" );
- return;
- }
- trap_FS_Read( text, len, f );
- trap_FS_FCloseFile( f );
- text[ len ] = 0;
-
- term = censors;
-
- text_p = text;
- while( 1 )
- {
- token = COM_Parse( &text_p );
- if( !*token || sizeof( censors ) - ( term - censors ) < 4 )
- break;
- Q_strncpyz( term, token, sizeof( censors ) - ( term - censors ) );
- Q_strlwr( term );
- term += strlen( term ) + 1;
- if( sizeof( censors ) - ( term - censors ) == 0 )
- break;
- token = COM_ParseExt( &text_p, qfalse );
- Q_strncpyz( term, token, sizeof( censors ) - ( term - censors ) );
- term += strlen( term ) + 1;
- numcensors++;
- }
- G_Printf( "Parsed %d string replacements\n", numcensors );
-}
-
-void G_CensorString( char *out, const char *in, int len, gentity_t *ent )
-{
- const char *s, *m;
- int i;
-
- if( !numcensors || G_admin_permission( ent, ADMF_NOCENSORFLOOD) )
- {
- Q_strncpyz( out, in, len );
- return;
- }
-
- len--;
- while( *in )
- {
- if( Q_IsColorString( in ) )
- {
- if( len < 2 )
- break;
- *out++ = *in++;
- *out++ = *in++;
- len -= 2;
- continue;
- }
- if( !isalnum( *in ) )
- {
- if( len < 1 )
- break;
- *out++ = *in++;
- len--;
- continue;
- }
- m = censors;
- for( i = 0; i < numcensors; i++, m++ )
- {
- s = in;
- while( *s && *m )
- {
- if( Q_IsColorString( s ) )
- {
- s += 2;
- continue;
- }
- if( !isalnum( *s ) )
- {
- s++;
- continue;
- }
- if( tolower( *s ) != *m )
- break;
- s++;
- m++;
- }
- // match
- if( !*m )
- {
- in = s;
- m++;
- while( *m )
- {
- if( len < 1 )
- break;
- *out++ = *m++;
- len--;
- }
- break;
- }
- else
- {
- while( *m )
- m++;
- m++;
- while( *m )
- m++;
- }
- }
- if( len < 1 )
- break;
- // no match
- if( i == numcensors )
- {
- *out++ = *in++;
- len--;
- }
- }
- *out = 0;
-}
-
-/*
-==================
-G_Say
-==================
-*/
-static qboolean G_SayTo( gentity_t *ent, gentity_t *other, saymode_t mode, const char *message )
-{
- if( !other )
- return qfalse;
-
- if( !other->inuse )
- return qfalse;
-
- if( !other->client )
- return qfalse;
-
- if( other->client->pers.connected != CON_CONNECTED )
- return qfalse;
-
- if( ( ent && !OnSameTeam( ent, other ) ) &&
- ( mode == SAY_TEAM || mode == SAY_AREA || mode == SAY_TPRIVMSG ) )
- {
- if( other->client->pers.teamSelection != TEAM_NONE )
- return qfalse;
-
- // specs with ADMF_SPEC_ALLCHAT flag can see team chat
- if( !G_admin_permission( other, ADMF_SPEC_ALLCHAT ) && mode != SAY_TPRIVMSG )
- return qfalse;
- }
-
- trap_SendServerCommand( other-g_entities, va( "chat %d %d \"%s\"",
- ent ? ent-g_entities : -1,
- mode,
- message ) );
-
- return qtrue;
-}
-
-void G_Say( gentity_t *ent, saymode_t mode, const char *chatText )
-{
- int j;
- gentity_t *other;
- // don't let text be too long for malicious reasons
- char text[ MAX_SAY_TEXT ];
-
- // check if blocked by g_specChat 0
- if( ( !g_specChat.integer ) && ( mode != SAY_TEAM ) &&
- ( ent ) && ( ent->client->pers.teamSelection == TEAM_NONE ) &&
- ( !G_admin_permission( ent, ADMF_NOCENSORFLOOD ) ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"say: Global chatting for "
- "spectators has been disabled. You may only use team chat.\n\"" );
- mode = SAY_TEAM;
- }
-
- switch( mode )
- {
- case SAY_ALL:
- G_LogPrintf( "Say: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_GREEN "%s\n",
- ( ent ) ? ent - g_entities : -1,
- ( ent ) ? ent->client->pers.netname : "console", chatText );
- break;
- case SAY_TEAM:
- // console say_team is handled in g_svscmds, not here
- if( !ent || !ent->client )
- Com_Error( ERR_FATAL, "SAY_TEAM by non-client entity\n" );
- G_LogPrintf( "SayTeam: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_CYAN "%s\n",
- ent - g_entities, ent->client->pers.netname, chatText );
- break;
- case SAY_RAW:
- if( ent )
- Com_Error( ERR_FATAL, "SAY_RAW by client entity\n" );
- G_LogPrintf( "Chat: -1 \"console\": %s\n", chatText );
- default:
- break;
- }
-
- G_CensorString( text, chatText, sizeof( text ), ent );
-
- // send it to all the apropriate clients
- for( j = 0; j < level.maxclients; j++ )
- {
- other = &g_entities[ j ];
- G_SayTo( ent, other, mode, text );
- }
-}
-
-/*
-==================
-Cmd_SayArea_f
-==================
-*/
-static void Cmd_SayArea_f( gentity_t *ent )
-{
- int entityList[ MAX_GENTITIES ];
- int num, i;
- vec3_t range = { 1000.0f, 1000.0f, 1000.0f };
- vec3_t mins, maxs;
- char *msg;
-
- if( trap_Argc( ) < 2 )
- {
- ADMP( "usage: say_area [message]\n" );
- return;
- }
-
- msg = ConcatArgs( 1 );
-
- for(i = 0; i < 3; i++ )
- range[ i ] = g_sayAreaRange.value;
-
- G_LogPrintf( "SayArea: %d \"%s" S_COLOR_WHITE "\": " S_COLOR_BLUE "%s\n",
- ent - g_entities, ent->client->pers.netname, msg );
-
- VectorAdd( ent->s.origin, range, maxs );
- VectorSubtract( ent->s.origin, range, mins );
-
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- G_SayTo( ent, &g_entities[ entityList[ i ] ], SAY_AREA, msg );
-
- //Send to ADMF_SPEC_ALLCHAT candidates
- for( i = 0; i < level.maxclients; i++ )
- {
- if( g_entities[ i ].client->pers.teamSelection == TEAM_NONE &&
- G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) )
- {
- G_SayTo( ent, &g_entities[ i ], SAY_AREA, msg );
- }
- }
-}
-
-
-/*
-==================
-Cmd_Say_f
-==================
-*/
-static void Cmd_Say_f( gentity_t *ent )
-{
- char *p;
- char cmd[ MAX_TOKEN_CHARS ];
- saymode_t mode = SAY_ALL;
-
- if( trap_Argc( ) < 2 )
- return;
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
- if( Q_stricmp( cmd, "say_team" ) == 0 )
- mode = SAY_TEAM;
-
- p = ConcatArgs( 1 );
-
- G_Say( ent, mode, p );
-}
-
-/*
-==================
-Cmd_VSay_f
-==================
-*/
-void Cmd_VSay_f( gentity_t *ent )
-{
- char arg[MAX_TOKEN_CHARS];
- char text[ MAX_TOKEN_CHARS ];
- voiceChannel_t vchan;
- voice_t *voice;
- voiceCmd_t *cmd;
- voiceTrack_t *track;
- int cmdNum = 0;
- int trackNum = 0;
- char voiceName[ MAX_VOICE_NAME_LEN ] = {"default"};
- char voiceCmd[ MAX_VOICE_CMD_LEN ] = {""};
- char vsay[ 12 ] = {""};
- weapon_t weapon;
-
- if( !ent || !ent->client )
- Com_Error( ERR_FATAL, "Cmd_VSay_f() called by non-client entity\n" );
-
- trap_Argv( 0, arg, sizeof( arg ) );
- if( trap_Argc( ) < 2 )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"usage: %s command [text] \n\"", arg ) );
- return;
- }
- if( !level.voices )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"%s: voice system is not installed on this server\n\"", arg ) );
- return;
- }
- if( !g_voiceChats.integer )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"%s: voice system administratively disabled on this server\n\"",
- arg ) );
- return;
- }
- if( !Q_stricmp( arg, "vsay" ) )
- vchan = VOICE_CHAN_ALL;
- else if( !Q_stricmp( arg, "vsay_team" ) )
- vchan = VOICE_CHAN_TEAM;
- else if( !Q_stricmp( arg, "vsay_local" ) )
- vchan = VOICE_CHAN_LOCAL;
- else
- return;
- Q_strncpyz( vsay, arg, sizeof( vsay ) );
-
- if( ent->client->pers.voice[ 0 ] )
- Q_strncpyz( voiceName, ent->client->pers.voice, sizeof( voiceName ) );
- voice = BG_VoiceByName( level.voices, voiceName );
- if( !voice )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"%s: voice '%s' not found\n\"", vsay, voiceName ) );
- return;
- }
-
- trap_Argv( 1, voiceCmd, sizeof( voiceCmd ) ) ;
- cmd = BG_VoiceCmdFind( voice->cmds, voiceCmd, &cmdNum );
- if( !cmd )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"%s: command '%s' not found in voice '%s'\n\"",
- vsay, voiceCmd, voiceName ) );
- return;
- }
-
- // filter non-spec humans by their primary weapon as well
- weapon = WP_NONE;
- if( ent->client->sess.spectatorState == SPECTATOR_NOT )
- {
- weapon = BG_PrimaryWeapon( ent->client->ps.stats );
- }
-
- track = BG_VoiceTrackFind( cmd->tracks, ent->client->pers.teamSelection,
- ent->client->pers.classSelection, weapon, (int)ent->client->voiceEnthusiasm,
- &trackNum );
- if( !track )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"%s: no available track for command '%s', team %d, "
- "class %d, weapon %d, and enthusiasm %d in voice '%s'\n\"",
- vsay, voiceCmd, ent->client->pers.teamSelection,
- ent->client->pers.classSelection, weapon,
- (int)ent->client->voiceEnthusiasm, voiceName ) );
- return;
- }
-
- if( !Q_stricmp( ent->client->lastVoiceCmd, cmd->cmd ) )
- ent->client->voiceEnthusiasm++;
-
- Q_strncpyz( ent->client->lastVoiceCmd, cmd->cmd,
- sizeof( ent->client->lastVoiceCmd ) );
-
- // optional user supplied text
- trap_Argv( 2, arg, sizeof( arg ) );
- G_CensorString( text, arg, sizeof( text ), ent );
-
- switch( vchan )
- {
- case VOICE_CHAN_ALL:
- case VOICE_CHAN_LOCAL:
- trap_SendServerCommand( -1, va(
- "voice %d %d %d %d \"%s\"\n",
- ent-g_entities, vchan, cmdNum, trackNum, text ) );
- break;
- case VOICE_CHAN_TEAM:
- G_TeamCommand( ent->client->pers.teamSelection, va(
- "voice %d %d %d %d \"%s\"\n",
- ent-g_entities, vchan, cmdNum, trackNum, text ) );
- break;
- default:
- break;
- }
-}
-
-/*
-==================
-Cmd_Where_f
-==================
-*/
-void Cmd_Where_f( gentity_t *ent )
-{
- if( !ent->client )
- return;
- trap_SendServerCommand( ent - g_entities,
- va( "print \"origin: %f %f %f\n\"",
- ent->s.origin[ 0 ], ent->s.origin[ 1 ],
- ent->s.origin[ 2 ] ) );
-}
-
-/*
-==================
-Cmd_CallVote_f
-==================
-*/
-void Cmd_CallVote_f( gentity_t *ent )
-{
- char cmd[ MAX_TOKEN_CHARS ],
- vote[ MAX_TOKEN_CHARS ],
- arg[ MAX_TOKEN_CHARS ];
- char name[ MAX_NAME_LENGTH ] = "";
- char caller[ MAX_NAME_LENGTH ] = "";
- char reason[ MAX_TOKEN_CHARS ];
- char *creason;
- int clientNum = -1;
- int id = -1;
- team_t team;
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
- trap_Argv( 1, vote, sizeof( vote ) );
- trap_Argv( 2, arg, sizeof( arg ) );
- creason = ConcatArgs( 3 );
- G_DecolorString( creason, reason, sizeof( reason ) );
-
- if( !Q_stricmp( cmd, "callteamvote" ) )
- team = ent->client->pers.teamSelection;
- else
- team = TEAM_NONE;
-
- if( !g_allowVote.integer )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: voting not allowed here\n\"", cmd ) );
- return;
- }
-
- if( level.voteTime[ team ] )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: a vote is already in progress\n\"", cmd ) );
- return;
- }
-
- if( level.voteExecuteTime[ team ] )
- G_ExecuteVote( team );
-
- level.voteDelay[ team ] = 0;
- level.voteThreshold[ team ] = 50;
-
- if( g_voteLimit.integer > 0 &&
- ent->client->pers.namelog->voteCount >= g_voteLimit.integer &&
- !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) )
- {
- trap_SendServerCommand( ent-g_entities, va(
- "print \"%s: you have already called the maximum number of votes (%d)\n\"",
- cmd, g_voteLimit.integer ) );
- return;
- }
-
- // kick, mute, unmute, denybuild, allowbuild
- if( !Q_stricmp( vote, "kick" ) ||
- !Q_stricmp( vote, "mute" ) || !Q_stricmp( vote, "unmute" ) ||
- !Q_stricmp( vote, "denybuild" ) || !Q_stricmp( vote, "allowbuild" ) )
- {
- char err[ MAX_STRING_CHARS ];
-
- if( !arg[ 0 ] )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: no target\n\"", cmd ) );
- return;
- }
-
- // with a little extra work only players from the right team are considered
- clientNum = G_ClientNumberFromString( arg, err, sizeof( err ) );
-
- if( clientNum == -1 )
- {
- ADMP( va( "%s: %s", cmd, err ) );
- return;
- }
-
- G_DecolorString( level.clients[ clientNum ].pers.netname, name, sizeof( name ) );
- id = level.clients[ clientNum ].pers.namelog->id;
-
- if( !Q_stricmp( vote, "kick" ) || !Q_stricmp( vote, "mute" ) ||
- !Q_stricmp( vote, "denybuild" ) )
- {
- if( G_admin_permission( g_entities + clientNum, ADMF_IMMUNITY ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: admin is immune\n\"", cmd ) );
-
- G_AdminMessage( NULL, va( S_COLOR_WHITE "%s" S_COLOR_YELLOW " attempted %s %s"
- " on immune admin " S_COLOR_WHITE "%s" S_COLOR_YELLOW
- " for: %s",
- ent->client->pers.netname, cmd, vote,
- g_entities[ clientNum ].client->pers.netname,
- reason[ 0 ] ? reason : "no reason" ) );
- return;
- }
-
- if( team != TEAM_NONE &&
- ( ent->client->pers.teamSelection !=
- level.clients[ clientNum ].pers.teamSelection ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: player is not on your team\n\"", cmd ) );
- return;
- }
-
- if( !reason[ 0 ] && !G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: You must provide a reason\n\"", cmd ) );
- return;
- }
- }
- }
-
- if( !Q_stricmp( vote, "kick" ) )
- {
- if( level.clients[ clientNum ].pers.localClient )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: admin is immune\n\"", cmd ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "ban %s \"1s%s\" vote kick (%s)", level.clients[ clientNum ].pers.ip.str,
- g_adminTempBan.string, reason );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ), "Kick player '%s'", name );
- if( reason[ 0 ] )
- {
- Q_strcat( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ), va( " for '%s'", reason ) );
- }
- }
- else if( team == TEAM_NONE )
- {
- if( !Q_stricmp( vote, "mute" ) )
- {
- if( level.clients[ clientNum ].pers.namelog->muted )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: player is already muted\n\"", cmd ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "mute %d", id );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Mute player '%s'", name );
- if( reason[ 0 ] )
- {
- Q_strcat( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ), va( " for '%s'", reason ) );
- }
- }
- else if( !Q_stricmp( vote, "unmute" ) )
- {
- if( !level.clients[ clientNum ].pers.namelog->muted )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: player is not currently muted\n\"", cmd ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "unmute %d", id );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Unmute player '%s'", name );
- }
- else if( !Q_stricmp( vote, "map_restart" ) )
- {
- strcpy( level.voteString[ team ], vote );
- strcpy( level.voteDisplayString[ team ], "Restart current map" );
- // map_restart comes with a default delay
- }
- else if( !Q_stricmp( vote, "map" ) )
- {
- if( !G_MapExists( arg ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: 'maps/%s.bsp' could not be found on the server\n\"",
- cmd, arg ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString ),
- "%s \"%s\"", vote, arg );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Change to map '%s'", arg );
- level.voteDelay[ team ] = 3000;
- }
- else if( !Q_stricmp( vote, "nextmap" ) )
- {
- if( G_MapExists( g_nextMap.string ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: the next map is already set to '%s'\n\"",
- cmd, g_nextMap.string ) );
- return;
- }
-
- if( !G_MapExists( arg ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: 'maps/%s.bsp' could not be found on the server\n\"",
- cmd, arg ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "set g_nextMap \"%s\"", arg );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Set the next map to '%s'", arg );
- }
- else if( !Q_stricmp( vote, "draw" ) )
- {
- strcpy( level.voteString[ team ], "evacuation" );
- strcpy( level.voteDisplayString[ team ], "End match in a draw" );
- level.voteDelay[ team ] = 3000;
- }
- else if( !Q_stricmp( vote, "sudden_death" ) )
- {
- if(!g_suddenDeathVotePercent.integer)
- {
- trap_SendServerCommand( ent-g_entities,
- "print \"Sudden Death votes have been disabled\n\"" );
- return;
- }
- if( G_TimeTilSuddenDeath( ) <= 0 )
- {
- trap_SendServerCommand( ent - g_entities,
- va( "print \"callvote: Sudden Death has already begun\n\"") );
- return;
- }
- if( level.suddenDeathBeginTime > 0 &&
- G_TimeTilSuddenDeath() <= g_suddenDeathVoteDelay.integer * 1000 )
- {
- trap_SendServerCommand( ent - g_entities,
- va( "print \"callvote: Sudden Death is imminent\n\"") );
- return;
- }
- level.voteThreshold[ team ] = g_suddenDeathVotePercent.integer;
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "suddendeath %d", g_suddenDeathVoteDelay.integer );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Begin sudden death in %d seconds",
- g_suddenDeathVoteDelay.integer );
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Valid vote commands are: "
- "map, nextmap, map_restart, draw, sudden_death, kick, mute and unmute\n" );
- return;
- }
- }
- else if( !Q_stricmp( vote, "denybuild" ) )
- {
- if( level.clients[ clientNum ].pers.namelog->denyBuild )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: player already lost building rights\n\"", cmd ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "denybuild %d", id );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Take away building rights from '%s'", name );
- if( reason[ 0 ] )
- {
- Q_strcat( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ), va( " for '%s'", reason ) );
- }
- }
- else if( !Q_stricmp( vote, "allowbuild" ) )
- {
- if( !level.clients[ clientNum ].pers.namelog->denyBuild )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: player already has building rights\n\"", cmd ) );
- return;
- }
-
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "allowbuild %d", id );
- Com_sprintf( level.voteDisplayString[ team ],
- sizeof( level.voteDisplayString[ team ] ),
- "Allow '%s' to build", name );
- }
- else if( !Q_stricmp( vote, "admitdefeat" ) )
- {
- Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ),
- "admitdefeat %d", team );
- strcpy( level.voteDisplayString[ team ], "Admit Defeat" );
- level.voteDelay[ team ] = 3000;
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
- trap_SendServerCommand( ent-g_entities,
- "print \"Valid team vote commands are: "
- "kick, denybuild, allowbuild and admitdefeat\n\"" );
- return;
- }
-
- G_LogPrintf( "%s: %d \"%s" S_COLOR_WHITE "\": %s\n",
- team == TEAM_NONE ? "CallVote" : "CallTeamVote",
- ent - g_entities, ent->client->pers.netname, level.voteString[ team ] );
-
- if( team == TEAM_NONE )
- {
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE
- " called a vote: %s\n\"", ent->client->pers.netname,
- level.voteDisplayString[ team ] ) );
- }
- else
- {
- int i;
-
- for( i = 0 ; i < level.maxclients ; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_CONNECTED )
- {
- if( level.clients[ i ].pers.teamSelection == team ||
- ( level.clients[ i ].pers.teamSelection == TEAM_NONE &&
- G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) ) )
- {
- trap_SendServerCommand( i, va( "print \"%s" S_COLOR_WHITE
- " called a team vote: %s\n\"", ent->client->pers.netname,
- level.voteDisplayString[ team ] ) );
- }
- else if( G_admin_permission( &g_entities[ i ], ADMF_ADMINCHAT ) )
- {
- trap_SendServerCommand( i, va( "chat -1 %d \"" S_COLOR_YELLOW "%s"
- S_COLOR_YELLOW " called a team vote (%ss): %s\"", SAY_ADMINS,
- ent->client->pers.netname, BG_TeamName( team ),
- level.voteDisplayString[ team ] ) );
- }
- }
- }
- }
-
- G_DecolorString( ent->client->pers.netname, caller, sizeof( caller ) );
-
- level.voteTime[ team ] = level.time;
- trap_SetConfigstring( CS_VOTE_TIME + team,
- va( "%d", level.voteTime[ team ] ) );
- trap_SetConfigstring( CS_VOTE_STRING + team,
- level.voteDisplayString[ team ] );
- trap_SetConfigstring( CS_VOTE_CALLER + team,
- caller );
-
- ent->client->pers.namelog->voteCount++;
- ent->client->pers.vote |= 1 << team;
- G_Vote( ent, team, qtrue );
-}
-
-/*
-==================
-Cmd_Vote_f
-==================
-*/
-void Cmd_Vote_f( gentity_t *ent )
-{
- char cmd[ MAX_TOKEN_CHARS ], vote[ MAX_TOKEN_CHARS ];
- team_t team = ent->client->pers.teamSelection;
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
- if( Q_stricmp( cmd, "teamvote" ) )
- team = TEAM_NONE;
-
- if( !level.voteTime[ team ] )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: no vote in progress\n\"", cmd ) );
- return;
- }
-
- if( ent->client->pers.voted & ( 1 << team ) )
- {
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: vote already cast\n\"", cmd ) );
- return;
- }
-
- trap_SendServerCommand( ent-g_entities,
- va( "print \"%s: vote cast\n\"", cmd ) );
-
- trap_Argv( 1, vote, sizeof( vote ) );
- if( vote[ 0 ] == 'y' )
- ent->client->pers.vote |= 1 << team;
- else
- ent->client->pers.vote &= ~( 1 << team );
- G_Vote( ent, team, qtrue );
-}
-
-
-/*
-=================
-Cmd_SetViewpos_f
-=================
-*/
-void Cmd_SetViewpos_f( gentity_t *ent )
-{
- vec3_t origin, angles;
- char buffer[ MAX_TOKEN_CHARS ];
- int i;
-
- if( trap_Argc( ) != 5 )
- {
- trap_SendServerCommand( ent-g_entities, "print \"usage: setviewpos x y z yaw\n\"" );
- return;
- }
-
- VectorClear( angles );
-
- for( i = 0; i < 3; i++ )
- {
- trap_Argv( i + 1, buffer, sizeof( buffer ) );
- origin[ i ] = atof( buffer );
- }
-
- trap_Argv( 4, buffer, sizeof( buffer ) );
- angles[ YAW ] = atof( buffer );
-
- TeleportPlayer( ent, origin, angles );
-}
-
-#define AS_OVER_RT3 ((ALIENSENSE_RANGE*0.5f)/M_ROOT3)
-
-static qboolean G_RoomForClassChange( gentity_t *ent, class_t class,
- vec3_t newOrigin )
-{
- vec3_t fromMins, fromMaxs;
- vec3_t toMins, toMaxs;
- vec3_t temp;
- trace_t tr;
- float nudgeHeight;
- float maxHorizGrowth;
- class_t oldClass = ent->client->ps.stats[ STAT_CLASS ];
-
- BG_ClassBoundingBox( oldClass, fromMins, fromMaxs, NULL, NULL, NULL );
- BG_ClassBoundingBox( class, toMins, toMaxs, NULL, NULL, NULL );
-
- VectorCopy( ent->s.origin, newOrigin );
-
- // find max x/y diff
- maxHorizGrowth = toMaxs[ 0 ] - fromMaxs[ 0 ];
- if( toMaxs[ 1 ] - fromMaxs[ 1 ] > maxHorizGrowth )
- maxHorizGrowth = toMaxs[ 1 ] - fromMaxs[ 1 ];
- if( toMins[ 0 ] - fromMins[ 0 ] > -maxHorizGrowth )
- maxHorizGrowth = -( toMins[ 0 ] - fromMins[ 0 ] );
- if( toMins[ 1 ] - fromMins[ 1 ] > -maxHorizGrowth )
- maxHorizGrowth = -( toMins[ 1 ] - fromMins[ 1 ] );
-
- if( maxHorizGrowth > 0.0f )
- {
- // test by moving the player up the max required on a 60 degree slope
- nudgeHeight = maxHorizGrowth * 2.0f;
- }
- else
- {
- // player is shrinking, so there's no need to nudge them upwards
- nudgeHeight = 0.0f;
- }
-
- // find what the new origin would be on a level surface
- newOrigin[ 2 ] -= toMins[ 2 ] - fromMins[ 2 ];
-
- //compute a place up in the air to start the real trace
- VectorCopy( newOrigin, temp );
- temp[ 2 ] += nudgeHeight;
- trap_Trace( &tr, newOrigin, toMins, toMaxs, temp, ent->s.number, MASK_PLAYERSOLID );
-
- //trace down to the ground so that we can evolve on slopes
- VectorCopy( newOrigin, temp );
- temp[ 2 ] += ( nudgeHeight * tr.fraction );
- trap_Trace( &tr, temp, toMins, toMaxs, newOrigin, ent->s.number, MASK_PLAYERSOLID );
- VectorCopy( tr.endpos, newOrigin );
-
- //make REALLY sure
- trap_Trace( &tr, newOrigin, toMins, toMaxs, newOrigin,
- ent->s.number, MASK_PLAYERSOLID );
-
- //check there is room to evolve
- return ( !tr.startsolid && tr.fraction == 1.0f );
-}
-
-/*
-=================
-Cmd_Class_f
-=================
-*/
-void Cmd_Class_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- int clientNum;
- int i;
- vec3_t infestOrigin;
- class_t currentClass = ent->client->pers.classSelection;
- class_t newClass;
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { AS_OVER_RT3, AS_OVER_RT3, AS_OVER_RT3 };
- vec3_t mins, maxs;
- int num;
- gentity_t *other;
- int oldBoostTime = -1;
- vec3_t oldVel;
-
- clientNum = ent->client - level.clients;
- trap_Argv( 1, s, sizeof( s ) );
- newClass = BG_ClassByName( s )->number;
-
- if( ent->client->sess.spectatorState != SPECTATOR_NOT )
- {
- if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
- G_StopFollowing( ent );
- if( ent->client->pers.teamSelection == TEAM_ALIENS )
- {
- if( newClass != PCL_ALIEN_BUILDER0 &&
- newClass != PCL_ALIEN_BUILDER0_UPG &&
- newClass != PCL_ALIEN_LEVEL0 )
- {
- G_TriggerMenuArgs( ent->client->ps.clientNum, MN_A_CLASSNOTSPAWN, newClass );
- return;
- }
-
- if( !BG_ClassIsAllowed( newClass ) )
- {
- G_TriggerMenuArgs( ent->client->ps.clientNum, MN_A_CLASSNOTALLOWED, newClass );
- return;
- }
-
- if( !BG_ClassAllowedInStage( newClass, g_alienStage.integer ) )
- {
- G_TriggerMenuArgs( ent->client->ps.clientNum, MN_A_CLASSNOTATSTAGE, newClass );
- return;
- }
-
- // spawn from an egg
- if( G_PushSpawnQueue( &level.alienSpawnQueue, clientNum ) )
- {
- ent->client->pers.classSelection = newClass;
- ent->client->ps.stats[ STAT_CLASS ] = newClass;
- }
- }
- else if( ent->client->pers.teamSelection == TEAM_HUMANS )
- {
- //set the item to spawn with
- if( !Q_stricmp( s, BG_Weapon( WP_MACHINEGUN )->name ) &&
- BG_WeaponIsAllowed( WP_MACHINEGUN ) )
- {
- ent->client->pers.humanItemSelection = WP_MACHINEGUN;
- }
- else if( !Q_stricmp( s, BG_Weapon( WP_HBUILD )->name ) &&
- BG_WeaponIsAllowed( WP_HBUILD ) )
- {
- ent->client->pers.humanItemSelection = WP_HBUILD;
- }
- else
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_UNKNOWNSPAWNITEM );
- return;
- }
- // spawn from a telenode
- if( G_PushSpawnQueue( &level.humanSpawnQueue, clientNum ) )
- {
- ent->client->pers.classSelection = PCL_HUMAN;
- ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN;
- }
- }
- return;
- }
-
- if( ent->health <= 0 )
- return;
-
- if( ent->client->pers.teamSelection == TEAM_ALIENS )
- {
- if( newClass == PCL_NONE )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_UNKNOWNCLASS );
- return;
- }
-
- //if we are not currently spectating, we are attempting evolution
- if( ent->client->pers.classSelection != PCL_NONE )
- {
- int cost;
-
- //check that we have an overmind
- if( !G_Overmind( ) )
- {
- G_TriggerMenu( clientNum, MN_A_NOOVMND_EVOLVE );
- return;
- }
-
- //check there are no humans nearby
- VectorAdd( ent->client->ps.origin, range, maxs );
- VectorSubtract( ent->client->ps.origin, range, mins );
-
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- other = &g_entities[ entityList[ i ] ];
-
- if( ( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
- ( other->s.eType == ET_BUILDABLE && other->buildableTeam == TEAM_HUMANS &&
- other->powered ) )
- {
- trace_t tr;
-
- trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, other->s.origin, ent->client->ps.clientNum, MASK_SOLID );
-
- if( tr.fraction > 0.99f )
- {
- G_TriggerMenu( clientNum, MN_A_TOOCLOSE );
- return;
- }
- }
- }
-
- //check that we are not wallwalking
- if( ent->client->ps.eFlags & EF_WALLCLIMB )
- {
- G_TriggerMenu( clientNum, MN_A_EVOLVEWALLWALK );
- return;
- }
-
- //guard against selling the HBUILD weapons exploit
- if( ent->client->sess.spectatorState == SPECTATOR_NOT &&
- ( currentClass == PCL_ALIEN_BUILDER0 ||
- currentClass == PCL_ALIEN_BUILDER0_UPG ) &&
- ent->client->buildTimer )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_EVOLVEBUILDTIMER );
- return;
- }
-
- cost = BG_ClassCanEvolveFromTo( currentClass, newClass,
- ent->client->pers.credit,
- g_alienStage.integer, 0 );
-
- if( G_RoomForClassChange( ent, newClass, infestOrigin ) )
- {
- if( cost >= 0 )
- {
-
- ent->client->pers.evolveHealthFraction = (float)ent->client->ps.stats[ STAT_HEALTH ] /
- (float)BG_Class( currentClass )->health;
-
- if( ent->client->pers.evolveHealthFraction < 0.0f )
- ent->client->pers.evolveHealthFraction = 0.0f;
- else if( ent->client->pers.evolveHealthFraction > 1.0f )
- ent->client->pers.evolveHealthFraction = 1.0f;
-
- //remove credit
- G_AddCreditToClient( ent->client, -cost, qtrue );
- ent->client->pers.classSelection = newClass;
- ClientUserinfoChanged( clientNum, qfalse );
- VectorCopy( infestOrigin, ent->s.pos.trBase );
- VectorCopy( ent->client->ps.velocity, oldVel );
-
- if( ent->client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
- oldBoostTime = ent->client->boostedTime;
-
- ClientSpawn( ent, ent, ent->s.pos.trBase, ent->s.apos.trBase );
-
- VectorCopy( oldVel, ent->client->ps.velocity );
- if( oldBoostTime > 0 )
- {
- ent->client->boostedTime = oldBoostTime;
- ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- }
- }
- else
- G_TriggerMenuArgs( clientNum, MN_A_CANTEVOLVE, newClass );
- }
- else
- G_TriggerMenu( clientNum, MN_A_NOEROOM );
- }
- }
- else if( ent->client->pers.teamSelection == TEAM_HUMANS )
- G_TriggerMenu( clientNum, MN_H_DEADTOCLASS );
-}
-
-
-/*
-=================
-Cmd_Destroy_f
-=================
-*/
-void Cmd_Destroy_f( gentity_t *ent )
-{
- vec3_t viewOrigin, forward, end;
- trace_t tr;
- gentity_t *traceEnt;
- char cmd[ 12 ];
- qboolean deconstruct = qtrue;
- qboolean lastSpawn = qfalse;
-
- if( ent->client->pers.namelog->denyBuild )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_REVOKED );
- return;
- }
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
- if( Q_stricmp( cmd, "destroy" ) == 0 )
- deconstruct = qfalse;
-
- BG_GetClientViewOrigin( &ent->client->ps, viewOrigin );
- AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
- VectorMA( viewOrigin, 100, forward, end );
-
- trap_Trace( &tr, viewOrigin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
- traceEnt = &g_entities[ tr.entityNum ];
-
- if( tr.fraction < 1.0f &&
- ( traceEnt->s.eType == ET_BUILDABLE ) &&
- ( traceEnt->buildableTeam == ent->client->pers.teamSelection ) &&
- ( ( ent->client->ps.weapon >= WP_ABUILD ) &&
- ( ent->client->ps.weapon <= WP_HBUILD ) ) )
- {
- // Always let the builder prevent the explosion
- if( traceEnt->health <= 0 )
- {
- G_QueueBuildPoints( traceEnt );
- G_RewardAttackers( traceEnt );
- G_FreeEntity( traceEnt );
- return;
- }
-
- // Cancel deconstruction (unmark)
- if( deconstruct && g_markDeconstruct.integer && traceEnt->deconstruct )
- {
- traceEnt->deconstruct = qfalse;
- return;
- }
-
- // Prevent destruction of the last spawn
- if( ent->client->pers.teamSelection == TEAM_ALIENS &&
- traceEnt->s.modelindex == BA_A_SPAWN )
- {
- if( level.numAlienSpawns <= 1 )
- lastSpawn = qtrue;
- }
- else if( ent->client->pers.teamSelection == TEAM_HUMANS &&
- traceEnt->s.modelindex == BA_H_SPAWN )
- {
- if( level.numHumanSpawns <= 1 )
- lastSpawn = qtrue;
- }
-
- if( lastSpawn && !g_cheats.integer &&
- !g_markDeconstruct.integer )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_LASTSPAWN );
- return;
- }
-
- // Don't allow destruction of buildables that cannot be rebuilt
- if( G_TimeTilSuddenDeath( ) <= 0 )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_SUDDENDEATH );
- return;
- }
-
- if( !g_markDeconstruct.integer ||
- ( ent->client->pers.teamSelection == TEAM_HUMANS &&
- !G_FindPower( traceEnt, qtrue ) ) )
- {
- if( ent->client->buildTimer )
- {
- G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum );
- return;
- }
- }
-
- if( traceEnt->health > 0 )
- {
- if( !deconstruct )
- {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- traceEnt->health, 0, MOD_SUICIDE );
- }
- else if( g_markDeconstruct.integer &&
- ( ent->client->pers.teamSelection != TEAM_HUMANS ||
- G_FindPower( traceEnt , qtrue ) || lastSpawn ) )
- {
- traceEnt->deconstruct = qtrue; // Mark buildable for deconstruction
- traceEnt->deconstructTime = level.time;
- }
- else
- {
- if( !g_cheats.integer && !g_instantBuild.integer ) // add a bit to the build timer
- {
- ent->client->buildTimer +=
- BG_Buildable( traceEnt->s.modelindex, traceEnt->cuboidSize )->buildTime / 4;
- G_RecalcBuildTimer(ent->client);
- }
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- traceEnt->health, 0, MOD_DECONSTRUCT );
- G_FreeEntity( traceEnt );
- }
- }
- }
-}
-
-/*
-=================
-Cmd_ActivateItem_f
-
-Activate an item
-=================
-*/
-void Cmd_ActivateItem_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- int upgrade, weapon;
-
- trap_Argv( 1, s, sizeof( s ) );
-
- // "weapon" aliased to whatever weapon you have
- if( !Q_stricmp( "weapon", s ) )
- {
- if( ent->client->ps.weapon == WP_BLASTER &&
- BG_PlayerCanChangeWeapon( &ent->client->ps ) )
- G_ForceWeaponChange( ent, WP_NONE );
- return;
- }
-
- upgrade = BG_UpgradeByName( s )->number;
- weapon = BG_WeaponByName( s )->number;
-
- if( upgrade != UP_NONE && BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
- BG_ActivateUpgrade( upgrade, ent->client->ps.stats );
- else if( weapon != WP_NONE &&
- BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
- {
- if( ent->client->ps.weapon != weapon &&
- BG_PlayerCanChangeWeapon( &ent->client->ps ) )
- G_ForceWeaponChange( ent, weapon );
- }
- else
- trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
-}
-
-
-/*
-=================
-Cmd_DeActivateItem_f
-
-Deactivate an item
-=================
-*/
-void Cmd_DeActivateItem_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- upgrade_t upgrade;
-
- trap_Argv( 1, s, sizeof( s ) );
- upgrade = BG_UpgradeByName( s )->number;
-
- if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
- {
- BG_DeactivateUpgrade( upgrade, ent->client->ps.stats );
- if( upgrade == UP_JETPACK )
- BG_AddPredictableEventToPlayerstate( EV_JETPACK_DEACTIVATE, 0, &ent->client->ps );
- }
- else
- trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
-}
-
-
-/*
-=================
-Cmd_ToggleItem_f
-=================
-*/
-void Cmd_ToggleItem_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- weapon_t weapon;
- upgrade_t upgrade;
-
- trap_Argv( 1, s, sizeof( s ) );
- upgrade = BG_UpgradeByName( s )->number;
- weapon = BG_WeaponByName( s )->number;
-
- if( weapon != WP_NONE )
- {
- if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
- return;
-
- //special case to allow switching between
- //the blaster and the primary weapon
- if( ent->client->ps.weapon != WP_BLASTER )
- weapon = WP_BLASTER;
- else
- weapon = WP_NONE;
-
- G_ForceWeaponChange( ent, weapon );
- }
- else if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
- {
- if( BG_UpgradeIsActive( upgrade, ent->client->ps.stats ) )
- {
- BG_DeactivateUpgrade( upgrade, ent->client->ps.stats );
- if( upgrade == UP_JETPACK )
- BG_AddPredictableEventToPlayerstate( EV_JETPACK_DEACTIVATE, 0, &ent->client->ps );
- }
- else
- BG_ActivateUpgrade( upgrade, ent->client->ps.stats );
- }
- else
- trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
-}
-
-/*
-=================
-Cmd_Buy_f
-=================
-*/
-void Cmd_Buy_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- weapon_t weapon;
- upgrade_t upgrade;
- qboolean energyOnly, sellHelmet = qfalse;
-
- trap_Argv( 1, s, sizeof( s ) );
-
- weapon = BG_WeaponByName( s )->number;
- upgrade = BG_UpgradeByName( s )->number;
-
- if( upgrade == UP_NONE && !Q_stricmp(s, "helmet") )
- {
- if( g_humanStage.integer < S2 )
- upgrade = UP_HELMET_MK1;
- else
- upgrade = UP_HELMET_MK2;
- sellHelmet = qtrue;
- }
-
- // Only give energy from reactors or repeaters
- if( G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
- energyOnly = qfalse;
- else if( upgrade == UP_AMMO &&
- BG_Weapon( ent->client->ps.stats[ STAT_WEAPON ] )->usesEnergy &&
- ( G_BuildableRange( ent->client->ps.origin, 100, BA_H_REACTOR ) ||
- G_BuildableRange( ent->client->ps.origin, 100, BA_H_REPEATER ) ) )
- energyOnly = qtrue;
- else
- {
- if( upgrade == UP_AMMO &&
- BG_Weapon( ent->client->ps.weapon )->usesEnergy )
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOENERGYAMMOHERE );
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOARMOURYHERE );
- return;
- }
-
- if( weapon != WP_NONE )
- {
- //already got this?
- if( BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_ITEMHELD );
- return;
- }
-
- // Only humans can buy stuff
- if( BG_Weapon( weapon )->team != TEAM_HUMANS )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't buy alien items\n\"" );
- return;
- }
-
- //are we /allowed/ to buy this?
- if( !BG_Weapon( weapon )->purchasable )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
- return;
- }
-
- //are we /allowed/ to buy this?
- if( !BG_WeaponAllowedInStage( weapon, g_humanStage.integer ) || !BG_WeaponIsAllowed( weapon ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
- return;
- }
-
- //can afford this?
- if( BG_Weapon( weapon )->price > (short)ent->client->pers.credit )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOFUNDS );
- return;
- }
-
- //have space to carry this?
- if( BG_Weapon( weapon )->slots & BG_SlotsForInventory( ent->client->ps.stats ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOSLOTS );
- return;
- }
-
- // In some instances, weapons can't be changed
- if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
- return;
-
- ent->client->ps.stats[ STAT_WEAPON ] = weapon;
- ent->client->ps.ammo = BG_Weapon( weapon )->maxAmmo;
- ent->client->ps.clips = BG_Weapon( weapon )->maxClips;
-
- if( BG_Weapon( weapon )->usesEnergy &&
- BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
- ent->client->ps.ammo *= BATTPACK_MODIFIER;
-
- G_ForceWeaponChange( ent, weapon );
-
- //set build delay/pounce etc to 0
- ent->client->ps.stats[ STAT_MISC ] = 0;
- ent->client->buildTimer = 0;
-
- //subtract from funds
- G_AddCreditToClient( ent->client, -(short)BG_Weapon( weapon )->price, qfalse );
- }
- else if( upgrade != UP_NONE )
- {
- //already got this?
- if( !sellHelmet && BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_ITEMHELD );
- return;
- }
-
- //can afford this?
- if( BG_Upgrade( upgrade )->price > (short)ent->client->pers.credit )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOFUNDS );
- return;
- }
-
- //have space to carry this?
- if( !sellHelmet && BG_Upgrade( upgrade )->slots & BG_SlotsForInventory( ent->client->ps.stats ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOSLOTS );
- return;
- }
-
- // Only humans can buy stuff
- if( BG_Upgrade( upgrade )->team != TEAM_HUMANS )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't buy alien items\n\"" );
- return;
- }
-
- //are we /allowed/ to buy this?
- if( !BG_Upgrade( upgrade )->purchasable )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
- return;
- }
-
- //are we /allowed/ to buy this?
- if( !BG_UpgradeAllowedInStage( upgrade, g_humanStage.integer ) || !BG_UpgradeIsAllowed( upgrade ) )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't buy this item\n\"" );
- return;
- }
-
- if( upgrade == UP_AMMO )
- {
- G_GiveClientMaxAmmo( ent, energyOnly );
- if( !energyOnly && BG_InventoryContainsUpgrade( UP_JETPACK, ent->client->ps.stats ) &&
- ent->client->ps.stats[ STAT_FUEL ] < JETPACK_FUEL_FULL )
- {
- G_AddEvent( ent, EV_JETPACK_REFUEL, 0) ;
- ent->client->ps.stats[ STAT_FUEL ] = JETPACK_FUEL_FULL;
- }
- }
- else
- {
- if( upgrade == UP_BATTLESUIT )
- {
- vec3_t newOrigin;
-
- if( !G_RoomForClassChange( ent, PCL_HUMAN_BSUIT, newOrigin ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITON );
- return;
- }
- VectorCopy( newOrigin, ent->client->ps.origin );
- ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN_BSUIT;
- ent->client->pers.classSelection = PCL_HUMAN_BSUIT;
- ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
- }
- else if( upgrade == UP_JETPACK )
- ent->client->ps.stats[ STAT_FUEL ] = JETPACK_FUEL_FULL;
-
- if( sellHelmet )
- {
- BG_RemoveUpgradeFromInventory( UP_HELMET_MK1, ent->client->ps.stats );
- BG_RemoveUpgradeFromInventory( UP_HELMET_MK2, ent->client->ps.stats );
- }
-
- //add to inventory
- BG_AddUpgradeToInventory( upgrade, ent->client->ps.stats );
- }
-
- if( upgrade == UP_BATTPACK )
- G_GiveClientMaxAmmo( ent, qtrue );
-
- //subtract from funds
- G_AddCreditToClient( ent->client, -(short)BG_Upgrade( upgrade )->price, qfalse );
- }
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_UNKNOWNITEM );
-
- //update ClientInfo
- ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
-}
-
-
-/*
-=================
-Cmd_Sell_f
-=================
-*/
-void Cmd_Sell_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- int i;
- weapon_t weapon;
- upgrade_t upgrade;
-
- trap_Argv( 1, s, sizeof( s ) );
-
- //no armoury nearby
- if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOARMOURYHERE );
- return;
- }
-
- if( !Q_stricmpn( s, "weapon", 6 ) )
- weapon = ent->client->ps.stats[ STAT_WEAPON ];
- else
- weapon = BG_WeaponByName( s )->number;
-
- upgrade = BG_UpgradeByName( s )->number;
-
- if( !upgrade && !Q_stricmp( s, "helmet" ) )
- {
- if( BG_InventoryContainsUpgrade( UP_HELMET_MK1, ent->client->ps.stats ) )
- upgrade = UP_HELMET_MK1;
- else if( BG_InventoryContainsUpgrade( UP_HELMET_MK2, ent->client->ps.stats ) )
- upgrade = UP_HELMET_MK2;
- }
-
- if( weapon != WP_NONE )
- {
- weapon_t selected = BG_GetPlayerWeapon( &ent->client->ps );
-
- if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
- return;
-
- //are we /allowed/ to sell this?
- if( !BG_Weapon( weapon )->purchasable )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't sell this weapon\n\"" );
- return;
- }
-
- //remove weapon if carried
- if( BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
- {
- //guard against selling the HBUILD weapons exploit
- if( weapon == WP_HBUILD && ent->client->buildTimer )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_ARMOURYBUILDTIMER );
- return;
- }
-
- ent->client->ps.stats[ STAT_WEAPON ] = WP_NONE;
- // Cancel ghost buildables
- ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
-
- //add to funds
- G_AddCreditToClient( ent->client, (short)BG_Weapon( weapon )->price, qfalse );
- }
-
- //if we have this weapon selected, force a new selection
- if( weapon == selected )
- G_ForceWeaponChange( ent, WP_NONE );
- }
- else if( upgrade != UP_NONE )
- {
- //are we /allowed/ to sell this?
- if( !BG_Upgrade( upgrade )->purchasable )
- {
- trap_SendServerCommand( ent-g_entities, "print \"You can't sell this item\n\"" );
- return;
- }
- //remove upgrade if carried
- if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
- {
- // shouldn't really need to test for this, but just to be safe
- if( upgrade == UP_BATTLESUIT )
- {
- vec3_t newOrigin;
-
- if( !G_RoomForClassChange( ent, PCL_HUMAN, newOrigin ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITOFF );
- return;
- }
- VectorCopy( newOrigin, ent->client->ps.origin );
- ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN;
- ent->client->pers.classSelection = PCL_HUMAN;
- ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
- }
-
- //add to inventory
- BG_RemoveUpgradeFromInventory( upgrade, ent->client->ps.stats );
-
- if( upgrade == UP_BATTPACK )
- G_GiveClientMaxAmmo( ent, qtrue );
-
- //add to funds
- G_AddCreditToClient( ent->client, (short)BG_Upgrade( upgrade )->price, qfalse );
- }
- }
- else if( !Q_stricmp( s, "weapons" ) )
- {
- weapon_t selected = BG_GetPlayerWeapon( &ent->client->ps );
-
- if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
- return;
-
- for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
- {
- //guard against selling the HBUILD weapons exploit
- if( i == WP_HBUILD && ent->client->buildTimer )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_ARMOURYBUILDTIMER );
- continue;
- }
-
- if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) &&
- BG_Weapon( i )->purchasable )
- {
- ent->client->ps.stats[ STAT_WEAPON ] = WP_NONE;
-
- //add to funds
- G_AddCreditToClient( ent->client, (short)BG_Weapon( i )->price, qfalse );
- }
-
- //if we have this weapon selected, force a new selection
- if( i == selected )
- G_ForceWeaponChange( ent, WP_NONE );
- }
- }
- else if( !Q_stricmp( s, "upgrades" ) )
- {
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- //remove upgrade if carried
- if( BG_InventoryContainsUpgrade( i, ent->client->ps.stats ) &&
- BG_Upgrade( i )->purchasable )
- {
-
- // shouldn't really need to test for this, but just to be safe
- if( i == UP_BATTLESUIT )
- {
- vec3_t newOrigin;
-
- if( !G_RoomForClassChange( ent, PCL_HUMAN, newOrigin ) )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOMBSUITOFF );
- continue;
- }
- VectorCopy( newOrigin, ent->client->ps.origin );
- ent->client->ps.stats[ STAT_CLASS ] = PCL_HUMAN;
- ent->client->pers.classSelection = PCL_HUMAN;
- ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
- }
-
- BG_RemoveUpgradeFromInventory( i, ent->client->ps.stats );
-
- if( i == UP_BATTPACK )
- G_GiveClientMaxAmmo( ent, qtrue );
-
- //add to funds
- G_AddCreditToClient( ent->client, (short)BG_Upgrade( i )->price, qfalse );
- }
- }
- }
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_H_UNKNOWNITEM );
-
- //update ClientInfo
- ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
-}
-
-/*
-=================
-Cmd_CheckCuboidSize
-
-Check if the specified dimensions are valid.
-=================
-*/
-qboolean Cmd_CheckCuboidSize(vec3_t dims)
-{
- if(g_cuboidSizeLimit.integer)
- if(dims[0]>g_cuboidSizeLimit.integer||dims[1]>g_cuboidSizeLimit.integer||dims[2]>g_cuboidSizeLimit.integer)
- return qfalse;
- if(dims[0]*dims[1]*dims[2]<CUBOID_MINVOLUME)
- return qfalse;
- if(dims[0]<1||dims[1]<1||dims[2]<1)
- return qfalse;
- return qtrue;
-}
-
-/*
-=================
-Cmd_Cb_f
-
-Sent by cgame in background (not directly by a person).
-Update player's cuboid selection (after validation) with data sent over network.
-=================
-*/
-void Cmd_Cb_f(gentity_t *ent)
-{
- char s[MAX_TOKEN_CHARS];
- int echo;
- vec3_t dims;
-
- if(trap_Argc()!=5)
- return;
- trap_Argv(1,s,sizeof(s));
- echo=atoi(s);
- trap_Argv(2,s,sizeof(s));
- dims[0]=atof(s);
- trap_Argv(3,s,sizeof(s));
- dims[1]=atof(s);
- trap_Argv(4,s,sizeof(s));
- dims[2]=atof(s);
- if(Cmd_CheckCuboidSize(dims))
- {
- VectorCopy(dims,ent->client->cuboidSelection);
- trap_SendServerCommand(ent->client-level.clients,va("cb3 %i\n",echo));
- G_RelayCuboidToSpectators(ent->client);
- }
- else
- {
- if(Cmd_CheckCuboidSize(ent->client->cuboidSelection))
- trap_SendServerCommand(ent->client-level.clients,va("cb3 %i %f %f %f\n",echo,ent->client->cuboidSelection[0],ent->client->cuboidSelection[1],ent->client->cuboidSelection[2]));
- else
- trap_SendServerCommand(ent->client-level.clients,va("cb3 %i %f %f %f\n",echo,g_cuboidSizeLimit.integer,g_cuboidSizeLimit.integer,g_cuboidSizeLimit.integer));
- }
-}
-
-
-/*
-=================
-Cmd_Build_f
-=================
-*/
-void Cmd_Build_f( gentity_t *ent )
-{
- char s[ MAX_TOKEN_CHARS ];
- buildable_t buildable;
- float dist;
- vec3_t origin, normal;
- team_t team;
- char buf[128];
- vec3_t dims;
-
- if( ent->client->pers.namelog->denyBuild )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_REVOKED );
- return;
- }
-
- if( ent->client->pers.teamSelection == level.surrenderTeam )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_SURRENDER );
- return;
- }
-
- trap_Argv( 1, s, sizeof( s ) );
-
- buildable = BG_BuildableByName( s )->number;
-
- /* To allow players build cuboids with completely arbitrary
- * dimensions (the current resizing method doesn't provide
- * much precision) the build command was extended with the
- * following syntax:
- * build [building] [X] [Y] [Z]
- * where X, Y and Z are respectively the cuboid's length
- * on the X, Y and Z axis.
- */
- if( BG_Buildable(buildable,NULL)->cuboid )
- {
- if( trap_Argc() >= 5 )
- {
- trap_Argv(2,s,sizeof(s));
- dims[0]=MAX(1,atof(s));
- trap_Argv(3,s,sizeof(s));
- dims[1]=MAX(1,atof(s));
- trap_Argv(4,s,sizeof(s));
- dims[2]=MAX(1,atof(s));
- if(!Cmd_CheckCuboidSize(dims))
- {
- Com_sprintf(buf,sizeof(buf),"print \"^1error: invalid cuboid size (min volume: %i, max size: %s)\n\"",
- CUBOID_MINVOLUME,(g_cuboidSizeLimit.integer?va("%ix%ix%i",g_cuboidSizeLimit.integer,g_cuboidSizeLimit.integer, g_cuboidSizeLimit.integer):"no limit"));
- trap_SendServerCommand(ent->client-level.clients,buf);
- return;
- }
- VectorCopy(dims,ent->client->cuboidSelection);
- }
- // client is building a cuboid for the first time so reset the selection to default
- if(!Cmd_CheckCuboidSize(ent->client->cuboidSelection))
- {
- ent->client->cuboidSelection[0]=32;
- ent->client->cuboidSelection[1]=32;
- ent->client->cuboidSelection[2]=32;
- trap_SendServerCommand(ent->client-level.clients,"cb2 32 32 32");
- G_RelayCuboidToSpectators(ent->client);
- }
-
- if(!BG_CuboidAllowed((team==TEAM_ALIENS?g_alienStage.integer:g_humanStage.integer)))
- {
- if(BG_CuboidMode()==1)
- G_TriggerMenu(ent->client->ps.clientNum,MN_B_CUBOID_MODE1);
- else
- G_TriggerMenu(ent->client->ps.clientNum,MN_B_CUBOID_MODE2);
- return;
- }
- }
-
- if( G_TimeTilSuddenDeath( ) <= 0 )
- {
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_SUDDENDEATH );
- return;
- }
-
- team = ent->client->ps.stats[ STAT_TEAM ];
-
- if( buildable != BA_NONE &&
- ( ( 1 << ent->client->ps.weapon ) & BG_Buildable( buildable, NULL )->buildWeapon ) &&
- BG_BuildableIsAllowed( buildable ) &&
- ( ( team == TEAM_ALIENS && BG_BuildableAllowedInStage( buildable, g_alienStage.integer ) ) ||
- ( team == TEAM_HUMANS && BG_BuildableAllowedInStage( buildable, g_humanStage.integer ) ) ) )
- {
- dynMenu_t err;
- dist = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->buildDist;
-
- ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
-
- //these are the errors displayed when the builder first selects something to use
- switch( G_CanBuild( ent, buildable, dist, origin, normal, ent->client->cuboidSelection ) )
- {
- // can place right away, set the blueprint and the valid togglebit
- case IBE_NONE:
- case IBE_TNODEWARN:
- case IBE_RPTNOREAC:
- case IBE_RPTPOWERHERE:
- case IBE_SPWNWARN:
- err = MN_NONE;
- // we OR-in the selected builable later
- ent->client->ps.stats[ STAT_BUILDABLE ] = SB_VALID_TOGGLEBIT;
- break;
-
- // can't place yet but maybe soon: start with valid togglebit off
- case IBE_NORMAL:
- case IBE_NOCREEP:
- case IBE_NOROOM:
- case IBE_NOOVERMIND:
- case IBE_NOPOWERHERE:
- case IBE_NOSURF:
- err = MN_NONE;
- break;
-
- // more serious errors just pop a menu
- case IBE_NOALIENBP:
- err = MN_A_NOBP;
- break;
-
- case IBE_ONEOVERMIND:
- err = MN_A_ONEOVERMIND;
- break;
-
- case IBE_ONEREACTOR:
- err = MN_H_ONEREACTOR;
- break;
-
- case IBE_NOHUMANBP:
- err = MN_H_NOBP;
- break;
-
- case IBE_NODCC:
- err = MN_H_NODCC;
- break;
-
- case IBE_PERMISSION:
- err = MN_B_CANNOT;
- break;
-
- case IBE_LASTSPAWN:
- err = MN_B_LASTSPAWN;
- break;
-
- case IBE_TOODENSE:
- err = MN_B_TOODENSE;
- break;
-
- default:
- err = -1; // stop uninitialised warning
- break;
- }
-
- if( ( err == MN_A_NOBP || err == MN_H_NOBP ) && BG_Buildable(buildable,NULL)->cuboid )
- {
- err = MN_NONE;
- ent->client->ps.stats[ STAT_BUILDABLE ] = SB_VALID_TOGGLEBIT;
- }
-
- if( err == MN_NONE || ent->client->pers.disableBlueprintErrors )
- {
- trap_SendServerCommand(ent->client-level.clients,va("cb2 %f %f %f\n",
- ent->client->cuboidSelection[0],
- ent->client->cuboidSelection[1],
- ent->client->cuboidSelection[2]));
- G_RelayCuboidToSpectators(ent->client);
- ent->client->ps.stats[ STAT_BUILDABLE ] |= buildable;
- }
- else
- G_TriggerMenu( ent->client->ps.clientNum, err );
- }
- else
- G_TriggerMenu( ent->client->ps.clientNum, MN_B_CANNOT );
-}
-
-/*
-=================
-Cmd_Reload_f
-=================
-*/
-void Cmd_Reload_f( gentity_t *ent )
-{
- playerState_t *ps = &ent->client->ps;
- int ammo;
-
- // weapon doesn't ever need reloading
- if( BG_Weapon( ps->weapon )->infiniteAmmo )
- return;
-
- if( ps->clips <= 0 )
- return;
-
- if( BG_Weapon( ps->weapon )->usesEnergy &&
- BG_InventoryContainsUpgrade( UP_BATTPACK, ps->stats ) )
- ammo = BG_Weapon( ps->weapon )->maxAmmo * BATTPACK_MODIFIER;
- else
- ammo = BG_Weapon( ps->weapon )->maxAmmo;
-
- // don't reload when full
- if( ps->ammo >= ammo )
- return;
-
- // the animation, ammo refilling etc. is handled by PM_Weapon
- if( ent->client->ps.weaponstate != WEAPON_RELOADING )
- ent->client->ps.pm_flags |= PMF_WEAPON_RELOAD;
-}
-
-/*
-=================
-G_StopFromFollowing
-
-stops any other clients from following this one
-called when a player leaves a team or dies
-=================
-*/
-void G_StopFromFollowing( gentity_t *ent )
-{
- int i;
-
- for( i = 0; i < level.maxclients; i++ )
- {
- if( level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW &&
- level.clients[ i ].sess.spectatorClient == ent->client->ps.clientNum )
- {
- if( !G_FollowNewClient( &g_entities[ i ], 1 ) )
- G_StopFollowing( &g_entities[ i ] );
- }
- }
-}
-
-/*
-=================
-G_StopFollowing
-
-If the client being followed leaves the game, or you just want to drop
-to free floating spectator mode
-=================
-*/
-void G_StopFollowing( gentity_t *ent )
-{
- ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;
-
- if( ent->client->pers.teamSelection == TEAM_NONE )
- {
- ent->client->sess.spectatorState =
- ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_FREE;
- }
- else
- {
- vec3_t spawn_origin, spawn_angles;
-
- ent->client->sess.spectatorState =
- ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_LOCKED;
-
- if( ent->client->pers.teamSelection == TEAM_ALIENS )
- G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
- else if( ent->client->pers.teamSelection == TEAM_HUMANS )
- G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
-
- G_SetOrigin( ent, spawn_origin );
- VectorCopy( spawn_origin, ent->client->ps.origin );
- G_SetClientViewAngle( ent, spawn_angles );
- }
- ent->client->sess.spectatorClient = -1;
- ent->client->ps.pm_flags &= ~PMF_FOLLOW;
- ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
- ent->client->ps.stats[ STAT_STATE ] = 0;
- ent->client->ps.stats[ STAT_VIEWLOCK ] = 0;
- ent->client->ps.eFlags &= ~( EF_WALLCLIMB | EF_WALLCLIMBCEILING );
- ent->client->ps.viewangles[ PITCH ] = 0.0f;
- ent->client->ps.clientNum = ent - g_entities;
- ent->client->ps.persistant[ PERS_CREDIT ] = ent->client->pers.credit;
-
- CalculateRanks( );
-}
-
-/*
-=================
-G_FollowLockView
-
-Client is still following a player, but that player has gone to spectator
-mode and cannot be followed for the moment
-=================
-*/
-void G_FollowLockView( gentity_t *ent )
-{
- vec3_t spawn_origin, spawn_angles;
- int clientNum;
-
- clientNum = ent->client->sess.spectatorClient;
- ent->client->sess.spectatorState =
- ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_FOLLOW;
- ent->client->ps.clientNum = clientNum;
- ent->client->ps.pm_flags &= ~PMF_FOLLOW;
- ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
- ent->client->ps.stats[ STAT_VIEWLOCK ] = 0;
- ent->client->ps.eFlags &= ~( EF_WALLCLIMB | EF_WALLCLIMBCEILING );
- ent->client->ps.eFlags ^= EF_TELEPORT_BIT;
- ent->client->ps.viewangles[ PITCH ] = 0.0f;
-
- // Put the view at the team spectator lock position
- if( level.clients[ clientNum ].pers.teamSelection == TEAM_ALIENS )
- G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
- else if( level.clients[ clientNum ].pers.teamSelection == TEAM_HUMANS )
- G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
-
- G_SetOrigin( ent, spawn_origin );
- VectorCopy( spawn_origin, ent->client->ps.origin );
- G_SetClientViewAngle( ent, spawn_angles );
-}
-
-/*
-=================
-G_FollowNewClient
-
-This was a really nice, elegant function. Then I fucked it up.
-=================
-*/
-qboolean G_FollowNewClient( gentity_t *ent, int dir )
-{
- int clientnum = ent->client->sess.spectatorClient;
- int original = clientnum;
- qboolean selectAny = qfalse;
-
- if( dir > 1 )
- dir = 1;
- else if( dir < -1 )
- dir = -1;
- else if( dir == 0 )
- return qtrue;
-
- if( ent->client->sess.spectatorState == SPECTATOR_NOT )
- return qfalse;
-
- // select any if no target exists
- if( clientnum < 0 || clientnum >= level.maxclients )
- {
- clientnum = original = 0;
- selectAny = qtrue;
- }
-
- do
- {
- clientnum += dir;
-
- if( clientnum >= level.maxclients )
- clientnum = 0;
-
- if( clientnum < 0 )
- clientnum = level.maxclients - 1;
-
- // can't follow self
- if( &g_entities[ clientnum ] == ent )
- continue;
-
- // avoid selecting existing follow target
- if( clientnum == original && !selectAny )
- continue; //effectively break;
-
- // can only follow connected clients
- if( level.clients[ clientnum ].pers.connected != CON_CONNECTED )
- continue;
-
- // can't follow a spectator
- if( level.clients[ clientnum ].pers.teamSelection == TEAM_NONE )
- continue;
-
- // if stickyspec is disabled, can't follow someone in queue either
- if( !ent->client->pers.stickySpec &&
- level.clients[ clientnum ].sess.spectatorState != SPECTATOR_NOT )
- continue;
-
- // can only follow teammates when dead and on a team
- if( ent->client->pers.teamSelection != TEAM_NONE &&
- ( level.clients[ clientnum ].pers.teamSelection !=
- ent->client->pers.teamSelection ) )
- continue;
-
- // this is good, we can use it
- ent->client->sess.spectatorClient = clientnum;
- ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
-
- // if this client is in the spawn queue, we need to do something special
- if( level.clients[ clientnum ].sess.spectatorState != SPECTATOR_NOT )
- G_FollowLockView( ent );
-
- return qtrue;
-
- } while( clientnum != original );
-
- return qfalse;
-}
-
-/*
-=================
-G_ToggleFollow
-=================
-*/
-void G_ToggleFollow( gentity_t *ent )
-{
- if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
- G_StopFollowing( ent );
- else
- G_FollowNewClient( ent, 1 );
-}
-
-/*
-=================
-Cmd_Follow_f
-=================
-*/
-void Cmd_Follow_f( gentity_t *ent )
-{
- int i;
- char arg[ MAX_NAME_LENGTH ];
-
- // won't work unless spectating
- if( ent->client->sess.spectatorState == SPECTATOR_NOT )
- return;
-
- if( trap_Argc( ) != 2 )
- {
- G_ToggleFollow( ent );
- }
- else
- {
- char err[ MAX_STRING_CHARS ];
- trap_Argv( 1, arg, sizeof( arg ) );
-
- i = G_ClientNumberFromString( arg, err, sizeof( err ) );
-
- if( i == -1 )
- {
- trap_SendServerCommand( ent - g_entities,
- va( "print \"follow: %s\"", err ) );
- return;
- }
-
- // can't follow self
- if( &level.clients[ i ] == ent->client )
- return;
-
- // can't follow another spectator if sticky spec is off
- if( !ent->client->pers.stickySpec &&
- level.clients[ i ].sess.spectatorState != SPECTATOR_NOT )
- return;
-
- // if not on team spectator, you can only follow teammates
- if( ent->client->pers.teamSelection != TEAM_NONE &&
- ( level.clients[ i ].pers.teamSelection !=
- ent->client->pers.teamSelection ) )
- return;
-
- ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
- ent->client->sess.spectatorClient = i;
- }
-}
-
-/*
-=================
-Cmd_FollowCycle_f
-=================
-*/
-void Cmd_FollowCycle_f( gentity_t *ent )
-{
- char args[ 11 ];
- int dir = 1;
-
- trap_Argv( 0, args, sizeof( args ) );
- if( Q_stricmp( args, "followprev" ) == 0 )
- dir = -1;
-
- // won't work unless spectating
- if( ent->client->sess.spectatorState == SPECTATOR_NOT )
- return;
-
- G_FollowNewClient( ent, dir );
-}
-
-static void Cmd_Ignore_f( gentity_t *ent )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ];
- char cmd[ 9 ];
- int matches = 0;
- int i;
- qboolean ignore = qfalse;
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
- if( Q_stricmp( cmd, "ignore" ) == 0 )
- ignore = qtrue;
-
- if( trap_Argc() < 2 )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "usage: %s [clientNum | partial name match]\n\"", cmd ) );
- return;
- }
-
- Q_strncpyz( name, ConcatArgs( 1 ), sizeof( name ) );
- matches = G_ClientNumbersFromString( name, pids, MAX_CLIENTS );
- if( matches < 1 )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "%s: no clients match the name '%s'\n\"", cmd, name ) );
- return;
- }
-
- for( i = 0; i < matches; i++ )
- {
- if( ignore )
- {
- if( !Com_ClientListContains( &ent->client->sess.ignoreList, pids[ i ] ) )
- {
- Com_ClientListAdd( &ent->client->sess.ignoreList, pids[ i ] );
- ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
- trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "ignore: added %s^7 to your ignore list\n\"",
- level.clients[ pids[ i ] ].pers.netname ) );
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "ignore: %s^7 is already on your ignore list\n\"",
- level.clients[ pids[ i ] ].pers.netname ) );
- }
- }
- else
- {
- if( Com_ClientListContains( &ent->client->sess.ignoreList, pids[ i ] ) )
- {
- Com_ClientListRemove( &ent->client->sess.ignoreList, pids[ i ] );
- ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
- trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "unignore: removed %s^7 from your ignore list\n\"",
- level.clients[ pids[ i ] ].pers.netname ) );
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
- "unignore: %s^7 is not on your ignore list\n\"",
- level.clients[ pids[ i ] ].pers.netname ) );
- }
- }
- }
-}
-
-/*
-=================
-Cmd_ListMaps_f
-
-List all maps on the server
-=================
-*/
-
-static int SortMaps( const void *a, const void *b )
-{
- return strcmp( *(char **)a, *(char **)b );
-}
-
-#define MAX_MAPLIST_MAPS 256
-#define MAX_MAPLIST_ROWS 9
-void Cmd_ListMaps_f( gentity_t *ent )
-{
- char search[ 16 ] = {""};
- char fileList[ 4096 ] = {""};
- char *fileSort[ MAX_MAPLIST_MAPS ];
- char *filePtr, *p;
- int numFiles;
- int fileLen = 0;
- int shown = 0;
- int count = 0;
- int page = 0;
- int pages;
- int row, rows;
- int start, i, j;
-
- if( trap_Argc( ) > 1 )
- {
- trap_Argv( 1, search, sizeof( search ) );
- for( p = search; ( *p ) && isdigit( *p ); p++ );
- if( !( *p ) )
- {
- page = atoi( search );
- search[ 0 ] = '\0';
- }
- else if( trap_Argc( ) > 2 )
- {
- char lp[ 8 ];
- trap_Argv( 2, lp, sizeof( lp ) );
- page = atoi( lp );
- }
-
- if( page > 0 )
- page--;
- else if( page < 0 )
- page = 0;
- }
-
- numFiles = trap_FS_GetFileList( "maps/", ".bsp",
- fileList, sizeof( fileList ) );
- filePtr = fileList;
- for( i = 0; i < numFiles && count < MAX_MAPLIST_MAPS; i++, filePtr += fileLen + 1 )
- {
- fileLen = strlen( filePtr );
- if ( fileLen < 5 )
- continue;
-
- filePtr[ fileLen - 4 ] = '\0';
-
- if( search[ 0 ] && !strstr( filePtr, search ) )
- continue;
-
- fileSort[ count ] = filePtr;
- count++;
- }
- qsort( fileSort, count, sizeof( fileSort[ 0 ] ), SortMaps );
-
- rows = ( count + 2 ) / 3;
- pages = MAX( 1, ( rows + MAX_MAPLIST_ROWS - 1 ) / MAX_MAPLIST_ROWS );
- if( page >= pages )
- page = pages - 1;
-
- start = page * MAX_MAPLIST_ROWS * 3;
- if( count < start + ( 3 * MAX_MAPLIST_ROWS ) )
- rows = ( count - start + 2 ) / 3;
- else
- rows = MAX_MAPLIST_ROWS;
-
- ADMBP_begin( );
- for( row = 0; row < rows; row++ )
- {
- for( i = start + row, j = 0; i < count && j < 3; i += rows, j++ )
- {
- ADMBP( va( "^7 %-20s", fileSort[ i ] ) );
- shown++;
- }
- ADMBP( "\n" );
- }
- if ( search[ 0 ] )
- ADMBP( va( "^3listmaps: ^7found %d maps matching '%s^7'", count, search ) );
- else
- ADMBP( va( "^3listmaps: ^7listing %d of %d maps", shown, count ) );
- if( pages > 1 )
- ADMBP( va( ", page %d of %d", page + 1, pages ) );
- if( page + 1 < pages )
- ADMBP( va( ", use 'listmaps %s%s%d' to see more",
- search, ( search[ 0 ] ) ? " ": "", page + 2 ) );
- ADMBP( ".\n" );
- ADMBP_end( );
-}
-
-/*
-=================
-Cmd_Test_f
-=================
-*/
-void Cmd_Test_f( gentity_t *humanPlayer )
-{
-}
-
-/*
-=================
-Cmd_Damage_f
-
-Deals damage to you (for testing), arguments: [damage] [dx] [dy] [dz]
-The dx/dy arguments describe the damage point's offset from the entity origin
-=================
-*/
-void Cmd_Damage_f( gentity_t *ent )
-{
- vec3_t point;
- char arg[ 16 ];
- float dx = 0.0f, dy = 0.0f, dz = 100.0f;
- int damage = 100;
- qboolean nonloc = qtrue;
-
- if( trap_Argc() > 1 )
- {
- trap_Argv( 1, arg, sizeof( arg ) );
- damage = atoi( arg );
- }
- if( trap_Argc() > 4 )
- {
- trap_Argv( 2, arg, sizeof( arg ) );
- dx = atof( arg );
- trap_Argv( 3, arg, sizeof( arg ) );
- dy = atof( arg );
- trap_Argv( 4, arg, sizeof( arg ) );
- dz = atof( arg );
- nonloc = qfalse;
- }
- VectorCopy( ent->s.origin, point );
- point[ 0 ] += dx;
- point[ 1 ] += dy;
- point[ 2 ] += dz;
- G_Damage( ent, NULL, NULL, NULL, point, damage,
- ( nonloc ? DAMAGE_NO_LOCDAMAGE : 0 ), MOD_TARGET_LASER );
-}
-
-/*
-==================
-G_FloodLimited
-
-Determine whether a user is flood limited, and adjust their flood demerits
-Print them a warning message if they are over the limit
-Return is time in msec until the user can speak again
-==================
-*/
-int G_FloodLimited( gentity_t *ent )
-{
- int deltatime, ms;
-
- if( g_floodMinTime.integer <= 0 )
- return 0;
-
- // handles !ent
- if( G_admin_permission( ent, ADMF_NOCENSORFLOOD ) )
- return 0;
-
- deltatime = level.time - ent->client->pers.floodTime;
-
- ent->client->pers.floodDemerits += g_floodMinTime.integer - deltatime;
- if( ent->client->pers.floodDemerits < 0 )
- ent->client->pers.floodDemerits = 0;
- ent->client->pers.floodTime = level.time;
-
- ms = ent->client->pers.floodDemerits - g_floodMaxDemerits.integer;
- if( ms <= 0 )
- return 0;
- trap_SendServerCommand( ent - g_entities, va( "print \"You are flooding: "
- "please wait %d second%s before trying again\n",
- ( ms + 999 ) / 1000, ( ms > 1000 ) ? "s" : "" ) );
- return ms;
-}
-
-commands_t cmds[ ] = {
- { "a", CMD_MESSAGE|CMD_INTERMISSION, Cmd_AdminMessage_f },
- { "build", CMD_TEAM|CMD_LIVING, Cmd_Build_f },
- { "buy", CMD_HUMAN|CMD_LIVING, Cmd_Buy_f },
- { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallVote_f },
- { "callvote", CMD_MESSAGE, Cmd_CallVote_f },
- { "cb", 0, Cmd_Cb_f }, //NOTE: it's a command used only by cgame
- { "class", CMD_TEAM, Cmd_Class_f },
- { "damage", CMD_CHEAT|CMD_LIVING, Cmd_Damage_f },
- { "deconstruct", CMD_TEAM|CMD_LIVING, Cmd_Destroy_f },
- { "destroy", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Destroy_f },
- { "follow", CMD_SPEC, Cmd_Follow_f },
- { "follownext", CMD_SPEC, Cmd_FollowCycle_f },
- { "followprev", CMD_SPEC, Cmd_FollowCycle_f },
- { "give", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Give_f },
- { "god", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_God_f },
- { "ignore", 0, Cmd_Ignore_f },
- { "itemact", CMD_HUMAN|CMD_LIVING, Cmd_ActivateItem_f },
- { "itemdeact", CMD_HUMAN|CMD_LIVING, Cmd_DeActivateItem_f },
- { "itemtoggle", CMD_HUMAN|CMD_LIVING, Cmd_ToggleItem_f },
- { "kill", CMD_TEAM|CMD_LIVING, Cmd_Kill_f },
- { "levelshot", CMD_CHEAT, Cmd_LevelShot_f },
- { "listmaps", CMD_MESSAGE|CMD_INTERMISSION, Cmd_ListMaps_f },
- { "m", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
- { "mt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
- { "noclip", CMD_CHEAT_TEAM, Cmd_Noclip_f },
- { "notarget", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Notarget_f },
- { "reload", CMD_HUMAN|CMD_LIVING, Cmd_Reload_f },
- { "say", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "say_area", CMD_MESSAGE|CMD_TEAM|CMD_LIVING, Cmd_SayArea_f },
- { "say_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "score", CMD_INTERMISSION, ScoreboardMessage },
- { "sell", CMD_HUMAN|CMD_LIVING, Cmd_Sell_f },
- { "setviewpos", CMD_CHEAT_TEAM, Cmd_SetViewpos_f },
- { "team", 0, Cmd_Team_f },
- { "teamvote", CMD_TEAM, Cmd_Vote_f },
- { "test", CMD_CHEAT, Cmd_Test_f },
- { "unignore", 0, Cmd_Ignore_f },
- { "vote", 0, Cmd_Vote_f },
- { "vsay", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VSay_f },
- { "vsay_local", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VSay_f },
- { "vsay_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VSay_f },
- { "where", 0, Cmd_Where_f }
-};
-static size_t numCmds = sizeof( cmds ) / sizeof( cmds[ 0 ] );
-
-/*
-=================
-ClientCommand
-=================
-*/
-void ClientCommand( int clientNum )
-{
- gentity_t *ent;
- char cmd[ MAX_TOKEN_CHARS ];
- commands_t *command;
-
- ent = g_entities + clientNum;
- if( !ent->client || ent->client->pers.connected != CON_CONNECTED )
- return; // not fully in game yet
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
-
- command = bsearch( cmd, cmds, numCmds, sizeof( cmds[ 0 ] ), cmdcmp );
-
- if( !command )
- {
- if( !G_admin_cmd_check( ent ) )
- trap_SendServerCommand( clientNum,
- va( "print \"Unknown command %s\n\"", cmd ) );
- return;
- }
-
- // do tests here to reduce the amount of repeated code
-
- if( !( command->cmdFlags & CMD_INTERMISSION ) &&
- ( level.intermissiontime || level.pausedTime ) )
- return;
-
- if( command->cmdFlags & CMD_CHEAT && !g_cheats.integer )
- {
- G_TriggerMenu( clientNum, MN_CMD_CHEAT );
- return;
- }
-
- if( command->cmdFlags & CMD_MESSAGE && ( ent->client->pers.namelog->muted ||
- G_FloodLimited( ent ) ) )
- return;
-
- if( command->cmdFlags & CMD_TEAM &&
- ent->client->pers.teamSelection == TEAM_NONE )
- {
- G_TriggerMenu( clientNum, MN_CMD_TEAM );
- return;
- }
-
- if( command->cmdFlags & CMD_CHEAT_TEAM && !g_cheats.integer &&
- ent->client->pers.teamSelection != TEAM_NONE )
- {
- G_TriggerMenu( clientNum, MN_CMD_CHEAT_TEAM );
- return;
- }
-
- if( command->cmdFlags & CMD_SPEC &&
- ent->client->sess.spectatorState == SPECTATOR_NOT )
- {
- G_TriggerMenu( clientNum, MN_CMD_SPEC );
- return;
- }
-
- if( command->cmdFlags & CMD_ALIEN &&
- ent->client->pers.teamSelection != TEAM_ALIENS )
- {
- G_TriggerMenu( clientNum, MN_CMD_ALIEN );
- return;
- }
-
- if( command->cmdFlags & CMD_HUMAN &&
- ent->client->pers.teamSelection != TEAM_HUMANS )
- {
- G_TriggerMenu( clientNum, MN_CMD_HUMAN );
- return;
- }
-
- if( command->cmdFlags & CMD_LIVING &&
- ( ent->client->ps.stats[ STAT_HEALTH ] <= 0 ||
- ent->client->sess.spectatorState != SPECTATOR_NOT ) )
- {
- G_TriggerMenu( clientNum, MN_CMD_LIVING );
- return;
- }
-
- command->cmdHandler( ent );
-}
-
-void G_ListCommands( gentity_t *ent )
-{
- int i;
- char out[ MAX_STRING_CHARS ] = "";
- int len, outlen;
-
- outlen = 0;
-
- for( i = 0; i < numCmds; i++ )
- {
- len = strlen( cmds[ i ].cmdName ) + 1;
- if( len + outlen >= sizeof( out ) - 1 )
- {
- trap_SendServerCommand( ent - g_entities, va( "cmds%s\n", out ) );
- outlen = 0;
- }
-
- strcpy( out + outlen, va( " %s", cmds[ i ].cmdName ) );
- outlen += len;
- }
-
- trap_SendServerCommand( ent - g_entities, va( "cmds%s\n", out ) );
- G_admin_cmdlist( ent );
-}
-
-void G_DecolorString( char *in, char *out, int len )
-{
- qboolean decolor = qtrue;
-
- len--;
-
- while( *in && len > 0 ) {
- if( *in == DECOLOR_OFF || *in == DECOLOR_ON )
- {
- decolor = ( *in == DECOLOR_ON );
- in++;
- continue;
- }
- if( Q_IsColorString( in ) && decolor ) {
- in += 2;
- continue;
- }
- *out++ = *in++;
- len--;
- }
- *out = '\0';
-}
-
-void G_UnEscapeString( char *in, char *out, int len )
-{
- len--;
-
- while( *in && len > 0 )
- {
- if( *in >= ' ' || *in == '\n' )
- {
- *out++ = *in;
- len--;
- }
- in++;
- }
- *out = '\0';
-}
-
-void Cmd_PrivateMessage_f( gentity_t *ent )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ];
- char cmd[ 12 ];
- char text[ MAX_STRING_CHARS ];
- char *msg;
- char color;
- int i, pcount;
- int count = 0;
- qboolean teamonly = qfalse;
- char recipients[ MAX_STRING_CHARS ] = "";
-
- if( !g_privateMessages.integer && ent )
- {
- ADMP( "Sorry, but private messages have been disabled\n" );
- return;
- }
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
- if( trap_Argc( ) < 3 )
- {
- ADMP( va( "usage: %s [name|slot#] [message]\n", cmd ) );
- return;
- }
-
- if( !Q_stricmp( cmd, "mt" ) )
- teamonly = qtrue;
-
- trap_Argv( 1, name, sizeof( name ) );
- msg = ConcatArgs( 2 );
- pcount = G_ClientNumbersFromString( name, pids, MAX_CLIENTS );
-
- G_CensorString( text, msg, sizeof( text ), ent );
-
- // send the message
- for( i = 0; i < pcount; i++ )
- {
- if( G_SayTo( ent, &g_entities[ pids[ i ] ],
- teamonly ? SAY_TPRIVMSG : SAY_PRIVMSG, text ) )
- {
- count++;
- Q_strcat( recipients, sizeof( recipients ), va( "%s" S_COLOR_WHITE ", ",
- level.clients[ pids[ i ] ].pers.netname ) );
- }
- }
-
- // report the results
- color = teamonly ? COLOR_CYAN : COLOR_YELLOW;
-
- if( !count )
- ADMP( va( "^3No player matching ^7\'%s^7\' ^3to send message to.\n",
- name ) );
- else
- {
- ADMP( va( "^%cPrivate message: ^7%s\n", color, text ) );
- // remove trailing ", "
- recipients[ strlen( recipients ) - 2 ] = '\0';
- ADMP( va( "^%csent to %i player%s: " S_COLOR_WHITE "%s\n", color, count,
- count == 1 ? "" : "s", recipients ) );
-
- G_LogPrintf( "%s: %d \"%s" S_COLOR_WHITE "\" \"%s\": ^%c%s\n",
- ( teamonly ) ? "TPrivMsg" : "PrivMsg",
- ( ent ) ? ent - g_entities : -1,
- ( ent ) ? ent->client->pers.netname : "console",
- name, color, msg );
- }
-}
-
-/*
-=================
-Cmd_AdminMessage_f
-
-Send a message to all active admins
-=================
-*/
-void Cmd_AdminMessage_f( gentity_t *ent )
-{
- // Check permissions and add the appropriate user [prefix]
- if( !G_admin_permission( ent, ADMF_ADMINCHAT ) )
- {
- if( !g_publicAdminMessages.integer )
- {
- ADMP( "Sorry, but use of /a by non-admins has been disabled.\n" );
- return;
- }
- else
- {
- ADMP( "Your message has been sent to any available admins "
- "and to the server logs.\n" );
- }
- }
-
- if( trap_Argc( ) < 2 )
- {
- ADMP( "usage: a [message]\n" );
- return;
- }
-
- G_AdminMessage( ent, ConcatArgs( 1 ) );
-}
-