From 21460c86b08d0234aacf176d21b2147b85392755 Mon Sep 17 00:00:00 2001
From: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Date: Sat, 11 Oct 2025 00:27:14 +0200
Subject: [PATCH] Mindrole trigger condition (#40323)
* mind role trigger condition
* fix
* nits
---------
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
---
Content.Shared/Roles/SharedRoleSystem.cs | 3 +-
.../MindRoleTriggerConditionComponent.cs | 27 +++++++
.../WhitelistTriggerConditionComponent.cs | 6 +-
.../Systems/TriggerSystem.Condition.cs | 79 ++++++++++++++-----
.../Trigger/Systems/TriggerSystem.cs | 4 +
5 files changed, 93 insertions(+), 26 deletions(-)
create mode 100644 Content.Shared/Trigger/Components/Conditions/MindRoleTriggerConditionComponent.cs
diff --git a/Content.Shared/Roles/SharedRoleSystem.cs b/Content.Shared/Roles/SharedRoleSystem.cs
index eeab329661..e85d4d86d8 100644
--- a/Content.Shared/Roles/SharedRoleSystem.cs
+++ b/Content.Shared/Roles/SharedRoleSystem.cs
@@ -23,7 +23,6 @@ public abstract class SharedRoleSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] protected readonly ISharedPlayerManager Player = default!;
- [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly SharedMindSystem _minds = default!;
[Dependency] private readonly IPrototypeManager _prototypes = default!;
@@ -400,7 +399,7 @@ public abstract class SharedRoleSystem : EntitySystem
foreach (var role in delete)
{
- _entityManager.DeleteEntity(role);
+ PredictedDel(role);
}
var update = MindRolesUpdate(mind);
diff --git a/Content.Shared/Trigger/Components/Conditions/MindRoleTriggerConditionComponent.cs b/Content.Shared/Trigger/Components/Conditions/MindRoleTriggerConditionComponent.cs
new file mode 100644
index 0000000000..32fb4d7d29
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Conditions/MindRoleTriggerConditionComponent.cs
@@ -0,0 +1,27 @@
+using Content.Shared.Whitelist;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Conditions;
+
+///
+/// Checks if a triggered entity or the user of a trigger has a certain mindrole.
+/// Cancels the trigger otherwise.
+///
+///
+/// Mind roles are only networked to their owner! So if you use this on any other entity than yourself it won't be predicted.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class MindRoleTriggerConditionComponent : BaseTriggerConditionComponent
+{
+ ///
+ /// Whitelist for what mind role components on the owning entity allow this trigger.
+ ///
+ [DataField, AutoNetworkedField]
+ public EntityWhitelist? EntityWhitelist;
+
+ ///
+ /// Whitelist for what mind role components on the User allow this trigger.
+ ///
+ [DataField, AutoNetworkedField]
+ public EntityWhitelist? UserWhitelist;
+}
diff --git a/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs b/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs
index a2779f79c6..7ec6188ee3 100644
--- a/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs
+++ b/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs
@@ -4,20 +4,20 @@ using Robust.Shared.GameStates;
namespace Content.Shared.Trigger.Components.Conditions;
///
-/// Checks if the user of a trigger satisfies a whitelist and blacklist condition for the triggered entity or the one triggering it.
+/// Checks if the user of a trigger satisfies a whitelist and blacklist condition.
/// Cancels the trigger otherwise.
///
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class WhitelistTriggerConditionComponent : BaseTriggerConditionComponent
{
///
- /// Whitelist for what entites can cause this trigger.
+ /// Whitelist for what entities can cause this trigger.
///
[DataField, AutoNetworkedField]
public EntityWhitelist? UserWhitelist;
///
- /// Blacklist for what entites can cause this trigger.
+ /// Blacklist for what entities can cause this trigger.
///
[DataField, AutoNetworkedField]
public EntityWhitelist? UserBlacklist;
diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs
index 2d0756556a..b039c8e9de 100644
--- a/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs
+++ b/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs
@@ -10,31 +10,36 @@ public sealed partial class TriggerSystem
private void InitializeCondition()
{
SubscribeLocalEvent(OnWhitelistTriggerAttempt);
-
SubscribeLocalEvent(OnUseDelayTriggerAttempt);
-
SubscribeLocalEvent(OnToggleTriggerAttempt);
- SubscribeLocalEvent>(OnToggleGetAltVerbs);
-
SubscribeLocalEvent(OnRandomChanceTriggerAttempt);
+ SubscribeLocalEvent(OnMindRoleTriggerAttempt);
+
+ SubscribeLocalEvent>(OnToggleGetAltVerbs);
}
private void OnWhitelistTriggerAttempt(Entity ent, ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
- args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist);
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist);
}
private void OnUseDelayTriggerAttempt(Entity ent, ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
- args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId);
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId);
}
private void OnToggleTriggerAttempt(Entity ent, ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
- args.Cancelled |= !ent.Comp.Enabled;
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ args.Cancelled |= !ent.Comp.Enabled;
}
private void OnToggleGetAltVerbs(Entity ent, ref GetVerbsEvent args)
@@ -62,19 +67,51 @@ public sealed partial class TriggerSystem
private void OnRandomChanceTriggerAttempt(Entity ent,
ref AttemptTriggerEvent args)
{
- if (args.Key == null || ent.Comp.Keys.Contains(args.Key))
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ // 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);
+
+ args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
+ }
+ private void OnMindRoleTriggerAttempt(Entity ent, ref AttemptTriggerEvent args)
+ {
+ if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
+ return;
+
+ if (ent.Comp.EntityWhitelist != null)
{
- // TODO: Replace with RandomPredicted once the engine PR is merged
- var hash = new List
+ if (!_mind.TryGetMind(ent.Owner, out var entMindId, out var entMindComp))
+ {
+ args.Cancelled = true; // the entity has no mind
+ return;
+ }
+ if (!_role.MindHasRole((entMindId, entMindComp), ent.Comp.EntityWhitelist))
+ {
+ args.Cancelled = true; // the entity does not have the required role
+ return;
+ }
+ }
+
+ if (ent.Comp.UserWhitelist != null)
+ {
+ if (args.User == null || !_mind.TryGetMind(args.User.Value, out var userMindId, out var userMindComp))
+ {
+ args.Cancelled = true; // no user or the user has no mind
+ return;
+ }
+ if (!_role.MindHasRole((userMindId, userMindComp), ent.Comp.UserWhitelist))
{
- (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);
-
- args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
+ args.Cancelled = true; // the user does not have the required role
+ }
}
}
}
diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.cs b/Content.Shared/Trigger/Systems/TriggerSystem.cs
index 25f8d51e11..a5fb509eed 100644
--- a/Content.Shared/Trigger/Systems/TriggerSystem.cs
+++ b/Content.Shared/Trigger/Systems/TriggerSystem.cs
@@ -3,7 +3,9 @@ using Content.Shared.Database;
using Content.Shared.DeviceLinking;
using Content.Shared.EntityTable;
using Content.Shared.Item.ItemToggle;
+using Content.Shared.Mind;
using Content.Shared.Popups;
+using Content.Shared.Roles;
using Content.Shared.Timing;
using Content.Shared.Trigger.Components;
using Content.Shared.Whitelist;
@@ -39,6 +41,8 @@ public sealed partial class TriggerSystem : EntitySystem
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly ItemToggleSystem _itemToggle = default!;
[Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!;
+ [Dependency] private readonly SharedRoleSystem _role = default!;
+ [Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly EntityTableSystem _entityTable = default!;
public const string DefaultTriggerKey = "trigger";
--
2.51.2