From dc4083d04aec92e429486e84b7e1bb015897055b Mon Sep 17 00:00:00 2001
From: kai <kai@zittrig.eu>
Date: Tue, 5 May 2020 23:14:58 +0100
Subject: g_humanBuildableNoCreep settings

---
 src/game/g_buildable.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/game/g_local.h     |  3 +++
 src/game/g_main.c      |  4 ++++
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 4e87681..81d303c 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -161,6 +161,42 @@ static int G_NumberOfDependants( gentity_t *self )
 
 #define POWER_REFRESH_TIME  2000
 
+/*
+================
+G_CheckSelfDestruct
+
+check to see whether we should self destruct a human buildable
+the g_humanBuildableNoCreepMode cvar controls this, with the following modes:
+  0 - disabled
+  1 - any unpowered human building dies after g_humanBuildableNoCreepTime seconds
+  2 - any unpowered human building except the spawns die after g_humanBuildableNoCreepTime seconds
+
+both cvars must be set for this to to be enabled
+================
+*/
+
+static void G_CheckSelfDestruct( gentity_t *self )
+{
+   // make sure the level.time is above 1s else the buildings die if the map is restarted
+  if( g_humanBuildableNoCreepMode.integer <= 0 || g_humanBuildableNoCreepTime.integer <= 0 || level.time < 1000 )
+    return;
+
+  // check for blacklisted buildables
+  if( self->s.modelindex == BA_H_REPEATER ||  // don't kill repeaters, ever.
+    ( g_humanBuildableNoCreepMode.integer == 2 && self->s.modelindex == BA_H_SPAWN ) ) // mode 2 = ignore the spawns
+    return;
+  
+  // only continue if the building has been unpowered for longer than g_humanBuildableNoCreepTime.
+  if( ( level.time - self->poweredAt ) / 1000 < g_humanBuildableNoCreepTime.integer )
+    return;
+  
+  // building begone
+  G_LogPrintf("Unpowered human buildable %s, killed at at %is, which last received power at %is (game time)\n", 
+    BG_FindNameForBuildable( self->s.modelindex ), level.time / 1000, self->poweredAt / 1000 );
+  
+  G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+}
+
 /*
 ================
 G_FindPower
@@ -182,11 +218,18 @@ static qboolean G_FindPower( gentity_t *self )
 
   //reactor is always powered
   if( self->s.modelindex == BA_H_REACTOR )
+  {  
+    self->poweredAt = level.time;
     return qtrue;
-
+  }
   //if this already has power then stop now
   if( self->parentNode && self->parentNode->powered )
+  {  
+    self->poweredAt = level.time;
     return qtrue;
+  }
+  if( self->poweredAt == 0 )
+    self->poweredAt = level.time; // set this now just in case
 
   //reset parent
   self->parentNode = NULL;
@@ -219,10 +262,14 @@ static qboolean G_FindPower( gentity_t *self )
   //if there were no power items nearby give up
   if( closestPower ) {
     self->parentNode = closestPower;
+    self->poweredAt = level.time;
     return qtrue;
   }
   else
+  {
+    G_CheckSelfDestruct( self );
     return qfalse;
+  }
 }
 
 /*
@@ -2769,7 +2816,7 @@ void HSpawn_Think( gentity_t *self )
   gentity_t *ent;
 
   // spawns work without power
-  self->powered = qtrue;
+  // self->powered = qtrue; // NOT ANY MORE THEY DON'T
 
   if( self->spawned )
   {
@@ -2838,6 +2885,8 @@ void HSpawn_Think( gentity_t *self )
   }
 
   self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+
+  self->powered = G_FindPower( self );
 }
 
 
diff --git a/src/game/g_local.h b/src/game/g_local.h
index e5463c5..3c1c249 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -212,6 +212,7 @@ struct gentity_s
   gentity_t         *parentNode;        // for creep and defence/spawn dependencies
   qboolean          active;             // for power repeater, but could be useful elsewhere
   qboolean          powered;            // for human buildables
+  int               poweredAt;          // when was the human buildable powered?
   int               builtBy;            // clientNum of person that built this
   gentity_t         *dccNode;           // controlling dcc
   gentity_t         *overmindNode;      // controlling overmind
@@ -1396,6 +1397,8 @@ extern  vmCvar_t  g_enableBreath;
 extern  vmCvar_t  g_singlePlayer;
 
 extern  vmCvar_t  g_humanBuildPoints;
+extern  vmCvar_t  g_humanBuildableNoCreepMode;
+extern  vmCvar_t  g_humanBuildableNoCreepTime;
 extern  vmCvar_t  g_alienBuildPoints;
 extern  vmCvar_t  g_humanStage;
 extern  vmCvar_t  g_humanKills;
diff --git a/src/game/g_main.c b/src/game/g_main.c
index b06e512..97cd2ae 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -124,6 +124,8 @@ vmCvar_t  g_newbieNumbering;
 vmCvar_t  g_newbieNamePrefix;
 
 vmCvar_t  g_humanBuildPoints;
+vmCvar_t  g_humanBuildableNoCreepMode;
+vmCvar_t  g_humanBuildableNoCreepTime;
 vmCvar_t  g_alienBuildPoints;
 vmCvar_t  g_humanStage;
 vmCvar_t  g_humanKills;
@@ -368,6 +370,8 @@ static cvarTable_t   gameCvarTable[ ] =
   { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse},
 
   { &g_humanBuildPoints, "g_humanBuildPoints", DEFAULT_HUMAN_BUILDPOINTS, CVAR_SERVERINFO, 0, qfalse  },
+  { &g_humanBuildableNoCreepMode, "g_humanBuildableNoCreepMode", "0", CVAR_ARCHIVE, 0, qtrue },
+  { &g_humanBuildableNoCreepTime, "g_humanBuildableNoCreepTime", "0", CVAR_ARCHIVE, 0, qtrue },
   { &g_alienBuildPoints, "g_alienBuildPoints", DEFAULT_ALIEN_BUILDPOINTS, CVAR_SERVERINFO, 0, qfalse  },
   { &g_humanStage, "g_humanStage", "0", 0, 0, qfalse  },
   { &g_humanKills, "g_humanKills", "0", 0, 0, qfalse  },
-- 
cgit