diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 407a515..dde4823 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -190,7 +190,7 @@ g_admin_cmd_t g_admin_cmds[ ] = "(^5name|start admin#^7) (^5minimum level to display^7)" }, - {"listlayouts", G_admin_listlayouts, "L", + {"listlayouts", G_admin_listlayouts, "j", "display a list of all available layouts for a map", "(^5mapname^7)" }, @@ -2141,7 +2141,13 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg ) seconds = G_admin_parse_time( secs ); if( seconds <= 0 ) { - if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) ) + if( g_adminMaxBan.integer ) + { + ADMP( va( "^3!ban: ^7using default ban length of %d days\n", + g_adminMaxBan.integer ) ); + seconds = g_adminMaxBan.integer * 60 * 60 * 24; + } + else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) ) { seconds = 0; } @@ -2155,6 +2161,15 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg ) else { reason = G_SayConcatArgs( 3 + skiparg ); + + if( g_adminMaxBan.integer && + seconds > g_adminMaxBan.integer * 60 * 60 * 24 && + !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) ) + { + seconds = g_adminMaxBan.integer * 60 * 60 * 24; + ADMP( va( "^3!ban: ^7ban length limited to %d days for your admin level\n", + g_adminMaxBan.integer ) ); + } } for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) @@ -2327,10 +2342,27 @@ qboolean G_admin_adjustban( gentity_t *ent, int skiparg ) if( length ) { qtime_t qt; + + if( g_adminMaxBan.integer && + !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) && + length > g_adminMaxBan.integer * 60 * 60 * 24 ) + { + ADMP( va( "^3!adjustban: ^7ban length is limited to %d days for your admin level\n", + g_adminMaxBan.integer ) ); + return qfalse; + } + expires = trap_RealTime( &qt ) + length; } else + { + if( !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) ) + { + ADMP( "^3adjustban: ^7permanent bans disabled for your admin level\n" ); + return qfalse; + } expires = 0; + } if( g_admin_bans[ bnum - 1 ]->expires == expires ) { @@ -5991,12 +6023,19 @@ void G_admin_maplog_update( void ) void G_admin_maplog_result( char *flag ) { + static int lastTime = 0; char maplog[ MAX_CVAR_VALUE_STRING ]; int t; if( !flag ) return; + // avoid race when called in same frame + if( level.time == lastTime ) + return; + + lastTime = level.time; + if( g_adminMapLog.string[ 0 ] && g_adminMapLog.string[ 1 ] == ';' ) { @@ -6085,6 +6124,9 @@ qboolean G_admin_maplog( gentity_t *ent, int skiparg ) case 'm': result = "^2map vote"; break; + case 'l': + result = "^2layout vote"; + break; case 'M': result = "^6admin changed map"; break; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 2c655e9..70e881f 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -1466,6 +1466,10 @@ void Cmd_CallVote_f( gentity_t *ent ) { G_admin_maplog_result( "m" ); } + else if( !Q_stricmpn( level.voteString, "!map", 4 ) ) + { + G_admin_maplog_result( "l" ); + } level.voteExecuteTime = 0; trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) ); @@ -1647,6 +1651,36 @@ void Cmd_CallVote_f( gentity_t *ent ) sizeof( level.voteDisplayString ), "Change to map '%s'", arg2 ); level.votePercentToPass = g_mapVotesPercent.integer; } + else if( !Q_stricmp( arg1, "layout" ) ) + { + char map[ 64 ]; + + if( g_mapvoteMaxTime.integer + && level.time >= g_mapvoteMaxTime.integer * 1000 + && !G_admin_permission( ent, ADMF_NO_VOTE_LIMIT ) + && (level.numPlayingClients > 0 && level.numConnectedClients>1) ) + { + trap_SendServerCommand( ent-g_entities, va( + "print \"You cannot call for a mapchange after %d seconds\n\"", + g_mapvoteMaxTime.integer ) ); + G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse ); + return; + } + + trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) ); + if( Q_stricmp( arg2, "*BUILTIN*" ) && + !trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, arg2 ), NULL, FS_READ ) ) + { + trap_SendServerCommand( ent - g_entities, va( "print \"callvote: " + "layout '%s' could not be found on the server\n\"", arg2 ) ); + return; + } + + Com_sprintf( level.voteString, sizeof( level.voteString ), "!map %s %s", map, arg2 ); + Com_sprintf( level.voteDisplayString, + sizeof( level.voteDisplayString ), "Change to map layout '%s'", arg2 ); + level.votePercentToPass = g_mapVotesPercent.integer; + } else if( !Q_stricmp( arg1, "draw" ) ) { Com_sprintf( level.voteString, sizeof( level.voteString ), "evacuation" ); @@ -1720,7 +1754,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, draw, extend, kick, mute, unmute, poll, and sudden_death\n" ); + "map, map_restart, layout, draw, extend, kick, mute, unmute, poll, and sudden_death\n" ); return; } @@ -2601,7 +2635,7 @@ void Cmd_Destroy_f( gentity_t *ent ) ( ent->client->ps.weapon <= WP_HBUILD ) ) ) { // Cancel deconstruction - if( g_markDeconstruct.integer && traceEnt->deconstruct ) + if( g_markDeconstruct.integer == 1 && traceEnt->deconstruct ) { traceEnt->deconstruct = qfalse; return; @@ -2618,7 +2652,7 @@ void Cmd_Destroy_f( gentity_t *ent ) // Prevent destruction of the last spawn - if( !g_markDeconstruct.integer ) + if( g_markDeconstruct.integer != 1 ) { if( ent->client->pers.teamSelection == PTE_ALIENS && traceEnt->s.modelindex == BA_A_SPAWN ) @@ -2660,7 +2694,7 @@ void Cmd_Destroy_f( gentity_t *ent ) if( traceEnt->health > 0 || g_deconDead.integer ) { - if( g_markDeconstruct.integer ) + if( g_markDeconstruct.integer == 1 ) { traceEnt->deconstruct = qtrue; // Mark buildable for deconstruction traceEnt->deconstructTime = level.time; @@ -2713,6 +2747,97 @@ void Cmd_Destroy_f( gentity_t *ent ) } } +void Cmd_Mark_f( gentity_t *ent ) +{ + vec3_t forward, end; + trace_t tr; + gentity_t *traceEnt; + + if( g_markDeconstruct.integer != 2 ) + { + trap_SendServerCommand( ent-g_entities, + "print \"Mark is disabled\n\"" ); + return; + } + + if( ent->client->pers.paused ) + { + trap_SendServerCommand( ent-g_entities, + "print \"You may not mark while paused\n\"" ); + return; + } + + if( ent->client->pers.denyBuild ) + { + trap_SendServerCommand( ent-g_entities, + "print \"Your building rights have been revoked\n\"" ); + return; + } + + // can't mark when in hovel + if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) + return; + + if( !( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) ) + { + AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL ); + VectorMA( ent->client->ps.origin, 100, forward, end ); + + trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID ); + traceEnt = &g_entities[ tr.entityNum ]; + + if( tr.fraction < 1.0f && + ( traceEnt->s.eType == ET_BUILDABLE ) && + ( traceEnt->biteam == ent->client->pers.teamSelection ) && + ( ( ent->client->ps.weapon >= WP_ABUILD ) && + ( ent->client->ps.weapon <= WP_HBUILD ) ) ) + { + if( ( traceEnt->s.eFlags & EF_DBUILDER ) && + !ent->client->pers.designatedBuilder ) + { + trap_SendServerCommand( ent-g_entities, + "print \"this structure is protected by a designated builder\n\"" ); + return; + } + + // Cancel deconstruction + if( traceEnt->deconstruct ) + { + traceEnt->deconstruct = qfalse; + + trap_SendServerCommand( ent-g_entities, + va( "print \"%s no longer marked for deconstruction\n\"", + BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) ); + return; + } + + // Don't allow marking of buildables that cannot be rebuilt + if(g_suddenDeath.integer && traceEnt->health > 0 && + ( ( g_suddenDeathMode.integer == SDMODE_SELECTIVE && + !BG_FindReplaceableTestForBuildable( traceEnt->s.modelindex ) ) || + ( g_suddenDeathMode.integer == SDMODE_BP && + BG_FindBuildPointsForBuildable( traceEnt->s.modelindex ) ) || + g_suddenDeathMode.integer == SDMODE_NO_BUILD ) ) + { + trap_SendServerCommand( ent-g_entities, + "print \"During Sudden Death you can only mark buildings that " + "can be rebuilt\n\"" ); + return; + } + + if( traceEnt->health > 0 ) + { + traceEnt->deconstruct = qtrue; // Mark buildable for deconstruction + traceEnt->deconstructTime = level.time; + + trap_SendServerCommand( ent-g_entities, + va( "print \"%s marked for deconstruction\n\"", + BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) ); + } + } + } +} + /* ================= @@ -3381,6 +3506,9 @@ void Cmd_Protect_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, "print \"Structure protection applied\n\"" ); traceEnt->s.eFlags |= EF_DBUILDER; + + // adding protection turns off deconstruction mark + traceEnt->deconstruct = qfalse; } } } @@ -4265,6 +4393,7 @@ commands_t cmds[ ] = { { "build", CMD_TEAM|CMD_LIVING, Cmd_Build_f }, { "deconstruct", CMD_TEAM|CMD_LIVING, Cmd_Destroy_f }, + { "mark", CMD_TEAM|CMD_LIVING, Cmd_Mark_f }, { "buy", CMD_HUMAN|CMD_LIVING, Cmd_Buy_f }, { "sell", CMD_HUMAN|CMD_LIVING, Cmd_Sell_f }, diff --git a/src/game/g_local.h b/src/game/g_local.h index c9e85de..8375083 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -1326,6 +1326,7 @@ extern vmCvar_t g_adminParseSay; extern vmCvar_t g_adminSayFilter; extern vmCvar_t g_adminNameProtect; extern vmCvar_t g_adminTempBan; +extern vmCvar_t g_adminMaxBan; extern vmCvar_t g_adminMapLog; extern vmCvar_t g_adminRegisterLevel; extern vmCvar_t g_adminRegisterAdminPass; diff --git a/src/game/g_main.c b/src/game/g_main.c index 3ac8baa..fd86b67 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -150,6 +150,7 @@ vmCvar_t g_adminParseSay; vmCvar_t g_adminSayFilter; vmCvar_t g_adminNameProtect; vmCvar_t g_adminTempBan; +vmCvar_t g_adminMaxBan; vmCvar_t g_adminMapLog; vmCvar_t g_adminRegisterLevel; vmCvar_t g_adminRegisterAdminPass; @@ -372,6 +373,7 @@ static cvarTable_t gameCvarTable[ ] = { &g_adminSayFilter, "g_adminSayFilter", "0", CVAR_ARCHIVE, 0, qfalse }, { &g_adminNameProtect, "g_adminNameProtect", "1", CVAR_ARCHIVE, 0, qfalse }, { &g_adminTempBan, "g_adminTempBan", "120", CVAR_ARCHIVE, 0, qfalse }, + { &g_adminMaxBan, "g_adminMaxBan", "0", CVAR_ARCHIVE, 0, qfalse }, { &g_minLevelToJoinTeam, "g_minLevelToJoinTeam", "0", CVAR_ARCHIVE, 0, qfalse }, { &g_adminMapLog, "g_adminMapLog", "", CVAR_ROM, 0, qfalse }, { &g_adminRegisterLevel, "g_adminRegisterLevel", "1", CVAR_ARCHIVE, 0, qfalse }, @@ -2316,6 +2318,10 @@ void CheckVote( void ) { G_admin_maplog_result( "m" ); } + else if( !Q_stricmpn( level.voteString, "!map", 4 ) ) + { + G_admin_maplog_result( "l" ); + } trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) ); if( !Q_stricmp( level.voteString, "map_restart" ) ||