diff --git a/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs b/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs index adcb5949ee..e2d7ba11a3 100644 --- a/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs +++ b/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs @@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Activities public class ResupplyAircraft : Activity { readonly Aircraft aircraft; + Activity inner; public ResupplyAircraft(Actor self) { @@ -27,22 +28,45 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { - var host = aircraft.GetActorBelow(); - - if (host == null) + if (IsCanceled) return NextActivity; - if (aircraft.IsPlane) - return ActivityUtils.SequenceActivities( - aircraft.GetResupplyActivities(host) - .Append(new CallFunc(() => aircraft.UnReserve())) - .Append(new WaitFor(() => NextActivity != null || Reservable.IsReserved(host))) - .Append(new TakeOff(self)) - .Append(NextActivity).ToArray()); + if (inner == null) + { + var host = aircraft.GetActorBelow(); - // If is helicopter move away as soon as the resupply ends - return ActivityUtils.SequenceActivities( - aircraft.GetResupplyActivities(host).Append(new TakeOff(self)).Append(NextActivity).ToArray()); + if (host == null) + return NextActivity; + + if (aircraft.IsPlane) + { + inner = ActivityUtils.SequenceActivities( + aircraft.GetResupplyActivities(host) + .Append(new CallFunc(() => aircraft.MayYieldReservation = true)) + .Append(new WaitFor(() => NextActivity != null || aircraft.ReservedActor == null)) + .ToArray()); + } + else + { + // Helicopters should take off from their helipad immediately after resupplying. + // HACK: NextActivity needs to be appended here because otherwise TakeOff does stupid things. + inner = ActivityUtils.SequenceActivities( + aircraft.GetResupplyActivities(host).Append(new TakeOff(self)).Append(NextActivity).ToArray()); + } + } + else + inner = ActivityUtils.RunActivity(self, inner); + + // The inner == NextActivity check is needed here because of the TakeOff issue mentioned in the comment above. + return inner == null || inner == NextActivity ? NextActivity : this; + } + + public override void Cancel(Actor self) + { + if (!IsCanceled && inner != null) + inner.Cancel(self); + + base.Cancel(self); } } } diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index 9e4f0311b8..2c9f5b090f 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -104,13 +104,14 @@ namespace OpenRA.Mods.Common.Traits UpgradeManager um; IDisposable reservation; - Actor reservedActor; IEnumerable speedModifiers; [Sync] public int Facing { get; set; } [Sync] public WPos CenterPosition { get; private set; } public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } } public int TurnSpeed { get { return Info.TurnSpeed; } } + public Actor ReservedActor { get; private set; } + public bool MayYieldReservation; bool airborne; bool cruising; @@ -190,7 +191,7 @@ namespace OpenRA.Mods.Common.Traits if (reservation != null) { - var distanceFromReservationActor = (reservedActor.CenterPosition - self.CenterPosition).HorizontalLength; + var distanceFromReservationActor = (ReservedActor.CenterPosition - self.CenterPosition).HorizontalLength; if (distanceFromReservationActor < Info.WaitDistanceFromResupplyBase.Length) return WVec.Zero; } @@ -277,7 +278,7 @@ namespace OpenRA.Mods.Common.Traits if (reservable != null) { reservation = reservable.Reserve(target, self, this); - reservedActor = target; + ReservedActor = target; } } @@ -288,7 +289,8 @@ namespace OpenRA.Mods.Common.Traits reservation.Dispose(); reservation = null; - reservedActor = null; + ReservedActor = null; + MayYieldReservation = false; if (self.World.Map.DistanceAboveTerrain(CenterPosition).Length <= Info.LandAltitude.Length) self.QueueActivity(new TakeOff(self)); @@ -614,8 +616,6 @@ namespace OpenRA.Mods.Common.Traits self.QueueActivity(new ResupplyAircraft(self)); } - else - UnReserve(); } #endregion diff --git a/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs b/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs index b5dff175c4..a5b08be5cf 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs @@ -29,11 +29,19 @@ namespace OpenRA.Mods.Common.Traits return; /* nothing to do */ if (!Target.FromActor(reservedFor).IsValidFor(self)) - reservedFor = null; /* not likely to arrive now. */ + { + /* Not likely to arrive now. */ + reservedForAircraft.UnReserve(); + reservedFor = null; + reservedForAircraft = null; + } } public IDisposable Reserve(Actor self, Actor forActor, Aircraft forAircraft) { + if (reservedForAircraft != null && reservedForAircraft.MayYieldReservation) + reservedForAircraft.UnReserve(); + reservedFor = forActor; reservedForAircraft = forAircraft; @@ -53,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits public static bool IsReserved(Actor a) { var res = a.TraitOrDefault(); - return res != null && res.reservedFor != null; + return res != null && res.reservedForAircraft != null && !res.reservedForAircraft.MayYieldReservation; } public void Disposing(Actor self)