diff options
author | Tim Angus <tim@ngus.net> | 2003-08-30 05:15:13 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2003-08-30 05:15:13 +0000 |
commit | 5ede5ba58b780c817941eff29617056d599a9ba8 (patch) | |
tree | 451fb75f70f49bd2dad45f9d1305e52a5ee6c5c3 /src | |
parent | 36c4ba57f49f9c1aae686b9a8629b18c4f859715 (diff) |
* Rewrote TeslaGen AI
* Refactored and improved MG Turret AI
* DCC now increases speed of MG turrets and coordinates attacks
Diffstat (limited to 'src')
-rw-r--r-- | src/game/g_buildable.c | 338 | ||||
-rw-r--r-- | src/game/g_weapon.c | 11 | ||||
-rw-r--r-- | src/game/tremulous.h | 2 |
3 files changed, 215 insertions, 136 deletions
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index 7ebd97d0..0c103423 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -44,7 +44,7 @@ void G_setIdleBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim ) ent->s.torsoAnim = anim; } -#define REFRESH_TIME 2000 +#define POWER_REFRESH_TIME 2000 /* ================ @@ -970,12 +970,12 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace ) /* ================ -adef_fireonemeny +ADef_fireonemeny Used by ADef2_Think to fire at enemy ================ */ -void adef_fireonenemy( gentity_t *self, int firespeed ) +void ADef_FireOnEnemy( gentity_t *self, int firespeed ) { vec3_t dirToTarget; vec3_t target; @@ -1012,12 +1012,12 @@ void adef_fireonenemy( gentity_t *self, int firespeed ) /* ================ -adef_checktarget +ADef_checktarget -Used by DDef2_Think to check enemies for validity +Used by ADef2_Think to check enemies for validity ================ */ -qboolean adef_checktarget( gentity_t *self, gentity_t *target, int range ) +qboolean ADef_CheckTarget( gentity_t *self, gentity_t *target, int range ) { vec3_t distance; trace_t trace; @@ -1062,7 +1062,7 @@ adef_findenemy Used by DDef2_Think to locate enemy gentities ================ */ -void adef_findenemy( gentity_t *ent, int range ) +void ADef_FindEnemy( gentity_t *ent, int range ) { gentity_t *target; @@ -1070,7 +1070,7 @@ void adef_findenemy( gentity_t *ent, int range ) for( target = g_entities; target < &g_entities[ level.num_entities ]; target++ ) { //if target is not valid keep searching - if( !adef_checktarget( ent, target, range ) ) + if( !ADef_CheckTarget( ent, target, range ) ) continue; //we found a target @@ -1108,8 +1108,8 @@ void ATrapper_Think( gentity_t *self ) if( self->spawned ) { //if the current target is not valid find a new one - if( !adef_checktarget( self, self->enemy, range ) ) - adef_findenemy( self, range ); + if( !ADef_CheckTarget( self, self->enemy, range ) ) + ADef_FindEnemy( self, range ); //if a new target cannot be found don't do anything if( !self->enemy ) @@ -1117,7 +1117,7 @@ void ATrapper_Think( gentity_t *self ) //if we are pointing at our target and we can fire shoot it if( self->count < level.time ) - adef_fireonenemy( self, firespeed ); + ADef_FireOnEnemy( self, firespeed ); } } @@ -1155,7 +1155,7 @@ void HRpt_Think( gentity_t *self ) self->powered = reactor; - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; } /* @@ -1244,7 +1244,7 @@ Think for armoury void HArmoury_Think( gentity_t *self ) { //make sure we have power - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; self->powered = findPower( self ); } @@ -1289,7 +1289,7 @@ Think for bank void HBank_Think( gentity_t *self ) { //make sure we have power - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; self->powered = findPower( self ); } @@ -1312,7 +1312,7 @@ Think for dcc void HDCC_Think( gentity_t *self ) { //make sure we have power - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; self->powered = findPower( self ); } @@ -1343,7 +1343,7 @@ void HMedistat_Think( gentity_t *self ) //make sure we have power if( !( self->powered = findPower( self ) ) ) { - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; return; } @@ -1468,7 +1468,7 @@ Think for floatmine void HFM_Think( gentity_t *self ) { //make sure we have power - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; if( !( self->powered = findPower( self ) ) ) G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); @@ -1479,11 +1479,14 @@ void HFM_Think( gentity_t *self ) //================================================================================== + + + /* ================ HMGTurret_TrackEnemy -Used by HDef_Think to track enemy location +Used by HMGTurret_Think to track enemy location ================ */ qboolean HMGTurret_TrackEnemy( gentity_t *self ) @@ -1491,6 +1494,18 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self ) vec3_t dirToTarget, dttAdjusted, angleToTarget, angularDiff, xNormal; vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; float temp, rotAngle; + float accuracyTolerance, angularSpeed; + + if( self->dcced ) + { + accuracyTolerance = MGTURRET_ACCURACYTOLERANCE; + angularSpeed = MGTURRET_ANGULARSPEED; + } + else + { + accuracyTolerance = MGTURRET_DCC_ACCURACYTOLERANCE; + angularSpeed = MGTURRET_DCC_ANGULARSPEED; + } VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); @@ -1507,10 +1522,10 @@ 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 ] < -MGTURRET_ACCURACYTOLERANCE ) - self->s.angles2[ PITCH ] += MGTURRET_ANGULARSPEED; - else if( angularDiff[ PITCH ] > MGTURRET_ACCURACYTOLERANCE ) - self->s.angles2[ PITCH ] -= MGTURRET_ANGULARSPEED; + if( angularDiff[ PITCH ] < (-accuracyTolerance) ) + self->s.angles2[ PITCH ] += angularSpeed; + else if( angularDiff[ PITCH ] > accuracyTolerance ) + self->s.angles2[ PITCH ] -= angularSpeed; else self->s.angles2[ PITCH ] = angleToTarget[ PITCH ]; @@ -1523,10 +1538,10 @@ 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 ] < -MGTURRET_ACCURACYTOLERANCE ) - self->s.angles2[ YAW ] += MGTURRET_ANGULARSPEED; - else if( angularDiff[ YAW ] > MGTURRET_ACCURACYTOLERANCE ) - self->s.angles2[ YAW ] -= MGTURRET_ANGULARSPEED; + if( angularDiff[ YAW ] < (-accuracyTolerance) ) + self->s.angles2[ YAW ] += angularSpeed; + else if( angularDiff[ YAW ] > accuracyTolerance ) + self->s.angles2[ YAW ] -= angularSpeed; else self->s.angles2[ YAW ] = angleToTarget[ YAW ]; @@ -1535,100 +1550,44 @@ qboolean HMGTurret_TrackEnemy( gentity_t *self ) vectoangles( dirToTarget, self->turretAim ); //if pointing at our target return true - if( abs( angleToTarget[ YAW ] - self->s.angles2[ YAW ] ) <= MGTURRET_ACCURACYTOLERANCE && - abs( angleToTarget[ PITCH ] - self->s.angles2[ PITCH ] ) <= MGTURRET_ACCURACYTOLERANCE ) + if( abs( angleToTarget[ YAW ] - self->s.angles2[ YAW ] ) <= accuracyTolerance && + abs( angleToTarget[ PITCH ] - self->s.angles2[ PITCH ] ) <= accuracyTolerance ) return qtrue; return qfalse; } -/* -================ -HTeslaGen_FireOnEnemy - -Used by HDef_Think to fire at enemy -================ -*/ -void HTeslaGen_FireOnEnemy( gentity_t *self, int firespeed ) -{ - vec3_t dirToTarget; - - //this doesn't operate without a dcc - if( !self->dcced ) - return; - - VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); - VectorNormalize( dirToTarget ); - vectoangles( dirToTarget, self->turretAim ); - - //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; -} - -/* -================ -HMGTurret_FireOnEnemy - -Used by HDef_Think to fire at enemy -================ -*/ -void HMGTurret_FireOnEnemy( gentity_t *self, int firespeed ) -{ - //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; -} /* ================ -HDef_CheckTarget +HMGTurret_CheckTarget -Used by HDef_Think to check enemies for validity +Used by HMGTurret_Think to check enemies for validity ================ */ -qboolean HDef_CheckTarget( gentity_t *self, gentity_t *target, int range ) +qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target, qboolean ignorePainted ) { - vec3_t distance; trace_t trace; - - if( !target ) // Do we have a target? + gentity_t *traceEnt; + + if( target->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) return qfalse; - if( !target->inuse ) // Does the target still exist? - return qfalse; - if( target == self ) // is the target us? - return qfalse; - if( !target->client ) // is the target a bot or player? + + if( target->health <= 0 ) return qfalse; - if( target->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) // is the target one of us? - return qfalse; - if( target->client->sess.sessionTeam == TEAM_SPECTATOR ) // is the target alive? - return qfalse; - if( target->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) // is the target alive? - return qfalse; - if( target->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) // is the target alive? - return qfalse; - if( target->health <= 0 ) // is the target still alive? - return qfalse; - if( self->dcced && target->targeted && target->targeted->powered ) //some turret has already selected this target + + //some turret has already selected this target + if( self->dcced && target->targeted && target->targeted->powered && !ignorePainted ) return qfalse; - VectorSubtract( target->r.currentOrigin, self->r.currentOrigin, distance ); - if( VectorLength( distance ) > range ) // is the target within range? + 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; - trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_OPAQUE ); - if( trace.fraction < 1.0 ) // can we see the target? + if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) return qfalse; return qtrue; @@ -1637,42 +1596,76 @@ qboolean HDef_CheckTarget( gentity_t *self, gentity_t *target, int range ) /* ================ -HDef_FindEnemy +HMGTurret_FindEnemy -Used by HDef_Think to locate enemy gentities +Used by HMGTurret_Think to locate enemy gentities ================ */ -void HDef_FindEnemy( gentity_t *ent, int range ) +void HMGTurret_FindEnemy( gentity_t *self ) { + int entityList[ MAX_GENTITIES ]; + vec3_t range; + vec3_t mins, maxs; + vec3_t dir; + int i, num; gentity_t *target; - //iterate through entities - for( target = g_entities; target < &g_entities[ level.num_entities ]; target++ ) + VectorSet( range, MGTURRET_RANGE, MGTURRET_RANGE, MGTURRET_RANGE ); + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); + + //find aliens + num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); + for( i = 0; i < num; i++ ) { - //if target is not valid keep searching - if( !HDef_CheckTarget( ent, target, range ) ) - continue; - - //we found a target - ent->enemy = target; - return; + 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, qfalse ) ) + continue; + + //we found a target + self->enemy = target; + 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 - ent->enemy = NULL; + self->enemy = NULL; } /* ================ -HDef_Think +HMGTurret_Think -think function for Human Defense +Think function for MG turret ================ */ -void HDef_Think( gentity_t *self ) +void HMGTurret_Think( gentity_t *self ) { - int range = BG_FindRangeForBuildable( self->s.modelindex ); int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); @@ -1683,7 +1676,7 @@ void HDef_Think( gentity_t *self ) //if not powered don't do anything and check again for power next think if( !( self->powered = findPower( self ) ) ) { - self->nextthink = level.time + REFRESH_TIME; + self->nextthink = level.time + POWER_REFRESH_TIME; return; } @@ -1693,12 +1686,12 @@ void HDef_Think( gentity_t *self ) self->dcced = findDCC( self ); //if the current target is not valid find a new one - if( !HDef_CheckTarget( self, self->enemy, range ) ) + if( !HMGTurret_CheckTarget( self, self->enemy, qfalse ) ) { if( self->enemy ) self->enemy->targeted = NULL; - HDef_FindEnemy( self, range ); + HMGTurret_FindEnemy( self ); } //if a new target cannot be found don't do anything @@ -1708,21 +1701,92 @@ void HDef_Think( gentity_t *self ) self->enemy->targeted = self; //if we are pointing at our target and we can fire shoot it - switch( self->s.modelindex ) + if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) ) { - case BA_H_MGTURRET: - if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) ) - HMGTurret_FireOnEnemy( self, firespeed ); - break; - - case BA_H_TESLAGEN: - if( self->count < level.time ) - HTeslaGen_FireOnEnemy( self, firespeed ); - break; + //fire at target + FireWeapon( self ); + + self->s.eFlags |= EF_FIRING; + G_AddEvent( self, EV_FIRE_WEAPON, 0 ); + G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - default: - Com_Printf( S_COLOR_YELLOW "WARNING: Unknown turret type in think\n" ); - break; + self->count = level.time + firespeed; + } + } +} + + + + +//================================================================================== + + + + +/* +================ +HTeslaGen_Think + +Think function for Tesla Generator +================ +*/ +void HTeslaGen_Think( gentity_t *self ) +{ + int entityList[ MAX_GENTITIES ]; + vec3_t range; + vec3_t mins, maxs; + vec3_t dir; + int i, num; + gentity_t *enemy; + + self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); + + //used for client side muzzle flashes + self->s.eFlags &= ~EF_FIRING; + + //if not powered don't do anything and check again for power next think + if( !( self->powered = findPower( self ) ) ) + { + self->nextthink = level.time + POWER_REFRESH_TIME; + return; + } + + //find DCC + if( !( self->dcced = findDCC( self ) ) ) + return; + + if( self->spawned && self->count < level.time ) + { + VectorSet( range, TESLAGEN_RANGE, TESLAGEN_RANGE, TESLAGEN_RANGE ); + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); + + //find aliens + num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); + for( i = 0; i < num; i++ ) + { + enemy = &g_entities[ entityList[ i ] ]; + + if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && + enemy->health > 0 ) + { + VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dir ); + VectorNormalize( dir ); + vectoangles( dir, self->turretAim ); + + //fire at target + FireWeapon( self ); + } + } + + if( self->s.eFlags & EF_FIRING ) + { + G_AddEvent( self, EV_FIRE_WEAPON, 0 ); + + //doesn't really need an anim + //G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); + + self->count = level.time + TESLAGEN_REPEAT; } } } @@ -2111,9 +2175,13 @@ gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin break; case BA_H_MGTURRET: + built->die = HSpawn_Die; + built->think = HMGTurret_Think; + break; + case BA_H_TESLAGEN: built->die = HSpawn_Die; - built->think = HDef_Think; + built->think = HTeslaGen_Think; break; case BA_H_ARMOURY: diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 3c10db5e..4f737bc3 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -397,7 +397,16 @@ void teslaFire( gentity_t *ent ) traceEnt = &g_entities[ tr.entityNum ]; - if( traceEnt->takedamage) + if( !traceEnt->client ) + return; + + if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) + return; + + //so the client side knows + ent->s.eFlags |= EF_FIRING; + + if( traceEnt->takedamage ) { G_Damage( traceEnt, ent, ent, forward, tr.endpos, TESLAGEN_DMG, 0, MOD_TESLAGEN ); diff --git a/src/game/tremulous.h b/src/game/tremulous.h index f9ec2ef3..6c356203 100644 --- a/src/game/tremulous.h +++ b/src/game/tremulous.h @@ -427,6 +427,8 @@ #define MGTURRET_RANGE 250 #define MGTURRET_SPREAD 200 #define MGTURRET_DMG HDM(5) +#define MGTURRET_DCC_ANGULARSPEED 7 +#define MGTURRET_DCC_ACCURACYTOLERANCE MGTURRET_DCC_ANGULARSPEED / 1.5f #define TESLAGEN_BP 100 #define TESLAGEN_HEALTH HBHM(200) |