110 lines
3.7 KiB
C#
110 lines
3.7 KiB
C#
using Content.Shared.Alert;
|
|
using Content.Shared.Damage;
|
|
using Content.Shared.FixedPoint;
|
|
using Content.Shared.Rejuvenate;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Shared._Offbrand.Wounds;
|
|
|
|
public sealed class LungDamageSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
|
[Dependency] private readonly IGameTiming _timing = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<LungDamageComponent, BeforeBreathEvent>(OnBeforeBreath);
|
|
SubscribeLocalEvent<LungDamageComponent, RejuvenateEvent>(OnRejuvenate);
|
|
SubscribeLocalEvent<LungDamageComponent, BaseLungFunctionEvent>(OnBaseLungFunction);
|
|
SubscribeLocalEvent<LungDamageAlertsComponent, AfterLungDamageChangedEvent>(OnLungDamageChanged);
|
|
SubscribeLocalEvent<LungDamageAlertsComponent, ComponentShutdown>(OnAlertsShutdown);
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
var query = EntityQueryEnumerator<LungDamageComponent, PassiveLungDamageComponent>();
|
|
while (query.MoveNext(out var uid, out var lung, out var passive))
|
|
{
|
|
if (_timing.CurTime < passive.NextUpdate)
|
|
continue;
|
|
|
|
passive.NextUpdate = _timing.CurTime + passive.UpdateInterval;
|
|
Dirty(uid, passive);
|
|
|
|
if (lung.Damage > passive.DamageCap)
|
|
continue;
|
|
|
|
TryModifyDamage((uid, lung), passive.Damage);
|
|
}
|
|
}
|
|
|
|
private void OnBeforeBreath(Entity<LungDamageComponent> ent, ref BeforeBreathEvent args)
|
|
{
|
|
args.BreathVolume *= 1f - MathF.Pow(ent.Comp.Damage.Float() / ent.Comp.MaxDamage.Float(), 3f);
|
|
}
|
|
|
|
public void TryModifyDamage(Entity<LungDamageComponent?> ent, FixedPoint2 damage)
|
|
{
|
|
if (!Resolve(ent, ref ent.Comp))
|
|
return;
|
|
|
|
ent.Comp.Damage = FixedPoint2.Clamp(ent.Comp.Damage + damage, FixedPoint2.Zero, ent.Comp.MaxDamage);
|
|
Dirty(ent);
|
|
|
|
var evt = new AfterLungDamageChangedEvent();
|
|
RaiseLocalEvent(ent, ref evt);
|
|
}
|
|
|
|
private void OnRejuvenate(Entity<LungDamageComponent> ent, ref RejuvenateEvent args)
|
|
{
|
|
ent.Comp.Damage = FixedPoint2.Zero;
|
|
Dirty(ent);
|
|
|
|
var evt = new AfterLungDamageChangedEvent();
|
|
RaiseLocalEvent(ent, ref evt);
|
|
}
|
|
|
|
private void OnBaseLungFunction(Entity<LungDamageComponent> ent, ref BaseLungFunctionEvent args)
|
|
{
|
|
var damage = ent.Comp.Damage.Float() / ent.Comp.MaxDamage.Float();
|
|
var health = 1f - damage;
|
|
var damageable = Comp<DamageableComponent>(ent);
|
|
if (!damageable.Damage.DamageDict.TryGetValue(ent.Comp.AsphyxiationDamage, out var asphyxiationAmount))
|
|
{
|
|
args.Function *= health - damage;
|
|
return;
|
|
}
|
|
|
|
var airSupply = Math.Clamp(1f - (asphyxiationAmount.Float() / ent.Comp.AsphyxiationThreshold.Float()), 0, 1);
|
|
|
|
args.Function *= health * airSupply;
|
|
}
|
|
|
|
private void OnLungDamageChanged(Entity<LungDamageAlertsComponent> ent, ref AfterLungDamageChangedEvent args)
|
|
{
|
|
var lungDamage = Comp<LungDamageComponent>(ent);
|
|
var targetAlert = ent.Comp.AlertThresholds.HighestMatch(lungDamage.Damage);
|
|
|
|
if (targetAlert == ent.Comp.CurrentAlertThresholdState)
|
|
return;
|
|
|
|
if (targetAlert is { } alert)
|
|
{
|
|
_alerts.ShowAlert(ent.Owner, alert);
|
|
}
|
|
else
|
|
{
|
|
_alerts.ClearAlertCategory(ent.Owner, ent.Comp.AlertCategory);
|
|
}
|
|
}
|
|
|
|
private void OnAlertsShutdown(Entity<LungDamageAlertsComponent> ent, ref ComponentShutdown args)
|
|
{
|
|
_alerts.ClearAlertCategory(ent.Owner, ent.Comp.AlertCategory);
|
|
}
|
|
}
|