diff --git a/Content.Client/Morgue/Visualizers/CrematoriumVisualLayers.cs b/Content.Client/Morgue/Visualizers/CrematoriumVisualLayers.cs new file mode 100644 index 0000000000..28e199c066 --- /dev/null +++ b/Content.Client/Morgue/Visualizers/CrematoriumVisualLayers.cs @@ -0,0 +1,7 @@ +namespace Content.Client.Morgue.Visualizers; +public enum CrematoriumVisualLayers : byte +{ + Base, + LightBurning, + LightContent +} diff --git a/Content.Client/Morgue/Visualizers/CrematoriumVisualizerSystem.cs b/Content.Client/Morgue/Visualizers/CrematoriumVisualizerSystem.cs deleted file mode 100644 index a63ec062a8..0000000000 --- a/Content.Client/Morgue/Visualizers/CrematoriumVisualizerSystem.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Content.Shared.Morgue; -using Content.Shared.Storage; -using JetBrains.Annotations; -using Robust.Client.GameObjects; - -namespace Content.Client.Morgue.Visualizers; - -public sealed class CrematoriumVisualizerSystem : VisualizerSystem -{ - public override void Initialize() - { - base.Initialize(); - } - - protected override void OnAppearanceChange(EntityUid uid, CrematoriumVisualsComponent component, ref AppearanceChangeEvent args) - { - if (args.Sprite == null) - return; - - string? lightState = null; - if (args.Component.TryGetData(CrematoriumVisuals.Burning, out bool isBurning) && isBurning) - lightState = component.LightBurning; - else if (args.Component.TryGetData(StorageVisuals.HasContents, out bool hasContents) && hasContents) - lightState = component.LightContents; - - if (lightState != null) - { - args.Sprite.LayerSetState(CrematoriumVisualLayers.Light, lightState); - args.Sprite.LayerSetVisible(CrematoriumVisualLayers.Light, true); - } - else - { - args.Sprite.LayerSetVisible(CrematoriumVisualLayers.Light, false); - } - } -} diff --git a/Content.Client/Morgue/Visualizers/CrematoriumVisualsComponent.cs b/Content.Client/Morgue/Visualizers/CrematoriumVisualsComponent.cs deleted file mode 100644 index b2bb026294..0000000000 --- a/Content.Client/Morgue/Visualizers/CrematoriumVisualsComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Content.Client.Morgue.Visualizers; - -[RegisterComponent] -public sealed class CrematoriumVisualsComponent : Component -{ - [DataField("lightContents", required: true)] - public string LightContents = default!; - [DataField("lightBurning", required: true)] - public string LightBurning = default!; -} - -public enum CrematoriumVisualLayers : byte -{ - Base, - Light, -} diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs index df96997c7a..add6e4350b 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -60,7 +60,6 @@ public sealed class PrototypeSaveTest "WeaponLauncherChinaLake", "WeaponLauncherRocket", "WeaponLauncherMultipleRocket", - "Crematorium", "JawsOfLife", "SyndicateJawsOfLife", "LightReplacer", diff --git a/Content.Server/Morgue/Components/ActiveCrematoriumComponent.cs b/Content.Server/Morgue/Components/ActiveCrematoriumComponent.cs new file mode 100644 index 0000000000..56e0b88e15 --- /dev/null +++ b/Content.Server/Morgue/Components/ActiveCrematoriumComponent.cs @@ -0,0 +1,11 @@ +namespace Content.Server.Morgue.Components; + +/// +/// used to track actively cooking crematoriums +/// +[RegisterComponent] +public sealed class ActiveCrematoriumComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite)] + public float Accumulator = 0; +} diff --git a/Content.Server/Morgue/Components/CrematoriumComponent.cs b/Content.Server/Morgue/Components/CrematoriumComponent.cs index a12d86c8dd..c86220ee05 100644 --- a/Content.Server/Morgue/Components/CrematoriumComponent.cs +++ b/Content.Server/Morgue/Components/CrematoriumComponent.cs @@ -1,5 +1,4 @@ using Robust.Shared.Audio; -using System.Threading; namespace Content.Server.Morgue.Components; @@ -7,18 +6,10 @@ namespace Content.Server.Morgue.Components; public sealed class CrematoriumComponent : Component { /// - /// Whether or not the crematorium is currently cooking - /// - [ViewVariables] - public bool Cooking; - - /// - /// The time it takes to cook + /// The time it takes to cook in second /// [ViewVariables(VVAccess.ReadWrite)] - public int BurnMilis = 5000; - - public CancellationTokenSource? CremateCancelToken; + public int CookTime = 5; [DataField("cremateStartSound")] public SoundSpecifier CremateStartSound = new SoundPathSpecifier("/Audio/Items/lighter1.ogg"); diff --git a/Content.Server/Morgue/CrematoriumSystem.cs b/Content.Server/Morgue/CrematoriumSystem.cs index effc609535..34cd85f1c0 100644 --- a/Content.Server/Morgue/CrematoriumSystem.cs +++ b/Content.Server/Morgue/CrematoriumSystem.cs @@ -2,9 +2,7 @@ using Content.Server.Morgue.Components; using Content.Shared.Morgue; using Robust.Server.GameObjects; using Robust.Shared.Player; -using Robust.Shared.Audio; using Content.Server.Storage.Components; -using System.Threading; using Content.Shared.Verbs; using Content.Shared.Database; using Content.Shared.Interaction.Events; @@ -21,6 +19,8 @@ namespace Content.Server.Morgue; public sealed class CrematoriumSystem : EntitySystem { + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly EntityStorageSystem _entityStorage = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; @@ -31,9 +31,9 @@ public sealed class CrematoriumSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnExamine); - SubscribeLocalEvent(OnAttemptOpen); SubscribeLocalEvent>(AddCremateVerb); SubscribeLocalEvent(OnSuicide); + SubscribeLocalEvent(OnAttemptOpen); } private void OnExamine(EntityUid uid, CrematoriumComponent component, ExaminedEvent args) @@ -49,10 +49,9 @@ public sealed class CrematoriumSystem : EntitySystem args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-empty")); } - private void OnAttemptOpen(EntityUid uid, CrematoriumComponent component, StorageOpenAttemptEvent args) + private void OnAttemptOpen(EntityUid uid, ActiveCrematoriumComponent component, StorageOpenAttemptEvent args) { - if (component.Cooking) - args.Cancel(); + args.Cancel(); } private void AddCremateVerb(EntityUid uid, CrematoriumComponent component, GetVerbsEvent args) @@ -60,7 +59,10 @@ public sealed class CrematoriumSystem : EntitySystem if (!TryComp(uid, out var storage)) return; - if (!args.CanAccess || !args.CanInteract || args.Hands == null || component.Cooking || storage.Open) + if (!args.CanAccess || !args.CanInteract || args.Hands == null || storage.Open) + return; + + if (HasComp(uid)) return; AlternativeVerb verb = new() @@ -73,58 +75,56 @@ public sealed class CrematoriumSystem : EntitySystem args.Verbs.Add(verb); } - public void Cremate(EntityUid uid, CrematoriumComponent? component = null, EntityStorageComponent? storage = null) + public bool Cremate(EntityUid uid, CrematoriumComponent? component = null, EntityStorageComponent? storage = null) { if (!Resolve(uid, ref component, ref storage)) - return; + return false; - if (TryComp(uid, out var app)) - app.SetData(CrematoriumVisuals.Burning, true); - component.Cooking = true; + if (HasComp(uid)) + return false; - SoundSystem.Play(component.CrematingSound.GetSound(), Filter.Pvs(uid), uid); + _audio.PlayPvs(component.CremateStartSound, uid); + _appearance.SetData(uid, CrematoriumVisuals.Burning, true); - component.CremateCancelToken?.Cancel(); - component.CremateCancelToken = new CancellationTokenSource(); - uid.SpawnTimer(component.BurnMilis, () => - { - if (Deleted(uid)) - return; - if (TryComp(uid, out var app)) - app.SetData(CrematoriumVisuals.Burning, false); - component.Cooking = false; + _audio.PlayPvs(component.CrematingSound, uid); - if (storage.Contents.ContainedEntities.Count > 0) - { - for (var i = storage.Contents.ContainedEntities.Count - 1; i >= 0; i--) - { - var item = storage.Contents.ContainedEntities[i]; - storage.Contents.Remove(item); - EntityManager.DeleteEntity(item); - } - - var ash = Spawn("Ash", Transform(uid).Coordinates); - storage.Contents.Insert(ash); - } - - _entityStorage.OpenStorage(uid, storage); - - SoundSystem.Play(component.CremateFinishSound.GetSound(), Filter.Pvs(uid), uid); - - }, component.CremateCancelToken.Token); + AddComp(uid); + return true; } - public void TryCremate(EntityUid uid, CrematoriumComponent component, EntityStorageComponent? storage = null) + public bool TryCremate(EntityUid uid, CrematoriumComponent? component = null, EntityStorageComponent? storage = null) + { + if (!Resolve(uid, ref component, ref storage)) + return false; + + if (storage.Open || storage.Contents.ContainedEntities.Count < 1) + return false; + + return Cremate(uid, component, storage); + } + + private void FinishCooking(EntityUid uid, CrematoriumComponent component, EntityStorageComponent? storage = null) { if (!Resolve(uid, ref storage)) return; - if (component.Cooking || storage.Open || storage.Contents.ContainedEntities.Count < 1) - return; + _appearance.SetData(uid, CrematoriumVisuals.Burning, false); + RemComp(uid); - SoundSystem.Play(component.CremateStartSound.GetSound(), Filter.Pvs(uid), uid); + if (storage.Contents.ContainedEntities.Count > 0) + { + for (var i = storage.Contents.ContainedEntities.Count - 1; i >= 0; i--) + { + var item = storage.Contents.ContainedEntities[i]; + storage.Contents.Remove(item); + EntityManager.DeleteEntity(item); + } + var ash = Spawn("Ash", Transform(uid).Coordinates); + storage.Contents.Insert(ash); + } - Cremate(uid, component, storage); + _entityStorage.OpenStorage(uid, storage); + _audio.PlayPvs(component.CremateFinishSound, uid); } private void OnSuicide(EntityUid uid, CrematoriumComponent component, SuicideEvent args) @@ -161,4 +161,17 @@ public sealed class CrematoriumSystem : EntitySystem _entityStorage.CloseStorage(uid); Cremate(uid, component); } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var (act, crem) in EntityQuery()) + { + act.Accumulator += frameTime; + + if (act.Accumulator >= crem.CookTime) + FinishCooking(act.Owner, crem); + } + } } diff --git a/Content.Server/Morgue/MorgueSystem.cs b/Content.Server/Morgue/MorgueSystem.cs index 46fefabfc5..78f6678c0f 100644 --- a/Content.Server/Morgue/MorgueSystem.cs +++ b/Content.Server/Morgue/MorgueSystem.cs @@ -2,17 +2,16 @@ using Content.Server.Morgue.Components; using Content.Shared.Morgue; using Content.Shared.Examine; using Robust.Server.GameObjects; -using Content.Server.Popups; -using Robust.Shared.Player; -using Robust.Shared.Audio; using Content.Server.Storage.Components; using Content.Shared.Body.Components; -using Content.Shared.Storage; namespace Content.Server.Morgue; -public sealed partial class MorgueSystem : EntitySystem +public sealed class MorgueSystem : EntitySystem { + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + public override void Initialize() { base.Initialize(); @@ -32,7 +31,7 @@ public sealed partial class MorgueSystem : EntitySystem return; appearance.TryGetData(MorgueVisuals.Contents, out MorgueContents contents); - + var text = contents switch { MorgueContents.HasSoul => "morgue-entity-storage-component-on-examine-details-body-has-soul", @@ -54,25 +53,25 @@ public sealed partial class MorgueSystem : EntitySystem if (storage.Contents.ContainedEntities.Count == 0) { - app.SetData(MorgueVisuals.Contents, MorgueContents.Empty); + _appearance.SetData(uid, MorgueVisuals.Contents, MorgueContents.Empty); return; } var hasMob = false; - + foreach (var ent in storage.Contents.ContainedEntities) { if (!hasMob && HasComp(ent)) hasMob = true; - if (TryComp(ent, out var actor) && actor.PlayerSession != null) + if (HasComp(ent)) { - app.SetData(MorgueVisuals.Contents, MorgueContents.HasSoul); + _appearance.SetData(uid, MorgueVisuals.Contents, MorgueContents.HasSoul, app); return; } } - app.SetData(MorgueVisuals.Contents, hasMob ? MorgueContents.HasMob : MorgueContents.HasContents); + _appearance.SetData(uid, MorgueVisuals.Contents, hasMob ? MorgueContents.HasMob : MorgueContents.HasContents, app); } /// @@ -86,7 +85,7 @@ public sealed partial class MorgueSystem : EntitySystem { comp.AccumulatedFrameTime += frameTime; - CheckContents(comp.Owner, comp, storage, appearance); + CheckContents(comp.Owner, comp, storage); if (comp.AccumulatedFrameTime < comp.BeepTime) continue; @@ -95,7 +94,7 @@ public sealed partial class MorgueSystem : EntitySystem if (comp.DoSoulBeep && appearance.TryGetData(MorgueVisuals.Contents, out MorgueContents contents) && contents == MorgueContents.HasSoul) { - SoundSystem.Play(comp.OccupantHasSoulAlarmSound.GetSound(), Filter.Pvs(comp.Owner), comp.Owner); + _audio.PlayPvs(comp.OccupantHasSoulAlarmSound, comp.Owner); } } } diff --git a/Resources/Maps/splitstation.yml b/Resources/Maps/splitstation.yml index 6e0978bc36..e08aa92050 100644 --- a/Resources/Maps/splitstation.yml +++ b/Resources/Maps/splitstation.yml @@ -59466,25 +59466,12 @@ entities: pos: 26.5,10.5 parent: 69 type: Transform -- uid: 5014 - type: CrematoriumTray - components: - - parent: 5015 - type: Transform - - canCollide: False - type: Physics - uid: 5015 type: Crematorium components: - pos: 25.5,13.5 parent: 69 type: Transform - - containers: - entity_storage: !type:Container - ents: [] - morgue_tray: !type:ContainerSlot - ent: 5014 - type: ContainerContainer - uid: 5016 type: AsteroidRock components: diff --git a/Resources/Prototypes/Entities/Structures/Storage/morgue.yml b/Resources/Prototypes/Entities/Structures/Storage/morgue.yml index dd72e44e1d..8768c7ce3e 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/morgue.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/morgue.yml @@ -2,6 +2,8 @@ id: Morgue name: morgue description: Used to store bodies until someone fetches them. Includes a high-tech alert system for false-positives! + placement: + mode: SnapgridCenter components: - type: Sprite netsync: false @@ -45,7 +47,6 @@ - type: ContainerContainer containers: entity_storage: !type:Container - morgue_tray: !type:ContainerSlot - type: Appearance - type: GenericVisualizer visuals: @@ -71,32 +72,12 @@ - type: StaticPrice price: 200 -#needs to be removed -- type: entity - id: MorgueTray - name: morgue tray - description: If you lay down to have a rest on this, you'll soon have a problem. - noSpawn: true - components: - - type: Physics - bodyType: Static - - type: Fixtures - fixtures: - - shape: - !type:PhysShapeAabb - bounds: "-0.5,-0.5,0.5,0.5" - mass: 25 - mask: - - Impassable - - type: Sprite - netsync: false - sprite: Structures/Storage/morgue.rsi - state: morgue_tray - - type: entity id: Crematorium name: crematorium description: A human incinerator. Works well on barbecue nights. + placement: + mode: SnapgridCenter components: - type: Sprite netsync: false @@ -109,7 +90,11 @@ map: ["enum.StorageVisualLayers.Door"] - state: crema_contents_light visible: false - map: ["enum.CrematoriumVisualLayers.Light"] + map: ["enum.CrematoriumVisualLayers.LightContent"] + shader: unshaded + - state: crema_active_light + visible: false + map: ["enum.CrematoriumVisualLayers.LightBurning"] shader: unshaded - type: Clickable - type: InteractionOutline @@ -136,26 +121,24 @@ path: /Audio/Items/deconstruct.ogg - type: EntityStorageLayingDownOverride - type: Crematorium + - type: ContainerContainer + containers: + entity_storage: !type:Container - type: Appearance visuals: - type: StorageVisualizer state: crema_closed state_alt: crema_open state_open: crema_tray - - type: CrematoriumVisuals - lightContents: crema_contents_light - lightBurning: crema_active_light + - type: GenericVisualizer + visuals: + enum.CrematoriumVisuals.Burning: + enum.CrematoriumVisualLayers.LightBurning: + True: { visible: true } + False: { visible: false } + enum.StorageVisuals.HasContents: + enum.CrematoriumVisualLayers.LightContent: + True: { visible: true } + False: { visible: false } - type: Transform anchored: true - -#needs to be removed -- type: entity - id: CrematoriumTray - name: crematorium tray - parent: MorgueTray - noSpawn: true - components: - - type: Sprite - netsync: false - sprite: Structures/Storage/morgue.rsi - state: crema_tray