Allow picking up items in combat mode (#20431)

* Allow picking up items in combat mode

* dont hardcode that
This commit is contained in:
Kara
2023-09-24 12:47:42 -07:00
committed by GitHub
parent 9e1bf43242
commit 657e4d861e
4 changed files with 60 additions and 6 deletions

View File

@@ -262,6 +262,35 @@ namespace Content.Shared.Interaction
return !_tagSystem.HasTag(user, "BypassInteractionRangeChecks");
}
/// <summary>
/// Returns true if the specified entity should hand interact with the target instead of attacking
/// </summary>
/// <param name="user">The user interacting in combat mode</param>
/// <param name="target">The target of the interaction</param>
/// <returns></returns>
public bool CombatModeCanHandInteract(EntityUid user, EntityUid? target)
{
// Always allow attack in these cases
if (target == null || !TryComp<HandsComponent>(user, out var hands) || hands.ActiveHand?.HeldEntity is not null)
return false;
// Only eat input if:
// - Target isn't an item
// - Target doesn't cancel should-interact event
// This is intended to allow items to be picked up in combat mode,
// but to also allow items to force attacks anyway (like mobs which are items, e.g. mice)
if (!HasComp<ItemComponent>(target))
return false;
var combatEv = new CombatModeShouldHandInteractEvent();
RaiseLocalEvent(target.Value, ref combatEv);
if (combatEv.Cancelled)
return false;
return true;
}
/// <summary>
/// Resolves user interactions with objects.
/// </summary>
@@ -285,7 +314,8 @@ namespace Content.Shared.Interaction
// TODO this needs to be handled better. This probably bypasses many complex can-interact checks in weird roundabout ways.
if (_actionBlockerSystem.CanInteract(user, target))
{
UserInteraction(relay.RelayEntity.Value, coordinates, target, altInteract, checkCanInteract, checkAccess, checkCanUse);
UserInteraction(relay.RelayEntity.Value, coordinates, target, altInteract, checkCanInteract,
checkAccess, checkCanUse);
return;
}
}
@@ -293,10 +323,10 @@ namespace Content.Shared.Interaction
if (target != null && Deleted(target.Value))
return;
if (!altInteract && TryComp(user, out CombatModeComponent? combatMode) && combatMode.IsInCombatMode)
if (!altInteract && TryComp<CombatModeComponent>(user, out var combatMode) && combatMode.IsInCombatMode)
{
// Eat the input
return;
if (!CombatModeCanHandInteract(user, target))
return;
}
if (!ValidateInteractAndFace(user, coordinates))
@@ -326,7 +356,7 @@ namespace Content.Shared.Interaction
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
// Does the user have hands?
if (!TryComp(user, out HandsComponent? hands) || hands.ActiveHand == null)
if (!TryComp<HandsComponent>(user, out var hands) || hands.ActiveHand == null)
{
var ev = new InteractNoHandEvent(user, target, coordinates);
RaiseLocalEvent(user, ev);
@@ -341,6 +371,8 @@ namespace Content.Shared.Interaction
}
// empty-hand interactions
// combat mode hand interactions will always be true here -- since
// they check this earlier before returning in
if (hands.ActiveHandEntity is not { } held)
{
if (inRangeUnobstructed && target != null)
@@ -1164,4 +1196,12 @@ namespace Content.Shared.Interaction
AltInteract = altInteract;
}
}
/// <summary>
/// Raised directed by-ref on an item to determine if hand interactions should go through.
/// Defaults to allowing hand interactions to go through. Cancel to force the item to be attacked instead.
/// </summary>
/// <param name="Cancelled">Whether the hand interaction should be cancelled.</param>
[ByRefEvent]
public record struct CombatModeShouldHandInteractEvent(bool Cancelled = false);
}