diff options
Diffstat (limited to 'src/game/g_buildable.c')
-rw-r--r-- | src/game/g_buildable.c | 550 |
1 files changed, 378 insertions, 172 deletions
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index c56dec3c..ad2ece9e 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -192,7 +192,7 @@ static qboolean G_FindPower( gentity_t *self ) //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->spawned && ent->health > 0 ) { VectorSubtract( self->s.origin, ent->s.origin, temp_v ); distance = VectorLength( temp_v ); @@ -268,28 +268,19 @@ buildable_t G_IsPowered( vec3_t origin ) ================ G_FindDCC -attempt to find a controlling DCC for self, return qtrue if successful +attempt to find a controlling DCC for self, return number found ================ */ -static qboolean G_FindDCC( gentity_t *self ) +int G_FindDCC( gentity_t *self ) { int i; gentity_t *ent; - gentity_t *closestDCC = NULL; int distance = 0; - int minDistance = 10000; vec3_t temp_v; - qboolean foundDCC = qfalse; + int foundDCC = 0; if( self->biteam != BIT_HUMANS ) - return qfalse; - - //if this already has dcc then stop now - if( self->dccNode && self->dccNode->powered ) - return qtrue; - - //reset parent - self->dccNode = NULL; + return 0; //iterate through entities for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) @@ -302,22 +293,14 @@ static qboolean G_FindDCC( gentity_t *self ) { VectorSubtract( self->s.origin, ent->s.origin, temp_v ); distance = VectorLength( temp_v ); - if( distance < minDistance && ent->powered ) + if( distance < DC_RANGE && ent->powered ) { - closestDCC = ent; - minDistance = distance; - foundDCC = qtrue; + foundDCC++; } } } - //if there was no nearby DCC give up - if( !foundDCC ) - return qfalse; - - self->dccNode = closestDCC; - - return qtrue; + return foundDCC; } /* @@ -333,7 +316,6 @@ qboolean G_IsDCCBuilt( void ) memset( &dummy, 0, sizeof( gentity_t ) ); - dummy.dccNode = NULL; dummy.biteam = BIT_HUMANS; return G_FindDCC( &dummy ); @@ -404,7 +386,7 @@ G_FindCreep attempt to find creep for self, return qtrue if successful ================ */ -static qboolean G_FindCreep( gentity_t *self ) +qboolean G_FindCreep( gentity_t *self ) { int i; gentity_t *ent; @@ -418,9 +400,9 @@ static qboolean G_FindCreep( gentity_t *self ) return qtrue; //if self does not have a parentNode or it's parentNode is invalid find a new one - if( ( self->parentNode == NULL ) || !self->parentNode->inuse ) + if( self->client || ( self->parentNode == NULL ) || !self->parentNode->inuse ) { - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) + for ( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ ) { if( ent->s.eType != ET_BUILDABLE ) continue; @@ -440,13 +422,17 @@ static qboolean G_FindCreep( gentity_t *self ) if( minDistance <= CREEP_BASESIZE ) { - self->parentNode = closestSpawn; + if( !self->client ) + self->parentNode = closestSpawn; return qtrue; } else return qfalse; } + if( self->client ) + return qfalse; + //if we haven't returned by now then we must already have a valid parent return qtrue; } @@ -845,29 +831,15 @@ void AOvermind_Think( gentity_t *self ) -/* -================ -ABarricade_Pain - -pain function for Alien Spawn -================ -*/ -void ABarricade_Pain( gentity_t *self, gentity_t *attacker, int damage ) -{ - if( rand( ) % 1 ) - G_SetBuildableAnim( self, BANIM_PAIN1, qfalse ); - else - G_SetBuildableAnim( self, BANIM_PAIN2, qfalse ); -} /* ================ -ABarricade_Blast +AGeneric_Blast -Called when an alien spawn dies +Called when an Alien buildable explodes after dead state ================ */ -void ABarricade_Blast( gentity_t *self ) +void AGeneric_Blast( gentity_t *self ) { vec3_t dir; @@ -890,18 +862,19 @@ void ABarricade_Blast( gentity_t *self ) /* ================ -ABarricade_Die +AGeneric_Die -Called when an alien spawn dies +Called when an Alien buildable is killed and enters a brief dead state prior to +exploding. ================ */ -void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) +void AGeneric_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) { G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue ); G_SetIdleBuildableAnim( self, BANIM_DESTROYED ); self->die = nullDieFunction; - self->think = ABarricade_Blast; + self->think = AGeneric_Blast; self->s.eFlags &= ~EF_FIRING; //prevent any firing effects if( self->spawned ) @@ -928,12 +901,12 @@ void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, /* ================ -ABarricade_Think +AGeneric_Think -Think function for Alien Barricade +A generic think function for Alien buildables ================ */ -void ABarricade_Think( gentity_t *self ) +void AGeneric_Think( gentity_t *self ) { self->powered = G_IsOvermindBuilt( ); @@ -950,6 +923,21 @@ void ABarricade_Think( gentity_t *self ) self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); } +/* +================ +AGeneric_Pain + +A generic pain function for Alien buildables +================ +*/ +void AGeneric_Pain( gentity_t *self, gentity_t *attacker, int damage ) +{ + if( rand( ) % 1 ) + G_SetBuildableAnim( self, BANIM_PAIN1, qfalse ); + else + G_SetBuildableAnim( self, BANIM_PAIN2, qfalse ); +} + @@ -958,6 +946,153 @@ void ABarricade_Think( gentity_t *self ) + +/* +================ +ABarricade_Pain + +Barricade pain animation depends on shrunk state +================ +*/ +void ABarricade_Pain( gentity_t *self, gentity_t *attacker, int damage ) +{ + if( !self->shrunkTime ) + G_SetBuildableAnim( self, BANIM_PAIN1, qfalse ); + else + G_SetBuildableAnim( self, BANIM_PAIN2, qfalse ); +} + +/* +================ +ABarricade_Shrink + +Set shrink state for a barricade. When unshrinking, checks to make sure there +is enough room. +================ +*/ +void ABarricade_Shrink( gentity_t *self, qboolean shrink ) +{ + if ( !self->spawned || self->health <= 0 ) + shrink = qtrue; + if ( shrink && self->shrunkTime ) + { + int anim; + + // We need to make sure that the animation has been set to shrunk mode + // because we start out shrunk but with the construct animation when built + self->shrunkTime = level.time; + anim = self->s.torsoAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT ); + if ( self->spawned && self->health > 0 && anim != BANIM_DESTROYED ) + { + G_SetIdleBuildableAnim( self, BANIM_DESTROYED ); + G_SetBuildableAnim( self, BANIM_ATTACK1, qtrue ); + } + return; + } + if ( !shrink && + ( !self->shrunkTime || + level.time < self->shrunkTime + BARRICADE_SHRINKTIMEOUT ) ) + return; + BG_FindBBoxForBuildable( BA_A_BARRICADE, self->r.mins, self->r.maxs ); + if ( shrink ) + { + self->r.maxs[ 2 ] = (int)( self->r.maxs[ 2 ] * BARRICADE_SHRINKPROP ); + self->shrunkTime = level.time; + + // shrink animation, the destroy animation is used + if ( self->spawned && self->health > 0 ) + { + G_SetBuildableAnim( self, BANIM_ATTACK1, qtrue ); + G_SetIdleBuildableAnim( self, BANIM_DESTROYED ); + } + } + else + { + trace_t tr; + int anim; + + trap_Trace( &tr, self->s.origin, self->r.mins, self->r.maxs, + self->s.origin, self->s.number, MASK_PLAYERSOLID ); + if ( tr.startsolid || tr.fraction < 1.f ) + { + self->r.maxs[ 2 ] = (int)( self->r.maxs[ 2 ] * BARRICADE_SHRINKPROP ); + return; + } + self->shrunkTime = 0; + + // unshrink animation, IDLE2 has been hijacked for this + anim = self->s.legsAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT ); + if ( self->spawned && self->health > 0 && + anim != BANIM_CONSTRUCT1 && anim != BANIM_CONSTRUCT2 ) + { + G_SetIdleBuildableAnim( self, BG_FindAnimForBuildable( BA_A_BARRICADE ) ); + G_SetBuildableAnim( self, BANIM_ATTACK2, qtrue ); + } + } + + // a change in size requires a relink + if ( self->spawned ) + trap_LinkEntity( self ); +} + +/* +================ +ABarricade_Die + +Called when an alien spawn dies +================ +*/ +void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) +{ + AGeneric_Die( self, inflictor, attacker, damage, mod ); + ABarricade_Shrink( self, qtrue ); +} + +/* +================ +ABarricade_Think + +Think function for Alien Barricade +================ +*/ +void ABarricade_Think( gentity_t *self ) +{ + AGeneric_Think( self ); + ABarricade_Shrink( self, !G_FindOvermind( self ) ); +} + +/* +================ +ABarricade_Touch + +Barricades shrink when they are come into contact with an Alien that can +pass through +================ +*/ + +void ABarricade_Touch( gentity_t *self, gentity_t *other, trace_t *trace ) +{ + gclient_t *client = other->client; + int client_z, min_z; + + if( !client || client->pers.teamSelection != PTE_ALIENS ) + return; + + // Client must be high enough to pass over. Note that STEPSIZE (18) is + // hardcoded here because we don't include bg_local.h! + client_z = other->s.origin[ 2 ] + other->r.mins[ 2 ]; + min_z = self->s.origin[ 2 ] - 18 + + (int)( self->r.maxs[ 2 ] * BARRICADE_SHRINKPROP ); + if( client_z < min_z ) + return; + ABarricade_Shrink( self, qtrue ); +} + +//================================================================================== + + + + void AAcidTube_Think( gentity_t *self ); /* @@ -1067,7 +1202,7 @@ Think function for Alien Hive void AHive_Think( gentity_t *self ) { int entityList[ MAX_GENTITIES ]; - vec3_t range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE }; + vec3_t range = { HIVE_SENSE_RANGE, HIVE_SENSE_RANGE, HIVE_SENSE_RANGE }; vec3_t mins, maxs; int i, num; gentity_t *enemy; @@ -1125,6 +1260,61 @@ void AHive_Think( gentity_t *self ) G_CreepSlow( self ); } +/* +================ +AHive_Pain + +pain function for Alien Hive +================ +*/ +void AHive_Pain( gentity_t *self, gentity_t *attacker, int damage ) +{ + if( attacker && attacker->client && attacker->biteam == BIT_HUMANS && + self->spawned && !self->active && G_FindOvermind( self ) ) + { + vec3_t dirToTarget; + + self->active = qtrue; + self->target_ent = attacker; + self->timestamp = level.time + HIVE_REPEAT; + + VectorSubtract( attacker->s.pos.trBase, self->s.pos.trBase, dirToTarget ); + VectorNormalize( dirToTarget ); + vectoangles( dirToTarget, self->turretAim ); + + //fire at target + FireWeapon( self ); + } + G_SetBuildableAnim( self, BANIM_PAIN1, qfalse ); +} + +/* +================ +AHive_Die + +pain function for Alien Hive +================ +*/ +void AHive_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) +{ + if( attacker && attacker->client && attacker->biteam == BIT_HUMANS && + self->spawned && !self->active && G_FindOvermind( self ) ) + { + vec3_t dirToTarget; + + self->active = qtrue; + self->target_ent = attacker; + self->timestamp = level.time + HIVE_REPEAT; + + VectorSubtract( attacker->s.pos.trBase, self->s.pos.trBase, dirToTarget ); + VectorNormalize( dirToTarget ); + vectoangles( dirToTarget, self->turretAim ); + + //fire at target + FireWeapon( self ); + } + AGeneric_Die( self, inflictor, attacker, damage, mod ); +} @@ -1181,7 +1371,7 @@ qboolean AHovel_Blocked( gentity_t *hovel, gentity_t *player, qboolean provideEx G_SetOrigin( player, origin ); VectorCopy( origin, player->client->ps.origin ); VectorCopy( vec3_origin, player->client->ps.velocity ); - SetClientViewAngle( player, angles ); + G_SetClientViewAngle( player, angles ); } if( tr.fraction < 1.0f ) @@ -1264,7 +1454,7 @@ void AHovel_Use( gentity_t *self, gentity_t *other, gentity_t *activator ) G_SetOrigin( activator, hovelOrigin ); VectorCopy( hovelOrigin, activator->client->ps.origin ); - SetClientViewAngle( activator, hovelAngles ); + G_SetClientViewAngle( activator, hovelAngles ); } } } @@ -1339,7 +1529,7 @@ void AHovel_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int G_SetOrigin( builder, newOrigin ); VectorCopy( newOrigin, builder->client->ps.origin ); - SetClientViewAngle( builder, newAngles ); + G_SetClientViewAngle( builder, newAngles ); //client leaves hovel builder->client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING; @@ -1397,15 +1587,8 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace ) if( client && client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) return; - //only allow boostage once every 30 seconds - if( client->lastBoostedTime + BOOSTER_INTERVAL > level.time ) - return; - - if( !( client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) ) - { - client->ps.stats[ STAT_STATE ] |= SS_BOOSTED; - client->lastBoostedTime = level.time; - } + client->ps.stats[ STAT_STATE ] |= SS_BOOSTED; + client->ps.stats[ STAT_MISC2 ] = BOOST_TIME; } @@ -1648,9 +1831,6 @@ void HRepeater_Use( gentity_t *self, gentity_t *other, gentity_t *activator ) G_GiveClientMaxAmmo( other, qtrue ); } - -#define DCC_ATTACK_PERIOD 10000 - /* ================ HReactor_Think @@ -1661,13 +1841,26 @@ Think function for Human Reactor void HReactor_Think( gentity_t *self ) { int entityList[ MAX_GENTITIES ]; - vec3_t range = { REACTOR_ATTACK_RANGE, REACTOR_ATTACK_RANGE, REACTOR_ATTACK_RANGE }; + vec3_t range = { REACTOR_ATTACK_RANGE, + REACTOR_ATTACK_RANGE, + REACTOR_ATTACK_RANGE }; + vec3_t dccrange = { REACTOR_ATTACK_DCC_RANGE, + REACTOR_ATTACK_DCC_RANGE, + REACTOR_ATTACK_DCC_RANGE }; vec3_t mins, maxs; int i, num; gentity_t *enemy, *tent; - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); + if( self->dcc ) + { + VectorAdd( self->s.origin, dccrange, maxs ); + VectorSubtract( self->s.origin, dccrange, mins ); + } + else + { + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); + } if( self->spawned && ( self->health > 0 ) ) { @@ -1680,8 +1873,18 @@ void HReactor_Think( gentity_t *self ) if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) { self->timestamp = level.time; - G_SelectiveRadiusDamage( self->s.pos.trBase, self, REACTOR_ATTACK_DAMAGE, - REACTOR_ATTACK_RANGE, self, MOD_REACTOR, PTE_HUMANS ); + if( self->dcc ) + { + G_SelectiveRadiusDamage( self->s.pos.trBase, self, + REACTOR_ATTACK_DCC_DAMAGE, REACTOR_ATTACK_DCC_RANGE, self, + MOD_REACTOR, PTE_HUMANS ); + } + else + { + G_SelectiveRadiusDamage( self->s.pos.trBase, self, + REACTOR_ATTACK_DAMAGE, REACTOR_ATTACK_RANGE, self, + MOD_REACTOR, PTE_HUMANS ); + } tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL ); @@ -1691,19 +1894,12 @@ void HReactor_Think( gentity_t *self ) tent->s.clientNum = enemy->s.number; //dest } } - - //reactor under attack - if( self->health < self->lastHealth && - level.time > level.humanBaseAttackTimer && G_IsDCCBuilt( ) ) - { - level.humanBaseAttackTimer = level.time + DCC_ATTACK_PERIOD; - G_BroadcastEvent( EV_DCC_ATTACK, 0 ); - } - - self->lastHealth = self->health; } - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); + if( self->dcc ) + self->nextthink = level.time + REACTOR_ATTACK_DCC_REPEAT; + else + self->nextthink = level.time + REACTOR_ATTACK_REPEAT; } //================================================================================== @@ -1847,7 +2043,8 @@ void HMedistat_Think( gentity_t *self ) if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) { - if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] && + if( ( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] || + player->client->ps.stats[ STAT_STAMINA ] < MAX_STAMINA ) && player->client->ps.pm_type != PM_DEAD ) { self->enemy = player; @@ -1873,17 +2070,26 @@ void HMedistat_Think( gentity_t *self ) self->active = qfalse; } - else if( self->enemy ) //heal! + else if( self->enemy && self->enemy->client ) //heal! { - if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_POISONED ) + if( self->enemy->client->ps.stats[ STAT_STATE ] & SS_POISONED ) self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; + if( self->enemy->client->ps.stats[ STAT_STAMINA ] < MAX_STAMINA ) + self->enemy->client->ps.stats[ STAT_STAMINA ] += STAMINA_MEDISTAT_RESTORE; + + if( self->enemy->client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA ) + self->enemy->client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; + self->enemy->health++; //if they're completely healed, give them a medkit - if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] && - !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) ) - BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats ); + if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] ) + { + self->enemy->health = self->enemy->client->ps.stats[ STAT_MAX_HEALTH ]; + if( !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) ) + BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats ); + } } } } @@ -1910,22 +2116,11 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self ) float temp, rotAngle; float accuracyTolerance, angularSpeed; - if( self->lev1Grabbed ) - { - //can't turn fast if grabbed - accuracyTolerance = MGTURRET_GRAB_ACCURACYTOLERANCE; - angularSpeed = MGTURRET_GRAB_ANGULARSPEED; - } - else if( self->dcced ) - { - accuracyTolerance = MGTURRET_DCC_ACCURACYTOLERANCE; - angularSpeed = MGTURRET_DCC_ANGULARSPEED; - } + accuracyTolerance = MGTURRET_ACCURACYTOLERANCE; + if( self->locked ) + angularSpeed = MGTURRET_ANGULARSPEED_LOCKED; else - { - accuracyTolerance = MGTURRET_ACCURACYTOLERANCE; angularSpeed = MGTURRET_ANGULARSPEED; - } VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); @@ -1942,9 +2137,9 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self ) angularDiff[ YAW ] = AngleSubtract( self->s.angles2[ YAW ], angleToTarget[ YAW ] ); //if not pointing at our target then move accordingly - if( angularDiff[ PITCH ] < (-accuracyTolerance) ) + if( angularDiff[ PITCH ] < 0 && angularDiff[ PITCH ] < (-angularSpeed) ) self->s.angles2[ PITCH ] += angularSpeed; - else if( angularDiff[ PITCH ] > accuracyTolerance ) + else if( angularDiff[ PITCH ] > 0 && angularDiff[ PITCH ] > angularSpeed ) self->s.angles2[ PITCH ] -= angularSpeed; else self->s.angles2[ PITCH ] = angleToTarget[ PITCH ]; @@ -1958,9 +2153,9 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self ) self->s.angles2[ PITCH ] = (-360) + MGTURRET_VERTICALCAP; //if not pointing at our target then move accordingly - if( angularDiff[ YAW ] < (-accuracyTolerance) ) + if( angularDiff[ YAW ] < 0 && angularDiff[ YAW ] < ( -angularSpeed ) ) self->s.angles2[ YAW ] += angularSpeed; - else if( angularDiff[ YAW ] > accuracyTolerance ) + else if( angularDiff[ YAW ] > 0 && angularDiff[ YAW ] > angularSpeed ) self->s.angles2[ YAW ] -= angularSpeed; else self->s.angles2[ YAW ] = angleToTarget[ YAW ]; @@ -1985,7 +2180,7 @@ HMGTurret_CheckTarget Used by HMGTurret_Think to check enemies for validity ================ */ -qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target, qboolean ignorePainted ) +qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target ) { trace_t trace; gentity_t *traceEnt; @@ -2005,8 +2200,14 @@ qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target, qboolean ign if( Distance( self->s.origin, target->s.pos.trBase ) > MGTURRET_RANGE ) return qfalse; - //some turret has already selected this target - if( self->dcced && target->targeted && target->targeted->powered && !ignorePainted ) + trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT ); + + traceEnt = &g_entities[ trace.entityNum ]; + + if( !traceEnt->client ) + return qfalse; + + if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) return qfalse; trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT ); @@ -2051,7 +2252,7 @@ void HMGTurret_FindEnemy( gentity_t *self ) if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) { //if target is not valid keep searching - if( !HMGTurret_CheckTarget( self, target, qfalse ) ) + if( !HMGTurret_CheckTarget( self, target ) ) continue; //we found a target @@ -2059,27 +2260,6 @@ void HMGTurret_FindEnemy( gentity_t *self ) return; } } - - if( self->dcced ) - { - //check again, this time ignoring painted targets - for( i = 0; i < num; i++ ) - { - target = &g_entities[ entityList[ i ] ]; - - if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - //if target is not valid keep searching - if( !HMGTurret_CheckTarget( self, target, qtrue ) ) - continue; - - //we found a target - self->enemy = target; - return; - } - } - } - //couldn't find a target self->enemy = NULL; } @@ -2110,12 +2290,10 @@ void HMGTurret_Think( gentity_t *self ) if( self->spawned ) { - //find a dcc for self - self->dcced = G_FindDCC( self ); - //if the current target is not valid find a new one - if( !HMGTurret_CheckTarget( self, self->enemy, qfalse ) ) + if( !HMGTurret_CheckTarget( self, self->enemy ) ) { + self->locked = qfalse; if( self->enemy ) self->enemy->targeted = NULL; @@ -2128,17 +2306,43 @@ void HMGTurret_Think( gentity_t *self ) self->enemy->targeted = self; - //if we are pointing at our target and we can fire shoot it - if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) ) + if( self->active ) { - //fire at target - FireWeapon( self ); + qboolean canFire = HMGTurret_TrackEnemy( self ); - self->s.eFlags |= EF_FIRING; - G_AddEvent( self, EV_FIRE_WEAPON, 0 ); - G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse ); + if( self->turretSpinupTime < level.time ) + { + if( canFire ) + { + if( !self->locked ) + { + self->active = qfalse; + } + else if( self->count < level.time ) + { + //fire at target + FireWeapon( self ); + self->s.eFlags |= EF_FIRING; + G_AddEvent( self, EV_FIRE_WEAPON, 0 ); + G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse ); + self->count = level.time + firespeed; + } + } + else + { + self->locked = qfalse; + } + } + return; + } - self->count = level.time + firespeed; + //if we are pointing at our target, start spinning up + if( HMGTurret_TrackEnemy( self ) && self->count < level.time ) + { + self->active = qtrue; + self->locked = qtrue; + self->turretSpinupTime = level.time + MGTURRET_SPINUP_TIME; + G_AddEvent( self, EV_MGTURRET_SPINUP, 0 ); } } } @@ -2170,7 +2374,7 @@ void HTeslaGen_Think( gentity_t *self ) self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); //if not powered don't do anything and check again for power next think - if( !( self->powered = G_FindPower( self ) ) || !( self->dcced = G_FindDCC( self ) ) ) + if( !( self->powered = G_FindPower( self ) ) ) { self->s.eFlags &= ~EF_FIRING; self->nextthink = level.time + POWER_REFRESH_TIME; @@ -2369,16 +2573,6 @@ void HSpawn_Think( gentity_t *self ) G_FreeEntity( ent ); //quietly remove } } - - //spawn under attack - if( self->health < self->lastHealth && - level.time > level.humanBaseAttackTimer && G_IsDCCBuilt( ) ) - { - level.humanBaseAttackTimer = level.time + DCC_ATTACK_PERIOD; - G_BroadcastEvent( EV_DCC_ATTACK, 0 ); - } - - self->lastHealth = self->health; } self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); @@ -2471,6 +2665,8 @@ void G_BuildableThink( gentity_t *ent, int msec ) ent->spawned = qtrue; } + ent->dcc = ( ent->biteam != BIT_HUMANS ) ? 0 : G_FindDCC( ent ); + ent->s.generic1 = (int)( ( (float)ent->health / (float)bHealth ) * B_HEALTH_MASK ); if( ent->s.generic1 < 0 ) @@ -2479,7 +2675,7 @@ void G_BuildableThink( gentity_t *ent, int msec ) if( ent->powered ) ent->s.generic1 |= B_POWERED_TOGGLEBIT; - if( ent->dcced ) + if( ent->dcc ) ent->s.generic1 |= B_DCCED_TOGGLEBIT; if( ent->spawned ) @@ -2496,9 +2692,19 @@ void G_BuildableThink( gentity_t *ent, int msec ) if( !ent->spawned && ent->health > 0 ) ent->health += (int)( ceil( (float)bHealth / (float)( bTime * 0.001 ) ) ); - else if( ent->biteam == BIT_ALIENS && ent->health > 0 && ent->health < bHealth && - bRegen && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) + else if( ent->health > 0 && ent->health < bHealth ) + { + if( ent->biteam == BIT_ALIENS && bRegen && + ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) + { ent->health += bRegen; + } + else if( ent->biteam == BIT_HUMANS && ent->dcc && + ( ent->lastDamageTime + HUMAN_REGEN_DAMAGE_TIME ) < level.time ) + { + ent->health += DC_HEALRATE * ent->dcc; + } + } if( ent->health > bHealth ) ent->health = bHealth; @@ -3002,7 +3208,7 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance tempent = G_FindBuildable( BA_A_OVERMIND ); if( tempent == NULL || !tempent->spawned || tempent->health <= 0 ) - reason = IBE_OVERMIND; + reason = IBE_NOOVERMIND; } //check there is creep near by for building on @@ -3196,29 +3402,32 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori built->die = ABarricade_Die; built->think = ABarricade_Think; built->pain = ABarricade_Pain; + built->touch = ABarricade_Touch; + built->shrunkTime = 0; + ABarricade_Shrink( built, qtrue ); break; case BA_A_BOOSTER: - built->die = ABarricade_Die; - built->think = ABarricade_Think; - built->pain = ABarricade_Pain; + built->die = AGeneric_Die; + built->think = AGeneric_Think; + built->pain = AGeneric_Pain; built->touch = ABooster_Touch; break; case BA_A_ACIDTUBE: - built->die = ABarricade_Die; + built->die = AGeneric_Die; built->think = AAcidTube_Think; built->pain = ASpawn_Pain; break; case BA_A_HIVE: - built->die = ABarricade_Die; + built->die = AHive_Die; built->think = AHive_Think; - built->pain = ASpawn_Pain; + built->pain = AHive_Pain; break; case BA_A_TRAPPER: - built->die = ABarricade_Die; + built->die = AGeneric_Die; built->think = ATrapper_Think; built->pain = ASpawn_Pain; break; @@ -3327,9 +3536,6 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori else if( ( built->powered = G_FindPower( built ) ) ) built->s.generic1 |= B_POWERED_TOGGLEBIT; - if( ( built->dcced = G_FindDCC( built ) ) ) - built->s.generic1 |= B_DCCED_TOGGLEBIT; - built->s.generic1 &= ~B_SPAWNED_TOGGLEBIT; VectorCopy( normal, built->s.origin2 ); |