summaryrefslogtreecommitdiff
path: root/src/game/g_buildable.c
diff options
context:
space:
mode:
authorBen Millwood <thebenmachine@gmail.com>2009-10-03 12:52:08 +0000
committerTim Angus <tim@ngus.net>2013-01-03 00:16:17 +0000
commiteb9f1d7a0e02993772facc4314a0ba9f62592879 (patch)
tree5ad820d9415d6b7181962453249044d3516f772d /src/game/g_buildable.c
parentfd69c6cdcccfee850fb769ce34883ee7813ab569 (diff)
Zone BP
Diffstat (limited to 'src/game/g_buildable.c')
-rw-r--r--src/game/g_buildable.c261
1 files changed, 195 insertions, 66 deletions
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 8d77267a..11ed8db4 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "g_local.h"
+zone_t zones[ MAX_ZONES ];
+
/*
================
G_SetBuildableAnim
@@ -212,7 +214,7 @@ Simple wrapper to G_FindPower to find the entity providing
power for the specified point
================
*/
-static gentity_t *G_PowerEntityForPoint( vec3_t origin )
+gentity_t *G_PowerEntityForPoint( vec3_t origin )
{
gentity_t dummy;
@@ -229,90 +231,112 @@ static gentity_t *G_PowerEntityForPoint( vec3_t origin )
/*
================
-G_FindRepeater
+G_IsPowered
+
+Check if a location has power, returning the entity type
+that is providing it
+================
+*/
+buildable_t G_IsPowered( vec3_t origin )
+{
+ gentity_t *ent = G_PowerEntityForPoint( origin );
+
+ if( ent )
+ return ent->s.modelindex;
+ else
+ return BA_NONE;
+}
+
+/*
+================
+G_RepeaterWouldOverlap
-attempt to find a repeater in range of self, return qtrue if successful
+Check if a repeater would create an overlapping power zone
================
*/
-static qboolean G_FindRepeater( gentity_t *self )
+static qboolean G_RepeaterWouldOverlap( vec3_t origin )
{
int i;
gentity_t *ent;
- gentity_t *closestPower = NULL;
- int distance = 0;
- int minDistance = REPEATER_BASESIZE + 1;
+ int distance;
vec3_t temp_v;
- if( self->buildableTeam != TEAM_HUMANS )
- return qfalse;
-
- //iterate through entities
+ // Iterate through entities
for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
continue;
- //if entity is a power item calculate the distance to it
- if( ent->s.modelindex == BA_H_REPEATER &&
+ // If entity is a power item calculate the distance to it
+ if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) &&
ent->spawned && ent->powered )
{
- VectorSubtract( self->s.origin, ent->s.origin, temp_v );
+ VectorSubtract( origin, ent->s.origin, temp_v );
distance = VectorLength( temp_v );
- if( distance < minDistance )
+ if( ent->s.modelindex == BA_H_REACTOR )
{
- closestPower = ent;
- minDistance = distance;
+ if( distance <= REACTOR_BASESIZE + REPEATER_BASESIZE )
+ return qtrue;
+ }
+ else if( ent->s.modelindex == BA_H_REPEATER )
+ {
+ if( distance <= REPEATER_BASESIZE + REPEATER_BASESIZE )
+ return qtrue;
}
}
}
- //if there were no power items nearby give up
- if( closestPower )
- {
- self->parentNode = closestPower;
- return qtrue;
- }
return qfalse;
}
+
/*
-================
-G_RepeaterEntityForPoint
+==================
+G_GetBuildPoints
-Simple wrapper to G_FindRepeater to find a repeater providing
-power for the specified point
-================
+Get the number of build points from a position
+==================
*/
-static gentity_t *G_RepeaterEntityForPoint( vec3_t origin )
+int G_GetBuildPoints( const vec3_t pos, team_t team, int dist )
{
- gentity_t dummy;
+ int i;
+ gentity_t *ent;
+ int distance = 0;
+ vec3_t temp_v;
+ int buildPoints = 0;
- dummy.parentNode = NULL;
- dummy.buildableTeam = TEAM_HUMANS;
- dummy.s.modelindex = BA_NONE;
- VectorCopy( origin, dummy.s.origin );
+ if( team == TEAM_HUMANS )
+ {
+ // Iterate through entities
+ for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ ent = &g_entities[ i ];
- if( G_FindRepeater( &dummy ) )
- return dummy.parentNode;
- else
- return NULL;
-}
-/*
-================
-G_IsPowered
+ VectorSubtract( pos, ent->s.origin, temp_v );
+ distance = VectorLength( temp_v );
-Check if a location has power, returning the entity type
-that is providing it
-================
-*/
-buildable_t G_IsPowered( vec3_t origin )
-{
- gentity_t *ent = G_PowerEntityForPoint( origin );
+ if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE + dist )
+ {
+ // Reactor is in range
+ buildPoints += level.humanBuildPoints;
+ }
+ else if( ent->s.modelindex == BA_H_REPEATER && distance <= REPEATER_BASESIZE + dist )
+ {
+ if( ent->usesZone && zones[ent->zone].active )
+ {
+ zone_t *zone = &zones[ent->zone];
- if( ent )
- return ent->s.modelindex;
- else
- return BA_NONE;
+ buildPoints += zone->totalBuildPoints - zone->queuedBuildPoints;
+ }
+ }
+ }
+ }
+ else if( team == TEAM_ALIENS )
+ {
+ buildPoints = level.alienBuildPoints;
+ }
+
+ return buildPoints;
}
/*
@@ -1625,6 +1649,48 @@ void ATrapper_Think( gentity_t *self )
+void HSpawn_Blast( gentity_t *ent );
+void HSpawn_Disappear( gentity_t *ent );
+
+/*
+================
+HRepeater_Die
+
+Called when a repeater dies
+================
+*/
+static void HRepeater_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod )
+{
+ G_RewardAttackers( self );
+ G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue );
+ G_SetIdleBuildableAnim( self, BANIM_DESTROYED );
+
+ self->die = nullDieFunction;
+ self->powered = qfalse; //free up power
+ self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
+
+ if( self->spawned )
+ {
+ self->think = HSpawn_Blast;
+ self->nextthink = level.time + HUMAN_DETONATION_DELAY;
+ }
+ else
+ {
+ self->think = HSpawn_Disappear;
+ self->nextthink = level.time; //blast immediately
+ }
+
+ G_LogDestruction( self, attacker, mod );
+
+ if( self->usesZone )
+ {
+ zone_t *zone = &zones[self->zone];
+
+ zone->active = qfalse;
+ self->usesZone = qfalse;
+ }
+}
+
/*
================
HRepeater_Think
@@ -1637,10 +1703,11 @@ void HRepeater_Think( gentity_t *self )
int i;
qboolean reactor = qfalse;
gentity_t *ent;
+ zone_t *zone;
if( self->spawned )
{
- //iterate through entities
+ // Iterate through entities
for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
@@ -1653,7 +1720,7 @@ void HRepeater_Think( gentity_t *self )
if( G_NumberOfDependants( self ) == 0 )
{
- //if no dependants for x seconds then disappear
+ // If no dependants for x seconds then disappear
if( self->count < 0 )
self->count = level.time;
else if( self->count > 0 && ( ( level.time - self->count ) > REPEATER_INACTIVE_TIME ) )
@@ -1664,6 +1731,29 @@ void HRepeater_Think( gentity_t *self )
self->powered = reactor;
+ // Initialise the zone once the repeater has spawned
+ if( self->spawned && ( !self->usesZone || !zones[ self->zone ].active ) )
+ {
+ // See if a free zone exists
+ for( i = 0; i < MIN( g_humanRepeaterMaxZones.integer, MAX_ZONES ); i++ )
+ {
+ zone = &zones[ i ];
+
+ if( !zone->active )
+ {
+ // Initialise the BP queue with all BP queued
+ zone->queuedBuildPoints = zone->totalBuildPoints = g_humanRepeaterBuildPoints.integer;
+ zone->nextQueueTime = level.time;
+ zone->active = qtrue;
+
+ self->zone = zone - zones;
+ self->usesZone = qtrue;
+
+ break;
+ }
+ }
+ }
+
self->nextthink = level.time + POWER_REFRESH_TIME;
}
@@ -2398,6 +2488,7 @@ G_QueueBuildPoints
void G_QueueBuildPoints( gentity_t *self )
{
gentity_t *killer = NULL;
+ gentity_t *powerEntity;
if( self->killedBy != ENTITYNUM_NONE )
killer = &g_entities[ self->killedBy ];
@@ -2425,11 +2516,34 @@ void G_QueueBuildPoints( gentity_t *self )
break;
case TEAM_HUMANS:
- if( !level.humanBuildPointQueue )
- level.humanNextQueueTime = level.time + g_humanBuildQueueTime.integer;
+ powerEntity = G_PowerEntityForPoint( self->s.origin );
+
+ if( powerEntity )
+ {
+ switch( powerEntity->s.modelindex )
+ {
+ default:
+ case BA_H_REACTOR:
+ if( !level.humanBuildPointQueue )
+ level.humanNextQueueTime = level.time + g_humanBuildQueueTime.integer;
+
+ level.humanBuildPointQueue +=
+ BG_Buildable( self->s.modelindex )->buildPoints;
+ break;
+
+ case BA_H_REPEATER:
+ if( powerEntity->usesZone && zones[powerEntity->zone].active )
+ {
+ zone_t *zone = &zones[powerEntity->zone];
- level.humanBuildPointQueue +=
- BG_Buildable( self->s.modelindex )->buildPoints;
+ if( !zone->queuedBuildPoints )
+ zone->nextQueueTime = level.time + g_humanRepeaterBuildQueueTime.integer;
+ zone->queuedBuildPoints +=
+ BG_Buildable( self->s.modelindex )->buildPoints;
+ }
+ break;
+ }
+ }
break;
}
}
@@ -2813,7 +2927,7 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
if( team == TEAM_ALIENS )
{
- remainingBP = level.alienBuildPoints;
+ remainingBP = G_GetBuildPoints( origin, team, 0 );
remainingSpawns = level.numAlienSpawns;
bpError = IBE_NOALIENBP;
spawn = BA_A_SPAWN;
@@ -2821,7 +2935,7 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
}
else if( team == TEAM_HUMANS )
{
- remainingBP = level.humanBuildPoints;
+ remainingBP = G_GetBuildPoints( origin, team, 0 );
remainingSpawns = level.numHumanSpawns;
bpError = IBE_NOHUMANBP;
spawn = BA_H_SPAWN;
@@ -2889,6 +3003,13 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
else
repeaterInRange = qfalse;
+ // Don't allow marked buildables to be replaced in another zone,
+ // unless the marked buildable is unpowered
+ if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER &&
+ G_PowerEntityForPoint( ent->s.origin ) != G_PowerEntityForPoint( origin ) &&
+ G_PowerEntityForPoint( ent->s.origin ) )
+ continue;
+
if( !ent->inuse )
continue;
@@ -2907,6 +3028,11 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
if( ent->s.modelindex == core && buildable != core )
continue;
+ // Don't allow a power source to be replaced by a non-power source
+ if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER &&
+ ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) )
+ continue;
+
if( ent->deconstruct )
{
level.markedBuildables[ numBuildables++ ] = ent;
@@ -3066,6 +3192,9 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
contents = trap_PointContents( entity_origin, -1 );
buildPoints = BG_Buildable( buildable )->buildPoints;
+ if( ( tempReason = G_SufficientBPAvailable( buildable, origin ) ) != IBE_NONE )
+ reason = tempReason;
+
if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
//alien criteria
@@ -3122,8 +3251,11 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
if( tempent == NULL ) // No reactor
reason = IBE_RPTNOREAC;
- else if( !g_markDeconstruct.integer && G_RepeaterEntityForPoint( entity_origin ) )
+ else if( G_RepeaterWouldOverlap( entity_origin ) )
+ {
+ // The repeater would cause power zones to overlap
reason = IBE_RPTPOWERHERE;
+ }
}
// Check permission to build here
@@ -3162,9 +3294,6 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
}
}
- if( ( tempReason = G_SufficientBPAvailable( buildable, origin ) ) != IBE_NONE )
- reason = tempReason;
-
// Relink buildables
G_SetBuildableLinkState( qtrue );
@@ -3355,7 +3484,7 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori
case BA_H_REPEATER:
built->think = HRepeater_Think;
- built->die = HSpawn_Die;
+ built->die = HRepeater_Die;
built->use = HRepeater_Use;
built->count = -1;
break;