diff options
-rw-r--r-- | src/cgame/cg_draw.c | 73 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 16 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 13 | ||||
-rw-r--r-- | src/cgame/cg_servercmds.c | 76 | ||||
-rw-r--r-- | src/game/bg_public.h | 13 | ||||
-rw-r--r-- | src/game/g_active.c | 6 | ||||
-rw-r--r-- | src/game/g_admin.c | 31 | ||||
-rw-r--r-- | src/game/g_buildable.c | 2 | ||||
-rw-r--r-- | src/game/g_client.c | 5 | ||||
-rw-r--r-- | src/game/g_cmds.c | 637 | ||||
-rw-r--r-- | src/game/g_local.h | 37 | ||||
-rw-r--r-- | src/game/g_main.c | 323 | ||||
-rw-r--r-- | src/game/g_svcmds.c | 16 | ||||
-rw-r--r-- | src/game/g_team.c | 2 |
14 files changed, 383 insertions, 867 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index 4ae6792d..ba8aaacf 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -2756,76 +2756,39 @@ static void CG_DrawCenterString( void ) CG_DrawVote ================= */ -static void CG_DrawVote( void ) +static void CG_DrawVote( team_t team ) { char *s; int sec; vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; char yeskey[ 32 ], nokey[ 32 ]; - if( !cgs.voteTime ) + if( !cgs.voteTime[ team ] ) return; // play a talk beep whenever it is modified - if( cgs.voteModified ) + if( cgs.voteModified[ team ] ) { - cgs.voteModified = qfalse; + cgs.voteModified[ team ] = qfalse; trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); } - sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000; + sec = ( VOTE_TIME - ( cg.time - cgs.voteTime[ team ] ) ) / 1000; if( sec < 0 ) sec = 0; - Q_strncpyz( yeskey, CG_KeyBinding( "vote yes" ), sizeof( yeskey ) ); - Q_strncpyz( nokey, CG_KeyBinding( "vote no" ), sizeof( nokey ) ); - s = va( "VOTE(%i): \"%s\" [%s]Yes:%i [%s]No:%i", sec, cgs.voteString, - yeskey, cgs.voteYes, nokey, cgs.voteNo ); - UI_Text_Paint( 8, 340, 0.3f, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL ); -} - -/* -================= -CG_DrawTeamVote -================= -*/ -static void CG_DrawTeamVote( void ) -{ - char *s; - int sec, cs_offset; - vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; - char yeskey[ 32 ], nokey[ 32 ]; - - if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS ) - cs_offset = 0; - else if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS ) - cs_offset = 1; - else - return; - - if( !cgs.teamVoteTime[ cs_offset ] ) - return; - - // play a talk beep whenever it is modified - if ( cgs.teamVoteModified[ cs_offset ] ) - { - cgs.teamVoteModified[ cs_offset ] = qfalse; - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - } - - sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[ cs_offset ] ) ) / 1000; - - if( sec < 0 ) - sec = 0; - - Q_strncpyz( yeskey, CG_KeyBinding( "teamvote yes" ), sizeof( yeskey ) ); - Q_strncpyz( nokey, CG_KeyBinding( "teamvote no" ), sizeof( nokey ) ); - s = va( "TEAMVOTE(%i): \"%s\" [%s]Yes:%i [%s]No:%i", sec, - cgs.teamVoteString[ cs_offset ], - yeskey, cgs.teamVoteYes[cs_offset], - nokey, cgs.teamVoteNo[ cs_offset ] ); - UI_Text_Paint( 8, 360, 0.3f, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL ); + Q_strncpyz( yeskey, + CG_KeyBinding( va( "%svote yes", team == TEAM_NONE ? "" : "team" ) ), + sizeof( yeskey ) ); + Q_strncpyz( nokey, + CG_KeyBinding( va( "%svote no", team == TEAM_NONE ? "" : "team" ) ), + sizeof( nokey ) ); + s = va( "%sVOTE(%i): \"%s\" [%s]Yes:%i [%s]No:%i", + team == TEAM_NONE ? "" : "TEAM", sec, cgs.voteString[ team ], + yeskey, cgs.voteYes[ team ], nokey, cgs.voteNo[ team ] ); + UI_Text_Paint( 8, team == TEAM_NONE ? 340 : 360, 0.3f, white, s, 0, 0, + ITEM_TEXTSTYLE_NORMAL ); } @@ -2999,8 +2962,8 @@ static void CG_Draw2D( void ) Menu_Paint( menu, qtrue ); - CG_DrawVote( ); - CG_DrawTeamVote( ); + CG_DrawVote( TEAM_NONE ); + CG_DrawVote( cg.predictedPlayerState.stats[ STAT_TEAM ] ); CG_DrawQueue( ); // don't draw center string if scoreboard is up diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 17328819..f7dda861 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1356,17 +1356,11 @@ typedef struct char mapname[ MAX_QPATH ]; qboolean markDeconstruct; // Whether or not buildables are marked - int voteTime; - int voteYes; - int voteNo; - qboolean voteModified; // beep whenever changed - char voteString[ MAX_STRING_TOKENS ]; - - int teamVoteTime[ 2 ]; - int teamVoteYes[ 2 ]; - int teamVoteNo[ 2 ]; - qboolean teamVoteModified[ 2 ]; // beep whenever changed - char teamVoteString[ 2 ][ MAX_STRING_TOKENS ]; + int voteTime[ NUM_TEAMS ]; + int voteYes[ NUM_TEAMS ]; + int voteNo[ NUM_TEAMS ]; + qboolean voteModified[ NUM_TEAMS ];// beep whenever changed + char voteString[ NUM_TEAMS ][ MAX_STRING_TOKENS ]; int levelStartTime; diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 68a34159..01c24579 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -1763,12 +1763,15 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) // copy vote display strings so they don't show up blank if we see // the same one directly after connecting - Q_strncpyz( cgs.voteString, CG_ConfigString( CS_VOTE_STRING ), + Q_strncpyz( cgs.voteString[ TEAM_NONE ], + CG_ConfigString( CS_VOTE_STRING + TEAM_NONE ), sizeof( cgs.voteString ) ); - Q_strncpyz( cgs.teamVoteString[ 0 ], CG_ConfigString( CS_TEAMVOTE_STRING + 0 ), - sizeof( cgs.teamVoteString[ 0 ] ) ); - Q_strncpyz( cgs.teamVoteString[ 1 ], CG_ConfigString( CS_TEAMVOTE_STRING + 1 ), - sizeof( cgs.teamVoteString[ 1 ] ) ); + Q_strncpyz( cgs.voteString[ TEAM_ALIENS ], + CG_ConfigString( CS_VOTE_STRING + TEAM_ALIENS ), + sizeof( cgs.voteString[ TEAM_ALIENS ] ) ); + Q_strncpyz( cgs.voteString[ TEAM_HUMANS ], + CG_ConfigString( CS_VOTE_STRING + TEAM_ALIENS ), + sizeof( cgs.voteString[ TEAM_HUMANS ] ) ); // check version s = CG_ConfigString( CS_GAME_VERSION ); diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c index 2d9b7038..8e18fd9c 100644 --- a/src/cgame/cg_servercmds.c +++ b/src/cgame/cg_servercmds.c @@ -291,65 +291,33 @@ static void CG_ConfigStringModified( void ) } else if( num == CS_LEVEL_START_TIME ) cgs.levelStartTime = atoi( str ); - else if( num == CS_VOTE_TIME ) + else if( num >= CS_VOTE_TIME && num < CS_VOTE_TIME + NUM_TEAMS ) { - cgs.voteTime = atoi( str ); - cgs.voteModified = qtrue; - - if( cgs.voteTime ) - trap_Cvar_Set( "ui_voteActive", "1" ); - else - trap_Cvar_Set( "ui_voteActive", "0" ); - } - else if( num == CS_VOTE_YES ) - { - cgs.voteYes = atoi( str ); - cgs.voteModified = qtrue; - } - else if( num == CS_VOTE_NO ) - { - cgs.voteNo = atoi( str ); - cgs.voteModified = qtrue; - } - else if( num == CS_VOTE_STRING ) - Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) ); - else if( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1 ) - { - int cs_offset = num - CS_TEAMVOTE_TIME; - - cgs.teamVoteTime[ cs_offset ] = atoi( str ); - cgs.teamVoteModified[ cs_offset ] = qtrue; - - if( cs_offset == 0 ) - { - if( cgs.teamVoteTime[ cs_offset ] ) - trap_Cvar_Set( "ui_humanTeamVoteActive", "1" ); - else - trap_Cvar_Set( "ui_humanTeamVoteActive", "0" ); - } - else if( cs_offset == 1 ) - { - if( cgs.teamVoteTime[ cs_offset ] ) - trap_Cvar_Set( "ui_alienTeamVoteActive", "1" ); - else - trap_Cvar_Set( "ui_alienTeamVoteActive", "0" ); - } - } - else if( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1 ) - { - cgs.teamVoteYes[ num - CS_TEAMVOTE_YES ] = atoi( str ); - cgs.teamVoteModified[ num - CS_TEAMVOTE_YES ] = qtrue; + cgs.voteTime[ num - CS_VOTE_TIME ] = atoi( str ); + cgs.voteModified[ num - CS_VOTE_TIME ] = qtrue; + + if( num - CS_VOTE_TIME == TEAM_NONE ) + trap_Cvar_Set( "ui_voteActive", cgs.voteTime[ TEAM_NONE ] ? "1" : "0" ); + else if( num - CS_VOTE_TIME == TEAM_ALIENS ) + trap_Cvar_Set( "ui_alienTeamVoteActive", + cgs.voteTime[ TEAM_ALIENS ] ? "1" : "0" ); + else if( num - CS_VOTE_TIME == TEAM_HUMANS ) + trap_Cvar_Set( "ui_humanTeamVoteActive", + cgs.voteTime[ TEAM_HUMANS ] ? "1" : "0" ); } - else if( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1 ) + else if( num >= CS_VOTE_YES && num < CS_VOTE_YES + NUM_TEAMS ) { - cgs.teamVoteNo[ num - CS_TEAMVOTE_NO ] = atoi( str ); - cgs.teamVoteModified[ num - CS_TEAMVOTE_NO ] = qtrue; + cgs.voteYes[ num - CS_VOTE_YES ] = atoi( str ); + cgs.voteModified[ num - CS_VOTE_YES ] = qtrue; } - else if( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1 ) + else if( num >= CS_VOTE_NO && num < CS_VOTE_NO + NUM_TEAMS ) { - Q_strncpyz( cgs.teamVoteString[ num - CS_TEAMVOTE_STRING ], str, - sizeof( cgs.teamVoteString[ num - CS_TEAMVOTE_STRING ] ) ); + cgs.voteNo[ num - CS_VOTE_NO ] = atoi( str ); + cgs.voteModified[ num - CS_VOTE_NO ] = qtrue; } + else if( num >= CS_VOTE_STRING && num < CS_VOTE_STRING + NUM_TEAMS ) + Q_strncpyz( cgs.voteString[ num - CS_VOTE_STRING ], str, + sizeof( cgs.voteString[ num - CS_VOTE_STRING ] ) ); else if( num == CS_INTERMISSION ) cg.intermissionStarted = atoi( str ); else if( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) @@ -406,7 +374,7 @@ static void CG_MapRestart( void ) cg.intermissionStarted = qfalse; - cgs.voteTime = 0; + cgs.voteTime[ TEAM_NONE ] = 0; cg.mapRestart = qtrue; diff --git a/src/game/bg_public.h b/src/game/bg_public.h index a42fb735..480139cf 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -52,14 +52,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // 6 UNUSED // 7 UNUSED #define CS_VOTE_TIME 8 -#define CS_VOTE_STRING 9 -#define CS_VOTE_YES 10 -#define CS_VOTE_NO 11 - -#define CS_TEAMVOTE_TIME 12 -#define CS_TEAMVOTE_STRING 14 -#define CS_TEAMVOTE_YES 16 -#define CS_TEAMVOTE_NO 18 +#define CS_VOTE_STRING (CS_VOTE_TIME + NUM_TEAMS) +#define CS_VOTE_YES (CS_VOTE_STRING + NUM_TEAMS) +#define CS_VOTE_NO (CS_VOTE_YES + NUM_TEAMS) #define CS_GAME_VERSION 20 #define CS_LEVEL_START_TIME 21 // so the timer only shows the current level @@ -296,8 +291,6 @@ typedef enum #define EF_MOVER_STOP 0x00001000 // will push otherwise #define EF_POISONCLOUDED 0x00002000 // player hit with basilisk gas #define EF_CONNECTION 0x00004000 // draw a connection trouble sprite -#define EF_VOTED 0x00008000 // already cast a vote -#define EF_TEAMVOTED 0x00010000 // already cast a vote #define EF_BLOBLOCKED 0x00020000 // caught by a trapper #define EF_WARN_CHARGE 0x00040000 // Lucifer Cannon is about to overcharge diff --git a/src/game/g_active.c b/src/game/g_active.c index 5eb5d3d1..236bc708 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -1812,7 +1812,7 @@ SpectatorClientEndFrame void SpectatorClientEndFrame( gentity_t *ent ) { gclient_t *cl; - int clientNum, flags; + int clientNum; int score, ping; // if we are doing a chase cam or a remote view, grab the latest info @@ -1824,9 +1824,6 @@ void SpectatorClientEndFrame( gentity_t *ent ) cl = &level.clients[ clientNum ]; if( cl->pers.connected == CON_CONNECTED ) { - // Save - flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) | - ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) ); score = ent->client->ps.persistant[ PERS_SCORE ]; ping = ent->client->ps.ping; @@ -1834,7 +1831,6 @@ void SpectatorClientEndFrame( gentity_t *ent ) ent->client->ps = cl->ps; // Restore - ent->client->ps.eFlags = flags; ent->client->ps.persistant[ PERS_SCORE ] = score; ent->client->ps.ping = ping; diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 167c134a..dc41e700 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -2669,33 +2669,18 @@ qboolean G_admin_endvote( gentity_t *ent, int skiparg ) msg = va( "print \"^3!%s: ^7%s^7 decided that everyone voted %s\n\"", cmd, ( ent ) ? ent->client->pers.netname : "console", cancel ? "No" : "Yes" ); - if( team == TEAM_NONE ) + if( !level.voteTime[ team ] ) { - if( !level.voteTime ) - { - ADMP( va( "^3!%s: ^7no vote in progress\n", cmd ) ); - return qfalse; - } - level.voteNo = cancel ? MAX_CLIENTS : 0; - level.voteYes = cancel ? 0 : MAX_CLIENTS; - CheckVote(); - AP( msg ); + ADMP( va( "^3!%s: ^7no vote in progress\n", cmd ) ); + return qfalse; } + level.voteNo[ team ] = cancel ? level.numVotingClients[ team ] : 0; + level.voteYes[ team ] = cancel ? 0 : level.numVotingClients[ team ]; + CheckVote( team ); + if( team == TEAM_NONE ) + AP( msg ); else - { - int offset = 0; - if( team == TEAM_ALIENS ) - offset++; - if( !level.teamVoteTime[ offset ] ) - { - ADMP( va( "^3!%s: ^7no vote in progress\n", cmd ) ); - return qfalse; - } - level.teamVoteNo[ offset ] = cancel ? MAX_CLIENTS : 0; - level.teamVoteYes[ offset ] = cancel ? 0 : MAX_CLIENTS; - CheckTeamVote( team ); G_TeamCommand( team, msg ); - } return qtrue; } diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index 3fb7296f..25edb023 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -346,7 +346,7 @@ Get the number of build points from a position */ int G_GetBuildPoints( const vec3_t pos, team_t team, int extraDistance ) { - if( level.suddenDeath ) + if( G_TimeTilSuddenDeath( ) <= 0 ) { return 0; } diff --git a/src/game/g_client.c b/src/game/g_client.c index 78440563..8fe6ae96 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1436,8 +1436,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles } // toggle the teleport bit so the client knows to not lerp - flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ); - flags ^= EF_TELEPORT_BIT; + flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // clear everything but the persistant data @@ -1689,7 +1688,7 @@ void ClientDisconnect( int clientNum ) G_admin_namelog_update( ent->client, qtrue ); G_LeaveTeam( ent ); - G_Vote( ent, qfalse ); + G_Vote( ent, TEAM_NONE, qfalse ); // stop any following clients for( i = 0; i < level.maxclients; i++ ) diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 6d9fc217..9cda473e 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -998,487 +998,267 @@ Cmd_CallVote_f */ void Cmd_CallVote_f( gentity_t *ent ) { - int i; - char arg1[ MAX_STRING_TOKENS ]; - char arg2[ MAX_NAME_LENGTH ]; - int clientNum = -1; - char name[ MAX_NAME_LENGTH ]; + char cmd[ MAX_TOKEN_CHARS ], + vote[ MAX_TOKEN_CHARS ], + arg[ MAX_TOKEN_CHARS ]; + char name[ MAX_NAME_LENGTH ] = ""; + int clientNum = -1; + team_t team; + + trap_Argv( 0, cmd, sizeof( cmd ) ); + trap_Argv( 1, vote, sizeof( vote ) ); + trap_Argv( 2, arg, sizeof( arg ) ); + + if( !Q_stricmp( cmd, "callteamvote" ) ) + team = ent->client->pers.teamSelection; + else + team = TEAM_NONE; if( !g_allowVote.integer ) { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" ); + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: voting not allowed here\n\"", cmd ) ); return; } - if( level.voteTime ) + if( level.voteTime[ team ] ) { - trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress\n\"" ); + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: a vote is already in progress\n\"", cmd ) ); return; } + level.voteThreshold[ team ] = 50; + if( g_voteLimit.integer > 0 && ent->client->pers.voteCount >= g_voteLimit.integer && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) ) { trap_SendServerCommand( ent-g_entities, va( - "print \"You have already called the maximum number of votes (%d)\n\"", - g_voteLimit.integer ) ); - return; - } - - // make sure it is a valid command to vote on - trap_Argv( 1, arg1, sizeof( arg1 ) ); - trap_Argv( 2, arg2, sizeof( arg2 ) ); - - if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) - { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" ); + "print \"%s: you have already called the maximum number of votes (%d)\n\"", + cmd, g_voteLimit.integer ) ); return; } - // if there is still a vote to be executed - if( level.voteExecuteTime ) + trap_Argv( 1, vote, sizeof( vote ) ); + // 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" ) ) { - level.voteExecuteTime = 0; - trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) ); - } + int clientNums[ MAX_CLIENTS ]; + int matches; + char err[ MAX_STRING_CHARS ]; - level.votePassThreshold = 50; - - // detect clientNum for partial name match votes - if( !Q_stricmp( arg1, "kick" ) || - !Q_stricmp( arg1, "mute" ) || - !Q_stricmp( arg1, "unmute" ) ) - { - int clientNums[ MAX_CLIENTS ]; - int matches = 0; - char err[ MAX_STRING_CHARS ] = ""; - - if( !arg2[ 0 ] ) + if( !arg[ 0 ] ) { trap_SendServerCommand( ent-g_entities, - "print \"callvote: no target\n\"" ); + va( "print \"%s: no target\n\"", cmd ) ); return; } - matches = G_ClientNumbersFromString( arg2, clientNums, MAX_CLIENTS ); + // with a little extra work only players from the right team are considered + matches = G_ClientNumbersFromString( arg, clientNums, MAX_CLIENTS ); if( matches == 1 ) - { - // there was only one partial name match clientNum = clientNums[ 0 ]; - } else - { - // look for an exact name match (sets clientNum to -1 if it fails) - clientNum = G_ClientNumberFromString( arg2 ); - } + clientNum = G_ClientNumberFromString( arg ); if( clientNum != -1 ) { - Q_strncpyz( name, level.clients[ clientNum ].pers.netname, - sizeof( name ) ); - Q_CleanStr( name ); + G_SanitiseString( level.clients[ clientNum ].pers.netname, name, sizeof( name ) ); } else if( matches > 1 ) { G_MatchOnePlayer( clientNums, matches, err, sizeof( err ) ); - ADMP( va( "^3callvote: ^7%s\n", err ) ); + ADMP( va( "%s: %s\n", cmd, err ) ); return; } else { trap_SendServerCommand( ent-g_entities, - "print \"callvote: invalid player\n\"" ); + va( "print \"%s: invalid player\n\"", cmd ) ); return; } - } - if( !Q_stricmp( arg1, "kick" ) ) - { - if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) ) - { - trap_SendServerCommand( ent-g_entities, - "print \"callvote: admin is immune from vote kick\n\"" ); - return; - } - if( level.clients[ clientNum ].pers.localClient ) + if( !Q_stricmp( vote, "kick" ) || !Q_stricmp( vote, "mute" ) || + !Q_stricmp( vote, "denybuild" ) ) { - trap_SendServerCommand( ent-g_entities, - "print \"callvote: host is immune from vote kick\n\"" ); - return; + if( G_admin_permission( g_entities + clientNum, ADMF_IMMUNITY ) ) + { + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: admin is immune\n\"", cmd ) ); + return; + } } - - // use ip in case this player disconnects before the vote ends - Com_sprintf( level.voteString, sizeof( level.voteString ), - "!ban %s \"1s%s\" vote kick", level.clients[ clientNum ].pers.ip, - g_adminTempBan.string ); - Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), - "Kick player \'%s\'", name ); } - else if( !Q_stricmp( arg1, "mute" ) ) - { - if( level.clients[ clientNum ].pers.muted ) - { - trap_SendServerCommand( ent-g_entities, - "print \"callvote: player is already muted\n\"" ); - return; - } - if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) ) - { - trap_SendServerCommand( ent-g_entities, - "print \"callvote: admin is immune from vote mute\n\"" ); - return; - } - Com_sprintf( level.voteString, sizeof( level.voteString ), - "!mute %i", clientNum ); - Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), - "Mute player \'%s\'", name ); - } - else if( !Q_stricmp( arg1, "unmute" ) ) + if( !Q_stricmp( vote, "kick" ) ) { - if( !level.clients[ clientNum ].pers.muted ) + if( level.clients[ clientNum ].pers.localClient ) { trap_SendServerCommand( ent-g_entities, - "print \"callvote: player is not currently muted\n\"" ); - return; - } - Com_sprintf( level.voteString, sizeof( level.voteString ), - "!unmute %i", clientNum ); - Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), - "Un-Mute player \'%s\'", name ); - } - else if( !Q_stricmp( arg1, "map_restart" ) ) - { - Com_sprintf( level.voteString, sizeof( level.voteString ), "%s", arg1 ); - Com_sprintf( level.voteDisplayString, - sizeof( level.voteDisplayString ), "Restart current map" ); - } - else if( !Q_stricmp( arg1, "map" ) ) - { - if( !G_MapExists( arg2 ) ) - { - trap_SendServerCommand( ent - g_entities, va( "print \"callvote: " - "'maps/%s.bsp' could not be found on the server\n\"", arg2 ) ); + va( "print \"%s: admin is immune\n\"", cmd ) ); return; } - Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 ); - Com_sprintf( level.voteDisplayString, - sizeof( level.voteDisplayString ), "Change to map '%s'", arg2 ); + Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ), + "ban %s \"1s%s\" vote kick", level.clients[ clientNum ].pers.ip, + g_adminTempBan.string ); + Com_sprintf( level.voteDisplayString[ team ], + sizeof( level.voteDisplayString[ team ] ), + "Kick player '%s'", name ); } - else if( !Q_stricmp( arg1, "nextmap" ) ) + else if( team == TEAM_NONE ) { - if( G_MapExists( g_nextMap.string ) ) + if( !Q_stricmp( vote, "mute" ) ) { - trap_SendServerCommand( ent - g_entities, va( "print \"callvote: " - "the next map is already set to '%s^7'\n\"", g_nextMap.string ) ); - return; - } + if( level.clients[ clientNum ].pers.muted ) + { + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: player is already muted\n\"", cmd ) ); + return; + } - if( !G_MapExists( arg2 ) ) - { - trap_SendServerCommand( ent - g_entities, va( "print \"callvote: " - "'maps/%s^7.bsp' could not be found on the server\n\"", arg2 ) ); - return; + Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ), + "mute %d", clientNum ); + Com_sprintf( level.voteDisplayString[ team ], + sizeof( level.voteDisplayString[ team ] ), + "Mute player '%s'", name ); } - - Com_sprintf( level.voteString, sizeof( level.voteString ), - "set g_nextMap %s", arg2 ); - - Com_sprintf( level.voteDisplayString, - sizeof( level.voteDisplayString ), "Set the next map to '%s^7'", arg2 ); - } - else if( !Q_stricmp( arg1, "draw" ) ) - { - Com_sprintf( level.voteString, sizeof( level.voteString ), "evacuation" ); - Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), - "End match in a draw" ); - } - else if( !Q_stricmp( arg1, "sudden_death" ) || - !Q_stricmp( arg1, "suddendeath" ) ) - { - if(!g_suddenDeathVotePercent.integer) - { - trap_SendServerCommand( ent-g_entities, - "print \"Sudden Death votes have been disabled\n\"" ); - return; - } - else if( g_suddenDeath.integer ) + else if( !Q_stricmp( vote, "unmute" ) ) { - trap_SendServerCommand( ent - g_entities, - va( "print \"callvote: Sudden Death has already begun\n\"") ); - return; + if( !level.clients[ clientNum ].pers.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", clientNum ); + Com_sprintf( level.voteDisplayString[ team ], + sizeof( level.voteDisplayString[ team ] ), + "Unmute player '%s'", name ); } - else if( G_TimeTilSuddenDeath() <= g_suddenDeathVoteDelay.integer * 1000 ) + else if( !Q_stricmp( vote, "map_restart" ) ) { - trap_SendServerCommand( ent - g_entities, - va( "print \"callvote: Sudden Death is already immenent\n\"") ); - return; + strcpy( level.voteString[ team ], vote ); + strcpy( level.voteDisplayString[ team ], "Restart current map" ); } - else + else if( !Q_stricmp( vote, "map" ) ) { - level.votePassThreshold = g_suddenDeathVotePercent.integer; - Com_sprintf( level.voteString, sizeof( level.voteString ), "suddendeath" ); - Com_sprintf( level.voteDisplayString, - sizeof( level.voteDisplayString ), "Begin sudden death" ); - - if( g_suddenDeathVoteDelay.integer ) - Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), - va( " in %d seconds", g_suddenDeathVoteDelay.integer ) ); + 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 ); } - } - 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, sudden_death, draw, kick, mute and unmute\n" ); - return; - } - - if( level.votePassThreshold != 50 ) - { - Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), - va( " (Needs > %d percent)", level.votePassThreshold ) ); - } - - trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE - " called a vote: %s^7\n\"", ent->client->pers.netname, - level.voteDisplayString ) ); - - G_LogPrintf( "CallVote: %d \"%s" S_COLOR_WHITE "\": %s\n", - ent - g_entities, ent->client->pers.netname, level.voteString ); - - ent->client->pers.voteCount++; - - // start the voting, the caller autoamtically votes yes - level.voteTime = level.time; - level.voteYes = 1; - level.voteNo = 0; - ent->client->pers.vote = qtrue; - - for( i = 0; i < level.maxclients; i++ ) - level.clients[i].ps.eFlags &= ~EF_VOTED; - - ent->client->ps.eFlags |= EF_VOTED; - - trap_SetConfigstring( CS_VOTE_TIME, va( "%i", level.voteTime ) ); - trap_SetConfigstring( CS_VOTE_STRING, level.voteDisplayString ); - trap_SetConfigstring( CS_VOTE_YES, "1" ); - trap_SetConfigstring( CS_VOTE_NO, "0" ); -} - -/* -================== -Cmd_Vote_f -================== -*/ -void Cmd_Vote_f( gentity_t *ent ) -{ - char msg[ 64 ]; - - if( !level.voteTime ) - { - trap_SendServerCommand( ent-g_entities, "print \"No vote in progress\n\"" ); - return; - } - - if( ent->client->ps.eFlags & EF_VOTED ) - { - trap_SendServerCommand( ent-g_entities, "print \"Vote already cast\n\"" ); - return; - } - - trap_SendServerCommand( ent-g_entities, "print \"Vote cast\n\"" ); - - trap_Argv( 1, msg, sizeof( msg ) ); - ent->client->pers.vote = ( tolower( msg[ 0 ] ) == 'y' || msg[ 0 ] == '1' ); - G_Vote( ent, qtrue ); - - // a majority will be determined in CheckVote, which will also account - // for players entering or leaving -} - -/* -================== -Cmd_CallTeamVote_f -================== -*/ -void Cmd_CallTeamVote_f( gentity_t *ent ) -{ - int i, team, cs_offset = 0; - char arg1[ MAX_STRING_TOKENS ]; - char arg2[ MAX_NAME_LENGTH ]; - int clientNum = -1; - char name[ MAX_NAME_LENGTH ]; - - team = ent->client->pers.teamSelection; - - if( team == TEAM_ALIENS ) - cs_offset = 1; - - if( !g_allowVote.integer ) - { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" ); - return; - } - - if( level.teamVoteTime[ cs_offset ] ) - { - trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress\n\"" ); - return; - } - - if( g_voteLimit.integer > 0 && - ent->client->pers.voteCount >= g_voteLimit.integer && - !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) ) - { - trap_SendServerCommand( ent-g_entities, va( - "print \"You have already called the maximum number of votes (%d)\n\"", - g_voteLimit.integer ) ); - return; - } - - // make sure it is a valid command to vote on - trap_Argv( 1, arg1, sizeof( arg1 ) ); - trap_Argv( 2, arg2, sizeof( arg2 ) ); - - if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) - { - trap_SendServerCommand( ent-g_entities, "print \"Invalid team vote string\n\"" ); - return; - } - - // detect clientNum for partial name match votes - if( !Q_stricmp( arg1, "kick" ) || - !Q_stricmp( arg1, "denybuild" ) || - !Q_stricmp( arg1, "allowbuild" ) ) - { - int clientNums[ MAX_CLIENTS ]; - int matches = 0; - char err[ MAX_STRING_CHARS ] = ""; - - if( !arg2[ 0 ] ) + else if( !Q_stricmp( vote, "nextmap" ) ) { - trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: no target\n\"" ); - return; - } + 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; + } - matches = G_ClientNumbersFromString( arg2, clientNums, MAX_CLIENTS ) ; - if( matches == 1 ) - { - // there was only one partial name match - clientNum = clientNums[ 0 ]; - } - else - { - // look for an exact name match (sets clientNum to -1 if it fails) - clientNum = G_ClientNumberFromString( arg2 ); - } + 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; + } - // make sure this player is on the same team - if( clientNum != -1 && level.clients[ clientNum ].pers.teamSelection != - team ) - { - clientNum = -1; + 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 go '%s'", arg ); } - - if( clientNum != -1 ) + else if( !Q_stricmp( vote, "draw" ) ) { - Q_strncpyz( name, level.clients[ clientNum ].pers.netname, - sizeof( name ) ); - Q_CleanStr( name ); + strcpy( level.voteString[ team ], "evacuation" ); + strcpy( level.voteDisplayString[ team ], "End match in a draw" ); } - else if( matches > 1 ) + else if( !Q_stricmp( vote, "sudden_death" ) ) { - G_MatchOnePlayer( clientNums, matches, err, sizeof( err ) ); - ADMP( va( "^3callteamvote: ^7%s\n", err ) ); - return; + 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( G_TimeTilSuddenDeath() <= g_suddenDeathVoteDelay.integer * 1000 ) + { + trap_SendServerCommand( ent - g_entities, + va( "print \"callvote: Sudden Death is already immenent\n\"") ); + return; + } + level.voteThreshold[ team ] = g_suddenDeathVotePercent.integer; + Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ), + "suddendeath %d", g_suddenDeathVoteDelay.integer ); + strcpy( level.voteDisplayString[ team ], "Begin sudden death" ); } else { - trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: invalid player\n\"" ); + 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, kick, mute and unmute\n" ); return; } } - - if( !Q_stricmp( arg1, "kick" ) ) - { - if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) ) - { - trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: admin is immune from vote kick\n\"" ); - return; - } - if( level.clients[ clientNum ].pers.localClient ) - { - trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: host is immune from vote kick\n\"" ); - return; - } - - // use ip in case this player disconnects before the vote ends - Com_sprintf( level.teamVoteString[ cs_offset ], - sizeof( level.teamVoteString[ cs_offset ] ), - "!ban %s \"1s%s\" team vote kick", level.clients[ clientNum ].pers.ip, - g_adminTempBan.string ); - Com_sprintf( level.teamVoteDisplayString[ cs_offset ], - sizeof( level.teamVoteDisplayString[ cs_offset ] ), - "Kick player '%s'", name ); - } - else if( !Q_stricmp( arg1, "denybuild" ) ) + else if( !Q_stricmp( vote, "denybuild" ) ) { if( level.clients[ clientNum ].pers.denyBuild ) { trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: player already lost building rights\n\"" ); - return; - } - - if( G_admin_permission( &g_entities[ clientNum ], ADMF_IMMUNITY ) ) - { - trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: admin is immune from denybuild\n\"" ); + va( "print \"%s: player already lost building rights\n\"", cmd ) ); return; } - Com_sprintf( level.teamVoteString[ cs_offset ], - sizeof( level.teamVoteString[ cs_offset ] ), "!denybuild %i", clientNum ); - Com_sprintf( level.teamVoteDisplayString[ cs_offset ], - sizeof( level.teamVoteDisplayString[ cs_offset ] ), - "Take away building rights from '%s'", name ); + Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ), + "denybuild %d", clientNum ); + Com_sprintf( level.voteDisplayString[ team ], + sizeof( level.voteDisplayString[ team ] ), + "Take away building rights from '%s'", name ); } - else if( !Q_stricmp( arg1, "allowbuild" ) ) + else if( !Q_stricmp( vote, "allowbuild" ) ) { if( !level.clients[ clientNum ].pers.denyBuild ) { trap_SendServerCommand( ent-g_entities, - "print \"callteamvote: player already has building rights\n\"" ); + va( "print \"%s: player already has building rights\n\"", cmd ) ); return; } - Com_sprintf( level.teamVoteString[ cs_offset ], - sizeof( level.teamVoteString[ cs_offset ] ), "!allowbuild %i", clientNum ); - Com_sprintf( level.teamVoteDisplayString[ cs_offset ], - sizeof( level.teamVoteDisplayString[ cs_offset ] ), - "Allow '%s' to build", name ); + Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ), + "allowbuild %d", clientNum ); + Com_sprintf( level.voteDisplayString[ team ], + sizeof( level.voteDisplayString[ team ] ), + "Allow '%s' to build", name ); } - else if( !Q_stricmp( arg1, "admitdefeat" ) ) + else if( !Q_stricmp( vote, "admitdefeat" ) ) { - if( team == level.surrenderTeam ) - { - trap_SendServerCommand( ent-g_entities, "print \"You have already surrendered\n\""); - return; - } - - Com_sprintf( level.teamVoteString[ cs_offset ], - sizeof( level.teamVoteString[ cs_offset ] ), "admitdefeat %i", team ); - Com_sprintf( level.teamVoteDisplayString[ cs_offset ], - sizeof( level.teamVoteDisplayString[ cs_offset ] ), - "Admit Defeat" ); + Com_sprintf( level.voteString[ team ], sizeof( level.voteString[ team ] ), + "admitdefeat %d", team ); + strcpy( level.voteDisplayString[ team ], "Admit Defeat" ); } else { @@ -1488,71 +1268,70 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) "kick, denybuild, allowbuild and admitdefeat\n\"" ); return; } - ent->client->pers.voteCount++; - - G_TeamCommand( team, va( "print \"%s " S_COLOR_WHITE "called a team vote: %s\n\"", - ent->client->pers.netname, level.teamVoteDisplayString[ cs_offset ] ) ); - G_LogPrintf( "CallTeamVote: %d \"%s" S_COLOR_WHITE "\": %s\n", - ent - g_entities, ent->client->pers.netname, - level.teamVoteDisplayString[ cs_offset ] ); + 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 ] ); - // start the voting, the caller autoamtically votes yes - level.teamVoteTime[ cs_offset ] = level.time; - level.teamVoteYes[ cs_offset ] = 1; - level.teamVoteNo[ cs_offset ] = 0; - ent->client->pers.teamVote = qtrue; - - for( i = 0; i < level.maxclients; i++ ) + if( team == TEAM_NONE ) { - if( level.clients[ i ].ps.stats[ STAT_TEAM ] == team ) - level.clients[ i ].ps.eFlags &= ~EF_TEAMVOTED; + trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE + " called a vote: %s\n\"", ent->client->pers.netname, + level.voteDisplayString[ team ] ) ); + } + else + { + G_TeamCommand( team, va( "print \"%s" S_COLOR_WHITE + " called a team vote: %s\n\"", ent->client->pers.netname, + level.voteDisplayString[ team ] ) ); } - ent->client->ps.eFlags |= EF_TEAMVOTED; + 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_TEAMVOTE_TIME + cs_offset, - va( "%i", level.teamVoteTime[ cs_offset ] ) ); - trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, - level.teamVoteDisplayString[ cs_offset ] ); - trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, "1" ); - trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, "0" ); + ent->client->pers.voteCount++; + ent->client->pers.vote[ team ] = qtrue; + G_Vote( ent, team, qtrue ); } - /* ================== -Cmd_TeamVote_f +Cmd_Vote_f ================== */ -void Cmd_TeamVote_f( gentity_t *ent ) +void Cmd_Vote_f( gentity_t *ent ) { - int cs_offset = 0; - char msg[ 64 ]; + char cmd[ MAX_TOKEN_CHARS ], vote[ MAX_TOKEN_CHARS ]; + team_t team = ent->client->pers.teamSelection; - if( ent->client->pers.teamSelection == TEAM_ALIENS ) - cs_offset = 1; + trap_Argv( 0, cmd, sizeof( cmd ) ); + if( Q_stricmp( cmd, "teamvote" ) ) + team = TEAM_NONE; - if( !level.teamVoteTime[ cs_offset ] ) + if( !level.voteTime[ team ] ) { - trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress\n\"" ); + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: no vote in progress\n\"", cmd ) ); return; } - if( ent->client->ps.eFlags & EF_TEAMVOTED ) + if( ent->client->pers.voted[ team ] ) { - trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast\n\"" ); + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: vote already cast\n\"", cmd ) ); return; } - trap_SendServerCommand( ent-g_entities, "print \"Team vote cast\n\"" ); - - trap_Argv( 1, msg, sizeof( msg ) ); - ent->client->pers.teamVote = ( tolower( msg[ 0 ] ) == 'y' || msg[ 0 ] == '1' ); - G_TeamVote( ent, qtrue ); + trap_SendServerCommand( ent-g_entities, + va( "print \"%s: vote cast\n\"", cmd ) ); - // a majority will be determined in CheckTeamVote, which will also account - // for players entering or leaving + trap_Argv( 1, vote, sizeof( vote ) ); + ent->client->pers.vote[ team ] = + ( tolower( vote[ 0 ] ) == 'y' || vote[ 0 ] == '1' ); + G_Vote( ent, team, qtrue ); } @@ -3100,7 +2879,7 @@ commands_t cmds[ ] = { // communication commands { "callvote", CMD_MESSAGE, Cmd_CallVote_f }, - { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallTeamVote_f }, + { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallVote_f }, { "say_area", CMD_MESSAGE|CMD_TEAM, Cmd_SayArea_f }, // can be used even during intermission { "say", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f }, @@ -3134,7 +2913,7 @@ commands_t cmds[ ] = { { "follownext", CMD_SPEC, Cmd_FollowCycle_f }, { "followprev", CMD_SPEC, Cmd_FollowCycle_f }, - { "teamvote", CMD_TEAM, Cmd_TeamVote_f }, + { "teamvote", CMD_TEAM, Cmd_Vote_f }, { "class", CMD_TEAM, Cmd_Class_f }, { "kill", CMD_TEAM|CMD_LIVING, Cmd_Kill_f }, diff --git a/src/game/g_local.h b/src/game/g_local.h index 48451f12..afafe587 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -324,9 +324,8 @@ typedef struct // used to save persistant[] values while in SPECTATOR_FOLLOW mode int credit; - // votes - qboolean vote; - qboolean teamVote; + qboolean voted[ NUM_TEAMS ]; + qboolean vote[ NUM_TEAMS ]; // flood protection int floodDemerits; @@ -542,22 +541,14 @@ typedef struct int warmupModificationCount; // for detecting if g_warmup is changed // voting state - char voteString[MAX_STRING_CHARS]; - char voteDisplayString[MAX_STRING_CHARS]; - int voteTime; // level.time vote was called - int votePassThreshold; // need at least this percent to pass - int voteExecuteTime; // time the vote is executed - int voteYes; - int voteNo; - int numVotingClients; // set by CalculateRanks - - // team voting state - char teamVoteString[ 2 ][ MAX_STRING_CHARS ]; - char teamVoteDisplayString[ 2 ][ MAX_STRING_CHARS ]; - int teamVoteTime[ 2 ]; // level.time vote was called - int teamVoteYes[ 2 ]; - int teamVoteNo[ 2 ]; - int numteamVotingClients[ 2 ]; // set by CalculateRanks + int voteThreshold[ NUM_TEAMS ]; // need at least this percent to pass + char voteString[ NUM_TEAMS ][ MAX_STRING_CHARS ]; + char voteDisplayString[ NUM_TEAMS ][ MAX_STRING_CHARS ]; + int voteTime[ NUM_TEAMS ]; // level.time vote was called + int voteExecuteTime[ NUM_TEAMS ]; // time the vote is executed + int voteYes[ NUM_TEAMS ]; + int voteNo[ NUM_TEAMS ]; + int numVotingClients[ NUM_TEAMS ];// set by CalculateRanks // spawn variables qboolean spawning; // the G_Spawn*() functions are valid @@ -617,7 +608,6 @@ typedef struct team_t lastWin; - qboolean suddenDeath; int suddenDeathBeginTime; timeWarning_t suddenDeathWarning; timeWarning_t timelimitWarning; @@ -966,10 +956,8 @@ void QDECL G_LogPrintf( const char *fmt, ... ); void SendScoreboardMessageToAllClients( void ); void QDECL G_Printf( const char *fmt, ... ); void QDECL G_Error( const char *fmt, ... ); -void G_Vote( gentity_t *ent, qboolean voting ); -void G_TeamVote( gentity_t *ent, qboolean voting ); -void CheckVote( void ); -void CheckTeamVote( team_t teamnum ); +void G_Vote( gentity_t *ent, team_t team, qboolean voting ); +void CheckVote( team_t teamnum ); void LogExit( const char *string ); int G_TimeTilSuddenDeath( void ); @@ -1056,7 +1044,6 @@ extern vmCvar_t g_maxNameChanges; extern vmCvar_t g_timelimit; extern vmCvar_t g_suddenDeathTime; -extern vmCvar_t g_suddenDeath; extern vmCvar_t g_friendlyFire; extern vmCvar_t g_friendlyBuildableFire; extern vmCvar_t g_dretchPunt; diff --git a/src/game/g_main.c b/src/game/g_main.c index da521eb3..0343353e 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -41,7 +41,6 @@ gclient_t g_clients[ MAX_CLIENTS ]; vmCvar_t g_fraglimit; vmCvar_t g_timelimit; vmCvar_t g_suddenDeathTime; -vmCvar_t g_suddenDeath; vmCvar_t g_capturelimit; vmCvar_t g_friendlyFire; vmCvar_t g_friendlyBuildableFire; @@ -164,7 +163,6 @@ static cvarTable_t gameCvarTable[ ] = { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_suddenDeathTime, "g_suddenDeathTime", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, - { &g_suddenDeath, "g_suddenDeath", "0", CVAR_SERVERINFO | CVAR_NORESTART, 0, qtrue }, { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse }, @@ -634,7 +632,6 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) trap_Cvar_Set( "g_humanStage", va( "%d", S1 ) ); trap_Cvar_Set( "g_alienCredits", 0 ); trap_Cvar_Set( "g_humanCredits", 0 ); - trap_Cvar_Set( "g_suddenDeath", 0 ); level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000; G_Printf( "-----------------------------------\n" ); @@ -654,15 +651,13 @@ remove all currently active votes */ static void G_ClearVotes( void ) { - level.voteTime = 0; - trap_SetConfigstring( CS_VOTE_TIME, "" ); - trap_SetConfigstring( CS_VOTE_STRING, "" ); - level.teamVoteTime[ 0 ] = 0; - trap_SetConfigstring( CS_TEAMVOTE_TIME, "" ); - trap_SetConfigstring( CS_TEAMVOTE_STRING, "" ); - level.teamVoteTime[ 1 ] = 0; - trap_SetConfigstring( CS_TEAMVOTE_TIME + 1, "" ); - trap_SetConfigstring( CS_TEAMVOTE_STRING + 1, "" ); + int i; + memset( level.voteTime, 0, sizeof( level.voteTime ) ); + for( i = 0; i < NUM_TEAMS; i++ ) + { + trap_SetConfigstring( CS_VOTE_TIME + i, "" ); + trap_SetConfigstring( CS_VOTE_STRING + i, "" ); + } } /* @@ -1053,11 +1048,12 @@ void G_CountSpawns( void ) G_TimeTilSuddenDeath ============ */ +#define SUDDENDEATHWARNING 60000 int G_TimeTilSuddenDeath( void ) { if( ( !g_suddenDeathTime.integer && level.suddenDeathBeginTime==0 ) || ( level.suddenDeathBeginTime < 0 ) ) - return 1; // Always some time away + return SUDDENDEATHWARNING + 1; // Always some time away return ( ( level.suddenDeathBeginTime ) - ( level.time - level.startTime ) ); } @@ -1098,54 +1094,18 @@ void G_CalculateBuildPoints( void ) } // Sudden Death checks - - // Note: g_suddenDeath sets what is going on and level.suddenDeath - // trails it to run stuff here. They're only inconsistent for as long - // as it takes this function to run once and update - - // reset if SD was on, but now it's off - if( !g_suddenDeath.integer && level.suddenDeath ) + if( G_TimeTilSuddenDeath( ) <= 0 && level.suddenDeathWarning < TW_PASSED ) { - level.suddenDeath = qfalse; - level.suddenDeathWarning = 0; - level.suddenDeathBeginTime = -1; - if( ( level.time - level.startTime ) < ( g_suddenDeathTime.integer * 60000 ) ) - level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000; - else - level.suddenDeathBeginTime = -1; + G_LogPrintf( "Beginning Sudden Death\n" ); + trap_SendServerCommand( -1, "cp \"Sudden Death!\"" ); + level.suddenDeathWarning = TW_PASSED; } - - // SD checks and warnings - if( !level.suddenDeath ) + else if( G_TimeTilSuddenDeath( ) <= SUDDENDEATHWARNING && + level.suddenDeathWarning < TW_IMMINENT ) { - // check conditions to enter sudden death - if( !level.warmupTime && - ( g_suddenDeath.integer || G_TimeTilSuddenDeath( ) <= 0 ) ) - { - // begin sudden death - if( level.suddenDeathWarning < TW_PASSED ) - { - G_LogPrintf( "Beginning Sudden Death\n" ); - trap_SendServerCommand( -1, "cp \"Sudden Death!\"" ); - - level.suddenDeathBeginTime = level.time; - level.suddenDeath=qtrue; - trap_Cvar_Set( "g_suddenDeath", "1" ); - - level.suddenDeathWarning = TW_PASSED; - } - } - else - { - // warn about sudden death - if( G_TimeTilSuddenDeath( ) <= 60000 && - level.suddenDeathWarning < TW_IMMINENT ) - { - trap_SendServerCommand( -1, va( "cp \"Sudden Death in %d seconds!\"", - (int)(G_TimeTilSuddenDeath() / 1000 ) ) ); - level.suddenDeathWarning = TW_IMMINENT; - } - } + trap_SendServerCommand( -1, va( "cp \"Sudden Death in %d seconds!\"", + (int)(G_TimeTilSuddenDeath() / 1000 ) ) ); + level.suddenDeathWarning = TW_IMMINENT; } level.humanBuildPoints = g_humanBuildPoints.integer - level.humanBuildPointQueue; @@ -1221,7 +1181,7 @@ void G_CalculateBuildPoints( void ) { zone = &level.buildPointZones[ ent->buildPointZone ]; - if( !level.suddenDeath ) + if( G_TimeTilSuddenDeath( ) > 0 ) { // BP queue updates while( zone->queuedBuildPoints > 0 && @@ -1412,7 +1372,7 @@ void CalculateRanks( void ) level.numConnectedClients = 0; level.numPlayingClients = 0; - level.numVotingClients = 0; // don't count bots + memset( level.numVotingClients, 0, sizeof( level.numVotingClients ) ); level.numAlienClients = 0; level.numHumanClients = 0; level.numLiveAlienClients = 0; @@ -1430,7 +1390,7 @@ void CalculateRanks( void ) if( level.clients[ i ].pers.connected != CON_CONNECTED ) continue; - level.numVotingClients++; + level.numVotingClients[ TEAM_NONE ]++; if( level.clients[ i ].pers.teamSelection != TEAM_NONE ) { level.numPlayingClients++; @@ -1451,8 +1411,8 @@ void CalculateRanks( void ) } level.numNonSpectatorClients = level.numLiveAlienClients + level.numLiveHumanClients; - level.numteamVotingClients[ 0 ] = level.numHumanClients; - level.numteamVotingClients[ 1 ] = level.numAlienClients; + level.numVotingClients[ TEAM_ALIENS ] = level.numAlienClients; + level.numVotingClients[ TEAM_HUMANS ] = level.numHumanClients; P[ i ] = '\0'; trap_Cvar_Set( "P", P ); @@ -2063,91 +2023,34 @@ void CheckExitRules( void ) G_Vote ================== */ -void G_Vote( gentity_t *ent, qboolean voting ) +void G_Vote( gentity_t *ent, team_t team, qboolean voting ) { - if( !level.voteTime ) + if( !level.voteTime[ team ] ) return; - if( voting ) - { - if( ent->client->ps.eFlags & EF_VOTED ) - return; - ent->client->ps.eFlags |= EF_VOTED; - } - else - { - if( !( ent->client->ps.eFlags & EF_VOTED ) ) - return; - ent->client->ps.eFlags &= ~EF_VOTED; - } - - if( ent->client->pers.vote ) - { - if( voting ) - level.voteYes++; - else - level.voteYes--; - trap_SetConfigstring( CS_VOTE_YES, va( "%d", level.voteYes ) ); - } - else - { - if( voting ) - level.voteNo++; - else - level.voteNo--; - trap_SetConfigstring( CS_VOTE_NO, va( "%d", level.voteNo ) ); - } -} - -/* -================== -G_TeamVote -================== -*/ -void G_TeamVote( gentity_t *ent, qboolean voting ) -{ - int cs_offset; - - if( ent->client->pers.teamSelection == TEAM_HUMANS ) - cs_offset = 0; - else if( ent->client->pers.teamSelection == TEAM_ALIENS ) - cs_offset = 1; - else + if( voting && ent->client->pers.voted[ team ] ) return; - - if( !level.teamVoteTime[ cs_offset ] ) + if( !voting && !ent->client->pers.voted[ team ] ) return; + ent->client->pers.voted[ team ] = voting; - if( voting ) - { - if( ent->client->ps.eFlags & EF_TEAMVOTED ) - return; - ent->client->ps.eFlags |= EF_TEAMVOTED; - } - else - { - if( !( ent->client->ps.eFlags & EF_TEAMVOTED ) ) - return; - ent->client->ps.eFlags &= ~EF_TEAMVOTED; - } - - if( ent->client->pers.teamVote ) + if( ent->client->pers.vote[ team ] ) { if( voting ) - level.teamVoteYes[ cs_offset ]++; + level.voteYes[ team ]++; else - level.teamVoteYes[ cs_offset ]--; - trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, - va( "%d", level.teamVoteYes[ cs_offset ] ) ); + level.voteYes[ team ]--; + trap_SetConfigstring( CS_VOTE_YES + team, + va( "%d", level.voteYes[ team ] ) ); } else { if( voting ) - level.teamVoteNo[ cs_offset ]++; + level.voteNo[ team ]++; else - level.teamVoteNo[ cs_offset ]--; - trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, - va( "%d", level.teamVoteNo[ cs_offset ] ) ); + level.voteNo[ team ]--; + trap_SetConfigstring( CS_VOTE_NO + team, + va( "%d", level.voteNo[ team ] ) ); } } @@ -2166,138 +2069,72 @@ FUNCTIONS CALLED EVERY FRAME CheckVote ================== */ -void CheckVote( void ) +void CheckVote( team_t team ) { - int votePassThreshold = level.votePassThreshold; - int voteYesPercent; + float votePassThreshold = (float)level.voteThreshold[ team ] / 100.0f; + qboolean pass = qfalse; + char *msg; + int i; - if( level.voteExecuteTime && level.voteExecuteTime < level.time ) + if( level.voteExecuteTime[ team ] && + level.voteExecuteTime[ team ] < level.time ) { - level.voteExecuteTime = 0; + level.voteExecuteTime[ team ] = 0; - trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) ); - if( !Q_stricmp( level.voteString, "map_restart" ) || - !Q_stricmpn( level.voteString, "map", 3 ) ) + trap_SendConsoleCommand( EXEC_APPEND, + va( "%s\n", level.voteString[ team ] ) ); + if( !Q_stricmp( level.voteString[ team ], "map_restart" ) || + !Q_stricmpn( level.voteString[ team ], "map", 3 ) ) { level.restarted = qtrue; } - - if( !Q_stricmp( level.voteString, "suddendeath" ) ) - { - level.suddenDeathBeginTime = level.time + - ( 1000 * g_suddenDeathVoteDelay.integer ) - level.startTime; - level.voteString[0] = '\0'; - - if( g_suddenDeathVoteDelay.integer ) - trap_SendServerCommand( -1, va("cp \"Sudden Death will begin in %d seconds\n\"", g_suddenDeathVoteDelay.integer ) ); - } } - if( !level.voteTime ) + if( !level.voteTime[ team ] ) return; - - if( level.voteYes + level.voteNo > 0 ) - voteYesPercent = (int)( 100 * ( level.voteYes ) / ( level.voteYes + level.voteNo ) ); - else - voteYesPercent = 0; - if( ( level.time - level.voteTime >= VOTE_TIME ) || - ( level.voteYes + level.voteNo == level.numConnectedClients ) ) + if( ( level.time - level.voteTime[ team ] >= VOTE_TIME ) || + ( level.voteYes[ team ] + level.voteNo[ team ] == level.numVotingClients[ team ] ) ) { - if( voteYesPercent> votePassThreshold || level.voteNo == 0 ) - { - // execute the command, then remove the vote - trap_SendServerCommand( -1, va("print \"Vote passed (%d - %d)\n\"", - level.voteYes, level.voteNo ) ); - G_LogPrintf( "Vote: Vote passed (%d-%d)\n", level.voteYes, level.voteNo ); - level.voteExecuteTime = level.time + 3000; - } - else - { - // same behavior as a timeout - trap_SendServerCommand( -1, va("print \"Vote failed (%d - %d)\n\"", - level.voteYes, level.voteNo ) ); - G_LogPrintf( "Vote: Vote failed (%d - %d)\n", level.voteYes, level.voteNo ); - } + pass = (float)level.voteYes[ team ] / 100.0f > votePassThreshold || + level.voteNo[ team ] == 0; } else { - if( level.voteYes > (int)( (double) level.numConnectedClients * - ( (double) votePassThreshold/100.0 ) ) ) + if( (float)level.voteYes[ team ] / 100.0f > + (float)level.numVotingClients[ team ] * votePassThreshold ) { - // execute the command, then remove the vote - trap_SendServerCommand( -1, va("print \"Vote passed (%d - %d)\n\"", - level.voteYes, level.voteNo ) ); - G_LogPrintf( "Vote: Vote passed (%d - %d)\n", level.voteYes, level.voteNo ); - level.voteExecuteTime = level.time + 3000; + pass = qtrue; } - else if( level.voteNo > (int)( (double) level.numConnectedClients * - ( (double) ( 100.0-votePassThreshold )/ 100.0 ) ) ) + else if( (float)level.voteNo[ team ] <= + (float)level.numVotingClients[ team ] * 1.0f - votePassThreshold ) { - // same behavior as a timeout - trap_SendServerCommand( -1, va("print \"Vote failed (%d - %d)\n\"", - level.voteYes, level.voteNo ) ); - G_LogPrintf("Vote failed\n"); - } - else - { - // still waiting for a majority return; } } - level.voteTime = 0; - trap_SetConfigstring( CS_VOTE_TIME, "" ); - trap_SetConfigstring( CS_VOTE_STRING, "" ); -} - + if( pass ) + level.voteExecuteTime[ team ] = level.time + 3000; -/* -================== -CheckTeamVote -================== -*/ -void CheckTeamVote( team_t team ) -{ - int cs_offset; - - if ( team == TEAM_HUMANS ) - cs_offset = 0; - else if ( team == TEAM_ALIENS ) - cs_offset = 1; + msg = va( "print \"%sote %sed (%d - %d)\n\"", + team == TEAM_NONE ? "V" : "Team v", pass ? "pass" : "fail", + level.voteYes[ team ], level.voteNo[ team ] ); + if( team == TEAM_NONE ) + trap_SendServerCommand( -1, msg ); else - return; + G_TeamCommand( team, msg ); - if( !level.teamVoteTime[ cs_offset ] ) - return; + level.voteTime[ team ] = 0; + level.voteYes[ team ] = 0; + level.voteNo[ team ] = 0; - if( level.time - level.teamVoteTime[ cs_offset ] >= VOTE_TIME ) - { - G_TeamCommand( team, "print \"Team vote failed\n\"" ); - } - else - { - if( level.teamVoteYes[ cs_offset ] > level.numteamVotingClients[ cs_offset ] / 2 ) - { - // execute the command, then remove the vote - G_TeamCommand( team, "print \"Team vote passed\n\"" ); - trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.teamVoteString[ cs_offset ] ) ); - } - else if( level.teamVoteNo[ cs_offset ] >= level.numteamVotingClients[ cs_offset ] / 2 ) - { - // same behavior as a timeout - G_TeamCommand( team, "print \"Team vote failed\n\"" ); - } - else - { - // still waiting for a majority - return; - } - } + for( i = 0; i < level.maxclients; i++ ) + level.clients[ i ].pers.voted[ team ] = qfalse; - level.teamVoteTime[ cs_offset ] = 0; - trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" ); - trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, "" ); + trap_SetConfigstring( CS_VOTE_TIME + team, "" ); + trap_SetConfigstring( CS_VOTE_STRING + team, "" ); + trap_SetConfigstring( CS_VOTE_YES + team, "0" ); + trap_SetConfigstring( CS_VOTE_NO + team, "0" ); } @@ -2555,11 +2392,9 @@ void G_RunFrame( int levelTime ) CheckTeamStatus( ); // cancel vote if timed out - CheckVote( ); - - // check team votes - CheckTeamVote( TEAM_HUMANS ); - CheckTeamVote( TEAM_ALIENS ); + CheckVote( TEAM_NONE ); + CheckVote( TEAM_ALIENS ); + CheckVote( TEAM_HUMANS ); level.frameMsec = trap_Milliseconds(); } diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index c81ffca1..75d757d1 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -509,6 +509,19 @@ static void Svcmd_MessageWrapper( void ) G_Say( NULL, SAY_ALL, ConcatArgs( 1 ) ); } +static void Svcmd_SuddenDeath_f( void ) +{ + char secs[ 5 ]; + int offset; + trap_Argv( 0, secs, sizeof( secs ) ); + offset = atoi( secs ); + + level.suddenDeathBeginTime = level.time - level.startTime + offset * 1000; + trap_SendServerCommand( -1, + va( "cp \"Sudden Death will begin in %d second%s\"", + offset, offset == 1 ? "" : "s" ) ); +} + struct { char *cmd; @@ -536,7 +549,8 @@ struct { "say", qtrue, Svcmd_MessageWrapper }, { "chat", qtrue, Svcmd_Chat_f }, { "m", qtrue, Svcmd_MessageWrapper }, - { "a", qtrue, Svcmd_MessageWrapper } + { "a", qtrue, Svcmd_MessageWrapper }, + { "suddendeath", qfalse, Svcmd_SuddenDeath_f } }; /* diff --git a/src/game/g_team.c b/src/game/g_team.c index 96e7e39e..7384b4b1 100644 --- a/src/game/g_team.c +++ b/src/game/g_team.c @@ -103,7 +103,7 @@ void G_LeaveTeam( gentity_t *self ) // stop any following clients G_StopFromFollowing( self ); - G_TeamVote( self, qfalse ); + G_Vote( self, team, qfalse ); self->suicideTime = 0; for( i = 0; i < level.num_entities; i++ ) |