From 7d3e935cc3ca35ee9515452bf19c8d8e7a44528c Mon Sep 17 00:00:00 2001
From: "Tony J. White" <tjw@tjw.org>
Date: Tue, 13 Feb 2007 17:06:01 +0000
Subject: * (bug 3021) allow building "on top of" existing marked buildables
 when   using g_markDeconstruct. (kevlarman)

---
 src/game/bg_misc.c     |   2 +-
 src/game/g_buildable.c | 101 ++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 84 insertions(+), 19 deletions(-)

diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index a8f10300..76616a67 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -5089,7 +5089,7 @@ void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,
   //so buildings drop to floor
   VectorMA( targetOrigin, -128, playerNormal, targetOrigin );
 
-  (*trace)( tr, entityOrigin, mins, maxs, targetOrigin, ps->clientNum, MASK_PLAYERSOLID );
+  (*trace)( tr, entityOrigin, mins, maxs, targetOrigin, ps->clientNum, MASK_DEADSOLID );
   VectorCopy( tr->endpos, entityOrigin );
   VectorMA( entityOrigin, 0.1f, playerNormal, outOrigin );
   vectoangles( forward, outAngles );
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 6a0fde75..f479d353 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -2607,11 +2607,12 @@ static qboolean G_SufficientBPAvailable( buildableTeam_t team,
                                          buildable_t     buildable )
 {
   int       i;
-  int       numBuildables = 0;
+  int       numBuildables = level.numBuildablesForRemoval;
   int       pointsYielded = 0;
   gentity_t *ent;
   qboolean  unique = BG_FindUniqueTestForBuildable( buildable );
   int       remainingBP, remainingSpawns;
+  int       numBuildablesInTheWay = level.numBuildablesForRemoval;
 
   if( team == BIT_ALIENS )
   {
@@ -2675,23 +2676,29 @@ static qboolean G_SufficientBPAvailable( buildableTeam_t team,
   if( buildPoints > 0 && numBuildables == 0 )
     return qfalse;
 
-  // Sort the list
-  qsort( level.markedBuildables, numBuildables, sizeof( level.markedBuildables[ 0 ] ),
-         G_CompareBuildablesForRemoval );
+  // Sort everything that was added to the list, but leave what was already 
+  // there in the front (those buildings are blocking the new buildable)
+  qsort( level.markedBuildables + numBuildablesInTheWay,
+    numBuildables - numBuildablesInTheWay,
+    sizeof( level.markedBuildables[ 0 ] ), G_CompareBuildablesForRemoval );
 
-  // Do a pass looking for a buildable of the same type that we're
-  // building and mark it (and only it) for destruction if found
-  for( i = 0; i < numBuildables; i++ )
+  // if any buildings are in the way of what we're building
+  // we must force them to be deconned regardless of bp, so this won't work
+  if( numBuildablesInTheWay == 0 )
   {
-    ent = level.markedBuildables[ i ];
-
-    if( ent->s.modelindex == buildable )
+    // Do a pass looking for a buildable of the same type that we're
+    // building and mark it (and only it) for destruction if found
+    for( i = 0; i < numBuildables; i++ )
     {
-      // If we're removing what we're building this will always work
-      level.markedBuildables[ 0 ]   = ent;
-      level.numBuildablesForRemoval = 1;
+      ent = level.markedBuildables[ i ];
 
-      return qtrue;
+      if( ent->s.modelindex == buildable )
+      {
+        // If we're removing what we're building this will always work
+        level.markedBuildables[ 0 ]   = ent;
+        level.numBuildablesForRemoval = 1;
+        return qtrue;
+      }
     }
   }
 
@@ -2703,6 +2710,11 @@ static qboolean G_SufficientBPAvailable( buildableTeam_t team,
     pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
   }
 
+  if( level.numBuildablesForRemoval < numBuildablesInTheWay )
+  {
+    level.numBuildablesForRemoval = numBuildablesInTheWay;
+  }
+
   // Not enough points yielded
   if( pointsYielded < buildPoints )
   {
@@ -2726,7 +2738,9 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
 {
   vec3_t            angles;
   vec3_t            entity_origin, normal;
-  vec3_t            mins, maxs;
+  vec3_t            mins, maxs, mins1, maxs1;
+  int               num;
+  int               entitylist[ MAX_GENTITIES ];
   trace_t           tr1, tr2, tr3;
   int               i;
   itemBuildError_t  reason = IBE_NONE;
@@ -2740,9 +2754,11 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
   BG_FindBBoxForBuildable( buildable, mins, maxs );
 
   BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, trap_Trace, entity_origin, angles, &tr1 );
-
-  trap_Trace( &tr2, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_PLAYERSOLID );
-  trap_Trace( &tr3, ps->origin, NULL, NULL, entity_origin, ent->s.number, MASK_PLAYERSOLID );
+  VectorAdd( entity_origin, mins, mins1 );
+  VectorAdd( entity_origin, maxs, maxs1 );
+  num = trap_EntitiesInBox( mins1, maxs1, entitylist, MAX_GENTITIES );
+  trap_Trace( &tr2, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_DEADSOLID );
+  trap_Trace( &tr3, ps->origin, NULL, NULL, entity_origin, ent->s.number, MASK_DEADSOLID );
 
   VectorCopy( entity_origin, origin );
 
@@ -2764,6 +2780,55 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
   contents = trap_PointContents( entity_origin, -1 );
   buildPoints = BG_FindBuildPointsForBuildable( buildable );
 
+  //force buildings that are blocking the current building to be
+  //deconstructed before other marked buildings
+  level.numBuildablesForRemoval = 0;
+  for(i = 0; i < num; i++)
+  {
+    gentity_t *tent = &g_entities[ entitylist[ i ] ];
+    if( tent->s.eType == ET_PLAYER )
+    {
+      reason = IBE_NOROOM;
+      break;
+    }
+    else if( tent->biteam != ent->client->ps.stats[ STAT_PTEAM ] )
+    {
+      reason = IBE_NOROOM;
+    }
+    else if( tent->s.eType == ET_BUILDABLE && !tent->deconstruct )
+    {
+      reason = IBE_NOROOM;
+      break;
+    }
+    else
+    {
+      if( tent->s.modelindex == BA_H_SPAWN && level.numHumanSpawns <= 1 )
+      {
+        reason = IBE_NOROOM;
+        break;
+      }
+      else if( tent->s.modelindex == BA_A_SPAWN && level.numHumanSpawns <= 1 )
+      {
+        reason = IBE_NOROOM;
+        break;
+      }
+      else if( tent->s.modelindex == BA_H_REACTOR && buildable != BA_H_REACTOR )
+      {
+        reason = IBE_NOROOM;
+        break;
+      }
+      else if( tent->s.modelindex == BA_A_OVERMIND && buildable != BA_A_OVERMIND )
+      {
+        reason = IBE_NOROOM;
+        break;
+      }
+      level.markedBuildables[ level.numBuildablesForRemoval++ ] = tent;
+    }
+  }
+  if( reason != IBE_NONE )
+  {
+    level.numBuildablesForRemoval = 0;
+  }
   if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
   {
     //alien criteria
-- 
cgit