Geiger counter (#12082)
95
Content.Client/Radiation/Systems/GeigerSystem.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using Content.Client.Items;
|
||||
using Content.Client.Radiation.UI;
|
||||
using Content.Shared.Radiation.Components;
|
||||
using Content.Shared.Radiation.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Radiation.Systems;
|
||||
|
||||
public sealed class GeigerSystem : SharedGeigerSystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<PlayerAttachSysMessage>(OnAttachedEntityChanged);
|
||||
SubscribeLocalEvent<GeigerComponent, ComponentHandleState>(OnHandleState);
|
||||
SubscribeLocalEvent<GeigerComponent, ItemStatusCollectMessage>(OnGetStatusMessage);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, GeigerComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not GeigerComponentState state)
|
||||
return;
|
||||
|
||||
UpdateGeigerSound(uid, state.IsEnabled, state.User, state.DangerLevel, false, component);
|
||||
|
||||
component.CurrentRadiation = state.CurrentRadiation;
|
||||
component.DangerLevel = state.DangerLevel;
|
||||
component.IsEnabled = state.IsEnabled;
|
||||
component.User = state.User;
|
||||
component.UiUpdateNeeded = true;
|
||||
}
|
||||
|
||||
private void OnGetStatusMessage(EntityUid uid, GeigerComponent component, ItemStatusCollectMessage args)
|
||||
{
|
||||
if (!component.ShowControl)
|
||||
return;
|
||||
|
||||
args.Controls.Add(new GeigerItemControl(component));
|
||||
}
|
||||
|
||||
private void OnAttachedEntityChanged(PlayerAttachSysMessage ev)
|
||||
{
|
||||
// need to go for each component known to client
|
||||
// and update their geiger sound
|
||||
foreach (var geiger in EntityQuery<GeigerComponent>())
|
||||
{
|
||||
ForceUpdateGeigerSound(geiger.Owner, geiger);
|
||||
}
|
||||
}
|
||||
|
||||
private void ForceUpdateGeigerSound(EntityUid uid, GeigerComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
UpdateGeigerSound(uid, component.IsEnabled, component.User, component.DangerLevel, true, component);
|
||||
}
|
||||
|
||||
private void UpdateGeigerSound(EntityUid uid, bool isEnabled, EntityUid? user,
|
||||
GeigerDangerLevel dangerLevel, bool force = false, GeigerComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
// check if we even need to update sound
|
||||
if (!force && isEnabled == component.IsEnabled &&
|
||||
user == component.User && dangerLevel == component.DangerLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.Stream?.Stop();
|
||||
|
||||
if (!isEnabled || user == null)
|
||||
return;
|
||||
if (!component.Sounds.TryGetValue(dangerLevel, out var sounds))
|
||||
return;
|
||||
|
||||
// check that that local player controls entity that is holding geiger counter
|
||||
if (_playerManager.LocalPlayer == null)
|
||||
return;
|
||||
var attachedEnt = _playerManager.LocalPlayer.Session.AttachedEntity;
|
||||
if (attachedEnt != user)
|
||||
return;
|
||||
|
||||
var sound = _audio.GetSound(sounds);
|
||||
var param = sounds.Params.WithLoop(true).WithVolume(-4f);
|
||||
component.Stream = _audio.Play(sound, Filter.Local(), uid, false, param);
|
||||
}
|
||||
}
|
||||
53
Content.Client/Radiation/UI/GeigerItemControl.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Radiation.Components;
|
||||
using Content.Shared.Radiation.Systems;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Radiation.UI;
|
||||
|
||||
public sealed class GeigerItemControl : Control
|
||||
{
|
||||
private readonly GeigerComponent _component;
|
||||
private readonly RichTextLabel _label;
|
||||
|
||||
public GeigerItemControl(GeigerComponent component)
|
||||
{
|
||||
_component = component;
|
||||
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
||||
AddChild(_label);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
if (!_component.UiUpdateNeeded)
|
||||
return;
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
string msg;
|
||||
if (_component.IsEnabled)
|
||||
{
|
||||
var color = SharedGeigerSystem.LevelToColor(_component.DangerLevel);
|
||||
var currentRads = _component.CurrentRadiation;
|
||||
var rads = currentRads.ToString("N1");
|
||||
msg = Loc.GetString("geiger-item-control-status",
|
||||
("rads", rads), ("color", color));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = Loc.GetString("geiger-item-control-disabled");
|
||||
}
|
||||
|
||||
_label.SetMarkup(msg);
|
||||
_component.UiUpdateNeeded = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Content.Server.Radiation.Systems;
|
||||
|
||||
namespace Content.Server.Radiation.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when <see cref="RadiationSystem"/> updated all
|
||||
/// radiation receivers and radiation sources.
|
||||
/// </summary>
|
||||
public record struct RadiationSystemUpdatedEvent;
|
||||
165
Content.Server/Radiation/Systems/GeigerSystem.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
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.Shared.GameStates;
|
||||
|
||||
namespace Content.Server.Radiation.Systems;
|
||||
|
||||
public sealed class GeigerSystem : SharedGeigerSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly RadiationSystem _radiation = 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);
|
||||
SubscribeLocalEvent<GeigerComponent, ComponentGetState>(OnGetState);
|
||||
}
|
||||
|
||||
private void OnActivate(EntityUid uid, GeigerComponent component, ActivateInWorldEvent args)
|
||||
{
|
||||
if (args.Handled || component.AttachedToSuit)
|
||||
return;
|
||||
args.Handled = true;
|
||||
|
||||
SetEnabled(uid, component, !component.IsEnabled);
|
||||
}
|
||||
|
||||
private void OnEquipped(EntityUid uid, GeigerComponent component, GotEquippedEvent args)
|
||||
{
|
||||
if (component.AttachedToSuit)
|
||||
SetEnabled(uid, component, true);
|
||||
SetUser(component, args.Equipee);
|
||||
}
|
||||
|
||||
private void OnEquippedHand(EntityUid uid, GeigerComponent component, GotEquippedHandEvent args)
|
||||
{
|
||||
if (component.AttachedToSuit)
|
||||
return;
|
||||
|
||||
SetUser(component, args.User);
|
||||
}
|
||||
|
||||
private void OnUnequipped(EntityUid uid, GeigerComponent component, GotUnequippedEvent args)
|
||||
{
|
||||
if (component.AttachedToSuit)
|
||||
SetEnabled(uid, component, false);
|
||||
SetUser(component, null);
|
||||
}
|
||||
|
||||
private void OnUnequippedHand(EntityUid uid, GeigerComponent component, GotUnequippedHandEvent args)
|
||||
{
|
||||
if (component.AttachedToSuit)
|
||||
return;
|
||||
|
||||
SetUser(component, null);
|
||||
}
|
||||
|
||||
private void OnUpdate(RadiationSystemUpdatedEvent ev)
|
||||
{
|
||||
// update only active geiger counters
|
||||
// deactivated shouldn't have rad receiver component
|
||||
var query = EntityQuery<GeigerComponent, RadiationReceiverComponent>();
|
||||
foreach (var (geiger, receiver) in query)
|
||||
{
|
||||
var rads = receiver.CurrentRadiation;
|
||||
SetCurrentRadiation(geiger.Owner, geiger, rads);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, GeigerComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new GeigerComponentState
|
||||
{
|
||||
CurrentRadiation = component.CurrentRadiation,
|
||||
DangerLevel = component.DangerLevel,
|
||||
IsEnabled = component.IsEnabled,
|
||||
User = component.User
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
private void SetUser(GeigerComponent component, EntityUid? user)
|
||||
{
|
||||
if (component.User == user)
|
||||
return;
|
||||
|
||||
component.User = user;
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
private void SetEnabled(EntityUid uid, GeigerComponent component, bool isEnabled)
|
||||
{
|
||||
if (component.IsEnabled == isEnabled)
|
||||
return;
|
||||
|
||||
component.IsEnabled = isEnabled;
|
||||
if (!isEnabled)
|
||||
{
|
||||
component.CurrentRadiation = 0f;
|
||||
component.DangerLevel = GeigerDangerLevel.None;
|
||||
}
|
||||
|
||||
_radiation.SetCanReceive(uid, isEnabled);
|
||||
|
||||
UpdateAppearance(uid, component);
|
||||
Dirty(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);
|
||||
}
|
||||
|
||||
public static GeigerDangerLevel RadsToLevel(float rads)
|
||||
{
|
||||
return rads switch
|
||||
{
|
||||
< 0.2f => GeigerDangerLevel.None,
|
||||
< 1f => GeigerDangerLevel.Low,
|
||||
< 3f => GeigerDangerLevel.Med,
|
||||
< 6f => GeigerDangerLevel.High,
|
||||
_ => GeigerDangerLevel.Extreme
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Radiation.Components;
|
||||
using Content.Server.Radiation.Events;
|
||||
using Content.Shared.Radiation.Components;
|
||||
using Content.Shared.Radiation.Systems;
|
||||
using Robust.Shared.Collections;
|
||||
@@ -82,6 +83,9 @@ public partial class RadiationSystem
|
||||
if (rads > 0)
|
||||
IrradiateEntity(receiver.Owner, rads,GridcastUpdateRate);
|
||||
}
|
||||
|
||||
// raise broadcast event that radiation system has updated
|
||||
RaiseLocalEvent(new RadiationSystemUpdatedEvent());
|
||||
}
|
||||
|
||||
private RadiationRay? Irradiate(EntityUid sourceUid, TransformComponent sourceTrs, Vector2 sourceWorld,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Radiation.Events;
|
||||
using Content.Server.Radiation.Components;
|
||||
using Content.Shared.Radiation.Events;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
@@ -43,4 +44,19 @@ public sealed partial class RadiationSystem : EntitySystem
|
||||
var msg = new OnIrradiatedEvent(time, radsPerSecond);
|
||||
RaiseLocalEvent(uid, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks entity to receive/ignore radiation rays.
|
||||
/// </summary>
|
||||
public void SetCanReceive(EntityUid uid, bool canReceive)
|
||||
{
|
||||
if (canReceive)
|
||||
{
|
||||
EnsureComp<RadiationReceiverComponent>(uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemComp<RadiationReceiverComponent>(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
118
Content.Shared/Radiation/Components/GeigerComponent.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using Content.Shared.Radiation.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Radiation.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Geiger counter that shows current radiation level.
|
||||
/// Can be added as a component to clothes.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[Access(typeof(SharedGeigerSystem))]
|
||||
public sealed class GeigerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// If true it will be active only when player equipped it.
|
||||
/// </summary>
|
||||
[DataField("attachedToSuit")]
|
||||
public bool AttachedToSuit;
|
||||
|
||||
/// <summary>
|
||||
/// Is geiger counter currently active?
|
||||
/// If false attached entity will ignore any radiation rays.
|
||||
/// </summary>
|
||||
[DataField("isEnabled")]
|
||||
public bool IsEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Should it shows examine message with current radiation level?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("showExamine")]
|
||||
public bool ShowExamine;
|
||||
|
||||
/// <summary>
|
||||
/// Should it shows item control when equipped by player?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("showControl")]
|
||||
public bool ShowControl;
|
||||
|
||||
/// <summary>
|
||||
/// Map of sounds that should be play on loop for different radiation levels.
|
||||
/// </summary>
|
||||
[DataField("sounds")]
|
||||
public Dictionary<GeigerDangerLevel, SoundSpecifier> Sounds = new()
|
||||
{
|
||||
{GeigerDangerLevel.Low, new SoundPathSpecifier("/Audio/Items/Geiger/low.ogg")},
|
||||
{GeigerDangerLevel.Med, new SoundPathSpecifier("/Audio/Items/Geiger/med.ogg")},
|
||||
{GeigerDangerLevel.High, new SoundPathSpecifier("/Audio/Items/Geiger/high.ogg")},
|
||||
{GeigerDangerLevel.Extreme, new SoundPathSpecifier("/Audio/Items/Geiger/ext.ogg")}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Current radiation level in rad per second.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float CurrentRadiation;
|
||||
|
||||
/// <summary>
|
||||
/// Estimated radiation danger level.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public GeigerDangerLevel DangerLevel = GeigerDangerLevel.None;
|
||||
|
||||
/// <summary>
|
||||
/// Current player that equipped geiger counter.
|
||||
/// Because sound is annoying, geiger counter clicks will play
|
||||
/// only for player that equipped it.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public EntityUid? User;
|
||||
|
||||
/// <summary>
|
||||
/// Marked true if control needs to update UI with latest component state.
|
||||
/// </summary>
|
||||
[Access(typeof(SharedGeigerSystem), Other = AccessPermissions.ReadWrite)]
|
||||
public bool UiUpdateNeeded;
|
||||
|
||||
/// <summary>
|
||||
/// Current stream of geiger counter audio.
|
||||
/// Played only for current user.
|
||||
/// </summary>
|
||||
public IPlayingAudioStream? Stream;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class GeigerComponentState : ComponentState
|
||||
{
|
||||
public float CurrentRadiation;
|
||||
public GeigerDangerLevel DangerLevel;
|
||||
public bool IsEnabled;
|
||||
public EntityUid? User;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum GeigerDangerLevel : byte
|
||||
{
|
||||
None,
|
||||
Low,
|
||||
Med,
|
||||
High,
|
||||
Extreme
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum GeigerLayers : byte
|
||||
{
|
||||
Screen
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum GeigerVisuals : byte
|
||||
{
|
||||
DangerLevel,
|
||||
IsEnabled
|
||||
}
|
||||
44
Content.Shared/Radiation/Systems/SharedGeigerSystem.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Radiation.Components;
|
||||
|
||||
namespace Content.Shared.Radiation.Systems;
|
||||
|
||||
public abstract class SharedGeigerSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<GeigerComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, GeigerComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!component.ShowExamine || !component.IsEnabled || !args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
var currentRads = component.CurrentRadiation;
|
||||
var rads = currentRads.ToString("N1");
|
||||
var color = LevelToColor(component.DangerLevel);
|
||||
var msg = Loc.GetString("geiger-component-examine",
|
||||
("rads", rads), ("color", color));
|
||||
args.PushMarkup(msg);
|
||||
}
|
||||
|
||||
public static Color LevelToColor(GeigerDangerLevel level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case GeigerDangerLevel.None:
|
||||
return Color.Green;
|
||||
case GeigerDangerLevel.Low:
|
||||
return Color.Yellow;
|
||||
case GeigerDangerLevel.Med:
|
||||
return Color.DarkOrange;
|
||||
case GeigerDangerLevel.High:
|
||||
case GeigerDangerLevel.Extreme:
|
||||
return Color.Red;
|
||||
default:
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Resources/Audio/Items/Geiger/attributions.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
- files:
|
||||
- "low.ogg"
|
||||
- "med.ogg"
|
||||
- "high.ogg"
|
||||
- "ext.ogg"
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/456cd10d94084c7c2574f628cf7ac9b67087ba26"
|
||||
source: "https://github.com/tgstation/tgstation/tree/456cd10d94084c7c2574f628cf7ac9b67087ba26/sound/items/geiger"
|
||||
BIN
Resources/Audio/Items/Geiger/ext.ogg
Normal file
BIN
Resources/Audio/Items/Geiger/high.ogg
Normal file
BIN
Resources/Audio/Items/Geiger/low.ogg
Normal file
BIN
Resources/Audio/Items/Geiger/med.ogg
Normal file
3
Resources/Locale/en-US/radiation/geiger-component.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
geiger-item-control-status = Radiation: [color={$color}]{$rads} rads[/color]
|
||||
geiger-item-control-disabled = Disabled
|
||||
geiger-component-examine = Current radiation: [color={$color}]{$rads} rads[/color]
|
||||
@@ -34,7 +34,7 @@
|
||||
sprite: Structures/Wallmounts/signs.rsi
|
||||
state: radiation
|
||||
product: CrateEmergencyRadiation
|
||||
cost: 900
|
||||
cost: 1000
|
||||
category: Emergency
|
||||
group: market
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@
|
||||
amount: 2
|
||||
- id: ClothingHeadHatHoodRad
|
||||
amount: 2
|
||||
# - id: GeigerCounter
|
||||
# amount: 2
|
||||
- id: GeigerCounter
|
||||
amount: 2
|
||||
- id: DrinkVodkaBottleFull
|
||||
amount: 1
|
||||
- id: DrinkShotGlass
|
||||
|
||||
@@ -115,3 +115,5 @@
|
||||
amount: 2
|
||||
- id: ClothingOuterSuitRad
|
||||
amount: 2
|
||||
- id: GeigerCounter
|
||||
amount: 2
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
- Screwdriver
|
||||
- Flashlight
|
||||
- Wrench
|
||||
# - GeigerCounter
|
||||
- GeigerCounter
|
||||
- Flare
|
||||
- CableCoil
|
||||
- CigPack
|
||||
@@ -81,7 +81,7 @@
|
||||
- Screwdriver
|
||||
- Flashlight
|
||||
- Wrench
|
||||
# - GeigerCounter
|
||||
- GeigerCounter
|
||||
- Flare
|
||||
- CableCoil
|
||||
- Powerdrill
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: ClothingOuterBase
|
||||
parent: [ClothingOuterBase, GeigerCounterClothing]
|
||||
id: ClothingOuterHardsuitBase
|
||||
name: base hardsuit
|
||||
components:
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
coefficient: 0.01
|
||||
|
||||
- type: entity
|
||||
parent: ClothingOuterBaseLarge
|
||||
parent: [ClothingOuterBaseLarge, GeigerCounterClothing]
|
||||
id: ClothingOuterSuitRad
|
||||
name: radiation suit
|
||||
description: "A suit that protects against radiation. The label reads, 'Made with lead. Please do not consume insulation.'"
|
||||
|
||||
@@ -10,3 +10,10 @@
|
||||
- WhitelistChameleon
|
||||
- type: StaticPrice
|
||||
price: 15
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
id: GeigerCounterClothing
|
||||
components:
|
||||
- type: Geiger
|
||||
attachedToSuit: true
|
||||
|
||||
35
Resources/Prototypes/Entities/Objects/Devices/geiger.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: GeigerCounter
|
||||
name: Geiger counter
|
||||
description: A handheld device used for detecting and measuring radiation pulses.
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
sprite: Objects/Tools/geiger.rsi
|
||||
layers:
|
||||
- state: geiger_base
|
||||
- state: geiger_on_idle
|
||||
map: ["enum.GeigerLayers.Screen"]
|
||||
shader: unshaded
|
||||
visible: false
|
||||
- type: Item
|
||||
sprite: Objects/Tools/geiger.rsi
|
||||
- type: Geiger
|
||||
showControl: true
|
||||
showExamine: true
|
||||
- type: Appearance
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.GeigerVisuals.IsEnabled:
|
||||
GeigerLayers.Screen:
|
||||
True: { visible: True }
|
||||
False: { visible: False }
|
||||
enum.GeigerVisuals.DangerLevel:
|
||||
GeigerLayers.Screen:
|
||||
None: {state: geiger_on_idle}
|
||||
Low: {state: geiger_on_low}
|
||||
Med: {state: geiger_on_med}
|
||||
High: {state: geiger_on_high}
|
||||
Extreme: {state: geiger_on_ext}
|
||||
|
||||
@@ -249,6 +249,9 @@
|
||||
- type: Tag
|
||||
id: Gauze
|
||||
|
||||
- type: Tag
|
||||
id: GeigerCounter
|
||||
|
||||
- type: Tag
|
||||
id: GlassBeaker
|
||||
|
||||
|
||||
BIN
Resources/Textures/Objects/Tools/geiger.rsi/geiger_base.png
Normal file
|
After Width: | Height: | Size: 427 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/geiger_on_ext.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/geiger_on_high.png
Normal file
|
After Width: | Height: | Size: 176 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/geiger_on_idle.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/geiger_on_low.png
Normal file
|
After Width: | Height: | Size: 176 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/geiger_on_med.png
Normal file
|
After Width: | Height: | Size: 176 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/inhand-left.png
Normal file
|
After Width: | Height: | Size: 302 B |
BIN
Resources/Textures/Objects/Tools/geiger.rsi/inhand-right.png
Normal file
|
After Width: | Height: | Size: 301 B |
43
Resources/Textures/Objects/Tools/geiger.rsi/meta.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "geiger_base"
|
||||
},
|
||||
{
|
||||
"name": "geiger_on_idle"
|
||||
},
|
||||
{
|
||||
"name": "geiger_on_low"
|
||||
},
|
||||
{
|
||||
"name": "geiger_on_med"
|
||||
},
|
||||
{
|
||||
"name": "geiger_on_high"
|
||||
},
|
||||
{
|
||||
"name": "geiger_on_ext",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-right",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||