--- /dev/null
+using Content.Shared.Tag;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Trigger.Components.Effects;
+
+/// <summary>
+/// Adds the given tags when triggered.
+/// If TargetUser is true the tags will be added to the user instead.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class AddTagsOnTriggerComponent : BaseXOnTriggerComponent
+{
+ /// <summary>
+ /// The tags to add.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public List<ProtoId<TagPrototype>> Tags = new();
+}
+
--- /dev/null
+using Content.Shared.StatusEffect;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Effects;
+
+/// <summary>
+/// Makes the entity play a jitter animation when triggered.
+/// If TargetUser is true the user will jitter instead.
+/// </summary>
+/// <summary>
+/// The target requires <see cref="StatusEffectsComponent"/>.
+/// TODO: Convert jitter to the new status effects system.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class JitterOnTriggerComponent : BaseXOnTriggerComponent
+{
+ /// <summary>
+ /// Jitteriness of the animation.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public float Amplitude = 10.0f;
+
+ /// <summary>
+ /// Frequency for jittering.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public float Frequency = 4.0f;
+
+ /// <summary>
+ /// For how much time to apply the effect.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public TimeSpan Time = TimeSpan.FromSeconds(2);
+
+ /// <summary>
+ /// The status effect cooldown should be refreshed (true) or accumulated (false).
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool Refresh;
+
+ /// <summary>
+ /// Whether to change any existing jitter value even if they're greater than the ones we're setting.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool ForceValueChange;
+}
+
--- /dev/null
+using Content.Shared.Tag;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Trigger.Components.Effects;
+
+/// <summary>
+/// Remove the given tags when triggered.
+/// If TargetUser is true the tags will be added to the user instead.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class RemoveTagsOnTriggerComponent : BaseXOnTriggerComponent
+{
+ /// <summary>
+ /// The tags to remove.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public List<ProtoId<TagPrototype>> Tags = new();
+}
+
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Effects;
+
+/// <summary>
+/// Swaps the location of the target and the user of the trigger when triggered.
+/// <see cref="BaseXOnTriggerComponent.TargetUser"/> is ignored.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class SwapLocationOnTriggerComponent : BaseXOnTriggerComponent;
--- /dev/null
+using Content.Shared.Jittering;
+using Content.Shared.Trigger.Components.Effects;
+using Robust.Shared.Network;
+
+namespace Content.Shared.Trigger.Systems;
+
+public sealed class JitterOnTriggerSystem : XOnTriggerSystem<JitterOnTriggerComponent>
+{
+ [Dependency] private readonly SharedJitteringSystem _jittering = default!;
+ [Dependency] private readonly INetManager _net = default!;
+
+ protected override void OnTrigger(Entity<JitterOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
+ {
+ // DoJitter mispredicts at the moment.
+ // TODO: Fix this and remove the IsServer check.
+ if (_net.IsServer)
+ _jittering.DoJitter(target, ent.Comp.Time, ent.Comp.Refresh, ent.Comp.Amplitude, ent.Comp.Frequency, ent.Comp.ForceValueChange);
+ args.Handled = true;
+ }
+}
--- /dev/null
+using Content.Shared.Trigger.Components.Effects;
+using Robust.Shared.Network;
+
+namespace Content.Shared.Trigger.Systems;
+
+public sealed class SwapLocationOnTriggerSystem : EntitySystem
+{
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly INetManager _net = default!;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<SwapLocationOnTriggerComponent, TriggerEvent>(OnTrigger);
+ }
+
+ private void OnTrigger(Entity<SwapLocationOnTriggerComponent> ent, ref TriggerEvent args)
+ {
+ if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
+ return;
+
+ if (args.User == null)
+ return;
+
+ // SwapPositions mispredicts at the moment.
+ // TODO: Fix this and remove the IsServer check.
+ if (_net.IsServer)
+ _transform.SwapPositions(ent.Owner, args.User.Value);
+ args.Handled = true;
+ }
+}
--- /dev/null
+using Content.Shared.Tag;
+using Content.Shared.Trigger.Components.Effects;
+
+namespace Content.Shared.Trigger.Systems;
+
+public sealed class AddTagsOnTriggerSystem : XOnTriggerSystem<AddTagsOnTriggerComponent>
+{
+ [Dependency] private readonly TagSystem _tag = default!;
+
+ protected override void OnTrigger(Entity<AddTagsOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
+ {
+ _tag.AddTags(target, ent.Comp.Tags);
+ args.Handled = true;
+ }
+}
+
+public sealed class RemoveTagsOnTriggerSystem : XOnTriggerSystem<RemoveTagsOnTriggerComponent>
+{
+ [Dependency] private readonly TagSystem _tag = default!;
+
+ protected override void OnTrigger(Entity<RemoveTagsOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
+ {
+ _tag.RemoveTags(target, ent.Comp.Tags);
+ args.Handled = true;
+ }
+}