From adb3c8e39ccd9618ec8d9e3cea382643ba94d89e Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 2 Jan 2020 16:17:10 +0000 Subject: [PATCH] Split fixed-wing attack and strafe attack types. --- .../Activities/Air/FlyAttack.cs | 44 ++++++++++++++++- .../Traits/Air/AttackAircraft.cs | 11 +++-- .../Rules/20191117/ReplaceAttackTypeStrafe.cs | 48 +++++++++++++++++++ OpenRA.Mods.Common/UpdateRules/UpdatePath.cs | 1 + mods/ra/rules/aircraft.yaml | 1 - 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 OpenRA.Mods.Common/UpdateRules/Rules/20191117/ReplaceAttackTypeStrafe.cs diff --git a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs index bf3903baee..65b0b72c1b 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs @@ -25,6 +25,7 @@ namespace OpenRA.Mods.Common.Activities readonly Rearmable rearmable; readonly bool forceAttack; readonly Color? targetLineColor; + readonly WDist strafeDistance; Target target; Target lastVisibleTarget; @@ -45,6 +46,8 @@ namespace OpenRA.Mods.Common.Activities attackAircraft = self.Trait(); rearmable = self.TraitOrDefault(); + strafeDistance = attackAircraft.Info.StrafeRunLength; + // 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 if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner)) @@ -151,7 +154,9 @@ namespace OpenRA.Mods.Common.Activities 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) + else if (attackAircraft.Info.AttackType == AirAttackType.Strafe) + QueueChild(new StrafeAttackRun(self, attackAircraft, target, strafeDistance != WDist.Zero ? strafeDistance : lastVisibleMaximumRange)); + else if (attackAircraft.Info.AttackType == AirAttackType.Default && !aircraft.Info.CanHover) QueueChild(new FlyAttackRun(self, target, lastVisibleMaximumRange)); // Turn to face the target if required. @@ -228,4 +233,41 @@ namespace OpenRA.Mods.Common.Activities return false; } } + + class StrafeAttackRun : Activity + { + Target target; + WDist exitRange; + readonly AttackAircraft attackAircraft; + + public StrafeAttackRun(Actor self, AttackAircraft attackAircraft, Target t, WDist exitRange) + { + ChildHasPriority = false; + + target = t; + this.attackAircraft = attackAircraft; + 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; + + // Strafe attacks target the ground below the original target + // Update the position if we seen the target move; keep the previous one if it dies or disappears + bool targetIsHiddenActor; + target = target.Recalculate(self.Owner, out targetIsHiddenActor); + if (!targetIsHiddenActor && target.Type == TargetType.Actor) + attackAircraft.SetRequestedTarget(self, Target.FromTargetPositions(target), true); + + return false; + } + } } diff --git a/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs b/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs index ad8a2c730e..9e55d6487f 100644 --- a/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs @@ -17,13 +17,18 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { // TODO: Add CurleyShuffle (TD, TS), Circle (Generals Gunship-style) - public enum AirAttackType { Hover, Strafe } + public enum AirAttackType { Default, Hover, Strafe } public class AttackAircraftInfo : AttackFollowInfo, Requires { - [Desc("Attack behavior. Currently supported types are Strafe (default) and Hover.")] - public readonly AirAttackType AttackType = AirAttackType.Strafe; + [Desc("Attack behavior. Currently supported types are:", + "Default: Attack while following the default movement rules.", + "Hover: Hover, even if the Aircraft can't hover while idle.", + "Strafe: Perform a fixed-length attack run on the target.")] + public readonly AirAttackType AttackType = AirAttackType.Default; + [Desc("Distance the strafing aircraft makes to a target before turning for another pass. When set to WDist.Zero this defaults to the maximum armament range.")] + public readonly WDist StrafeRunLength = WDist.Zero; [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; diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20191117/ReplaceAttackTypeStrafe.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20191117/ReplaceAttackTypeStrafe.cs new file mode 100644 index 0000000000..43753f0db0 --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20191117/ReplaceAttackTypeStrafe.cs @@ -0,0 +1,48 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Mods.Common.Traits; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class ReplaceAttackTypeStrafe : UpdateRule + { + public override string Name { get { return "Replaced AttackAircraft AttackType: Strafe logic."; } } + public override string Description + { + get + { + return "The AttackType: Strafe behaviour on AttackAircraft has been renamed to Default,\n" + + "and AttackTurnDelay has been removed. A new AttackType: Strafe has been added, with a\n" + + "new StrafeRunLength parameter, designed for use with the FirstBurstTargetOffset and\n" + + "FollowingBurstTargetOffset weapon parameters."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var aircraft = actorNode.LastChildMatching("Aircraft"); + if (aircraft != null) + { + var attackAircraft = actorNode.LastChildMatching("AttackAircraft"); + if (attackAircraft == null) + yield break; + + var attackType = attackAircraft.LastChildMatching("AttackType"); + if (attackType.NodeValue() == AirAttackType.Strafe) + attackAircraft.RemoveNode(attackType); + + attackAircraft.RemoveNodes("AttackTurnDelay"); + } + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index 8d76a05107..5e75b50f98 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -144,6 +144,7 @@ namespace OpenRA.Mods.Common.UpdateRules new RemoveInitialFacingHardcoding(), new RemoveAirdropActorTypeDefault(), new RenameProneTime(), + new ReplaceAttackTypeStrafe(), }) }; diff --git a/mods/ra/rules/aircraft.yaml b/mods/ra/rules/aircraft.yaml index 8a76f3f448..5f6ebc965c 100644 --- a/mods/ra/rules/aircraft.yaml +++ b/mods/ra/rules/aircraft.yaml @@ -112,7 +112,6 @@ MIG: AttackAircraft: FacingTolerance: 20 PersistentTargeting: false - AttackTurnDelay: 30 Aircraft: CruiseAltitude: 2560 InitialFacing: 192