Blindness rework - damaged eyes are now a stylized simulation of legal blindness (#23212)

* blindness rework - damaged eyes now simulate legal blindness

* hEY THATS FOR DEMONSTRATION PURPOSES ONLY AAA

* attributions

* makes eyeclosecomponent adminbus compatible

* useshader(null)
This commit is contained in:
deathride58
2024-01-03 04:07:02 -05:00
committed by GitHub
parent 1a531342c5
commit aa6645c8e9
28 changed files with 508 additions and 89 deletions

View File

@@ -7,57 +7,67 @@ namespace Content.Shared.Eye.Blinding.Systems;
public sealed class BlindableSystem : EntitySystem
{
[Dependency] private readonly BlurryVisionSystem _blurriness = default!;
[Dependency] private readonly EyeClosingSystem _eyelids = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BlindableComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<BlindableComponent, EyeDamageChangedEvent>(OnDamageChanged);
}
private void OnRejuvenate(EntityUid uid, BlindableComponent component, RejuvenateEvent args)
private void OnRejuvenate(Entity<BlindableComponent> ent, ref RejuvenateEvent args)
{
AdjustEyeDamage(uid, -component.EyeDamage, component);
AdjustEyeDamage((ent.Owner, ent.Comp), -ent.Comp.EyeDamage);
}
private void OnDamageChanged(Entity<BlindableComponent> ent, ref EyeDamageChangedEvent args)
{
_blurriness.UpdateBlurMagnitude((ent.Owner, ent.Comp));
_eyelids.UpdateEyesClosable((ent.Owner, ent.Comp));
}
[PublicAPI]
public void UpdateIsBlind(EntityUid uid, BlindableComponent? blindable = null)
public void UpdateIsBlind(Entity<BlindableComponent?> blindable)
{
if (!Resolve(uid, ref blindable, false))
if (!Resolve(blindable, ref blindable.Comp, false))
return;
var old = blindable.IsBlind;
var old = blindable.Comp.IsBlind;
// Don't bother raising an event if the eye is too damaged.
if (blindable.EyeDamage >= BlindableComponent.MaxDamage)
if (blindable.Comp.EyeDamage >= BlindableComponent.MaxDamage)
{
blindable.IsBlind = true;
blindable.Comp.IsBlind = true;
}
else
{
var ev = new CanSeeAttemptEvent();
RaiseLocalEvent(uid, ev);
blindable.IsBlind = ev.Blind;
RaiseLocalEvent(blindable.Owner, ev);
blindable.Comp.IsBlind = ev.Blind;
}
if (old == blindable.IsBlind)
if (old == blindable.Comp.IsBlind)
return;
var changeEv = new BlindnessChangedEvent(blindable.IsBlind);
RaiseLocalEvent(uid, ref changeEv);
var changeEv = new BlindnessChangedEvent(blindable.Comp.IsBlind);
RaiseLocalEvent(blindable.Owner, ref changeEv);
Dirty(blindable);
}
public void AdjustEyeDamage(EntityUid uid, int amount, BlindableComponent? blindable = null)
public void AdjustEyeDamage(Entity<BlindableComponent?> blindable, int amount)
{
if (!Resolve(uid, ref blindable, false) || amount == 0)
if (!Resolve(blindable, ref blindable.Comp, false) || amount == 0)
return;
blindable.EyeDamage += amount;
blindable.EyeDamage = Math.Clamp(blindable.EyeDamage, 0, BlindableComponent.MaxDamage);
blindable.Comp.EyeDamage += amount;
blindable.Comp.EyeDamage = Math.Clamp(blindable.Comp.EyeDamage, 0, BlindableComponent.MaxDamage);
Dirty(blindable);
UpdateIsBlind(uid, blindable);
UpdateIsBlind(blindable);
var ev = new EyeDamageChangedEvent(blindable.EyeDamage);
RaiseLocalEvent(uid, ref ev);
var ev = new EyeDamageChangedEvent(blindable.Comp.EyeDamage);
RaiseLocalEvent(blindable.Owner, ref ev);
}
}
@@ -71,7 +81,7 @@ public record struct BlindnessChangedEvent(bool Blind);
/// This event is raised when an entity's eye damage changes
/// </summary>
[ByRefEvent]
public record struct EyeDamageChangedEvent(int Damage);
public record struct EyeDamageChangedEvent(int Damage);
/// <summary>
/// Raised directed at an entity to see whether the entity is currently blind or not.

View File

@@ -17,17 +17,17 @@ public sealed class BlindfoldSystem : EntitySystem
SubscribeLocalEvent<BlindfoldComponent, InventoryRelayedEvent<CanSeeAttemptEvent>>(OnBlindfoldTrySee);
}
private void OnBlindfoldTrySee(EntityUid uid, BlindfoldComponent component, InventoryRelayedEvent<CanSeeAttemptEvent> args)
private void OnBlindfoldTrySee(Entity<BlindfoldComponent> blindfold, ref InventoryRelayedEvent<CanSeeAttemptEvent> args)
{
args.Args.Cancel();
}
private void OnEquipped(EntityUid uid, BlindfoldComponent component, GotEquippedEvent args)
private void OnEquipped(Entity<BlindfoldComponent> blindfold, ref GotEquippedEvent args)
{
_blindableSystem.UpdateIsBlind(args.Equipee);
}
private void OnUnequipped(EntityUid uid, BlindfoldComponent component, GotUnequippedEvent args)
private void OnUnequipped(Entity<BlindfoldComponent> blindfold, ref GotUnequippedEvent args)
{
_blindableSystem.UpdateIsBlind(args.Equipee);
}

View File

@@ -6,54 +6,52 @@ namespace Content.Shared.Eye.Blinding.Systems;
public sealed class BlurryVisionSystem : EntitySystem
{
[Dependency] private readonly IEntityManager _entityManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BlindableComponent, EyeDamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<VisionCorrectionComponent, GotEquippedEvent>(OnGlassesEquipped);
SubscribeLocalEvent<VisionCorrectionComponent, GotUnequippedEvent>(OnGlassesUnequipped);
SubscribeLocalEvent<VisionCorrectionComponent, InventoryRelayedEvent<GetBlurEvent>>(OnGetBlur);
}
private void OnGetBlur(EntityUid uid, VisionCorrectionComponent component, InventoryRelayedEvent<GetBlurEvent> args)
private void OnGetBlur(Entity<VisionCorrectionComponent> glasses, ref InventoryRelayedEvent<GetBlurEvent> args)
{
args.Args.Blur += component.VisionBonus;
args.Args.Blur += glasses.Comp.VisionBonus;
args.Args.CorrectionPower *= glasses.Comp.CorrectionPower;
}
private void OnDamageChanged(EntityUid uid, BlindableComponent component, ref EyeDamageChangedEvent args)
public void UpdateBlurMagnitude(Entity<BlindableComponent?> ent)
{
UpdateBlurMagnitude(uid, component);
}
private void UpdateBlurMagnitude(EntityUid uid, BlindableComponent? component = null)
{
if (!Resolve(uid, ref component, false))
if (!Resolve(ent.Owner, ref ent.Comp, false))
return;
var ev = new GetBlurEvent(component.EyeDamage);
RaiseLocalEvent(uid, ev);
var ev = new GetBlurEvent(ent.Comp.EyeDamage);
RaiseLocalEvent(ent, ev);
var blur = Math.Clamp(0, ev.Blur, BlurryVisionComponent.MaxMagnitude);
var blur = Math.Clamp(ev.Blur, 0, BlurryVisionComponent.MaxMagnitude);
if (blur <= 0)
{
RemCompDeferred<BlurryVisionComponent>(uid);
RemCompDeferred<BlurryVisionComponent>(ent);
return;
}
var blurry = EnsureComp<BlurryVisionComponent>(uid);
var blurry = EnsureComp<BlurryVisionComponent>(ent);
blurry.Magnitude = blur;
Dirty(blurry);
blurry.CorrectionPower = ev.CorrectionPower;
Dirty(ent, blurry);
}
private void OnGlassesEquipped(EntityUid uid, VisionCorrectionComponent component, GotEquippedEvent args)
private void OnGlassesEquipped(Entity<VisionCorrectionComponent> glasses, ref GotEquippedEvent args)
{
UpdateBlurMagnitude(uid);
UpdateBlurMagnitude(args.Equipee);
}
private void OnGlassesUnequipped(EntityUid uid, VisionCorrectionComponent component, GotUnequippedEvent args)
private void OnGlassesUnequipped(Entity<VisionCorrectionComponent> glasses, ref GotUnequippedEvent args)
{
UpdateBlurMagnitude(uid);
UpdateBlurMagnitude(args.Equipee);
}
}
@@ -61,6 +59,7 @@ public sealed class GetBlurEvent : EntityEventArgs, IInventoryRelayEvent
{
public readonly float BaseBlur;
public float Blur;
public float CorrectionPower = BlurryVisionComponent.DefaultCorrectionPower;
public GetBlurEvent(float blur)
{

View File

@@ -0,0 +1,141 @@
using Content.Shared.Actions;
using Content.Shared.Eye.Blinding.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Timing;
namespace Content.Shared.Eye.Blinding.Systems;
public sealed class EyeClosingSystem : EntitySystem
{
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly BlindableSystem _blindableSystem = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EyeClosingComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<EyeClosingComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<EyeClosingComponent, ToggleEyesActionEvent>(OnToggleAction);
SubscribeLocalEvent<EyeClosingComponent, CanSeeAttemptEvent>(OnTrySee);
SubscribeLocalEvent<EyeClosingComponent, AfterAutoHandleStateEvent>(OnHandleState);
}
private void OnMapInit(Entity<EyeClosingComponent> eyelids, ref MapInitEvent args)
{
_actionsSystem.AddAction(eyelids, ref eyelids.Comp.EyeToggleActionEntity, eyelids.Comp.EyeToggleAction);
Dirty(eyelids);
}
private void OnShutdown(Entity<EyeClosingComponent> eyelids, ref ComponentShutdown args)
{
_actionsSystem.RemoveAction(eyelids, eyelids.Comp.EyeToggleActionEntity);
SetEyelids((eyelids.Owner, eyelids.Comp), false);
}
private void OnToggleAction(Entity<EyeClosingComponent> eyelids, ref ToggleEyesActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
SetEyelids((eyelids.Owner, eyelids.Comp), !eyelids.Comp.EyesClosed);
}
private void OnHandleState(Entity<EyeClosingComponent> eyelids, ref AfterAutoHandleStateEvent args)
{
DoAudioFeedback((eyelids.Owner, eyelids.Comp), eyelids.Comp.EyesClosed);
}
private void OnTrySee(Entity<EyeClosingComponent> eyelids, ref CanSeeAttemptEvent args)
{
if (eyelids.Comp.EyesClosed)
args.Cancel();
}
/// <summary>
/// Checks whether or not the entity's eyelids are closed.
/// </summary>
/// <param name="eyelids">The entity that contains an EyeClosingComponent</param>
/// <returns>Exactly what this function says on the tin. True if eyes are closed, false if they're open.</returns>
public bool AreEyesClosed(Entity<EyeClosingComponent?> eyelids)
{
return Resolve(eyelids, ref eyelids.Comp, false) && eyelids.Comp.EyesClosed;
}
/// <summary>
/// Sets whether or not the entity's eyelids are closed.
/// </summary>
/// <param name="eyelids">The entity that contains an EyeClosingComponent</param>
/// <param name="value">Set to true to close the entity's eyes. Set to false to open them</param>
public void SetEyelids(Entity<EyeClosingComponent?> eyelids, bool value)
{
if (!Resolve(eyelids, ref eyelids.Comp))
return;
if (eyelids.Comp.EyesClosed == value)
return;
eyelids.Comp.EyesClosed = value;
Dirty(eyelids);
if (eyelids.Comp.EyeToggleActionEntity != null)
_actionsSystem.SetToggled(eyelids.Comp.EyeToggleActionEntity, eyelids.Comp.EyesClosed);
_blindableSystem.UpdateIsBlind(eyelids.Owner);
DoAudioFeedback(eyelids, eyelids.Comp.EyesClosed);
}
public void DoAudioFeedback(Entity<EyeClosingComponent?> eyelids, bool eyelidTarget)
{
if (!Resolve(eyelids, ref eyelids.Comp))
return;
if (!_net.IsClient || !_timing.IsFirstTimePredicted)
return;
if (eyelids.Comp.PreviousEyelidPosition == eyelidTarget)
return;
eyelids.Comp.PreviousEyelidPosition = eyelidTarget;
if (_playerManager.TryGetSessionByEntity(eyelids, out var session))
_audio.PlayGlobal(eyelidTarget ? eyelids.Comp.EyeCloseSound : eyelids.Comp.EyeOpenSound, session);
}
public void UpdateEyesClosable(Entity<BlindableComponent?> blindable)
{
if (!Resolve(blindable, ref blindable.Comp, false))
return;
var ev = new GetBlurEvent(blindable.Comp.EyeDamage);
RaiseLocalEvent(blindable.Owner, ev);
if (_entityManager.TryGetComponent<EyeClosingComponent>(blindable, out var eyelids) && !eyelids.NaturallyCreated)
return;
if (ev.Blur < BlurryVisionComponent.MaxMagnitude || ev.Blur >= BlindableComponent.MaxDamage)
{
RemCompDeferred<EyeClosingComponent>(blindable);
return;
}
var naturalEyelids = EnsureComp<EyeClosingComponent>(blindable);
naturalEyelids.NaturallyCreated = true;
Dirty(blindable);
}
}
public sealed partial class ToggleEyesActionEvent : InstantActionEvent
{
}