diff --git a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs index ab5767b190..4f14d711e3 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs @@ -24,7 +24,6 @@ namespace OpenRA.Mods.Common.Activities readonly AttackAircraft attackAircraft; readonly Rearmable rearmable; readonly bool forceAttack; - readonly int ticksUntilTurn; readonly Color? targetLineColor; Target target; @@ -35,6 +34,7 @@ namespace OpenRA.Mods.Common.Activities bool useLastVisibleTarget; bool hasTicked; bool returnToBase; + int remainingTicksUntilTurn; public FlyAttack(Actor self, Target target, bool forceAttack, Color? targetLineColor) { @@ -45,7 +45,6 @@ namespace OpenRA.Mods.Common.Activities aircraft = self.Trait(); attackAircraft = self.Trait(); rearmable = self.TraitOrDefault(); - ticksUntilTurn = attackAircraft.Info.AttackTurnDelay; // The target may become hidden between the initial order request and the first tick (e.g. if queued) // Moving to any position (even if quite stale) is still better than immediately giving up @@ -132,28 +131,33 @@ namespace OpenRA.Mods.Common.Activities var delta = attackAircraft.GetTargetPosition(pos, target) - pos; var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; - var isAirborne = self.World.Map.DistanceAboveTerrain(pos).Length >= aircraft.Info.MinAirborneAltitude; - if (!isAirborne) - QueueChild(new TakeOff(self)); + QueueChild(new TakeOff(self)); - if (attackAircraft.Info.AttackType == AirAttackType.Strafe) + var minimumRange = attackAircraft.Info.AttackType == AirAttackType.Strafe ? WDist.Zero : attackAircraft.GetMinimumRangeVersusTarget(target); + + // When strafing we must move forward for a minimum number of ticks after passing the target. + if (remainingTicksUntilTurn > 0) { - if (target.IsInRange(pos, attackAircraft.GetMinimumRange())) - QueueChild(new FlyTimed(ticksUntilTurn, self)); + Fly.FlyTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); + remainingTicksUntilTurn--; + } - QueueChild(new Fly(self, target, target.CenterPosition, Color.Red)); - QueueChild(new FlyTimed(ticksUntilTurn, self)); - } - else + // Move into range of the target. + else if (!target.IsInRange(pos, lastVisibleMaximumRange) || target.IsInRange(pos, minimumRange)) + QueueChild(aircraft.MoveWithinRange(target, minimumRange, lastVisibleMaximumRange, target.CenterPosition, Color.Red)); + + // The aircraft must keep moving forward even if it is already in an ideal position. + else if (!aircraft.Info.CanHover || attackAircraft.Info.AttackType == AirAttackType.Strafe) { - var minimumRange = attackAircraft.GetMinimumRangeVersusTarget(target); - if (!target.IsInRange(pos, lastVisibleMaximumRange) || target.IsInRange(pos, minimumRange)) - QueueChild(new Fly(self, target, minimumRange, lastVisibleMaximumRange, target.CenterPosition, Color.Red)); - else if (isAirborne) // Don't use 'else' to avoid conflict with TakeOff - Fly.VerticalTakeOffOrLandTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude); + Fly.FlyTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); + remainingTicksUntilTurn = attackAircraft.Info.AttackTurnDelay; } + // Turn to face the target if required. + else if (!attackAircraft.TargetInFiringArc(self, target, attackAircraft.Info.FacingTolerance)) + aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.TurnSpeed); + return false; } diff --git a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs index 23241159f2..d9e14389e1 100644 --- a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs +++ b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs @@ -39,6 +39,9 @@ namespace OpenRA.Mods.Common.Activities if (aircraft.ForceLanding) return; + if (self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition).Length >= aircraft.Info.MinAirborneAltitude) + return; + // We are taking off, so remove reservation and influence in ground cells. aircraft.UnReserve(); aircraft.RemoveInfluence();