From 4ade6f60ff2f5ced7053a9ef8ec57015f365fd96 Mon Sep 17 00:00:00 2001
From: Slava0135 <40753025+Slava0135@users.noreply.github.com>
Date: Sat, 29 Apr 2023 23:05:10 +0300
Subject: [PATCH] Electrified grille sparks effect (#15178)
* use file namespace
* shorter systems name
* replace SoundSystem with AudioSystem
* refactor update function
* refactor
* refactor 2
* remove setters
* uh oh
* remove getters
* active checks
* refactor 3
* better way
* update state
* have to remove this for now
* move electrified component to shared
* forgot this
* fix airlocks
* add effect
* Revert "move electrified component to shared"
This reverts commit 6457e8fc9c3b674a705a61034831ce6f084e2b01.
* Revert "forgot this"
This reverts commit ed361cee2d5b8b958830ba0af07fcc2627eb7845.
* functioning effects
* use animation by Aleksh
* make effect part of grille
* optimisation?
* remove timing
* file name
* only activate when touched
* refactor electrocution comp too
* make it 1 sec
* formatting
* replace all entity query with enumerator
* queue del
---
.../ActivatedElectrifiedComponent.cs | 14 +
.../Components/ElectrifiedComponent.cs | 105 ++-
.../Components/ElectrocutionComponent.cs | 31 +-
.../Electrocution/ElectrocutionSystem.cs | 630 +++++++++---------
.../Electrocution/SharedElectrocution.cs | 15 +
.../Entities/Structures/Walls/grille.yml | 16 +-
.../Effects/electricity.rsi/electrified.png | Bin 0 -> 1047 bytes
.../Effects/electricity.rsi/meta.json | 24 +
8 files changed, 457 insertions(+), 378 deletions(-)
create mode 100644 Content.Server/Electrocution/Components/ActivatedElectrifiedComponent.cs
create mode 100644 Content.Shared/Electrocution/SharedElectrocution.cs
create mode 100644 Resources/Textures/Effects/electricity.rsi/electrified.png
create mode 100644 Resources/Textures/Effects/electricity.rsi/meta.json
diff --git a/Content.Server/Electrocution/Components/ActivatedElectrifiedComponent.cs b/Content.Server/Electrocution/Components/ActivatedElectrifiedComponent.cs
new file mode 100644
index 0000000000..60c3cff880
--- /dev/null
+++ b/Content.Server/Electrocution/Components/ActivatedElectrifiedComponent.cs
@@ -0,0 +1,14 @@
+namespace Content.Server.Electrocution;
+
+///
+/// Updates every frame for short duration to check if electrifed entity is powered when activated, e.g to play animation
+///
+[RegisterComponent]
+public sealed class ActivatedElectrifiedComponent : Component
+{
+ ///
+ /// How long electrified entity will remain active
+ ///
+ [ViewVariables]
+ public float TimeLeft = 1f;
+}
diff --git a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs
index 0d2ed0a244..97a24ffe0c 100644
--- a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs
+++ b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs
@@ -1,77 +1,76 @@
using Robust.Shared.Audio;
-namespace Content.Server.Electrocution
+namespace Content.Server.Electrocution;
+
+///
+/// Component for things that shock users on touch.
+///
+[RegisterComponent]
+public sealed class ElectrifiedComponent : Component
{
- ///
- /// Component for things that shock users on touch.
- ///
- [RegisterComponent]
- public sealed class ElectrifiedComponent : Component
- {
- [DataField("enabled")]
- public bool Enabled { get; set; } = true;
+ [DataField("enabled")]
+ public bool Enabled = true;
- [DataField("onBump")]
- public bool OnBump { get; set; } = true;
+ [DataField("onBump")]
+ public bool OnBump = true;
- [DataField("onAttacked")]
- public bool OnAttacked { get; set; } = true;
+ [DataField("onAttacked")]
+ public bool OnAttacked = true;
- [DataField("noWindowInTile")]
- public bool NoWindowInTile { get; set; } = false;
+ [DataField("noWindowInTile")]
+ public bool NoWindowInTile = false;
- [DataField("onHandInteract")]
- public bool OnHandInteract { get; set; } = true;
+ [DataField("onHandInteract")]
+ public bool OnHandInteract = true;
- [DataField("onInteractUsing")]
- public bool OnInteractUsing { get; set; } = true;
+ [DataField("onInteractUsing")]
+ public bool OnInteractUsing = true;
- [DataField("requirePower")]
- public bool RequirePower { get; } = true;
+ [DataField("requirePower")]
+ public bool RequirePower = true;
- [DataField("usesApcPower")]
- public bool UsesApcPower { get; } = false;
+ [DataField("usesApcPower")]
+ public bool UsesApcPower = false;
- [DataField("highVoltageNode")]
- public string? HighVoltageNode { get; }
+ [DataField("highVoltageNode")]
+ public string? HighVoltageNode;
- [DataField("mediumVoltageNode")]
- public string? MediumVoltageNode { get; }
+ [DataField("mediumVoltageNode")]
+ public string? MediumVoltageNode;
- [DataField("lowVoltageNode")]
- public string? LowVoltageNode { get; }
+ [DataField("lowVoltageNode")]
+ public string? LowVoltageNode;
- [DataField("highVoltageDamageMultiplier")]
- public float HighVoltageDamageMultiplier { get; } = 3f;
+ [DataField("highVoltageDamageMultiplier")]
+ public float HighVoltageDamageMultiplier = 3f;
- [DataField("highVoltageTimeMultiplier")]
- public float HighVoltageTimeMultiplier { get; } = 1.5f;
+ [DataField("highVoltageTimeMultiplier")]
+ public float HighVoltageTimeMultiplier = 1.5f;
- [DataField("mediumVoltageDamageMultiplier")]
- public float MediumVoltageDamageMultiplier { get; } = 2f;
+ [DataField("mediumVoltageDamageMultiplier")]
+ public float MediumVoltageDamageMultiplier = 2f;
- [DataField("mediumVoltageTimeMultiplier")]
- public float MediumVoltageTimeMultiplier { get; } = 1.25f;
+ [DataField("mediumVoltageTimeMultiplier")]
+ public float MediumVoltageTimeMultiplier = 1.25f;
- [DataField("shockDamage")]
- public int ShockDamage { get; } = 20;
+ [DataField("shockDamage")]
+ public int ShockDamage = 20;
- ///
- /// Shock time, in seconds.
- ///
- [DataField("shockTime")]
- public float ShockTime { get; } = 8f;
+ ///
+ /// Shock time, in seconds.
+ ///
+ [DataField("shockTime")]
+ public float ShockTime = 8f;
- [DataField("siemensCoefficient")]
- public float SiemensCoefficient { get; } = 1f;
+ [DataField("siemensCoefficient")]
+ public float SiemensCoefficient = 1f;
- [DataField("shockNoises")]
- public SoundSpecifier ShockNoises { get; } = new SoundCollectionSpecifier("sparks");
+ [DataField("shockNoises")]
+ public SoundSpecifier ShockNoises = new SoundCollectionSpecifier("sparks");
- [DataField("playSoundOnShock")]
- public bool PlaySoundOnShock { get; } = true;
+ [DataField("playSoundOnShock")]
+ public bool PlaySoundOnShock = true;
- [DataField("shockVolume")]
- public float ShockVolume { get; } = 20;
- }
+ [DataField("shockVolume")]
+ public float ShockVolume = 20;
}
diff --git a/Content.Server/Electrocution/Components/ElectrocutionComponent.cs b/Content.Server/Electrocution/Components/ElectrocutionComponent.cs
index a93b55a525..60c752c34d 100644
--- a/Content.Server/Electrocution/Components/ElectrocutionComponent.cs
+++ b/Content.Server/Electrocution/Components/ElectrocutionComponent.cs
@@ -1,16 +1,21 @@
-namespace Content.Server.Electrocution
+namespace Content.Server.Electrocution;
+
+///
+/// Component for virtual electrocution entities (representing an in-progress shock).
+///
+[RegisterComponent]
+[Access(typeof(ElectrocutionSystem))]
+public sealed class ElectrocutionComponent : Component
{
- ///
- /// Component for virtual electrocution entities (representing an in-progress shock).
- ///
- [RegisterComponent]
- [Access(typeof(ElectrocutionSystem))]
- public sealed class ElectrocutionComponent : Component
- {
- [DataField("timeLeft")] public float TimeLeft { get; set; }
- [DataField("electrocuting")] public EntityUid Electrocuting { get; set; }
- [DataField("accumDamage")] public float AccumulatedDamage { get; set; }
- [DataField("source")] public EntityUid Source { get; set; }
+ [DataField("timeLeft")]
+ public float TimeLeft;
+
+ [DataField("electrocuting")]
+ public EntityUid Electrocuting;
+
+ [DataField("accumDamage")]
+ public float AccumulatedDamage;
- }
+ [DataField("source")]
+ public EntityUid Source;
}
diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs
index 811232a86a..11db6184e3 100644
--- a/Content.Server/Electrocution/ElectrocutionSystem.cs
+++ b/Content.Server/Electrocution/ElectrocutionSystem.cs
@@ -23,107 +23,138 @@ using Content.Shared.Tag;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio;
-using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using Robust.Shared.Utility;
-namespace Content.Server.Electrocution
+namespace Content.Server.Electrocution;
+
+public sealed class ElectrocutionSystem : SharedElectrocutionSystem
{
- public sealed class ElectrocutionSystem : SharedElectrocutionSystem
+ [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
+ [Dependency] private readonly SharedJitteringSystem _jittering = default!;
+ [Dependency] private readonly SharedStunSystem _stun = default!;
+ [Dependency] private readonly SharedStutteringSystem _stuttering = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+ [Dependency] private readonly NodeGroupSystem _nodeGroup = default!;
+ [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly TagSystem _tag = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+ private const string StatusEffectKey = "Electrocution";
+ private const string DamageType = "Shock";
+
+ // Yes, this is absurdly small for a reason.
+ private const float ElectrifiedDamagePerWatt = 0.0015f;
+
+ private const float RecursiveDamageMultiplier = 0.75f;
+ private const float RecursiveTimeMultiplier = 0.8f;
+
+ private const float ParalyzeTimeMultiplier = 1f;
+
+ private const float StutteringTimeMultiplier = 1.5f;
+
+ private const float JitterTimeMultiplier = 0.75f;
+ private const float JitterAmplitude = 80f;
+ private const float JitterFrequency = 8f;
+
+ public override void Initialize()
{
- [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
- [Dependency] private readonly SharedJitteringSystem _jitteringSystem = default!;
- [Dependency] private readonly SharedStunSystem _stunSystem = default!;
- [Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!;
- [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
- [Dependency] private readonly DamageableSystem _damageableSystem = default!;
- [Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
- [Dependency] private readonly IAdminLogManager _adminLogger= default!;
- [Dependency] private readonly TagSystem _tagSystem = default!;
-
- private const string StatusEffectKey = "Electrocution";
- private const string DamageType = "Shock";
+ base.Initialize();
- // Yes, this is absurdly small for a reason.
- private const float ElectrifiedDamagePerWatt = 0.0015f;
+ SubscribeLocalEvent(OnElectrifiedStartCollide);
+ SubscribeLocalEvent(OnElectrifiedAttacked);
+ SubscribeLocalEvent(OnElectrifiedHandInteract);
+ SubscribeLocalEvent(OnElectrifiedInteractUsing);
+ SubscribeLocalEvent(OnRandomInsulationMapInit);
- private const float RecursiveDamageMultiplier = 0.75f;
- private const float RecursiveTimeMultiplier = 0.8f;
+ UpdatesAfter.Add(typeof(PowerNetSystem));
+ }
- private const float ParalyzeTimeMultiplier = 1f;
+ public override void Update(float frameTime)
+ {
+ UpdateElectrocutions(frameTime);
+ UpdateState(frameTime);
+ }
- private const float StutteringTimeMultiplier = 1.5f;
+ private void UpdateElectrocutions(float frameTime)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var electrocution, out var consumer))
+ {
+ var timePassed = Math.Min(frameTime, electrocution.TimeLeft);
- private const float JitterTimeMultiplier = 0.75f;
- private const float JitterAmplitude = 80f;
- private const float JitterFrequency = 8f;
+ electrocution.TimeLeft -= timePassed;
+ electrocution.AccumulatedDamage += consumer.ReceivedPower * ElectrifiedDamagePerWatt * timePassed;
- public override void Initialize()
- {
- base.Initialize();
+ if (!MathHelper.CloseTo(electrocution.TimeLeft, 0))
+ continue;
- SubscribeLocalEvent(OnElectrifiedStartCollide);
- SubscribeLocalEvent(OnElectrifiedAttacked);
- SubscribeLocalEvent(OnElectrifiedHandInteract);
- SubscribeLocalEvent(OnElectrifiedInteractUsing);
- SubscribeLocalEvent(OnRandomInsulationMapInit);
+ if (EntityManager.EntityExists(electrocution.Electrocuting))
+ {
+ // TODO: damage should be scaled by shock damage multiplier
+ // TODO: better paralyze/jitter timing
+ var damage = new DamageSpecifier(_prototypeManager.Index(DamageType), (int) electrocution.AccumulatedDamage);
- UpdatesAfter.Add(typeof(PowerNetSystem));
+ var actual = _damageable.TryChangeDamage(electrocution.Electrocuting, damage, origin: electrocution.Source);
+ if (actual != null)
+ {
+ _adminLogger.Add(LogType.Electrocution,
+ $"{ToPrettyString(electrocution.Electrocuting):entity} received {actual.Total:damage} powered electrocution damage from {ToPrettyString(electrocution.Source):source}");
+ }
+ }
+ QueueDel(uid);
}
+ }
- public override void Update(float frameTime)
+ private void UpdateState(float frameTime)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var activated, out var electrified, out var transform))
{
- // Update "in progress" electrocutions
-
- RemQueue finishedElectrocutionsQueue = new();
- foreach (var (electrocution, consumer) in EntityManager
- .EntityQuery())
+ activated.TimeLeft -= frameTime;
+ if (activated.TimeLeft <= 0 || !IsPowered(uid, electrified, transform))
{
- var ftAdjusted = Math.Min(frameTime, electrocution.TimeLeft);
-
- electrocution.TimeLeft -= ftAdjusted;
- electrocution.AccumulatedDamage += consumer.ReceivedPower * ElectrifiedDamagePerWatt * ftAdjusted;
-
- if (MathHelper.CloseTo(electrocution.TimeLeft, 0))
- finishedElectrocutionsQueue.Add(electrocution);
+ _appearance.SetData(uid, ElectrifiedVisuals.IsPowered, false);
+ RemComp(uid);
}
+ }
+ }
- foreach (var finished in finishedElectrocutionsQueue)
+ private bool IsPowered(EntityUid uid, ElectrifiedComponent electrified, TransformComponent transform)
+ {
+ if (!electrified.Enabled)
+ return false;
+ if (electrified.NoWindowInTile)
+ {
+ foreach (var entity in transform.Coordinates.GetEntitiesInTile(LookupFlags.Approximate | LookupFlags.Static, _entityLookup))
{
- var uid = finished.Owner;
- if (EntityManager.EntityExists(finished.Electrocuting))
- {
- // TODO: damage should be scaled by shock damage multiplier
- // TODO: better paralyze/jitter timing
- var damage = new DamageSpecifier(
- _prototypeManager.Index(DamageType),
- (int) finished.AccumulatedDamage);
-
- var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage, origin: finished.Source);
- if (actual != null)
- {
- _adminLogger.Add(LogType.Electrocution,
- $"{ToPrettyString(finished.Electrocuting):entity} received {actual.Total:damage} powered electrocution damage from {ToPrettyString(finished.Source):source}");
- }
- }
-
- EntityManager.DeleteEntity(uid);
+ if (_tag.HasTag(entity, "Window"))
+ return false;
}
}
-
- private void OnElectrifiedStartCollide(EntityUid uid, ElectrifiedComponent electrified, ref StartCollideEvent args)
+ if (electrified.UsesApcPower)
{
- if (!electrified.OnBump)
- return;
+ if (!this.IsPowered(uid, EntityManager))
+ return false;
+ }
+ else if (electrified.RequirePower && PoweredNode(uid, electrified) == null)
+ return false;
+
+ return true;
+ }
+ private void OnElectrifiedStartCollide(EntityUid uid, ElectrifiedComponent electrified, ref StartCollideEvent args)
+ {
+ if (electrified.OnBump)
TryDoElectrifiedAct(uid, args.OtherFixture.Body.Owner, 1, electrified);
- }
+ }
private void OnElectrifiedAttacked(EntityUid uid, ElectrifiedComponent electrified, AttackedEvent args)
{
@@ -138,129 +169,112 @@ namespace Content.Server.Electrocution
}
TryDoElectrifiedAct(uid, args.User, 1, electrified);
- }
-
- private void OnElectrifiedHandInteract(EntityUid uid, ElectrifiedComponent electrified, InteractHandEvent args)
- {
- if (!electrified.OnHandInteract)
- return;
+ }
+ private void OnElectrifiedHandInteract(EntityUid uid, ElectrifiedComponent electrified, InteractHandEvent args)
+ {
+ if (electrified.OnHandInteract)
TryDoElectrifiedAct(uid, args.User, 1, electrified);
- }
+ }
- private void OnElectrifiedInteractUsing(EntityUid uid, ElectrifiedComponent electrified, InteractUsingEvent args)
- {
- if (!electrified.OnInteractUsing)
- return;
+ private void OnElectrifiedInteractUsing(EntityUid uid, ElectrifiedComponent electrified, InteractUsingEvent args)
+ {
+ if (!electrified.OnInteractUsing)
+ return;
- var siemens = TryComp(args.Used, out InsulatedComponent? insulation)
- ? insulation.SiemensCoefficient
- : 1;
+ var siemens = TryComp(args.Used, out var insulation)
+ ? insulation.SiemensCoefficient
+ : 1;
- TryDoElectrifiedAct(uid, args.User, siemens, electrified);
- }
+ TryDoElectrifiedAct(uid, args.User, siemens, electrified);
+ }
- public bool TryDoElectrifiedAct(EntityUid uid, EntityUid targetUid,
- float siemens = 1,
- ElectrifiedComponent? electrified = null,
- NodeContainerComponent? nodeContainer = null,
- TransformComponent? transform = null)
- {
- if (!Resolve(uid, ref electrified, ref transform, false))
- return false;
+ public bool TryDoElectrifiedAct(EntityUid uid, EntityUid targetUid,
+ float siemens = 1,
+ ElectrifiedComponent? electrified = null,
+ NodeContainerComponent? nodeContainer = null,
+ TransformComponent? transform = null)
+ {
+ if (!Resolve(uid, ref electrified, ref transform, false))
+ return false;
- if (!electrified.Enabled)
- return false;
+ if (!IsPowered(uid, electrified, transform))
+ return false;
- if (electrified.NoWindowInTile)
- {
- foreach (var entity in transform.Coordinates.GetEntitiesInTile(
- LookupFlags.Approximate | LookupFlags.Static, _entityLookup))
- {
- if (_tagSystem.HasTag(entity, "Window"))
- return false;
- }
- }
+ EnsureComp(uid);
+ _appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true);
- siemens *= electrified.SiemensCoefficient;
- if (!DoCommonElectrocutionAttempt(targetUid, uid, ref siemens) || siemens <= 0)
- return false; // If electrocution would fail, do nothing.
+ siemens *= electrified.SiemensCoefficient;
+ if (siemens <= 0 || !DoCommonElectrocutionAttempt(targetUid, uid, ref siemens))
+ return false; // If electrocution would fail, do nothing.
- var targets = new List<(EntityUid entity, int depth)>();
- GetChainedElectrocutionTargets(targetUid, targets);
- if (!electrified.RequirePower || electrified.UsesApcPower)
+ var targets = new List<(EntityUid entity, int depth)>();
+ GetChainedElectrocutionTargets(targetUid, targets);
+ if (!electrified.RequirePower || electrified.UsesApcPower)
+ {
+ var lastRet = true;
+ for (var i = targets.Count - 1; i >= 0; i--)
{
- // Does it use APC power for its electrification check? Check if it's powered, and then
- // attempt an electrocution if all the checks succeed.
-
- if (electrified.UsesApcPower && !this.IsPowered(uid, EntityManager))
- {
- return false;
- }
-
- var lastRet = true;
- for (var i = targets.Count - 1; i >= 0; i--)
- {
- var (entity, depth) = targets[i];
- lastRet = TryDoElectrocution(
- entity,
- uid,
- (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)),
- TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)), true,
- electrified.SiemensCoefficient);
- }
-
- return lastRet;
+ var (entity, depth) = targets[i];
+ lastRet = TryDoElectrocution(
+ entity,
+ uid,
+ (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)),
+ TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)),
+ true,
+ electrified.SiemensCoefficient
+ );
}
+ return lastRet;
+ }
- if (!Resolve(uid, ref nodeContainer, false))
- return false;
-
- var node = TryNode(electrified.HighVoltageNode) ??
- TryNode(electrified.MediumVoltageNode) ??
- TryNode(electrified.LowVoltageNode);
-
- if (node == null)
- return false;
+ var node = PoweredNode(uid, electrified, nodeContainer);
+ if (node == null)
+ return false;
- var (damageMult, timeMult) = node.NodeGroupID switch
- {
- NodeGroupID.HVPower => (electrified.HighVoltageDamageMultiplier, electrified.HighVoltageTimeMultiplier),
- NodeGroupID.MVPower => (electrified.MediumVoltageDamageMultiplier,
- electrified.MediumVoltageTimeMultiplier),
- _ => (1f, 1f)
- };
+ var (damageMult, timeMult) = node.NodeGroupID switch
+ {
+ NodeGroupID.HVPower => (electrified.HighVoltageDamageMultiplier, electrified.HighVoltageTimeMultiplier),
+ NodeGroupID.MVPower => (electrified.MediumVoltageDamageMultiplier, electrified.MediumVoltageTimeMultiplier),
+ _ => (1f, 1f)
+ };
+ {
+ var lastRet = true;
+ for (var i = targets.Count - 1; i >= 0; i--)
{
- var lastRet = true;
- for (var i = targets.Count - 1; i >= 0; i--)
- {
- var (entity, depth) = targets[i];
- lastRet = TryDoElectrocutionPowered(
- entity,
- uid,
- node,
- (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth) * damageMult),
- TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth) *
- timeMult), true,
- electrified.SiemensCoefficient);
- }
-
- return lastRet;
+ var (entity, depth) = targets[i];
+ lastRet = TryDoElectrocutionPowered(
+ entity,
+ uid,
+ node,
+ (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth) * damageMult),
+ TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth) * timeMult),
+ true,
+ electrified.SiemensCoefficient);
}
+ return lastRet;
+ }
+ }
+ private Node? PoweredNode(EntityUid uid, ElectrifiedComponent electrified, NodeContainerComponent? nodeContainer = null)
+ {
+ if (!Resolve(uid, ref nodeContainer, false))
+ return null;
- Node? TryNode(string? id)
- {
- if (id != null && nodeContainer.TryGetNode(id, out var tryNode)
- && tryNode.NodeGroup is IBasePowerNet { NetworkNode: { LastCombinedSupply: >0 } })
- {
- return tryNode;
- }
+ return TryNode(electrified.HighVoltageNode) ?? TryNode(electrified.MediumVoltageNode) ?? TryNode(electrified.LowVoltageNode);
- return null;
+ Node? TryNode(string? id)
+ {
+ if (id != null &&
+ nodeContainer.TryGetNode(id, out var tryNode) &&
+ tryNode.NodeGroup is IBasePowerNet { NetworkNode: { LastCombinedSupply: > 0 } })
+ {
+ return tryNode;
}
+ return null;
}
+ }
/// Entity being electrocuted.
/// Source entity of the electrocution.
@@ -283,184 +297,178 @@ namespace Content.Server.Electrocution
return true;
}
- private bool TryDoElectrocutionPowered(
- EntityUid uid,
- EntityUid sourceUid,
- Node node,
- int shockDamage,
- TimeSpan time,
- bool refresh,
- float siemensCoefficient = 1f,
- StatusEffectsComponent? statusEffects = null,
- TransformComponent? sourceTransform = null)
- {
- if (!DoCommonElectrocutionAttempt(uid, sourceUid, ref siemensCoefficient))
- return false;
-
- // Coefficient needs to be higher than this to do a powered electrocution!
- if (siemensCoefficient <= 0.5f)
- return DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects);
+ private bool TryDoElectrocutionPowered(
+ EntityUid uid,
+ EntityUid sourceUid,
+ Node node,
+ int shockDamage,
+ TimeSpan time,
+ bool refresh,
+ float siemensCoefficient = 1f,
+ StatusEffectsComponent? statusEffects = null,
+ TransformComponent? sourceTransform = null)
+ {
+ if (!DoCommonElectrocutionAttempt(uid, sourceUid, ref siemensCoefficient))
+ return false;
- if (!DoCommonElectrocution(uid, sourceUid, null, time, refresh, siemensCoefficient, statusEffects))
- return false;
+ // Coefficient needs to be higher than this to do a powered electrocution!
+ if (siemensCoefficient <= 0.5f)
+ return DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects);
- if (!Resolve(sourceUid, ref sourceTransform)) // This shouldn't really happen, but just in case...
- return true;
+ if (!DoCommonElectrocution(uid, sourceUid, null, time, refresh, siemensCoefficient, statusEffects))
+ return false;
- var electrocutionEntity = EntityManager.SpawnEntity(
- $"VirtualElectrocutionLoad{node.NodeGroupID}", sourceTransform.Coordinates);
+ if (!Resolve(sourceUid, ref sourceTransform)) // This shouldn't really happen, but just in case...
+ return true;
- var electrocutionNode = EntityManager.GetComponent(electrocutionEntity)
- .GetNode("electrocution");
+ var electrocutionEntity = Spawn($"VirtualElectrocutionLoad{node.NodeGroupID}", sourceTransform.Coordinates);
+ var electrocutionNode = Comp(electrocutionEntity).GetNode("electrocution");
+ var electrocutionComponent = Comp(electrocutionEntity);
- var electrocutionComponent = EntityManager.GetComponent(electrocutionEntity);
+ electrocutionNode.CableEntity = sourceUid;
+ electrocutionNode.NodeName = node.Name;
- electrocutionNode.CableEntity = sourceUid;
- electrocutionNode.NodeName = node.Name;
+ _nodeGroup.QueueReflood(electrocutionNode);
- _nodeGroupSystem.QueueReflood(electrocutionNode);
+ electrocutionComponent.TimeLeft = 1f;
+ electrocutionComponent.Electrocuting = uid;
+ electrocutionComponent.Source = sourceUid;
- electrocutionComponent.TimeLeft = 1f;
- electrocutionComponent.Electrocuting = uid;
- electrocutionComponent.Source = sourceUid;
+ RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true);
- RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true);
+ return true;
+ }
- return true;
- }
+ private bool DoCommonElectrocutionAttempt(EntityUid uid, EntityUid? sourceUid, ref float siemensCoefficient, bool ignoreInsulation = false)
+ {
- private bool DoCommonElectrocutionAttempt(EntityUid uid, EntityUid? sourceUid, ref float siemensCoefficient, bool ignoreInsulation = false)
- {
+ var attemptEvent = new ElectrocutionAttemptEvent(uid, sourceUid, siemensCoefficient,
+ ignoreInsulation ? SlotFlags.NONE : ~SlotFlags.POCKET);
+ RaiseLocalEvent(uid, attemptEvent, true);
- var attemptEvent = new ElectrocutionAttemptEvent(uid, sourceUid, siemensCoefficient,
- ignoreInsulation ? SlotFlags.NONE : ~SlotFlags.POCKET);
- RaiseLocalEvent(uid, attemptEvent, true);
+ // Cancel the electrocution early, so we don't recursively electrocute anything.
+ if (attemptEvent.Cancelled)
+ return false;
- // Cancel the electrocution early, so we don't recursively electrocute anything.
- if (attemptEvent.Cancelled)
- return false;
+ siemensCoefficient = attemptEvent.SiemensCoefficient;
+ return true;
+ }
- siemensCoefficient = attemptEvent.SiemensCoefficient;
- return true;
- }
+ private bool DoCommonElectrocution(EntityUid uid, EntityUid? sourceUid,
+ int? shockDamage, TimeSpan time, bool refresh, float siemensCoefficient = 1f,
+ StatusEffectsComponent? statusEffects = null)
+ {
+ if (siemensCoefficient <= 0)
+ return false;
- private bool DoCommonElectrocution(EntityUid uid, EntityUid? sourceUid,
- int? shockDamage, TimeSpan time, bool refresh, float siemensCoefficient = 1f,
- StatusEffectsComponent? statusEffects = null)
+ if (shockDamage != null)
{
- if (siemensCoefficient <= 0)
- return false;
-
- if (shockDamage != null)
- {
- shockDamage = (int) (shockDamage * siemensCoefficient);
+ shockDamage = (int) (shockDamage * siemensCoefficient);
- if (shockDamage.Value <= 0)
- return false;
- }
-
- if (!Resolve(uid, ref statusEffects, false) ||
- !_statusEffectsSystem.CanApplyEffect(uid, StatusEffectKey, statusEffects))
+ if (shockDamage.Value <= 0)
return false;
+ }
- if (!_statusEffectsSystem.TryAddStatusEffect(uid, StatusEffectKey, time, refresh,
- statusEffects))
- return false;
+ if (!Resolve(uid, ref statusEffects, false) ||
+ !_statusEffects.CanApplyEffect(uid, StatusEffectKey, statusEffects))
+ {
+ return false;
+ }
+
+ if (!_statusEffects.TryAddStatusEffect(uid, StatusEffectKey, time, refresh, statusEffects))
+ return false;
- var shouldStun = siemensCoefficient > 0.5f;
+ var shouldStun = siemensCoefficient > 0.5f;
- if (shouldStun)
- _stunSystem.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects);
+ if (shouldStun)
+ _stun.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects);
- // TODO: Sparks here.
+ // TODO: Sparks here.
- if(shockDamage is {} dmg)
- {
- var actual = _damageableSystem.TryChangeDamage(uid,
- new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), origin: sourceUid);
+ if (shockDamage is { } dmg)
+ {
+ var actual = _damageable.TryChangeDamage(uid,
+ new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), origin: sourceUid);
- if (actual != null)
- {
- _adminLogger.Add(LogType.Electrocution,
- $"{ToPrettyString(statusEffects.Owner):entity} received {actual.Total:damage} powered electrocution damage{(sourceUid != null ? " from " + ToPrettyString(sourceUid.Value) : ""):source}");
- }
+ if (actual != null)
+ {
+ _adminLogger.Add(LogType.Electrocution,
+ $"{ToPrettyString(uid):entity} received {actual.Total:damage} powered electrocution damage{(sourceUid != null ? " from " + ToPrettyString(sourceUid.Value) : ""):source}");
}
+ }
- _stutteringSystem.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects);
- _jitteringSystem.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true,
- statusEffects);
-
- _popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid, uid);
+ _stuttering.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects);
+ _jittering.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true, statusEffects);
- var filter = Filter.PvsExcept(uid, entityManager: EntityManager);
+ _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid, uid);
- // TODO: Allow being able to pass EntityUid to Loc...
- if (sourceUid != null)
- {
- _popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-by-source-popup-others",
- ("mob", uid), ("source", (sourceUid.Value))), uid, filter, true);
- PlayElectrocutionSound(uid, sourceUid.Value);
- }
- else
- {
- _popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-others",
- ("mob", uid)), uid, filter, true);
- }
+ var filter = Filter.PvsExcept(uid, entityManager: EntityManager);
- return true;
+ // TODO: Allow being able to pass EntityUid to Loc...
+ if (sourceUid != null)
+ {
+ _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-by-source-popup-others",
+ ("mob", uid), ("source", (sourceUid.Value))), uid, filter, true);
+ PlayElectrocutionSound(uid, sourceUid.Value);
}
-
- private void GetChainedElectrocutionTargets(EntityUid source, List<(EntityUid entity, int depth)> all)
+ else
{
- var visited = new HashSet();
-
- GetChainedElectrocutionTargetsRecurse(source, 1, visited, all);
+ _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-others",
+ ("mob", uid)), uid, filter, true);
}
- private void GetChainedElectrocutionTargetsRecurse(
- EntityUid entity,
- int depth,
- HashSet visited,
- List<(EntityUid entity, int depth)> all)
- {
- all.Add((entity, depth));
- visited.Add(entity);
+ return true;
+ }
- if (EntityManager.TryGetComponent(entity, out SharedPullableComponent? pullable)
- && pullable.Puller is {Valid: true} pullerId
- && !visited.Contains(pullerId))
- {
- GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all);
- }
+ private void GetChainedElectrocutionTargets(EntityUid source, List<(EntityUid entity, int depth)> all)
+ {
+ var visited = new HashSet();
- if (EntityManager.TryGetComponent(entity, out SharedPullerComponent? puller)
- && puller.Pulling is {Valid: true} pullingId
- && !visited.Contains(pullingId))
- {
- GetChainedElectrocutionTargetsRecurse(pullingId, depth + 1, visited, all);
- }
+ GetChainedElectrocutionTargetsRecurse(source, 1, visited, all);
+ }
+
+ private void GetChainedElectrocutionTargetsRecurse(
+ EntityUid entity,
+ int depth,
+ HashSet visited,
+ List<(EntityUid entity, int depth)> all)
+ {
+ all.Add((entity, depth));
+ visited.Add(entity);
+
+ if (TryComp(entity, out var pullable) &&
+ pullable.Puller is { Valid: true } pullerId &&
+ !visited.Contains(pullerId))
+ {
+ GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all);
}
- private void OnRandomInsulationMapInit(EntityUid uid, RandomInsulationComponent randomInsulation,
- MapInitEvent args)
+ if (TryComp(entity, out var puller) &&
+ puller.Pulling is { Valid: true } pullingId &&
+ !visited.Contains(pullingId))
{
- if (!EntityManager.TryGetComponent(uid, out InsulatedComponent? insulated))
- return;
+ GetChainedElectrocutionTargetsRecurse(pullingId, depth + 1, visited, all);
+ }
+ }
- if (randomInsulation.List.Length == 0)
- return;
+ private void OnRandomInsulationMapInit(EntityUid uid, RandomInsulationComponent randomInsulation,
+ MapInitEvent args)
+ {
+ if (!TryComp(uid, out var insulated))
+ return;
- SetInsulatedSiemensCoefficient(uid, _random.Pick(randomInsulation.List), insulated);
- }
+ if (randomInsulation.List.Length == 0)
+ return;
- private void PlayElectrocutionSound(EntityUid targetUid, EntityUid sourceUid, ElectrifiedComponent? electrified = null)
- {
- if (!Resolve(sourceUid, ref electrified) || !electrified.PlaySoundOnShock)
- {
- return;
- }
+ SetInsulatedSiemensCoefficient(uid, _random.Pick(randomInsulation.List), insulated);
+ }
- SoundSystem.Play(electrified.ShockNoises.GetSound(), Filter.Pvs(targetUid), targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
+ private void PlayElectrocutionSound(EntityUid targetUid, EntityUid sourceUid, ElectrifiedComponent? electrified = null)
+ {
+ if (!Resolve(sourceUid, ref electrified) || !electrified.PlaySoundOnShock)
+ {
+ return;
}
+ _audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
}
}
diff --git a/Content.Shared/Electrocution/SharedElectrocution.cs b/Content.Shared/Electrocution/SharedElectrocution.cs
new file mode 100644
index 0000000000..4060856d4d
--- /dev/null
+++ b/Content.Shared/Electrocution/SharedElectrocution.cs
@@ -0,0 +1,15 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Electrocution;
+
+[Serializable, NetSerializable]
+public enum ElectrifiedLayers : byte
+{
+ Powered
+}
+
+[Serializable, NetSerializable]
+public enum ElectrifiedVisuals : byte
+{
+ IsPowered
+}
diff --git a/Resources/Prototypes/Entities/Structures/Walls/grille.yml b/Resources/Prototypes/Entities/Structures/Walls/grille.yml
index b3123dc6a7..9ebacb7779 100644
--- a/Resources/Prototypes/Entities/Structures/Walls/grille.yml
+++ b/Resources/Prototypes/Entities/Structures/Walls/grille.yml
@@ -17,7 +17,13 @@
netsync: false
drawdepth: Walls
sprite: Structures/Walls/grille.rsi
- state: grille
+ layers:
+ - state: grille
+ - state: electrified
+ sprite: Effects/electricity.rsi
+ map: ["enum.ElectrifiedLayers.Powered"]
+ shader: unshaded
+ visible: false
- type: Icon
sprite: Structures/Walls/grille.rsi
state: grille
@@ -71,6 +77,14 @@
node: grilleBroken
- !type:DoActsBehavior
acts: ["Breakage"]
+ - type: Appearance
+ - type: GenericVisualizer
+ visuals:
+ enum.ElectrifiedVisuals.IsPowered:
+ enum.ElectrifiedLayers.Powered:
+ True: { visible: True }
+ False: { visible: False }
+ - type: AnimationPlayer
- type: entity
id: GrilleBroken
diff --git a/Resources/Textures/Effects/electricity.rsi/electrified.png b/Resources/Textures/Effects/electricity.rsi/electrified.png
new file mode 100644
index 0000000000000000000000000000000000000000..ec6a863bf93c7efc5240508ec7937263d199113b
GIT binary patch
literal 1047
zcmV+y1nB#TP)#Uev_Jt!2u`4tD1a8&D|afO5_&*dJ>>B6HZR19Lm2~H|LvzYYy4lj
zC(1fQ-l+gU`Pwc`g#gz9h|={K9FSc)6io*}QILmgN)Q0R_#xpod
zpn5^{Udg2V3;?qI(?_)!9m_7v?WGi_IZg~glA$O7&=@#XL@nWA3X`0q6qJje1bc)j
z05}Tp3?MaH&fL;_LRAtoyQfKek|iokLsu>VcudwI0cSZBGp?k{;{
z+OTn(wrc?AZk0Qjlma|fOs$Z}HJGkWP)fn2m?}NCh>=i&sDb`SO05fuwNeIF$(klSX#?T!AfD`u&W&=r&s^ojv
zTC%tTkS0Q{3AggWX}tMY-6Vjt1Jo+R_(8
z+L&2*L;8HrAt*Mp*h}HV0IWLXR=w{f1htHl4IpkG!tRmPdtaeLM><|F06fqC$*|CS`eq#VdQoV^jK9)V1GSqRU>)bV
z-mn`0ac#=8wU;2V09coFaU!7sJpVx-vPCcG2H-{cdGC?G(ZUT0v+rX803l(6!9#+x
zZU8|CBSzT`AhnP!y1bT!$J2x9_>_Fa24HP@BUYyc;mSCPOEU)m1sXlZ`4{vsa7N{U
R<_!P<002ovPDHLkV1ix6$mIY4
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Effects/electricity.rsi/meta.json b/Resources/Textures/Effects/electricity.rsi/meta.json
new file mode 100644
index 0000000000..0b762debd0
--- /dev/null
+++ b/Resources/Textures/Effects/electricity.rsi/meta.json
@@ -0,0 +1,24 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "made by Aleksh#7552 (Discord) / Alekshhh (Github) for SS14",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "electrified",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
--
2.51.2