mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-21 23:48:15 +03:00
# Description This refactors Geiger Counters so that their behavior of "Only making sound to a person holding them" is no longer hardcoded. The GeigerCounterComponent now can define how loud it ticks, how far away people can hear the ticks, and whether it plays only for the person holding it or for anyone nearby. This PR partially fulfills one of the "Nice To Have" features requested for https://github.com/Simple-Station/Einstein-Engines/pull/341 by making it possible to create stationary radiation alarm objects. It also serves as a substantial quality of life improvement for Engineering and Science crew, since it's now possible to place an active Geiger counter in the artifact lab, and then be able to audibly hear if the lab becomes radioactive due to an artifact. <details><summary><h1>Media</h1></summary> <p> https://github.com/user-attachments/assets/74122135-7345-4995-bb0e-d1216e1d53b6 https://github.com/user-attachments/assets/de79db6f-e1c1-471f-88b5-0a47ff4bfa16 </p> </details> # Changelog 🆑 - add: Geiger Counters other than ones installed in Hardsuits now generate an audible sound when active and exposed to radiation. - add: Wall mounted geiger counters have been added to the game. --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com>
182 lines
5.8 KiB
C#
182 lines
5.8 KiB
C#
using Content.Server.Radiation.Components;
|
|
using Content.Server.Radiation.Events;
|
|
using Content.Shared.Hands;
|
|
using Content.Shared.Interaction;
|
|
using Content.Shared.Inventory.Events;
|
|
using Content.Shared.Radiation.Components;
|
|
using Content.Shared.Radiation.Systems;
|
|
using Robust.Server.Audio;
|
|
using Robust.Server.Player;
|
|
using Robust.Shared.Player;
|
|
|
|
namespace Content.Server.Radiation.Systems;
|
|
|
|
public sealed class GeigerSystem : SharedGeigerSystem
|
|
{
|
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
[Dependency] private readonly RadiationSystem _radiation = default!;
|
|
[Dependency] private readonly AudioSystem _audio = default!;
|
|
[Dependency] private readonly IPlayerManager _player = default!;
|
|
|
|
private static readonly float ApproxEqual = 0.01f;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
SubscribeLocalEvent<GeigerComponent, ActivateInWorldEvent>(OnActivate);
|
|
|
|
SubscribeLocalEvent<GeigerComponent, GotEquippedEvent>(OnEquipped);
|
|
SubscribeLocalEvent<GeigerComponent, GotEquippedHandEvent>(OnEquippedHand);
|
|
SubscribeLocalEvent<GeigerComponent, GotUnequippedEvent>(OnUnequipped);
|
|
SubscribeLocalEvent<GeigerComponent, GotUnequippedHandEvent>(OnUnequippedHand);
|
|
|
|
SubscribeLocalEvent<RadiationSystemUpdatedEvent>(OnUpdate);
|
|
}
|
|
|
|
private void OnActivate(Entity<GeigerComponent> geiger, ref ActivateInWorldEvent args)
|
|
{
|
|
if (args.Handled || geiger.Comp.AttachedToSuit)
|
|
return;
|
|
args.Handled = true;
|
|
|
|
SetEnabled(geiger, !geiger.Comp.IsEnabled);
|
|
}
|
|
|
|
private void OnEquipped(Entity<GeigerComponent> geiger, ref GotEquippedEvent args)
|
|
{
|
|
if (geiger.Comp.AttachedToSuit)
|
|
SetEnabled(geiger, true);
|
|
SetUser(geiger, args.Equipee);
|
|
}
|
|
|
|
private void OnEquippedHand(Entity<GeigerComponent> geiger, ref GotEquippedHandEvent args)
|
|
{
|
|
if (geiger.Comp.AttachedToSuit)
|
|
return;
|
|
|
|
SetUser(geiger, args.User);
|
|
}
|
|
|
|
private void OnUnequipped(Entity<GeigerComponent> geiger, ref GotUnequippedEvent args)
|
|
{
|
|
if (geiger.Comp.AttachedToSuit)
|
|
SetEnabled(geiger, false);
|
|
SetUser(geiger, null);
|
|
}
|
|
|
|
private void OnUnequippedHand(Entity<GeigerComponent> geiger, ref GotUnequippedHandEvent args)
|
|
{
|
|
if (geiger.Comp.AttachedToSuit)
|
|
return;
|
|
|
|
SetUser(geiger, null);
|
|
}
|
|
|
|
private void OnUpdate(RadiationSystemUpdatedEvent ev)
|
|
{
|
|
// update only active geiger counters
|
|
// deactivated shouldn't have rad receiver component
|
|
var query = EntityQueryEnumerator<GeigerComponent, RadiationReceiverComponent>();
|
|
while (query.MoveNext(out var uid, out var geiger, out var receiver))
|
|
{
|
|
var rads = receiver.CurrentRadiation;
|
|
SetCurrentRadiation(uid, geiger, rads);
|
|
}
|
|
}
|
|
|
|
private void SetCurrentRadiation(EntityUid uid, GeigerComponent component, float rads)
|
|
{
|
|
// check that it's approx equal
|
|
if (MathHelper.CloseTo(component.CurrentRadiation, rads, ApproxEqual))
|
|
return;
|
|
|
|
var curLevel = component.DangerLevel;
|
|
var newLevel = RadsToLevel(rads);
|
|
|
|
component.CurrentRadiation = rads;
|
|
component.DangerLevel = newLevel;
|
|
|
|
if (curLevel != newLevel)
|
|
{
|
|
UpdateAppearance(uid, component);
|
|
UpdateSound(uid, component);
|
|
}
|
|
|
|
Dirty(uid, component);
|
|
}
|
|
|
|
private void SetUser(Entity<GeigerComponent> component, EntityUid? user)
|
|
{
|
|
if (component.Comp.User == user)
|
|
return;
|
|
|
|
component.Comp.User = user;
|
|
Dirty(component);
|
|
UpdateSound(component, component);
|
|
}
|
|
|
|
private void SetEnabled(Entity<GeigerComponent> geiger, bool isEnabled)
|
|
{
|
|
var component = geiger.Comp;
|
|
if (component.IsEnabled == isEnabled)
|
|
return;
|
|
|
|
component.IsEnabled = isEnabled;
|
|
if (!isEnabled)
|
|
{
|
|
component.CurrentRadiation = 0f;
|
|
component.DangerLevel = GeigerDangerLevel.None;
|
|
}
|
|
|
|
_radiation.SetCanReceive(geiger, isEnabled);
|
|
|
|
UpdateAppearance(geiger, component);
|
|
UpdateSound(geiger, component);
|
|
Dirty(geiger, component);
|
|
}
|
|
|
|
private void UpdateAppearance(EntityUid uid, GeigerComponent? component = null,
|
|
AppearanceComponent? appearance = null)
|
|
{
|
|
if (!Resolve(uid, ref component, ref appearance, false))
|
|
return;
|
|
|
|
_appearance.SetData(uid, GeigerVisuals.IsEnabled, component.IsEnabled, appearance);
|
|
_appearance.SetData(uid, GeigerVisuals.DangerLevel, component.DangerLevel, appearance);
|
|
}
|
|
|
|
private void UpdateSound(EntityUid uid, GeigerComponent? component = null)
|
|
{
|
|
if (!Resolve(uid, ref component, false))
|
|
return;
|
|
|
|
component.Stream = _audio.Stop(component.Stream);
|
|
|
|
if (component.Sounds.TryGetValue(component.DangerLevel, out var sounds))
|
|
{
|
|
var sound = _audio.GetSound(sounds);
|
|
|
|
if (component.LocalSoundOnly
|
|
&& component.User is not null
|
|
&& _player.TryGetSessionByEntity(component.User.Value, out var session))
|
|
{
|
|
component.Stream = _audio.PlayGlobal(sound, session, component.AudioParameters)?.Entity;
|
|
return;
|
|
}
|
|
component.Stream = _audio.PlayEntity(sound, Filter.Pvs(uid), uid, true, component.AudioParameters)?.Entity;
|
|
}
|
|
}
|
|
|
|
public static GeigerDangerLevel RadsToLevel(float rads)
|
|
{
|
|
return rads switch
|
|
{
|
|
< 0.2f => GeigerDangerLevel.None,
|
|
< 1f => GeigerDangerLevel.Low,
|
|
< 3f => GeigerDangerLevel.Med,
|
|
< 6f => GeigerDangerLevel.High,
|
|
_ => GeigerDangerLevel.Extreme
|
|
};
|
|
}
|
|
}
|