using System.Numerics;
using Content.Shared.DoAfter;
+using Content.Client.UserInterface.Systems;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
-using Robust.Shared.Graphics;
using Robust.Client.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
private readonly IPlayerManager _player;
private readonly SharedTransformSystem _transform;
private readonly MetaDataSystem _meta;
+ private readonly ProgressColorSystem _progressColor;
private readonly Texture _barTexture;
private readonly ShaderInstance _shader;
_player = player;
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
+ _progressColor = _entManager.System<ProgressColorSystem>();
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
var cancelElapsed = (time - doAfter.CancelledTime.Value).TotalSeconds;
var flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0;
- color = new Color(1f, 0f, 0f, flash ? alpha : 0f);
+ color = GetProgressColor(0, flash ? alpha : 0);
}
else
{
handle.SetTransform(Matrix3.Identity);
}
- public static Color GetProgressColor(float progress, float alpha = 1f)
+ public Color GetProgressColor(float progress, float alpha = 1f)
{
- if (progress >= 1.0f)
- {
- return new Color(0f, 1f, 0f, alpha);
- }
- // lerp
- var hue = (5f / 18f) * progress;
- return Color.FromHsv((hue, 1f, 0.75f, alpha));
+ return _progressColor.GetProgressColor(progress).WithAlpha(alpha);
}
}
xmlns:xNamespace="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Content.Client.Stylesheets">
<BoxContainer Orientation="Vertical">
- <BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
- <Label Text="{Loc 'ui-options-general-ui-style'}"
- FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
- StyleClasses="LabelKeyText"/>
- <BoxContainer Orientation="Horizontal">
- <Label Text="{Loc 'ui-options-hud-theme'}" />
- <Control MinSize="4 0" />
- <OptionButton Name="HudThemeOption" />
+ <ScrollContainer VerticalExpand="True" HorizontalExpand="True">
+ <BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
+ <Label Text="{Loc 'ui-options-general-ui-style'}"
+ FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
+ StyleClasses="LabelKeyText"/>
+ <BoxContainer Orientation="Horizontal">
+ <Label Text="{Loc 'ui-options-hud-theme'}" />
+ <Control MinSize="4 0" />
+ <OptionButton Name="HudThemeOption" />
+ </BoxContainer>
+ <BoxContainer Orientation="Horizontal">
+ <Label Text="{Loc 'ui-options-hud-layout'}" />
+ <Control MinSize="4 0" />
+ <OptionButton Name="HudLayoutOption" />
+ </BoxContainer>
+ <Label Text="{Loc 'ui-options-general-accessibility'}"
+ FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
+ StyleClasses="LabelKeyText"/>
+ <CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
+ <CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
+ <CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
+ <BoxContainer Orientation="Horizontal">
+ <Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
+ <Slider Name="ScreenShakeIntensitySlider"
+ MinValue="0"
+ MaxValue="100"
+ Rounded="True"
+ MinWidth="200" />
+ <Label Name="ScreenShakeIntensityLabel" Margin="8 0" />
+ </BoxContainer>
+ <Label Text="{Loc 'ui-options-general-discord'}"
+ FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
+ StyleClasses="LabelKeyText"/>
+ <CheckBox Name="DiscordRich" Text="{Loc 'ui-options-discordrich'}" />
+ <Label Text="{Loc 'ui-options-general-speech'}"
+ FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
+ StyleClasses="LabelKeyText"/>
+ <CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
+ <CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
+ <CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
+ <Label Text="{Loc 'ui-options-general-cursor'}"
+ FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
+ StyleClasses="LabelKeyText"/>
+ <CheckBox Name="ShowHeldItemCheckBox" Text="{Loc 'ui-options-show-held-item'}" />
+ <CheckBox Name="ShowCombatModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-combat-mode-indicators'}" />
+ <Label Text="{Loc 'ui-options-general-storage'}"
+ FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
+ StyleClasses="LabelKeyText"/>
+ <CheckBox Name="OpaqueStorageWindowCheckBox" Text="{Loc 'ui-options-opaque-storage-window'}" />
+ <CheckBox Name="StaticStorageUI" Text="{Loc 'ui-options-static-storage-ui'}" />
+ <!-- <CheckBox Name="ToggleWalk" Text="{Loc 'ui-options-hotkey-toggle-walk'}" /> -->
</BoxContainer>
- <BoxContainer Orientation="Horizontal">
- <Label Text="{Loc 'ui-options-hud-layout'}" />
- <Control MinSize="4 0" />
- <OptionButton Name="HudLayoutOption" />
- </BoxContainer>
- <Label Text="{Loc 'ui-options-general-accessibility'}"
- FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
- StyleClasses="LabelKeyText"/>
- <CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
- <CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
- <BoxContainer Orientation="Horizontal">
- <Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
- <Slider Name="ScreenShakeIntensitySlider"
- MinValue="0"
- MaxValue="100"
- Rounded="True"
- MinWidth="200" />
- <Label Name="ScreenShakeIntensityLabel" Margin="8 0" />
- </BoxContainer>
- <Label Text="{Loc 'ui-options-general-discord'}"
- FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
- StyleClasses="LabelKeyText"/>
- <CheckBox Name="DiscordRich" Text="{Loc 'ui-options-discordrich'}" />
- <Label Text="{Loc 'ui-options-general-speech'}"
- FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
- StyleClasses="LabelKeyText"/>
- <CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
- <CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
- <CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
- <Label Text="{Loc 'ui-options-general-cursor'}"
- FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
- StyleClasses="LabelKeyText"/>
- <CheckBox Name="ShowHeldItemCheckBox" Text="{Loc 'ui-options-show-held-item'}" />
- <CheckBox Name="ShowCombatModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-combat-mode-indicators'}" />
- <Label Text="{Loc 'ui-options-general-storage'}"
- FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
- StyleClasses="LabelKeyText"/>
- <CheckBox Name="OpaqueStorageWindowCheckBox" Text="{Loc 'ui-options-opaque-storage-window'}" />
- <CheckBox Name="StaticStorageUI" Text="{Loc 'ui-options-static-storage-ui'}" />
- <!-- <CheckBox Name="ToggleWalk" Text="{Loc 'ui-options-hotkey-toggle-walk'}" /> -->
-
- </BoxContainer>
+ </ScrollContainer>
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
<Button Name="ApplyButton"
Text="{Loc 'ui-options-apply'}"
FancySpeechBubblesCheckBox.OnToggled += OnCheckBoxToggled;
FancyNameBackgroundsCheckBox.OnToggled += OnCheckBoxToggled;
EnableColorNameCheckBox.OnToggled += OnCheckBoxToggled;
+ ColorblindFriendlyCheckBox.OnToggled += OnCheckBoxToggled;
ReducedMotionCheckBox.OnToggled += OnCheckBoxToggled;
ScreenShakeIntensitySlider.OnValueChanged += OnScreenShakeIntensitySliderChanged;
// ToggleWalk.OnToggled += OnCheckBoxToggled;
FancySpeechBubblesCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
FancyNameBackgroundsCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatFancyNameBackground);
EnableColorNameCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableColorName);
+ ColorblindFriendlyCheckBox.Pressed = _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
ReducedMotionCheckBox.Pressed = _cfg.GetCVar(CCVars.ReducedMotion);
ScreenShakeIntensitySlider.Value = _cfg.GetCVar(CCVars.ScreenShakeIntensity) * 100f;
// ToggleWalk.Pressed = _cfg.GetCVar(CCVars.ToggleWalk);
_cfg.SetCVar(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableColorName, EnableColorNameCheckBox.Pressed);
+ _cfg.SetCVar(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox.Pressed);
_cfg.SetCVar(CCVars.ReducedMotion, ReducedMotionCheckBox.Pressed);
_cfg.SetCVar(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider.Value / 100f);
// _cfg.SetCVar(CCVars.ToggleWalk, ToggleWalk.Pressed);
var isFancyChatSame = FancySpeechBubblesCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
var isFancyBackgroundSame = FancyNameBackgroundsCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatFancyNameBackground);
var isEnableColorNameSame = EnableColorNameCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableColorName);
+ var isColorblindFriendly = ColorblindFriendlyCheckBox.Pressed == _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
var isReducedMotionSame = ReducedMotionCheckBox.Pressed == _cfg.GetCVar(CCVars.ReducedMotion);
var isScreenShakeIntensitySame = Math.Abs(ScreenShakeIntensitySlider.Value / 100f - _cfg.GetCVar(CCVars.ScreenShakeIntensity)) < 0.01f;
// var isToggleWalkSame = ToggleWalk.Pressed == _cfg.GetCVar(CCVars.ToggleWalk);
isFancyChatSame &&
isFancyBackgroundSame &&
isEnableColorNameSame &&
+ isColorblindFriendly &&
isReducedMotionSame &&
isScreenShakeIntensitySame &&
// isToggleWalkSame &&
using Robust.Shared.Enums;
using System.Numerics;
using Content.Shared.StatusIcon.Components;
+using Content.Client.UserInterface.Systems;
+using Robust.Shared.Prototypes;
using static Robust.Shared.Maths.Color;
namespace Content.Client.Overlays;
/// </summary>
public sealed class EntityHealthBarOverlay : Overlay
{
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
private readonly IEntityManager _entManager;
private readonly SharedTransformSystem _transform;
private readonly MobStateSystem _mobStateSystem;
private readonly MobThresholdSystem _mobThresholdSystem;
+ private readonly ProgressColorSystem _progressColor;
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
public HashSet<string> DamageContainers = new();
+ private readonly ShaderInstance _shader;
public EntityHealthBarOverlay(IEntityManager entManager)
{
+ IoCManager.InjectDependencies(this);
_entManager = entManager;
- _transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
- _mobStateSystem = _entManager.EntitySysManager.GetEntitySystem<MobStateSystem>();
- _mobThresholdSystem = _entManager.EntitySysManager.GetEntitySystem<MobThresholdSystem>();
+ _transform = _entManager.System<SharedTransformSystem>();
+ _mobStateSystem = _entManager.System<MobStateSystem>();
+ _mobThresholdSystem = _entManager.System<MobThresholdSystem>();
+ _progressColor = _entManager.System<ProgressColorSystem>();
+ _shader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
}
protected override void Draw(in OverlayDrawArgs args)
var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale));
var rotationMatrix = Matrix3.CreateRotation(-rotation);
+ handle.UseShader(_shader);
+
var query = _entManager.AllEntityQueryEnumerator<MobThresholdsComponent, MobStateComponent, DamageableComponent, SpriteComponent>();
while (query.MoveNext(out var uid,
out var mobThresholdsComponent,
return (0, true);
}
- public static Color GetProgressColor(float progress, bool crit)
+ public Color GetProgressColor(float progress, bool crit)
{
- if (progress >= 1.0f)
- {
- return SeaBlue;
- }
-
- if (!crit)
- {
- switch (progress)
- {
- case > 0.90F:
- return SeaBlue;
- case > 0.50F:
- return Violet;
- case > 0.15F:
- return Ruber;
- }
- }
+ if (crit)
+ progress = 0;
- return VividGamboge;
+ return _progressColor.GetProgressColor(progress);
}
}
using System.Numerics;
-using Content.Client.DoAfter;
+using Content.Client.UserInterface.Systems;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
{
public float Progress;
+ private readonly ProgressColorSystem _progressColor = IoCManager.Resolve<IEntityManager>().System<ProgressColorSystem>();
+
protected override void Draw(DrawingHandleScreen handle)
{
var dims = Texture != null ? GetDrawDimensions(Texture) : UIBox2.FromDimensions(Vector2.Zero, PixelSize);
dims.Top = Math.Max(dims.Bottom - dims.Bottom * Progress,0);
- handle.DrawRect(dims, DoAfterOverlay.GetProgressColor(Progress));
+ handle.DrawRect(dims, _progressColor.GetProgressColor(Progress));
base.Draw(handle);
}
--- /dev/null
+using Content.Shared.CCVar;
+using Robust.Shared.Configuration;
+
+namespace Content.Client.UserInterface.Systems;
+
+/// <summary>
+/// This system handles getting an interpolated color based on the value of a cvar.
+/// </summary>
+public sealed class ProgressColorSystem : EntitySystem
+{
+ [Dependency] private readonly IConfigurationManager _configuration = default!;
+
+ private bool _colorBlindFriendly;
+
+ private static readonly Color[] Plasma =
+ {
+ new(240, 249, 33),
+ new(248, 149, 64),
+ new(204, 71, 120),
+ new(126, 3, 168),
+ new(13, 8, 135)
+ };
+
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ Subs.CVar(_configuration, CCVars.AccessibilityColorblindFriendly, OnColorBlindFriendlyChanged, true);
+ }
+
+ private void OnColorBlindFriendlyChanged(bool value, in CVarChangeInfo info)
+ {
+ _colorBlindFriendly = value;
+ }
+
+ public Color GetProgressColor(float progress)
+ {
+ if (!_colorBlindFriendly)
+ {
+ if (progress >= 1.0f)
+ {
+ return new Color(0f, 1f, 0f);
+ }
+
+ // lerp
+ var hue = 5f / 18f * progress;
+ return Color.FromHsv((hue, 1f, 0.75f, 1f));
+ }
+
+ return InterpolateColorGaussian(Plasma, progress);
+ }
+
+ /// <summary>
+ /// Interpolates between multiple colors based on a gaussian distribution.
+ /// Taken from https://stackoverflow.com/a/26103117
+ /// </summary>
+ public static Color InterpolateColorGaussian(Color[] colors, double x)
+ {
+ double r = 0.0, g = 0.0, b = 0.0;
+ var total = 0f;
+ var step = 1.0 / (colors.Length - 1);
+ var mu = 0.0;
+ const double sigma2 = 0.035;
+
+ foreach(var color in colors)
+ {
+ var percent = Math.Exp(-(x - mu) * (x - mu) / (2.0 * sigma2)) / Math.Sqrt(2.0 * Math.PI * sigma2);
+ total += (float) percent;
+ mu += step;
+
+ r += color.R * percent;
+ g += color.G * percent;
+ b += color.B * percent;
+ }
+
+ return new Color((float) r / total, (float) g / total, (float) b / total);
+ }
+}
public static readonly CVarDef<float> ScreenShakeIntensity =
CVarDef.Create("accessibility.screen_shake_intensity", 1f, CVar.CLIENTONLY | CVar.ARCHIVE);
+ /// <summary>
+ /// A generic toggle for various visual effects that are color sensitive.
+ /// As of 2/16/24, only applies to progress bar colors.
+ /// </summary>
+ public static readonly CVarDef<bool> AccessibilityColorblindFriendly =
+ CVarDef.Create("accessibility.colorblind_friendly", false, CVar.CLIENTONLY | CVar.ARCHIVE);
+
/*
* CHAT
*/
ui-options-fancy-speech = Show names in speech bubbles
ui-options-fancy-name-background = Add background to speech bubble names
ui-options-enable-color-name = Add colors to character names
+ui-options-colorblind-friendly = Colorblind friendly mode
ui-options-reduced-motion = Reduce motion of visual effects
ui-options-screen-shake-intensity = Screen shake intensity
ui-options-screen-shake-percent = { TOSTRING($intensity, "P0") }