/*
===========================================================================
Wolfenstein: Enemy Territory GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Wolfenstein: Enemy Territory GPL Source Code (Wolf ET Source Code).
Wolf ET Source Code 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 3 of the License, or
(at your option) any later version.
Wolf ET Source Code 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 Wolf ET Source Code. If not, see .
In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// G_referee.c: Referee handling
// -------------------------------
// 04 Apr 02
// rhea@OrangeSmoothie.org
//
#include "g_local.h"
#include "../../etmain/ui/menudef.h"
//
// UGH! Clean me!!!!
//
// Parses for a referee command.
// --> ref arg allows for the server console to utilize all referee commands (ent == NULL)
//
qboolean G_refCommandCheck( gentity_t *ent, char *cmd ) {
if ( !Q_stricmp( cmd, "allready" ) ) {
G_refAllReady_cmd( ent );
} else if ( !Q_stricmp( cmd, "lock" ) ) {
G_refLockTeams_cmd( ent, qtrue );
} else if ( !Q_stricmp( cmd, "help" ) ) {
G_refHelp_cmd( ent );
} else if ( !Q_stricmp( cmd, "pause" ) ) {
G_refPause_cmd( ent, qtrue );
} else if ( !Q_stricmp( cmd, "putallies" ) ) {
G_refPlayerPut_cmd( ent, TEAM_ALLIES );
} else if ( !Q_stricmp( cmd, "putaxis" ) ) {
G_refPlayerPut_cmd( ent, TEAM_AXIS );
} else if ( !Q_stricmp( cmd, "remove" ) ) {
G_refRemove_cmd( ent );
} else if ( !Q_stricmp( cmd, "speclock" ) ) {
G_refSpeclockTeams_cmd( ent, qtrue );
} else if ( !Q_stricmp( cmd, "specunlock" ) ) {
G_refSpeclockTeams_cmd( ent, qfalse );
} else if ( !Q_stricmp( cmd, "unlock" ) ) {
G_refLockTeams_cmd( ent, qfalse );
} else if ( !Q_stricmp( cmd, "unpause" ) ) {
G_refPause_cmd( ent, qfalse );
} else if ( !Q_stricmp( cmd, "warmup" ) ) {
G_refWarmup_cmd( ent );
} else if ( !Q_stricmp( cmd, "warn" ) ) {
G_refWarning_cmd( ent );
} else if ( !Q_stricmp( cmd, "mute" ) ) {
G_refMute_cmd( ent, qtrue );
} else if ( !Q_stricmp( cmd, "unmute" ) ) {
G_refMute_cmd( ent, qfalse );
} else { return( qfalse );}
return( qtrue );
}
// Lists ref commands.
void G_refHelp_cmd( gentity_t *ent ) {
// List commands only for enabled refs.
if ( ent ) {
if ( !ent->client->sess.referee ) {
CP( "cpm \"Sorry, you are not a referee!\n" );
return;
}
CP( "print \"\n^3Referee commands:^7\n\"" );
CP( "print \"------------------------------------------\n\"" );
G_voteHelp( ent, qfalse );
CP( "print \"\n^5allready putallies^7 ^5speclock warmup\n\"" );
CP( "print \"^5lock putaxis^7 ^5specunlock warn ^7\n\"" );
CP( "print \"^5help remove unlock mute ^7\n\"" );
CP( "print \"^5pause restart unpause unmute ^7\n\"" );
CP( "print \"Usage: ^3\\ref [params]\n\n\"" );
// Help for the console
} else {
G_Printf( "\nAdditional console commands:\n" );
G_Printf( "----------------------------------------------\n" );
G_Printf( "allready putallies unlock\n" );
G_Printf( "lock putaxis unpause\n" );
G_Printf( "help restart warmup [value]\n" );
G_Printf( "pause speclock warn \n" );
G_Printf( "remove specunlock\n\n" );
G_Printf( "Usage: [params]\n\n" );
}
}
// Request for ref status or lists ref commands.
void G_ref_cmd( gentity_t *ent, unsigned int dwCommand, qboolean fValue ) {
char arg[MAX_TOKEN_CHARS];
// Roll through ref commands if already a ref
if ( ent == NULL || ent->client->sess.referee ) {
voteInfo_t votedata;
trap_Argv( 1, arg, sizeof( arg ) );
memcpy( &votedata, &level.voteInfo, sizeof( voteInfo_t ) );
if ( Cmd_CallVote_f( ent, 0, qtrue ) ) {
memcpy( &level.voteInfo, &votedata, sizeof( voteInfo_t ) );
return;
} else {
memcpy( &level.voteInfo, &votedata, sizeof( voteInfo_t ) );
if ( G_refCommandCheck( ent, arg ) ) {
return;
} else {
G_refHelp_cmd( ent );
}
}
return;
}
if ( ent ) {
if ( !Q_stricmp( refereePassword.string, "none" ) || !refereePassword.string[0] ) {
CP( "cpm \"Sorry, referee status disabled on this server.\n\"" );
return;
}
if ( trap_Argc() < 2 ) {
CP( "cpm \"Usage: ref [password]\n\"" );
return;
}
trap_Argv( 1, arg, sizeof( arg ) );
if ( Q_stricmp( arg, refereePassword.string ) ) {
CP( "cpm \"Invalid referee password!\n\"" );
return;
}
ent->client->sess.referee = 1;
ent->client->sess.spec_invite = TEAM_AXIS | TEAM_ALLIES;
AP( va( "cp \"%s\n^3has become a referee\n\"", ent->client->pers.netname ) );
ClientUserinfoChanged( ent - g_entities );
}
}
// Readies all players in the game.
void G_refAllReady_cmd( gentity_t *ent ) {
int i;
gclient_t *cl;
if ( g_gamestate.integer == GS_PLAYING ) {
// rain - #105 - allow allready in intermission
// || g_gamestate.integer == GS_INTERMISSION) {
G_refPrintf( ent, "Match already in progress!" );
return;
}
// Ready them all and lock the teams
for ( i = 0; i < level.numConnectedClients; i++ ) {
cl = level.clients + level.sortedClients[i];
if ( cl->sess.sessionTeam != TEAM_SPECTATOR ) {
cl->pers.ready = qtrue;
}
}
// Can we start?
level.ref_allready = qtrue;
G_readyMatchState();
}
// Changes team lock status
void G_refLockTeams_cmd( gentity_t *ent, qboolean fLock ) {
char *status;
teamInfo[TEAM_AXIS].team_lock = ( TeamCount( -1, TEAM_AXIS ) ) ? fLock : qfalse;
teamInfo[TEAM_ALLIES].team_lock = ( TeamCount( -1, TEAM_ALLIES ) ) ? fLock : qfalse;
status = va( "Referee has ^3%sLOCKED^7 teams", ( ( fLock ) ? "" : "UN" ) );
G_printFull( status, ent );
G_refPrintf( ent, "You have %sLOCKED teams\n", ( ( fLock ) ? "" : "UN" ) );
if ( fLock ) {
level.server_settings |= CV_SVS_LOCKTEAMS;
} else {
level.server_settings &= ~CV_SVS_LOCKTEAMS;
}
trap_SetConfigstring( CS_SERVERTOGGLES, va( "%d", level.server_settings ) );
}
// Pause/unpause a match.
void G_refPause_cmd( gentity_t *ent, qboolean fPause ) {
char *status[2] = { "^5UN", "^1" };
char *referee = ( ent ) ? "Referee" : "ref";
if ( ( PAUSE_UNPAUSING >= level.match_pause && !fPause ) || ( PAUSE_NONE != level.match_pause && fPause ) ) {
G_refPrintf( ent, "The match is already %sPAUSED!\n\"", status[fPause] );
return;
}
if ( ent && !G_cmdDebounce( ent, ( ( fPause ) ? "pause" : "unpause" ) ) ) {
return;
}
// Trigger the auto-handling of pauses
if ( fPause ) {
level.match_pause = 100 + ( ( ent ) ? ( 1 + ent - g_entities ) : 0 );
G_globalSound( "sound/misc/referee.wav" );
G_spawnPrintf( DP_PAUSEINFO, level.time + 15000, NULL );
AP( va( "print \"^3%s ^1PAUSED^3 the match^3!\n", referee ) );
CP( va( "cp \"^3Match is ^1PAUSED^3! (^7%s^3)\n\"", referee ) );
level.server_settings |= CV_SVS_PAUSE;
trap_SetConfigstring( CS_SERVERTOGGLES, va( "%d", level.server_settings ) );
} else {
AP( va( "print \"\n^3%s ^5UNPAUSES^3 the match ... resuming in 10 seconds!\n\n\"", referee ) );
level.match_pause = PAUSE_UNPAUSING;
G_globalSound( "sound/osp/prepare.wav" );
G_spawnPrintf( DP_UNPAUSING, level.time + 10, NULL );
return;
}
}
// Puts a player on a team.
void G_refPlayerPut_cmd( gentity_t *ent, int team_id ) {
int pid;
char arg[MAX_TOKEN_CHARS];
gentity_t *player;
// Works for teamplayish matches
if ( g_gametype.integer < GT_WOLF ) {
G_refPrintf( ent, "\"put[allies|axis]\" only for team-based games!" );
return;
}
// Find the player to place.
trap_Argv( 2, arg, sizeof( arg ) );
if ( ( pid = ClientNumberFromString( ent, arg ) ) == -1 ) {
return;
}
player = g_entities + pid;
// Can only move to other teams.
if ( player->client->sess.sessionTeam == team_id ) {
G_refPrintf( ent, "\"%s\" is already on team %s!\n", player->client->pers.netname, aTeams[team_id] );
return;
}
if ( team_maxplayers.integer && TeamCount( -1, team_id ) >= team_maxplayers.integer ) {
G_refPrintf( ent, "Sorry, the %s team is already full!\n", aTeams[team_id] );
return;
}
player->client->pers.invite = team_id;
player->client->pers.ready = qfalse;
if ( team_id == TEAM_AXIS ) {
SetTeam( player, "red", qtrue, -1, -1, qfalse );
} else {
SetTeam( player, "blue", qtrue, -1, -1, qfalse );
}
if ( g_gamestate.integer == GS_WARMUP || g_gamestate.integer == GS_WARMUP_COUNTDOWN ) {
G_readyMatchState();
}
}
// Removes a player from a team.
void G_refRemove_cmd( gentity_t *ent ) {
int pid;
char arg[MAX_TOKEN_CHARS];
gentity_t *player;
// Works for teamplayish matches
if ( g_gametype.integer < GT_WOLF ) {
G_refPrintf( ent, "\"remove\" only for team-based games!" );
return;
}
// Find the player to remove.
trap_Argv( 2, arg, sizeof( arg ) );
if ( ( pid = ClientNumberFromString( ent, arg ) ) == -1 ) {
return;
}
player = g_entities + pid;
// Can only remove active players.
if ( player->client->sess.sessionTeam == TEAM_SPECTATOR ) {
G_refPrintf( ent, "You can only remove people in the game!" );
return;
}
// Announce the removal
AP( va( "cp \"%s\n^7removed from team %s\n\"", player->client->pers.netname, aTeams[player->client->sess.sessionTeam] ) );
CPx( pid, va( "print \"^5You've been removed from the %s team\n\"", aTeams[player->client->sess.sessionTeam] ) );
SetTeam( player, "s", qtrue, -1, -1, qfalse );
if ( g_gamestate.integer == GS_WARMUP || g_gamestate.integer == GS_WARMUP_COUNTDOWN ) {
G_readyMatchState();
}
}
// Changes team spectator lock status
void G_refSpeclockTeams_cmd( gentity_t *ent, qboolean fLock ) {
char *status;
// Ensure proper locking
G_updateSpecLock( TEAM_AXIS, ( TeamCount( -1, TEAM_AXIS ) ) ? fLock : qfalse );
G_updateSpecLock( TEAM_ALLIES, ( TeamCount( -1, TEAM_ALLIES ) ) ? fLock : qfalse );
status = va( "Referee has ^3SPECTATOR %sLOCKED^7 teams", ( ( fLock ) ? "" : "UN" ) );
G_printFull( status, ent );
// Update viewers as necessary
// G_pollMultiPlayers();
if ( fLock ) {
level.server_settings |= CV_SVS_LOCKSPECS;
} else {
level.server_settings &= ~CV_SVS_LOCKSPECS;
}
trap_SetConfigstring( CS_SERVERTOGGLES, va( "%d", level.server_settings ) );
}
void G_refWarmup_cmd( gentity_t* ent ) {
char cmd[MAX_TOKEN_CHARS];
trap_Argv( 2, cmd, sizeof( cmd ) );
if ( !*cmd || atoi( cmd ) < 0 ) {
trap_Cvar_VariableStringBuffer( "g_warmup", cmd, sizeof( cmd ) );
G_refPrintf( ent, "Warmup Time: %d\n", atoi( cmd ) );
return;
}
trap_Cvar_Set( "g_warmup", va( "%d", atoi( cmd ) ) );
}
void G_refWarning_cmd( gentity_t* ent ) {
char cmd[MAX_TOKEN_CHARS];
char reason[MAX_TOKEN_CHARS];
int kicknum;
trap_Argv( 2, cmd, sizeof( cmd ) );
if ( !*cmd ) {
G_refPrintf( ent, "usage: ref warn [reason]." );
return;
}
trap_Argv( 3, reason, sizeof( reason ) );
kicknum = G_refClientnumForName( ent, cmd );
if ( kicknum != MAX_CLIENTS ) {
if ( level.clients[kicknum].sess.referee == RL_NONE || ( ( !ent || ent->client->sess.referee == RL_RCON ) && level.clients[kicknum].sess.referee <= RL_REFEREE ) ) {
trap_SendServerCommand( -1, va( "cpm \"%s^7 was issued a ^1Warning^7 (%s)\n\"\n", level.clients[kicknum].pers.netname, *reason ? reason : "No Reason Supplied" ) );
} else {
G_refPrintf( ent, "Insufficient rights to issue client a warning." );
}
}
}
// (Un)Mutes a player
void G_refMute_cmd( gentity_t *ent, qboolean mute ) {
int pid;
char arg[MAX_TOKEN_CHARS];
gentity_t *player;
// Find the player to mute.
trap_Argv( 2, arg, sizeof( arg ) );
if ( ( pid = ClientNumberFromString( ent, arg ) ) == -1 ) {
return;
}
player = g_entities + pid;
if ( player->client->sess.referee != RL_NONE ) {
G_refPrintf( ent, "Cannot mute a referee.\n" );
return;
}
if ( player->client->sess.muted == mute ) {
G_refPrintf( ent, "\"%s^*\" %s\n", player->client->pers.netname, mute ? "is already muted!" : "is not muted!" );
return;
}
if ( mute ) {
CPx( pid, "print \"^5You've been muted\n\"" );
player->client->sess.muted = qtrue;
G_Printf( "\"%s^*\" has been muted\n", player->client->pers.netname );
ClientUserinfoChanged( pid );
} else {
CPx( pid, "print \"^5You've been unmuted\n\"" );
player->client->sess.muted = qfalse;
G_Printf( "\"%s^*\" has been unmuted\n", player->client->pers.netname );
ClientUserinfoChanged( pid );
}
}
//////////////////////////////
// Client authentication
//
void Cmd_AuthRcon_f( gentity_t *ent ) {
char buf[MAX_TOKEN_CHARS], cmd[MAX_TOKEN_CHARS];
trap_Cvar_VariableStringBuffer( "rconPassword", buf, sizeof( buf ) );
trap_Argv( 1, cmd, sizeof( cmd ) );
if ( *buf && !strcmp( buf, cmd ) ) {
ent->client->sess.referee = RL_RCON;
}
}
//////////////////////////////
// Console admin commands
//
void G_PlayerBan() {
char cmd[MAX_TOKEN_CHARS];
int bannum;
trap_Argv( 1, cmd, sizeof( cmd ) );
if ( !*cmd ) {
G_Printf( "usage: ban ." );
return;
}
bannum = G_refClientnumForName( NULL, cmd );
if ( bannum != MAX_CLIENTS ) {
// if( level.clients[bannum].sess.referee != RL_RCON ) {
const char* value;
char userinfo[MAX_INFO_STRING];
trap_GetUserinfo( bannum, userinfo, sizeof( userinfo ) );
value = Info_ValueForKey( userinfo, "ip" );
AddIPBan( value );
// } else {
// G_Printf( "^3*** Can't ban a superuser!\n" );
// }
}
}
void G_MakeReferee() {
char cmd[MAX_TOKEN_CHARS];
int cnum;
trap_Argv( 1, cmd, sizeof( cmd ) );
if ( !*cmd ) {
G_Printf( "usage: MakeReferee ." );
return;
}
cnum = G_refClientnumForName( NULL, cmd );
if ( cnum != MAX_CLIENTS ) {
if ( level.clients[cnum].sess.referee == RL_NONE ) {
level.clients[cnum].sess.referee = RL_REFEREE;
AP( va( "cp \"%s\n^3has been made a referee\n\"", cmd ) );
G_Printf( "%s has been made a referee.\n", cmd );
} else {
G_Printf( "User is already authed.\n" );
}
}
}
void G_RemoveReferee() {
char cmd[MAX_TOKEN_CHARS];
int cnum;
trap_Argv( 1, cmd, sizeof( cmd ) );
if ( !*cmd ) {
G_Printf( "usage: RemoveReferee ." );
return;
}
cnum = G_refClientnumForName( NULL, cmd );
if ( cnum != MAX_CLIENTS ) {
if ( level.clients[cnum].sess.referee == RL_REFEREE ) {
level.clients[cnum].sess.referee = RL_NONE;
G_Printf( "%s is no longer a referee.\n", cmd );
} else {
G_Printf( "User is not a referee.\n" );
}
}
}
void G_MuteClient() {
char cmd[MAX_TOKEN_CHARS];
int cnum;
trap_Argv( 1, cmd, sizeof( cmd ) );
if ( !*cmd ) {
G_Printf( "usage: Mute ." );
return;
}
cnum = G_refClientnumForName( NULL, cmd );
if ( cnum != MAX_CLIENTS ) {
if ( level.clients[cnum].sess.referee != RL_RCON ) {
trap_SendServerCommand( cnum, va( "cpm \"^3You have been muted\"" ) );
level.clients[cnum].sess.muted = qtrue;
G_Printf( "%s^* has been muted\n", cmd );
ClientUserinfoChanged( cnum );
} else {
G_Printf( "Cannot mute a referee.\n" );
}
}
}
void G_UnMuteClient() {
char cmd[MAX_TOKEN_CHARS];
int cnum;
trap_Argv( 1, cmd, sizeof( cmd ) );
if ( !*cmd ) {
G_Printf( "usage: Unmute .\n" );
return;
}
cnum = G_refClientnumForName( NULL, cmd );
if ( cnum != MAX_CLIENTS ) {
if ( level.clients[cnum].sess.muted ) {
trap_SendServerCommand( cnum, va( "cpm \"^2You have been un-muted\"" ) );
level.clients[cnum].sess.muted = qfalse;
G_Printf( "%s has been un-muted\n", cmd );
ClientUserinfoChanged( cnum );
} else {
G_Printf( "User is not muted.\n" );
}
}
}
/////////////////
// Utility
//
int G_refClientnumForName( gentity_t *ent, const char *name ) {
char cleanName[MAX_TOKEN_CHARS];
int i;
if ( !*name ) {
return( MAX_CLIENTS );
}
for ( i = 0; i < level.numConnectedClients; i++ ) {
Q_strncpyz( cleanName, level.clients[level.sortedClients[i]].pers.netname, sizeof( cleanName ) );
Q_CleanStr( cleanName );
if ( !Q_stricmp( cleanName, name ) ) {
return( level.sortedClients[i] );
}
}
G_refPrintf( ent, "Client not on server." );
return( MAX_CLIENTS );
}
void G_refPrintf( gentity_t* ent, const char *fmt, ... ) {
va_list argptr;
char text[1024];
va_start( argptr, fmt );
Q_vsnprintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
if ( ent == NULL ) {
trap_Printf( text );
} else { CP( va( "cpm \"%s\n\"", text ) );}
}