using System.Diagnostics.CodeAnalysis;
using Content.Shared.Hands.Components;
using Content.Shared.Verbs;
using Robust.Shared.Serialization;
namespace Content.Shared.InteractionVerbs;
public sealed partial class InteractionArgs
{
public EntityUid User, Target;
public EntityUid? Used;
public bool CanAccess, CanInteract, HasHands;
///
/// A float value between 0 and positive infinity that indicates how much stronger the user
/// is compared to the target in terms of contests allowed for this verb. 1.0 means no advantage or disadvantage.
///
/// Can be null, which means it's not calculated yet. That can happen before the user attempts to perform the verb.
public float? ContestAdvantage;
///
/// A dictionary for actions and requirements to store data between different execution stages.
/// For instance, an action can cache some data in its CanPerform check and later use it in Perform.
///
///
/// Non-action classes are highly not recommended to write anything to this dictionary - it can easily lead to errors.
///
public Dictionary Blackboard => _blackboardField ??= new(3);
private Dictionary? _blackboardField; // null by default, allocated lazily (only if actually needed)
public InteractionArgs(EntityUid user, EntityUid target, EntityUid? used, bool canAccess, bool canInteract, bool hasHands, float? contestAdvantage)
{
User = user;
Target = target;
Used = used;
CanAccess = canAccess;
CanInteract = canInteract;
HasHands = hasHands;
ContestAdvantage = contestAdvantage;
}
public InteractionArgs(InteractionArgs other) : this(other.User, other.Target, other.Used, other.CanAccess, other.CanInteract, other.HasHands, other.ContestAdvantage) {}
public static InteractionArgs From(GetVerbsEvent ev) where T : Verb => new(ev.User, ev.Target, ev.Using, ev.CanAccess, ev.CanInteract, ev.Hands is not null, null);
///
/// Tries to get a value from the blackboard as an instance of a specific type.
///
public bool TryGetBlackboard(string key, [NotNullWhen(true)] out T? value)
{
value = default;
if (_blackboardField == null || !_blackboardField.TryGetValue(key, out var maybeValue))
return false;
// Cannot use a type check here. If someone fucks up, it's gonna be on them.
value = (T?) maybeValue;
return value != null;
}
}