Emags (#6738)
This commit is contained in:
@@ -12,6 +12,7 @@ namespace Content.Client.Power.APC
|
|||||||
public static readonly Color LackColor = Color.FromHex("#d1332e");
|
public static readonly Color LackColor = Color.FromHex("#d1332e");
|
||||||
public static readonly Color ChargingColor = Color.FromHex("#2e8ad1");
|
public static readonly Color ChargingColor = Color.FromHex("#2e8ad1");
|
||||||
public static readonly Color FullColor = Color.FromHex("#3db83b");
|
public static readonly Color FullColor = Color.FromHex("#3db83b");
|
||||||
|
public static readonly Color EmagColor = Color.FromHex("#1f48d6");
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public override void InitializeEntity(EntityUid entity)
|
public override void InitializeEntity(EntityUid entity)
|
||||||
@@ -55,6 +56,9 @@ namespace Content.Client.Power.APC
|
|||||||
case ApcChargeState.Full:
|
case ApcChargeState.Full:
|
||||||
sprite.LayerSetState(Layers.ChargeState, "apco3-2");
|
sprite.LayerSetState(Layers.ChargeState, "apco3-2");
|
||||||
break;
|
break;
|
||||||
|
case ApcChargeState.Emag:
|
||||||
|
sprite.LayerSetState(Layers.ChargeState, "emag-unlit");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent.TryGetComponent(component.Owner, out SharedPointLightComponent? light))
|
if (ent.TryGetComponent(component.Owner, out SharedPointLightComponent? light))
|
||||||
@@ -64,6 +68,7 @@ namespace Content.Client.Power.APC
|
|||||||
ApcChargeState.Lack => LackColor,
|
ApcChargeState.Lack => LackColor,
|
||||||
ApcChargeState.Charging => ChargingColor,
|
ApcChargeState.Charging => ChargingColor,
|
||||||
ApcChargeState.Full => FullColor,
|
ApcChargeState.Full => FullColor,
|
||||||
|
ApcChargeState.Emag => EmagColor,
|
||||||
_ => LackColor
|
_ => LackColor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Server.Atmos.Monitor.Components;
|
|||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -16,6 +17,7 @@ namespace Content.Server.Atmos.Monitor.Systems
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<FireAlarmComponent, InteractHandEvent>(OnInteractHand);
|
SubscribeLocalEvent<FireAlarmComponent, InteractHandEvent>(OnInteractHand);
|
||||||
|
SubscribeLocalEvent<FireAlarmComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInteractHand(EntityUid uid, FireAlarmComponent component, InteractHandEvent args)
|
private void OnInteractHand(EntityUid uid, FireAlarmComponent component, InteractHandEvent args)
|
||||||
@@ -38,5 +40,18 @@ namespace Content.Server.Atmos.Monitor.Systems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(EntityUid uid, FireAlarmComponent component, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if (TryComp<AtmosMonitorComponent>(uid, out var atmosMonitor))
|
||||||
|
{
|
||||||
|
if (atmosMonitor?.MonitorFire == true)
|
||||||
|
{
|
||||||
|
atmosMonitor.MonitorFire = false;
|
||||||
|
_monitorSystem.Alert(uid, AtmosMonitorAlarmType.Emagged);
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ using Robust.Shared.Player;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.Components
|
namespace Content.Server.Chemistry.Components
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,11 @@ namespace Content.Server.Chemistry.Components
|
|||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
|
|
||||||
[ViewVariables] [DataField("pack")] private string _packPrototypeId = "";
|
[ViewVariables] [DataField("pack", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentDispenserInventoryPrototype>))] private string _packPrototypeId = "";
|
||||||
|
|
||||||
|
[ViewVariables] [DataField("emagPack", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentDispenserInventoryPrototype>))] public string EmagPackPrototypeId = "";
|
||||||
|
|
||||||
|
public bool AlreadyEmagged = false;
|
||||||
|
|
||||||
[DataField("clickSound")]
|
[DataField("clickSound")]
|
||||||
private SoundSpecifier _clickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
private SoundSpecifier _clickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
||||||
@@ -119,6 +124,24 @@ namespace Content.Server.Chemistry.Components
|
|||||||
Inventory.Sort(_comparer);
|
Inventory.Sort(_comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddFromPrototype(string pack)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(pack)) return;
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex(pack, out ReagentDispenserInventoryPrototype? packPrototype))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in packPrototype.Inventory)
|
||||||
|
{
|
||||||
|
Inventory.Add(new ReagentDispenserInventoryEntry(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory.Sort(_comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnPowerChanged(PowerChangedMessage e)
|
private void OnPowerChanged(PowerChangedMessage e)
|
||||||
{
|
{
|
||||||
UpdateUserInterface();
|
UpdateUserInterface();
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Content.Shared.Chemistry.Dispenser;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.EntitySystems
|
namespace Content.Server.Chemistry.EntitySystems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class ReagentDispenserSystem : SharedReagentDispenserSystem
|
public sealed class ReagentDispenserSystem : SharedReagentDispenserSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -16,6 +19,17 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
SubscribeLocalEvent<ReagentDispenserComponent, SolutionChangedEvent>((_, comp, _) => comp.UpdateUserInterface());
|
SubscribeLocalEvent<ReagentDispenserComponent, SolutionChangedEvent>((_, comp, _) => comp.UpdateUserInterface());
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, EntInsertedIntoContainerMessage>((_, comp, _) => comp.UpdateUserInterface());
|
SubscribeLocalEvent<ReagentDispenserComponent, EntInsertedIntoContainerMessage>((_, comp, _) => comp.UpdateUserInterface());
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, EntRemovedFromContainerMessage>((_, comp, _) => comp.UpdateUserInterface());
|
SubscribeLocalEvent<ReagentDispenserComponent, EntRemovedFromContainerMessage>((_, comp, _) => comp.UpdateUserInterface());
|
||||||
|
SubscribeLocalEvent<ReagentDispenserComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(EntityUid uid, ReagentDispenserComponent comp, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if (!comp.AlreadyEmagged)
|
||||||
|
{
|
||||||
|
comp.AddFromPrototype(comp.EmagPackPrototypeId);
|
||||||
|
comp.AlreadyEmagged = true;
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ using Content.Server.Construction;
|
|||||||
using Content.Server.Construction.Components;
|
using Content.Server.Construction.Components;
|
||||||
using Content.Server.Tools;
|
using Content.Server.Tools;
|
||||||
using Content.Server.Tools.Components;
|
using Content.Server.Tools.Components;
|
||||||
|
using Content.Server.Doors.Components;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.Doors;
|
using Content.Shared.Doors;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Doors.Systems;
|
using Content.Shared.Doors.Systems;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -39,6 +41,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
SubscribeLocalEvent<DoorComponent, PryCancelledEvent>(OnPryCancelled);
|
SubscribeLocalEvent<DoorComponent, PryCancelledEvent>(OnPryCancelled);
|
||||||
SubscribeLocalEvent<DoorComponent, WeldFinishedEvent>(OnWeldFinished);
|
SubscribeLocalEvent<DoorComponent, WeldFinishedEvent>(OnWeldFinished);
|
||||||
SubscribeLocalEvent<DoorComponent, WeldCancelledEvent>(OnWeldCancelled);
|
SubscribeLocalEvent<DoorComponent, WeldCancelledEvent>(OnWeldCancelled);
|
||||||
|
SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
protected override void OnInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
||||||
@@ -303,6 +306,18 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
if(!container.Insert(board))
|
if(!container.Insert(board))
|
||||||
Logger.Warning($"Couldn't insert board {ToPrettyString(board)} into door {ToPrettyString(uid)}!");
|
Logger.Warning($"Couldn't insert board {ToPrettyString(board)} into door {ToPrettyString(uid)}!");
|
||||||
}
|
}
|
||||||
|
private void OnEmagged(EntityUid uid, DoorComponent door, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if(TryComp<AirlockComponent>(uid, out var airlockComponent))
|
||||||
|
{
|
||||||
|
if (door.State == DoorState.Closed)
|
||||||
|
{
|
||||||
|
StartOpening(uid);
|
||||||
|
airlockComponent?.SetBoltsWithAudio(!airlockComponent.IsBolted());
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class PryFinishedEvent : EntityEventArgs { }
|
public sealed class PryFinishedEvent : EntityEventArgs { }
|
||||||
|
|||||||
32
Content.Server/Emag/EmagSystem.cs
Normal file
32
Content.Server/Emag/EmagSystem.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Content.Shared.Emag.Components;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
|
|
||||||
|
namespace Content.Server.Emag
|
||||||
|
{
|
||||||
|
public sealed class EmagSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
foreach (var emag in EntityManager.EntityQuery<EmagComponent>())
|
||||||
|
{
|
||||||
|
if (emag.Charges == emag.MaxCharges)
|
||||||
|
{
|
||||||
|
emag.Accumulator = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
emag.Accumulator += frameTime;
|
||||||
|
|
||||||
|
if (emag.Accumulator < emag.RechargeTime)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
emag.Accumulator -= emag.RechargeTime;
|
||||||
|
emag.Charges++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Server.Access.Components;
|
using Content.Server.Access.Components;
|
||||||
using Content.Server.Access.Systems;
|
using Content.Server.Access.Systems;
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Content.Shared.Emag.Components;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
@@ -33,6 +35,7 @@ namespace Content.Server.Lock
|
|||||||
SubscribeLocalEvent<LockComponent, ActivateInWorldEvent>(OnActivated);
|
SubscribeLocalEvent<LockComponent, ActivateInWorldEvent>(OnActivated);
|
||||||
SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
|
SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
|
||||||
SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
|
SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
|
||||||
|
SubscribeLocalEvent<LockComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
|
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
|
||||||
@@ -182,5 +185,23 @@ namespace Content.Server.Lock
|
|||||||
// TODO VERB ICONS need padlock open/close icons.
|
// TODO VERB ICONS need padlock open/close icons.
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(EntityUid uid, LockComponent component, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if (component.Locked == true)
|
||||||
|
{
|
||||||
|
if (component.UnlockSound != null)
|
||||||
|
{
|
||||||
|
SoundSystem.Play(Filter.Pvs(component.Owner), component.UnlockSound.GetSound(), component.Owner, AudioParams.Default.WithVolume(-5));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearanceComp))
|
||||||
|
{
|
||||||
|
appearanceComp.SetData(StorageVisuals.Locked, false);
|
||||||
|
}
|
||||||
|
EntityManager.RemoveComponent<LockComponent>(uid); //Literally destroys the lock as a tell it was emagged
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public sealed class ApcComponent : BaseApcNetComponent
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool MainBreakerEnabled = true;
|
public bool MainBreakerEnabled = true;
|
||||||
|
|
||||||
|
public bool Emagged = false;
|
||||||
|
|
||||||
public const float HighPowerThreshold = 0.9f;
|
public const float HighPowerThreshold = 0.9f;
|
||||||
public static TimeSpan VisualsChangeDelay = TimeSpan.FromSeconds(1);
|
public static TimeSpan VisualsChangeDelay = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Server.Power.Pow3r;
|
|||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.APC;
|
using Content.Shared.APC;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -34,6 +35,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
SubscribeLocalEvent<ApcComponent, MapInitEvent>(OnApcInit);
|
SubscribeLocalEvent<ApcComponent, MapInitEvent>(OnApcInit);
|
||||||
SubscribeLocalEvent<ApcComponent, ChargeChangedEvent>(OnBatteryChargeChanged);
|
SubscribeLocalEvent<ApcComponent, ChargeChangedEvent>(OnBatteryChargeChanged);
|
||||||
SubscribeLocalEvent<ApcComponent, ApcToggleMainBreakerMessage>(OnToggleMainBreaker);
|
SubscribeLocalEvent<ApcComponent, ApcToggleMainBreakerMessage>(OnToggleMainBreaker);
|
||||||
|
SubscribeLocalEvent<ApcComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the APC's state only when the battery state changes, or when it's first created.
|
// Change the APC's state only when the battery state changes, or when it's first created.
|
||||||
@@ -68,6 +70,15 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(EntityUid uid, ApcComponent comp, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if(!comp.Emagged)
|
||||||
|
{
|
||||||
|
comp.Emagged = true;
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateApcState(EntityUid uid,
|
public void UpdateApcState(EntityUid uid,
|
||||||
ApcComponent? apc=null,
|
ApcComponent? apc=null,
|
||||||
BatteryComponent? battery=null)
|
BatteryComponent? battery=null)
|
||||||
@@ -115,6 +126,9 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
ApcComponent? apc=null,
|
ApcComponent? apc=null,
|
||||||
BatteryComponent? battery=null)
|
BatteryComponent? battery=null)
|
||||||
{
|
{
|
||||||
|
if (apc != null && apc.Emagged)
|
||||||
|
return ApcChargeState.Emag;
|
||||||
|
|
||||||
if (!Resolve(uid, ref apc, ref battery))
|
if (!Resolve(uid, ref apc, ref battery))
|
||||||
return ApcChargeState.Lack;
|
return ApcChargeState.Lack;
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ using Content.Server.Power.Components;
|
|||||||
using Content.Server.Recycling.Components;
|
using Content.Server.Recycling.Components;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Recycling;
|
using Content.Shared.Recycling;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Physics.Dynamics;
|
using Robust.Shared.Physics.Dynamics;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.Recycling
|
namespace Content.Server.Recycling
|
||||||
{
|
{
|
||||||
@@ -14,6 +16,7 @@ namespace Content.Server.Recycling
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<RecyclerComponent, StartCollideEvent>(HandleCollide);
|
SubscribeLocalEvent<RecyclerComponent, StartCollideEvent>(HandleCollide);
|
||||||
|
SubscribeLocalEvent<RecyclerComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCollide(EntityUid uid, RecyclerComponent component, StartCollideEvent args)
|
private void HandleCollide(EntityUid uid, RecyclerComponent component, StartCollideEvent args)
|
||||||
@@ -53,5 +56,14 @@ namespace Content.Server.Recycling
|
|||||||
appearance.SetData(RecyclerVisuals.Bloody, true);
|
appearance.SetData(RecyclerVisuals.Bloody, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(EntityUid uid, RecyclerComponent component, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if (component.Safe == true)
|
||||||
|
{
|
||||||
|
component.Safe = false;
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,4 +63,5 @@ public enum LogType
|
|||||||
Emitter = 59,
|
Emitter = 59,
|
||||||
GhostRoleTaken = 60,
|
GhostRoleTaken = 60,
|
||||||
Chat = 61,
|
Chat = 61,
|
||||||
|
Emag = 69,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ namespace Content.Shared.APC
|
|||||||
/// APC battery is full and has enough power.
|
/// APC battery is full and has enough power.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Full,
|
Full,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// APC is emagged (and not displaying other useful power colors at a glance)
|
||||||
|
/// </summary>
|
||||||
|
Emag,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -22,6 +23,7 @@ namespace Content.Shared.Access.Systems
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<AccessReaderComponent, ComponentInit>(OnInit);
|
SubscribeLocalEvent<AccessReaderComponent, ComponentInit>(OnInit);
|
||||||
|
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, AccessReaderComponent reader, ComponentInit args)
|
private void OnInit(EntityUid uid, AccessReaderComponent reader, ComponentInit args)
|
||||||
@@ -36,6 +38,15 @@ namespace Content.Shared.Access.Systems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, GotEmaggedEvent args)
|
||||||
|
{
|
||||||
|
if (reader.Enabled == true)
|
||||||
|
{
|
||||||
|
reader.Enabled = false;
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Searches an <see cref="AccessComponent"/> in the entity itself, in its active hand or in its ID slot.
|
/// Searches an <see cref="AccessComponent"/> in the entity itself, in its active hand or in its ID slot.
|
||||||
/// Then compares the found access with the configured access lists to see if it is allowed.
|
/// Then compares the found access with the configured access lists to see if it is allowed.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace Content.Shared.Atmos.Monitor
|
|||||||
{
|
{
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
Warning = 1,
|
Warning = 1,
|
||||||
Danger = 2 // 1 << 1 is the exact same thing and we're not really doing **bitmasking** are we?
|
Danger = 2, // 1 << 1 is the exact same thing and we're not really doing **bitmasking** are we?
|
||||||
|
Emagged = 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Content.Shared.Chemistry.Dispenser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of reagents which this may dispense. Defined in yaml prototype, see <see cref="ReagentDispenserInventoryPrototype"/>.
|
/// A list of reagents which this may dispense. Defined in yaml prototype, see <see cref="ReagentDispenserInventoryPrototype"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly List<ReagentDispenserInventoryEntry> Inventory = new();
|
public readonly List<ReagentDispenserInventoryEntry> Inventory = new();
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
|
public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
|
||||||
|
|||||||
16
Content.Shared/Emag/Components/EmagComponent.cs
Normal file
16
Content.Shared/Emag/Components/EmagComponent.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Content.Shared.Emag.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class EmagComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("maxCharges")]
|
||||||
|
public int MaxCharges = 3;
|
||||||
|
|
||||||
|
[DataField("charges")]
|
||||||
|
public int Charges = 3;
|
||||||
|
|
||||||
|
[DataField("rechargeTime")]
|
||||||
|
public float RechargeTime = 90f;
|
||||||
|
public float Accumulator = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
65
Content.Shared/Emag/Systems/SharedEmagSystem.cs
Normal file
65
Content.Shared/Emag/Systems/SharedEmagSystem.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using Content.Shared.Emag.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Shared.Emag.Systems
|
||||||
|
{
|
||||||
|
/// How to add an emag interaction:
|
||||||
|
/// 1. Go to the system for the component you want the interaction with
|
||||||
|
/// 2. Subscribe to the GotEmaggedEvent
|
||||||
|
/// 3. Have some check for if this actually needs to be emagged or is already emagged (to stop charge waste)
|
||||||
|
/// 4. Past the check, add all the effects you desire and HANDLE THE EVENT ARGUMENT so a charge is spent
|
||||||
|
public sealed class SharedEmagSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAdminLogSystem _adminLog = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<EmagComponent, AfterInteractEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<EmagComponent, ExaminedEvent>(OnExamine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamine(EntityUid uid, EmagComponent component, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("emag-charges-remaining", ("charges", component.Charges)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAfterInteract(EntityUid uid, EmagComponent component, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (!args.CanReach || args.Target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.Charges <= 0)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("emag-no-charges"), args.User, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var emaggedEvent = new GotEmaggedEvent(args.User);
|
||||||
|
RaiseLocalEvent(args.Target.Value, emaggedEvent, false);
|
||||||
|
if (emaggedEvent.Handled)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("emag-success",("target", args.Target)), args.User, Filter.Entities(args.User));
|
||||||
|
_adminLog.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(args.User):player} emagged {ToPrettyString(args.Target.Value):target}");
|
||||||
|
component.Charges--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class GotEmaggedEvent : HandledEntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly EntityUid UserUid;
|
||||||
|
|
||||||
|
public GotEmaggedEvent(EntityUid userUid)
|
||||||
|
{
|
||||||
|
userUid = UserUid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Resources/Locale/en-US/emag/emag.ftl
Normal file
3
Resources/Locale/en-US/emag/emag.ftl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
emag-success = The card zaps something in {THE($target)}.
|
||||||
|
emag-no-charges = No charges left!
|
||||||
|
emag-charges-remaining = It has {$charges} charges remaining.
|
||||||
@@ -50,3 +50,18 @@
|
|||||||
#- Patron
|
#- Patron
|
||||||
#- JuiceWatermelon
|
#- JuiceWatermelon
|
||||||
#- JuiceBerry
|
#- JuiceBerry
|
||||||
|
|
||||||
|
|
||||||
|
- type: reagentDispenserInventory
|
||||||
|
id: SodaDispenserEmagInventory
|
||||||
|
inventory:
|
||||||
|
- FourteenLoko
|
||||||
|
- Ephedrine
|
||||||
|
- Histamine
|
||||||
|
|
||||||
|
- type: reagentDispenserInventory
|
||||||
|
id: BoozeDispenserEmagInventory
|
||||||
|
inventory:
|
||||||
|
- AtomicBomb
|
||||||
|
- Ethanol
|
||||||
|
- Iron
|
||||||
|
|||||||
@@ -24,3 +24,11 @@
|
|||||||
- Sulfur
|
- Sulfur
|
||||||
- SulfuricAcid
|
- SulfuricAcid
|
||||||
- Uranium
|
- Uranium
|
||||||
|
|
||||||
|
- type: reagentDispenserInventory
|
||||||
|
id: ChemDispenserEmaggedInventory
|
||||||
|
inventory: ##Feel free to change this to something more interesting when more chems are added
|
||||||
|
- Napalm
|
||||||
|
- Toxin
|
||||||
|
- Epinephrine
|
||||||
|
- Ultravasculine
|
||||||
|
|||||||
@@ -121,6 +121,14 @@
|
|||||||
icon: /Textures/Objects/Misc/guardian_info.rsi/icon.png
|
icon: /Textures/Objects/Misc/guardian_info.rsi/icon.png
|
||||||
price: 14
|
price: 14
|
||||||
|
|
||||||
|
- type: uplinkListing
|
||||||
|
id: UplinkEmag
|
||||||
|
category: Utility
|
||||||
|
itemId: Emag
|
||||||
|
description: This sequencer, or "emag", can be used to open or hack a huge variety of items around the station.
|
||||||
|
icon: /Textures/Objects/Tools/emag.rsi/icon.png
|
||||||
|
price: 8
|
||||||
|
|
||||||
# Bundles
|
# Bundles
|
||||||
|
|
||||||
- type: uplinkListing
|
- type: uplinkListing
|
||||||
|
|||||||
11
Resources/Prototypes/Entities/Objects/Tools/emag.yml
Normal file
11
Resources/Prototypes/Entities/Objects/Tools/emag.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
- type: entity
|
||||||
|
parent: BaseItem
|
||||||
|
id: Emag
|
||||||
|
name: cryptographic sequencer
|
||||||
|
description: The iconic card of ill omen.
|
||||||
|
components:
|
||||||
|
- type: Emag
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
sprite: Objects/Tools/emag.rsi
|
||||||
|
state: icon
|
||||||
@@ -25,3 +25,4 @@
|
|||||||
- SmallImpassable
|
- SmallImpassable
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
pack: BoozeDispenserInventory
|
pack: BoozeDispenserInventory
|
||||||
|
emagPack: BoozeDispenserEmagInventory
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
state: industrial-working
|
state: industrial-working
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
pack: ChemDispenserStandardInventory
|
pack: ChemDispenserStandardInventory
|
||||||
|
emagPack: ChemDispenserEmaggedInventory
|
||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: Construction
|
- type: Construction
|
||||||
|
|||||||
@@ -25,3 +25,4 @@
|
|||||||
- SmallImpassable
|
- SmallImpassable
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
pack: SodaDispenserInventory
|
pack: SodaDispenserInventory
|
||||||
|
emagPack: SodaDispenserEmagInventory
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: CrateGenericSteel
|
graph: CrateGenericSteel
|
||||||
node: crategenericsteel
|
node: crategenericsteel
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CratePlastic
|
id: CratePlastic
|
||||||
@@ -431,7 +431,7 @@
|
|||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state_open: scicratesecure_open
|
state_open: scicratesecure_open
|
||||||
state_closed: scicratesecure_door
|
state_closed: scicratesecure_door
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CratePlasma
|
id: CratePlasma
|
||||||
name: plasma crate
|
name: plasma crate
|
||||||
@@ -517,7 +517,7 @@
|
|||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state_open: hydrocratesecure_open
|
state_open: hydrocratesecure_open
|
||||||
state_closed: hydrocratesecure_door
|
state_closed: hydrocratesecure_door
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateWeaponSecure
|
id: CrateWeaponSecure
|
||||||
name: secure weapon crate
|
name: secure weapon crate
|
||||||
@@ -543,7 +543,7 @@
|
|||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state_open: weaponcrate_open
|
state_open: weaponcrate_open
|
||||||
state_closed: weaponcrate_door
|
state_closed: weaponcrate_door
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateCommandSecure
|
id: CrateCommandSecure
|
||||||
name: command crate
|
name: command crate
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
Normal: fire_off
|
Normal: fire_off
|
||||||
Warning: fire_off # shouldn't be alarming at a warning
|
Warning: fire_off # shouldn't be alarming at a warning
|
||||||
Danger: fire_on
|
Danger: fire_on
|
||||||
|
Emagged: fire_emagged
|
||||||
hideOnDepowered: ["fireAlarmState"]
|
hideOnDepowered: ["fireAlarmState"]
|
||||||
- type: WiresVisualizer
|
- type: WiresVisualizer
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
|
|||||||
BIN
Resources/Textures/Objects/Tools/emag.rsi/icon.png
Normal file
BIN
Resources/Textures/Objects/Tools/emag.rsi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 317 B |
14
Resources/Textures/Objects/Tools/emag.rsi/meta.json
Normal file
14
Resources/Textures/Objects/Tools/emag.rsi/meta.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "Taken from tgstation wiki at https://tgstation13.org/wiki/File:Emag.png",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "icon"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user