disallow unanchoring or opening panels on locked emitters/APEs (#26600)
* disallow unanchoring or opening panels on locked emitters/APEs * no locking open panels * oops * needback feedback * Update Content.Shared/Lock/LockSystem.cs * Update Content.Shared/Lock/LockSystem.cs * Update Content.Shared/Lock/LockSystem.cs * sanity --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -163,10 +163,13 @@ namespace Content.Client.Popups
|
||||
PopupEntity(message, uid, type);
|
||||
}
|
||||
|
||||
public override void PopupClient(string? message, EntityUid uid, EntityUid recipient, PopupType type = PopupType.Small)
|
||||
public override void PopupClient(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
|
||||
{
|
||||
if (recipient == null)
|
||||
return;
|
||||
|
||||
if (_timing.IsFirstTimePredicted)
|
||||
PopupEntity(message, uid, recipient, type);
|
||||
PopupEntity(message, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
public override void PopupEntity(string? message, EntityUid uid, PopupType type = PopupType.Small)
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Content.Server.Popups
|
||||
RaiseNetworkEvent(new PopupEntityEvent(message, type, GetNetEntity(uid)), actor.PlayerSession);
|
||||
}
|
||||
|
||||
public override void PopupClient(string? message, EntityUid uid, EntityUid recipient, PopupType type = PopupType.Small)
|
||||
public override void PopupClient(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
|
||||
{
|
||||
// do nothing duh its for client only
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Construction.Components;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Examine;
|
||||
@@ -9,6 +10,7 @@ using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Wires;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -40,8 +42,11 @@ public sealed class LockSystem : EntitySystem
|
||||
SubscribeLocalEvent<LockComponent, GotEmaggedEvent>(OnEmagged);
|
||||
SubscribeLocalEvent<LockComponent, LockDoAfter>(OnDoAfterLock);
|
||||
SubscribeLocalEvent<LockComponent, UnlockDoAfter>(OnDoAfterUnlock);
|
||||
}
|
||||
|
||||
SubscribeLocalEvent<LockedWiresPanelComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
|
||||
SubscribeLocalEvent<LockedWiresPanelComponent, AttemptChangePanelEvent>(OnAttemptChangePanel);
|
||||
SubscribeLocalEvent<LockedAnchorableComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
||||
}
|
||||
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
|
||||
{
|
||||
_appearanceSystem.SetData(uid, LockVisuals.Locked, lockComp.Locked);
|
||||
@@ -226,18 +231,18 @@ public sealed class LockSystem : EntitySystem
|
||||
|
||||
private void AddToggleLockVerb(EntityUid uid, LockComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || !CanToggleLock(uid, args.User))
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Act = component.Locked ?
|
||||
() => TryUnlock(uid, args.User, component) :
|
||||
() => TryLock(uid, args.User, component),
|
||||
Act = component.Locked
|
||||
? () => TryUnlock(uid, args.User, component)
|
||||
: () => TryLock(uid, args.User, component),
|
||||
Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"),
|
||||
Icon = component.Locked ?
|
||||
new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/unlock.svg.192dpi.png")) :
|
||||
new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/lock.svg.192dpi.png")),
|
||||
Icon = !component.Locked
|
||||
? new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/lock.svg.192dpi.png"))
|
||||
: new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/unlock.svg.192dpi.png")),
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
@@ -275,5 +280,53 @@ public sealed class LockSystem : EntitySystem
|
||||
|
||||
TryUnlock(uid, args.User, skipDoAfter: true);
|
||||
}
|
||||
|
||||
private void OnLockToggleAttempt(Entity<LockedWiresPanelComponent> ent, ref LockToggleAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (!TryComp<WiresPanelComponent>(ent, out var panel) || !panel.Open)
|
||||
return;
|
||||
|
||||
if (!args.Silent)
|
||||
{
|
||||
_sharedPopupSystem.PopupClient(Loc.GetString("construction-step-condition-wire-panel-close"),
|
||||
ent,
|
||||
args.User);
|
||||
}
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
|
||||
private void OnAttemptChangePanel(Entity<LockedWiresPanelComponent> ent, ref AttemptChangePanelEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (!TryComp<LockComponent>(ent, out var lockComp) || !lockComp.Locked)
|
||||
return;
|
||||
|
||||
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-generic-fail",
|
||||
("target", Identity.Entity(ent, EntityManager))),
|
||||
ent,
|
||||
args.User);
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnUnanchorAttempt(Entity<LockedAnchorableComponent> ent, ref UnanchorAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (!TryComp<LockComponent>(ent, out var lockComp) || !lockComp.Locked)
|
||||
return;
|
||||
|
||||
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-generic-fail",
|
||||
("target", Identity.Entity(ent, EntityManager))),
|
||||
ent,
|
||||
args.User);
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
Content.Shared/Lock/LockedAnchorableComponent.cs
Normal file
13
Content.Shared/Lock/LockedAnchorableComponent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.Construction.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Lock;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for a <see cref="AnchorableComponent"/> that cannot be unanchored while locked.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(LockSystem))]
|
||||
public sealed partial class LockedAnchorableComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
13
Content.Shared/Lock/LockedWiresPanelComponent.cs
Normal file
13
Content.Shared/Lock/LockedWiresPanelComponent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Lock;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for a <see cref="WiresPanelComponent"/> that cannot be opened while locked.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(LockSystem))]
|
||||
public sealed partial class LockedWiresPanelComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace Content.Shared.Popups
|
||||
/// Variant of <see cref="PopupEntity(string, EntityUid, EntityUid, PopupType)"/> that only runs on the client, outside of prediction.
|
||||
/// Useful for shared code that is always ran by both sides to avoid duplicate popups.
|
||||
/// </summary>
|
||||
public abstract void PopupClient(string? message, EntityUid uid, EntityUid recipient, PopupType type = PopupType.Small);
|
||||
public abstract void PopupClient(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small);
|
||||
|
||||
/// <summary>
|
||||
/// Variant of <see cref="PopupEntity(string, EntityUid, EntityUid, PopupType)"/> for use with prediction. The local client will show
|
||||
|
||||
@@ -28,15 +28,24 @@ public abstract class SharedWiresSystem : EntitySystem
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
TogglePanel(uid, panel, !panel.Open);
|
||||
if (!TogglePanel(uid, panel, !panel.Open, args.User))
|
||||
return;
|
||||
|
||||
AdminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.User):user} screwed {ToPrettyString(uid):target}'s maintenance panel {(panel.Open ? "open" : "closed")}");
|
||||
|
||||
var sound = panel.Open ? panel.ScrewdriverOpenSound : panel.ScrewdriverCloseSound;
|
||||
Audio.PlayPredicted(sound, uid, args.User);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnInteractUsing(Entity<WiresPanelComponent> ent, ref InteractUsingEvent args)
|
||||
{
|
||||
if (!Tool.HasQuality(args.Used, ent.Comp.OpeningTool))
|
||||
return;
|
||||
|
||||
if (!CanTogglePanel(ent, args.User))
|
||||
return;
|
||||
|
||||
if (!Tool.UseTool(
|
||||
args.Used,
|
||||
args.User,
|
||||
@@ -89,14 +98,25 @@ public abstract class SharedWiresSystem : EntitySystem
|
||||
Appearance.SetData(uid, WiresVisuals.MaintenancePanelState, panel.Open && panel.Visible, appearance);
|
||||
}
|
||||
|
||||
public void TogglePanel(EntityUid uid, WiresPanelComponent component, bool open)
|
||||
public bool TogglePanel(EntityUid uid, WiresPanelComponent component, bool open, EntityUid? user = null)
|
||||
{
|
||||
if (!CanTogglePanel((uid, component), user))
|
||||
return false;
|
||||
|
||||
component.Open = open;
|
||||
UpdateAppearance(uid, component);
|
||||
Dirty(uid, component);
|
||||
|
||||
var ev = new PanelChangedEvent(component.Open);
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanTogglePanel(Entity<WiresPanelComponent> ent, EntityUid? user)
|
||||
{
|
||||
var attempt = new AttemptChangePanelEvent(ent.Comp.Open, user);
|
||||
RaiseLocalEvent(ent, ref attempt);
|
||||
return !attempt.Cancelled;
|
||||
}
|
||||
|
||||
public bool IsPanelOpen(Entity<WiresPanelComponent?> entity)
|
||||
|
||||
@@ -57,6 +57,12 @@ public sealed partial class WiresPanelComponent : Component
|
||||
public LocId? ExamineTextOpen = "wires-panel-component-on-examine-open";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised on a <see cref="WiresPanelComponent"/> before its open state is about to be changed.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct AttemptChangePanelEvent(bool Open, EntityUid? User, bool Cancelled = false);
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a panel is opened or closed.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,8 +3,9 @@ lock-comp-on-examined-is-unlocked = The {$entityName} seems to be unlocked.
|
||||
lock-comp-do-lock-success = You lock the {$entityName}.
|
||||
lock-comp-do-unlock-success = You unlock the {$entityName}.
|
||||
lock-comp-has-user-access-fail = Access denied
|
||||
lock-comp-generic-fail = {CAPITALIZE(SUBJECT($target))} {CONJUGATE-BE($target)} locked.
|
||||
|
||||
## ToggleLockVerb
|
||||
|
||||
toggle-lock-verb-unlock = Unlock
|
||||
toggle-lock-verb-lock = Lock
|
||||
toggle-lock-verb-lock = Lock
|
||||
|
||||
@@ -140,6 +140,7 @@
|
||||
- type: Lock
|
||||
locked: true
|
||||
- type: ActivatableUIRequiresLock
|
||||
- type: LockedWiresPanel
|
||||
- type: Flashable
|
||||
- type: Damageable
|
||||
damageContainer: Silicon
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
board: APECircuitboard
|
||||
- type: Lock
|
||||
locked: false
|
||||
- type: LockedWiresPanel
|
||||
- type: AccessReader
|
||||
access: [[ "Research" ]]
|
||||
- type: Emitter
|
||||
@@ -204,6 +205,7 @@
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
- type: LockVisuals
|
||||
- type: LockedAnchorable
|
||||
- type: DeviceNetwork
|
||||
deviceNetId: Wireless
|
||||
receiveFrequencyId: BasicDevice
|
||||
|
||||
@@ -84,6 +84,8 @@
|
||||
- type: Lock
|
||||
locked: false
|
||||
- type: LockVisuals
|
||||
- type: LockedAnchorable
|
||||
- type: LockedWiresPanel
|
||||
- type: AccessReader
|
||||
access: [[ "Engineering" ]]
|
||||
- type: Machine
|
||||
|
||||
Reference in New Issue
Block a user