summaryrefslogtreecommitdiff
path: root/src/game/g_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_main.c')
-rw-r--r--src/game/g_main.c108
1 files changed, 107 insertions, 1 deletions
diff --git a/src/game/g_main.c b/src/game/g_main.c
index b2e329a..9316f06 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -284,6 +284,15 @@ vmCvar_t g_scrimMode;
vmCvar_t g_revertCooldownTime;
+vmCvar_t g_antistack;
+vmCvar_t g_antistackBias;
+vmCvar_t g_antistackTimeThreshold;
+vmCvar_t g_antistackKillThreshold;
+vmCvar_t g_antistackBiasThreshold;
+vmCvar_t g_antistackHandicapMultiplier;
+vmCvar_t g_antistackHandicapOffset;
+vmCvar_t g_antistackInterval;
+
static cvarTable_t gameCvarTable[ ] =
{
// don't override the cheat state set by the system
@@ -555,7 +564,15 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_schachtmeisterAutobahnThreshold, "g_schachtmeisterAutobahnThreshold", "-30", CVAR_ARCHIVE, 0, qfalse },
{ &g_schachtmeisterAutobahnMessage, "g_schachtmeisterAutobahnMessage", "Your host is blacklisted.", CVAR_ARCHIVE, 0, qfalse },
- { &g_revertCooldownTime, "g_revertCooldownTime", "30", CVAR_ARCHIVE, 0, qfalse }
+ { &g_revertCooldownTime, "g_revertCooldownTime", "30", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_antistack, "g_antistack", "0", CVAR_ARCHIVE, 0, qfalse },
+ { &g_antistackBias, "g_antistackBias", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_antistackTimeThreshold, "g_antistackTimeThreshold", "120", CVAR_ARCHIVE, 0, qfalse },
+ { &g_antistackKillThreshold, "g_antistackKillThreshold", "10", CVAR_ARCHIVE, 0, qfalse },
+ { &g_antistackBiasThreshold, "g_antistackBiasThreshold", "2", CVAR_ARCHIVE, 0, qfalse },
+ { &g_antistackHandicapMultiplier, "g_antistackHandicapMultiplier", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_antistackInterval, "g_antistackInterval", "60", CVAR_ARCHIVE, 0, qfalse },
};
static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[ 0 ] );
@@ -997,6 +1014,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
level.humanTeamLocked=qtrue;
trap_Cvar_Set( "g_lockTeamsAtStart", "0" );
}
+
+ level.antistackNextCheck = g_antistackTimeThreshold.integer * 1000;
}
/*
@@ -2662,6 +2681,90 @@ void CheckExitRules( void )
}
}
+/*
+=================
+AntistackHandicap
+=================
+*/
+
+static qboolean AntistackHandicap(void)
+{
+ qboolean human_bias;
+ float bias, handicap;
+
+ if (level.alienKills < g_antistackKillThreshold.integer &&
+ level.humanKills < g_antistackKillThreshold.integer)
+ return qfalse;
+
+ if (level.humanKills > level.alienKills) {
+ human_bias = qtrue;
+ bias = (float)level.humanKills / level.alienKills;
+ } else {
+ human_bias = qfalse;
+ bias = (float)level.alienKills / level.humanKills;
+ }
+
+ bias *= g_antistackBias.value;
+
+ if (bias < g_antistackBiasThreshold.value)
+ return qfalse;
+
+ handicap = g_antistackHandicapMultiplier.value / (bias - 1.0f + 0.2f);
+
+ if (human_bias) {
+ level.alienHandicap = 1.0f;
+ level.humanHandicap = handicap;
+ } else {
+ level.alienHandicap = handicap;
+ level.humanHandicap = 1.0f;
+ }
+
+ G_LogPrintf("Antistack: %d %d %f %s %f", level.alienKills, level.humanKills,
+ bias, (human_bias ? "human" : "alien"), handicap);
+ if (g_antistack.integer > 0)
+ trap_SendServerCommand(-1, va("print \"^1Teams are uneven. %s income is decreased by %.0f percent.\"",
+ (human_bias ? "Human" : "Alien"),
+ (1.0f - handicap) * 100.0f));
+
+ level.antistackWasHandicapping = qtrue;
+ return qtrue;
+}
+
+/*
+=================
+CheckAntistack
+=================
+*/
+static void CheckAntistack(void)
+{
+ if (!g_antistack.integer || level.intermissiontime)
+ return;
+
+ if (level.time < level.antistackNextCheck)
+ return;
+
+ if (!AntistackHandicap()) {
+ level.alienHandicap = 1.0f;
+ level.humanHandicap = 1.0f;
+
+ if (level.antistackWasHandicapping) {
+ G_LogPrintf("Antistack: %d %d reset\n",
+ level.alienKills, level.humanKills);
+ if (g_antistack.integer > 0)
+ trap_SendServerCommand(-1, "^1Teams are no longer uneven.");
+ }
+
+ level.antistackWasHandicapping = qfalse;
+ }
+
+ // Negative g_antistack values cause a dry run and are for debugging.
+ if (g_antistack.integer < 0) {
+ level.alienHandicap = 1.0f;
+ level.humanHandicap = 1.0f;
+ }
+
+ level.antistackNextCheck = level.time + g_antistackInterval.integer * 1000;
+}
/*
@@ -3502,6 +3605,9 @@ void G_RunFrame( int levelTime )
// update to team status?
CheckTeamStatus( );
+ // anti-stacking
+ CheckAntistack( );
+
// cancel vote if timed out
CheckVote( );