From 01d000a4e2c509ffa0d628a37ae24115ea6bf1be Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Mon, 12 Nov 2018 21:30:01 +0100 Subject: Prototype anti-stacking system --- src/game/g_combat.c | 4 +- src/game/g_local.h | 14 +++++++ src/game/g_main.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 3 deletions(-) (limited to 'src/game') 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( ); -- cgit