Files

141 lines
5.3 KiB
C#

using System;
using HSUI.Helpers;
using Dalamud.Bindings.ImGui;
using System.Collections.Generic;
using System.Numerics;
using HSUI.Config;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
namespace HSUI.Interface.GeneralElements
{
public class MouseGCDIndicatorHud : DraggableHudElement, IHudElementWithActor, IHudElementWithVisibilityConfig
{
private MouseGCDIndicatorConfig Config => (MouseGCDIndicatorConfig)_config;
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
public IGameObject? Actor { get; set; } = null;
private float _lastTotalCastTime = 0;
public MouseGCDIndicatorHud(MouseGCDIndicatorConfig config, string displayName) : base(config, displayName) { }
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
{
return (new List<Vector2>(), new List<Vector2>());
}
protected override void DrawDraggableArea(Vector2 origin)
{
return;
}
public override void DrawChildren(Vector2 origin)
{
if (!Config.Enabled || Actor == null || Actor is not IPlayerCharacter)
{
return;
}
GCDHelper.GetGCDInfo((IPlayerCharacter)Actor, out var elapsed, out var total);
if (!Config.AlwaysShow && total == 0)
{
_lastTotalCastTime = 0;
return;
}
if (_lastTotalCastTime == 0 && Utils.IsActorCasting(Actor))
{
_lastTotalCastTime = ((IBattleChara)Actor).TotalCastTime;
}
var scale = elapsed / total;
if (scale <= 0)
{
_lastTotalCastTime = 0;
return;
}
bool instantGCDsOnly = Config.InstantGCDsOnly && _lastTotalCastTime != 0;
bool thresholdGCDs = Config.LimitGCDThreshold && _lastTotalCastTime > Config.GCDThreshold;
if (instantGCDsOnly || thresholdGCDs)
{
if (Config.AlwaysShow)
{
elapsed = 0;
total = 0;
}
else
{
return;
}
}
Vector2 center = ImGui.GetMousePos() + Config.CursorCenterOffset;
AddDrawAction(_config.StrataLevel, () =>
{
DrawCircularIndicator(center, Config.CircleRadius, elapsed, total);
});
}
private void DrawCircularIndicator(Vector2 position, float radius, float current, float total)
{
total = Config.AlwaysShow && total == 0 ? 1 : total;
current = Config.AlwaysShow && current == 0 ? total : current;
var size = new Vector2(radius * 2);
DrawHelper.DrawInWindow(ID, position - size / 2, size, false, (drawList) =>
{
current = Math.Min(current, total);
const int segments = 100;
const float queueTime = 0.5f;
float startAngle = 0f;
float endAngle = 2f * (float)Math.PI;
float offset = (float)(-Math.PI / 2f + (Config.CircleStartAngle * (Math.PI / 180f)));
if (Config.RotateCCW)
{
startAngle *= -1;
endAngle *= -1;
}
if (Config.AlwaysShow && current == total)
{
drawList.PathArcTo(position, radius, startAngle + offset, endAngle + offset, segments);
drawList.PathStroke(Config.FillColor.Base, ImDrawFlags.None, Config.CircleThickness);
}
else
{
float progressAngle = Math.Min(current, total - (Config.ShowGCDQueueIndicator ? queueTime : 0f)) / total * endAngle;
drawList.PathArcTo(position, radius, startAngle + offset, progressAngle + offset, segments);
drawList.PathStroke(Config.FillColor.Base, ImDrawFlags.None, Config.CircleThickness);
if (Config.ShowGCDQueueIndicator && current > total - queueTime)
{
float oldAngle = progressAngle - 0.0003f * total * endAngle;
progressAngle = current / total * endAngle;
drawList.PathArcTo(position, radius, oldAngle + offset, progressAngle + offset, segments);
drawList.PathStroke(Config.QueueColor.Base, ImDrawFlags.None, Config.CircleThickness);
}
drawList.PathArcTo(position, radius, progressAngle + offset, endAngle + offset, segments);
drawList.PathStroke(Config.BackgroundColor.Base, ImDrawFlags.None, Config.CircleThickness);
}
if (Config.ShowBorder)
{
drawList.PathArcTo(position, radius - Config.CircleThickness / 2f, 0, endAngle, segments);
drawList.PathStroke(0xFF000000, ImDrawFlags.None, 1);
drawList.PathArcTo(position, radius + Config.CircleThickness / 2f, 0, endAngle, segments);
drawList.PathStroke(0xFF000000, ImDrawFlags.None, 1);
}
});
}
}
}