DockClientManager: enter cursor per DockHost's DockType
This commit is contained in:
committed by
Gustas Kažukauskas
parent
56c615d890
commit
5537a194fa
@@ -14,6 +14,7 @@ using System.Linq;
|
|||||||
using OpenRA.Mods.Common.Activities;
|
using OpenRA.Mods.Common.Activities;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
using static OpenRA.Mods.Common.Traits.DockActorTargeter;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
@@ -66,12 +67,18 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new DockActorTargeter(
|
yield return new DockActorTargeter(
|
||||||
6,
|
priority: 6,
|
||||||
Info.EnterCursor,
|
context =>
|
||||||
Info.EnterBlockedCursor,
|
{
|
||||||
() => Info.RequiresForceMove,
|
if (Info.RequiresForceMove && !context.ForceEnter)
|
||||||
CanQueueDockAt,
|
return CanTargetResult.Blocked(Info.EnterCursor);
|
||||||
CanDockAt);
|
|
||||||
|
if (!CanQueueDockAt(context.Target.Actor, context.ForceEnter, context.IsQueued))
|
||||||
|
return CanTargetResult.Blocked(Info.EnterCursor);
|
||||||
|
|
||||||
|
var cursor = context.IsQueued || CanDockAt(context.Target.Actor, context.ForceEnter) ? Info.EnterCursor : Info.EnterBlockedCursor;
|
||||||
|
return CanTargetResult.Allowed(cursor);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using OpenRA.Mods.Common.Activities;
|
|||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
using static OpenRA.Mods.Common.Traits.DockActorTargeter;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
@@ -33,9 +34,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public readonly BooleanExpression RequireForceMoveCondition = null;
|
public readonly BooleanExpression RequireForceMoveCondition = null;
|
||||||
|
|
||||||
[CursorReference]
|
[CursorReference]
|
||||||
[Desc("Cursor to display when able to dock at target actor.")]
|
[Desc($"Default cursor to display when able to dock at target actor. Can be overriden using {nameof(EnterCursorOverrides)}.")]
|
||||||
public readonly string EnterCursor = "enter";
|
public readonly string EnterCursor = "enter";
|
||||||
|
|
||||||
|
[CursorReference(dictionaryReference: LintDictionaryReference.Values)]
|
||||||
|
[Desc($"Cursor to display when able to dock at target actor. Overrides the default cursor specified in {nameof(EnterCursor)}",
|
||||||
|
"A dictionary of [DockType]: [cursor name].")]
|
||||||
|
public readonly Dictionary<string, string> EnterCursorOverrides = [];
|
||||||
|
|
||||||
[CursorReference]
|
[CursorReference]
|
||||||
[Desc("Cursor to display when unable to dock at target actor.")]
|
[Desc("Cursor to display when unable to dock at target actor.")]
|
||||||
public readonly string EnterBlockedCursor = "enter-blocked";
|
public readonly string EnterBlockedCursor = "enter-blocked";
|
||||||
@@ -155,13 +161,38 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new DockActorTargeter(
|
yield return new DockActorTargeter(6,
|
||||||
6,
|
context =>
|
||||||
Info.EnterCursor,
|
{
|
||||||
Info.EnterBlockedCursor,
|
if (requireForceMove && !context.ForceEnter)
|
||||||
() => requireForceMove,
|
return CanTargetResult.Blocked(Info.EnterCursor);
|
||||||
CanQueueDockAt,
|
|
||||||
(target, forceEnter) => CanDockAt(target, forceEnter, true));
|
if (IsTraitDisabled)
|
||||||
|
return CanTargetResult.Blocked(Info.EnterBlockedCursor);
|
||||||
|
|
||||||
|
var availableDockHosts = GetDockableHosts(context.Target.Actor, context.ForceEnter, context.IsQueued).ToList();
|
||||||
|
if (availableDockHosts.Count == 0)
|
||||||
|
return CanTargetResult.Blocked(Info.EnterCursor);
|
||||||
|
|
||||||
|
var canDock = availableDockHosts.Any(
|
||||||
|
host => dockClients.Any(client => client.CanDockAt(context.Target.Actor, host, context.ForceEnter, true)));
|
||||||
|
|
||||||
|
var cursor = context.IsQueued || canDock
|
||||||
|
? GetCursorOverride(availableDockHosts) ?? Info.EnterCursor
|
||||||
|
: Info.EnterBlockedCursor;
|
||||||
|
|
||||||
|
return CanTargetResult.Allowed(cursor);
|
||||||
|
|
||||||
|
string GetCursorOverride(IEnumerable<IDockHost> dockHosts)
|
||||||
|
{
|
||||||
|
foreach (var dockHost in dockHosts)
|
||||||
|
foreach (var dockType in dockHost.GetDockType)
|
||||||
|
if (Info.EnterCursorOverrides.TryGetValue(dockType, out var cursor))
|
||||||
|
return cursor;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +292,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
.Any(host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued)));
|
.Any(host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerable<IDockHost> GetDockableHosts(Actor target, bool forceEnter, bool isQueued)
|
||||||
|
{
|
||||||
|
return target.TraitsImplementing<IDockHost>()
|
||||||
|
.Where(host => dockClients.Any(client => client.CanQueueDockAt(target, host, forceEnter, isQueued)));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Find the closest viable <see cref="IDockHost"/>.</summary>
|
/// <summary>Find the closest viable <see cref="IDockHost"/>.</summary>
|
||||||
/// <remarks>If <paramref name="type"/> is not set, scans all clients. Does not check if <see cref="DockClientManager"/> is enabled.</remarks>
|
/// <remarks>If <paramref name="type"/> is not set, scans all clients. Does not check if <see cref="DockClientManager"/> is enabled.</remarks>
|
||||||
public TraitPair<IDockHost>? ClosestDock(IDockHost ignore, BitSet<DockType> type = default, bool forceEnter = false, bool ignoreOccupancy = false)
|
public TraitPair<IDockHost>? ClosestDock(IDockHost ignore, BitSet<DockType> type = default, bool forceEnter = false, bool ignoreOccupancy = false)
|
||||||
@@ -298,22 +335,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public class DockActorTargeter : IOrderTargeter
|
public class DockActorTargeter : IOrderTargeter
|
||||||
{
|
{
|
||||||
readonly string enterCursor;
|
readonly Func<CanTargetContext, CanTargetResult> canTarget;
|
||||||
readonly string enterBlockedCursor;
|
|
||||||
readonly Func<bool> requireForceMove;
|
|
||||||
readonly Func<Actor, bool, bool, bool> canTarget;
|
|
||||||
readonly Func<Actor, bool, bool> useEnterCursor;
|
|
||||||
|
|
||||||
public DockActorTargeter(int priority, string enterCursor, string enterBlockedCursor,
|
public DockActorTargeter(int priority, Func<CanTargetContext, CanTargetResult> canTarget)
|
||||||
Func<bool> requireForceMove, Func<Actor, bool, bool, bool> canTarget, Func<Actor, bool, bool> useEnterCursor)
|
|
||||||
{
|
{
|
||||||
OrderID = "Dock";
|
OrderID = "Dock";
|
||||||
OrderPriority = priority;
|
OrderPriority = priority;
|
||||||
this.enterCursor = enterCursor;
|
|
||||||
this.enterBlockedCursor = enterBlockedCursor;
|
|
||||||
this.requireForceMove = requireForceMove;
|
|
||||||
this.canTarget = canTarget;
|
this.canTarget = canTarget;
|
||||||
this.useEnterCursor = useEnterCursor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string OrderID { get; private set; }
|
public string OrderID { get; private set; }
|
||||||
@@ -326,25 +354,43 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (target.Type != TargetType.Actor)
|
if (target.Type != TargetType.Actor)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cursor = enterCursor;
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
var forceEnter = modifiers.HasModifier(TargetModifiers.ForceMove);
|
var forceEnter = modifiers.HasModifier(TargetModifiers.ForceMove);
|
||||||
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
OrderID = forceEnter ? "ForceDock" : "Dock";
|
OrderID = forceEnter ? "ForceDock" : "Dock";
|
||||||
|
|
||||||
if (requireForceMove() && !forceEnter)
|
var context = new CanTargetContext { Target = target, IsQueued = IsQueued, ForceEnter = forceEnter };
|
||||||
return false;
|
var result = canTarget(context);
|
||||||
|
cursor = result.Cursor;
|
||||||
if (!canTarget(target.Actor, forceEnter, IsQueued))
|
return result.CanTarget;
|
||||||
return false;
|
|
||||||
|
|
||||||
cursor = IsQueued || useEnterCursor(target.Actor, forceEnter)
|
|
||||||
? enterCursor
|
|
||||||
: enterBlockedCursor;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool IsQueued { get; protected set; }
|
public virtual bool IsQueued { get; protected set; }
|
||||||
|
|
||||||
|
public readonly record struct CanTargetContext
|
||||||
|
{
|
||||||
|
public required Target Target { get; init; }
|
||||||
|
|
||||||
|
public bool ForceEnter { get; init; }
|
||||||
|
|
||||||
|
public bool IsQueued { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly record struct CanTargetResult
|
||||||
|
{
|
||||||
|
public string Cursor { get; init; }
|
||||||
|
|
||||||
|
public bool CanTarget { get; init; }
|
||||||
|
|
||||||
|
public static CanTargetResult Blocked(string cursor = null)
|
||||||
|
{
|
||||||
|
return new() { CanTarget = false, Cursor = cursor };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CanTargetResult Allowed(string cursor)
|
||||||
|
{
|
||||||
|
return new() { CanTarget = true, Cursor = cursor };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DockExts
|
public static class DockExts
|
||||||
|
|||||||
Reference in New Issue
Block a user