Skip to content

Commit

Permalink
feat: unfuck the cpr
Browse files Browse the repository at this point in the history
Signed-off-by: Remuchi <[email protected]>
  • Loading branch information
Remuchi committed Jan 2, 2025
1 parent 2178869 commit 37df814
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 197 deletions.
124 changes: 124 additions & 0 deletions Content.Server/Medical/CPR/CPRSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using Content.Server.Atmos.Rotting;
using Content.Server.DoAfter;
using Content.Server.Nutrition.EntitySystems;
using Content.Server.Popups;
using Content.Shared.Atmos.Rotting;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.Inventory;
using Content.Shared.Medical;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Verbs;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Random;
using Robust.Shared.Utility;

namespace Content.Server.Medical.CPR;

public sealed class CPRSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly FoodSystem _foodSystem = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly RottingSystem _rottingSystem = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly AudioSystem _audio = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CPRTrainingComponent, GetVerbsEvent<InnateVerb>>(AddCPRVerb);
SubscribeLocalEvent<CPRTrainingComponent, CPRDoAfterEvent>(OnCPRDoAfter);
}

private void AddCPRVerb(Entity<CPRTrainingComponent> performer, ref GetVerbsEvent<InnateVerb> args)
{
if (!args.CanInteract || !args.CanAccess || !TryComp<MobStateComponent>(args.Target, out var targetState)
|| targetState.CurrentState == MobState.Alive)
return;

var target = args.Target;
InnateVerb verb = new()
{
Act = () => { StartCPR(performer, target); },
Text = Loc.GetString("cpr-verb"),
Icon = new SpriteSpecifier.Rsi(new("Interface/Alerts/human_alive.rsi"), "health4"),
Priority = 2
};

args.Verbs.Add(verb);
}

private void StartCPR(Entity<CPRTrainingComponent> performer, EntityUid target)
{
if (HasComp<RottingComponent>(target))
{
_popupSystem.PopupEntity(Loc.GetString("cpr-target-rotting", ("entity", target)), performer, performer);
return;
}

if (_inventory.TryGetSlotEntity(target, "outerClothing", out var outer))
{
_popupSystem.PopupEntity(Loc.GetString("cpr-must-remove", ("clothing", outer)), performer, performer);
return;
}

if (_foodSystem.IsMouthBlocked(performer, performer) || _foodSystem.IsMouthBlocked(target, performer))
return;

_popupSystem.PopupEntity(Loc.GetString("cpr-start-second-person", ("target", target)), target, performer);
_popupSystem.PopupEntity(Loc.GetString("cpr-start-second-person-patient", ("user", performer)), target, target);

var doAfterArgs = new DoAfterArgs(
EntityManager, performer, performer.Comp.DoAfterDuration, new CPRDoAfterEvent(), performer, target,
performer)
{
BreakOnMove = true,
NeedHand = true,
BlockDuplicate = true
};

_doAfterSystem.TryStartDoAfter(doAfterArgs);

var playingStream = _audio.PlayPvs(performer.Comp.CPRSound, performer, AudioParams.Default.WithLoop(true));
if (!playingStream.HasValue)
return;

performer.Comp.CPRPlayingStream = playingStream.Value.Entity;
}

private void OnCPRDoAfter(Entity<CPRTrainingComponent> performer, ref CPRDoAfterEvent args)
{
if (args.Cancelled || args.Handled || !args.Target.HasValue)
{
performer.Comp.CPRPlayingStream = _audio.Stop(performer.Comp.CPRPlayingStream);
return;
}

if (!performer.Comp.CPRHealing.Empty)
_damageable.TryChangeDamage(args.Target, performer.Comp.CPRHealing, true, origin: performer);

if (performer.Comp.RotReductionMultiplier > 0)
_rottingSystem.ReduceAccumulator(
(EntityUid)args.Target, performer.Comp.DoAfterDuration * performer.Comp.RotReductionMultiplier);

if (_robustRandom.Prob(performer.Comp.ResuscitationChance)
&& _mobThreshold.TryGetThresholdForState((EntityUid)args.Target, MobState.Dead, out var threshold)
&& TryComp<DamageableComponent>(args.Target, out var damageableComponent)
&& TryComp<MobStateComponent>(args.Target, out var state)
&& damageableComponent.TotalDamage < threshold)
_mobStateSystem.ChangeMobState(args.Target.Value, MobState.Critical, state, performer);

var isAlive = _mobStateSystem.IsAlive(args.Target.Value);
args.Repeat = !isAlive;
if (isAlive)
performer.Comp.CPRPlayingStream = _audio.Stop(performer.Comp.CPRPlayingStream);
}
}
30 changes: 30 additions & 0 deletions Content.Server/Medical/CPR/CPRTrainingComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;

namespace Content.Server.Medical.CPR;

[RegisterComponent]
public sealed partial class CPRTrainingComponent : Component
{
[DataField]
public SoundSpecifier CPRSound = new SoundPathSpecifier("/Audio/Effects/CPR.ogg");

[DataField]
public TimeSpan DoAfterDuration = TimeSpan.FromSeconds(3);

[DataField] public DamageSpecifier CPRHealing = new()
{
DamageDict =
{
["Asphyxiation"] = -6
}
};

[DataField] public float CrackRibsModifier = 1f;

[DataField] public float ResuscitationChance = 0.1f;

[DataField] public float RotReductionMultiplier;

public EntityUid? CPRPlayingStream;
}
33 changes: 0 additions & 33 deletions Content.Shared/Medical/CPR/Components/CPRTrainingComponent.cs

This file was deleted.

27 changes: 0 additions & 27 deletions Content.Shared/Medical/CPR/Systems/CPRSystem.CVars.cs

This file was deleted.

137 changes: 0 additions & 137 deletions Content.Shared/Medical/CPR/Systems/CPRSystem.cs

This file was deleted.

7 changes: 7 additions & 0 deletions Content.Shared/Medical/CPRDoAfterEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Content.Shared.DoAfter;
using Robust.Shared.Serialization;

namespace Content.Shared.Medical;

[Serializable, NetSerializable]
public sealed partial class CPRDoAfterEvent : SimpleDoAfterEvent;

0 comments on commit 37df814

Please sign in to comment.