/*
===========================================================================
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_vote.c: All callvote handling
// -------------------------------
//
#include "g_local.h"
#include "../../etmain/ui/menudef.h" // For vote options
#define T_FFA 0x01
#define T_1V1 0x02
#define T_SP 0x04
#define T_TDM 0x08
#define T_CTF 0x10
#define T_WLF 0x20
#define T_WSW 0x40
#define T_WCP 0x80
#define T_WCH 0x100
static const char *ACTIVATED = "ACTIVATED";
static const char *DEACTIVATED = "DEACTIVATED";
static const char *ENABLED = "ENABLED";
static const char *DISABLED = "DISABLED";
static const char *gameNames[] = {
"Single Player",
"Cooperative",
"Objective",
"Stopwatch",
"Campaign",
"Last Man Standing"
};
//
// Update info:
// 1. Add line to aVoteInfo w/appropriate info
// 2. Add implementation for attempt and success (see an existing command for an example)
//
typedef struct {
unsigned int dwGameTypes;
const char *pszVoteName;
int ( *pVoteCommand )( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd );
const char *pszVoteMessage;
const char *pszVoteHelp;
} vote_reference_t;
// VC optimizes for dup strings :)
static const vote_reference_t aVoteInfo[] = {
{ 0x1ff, "comp", G_Comp_v, "Load Competition Settings", "^7\n Loads standard competition settings for the current mode" },
{ 0x1ff, "gametype", G_Gametype_v, "Set Gametype to", " ^7\n Changes the current gametype" },
{ 0x1ff, "kick", G_Kick_v, "KICK", " ^7\n Attempts to kick player from server" },
{ 0x1ff, "mute", G_Mute_v, "MUTE", " ^7\n Removes the chat capabilities of a player" },
{ 0x1ff, "unmute", G_UnMute_v, "UN-MUTE", " ^7\n Restores the chat capabilities of a player" },
{ 0x1ff, "map", G_Map_v, "Change map to", " ^7\n Votes for a new map to be loaded" },
{ 0x1ff, "campaign", G_Campaign_v, "Change campaign to", " ^7\n Votes for a new map to be loaded" },
{ 0x1ff, "maprestart", G_MapRestart_v, "Map Restart", "^7\n Restarts the current map in progress" },
{ 0x1ff, "matchreset", G_MatchReset_v, "Match Reset", "^7\n Resets the entire match" },
{ 0x1ff, "mutespecs", G_Mutespecs_v, "Mute Spectators", " <0|1>^7\n Mutes in-game spectator chat" },
{ 0x1ff, "nextmap", G_Nextmap_v, "Load Next Map", "^7\n Loads the next map or campaign in the map queue" },
{ 0x1ff, "pub", G_Pub_v, "Load Public Settings", "^7\n Loads standard public settings for the current mode" },
{ 0x1ff, "referee", G_Referee_v, "Referee", " ^7\n Elects a player to have admin abilities" },
{ 0x1ff, "shuffleteamsxp", G_ShuffleTeams_v, "Shuffle Teams by XP", " ^7\n Randomly place players on each team, based on XP" },
{ 0x1ff, "startmatch", G_StartMatch_v, "Start Match", " ^7\n Sets all players to \"ready\" status to start the match" },
{ 0x1ff, "swapteams", G_SwapTeams_v, "Swap Teams", " ^7\n Switch the players on each team" },
{ 0x1ff, "friendlyfire", G_FriendlyFire_v, "Friendly Fire", " <0|1>^7\n Toggles ability to hurt teammates" },
{ 0x1ff, "timelimit", G_Timelimit_v, "Timelimit", " ^7\n Changes the current timelimit" },
{ 0x1ff, "unreferee", G_Unreferee_v, "UNReferee", " ^7\n Elects a player to have admin abilities removed" },
{ 0x1ff, "warmupdamage", G_Warmupfire_v, "Warmup Damage", " <0|1|2>^7\n Specifies if players can inflict damage during warmup" },
{ 0x1ff, "antilag", G_AntiLag_v, "Anti-Lag", " <0|1>^7\n Toggles Anit-Lag on the server" },
{ 0x1ff, "balancedteams",G_BalancedTeams_v, "Balanced Teams", " <0|1>^7\n Toggles team balance forcing" },
{ 0, 0, NULL, 0 }
};
// Checks for valid custom callvote requests from the client.
int G_voteCmdCheck( gentity_t *ent, char *arg, char *arg2, qboolean fRefereeCmd ) {
unsigned int i, cVoteCommands = sizeof( aVoteInfo ) / sizeof( aVoteInfo[0] );
for ( i = 0; i < cVoteCommands; i++ ) {
if ( !Q_stricmp( arg, aVoteInfo[i].pszVoteName ) ) {
int hResult = aVoteInfo[i].pVoteCommand( ent, i, arg, arg2, fRefereeCmd );
if ( hResult == G_OK ) {
Com_sprintf( arg, VOTE_MAXSTRING, aVoteInfo[i].pszVoteMessage );
level.voteInfo.vote_fn = aVoteInfo[i].pVoteCommand;
} else {
level.voteInfo.vote_fn = NULL;
}
return( hResult );
}
}
return( G_NOTFOUND );
}
// Voting help summary.
void G_voteHelp( gentity_t *ent, qboolean fShowVote ) {
int i, rows = 0, num_cmds = sizeof( aVoteInfo ) / sizeof( aVoteInfo[0] ) - 1; // Remove terminator;
int vi[100]; // Just make it large static.
if ( fShowVote ) {
CP( "print \"\nValid ^3callvote^7 commands are:\n^3----------------------------\n\"" );
}
for ( i = 0; i < num_cmds; i++ ) {
if ( aVoteInfo[i].dwGameTypes & ( 1 << g_gametype.integer ) ) {
vi[rows++] = i;
}
}
num_cmds = rows;
rows = num_cmds / HELP_COLUMNS;
if ( num_cmds % HELP_COLUMNS ) {
rows++;
}
if ( rows < 0 ) {
return;
}
for ( i = 0; i < rows; i++ ) {
if ( i + rows * 3 + 1 <= num_cmds ) {
G_refPrintf( ent, "^5%-17s%-17s%-17s%-17s", aVoteInfo[vi[i]].pszVoteName,
aVoteInfo[vi[i + rows]].pszVoteName,
aVoteInfo[vi[i + rows * 2]].pszVoteName,
aVoteInfo[vi[i + rows * 3]].pszVoteName );
} else if ( i + rows * 2 + 1 <= num_cmds ) {
G_refPrintf( ent, "^5%-17s%-17s%-17s", aVoteInfo[vi[i]].pszVoteName,
aVoteInfo[vi[i + rows]].pszVoteName,
aVoteInfo[vi[i + rows * 2]].pszVoteName );
} else if ( i + rows + 1 <= num_cmds ) {
G_refPrintf( ent, "^5%-17s%-17s", aVoteInfo[vi[i]].pszVoteName,
aVoteInfo[vi[i + rows]].pszVoteName );
} else {
G_refPrintf( ent, "^5%-17s", aVoteInfo[vi[i]].pszVoteName );
}
}
if ( fShowVote ) {
CP( "print \"\nUsage: ^3\\callvote \n^7For current settings/help, use: ^3\\callvote ?\n\n\"" );
}
return;
}
// Set disabled votes for client UI
void G_voteFlags( void ) {
int i, flags = 0;
for ( i = 0; i < numVotesAvailable; i++ ) {
if ( trap_Cvar_VariableIntegerValue( voteToggles[i].pszCvar ) == 0 ) {
flags |= voteToggles[i].flag;
}
}
if ( flags != voteFlags.integer ) {
trap_Cvar_Set( "voteFlags", va( "%d", flags ) );
}
}
// Prints specific callvote command help description.
qboolean G_voteDescription( gentity_t *ent, qboolean fRefereeCmd, int cmd ) {
char arg[MAX_TOKEN_CHARS];
char *ref_cmd = ( fRefereeCmd ) ? "\\ref" : "\\callvote";
if ( !ent ) {
return( qfalse );
}
trap_Argv( 2, arg, sizeof( arg ) );
if ( !Q_stricmp( arg, "?" ) || trap_Argc() == 2 ) {
trap_Argv( 1, arg, sizeof( arg ) );
G_refPrintf( ent, "\nUsage: ^3%s %s%s\n", ref_cmd, arg, aVoteInfo[cmd].pszVoteHelp );
return( qtrue );
}
return( qfalse );
}
// Localize disable message info.
void G_voteDisableMessage( gentity_t *ent, const char *cmd ) {
G_refPrintf( ent, "Sorry, [lof]^3%s^7 [lon]voting has been disabled", cmd );
}
// Player ID message stub.
void G_playersMessage( gentity_t *ent ) {
G_refPrintf( ent, "Use the ^3players^7 command to find a valid player ID." );
}
// Localize current parameter setting.
void G_voteCurrentSetting( gentity_t *ent, const char *cmd, const char *setting ) {
G_refPrintf( ent, "^2%s^7 is currently ^3%s\n", cmd, setting );
}
// Vote toggling
int G_voteProcessOnOff( gentity_t *ent, char *arg, char *arg2, qboolean fRefereeCmd, int curr_setting, int vote_allow, int vote_type ) {
if ( !vote_allow && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, aVoteInfo[vote_type].pszVoteName );
G_voteCurrentSetting( ent, aVoteInfo[vote_type].pszVoteName, ( ( curr_setting ) ? ENABLED : DISABLED ) );
return( G_INVALID );
}
if ( G_voteDescription( ent, fRefereeCmd, vote_type ) ) {
G_voteCurrentSetting( ent, aVoteInfo[vote_type].pszVoteName, ( ( curr_setting ) ? ENABLED : DISABLED ) );
return( G_INVALID );
}
if ( ( atoi( arg2 ) && curr_setting ) || ( !atoi( arg2 ) && !curr_setting ) ) {
G_refPrintf( ent, "^3%s^5 is already %s!", aVoteInfo[vote_type].pszVoteName, ( ( curr_setting ) ? ENABLED : DISABLED ) );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%s", arg2 );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", ( atoi( arg2 ) ) ? ACTIVATED : DEACTIVATED );
return( G_OK );
}
//
// Several commands to help with cvar setting
//
void G_voteSetOnOff( const char *desc, const char *cvar ) {
AP( va( "cpm \"^3%s is: ^5%s\n\"", desc, ( atoi( level.voteInfo.vote_value ) ) ? ENABLED : DISABLED ) );
//trap_SendConsoleCommand(EXEC_APPEND, va("%s %s\n", cvar, level.voteInfo.vote_value));
trap_Cvar_Set( cvar, level.voteInfo.vote_value );
}
void G_voteSetValue( const char *desc, const char *cvar ) {
AP( va( "cpm \"^3%s set to: ^5%s\n\"", desc, level.voteInfo.vote_value ) );
//trap_SendConsoleCommand(EXEC_APPEND, va("%s %s\n", cvar, level.voteInfo.vote_value));
trap_Cvar_Set( cvar, level.voteInfo.vote_value );
}
void G_voteSetVoteString( const char *desc ) {
AP( va( "print \"^3%s set to: ^5%s\n\"", desc, level.voteInfo.vote_value ) );
trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteInfo.voteString ) );
}
////////////////////////////////////////////////////////
//
// Actual vote command implementation
//
////////////////////////////////////////////////////////
// *** Load competition settings for current mode ***
int G_Comp_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
} else if ( vote_allow_comp.integer <= 0 && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
}
// Vote action (vote has passed)
} else {
// Load in comp settings for current gametype
G_configSet( g_gametype.integer, qtrue );
AP( "cp \"Competition Settings Loaded!\n\"" );
}
return( G_OK );
}
void G_GametypeList( gentity_t *ent ) {
int i;
G_refPrintf( ent, "\nAvailable gametypes:\n--------------------" );
for ( i = GT_WOLF; i < GT_MAX_GAME_TYPE; i++ ) {
if ( i != GT_WOLF_CAMPAIGN ) {
G_refPrintf( ent, " %d ^3(%s)", i, gameNames[i] );
}
}
G_refPrintf( ent, "\n" );
}
// *** GameType ***
int G_Gametype_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
int i = atoi( arg2 );
if ( !vote_allow_gametype.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
G_GametypeList( ent );
G_voteCurrentSetting( ent, arg, va( "%d (%s)", g_gametype.integer, gameNames[g_gametype.integer] ) );
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
G_GametypeList( ent );
G_voteCurrentSetting( ent, arg, va( "%d (%s)", g_gametype.integer, gameNames[g_gametype.integer] ) );
return( G_INVALID );
}
if ( i < GT_WOLF || i >= GT_MAX_GAME_TYPE || i == GT_WOLF_CAMPAIGN ) {
G_refPrintf( ent, "\n^3Invalid gametype: ^7%d", i );
G_GametypeList( ent );
return( G_INVALID );
}
if ( i == g_gametype.integer ) {
G_refPrintf( ent, "\n^3Gametype^5 is already set to %s!", gameNames[i] );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%s", arg2 );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", gameNames[i] );
// Vote action (vote has passed)
} else {
// Set gametype
G_voteSetValue( "Gametype", "g_gametype" );
Svcmd_ResetMatch_f( qtrue, qtrue );
}
return( G_OK );
}
// *** Player Kick ***
int G_Kick_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
int pid;
if ( !vote_allow_kick.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return G_INVALID;
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
return G_INVALID;
} else if ( ( pid = ClientNumberFromString( ent, arg2 ) ) == -1 ) {
return G_INVALID;
}
if ( level.clients[ pid ].sess.referee ) {
G_refPrintf( ent, "Can't vote to kick referees!" );
return G_INVALID;
}
if ( !fRefereeCmd && ent ) {
if ( level.clients[ pid ].sess.sessionTeam != TEAM_SPECTATOR && level.clients[ pid ].sess.sessionTeam != ent->client->sess.sessionTeam ) {
G_refPrintf( ent, "Can't vote to kick players on opposing team!" );
return G_INVALID;
}
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%d", pid );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", level.clients[pid].pers.netname );
// Vote action (vote has passed)
} else {
// Kick a player
trap_SendConsoleCommand( EXEC_APPEND, va( "clientkick %d\n", atoi( level.voteInfo.vote_value ) ) );
AP( va( "cp \"%s\n^3has been kicked!\n\"", level.clients[ atoi( level.voteInfo.vote_value ) ].pers.netname ) );
}
return G_OK;
}
// *** Player Mute ***
int G_Mute_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
if ( fRefereeCmd ) {
// handled elsewhere
return( G_NOTFOUND );
}
// Vote request (vote is being initiated)
if ( arg ) {
int pid;
if ( !vote_allow_muting.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
return( G_INVALID );
} else if ( ( pid = ClientNumberFromString( ent, arg2 ) ) == -1 ) {
return( G_INVALID );
}
if ( level.clients[pid].sess.referee ) {
G_refPrintf( ent, "Can't vote to mute referees!" );
return( G_INVALID );
}
if ( level.clients[pid].sess.muted ) {
G_refPrintf( ent, "Player is already muted!" );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%d", pid );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", level.clients[pid].pers.netname );
// Vote action (vote has passed)
} else {
int pid = atoi( level.voteInfo.vote_value );
// Mute a player
if ( level.clients[pid].sess.referee != RL_RCON ) {
trap_SendServerCommand( pid, va( "cpm \"^3You have been muted\"" ) );
level.clients[pid].sess.muted = qtrue;
AP( va( "cp \"%s\n^3has been muted!\n\"", level.clients[pid].pers.netname ) );
ClientUserinfoChanged( pid );
} else {
G_Printf( "Cannot mute a referee.\n" );
}
}
return( G_OK );
}
// *** Player Un-Mute ***
int G_UnMute_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
if ( fRefereeCmd ) {
// handled elsewhere
return( G_NOTFOUND );
}
// Vote request (vote is being initiated)
if ( arg ) {
int pid;
if ( !vote_allow_muting.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
return( G_INVALID );
} else if ( ( pid = ClientNumberFromString( ent, arg2 ) ) == -1 ) {
return( G_INVALID );
}
if ( level.clients[pid].sess.referee ) {
G_refPrintf( ent, "Can't vote to un-mute referees!" );
return( G_INVALID );
}
if ( !level.clients[pid].sess.muted ) {
G_refPrintf( ent, "Player is not muted!" );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%d", pid );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", level.clients[pid].pers.netname );
// Vote action (vote has passed)
} else {
int pid = atoi( level.voteInfo.vote_value );
// Mute a player
if ( level.clients[pid].sess.referee != RL_RCON ) {
trap_SendServerCommand( pid, va( "cpm \"^3You have been un-muted\"" ) );
level.clients[pid].sess.muted = qfalse;
AP( va( "cp \"%s\n^3has been un-muted!\n\"", level.clients[pid].pers.netname ) );
ClientUserinfoChanged( pid );
} else {
G_Printf( "Cannot un-mute a referee.\n" );
}
}
return( G_OK );
}
// *** Map - simpleton: we dont verify map is allowed/exists ***
int G_Map_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
char serverinfo[MAX_INFO_STRING];
trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
if ( !vote_allow_map.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
G_voteCurrentSetting( ent, arg, Info_ValueForKey( serverinfo, "mapname" ) );
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
G_voteCurrentSetting( ent, arg, Info_ValueForKey( serverinfo, "mapname" ) );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%s", arg2 );
// Vote action (vote has passed)
} else {
char s[MAX_STRING_CHARS];
if ( g_gametype.integer == GT_WOLF_CAMPAIGN ) {
trap_Cvar_VariableStringBuffer( "nextcampaign", s, sizeof( s ) );
trap_SendConsoleCommand( EXEC_APPEND, va( "campaign %s%s\n", level.voteInfo.vote_value, ( ( *s ) ? va( "; set nextcampaign \"%s\"", s ) : "" ) ) );
} else {
Svcmd_ResetMatch_f( qtrue, qfalse );
trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof( s ) );
trap_SendConsoleCommand( EXEC_APPEND, va( "map %s%s\n", level.voteInfo.vote_value, ( ( *s ) ? va( "; set nextmap \"%s\"", s ) : "" ) ) );
}
}
return( G_OK );
}
// *** Campaign - simpleton: we dont verify map is allowed/exists ***
int G_Campaign_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
char serverinfo[MAX_INFO_STRING];
trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
if ( !vote_allow_map.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
if ( g_gametype.integer == GT_WOLF_CAMPAIGN ) {
G_voteCurrentSetting( ent, arg, g_campaigns[level.currentCampaign].shortname );
}
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
if ( g_gametype.integer == GT_WOLF_CAMPAIGN ) {
G_voteCurrentSetting( ent, arg, g_campaigns[level.currentCampaign].shortname );
}
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%s", arg2 );
// Vote action (vote has passed)
} else {
char s[MAX_STRING_CHARS];
trap_Cvar_VariableStringBuffer( "nextcampaign", s, sizeof( s ) );
trap_SendConsoleCommand( EXEC_APPEND, va( "campaign %s%s\n", level.voteInfo.vote_value, ( ( *s ) ? va( "; set nextcampaign \"%s\"", s ) : "" ) ) );
}
return( G_OK );
}
// *** Map Restart ***
int G_MapRestart_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
if ( !Q_stricmp( arg2, "?" ) ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
}
}
// Vote action (vote has passed)
} else {
// Restart the map back to warmup
Svcmd_ResetMatch_f( qfalse, qtrue );
AP( "cp \"^1*** Level Restarted! ***\n\"" );
}
return( G_OK );
}
// *** Match Restart ***
int G_MatchReset_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( !vote_allow_matchreset.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
} else if ( trap_Argc() != 2 && G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
return( G_INVALID );
// } else if(trap_Argc() > 2) {
// if(!Q_stricmp(arg2, "?")) {
// G_refPrintf(ent, "Usage: ^3%s %s%s\n", ((fRefereeCmd) ? "\\ref" : "\\callvote"), arg, aVoteInfo[dwVoteIndex].pszVoteHelp);
// return(G_INVALID);
// }
}
// Vote action (vote has passed)
} else {
// Restart the map back to warmup
Svcmd_ResetMatch_f( qtrue, qtrue );
AP( "cp \"^1*** Match Reset! ***\n\"" );
}
return( G_OK );
}
// *** Mute Spectators ***
int G_Mutespecs_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
return( G_voteProcessOnOff( ent, arg, arg2, fRefereeCmd,
!!( match_mutespecs.integer ),
vote_allow_mutespecs.integer,
dwVoteIndex ) );
// Vote action (vote has passed)
} else {
// Mute/unmute spectators
G_voteSetOnOff( "Spectator Muting", "match_mutespecs" );
}
return( G_OK );
}
// *** Nextmap ***
int G_Nextmap_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
} else if ( !vote_allow_nextmap.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
} else {
char s[MAX_STRING_CHARS];
if ( g_gametype.integer == GT_WOLF_CAMPAIGN ) {
trap_Cvar_VariableStringBuffer( "nextcampaign", s, sizeof( s ) );
if ( !*s ) {
G_refPrintf( ent, "'nextcampaign' is not set." );
return( G_INVALID );
}
} else {
trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof( s ) );
if ( !*s ) {
G_refPrintf( ent, "'nextmap' is not set." );
return( G_INVALID );
}
}
}
// Vote action (vote has passed)
} else {
if ( g_gametype.integer == GT_WOLF_CAMPAIGN ) {
// Load in the nextcampaign
trap_SendConsoleCommand( EXEC_APPEND, "vstr nextcampaign\n" );
AP( "cp \"^3*** Loading nextcampaign! ***\n\"" );
} else {
// Load in the nextmap
trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" );
AP( "cp \"^3*** Loading nextmap! ***\n\"" );
}
}
return( G_OK );
}
// *** Load public settings for current mode ***
int G_Pub_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
} else if ( vote_allow_pub.integer <= 0 && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
}
// Vote action (vote has passed)
} else {
// Load in pub settings for current gametype
G_configSet( g_gametype.integer, qfalse );
AP( "cp \"Public Settings Loaded!\n\"" );
}
return( G_OK );
}
// *** Referee voting ***
int G_Referee_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
int pid;
if ( !vote_allow_referee.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
}
if ( !ent->client->sess.referee && level.numPlayingClients < 3 ) {
G_refPrintf( ent, "Sorry, not enough clients in the game to vote for a referee" );
return( G_INVALID );
}
if ( ent->client->sess.referee && trap_Argc() == 2 ) {
G_playersMessage( ent );
return( G_INVALID );
} else if ( trap_Argc() == 2 ) {
pid = ent - g_entities;
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
return( G_INVALID );
} else if ( ( pid = ClientNumberFromString( ent, arg2 ) ) == -1 ) {
return( G_INVALID );
}
if ( level.clients[pid].sess.referee ) {
G_refPrintf( ent, "[lof]%s [lon]is already a referee!", level.clients[pid].pers.netname );
return( -1 );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%d", pid );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", level.clients[pid].pers.netname );
// Vote action (vote has passed)
} else {
// Voting in a new referee
gclient_t *cl = &level.clients[atoi( level.voteInfo.vote_value )];
if ( cl->pers.connected == CON_DISCONNECTED ) {
AP( "print \"Player left before becoming referee\n\"" );
} else {
cl->sess.referee = RL_REFEREE; // FIXME: Differentiate voted refs from passworded refs
cl->sess.spec_invite = TEAM_AXIS | TEAM_ALLIES;
AP( va( "cp \"%s^7 is now a referee\n\"", cl->pers.netname ) );
ClientUserinfoChanged( atoi( level.voteInfo.vote_value ) );
}
}
return( G_OK );
}
// *** Shuffle teams
int G_ShuffleTeams_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
} else if ( !vote_allow_shuffleteamsxp.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
}
// Vote action (vote has passed)
} else {
// Swap the teams!
Svcmd_ShuffleTeams_f();
}
return( G_OK );
}
// *** Start Match ***
int G_StartMatch_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
if ( !Q_stricmp( arg2, "?" ) ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
}
}
if ( g_gamestate.integer == GS_PLAYING || g_gamestate.integer == GS_INTERMISSION ) {
G_refPrintf( ent, "^3Match is already in progress!" );
return( G_INVALID );
}
if ( g_gamestate.integer == GS_WARMUP_COUNTDOWN ) {
G_refPrintf( ent, "^3Countdown already started!" );
return( G_INVALID );
}
if ( level.numPlayingClients < match_minplayers.integer ) {
G_refPrintf( ent, "^3Not enough players to start match!" );
return( G_INVALID );
}
// Vote action (vote has passed)
} else {
// Set everyone to "ready" status
G_refAllReady_cmd( NULL );
}
return( G_OK );
}
// *** Swap teams
int G_SwapTeams_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( trap_Argc() > 2 ) {
G_refPrintf( ent, "Usage: ^3%s %s%s\n", ( ( fRefereeCmd ) ? "\\ref" : "\\callvote" ), arg, aVoteInfo[dwVoteIndex].pszVoteHelp );
return( G_INVALID );
} else if ( !vote_allow_swapteams.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
}
// Vote action (vote has passed)
} else {
// Swap the teams!
Svcmd_SwapTeams_f();
}
return( G_OK );
}
// *** Team Damage ***
int G_FriendlyFire_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
return( G_voteProcessOnOff( ent, arg, arg2, fRefereeCmd,
!!( g_friendlyFire.integer ),
vote_allow_friendlyfire.integer,
dwVoteIndex ) );
// Vote action (vote has passed)
} else {
// Team damage (friendlyFire)
G_voteSetOnOff( "Friendly Fire", "g_friendlyFire" );
}
return( G_OK );
}
// Anti-Lag
int G_AntiLag_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
return( G_voteProcessOnOff( ent, arg, arg2, fRefereeCmd,
!!( g_antilag.integer ),
vote_allow_antilag.integer,
dwVoteIndex ) );
// Vote action (vote has passed)
} else {
// Anti-Lag (g_antilag)
G_voteSetOnOff( "Anti-Lag", "g_antilag" );
}
return( G_OK );
}
// Balanced Teams
int G_BalancedTeams_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
return( G_voteProcessOnOff( ent, arg, arg2, fRefereeCmd,
!!( g_balancedteams.integer ),
vote_allow_balancedteams.integer,
dwVoteIndex ) );
// Vote action (vote has passed)
} else {
// Balanced Teams (g_balancedteams)
G_voteSetOnOff( "Balanced Teams", "g_balancedteams" );
trap_Cvar_Set( "g_teamForceBalance", level.voteInfo.vote_value );
trap_Cvar_Set( "g_lms_teamForceBalance", level.voteInfo.vote_value );
}
return( G_OK );
}
// *** Timelimit ***
int G_Timelimit_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
if ( !vote_allow_timelimit.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
G_voteCurrentSetting( ent, arg, g_timelimit.string );
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
G_voteCurrentSetting( ent, arg, g_timelimit.string );
return( G_INVALID );
} else if ( atoi( arg2 ) < 0 ) {
G_refPrintf( ent, "Sorry, can't specify a timelimit < 0!" );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%s", arg2 );
// Vote action (vote has passed)
} else {
// Timelimit change
G_voteSetVoteString( "Timelimit" );
}
return( G_OK );
}
char *warmupType[] = { "None", "Enemies Only", "Everyone" };
void G_WarmupDamageTypeList( gentity_t *ent ) {
int i;
G_refPrintf( ent, "\nAvailable Warmup Damage types:\n------------------------------" );
for ( i = 0; i < ( sizeof( warmupType ) / sizeof( char * ) ); i++ ) G_refPrintf( ent, " %d ^3(%s)", i, warmupType[i] );
G_refPrintf( ent, "\n" );
}
// *** Warmup Weapon Fire ***
int G_Warmupfire_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
int i = atoi( arg2 ), val = ( match_warmupDamage.integer < 0 ) ? 0 :
( match_warmupDamage.integer > 2 ) ? 2 :
match_warmupDamage.integer;
if ( !vote_allow_warmupdamage.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
G_WarmupDamageTypeList( ent );
G_voteCurrentSetting( ent, arg, va( "%d (%s)", val, warmupType[val] ) );
return( G_INVALID );
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
G_WarmupDamageTypeList( ent );
G_voteCurrentSetting( ent, arg, va( "%d (%s)", val, warmupType[val] ) );
return( G_INVALID );
}
if ( i < 0 || i > 2 ) {
G_refPrintf( ent, "\n^3Invalid Warmup Damage type: ^7%d", i );
G_WarmupDamageTypeList( ent );
return( G_INVALID );
}
if ( i == val ) {
G_refPrintf( ent, "\n^3Warmup Damage^5 is already set to %s!", warmupType[i] );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%s", arg2 );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", warmupType[i] );
// Vote action (vote has passed)
} else {
// Warmup damage setting
AP( va( "print \"^3Warmup Damage set to: ^5%s\n\"", warmupType[atoi( level.voteInfo.vote_value )] ) );
trap_SendConsoleCommand( EXEC_APPEND, va( "match_warmupDamage %s\n", level.voteInfo.vote_value ) );
}
return( G_OK );
}
// *** Un-Referee voting ***
int G_Unreferee_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
// Vote request (vote is being initiated)
if ( arg ) {
int pid;
if ( !vote_allow_referee.integer && ent && !ent->client->sess.referee ) {
G_voteDisableMessage( ent, arg );
return( G_INVALID );
}
if ( ent->client->sess.referee && trap_Argc() == 2 ) {
G_playersMessage( ent );
return( G_INVALID );
} else if ( trap_Argc() == 2 ) {
pid = ent - g_entities;
} else if ( G_voteDescription( ent, fRefereeCmd, dwVoteIndex ) ) {
return( G_INVALID );
} else if ( ( pid = ClientNumberFromString( ent, arg2 ) ) == -1 ) {
return( G_INVALID );
}
if ( level.clients[pid].sess.referee == RL_NONE ) {
G_refPrintf( ent, "[lof]%s [lon]isn't a referee!", level.clients[pid].pers.netname );
return( G_INVALID );
}
if ( level.clients[pid].sess.referee == RL_RCON ) {
G_refPrintf( ent, "[lof]%s's [lon]status cannot be removed", level.clients[pid].pers.netname );
return( G_INVALID );
}
if ( level.clients[pid].pers.localClient ) {
G_refPrintf( ent, "[lof]%s's [lon]is the Server Host", level.clients[pid].pers.netname );
return( G_INVALID );
}
Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%d", pid );
Com_sprintf( arg2, VOTE_MAXSTRING, "%s", level.clients[pid].pers.netname );
// Vote action (vote has passed)
} else {
// Stripping of referee status
gclient_t *cl = &level.clients[atoi( level.voteInfo.vote_value )];
cl->sess.referee = RL_NONE;
cl->sess.spec_invite = 0;
AP( va( "cp \"%s^7\nis no longer a referee\n\"", cl->pers.netname ) );
ClientUserinfoChanged( atoi( level.voteInfo.vote_value ) );
}
return( G_OK );
}