mirror of
https://github.com/corvax-team/ss14-wl.git
synced 2026-02-14 19:29:57 +01:00
Thermal and Night Vision update (#429)
* base * fix * fix * fix2 * xeno * xenoborg + locale
This commit is contained in:
@@ -42,7 +42,7 @@ public sealed class BaseSwitchableOverlay<TComp> : Overlay where TComp : Switcha
|
||||
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
worldHandle.UseShader(_shader);
|
||||
worldHandle.DrawRect(args.WorldBounds, Comp.Color.WithAlpha(alpha));
|
||||
worldHandle.DrawRect(args.WorldBounds, Comp.Color.WithAlpha(alpha * Comp.OverlayOpacity));
|
||||
worldHandle.UseShader(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,21 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client._White.Overlays;
|
||||
|
||||
public sealed class ThermalVisionOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private readonly TransformSystem _transform;
|
||||
private readonly StealthSystem _stealth;
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly ContainerSystem _container;
|
||||
private readonly SharedPointLightSystem _light;
|
||||
|
||||
@@ -42,6 +45,7 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
_container = _entity.System<ContainerSystem>();
|
||||
_transform = _entity.System<TransformSystem>();
|
||||
_stealth = _entity.System<StealthSystem>();
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
_light = _entity.System<SharedPointLightSystem>();
|
||||
|
||||
ZIndex = -1;
|
||||
@@ -111,7 +115,7 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
Render(entry.Ent, entry.Map, worldHandle, entry.EyeRot, Comp.Color, alpha);
|
||||
Render(entry.Ent, entry.Map, worldHandle, entry.EyeRot, Comp.Color, Comp.ThermalShader, alpha);
|
||||
}
|
||||
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
@@ -122,6 +126,7 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
DrawingHandleWorld handle,
|
||||
Angle eyeRot,
|
||||
Color color,
|
||||
string? shader,
|
||||
float alpha)
|
||||
{
|
||||
var (uid, sprite, xform) = ent;
|
||||
@@ -131,11 +136,40 @@ public sealed class ThermalVisionOverlay : Overlay
|
||||
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;
|
||||
Dictionary<int, (ShaderInstance? shader, Color color)> layerData = new();
|
||||
if (shader != null)
|
||||
{
|
||||
// Layer shaders break handle shader so we have to do this. It has a side effect of clothing not rendering
|
||||
// on some species or on female characters but its fine cause shader itself makes things hard to see
|
||||
var allLayers = sprite.AllLayers.ToList();
|
||||
for (var i = 0; i < allLayers.Count; i++)
|
||||
{
|
||||
if (allLayers[i] is not SpriteComponent.Layer { Visible: true } layer)
|
||||
continue;
|
||||
|
||||
if (layer.ShaderPrototype?.Id is "DisplacedDraw" or "DisplacedStencilDraw")
|
||||
_sprite.LayerSetVisible((uid, sprite), i, false);
|
||||
|
||||
layerData[i] = (layer.Shader, layer.Color);
|
||||
layer.Shader = null;
|
||||
_sprite.LayerSetColor(layer, Color.White.WithAlpha(layer.Color.A));
|
||||
}
|
||||
|
||||
_sprite.SetColor((uid, sprite), Color.White.WithAlpha(alpha));
|
||||
handle.UseShader(_protoMan.Index<ShaderPrototype>(shader).Instance());
|
||||
}
|
||||
else
|
||||
_sprite.SetColor((uid, sprite), color.WithAlpha(alpha));
|
||||
_sprite.RenderSprite((uid, sprite), handle, eyeRot, rotation, position);
|
||||
_sprite.SetColor((uid, sprite), originalColor);
|
||||
handle.UseShader(null);
|
||||
foreach (var (key, value) in layerData)
|
||||
{
|
||||
((SpriteComponent.Layer) sprite[key]).Shader = value.shader;
|
||||
_sprite.LayerSetColor((uid, sprite), key, value.color);
|
||||
_sprite.LayerSetVisible((uid, sprite), key, true);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanSee(EntityUid uid, SpriteComponent sprite)
|
||||
|
||||
@@ -75,6 +75,8 @@ public abstract class SwitchableOverlaySystem<TComp, TEvent> : EntitySystem
|
||||
DeactivateSound = component.DeactivateSound,
|
||||
ToggleAction = component.ToggleAction,
|
||||
LightRadius = component is ThermalVisionComponent thermal ? thermal.LightRadius : 0f,
|
||||
DrawOverlay = component.DrawOverlay,
|
||||
OverlayOpacity = component.OverlayOpacity,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,6 +89,8 @@ public abstract class SwitchableOverlaySystem<TComp, TEvent> : EntitySystem
|
||||
component.IsEquipment = state.IsEquipment;
|
||||
component.ActivateSound = state.ActivateSound;
|
||||
component.DeactivateSound = state.DeactivateSound;
|
||||
component.DrawOverlay = state.DrawOverlay;
|
||||
component.OverlayOpacity = state.OverlayOpacity;
|
||||
|
||||
if (component.ToggleAction != state.ToggleAction)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,9 @@ public abstract partial class SwitchableVisionOverlayComponent : BaseVisionOverl
|
||||
[DataField]
|
||||
public bool DrawOverlay = true;
|
||||
|
||||
[DataField]
|
||||
public float OverlayOpacity = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether it should grant equipment enhanced vision or is it mob vision
|
||||
/// </summary>
|
||||
@@ -50,4 +53,6 @@ public sealed class SwitchableVisionOverlayComponentState : IComponentState
|
||||
public SoundSpecifier? DeactivateSound;
|
||||
public EntProtoId? ToggleAction;
|
||||
public float LightRadius;
|
||||
public bool DrawOverlay;
|
||||
public float OverlayOpacity;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,13 @@ public sealed partial class ThermalVisionComponent : SwitchableVisionOverlayComp
|
||||
{
|
||||
public override EntProtoId? ToggleAction { get; set; } = "ToggleThermalVision";
|
||||
|
||||
public override Color Color { get; set; } = Color.FromHex("#F84742");
|
||||
public override Color Color { get; set; } = Color.FromHex("#d06764");
|
||||
|
||||
[DataField]
|
||||
public float LightRadius = 5f;
|
||||
public float LightRadius = 2f;
|
||||
|
||||
[DataField]
|
||||
public string? ThermalShader = "ThermalVision";
|
||||
}
|
||||
|
||||
public sealed partial class ToggleThermalVisionEvent : InstantActionEvent;
|
||||
|
||||
6
Resources/Locale/ru-RU/_White/actions/types.ftl
Normal file
6
Resources/Locale/ru-RU/_White/actions/types.ftl
Normal file
@@ -0,0 +1,6 @@
|
||||
ent-ToggleNightVision = Включить/выключить ночное зрение
|
||||
.desc = Включает или выключает ночное зрение.
|
||||
ent-ToggleThermalVision = Включить/выключить тепловое зрение
|
||||
.desc = Включает или выключает тепловое зрение.
|
||||
ent-PulseThermalVision = Импульс теплового зрения
|
||||
.desc = Временно активирует тепловое зрение.
|
||||
@@ -246,6 +246,12 @@
|
||||
cell_slot:
|
||||
name: power-cell-slot-component-slot-name-default
|
||||
startingItem: PowerCellHigh
|
||||
# WL-Night-Vision-Start
|
||||
- type: NightVision
|
||||
color: "#224fff"
|
||||
activateSound: null
|
||||
deactivateSound: null
|
||||
# WL-Night-Vision-End
|
||||
|
||||
|
||||
# xenoborgs empty
|
||||
|
||||
@@ -118,6 +118,12 @@
|
||||
molsPerSecondPerUnitMass: 0.0005
|
||||
- type: Speech
|
||||
speechVerb: LargeMob
|
||||
# WL-Night-Vision-Start
|
||||
- type: NightVision
|
||||
color: "#A3A3A3"
|
||||
activateSound: null
|
||||
deactivateSound: null
|
||||
# WL-Night-Vision-End
|
||||
|
||||
- type: entity
|
||||
name: praetorian
|
||||
|
||||
6
Resources/Prototypes/_Goobstation/Shaders/shaders.yml
Normal file
6
Resources/Prototypes/_Goobstation/Shaders/shaders.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
- type: shader
|
||||
id: ThermalVision
|
||||
kind: source
|
||||
path: "/Textures/_Goobstation/Shaders/thermal.swsl"
|
||||
params:
|
||||
pixelSize: 32.0
|
||||
56
Resources/Textures/_Goobstation/Shaders/thermal.swsl
Normal file
56
Resources/Textures/_Goobstation/Shaders/thermal.swsl
Normal file
@@ -0,0 +1,56 @@
|
||||
light_mode unshaded;
|
||||
|
||||
uniform lowp float pixelSize;
|
||||
|
||||
//
|
||||
// https://gamedev.stackexchange.com/a/59808
|
||||
//
|
||||
// Author: sam hocevar
|
||||
// Answered: Jul 27, 2013 at 13:33
|
||||
// License: CC BY-SA 3.0
|
||||
//
|
||||
|
||||
highp vec3 rgb2hsv(highp vec3 c) {
|
||||
highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
highp vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||
highp vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||
|
||||
highp float d = q.x - min(q.w, q.y);
|
||||
highp float e = 0.00000000010; //because this doesn't support doing 1.0e-10
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
highp vec3 hsv2rgb(highp vec3 c) {
|
||||
highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
|
||||
highp float getNeighbor(highp vec2 uv, lowp int x, lowp int y) {
|
||||
lowp float xdif = float(x) / pixelSize;
|
||||
lowp float ydif = float(y) / pixelSize;
|
||||
highp vec2 res = vec2(uv.x + xdif, uv.y + ydif);
|
||||
if (res.x < 0.0 || res.x > 1.0 || res.y < 0.0 || res.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
return zTexture(res).a;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
highp vec4 sprite = zTexture(UV);
|
||||
if (sprite.a == 0.0) {
|
||||
discard;
|
||||
}
|
||||
highp float s = 0.0;
|
||||
for(int y = -2; y <= 2; y++) {
|
||||
for(int x = -2; x <= 2; x++) {
|
||||
s = s + getNeighbor(UV, x, y) * 0.4;
|
||||
}
|
||||
}
|
||||
highp vec3 hsv = rgb2hsv(sprite.xyz);
|
||||
sprite.rgb = hsv2rgb(vec3(pow(hsv.z, 0.5), s, 1.0));
|
||||
// sprite.rgb = sprite.rgb * vec3(1.0, 1.0, 0.5);
|
||||
|
||||
COLOR = sprite;
|
||||
}
|
||||
Reference in New Issue
Block a user