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
This commit is contained in:
Slava0135
2023-04-29 23:05:10 +03:00
committed by GitHub
parent 174b28e62c
commit 4ade6f60ff
8 changed files with 504 additions and 425 deletions

View File

@@ -0,0 +1,14 @@
namespace Content.Server.Electrocution;
/// <summary>
/// Updates every frame for short duration to check if electrifed entity is powered when activated, e.g to play animation
/// </summary>
[RegisterComponent]
public sealed class ActivatedElectrifiedComponent : Component
{
/// <summary>
/// How long electrified entity will remain active
/// </summary>
[ViewVariables]
public float TimeLeft = 1f;
}

View File

@@ -1,77 +1,76 @@
using Robust.Shared.Audio; using Robust.Shared.Audio;
namespace Content.Server.Electrocution namespace Content.Server.Electrocution;
/// <summary>
/// Component for things that shock users on touch.
/// </summary>
[RegisterComponent]
public sealed class ElectrifiedComponent : Component
{ {
/// <summary>
/// Component for things that shock users on touch.
/// </summary>
[RegisterComponent]
public sealed class ElectrifiedComponent : Component
{
[DataField("enabled")] [DataField("enabled")]
public bool Enabled { get; set; } = true; public bool Enabled = true;
[DataField("onBump")] [DataField("onBump")]
public bool OnBump { get; set; } = true; public bool OnBump = true;
[DataField("onAttacked")] [DataField("onAttacked")]
public bool OnAttacked { get; set; } = true; public bool OnAttacked = true;
[DataField("noWindowInTile")] [DataField("noWindowInTile")]
public bool NoWindowInTile { get; set; } = false; public bool NoWindowInTile = false;
[DataField("onHandInteract")] [DataField("onHandInteract")]
public bool OnHandInteract { get; set; } = true; public bool OnHandInteract = true;
[DataField("onInteractUsing")] [DataField("onInteractUsing")]
public bool OnInteractUsing { get; set; } = true; public bool OnInteractUsing = true;
[DataField("requirePower")] [DataField("requirePower")]
public bool RequirePower { get; } = true; public bool RequirePower = true;
[DataField("usesApcPower")] [DataField("usesApcPower")]
public bool UsesApcPower { get; } = false; public bool UsesApcPower = false;
[DataField("highVoltageNode")] [DataField("highVoltageNode")]
public string? HighVoltageNode { get; } public string? HighVoltageNode;
[DataField("mediumVoltageNode")] [DataField("mediumVoltageNode")]
public string? MediumVoltageNode { get; } public string? MediumVoltageNode;
[DataField("lowVoltageNode")] [DataField("lowVoltageNode")]
public string? LowVoltageNode { get; } public string? LowVoltageNode;
[DataField("highVoltageDamageMultiplier")] [DataField("highVoltageDamageMultiplier")]
public float HighVoltageDamageMultiplier { get; } = 3f; public float HighVoltageDamageMultiplier = 3f;
[DataField("highVoltageTimeMultiplier")] [DataField("highVoltageTimeMultiplier")]
public float HighVoltageTimeMultiplier { get; } = 1.5f; public float HighVoltageTimeMultiplier = 1.5f;
[DataField("mediumVoltageDamageMultiplier")] [DataField("mediumVoltageDamageMultiplier")]
public float MediumVoltageDamageMultiplier { get; } = 2f; public float MediumVoltageDamageMultiplier = 2f;
[DataField("mediumVoltageTimeMultiplier")] [DataField("mediumVoltageTimeMultiplier")]
public float MediumVoltageTimeMultiplier { get; } = 1.25f; public float MediumVoltageTimeMultiplier = 1.25f;
[DataField("shockDamage")] [DataField("shockDamage")]
public int ShockDamage { get; } = 20; public int ShockDamage = 20;
/// <summary> /// <summary>
/// Shock time, in seconds. /// Shock time, in seconds.
/// </summary> /// </summary>
[DataField("shockTime")] [DataField("shockTime")]
public float ShockTime { get; } = 8f; public float ShockTime = 8f;
[DataField("siemensCoefficient")] [DataField("siemensCoefficient")]
public float SiemensCoefficient { get; } = 1f; public float SiemensCoefficient = 1f;
[DataField("shockNoises")] [DataField("shockNoises")]
public SoundSpecifier ShockNoises { get; } = new SoundCollectionSpecifier("sparks"); public SoundSpecifier ShockNoises = new SoundCollectionSpecifier("sparks");
[DataField("playSoundOnShock")] [DataField("playSoundOnShock")]
public bool PlaySoundOnShock { get; } = true; public bool PlaySoundOnShock = true;
[DataField("shockVolume")] [DataField("shockVolume")]
public float ShockVolume { get; } = 20; public float ShockVolume = 20;
}
} }

View File

@@ -1,16 +1,21 @@
namespace Content.Server.Electrocution namespace Content.Server.Electrocution;
{
/// <summary>
/// Component for virtual electrocution entities (representing an in-progress shock).
/// </summary>
[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; }
} /// <summary>
/// Component for virtual electrocution entities (representing an in-progress shock).
/// </summary>
[RegisterComponent]
[Access(typeof(ElectrocutionSystem))]
public sealed class ElectrocutionComponent : Component
{
[DataField("timeLeft")]
public float TimeLeft;
[DataField("electrocuting")]
public EntityUid Electrocuting;
[DataField("accumDamage")]
public float AccumulatedDamage;
[DataField("source")]
public EntityUid Source;
} }

View File

@@ -23,29 +23,29 @@ using Content.Shared.Tag;
using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Events;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; 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 EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
[Dependency] private readonly SharedJitteringSystem _jitteringSystem = default!; [Dependency] private readonly SharedJitteringSystem _jittering = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!; [Dependency] private readonly SharedStutteringSystem _stuttering = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!; [Dependency] private readonly NodeGroupSystem _nodeGroup = default!;
[Dependency] private readonly IAdminLogManager _adminLogger= default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly TagSystem _tagSystem = 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 StatusEffectKey = "Electrocution";
private const string DamageType = "Shock"; private const string DamageType = "Shock";
@@ -79,49 +79,80 @@ namespace Content.Server.Electrocution
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
// Update "in progress" electrocutions UpdateElectrocutions(frameTime);
UpdateState(frameTime);
RemQueue<ElectrocutionComponent> finishedElectrocutionsQueue = new();
foreach (var (electrocution, consumer) in EntityManager
.EntityQuery<ElectrocutionComponent, PowerConsumerComponent>())
{
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);
} }
foreach (var finished in finishedElectrocutionsQueue) private void UpdateElectrocutions(float frameTime)
{ {
var uid = finished.Owner; var query = EntityQueryEnumerator<ElectrocutionComponent, PowerConsumerComponent>();
if (EntityManager.EntityExists(finished.Electrocuting)) while (query.MoveNext(out var uid, out var electrocution, out var consumer))
{
var timePassed = Math.Min(frameTime, electrocution.TimeLeft);
electrocution.TimeLeft -= timePassed;
electrocution.AccumulatedDamage += consumer.ReceivedPower * ElectrifiedDamagePerWatt * timePassed;
if (!MathHelper.CloseTo(electrocution.TimeLeft, 0))
continue;
if (EntityManager.EntityExists(electrocution.Electrocuting))
{ {
// TODO: damage should be scaled by shock damage multiplier // TODO: damage should be scaled by shock damage multiplier
// TODO: better paralyze/jitter timing // TODO: better paralyze/jitter timing
var damage = new DamageSpecifier( var damage = new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>(DamageType), (int) electrocution.AccumulatedDamage);
_prototypeManager.Index<DamageTypePrototype>(DamageType),
(int) finished.AccumulatedDamage);
var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage, origin: finished.Source); var actual = _damageable.TryChangeDamage(electrocution.Electrocuting, damage, origin: electrocution.Source);
if (actual != null) if (actual != null)
{ {
_adminLogger.Add(LogType.Electrocution, _adminLogger.Add(LogType.Electrocution,
$"{ToPrettyString(finished.Electrocuting):entity} received {actual.Total:damage} powered electrocution damage from {ToPrettyString(finished.Source):source}"); $"{ToPrettyString(electrocution.Electrocuting):entity} received {actual.Total:damage} powered electrocution damage from {ToPrettyString(electrocution.Source):source}");
}
}
QueueDel(uid);
} }
} }
EntityManager.DeleteEntity(uid); private void UpdateState(float frameTime)
{
var query = EntityQueryEnumerator<ActivatedElectrifiedComponent, ElectrifiedComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var activated, out var electrified, out var transform))
{
activated.TimeLeft -= frameTime;
if (activated.TimeLeft <= 0 || !IsPowered(uid, electrified, transform))
{
_appearance.SetData(uid, ElectrifiedVisuals.IsPowered, false);
RemComp<ActivatedElectrifiedComponent>(uid);
} }
} }
}
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))
{
if (_tag.HasTag(entity, "Window"))
return false;
}
}
if (electrified.UsesApcPower)
{
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) private void OnElectrifiedStartCollide(EntityUid uid, ElectrifiedComponent electrified, ref StartCollideEvent args)
{ {
if (!electrified.OnBump) if (electrified.OnBump)
return;
TryDoElectrifiedAct(uid, args.OtherFixture.Body.Owner, 1, electrified); TryDoElectrifiedAct(uid, args.OtherFixture.Body.Owner, 1, electrified);
} }
@@ -142,9 +173,7 @@ namespace Content.Server.Electrocution
private void OnElectrifiedHandInteract(EntityUid uid, ElectrifiedComponent electrified, InteractHandEvent args) private void OnElectrifiedHandInteract(EntityUid uid, ElectrifiedComponent electrified, InteractHandEvent args)
{ {
if (!electrified.OnHandInteract) if (electrified.OnHandInteract)
return;
TryDoElectrifiedAct(uid, args.User, 1, electrified); TryDoElectrifiedAct(uid, args.User, 1, electrified);
} }
@@ -153,7 +182,7 @@ namespace Content.Server.Electrocution
if (!electrified.OnInteractUsing) if (!electrified.OnInteractUsing)
return; return;
var siemens = TryComp(args.Used, out InsulatedComponent? insulation) var siemens = TryComp<InsulatedComponent>(args.Used, out var insulation)
? insulation.SiemensCoefficient ? insulation.SiemensCoefficient
: 1; : 1;
@@ -169,35 +198,20 @@ namespace Content.Server.Electrocution
if (!Resolve(uid, ref electrified, ref transform, false)) if (!Resolve(uid, ref electrified, ref transform, false))
return false; return false;
if (!electrified.Enabled) if (!IsPowered(uid, electrified, transform))
return false; return false;
if (electrified.NoWindowInTile) EnsureComp<ActivatedElectrifiedComponent>(uid);
{ _appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true);
foreach (var entity in transform.Coordinates.GetEntitiesInTile(
LookupFlags.Approximate | LookupFlags.Static, _entityLookup))
{
if (_tagSystem.HasTag(entity, "Window"))
return false;
}
}
siemens *= electrified.SiemensCoefficient; siemens *= electrified.SiemensCoefficient;
if (!DoCommonElectrocutionAttempt(targetUid, uid, ref siemens) || siemens <= 0) if (siemens <= 0 || !DoCommonElectrocutionAttempt(targetUid, uid, ref siemens))
return false; // If electrocution would fail, do nothing. return false; // If electrocution would fail, do nothing.
var targets = new List<(EntityUid entity, int depth)>(); var targets = new List<(EntityUid entity, int depth)>();
GetChainedElectrocutionTargets(targetUid, targets); GetChainedElectrocutionTargets(targetUid, targets);
if (!electrified.RequirePower || electrified.UsesApcPower) if (!electrified.RequirePower || electrified.UsesApcPower)
{ {
// 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; var lastRet = true;
for (var i = targets.Count - 1; i >= 0; i--) for (var i = targets.Count - 1; i >= 0; i--)
{ {
@@ -206,28 +220,22 @@ namespace Content.Server.Electrocution
entity, entity,
uid, uid,
(int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)), (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)),
TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)), true, TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)),
electrified.SiemensCoefficient); true,
electrified.SiemensCoefficient
);
} }
return lastRet; return lastRet;
} }
if (!Resolve(uid, ref nodeContainer, false)) var node = PoweredNode(uid, electrified, nodeContainer);
return false;
var node = TryNode(electrified.HighVoltageNode) ??
TryNode(electrified.MediumVoltageNode) ??
TryNode(electrified.LowVoltageNode);
if (node == null) if (node == null)
return false; return false;
var (damageMult, timeMult) = node.NodeGroupID switch var (damageMult, timeMult) = node.NodeGroupID switch
{ {
NodeGroupID.HVPower => (electrified.HighVoltageDamageMultiplier, electrified.HighVoltageTimeMultiplier), NodeGroupID.HVPower => (electrified.HighVoltageDamageMultiplier, electrified.HighVoltageTimeMultiplier),
NodeGroupID.MVPower => (electrified.MediumVoltageDamageMultiplier, NodeGroupID.MVPower => (electrified.MediumVoltageDamageMultiplier, electrified.MediumVoltageTimeMultiplier),
electrified.MediumVoltageTimeMultiplier),
_ => (1f, 1f) _ => (1f, 1f)
}; };
@@ -241,23 +249,29 @@ namespace Content.Server.Electrocution
uid, uid,
node, node,
(int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth) * damageMult), (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth) * damageMult),
TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth) * TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth) * timeMult),
timeMult), true, true,
electrified.SiemensCoefficient); electrified.SiemensCoefficient);
} }
return lastRet; return lastRet;
} }
}
private Node? PoweredNode(EntityUid uid, ElectrifiedComponent electrified, NodeContainerComponent? nodeContainer = null)
{
if (!Resolve(uid, ref nodeContainer, false))
return null;
return TryNode(electrified.HighVoltageNode) ?? TryNode(electrified.MediumVoltageNode) ?? TryNode(electrified.LowVoltageNode);
Node? TryNode(string? id) Node? TryNode(string? id)
{ {
if (id != null && nodeContainer.TryGetNode<Node>(id, out var tryNode) if (id != null &&
&& tryNode.NodeGroup is IBasePowerNet { NetworkNode: { LastCombinedSupply: >0 } }) nodeContainer.TryGetNode<Node>(id, out var tryNode) &&
tryNode.NodeGroup is IBasePowerNet { NetworkNode: { LastCombinedSupply: > 0 } })
{ {
return tryNode; return tryNode;
} }
return null; return null;
} }
} }
@@ -307,18 +321,14 @@ namespace Content.Server.Electrocution
if (!Resolve(sourceUid, ref sourceTransform)) // This shouldn't really happen, but just in case... if (!Resolve(sourceUid, ref sourceTransform)) // This shouldn't really happen, but just in case...
return true; return true;
var electrocutionEntity = EntityManager.SpawnEntity( var electrocutionEntity = Spawn($"VirtualElectrocutionLoad{node.NodeGroupID}", sourceTransform.Coordinates);
$"VirtualElectrocutionLoad{node.NodeGroupID}", sourceTransform.Coordinates); var electrocutionNode = Comp<NodeContainerComponent>(electrocutionEntity).GetNode<ElectrocutionNode>("electrocution");
var electrocutionComponent = Comp<ElectrocutionComponent>(electrocutionEntity);
var electrocutionNode = EntityManager.GetComponent<NodeContainerComponent>(electrocutionEntity)
.GetNode<ElectrocutionNode>("electrocution");
var electrocutionComponent = EntityManager.GetComponent<ElectrocutionComponent>(electrocutionEntity);
electrocutionNode.CableEntity = sourceUid; electrocutionNode.CableEntity = sourceUid;
electrocutionNode.NodeName = node.Name; electrocutionNode.NodeName = node.Name;
_nodeGroupSystem.QueueReflood(electrocutionNode); _nodeGroup.QueueReflood(electrocutionNode);
electrocutionComponent.TimeLeft = 1f; electrocutionComponent.TimeLeft = 1f;
electrocutionComponent.Electrocuting = uid; electrocutionComponent.Electrocuting = uid;
@@ -360,50 +370,50 @@ namespace Content.Server.Electrocution
} }
if (!Resolve(uid, ref statusEffects, false) || if (!Resolve(uid, ref statusEffects, false) ||
!_statusEffectsSystem.CanApplyEffect(uid, StatusEffectKey, statusEffects)) !_statusEffects.CanApplyEffect(uid, StatusEffectKey, statusEffects))
{
return false; return false;
}
if (!_statusEffectsSystem.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusEffectKey, time, refresh, if (!_statusEffects.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusEffectKey, time, refresh, statusEffects))
statusEffects))
return false; return false;
var shouldStun = siemensCoefficient > 0.5f; var shouldStun = siemensCoefficient > 0.5f;
if (shouldStun) if (shouldStun)
_stunSystem.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects); _stun.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects);
// TODO: Sparks here. // TODO: Sparks here.
if(shockDamage is {} dmg) if (shockDamage is { } dmg)
{ {
var actual = _damageableSystem.TryChangeDamage(uid, var actual = _damageable.TryChangeDamage(uid,
new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>(DamageType), dmg), origin: sourceUid); new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>(DamageType), dmg), origin: sourceUid);
if (actual != null) if (actual != null)
{ {
_adminLogger.Add(LogType.Electrocution, _adminLogger.Add(LogType.Electrocution,
$"{ToPrettyString(statusEffects.Owner):entity} received {actual.Total:damage} powered electrocution damage{(sourceUid != null ? " from " + ToPrettyString(sourceUid.Value) : ""):source}"); $"{ToPrettyString(uid):entity} received {actual.Total:damage} powered electrocution damage{(sourceUid != null ? " from " + ToPrettyString(sourceUid.Value) : ""):source}");
} }
} }
_stutteringSystem.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects); _stuttering.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects);
_jitteringSystem.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true, _jittering.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true, statusEffects);
statusEffects);
_popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid, uid); _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid, uid);
var filter = Filter.PvsExcept(uid, entityManager: EntityManager); var filter = Filter.PvsExcept(uid, entityManager: EntityManager);
// TODO: Allow being able to pass EntityUid to Loc... // TODO: Allow being able to pass EntityUid to Loc...
if (sourceUid != null) if (sourceUid != null)
{ {
_popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-by-source-popup-others", _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-by-source-popup-others",
("mob", uid), ("source", (sourceUid.Value))), uid, filter, true); ("mob", uid), ("source", (sourceUid.Value))), uid, filter, true);
PlayElectrocutionSound(uid, sourceUid.Value); PlayElectrocutionSound(uid, sourceUid.Value);
} }
else else
{ {
_popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-others", _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-others",
("mob", uid)), uid, filter, true); ("mob", uid)), uid, filter, true);
} }
@@ -426,16 +436,16 @@ namespace Content.Server.Electrocution
all.Add((entity, depth)); all.Add((entity, depth));
visited.Add(entity); visited.Add(entity);
if (EntityManager.TryGetComponent(entity, out SharedPullableComponent? pullable) if (TryComp<SharedPullableComponent>(entity, out var pullable) &&
&& pullable.Puller is {Valid: true} pullerId pullable.Puller is { Valid: true } pullerId &&
&& !visited.Contains(pullerId)) !visited.Contains(pullerId))
{ {
GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all); GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all);
} }
if (EntityManager.TryGetComponent(entity, out SharedPullerComponent? puller) if (TryComp<SharedPullerComponent>(entity, out var puller) &&
&& puller.Pulling is {Valid: true} pullingId puller.Pulling is { Valid: true } pullingId &&
&& !visited.Contains(pullingId)) !visited.Contains(pullingId))
{ {
GetChainedElectrocutionTargetsRecurse(pullingId, depth + 1, visited, all); GetChainedElectrocutionTargetsRecurse(pullingId, depth + 1, visited, all);
} }
@@ -444,7 +454,7 @@ namespace Content.Server.Electrocution
private void OnRandomInsulationMapInit(EntityUid uid, RandomInsulationComponent randomInsulation, private void OnRandomInsulationMapInit(EntityUid uid, RandomInsulationComponent randomInsulation,
MapInitEvent args) MapInitEvent args)
{ {
if (!EntityManager.TryGetComponent(uid, out InsulatedComponent? insulated)) if (!TryComp<InsulatedComponent>(uid, out var insulated))
return; return;
if (randomInsulation.List.Length == 0) if (randomInsulation.List.Length == 0)
@@ -459,8 +469,6 @@ namespace Content.Server.Electrocution
{ {
return; return;
} }
_audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
SoundSystem.Play(electrified.ShockNoises.GetSound(), Filter.Pvs(targetUid), targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
}
} }
} }

View File

@@ -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
}

View File

@@ -17,7 +17,13 @@
netsync: false netsync: false
drawdepth: Walls drawdepth: Walls
sprite: Structures/Walls/grille.rsi 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 - type: Icon
sprite: Structures/Walls/grille.rsi sprite: Structures/Walls/grille.rsi
state: grille state: grille
@@ -71,6 +77,14 @@
node: grilleBroken node: grilleBroken
- !type:DoActsBehavior - !type:DoActsBehavior
acts: ["Breakage"] acts: ["Breakage"]
- type: Appearance
- type: GenericVisualizer
visuals:
enum.ElectrifiedVisuals.IsPowered:
enum.ElectrifiedLayers.Powered:
True: { visible: True }
False: { visible: False }
- type: AnimationPlayer
- type: entity - type: entity
id: GrilleBroken id: GrilleBroken

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -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
]
]
}
]
}