Files
wwdpublic/Content.Server/Atmos/Rotting/RottingSystem.cs
VMSolidus aed3baba15 CPR Remake (#487)
# Description

This is a re implementation and complete rewrite of the original
Nyanotrasen CPR feature, this time as its own completely standalone
system. Unlike the original CPR, this system requires no modification of
base game code, and can be toggled on and off via CVars while the server
is running.

Fixes #473
Fixes #49

# Changelog
🆑
- add: CPR has been added to the game. People with CPR training can now
perform CPR on anyone who is in either crit or dead states.
- add: CPR Training has been added to the game as a new positive trait.
All medical staff start with this trait for free.

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
2024-08-05 22:28:53 -07:00

133 lines
4.9 KiB
C#

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<RottingComponent, BeingGibbedEvent>(OnGibbed);
SubscribeLocalEvent<TemperatureComponent, IsRottingEvent>(OnTempIsRotting);
}
private void OnGibbed(EntityUid uid, RottingComponent component, BeingGibbedEvent args)
{
if (!TryComp<PhysicsComponent>(uid, out var physics))
return;
if (!TryComp<PerishableComponent>(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;
}
/// <summary>
/// Is anything speeding up the decay?
/// e.g. buried in a grave
/// TODO: hot temperatures increase rot?
/// </summary>
/// <returns></returns>
private float GetRotRate(EntityUid uid)
{
if (_container.TryGetContainingContainer(uid, out var container) &&
TryComp<ProRottingContainerComponent>(container.Owner, out var rotContainer))
{
return rotContainer.DecayModifier;
}
return 1f;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var perishQuery = EntityQueryEnumerator<PerishableComponent>();
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<RottingComponent>(uid);
rot.NextRotUpdate = _timing.CurTime + rot.RotUpdateRate;
}
}
var rotQuery = EntityQueryEnumerator<RottingComponent, PerishableComponent, TransformComponent>();
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<RotIntoComponent>(uid, out var rotInto))
{
var stage = RotStage(uid, rotting, perishable);
if (stage >= rotInto.Stage)
{
Spawn(rotInto.Entity, xform.Coordinates);
QueueDel(uid);
continue;
}
}
if (!TryComp<PhysicsComponent>(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);
}
}
}