Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Adds NearSighted trait from Parkstation. #176

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
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
130 changes: 130 additions & 0 deletions Content.Client/SimpleStation14/Overlays/Shaders/NearsightedOverlays.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using Content.Shared.SimpleStation14.Traits.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Client.SimpleStation14.Overlays.Shaders;

public sealed class NearsightedOverlay : Overlay
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;

public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _nearsightShader;

public float Radius;
private float _oldRadius;
public float Darkness;
private float _oldDarkness;

private float _lerpTime;
public float LerpDuration;


public NearsightedOverlay()
{
IoCManager.InjectDependencies(this);
_nearsightShader = _prototypeManager.Index<ShaderPrototype>("GradientCircleMask").InstanceUnique();
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
{
// Check if the player has a NearsightedComponent and is controlling it
if (!_entityManager.TryGetComponent(_playerManager.LocalPlayer?.ControlledEntity, out NearsightedComponent? nearComp) ||
_playerManager.LocalPlayer?.ControlledEntity != nearComp.Owner)
return false;

// Check if the player has an EyeComponent and if the overlay should be drawn for this eye
if (!_entityManager.TryGetComponent(_playerManager.LocalPlayer?.ControlledEntity, out EyeComponent? eyeComp) ||
args.Viewport.Eye != eyeComp.Eye)
return false;

return true;
}

protected override void Draw(in OverlayDrawArgs args)
{
// We already checked if they have a NearsightedComponent and are controlling it in BeforeDraw, so we assume this hasn't changed
var nearComp = _entityManager.GetComponent<NearsightedComponent>(_playerManager.LocalPlayer!.ControlledEntity!.Value);

// Set LerpDuration based on nearComp.LerpDuration
LerpDuration = nearComp.LerpDuration;

// Set the radius and darkness values based on whether the player is wearing glasses or not
if (nearComp.Active)
{
Radius = nearComp.EquippedRadius;
Darkness = nearComp.EquippedAlpha;
}
else
{
Radius = nearComp.Radius;
Darkness = nearComp.Alpha;
}


var viewport = args.WorldAABB;
var handle = args.WorldHandle;
var distance = args.ViewportBounds.Width;

var lastFrameTime = (float) _timing.FrameTime.TotalSeconds;


// If the current radius value is different from the previous one, lerp between them
if (!MathHelper.CloseTo(_oldRadius, Radius, 0.001f))
{
_lerpTime += lastFrameTime;
var t = MathHelper.Clamp(_lerpTime / LerpDuration, 0f, 1f); // Calculate lerp time
_oldRadius = MathHelper.Lerp(_oldRadius, Radius, t); // Lerp between old and new radius values
}
// If the current radius value is the same as the previous one, reset the lerp time and old radius value
else
{
_lerpTime = 0f;
_oldRadius = Radius;
}

// If the current darkness value is different from the previous one, lerp between them
if (!MathHelper.CloseTo(_oldDarkness, Darkness, 0.001f))
{
_lerpTime += lastFrameTime;
var t = MathHelper.Clamp(_lerpTime / LerpDuration, 0f, 1f); // Calculate lerp time
_oldDarkness = MathHelper.Lerp(_oldDarkness, Darkness, t); // Lerp between old and new darkness values
}
// If the current darkness value is the same as the previous one, reset the lerp time and old darkness value
else
{
_lerpTime = 0f;
_oldDarkness = Darkness;
}


// Calculate the outer and inner radii based on the current radius value
var outerMaxLevel = 0.6f * distance;
var outerMinLevel = 0.06f * distance;
var innerMaxLevel = 0.02f * distance;
var innerMinLevel = 0.02f * distance;

var outerRadius = outerMaxLevel - _oldRadius * (outerMaxLevel - outerMinLevel);
var innerRadius = innerMaxLevel - _oldRadius * (innerMaxLevel - innerMinLevel);

// Set the shader parameters and draw the overlay
_nearsightShader.SetParameter("time", 0.0f);
_nearsightShader.SetParameter("color", new Vector3(1f, 1f, 1f));
_nearsightShader.SetParameter("darknessAlphaOuter", _oldDarkness);
_nearsightShader.SetParameter("innerCircleRadius", innerRadius);
_nearsightShader.SetParameter("innerCircleMaxRadius", innerRadius);
_nearsightShader.SetParameter("outerCircleRadius", outerRadius);
_nearsightShader.SetParameter("outerCircleMaxRadius", outerRadius + 0.2f * distance);
handle.UseShader(_nearsightShader);
handle.DrawRect(viewport, Color.Black);

handle.UseShader(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Content.Client.SimpleStation14.Overlays.Shaders;
using Content.Shared.Inventory.Events;
using Content.Shared.SimpleStation14.Traits;
using Content.Shared.SimpleStation14.Traits.Components;
using Content.Shared.Tag;
using Robust.Client.Graphics;

namespace Content.Client.SimpleStation14.Overlays.Systems;

public sealed class NearsightedSystem : EntitySystem
{
[Dependency] private readonly IOverlayManager _overlayMan = default!;

private NearsightedOverlay _overlay = default!;

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

_overlay = new NearsightedOverlay();

SubscribeLocalEvent<NearsightedComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<GotEquippedEvent>(OnEquip);
SubscribeLocalEvent<GotUnequippedEvent>(OnUnEquip);
}


private void OnStartup(EntityUid uid, NearsightedComponent component, ComponentStartup args)
{
UpdateShader(component, false);
}

private void OnEquip(GotEquippedEvent args)
{
if (TryComp<NearsightedComponent>(args.Equipee, out var nearsighted) &&
EnsureComp<TagComponent>(args.Equipment).Tags.Contains("GlassesNearsight"))
UpdateShader(nearsighted, true);
}

private void OnUnEquip(GotUnequippedEvent args)
{
if (TryComp<NearsightedComponent>(args.Equipee, out var nearsighted) &&
EnsureComp<TagComponent>(args.Equipment).Tags.Contains("GlassesNearsight"))
UpdateShader(nearsighted, false);
}


private void UpdateShader(NearsightedComponent component, bool booLean)
{
while (_overlayMan.HasOverlay<NearsightedOverlay>())
{
_overlayMan.RemoveOverlay(_overlay);
}

component.Active = booLean;
_overlayMan.AddOverlay(_overlay);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Content.Shared.SimpleStation14.Clothing;

[RegisterComponent]
public sealed class ClothingGrantTagComponent : Component
{
[DataField("tag", required: true), ViewVariables(VVAccess.ReadWrite)]
public string Tag = "";

[ViewVariables(VVAccess.ReadWrite)]
public bool IsActive = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ public sealed class ClothingGrantingSystem : EntitySystem
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ClothingGrantComponentComponent, GotEquippedEvent>(OnCompEquip);
SubscribeLocalEvent<ClothingGrantComponentComponent, GotUnequippedEvent>(OnCompUnequip);

SubscribeLocalEvent<ClothingGrantTagComponent, GotEquippedEvent>(OnTagEquip);
SubscribeLocalEvent<ClothingGrantTagComponent, GotUnequippedEvent>(OnTagUnequip);
}

private void OnCompEquip(EntityUid uid, ClothingGrantComponentComponent component, GotEquippedEvent args)
Expand Down Expand Up @@ -60,4 +64,29 @@ private void OnCompUnequip(EntityUid uid, ClothingGrantComponentComponent compon

component.IsActive = false;
}


private void OnTagEquip(EntityUid uid, ClothingGrantTagComponent component, GotEquippedEvent args)
{
if (!TryComp<ClothingComponent>(uid, out var clothing))
return;

if (!clothing.Slots.HasFlag(args.SlotFlags))
return;

EnsureComp<TagComponent>(args.Equipee);
_tagSystem.AddTag(args.Equipee, component.Tag);

component.IsActive = true;
}

private void OnTagUnequip(EntityUid uid, ClothingGrantTagComponent component, GotUnequippedEvent args)
{
if (!component.IsActive)
return;

_tagSystem.RemoveTag(args.Equipee, component.Tag);

component.IsActive = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Robust.Shared.GameStates;

namespace Content.Shared.SimpleStation14.Traits.Components;

/// <summary>
/// Owner entity cannot see well, without prescription glasses.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class NearsightedComponent : Component
{
/// <summary>
/// Distance from the edge of the screen to the center
/// </summary>
/// <remarks>
/// I don't know how the distance is measured, 1 is very close to the center, 0 is maybe visible around the edge
/// </remarks>
[DataField("radius"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Radius = 0.8f;

/// <summary>
/// How dark the circle mask is from <see cref="Radius"/>
/// </summary>
/// <remarks>
/// I also don't know how this works, it only starts getting noticeably dark at 0.7, and is definitely noticeable at 0.9, 1 is black
/// </remarks>
[DataField("alpha"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Alpha = 0.995f;

/// <inheritdoc cref="Radius"/>
[DataField("equippedRadius"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float EquippedRadius = 0.45f;

/// <inheritdoc cref="Alpha"/>
[DataField("equippedAlpha"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float EquippedAlpha = 0.93f;

/// <summary>
/// How long the lerp animation should go on for in seconds.
/// </summary>
[DataField("lerpDuration"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float LerpDuration = 0.25f;

/// <summary>
/// If true, uses the variables prefixed "Equipped"
/// If false, uses the variables without a prefix
/// </summary>
[ViewVariables(VVAccess.ReadWrite)] // Make the system shared if you want this networked, I don't wanna do that
public bool Active = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
trait-nearsighted-name = Nearsighted
trait-nearsighted-desc = You require glasses to see properly.
trait-nearsighted-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are pretty unfocused. It doesn't seem like {SUBJECT($target)} can see things that well.[/color]
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@
ClothingHeadTinfoil: 2
ClothingHeadRastaHat: 2
ClothingBeltStorageWaistbag: 3
ClothingEyesGlasses: 5
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
Bloodpack: 5
EpinephrineChemistryBottle: 3
Syringe: 5
ClothingEyesGlasses: 5
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
- type: Clothing
sprite: Clothing/Eyes/Glasses/glasses.rsi
- type: VisionCorrection
- type: Tag
tags:
- GlassesNearsight

- type: entity
parent: ClothingEyesBase
Expand Down
7 changes: 7 additions & 0 deletions Resources/Prototypes/SimpleStation14/Traits/disabilities.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- type: trait
id: Nearsighted
name: trait-nearsighted-name
description: You require glasses to see properly.
traitGear: ClothingEyesGlasses
components:
- type: Nearsighted
2 changes: 2 additions & 0 deletions Resources/Prototypes/SimpleStation14/tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- type: Tag
id: GlassesNearsight
Loading