* do_after Ports (most of) do_after from SS13. Callers are expected to await the DoAfter task from the DoAfterSystem. I had a dummy component for in-game testing which I removed for the PR so nothing in game uses do_after at the moment. Currently only the movement cancellation is predicted client-side. * Minor do_after doc cleanup * do_the_shuffle Fix nullable build errors. * The last nullable * Implement NeedHand Thanks zum. * nullable dereference * Adjust the system query Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
136 lines
3.9 KiB
C#
136 lines
3.9 KiB
C#
#nullable enable
|
|
using System;
|
|
using Robust.Client.Graphics.Drawing;
|
|
using Robust.Client.Graphics.Shaders;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Shared.Interfaces.Timing;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Client.GameObjects.EntitySystems.DoAfter
|
|
{
|
|
public sealed class DoAfterBar : Control
|
|
{
|
|
private IGameTiming _gameTiming = default!;
|
|
|
|
private ShaderInstance _shader;
|
|
|
|
/// <summary>
|
|
/// Set from 0.0f to 1.0f to reflect bar progress
|
|
/// </summary>
|
|
public float Ratio
|
|
{
|
|
get => _ratio;
|
|
set => _ratio = value;
|
|
}
|
|
|
|
private float _ratio = 1.0f;
|
|
|
|
/// <summary>
|
|
/// Flash red until removed
|
|
/// </summary>
|
|
public bool Cancelled
|
|
{
|
|
get => _cancelled;
|
|
set
|
|
{
|
|
if (_cancelled == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_cancelled = value;
|
|
if (_cancelled)
|
|
{
|
|
_gameTiming = IoCManager.Resolve<IGameTiming>();
|
|
_lastFlash = _gameTiming.CurTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool _cancelled;
|
|
|
|
/// <summary>
|
|
/// Is the cancellation bar red?
|
|
/// </summary>
|
|
private bool _flash = true;
|
|
|
|
/// <summary>
|
|
/// Last time we swapped the flash.
|
|
/// </summary>
|
|
private TimeSpan _lastFlash;
|
|
|
|
/// <summary>
|
|
/// How long each cancellation bar flash lasts in seconds.
|
|
/// </summary>
|
|
private const float FlashTime = 0.125f;
|
|
|
|
private const int XPixelDiff = 20 * DoAfterBarScale;
|
|
|
|
public const byte DoAfterBarScale = 2;
|
|
private static readonly Color StartColor = new Color(0.8f, 0.0f, 0.2f);
|
|
private static readonly Color EndColor = new Color(0.2f, 0.4f, 1.0f);
|
|
|
|
public DoAfterBar()
|
|
{
|
|
IoCManager.InjectDependencies(this);
|
|
_shader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>("unshaded").Instance();
|
|
}
|
|
|
|
protected override void FrameUpdate(FrameEventArgs args)
|
|
{
|
|
base.FrameUpdate(args);
|
|
if (Cancelled)
|
|
{
|
|
if ((_gameTiming.CurTime - _lastFlash).TotalSeconds > FlashTime)
|
|
{
|
|
_lastFlash = _gameTiming.CurTime;
|
|
_flash = !_flash;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void Draw(DrawingHandleScreen handle)
|
|
{
|
|
base.Draw(handle);
|
|
|
|
Color color;
|
|
|
|
if (Cancelled)
|
|
{
|
|
if ((_gameTiming.CurTime - _lastFlash).TotalSeconds > FlashTime)
|
|
{
|
|
_lastFlash = _gameTiming.CurTime;
|
|
_flash = !_flash;
|
|
}
|
|
|
|
color = new Color(1.0f, 0.0f, 0.0f, _flash ? 1.0f : 0.0f);
|
|
}
|
|
else if (Ratio >= 1.0f)
|
|
{
|
|
color = new Color(0.92f, 0.77f, 0.34f);
|
|
}
|
|
else
|
|
{
|
|
// lerp
|
|
color = new Color(
|
|
StartColor.R + (EndColor.R - StartColor.R) * Ratio,
|
|
StartColor.G + (EndColor.G - StartColor.G) * Ratio,
|
|
StartColor.B + (EndColor.B - StartColor.B) * Ratio,
|
|
StartColor.A);
|
|
}
|
|
|
|
handle.UseShader(_shader);
|
|
// If you want to make this less hard-coded be my guest
|
|
var leftOffset = 2 * DoAfterBarScale;
|
|
var box = new UIBox2i(
|
|
leftOffset,
|
|
-2 + 2 * DoAfterBarScale,
|
|
leftOffset + (int) (XPixelDiff * Ratio),
|
|
-2);
|
|
handle.DrawRect(box, color);
|
|
}
|
|
}
|
|
} |