commit 4a3bd06890950c6b31422494a5f438f5c98b4cbe Author: /dev/humancontroller Date: Fri Aug 5 23:04:06 2011 +0200 target_power and target_creep, power range logic rewrite diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index faadc4f..3579731 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -122,143 +122,127 @@ attempt to find power for self, return qtrue if successful */ qboolean G_FindPower( gentity_t *self, qboolean searchUnspawned ) { - int i, j; - gentity_t *ent, *ent2; - gentity_t *closestPower = NULL; - int distance = 0; - int minDistance = REPEATER_BASESIZE + 1; - vec3_t temp_v; + gentity_t *reactorEnt; + int requiredBP; + gentity_t *oldParent; + int remainingBP; + gentity_t *ent; + qboolean inReactorlikeZone; + gentity_t *replike; + float minDistance; if( self->buildableTeam != TEAM_HUMANS ) return qfalse; - // Reactor is always powered + // the reactor is always powered if( self->s.modelindex == BA_H_REACTOR ) { self->parentNode = self; - return qtrue; } - // Handle repeaters + reactorEnt = G_Reactor(); + + // handle repeaters if( self->s.modelindex == BA_H_REPEATER ) { - self->parentNode = G_Reactor( ); - + self->parentNode = reactorEnt; return self->parentNode != NULL; } - // Iterate through entities - for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ ) + // dummy buildables require no power, they only poll for a potential parent node + if( self->s.modelindex == BA_NONE ) + requiredBP = -999999999; // negative in case a zone is temporarily overloaded + else + requiredBP = BG_Buildable( self->s.modelindex )->buildPoints; + + // detach the parent node for now. we'll attach a parent node later if there is enough power + oldParent = self->parentNode; + self->parentNode = NULL; + + // count the remaining buildpoints in the reactor-like zone + remainingBP = g_humanBuildPoints.integer; + for( ent = &g_entities[ MAX_CLIENTS ]; ent < &g_entities[ level.num_entities ]; ++ent ) { - if( ent->s.eType != ET_BUILDABLE ) - continue; + gentity_t *par = ent->parentNode; + if( par != NULL && ( par == reactorEnt || ( par->altSupportType > 2 && par->enabled ) ) ) + remainingBP -= BG_Buildable( ent->s.modelindex )->buildPoints; + } - // If entity is a power item calculate the distance to it - if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) && - ( searchUnspawned || ent->spawned ) && ent->powered && ent->health > 0 ) + // find out wether self is in the reactor-like zone, and attempt to power self there + inReactorlikeZone = qfalse; + for( ent = &g_entities[ MAX_CLIENTS ]; ent < &g_entities[ level.num_entities ]; ++ent ) + { + if( ( ent->s.eType == ET_BUILDABLE && ent->s.modelindex == BA_H_REACTOR && + ( searchUnspawned || ent->spawned ) && ent->health > 0 && + Distance( self->s.origin, ent->s.origin ) <= REACTOR_BASESIZE ) || + ( ent->altSupportType > 2 && ent->enabled && + Distance( self->s.origin, ent->s.origin ) <= ent->altSupportRadius ) ) { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - - // Always prefer a reactor if there is one in range - if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE ) + inReactorlikeZone = qtrue; + // if there is a reactor, or self is in a master reactor-like zone, then self can be powered + if( ( reactorEnt != NULL || ent->altSupportType == 4 ) && remainingBP >= requiredBP ) { - // Only power as much BP as the reactor can hold - if( self->s.modelindex != BA_NONE ) - { - int buildPoints = g_humanBuildPoints.integer; - - // Scan the buildables in the reactor zone - for( j = MAX_CLIENTS, ent2 = g_entities + j; j < level.num_entities; j++, ent2++ ) - { - if( ent2->s.eType != ET_BUILDABLE ) - continue; - - if( ent2 == self ) - continue; - - if( ent2->parentNode == ent ) - { - buildPoints -= BG_Buildable( ent2->s.modelindex )->buildPoints; - } - } - - buildPoints -= level.humanBuildPointQueue; - - buildPoints -= BG_Buildable( self->s.modelindex )->buildPoints; - - if( buildPoints >= 0 ) - { - self->parentNode = ent; - return qtrue; - } - else - { - // a buildable can still be built if it shares BP from two zones - - // TODO: handle combined power zones here - } - } - - // Dummy buildables don't need to look for zones + // keep the existing parent node if possible + if( oldParent != NULL && ( oldParent == reactorEnt || + ( oldParent->altSupportType > 2 && oldParent->enabled ) ) ) + self->parentNode = oldParent; else - { self->parentNode = ent; - return qtrue; - } + return qtrue; } - else if( distance < minDistance ) - { - // It's a repeater, so check that enough BP will be available to power - // the buildable but only if self is a real buildable - - if( self->s.modelindex != BA_NONE ) - { - int buildPoints = g_humanRepeaterBuildPoints.integer; - - // Scan the buildables in the repeater zone - for( j = MAX_CLIENTS, ent2 = g_entities + j; j < level.num_entities; j++, ent2++ ) - { - if( ent2->s.eType != ET_BUILDABLE ) - continue; + } + } - if( ent2 == self ) - continue; + // without a reactor, buildables in the non-master reactor-like zone + // are left unpowered. also, excessive buildables in the reactor-like + // zone are left unpowered. (even if there are repeaters nearby.) + if( inReactorlikeZone ) + return qfalse; - if( ent2->parentNode == ent ) - buildPoints -= BG_Buildable( ent2->s.modelindex )->buildPoints; - } + // otherwise self can only be powered by the nearest repeater-like entity in range, if there is one + replike = NULL; + minDistance = 0; + for( ent = &g_entities[ MAX_CLIENTS ]; ent < &g_entities[ level.num_entities ]; ++ent ) + { + float distance; + if( ( ent->s.eType == ET_BUILDABLE && ent->s.modelindex == BA_H_REPEATER && + ( searchUnspawned || ent->spawned ) && ent->powered && ent->health > 0 && + ( distance = Distance( self->s.origin, ent->s.origin ) ) <= REPEATER_BASESIZE ) || + ( ent->altSupportType > 0 && ent->enabled && + ( distance = Distance( self->s.origin, ent->s.origin ) ) <= ent->altSupportRadius ) ) + { + if( replike == NULL || distance < minDistance ) + { + replike = ent; + minDistance = distance; + } + } + } - if( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active ) - buildPoints -= level.buildPointZones[ ent->buildPointZone ].queuedBuildPoints; + if( replike != NULL ) + { + // count the remaining buildpoints in the repeater-like zone, without taking self into calculation + remainingBP = ( replike->altSupportType > 0 && replike->localBuildPointSetting >= 0 ? + replike->localBuildPointSetting : g_humanRepeaterBuildPoints.integer ); - buildPoints -= BG_Buildable( self->s.modelindex )->buildPoints; + if( replike->usesBuildPointZone && level.buildPointZones[ replike->buildPointZone ].active ) + remainingBP -= level.buildPointZones[ replike->buildPointZone ].queuedBuildPoints; - if( buildPoints >= 0 ) - { - closestPower = ent; - minDistance = distance; - } - else - { - // a buildable can still be built if it shares BP from two zones + for( ent = &g_entities[ MAX_CLIENTS ]; ent < &g_entities[ level.num_entities ]; ++ent ) + { + if( ent->parentNode == replike ) + remainingBP -= BG_Buildable( ent->s.modelindex )->buildPoints; + } - // TODO: handle combined power zones here - } - } - else - { - // Dummy buildables don't need to look for zones - closestPower = ent; - minDistance = distance; - } - } + if( remainingBP >= requiredBP ) + { + self->parentNode = replike; + return qtrue; } } - self->parentNode = closestPower; - return self->parentNode != NULL; + return qfalse; } /* @@ -300,25 +284,6 @@ gentity_t *G_PowerEntityForEntity( gentity_t *ent ) } /* -================ -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_GetBuildPoints @@ -415,36 +380,22 @@ providers will find themselves. */ gentity_t *G_InPowerZone( gentity_t *self ) { - int i; gentity_t *ent; - int distance; - vec3_t temp_v; - for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ ) + for( ent = &g_entities[ MAX_CLIENTS ]; ent < &g_entities[ level.num_entities ]; ++ent ) { - if( ent->s.eType != ET_BUILDABLE ) - continue; - if( ent == self ) continue; - if( !ent->spawned ) - continue; - - if( ent->health <= 0 ) - continue; - - // 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 ) + if( ( ent->s.eType == ET_BUILDABLE && ent->spawned && ent->powered && ent->health > 0 && + ( ( ent->s.modelindex == BA_H_REACTOR && + Distance( self->s.origin, ent->s.origin ) <= REACTOR_BASESIZE ) || + ( ent->s.modelindex == BA_H_REPEATER && + Distance( self->s.origin, ent->s.origin ) <= REPEATER_BASESIZE ) ) ) || + ( ent->altSupportType > 0 && ent->enabled && + Distance( self->s.origin, ent->s.origin ) <= ent->altSupportRadius ) ) { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - - if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE ) - return ent; - else if( ent->s.modelindex == BA_H_REPEATER && distance <= REPEATER_BASESIZE ) - return ent; + return ent; } } @@ -568,6 +519,49 @@ gentity_t *G_Overmind( void ) /* ================ +G_FindAlternateSupportNode + +anull the parent node if it was removed or the target_power/target_creep +was disabled. attempt to find an enabled master target_power/target_creep +in range. the parent node will be set to the said target_ if such is found, +and no change will be done otherwise. return wether the said target_ is found. +================ +*/ +qboolean G_FindAlternateSupportNode( gentity_t *self, qboolean creep ) +{ + int searchedType; + gentity_t *e; + + if( creep ) + searchedType = -2; + else + searchedType = 2; + + if( self->parentNode ) + { + if( !self->parentNode->inuse ) + self->parentNode = NULL; // ? + else if( self->parentNode->altSupportType != 0 && !self->enabled ) + self->parentNode = NULL; // the used node was turned off + else if( self->parentNode->altSupportType == searchedType ) + return qtrue; // the used alternate support node is still working + } + + for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e ) + { + if( e->altSupportType == searchedType && e->enabled && + Distance( self->s.origin, e->s.origin ) <= e->altSupportRadius ) + { + self->parentNode = e; + return qtrue; + } + } + + return qfalse; +} + +/* +================ G_FindCreep attempt to find creep for self, return qtrue if successful @@ -588,10 +582,19 @@ qboolean G_FindCreep( gentity_t *self ) //if self does not have a parentNode or its parentNode is invalid, then find a new one if( self->client || self->parentNode == NULL || !self->parentNode->inuse || - self->parentNode->health <= 0 ) + ( self->parentNode->altSupportType == 0 && self->parentNode->health <= 0 ) || + ( self->parentNode->altSupportType != 0 && !self->parentNode->enabled ) ) { for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ ) { + if( ent->altSupportType < 0 && ent->enabled && + Distance( self->s.origin, ent->s.origin ) <= ent->altSupportRadius ) + { + if( !self->client ) + self->parentNode = ent; + return qtrue; + } + if( ent->s.eType != ET_BUILDABLE ) continue; @@ -628,6 +631,26 @@ qboolean G_FindCreep( gentity_t *self ) /* ================ +G_IsAlternateSupportHere + +simple wrapper for G_FindAlternateSupportNode to check wether + a location has an enabled master target_power or target_creep +================ +*/ +static qboolean G_IsAlternateSupportHere( const vec3_t origin, qboolean creep ) +{ + gentity_t dummy; + + memset( &dummy, 0, sizeof( gentity_t ) ); + + dummy.parentNode = NULL; + VectorCopy( origin, dummy.s.origin ); + + return G_FindAlternateSupportNode( &dummy, creep ); +} + +/* +================ G_IsCreepHere simple wrapper to G_FindCreep to check if a location has creep @@ -794,30 +817,6 @@ void AGeneric_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, i /* ================ -AGeneric_CreepCheck - -Tests for creep and kills the buildable if there is none -================ -*/ -void AGeneric_CreepCheck( gentity_t *self ) -{ - gentity_t *spawn; - - spawn = self->parentNode; - if( !G_FindCreep( self ) ) - { - if( spawn ) - G_Damage( self, NULL, g_entities + spawn->killedBy, NULL, NULL, - self->health, 0, MOD_NOCREEP ); - else - G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_NOCREEP ); - return; - } - G_CreepSlow( self ); -} - -/* -================ AGeneric_Think A generic think function for Alien buildables @@ -825,9 +824,30 @@ A generic think function for Alien buildables */ void AGeneric_Think( gentity_t *self ) { - self->powered = G_Overmind( ) != NULL; + gentity_t *lastParentNode; + self->nextthink = level.time + BG_Buildable( self->s.modelindex )->nextthink; - AGeneric_CreepCheck( self ); + + lastParentNode = self->parentNode; + + if( G_FindAlternateSupportNode( self, qtrue ) ) + self->powered = qtrue; + else + { + self->powered = G_Overmind( ) != NULL; + + if( !G_FindCreep( self ) ) + { + if( lastParentNode && lastParentNode->altSupportType == 0 ) + G_Damage( self, NULL, g_entities + lastParentNode->killedBy, + NULL, NULL, self->health, 0, MOD_NOCREEP ); + else + G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_NOCREEP ); + return; + } + } + + G_CreepSlow( self ); } /* @@ -1763,6 +1783,38 @@ static void HRepeater_Die( gentity_t *self, gentity_t *inflictor, gentity_t *att } /* +==================== +G_AllocateBuildPointZone +==================== +*/ +qboolean G_AllocateBuildPointZone( int buildPointSetting, int *buildPointZonePtr ) +{ + int i; + buildPointZone_t *zone; + + // See if a free zone exists + for( i = 0; i < g_humanRepeaterMaxZones.integer; i++ ) + { + zone = &level.buildPointZones[ i ]; + + if( !zone->active ) + { + // Initialise the BP queue with all BP queued + zone->buildPointSetting = buildPointSetting; + zone->queuedBuildPoints = zone->totalBuildPoints = ( buildPointSetting >= 0 ? + buildPointSetting : g_humanRepeaterBuildPoints.integer ); + zone->nextQueueTime = level.time; + zone->active = qtrue; + + *buildPointZonePtr = i; + return qtrue; + } + } + + return qfalse; +} + +/* ================ HRepeater_Think @@ -1771,9 +1823,7 @@ Think for human power repeater */ void HRepeater_Think( gentity_t *self ) { - int i; gentity_t *powerEnt; - buildPointZone_t *zone; self->powered = G_FindPower( self, qfalse ); @@ -1794,26 +1844,7 @@ void HRepeater_Think( gentity_t *self ) // Initialise the zone once the repeater has spawned if( self->spawned && ( !self->usesBuildPointZone || !level.buildPointZones[ self->buildPointZone ].active ) ) - { - // See if a free zone exists - for( i = 0; i < g_humanRepeaterMaxZones.integer; i++ ) - { - zone = &level.buildPointZones[ 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->buildPointZone = zone - level.buildPointZones; - self->usesBuildPointZone = qtrue; - - break; - } - } - } + self->usesBuildPointZone = G_AllocateBuildPointZone( -1, &self->buildPointZone ); self->nextthink = level.time + POWER_REFRESH_TIME; } @@ -3077,6 +3108,7 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable, buildable_t core; int spawnCount = 0; qboolean changed = qtrue; + gentity_t *originPower; level.numBuildablesForRemoval = 0; @@ -3128,6 +3160,14 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable, // Set buildPoints to the number extra that are required buildPoints -= remainingBP; + originPower = G_PowerEntityForPoint( origin ); + + // target_power entities cannot be replaced + if( buildable == BA_H_REPEATER && originPower != NULL && + originPower->altSupportType > 0 && originPower->enabled && + Distance( origin, originPower->s.origin ) <= originPower->altSupportRadius ) + return IBE_RPTPOWERHERE; + // Build a list of buildable entities for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ ) { @@ -3167,7 +3207,10 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable, if( team == TEAM_HUMANS && buildable != BA_H_REACTOR && buildable != BA_H_REPEATER && - ent->parentNode != G_PowerEntityForPoint( origin ) ) + originPower != NULL && ent->parentNode != NULL && + !( originPower == ent->parentNode || + ( originPower->altSupportType > 2 && + ent->parentNode->altSupportType > 2 ) ) ) continue; if( !ent->inuse ) @@ -3186,7 +3229,7 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable, // Don't allow a power source to be replaced by a dependant if( team == TEAM_HUMANS && - G_PowerEntityForPoint( origin ) == ent && + originPower == ent && buildable != BA_H_REPEATER && buildable != core ) continue; @@ -3353,7 +3396,7 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance vec3_t mins, maxs; trace_t tr1, tr2, tr3; itemBuildError_t reason = IBE_NONE, tempReason; - gentity_t *tempent; + gentity_t *powerent, *tempent; float minNormal; qboolean invert; int contents; @@ -3399,7 +3442,7 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance // Check there is an Overmind if( buildable != BA_A_OVERMIND ) { - if( !G_Overmind( ) ) + if( !( G_Overmind() || G_IsAlternateSupportHere( entity_origin, qtrue ) ) ) reason = IBE_NOOVERMIND; } @@ -3417,9 +3460,10 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance else if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { //human criteria + powerent = G_PowerEntityForPoint( entity_origin ); // Check for power - if( G_IsPowered( entity_origin ) == BA_NONE ) + if( powerent == NULL ) { //tell player to build a repeater to provide power if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER ) @@ -3437,9 +3481,9 @@ 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_IsPowered( entity_origin ) == BA_H_REACTOR ) + else if( g_markDeconstruct.integer && powerent != NULL && powerent->s.modelindex == BA_H_REACTOR ) reason = IBE_RPTPOWERHERE; - else if( !g_markDeconstruct.integer && G_IsPowered( entity_origin ) ) + else if( !g_markDeconstruct.integer && powerent != NULL ) reason = IBE_RPTPOWERHERE; } diff --git a/src/game/g_local.h b/src/game/g_local.h index cc12aaf..0294662 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -264,6 +264,10 @@ struct gentity_s char *cvarName; char *op; int value; + qboolean enabled; + int altSupportType; + float altSupportRadius; + int localBuildPointSetting; }; typedef enum @@ -491,6 +495,7 @@ typedef struct { int active; + int buildPointSetting; int totalBuildPoints; int queuedBuildPoints; int nextQueueTime; @@ -820,6 +825,7 @@ int G_LayoutList( const char *map, char *list, int len ); void G_LayoutSelect( void ); void G_LayoutLoad( void ); void G_BaseSelfDestruct( team_t team ); +qboolean G_AllocateBuildPointZone( int buildPointSetting, int *buildPointZonePtr ); int G_NextQueueTime( int queuedBP, int totalBP, int queueBaseRate ); void G_QueueBuildPoints( gentity_t *self ); int G_GetBuildPoints( const vec3_t pos, team_t team ); diff --git a/src/game/g_main.c b/src/game/g_main.c index 7aef2a6..28d5225 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -545,9 +545,11 @@ void G_MapConfigs( const char *mapname ) /* ============ G_InitGame - ============ */ + +static void G_CheckNumZones( void ); + void G_InitGame( int levelTime, int randomSeed, int restart ) { int i; @@ -649,6 +651,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) // this has to be flipped after the first UpdateCvars level.spawning = qtrue; + + G_CheckNumZones( ); // parse the key/value pairs and spawn gentities G_SpawnEntitiesFromString( ); @@ -1186,7 +1190,8 @@ void G_CalculateBuildPoints( void ) buildPointZone_t *zone = &level.buildPointZones[ i ]; zone->active = qfalse; - zone->totalBuildPoints = g_humanRepeaterBuildPoints.integer; + zone->totalBuildPoints = ( zone->buildPointSetting >= 0 ? + zone->buildPointSetting : g_humanRepeaterBuildPoints.integer ); } // Iterate through entities @@ -1194,14 +1199,12 @@ void G_CalculateBuildPoints( void ) { gentity_t *ent = &g_entities[ i ]; buildPointZone_t *zone; - buildable_t buildable; int cost; - if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD ) - continue; - // mark a zone as active - if( ent->usesBuildPointZone ) + if( ( ( ent->s.eType == ET_BUILDABLE && !( ent->s.eFlags & EF_DEAD ) ) || + ent->altSupportType > 0 ) && + ent->usesBuildPointZone ) { assert( ent->buildPointZone >= 0 && ent->buildPointZone < g_humanRepeaterMaxZones.integer ); @@ -1209,6 +1212,9 @@ void G_CalculateBuildPoints( void ) zone->active = qtrue; } + if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD ) + continue; + // Subtract the BP from the appropriate pool buildable = ent->s.modelindex; cost = BG_Buildable( buildable )->buildPoints; @@ -1237,16 +1243,10 @@ void G_CalculateBuildPoints( void ) { gentity_t *ent = &g_entities[ i ]; - if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD || - ent->buildableTeam != TEAM_HUMANS ) - continue; - - buildable = ent->s.modelindex; - - if( buildable != BA_H_REPEATER ) - continue; - - if( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active ) + if( ( ( ent->s.eType == ET_BUILDABLE && ent->s.modelindex == BA_H_REPEATER && + !( ent->s.eFlags & EF_DEAD ) && ent->buildableTeam == TEAM_HUMANS ) || + ent->altSupportType > 0 ) && + ( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active ) ) { zone = &level.buildPointZones[ ent->buildPointZone ]; @@ -2230,7 +2230,6 @@ void CheckCvars( void ) static int lastPasswordModCount = -1; static int lastMarkDeconModCount = -1; static int lastSDTimeModCount = -1; - static int lastNumZones = 0; if( g_password.modificationCount != lastPasswordModCount ) { @@ -2258,6 +2257,20 @@ void CheckCvars( void ) level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000; } + G_CheckNumZones( ); + + level.frameMsec = trap_Milliseconds( ); +} + +/* +================== +G_CheckNumZones +================== +*/ +static void G_CheckNumZones( void ) +{ + static int lastNumZones = 0; + // If the number of zones changes, we need a new array if( g_humanRepeaterMaxZones.integer != lastNumZones ) { @@ -2275,10 +2288,9 @@ void CheckCvars( void ) level.buildPointZones = newZones; lastNumZones = g_humanRepeaterMaxZones.integer; } - - level.frameMsec = trap_Milliseconds( ); } + /* ============= G_RunThink diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index bee667e..6499a66 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -210,6 +210,7 @@ void SP_target_force_weapon( gentity_t *ent ); void SP_target_force_class( gentity_t *ent ); void SP_target_bpctrl( gentity_t *ent ); void SP_target_equipment_class( gentity_t *ent ); +void SP_target_power_creep( gentity_t *ent ); void SP_light( gentity_t *self ); void SP_info_null( gentity_t *self ); @@ -268,6 +269,7 @@ spawn_t spawns[ ] = { "target_bpctrl", SP_target_bpctrl }, { "target_class", SP_target_equipment_class }, { "target_count", SP_target_count }, + { "target_creep", SP_target_power_creep }, { "target_delay", SP_target_delay }, { "target_equipment", SP_target_equipment_class }, { "target_force_class", SP_target_force_class }, @@ -280,6 +282,7 @@ spawn_t spawns[ ] = { "target_location", SP_target_location }, { "target_or", SP_target_logic_gate }, { "target_position", SP_target_position }, + { "target_power", SP_target_power_creep }, { "target_print", SP_target_print }, { "target_push", SP_target_push }, { "target_relay", SP_target_relay }, diff --git a/src/game/g_target.c b/src/game/g_target.c index a3c05fa..675e57c 100644 --- a/src/game/g_target.c +++ b/src/game/g_target.c @@ -1171,3 +1171,65 @@ void SP_target_equipment_class( gentity_t *ent ) ent->use = Use_target_equipment_class; } + + +/* +==================== +Use_target_power_creep +==================== +*/ +void Use_target_power_creep( gentity_t *ent, gentity_t *other, gentity_t *activator ) +{ + if( ent->enabled ) + { + ent->enabled = qfalse; + if( ent->altSupportType > 0 && ent->altSupportType <= 2 && ent->usesBuildPointZone ) + { + ent->usesBuildPointZone = qfalse; + level.buildPointZones[ ent->buildPointZone ].active = qfalse; + } + } + else + { + ent->enabled = qtrue; + if( ent->altSupportType > 0 && ent->altSupportType <= 2 ) + ent->usesBuildPointZone = G_AllocateBuildPointZone( ent->localBuildPointSetting, + &ent->buildPointZone ); + } +} + +/* +==================== +SP_target_power_creep +==================== +*/ +void SP_target_power_creep( gentity_t *ent ) +{ + G_SpawnFloat( "radius", "100", &ent->altSupportRadius ); + + if( ent->spawnflags & 1 ) + ent->altSupportType = 2; + else + ent->altSupportType = 1; + + if( !strcmp( ent->classname, "target_creep" ) ) + ent->altSupportType *= -1; + else + { + if( ent->spawnflags & 4 ) + { + ent->altSupportType += 2; + ent->s.modelindex = BA_H_REACTOR; + } + else + { + G_SpawnInt( "localbp", "-1", &ent->localBuildPointSetting ); + ent->s.modelindex = BA_H_REPEATER; + } + } + + if( !( ent->spawnflags & 2 ) ) + Use_target_power_creep( ent, NULL, NULL ); + + ent->use = Use_target_power_creep; +}