diff --git a/Content.Server/Light/Components/LightReplacerComponent.cs b/Content.Server/Light/Components/LightReplacerComponent.cs
index 8835fb0c84..49c4523b86 100644
--- a/Content.Server/Light/Components/LightReplacerComponent.cs
+++ b/Content.Server/Light/Components/LightReplacerComponent.cs
@@ -1,45 +1,35 @@
-using Content.Shared.Light.Component;
+using Content.Server.Light.EntitySystems;
+using Content.Shared.Storage;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-namespace Content.Server.Light.Components
+namespace Content.Server.Light.Components;
+
+///
+/// Device that allows user to quikly change bulbs in
+/// Can be reloaded by new light tubes or light bulbs
+///
+[RegisterComponent, Access(typeof(LightReplacerSystem))]
+public sealed class LightReplacerComponent : Component
{
- ///
- /// Device that allows user to quikly change bulbs in
- /// Can be reloaded by new light tubes or light bulbs
- ///
- [RegisterComponent]
- public sealed class LightReplacerComponent : Component
+ [DataField("sound")]
+ public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Weapons/click.ogg")
{
- [DataField("sound")]
- public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Weapons/click.ogg");
-
- ///
- /// Bulbs that were inside light replacer when it spawned
- ///
- [DataField("contents")]
- public List Contents = new();
-
- ///
- /// Bulbs that were inserted inside light replacer
- ///
- [ViewVariables]
- public IContainer InsertedBulbs = default!;
-
- [Serializable]
- [DataDefinition]
- public sealed class LightReplacerEntity
+ Params = new()
{
- [DataField("name", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string PrototypeName = default!;
-
- [DataField("amount")]
- public int Amount;
-
- [DataField("type")]
- public LightBulbType Type;
+ Volume = -4f
}
- }
+ };
+
+ ///
+ /// Bulbs that were inserted inside light replacer
+ ///
+ [ViewVariables]
+ public Container InsertedBulbs = default!;
+
+ ///
+ /// The default starting bulbs
+ ///
+ [DataField("contents")]
+ public List Contents = new();
}
diff --git a/Content.Server/Light/EntitySystems/LightReplacerSystem.cs b/Content.Server/Light/EntitySystems/LightReplacerSystem.cs
index 2f7a6d07a5..e43ce5a5ae 100644
--- a/Content.Server/Light/EntitySystems/LightReplacerSystem.cs
+++ b/Content.Server/Light/EntitySystems/LightReplacerSystem.cs
@@ -1,217 +1,236 @@
using System.Linq;
using Content.Server.Light.Components;
using Content.Server.Storage.Components;
+using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Light.Component;
using Content.Shared.Popups;
+using Content.Shared.Storage;
using JetBrains.Annotations;
-using Robust.Shared.Audio;
using Robust.Shared.Containers;
-using Robust.Shared.Player;
-namespace Content.Server.Light.EntitySystems
+namespace Content.Server.Light.EntitySystems;
+
+[UsedImplicitly]
+public sealed class LightReplacerSystem : EntitySystem
{
- [UsedImplicitly]
- public sealed class LightReplacerSystem : EntitySystem
+ [Dependency] private readonly PoweredLightSystem _poweredLight = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+
+ public override void Initialize()
{
- [Dependency] private readonly PoweredLightSystem _poweredLight = default!;
- [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+ base.Initialize();
- public override void Initialize()
+ SubscribeLocalEvent(OnExamined);
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(HandleInteract);
+ SubscribeLocalEvent(HandleAfterInteract);
+ }
+
+ private void OnExamined(EntityUid uid, LightReplacerComponent component, ExaminedEvent args)
+ {
+ if (!component.InsertedBulbs.ContainedEntities.Any())
{
- base.Initialize();
-
- SubscribeLocalEvent(OnInit);
- SubscribeLocalEvent(HandleInteract);
- SubscribeLocalEvent(HandleAfterInteract);
+ args.PushMarkup(Loc.GetString("comp-light-replacer-no-lights"));
+ return;
+ }
+ args.PushMarkup(Loc.GetString("comp-light-replacer-has-lights"));
+ var groups = new Dictionary();
+ var metaQuery = GetEntityQuery();
+ foreach (var bulb in component.InsertedBulbs.ContainedEntities)
+ {
+ var metaData = metaQuery.GetComponent(bulb);
+ groups[metaData.EntityName] = groups.GetValueOrDefault(metaData.EntityName) + 1;
}
- private void OnInit(EntityUid uid, LightReplacerComponent replacer, ComponentInit args)
+ foreach (var (name, amount) in groups)
{
- replacer.InsertedBulbs = ContainerHelpers.EnsureContainer(replacer.Owner, "light_replacer_storage");
- }
-
- private void HandleAfterInteract(EntityUid uid, LightReplacerComponent component, AfterInteractEvent eventArgs)
- {
- if (eventArgs.Handled)
- return;
-
- // standard interaction checks
- if (!eventArgs.CanReach) return;
-
- // behaviour will depends on target type
- if (eventArgs.Target != null)
- {
- var targetUid = (EntityUid) eventArgs.Target;
-
- // replace broken light in fixture?
- if (EntityManager.TryGetComponent(targetUid, out PoweredLightComponent? fixture))
- eventArgs.Handled = TryReplaceBulb(uid, targetUid, eventArgs.User, component, fixture);
- // add new bulb to light replacer container?
- else if (EntityManager.TryGetComponent(targetUid, out LightBulbComponent? bulb))
- eventArgs.Handled = TryInsertBulb(uid, targetUid, eventArgs.User, true, component, bulb);
- }
- }
-
- private void HandleInteract(EntityUid uid, LightReplacerComponent component, InteractUsingEvent eventArgs)
- {
- if (eventArgs.Handled)
- return;
-
- var usedUid = eventArgs.Used;
-
- // want to insert a new light bulb?
- if (EntityManager.TryGetComponent(usedUid, out LightBulbComponent? bulb))
- eventArgs.Handled = TryInsertBulb(uid, usedUid, eventArgs.User, true, component, bulb);
- // add bulbs from storage?
- else if (EntityManager.TryGetComponent(usedUid, out ServerStorageComponent? storage))
- eventArgs.Handled = TryInsertBulbsFromStorage(uid, usedUid, eventArgs.User, component, storage);
- }
-
- ///
- /// Try to replace a light bulb in
- /// using light replacer. Light fixture should have .
- ///
- /// True if successfully replaced light, false otherwise
- public bool TryReplaceBulb(EntityUid replacerUid, EntityUid fixtureUid, EntityUid? userUid = null,
- LightReplacerComponent? replacer = null, PoweredLightComponent? fixture = null)
- {
- if (!Resolve(replacerUid, ref replacer))
- return false;
- if (!Resolve(fixtureUid, ref fixture))
- return false;
-
- // check if light bulb is broken or missing
- var fixtureBulbUid = _poweredLight.GetBulb(fixture.Owner, fixture);
- if (fixtureBulbUid != null)
- {
- if (!EntityManager.TryGetComponent(fixtureBulbUid.Value, out LightBulbComponent? fixtureBulb))
- return false;
- if (fixtureBulb.State == LightBulbState.Normal)
- return false;
- }
-
- // try get first inserted bulb of the same type as targeted light fixtutre
- var bulb = replacer.InsertedBulbs.ContainedEntities.FirstOrDefault(
- (e) => EntityManager.GetComponentOrNull(e)?.Type == fixture.BulbType);
-
- // found bulb in inserted storage
- if (bulb.Valid) // FirstOrDefault can return default/invalid uid.
- {
- // try to remove it
- var hasRemoved = replacer.InsertedBulbs.Remove(bulb);
- if (!hasRemoved)
- return false;
- }
- // try to create new instance of bulb from LightReplacerEntity
- else
- {
- var bulbEnt = replacer.Contents.FirstOrDefault((e) => e.Type == fixture.BulbType && e.Amount > 0);
-
- // found right bulb, let's spawn it
- if (bulbEnt != null)
- {
- bulb = EntityManager.SpawnEntity(bulbEnt.PrototypeName, EntityManager.GetComponent(replacer.Owner).Coordinates);
- bulbEnt.Amount--;
- }
- // not found any light bulbs
- else
- {
- if (userUid != null)
- {
- var msg = Loc.GetString("comp-light-replacer-missing-light",
- ("light-replacer", replacer.Owner));
- _popupSystem.PopupEntity(msg, replacerUid, userUid.Value);
- }
- return false;
- }
- }
-
- // insert it into fixture
- var wasReplaced = _poweredLight.ReplaceBulb(fixtureUid, bulb, fixture);
- if (wasReplaced)
- {
- SoundSystem.Play(replacer.Sound.GetSound(),
- Filter.Pvs(replacerUid), replacerUid, AudioParams.Default.WithVolume(-4f));
- }
-
-
- return wasReplaced;
- }
-
- ///
- /// Try to insert a new bulb inside light replacer
- ///
- /// True if successfully inserted light, false otherwise
- public bool TryInsertBulb(EntityUid replacerUid, EntityUid bulbUid, EntityUid? userUid = null, bool showTooltip = false,
- LightReplacerComponent? replacer = null, LightBulbComponent? bulb = null)
- {
- if (!Resolve(replacerUid, ref replacer))
- return false;
- if (!Resolve(bulbUid, ref bulb))
- return false;
-
- // only normal (non-broken) bulbs can be inserted inside light replacer
- if (bulb.State != LightBulbState.Normal)
- {
- if (showTooltip && userUid != null)
- {
- var msg = Loc.GetString("comp-light-replacer-insert-broken-light");
- _popupSystem.PopupEntity(msg, replacerUid, userUid.Value);
- }
-
- return false;
- }
-
- // try insert light and show message
- var hasInsert = replacer.InsertedBulbs.Insert(bulb.Owner);
- if (hasInsert && showTooltip && userUid != null)
- {
- var msg = Loc.GetString("comp-light-replacer-insert-light",
- ("light-replacer", replacer.Owner), ("bulb", bulb.Owner));
- _popupSystem.PopupEntity(msg, replacerUid, userUid.Value, PopupType.Medium);
- }
-
- return hasInsert;
- }
-
- ///
- /// Try to insert all light bulbs from storage (for example light tubes box)
- ///
- ///
- /// Returns true if storage contained at least one light bulb
- /// which was successfully inserted inside light replacer
- ///
- public bool TryInsertBulbsFromStorage(EntityUid replacerUid, EntityUid storageUid, EntityUid? userUid = null,
- LightReplacerComponent? replacer = null, ServerStorageComponent? storage = null)
- {
- if (!Resolve(replacerUid, ref replacer))
- return false;
- if (!Resolve(storageUid, ref storage))
- return false;
-
- if (storage.StoredEntities == null)
- return false;
-
- var insertedBulbs = 0;
- var storagedEnts = storage.StoredEntities.ToArray();
- foreach (var ent in storagedEnts)
- {
- if (EntityManager.TryGetComponent(ent, out LightBulbComponent? bulb))
- {
- if (TryInsertBulb(replacerUid, ent, userUid, false, replacer, bulb))
- insertedBulbs++;
- }
- }
-
- // show some message if success
- if (insertedBulbs > 0 && userUid != null)
- {
- var msg = Loc.GetString("comp-light-replacer-refill-from-storage", ("light-replacer", storage.Owner));
- _popupSystem.PopupEntity(msg, replacerUid, userUid.Value, PopupType.Medium);
- }
-
- return insertedBulbs > 0;
+ args.PushMarkup(Loc.GetString("comp-light-replacer-light-listing", ("amount", amount), ("name", name)));
}
}
+
+ private void OnMapInit(EntityUid uid, LightReplacerComponent component, MapInitEvent args)
+ {
+ var xform = Transform(uid);
+ foreach (var spawn in EntitySpawnCollection.GetSpawns(component.Contents))
+ {
+ var ent = Spawn(spawn, xform.Coordinates);
+ TryInsertBulb(uid, ent, replacer: component);
+ }
+ }
+
+ private void OnInit(EntityUid uid, LightReplacerComponent replacer, ComponentInit args)
+ {
+ replacer.InsertedBulbs = _container.EnsureContainer(uid, "light_replacer_storage");
+ }
+
+ private void HandleAfterInteract(EntityUid uid, LightReplacerComponent component, AfterInteractEvent eventArgs)
+ {
+ if (eventArgs.Handled)
+ return;
+
+ // standard interaction checks
+ if (!eventArgs.CanReach)
+ return;
+
+ // behaviour will depends on target type
+ if (eventArgs.Target != null)
+ {
+ var targetUid = (EntityUid) eventArgs.Target;
+
+ // replace broken light in fixture?
+ if (TryComp(targetUid, out var fixture))
+ eventArgs.Handled = TryReplaceBulb(uid, targetUid, eventArgs.User, component, fixture);
+ // add new bulb to light replacer container?
+ else if (TryComp(targetUid, out var bulb))
+ eventArgs.Handled = TryInsertBulb(uid, targetUid, eventArgs.User, true, component, bulb);
+ }
+ }
+
+ private void HandleInteract(EntityUid uid, LightReplacerComponent component, InteractUsingEvent eventArgs)
+ {
+ if (eventArgs.Handled)
+ return;
+
+ var usedUid = eventArgs.Used;
+
+ // want to insert a new light bulb?
+ if (TryComp(usedUid, out var bulb))
+ eventArgs.Handled = TryInsertBulb(uid, usedUid, eventArgs.User, true, component, bulb);
+ // add bulbs from storage?
+ else if (TryComp(usedUid, out var storage))
+ eventArgs.Handled = TryInsertBulbsFromStorage(uid, usedUid, eventArgs.User, component, storage);
+ }
+
+ ///
+ /// Try to replace a light bulb in
+ /// using light replacer. Light fixture should have .
+ ///
+ /// True if successfully replaced light, false otherwise
+ public bool TryReplaceBulb(EntityUid replacerUid, EntityUid fixtureUid, EntityUid? userUid = null,
+ LightReplacerComponent? replacer = null, PoweredLightComponent? fixture = null)
+ {
+ if (!Resolve(replacerUid, ref replacer))
+ return false;
+ if (!Resolve(fixtureUid, ref fixture))
+ return false;
+
+ // check if light bulb is broken or missing
+ var fixtureBulbUid = _poweredLight.GetBulb(fixtureUid, fixture);
+ if (fixtureBulbUid != null)
+ {
+ if (!TryComp(fixtureBulbUid.Value, out var fixtureBulb))
+ return false;
+ if (fixtureBulb.State == LightBulbState.Normal)
+ return false;
+ }
+
+ // try get first inserted bulb of the same type as targeted light fixtutre
+ var bulb = replacer.InsertedBulbs.ContainedEntities.FirstOrDefault(
+ e => CompOrNull(e)?.Type == fixture.BulbType);
+
+ // found bulb in inserted storage
+ if (bulb.Valid) // FirstOrDefault can return default/invalid uid.
+ {
+ // try to remove it
+ var hasRemoved = replacer.InsertedBulbs.Remove(bulb);
+ if (!hasRemoved)
+ return false;
+ }
+ else
+ {
+ if (userUid != null)
+ {
+ var msg = Loc.GetString("comp-light-replacer-missing-light",
+ ("light-replacer", replacerUid));
+ _popupSystem.PopupEntity(msg, replacerUid, userUid.Value);
+ }
+ return false;
+ }
+
+ // insert it into fixture
+ var wasReplaced = _poweredLight.ReplaceBulb(fixtureUid, bulb, fixture);
+ if (wasReplaced)
+ {
+ _audio.PlayPvs(replacer.Sound, replacerUid);
+ }
+
+ return wasReplaced;
+ }
+
+ ///
+ /// Try to insert a new bulb inside light replacer
+ ///
+ /// True if successfully inserted light, false otherwise
+ public bool TryInsertBulb(EntityUid replacerUid, EntityUid bulbUid, EntityUid? userUid = null, bool showTooltip = false,
+ LightReplacerComponent? replacer = null, LightBulbComponent? bulb = null)
+ {
+ if (!Resolve(replacerUid, ref replacer))
+ return false;
+ if (!Resolve(bulbUid, ref bulb))
+ return false;
+
+ // only normal (non-broken) bulbs can be inserted inside light replacer
+ if (bulb.State != LightBulbState.Normal)
+ {
+ if (showTooltip && userUid != null)
+ {
+ var msg = Loc.GetString("comp-light-replacer-insert-broken-light");
+ _popupSystem.PopupEntity(msg, replacerUid, userUid.Value);
+ }
+
+ return false;
+ }
+
+ // try insert light and show message
+ var hasInsert = replacer.InsertedBulbs.Insert(bulbUid);
+ if (hasInsert && showTooltip && userUid != null)
+ {
+ var msg = Loc.GetString("comp-light-replacer-insert-light",
+ ("light-replacer", replacerUid), ("bulb", bulbUid));
+ _popupSystem.PopupEntity(msg, replacerUid, userUid.Value, PopupType.Medium);
+ }
+
+ return hasInsert;
+ }
+
+ ///
+ /// Try to insert all light bulbs from storage (for example light tubes box)
+ ///
+ ///
+ /// Returns true if storage contained at least one light bulb
+ /// which was successfully inserted inside light replacer
+ ///
+ public bool TryInsertBulbsFromStorage(EntityUid replacerUid, EntityUid storageUid, EntityUid? userUid = null,
+ LightReplacerComponent? replacer = null, ServerStorageComponent? storage = null)
+ {
+ if (!Resolve(replacerUid, ref replacer))
+ return false;
+ if (!Resolve(storageUid, ref storage))
+ return false;
+
+ if (storage.StoredEntities == null)
+ return false;
+
+ var insertedBulbs = 0;
+ var storagedEnts = storage.StoredEntities.ToArray();
+ foreach (var ent in storagedEnts)
+ {
+ if (TryComp(ent, out var bulb) &&
+ TryInsertBulb(replacerUid, ent, userUid, false, replacer, bulb))
+ insertedBulbs++;
+ }
+
+ // show some message if success
+ if (insertedBulbs > 0 && userUid != null)
+ {
+ var msg = Loc.GetString("comp-light-replacer-refill-from-storage", ("light-replacer", storageUid));
+ _popupSystem.PopupEntity(msg, replacerUid, userUid.Value, PopupType.Medium);
+ }
+
+ return insertedBulbs > 0;
+ }
}
diff --git a/Resources/Locale/en-US/light/components/light-replacer-component.ftl b/Resources/Locale/en-US/light/components/light-replacer-component.ftl
index f183ac8f7e..0cbb287a67 100644
--- a/Resources/Locale/en-US/light/components/light-replacer-component.ftl
+++ b/Resources/Locale/en-US/light/components/light-replacer-component.ftl
@@ -1,14 +1,23 @@
### Interaction Messages
-# Shown when player tries to replace light, but there is no lighs left
-comp-light-replacer-missing-light = No lights left in {$light-replacer}.
+# Shown when player tries to replace light, but there is no lights left
+comp-light-replacer-missing-light = No lights left in {THE($light-replacer)}.
# Shown when player inserts light bulb inside light replacer
-comp-light-replacer-insert-light = You insert {$bulb} into {$light-replacer}.
+comp-light-replacer-insert-light = You insert {$bulb} into {THE($light-replacer)}.
# Shown when player tries to insert in light replacer brolen light bulb
comp-light-replacer-insert-broken-light = You can't insert broken lights!
# Shown when player refill light from light box
-comp-light-replacer-refill-from-storage = You refill {$light-replacer}.
\ No newline at end of file
+comp-light-replacer-refill-from-storage = You refill {THE($light-replacer)}.
+
+### Examine
+
+comp-light-replacer-no-lights = It's empty.
+comp-light-replacer-has-lights = It contains the following:
+comp-light-replacer-light-listing = {$amount ->
+ [one] [color=yellow]{$amount}[/color] [color=gray]{$name}[/color]
+ *[other] [color=yellow]{$amount}[/color] [color=gray]{$name}s[/color]
+}
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml b/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml
index 208843ad19..e0282ce830 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml
@@ -11,12 +11,10 @@
sprite: Objects/Specific/Janitorial/light_replacer.rsi
- type: LightReplacer
contents:
- - name: LightTube
+ - id: LightTube
amount: 8
- type: Tube
- - name: LightBulb
+ - id: LightBulb
amount: 5
- type: Bulb
- type: Tag
tags:
- DroneUsable
@@ -25,3 +23,13 @@
- type: ContainerContainer
containers:
light_replacer_storage: !type:Container
+
+- type: entity
+ parent: LightReplacer
+ id: LightReplacerEmpty
+ suffix: Empty
+ components:
+ - type: LightReplacer
+ contents:
+ - id: LightTube
+ amount: 0
diff --git a/Resources/Prototypes/Recipes/Lathes/janitorial.yml b/Resources/Prototypes/Recipes/Lathes/janitorial.yml
index a9a2866c1d..6165bf274c 100644
--- a/Resources/Prototypes/Recipes/Lathes/janitorial.yml
+++ b/Resources/Prototypes/Recipes/Lathes/janitorial.yml
@@ -50,11 +50,11 @@
- type: latheRecipe
id: LightReplacer
- result: LightReplacer
+ result: LightReplacerEmpty
completetime: 2.4
materials:
Steel: 100
- Glass: 1000
+ Glass: 500
- type: latheRecipe
id: AdvMopItem