diff --git a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs index b7ad68364c..868e2d250d 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Activities { readonly Target target; readonly Aircraft aircraft; - readonly AttackPlane attackPlane; + readonly AttackAircraft attackAircraft; readonly Rearmable rearmable; int ticksUntilTurn; @@ -29,9 +29,9 @@ namespace OpenRA.Mods.Common.Activities { this.target = target; aircraft = self.Trait(); - attackPlane = self.Trait(); + attackAircraft = self.Trait(); rearmable = self.TraitOrDefault(); - ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay; + ticksUntilTurn = attackAircraft.AttackAircraftInfo.AttackTurnDelay; } public override Activity Tick(Actor self) @@ -47,10 +47,10 @@ namespace OpenRA.Mods.Common.Activities return NextActivity; // If all valid weapons have depleted their ammo and Rearmable trait exists, return to RearmActor to reload and then resume the activity - if (rearmable != null && attackPlane.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self))) + if (rearmable != null && attackAircraft.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self))) return ActivityUtils.SequenceActivities(new ReturnToBase(self, aircraft.Info.AbortOnResupply), this); - attackPlane.DoAttack(self, target); + attackAircraft.DoAttack(self, target); if (ChildActivity == null) { @@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.Activities return NextActivity; // TODO: This should fire each weapon at its maximum range - if (attackPlane != null && target.IsInRange(self.CenterPosition, attackPlane.Armaments.Where(Exts.IsTraitEnabled).Select(a => a.Weapon.MinRange).Min())) + if (attackAircraft != null && target.IsInRange(self.CenterPosition, attackAircraft.Armaments.Where(Exts.IsTraitEnabled).Select(a => a.Weapon.MinRange).Min())) ChildActivity = ActivityUtils.SequenceActivities(new FlyTimed(ticksUntilTurn, self), new Fly(self, target), new FlyTimed(ticksUntilTurn, self)); else ChildActivity = ActivityUtils.SequenceActivities(new Fly(self, target), new FlyTimed(ticksUntilTurn, self)); diff --git a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs index aa2db66d26..90a6e92425 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Activities public class HeliAttack : Activity { readonly Aircraft aircraft; - readonly AttackHeli attackHeli; + readonly AttackAircraft attackAircraft; readonly bool attackOnlyVisibleTargets; readonly Rearmable rearmable; @@ -45,7 +45,7 @@ namespace OpenRA.Mods.Common.Activities { Target = target; aircraft = self.Trait(); - attackHeli = self.Trait(); + attackAircraft = self.Trait(); this.attackOnlyVisibleTargets = attackOnlyVisibleTargets; rearmable = self.TraitOrDefault(); } @@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Activities return NextActivity; var pos = self.CenterPosition; - var targetPos = attackHeli.GetTargetPosition(pos, target); + var targetPos = attackAircraft.GetTargetPosition(pos, target); if (attackOnlyVisibleTargets && target.Type == TargetType.Actor && canHideUnderFog && !target.Actor.CanBeViewedByPlayer(self.Owner)) { @@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Activities } // If all valid weapons have depleted their ammo and Rearmable trait exists, return to RearmActor to reload and then resume the activity - if (rearmable != null && attackHeli.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self))) + if (rearmable != null && attackAircraft.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self))) return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, aircraft.Info.AbortOnResupply), this); var dist = targetPos - pos; @@ -88,11 +88,11 @@ namespace OpenRA.Mods.Common.Activities return this; // Fly towards the target - if (!target.IsInRange(pos, attackHeli.GetMaximumRangeVersusTarget(target))) + if (!target.IsInRange(pos, attackAircraft.GetMaximumRangeVersusTarget(target))) aircraft.SetPosition(self, aircraft.CenterPosition + aircraft.FlyStep(desiredFacing)); // Fly backwards from the target - if (target.IsInRange(pos, attackHeli.GetMinimumRangeVersusTarget(target))) + if (target.IsInRange(pos, attackAircraft.GetMinimumRangeVersusTarget(target))) { // Facing 0 doesn't work with the following position change var facing = 1; @@ -103,7 +103,7 @@ namespace OpenRA.Mods.Common.Activities aircraft.SetPosition(self, aircraft.CenterPosition + aircraft.FlyStep(-facing)); } - attackHeli.DoAttack(self, target); + attackAircraft.DoAttack(self, target); return this; } diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index d0b222df53..5144480a84 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -273,8 +273,7 @@ - - + @@ -932,6 +931,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Air/AttackPlane.cs b/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs similarity index 73% rename from OpenRA.Mods.Common/Traits/Air/AttackPlane.cs rename to OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs index 145cc61d12..544dbe8962 100644 --- a/OpenRA.Mods.Common/Traits/Air/AttackPlane.cs +++ b/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs @@ -15,28 +15,31 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class AttackPlaneInfo : AttackFrontalInfo, Requires + public class AttackAircraftInfo : AttackFrontalInfo, Requires { - [Desc("Delay, in game ticks, before turning to attack.")] + [Desc("Delay, in game ticks, before non-hovering aircraft turns to attack.")] public readonly int AttackTurnDelay = 50; - public override object Create(ActorInitializer init) { return new AttackPlane(init.Self, this); } + public override object Create(ActorInitializer init) { return new AttackAircraft(init.Self, this); } } - public class AttackPlane : AttackFrontal + public class AttackAircraft : AttackFrontal { - public readonly AttackPlaneInfo AttackPlaneInfo; + public readonly AttackAircraftInfo AttackAircraftInfo; readonly AircraftInfo aircraftInfo; - public AttackPlane(Actor self, AttackPlaneInfo info) + public AttackAircraft(Actor self, AttackAircraftInfo info) : base(self, info) { - AttackPlaneInfo = info; + AttackAircraftInfo = info; aircraftInfo = self.Info.TraitInfo(); } public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove, bool forceAttack) { + if (aircraftInfo.CanHover) + return new HeliAttack(self, newTarget); + return new FlyAttack(self, newTarget); } diff --git a/OpenRA.Mods.Common/Traits/Air/AttackHeli.cs b/OpenRA.Mods.Common/Traits/Air/AttackHeli.cs deleted file mode 100644 index fe89bd3698..0000000000 --- a/OpenRA.Mods.Common/Traits/Air/AttackHeli.cs +++ /dev/null @@ -1,33 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2018 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 OpenRA.Activities; -using OpenRA.Mods.Common.Activities; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - public class AttackHeliInfo : AttackFrontalInfo - { - public override object Create(ActorInitializer init) { return new AttackHeli(init.Self, this); } - } - - public class AttackHeli : AttackFrontal - { - public AttackHeli(Actor self, AttackHeliInfo info) - : base(self, info) { } - - public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove, bool forceAttack) - { - return new HeliAttack(self, newTarget); - } - } -} diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20180923/MergeAttackPlaneAndHeli.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20180923/MergeAttackPlaneAndHeli.cs new file mode 100644 index 0000000000..19c163f9e0 --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20180923/MergeAttackPlaneAndHeli.cs @@ -0,0 +1,79 @@ +#region Copyright & License Information +/* + * Copyright 2007-2018 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 System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class MergeAttackPlaneAndHeli : UpdateRule + { + public override string Name { get { return "AttackPlane and AttackHeli were merged to AttackAircraft"; } } + public override string Description + { + get + { + return "The AttackPlane and AttackHeli traits were merged intto a single\n" + + "AttackAircraft trait."; + } + } + + bool displayedMessage; + public override IEnumerable AfterUpdate(ModData modData) + { + var message = "If an actor had a total of more than one AttackPlane and/or AttackHeli,\n" + + "you may want to check the update results for possible redundant entries.\n"; + + if (!displayedMessage) + yield return message; + + displayedMessage = true; + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var attackPlanes = actorNode.ChildrenMatching("AttackPlane"); + var attackHelis = actorNode.ChildrenMatching("AttackHeli"); + var attackPlanesTotal = attackPlanes.Count(); + var attackHelisTotal = attackHelis.Count(); + + if (attackPlanesTotal == 0 && attackHelisTotal == 0) + yield break; + else if (attackPlanesTotal == 1 && attackHelisTotal == 0) + foreach (var attackPlane in attackPlanes) + attackPlane.RenameKey("AttackAircraft"); + else if (attackPlanesTotal == 0 && attackHelisTotal == 1) + foreach (var attackHeli in attackHelis) + attackHeli.RenameKey("AttackAircraft"); + else + { + // If we got here, we have at least two AttackPlane/-Heli traits in total + var attackPlanesCount = 0; + foreach (var attackPlane in attackPlanes) + { + var suffixCount = attackPlanesCount > 0 ? attackPlanesCount.ToString() : ""; + attackPlane.RenameKey("AttackAircraft@Plane" + suffixCount, false, true); + ++attackPlanesCount; + } + + var attackHelisCount = 0; + foreach (var attackHeli in attackHelis) + { + var suffixCount = attackHelisCount > 0 ? attackHelisCount.ToString() : ""; + attackHeli.RenameKey("AttackAircraft@Heli" + suffixCount, false, true); + ++attackHelisCount; + } + } + + yield break; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index 5ea2410c4b..cac2311d15 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -101,6 +101,7 @@ namespace OpenRA.Mods.Common.UpdateRules new RenameCrateActionNotification(), new RemoveRepairBuildingsFromAircraft(), new AddRearmable(), + new MergeAttackPlaneAndHeli(), }) }; diff --git a/mods/cnc/rules/aircraft.yaml b/mods/cnc/rules/aircraft.yaml index 0444cfc93f..68afaf5217 100644 --- a/mods/cnc/rules/aircraft.yaml +++ b/mods/cnc/rules/aircraft.yaml @@ -86,7 +86,7 @@ HELI: PauseOnCondition: !ammo AutoTarget: ScanRadius: 4 - AttackHeli: + AttackAircraft: FacingTolerance: 20 AmmoPool: Ammo: 10 @@ -144,7 +144,7 @@ ORCA: PauseOnCondition: !ammo AutoTarget: ScanRadius: 5 - AttackHeli: + AttackAircraft: FacingTolerance: 20 AmmoPool: Ammo: 6 diff --git a/mods/ra/rules/aircraft.yaml b/mods/ra/rules/aircraft.yaml index c1bc42b930..2e46afd5ff 100644 --- a/mods/ra/rules/aircraft.yaml +++ b/mods/ra/rules/aircraft.yaml @@ -106,7 +106,7 @@ MIG: LocalOffset: 0,-640,0, 0,640,0 LocalYaw: -40, 24 PauseOnCondition: !ammo - AttackPlane: + AttackAircraft: FacingTolerance: 20 Aircraft: CruiseAltitude: 2560 @@ -173,7 +173,7 @@ YAK: LocalOffset: 256,213,0 MuzzleSequence: muzzle PauseOnCondition: !ammo - AttackPlane: + AttackAircraft: FacingTolerance: 20 Aircraft: CruiseAltitude: 2560 @@ -291,7 +291,7 @@ HELI: Weapon: HellfireAG LocalOffset: 0,213,-85, 0,-213,-85 PauseOnCondition: !ammo - AttackHeli: + AttackAircraft: FacingTolerance: 20 Aircraft: LandWhenIdle: false @@ -357,7 +357,7 @@ HIND: LocalOffset: 85,213,-85, 85,-213,-85 MuzzleSequence: muzzle PauseOnCondition: !ammo - AttackHeli: + AttackAircraft: FacingTolerance: 20 Aircraft: LandWhenIdle: false diff --git a/mods/ts/rules/aircraft.yaml b/mods/ts/rules/aircraft.yaml index 0b7f3609f5..a524977bf3 100644 --- a/mods/ts/rules/aircraft.yaml +++ b/mods/ts/rules/aircraft.yaml @@ -23,7 +23,7 @@ DPOD: EjectOnDeath: true Armament: Weapon: Vulcan2 - AttackHeli: + AttackAircraft: Voice: Attack AmmoPool: Ammo: 5 @@ -95,7 +95,7 @@ ORCA: Armament: Weapon: Hellfire PauseOnCondition: !ammo - AttackHeli: + AttackAircraft: FacingTolerance: 20 Voice: Attack PauseOnCondition: empdisable @@ -147,7 +147,7 @@ ORCAB: Armament: Weapon: Bomb PauseOnCondition: !ammo - AttackPlane: + AttackAircraft: Voice: Attack FacingTolerance: 20 PauseOnCondition: empdisable @@ -278,7 +278,7 @@ SCRIN: Armament: Weapon: Proton PauseOnCondition: !ammo - AttackPlane: + AttackAircraft: Voice: Attack FacingTolerance: 20 PauseOnCondition: empdisable @@ -326,7 +326,7 @@ APACHE: Armament: Weapon: HarpyClaw PauseOnCondition: !ammo - AttackHeli: + AttackAircraft: FacingTolerance: 20 Voice: Attack PauseOnCondition: empdisable