Files
HSUI/Interface/EnemyList/EnemyListHud.cs

429 lines
18 KiB
C#

using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface.Textures.TextureWraps;
using HSUI.Config;
using HSUI.Enums;
using HSUI.Helpers;
using HSUI.Interface.Bars;
using HSUI.Interface.GeneralElements;
using HSUI.Interface.StatusEffects;
using Dalamud.Bindings.ImGui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace HSUI.Interface.EnemyList
{
public class EnemyListHud : DraggableHudElement, IHudElementWithMouseOver, IHudElementWithPreview
{
private EnemyListConfig Config => (EnemyListConfig)_config;
private EnemyListConfigs Configs;
private EnemyListHelper _helper = new EnemyListHelper();
private List<SmoothHPHelper> _smoothHPHelpers = new List<SmoothHPHelper>();
private const int MaxEnemyCount = 8;
private List<float> _previewValues = new List<float>(MaxEnemyCount);
private bool _wasHovering = false;
private LabelHud _nameLabelHud;
private LabelHud _healthLabelHud;
private LabelHud _orderLabelHud;
private List<EnemyListCastbarHud> _castbarHud;
private StatusEffectsListHud _buffsListHud;
private StatusEffectsListHud _debuffsListHud;
private IDalamudTextureWrap? _iconsTexture => TexturesHelper.GetTextureFromPath("ui/uld/enemylist_hr1.tex");
public EnemyListHud(EnemyListConfig config, string displayName) : base(config, displayName)
{
Configs = EnemyListConfigs.GetConfigs();
config.ValueChangeEvent += OnConfigPropertyChanged;
_nameLabelHud = new LabelHud(Configs.HealthBar.NameLabel);
_healthLabelHud = new LabelHud(Configs.HealthBar.HealthLabel);
_orderLabelHud = new LabelHud(Configs.HealthBar.OrderLabel);
_castbarHud = new List<EnemyListCastbarHud>();
_buffsListHud = new StatusEffectsListHud(Configs.Buffs);
_debuffsListHud = new StatusEffectsListHud(Configs.Debuffs);
for (int i = 0; i < MaxEnemyCount; i++)
{
_smoothHPHelpers.Add(new SmoothHPHelper());
_castbarHud.Add(new EnemyListCastbarHud(Configs.CastBar));
}
UpdatePreview();
}
protected override void InternalDispose()
{
_config.ValueChangeEvent -= OnConfigPropertyChanged;
}
private void OnConfigPropertyChanged(object sender, OnChangeBaseArgs args)
{
if (args.PropertyName == "Preview")
{
UpdatePreview();
}
}
private void UpdatePreview()
{
_previewValues.Clear();
if (!Config.Preview) { return; }
Random RNG = new Random((int)ImGui.GetTime());
for (int i = 0; i < MaxEnemyCount; i++)
{
_previewValues.Add(RNG.Next(0, 101) / 100f);
}
}
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
{
Vector2 size = new Vector2(Configs.HealthBar.Size.X, MaxEnemyCount * Configs.HealthBar.Size.Y + (MaxEnemyCount - 1) * Config.VerticalPadding);
Vector2 pos = Config.GrowthDirection == EnemyListGrowthDirection.Down ? Config.Position : Config.Position - new Vector2(0, size.Y);
return (new List<Vector2>() { pos + size / 2f }, new List<Vector2>() { size });
}
public void StopPreview()
{
Config.Preview = false;
foreach (EnemyListCastbarHud castbar in _castbarHud)
{
castbar.StopPreview();
}
_buffsListHud.StopPreview();
_debuffsListHud.StopPreview();
Configs.HealthBar.MouseoverAreaConfig.Preview = false;
Configs.SignIcon.Preview = false;
}
public void StopMouseover()
{
if (_wasHovering)
{
InputsHelper.Instance.ClearTarget();
_wasHovering = false;
}
}
public override void DrawChildren(Vector2 origin)
{
if (!Config.Enabled) { return; }
_helper.Update();
int count = Math.Min(MaxEnemyCount, Config.Preview ? MaxEnemyCount : _helper.EnemyCount);
uint fakeMaxHp = 100000;
ICharacter? mouseoverTarget = null;
bool hovered = false;
for (int i = 0; i < count; i++)
{
// hp bar
ICharacter? character = Config.Preview ? null : Plugin.ObjectTable.SearchById((uint)_helper.EnemiesData.ElementAt(i).EntityId) as ICharacter;
uint currentHp = Config.Preview ? (uint)(_previewValues[i] * fakeMaxHp) : character?.CurrentHp ?? fakeMaxHp;
uint maxHp = Config.Preview ? fakeMaxHp : character?.MaxHp ?? fakeMaxHp;
int enmityLevel = Config.Preview ? Math.Max(4, i + 1) : _helper.EnemiesData.ElementAt(i).EnmityLevel;
if (Configs.HealthBar.SmoothHealthConfig.Enabled)
{
currentHp = _smoothHPHelpers[i].GetNextHp((int)currentHp, (int)maxHp, Configs.HealthBar.SmoothHealthConfig.Velocity);
}
int direction = Config.GrowthDirection == EnemyListGrowthDirection.Down ? 1 : -1;
float y = Config.Position.Y + i * direction * Configs.HealthBar.Size.Y + i * direction * Config.VerticalPadding;
Vector2 pos = new Vector2(Config.Position.X, y);
PluginConfigColor fillColor = GetColor(character, currentHp, maxHp);
PluginConfigColor bgColor = Configs.HealthBar.BackgroundColor;
if (Configs.HealthBar.RangeConfig.Enabled)
{
fillColor = GetDistanceColor(character, fillColor);
bgColor = GetDistanceColor(character, bgColor);
}
Rect background = new Rect(pos, Configs.HealthBar.Size, bgColor);
PluginConfigColor borderColor = GetBorderColor(character, enmityLevel);
Rect healthFill = BarUtilities.GetFillRect(pos, Configs.HealthBar.Size, Configs.HealthBar.FillDirection, fillColor, currentHp, maxHp);
BarHud bar = new BarHud(
Configs.HealthBar.ID + $"_{i}",
Configs.HealthBar.DrawBorder,
borderColor,
GetBorderThickness(character),
DrawAnchor.TopLeft,
current: currentHp,
max: maxHp,
shadowConfig: Configs.HealthBar.ShadowConfig,
barTextureName: Configs.HealthBar.BarTextureName,
barTextureDrawMode: Configs.HealthBar.BarTextureDrawMode
);
bar.NeedsInputs = true;
bar.SetBackground(background);
bar.AddForegrounds(healthFill);
if (Configs.HealthBar.Colors.UseMissingHealthBar)
{
Vector2 healthMissingSize = Configs.HealthBar.Size - BarUtilities.GetFillDirectionOffset(healthFill.Size, Configs.HealthBar.FillDirection);
Vector2 healthMissingPos = Configs.HealthBar.FillDirection.IsInverted() ? pos : pos + BarUtilities.GetFillDirectionOffset(healthFill.Size, Configs.HealthBar.FillDirection);
PluginConfigColor? color = Configs.HealthBar.RangeConfig.Enabled ? GetDistanceColor(character, Configs.HealthBar.Colors.HealthMissingColor) : Configs.HealthBar.Colors.HealthMissingColor;
bar.AddForegrounds(new Rect(healthMissingPos, healthMissingSize, color));
}
// highlight
var (areaStart, areaEnd) = Configs.HealthBar.MouseoverAreaConfig.GetArea(origin + pos, Configs.HealthBar.Size);
bool isHovering = character != null && ImGui.IsMouseHoveringRect(areaStart, areaEnd);
bool isSoftTarget = character != null && character.EntityId == Plugin.TargetManager.SoftTarget?.EntityId;
if (isHovering || isSoftTarget)
{
if (Configs.HealthBar.Colors.ShowHighlight)
{
Rect highlight = new Rect(pos, Configs.HealthBar.Size, Configs.HealthBar.Colors.HighlightColor);
bar.AddForegrounds(highlight);
}
mouseoverTarget = character;
hovered = isHovering;
}
AddDrawActions(bar.GetDrawActions(origin, Configs.HealthBar.StrataLevel));
// mouseover area
BarHud? mouseoverAreaBar = Configs.HealthBar.MouseoverAreaConfig.GetBar(
pos,
Configs.HealthBar.Size,
Configs.HealthBar.ID + "_mouseoverArea"
);
if (mouseoverAreaBar != null)
{
AddDrawActions(mouseoverAreaBar.GetDrawActions(origin, StrataLevel.HIGHEST));
}
// enmity icon
if (_iconsTexture != null && Configs.EnmityIcon.Enabled)
{
var parentPos = Utils.GetAnchoredPosition(origin + pos, -Configs.HealthBar.Size, Configs.EnmityIcon.HealthBarAnchor);
var iconPos = Utils.GetAnchoredPosition(parentPos + Configs.EnmityIcon.Position, Configs.EnmityIcon.Size, Configs.EnmityIcon.Anchor);
int enmityIndex = Config.Preview ? Math.Min(3, i) : _helper.EnemiesData.ElementAt(i).EnmityLevel - 1;
AddDrawAction(Configs.EnmityIcon.StrataLevel, () =>
{
DrawHelper.DrawInWindow(ID + "_enmityIcon", iconPos, Configs.EnmityIcon.Size, false, (drawList) =>
{
float w = 48f / _iconsTexture.Width;
float h = 48f / _iconsTexture.Height;
Vector2 uv0 = new Vector2(w * enmityIndex, 0.48f);
Vector2 uv1 = new Vector2(w * (enmityIndex + 1), 0.48f + h);
drawList.AddImage(_iconsTexture.Handle, iconPos, iconPos + Configs.EnmityIcon.Size, uv0, uv1);
});
});
}
// sign icon
uint? signIconId = null;
if (Configs.SignIcon.Enabled)
{
signIconId = Configs.SignIcon.IconID(character);
if (signIconId.HasValue)
{
var parentPos = Utils.GetAnchoredPosition(origin + pos, -Configs.HealthBar.Size, Configs.SignIcon.HealthBarAnchor);
var iconPos = Utils.GetAnchoredPosition(parentPos + Configs.SignIcon.Position, Configs.SignIcon.Size, Configs.SignIcon.Anchor);
AddDrawAction(Configs.SignIcon.StrataLevel, () =>
{
DrawHelper.DrawInWindow(ID + "_signIcon", iconPos, Configs.SignIcon.Size, false, (drawList) =>
{
DrawHelper.DrawIcon(signIconId.Value, iconPos, Configs.SignIcon.Size, false, drawList);
});
});
}
}
// labels
string? name = Config.Preview ? "Fake Name" : null;
AddDrawAction(Configs.HealthBar.NameLabel.StrataLevel, () =>
{
_nameLabelHud.Draw(origin + pos, Configs.HealthBar.Size, character, name, currentHp, maxHp);
});
AddDrawAction(Configs.HealthBar.HealthLabel.StrataLevel, () =>
{
_healthLabelHud.Draw(origin + pos, Configs.HealthBar.Size, character, name, currentHp, maxHp);
});
if (!signIconId.HasValue || !Configs.SignIcon.ReplaceOrderLabel)
{
int letter = i;
if (!Config.Preview && _helper.EnemiesData.ElementAt(i).LetterIndex.HasValue)
{
letter = _helper.EnemiesData.ElementAt(i).LetterIndex!.Value;
}
string str = char.ConvertFromUtf32(0xE071 + letter).ToString();
AddDrawAction(Configs.HealthBar.OrderLabel.StrataLevel, () =>
{
Configs.HealthBar.OrderLabel.SetText(str);
_orderLabelHud.Draw(origin + pos, Configs.HealthBar.Size);
});
}
// buffs / debuffs
var buffsPos = Utils.GetAnchoredPosition(origin + pos, -Configs.HealthBar.Size, Configs.Buffs.HealthBarAnchor);
AddDrawAction(Configs.Buffs.StrataLevel, () =>
{
_buffsListHud.Actor = character;
_buffsListHud.PrepareForDraw(buffsPos);
_buffsListHud.Draw(buffsPos);
});
var debuffsPos = Utils.GetAnchoredPosition(origin + pos, -Configs.HealthBar.Size, Configs.Debuffs.HealthBarAnchor);
AddDrawAction(Configs.Debuffs.StrataLevel, () =>
{
_debuffsListHud.Actor = character;
_debuffsListHud.PrepareForDraw(debuffsPos);
_debuffsListHud.Draw(debuffsPos);
});
// castbar
EnemyListCastbarHud castbar = _castbarHud[i];
castbar.EnemyListIndex = i;
var castbarPos = Utils.GetAnchoredPosition(origin + pos, -Configs.HealthBar.Size, Configs.CastBar.HealthBarAnchor);
AddDrawAction(Configs.CastBar.StrataLevel, () =>
{
castbar.Actor = character;
castbar.PrepareForDraw(castbarPos);
castbar.Draw(castbarPos);
});
}
// mouseover
bool ignoreMouseover = Configs.HealthBar.MouseoverAreaConfig.Enabled && Configs.HealthBar.MouseoverAreaConfig.Ignore;
if (hovered && mouseoverTarget != null)
{
_wasHovering = true;
InputsHelper.Instance.SetTarget(mouseoverTarget, ignoreMouseover);
// left click
if (InputsHelper.Instance.LeftButtonClicked)
{
Plugin.TargetManager.Target = mouseoverTarget;
}
}
else if (_wasHovering)
{
InputsHelper.Instance.ClearTarget();
_wasHovering = false;
}
}
private PluginConfigColor GetColor(ICharacter? character, uint currentHp = 0, uint maxHp = 0)
{
if (Configs.HealthBar.Colors.ColorByHealth.Enabled && (character != null || Config.Preview))
{
var scale = (float)currentHp / Math.Max(1, maxHp);
return ColorUtils.GetColorByScale(scale, Configs.HealthBar.Colors.ColorByHealth);
}
return Configs.HealthBar.FillColor;
}
private PluginConfigColor GetBorderColor(ICharacter? character, int enmityLevel)
{
IGameObject? target = Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target;
if (character != null && target != null && character.EntityId == target.EntityId)
{
return Configs.HealthBar.Colors.TargetBordercolor;
}
if (!Configs.HealthBar.Colors.ShowEnmityBorderColors)
{
return Configs.HealthBar.BorderColor;
}
return enmityLevel switch
{
>= 3 => Configs.HealthBar.Colors.EnmityLeaderBorderColor,
>= 1 => Configs.HealthBar.Colors.EnmitySecondBorderColor,
_ => Configs.HealthBar.BorderColor
};
}
private int GetBorderThickness(ICharacter? character)
{
IGameObject? target = Plugin.TargetManager.Target;
if (character != null && character == target)
{
return Configs.HealthBar.Colors.TargetBorderThickness;
}
return Configs.HealthBar.BorderThickness;
}
private PluginConfigColor GetDistanceColor(ICharacter? character, PluginConfigColor color)
{
byte distance = character != null ? character.YalmDistanceX : byte.MaxValue;
float currentAlpha = color.Vector.W * 100f;
float alpha = Configs.HealthBar.RangeConfig.AlphaForDistance(distance, currentAlpha) / 100f;
return color.WithAlpha(alpha);
}
}
#region utils
public struct EnemyListConfigs
{
public EnemyListHealthBarConfig HealthBar;
public EnemyListEnmityIconConfig EnmityIcon;
public EnemyListSignIconConfig SignIcon;
public EnemyListCastbarConfig CastBar;
public EnemyListBuffsConfig Buffs;
public EnemyListDebuffsConfig Debuffs;
public EnemyListConfigs(
EnemyListHealthBarConfig healthBar,
EnemyListEnmityIconConfig enmityIcon,
EnemyListSignIconConfig signIcon,
EnemyListCastbarConfig castBar,
EnemyListBuffsConfig buffs,
EnemyListDebuffsConfig debuffs)
{
HealthBar = healthBar;
EnmityIcon = enmityIcon;
SignIcon = signIcon;
CastBar = castBar;
Buffs = buffs;
Debuffs = debuffs;
}
public static EnemyListConfigs GetConfigs()
{
return new EnemyListConfigs(
ConfigurationManager.Instance.GetConfigObject<EnemyListHealthBarConfig>(),
ConfigurationManager.Instance.GetConfigObject<EnemyListEnmityIconConfig>(),
ConfigurationManager.Instance.GetConfigObject<EnemyListSignIconConfig>(),
ConfigurationManager.Instance.GetConfigObject<EnemyListCastbarConfig>(),
ConfigurationManager.Instance.GetConfigObject<EnemyListBuffsConfig>(),
ConfigurationManager.Instance.GetConfigObject<EnemyListDebuffsConfig>()
);
}
}
#endregion
}