predict emag and make blessed record struct events (#13623)
This commit is contained in:
@@ -74,7 +74,7 @@ public sealed class FireAlarmSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, FireAlarmComponent component, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, FireAlarmComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<AtmosAlarmableComponent>(uid, out var alarmable))
|
if (TryComp<AtmosAlarmableComponent>(uid, out var alarmable))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ namespace Content.Server.Bed
|
|||||||
UpdateMetabolisms(uid, component, args.Powered);
|
UpdateMetabolisms(uid, component, args.Powered);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, StasisBedComponent component, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, StasisBedComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
// Repeatable
|
// Repeatable
|
||||||
// Reset any metabolisms first so they receive the multiplier correctly
|
// Reset any metabolisms first so they receive the multiplier correctly
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, ReagentDispenserComponent reagentDispenser, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, ReagentDispenserComponent reagentDispenser, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (!reagentDispenser.IsEmagged)
|
if (!reagentDispenser.IsEmagged)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
if (Tags.HasTag(otherUid, "DoorBumpOpener"))
|
if (Tags.HasTag(otherUid, "DoorBumpOpener"))
|
||||||
TryOpen(uid, door, otherUid);
|
TryOpen(uid, door, otherUid);
|
||||||
}
|
}
|
||||||
private void OnEmagged(EntityUid uid, DoorComponent door, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if(TryComp<AirlockComponent>(uid, out var airlockComponent))
|
if(TryComp<AirlockComponent>(uid, out var airlockComponent))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
using Content.Shared.Administration.Logs;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.Emag.Components;
|
|
||||||
using Content.Shared.Emag.Systems;
|
|
||||||
using Content.Shared.IdentityManagement;
|
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Tag;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Emag
|
|
||||||
{
|
|
||||||
public sealed class EmagSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
|
||||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
|
||||||
|
|
||||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<EmagComponent, AfterInteractEvent>(OnAfterInteract);
|
|
||||||
}
|
|
||||||
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAfterInteract(EntityUid uid, EmagComponent component, AfterInteractEvent args)
|
|
||||||
{
|
|
||||||
if (!args.CanReach || args.Target == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_tagSystem.HasTag(args.Target.Value, "EmagImmune"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (component.Charges <= 0)
|
|
||||||
{
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("emag-no-charges"), args.User, args.User);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var handled = DoEmag(args.Target, args.User);
|
|
||||||
if (handled)
|
|
||||||
{
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("emag-success", ("target", Identity.Entity(args.Target.Value, EntityManager))), args.User,
|
|
||||||
args.User, PopupType.Medium);
|
|
||||||
_adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(args.User):player} emagged {ToPrettyString(args.Target.Value):target}");
|
|
||||||
component.Charges--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoEmag(EntityUid? target, EntityUid? user)
|
|
||||||
{
|
|
||||||
if (target == null || user == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var emaggedEvent = new GotEmaggedEvent(user.Value);
|
|
||||||
RaiseLocalEvent(target.Value, emaggedEvent, false);
|
|
||||||
return emaggedEvent.Handled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -226,7 +226,7 @@ public sealed class FaxSystem : EntitySystem
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, FaxMachineComponent component, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, FaxMachineComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (component.Emagged)
|
if (component.Emagged)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ namespace Content.Server.Lock
|
|||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, LockComponent component, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (component.Locked)
|
if (component.Locked)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace Content.Server.Power.EntitySystems
|
|||||||
SoundSystem.Play(apc.OnReceiveMessageSound.GetSound(), Filter.Pvs(uid), uid, AudioParams.Default.WithVolume(-2f));
|
SoundSystem.Play(apc.OnReceiveMessageSound.GetSound(), Filter.Pvs(uid), uid, AudioParams.Default.WithVolume(-2f));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, ApcComponent comp, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, ApcComponent comp, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if(!comp.Emagged)
|
if(!comp.Emagged)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ namespace Content.Server.Recycling
|
|||||||
QueueDel(component.Owner);
|
QueueDel(component.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, RecyclerComponent component, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, RecyclerComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (!component.Safe) return;
|
if (!component.Safe) return;
|
||||||
component.Safe = false;
|
component.Safe = false;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Content.Shared.Revenant;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Content.Shared.Maps;
|
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
using Content.Server.Light.Components;
|
using Content.Server.Light.Components;
|
||||||
using Content.Server.Ghost;
|
using Content.Server.Ghost;
|
||||||
@@ -18,12 +17,10 @@ using Content.Server.Disease.Components;
|
|||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Bed.Sleep;
|
using Content.Shared.Bed.Sleep;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Beam;
|
|
||||||
using Content.Server.Emag;
|
|
||||||
using Content.Server.Humanoid;
|
|
||||||
using Content.Server.Maps;
|
using Content.Server.Maps;
|
||||||
using Content.Server.Revenant.Components;
|
using Content.Server.Revenant.Components;
|
||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
@@ -339,7 +336,7 @@ public sealed partial class RevenantSystem
|
|||||||
|
|
||||||
foreach (var ent in _lookup.GetEntitiesInRange(uid, component.MalfunctionRadius))
|
foreach (var ent in _lookup.GetEntitiesInRange(uid, component.MalfunctionRadius))
|
||||||
{
|
{
|
||||||
_emag.DoEmag(ent, ent); //it emags itself. spooky.
|
_emag.DoEmagEffect(ent, ent); //it emags itself. spooky.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ namespace Content.Server.VendingMachines
|
|||||||
TryUpdateVisualState(uid, vendComponent);
|
TryUpdateVisualState(uid, vendComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, VendingMachineComponent component, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, VendingMachineComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (component.Emagged || component.EmaggedInventory.Count == 0 )
|
if (component.Emagged || component.EmaggedInventory.Count == 0 )
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace Content.Shared.Access.Systems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (reader.Enabled)
|
if (reader.Enabled)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,18 +1,70 @@
|
|||||||
namespace Content.Shared.Emag.Components
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Emag.Components;
|
||||||
|
|
||||||
|
[Access(typeof(EmagSystem))]
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed class EmagComponent : Component
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
/// <summary>
|
||||||
public sealed class EmagComponent : Component
|
/// The maximum number of charges the emag can have
|
||||||
|
/// </summary>
|
||||||
|
[DataField("maxCharges"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int MaxCharges = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current number of charges on the emag
|
||||||
|
/// </summary>
|
||||||
|
[DataField("charges"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int Charges = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the emag automatically recharges over time.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("autoRecharge"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool AutoRecharge = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time it takes to regain a single charge
|
||||||
|
/// </summary>
|
||||||
|
[DataField("rechargeDuration"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan RechargeDuration = TimeSpan.FromSeconds(90);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time when the next charge will be added
|
||||||
|
/// </summary>
|
||||||
|
[DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan NextChargeTime = TimeSpan.MaxValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tag that marks an entity as immune to emags
|
||||||
|
/// </summary>
|
||||||
|
[DataField("emagImmuneTag", customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>)), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string EmagImmuneTag = "EmagImmune";
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class EmagComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public int MaxCharges;
|
||||||
|
public int Charges;
|
||||||
|
public bool AutoRecharge;
|
||||||
|
public TimeSpan RechargeTime;
|
||||||
|
public TimeSpan NextChargeTime;
|
||||||
|
public string EmagImmuneTag;
|
||||||
|
|
||||||
|
public EmagComponentState(int maxCharges, int charges, TimeSpan rechargeTime, TimeSpan nextChargeTime, string emagImmuneTag, bool autoRecharge)
|
||||||
{
|
{
|
||||||
[DataField("maxCharges"), ViewVariables(VVAccess.ReadWrite)]
|
MaxCharges = maxCharges;
|
||||||
public int MaxCharges = 3;
|
Charges = charges;
|
||||||
|
RechargeTime = rechargeTime;
|
||||||
[DataField("charges"), ViewVariables(VVAccess.ReadWrite)]
|
NextChargeTime = nextChargeTime;
|
||||||
public int Charges = 3;
|
EmagImmuneTag = emagImmuneTag;
|
||||||
|
AutoRecharge = autoRecharge;
|
||||||
[DataField("rechargeTime"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float RechargeTime = 90f;
|
|
||||||
|
|
||||||
[DataField("accumulator")]
|
|
||||||
public float Accumulator = 0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
167
Content.Shared/Emag/Systems/EmagSystem.cs
Normal file
167
Content.Shared/Emag/Systems/EmagSystem.cs
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Emag.Components;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
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 EmagSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<EmagComponent, ExaminedEvent>(OnExamine);
|
||||||
|
SubscribeLocalEvent<EmagComponent, AfterInteractEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<EmagComponent, ComponentGetState>(OnGetState);
|
||||||
|
SubscribeLocalEvent<EmagComponent, ComponentHandleState>(OnHandleState);
|
||||||
|
SubscribeLocalEvent<EmagComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetState(EntityUid uid, EmagComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new EmagComponentState(component.MaxCharges, component.Charges, component.RechargeDuration,
|
||||||
|
component.NextChargeTime, component.EmagImmuneTag, component.AutoRecharge);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandleState(EntityUid uid, EmagComponent component, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
if (args.Current is not EmagComponentState state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.MaxCharges = state.MaxCharges;
|
||||||
|
component.Charges = state.Charges;
|
||||||
|
component.RechargeDuration = state.RechargeTime;
|
||||||
|
component.NextChargeTime = state.NextChargeTime;
|
||||||
|
component.EmagImmuneTag = state.EmagImmuneTag;
|
||||||
|
component.AutoRecharge = state.AutoRecharge;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnpaused(EntityUid uid, EmagComponent component, ref EntityUnpausedEvent args)
|
||||||
|
{
|
||||||
|
component.NextChargeTime += args.PausedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamine(EntityUid uid, EmagComponent component, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("emag-charges-remaining", ("charges", component.Charges)));
|
||||||
|
if (component.Charges == component.MaxCharges)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("emag-max-charges"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var timeRemaining = Math.Round((component.NextChargeTime - _timing.CurTime).TotalSeconds);
|
||||||
|
args.PushMarkup(Loc.GetString("emag-recharging", ("seconds", timeRemaining)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
foreach (var emag in EntityQuery<EmagComponent>())
|
||||||
|
{
|
||||||
|
if (!emag.AutoRecharge)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (emag.Charges == emag.MaxCharges)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_timing.CurTime < emag.NextChargeTime)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ChangeEmagCharge(emag.Owner, 1, true, emag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAfterInteract(EntityUid uid, EmagComponent component, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (!args.CanReach || args.Target is not { } target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = TryUseEmag(uid, args.User, target, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the charge on an emag.
|
||||||
|
/// </summary>
|
||||||
|
public bool ChangeEmagCharge(EntityUid uid, int change, bool resetTimer, EmagComponent? component = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref component))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (component.Charges + change < 0 || component.Charges + change > component.MaxCharges)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (resetTimer || component.Charges == component.MaxCharges)
|
||||||
|
component.NextChargeTime = _timing.CurTime + component.RechargeDuration;
|
||||||
|
|
||||||
|
component.Charges += change;
|
||||||
|
Dirty(component);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to use the emag on a target entity
|
||||||
|
/// </summary>
|
||||||
|
public bool TryUseEmag(EntityUid emag, EntityUid user, EntityUid target, EmagComponent? component = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(emag, ref component, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_tagSystem.HasTag(target, component.EmagImmuneTag))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (component.Charges <= 0)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("emag-no-charges"), user, user);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handled = DoEmagEffect(user, target);
|
||||||
|
if (!handled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// only do popup on client
|
||||||
|
if (_net.IsClient && _timing.IsFirstTimePredicted)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("emag-success", ("target", Identity.Entity(target, EntityManager))), user,
|
||||||
|
user, PopupType.Medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
_adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(user):player} emagged {ToPrettyString(target):target}");
|
||||||
|
|
||||||
|
ChangeEmagCharge(emag, -1, false, component);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does the emag effect on a specified entity
|
||||||
|
/// </summary>
|
||||||
|
public bool DoEmagEffect(EntityUid user, EntityUid target)
|
||||||
|
{
|
||||||
|
var emaggedEvent = new GotEmaggedEvent(user);
|
||||||
|
RaiseLocalEvent(target, ref emaggedEvent);
|
||||||
|
return emaggedEvent.Handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false);
|
||||||
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Content.Shared.Emag.Components;
|
|
||||||
using Content.Shared.Examine;
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
SubscribeLocalEvent<EmagComponent, ExaminedEvent>(OnExamine);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnExamine(EntityUid uid, EmagComponent component, ExaminedEvent args)
|
|
||||||
{
|
|
||||||
float timeRemaining = component.RechargeTime - component.Accumulator;
|
|
||||||
args.PushMarkup(Loc.GetString("emag-charges-remaining", ("charges", component.Charges)));
|
|
||||||
if (component.Charges == component.MaxCharges)
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("emag-max-charges"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
args.PushMarkup(Loc.GetString("emag-recharging", ("seconds", Math.Round(timeRemaining))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class GotEmaggedEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
public readonly EntityUid UserUid;
|
|
||||||
|
|
||||||
public GotEmaggedEvent(EntityUid userUid)
|
|
||||||
{
|
|
||||||
UserUid = userUid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -123,7 +123,7 @@ public abstract partial class SharedCryoPodSystem: EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OnEmagged(EntityUid uid, SharedCryoPodComponent? cryoPodComponent, GotEmaggedEvent args)
|
protected void OnEmagged(EntityUid uid, SharedCryoPodComponent? cryoPodComponent, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref cryoPodComponent))
|
if (!Resolve(uid, ref cryoPodComponent))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
emag-success = The card zaps something in {THE($target)}.
|
emag-success = The card zaps something in {THE($target)}.
|
||||||
emag-no-charges = No charges left!
|
emag-no-charges = No charges left!
|
||||||
emag-charges-remaining = It has [color=fuchsia]{$charges}[/color] charges remaining.
|
emag-charges-remaining = {$charges ->
|
||||||
|
[one] It has [color=fuchsia]{$charges}[/color] charge remaining.
|
||||||
|
*[other] It has [color=fuchsia]{$charges}[/color] charges remaining.
|
||||||
|
}
|
||||||
|
|
||||||
emag-max-charges = It's at [color=green]maximum[/color] charges.
|
emag-max-charges = It's at [color=green]maximum[/color] charges.
|
||||||
emag-recharging = There are [color=yellow]{$seconds}[/color] seconds left until the next charge.
|
emag-recharging = {$seconds ->
|
||||||
|
[one] There is [color=yellow]{$seconds}[/color] second left until the next charge.
|
||||||
|
*[other] There are [color=yellow]{$seconds}[/color] seconds left until the next charge.
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user