From 0ebeb30880a45ae881b27a77aa9fb05bdd5e5fa6 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Fri, 14 Jun 2019 10:36:54 +0200 Subject: [PATCH] Replace various Aircraft fields with FlightDynamics Replaces various booleans with a FlightDynamics flag list. --- OpenRA.Mods.Common/Activities/Air/Fly.cs | 20 +++-- .../Activities/Air/FlyCircle.cs | 2 +- .../Activities/Air/FlyFollow.cs | 4 +- OpenRA.Mods.Common/Activities/Air/Land.cs | 10 +-- .../Activities/Air/ReturnToBase.cs | 8 +- OpenRA.Mods.Common/Activities/Air/TakeOff.cs | 4 +- OpenRA.Mods.Common/Traits/Air/Aircraft.cs | 77 +++++++++---------- OpenRA.Mods.Common/Traits/Carryall.cs | 4 +- 8 files changed, 65 insertions(+), 64 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Air/Fly.cs b/OpenRA.Mods.Common/Activities/Air/Fly.cs index eacc693d13..5dd5823d81 100644 --- a/OpenRA.Mods.Common/Activities/Air/Fly.cs +++ b/OpenRA.Mods.Common/Activities/Air/Fly.cs @@ -53,7 +53,8 @@ namespace OpenRA.Mods.Common.Activities public static void FlyTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, WVec moveOverride, int turnSpeedOverride = -1) { var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); - var move = aircraft.Info.CanHover ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); + var isSlider = aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.Slide); + var move = isSlider ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); if (moveOverride != WVec.Zero) move = moveOverride; @@ -115,7 +116,7 @@ namespace OpenRA.Mods.Common.Activities // If the aircraft lands when idle and is idle, we let the default idle handler manage this. // TODO: Remove this after fixing all activities to work properly with arbitrary starting altitudes. var skipHeightAdjustment = aircraft.Info.LandWhenIdle && self.CurrentActivity.IsCanceling && self.CurrentActivity.NextActivity == null; - if (aircraft.Info.CanHover && !skipHeightAdjustment && dat != aircraft.Info.CruiseAltitude) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.Hover) && !skipHeightAdjustment && dat != aircraft.Info.CruiseAltitude) { if (dat <= aircraft.LandAltitude) QueueChild(new TakeOff(self, target)); @@ -160,19 +161,22 @@ namespace OpenRA.Mods.Common.Activities if (insideMaxRange && !insideMinRange) return true; - var move = aircraft.Info.CanHover ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); + var isSlider = aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.Slide); + var move = isSlider ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); - // Inside the minimum range, so reverse if CanHover - if (aircraft.Info.CanHover && insideMinRange) + // Inside the minimum range, so reverse if we have Slide flag + if (isSlider && insideMinRange) { FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, -move); return false; } - // The next move would overshoot, so consider it close enough or set final position if CanHover + // The next move would overshoot, so consider it close enough or set final position if we have Slide flag if (delta.HorizontalLengthSquared < move.HorizontalLengthSquared) { - if (aircraft.Info.CanHover) + // For VTOL landing to succeed, it must reach the exact target position, + // so for the final move it needs to behave as if it had the Slide flag. + if (isSlider || aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL)) { // Set final (horizontal) position if (delta.HorizontalLengthSquared != 0) @@ -193,7 +197,7 @@ namespace OpenRA.Mods.Common.Activities return true; } - if (!aircraft.Info.CanHover) + if (!isSlider) { // Using the turn rate, compute a hypothetical circle traced by a continuous turn. // If it contains the destination point, it's unreachable without more complex manuvering. diff --git a/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs b/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs index 2586149c6c..7df134af3d 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs @@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Activities // We can't possibly turn this fast var desiredFacing = aircraft.Facing + 64; - // This override is necessary, otherwise CanHover aircraft would circle sideways + // This override is necessary, otherwise aircraft with Slide flag would circle sideways var move = aircraft.FlyStep(aircraft.Facing); Fly.FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move, turnSpeedOverride); diff --git a/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs b/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs index 6f0dd472dc..2cd6db1b6d 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs @@ -84,7 +84,9 @@ namespace OpenRA.Mods.Common.Activities // otherwise if it is hidden or dead we give up if (checkTarget.IsInRange(pos, maxRange) && !checkTarget.IsInRange(pos, minRange)) { - Fly.FlyTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); + if (!aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.Hover)) + Fly.FlyTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); + return useLastVisibleTarget; } diff --git a/OpenRA.Mods.Common/Activities/Air/Land.cs b/OpenRA.Mods.Common/Activities/Air/Land.cs index 49b6ebc0e3..00d3615256 100644 --- a/OpenRA.Mods.Common/Activities/Air/Land.cs +++ b/OpenRA.Mods.Common/Activities/Air/Land.cs @@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Activities // NOTE: desiredFacing = -1 means we should not prefer any particular facing and instead just // use whatever facing gives us the most direct path to the landing site. - if (facing == -1 && aircraft.Info.TurnToLand) + if (facing == -1 && aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.TurnToLand)) desiredFacing = aircraft.Info.InitialFacing; else desiredFacing = facing; @@ -130,7 +130,7 @@ namespace OpenRA.Mods.Common.Activities } // Move towards landing location - if (aircraft.Info.VTOL && (pos - targetPosition).HorizontalLengthSquared != 0) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL) && (pos - targetPosition).HorizontalLengthSquared != 0) { QueueChild(new Fly(self, Target.FromPos(targetPosition))); @@ -140,7 +140,7 @@ namespace OpenRA.Mods.Common.Activities return false; } - if (!aircraft.Info.VTOL && !finishedApproach) + if (!aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL) && !finishedApproach) { // Calculate approach trajectory var altitude = aircraft.Info.CruiseAltitude.Length; @@ -207,7 +207,7 @@ namespace OpenRA.Mods.Common.Activities if (!aircraft.CanLand(blockingCells, target.Actor)) { // Maintain holding pattern. - if (aircraft.Info.CanHover) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.Hover)) QueueChild(new Wait(25)); else QueueChild(new FlyCircle(self, 25)); @@ -226,7 +226,7 @@ namespace OpenRA.Mods.Common.Activities } // Final descent. - if (aircraft.Info.VTOL) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL)) { var landAltitude = self.World.Map.DistanceAboveTerrain(targetPosition) + aircraft.LandAltitude; if (Fly.VerticalTakeOffOrLandTick(self, aircraft, aircraft.Facing, landAltitude)) diff --git a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs index bbfe41e15e..ae1d62d1ed 100644 --- a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs @@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Activities if (nearestResupplier != null) { - if (aircraft.Info.CanHover) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.Hover)) { var distanceFromResupplier = (nearestResupplier.CenterPosition - self.CenterPosition).HorizontalLength; var distanceLength = aircraft.Info.WaitDistanceFromResupplyBase.Length; @@ -113,15 +113,15 @@ namespace OpenRA.Mods.Common.Activities { var exit = dest.FirstExitOrDefault(null); var offset = exit != null ? exit.Info.SpawnOffset : WVec.Zero; - if (aircraft.Info.TurnToDock) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.TurnToDock)) facing = aircraft.Info.InitialFacing; - if (!aircraft.Info.VTOL) + if (!aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL)) facing = 192; aircraft.MakeReservation(dest); QueueChild(new Land(self, Target.FromActor(dest), offset, facing)); QueueChild(new Resupply(self, dest, WDist.Zero)); - if (aircraft.Info.TakeOffOnResupply && !alwaysLand) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.TakeOffOnResupply) && !alwaysLand) QueueChild(new TakeOff(self)); return true; diff --git a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs index e5b6fa8c21..f92847a279 100644 --- a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs +++ b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs @@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Activities if (dat < aircraft.Info.CruiseAltitude) { // If we're a VTOL, rise before flying forward - if (aircraft.Info.VTOL) + if (aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL)) { Fly.VerticalTakeOffOrLandTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); return false; @@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Activities // Checking for NextActivity == null again in case another activity was queued while taking off if (moveToRallyPoint && NextActivity == null) { - if (!aircraft.Info.VTOL && assignTargetOnFirstRun) + if (!aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.VTOL) && assignTargetOnFirstRun) return true; QueueChild(new AttackMoveActivity(self, () => move.MoveToTarget(self, target))); diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index 08e78748e8..9705882c6c 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -21,9 +21,34 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { + [Flags] + public enum FlightDynamic + { + None = 0, + MoveIntoShroud = 1, + Slide = 2, + Hover = 4, + VTOL = 8, + TurnToLand = 16, + TurnToDock = 32, + TakeOffOnResupply = 64, + TakeOffOnCreation = 128, + } + public class AircraftInfo : ITraitInfo, IPositionableInfo, IFacingInfo, IMoveInfo, ICruiseAltitudeInfo, IActorPreviewInitInfo, IEditorActorOptions, IObservesVariablesInfo { + [Desc("List of flags that alter the movement behavior. Options:", + "MoveIntoShroud = Can be ordered to move into shroud.", + "Slide = Changes direction immediately, independently of current facing. Without this flag, needs to fly a curve.", + "Hover = Able to statically hover in air while idle or waiting. Without this flag, aircraft will fly in circles.", + "VTOL = Vertical-only take-off/land. Without this flag, lands/takes off diagonally.", + "TurnToLand = Does the aircraft need to turn towards InitialFacing before landing on terrain? No effect if VTOL flag is missing.", + "TurnToDock = Does the aircraft need to turn towards InitialFacing before landing on dock? No effect if VTOL flag is missing.", + "TakeOffOnResupply = Take off as soon as resupplies/repairs are finished.", + "TakeOffOnCreation = Take off from creator when spawned.")] + public readonly FlightDynamic FlightDynamics = FlightDynamic.TakeOffOnCreation | FlightDynamic.MoveIntoShroud; + public readonly WDist CruiseAltitude = new WDist(1280); [Desc("Whether the aircraft can be repulsed.")] @@ -49,9 +74,6 @@ namespace OpenRA.Mods.Common.Traits public readonly HashSet LandableTerrainTypes = new HashSet(); - [Desc("Can the actor be ordered to move in to shroud?")] - public readonly bool MoveIntoShroud = true; - [Desc("e.g. crate, wall, infantry")] public readonly BitSet Crushes = default(BitSet); @@ -69,30 +91,12 @@ namespace OpenRA.Mods.Common.Traits [Desc("The condition to grant to self while at cruise altitude.")] public readonly string CruisingCondition = null; - [Desc("Can the actor hover in place mid-air? If not, then the actor will have to remain in motion (circle around).")] - public readonly bool CanHover = false; - - [Desc("Does the actor land and take off vertically?")] - public readonly bool VTOL = false; - [Desc("Will this actor try to land after it has no more commands?")] public readonly bool LandWhenIdle = true; - [Desc("Does this VTOL actor need to turn before landing (on terrain)?")] - public readonly bool TurnToLand = false; - - [Desc("Does this VTOL actor need to turn before landing on a resupplier?")] - public readonly bool TurnToDock = true; - [Desc("Does this actor cancel its previous activity after resupplying?")] public readonly bool AbortOnResupply = true; - [Desc("Does this actor automatically take off after resupplying?")] - public readonly bool TakeOffOnResupply = false; - - [Desc("Does this actor automatically take off after creation?")] - public readonly bool TakeOffOnCreation = true; - [Desc("Altitude at which the aircraft considers itself landed.")] public readonly WDist LandAltitude = WDist.Zero; @@ -344,7 +348,7 @@ namespace OpenRA.Mods.Common.Traits MakeReservation(host); - if (Info.TakeOffOnCreation) + if (Info.FlightDynamics.HasFlag(FlightDynamic.TakeOffOnCreation)) self.QueueActivity(new TakeOff(self)); } @@ -440,7 +444,7 @@ namespace OpenRA.Mods.Common.Traits repulsionForce += new WVec(1024, 0, 0).Rotate(WRot.FromYaw((self.CenterPosition - center).Yaw)); } - if (Info.CanHover) + if (Info.FlightDynamics.HasFlag(FlightDynamic.Slide)) return repulsionForce; // Non-hovering actors mush always keep moving forward, so they need extra calculations. @@ -681,18 +685,13 @@ namespace OpenRA.Mods.Common.Traits } } + var isCircler = !Info.FlightDynamics.HasFlag(FlightDynamic.Hover); if (!atLandAltitude && Info.LandWhenIdle && Info.LandableTerrainTypes.Count > 0) self.QueueActivity(new Land(self)); - else if (!Info.CanHover && !atLandAltitude) + else if (isCircler && !atLandAltitude) self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed)); else if (atLandAltitude && !CanLand(self.Location) && ReservedActor == null) self.QueueActivity(new TakeOff(self)); - else if (Info.CanHover && Info.IdleTurnSpeed > 0) - { - // Temporary HACK for the AutoCarryall special case (needs CanHover, but also FlyCircle on idle). - // Will go away soon (in a separate PR) with the arrival of ActionsWhenIdle. - self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed)); - } else if (!atLandAltitude && altitude != Info.CruiseAltitude && !Info.LandWhenIdle) self.QueueActivity(new TakeOff(self)); } @@ -834,11 +833,7 @@ namespace OpenRA.Mods.Common.Traits public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { - if (!Info.CanHover) - return new FlyFollow(self, target, minRange, maxRange, - initialTargetPosition, targetLineColor); - - return new Follow(self, target, minRange, maxRange, + return new FlyFollow(self, target, minRange, maxRange, initialTargetPosition, targetLineColor); } @@ -943,7 +938,7 @@ namespace OpenRA.Mods.Common.Traits { case "Land": case "Move": - if (!Info.MoveIntoShroud && order.Target.Type != TargetType.Invalid) + if (!Info.FlightDynamics.HasFlag(FlightDynamic.MoveIntoShroud) && order.Target.Type != TargetType.Invalid) { var cell = self.World.Map.CellContaining(order.Target.CenterPosition); if (!self.Owner.Shroud.IsExplored(cell)) @@ -968,7 +963,7 @@ namespace OpenRA.Mods.Common.Traits if (orderString == "Move") { var cell = self.World.Map.Clamp(self.World.Map.CellContaining(order.Target.CenterPosition)); - if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell)) + if (!Info.FlightDynamics.HasFlag(FlightDynamic.MoveIntoShroud) && !self.Owner.Shroud.IsExplored(cell)) return; if (!order.Queued) @@ -981,7 +976,7 @@ namespace OpenRA.Mods.Common.Traits else if (orderString == "Land") { var cell = self.World.Map.Clamp(self.World.Map.CellContaining(order.Target.CenterPosition)); - if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell)) + if (!Info.FlightDynamics.HasFlag(FlightDynamic.MoveIntoShroud) && !self.Owner.Shroud.IsExplored(cell)) return; if (!order.Queued) @@ -1011,7 +1006,7 @@ namespace OpenRA.Mods.Common.Traits // Aircraft with TakeOffOnResupply would immediately take off again, so there's no point in automatically forcing // them to land on a resupplier. For aircraft without it, it makes more sense to land than to idle above a // free resupplier. - var forceLand = orderString == "ForceEnter" || !Info.TakeOffOnResupply; + var forceLand = orderString == "ForceEnter" || !Info.FlightDynamics.HasFlag(FlightDynamic.TakeOffOnResupply); self.QueueActivity(order.Queued, new ReturnToBase(self, targetActor, forceLand)); } else if (orderString == "Stop") @@ -1036,7 +1031,7 @@ namespace OpenRA.Mods.Common.Traits // Aircraft with TakeOffOnResupply would immediately take off again, so there's no point in forcing them to land // on a resupplier. For aircraft without it, it makes more sense to land than to idle above a free resupplier. - self.QueueActivity(order.Queued, new ReturnToBase(self, null, !Info.TakeOffOnResupply)); + self.QueueActivity(order.Queued, new ReturnToBase(self, null, !Info.FlightDynamics.HasFlag(FlightDynamic.TakeOffOnResupply))); } else if (orderString == "Scatter") Nudge(self); @@ -1154,7 +1149,7 @@ namespace OpenRA.Mods.Common.Traits IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue); - if (!explored && !aircraft.Info.MoveIntoShroud) + if (!explored && !aircraft.Info.FlightDynamics.HasFlag(FlightDynamic.MoveIntoShroud)) cursor = "move-blocked"; return true; diff --git a/OpenRA.Mods.Common/Traits/Carryall.cs b/OpenRA.Mods.Common/Traits/Carryall.cs index 3c2727b592..e0523217d1 100644 --- a/OpenRA.Mods.Common/Traits/Carryall.cs +++ b/OpenRA.Mods.Common/Traits/Carryall.cs @@ -293,7 +293,7 @@ namespace OpenRA.Mods.Common.Traits if (order.OrderString == "DeliverUnit") { var cell = self.World.Map.Clamp(self.World.Map.CellContaining(order.Target.CenterPosition)); - if (!aircraftInfo.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell)) + if (!aircraftInfo.FlightDynamics.HasFlag(FlightDynamic.MoveIntoShroud) && !self.Owner.Shroud.IsExplored(cell)) return; var targetLocation = move.NearestMoveableCell(cell); @@ -406,7 +406,7 @@ namespace OpenRA.Mods.Common.Traits IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue); - if (!explored && !aircraftInfo.MoveIntoShroud) + if (!explored && !aircraftInfo.FlightDynamics.HasFlag(FlightDynamic.MoveIntoShroud)) cursor = info.DropOffBlockedCursor; return true;