Skip to content

Commit

Permalink
the nightmare continues unchecked
Browse files Browse the repository at this point in the history
  • Loading branch information
MilonPL committed Nov 13, 2024
1 parent 3b954d1 commit 8466998
Show file tree
Hide file tree
Showing 11 changed files with 361 additions and 0 deletions.
52 changes: 52 additions & 0 deletions Content.Client/DeltaV/Overlays/PainOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Numerics;
using Content.Shared.DeltaV.Pain;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;

namespace Content.Client.DeltaV.Overlays;

public sealed partial class PainOverlay : Overlay
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IEntityManager _entity = default!;

public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _painShader;
private readonly ProtoId<ShaderPrototype> _shaderProto = "ChromaticAberration";

public PainOverlay()
{
IoCManager.InjectDependencies(this);
_painShader = _prototype.Index(_shaderProto).Instance().Duplicate();
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (_player.LocalEntity is not { Valid: true } player
|| !_entity.HasComponent<PainComponent>(player))
{
return false;
}

return base.BeforeDraw(in args);
}

protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture is null)
return;

_painShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);

var worldHandle = args.WorldHandle;
var viewport = args.WorldBounds;
worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.UseShader(_painShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
}
}
65 changes: 65 additions & 0 deletions Content.Client/DeltaV/Overlays/PainSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Content.Shared.DeltaV.Pain;
using Robust.Client.Graphics;
using Robust.Shared.Player;

namespace Content.Client.DeltaV.Overlays;

public sealed partial class PainSystem : EntitySystem
{
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly ISharedPlayerManager _playerMan = default!;

private PainOverlay _overlay = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<PainComponent, ComponentInit>(OnPainInit);
SubscribeLocalEvent<PainComponent, ComponentShutdown>(OnPainShutdown);
SubscribeLocalEvent<PainComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<PainComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);

_overlay = new();
}

private void OnPainInit(Entity<PainComponent> ent, ref ComponentInit args)
{
if (ent.Owner == _playerMan.LocalEntity && !ent.Comp.Suppressed)
_overlayMan.AddOverlay(_overlay);
}

private void OnPainShutdown(Entity<PainComponent> ent, ref ComponentShutdown args)
{
if (ent.Owner == _playerMan.LocalEntity)
_overlayMan.RemoveOverlay(_overlay);
}

private void OnPlayerAttached(Entity<PainComponent> ent, ref LocalPlayerAttachedEvent args)
{
if (!ent.Comp.Suppressed)
_overlayMan.AddOverlay(_overlay);
}

private void OnPlayerDetached(Entity<PainComponent> ent, ref LocalPlayerDetachedEvent args)
{
_overlayMan.RemoveOverlay(_overlay);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

// Handle showing/hiding overlay based on suppression status
if (_playerMan.LocalEntity is not { } player)
return;

if (!TryComp<PainComponent>(player, out var comp))
return;

if (comp.Suppressed && _overlayMan.HasOverlay<PainOverlay>())
_overlayMan.RemoveOverlay(_overlay);
else if (!comp.Suppressed && !_overlayMan.HasOverlay<PainOverlay>())
_overlayMan.AddOverlay(_overlay);
}
}
30 changes: 30 additions & 0 deletions Content.Server/DeltaV/EntityEffects/Effects/InPain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Shared.DeltaV.Pain;
using Content.Shared.EntityEffects;
using Robust.Shared.Prototypes;

namespace Content.Server.EntityEffects.Effects;

public sealed partial class InPain : EntityEffect
{
/// <summary>
/// How long should each metabolism cycle make the effect last for.
/// </summary>
[DataField]
public float PainTime = 5f;

protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-addicted", ("chance", Probability));

public override void Effect(EntityEffectBaseArgs args)
{
var painTime = PainTime;

if (args is EntityEffectReagentArgs reagentArgs)
{
painTime *= reagentArgs.Scale.Float();
}

var painSystem = args.EntityManager.System<SharedPainSystem>();
painSystem.TryApplyPain(args.TargetEntity, painTime);
}
}
30 changes: 30 additions & 0 deletions Content.Server/DeltaV/EntityEffects/Effects/PainSuppression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Shared.DeltaV.Pain;
using Content.Shared.EntityEffects;
using Robust.Shared.Prototypes;

namespace Content.Server.EntityEffects.Effects;

public sealed partial class PainSuppression : EntityEffect
{
/// <summary>
/// How long should the pain suppression last for each metabolism cycle
/// </summary>
[DataField]
public float SuppressionTime = 30f;

protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-pain-suppression", ("chance", Probability));

public override void Effect(EntityEffectBaseArgs args)
{
var suppressionTime = SuppressionTime;

if (args is EntityEffectReagentArgs reagentArgs)
{
suppressionTime *= reagentArgs.Scale.Float();
}

var painSystem = args.EntityManager.System<SharedPainSystem>();
painSystem.TrySuppressPain(args.TargetEntity, suppressionTime);
}
}
67 changes: 67 additions & 0 deletions Content.Server/DeltaV/Pain/PainSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Content.Shared.DeltaV.Pain;
using Robust.Shared.Timing;

namespace Content.Server.DeltaV.Pain;

public sealed class PainSystem : SharedPainSystem
{
[Dependency] private readonly IGameTiming _timing = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PainComponent, ComponentStartup>(OnInit);
}

private void OnInit(Entity<PainComponent> ent, ref ComponentStartup args)
{
ent.Comp.NextUpdateTime = _timing.CurTime;
}

protected override void UpdatePainSuppression(EntityUid uid, float duration)
{
if (!TryComp<PainComponent>(uid, out var component))
return;

var ent = new Entity<PainComponent>(uid, component);
var curTime = _timing.CurTime;
var newEndTime = curTime + TimeSpan.FromSeconds(duration);

// Only update if this would extend the suppression
if (newEndTime <= component.SuppressionEndTime)
return;

ent.Comp.LastPainkillerTime = curTime;
ent.Comp.SuppressionEndTime = newEndTime;
UpdateSuppressed(ent);
}

private void UpdateSuppressed(Entity<PainComponent> ent)
{
ent.Comp.Suppressed = (_timing.CurTime < ent.Comp.SuppressionEndTime);
Dirty(ent);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var curTime = _timing.CurTime;
var query = EntityQueryEnumerator<PainComponent>();

while (query.MoveNext(out var uid, out var component))
{
if (curTime < component.NextUpdateTime)
continue;

var ent = new Entity<PainComponent>(uid, component);

if (component.Suppressed)
{
UpdateSuppressed(ent);
}

component.NextUpdateTime = curTime + TimeSpan.FromSeconds(1);
}
}
}
36 changes: 36 additions & 0 deletions Content.Shared/DeltaV/Pain/PainComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;

namespace Content.Shared.DeltaV.Pain;

[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState, AutoGenerateComponentPause]
public sealed partial class PainComponent : Component
{
/// <summary>
/// Whether pain effects are currently suppressed by painkillers
/// </summary>
[DataField, AutoNetworkedField]
public bool Suppressed;

/// <summary>
/// The last time painkillers were administered
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan LastPainkillerTime;

/// <summary>
/// When the pain suppression effect ends
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan SuppressionEndTime;

/// <summary>
/// When to next update this component
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan NextUpdateTime;
}
37 changes: 37 additions & 0 deletions Content.Shared/DeltaV/Pain/SharedPainSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Content.Shared.StatusEffect;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Shared.DeltaV.Pain;

public abstract class SharedPainSystem : EntitySystem
{
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;

public ProtoId<StatusEffectPrototype> StatusEffectKey = "InPain";

protected abstract void UpdatePainSuppression(EntityUid uid, float duration);

public virtual void TryApplyPain(EntityUid uid, float painTime, StatusEffectsComponent? status = null)
{
if (!Resolve(uid, ref status, false))
return;

if (!_statusEffects.HasStatusEffect(uid, StatusEffectKey, status))
{
_statusEffects.TryAddStatusEffect<PainComponent>(uid, StatusEffectKey, TimeSpan.FromSeconds(painTime), true, status);
}
else
{
_statusEffects.TryAddTime(uid, StatusEffectKey, TimeSpan.FromSeconds(painTime), status);
}
}

public virtual void TrySuppressPain(EntityUid uid, float duration)
{
if (!TryComp<PainComponent>(uid, out _))
return;

UpdatePainSuppression(uid, duration);
}
}
4 changes: 4 additions & 0 deletions Resources/Prototypes/DeltaV/Shaders/chromatic_aberration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- type: shader
id: ChromaticAberration
kind: source
path: "/Textures/DeltaV/Shaders/chromatic_aberration.swsl"
6 changes: 6 additions & 0 deletions Resources/Prototypes/DeltaV/status_effects.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
- type: statusEffect
id: Addicted

- type: statusEffect
id: InPain

- type: statusEffect
id: PainSuppression
2 changes: 2 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Species/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@
- PsionicsDisabled #Nyano - Summary: PCs can have psionics disabled.
- PsionicallyInsulated #Nyano - Summary: PCs can be made insulated from psionic powers.
- Addicted # DeltaV - Psych med addictions system
- InPain # DeltaV - Pain system
- PainSuppression # DeltaV - Pain system
- type: Body
prototype: Human
requiredLegs: 2
Expand Down
32 changes: 32 additions & 0 deletions Resources/Textures/DeltaV/Shaders/chromatic_aberration.swsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
uniform sampler2D SCREEN_TEXTURE;

void fragment() {
highp vec2 coord = FRAGCOORD.xy * SCREEN_PIXEL_SIZE.xy;
highp float time = TIME * 0.3;

const highp float distortAmount = 0.003;

highp vec2 waveOffset = vec2(
distortAmount * (
sin(time * 0.5 + coord.y * 4.0) + // Primary wave
sin(time * 0.7 + coord.y * 8.0) * 0.5 + // Secondary faster wave
sin(time * 0.2 + coord.x * 3.0) * 0.8 // Slower cross wave
),
distortAmount * (
cos(time * 0.5 + coord.x * 4.0) + // Primary wave
cos(time * 0.7 + coord.x * 8.0) * 0.5 + // Secondary faster wave
cos(time * 0.2 + coord.y * 3.0) * 0.8 // Slower cross wave
)
);

highp vec4 redChannel = zTextureSpec(SCREEN_TEXTURE, coord + waveOffset * 1.5 + vec2(-distortAmount * 2.0, distortAmount));
highp vec4 greenChannel = zTextureSpec(SCREEN_TEXTURE, coord + waveOffset);
highp vec4 blueChannel = zTextureSpec(SCREEN_TEXTURE, coord + waveOffset * 1.2 + vec2(distortAmount * 2.0, -distortAmount));

COLOR = vec4(
redChannel.r,
greenChannel.g,
blueChannel.b,
(redChannel.a + greenChannel.a + blueChannel.a) / 3.0
);
}

0 comments on commit 8466998

Please sign in to comment.