Added rotation map votes (Issue 145)

Added nextmap votes and nextmap cvar (issue 146)
Added fix for building near walls/doors and in corpses (Issue 147)
This commit is contained in:
Paradox460 committed 2008-07-15 22:42:35 +00:00
1 parent 6407b9fafa
commit a4a1caa918
6 files changed
+468 -7

No files matched your search

+16 -1
View File
@@ -433,7 +433,8 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
G_TouchTriggers( ent );
trap_UnlinkEntity( ent );
if( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) )
if( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) &&
!level.mapRotationVoteTime )
{
//if waiting in a queue remove from the queue
if( client->ps.pm_flags & PMF_QUEUED )
@@ -475,6 +476,14 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
if( ( client->buttons & BUTTON_USE_HOLDABLE ) && !( client->oldbuttons & BUTTON_USE_HOLDABLE ) )
G_ToggleFollow( ent );
if( level.mapRotationVoteTime )
{
if ( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) )
G_IntermissionMapVoteCommand( ent, qtrue, qfalse );
if ( ( client->buttons & BUTTON_ATTACK2 ) && !( client->oldbuttons & BUTTON_ATTACK2 ) )
G_IntermissionMapVoteCommand( ent, qfalse, qfalse );
}
}
@@ -1534,6 +1543,12 @@ void ClientThink_real( gentity_t *ent )
//
if( level.intermissiontime )
{
if( level.mapRotationVoteTime )
{
SpectatorThink( ent, ucmd );
return;
}
ClientIntermissionThink( client );
return;
}
+4
View File
@@ -3125,6 +3125,10 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
}
level.markedBuildables[ level.numBuildablesForRemoval++ ] = tent;
}
if( tent->r.contents != MASK_PLAYERSOLID && tent->s.eType != ET_BUILDABLE && ( normal[ 2 ] >= minNormal || ( invert && normal[ 2 ] <= -minNormal ) ) )
{
reason = IBE_NONE;
}
}
if( reason != IBE_NONE )
{
+41 -2
View File
@@ -1957,6 +1957,27 @@ void Cmd_CallVote_f( gentity_t *ent )
sizeof( level.voteDisplayString ), "Change to layout '%s'", arg2 );
level.votePercentToPass = g_layoutVotePercent.integer;
}
else if( !Q_stricmp( arg1, "nextmap" ) )
{
if( G_MapExists( g_nextMap.string ) )
{
trap_SendServerCommand( ent - g_entities, va( "print \"callvote: "
"the next map is already set to '%s^7'\n\"", g_nextMap.string ) );
return;
}
if( !trap_FS_FOpenFile( va( "maps/%s.bsp", arg2 ), NULL, FS_READ ) )
{
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, sizeof( level.voteString ),
"set g_nextMap %s", arg2 );
Com_sprintf( level.voteDisplayString,
sizeof( level.voteDisplayString ), "Next map '%s^7'", arg2 );
level.votePercentToPass = g_mapVotesPercent.integer;
}
else if( !Q_stricmp( arg1, "draw" ) )
{
Com_sprintf( level.voteString, sizeof( level.voteString ), "evacuation" );
@@ -2030,7 +2051,7 @@ void Cmd_CallVote_f( gentity_t *ent )
{
trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
trap_SendServerCommand( ent-g_entities, "print \"Valid vote commands are: "
"map, map_restart, layout, draw, extend, kick, mute, unmute, poll, and sudden_death\n" );
"map, map_restart, nextmap, layout, draw, extend, kick, mute, unmute, poll, and sudden_death\n" );
return;
}
@@ -2080,6 +2101,18 @@ void Cmd_Vote_f( gentity_t *ent )
{
char msg[ 64 ];
if ( level.intermissiontime || level.paused )
{
if( level.mapRotationVoteTime )
{
trap_Argv( 1, msg, sizeof( msg ) );
if( msg[ 0 ] == 'y' || msg[ 1 ] == 'Y' || msg[ 1 ] == '1' )
G_IntermissionMapVoteCommand( ent, qfalse, qtrue );
}
return;
}
if( !level.voteTime )
{
if( ent->client->pers.teamSelection != PTE_NONE )
@@ -4409,6 +4442,12 @@ G_ToggleFollow
*/
void G_ToggleFollow( gentity_t *ent )
{
if( level.mapRotationVoteTime )
{
G_IntermissionMapVoteCommand( ent, qfalse, qtrue );
return;
}
if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
G_StopFollowing( ent );
else if( ent->client->sess.spectatorState == SPECTATOR_FREE )
@@ -5014,7 +5053,7 @@ static void Cmd_Ignore_f( gentity_t *ent )
commands_t cmds[ ] = {
// normal commands
{ "team", 0, Cmd_Team_f },
{ "vote", 0, Cmd_Vote_f },
{ "vote", CMD_INTERMISSION, Cmd_Vote_f },
{ "ignore", 0, Cmd_Ignore_f },
{ "unignore", 0, Cmd_Ignore_f },
+13 -2
View File
@@ -759,6 +759,7 @@ typedef struct
char layout[ MAX_QPATH ];
int extend_vote_count;
int mapRotationVoteTime;
int lastMsgTime;
@@ -1150,7 +1151,7 @@ void G_WriteSessionData( void );
#define MAX_MAP_ROTATIONS 16
#define MAX_MAP_ROTATION_MAPS 64
#define MAX_MAP_COMMANDS 16
#define MAX_MAP_ROTATION_CONDS 4
#define MAX_MAP_ROTATION_CONDS 8
#define NOT_ROTATING -1
@@ -1159,7 +1160,8 @@ typedef enum
MCV_ERR,
MCV_RANDOM,
MCV_NUMCLIENTS,
MCV_LASTWIN
MCV_LASTWIN,
MCV_VOTE
} mapConditionVariable_t;
typedef enum
@@ -1216,6 +1218,7 @@ typedef struct mapRotations_s
int numRotations;
} mapRotations_t;
qboolean G_MapExists( char *name );
void G_PrintRotations( void );
qboolean G_AdvanceMapRotation( void );
qboolean G_StartMapRotation( char *name, qboolean changeMap );
@@ -1224,6 +1227,12 @@ qboolean G_MapRotationActive( void );
void G_InitMapRotations( void );
qboolean G_GetRandomMap(char *name, int size);
qboolean G_CheckMapRotationVote( void );
qboolean G_IntermissionMapVoteWinner( void );
void G_IntermissionMapVoteMessage( gentity_t *ent );
void G_IntermissionMapVoteMessageAll( void );
void G_IntermissionMapVoteCommand( gentity_t *ent, qboolean next, qboolean choose );
//
// g_ptr.c
//
@@ -1301,6 +1310,7 @@ extern vmCvar_t g_extendVotesPercent;
extern vmCvar_t g_extendVotesTime;
extern vmCvar_t g_extendVotesCount;
extern vmCvar_t g_mapVotesPercent;
extern vmCvar_t g_mapRotationVote;
extern vmCvar_t g_layoutVotePercent;
extern vmCvar_t g_designateVotes;
extern vmCvar_t g_admitDefeatVotePercent;
@@ -1345,6 +1355,7 @@ extern vmCvar_t g_deconDead;
extern vmCvar_t g_debugMapRotation;
extern vmCvar_t g_currentMapRotation;
extern vmCvar_t g_currentMap;
extern vmCvar_t g_nextMap;
extern vmCvar_t g_initialMapRotation;
extern vmCvar_t g_chatTeamPrefix;
extern vmCvar_t g_floodMaxDemerits;
+55 -2
View File
@@ -91,6 +91,7 @@ vmCvar_t g_extendVotesPercent;
vmCvar_t g_extendVotesTime;
vmCvar_t g_extendVotesCount;
vmCvar_t g_mapVotesPercent;
vmCvar_t g_mapRotationVote;
vmCvar_t g_layoutVotePercent;
vmCvar_t g_designateVotes;
vmCvar_t g_admitDefeatVotePercent;
@@ -138,6 +139,7 @@ vmCvar_t g_deconDead;
vmCvar_t g_debugMapRotation;
vmCvar_t g_currentMapRotation;
vmCvar_t g_currentMap;
vmCvar_t g_nextMap;
vmCvar_t g_initialMapRotation;
vmCvar_t g_shove;
@@ -362,6 +364,7 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_extendVotesTime, "g_extendVotesTime", "10", CVAR_ARCHIVE, 0, qfalse },
{ &g_extendVotesCount, "g_extendVotesCount", "3", CVAR_ARCHIVE, 0, qfalse },
{ &g_mapVotesPercent, "g_mapVotesPercent", "50", CVAR_ARCHIVE, 0, qfalse },
{ &g_mapRotationVote, "g_mapRotationVote", "15", CVAR_ARCHIVE, 0, qfalse },
{ &g_layoutVotePercent, "g_layoutVotePercent", "50", CVAR_ARCHIVE, 0, qfalse },
{ &g_designateVotes, "g_designateVotes", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_admitDefeatVotePercent, "g_admitDefeatVotePercent", "50", CVAR_ARCHIVE, 0, qfalse },
@@ -412,6 +415,7 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_debugMapRotation, "g_debugMapRotation", "0", 0, 0, qfalse },
{ &g_currentMapRotation, "g_currentMapRotation", "-1", 0, 0, qfalse }, // -1 = NOT_ROTATING
{ &g_currentMap, "g_currentMap", "0", 0, 0, qfalse },
{ &g_nextMap, "g_nextMap", "", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qtrue },
{ &g_initialMapRotation, "g_initialMapRotation", "", CVAR_ARCHIVE, 0, qfalse },
{ &g_shove, "g_shove", "15", CVAR_ARCHIVE, 0, qfalse },
{ &g_mapConfigs, "g_mapConfigs", "", CVAR_ARCHIVE, 0, qfalse },
@@ -1703,7 +1707,7 @@ void CalculateRanks( void )
CheckExitRules( );
// if we are at the intermission, send the new info to everyone
if( level.intermissiontime )
if( level.intermissiontime && !level.mapRotationVoteTime )
SendScoreboardMessageToAllClients( );
}
@@ -1843,6 +1847,32 @@ void BeginIntermission( void )
SendScoreboardMessageToAllClients( );
}
void BeginMapRotationVote( void )
{
gentity_t *ent;
int length;
int i;
if( level.mapRotationVoteTime )
return;
length = g_mapRotationVote.integer;
if( length > 60 )
length = 60;
level.mapRotationVoteTime = level.time + ( length * 1000 );
for( i = 0; i < level.maxclients; i++ )
{
ent = g_entities + i;
if( !ent->inuse )
continue;
ent->client->ps.pm_type = PM_SPECTATOR;
ent->client->sess.sessionTeam = TEAM_SPECTATOR;
ent->client->sess.spectatorState = SPECTATOR_LOCKED;
}
}
/*
=============
@@ -1859,6 +1889,19 @@ void ExitLevel( void )
buildHistory_t *tmp, *mark;
if( level.mapRotationVoteTime )
{
if( level.time < level.mapRotationVoteTime &&
!G_IntermissionMapVoteWinner( ) )
return;
}
else if( g_mapRotationVote.integer > 0 &&
G_CheckMapRotationVote() )
{
BeginMapRotationVote( );
return;
}
while( ( tmp = level.buildHistory ) )
{
level.buildHistory = level.buildHistory->next;
@@ -1870,11 +1913,15 @@ void ExitLevel( void )
}
if( G_MapRotationActive( ) )
if ( G_MapExists( g_nextMap.string ) )
trap_SendConsoleCommand( EXEC_APPEND, va("!map %s\n", g_nextMap.string ) );
else if( G_MapRotationActive( ) )
G_AdvanceMapRotation( );
else
trap_SendConsoleCommand( EXEC_APPEND, "map_restart\n" );
trap_Cvar_Set( "g_nextMap", "" );
level.restarted = qtrue;
level.changemap = NULL;
level.intermissiontime = 0;
@@ -2573,6 +2620,12 @@ void CheckMsgTimer( void )
LastTime = level.time;
if( level.mapRotationVoteTime )
{
G_IntermissionMapVoteMessageAll( );
return;
}
if( g_welcomeMsgTime.integer && g_welcomeMsg.string[ 0 ] )
{
char buffer[ MAX_STRING_CHARS ];
+339
View File
@@ -27,6 +27,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static mapRotations_t mapRotations;
static qboolean G_GetVotedMap( char *name, int size, int rotation, int map );
/*
* ===============
* G_MapExists
*
* Check if a map exists
* ===============
* */
qboolean G_MapExists( char *name )
{
return trap_FS_FOpenFile( va( "maps/%s.bsp", name ), NULL, FS_READ );
}
/*
===============
G_ParseCommandSection
@@ -237,6 +252,68 @@ static qboolean G_ParseMapRotation( mapRotation_t *mr, char **text_p )
continue;
}
else if( !Q_stricmp( token, "*VOTE*" ) )
{
if( mr->numMaps == MAX_MAP_ROTATION_MAPS )
{
G_Printf( S_COLOR_RED "ERROR: maximum number of maps in one rotation (%d) reached\n",
MAX_MAP_ROTATION_MAPS );
return qfalse;
}
mre = &mr->maps[ mr->numMaps ];
Q_strncpyz( mre->name, token, sizeof( mre->name ) );
token = COM_Parse( text_p );
if( !Q_stricmp( token, "{" ) )
{
while( 1 )
{
token = COM_Parse( text_p );
if( !token )
break;
if( !Q_stricmp( token, "}" ) )
{
break;
}
else
{
if( mre->numConditions < MAX_MAP_ROTATION_CONDS )
{
mrc = &mre->conditions[ mre->numConditions ];
mrc->lhs = MCV_VOTE;
mrc->unconditional = qfalse;
Q_strncpyz( mrc->dest, token, sizeof( mrc->dest ) );
mre->numConditions++;
}
else
{
G_Printf( S_COLOR_YELLOW "ERROR: maximum number of maps for one vote (%d) reached\n",
MAX_MAP_ROTATION_CONDS );
}
}
}
if( !mre->numConditions )
{
G_Printf( S_COLOR_YELLOW "WARNING: no maps in *VOTE* section\n" );
}
else
{
mr->numMaps++;
mnSet = qtrue;
}
}
else
{
G_Printf( S_COLOR_RED "ERROR: *VOTE* with no section\n" );
return qfalse;
}
continue;
}
else if( !Q_stricmp( token, "}" ) )
return qtrue; //reached the end of this map rotation
@@ -494,6 +571,9 @@ static void G_IssueMapChange( int rotation )
if (!Q_stricmp(mapName, "*RANDOM*"))
G_GetRandomMap(mapName, sizeof(mapName));
if (!Q_stricmp(mapName, "*VOTE*"))
G_GetVotedMap(mapName, sizeof(mapName), rotation, map );
if( trap_FS_FOpenFile( va("maps/%s.bsp", mapName), &f, FS_READ ) > 0 )
trap_FS_FCloseFile( f );
else
@@ -596,6 +676,10 @@ static qboolean G_EvaluateMapCondition( mapRotationCondition_t *mrc )
return level.lastWin == mrc->lastWin;
break;
case MCV_VOTE:
// ignore vote for conditions;
break;
default:
case MCV_ERR:
G_Printf( S_COLOR_RED "ERROR: malformed map switch condition\n" );
@@ -853,3 +937,258 @@ qboolean G_GetRandomMap(char *name, int size)
}
return qfalse;
}
static char rotationVoteList[ MAX_MAP_ROTATION_CONDS ][ MAX_QPATH ];
static int rotationVoteLen = 0;
static int rotationVoteClientPosition[ MAX_CLIENTS ];
static int rotationVoteClientSelection[ MAX_CLIENTS ];
/*
===============
G_CheckMapRotationVote
===============
*/
qboolean G_CheckMapRotationVote( void )
{
mapRotation_t *mr;
mapRotationEntry_t *mre;
mapRotationCondition_t *mrc;
int currentRotation, currentMap, nextMap;
int i;
rotationVoteLen = 0;
if( g_mapRotationVote.integer < 1 )
return qfalse;
if( ( currentRotation = g_currentMapRotation.integer ) == NOT_ROTATING )
return qfalse;
currentMap = G_GetCurrentMap( currentRotation );
mr = &mapRotations.rotations[ currentRotation ];
nextMap = ( currentMap + 1 ) % mr->numMaps;
mre = &mr->maps[ nextMap ];
for( i = 0; i < mre->numConditions; i++ )
{
mrc = &mre->conditions[ i ];
if( mrc->lhs == MCV_VOTE )
{
Q_strncpyz( rotationVoteList[ rotationVoteLen ], mrc->dest,
sizeof( rotationVoteList[ rotationVoteLen ] ) );
rotationVoteLen++;
if( rotationVoteLen >= MAX_MAP_ROTATION_CONDS )
break;
}
}
if( !rotationVoteLen )
return qfalse;
for( i = 0; i < MAX_CLIENTS; i++ )
{
rotationVoteClientPosition[ i ] = 0;
rotationVoteClientSelection[ i ] = -1;
}
return qtrue;
}
static int G_GetMapVoteWinner( int *winvotes, int *totalvotes )
{
int results[ MAX_MAP_ROTATION_CONDS ];
int winner = 0;
int wv = 0;
int tv = 0;
int i, n;
memset( results, 0, sizeof( results ));
for( i = 0; i < MAX_CLIENTS; i++ )
{
n = rotationVoteClientSelection[ i ];
if( n >=0 && n < MAX_MAP_ROTATION_CONDS )
{
results[ n ] += 1;
tv++;
}
}
for( i = 0; i < MAX_MAP_ROTATION_CONDS; i++ )
{
if( results[ i ] > winner )
{
winner = i;
wv = results[ i ];
}
}
if( winvotes != NULL )
*winvotes = wv;
if( totalvotes != NULL )
*totalvotes = tv;
return winner;
}
qboolean G_IntermissionMapVoteWinner( void )
{
int winner, winvotes, totalvotes;
int nonvotes;
winner = G_GetMapVoteWinner( &winvotes, &totalvotes );
if( winvotes * 2 > level.numConnectedClients )
return qtrue;
nonvotes = level.numConnectedClients - totalvotes;
if( nonvotes < 0 )
nonvotes = 0;
if( winvotes > nonvotes + ( totalvotes - winvotes ) )
return qtrue;
return qfalse;
}
static qboolean G_GetVotedMap( char *name, int size, int rotation, int map )
{
mapRotation_t *mr;
mapRotationEntry_t *mre;
mapRotationCondition_t *mrc;
int i, n;
int winner;
qboolean found = qfalse;
if( !rotationVoteLen )
return qfalse;
winner = G_GetMapVoteWinner( NULL, NULL );
mr = &mapRotations.rotations[ rotation ];
mre = &mr->maps[ map ];
n = 0;
for( i = 0; i < mre->numConditions && n < rotationVoteLen; i++ )
{
mrc = &mre->conditions[ i ];
if( mrc->lhs == MCV_VOTE )
{
if( n == winner )
{
Q_strncpyz( name, mrc->dest, size );
found = qtrue;
break;
}
n++;
}
}
rotationVoteLen = 0;
return found;
}
static void G_IntermissionMapVoteMessageReal( gentity_t *ent, int winner, int winvotes, int totalvotes )
{
int clientNum;
char string[ MAX_STRING_CHARS ];
char entry[ MAX_STRING_CHARS ];
int len = 0;
int index, selection;
int i;
char *color;
clientNum = ent-g_entities;
index = rotationVoteClientSelection[ clientNum ];
selection = rotationVoteClientPosition[ clientNum ];
if( winner < 0 || winner >= MAX_MAP_ROTATION_CONDS )
winner = G_GetMapVoteWinner( &winvotes, &totalvotes );
Q_strncpyz( string, "^7Attack = down ^0/^7 Repair = up ^0/^7 F1 = vote\n\n"
"^2Map Vote Menu\n"
"^7+------------------+\n", sizeof( string ) );
for( i = 0; i < rotationVoteLen; i++ )
{
if( i == selection )
color = "^5";
else if( i == index )
color = "^1";
else
color = "^7";
Com_sprintf( entry, sizeof( entry ), "^7%s%s%s %s %s^7%s\n",
( i == index ) ? "^1>>>" : "",
( i == selection ) ? "^7(" : " ",
color,
rotationVoteList[ i ],
( i == selection ) ? "^7)" : " ",
( i == index ) ? "^1<<<" : "" );
Q_strcat( string, sizeof( string ), entry );
len += strlen( entry );
}
Com_sprintf( entry, sizeof( entry ),
"\n^7+----------------+\nleader: ^3%s^7 with %d vote%s\nvoters: %d\ntime left: %d",
rotationVoteList[ winner ],
winvotes,
( winvotes == 1 ) ? "" : "s",
totalvotes,
( level.mapRotationVoteTime - level.time ) / 1000 );
Q_strcat( string, sizeof( string ), entry );
trap_SendServerCommand( ent-g_entities, va( "cp \"%s\"\n", string ) );
}
void G_IntermissionMapVoteMessageAll( void )
{
int winner;
int winvotes, totalvotes;
int i;
winner = G_GetMapVoteWinner( &winvotes, &totalvotes );
for( i = 0; i < level.maxclients; i++ )
{
if( level.clients[ i ].pers.connected == CON_CONNECTED )
G_IntermissionMapVoteMessageReal( g_entities + i, winner, winvotes, totalvotes );
}
}
void G_IntermissionMapVoteMessage( gentity_t *ent )
{
G_IntermissionMapVoteMessageReal( ent, -1, 0, 0 );
}
void G_IntermissionMapVoteCommand( gentity_t *ent, qboolean next, qboolean choose )
{
int clientNum;
int n;
clientNum = ent-g_entities;
if( choose )
{
rotationVoteClientSelection[ clientNum ] = rotationVoteClientPosition[ clientNum ];
}
else
{
n = rotationVoteClientPosition[ clientNum ];
if( next )
n++;
else
n--;
if( n >= rotationVoteLen )
n = rotationVoteLen - 1;
if( n < 0 )
n = 0;
rotationVoteClientPosition[ clientNum ] = n;
}
G_IntermissionMapVoteMessage( ent );
}