From 52102da839fea895c4c78ce8ac4aa5fd6958588f Mon Sep 17 00:00:00 2001 From: Gustas <37534529+PunkPun@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:57:41 +0200 Subject: [PATCH] Fix harvesters refusing to queue dock orders whenn empty (cherry picked from commit 19040126046a53fd5092515f2a4895fdd5c9c87a) --- .../TransformsIntoDockClientManager.cs | 29 +++++++++++------ OpenRA.Mods.Common/Traits/DockClientBase.cs | 11 +++++-- .../Traits/DockClientManager.cs | 32 +++++++++++++------ OpenRA.Mods.Common/Traits/Harvester.cs | 6 ++++ OpenRA.Mods.Common/TraitsInterfaces.cs | 11 +++++-- 5 files changed, 64 insertions(+), 25 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoDockClientManager.cs b/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoDockClientManager.cs index ed6a99ed23..73b6bbeb4b 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoDockClientManager.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoDockClientManager.cs @@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits Info.EnterCursor, Info.EnterBlockedCursor, () => Info.RequiresForceMove, - DockingPossible, + CanQueueDockAt, CanDockAt); } } @@ -109,9 +109,13 @@ namespace OpenRA.Mods.Common.Traits string IOrderVoice.VoicePhraseForOrder(Actor self, Order order) { - if (order.OrderString == "Dock" && CanDockAt(order.Target.Actor, false)) - return Info.Voice; - else if (order.OrderString == "ForceDock" && CanDockAt(order.Target.Actor, true)) + if (order.Target.Type != TargetType.Actor || IsTraitDisabled) + return null; + + if (order.OrderString != "Dock" && order.OrderString != "ForceDock") + return null; + + if (CanQueueDockAt(order.Target.Actor, order.OrderString == "ForceDock", order.Queued)) return Info.Voice; return null; @@ -125,12 +129,6 @@ namespace OpenRA.Mods.Common.Traits return null; } - /// Clone of . - public bool DockingPossible(Actor target, bool forceEnter) - { - return !IsTraitDisabled && target.TraitsImplementing().Any(host => dockClients.Any(client => client.CanDock(host.GetDockType))); - } - /// Clone of . public bool CanDockAt(Actor target, bool forceEnter) { @@ -140,5 +138,16 @@ namespace OpenRA.Mods.Common.Traits return !IsTraitDisabled && target.TraitsImplementing().Any( host => dockClients.Any(client => client.CanDockAt(target, host, forceEnter, true))); } + + /// Clone of . + public bool CanQueueDockAt(Actor target, bool forceEnter, bool isQueued) + { + if (Info.RequiresForceMove && !forceEnter) + return false; + + return (!IsTraitDisabled) + && target.TraitsImplementing().Any( + host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued))); + } } } diff --git a/OpenRA.Mods.Common/Traits/DockClientBase.cs b/OpenRA.Mods.Common/Traits/DockClientBase.cs index e542209199..cb2a08f709 100644 --- a/OpenRA.Mods.Common/Traits/DockClientBase.cs +++ b/OpenRA.Mods.Common/Traits/DockClientBase.cs @@ -37,9 +37,14 @@ namespace OpenRA.Mods.Common.Traits public virtual bool CanDockAt(Actor hostActor, IDockHost host, bool forceEnter = false, bool ignoreOccupancy = false) { - return (forceEnter || self.Owner.IsAlliedWith(hostActor.Owner)) && - CanDock(host.GetDockType, forceEnter) && - host.IsDockingPossible(self, this, ignoreOccupancy); + return CanDock(host.GetDockType, forceEnter) + && host.IsDockingPossible(self, this, ignoreOccupancy); + } + + public virtual bool CanQueueDockAt(Actor hostActor, IDockHost host, bool forceEnter, bool isQueued) + { + return CanDock(host.GetDockType, true) + && host.IsDockingPossible(self, this, true); } public virtual void OnDockStarted(Actor self, Actor hostActor, IDockHost host) { } diff --git a/OpenRA.Mods.Common/Traits/DockClientManager.cs b/OpenRA.Mods.Common/Traits/DockClientManager.cs index 794ad5895f..ca1d17f671 100644 --- a/OpenRA.Mods.Common/Traits/DockClientManager.cs +++ b/OpenRA.Mods.Common/Traits/DockClientManager.cs @@ -160,7 +160,7 @@ namespace OpenRA.Mods.Common.Traits Info.EnterCursor, Info.EnterBlockedCursor, () => requireForceMove, - DockingPossible, + CanQueueDockAt, (target, forceEnter) => CanDockAt(target, forceEnter, true)); } } @@ -194,9 +194,10 @@ namespace OpenRA.Mods.Common.Traits if (order.Target.Type != TargetType.Actor || IsTraitDisabled) return null; - if (order.OrderString == "Dock" && CanDockAt(order.Target.Actor, false, true)) - return Info.Voice; - else if (order.OrderString == "ForceDock" && CanDockAt(order.Target.Actor, true, true)) + if (order.OrderString != "Dock" && order.OrderString != "ForceDock") + return null; + + if (CanQueueDockAt(order.Target.Actor, order.OrderString == "ForceDock", order.Queued)) return Info.Voice; return null; @@ -225,13 +226,13 @@ namespace OpenRA.Mods.Common.Traits } /// Do we have an enabled client with matching . - public bool DockingPossible(BitSet type, bool forceEnter = false) + public bool CanDock(BitSet type, bool forceEnter = false) { return !IsTraitDisabled && dockClients.Any(client => client.CanDock(type, forceEnter)); } /// Does this contain at least one enabled with maching . - public bool DockingPossible(Actor target, bool forceEnter = false) + public bool CanDock(Actor target, bool forceEnter = false) { return !IsTraitDisabled && target.TraitsImplementing() @@ -252,6 +253,14 @@ namespace OpenRA.Mods.Common.Traits host => dockClients.Any(client => client.CanDockAt(target, host, forceEnter, ignoreOccupancy))); } + /// Can we dock to this . + public bool CanQueueDockAt(Actor target, bool forceEnter, bool isQueued) + { + return !IsTraitDisabled + && target.TraitsImplementing() + .Any(host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued))); + } + /// Find the closest viable . /// If is not set, scans all clients. Does not check if is enabled. public TraitPair? ClosestDock(IDockHost ignore, BitSet type = default, bool forceEnter = false, bool ignoreOccupancy = false) @@ -292,11 +301,11 @@ namespace OpenRA.Mods.Common.Traits readonly string enterCursor; readonly string enterBlockedCursor; readonly Func requireForceMove; - readonly Func canTarget; + readonly Func canTarget; readonly Func useEnterCursor; public DockActorTargeter(int priority, string enterCursor, string enterBlockedCursor, - Func requireForceMove, Func canTarget, Func useEnterCursor) + Func requireForceMove, Func canTarget, Func useEnterCursor) { OrderID = "Dock"; OrderPriority = priority; @@ -325,10 +334,13 @@ namespace OpenRA.Mods.Common.Traits if (requireForceMove() && !forceEnter) return false; - if (!canTarget(target.Actor, forceEnter)) + if (!canTarget(target.Actor, forceEnter, IsQueued)) return false; - cursor = useEnterCursor(target.Actor, forceEnter) ? enterCursor : enterBlockedCursor; + cursor = IsQueued || useEnterCursor(target.Actor, forceEnter) + ? enterCursor + : enterBlockedCursor; + return true; } diff --git a/OpenRA.Mods.Common/Traits/Harvester.cs b/OpenRA.Mods.Common/Traits/Harvester.cs index 87b6d09f73..455edc2013 100644 --- a/OpenRA.Mods.Common/Traits/Harvester.cs +++ b/OpenRA.Mods.Common/Traits/Harvester.cs @@ -137,6 +137,12 @@ namespace OpenRA.Mods.Common.Traits && (self.Owner == hostActor.Owner || (ignoreOccupancy && self.Owner.IsAlliedWith(hostActor.Owner))); } + public override bool CanQueueDockAt(Actor hostActor, IDockHost host, bool forceEnter, bool isQueued) + { + return base.CanQueueDockAt(hostActor, host, forceEnter, isQueued) + && self.Owner.IsAlliedWith(hostActor.Owner); + } + void UpdateCondition(Actor self) { if (string.IsNullOrEmpty(Info.EmptyCondition)) diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 74e24f3316..cc766a47b8 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -220,19 +220,26 @@ namespace OpenRA.Mods.Common.Traits bool OnDockTick(Actor self, Actor hostActor, IDockHost dock); void OnDockCompleted(Actor self, Actor hostActor, IDockHost host); - /// Is this client allowed to dock. + /// Are we allowed to dock. /// /// Does not check if is enabled. /// Function should only be called from within or . /// bool CanDock(BitSet type, bool forceEnter = false); - /// Is this client allowed to dock to . + /// Are we allowed to dock to this . /// /// Does not check if is enabled. /// Function should only be called from within or . /// bool CanDockAt(Actor hostActor, IDockHost host, bool forceEnter = false, bool ignoreOccupancy = false); + + /// Are we allowed to give a docking order for this . + /// + /// Does not check if is enabled. + /// Function should only be called from within or . + /// + bool CanQueueDockAt(Actor hostActor, IDockHost host, bool forceEnter, bool isQueued); } public interface IDockHostInfo : ITraitInfoInterface { }