/*------------------------------------------------------------------- Procedure : Exogenon Fire Input : ENEMY * Enemy Output : Nothing -------------------------------------------------------------------*/ void AI_EXOGENON_FIRE( register ENEMY * Enemy ) { VECTOR TempVector; VECTOR TempUpVector; VECTOR TempOffset = { 0.0F, 0.0F, 180.0F }; float Distance; Enemy->Object.AnimSpeed = 1.0F; if( Enemy->Timer ) { Enemy->Timer -= framelag; if( Enemy->Timer <= 0.0F ) { // This is where the main Weapon would fire.... Enemy->Timer = 0.0F; if( EnemyTypes[Enemy->Type].PrimaryWeaponType != NO_PRIMARY ) { ApplyMatrix( &Enemy->Object.Mat, &Forward, &TempVector ); Distance = DistanceVector2Vector( &Ships[WhoIAm].Object.Pos ,&Enemy->Object.Pos ); TempVector.x *= Distance; TempVector.y *= Distance; TempVector.z *= Distance; TempVector.y -= Enemy->Object.Pos.y - Ships[WhoIAm].Object.Pos.y; NormaliseVector(&TempVector); ApplyMatrix( &Enemy->Object.Mat, &SlideUp, &TempUpVector ); EnemyFirePrimary( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, EnemyTypes[Enemy->Type].PrimaryWeaponType, Enemy->Object.Group, &Enemy->Object.Pos, &TempOffset, &TempVector, &TempUpVector, EnemyTypes[Enemy->Type].PowerLevel, (EnemyTypes[Enemy->Type].PowerLevel +1) * 33.0F, FALSE, NULL ); } Enemy->Object.AI_Mode = AIMODE_EXOGENON_SWEEP; ExogenonAim( Enemy ); ExogenonSweepDir = Enemy->AIMoveFlags; ExogenonSweepAngle = Enemy->AI_Angle; Enemy->Timer = 60.0F * 1.0F; } } }
/*=================================================================== Procedure : Update an Enemies Guns... Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_UPDATEGUNS( register ENEMY * Enemy ) { OBJECT * TObject; GUNOBJECT * GObject; VECTOR TempVector; VECTOR TempUpVector; VECTOR TempOffset = { 0.0F, 0.0F, 0.0F }; VECTOR NewPos; VECTOR FireOffset; FIREPOS * FirePosPnt; VECTOR AimOffset; u_int16_t i; BYTE Weapon; TObject = (OBJECT*) Enemy->TShip; if( !TObject || TObject->Mode != NORMAL_MODE ) return; GObject = Enemy->Object.FirstGun; while( GObject ) { // if( TObject && ( (Enemy->AIFlags & AI_ICANSEEPLAYER) || (Enemy->Object.ControlType == ENEMY_CONTROLTYPE_TURRET_AI) || (Enemy->Object.ControlType == ENEMY_CONTROLTYPE_SPLINE) ) ) if( TObject && ( (Enemy->AIFlags & AI_ICANSEEPLAYER) || (Enemy->Object.ControlType == ENEMY_CONTROLTYPE_SPLINE) ) ) { FirePosPnt = EnemyTypes[Enemy->Type].GunFirePoints[GObject->GunNum>>1]; ApplyMatrix( &GObject->Mat , &FirePosPnt->Points[GObject->FirePosCount] , &FireOffset ); FireOffset.x += GObject->FirePos.x; FireOffset.y += GObject->FirePos.y; FireOffset.z += GObject->FirePos.z; FireOffset.x -= Enemy->Object.Pos.x; FireOffset.y -= Enemy->Object.Pos.y; FireOffset.z -= Enemy->Object.Pos.z; ApplyMatrix( &GObject->Mat, EnemyTypes[ Enemy->Type ].GunAimPos[GObject->GunNum>>1], &AimOffset ); AimOffset.x += Enemy->Object.Pos.x; AimOffset.y += Enemy->Object.Pos.y; AimOffset.z += Enemy->Object.Pos.z; if( !GunTypes[GObject->Type].BurstMasterCount ) { // Normal gun that just fires when it can.. if( GunTypes[GObject->Type].PrimarySecondary ) { AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move ,&AimOffset, TObject , &NewPos , SecondaryWeaponAttribs[GunTypes[GObject->Type].WeaponType].Speed); }else{ AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move ,&AimOffset, TObject , &NewPos , PrimaryWeaponAttribs[GunTypes[GObject->Type].WeaponType].Speed[GunTypes[GObject->Type].PowerLevel]); } AI_AimAtTarget( &GObject->InvMat , &AimOffset, &NewPos ); GObject->AIMoveFlags |= AimData.Flags; GObject->AI_Angle = AimData.Angle; if( GObject->Type == GUN_MetaTankMain ) { if( (GObject->ReloadTime <= (0.5F*60.0F) ) && !Enemy->Object.Animating ) { SetCurAnimSeq( 0, &Enemy->Object ); } } if( GObject->ReloadTime <= 0.0F && ( (( ( GObject->AI_Angle.x < GunTypes[GObject->Type].BurstAngle && GObject->AI_Angle.x > -GunTypes[GObject->Type].BurstAngle ) && ( GObject->AI_Angle.y < GunTypes[GObject->Type].BurstAngle && GObject->AI_Angle.y > -GunTypes[GObject->Type].BurstAngle ) ) ) || GObject->Type == GUN_MetaTankMain ) ) { ApplyMatrix( &GObject->Mat, &Forward, &TempVector ); ApplyMatrix( &GObject->Mat, &SlideUp, &TempUpVector ); if( !(Enemy->Object.Flags & SHIP_Scattered ) && (!GunTypes[GObject->Type].Range || ( DistanceVector2Vector( &TObject->Pos , &Enemy->Object.Pos) < GunTypes[GObject->Type].Range ) )) { if(Enemy->Object.ControlType == ENEMY_CONTROLTYPE_TURRET_AI) { if( !Enemy->Object.Animating && (Enemy->Type != ENEMY_MissileTurret) ) { SetCurAnimSeq( TURRETSEQ_Fire, &Enemy->Object ); } } if( GunTypes[GObject->Type].PrimarySecondary ) { InitOneSecBull( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, Enemy->Object.Group, &Enemy->Object.Pos, &FireOffset, &TempVector, &TempUpVector, &TempOffset, GunTypes[GObject->Type].WeaponType, false ); }else{ Weapon = BodgePrimaryWeapon( GunTypes[GObject->Type].WeaponType, Enemy->PickupHeld ); i = EnemyFirePrimary( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, Weapon, Enemy->Object.Group, &Enemy->Object.Pos, &FireOffset, &TempVector, &TempUpVector, GunTypes[GObject->Type].PowerLevel, (GunTypes[GObject->Type].PowerLevel +1) * 33.0F, false, GObject ); if( i != (u_int16_t) -1 ) { PrimBulls[i].FirePoint = GObject->FirePosCount; } } GObject->FirePosCount++; if( GObject->FirePosCount >= FirePosPnt->NumPoints ) GObject->FirePosCount = 0; GObject->ReloadTime =GunTypes[GObject->Type].ReloadTime; } } }else{ // A Gun That Does a Burst... if( GObject->BurstCount ) { if( GunTypes[GObject->Type].PrimarySecondary ) { AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move ,&AimOffset, TObject , &NewPos , SecondaryWeaponAttribs[GunTypes[GObject->Type].WeaponType].Speed); }else{ AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move ,&AimOffset, TObject , &NewPos , PrimaryWeaponAttribs[GunTypes[GObject->Type].WeaponType].Speed[GunTypes[GObject->Type].PowerLevel]); } AI_AimAtTarget( &GObject->InvMat , &AimOffset, &NewPos ); GObject->AIMoveFlags |= AimData.Flags; GObject->AIMoveFlags &= ~(AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ); GObject->AI_Angle = AimData.Angle; if( GObject->BurstStartSign < 0.0F ) { GObject->AIMoveFlags |= AI_CONTROL_TURNLEFT; }else{ GObject->AIMoveFlags |= AI_CONTROL_TURNRIGHT; } if( !(Enemy->Object.Flags & SHIP_Scattered ) &&GObject->ReloadTime <= 0.0F ) { ApplyMatrix( &GObject->Mat, &Forward, &TempVector ); ApplyMatrix( &GObject->Mat, &SlideUp, &TempUpVector ); if(Enemy->Object.ControlType == ENEMY_CONTROLTYPE_TURRET_AI) { if( !Enemy->Object.Animating && (Enemy->Type != ENEMY_MissileTurret) ) { SetCurAnimSeq( TURRETSEQ_Fire, &Enemy->Object ); } } if( GunTypes[GObject->Type].PrimarySecondary ) { InitOneSecBull( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, Enemy->Object.Group, &Enemy->Object.Pos, &FireOffset, &TempVector, &TempUpVector, &TempOffset, GunTypes[GObject->Type].WeaponType, false ); }else{ Weapon = BodgePrimaryWeapon( GunTypes[GObject->Type].WeaponType, Enemy->PickupHeld ); i = EnemyFirePrimary( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, Weapon, Enemy->Object.Group, &Enemy->Object.Pos, &FireOffset, &TempVector, &TempUpVector, GunTypes[GObject->Type].PowerLevel, (GunTypes[GObject->Type].PowerLevel +1) * 33.0F, false, GObject ); if( i != (u_int16_t) -1 ) { PrimBulls[i].FirePoint = GObject->FirePosCount; } } GObject->FirePosCount++; if( GObject->FirePosCount >= FirePosPnt->NumPoints ) GObject->FirePosCount = 0; GObject->ReloadTime = GunTypes[GObject->Type].ReloadTime; GObject->BurstCount--; } } if( !GObject->BurstCount && GunTypes[GObject->Type].BurstMasterCount ) { if( GunTypes[GObject->Type].PrimarySecondary ) { AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move ,&AimOffset, TObject , &NewPos , SecondaryWeaponAttribs[GunTypes[GObject->Type].WeaponType].Speed); }else{ AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move ,&AimOffset, TObject , &NewPos , PrimaryWeaponAttribs[GunTypes[GObject->Type].WeaponType].Speed[GunTypes[GObject->Type].PowerLevel]); } AI_AimAtTarget( &GObject->InvMat , &AimOffset, &NewPos ); GObject->AIMoveFlags |= AimData.Flags; GObject->AI_Angle = AimData.Angle; if( GObject->BurstTime == 0.0F ) { if( (GObject->AI_Angle.y <= GunTypes[GObject->Type].BurstAngle) && (GObject->AI_Angle.y >= -GunTypes[GObject->Type].BurstAngle) ) { GObject->BurstCount = GunTypes[GObject->Type].BurstMasterCount; GObject->BurstTime = GunTypes[GObject->Type].BurstMasterTime; GObject->BurstStartSign = GObject->AI_Angle.y; } } } } } GObject = GObject->Next; }
/*=================================================================== Procedure : AIR Formation Flying Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_AIR_FORMATION( register ENEMY * Enemy ) { float Dist; OBJECT * TObject; OBJECT * SObject; VECTOR NewPos; VECTOR TempVector; VECTOR TempUpVector; VECTOR TempOffset = { 0.0F, 0.0F, 0.0F }; VECTOR Offset; VECTOR TargetPos; VECTOR TempDir; ENEMY * LinkEnemy; SObject = &Enemy->Object; // Is it time to think??? AI_THINK( Enemy , false ,false); LinkEnemy = Enemy->FormationLink; if( !LinkEnemy || ( LinkEnemy->Object.AI_Mode == AIMODE_RETREAT ) ) { if( Enemy->AIFlags & ( AI_ICANSEEPLAYER + AI_ICANHEARPLAYER ) ) { AI_SetDOGFIGHT( Enemy ); return; }else{ AI_SetFOLLOWPATH( Enemy ); return; } } TObject = (OBJECT*) Enemy->TShip; Enemy->Timer -= framelag; if( Enemy->Timer < 0.0F ) Enemy->Timer = 0.0F; Enemy->PrimaryFireTimer -= framelag; if( Enemy->PrimaryFireTimer < 0.0F ) Enemy->PrimaryFireTimer = 0.0F; Enemy->SecondaryFireTimer -= framelag; if( Enemy->SecondaryFireTimer < 0.0F ) Enemy->SecondaryFireTimer = 0.0F; if( Enemy->AIFlags & ( AI_ICANSEEPLAYER + AI_ICANHEARPLAYER ) ) { Enemy->TNode = NULL; if( !(Enemy->Object.Flags & SHIP_Scattered ) && (Enemy->AIFlags & AI_ICANSEEPLAYER) && !(Enemy->AIFlags & AI_FRIENDLYFIRE) ) { ApplyMatrix( &SObject->Mat, &Forward, &TempVector ); ApplyMatrix( &SObject->Mat, &SlideUp, &TempUpVector ); if( (Enemy->PrimaryFireTimer == 0.0F) && ( EnemyTypes[Enemy->Type].PrimaryWeaponType != NO_PRIMARY ) ) { Enemy->PrimaryFireTimer = EnemyTypes[Enemy->Type].PrimaryFireRate + (float) Random_Range( (u_int16_t) EnemyTypes[Enemy->Type].PrimaryFireRate ); EnemyFirePrimary( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, EnemyTypes[Enemy->Type].PrimaryWeaponType, Enemy->Object.Group, &Enemy->Object.Pos, &TempOffset, &TempVector, &TempUpVector, EnemyTypes[Enemy->Type].PowerLevel, 0.0F, false, NULL ); } } } if( (Enemy->Object.Flags & SHIP_Scattered ) || ( (EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_RETREAT) && ( Enemy->Object.Shield <= (EnemyTypes[Enemy->Type].Shield * 0.15 ) ) ) ) { // we should get out of hear.. Enemy->FormationLink = NULL; AI_SetRETREAT( Enemy ); return; } AI_UPDATEGUNS( Enemy ); // Aim at target if( TObject && ( Enemy->AIFlags & AI_ICANSEEPLAYER ) ) { if( EnemyTypes[Enemy->Type].PrimaryWeaponType != NO_PRIMARY ) { AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move , &Enemy->Object.Pos , TObject , &NewPos , PrimaryWeaponAttribs[EnemyTypes[Enemy->Type].PrimaryWeaponType].Speed[0] ); }else{ NewPos = TObject->Pos; } AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &NewPos ); if( !( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ICANTPITCH ) ) { Enemy->AIMoveFlags |= AimData.Flags; }else{ //This enemy cant look up or down so it has to move up and down to compensate.... Enemy->AIMoveFlags |= ( AimData.Flags & ( AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ) ); if( AimData.Flags & AI_CONTROL_TURNUP ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; }else if( AimData.Flags & AI_CONTROL_TURNDOWN ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } } Enemy->AI_Angle = AimData.Angle; }else{ ApplyMatrix( &LinkEnemy->Object.Mat, &Forward, &TempDir ); TempDir.x *= 1024.0F * GLOBAL_SCALE * 5.0F; TempDir.y *= 1024.0F * GLOBAL_SCALE * 5.0F; TempDir.z *= 1024.0F * GLOBAL_SCALE * 5.0F; NewPos.x = LinkEnemy->Object.Pos.x + TempDir.x; NewPos.y = LinkEnemy->Object.Pos.y + TempDir.y; NewPos.z = LinkEnemy->Object.Pos.z + TempDir.z; AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &NewPos ); if( !( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ICANTPITCH ) ) { Enemy->AIMoveFlags |= AimData.Flags; }else{ //This enemy cant look up or down so it has to move up and down to compensate.... Enemy->AIMoveFlags |= ( AimData.Flags & ( AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ) ); if( AimData.Flags & AI_CONTROL_TURNUP ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; }else if( AimData.Flags & AI_CONTROL_TURNDOWN ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } } Enemy->AI_Angle = AimData.Angle; } if( Enemy->AvoidTimer ) { Enemy->AIMoveFlags = Enemy->AvoidType; }else{ Offset = Enemy->FormationOffset; ApplyMatrix( &LinkEnemy->Object.Mat, &Offset, &TargetPos ); TargetPos.x += LinkEnemy->Object.Pos.x; TargetPos.y += LinkEnemy->Object.Pos.y; TargetPos.z += LinkEnemy->Object.Pos.z; Dist = DistanceVector2Vector( &TargetPos , &Enemy->Object.Pos); if( Dist > (EnemyTypes[Enemy->Type].Radius * 0.75F) ) { Offset.x = TargetPos.x - Enemy->Object.Pos.x; Offset.y = TargetPos.y - Enemy->Object.Pos.y; Offset.z = TargetPos.z - Enemy->Object.Pos.z; ApplyMatrix( &Enemy->Object.InvMat, &Offset, &TargetPos ); if( TargetPos.x < -(EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_LEFT; } if( TargetPos.x > (EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_RIGHT; } if( TargetPos.y < -(EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } if( TargetPos.y > (EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; } if( TargetPos.z < -(EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_BACK; } if( TargetPos.z > (EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; } } } }