* The all-in-one hacking solution The thinking man's lockpick The iconic EMAG * emagged medbay's stasis bed * left med, emagged sec' apc * went back to chem, emagged the dispenser * emagged the fax while i was there * had a donut while waiting for emag to charge * i broke into the bridge then announced 'mandatory johnson inspection in medical' * get system instead of dependency * feedback * net suggestion Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * use EnsureComp and import NetworkedComponent --------- Co-authored-by: deltanedas <user@zenith> Co-authored-by: deltanedas <deltanedas@laptop> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server.Access;
|
||||
@@ -14,26 +15,28 @@ public sealed class AccessWireAction : ComponentWireAction<AccessReaderComponent
|
||||
private int _pulseTimeout = 30;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, AccessReaderComponent comp)
|
||||
=> comp.Enabled ? StatusLightState.On : StatusLightState.Off;
|
||||
{
|
||||
return EntityManager.HasComponent<EmaggedComponent>(comp.Owner) ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override object StatusKey { get; } = AccessWireActionKey.Status;
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, AccessReaderComponent comp)
|
||||
{
|
||||
WiresSystem.TryCancelWireAction(wire.Owner, PulseTimeoutKey.Key);
|
||||
comp.Enabled = false;
|
||||
EntityManager.RemoveComponent<EmaggedComponent>(comp.Owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, AccessReaderComponent comp)
|
||||
{
|
||||
comp.Enabled = true;
|
||||
EntityManager.AddComponent<EmaggedComponent>(comp.Owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, AccessReaderComponent comp)
|
||||
{
|
||||
comp.Enabled = false;
|
||||
EntityManager.RemoveComponent<EmaggedComponent>(comp.Owner);
|
||||
WiresSystem.StartWireAction(wire.Owner, _pulseTimeout, PulseTimeoutKey.Key, new TimedWireEvent(AwaitPulseCancel, wire));
|
||||
}
|
||||
|
||||
@@ -49,9 +52,10 @@ public sealed class AccessWireAction : ComponentWireAction<AccessReaderComponent
|
||||
{
|
||||
if (!wire.IsCut)
|
||||
{
|
||||
// check is still here incase you somehow TOCTOU it into unemagging something it shouldn't
|
||||
if (EntityManager.TryGetComponent<AccessReaderComponent>(wire.Owner, out var access))
|
||||
{
|
||||
access.Enabled = true;
|
||||
EntityManager.RemoveComponent<EmaggedComponent>(wire.Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Server.Construction;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
@@ -114,7 +115,7 @@ namespace Content.Server.Bed
|
||||
|
||||
private void OnEmagged(EntityUid uid, StasisBedComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
// Repeatable
|
||||
args.Repeatable = true;
|
||||
// Reset any metabolisms first so they receive the multiplier correctly
|
||||
UpdateMetabolisms(uid, component, false);
|
||||
component.Multiplier = 1 / component.Multiplier;
|
||||
@@ -139,7 +140,7 @@ namespace Content.Server.Bed
|
||||
{
|
||||
var metabolismRating = args.PartRatings[component.MachinePartMetabolismModifier];
|
||||
component.Multiplier = component.BaseMultiplier * metabolismRating; //linear scaling so it's not OP
|
||||
if (component.Emagged)
|
||||
if (HasComp<EmaggedComponent>(uid))
|
||||
component.Multiplier = 1f / component.Multiplier;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,6 @@ namespace Content.Server.Bed.Components
|
||||
[RegisterComponent]
|
||||
public sealed class StasisBedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores whether or not the stasis bed has been emagged,
|
||||
/// which causes the multiplier to speed up rather than
|
||||
/// slow down. Needs to be stored for machine upgrades.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Emagged = false;
|
||||
|
||||
[DataField("baseMultiplier", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float BaseMultiplier = 10f;
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@ namespace Content.Server.Chemistry.Components
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? EmagPackPrototypeId = default!;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool IsEmagged = false;
|
||||
|
||||
[DataField("clickSound"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Dispenser;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.FixedPoint;
|
||||
using JetBrains.Annotations;
|
||||
@@ -79,7 +80,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
inventory.AddRange(packPrototype.Inventory);
|
||||
}
|
||||
|
||||
if (reagentDispenser.IsEmagged
|
||||
if (HasComp<EmaggedComponent>(reagentDispenser.Owner)
|
||||
&& reagentDispenser.EmagPackPrototypeId is not null
|
||||
&& _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
|
||||
{
|
||||
@@ -91,12 +92,10 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
|
||||
private void OnEmagged(EntityUid uid, ReagentDispenserComponent reagentDispenser, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (!reagentDispenser.IsEmagged)
|
||||
{
|
||||
reagentDispenser.IsEmagged = true;
|
||||
args.Handled = true;
|
||||
UpdateUiState(reagentDispenser);
|
||||
}
|
||||
// adding component manually to have correct state
|
||||
EntityManager.AddComponent<EmaggedComponent>(uid);
|
||||
UpdateUiState(reagentDispenser);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnSetDispenseAmountMessage(EntityUid uid, ReagentDispenserComponent reagentDispenser, ReagentDispenserSetDispenseAmountMessage message)
|
||||
|
||||
@@ -15,6 +15,7 @@ using Content.Shared.Access.Systems;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Communications;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -175,7 +176,7 @@ namespace Content.Server.Communications
|
||||
if (!_interaction.InRangeUnobstructed(console, user))
|
||||
return false;
|
||||
|
||||
if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent) && accessReaderComponent.Enabled)
|
||||
if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent) && !HasComp<EmaggedComponent>(console))
|
||||
{
|
||||
return _accessReaderSystem.IsAllowed(user, accessReaderComponent);
|
||||
}
|
||||
|
||||
@@ -50,13 +50,6 @@ public sealed class FaxMachineComponent : Component
|
||||
[DataField("receiveNukeCodes")]
|
||||
public bool ReceiveNukeCodes { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Is fax was emaaged
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("emagged")]
|
||||
public bool Emagged { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Sound to play when fax has been emagged
|
||||
/// </summary>
|
||||
|
||||
@@ -13,6 +13,7 @@ using Content.Server.UserInterface;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Fax;
|
||||
using Content.Shared.Interaction;
|
||||
@@ -210,7 +211,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.KnownFaxes.ContainsValue(newName) && !component.Emagged) // Allow exist names if emagged for fun
|
||||
if (component.KnownFaxes.ContainsValue(newName) && !HasComp<EmaggedComponent>(uid)) // Allow existing names if emagged for fun
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-exist"), uid);
|
||||
return;
|
||||
@@ -228,11 +229,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
|
||||
private void OnEmagged(EntityUid uid, FaxMachineComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (component.Emagged)
|
||||
return;
|
||||
|
||||
_audioSystem.PlayPvs(component.EmagSound, uid);
|
||||
component.Emagged = true;
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -246,7 +243,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
switch (command)
|
||||
{
|
||||
case FaxConstants.FaxPingCommand:
|
||||
var isForSyndie = component.Emagged &&
|
||||
var isForSyndie = HasComp<EmaggedComponent>(uid) &&
|
||||
args.Data.ContainsKey(FaxConstants.FaxSyndicateData);
|
||||
if (!isForSyndie && !component.ResponsePings)
|
||||
return;
|
||||
@@ -362,7 +359,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
{ DeviceNetworkConstants.Command, FaxConstants.FaxPingCommand }
|
||||
};
|
||||
|
||||
if (component.Emagged)
|
||||
if (HasComp<EmaggedComponent>(uid))
|
||||
payload.Add(FaxConstants.FaxSyndicateData, true);
|
||||
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload);
|
||||
|
||||
@@ -27,8 +27,6 @@ public sealed class ApcComponent : BaseApcNetComponent
|
||||
[ViewVariables]
|
||||
public bool MainBreakerEnabled = true;
|
||||
|
||||
public bool Emagged = false;
|
||||
|
||||
public const float HighPowerThreshold = 0.9f;
|
||||
public static TimeSpan VisualsChangeDelay = TimeSpan.FromSeconds(1);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.Wires;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.APC;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction;
|
||||
@@ -88,11 +89,8 @@ namespace Content.Server.Power.EntitySystems
|
||||
|
||||
private void OnEmagged(EntityUid uid, ApcComponent comp, ref GotEmaggedEvent args)
|
||||
{
|
||||
if(!comp.Emagged)
|
||||
{
|
||||
comp.Emagged = true;
|
||||
args.Handled = true;
|
||||
}
|
||||
// no fancy conditions
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public void UpdateApcState(EntityUid uid,
|
||||
@@ -147,7 +145,7 @@ namespace Content.Server.Power.EntitySystems
|
||||
ApcComponent? apc=null,
|
||||
BatteryComponent? battery=null)
|
||||
{
|
||||
if (apc != null && apc.Emagged)
|
||||
if (apc != null && HasComp<EmaggedComponent>(uid))
|
||||
return ApcChargeState.Emag;
|
||||
|
||||
if (!Resolve(uid, ref apc, ref battery))
|
||||
|
||||
@@ -13,13 +13,6 @@ namespace Content.Server.Recycling.Components
|
||||
[DataField("enabled")]
|
||||
public bool Enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not sentient beings will be recycled
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("safe")]
|
||||
internal bool Safe = true;
|
||||
|
||||
/// <summary>
|
||||
/// The percentage of material that will be recovered
|
||||
/// </summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Recycling.Components;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
@@ -131,7 +132,7 @@ namespace Content.Server.Recycling
|
||||
|
||||
// Can only recycle things that are tagged trash or recyclable... And also check the safety of the thing to recycle.
|
||||
if (!_tags.HasAnyTag(entity, "Trash", "Recyclable") &&
|
||||
(!TryComp(entity, out recyclable) || !recyclable.Safe && component.Safe))
|
||||
(!TryComp(entity, out recyclable) || !recyclable.Safe && !HasComp<EmaggedComponent>(component.Owner)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -162,7 +163,7 @@ namespace Content.Server.Recycling
|
||||
|
||||
private bool CanGib(RecyclerComponent component, EntityUid entity)
|
||||
{
|
||||
return HasComp<BodyComponent>(entity) && !component.Safe &&
|
||||
return HasComp<BodyComponent>(entity) && HasComp<EmaggedComponent>(component.Owner) &&
|
||||
this.IsPowered(component.Owner, EntityManager);
|
||||
}
|
||||
|
||||
@@ -191,8 +192,7 @@ namespace Content.Server.Recycling
|
||||
|
||||
private void OnEmagged(EntityUid uid, RecyclerComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (!component.Safe) return;
|
||||
component.Safe = false;
|
||||
// no fancy conditions
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.ActionTypes;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Throwing;
|
||||
@@ -133,11 +134,8 @@ namespace Content.Server.VendingMachines
|
||||
|
||||
private void OnEmagged(EntityUid uid, VendingMachineComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (component.Emagged || component.EmaggedInventory.Count == 0 )
|
||||
return;
|
||||
|
||||
component.Emagged = true;
|
||||
args.Handled = true;
|
||||
// only emag if there are emag-only items
|
||||
args.Handled = component.EmaggedInventory.Count > 0;
|
||||
}
|
||||
|
||||
private void OnDamage(EntityUid uid, VendingMachineComponent component, DamageChangedEvent args)
|
||||
@@ -224,7 +222,7 @@ namespace Content.Server.VendingMachines
|
||||
|
||||
if (TryComp<AccessReaderComponent?>(vendComponent.Owner, out var accessReader))
|
||||
{
|
||||
if (!_accessReader.IsAllowed(sender.Value, accessReader) && !vendComponent.Emagged)
|
||||
if (!_accessReader.IsAllowed(sender.Value, accessReader) && !HasComp<EmaggedComponent>(uid))
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("vending-machine-component-try-eject-access-denied"), uid);
|
||||
Deny(uid, vendComponent);
|
||||
@@ -391,7 +389,7 @@ namespace Content.Server.VendingMachines
|
||||
|
||||
private VendingMachineInventoryEntry? GetEntry(string entryId, InventoryType type, VendingMachineComponent component)
|
||||
{
|
||||
if (type == InventoryType.Emagged && component.Emagged)
|
||||
if (type == InventoryType.Emagged && HasComp<EmaggedComponent>(component.Owner))
|
||||
return component.EmaggedInventory.GetValueOrDefault(entryId);
|
||||
|
||||
if (type == InventoryType.Contraband && component.Contraband)
|
||||
|
||||
@@ -7,13 +7,6 @@ namespace Content.Shared.Access.Components
|
||||
[RegisterComponent]
|
||||
public sealed class AccessReaderComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this reader is enabled or not. If disabled, all access
|
||||
/// checks will pass.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// The set of tags that will automatically deny an allowed check, if any of them are present.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.PDA;
|
||||
using Content.Shared.Access.Components;
|
||||
@@ -28,7 +29,7 @@ namespace Content.Shared.Access.Systems
|
||||
{
|
||||
if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
|
||||
return;
|
||||
if (component.Enabled && !IsAllowed(args.User.Value, component))
|
||||
if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, component))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
@@ -46,12 +47,10 @@ namespace Content.Shared.Access.Systems
|
||||
|
||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (reader.Enabled)
|
||||
{
|
||||
reader.Enabled = false;
|
||||
args.Handled = true;
|
||||
}
|
||||
// no fancy conditions
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the source for access tags
|
||||
/// then compares it with the targets readers access list to see if it is allowed.
|
||||
@@ -86,7 +85,7 @@ namespace Content.Shared.Access.Systems
|
||||
/// <param name="reader">An access reader to check against</param>
|
||||
public bool IsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
|
||||
{
|
||||
if (!reader.Enabled)
|
||||
if (HasComp<EmaggedComponent>(reader.Owner))
|
||||
{
|
||||
// Access reader is totally disabled, so access is always allowed.
|
||||
return true;
|
||||
|
||||
11
Content.Shared/Emag/Components/EmaggedComponent.cs
Normal file
11
Content.Shared/Emag/Components/EmaggedComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Emag.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Marker component for emagged entities
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class EmaggedComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -156,12 +156,19 @@ namespace Content.Shared.Emag.Systems
|
||||
/// </summary>
|
||||
public bool DoEmagEffect(EntityUid user, EntityUid target)
|
||||
{
|
||||
// prevent emagging twice
|
||||
if (HasComp<EmaggedComponent>(target))
|
||||
return false;
|
||||
|
||||
var emaggedEvent = new GotEmaggedEvent(user);
|
||||
RaiseLocalEvent(target, ref emaggedEvent);
|
||||
|
||||
if (!emaggedEvent.Repeatable)
|
||||
EnsureComp<EmaggedComponent>(target);
|
||||
return emaggedEvent.Handled;
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false);
|
||||
public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false, bool Repeatable = false);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Emag.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
|
||||
@@ -36,7 +37,7 @@ public abstract class SharedVendingMachineSystem : EntitySystem
|
||||
|
||||
/// <summary>
|
||||
/// Returns all of the vending machine's inventory. Only includes emagged and contraband inventories if
|
||||
/// <see cref="VendingMachineComponent.Emagged"/> and <see cref="VendingMachineComponent.Contraband"/>
|
||||
/// <see cref="EmaggedComponent"/> exists and <see cref="VendingMachineComponent.Contraband"/> is true
|
||||
/// are <c>true</c> respectively.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
@@ -49,7 +50,7 @@ public abstract class SharedVendingMachineSystem : EntitySystem
|
||||
|
||||
var inventory = new List<VendingMachineInventoryEntry>(component.Inventory.Values);
|
||||
|
||||
if (component.Emagged)
|
||||
if (HasComp<EmaggedComponent>(uid))
|
||||
inventory.AddRange(component.EmaggedInventory.Values);
|
||||
|
||||
if (component.Contraband)
|
||||
|
||||
@@ -40,7 +40,6 @@ namespace Content.Shared.VendingMachines
|
||||
[ViewVariables]
|
||||
public Dictionary<string, VendingMachineInventoryEntry> ContrabandInventory = new();
|
||||
|
||||
public bool Emagged;
|
||||
public bool Contraband;
|
||||
|
||||
public bool Ejecting;
|
||||
|
||||
Reference in New Issue
Block a user