From 31ade640d0c6898ec05391d16a746c449404b76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=81da?= Date: Thu, 13 Nov 2025 17:56:17 -0600 Subject: [PATCH] RandomTriggerOnTriggerComponent (#41422) * commit * rename * prevent recusion --------- Co-authored-by: iaada --- .../RandomTriggerOnTriggerComponent.cs | 21 ++++++++++ .../Systems/RandomTriggerOnTriggerSystem.cs | 38 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Content.Shared/Trigger/Components/Effects/RandomTriggerOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Systems/RandomTriggerOnTriggerSystem.cs diff --git a/Content.Shared/Trigger/Components/Effects/RandomTriggerOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/RandomTriggerOnTriggerComponent.cs new file mode 100644 index 0000000000..f7d8c5036c --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/RandomTriggerOnTriggerComponent.cs @@ -0,0 +1,21 @@ +using Content.Shared.Random; +using Content.Shared.Trigger.Components.Triggers; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// When triggered this component will choose a key and send a new trigger. +/// Trigger is sent to user if is true. +/// +/// Does not support recursive loops where this component triggers itself. Use instead. +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RandomTriggerOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The trigger keys and their weights. + /// + [DataField(required: true), AutoNetworkedField] + public ProtoId RandomKeyOut; +} diff --git a/Content.Shared/Trigger/Systems/RandomTriggerOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/RandomTriggerOnTriggerSystem.cs new file mode 100644 index 0000000000..75acc005d0 --- /dev/null +++ b/Content.Shared/Trigger/Systems/RandomTriggerOnTriggerSystem.cs @@ -0,0 +1,38 @@ +using Content.Shared.Random.Helpers; +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Shared.Trigger.Systems; + +public sealed class RandomTriggerOnTriggerSystem : XOnTriggerSystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + protected override void OnTrigger(Entity ent, EntityUid target, ref TriggerEvent args) + { + // TODO: Replace with RandomPredicted once the engine PR is merged + var hash = new List + { + (int)_timing.CurTick.Value, + GetNetEntity(ent).Id, + args.User == null ? 0 : GetNetEntity(args.User.Value).Id, + }; + var seed = SharedRandomExtensions.HashCodeCombine(hash); + var rand = new System.Random(seed); + + var keyOut = _prototypeManager.Index(ent.Comp.RandomKeyOut).Pick(rand); + + // Prevent recursive triggers + if (target == ent.Owner && ent.Comp.KeysIn.Contains(keyOut)) + { + Log.Warning($"{ToPrettyString(ent)} attempted to recursively trigger itself using RandomTriggerOnTriggerComponent."); + return; + } + + _trigger.Trigger(target, args.User, keyOut); + args.Handled = true; + } +}