using Content.Server.Atmos.EntitySystems;
+using Content.Shared.Atmos.Components;
using Content.Shared.Trigger;
using Content.Shared.Trigger.Components.Effects;
if (target == null)
return;
- _flame.AdjustFireStacks(target.Value, ent.Comp.FireStacks, ignite: ent.Comp.DoIgnite);
+ if (!TryComp<FlammableComponent>(target.Value, out var flammable))
+ return;
+
+ _flame.AdjustFireStacks(target.Value, ent.Comp.FireStacks, ignite: ent.Comp.DoIgnite, flammable: flammable);
args.Handled = true;
}
if (target == null)
return;
- _flame.Extinguish(target.Value);
+ if (!TryComp<FlammableComponent>(target.Value, out var flammable))
+ return;
+
+ _flame.Extinguish(target.Value, flammable: flammable);
args.Handled = true;
}
using JetBrains.Annotations;
-using Robust.Shared.Map;
-namespace Content.Shared.Interaction
+namespace Content.Shared.Interaction;
+
+public sealed class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs
{
- public sealed class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs
+ public InteractHandEventArgs(EntityUid user, EntityUid target)
{
- public InteractHandEventArgs(EntityUid user, EntityUid target)
- {
- User = user;
- Target = target;
- }
-
- public EntityUid User { get; }
- public EntityUid Target { get; }
+ User = user;
+ Target = target;
}
+ public EntityUid User { get; }
+ public EntityUid Target { get; }
+}
+
+/// <summary>
+/// Raised directed on a target entity when it is interacted with by a user with an empty hand.
+/// </summary>
+[PublicAPI]
+public sealed class InteractHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs
+{
+ /// <summary>
+ /// Entity that triggered the interaction.
+ /// </summary>
+ public EntityUid User { get; }
+
/// <summary>
- /// Raised directed on a target entity when it is interacted with by a user with an empty hand.
+ /// Entity that was interacted on.
/// </summary>
- [PublicAPI]
- public sealed class InteractHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs
+ public EntityUid Target { get; }
+
+ public InteractHandEvent(EntityUid user, EntityUid target)
{
- /// <summary>
- /// Entity that triggered the interaction.
- /// </summary>
- public EntityUid User { get; }
-
- /// <summary>
- /// Entity that was interacted on.
- /// </summary>
- public EntityUid Target { get; }
-
- public InteractHandEvent(EntityUid user, EntityUid target)
- {
- User = user;
- Target = target;
- }
+ User = user;
+ Target = target;
}
+}
+/// <summary>
+/// Raised directed on the user when they interact with an entity with an empty hand.
+/// </summary>
+[PublicAPI]
+public sealed class UserInteractHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs
+{
/// <summary>
- /// Raised on the user before interacting on an entity with bare hand.
- /// Interaction is cancelled if this event is handled, so set it to true if you do custom interaction logic.
+ /// Entity that triggered the interaction.
/// </summary>
- public sealed class BeforeInteractHandEvent : HandledEntityEventArgs
+ public EntityUid User { get; }
+
+ /// <summary>
+ /// Entity that was interacted on.
+ /// </summary>
+ public EntityUid Target { get; }
+
+ public UserInteractHandEvent(EntityUid user, EntityUid target)
{
- public EntityUid Target { get; }
+ User = user;
+ Target = target;
+ }
+}
+
+/// <summary>
+/// Raised on the user before interacting on an entity with bare hand.
+/// Interaction is cancelled if this event is handled, so set it to true if you do custom interaction logic.
+/// </summary>
+public sealed class BeforeInteractHandEvent : HandledEntityEventArgs
+{
+ public EntityUid Target { get; }
- public BeforeInteractHandEvent(EntityUid target)
- {
- Target = target;
- }
+ public BeforeInteractHandEvent(EntityUid target)
+ {
+ Target = target;
}
}
using Robust.Shared.Map;
using Robust.Shared.Utility;
-namespace Content.Shared.Interaction
+namespace Content.Shared.Interaction;
+
+/// <summary>
+/// Raised when a target entity is interacted with by a user while holding an object in their hand.
+/// </summary>
+[PublicAPI]
+public sealed class InteractUsingEvent : HandledEntityEventArgs
{
/// <summary>
- /// Raised when a target entity is interacted with by a user while holding an object in their hand.
+ /// Entity that triggered the interaction.
+ /// </summary>
+ public EntityUid User { get; }
+
+ /// <summary>
+ /// Entity that the user used to interact.
+ /// </summary>
+ public EntityUid Used { get; }
+
+ /// <summary>
+ /// Entity that was interacted on.
+ /// </summary>
+ public EntityUid Target { get; }
+
+ /// <summary>
+ /// The original location that was clicked by the user.
/// </summary>
- [PublicAPI]
- public sealed class InteractUsingEvent : HandledEntityEventArgs
+ public EntityCoordinates ClickLocation { get; }
+
+ public InteractUsingEvent(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation)
{
- /// <summary>
- /// Entity that triggered the interaction.
- /// </summary>
- public EntityUid User { get; }
-
- /// <summary>
- /// Entity that the user used to interact.
- /// </summary>
- public EntityUid Used { get; }
-
- /// <summary>
- /// Entity that was interacted on.
- /// </summary>
- public EntityUid Target { get; }
-
- /// <summary>
- /// The original location that was clicked by the user.
- /// </summary>
- public EntityCoordinates ClickLocation { get; }
-
- public InteractUsingEvent(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation)
- {
- // Interact using should not have the same used and target.
- // That should be a use-in-hand event instead.
- // If this is not the case, can lead to bugs (e.g., attempting to merge a item stack into itself).
- DebugTools.Assert(used != target);
-
- User = user;
- Used = used;
- Target = target;
- ClickLocation = clickLocation;
- }
+ // Interact using should not have the same used and target.
+ // That should be a use-in-hand event instead.
+ // If this is not the case, can lead to bugs (e.g., attempting to merge a item stack into itself).
+ DebugTools.Assert(used != target);
+
+ User = user;
+ Used = used;
+ Target = target;
+ ClickLocation = clickLocation;
}
}
+
+/// <summary>
+/// Raised when a user entity interacts with a target while holding an object in their hand.
+/// </summary>
+[PublicAPI]
+public sealed class UserInteractUsingEvent : HandledEntityEventArgs
+{
+ /// <summary>
+ /// Entity that triggered the interaction.
+ /// </summary>
+ public EntityUid User { get; }
+
+ /// <summary>
+ /// Entity that the user used to interact.
+ /// </summary>
+ public EntityUid Used { get; }
+
+ /// <summary>
+ /// Entity that was interacted on.
+ /// </summary>
+ public EntityUid Target { get; }
+
+ /// <summary>
+ /// The original location that was clicked by the user.
+ /// </summary>
+ public EntityCoordinates ClickLocation { get; }
+
+ public UserInteractUsingEvent(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation)
+ {
+ // Interact using should not have the same used and target.
+ // That should be a use-in-hand event instead.
+ // If this is not the case, can lead to bugs (e.g., attempting to merge a item stack into itself).
+ DebugTools.Assert(used != target);
+
+ User = user;
+ Used = used;
+ Target = target;
+ ClickLocation = clickLocation;
+ }
+}
+
}
DebugTools.Assert(!IsDeleted(user) && !IsDeleted(target));
+
// all interactions should only happen when in range / unobstructed, so no range check is needed
var message = new InteractHandEvent(user, target);
RaiseLocalEvent(target, message, true);
+ var userMessage = new UserInteractHandEvent(user, target);
+ RaiseLocalEvent(user, userMessage, true);
+
_adminLogger.Add(LogType.InteractHand, LogImpact.Low, $"{user} interacted with {target}");
DoContactInteraction(user, target, message);
- if (message.Handled)
+ if (message.Handled || userMessage.Handled)
return;
DebugTools.Assert(!IsDeleted(user) && !IsDeleted(target));
// all interactions should only happen when in range / unobstructed, so no range check is needed
var interactUsingEvent = new InteractUsingEvent(user, used, target, clickLocation);
RaiseLocalEvent(target, interactUsingEvent, true);
+
+ var userInteractUsingEvent = new UserInteractUsingEvent(user, used, target, clickLocation);
+ RaiseLocalEvent(user, userInteractUsingEvent, true);
+
DoContactInteraction(user, used, interactUsingEvent);
DoContactInteraction(user, target, interactUsingEvent);
// Contact interactions are currently only used for forensics, so we don't raise used -> target
- if (interactUsingEvent.Handled)
+ if (interactUsingEvent.Handled || userInteractUsingEvent.Handled)
return true;
if (InteractDoAfter(user, used, target, clickLocation, canReach: true, checkDeletion: false))
--- /dev/null
+using Content.Shared.Interaction;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+/// <summary>
+/// Trigger on <see cref="UserInteractHandEvent"/>, aka when owner clicks on an entity with an empty hand.
+/// The trigger user is the entity that got interacted with.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnUserInteractHandComponent : BaseTriggerOnXComponent
+{
+ /// <summary>
+ /// Whether the interaction should be marked as handled after it happens.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool Handle = true;
+}
--- /dev/null
+using Content.Shared.Interaction;
+using Content.Shared.Whitelist;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+/// <summary>
+/// Triggers when the owner uses another entity to interact with another entity (<see cref="UserInteractUsingEvent"/>).
+/// The trigger user is the interacted entity or the item used, depending on the TargetUsed datafield.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnUserInteractUsingComponent : BaseTriggerOnXComponent
+{
+ /// <summary>
+ /// Whitelist of entities that can be used to trigger this component.
+ /// </summary>
+ /// <remarks>No whitelist check when null.</remarks>
+ [DataField, AutoNetworkedField]
+ public EntityWhitelist? Whitelist;
+
+ /// <summary>
+ /// Blacklist of entities that cannot be used to trigger this component.
+ /// </summary>
+ /// <remarks>No blacklist check when null.</remarks>
+ [DataField, AutoNetworkedField]
+ public EntityWhitelist? Blacklist;
+
+ /// <summary>
+ /// If false, the trigger user will be the entity that got interacted with.
+ /// If true, the trigger user will the entity that was used to interact.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool TargetUsed = false;
+
+ /// <summary>
+ /// Whether the interaction should be marked as handled after it happens.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool Handle = true;
+}
SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<TriggerOnUseComponent, UseInHandEvent>(OnUse);
SubscribeLocalEvent<TriggerOnInteractHandComponent, InteractHandEvent>(OnInteractHand);
+ SubscribeLocalEvent<TriggerOnUserInteractHandComponent, UserInteractHandEvent>(OnUserInteractHand);
SubscribeLocalEvent<TriggerOnInteractUsingComponent, InteractUsingEvent>(OnInteractUsing);
+ SubscribeLocalEvent<TriggerOnUserInteractUsingComponent, UserInteractUsingEvent>(OnUserInteractUsing);
SubscribeLocalEvent<TriggerOnThrowComponent, ThrowEvent>(OnThrow);
SubscribeLocalEvent<TriggerOnThrownComponent, ThrownEvent>(OnThrown);
args.Handled = true;
}
+ private void OnUserInteractHand(Entity<TriggerOnUserInteractHandComponent> ent, ref UserInteractHandEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ Trigger(ent.Owner, args.Target, ent.Comp.KeyOut);
+
+ if (ent.Comp.Handle)
+ args.Handled = true;
+ }
+
private void OnInteractUsing(Entity<TriggerOnInteractUsingComponent> ent, ref InteractUsingEvent args)
{
if (args.Handled)
args.Handled = true;
}
+ private void OnUserInteractUsing(Entity<TriggerOnUserInteractUsingComponent> ent, ref UserInteractUsingEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ if (!_whitelist.CheckBoth(args.Used, ent.Comp.Blacklist, ent.Comp.Whitelist))
+ return;
+
+ Trigger(ent.Owner, ent.Comp.TargetUsed ? args.Used : args.Target, ent.Comp.KeyOut);
+
+ if (ent.Comp.Handle)
+ args.Handled = true;
+ }
+
private void OnThrow(Entity<TriggerOnThrowComponent> ent, ref ThrowEvent args)
{
Trigger(ent.Owner, args.Thrown, ent.Comp.KeyOut);