summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2018-11-12 21:30:01 +0100
committerPaweł Redman <pawel.redman@gmail.com>2019-02-10 14:47:47 +0100
commit01d000a4e2c509ffa0d628a37ae24115ea6bf1be (patch)
tree3e746378c32aae29858399746e942d40940ac01b /src/game
parentcc57d1bf292667944c2712333c226defe4204417 (diff)
Prototype anti-stacking system
Diffstat (limited to 'src/game')
-rw-r--r--src/game/g_combat.c4
-rw-r--r--src/game/g_local.h14
-rw-r--r--src/game/g_main.c108
3 files changed, 123 insertions, 3 deletions
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index f0ea442..8dd4a44 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -507,7 +507,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
if( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
{
//nice simple happy bouncy human land
- float classValue = BG_FindValueOfClass( self->client->ps.stats[ STAT_PCLASS ] );
+ float classValue = BG_FindValueOfClass( self->client->ps.stats[ STAT_PCLASS ] ) * level.humanHandicap;
for( i = 0; i < MAX_CLIENTS; i++ )
{
@@ -540,7 +540,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
else if( self->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
{
//horribly complex nasty alien land
- float humanValue = BG_GetValueOfHuman( &self->client->ps );
+ float humanValue = BG_GetValueOfHuman( &self->client->ps ) * level.alienHandicap;
int frags;
int unclaimedFrags = (int)humanValue;
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 82ad397..342494d 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -831,6 +831,11 @@ typedef struct
statsCounters_level alienStatsCounters;
statsCounters_level humanStatsCounters;
+
+ int antistackNextCheck;
+ qboolean antistackWasHandicapping;
+ float alienHandicap;
+ float humanHandicap;
} level_locals_t;
#define CMD_CHEAT 0x01
@@ -1576,6 +1581,15 @@ extern vmCvar_t g_scrimMode;
extern vmCvar_t g_revertCooldownTime;
+extern vmCvar_t g_antistack;
+extern vmCvar_t g_antistackBias;
+extern vmCvar_t g_antistackTimeThreshold;
+extern vmCvar_t g_antistackKillThreshold;
+extern vmCvar_t g_antistackBiasThreshold;
+extern vmCvar_t g_antistackHandicapMultiplier;
+extern vmCvar_t g_antistackHandicapOffset;
+extern vmCvar_t g_antistackInterval;
+
void trap_Printf( const char *fmt );
void trap_Error( const char *fmt );
int trap_Milliseconds( void );
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( );