diff --git a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs index bfa00d0493..a1b31b1b92 100644 --- a/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Activities // TODO: This should check whether there is ammo left that is actually suitable for the target if (ammoPools.All(x => !x.Info.SelfReloads && !x.HasAmmo())) - return ActivityUtils.SequenceActivities(new ReturnToBase(self), this); + return ActivityUtils.SequenceActivities(new ReturnToBase(self, aircraft.Info.AbortOnResupply), this); if (attackPlane != null) attackPlane.DoAttack(self, target); diff --git a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs index 8a429e6f01..339591b33e 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliAttack.cs @@ -67,7 +67,7 @@ namespace OpenRA.Mods.Common.Activities // If any AmmoPool is depleted and no weapon is valid against target, return to helipad to reload and then resume the activity if (ammoPools.Any(x => !x.Info.SelfReloads && !x.HasAmmo()) && !attackHeli.HasAnyValidWeapons(target)) - return ActivityUtils.SequenceActivities(new HeliReturnToBase(self), this); + return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, helicopter.Info.AbortOnResupply), this); var dist = target.CenterPosition - self.CenterPosition; diff --git a/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs index 471352b9c1..98b6adc019 100644 --- a/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/HeliReturnToBase.cs @@ -19,10 +19,14 @@ namespace OpenRA.Mods.Common.Activities public class HeliReturnToBase : Activity { readonly Aircraft heli; + readonly bool alwaysLand; + readonly bool abortOnResupply; - public HeliReturnToBase(Actor self) + public HeliReturnToBase(Actor self, bool abortOnResupply, bool alwaysLand = true) { heli = self.Trait(); + this.alwaysLand = alwaysLand; + this.abortOnResupply = abortOnResupply; } public Actor ChooseHelipad(Actor self) @@ -68,17 +72,36 @@ namespace OpenRA.Mods.Common.Activities } } - heli.MakeReservation(dest); - var exit = dest.Info.TraitInfos().FirstOrDefault(); var offset = (exit != null) ? exit.SpawnOffset : WVec.Zero; + if (ShouldLandAtBuilding(self, dest)) + { + heli.MakeReservation(dest); + + return ActivityUtils.SequenceActivities( + new HeliFly(self, Target.FromPos(dest.CenterPosition + offset)), + new Turn(self, initialFacing), + new HeliLand(self, false), + new ResupplyAircraft(self), + !abortOnResupply ? NextActivity : null); + } + return ActivityUtils.SequenceActivities( new HeliFly(self, Target.FromPos(dest.CenterPosition + offset)), - new Turn(self, initialFacing), - new HeliLand(self, false), - new ResupplyAircraft(self), NextActivity); } + + bool ShouldLandAtBuilding(Actor self, Actor dest) + { + if (alwaysLand) + return true; + + if (heli.Info.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged) + return true; + + return heli.Info.RearmBuildings.Contains(dest.Info.Name) && self.TraitsImplementing() + .Any(p => !p.Info.SelfReloads && !p.FullAmmo()); + } } } diff --git a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs index 9ca9e7aaeb..446c9ca281 100644 --- a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs @@ -22,13 +22,17 @@ namespace OpenRA.Mods.Common.Activities { readonly Aircraft plane; readonly AircraftInfo planeInfo; + readonly bool alwaysLand; + readonly bool abortOnResupply; bool isCalculated; Actor dest; WPos w1, w2, w3; - public ReturnToBase(Actor self, Actor dest = null) + public ReturnToBase(Actor self, bool abortOnResupply, Actor dest = null, bool alwaysLand = true) { this.dest = dest; + this.alwaysLand = alwaysLand; + this.abortOnResupply = abortOnResupply; plane = self.Trait(); planeInfo = self.Info.TraitInfo(); } @@ -51,8 +55,6 @@ namespace OpenRA.Mods.Common.Activities if (dest == null) return; - plane.MakeReservation(dest); - var landPos = dest.CenterPosition; var altitude = planeInfo.CruiseAltitude.Length; @@ -94,6 +96,18 @@ namespace OpenRA.Mods.Common.Activities isCalculated = true; } + bool ShouldLandAtBuilding(Actor self, Actor dest) + { + if (alwaysLand) + return true; + + if (planeInfo.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged) + return true; + + return planeInfo.RearmBuildings.Contains(dest.Info.Name) && self.TraitsImplementing() + .Any(p => !p.Info.SelfReloads && !p.FullAmmo()); + } + public override Activity Tick(Actor self) { if (IsCanceled || self.IsDead) @@ -128,9 +142,17 @@ namespace OpenRA.Mods.Common.Activities // Fix a problem when the airplane is send to resupply near the airport landingProcedures.Add(new Fly(self, Target.FromPos(w3), WDist.Zero, new WDist(turnRadius / 2))); - landingProcedures.Add(new Land(self, Target.FromActor(dest))); - landingProcedures.Add(new ResupplyAircraft(self)); - landingProcedures.Add(NextActivity); + + if (ShouldLandAtBuilding(self, dest)) + { + plane.MakeReservation(dest); + + landingProcedures.Add(new Land(self, Target.FromActor(dest))); + landingProcedures.Add(new ResupplyAircraft(self)); + } + + if (!abortOnResupply) + landingProcedures.Add(NextActivity); return ActivityUtils.SequenceActivities(landingProcedures.ToArray()); } diff --git a/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs index 439697f88a..13b71c126d 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/AircraftProperties.cs @@ -42,9 +42,9 @@ namespace OpenRA.Mods.Common.Scripting public void ReturnToBase(Actor airfield = null) { if (isPlane) - Self.QueueActivity(new ReturnToBase(Self, airfield)); + Self.QueueActivity(new ReturnToBase(Self, false, airfield)); else - Self.QueueActivity(new HeliReturnToBase(Self)); + Self.QueueActivity(new HeliReturnToBase(Self, false)); } [ScriptActorPropertyActivity] diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index 6789a96670..b3097617b4 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -69,6 +69,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Does this actor need to turn before landing?")] public readonly bool TurnToLand = false; + [Desc("Does this actor cancel its previous activity after resupplying?")] + public readonly bool AbortOnResupply = true; + public readonly WDist LandAltitude = WDist.Zero; [Desc("How fast this actor ascends or descends when using horizontal take off/landing.")] @@ -559,9 +562,9 @@ namespace OpenRA.Mods.Common.Traits if (Reservable.IsReserved(order.TargetActor)) { if (IsPlane) - self.QueueActivity(new ReturnToBase(self)); + self.QueueActivity(new ReturnToBase(self, Info.AbortOnResupply)); else - self.QueueActivity(new HeliReturnToBase(self)); + self.QueueActivity(new HeliReturnToBase(self, Info.AbortOnResupply)); } else { @@ -570,7 +573,7 @@ namespace OpenRA.Mods.Common.Traits if (IsPlane) { self.QueueActivity(order.Queued, ActivityUtils.SequenceActivities( - new ReturnToBase(self, order.TargetActor), + new ReturnToBase(self, Info.AbortOnResupply, order.TargetActor), new ResupplyAircraft(self))); } else @@ -618,11 +621,9 @@ namespace OpenRA.Mods.Common.Traits UnReserve(); self.CancelActivity(); if (IsPlane) - self.QueueActivity(new ReturnToBase(self)); + self.QueueActivity(new ReturnToBase(self, Info.AbortOnResupply, null, false)); else - self.QueueActivity(new HeliReturnToBase(self)); - - self.QueueActivity(new ResupplyAircraft(self)); + self.QueueActivity(new HeliReturnToBase(self, Info.AbortOnResupply, false)); } } diff --git a/OpenRA.Mods.Common/Traits/Air/ReturnOnIdle.cs b/OpenRA.Mods.Common/Traits/Air/ReturnOnIdle.cs index 78e1847462..d6843e56c2 100644 --- a/OpenRA.Mods.Common/Traits/Air/ReturnOnIdle.cs +++ b/OpenRA.Mods.Common/Traits/Air/ReturnOnIdle.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Traits var airfield = ReturnToBase.ChooseAirfield(self, true); if (airfield != null) { - self.QueueActivity(new ReturnToBase(self, airfield)); + self.QueueActivity(new ReturnToBase(self, aircraftInfo.AbortOnResupply, airfield)); self.QueueActivity(new ResupplyAircraft(self)); } else