using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Temperature.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Rotting; using Content.Shared.Damage; using Robust.Server.Containers; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; namespace Content.Server.Atmos.Rotting; public sealed class RottingSystem : SharedRottingSystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly AtmosphereSystem _atmosphere = default!; [Dependency] private readonly ContainerSystem _container = default!; [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnGibbed); SubscribeLocalEvent(OnTempIsRotting); } private void OnGibbed(EntityUid uid, RottingComponent component, BeingGibbedEvent args) { if (!TryComp(uid, out var physics)) return; if (!TryComp(uid, out var perishable)) return; var molsToDump = perishable.MolsPerSecondPerUnitMass * physics.FixturesMass * (float)component.TotalRotTime.TotalSeconds; var tileMix = _atmosphere.GetTileMixture(uid, excite: true); tileMix?.AdjustMoles(Gas.Ammonia, molsToDump); } private void OnTempIsRotting(EntityUid uid, TemperatureComponent component, ref IsRottingEvent args) { if (args.Handled) return; args.Handled = component.CurrentTemperature < Atmospherics.T0C + 0.85f; } /// /// Is anything speeding up the decay? /// e.g. buried in a grave /// TODO: hot temperatures increase rot? /// /// private float GetRotRate(EntityUid uid) { if (_container.TryGetContainingContainer((uid, null, null), out var container) && TryComp(container.Owner, out var rotContainer)) { return rotContainer.DecayModifier; } return 1f; } public override void Update(float frameTime) { base.Update(frameTime); var perishQuery = EntityQueryEnumerator(); while (perishQuery.MoveNext(out var uid, out var perishable)) { if (_timing.CurTime < perishable.RotNextUpdate) continue; perishable.RotNextUpdate += perishable.PerishUpdateRate; var stage = PerishStage((uid, perishable), MaxStages); if (stage != perishable.Stage) { perishable.Stage = stage; Dirty(uid, perishable); } if (IsRotten(uid) || !IsRotProgressing(uid, perishable)) continue; perishable.RotAccumulator += perishable.PerishUpdateRate * GetRotRate(uid); if (perishable.RotAccumulator >= perishable.RotAfter) { var rot = AddComp(uid); rot.NextRotUpdate = _timing.CurTime + rot.RotUpdateRate; } } var rotQuery = EntityQueryEnumerator(); while (rotQuery.MoveNext(out var uid, out var rotting, out var perishable, out var xform)) { if (_timing.CurTime < rotting.NextRotUpdate) // This is where it starts to get noticable on larger animals, no need to run every second continue; rotting.NextRotUpdate += rotting.RotUpdateRate; if (!IsRotProgressing(uid, perishable)) continue; rotting.TotalRotTime += rotting.RotUpdateRate * GetRotRate(uid); if (rotting.DealDamage) { var damage = rotting.Damage * rotting.RotUpdateRate.TotalSeconds; _damageable.TryChangeDamage(uid, damage, true, false); } if (TryComp(uid, out var rotInto)) { var stage = RotStage(uid, rotting, perishable); if (stage >= rotInto.Stage) { Spawn(rotInto.Entity, xform.Coordinates); QueueDel(uid); continue; } } if (!TryComp(uid, out var physics)) continue; // We need a way to get the mass of the mob alone without armor etc in the future // or just remove the mass mechanics altogether because they aren't good. var molRate = perishable.MolsPerSecondPerUnitMass * (float)rotting.RotUpdateRate.TotalSeconds; var tileMix = _atmosphere.GetTileMixture(uid, excite: true); tileMix?.AdjustMoles(Gas.Ammonia, molRate * physics.FixturesMass); } } }