diff --git a/OpenRA.Mods.Common/Activities/Air/Fly.cs b/OpenRA.Mods.Common/Activities/Air/Fly.cs index 5293e3047b..91bf7ae50f 100644 --- a/OpenRA.Mods.Common/Activities/Air/Fly.cs +++ b/OpenRA.Mods.Common/Activities/Air/Fly.cs @@ -113,11 +113,28 @@ namespace OpenRA.Mods.Common.Activities if (aircraft.ForceLanding) Cancel(self); - if (IsCanceling) - return NextActivity; - var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); - if (dat <= aircraft.LandAltitude) + if (IsCanceling) + { + // We must return the actor to a sensible height before continuing. + // If the aircraft is on the ground we queue TakeOff to manage the influence reservation and takeoff sounds etc. + // TODO: It would be better to not take off at all, but we lack the plumbing to detect current airborne/landed state. + // 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 (dat <= aircraft.LandAltitude) + QueueChild(self, new TakeOff(self, target), true); + else + VerticalTakeOffOrLandTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude); + + return this; + } + + return NextActivity; + } + else if (dat <= aircraft.LandAltitude) { QueueChild(self, new TakeOff(self, target), true); return this; diff --git a/OpenRA.Mods.Common/Activities/Air/Land.cs b/OpenRA.Mods.Common/Activities/Air/Land.cs index 45c3277c71..bcff084153 100644 --- a/OpenRA.Mods.Common/Activities/Air/Land.cs +++ b/OpenRA.Mods.Common/Activities/Air/Land.cs @@ -48,8 +48,23 @@ namespace OpenRA.Mods.Common.Activities if (IsCanceling || target.Type == TargetType.Invalid) { - aircraft.RemoveInfluence(); - return NextActivity; + // We must return the actor to a sensible height before continuing. + // If the aircraft lands when idle and is idle, continue landing, + // otherwise climb back to CruiseAltitude. + // TODO: Remove this after fixing all activities to work properly with arbitrary starting altitudes. + var continueLanding = aircraft.Info.LandWhenIdle && self.CurrentActivity.IsCanceling && self.CurrentActivity.NextActivity == null; + if (!continueLanding) + { + var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); + if (dat > aircraft.LandAltitude && dat < aircraft.Info.CruiseAltitude) + { + QueueChild(self, new TakeOff(self), true); + return this; + } + + aircraft.RemoveInfluence(); + return NextActivity; + } } if (!landingInitiated)