diff --git a/Content.Client/Options/UI/OptionsMenu.xaml b/Content.Client/Options/UI/OptionsMenu.xaml index 90486a196ad1..a93bc0e7a9c1 100644 --- a/Content.Client/Options/UI/OptionsMenu.xaml +++ b/Content.Client/Options/UI/OptionsMenu.xaml @@ -1,5 +1,6 @@ diff --git a/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml b/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml index ecfaa96c7979..8d104f686037 100644 --- a/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml +++ b/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml @@ -8,6 +8,7 @@ + diff --git a/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml.cs b/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml.cs index 0d60c68e1a68..0f8365928374 100644 --- a/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml.cs @@ -1,4 +1,5 @@ using Content.Shared._Impstation.CCVar; +using Content.Shared._DV.CCVars; using Content.Shared.CCVar; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface; @@ -17,6 +18,7 @@ public AccessibilityTab() Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox); Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox); Control.AddOptionCheckBox(ImpCCVars.DisableSinguloWarping, DisableSinguloWarpingCheckBox); + Control.AddOptionCheckBox(DCCVars.NoVisionFilters, DisableFiltersCheckBox); Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider); Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider); Control.AddOptionCheckBox(ImpCCVars.ChatAutoFillHighlights, AutoFillHighlightsCheckBox); diff --git a/Content.Client/_DV/Overlays/UltraVisionOverlay.cs b/Content.Client/_DV/Overlays/UltraVisionOverlay.cs new file mode 100644 index 000000000000..63ee769149cf --- /dev/null +++ b/Content.Client/_DV/Overlays/UltraVisionOverlay.cs @@ -0,0 +1,52 @@ +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; +using Content.Shared.Abilities; +using System.Numerics; + +namespace Content.Client._DV.Overlays; + +public sealed partial class UltraVisionOverlay : Overlay +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] IEntityManager _entityManager = default!; + + + public override bool RequestScreenTexture => true; + public override OverlaySpace Space => OverlaySpace.WorldSpace; + private readonly ShaderInstance _ultraVisionShader; + + public UltraVisionOverlay() + { + IoCManager.InjectDependencies(this); + _ultraVisionShader = _prototypeManager.Index("UltraVision").Instance().Duplicate(); + } + + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + if (_playerManager.LocalEntity is not { Valid: true } player + || !_entityManager.HasComponent(player)) + { + return false; + } + + return base.BeforeDraw(in args); + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (ScreenTexture is null) + return; + + _ultraVisionShader.SetParameter("SCREEN_TEXTURE", ScreenTexture); + + var worldHandle = args.WorldHandle; + var viewport = args.WorldBounds; + worldHandle.SetTransform(Matrix3x2.Identity); + worldHandle.UseShader(_ultraVisionShader); + worldHandle.DrawRect(viewport, Color.White); + worldHandle.UseShader(null); // important - as of writing, construction overlay breaks without this + } +} diff --git a/Content.Client/_DV/Overlays/UltraVisionSystem.cs b/Content.Client/_DV/Overlays/UltraVisionSystem.cs new file mode 100644 index 000000000000..d576d24b7b6b --- /dev/null +++ b/Content.Client/_DV/Overlays/UltraVisionSystem.cs @@ -0,0 +1,61 @@ +using Content.Shared.Abilities; +using Content.Shared._DV.CCVars; +using Robust.Client.Graphics; +using Robust.Shared.Configuration; +using Robust.Shared.Player; + +namespace Content.Client._DV.Overlays; + +public sealed partial class UltraVisionSystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayMan = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly ISharedPlayerManager _playerMan = default!; + + private UltraVisionOverlay _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUltraVisionInit); + SubscribeLocalEvent(OnUltraVisionShutdown); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + + Subs.CVar(_cfg, DCCVars.NoVisionFilters, OnNoVisionFiltersChanged); + + _overlay = new(); + } + + private void OnUltraVisionInit(EntityUid uid, UltraVisionComponent component, ComponentInit args) + { + if (uid == _playerMan.LocalEntity && !_cfg.GetCVar(DCCVars.NoVisionFilters)) + _overlayMan.AddOverlay(_overlay); + } + + private void OnUltraVisionShutdown(EntityUid uid, UltraVisionComponent component, ComponentShutdown args) + { + if (uid == _playerMan.LocalEntity) + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnPlayerAttached(EntityUid uid, UltraVisionComponent component, LocalPlayerAttachedEvent args) + { + if (!_cfg.GetCVar(DCCVars.NoVisionFilters)) + _overlayMan.AddOverlay(_overlay); + } + + private void OnPlayerDetached(EntityUid uid, UltraVisionComponent component, LocalPlayerDetachedEvent args) + { + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnNoVisionFiltersChanged(bool enabled) + { + if (enabled) + _overlayMan.RemoveOverlay(_overlay); + else + _overlayMan.AddOverlay(_overlay); + } +} diff --git a/Content.Client/_Nyanotrasen/Overlays/DogVisionOverlay.cs b/Content.Client/_Nyanotrasen/Overlays/DogVisionOverlay.cs new file mode 100644 index 000000000000..9ee69ff063c6 --- /dev/null +++ b/Content.Client/_Nyanotrasen/Overlays/DogVisionOverlay.cs @@ -0,0 +1,52 @@ +using System.Numerics; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; +using Content.Shared.Abilities; + +namespace Content.Client._Nyanotrasen.Overlays; + +public sealed partial class DogVisionOverlay : Overlay +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] IEntityManager _entityManager = default!; + + + public override bool RequestScreenTexture => true; + public override OverlaySpace Space => OverlaySpace.WorldSpace; + private readonly ShaderInstance _dogVisionShader; + + public DogVisionOverlay() + { + IoCManager.InjectDependencies(this); + _dogVisionShader = _prototypeManager.Index("DogVision").Instance().Duplicate(); + } + + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + if (_playerManager.LocalEntity is not { Valid: true } player + || !_entityManager.HasComponent(player)) + { + return false; + } + + return base.BeforeDraw(in args); + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (ScreenTexture is null) + return; + + _dogVisionShader.SetParameter("SCREEN_TEXTURE", ScreenTexture); + + var worldHandle = args.WorldHandle; + var viewport = args.WorldBounds; + worldHandle.SetTransform(Matrix3x2.Identity); + worldHandle.UseShader(_dogVisionShader); + worldHandle.DrawRect(viewport, Color.White); + worldHandle.UseShader(null); // important - as of writing, construction overlay breaks without this + } +} diff --git a/Content.Client/_Nyanotrasen/Overlays/DogVisionSystem.cs b/Content.Client/_Nyanotrasen/Overlays/DogVisionSystem.cs new file mode 100644 index 000000000000..3b18720fff07 --- /dev/null +++ b/Content.Client/_Nyanotrasen/Overlays/DogVisionSystem.cs @@ -0,0 +1,61 @@ +using Content.Shared.Abilities; +using Content.Shared._DV.CCVars; +using Robust.Client.Graphics; +using Robust.Shared.Configuration; +using Robust.Shared.Player; + +namespace Content.Client._Nyanotrasen.Overlays; + +public sealed partial class DogVisionSystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayMan = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly ISharedPlayerManager _playerMan = default!; + + private DogVisionOverlay _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDogVisionInit); + SubscribeLocalEvent(OnDogVisionShutdown); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + + Subs.CVar(_cfg, DCCVars.NoVisionFilters, OnNoVisionFiltersChanged); + + _overlay = new(); + } + + private void OnDogVisionInit(EntityUid uid, DogVisionComponent component, ComponentInit args) + { + if (uid == _playerMan.LocalEntity && !_cfg.GetCVar(DCCVars.NoVisionFilters)) + _overlayMan.AddOverlay(_overlay); + } + + private void OnDogVisionShutdown(EntityUid uid, DogVisionComponent component, ComponentShutdown args) + { + if (uid == _playerMan.LocalEntity) + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnPlayerAttached(EntityUid uid, DogVisionComponent component, LocalPlayerAttachedEvent args) + { + if (!_cfg.GetCVar(DCCVars.NoVisionFilters)) + _overlayMan.AddOverlay(_overlay); + } + + private void OnPlayerDetached(EntityUid uid, DogVisionComponent component, LocalPlayerDetachedEvent args) + { + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnNoVisionFiltersChanged(bool enabled) + { + if (enabled) + _overlayMan.RemoveOverlay(_overlay); + else + _overlayMan.AddOverlay(_overlay); + } +} diff --git a/Content.Shared/_DV/Abilities/UltraVisionComponent.cs b/Content.Shared/_DV/Abilities/UltraVisionComponent.cs new file mode 100644 index 000000000000..5f631c54f252 --- /dev/null +++ b/Content.Shared/_DV/Abilities/UltraVisionComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameStates; +namespace Content.Shared.Abilities; + +[RegisterComponent] +[NetworkedComponent] + +public sealed partial class UltraVisionComponent : Component +{} diff --git a/Content.Shared/_DV/CCVars/DCCVars.cs b/Content.Shared/_DV/CCVars/DCCVars.cs index 8fbe0623346f..5f3fdba2c140 100644 --- a/Content.Shared/_DV/CCVars/DCCVars.cs +++ b/Content.Shared/_DV/CCVars/DCCVars.cs @@ -111,4 +111,9 @@ public sealed class DCCVars public static readonly CVarDef MailLargeMalus = CVarDef.Create("mail.largemalus", -250, CVar.SERVERONLY); + /// + /// Disables all vision filters for species like Vulpkanin or Harpies. There are good reasons someone might want to disable these. + /// + public static readonly CVarDef NoVisionFilters = + CVarDef.Create("accessibility.no_vision_filters", false, CVar.CLIENTONLY | CVar.ARCHIVE); } diff --git a/Content.Shared/_Nyanotrasen/Abilities/DogVisionComponent.cs b/Content.Shared/_Nyanotrasen/Abilities/DogVisionComponent.cs new file mode 100644 index 000000000000..05867aff721b --- /dev/null +++ b/Content.Shared/_Nyanotrasen/Abilities/DogVisionComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Abilities +{ + [RegisterComponent] + [NetworkedComponent] + + public sealed partial class DogVisionComponent : Component + {} +} diff --git a/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl b/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl new file mode 100644 index 000000000000..ad4f3403d278 --- /dev/null +++ b/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl @@ -0,0 +1,4 @@ +ui-options-tab-extra = Extra +ui-options-general-forknotice = Note: These settings are fork-specific and might not apply on other servers. + +ui-options-no-filters = Disable trait-specific shaders diff --git a/Resources/Locale/en-US/_DV/traits/traits.ftl b/Resources/Locale/en-US/_DV/traits/traits.ftl index 9a5cb6f3f431..303e130b4c68 100644 --- a/Resources/Locale/en-US/_DV/traits/traits.ftl +++ b/Resources/Locale/en-US/_DV/traits/traits.ftl @@ -24,3 +24,13 @@ trait-estradiol-sensitive-desc = Your body is capable of taking on Nanotrasen's trait-testosterone-sensitive-name = Testosterone sensitive trait-testosterone-sensitive-desc = Your body is capable of taking on Nanotrasen's special masculinization medicines. + +# impstation edit - removing mentions of unimplemented species + +trait-ultravision-name = Ultraviolet vision +trait-ultravision-desc = Whether through custom bionic eyes, random mutation, + or something else, you perceive the world with ultraviolet light. + +trait-deuteranopia-name = Deuteranopia +trait-deuteranopia-desc = Whether through custom bionic eyes, random mutation, + or something else, you have red-green colour blindness. diff --git a/Resources/Prototypes/_DV/Shaders/birdvision.yml b/Resources/Prototypes/_DV/Shaders/birdvision.yml new file mode 100644 index 000000000000..e6d2f2fa7b89 --- /dev/null +++ b/Resources/Prototypes/_DV/Shaders/birdvision.yml @@ -0,0 +1,4 @@ +- type: shader + id: UltraVision + kind: source + path: "/Textures/_DV/Shaders/ultravision.swsl" diff --git a/Resources/Prototypes/_DV/Traits/disabilities.yml b/Resources/Prototypes/_DV/Traits/disabilities.yml new file mode 100644 index 000000000000..3d416797e157 --- /dev/null +++ b/Resources/Prototypes/_DV/Traits/disabilities.yml @@ -0,0 +1,15 @@ +- type: trait + id: UltraVision + name: trait-ultravision-name + description: trait-ultravision-desc + category: Disabilities + components: + - type: UltraVision + +- type: trait + id: DogVision + name: trait-deuteranopia-name + description: trait-deuteranopia-desc + category: Disabilities + components: + - type: DogVision diff --git a/Resources/Prototypes/_Nyanotrasen/Shaders/dogvision.yml b/Resources/Prototypes/_Nyanotrasen/Shaders/dogvision.yml new file mode 100644 index 000000000000..5a34b44c9383 --- /dev/null +++ b/Resources/Prototypes/_Nyanotrasen/Shaders/dogvision.yml @@ -0,0 +1,4 @@ +- type: shader + id: DogVision + kind: source + path: "/Textures/_Nyanotrasen/Shaders/dogvision.swsl" diff --git a/Resources/Textures/_DV/Shaders/ultravision.swsl b/Resources/Textures/_DV/Shaders/ultravision.swsl new file mode 100644 index 000000000000..a0dccaf24594 --- /dev/null +++ b/Resources/Textures/_DV/Shaders/ultravision.swsl @@ -0,0 +1,14 @@ +uniform sampler2D SCREEN_TEXTURE; + +void fragment() { + highp vec4 color = zTextureSpec(SCREEN_TEXTURE, UV); + + highp mat3 m = mat3( + vec3(0.000,1.000,0.000), + vec3(0.000,0.000,1.000), + vec3(-0.165,0.165,1.000) + ); + highp vec3 result = color.rgb * m; + + COLOR = vec4(result, 1); +} diff --git a/Resources/Textures/_Nyanotrasen/Shaders/dogvision.swsl b/Resources/Textures/_Nyanotrasen/Shaders/dogvision.swsl new file mode 100644 index 000000000000..1e8c7d2ed355 --- /dev/null +++ b/Resources/Textures/_Nyanotrasen/Shaders/dogvision.swsl @@ -0,0 +1,14 @@ +uniform sampler2D SCREEN_TEXTURE; + +void fragment() { + highp vec4 color = zTextureSpec(SCREEN_TEXTURE, UV); + + highp mat3 m = mat3( + vec3(0.625,0.375,0.000), + vec3(0.700,0.300,0.000), + vec3(0.000,0.300,0.700) + ); + highp vec3 result = color.rgb * m; + + COLOR = vec4(result, 1); +}