Initial release: HSUI v1.0.0.0 - HUD replacement with configurable hotbars
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using HSUI.Interface.GeneralElements;
|
||||
using HSUI.Interface.StatusEffects;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.EnemyList
|
||||
{
|
||||
public enum EnemyListGrowthDirection
|
||||
{
|
||||
Down = 0,
|
||||
Up
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("General", 0)]
|
||||
public class EnemyListConfig : MovablePluginConfigObject
|
||||
{
|
||||
public new static EnemyListConfig DefaultConfig()
|
||||
{
|
||||
var config = new EnemyListConfig();
|
||||
Vector2 screenSize = ImGui.GetMainViewport().Size;
|
||||
config.Position = new Vector2(screenSize.X * 0.2f, -screenSize.Y * 0.2f);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
[Checkbox("Preview", isMonitored = true)]
|
||||
[Order(4)]
|
||||
public bool Preview = false;
|
||||
|
||||
[Combo("Growth Direction", "Down", "Up", spacing = true)]
|
||||
[Order(20)]
|
||||
public EnemyListGrowthDirection GrowthDirection = EnemyListGrowthDirection.Down;
|
||||
|
||||
[DragInt("Vertical Padding", min = 0, max = 500)]
|
||||
[Order(25)]
|
||||
public int VerticalPadding = 10;
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[DisableParentSettings("Position", "Anchor", "HideWhenInactive")]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("Health Bar", 0)]
|
||||
public class EnemyListHealthBarConfig : BarConfig
|
||||
{
|
||||
[NestedConfig("Name Label", 70)]
|
||||
public EditableLabelConfig NameLabel = new EditableLabelConfig(new Vector2(-5, 12), "[name]", DrawAnchor.TopRight, DrawAnchor.BottomRight);
|
||||
|
||||
[NestedConfig("Health Label", 80)]
|
||||
public EditableLabelConfig HealthLabel = new EditableLabelConfig(new Vector2(30, 0), "[health:percent]%", DrawAnchor.Left, DrawAnchor.Left);
|
||||
|
||||
[NestedConfig("Order Label", 90)]
|
||||
public DefaultFontLabelConfig OrderLabel = new DefaultFontLabelConfig(new Vector2(5, 0), "", DrawAnchor.Left, DrawAnchor.Left);
|
||||
|
||||
[NestedConfig("Colors", 100)]
|
||||
public EnemyListHealthBarColorsConfig Colors = new EnemyListHealthBarColorsConfig();
|
||||
|
||||
[NestedConfig("Change Alpha Based on Range", 110)]
|
||||
public EnemyListRangeConfig RangeConfig = new EnemyListRangeConfig();
|
||||
|
||||
[NestedConfig("Use Smooth Transitions", 120)]
|
||||
public SmoothHealthConfig SmoothHealthConfig = new SmoothHealthConfig();
|
||||
|
||||
[NestedConfig("Custom Mouseover Area", 130)]
|
||||
public MouseoverAreaConfig MouseoverAreaConfig = new MouseoverAreaConfig();
|
||||
|
||||
public new static EnemyListHealthBarConfig DefaultConfig()
|
||||
{
|
||||
Vector2 size = new Vector2(180, 40);
|
||||
|
||||
var config = new EnemyListHealthBarConfig(Vector2.Zero, size, new PluginConfigColor(new(233f / 255f, 4f / 255f, 4f / 255f, 100f / 100f)));
|
||||
config.Colors.ColorByHealth.Enabled = false;
|
||||
|
||||
config.NameLabel.FontID = FontsConfig.DefaultMediumFontKey;
|
||||
config.HealthLabel.FontID = FontsConfig.DefaultMediumFontKey;
|
||||
|
||||
config.MouseoverAreaConfig.Enabled = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public EnemyListHealthBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor, BarDirection fillDirection = BarDirection.Right)
|
||||
: base(position, size, fillColor, fillDirection)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Exportable(false)]
|
||||
public class EnemyListHealthBarColorsConfig : PluginConfigObject
|
||||
{
|
||||
[NestedConfig("Color Based On Health Value", 30, collapsingHeader = false)]
|
||||
public ColorByHealthValueConfig ColorByHealth = new ColorByHealthValueConfig();
|
||||
|
||||
[Checkbox("Highlight When Hovering With Cursor Or Soft Targeting", spacing = true)]
|
||||
[Order(40)]
|
||||
public bool ShowHighlight = true;
|
||||
|
||||
[ColorEdit4("Highlight Color")]
|
||||
[Order(41, collapseWith = nameof(ShowHighlight))]
|
||||
public PluginConfigColor HighlightColor = new PluginConfigColor(new Vector4(255f / 255f, 255f / 255f, 255f / 255f, 5f / 100f));
|
||||
|
||||
[Checkbox("Missing Health Color", spacing = true)]
|
||||
[Order(45)]
|
||||
public bool UseMissingHealthBar = false;
|
||||
|
||||
[ColorEdit4("Color" + "##MissingHealth")]
|
||||
[Order(46, collapseWith = nameof(UseMissingHealthBar))]
|
||||
public PluginConfigColor HealthMissingColor = new PluginConfigColor(new Vector4(255f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Target Border Color", spacing = true)]
|
||||
[Order(50)]
|
||||
public PluginConfigColor TargetBordercolor = new PluginConfigColor(new Vector4(255f / 255f, 255f / 255f, 255f / 255f, 100f / 100f));
|
||||
|
||||
[DragInt("Target Border Thickness", min = 1, max = 10)]
|
||||
[Order(51)]
|
||||
public int TargetBorderThickness = 1;
|
||||
|
||||
[Checkbox("Show Enmity Border Colors", spacing = true)]
|
||||
[Order(60)]
|
||||
public bool ShowEnmityBorderColors = true;
|
||||
|
||||
[ColorEdit4("Enmity Leader Color")]
|
||||
[Order(61, collapseWith = nameof(ShowEnmityBorderColors))]
|
||||
public PluginConfigColor EnmityLeaderBorderColor = new PluginConfigColor(new Vector4(255f / 255f, 40f / 255f, 40f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Enmity Close To Leader Color")]
|
||||
[Order(62, collapseWith = nameof(ShowEnmityBorderColors))]
|
||||
public PluginConfigColor EnmitySecondBorderColor = new PluginConfigColor(new Vector4(255f / 255f, 175f / 255f, 40f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class EnemyListRangeConfig : PluginConfigObject
|
||||
{
|
||||
[DragInt("Range (yalms)", min = 1, max = 500)]
|
||||
[Order(5)]
|
||||
public int Range = 30;
|
||||
|
||||
[DragFloat("Alpha", min = 1, max = 100)]
|
||||
[Order(10)]
|
||||
public float Alpha = 25;
|
||||
|
||||
|
||||
public float AlphaForDistance(int distance, float alpha = 100f)
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
return 100f;
|
||||
}
|
||||
|
||||
return distance > Range ? Alpha : alpha;
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("FrameAnchor")]
|
||||
[Exportable(false)]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("Enmity Icon", 0)]
|
||||
public class EnemyListEnmityIconConfig : IconConfig
|
||||
{
|
||||
[Anchor("Health Bar Anchor")]
|
||||
[Order(16)]
|
||||
public DrawAnchor HealthBarAnchor = DrawAnchor.TopLeft;
|
||||
|
||||
public new static EnemyListEnmityIconConfig DefaultConfig() =>
|
||||
new EnemyListEnmityIconConfig(new Vector2(5), new Vector2(24), DrawAnchor.Center, DrawAnchor.TopLeft);
|
||||
|
||||
public EnemyListEnmityIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
HealthBarAnchor = frameAnchor;
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("FrameAnchor")]
|
||||
[Exportable(false)]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("Sign Icon", 0)]
|
||||
public class EnemyListSignIconConfig : SignIconConfig
|
||||
{
|
||||
[Anchor("Health Bar Anchor")]
|
||||
[Order(16)]
|
||||
public DrawAnchor HealthBarAnchor = DrawAnchor.TopLeft;
|
||||
|
||||
[Checkbox("Replace Order Label", help = "When enabled and if the enemy has a sign assigned, the sign icon will be drawn instead of the order label.")]
|
||||
[Order(30)]
|
||||
public bool ReplaceOrderLabel = true;
|
||||
|
||||
public new static EnemyListSignIconConfig DefaultConfig() =>
|
||||
new EnemyListSignIconConfig(new Vector2(0), new Vector2(30), DrawAnchor.Center, DrawAnchor.Left);
|
||||
|
||||
public EnemyListSignIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
HealthBarAnchor = frameAnchor;
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("AnchorToUnitFrame", "UnitFrameAnchor", "HideWhenInactive", "FillDirection")]
|
||||
[Exportable(false)]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("Castbar", 0)]
|
||||
public class EnemyListCastbarConfig : TargetCastbarConfig
|
||||
{
|
||||
public new static EnemyListCastbarConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(180, 10);
|
||||
|
||||
var castNameConfig = new LabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
castNameConfig.FontID = FontsConfig.DefaultMediumFontKey;
|
||||
var castTimeConfig = new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right);
|
||||
castTimeConfig.Enabled = false;
|
||||
castTimeConfig.FontID = FontsConfig.DefaultMediumFontKey;
|
||||
castTimeConfig.NumberFormat = 1;
|
||||
|
||||
var config = new EnemyListCastbarConfig(Vector2.Zero, size, castNameConfig, castTimeConfig);
|
||||
config.HealthBarAnchor = DrawAnchor.Bottom;
|
||||
config.Anchor = DrawAnchor.Bottom;
|
||||
config.ShowIcon = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
[Anchor("Health Bar Anchor")]
|
||||
[Order(16)]
|
||||
public DrawAnchor HealthBarAnchor = DrawAnchor.BottomLeft;
|
||||
|
||||
public EnemyListCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, castNameConfig, castTimeConfig)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("Buffs", 0)]
|
||||
public class EnemyListBuffsConfig : EnemyListStatusEffectsListConfig
|
||||
{
|
||||
public new static EnemyListBuffsConfig DefaultConfig()
|
||||
{
|
||||
var durationConfig = new LabelConfig(new Vector2(0, -4), "", DrawAnchor.Bottom, DrawAnchor.Center);
|
||||
var stacksConfig = new LabelConfig(new Vector2(-3, 4), "", DrawAnchor.TopRight, DrawAnchor.Center);
|
||||
stacksConfig.Color = new(Vector4.UnitW);
|
||||
stacksConfig.OutlineColor = new(Vector4.One);
|
||||
|
||||
var iconConfig = new StatusEffectIconConfig(durationConfig, stacksConfig);
|
||||
iconConfig.DispellableBorderConfig.Enabled = false;
|
||||
iconConfig.Size = new Vector2(24, 24);
|
||||
|
||||
var pos = new Vector2(5, 8);
|
||||
var size = new Vector2(iconConfig.Size.X * 4 + 6, iconConfig.Size.Y);
|
||||
|
||||
var config = new EnemyListBuffsConfig(DrawAnchor.TopRight, pos, size, true, false, false, GrowthDirections.Right | GrowthDirections.Down, iconConfig);
|
||||
config.Limit = 4;
|
||||
config.ShowPermanentEffects = true;
|
||||
config.IconConfig.DispellableBorderConfig.Enabled = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public EnemyListBuffsConfig(DrawAnchor anchor, Vector2 position, Vector2 size, bool showBuffs, bool showDebuffs, bool showPermanentEffects,
|
||||
GrowthDirections growthDirections, StatusEffectIconConfig iconConfig)
|
||||
: base(anchor, position, size, showBuffs, showDebuffs, showPermanentEffects, growthDirections, iconConfig)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Enemy List", true)]
|
||||
[SubSection("Debuffs", 0)]
|
||||
public class EnemyListDebuffsConfig : EnemyListStatusEffectsListConfig
|
||||
{
|
||||
public new static EnemyListDebuffsConfig DefaultConfig()
|
||||
{
|
||||
var durationConfig = new LabelConfig(new Vector2(0, -4), "", DrawAnchor.Bottom, DrawAnchor.Center);
|
||||
var stacksConfig = new LabelConfig(new Vector2(-3, 4), "", DrawAnchor.TopRight, DrawAnchor.Center);
|
||||
stacksConfig.Color = new(Vector4.UnitW);
|
||||
stacksConfig.OutlineColor = new(Vector4.One);
|
||||
|
||||
var iconConfig = new StatusEffectIconConfig(durationConfig, stacksConfig);
|
||||
iconConfig.Size = new Vector2(24, 24);
|
||||
|
||||
var pos = new Vector2(-5, 8);
|
||||
var size = new Vector2(iconConfig.Size.X * 4 + 6, iconConfig.Size.Y);
|
||||
|
||||
var config = new EnemyListDebuffsConfig(DrawAnchor.TopLeft, pos, size, false, true, false, GrowthDirections.Left | GrowthDirections.Down, iconConfig);
|
||||
config.Limit = 4;
|
||||
config.ShowPermanentEffects = true;
|
||||
config.IconConfig.DispellableBorderConfig.Enabled = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public EnemyListDebuffsConfig(DrawAnchor anchor, Vector2 position, Vector2 size, bool showBuffs, bool showDebuffs, bool showPermanentEffects,
|
||||
GrowthDirections growthDirections, StatusEffectIconConfig iconConfig)
|
||||
: base(anchor, position, size, showBuffs, showDebuffs, showPermanentEffects, growthDirections, iconConfig)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class EnemyListStatusEffectsListConfig : StatusEffectsListConfig
|
||||
{
|
||||
[Anchor("Health Bar Anchor")]
|
||||
[Order(4)]
|
||||
public DrawAnchor HealthBarAnchor = DrawAnchor.BottomLeft;
|
||||
|
||||
public EnemyListStatusEffectsListConfig(DrawAnchor anchor, Vector2 position, Vector2 size, bool showBuffs, bool showDebuffs, bool showPermanentEffects,
|
||||
GrowthDirections growthDirections, StatusEffectIconConfig iconConfig)
|
||||
: base(position, size, showBuffs, showDebuffs, showPermanentEffects, growthDirections, iconConfig)
|
||||
{
|
||||
HealthBarAnchor = anchor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using Dalamud.Memory;
|
||||
using HSUI.Helpers;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Arrays;
|
||||
using StructsFramework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework;
|
||||
|
||||
namespace HSUI.Interface.EnemyList
|
||||
{
|
||||
public unsafe class EnemyListHelper
|
||||
{
|
||||
private List<EnemyListData> _enemiesData = new List<EnemyListData>();
|
||||
public IReadOnlyCollection<EnemyListData> EnemiesData => _enemiesData.AsReadOnly();
|
||||
public int EnemyCount => _enemiesData.Count;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_enemiesData.Clear();
|
||||
|
||||
var enemyListNumberInstance = EnemyListNumberArray.Instance();
|
||||
var enemyNumberArrayEnemies = enemyListNumberInstance->Enemies;
|
||||
int enemyCount = *(int*)((byte*)enemyListNumberInstance + 0x04);
|
||||
//TODO: Change it to the correct property when it lands in CS
|
||||
//int enemyCount = enemyListNumberInstance->Unk1;
|
||||
|
||||
if(enemyCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < enemyCount; i++)
|
||||
{
|
||||
int entityId = enemyNumberArrayEnemies[i].EntityId;
|
||||
int? letter = GetEnemyLetter(entityId, i);
|
||||
int enmityLevel = GetEnmityLevelForIndex(i);
|
||||
_enemiesData.Add(new EnemyListData(entityId, letter, enmityLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private int? GetEnemyLetter(int objectId, int index)
|
||||
{
|
||||
var enemyStringArrayMembers = EnemyListStringArray.Instance()->Members;
|
||||
if (enemyStringArrayMembers.IsEmpty || enemyStringArrayMembers.Length <= index)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string name = enemyStringArrayMembers[index].EnemyName;
|
||||
|
||||
bool isMarked = Utils.SignIconIDForObjectID((uint)objectId) != null;
|
||||
char letterSymbol = isMarked && name.Length > 1 ? name[2] : name[0];
|
||||
return letterSymbol - 57457;
|
||||
}
|
||||
|
||||
private int GetEnmityLevelForIndex(int index)
|
||||
{
|
||||
// gets enmity level by checking texture in enemy list addon
|
||||
|
||||
AtkUnitBase* enemyList = (AtkUnitBase*)Plugin.GameGui.GetAddonByName("_EnemyList", 1).Address;
|
||||
if (enemyList == null || enemyList->RootNode == null) { return 0; }
|
||||
|
||||
int id = index == 0 ? 2 : 20000 + index; // makes no sense but it is what it is (blame SE)
|
||||
AtkResNode* node = enemyList->GetNodeById((uint)id);
|
||||
if (node == null || node->GetComponent() == null) { return 0; }
|
||||
|
||||
AtkImageNode* imageNode = (AtkImageNode*)node->GetComponent()->UldManager.SearchNodeById(13);
|
||||
if (imageNode == null) { return 0; }
|
||||
|
||||
return Math.Min(4, imageNode->PartId + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public struct EnemyListData
|
||||
{
|
||||
public int EntityId;
|
||||
public int? LetterIndex;
|
||||
public int EnmityLevel;
|
||||
|
||||
public EnemyListData(int entityId, int? letterIndex, int enmityLevel)
|
||||
{
|
||||
EntityId = entityId;
|
||||
LetterIndex = letterIndex;
|
||||
EnmityLevel = enmityLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user