Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions Content.Client/Drugs/DrugOverlaySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public sealed class DrugOverlaySystem : EntitySystem

public static string RainbowKey = "SeeingRainbows";

// TheDen - Added mnemolith overlays
private MnemolithOverlay _mnemolithOverlay = default!;

public static string MnemolithKey = "SeeingMnemolith";

public override void Initialize()
{
base.Initialize();
Expand All @@ -38,6 +43,15 @@ public override void Initialize()
SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);

_overlay = new();

// TheDen - Added mnemolith overlays, but did whoever made SeeingRainbows not think we'd ever need another kind of OnInit in this file? Excuse the ugly names...
SubscribeLocalEvent<SeeingMnemolithComponent, ComponentInit>(OnMnemolithInit);
SubscribeLocalEvent<SeeingMnemolithComponent, ComponentShutdown>(OnMnemolithShutdown);

SubscribeLocalEvent<SeeingMnemolithComponent, LocalPlayerAttachedEvent>(OnPlayerMnemolithAttached);
SubscribeLocalEvent<SeeingMnemolithComponent, LocalPlayerDetachedEvent>(OnPlayerMnemolithDetached);

_mnemolithOverlay = new();
}

private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerAttachedEvent args)
Expand Down Expand Up @@ -70,4 +84,36 @@ private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, Compon
_overlayMan.RemoveOverlay(_overlay);
}
}

// TheDen - Added mnemolith overlays
private void OnPlayerMnemolithAttached(EntityUid uid, SeeingMnemolithComponent component, LocalPlayerAttachedEvent args)
{
_overlayMan.AddOverlay(_mnemolithOverlay);
}

private void OnPlayerMnemolithDetached(EntityUid uid, SeeingMnemolithComponent component, LocalPlayerDetachedEvent args)
{
_mnemolithOverlay.Intoxication = 0;
_mnemolithOverlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_mnemolithOverlay);
}

private void OnMnemolithInit(EntityUid uid, SeeingMnemolithComponent component, ComponentInit args)
{
if (_player.LocalEntity == uid)
{
_mnemolithOverlay.Phase = _random.NextFloat(MathF.Tau);
_overlayMan.AddOverlay(_mnemolithOverlay);
}
}

private void OnMnemolithShutdown(EntityUid uid, SeeingMnemolithComponent component, ComponentShutdown args)
{
if (_player.LocalEntity == uid)
{
_mnemolithOverlay.Intoxication = 0;
_mnemolithOverlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_mnemolithOverlay);
}
}
}
99 changes: 99 additions & 0 deletions Content.Client/_DEN/Drugs/MnemolithOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using Content.Shared._DV.CCVars;
using Content.Shared.CCVar;
using Content.Shared.Drugs;
using Content.Shared.StatusEffect;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Client.Drugs;

public sealed class MnemolithOverlay : Overlay
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[Dependency] private readonly IConfigurationManager _config = default!;

public override OverlaySpace Space => OverlaySpace.WorldSpace;
public override bool RequestScreenTexture => true;
private readonly ShaderInstance _mnemolithShader;

// Ramp timer
public float Elapsed = 0.0f;
public float Phase = 0.0f;

private float _timeScale = 1.0f;
private float _warpScale = 1.0f;

// Ramp duration in seconds
private const float RampDuration = 1.0f; // TODO: Adjust ramp time

// Effect strength goes from 0 → 1 over RampDuration
private float EffectScale => Math.Clamp(Elapsed / RampDuration, 0.0f, 1.0f);

public MnemolithOverlay()
{
IoCManager.InjectDependencies(this);

_mnemolithShader = _prototypeManager.Index<ShaderPrototype>("Mnemolith").InstanceUnique();
_config.OnValueChanged(DCCVars.DisableDrugWarping, OnDisableDrugWarpingChanged, invokeImmediately: true);
}

private void OnDisableDrugWarpingChanged(bool disabled)
{
_timeScale = disabled ? 0.0f : 1.0f;
_warpScale = disabled ? 0.0f : 1.0f;
}

protected override void FrameUpdate(FrameEventArgs args)
{
var playerEntity = _playerManager.LocalEntity;
if (playerEntity == null)
return;

// FIX: correct component name
if (!_entityManager.HasComponent<SeeingMnemolithComponent>(playerEntity)
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
return;

var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.MnemolithKey, out var time, status))
return;

// Ramp elapsed time up linearly
Elapsed = Math.Min(Elapsed + args.DeltaSeconds, RampDuration);
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp))
return false;

if (args.Viewport.Eye != eyeComp.Eye)
return false;

// Draw immediately once effect starts
return Elapsed > 0f;
}

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

var handle = args.WorldHandle;
_mnemolithShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_mnemolithShader.SetParameter("colorScale", EffectScale);
_mnemolithShader.SetParameter("timeScale", _timeScale);
_mnemolithShader.SetParameter("warpScale", _warpScale * EffectScale);
_mnemolithShader.SetParameter("phase", Phase);
handle.UseShader(_mnemolithShader);
handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);
}
}
112 changes: 112 additions & 0 deletions Content.Client/_DEN/Overlays/SeeingMnemolithHighlightOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: AGPL-3.0-or-later AND MIT

using System.Linq;
using System.Numerics;
using Content.Shared.Drugs;
using Content.Shared.Body.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Timing;

namespace Content.Client.Drugs;

public sealed class MnemolithHighlightOverlay : Overlay
{
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IGameTiming _timing = default!;

private readonly TransformSystem _transform;
private readonly VisibilitySystem _visibility;

public override bool RequestScreenTexture => false;
public override OverlaySpace Space => OverlaySpace.WorldSpace;

private readonly List<MnemolithRenderEntry> _entries = [];

public SeeingMnemolithHighlightComponent? Comp;

public MnemolithHighlightOverlay()
{
IoCManager.InjectDependencies(this);

_transform = _entity.System<TransformSystem>();
_visibility = _entity.System<VisibilitySystem>();

ZIndex = -1;
}

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

var worldHandle = args.WorldHandle;
var eye = args.Viewport.Eye;

if (eye == null)
return;

var player = _player.LocalEntity;
if (!_entity.TryGetComponent(player, out TransformComponent? playerXform))
return;

var accumulator = Math.Clamp(Comp.PulseAccumulator, 0f, Comp.PulseTime);
var alpha = Comp.PulseTime <= 0 ? 1f : float.Lerp(1f, 0f, accumulator / Comp.PulseTime);

var mapId = eye.Position.MapId;
var eyeRot = eye.Rotation;

_entries.Clear();
var entities = _entity.EntityQueryEnumerator<BodyComponent, SpriteComponent, TransformComponent>();
while (entities.MoveNext(out var uid, out var body, out var sprite, out var xform))
{
if (!body.ThermalVisibility)
continue;

// TODO: If I understand robust right, this SHOULD check for LOS. Not super certain. Needs testing? Remove most of this comment after testing plsthx.
if (!_visibility.InView(eye, uid))
continue;

if (_entries.Any(e => e.Ent.Owner == uid))
continue;

_entries.Add(new MnemolithRenderEntry((uid, sprite, xform), mapId, eyeRot));
}

foreach (var entry in _entries)
{
Render(entry.Ent, entry.Map, worldHandle, entry.EyeRot, Comp.Color, alpha);
}

worldHandle.SetTransform(Matrix3x2.Identity);
}

private void Render(Entity<SpriteComponent, TransformComponent> ent,
MapId? map,
DrawingHandleWorld handle,
Angle eyeRot,
Color color,
float alpha)
{
var (uid, sprite, xform) = ent;
if (xform.MapID != map)
return;

var position = _transform.GetWorldPosition(xform);
var rotation = _transform.GetWorldRotation(xform);

var originalColor = sprite.Color;
sprite.Color = color.WithAlpha(alpha);
sprite.Render(handle, eyeRot, rotation, position: position);
sprite.Color = originalColor;
}
}

public record struct MnemolithRenderEntry(
Entity<SpriteComponent, TransformComponent> Ent,
MapId? Map,
Angle EyeRot);
68 changes: 68 additions & 0 deletions Content.Client/_DEN/Overlays/SeeingMnemolithHighlightSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: AGPL-3.0-or-later AND MIT

using Content.Shared.Drugs;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Robust.Client.Graphics;
using Robust.Shared.Timing;

namespace Content.Client.Drugs;

public sealed class MnemolithHighlightSystem : EquipmentHudSystem<SeeingMnemolithHighlightComponent>
{
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly IGameTiming _timing = default!;

private MnemolithHighlightOverlay _highlightOverlay = default!;

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

SubscribeLocalEvent<SeeingMnemolithHighlightComponent, SwitchableOverlayToggledEvent>(OnToggle);

_highlightOverlay = new MnemolithHighlightOverlay();
}

private void OnToggle(Entity<SeeingMnemolithHighlightComponent> ent, ref SwitchableOverlayToggledEvent args)
{
RefreshOverlay(args.User);
}

protected override void UpdateInternal(RefreshEquipmentHudEvent<SeeingMnemolithHighlightComponent> args)
{
base.UpdateInternal(args);

SeeingMnemolithHighlightComponent? comp = null;
foreach (var c in args.Components)
{
if (!c.IsActive && (c.PulseTime <= 0f || c.PulseAccumulator >= c.PulseTime))
continue;

comp ??= c;
}

UpdateHighlightOverlay(comp);
}

protected override void DeactivateInternal()
{
base.DeactivateInternal();
UpdateHighlightOverlay(null);
}

private void UpdateHighlightOverlay(SeeingMnemolithHighlightComponent? comp)
{
_highlightOverlay.Comp = comp;

switch (comp)
{
case not null when !_overlayMan.HasOverlay<MnemolithHighlightOverlay>():
_overlayMan.AddOverlay(_highlightOverlay);
break;
case null:
_overlayMan.RemoveOverlay(_highlightOverlay);
break;
}
}
}
9 changes: 9 additions & 0 deletions Content.Shared/_DEN/Drugs/SeeingMnemolithComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Robust.Shared.GameStates;

namespace Content.Shared.Drugs;

/// <summary>
/// Exists for use as a status effect. Adds a shader to the client that scales with the effect duration.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class SeeingMnemolithComponent : Component { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: AGPL-3.0-or-later AND MIT

using Content.Shared.Actions;
using Robust.Shared.GameStates;

namespace Content.Shared.Drugs;

[RegisterComponent, NetworkedComponent]
public sealed partial class SeeingMnemolithHighlightComponent : SwitchableOverlayComponent
{
public override string? ToggleAction { get; set; } = "ToggleMnemolithHighlight";

public override Color Color { get; set; } = Color.FromHex("#7A42F8");

[DataField]
public override float PulseTime { get; set; } = 2f;
}

public sealed partial class ToggleMnemolithHighlightEvent : InstantActionEvent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later AND MIT

namespace Content.Shared.Drugs;

public sealed class SharedMnemolithHighlightSystem
: SwitchableOverlaySystem<SeeingMnemolithHighlightComponent, ToggleMnemolithHighlightEvent>;
2 changes: 1 addition & 1 deletion Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
allowedStates:
- Critical
damageCap: 400
damage:
damage:
types:
Bloodloss: 0.5
- type: StatusEffects
Expand Down
Loading