diff --git a/Content.Client/Atmos/Miasma/FliesComponent.cs b/Content.Client/Atmos/Miasma/FliesComponent.cs new file mode 100644 index 0000000000..21a7b1bd32 --- /dev/null +++ b/Content.Client/Atmos/Miasma/FliesComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Atmos.Miasma; +using Robust.Shared.GameStates; + +namespace Content.Client.Atmos.Miasma; + +[NetworkedComponent, RegisterComponent] +public sealed class FliesComponent : SharedFliesComponent +{ } diff --git a/Content.Client/Atmos/Miasma/FliesSystem.cs b/Content.Client/Atmos/Miasma/FliesSystem.cs new file mode 100644 index 0000000000..493ca8bd4b --- /dev/null +++ b/Content.Client/Atmos/Miasma/FliesSystem.cs @@ -0,0 +1,41 @@ +using Robust.Client.GameObjects; +using Robust.Shared.Utility; + +namespace Content.Client.Atmos.Miasma; + +public sealed class FliesSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(FliesAdded); + SubscribeLocalEvent(FliesRemoved); + } + + private void FliesRemoved(EntityUid uid, FliesComponent component, ComponentShutdown args) + { + if (!TryComp(uid, out var sprite)) + return; + + if (!sprite.LayerMapTryGet(FliesKey.Key, out var layer)) + return; + + sprite.RemoveLayer(layer); + } + + private void FliesAdded(EntityUid uid, FliesComponent component, ComponentStartup args) + { + if (!TryComp(uid, out var sprite)) + return; + + if (sprite.LayerMapTryGet(FliesKey.Key, out var _)) + return; + + var layer = sprite.AddLayer(new SpriteSpecifier.Rsi(new ResourcePath("Objects/Misc/flies.rsi"), "flies")); + sprite.LayerMapSet(FliesKey.Key, layer); + } + + private enum FliesKey + { + Key, + } +} diff --git a/Content.Server/Administration/Commands/RejuvenateCommand.cs b/Content.Server/Administration/Commands/RejuvenateCommand.cs index 7554e25986..b6875279d6 100644 --- a/Content.Server/Administration/Commands/RejuvenateCommand.cs +++ b/Content.Server/Administration/Commands/RejuvenateCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Miasma; using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Disease.Components; @@ -89,15 +90,13 @@ namespace Content.Server.Administration.Commands sys.TryModifyBloodLevel(target, bloodStream.BloodSolution.AvailableVolume, bloodStream); } - if (entMan.HasComponent(target)) - { - entMan.RemoveComponent(target); - } - if (entMan.TryGetComponent(target, out var carrier)) { EntitySystem.Get().CureAllDiseases(target, carrier); } + + entMan.RemoveComponent(target); + entMan.RemoveComponent(target); } } } diff --git a/Content.Server/Atmos/Miasma/NoRotContainerComponent.cs b/Content.Server/Atmos/Miasma/AntiRottingContainerComponent.cs similarity index 100% rename from Content.Server/Atmos/Miasma/NoRotContainerComponent.cs rename to Content.Server/Atmos/Miasma/AntiRottingContainerComponent.cs diff --git a/Content.Server/Atmos/Miasma/FliesComponent.cs b/Content.Server/Atmos/Miasma/FliesComponent.cs new file mode 100644 index 0000000000..fddb88652f --- /dev/null +++ b/Content.Server/Atmos/Miasma/FliesComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.Atmos.Miasma; +using Robust.Shared.GameStates; + +namespace Content.Server.Atmos.Miasma; + +[NetworkedComponent, RegisterComponent] +public sealed class FliesComponent : SharedFliesComponent +{ + /// Need something to hold the ambient sound, at least until that system becomes more robust + public EntityUid VirtFlies; +} diff --git a/Content.Server/Atmos/Miasma/MiasmaSystem.cs b/Content.Server/Atmos/Miasma/MiasmaSystem.cs index 211c353538..73d1168ae3 100644 --- a/Content.Server/Atmos/Miasma/MiasmaSystem.cs +++ b/Content.Server/Atmos/Miasma/MiasmaSystem.cs @@ -2,12 +2,10 @@ using Content.Shared.MobState; using Content.Shared.Damage; using Content.Shared.Atmos; using Content.Server.Atmos.EntitySystems; -using Content.Server.Temperature.Components; +using Content.Server.Temperature.Systems; using Content.Server.Body.Components; -using Content.Server.Popups; using Content.Shared.Examine; using Robust.Shared.Containers; -using Robust.Shared.Player; namespace Content.Server.Atmos.Miasma { @@ -15,8 +13,8 @@ namespace Content.Server.Atmos.Miasma { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; - - [Dependency] private readonly PopupSystem _popupSystem = default!; + /// Feel free to weak this if there are perf concerns + private float UpdateRate = 5f; public override void Update(float frameTime) { @@ -26,18 +24,17 @@ namespace Content.Server.Atmos.Miasma if (!perishable.Progressing) continue; - if (TryComp(perishable.Owner, out var temp) && temp.CurrentTemperature < 274f) - continue; - perishable.DeathAccumulator += frameTime; if (perishable.DeathAccumulator < perishable.RotAfter.TotalSeconds) continue; perishable.RotAccumulator += frameTime; - if (perishable.RotAccumulator < 1f) + if (perishable.RotAccumulator < UpdateRate) // This is where it starts to get noticable on larger animals, no need to run every second continue; - perishable.RotAccumulator -= 1f; + perishable.RotAccumulator -= UpdateRate; + + EnsureComp(perishable.Owner); DamageSpecifier damage = new(); damage.DamageDict.Add("Blunt", 0.3); // Slowly accumulate enough to gib after like half an hour @@ -49,21 +46,45 @@ namespace Content.Server.Atmos.Miasma continue; // We need a way to get the mass of the mob alone without armor etc in the future + float molRate = perishable.MolsPerSecondPerUnitMass * UpdateRate; + var tileMix = _atmosphereSystem.GetTileMixture(Transform(perishable.Owner).Coordinates); if (tileMix != null) - tileMix.AdjustMoles(Gas.Miasma, perishable.MolsPerSecondPerUnitMass * physics.FixturesMass); + tileMix.AdjustMoles(Gas.Miasma, molRate * physics.FixturesMass); } } - public override void Initialize() { base.Initialize(); + // Core rotting stuff + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnTempChange); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnGibbed); SubscribeLocalEvent(OnExamined); + // Containers SubscribeLocalEvent(OnEntInserted); SubscribeLocalEvent(OnEntRemoved); + // Fly audiovisual stuff + SubscribeLocalEvent(OnFliesInit); + SubscribeLocalEvent(OnFliesShutdown); + } + + private void OnShutdown(EntityUid uid, RottingComponent component, ComponentShutdown args) + { + RemComp(uid); + if (TryComp(uid, out var perishable)) + { + perishable.DeathAccumulator = 0; + perishable.RotAccumulator = 0; + } + } + + private void OnTempChange(EntityUid uid, RottingComponent component, OnTemperatureChangeEvent args) + { + bool decompose = (args.CurrentTemperature > 274f); + ToggleDecomposition(uid, decompose); } private void OnMobStateChanged(EntityUid uid, PerishableComponent component, MobStateChangedEvent args) @@ -77,7 +98,7 @@ namespace Content.Server.Atmos.Miasma if (!TryComp(uid, out var physics)) return; - if (component.DeathAccumulator <= component.RotAfter.TotalSeconds) + if (!component.Rotting) return; var molsToDump = (component.MolsPerSecondPerUnitMass * physics.FixturesMass) * component.DeathAccumulator; @@ -85,28 +106,69 @@ namespace Content.Server.Atmos.Miasma if (tileMix != null) tileMix.AdjustMoles(Gas.Miasma, molsToDump); + // Waste of entities to let these through foreach (var part in args.GibbedParts) - { - EntityManager.QueueDeleteEntity(part); - } + EntityManager.DeleteEntity(part); } private void OnExamined(EntityUid uid, PerishableComponent component, ExaminedEvent args) { - if (component.DeathAccumulator >= component.RotAfter.TotalSeconds) + if (component.Rotting) args.PushMarkup(Loc.GetString("miasma-rotting")); } + /// Containers + private void OnEntInserted(EntityUid uid, AntiRottingContainerComponent component, EntInsertedIntoContainerMessage args) { if (TryComp(args.Entity, out var perishable)) - perishable.Progressing = false; + ToggleDecomposition(args.Entity, false, perishable); } - private void OnEntRemoved(EntityUid uid, AntiRottingContainerComponent component, EntRemovedFromContainerMessage args) { if (TryComp(args.Entity, out var perishable)) + ToggleDecomposition(args.Entity, true, perishable); + } + + + /// Fly stuff + + private void OnFliesInit(EntityUid uid, FliesComponent component, ComponentInit args) + { + component.VirtFlies = EntityManager.SpawnEntity("AmbientSoundSourceFlies", Transform(uid).Coordinates); + Transform(component.VirtFlies).AttachParent(uid); + } + + private void OnFliesShutdown(EntityUid uid, FliesComponent component, ComponentShutdown args) + { + EntityManager.DeleteEntity(component.VirtFlies); + } + + /// Public functions + + public void ToggleDecomposition(EntityUid uid, bool decompose, PerishableComponent? perishable = null) + { + if (!Resolve(uid, ref perishable)) + return; + + if (decompose == perishable.Progressing) // Saved a few cycles + return; + + if (!HasComp(uid)) + return; + + if (!perishable.Rotting) + return; + + if (decompose) + { perishable.Progressing = true; + EnsureComp(uid); + return; + } + + perishable.Progressing = false; + RemComp(uid); } } } diff --git a/Content.Server/Atmos/Miasma/PerishableComponent.cs b/Content.Server/Atmos/Miasma/PerishableComponent.cs index 252c23f200..0661d27065 100644 --- a/Content.Server/Atmos/Miasma/PerishableComponent.cs +++ b/Content.Server/Atmos/Miasma/PerishableComponent.cs @@ -25,6 +25,8 @@ namespace Content.Server.Atmos.Miasma /// public TimeSpan RotAfter = TimeSpan.FromMinutes(5); + public bool Rotting => (DeathAccumulator > RotAfter.TotalSeconds); + /// /// Gasses are released every second. /// diff --git a/Content.Shared/Atmos/Miasma/SharedFliesComponent.cs b/Content.Shared/Atmos/Miasma/SharedFliesComponent.cs new file mode 100644 index 0000000000..e0d08b4782 --- /dev/null +++ b/Content.Shared/Atmos/Miasma/SharedFliesComponent.cs @@ -0,0 +1,5 @@ +namespace Content.Shared.Atmos.Miasma; +public abstract class SharedFliesComponent : Component +{ + +} diff --git a/Resources/Audio/Ambience/Temporary/flies.ogg b/Resources/Audio/Ambience/Temporary/flies.ogg new file mode 100644 index 0000000000..756858aa08 Binary files /dev/null and b/Resources/Audio/Ambience/Temporary/flies.ogg differ diff --git a/Resources/Audio/Ambience/Temporary/license.txt b/Resources/Audio/Ambience/Temporary/license.txt new file mode 100644 index 0000000000..622886e2ac --- /dev/null +++ b/Resources/Audio/Ambience/Temporary/license.txt @@ -0,0 +1 @@ +flies.ogg taken from https://freesound.org/people/telezon/sounds/321870/ licensed under CC-0 diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml b/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml index 0696254ee8..80abc481ae 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml @@ -78,7 +78,7 @@ sprite: Mobs/Animals/cow.rsi state: cow product: CrateNPCCow - cost: 1000 + cost: 3200 category: Livestock group: market @@ -129,7 +129,7 @@ cost: 1500 category: Livestock group: market - + - type: cargoProduct name: "mice crate" id: LivestockMouse diff --git a/Resources/Prototypes/Entities/Effects/ambient_sounds.yml b/Resources/Prototypes/Entities/Effects/ambient_sounds.yml new file mode 100644 index 0000000000..f686779b3e --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/ambient_sounds.yml @@ -0,0 +1,12 @@ +- type: entity + id: AmbientSoundSourceFlies + noSpawn: true + components: + - type: AmbientSound + volume: -5 + range: 3 + sound: + path: /Audio/Ambience/Temporary/flies.ogg + - type: Tag + tags: + - HideContextMenu diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml index da368f1483..f2731e2d49 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml @@ -76,6 +76,7 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + - type: AntiRottingContainer - type: entity id: CrateHydroponics diff --git a/Resources/Textures/Objects/Misc/flies.rsi/flies.png b/Resources/Textures/Objects/Misc/flies.rsi/flies.png new file mode 100644 index 0000000000..b93ca6e304 Binary files /dev/null and b/Resources/Textures/Objects/Misc/flies.rsi/flies.png differ diff --git a/Resources/Textures/Objects/Misc/flies.rsi/meta.json b/Resources/Textures/Objects/Misc/flies.rsi/meta.json new file mode 100644 index 0000000000..27ad389e82 --- /dev/null +++ b/Resources/Textures/Objects/Misc/flies.rsi/meta.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Created by github user @elijahrane", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "flies", + "directions": 1, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +}