diff --git a/OpenRA.Mods.Common/Activities/Air/Fly.cs b/OpenRA.Mods.Common/Activities/Air/Fly.cs index ec08bee863..247b87f2b2 100644 --- a/OpenRA.Mods.Common/Activities/Air/Fly.cs +++ b/OpenRA.Mods.Common/Activities/Air/Fly.cs @@ -165,7 +165,6 @@ namespace OpenRA.Mods.Common.Activities var checkTarget = useLastVisibleTarget ? lastVisibleTarget : target; var pos = aircraft.GetPosition(); var delta = checkTarget.CenterPosition - pos; - var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; // Inside the target annulus, so we're done var insideMaxRange = maxRange.Length > 0 && checkTarget.IsInRange(pos, maxRange); @@ -174,12 +173,20 @@ namespace OpenRA.Mods.Common.Activities return true; var isSlider = aircraft.Info.CanSlide; + var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; var move = isSlider ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); - // Inside the minimum range, so reverse if we CanSlide - if (isSlider && insideMinRange) + // Inside the minimum range, so reverse if we CanSlide, otherwise face away from the target. + if (insideMinRange) { - FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, -move); + if (isSlider) + FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, -move); + else + { + desiredFacing = Util.NormalizeFacing(desiredFacing + 128); + FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move); + } + return false; } diff --git a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs index e5a60ab0f9..bf3903baee 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs @@ -34,7 +34,6 @@ namespace OpenRA.Mods.Common.Activities bool useLastVisibleTarget; bool hasTicked; bool returnToBase; - int remainingTicksUntilTurn; public FlyAttack(Actor self, Target target, bool forceAttack, Color? targetLineColor) { @@ -147,23 +146,13 @@ namespace OpenRA.Mods.Common.Activities 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) - { - Fly.FlyTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); - remainingTicksUntilTurn--; - } - // Move into range of the target. - else if (!target.IsInRange(pos, lastVisibleMaximumRange) || target.IsInRange(pos, minimumRange)) + 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) - { - Fly.FlyTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); - remainingTicksUntilTurn = attackAircraft.Info.AttackTurnDelay; - } + QueueChild(new FlyAttackRun(self, target, lastVisibleMaximumRange)); // Turn to face the target if required. else if (!attackAircraft.TargetInFiringArc(self, target, attackAircraft.Info.FacingTolerance)) @@ -201,4 +190,42 @@ namespace OpenRA.Mods.Common.Activities } } } + + class FlyAttackRun : Activity + { + Target target; + WDist exitRange; + bool targetIsVisibleActor; + + public FlyAttackRun(Actor self, Target t, WDist exitRange) + { + ChildHasPriority = false; + + target = t; + this.exitRange = exitRange; + } + + protected override void OnFirstRun(Actor self) + { + QueueChild(new Fly(self, target, target.CenterPosition)); + QueueChild(new Fly(self, target, exitRange, WDist.MaxValue, target.CenterPosition)); + } + + public override bool Tick(Actor self) + { + if (TickChild(self) || IsCanceling) + return true; + + // Cancel the run if the target become invalid (e.g. killed) while visible + var targetWasVisibleActor = targetIsVisibleActor; + bool targetIsHiddenActor; + target = target.Recalculate(self.Owner, out targetIsHiddenActor); + targetIsVisibleActor = target.Type == TargetType.Actor && !targetIsHiddenActor; + + if (targetWasVisibleActor && !target.IsValidFor(self)) + Cancel(self); + + return false; + } + } } diff --git a/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs b/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs index e4a425c64c..ad8a2c730e 100644 --- a/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs @@ -24,8 +24,6 @@ namespace OpenRA.Mods.Common.Traits [Desc("Attack behavior. Currently supported types are Strafe (default) and Hover.")] public readonly AirAttackType AttackType = AirAttackType.Strafe; - [Desc("Delay, in game ticks, before strafing aircraft turns to attack.")] - public readonly int AttackTurnDelay = 50; [Desc("Does this actor cancel its attack activity when it needs to resupply? Setting this to 'false' will make the actor resume attack after reloading.")] public readonly bool AbortOnResupply = true;