Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stealth shader tweaks #1047

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
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
4 changes: 3 additions & 1 deletion Content.Client/Stealth/StealthSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ private void OnShaderRender(EntityUid uid, StealthComponent component, BeforePos
var reference = args.Viewport.WorldToLocal(_transformSystem.GetWorldPosition(parentXform));
reference.X = -reference.X;
var visibility = GetVisibility(uid, component);
var fullyInvisible = GetFullyInvisible(uid, component);

// actual visual visibility effect is limited to +/- 1.
// actual visual visibility effect is limited to +/- 1.r
visibility = Math.Clamp(visibility, -1f, 1f);

_shader.SetParameter("reference", reference);
_shader.SetParameter("visibility", visibility);
_shader.SetParameter("fully_invisible", fullyInvisible);

visibility = MathF.Max(0, visibility);
args.Sprite.Color = new Color(visibility, visibility, 1, 1);
Expand Down
25 changes: 24 additions & 1 deletion Content.Server/Pointing/EntitySystems/PointingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using Content.Shared.Mind;
using Content.Shared.Pointing;
using Content.Shared.Popups;
using Content.Shared.Stealth;
using Content.Shared.Stealth.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.Player;
Expand Down Expand Up @@ -43,6 +45,8 @@ internal sealed class PointingSystem : SharedPointingSystem
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly SharedStealthSystem _stealth = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;

private TimeSpan _pointDelay = TimeSpan.FromSeconds(0.5f);

Expand Down Expand Up @@ -203,8 +207,10 @@ bool ViewerPredicate(ICommonSession playerSession)
string viewerMessage;
string? viewerPointedAtMessage = null;
var playerName = Identity.Entity(player, EntityManager);
var isInvisible = TryComp<StealthComponent>(pointed, out var stealthComp) && _stealth.GetVisibility(pointed, stealthComp) < stealthComp.ExamineThreshold;
var entIntersect = _lookup.GetEntitiesIntersecting(mapCoordsPointed, LookupFlags.StaticSundries);

if (Exists(pointed))
if (Exists(pointed) && !isInvisible)
{
var pointedName = Identity.Entity(pointed, EntityManager);

Expand All @@ -225,6 +231,23 @@ bool ViewerPredicate(ICommonSession playerSession)

_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):user} pointed at {ToPrettyString(pointed):target} {Transform(pointed).Coordinates}");
}
else if (isInvisible && entIntersect.Count > 1)
{
var entFirst = player == entIntersect.FirstOrDefault()
? entIntersect.ElementAtOrDefault(1)
: entIntersect.FirstOrDefault();
var pointedName = Identity.Entity(entFirst, EntityManager);

selfMessage = Loc.GetString("pointing-system-point-at-other", ("other", pointedName));
viewerMessage = Loc.GetString("pointing-system-point-at-other-others", ("otherName", playerName), ("other", pointedName));

var ev = new AfterPointedAtEvent(entFirst);
RaiseLocalEvent(player, ref ev);
var gotev = new AfterGotPointedAtEvent(player);
RaiseLocalEvent(entFirst, ref gotev);

_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):user} tried to point at invisible entity {ToPrettyString(pointed):target}, instead pointed at {ToPrettyString(entFirst):target} {Transform(entFirst).Coordinates}");
}
else
{
TileRef? tileRef = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,13 @@ public void OnChameleonSkin(EntityUid uid, ChangelingComponent comp, ref ActionC
return;
}

EnsureComp<StealthComponent>(uid);
_stealth.SetMinVisibility(uid, 0);
var stealth = EnsureComp<StealthComponent>(uid);
_stealth.SetFullyInvisible(uid, true);

var stealthOnMove = EnsureComp<StealthOnMoveComponent>(uid);
stealthOnMove.MovementVisibilityRate = 1;
stealthOnMove.MovementVisibilityRate = 1.5f;
stealthOnMove.PassiveVisibilityRate = -0.37f;
Dirty(uid, stealthOnMove);

_popup.PopupEntity(Loc.GetString("changeling-chameleon-start"), uid, uid);
}
Expand Down
12 changes: 11 additions & 1 deletion Content.Shared/Stealth/Components/StealthComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,29 @@ public sealed partial class StealthComponent : Component
/// </summary>
[DataField("examinedDesc")]
public string ExaminedDesc = "stealth-visual-effect";

/// <summary>
/// The entity will be fully invisible without any shimmer shader at minimum visibility.
/// </summary>
[DataField("fullyInvisible")]
public bool FullyInvisible = false;
}

[Serializable, NetSerializable]
public sealed class StealthComponentState : ComponentState
{
public readonly float Visibility;
public readonly float MinVisibility;
public readonly TimeSpan? LastUpdated;
public readonly bool FullyInvisible;
public readonly bool Enabled;

public StealthComponentState(float stealthLevel, TimeSpan? lastUpdated, bool enabled)
public StealthComponentState(float stealthLevel, float minVisibility, TimeSpan? lastUpdated, bool fullyInvisible, bool enabled)
{
Visibility = stealthLevel;
MinVisibility = minVisibility;
LastUpdated = lastUpdated;
FullyInvisible = fullyInvisible;
Enabled = enabled;
}
}
6 changes: 3 additions & 3 deletions Content.Shared/Stealth/Components/StealthOnMoveComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ namespace Content.Shared.Stealth.Components
/// When added to an entity with stealth component, this component will change the visibility
/// based on the entity's (lack of) movement.
/// </summary>
[RegisterComponent, NetworkedComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class StealthOnMoveComponent : Component
{
/// <summary>
/// Rate that effects how fast an entity's visibility passively changes.
/// </summary>
[DataField("passiveVisibilityRate")]
[DataField("passiveVisibilityRate"), AutoNetworkedField]
public float PassiveVisibilityRate = -0.15f;

/// <summary>
/// Rate for movement induced visibility changes. Scales with distance moved.
/// </summary>
[DataField("movementVisibilityRate")]
[DataField("movementVisibilityRate"), AutoNetworkedField]
public float MovementVisibilityRate = 0.2f;
}
}
28 changes: 27 additions & 1 deletion Content.Shared/Stealth/SharedStealthSystem.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Content.Shared.Examine;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Systems;
using Content.Shared.Pointing;
using Content.Shared.Stealth.Components;
using Robust.Shared.GameStates;
using Robust.Shared.Timing;
Expand Down Expand Up @@ -98,7 +99,7 @@ protected virtual void OnInit(EntityUid uid, StealthComponent component, Compone

private void OnStealthGetState(EntityUid uid, StealthComponent component, ref ComponentGetState args)
{
args.State = new StealthComponentState(component.LastVisibility, component.LastUpdated, component.Enabled);
args.State = new StealthComponentState(component.LastVisibility, component.MinVisibility, component.LastUpdated, component.FullyInvisible, component.Enabled);
}

private void OnStealthHandleState(EntityUid uid, StealthComponent component, ref ComponentHandleState args)
Expand All @@ -108,7 +109,9 @@ private void OnStealthHandleState(EntityUid uid, StealthComponent component, ref

SetEnabled(uid, cast.Enabled, component);
component.LastVisibility = cast.Visibility;
component.MinVisibility = cast.MinVisibility;
component.LastUpdated = cast.LastUpdated;
component.FullyInvisible = cast.FullyInvisible;
}

private void OnMove(EntityUid uid, StealthOnMoveComponent component, ref MoveEvent args)
Expand Down Expand Up @@ -222,4 +225,27 @@ public void SetMinVisibility(EntityUid uid, float value, StealthComponent? compo

Dirty(uid, component);
}

/// <summary>
/// Sets whether an entity should be fully invisible.
/// </summary>
public void SetFullyInvisible(EntityUid uid, bool value, StealthComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

component.FullyInvisible = value;

Dirty(uid, component);
}

/// <summary>
/// Gets whether an entity is fully invisible from the <see cref="StealthComponent"/>
public bool GetFullyInvisible(EntityUid uid, StealthComponent? component = null)
{
if (!Resolve(uid, ref component) || !component.Enabled)
return false;

return component.FullyInvisible;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,9 @@
parent: true
components:
- type: Stealth
minVisibility: 0.1
lastVisibility: 0.1
minVisibility: 0.22
lastVisibility: 0.22
fullyInvisible: true
- type: PowerCellDraw
drawRate: 1.8 # 200 seconds on the default cell
- type: ToggleCellDraw
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
quiet: true
- type: Stealth
hadOutline: true
fullyInvisible: true
- type: StealthOnMove
passiveVisibilityRate: -0.37
movementVisibilityRate: 0.20
Expand Down
8 changes: 7 additions & 1 deletion Resources/Textures/Shaders/stealth.swsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ light_mode unshaded;
uniform sampler2D SCREEN_TEXTURE;
uniform highp float visibility; // number between -1 and 1
uniform mediump vec2 reference;
uniform bool fully_invisible;

const mediump float time_scale = 0.25;
const mediump float distance_scale = 0.125;
Expand Down Expand Up @@ -33,5 +34,10 @@ void fragment() {
alpha = 0.0;

COLOR.xyz = mix(background.xyz, sprite.xyz, alpha);
COLOR.a = 1.0;

if (fully_invisible) {
COLOR.a = min(1.0, alpha * 2.0);
} else {
COLOR.a = 1.0;
}
}