From c633e074109aca430012a3d810f7ffa81e317374 Mon Sep 17 00:00:00 2001 From: tovl Date: Fri, 15 Feb 2019 15:39:54 +0100 Subject: [PATCH] Make aircraft occupy cells when landed. --- .../Traits/Buildings/ProductionAirdrop.cs | 2 +- OpenRA.Mods.Common/Activities/Air/Fly.cs | 3 ++ OpenRA.Mods.Common/Activities/Air/HeliFly.cs | 3 ++ OpenRA.Mods.Common/Activities/Air/HeliLand.cs | 26 ++++++++--- OpenRA.Mods.Common/Activities/Air/Land.cs | 34 ++++++++++++++- .../Activities/Air/ReturnToBase.cs | 4 +- .../Scripting/Global/ReinforcementsGlobal.cs | 2 +- .../Properties/AircraftProperties.cs | 2 +- OpenRA.Mods.Common/Traits/Air/Aircraft.cs | 43 +++++++++++++++---- OpenRA.Mods.Common/Traits/Cargo.cs | 2 +- mods/ts/rules/aircraft.yaml | 2 +- 11 files changed, 101 insertions(+), 22 deletions(-) diff --git a/OpenRA.Mods.Cnc/Traits/Buildings/ProductionAirdrop.cs b/OpenRA.Mods.Cnc/Traits/Buildings/ProductionAirdrop.cs index fc98b1bfeb..1bfbc9b678 100644 --- a/OpenRA.Mods.Cnc/Traits/Buildings/ProductionAirdrop.cs +++ b/OpenRA.Mods.Cnc/Traits/Buildings/ProductionAirdrop.cs @@ -72,7 +72,7 @@ namespace OpenRA.Mods.Cnc.Traits }); actor.QueueActivity(new Fly(actor, Target.FromPos(self.CenterPosition + new WVec(landDistance, 0, 0)))); - actor.QueueActivity(new Land(actor, Target.FromActor(self))); + actor.QueueActivity(new Land(actor, Target.FromActor(self), false)); actor.QueueActivity(new CallFunc(() => { if (!self.IsInWorld || self.IsDead) diff --git a/OpenRA.Mods.Common/Activities/Air/Fly.cs b/OpenRA.Mods.Common/Activities/Air/Fly.cs index 615b51f738..acd9b8b297 100644 --- a/OpenRA.Mods.Common/Activities/Air/Fly.cs +++ b/OpenRA.Mods.Common/Activities/Air/Fly.cs @@ -105,6 +105,9 @@ namespace OpenRA.Mods.Common.Activities soundPlayed = true; } + if (self.IsAtGroundLevel()) + aircraft.RemoveInfluence(); + // Inside the target annulus, so we're done var insideMaxRange = maxRange.Length > 0 && checkTarget.IsInRange(aircraft.CenterPosition, maxRange); var insideMinRange = minRange.Length > 0 && checkTarget.IsInRange(aircraft.CenterPosition, minRange); diff --git a/OpenRA.Mods.Common/Activities/Air/HeliFly.cs b/OpenRA.Mods.Common/Activities/Air/HeliFly.cs index 2128310c2f..c515027db0 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliFly.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliFly.cs @@ -98,6 +98,9 @@ namespace OpenRA.Mods.Common.Activities soundPlayed = true; } + if (self.IsAtGroundLevel()) + aircraft.RemoveInfluence(); + if (AdjustAltitude(self, aircraft, aircraft.Info.CruiseAltitude)) return this; diff --git a/OpenRA.Mods.Common/Activities/Air/HeliLand.cs b/OpenRA.Mods.Common/Activities/Air/HeliLand.cs index a9116e3d86..c1eda44c41 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliLand.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliLand.cs @@ -19,26 +19,42 @@ namespace OpenRA.Mods.Common.Activities readonly Aircraft aircraft; readonly WDist landAltitude; readonly bool requireSpace; + readonly Actor ignoreActor; bool soundPlayed; + bool landingInitiated; - public HeliLand(Actor self, bool requireSpace) - : this(self, requireSpace, self.Info.TraitInfo().LandAltitude) { } + public HeliLand(Actor self, bool requireSpace, Actor ignoreActor = null) + : this(self, requireSpace, self.Info.TraitInfo().LandAltitude, ignoreActor) { } - public HeliLand(Actor self, bool requireSpace, WDist landAltitude) + public HeliLand(Actor self, bool requireSpace, WDist landAltitude, Actor ignoreActor = null) { this.requireSpace = requireSpace; this.landAltitude = landAltitude; + this.ignoreActor = ignoreActor; aircraft = self.Trait(); } public override Activity Tick(Actor self) { if (IsCanceling) + { + aircraft.RemoveInfluence(); return NextActivity; + } - if (requireSpace && !aircraft.CanLand(self.Location)) - return this; + if (requireSpace && !landingInitiated) + { + var landingCell = self.Location; + if (!aircraft.CanLand(landingCell, ignoreActor)) + { + self.NotifyBlocker(landingCell); + return this; + } + + aircraft.AddInfluence(landingCell); + landingInitiated = true; + } if (!soundPlayed && aircraft.Info.LandingSounds.Length > 0 && !self.IsAtGroundLevel()) { diff --git a/OpenRA.Mods.Common/Activities/Air/Land.cs b/OpenRA.Mods.Common/Activities/Air/Land.cs index 95641f8b03..a3769ae3ca 100644 --- a/OpenRA.Mods.Common/Activities/Air/Land.cs +++ b/OpenRA.Mods.Common/Activities/Air/Land.cs @@ -19,22 +19,52 @@ namespace OpenRA.Mods.Common.Activities { readonly Target target; readonly Aircraft aircraft; + readonly bool requireSpace; + readonly Actor ignoreActor; + bool landingInitiated; bool soundPlayed; - public Land(Actor self, Target t) + public Land(Actor self, Target t, bool requireSpace, Actor ignoreActor = null) { target = t; aircraft = self.Trait(); + this.requireSpace = requireSpace; + this.ignoreActor = ignoreActor; } public override Activity Tick(Actor self) { + if (ChildActivity != null) + { + ChildActivity = ActivityUtils.RunActivity(self, ChildActivity); + if (ChildActivity != null) + return this; + } + if (!target.IsValidFor(self)) - Cancel(self); + return NextActivity; if (IsCanceling) + { + aircraft.RemoveInfluence(); return NextActivity; + } + + if (requireSpace && !landingInitiated) + { + var landingCell = self.World.Map.CellContaining(target.CenterPosition); + if (!aircraft.CanLand(landingCell, ignoreActor)) + { + // Maintain holding pattern. + QueueChild(self, new FlyCircle(self, 25), true); + self.NotifyBlocker(landingCell); + return this; + } + + aircraft.AddInfluence(landingCell); + landingInitiated = true; + } if (!soundPlayed && aircraft.Info.LandingSounds.Length > 0 && !self.IsAtGroundLevel()) { diff --git a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs index 9ad1e2de27..d8748c626f 100644 --- a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs @@ -230,10 +230,10 @@ namespace OpenRA.Mods.Common.Activities if (aircraft.Info.TurnToDock) QueueChild(self, new Turn(self, aircraft.Info.InitialFacing), true); - QueueChild(self, new HeliLand(self, false), true); + QueueChild(self, new HeliLand(self, true, dest), true); } else - QueueChild(self, new Land(self, Target.FromPos(dest.CenterPosition + offset)), true); + QueueChild(self, new Land(self, Target.FromPos(dest.CenterPosition + offset), true, dest), true); QueueChild(self, new ResupplyAircraft(self), true); resupplied = true; diff --git a/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs b/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs index 89e0b68a79..e4d6d33e27 100644 --- a/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs +++ b/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs @@ -187,7 +187,7 @@ namespace OpenRA.Mods.Common.Scripting } else { - transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, destination))); + transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, destination), true)); } transport.QueueActivity(new Wait(15)); diff --git a/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs index f91961f03c..7fe6a44620 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs @@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Queues a landing activity on the specififed actor.")] public void Land(Actor landOn) { - Self.QueueActivity(new Land(Self, Target.FromActor(landOn))); + Self.QueueActivity(new Land(Self, Target.FromActor(landOn), true, landOn)); } [ScriptActorPropertyActivity] diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index 1645a3848d..2f25f8851d 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -166,8 +166,6 @@ namespace OpenRA.Mods.Common.Traits INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, INotifyBecomingIdle, IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables { - static readonly Pair[] NoCells = { }; - public readonly AircraftInfo Info; readonly Actor self; @@ -185,6 +183,7 @@ namespace OpenRA.Mods.Common.Traits public Actor ReservedActor { get; private set; } public bool MayYieldReservation { get; private set; } public bool ForceLanding { get; private set; } + CPos landingCell; bool airborne; bool cruising; @@ -493,7 +492,13 @@ namespace OpenRA.Mods.Common.Traits get { return Util.ApplyPercentageModifiers(Info.Speed, speedModifiers); } } - public Pair[] OccupiedCells() { return NoCells; } + public Pair[] OccupiedCells() + { + if (!self.IsAtGroundLevel()) + return new[] { Pair.New(landingCell, SubCell.FullCell) }; + + return new[] { Pair.New(TopLeft, SubCell.FullCell) }; + } public WVec FlyStep(int facing) { @@ -506,13 +511,22 @@ namespace OpenRA.Mods.Common.Traits return speed * dir / 1024; } - public bool CanLand(CPos cell) + public bool CanLand(CPos cell, Actor ignoreActor = null) { if (!self.World.Map.Contains(cell)) return false; - if (self.World.ActorMap.AnyActorsAt(cell)) - return false; + foreach (var otherActor in self.World.ActorMap.GetActorsAt(cell)) + { + if (otherActor != ignoreActor) + return false; + } + + foreach (var otherActor in self.World.ActorMap.GetActorsAt(cell)) + { + if (AircraftCanEnter(otherActor)) + return true; + } var type = self.World.Map.GetTerrainInfo(cell).Type; return Info.LandableTerrainTypes.Contains(type); @@ -575,7 +589,7 @@ namespace OpenRA.Mods.Common.Traits } else if (!Info.CanHover && !atLandAltitude) self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed)); - else if (atLandAltitude && !CanLand(self.Location) && ReservedActor == null) + else if (atLandAltitude && !CanLand(self.Location, self) && ReservedActor == null) self.QueueActivity(new TakeOff(self)); else if (Info.CanHover && self.Info.HasTraitInfo() && Info.IdleTurnSpeed > -1) { @@ -627,6 +641,19 @@ namespace OpenRA.Mods.Common.Traits OnCruisingAltitudeLeft(); } + public void AddInfluence(CPos landingCell) + { + this.landingCell = landingCell; + if (self.IsInWorld) + self.World.ActorMap.AddInfluence(self, this); + } + + public void RemoveInfluence() + { + if (self.IsInWorld) + self.World.ActorMap.RemoveInfluence(self, this); + } + #endregion #region Implement IMove @@ -701,7 +728,7 @@ namespace OpenRA.Mods.Common.Traits public Activity MoveIntoTarget(Actor self, Target target) { if (!Info.VTOL) - return new Land(self, target); + return new Land(self, target, false); return new HeliLand(self, false); } diff --git a/OpenRA.Mods.Common/Traits/Cargo.cs b/OpenRA.Mods.Common/Traits/Cargo.cs index ffe477f135..5a656a41ac 100644 --- a/OpenRA.Mods.Common/Traits/Cargo.cs +++ b/OpenRA.Mods.Common/Traits/Cargo.cs @@ -213,7 +213,7 @@ namespace OpenRA.Mods.Common.Traits return false; } - return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location)) + return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location, self)) && CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => p.Trait().CanEnterCell(c, null, immediate))); } diff --git a/mods/ts/rules/aircraft.yaml b/mods/ts/rules/aircraft.yaml index 6ae36953d9..2904d96962 100644 --- a/mods/ts/rules/aircraft.yaml +++ b/mods/ts/rules/aircraft.yaml @@ -409,4 +409,4 @@ HUNTER: Palette: pips HitShape: MapEditorData: - Categories: System \ No newline at end of file + Categories: System