From aa95373c014ce4c79d8692fb0cc6d82cbebd783a Mon Sep 17 00:00:00 2001 From: Krunklehorn Date: Sun, 21 Jan 2024 23:00:04 -0500 Subject: [PATCH] Prevent willful deconversion --- Content.Server/Implants/ImplanterSystem.cs | 15 +++++-- .../Implants/SharedImplanterSystem.cs | 15 +++++++ .../SharedRevolutionarySystem.cs | 39 +++++++++++++++++++ .../game-presets/preset-revolutionary.ftl | 2 + 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/Content.Server/Implants/ImplanterSystem.cs b/Content.Server/Implants/ImplanterSystem.cs index 0d46241f4146..69f090088959 100644 --- a/Content.Server/Implants/ImplanterSystem.cs +++ b/Content.Server/Implants/ImplanterSystem.cs @@ -48,10 +48,17 @@ private void OnImplanterAfterInteract(EntityUid uid, ImplanterComponent componen if (implant == null) return; - // show popup to the user saying implant failed - var name = Identity.Name(target, EntityManager, args.User); - var msg = Loc.GetString("implanter-component-implant-failed", ("implant", implant), ("target", name)); - _popup.PopupEntity(msg, target, args.User); + // optionally, show popup to explain why the implant failed + var ev = new PopupAfterFailedImplantEvent(args.User, target, implant.Value); + RaiseLocalEvent(target, ev); + if (!ev.Handled) + { + // show generic popup saying the implant failed + var name = Identity.Name(target, EntityManager, args.User); + var msg = Loc.GetString("implanter-component-implant-failed", ("implant", implant), ("target", name)); + _popup.PopupEntity(msg, target, args.User); + } + // prevent further interaction since popup was shown args.Handled = true; return; diff --git a/Content.Shared/Implants/SharedImplanterSystem.cs b/Content.Shared/Implants/SharedImplanterSystem.cs index 36a31bac1d28..313fab6aae13 100644 --- a/Content.Shared/Implants/SharedImplanterSystem.cs +++ b/Content.Shared/Implants/SharedImplanterSystem.cs @@ -225,3 +225,18 @@ public AddImplantAttemptEvent(EntityUid user, EntityUid target, EntityUid implan Implanter = implanter; } } + +public sealed class PopupAfterFailedImplantEvent : CancellableEntityEventArgs +{ + public readonly EntityUid User; + public readonly EntityUid Target; + public readonly EntityUid Implant; + public bool Handled = false; + + public PopupAfterFailedImplantEvent(EntityUid user, EntityUid target, EntityUid implant) + { + User = user; + Target = target; + Implant = implant; + } +} diff --git a/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs b/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs index 1399b116e0f6..6f8b8f7b81e8 100644 --- a/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs +++ b/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs @@ -1,8 +1,10 @@ using Content.Shared.IdentityManagement; +using Content.Shared.Implants; using Content.Shared.Mindshield.Components; using Content.Shared.Popups; using Content.Shared.Revolutionary.Components; using Content.Shared.Stunnable; +using Content.Shared.Tag; namespace Content.Shared.Revolutionary; @@ -10,13 +12,50 @@ public sealed class SharedRevolutionarySystem : EntitySystem { [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedStunSystem _sharedStun = default!; + [Dependency] private readonly TagSystem _tag = default!; + + [ValidatePrototypeId] + public const string MindShieldTag = "MindShield"; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(PreventSelfDeconvert); + SubscribeLocalEvent(InformTargetWasSelf); SubscribeLocalEvent(MindShieldImplanted); } + /// + /// Prevents Revs from attempting to implant themselves with a mindshield. + /// + public void PreventSelfDeconvert(EntityUid uid, RevolutionaryComponent comp, ref AddImplantAttemptEvent ev) + { + if (IsMindshieldTargetSelf(ev.User, ev.Target, ev.Implant)) + { + ev.Cancel(); + } + } + + /// + /// Informs the Rev why the implant failed. + /// + public void InformTargetWasSelf(EntityUid uid, RevolutionaryComponent comp, ref PopupAfterFailedImplantEvent ev) + { + if (IsMindshieldTargetSelf(ev.User, ev.Target, ev.Implant)) + { + _popupSystem.PopupEntity(Loc.GetString("rev-fail-self-mindshield"), ev.User); + ev.Handled = true; + } + } + + /// + /// Checks if a Rev is attempting to implant themselves with a mindshield. + /// + public bool IsMindshieldTargetSelf(EntityUid user, EntityUid target, EntityUid implant) + { + return _tag.HasTag(implant, MindShieldTag) && HasComp(user) && !HasComp(user) && user == target; + } + /// /// When the mindshield is implanted in the rev it will popup saying they were deconverted. In Head Revs it will remove the mindshield component. /// diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl index 5fb1d40b3d37..e374f0d9a72a 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl @@ -31,6 +31,8 @@ rev-role-greeting = rev-briefing = Help your head revolutionaries kill every head to take over the station. +rev-fail-self-mindshield = You cannot bring yourself to betray the revolution! + ## General rev-title = Revolutionaries