From 1d1802a163becdead89dc7bb248f451231fb916e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-R=C3=A9my=20Buchs?= Date: Sat, 3 Jun 2017 00:48:28 +0200 Subject: [PATCH] Add LandOnCondition to the trait Aircraft which triggers a landing and prevents takeoffs while the condition is met --- OpenRA.Mods.Common/Activities/Air/Fly.cs | 7 +++ .../Activities/Air/FlyAttack.cs | 7 +++ .../Activities/Air/FlyCircle.cs | 7 +++ .../Activities/Air/FlyFollow.cs | 7 +++ .../Activities/Air/FlyOffMap.cs | 7 +++ OpenRA.Mods.Common/Activities/Air/FlyTimed.cs | 7 +++ .../Activities/Air/HeliAttack.cs | 7 +++ OpenRA.Mods.Common/Activities/Air/HeliFly.cs | 7 +++ .../Activities/Air/HeliFlyCircle.cs | 7 +++ .../Activities/Air/HeliReturnToBase.cs | 5 ++ .../Activities/Air/ReturnToBase.cs | 5 ++ OpenRA.Mods.Common/Activities/Air/TakeOff.cs | 7 +++ OpenRA.Mods.Common/Traits/Air/Aircraft.cs | 48 ++++++++++++++++++- 13 files changed, 126 insertions(+), 2 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Air/Fly.cs b/OpenRA.Mods.Common/Activities/Air/Fly.cs index cc29459083..46318c94c4 100644 --- a/OpenRA.Mods.Common/Activities/Air/Fly.cs +++ b/OpenRA.Mods.Common/Activities/Air/Fly.cs @@ -57,6 +57,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (plane.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs index d8421075bd..92b922f3ad 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs @@ -36,6 +36,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (aircraft.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (!target.IsValidFor(self)) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs b/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs index ea89930fc7..875f5c4555 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyCircle.cs @@ -28,6 +28,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (plane.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs b/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs index c8b8e62e02..0af76666f7 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs @@ -32,6 +32,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (plane.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs b/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs index aaf90a5dea..56de25debc 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs @@ -25,6 +25,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (plane.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled || !self.World.Map.Contains(self.Location)) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs b/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs index 319a109ea5..8b1d83dec2 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs @@ -29,6 +29,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (plane.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled || remainingTicks-- == 0) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs index c45952f269..a4637e2bff 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs @@ -52,6 +52,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (helicopter.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/HeliFly.cs b/OpenRA.Mods.Common/Activities/Air/HeliFly.cs index c4f29b0a9e..493c159515 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliFly.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliFly.cs @@ -54,6 +54,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (helicopter.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/HeliFlyCircle.cs b/OpenRA.Mods.Common/Activities/Air/HeliFlyCircle.cs index 2eac754c36..78a0be5688 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliFlyCircle.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliFlyCircle.cs @@ -27,6 +27,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (helicopter.ForceLanding) + { + Cancel(self); + return NextActivity; + } + if (IsCanceled) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs index 179ed67478..498fe16445 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs @@ -42,6 +42,11 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + // Special case: Don't kill other deploy hotkey activities. + if (heli.ForceLanding) + return NextActivity; + if (IsCanceled) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs index 3c5e47cd9b..7d700a6851 100644 --- a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs @@ -110,6 +110,11 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + // Special case: Don't kill other deploy hotkey activities. + if (plane.ForceLanding) + return NextActivity; + if (IsCanceled || self.IsDead) return NextActivity; diff --git a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs index c271d565aa..f0a375a7dd 100644 --- a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs +++ b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs @@ -28,6 +28,13 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { + // Refuse to take off if it would land immediately again. + if (aircraft.ForceLanding) + { + Cancel(self); + return NextActivity; + } + aircraft.UnReserve(); var host = aircraft.GetActorBelow(); diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index 4d286e8e48..55b9aa0672 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -17,6 +17,7 @@ using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Primitives; +using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -39,7 +40,7 @@ namespace OpenRA.Mods.Common.Traits public readonly int TurnSpeed = 255; public readonly int Speed = 1; - [Desc("Minimum altitude where this aircraft is considered airborne")] + [Desc("Minimum altitude where this aircraft is considered airborne.")] public readonly int MinAirborneAltitude = 1; public readonly HashSet LandableTerrainTypes = new HashSet(); @@ -100,6 +101,9 @@ namespace OpenRA.Mods.Common.Traits yield return new FacingInit(PreviewFacing); } + [Desc("Condition when this aircraft should land as soon as possible and refuse to take off.")] + public readonly BooleanExpression LandOnCondition; + public IReadOnlyDictionary OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any) { return new ReadOnlyDictionary(); } bool IOccupySpaceInfo.SharesCell { get { return false; } } @@ -124,7 +128,7 @@ namespace OpenRA.Mods.Common.Traits } public class Aircraft : ITick, ISync, IFacing, IPositionable, IMove, IIssueOrder, IResolveOrder, IOrderVoice, IDeathActorInitModifier, - INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, IActorPreviewInitModifier, IIssueDeployOrder + INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables { static readonly Pair[] NoCells = { }; @@ -142,6 +146,7 @@ namespace OpenRA.Mods.Common.Traits public int TurnSpeed { get { return Info.TurnSpeed; } } public Actor ReservedActor { get; private set; } public bool MayYieldReservation { get; private set; } + public bool ForceLanding { get; private set; } bool airborne; bool cruising; @@ -152,6 +157,7 @@ namespace OpenRA.Mods.Common.Traits bool isMoving; bool isMovingVertically; WPos cachedPosition; + bool? landNow; public Aircraft(ActorInitializer init, AircraftInfo info) { @@ -171,6 +177,17 @@ namespace OpenRA.Mods.Common.Traits IsPlane = !info.CanHover; } + public virtual IEnumerable GetVariableObservers() + { + if (Info.LandOnCondition != null) + yield return new VariableObserver(ForceLandConditionChanged, Info.LandOnCondition.Variables); + } + + void ForceLandConditionChanged(Actor self, IReadOnlyDictionary variables) + { + landNow = Info.LandOnCondition.Evaluate(variables); + } + public void Created(Actor self) { conditionManager = self.TraitOrDefault(); @@ -208,6 +225,33 @@ namespace OpenRA.Mods.Common.Traits self.QueueActivity(new TakeOff(self)); } + // Add land activity if LandOnCondidion resolves to true and the actor can land at the current location. + if (landNow.HasValue && landNow.Value && airborne && CanLand(self.Location) + && !(self.CurrentActivity is HeliLand || self.CurrentActivity is Turn)) + { + self.CancelActivity(); + + if (Info.TurnToLand) + self.QueueActivity(new Turn(self, Info.InitialFacing)); + + self.QueueActivity(new HeliLand(self, true)); + + ForceLanding = true; + } + + // Add takeoff activity if LandOnCondidion resolves to false and the actor should not land when idle. + if (landNow.HasValue && !landNow.Value && !cruising && !(self.CurrentActivity is TakeOff)) + { + ForceLanding = false; + + if (!Info.LandWhenIdle) + { + self.CancelActivity(); + + self.QueueActivity(new TakeOff(self)); + } + } + var oldCachedPosition = cachedPosition; cachedPosition = self.CenterPosition; isMoving = (oldCachedPosition - cachedPosition).HorizontalLengthSquared != 0;