Initial release: HSUI v1.0.0.0 - HUD replacement with configurable hotbars
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,159 @@
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using Dalamud.Memory.Exceptions;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Disableable(false)]
|
||||
[Section("Customization")]
|
||||
[SubSection("Bar Textures", 0)]
|
||||
public class BarTexturesConfig : PluginConfigObject
|
||||
{
|
||||
public new static BarTexturesConfig DefaultConfig() { return new BarTexturesConfig(); }
|
||||
|
||||
public string BarTexturesPath = "C:\\";
|
||||
|
||||
[JsonIgnore] public string ValidatedBarTexturesPath => ValidatePath(BarTexturesPath);
|
||||
|
||||
[JsonIgnore] private int _inputBarTexture = 0;
|
||||
[JsonIgnore] private int _drawModeIndex = 0;
|
||||
[JsonIgnore] private Vector4 _color = new Vector4(229 / 255f, 57 / 255f, 57 / 255f, 1);
|
||||
[JsonIgnore] private PluginConfigColor _pluginConfigColor = PluginConfigColor.FromHex(0xFFE53939);
|
||||
[JsonIgnore] private FileDialogManager _fileDialogManager = new FileDialogManager();
|
||||
[JsonIgnore] private bool _applying = false;
|
||||
|
||||
private string ValidatePath(string path)
|
||||
{
|
||||
if (path.EndsWith("\\") || path.EndsWith("/"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return path + "\\";
|
||||
}
|
||||
|
||||
private void SelectFolder()
|
||||
{
|
||||
Action<bool, string> callback = (finished, path) =>
|
||||
{
|
||||
if (finished && path.Length > 0)
|
||||
{
|
||||
BarTexturesPath = path;
|
||||
BarTexturesManager.Instance?.ReloadTextures();
|
||||
}
|
||||
};
|
||||
|
||||
_fileDialogManager.OpenFolderDialog("Select Bar Textures Folder", callback);
|
||||
}
|
||||
|
||||
[ManualDraw]
|
||||
public bool Draw(ref bool changed)
|
||||
{
|
||||
if (BarTexturesManager.Instance == null) { return false; }
|
||||
|
||||
string[] textureNames = BarTexturesManager.Instance.BarTextureNames.ToArray();
|
||||
string[] drawModes = new string[] { "Stretch", "Repeat Horizontal", "Repeat Vertical", "Repeat" };
|
||||
|
||||
if (ImGui.BeginChild("Bar Textures", new Vector2(800, 400), false, ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
|
||||
{
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
ImGui.Text("Custom Bar Textures path");
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
if (ImGui.InputText("", ref BarTexturesPath, 200, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
changed = true;
|
||||
BarTexturesManager.Instance?.ReloadTextures();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button(FontAwesomeIcon.Folder.ToIconString(), new Vector2(0, 0)))
|
||||
{
|
||||
SelectFolder();
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
ImGui.Text("Preview");
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Combo("Bar Texture ##bar texture", ref _inputBarTexture, textureNames);
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Combo("Draw Mode", ref _drawModeIndex, drawModes);
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
if (ImGui.ColorEdit4("Color", ref _color))
|
||||
{
|
||||
_pluginConfigColor = new PluginConfigColor(_color);
|
||||
}
|
||||
|
||||
if (textureNames.Length > _inputBarTexture)
|
||||
{
|
||||
// draw preview
|
||||
ImGui.NewLine();
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
Vector2 pos = ImGui.GetWindowPos() + ImGui.GetCursorPos();
|
||||
Vector2 size = new Vector2(512, 64);
|
||||
ImDrawListPtr drawList = ImGui.GetWindowDrawList();
|
||||
|
||||
DrawHelper.DrawBarTexture(
|
||||
pos,
|
||||
size,
|
||||
_pluginConfigColor,
|
||||
textureNames[_inputBarTexture],
|
||||
(BarTextureDrawMode)_drawModeIndex,
|
||||
drawList
|
||||
);
|
||||
|
||||
ImGuiHelper.DrawSpacing(3);
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.Button("Apply to all bars", new Vector2(200, 30)))
|
||||
{
|
||||
_applying = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
_fileDialogManager.Draw();
|
||||
|
||||
if (_applying)
|
||||
{
|
||||
string[] lines = new string[] { "This will replace the Bar Texture", "and Draw Mode for ALL bars!", "THIS CAN'T BE UNDONE!", "Are you sure?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("Apply to ALL bars?", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
List<BarConfig> barConfigs = ConfigurationManager.Instance.GetObjects<BarConfig>();
|
||||
foreach (BarConfig barConfig in barConfigs)
|
||||
{
|
||||
barConfig.BarTextureName = textureNames[_inputBarTexture];
|
||||
barConfig.BarTextureDrawMode = (BarTextureDrawMode)_drawModeIndex;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_applying = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Section("Castbars")]
|
||||
[SubSection("Player", 0)]
|
||||
public class PlayerCastbarConfig : UnitFrameCastbarConfig
|
||||
{
|
||||
[Checkbox("Use Job Color", spacing = true)]
|
||||
[Order(19)]
|
||||
public bool UseJobColor = false;
|
||||
|
||||
[Checkbox("Slide Cast", spacing = true)]
|
||||
[Order(60)]
|
||||
public bool ShowSlideCast = true;
|
||||
|
||||
[DragInt("Time (milliseconds)", min = 0, max = 10000)]
|
||||
[Order(61, collapseWith = nameof(ShowSlideCast))]
|
||||
public int SlideCastTime = 500;
|
||||
|
||||
[ColorEdit4("Color ##SlidecastColor")]
|
||||
[Order(62, collapseWith = nameof(ShowSlideCast))]
|
||||
public PluginConfigColor SlideCastColor = new PluginConfigColor(new(190f / 255f, 28f / 255f, 57f / 255f, 100f / 100f));
|
||||
|
||||
public PlayerCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, castNameConfig, castTimeConfig)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new static PlayerCastbarConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(254, 24);
|
||||
var pos = new Vector2(0, HUDConstants.PlayerCastbarY);
|
||||
|
||||
var castNameConfig = new LabelConfig(new Vector2(5, 0), "", DrawAnchor.Left, DrawAnchor.Left);
|
||||
var castTimeConfig = new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right);
|
||||
castTimeConfig.NumberFormat = 1;
|
||||
|
||||
return new PlayerCastbarConfig(pos, size, castNameConfig, castTimeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
[Section("Castbars")]
|
||||
[SubSection("Target", 0)]
|
||||
public class TargetCastbarConfig : UnitFrameCastbarConfig
|
||||
{
|
||||
[Checkbox("Interruptable Color", spacing = true)]
|
||||
[Order(50)]
|
||||
public bool ShowInterruptableColor = true;
|
||||
|
||||
[ColorEdit4("Interruptable")]
|
||||
[Order(51, collapseWith = nameof(ShowInterruptableColor))]
|
||||
public PluginConfigColor InterruptableColor = new PluginConfigColor(new(255f / 255f, 87f / 255f, 113f / 255f, 100f / 100f));
|
||||
|
||||
[Checkbox("Damage Type Colors", spacing = true)]
|
||||
[Order(60)]
|
||||
public bool UseColorForDamageTypes = true;
|
||||
|
||||
[ColorEdit4("Physical")]
|
||||
[Order(61, collapseWith = nameof(UseColorForDamageTypes))]
|
||||
public PluginConfigColor PhysicalDamageColor = new PluginConfigColor(new(190f / 255f, 28f / 255f, 57f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Magical")]
|
||||
[Order(62, collapseWith = nameof(UseColorForDamageTypes))]
|
||||
public PluginConfigColor MagicalDamageColor = new PluginConfigColor(new(0f / 255f, 72f / 255f, 179f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Darkness")]
|
||||
[Order(63, collapseWith = nameof(UseColorForDamageTypes))]
|
||||
public PluginConfigColor DarknessDamageColor = new PluginConfigColor(new(188f / 255f, 19f / 255f, 254f / 255f, 100f / 100f));
|
||||
|
||||
public TargetCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, castNameConfig, castTimeConfig)
|
||||
{
|
||||
|
||||
}
|
||||
public new static TargetCastbarConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(254, 24);
|
||||
var pos = new Vector2(0, HUDConstants.BaseHUDOffsetY / 2f - size.Y / 2);
|
||||
|
||||
var castNameConfig = new LabelConfig(new Vector2(5, 0), "", DrawAnchor.Left, DrawAnchor.Left);
|
||||
var castTimeConfig = new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right);
|
||||
castTimeConfig.NumberFormat = 1;
|
||||
|
||||
return new TargetCastbarConfig(pos, size, castNameConfig, castTimeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
[Section("Castbars")]
|
||||
[SubSection("Target of Target", 0)]
|
||||
public class TargetOfTargetCastbarConfig : TargetCastbarConfig
|
||||
{
|
||||
public TargetOfTargetCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, castNameConfig, castTimeConfig)
|
||||
{
|
||||
|
||||
}
|
||||
public new static TargetOfTargetCastbarConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(120, 24);
|
||||
var pos = new Vector2(0, -1);
|
||||
|
||||
var castNameConfig = new LabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
var castTimeConfig = new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right);
|
||||
castTimeConfig.Enabled = false;
|
||||
castTimeConfig.NumberFormat = 1;
|
||||
|
||||
var config = new TargetOfTargetCastbarConfig(pos, size, castNameConfig, castTimeConfig);
|
||||
config.Anchor = DrawAnchor.Top;
|
||||
config.AnchorToUnitFrame = true;
|
||||
config.ShowIcon = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
[Section("Castbars")]
|
||||
[SubSection("Focus Target", 0)]
|
||||
public class FocusTargetCastbarConfig : TargetCastbarConfig
|
||||
{
|
||||
public FocusTargetCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, castNameConfig, castTimeConfig)
|
||||
{
|
||||
|
||||
}
|
||||
public new static FocusTargetCastbarConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(120, 24);
|
||||
var pos = new Vector2(0, -1);
|
||||
|
||||
var castNameConfig = new LabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
var castTimeConfig = new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right);
|
||||
castTimeConfig.Enabled = false;
|
||||
castTimeConfig.NumberFormat = 1;
|
||||
|
||||
var config = new FocusTargetCastbarConfig(pos, size, castNameConfig, castTimeConfig);
|
||||
config.Anchor = DrawAnchor.Top;
|
||||
config.AnchorToUnitFrame = true;
|
||||
config.ShowIcon = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class UnitFrameCastbarConfig : CastbarConfig
|
||||
{
|
||||
[Checkbox("Anchor to Unit Frame")]
|
||||
[Order(16)]
|
||||
public bool AnchorToUnitFrame = false;
|
||||
|
||||
[Anchor("Unit Frame Anchor")]
|
||||
[Order(17, collapseWith = nameof(AnchorToUnitFrame))]
|
||||
public DrawAnchor UnitFrameAnchor = DrawAnchor.Bottom;
|
||||
|
||||
public UnitFrameCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, castNameConfig, castTimeConfig)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive")]
|
||||
public abstract class CastbarConfig : BarConfig
|
||||
{
|
||||
[Checkbox("Preview")]
|
||||
[Order(3)]
|
||||
public bool Preview = false;
|
||||
|
||||
[Checkbox("Show Ability Icon")]
|
||||
[Order(4)]
|
||||
public bool ShowIcon = true;
|
||||
|
||||
[Checkbox("Reverse Fill Background Color")]
|
||||
[Order(5)]
|
||||
public bool UseReverseFill = false;
|
||||
|
||||
[Checkbox("Show Current Cast Time + Max Cast Time")]
|
||||
[Order(6)]
|
||||
public bool ShowMaxCastTime = false;
|
||||
|
||||
[Checkbox("Truncate Cast Name", help = "This will automatically truncate the cast name if it's too long and won't fit inside the bar.")]
|
||||
[Order(7)]
|
||||
public bool TruncateCastName = false;
|
||||
|
||||
[Checkbox("Separate Icon", spacing = true)]
|
||||
[Order(100)]
|
||||
public bool SeparateIcon = false;
|
||||
|
||||
[DragInt2("Custom Icon Position", min = -500, max = 500)]
|
||||
[Order(101, collapseWith = nameof(SeparateIcon))]
|
||||
public Vector2 CustomIconPosition = Vector2.Zero;
|
||||
|
||||
[DragInt2("Custom Icon Size", min = 1, max = 500)]
|
||||
[Order(101, collapseWith = nameof(SeparateIcon))]
|
||||
public Vector2 CustomIconSize = new Vector2(40);
|
||||
|
||||
[NestedConfig("Cast Name", 500)]
|
||||
public LabelConfig CastNameLabel;
|
||||
|
||||
[NestedConfig("Cast Time", 505)]
|
||||
public NumericLabelConfig CastTimeLabel;
|
||||
|
||||
[ColorEdit4("Color" + "##ReverseFill")]
|
||||
[Order(515, collapseWith = nameof(UseReverseFill))]
|
||||
public PluginConfigColor ReverseFillColor = new(new Vector4(255f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
public CastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
|
||||
: base(position, size, new PluginConfigColor(new(0f / 255f, 162f / 255f, 252f / 255f, 100f / 100f)), BarDirection.Right)
|
||||
{
|
||||
CastNameLabel = castNameConfig;
|
||||
CastTimeLabel = castTimeConfig;
|
||||
|
||||
Strata = StrataLevel.MID;
|
||||
}
|
||||
}
|
||||
|
||||
public class CastbarConfigConverter : PluginConfigObjectConverter
|
||||
{
|
||||
public CastbarConfigConverter()
|
||||
{
|
||||
SameClassFieldConverter<LabelConfig> name = new SameClassFieldConverter<LabelConfig>(
|
||||
"CastNameLabel",
|
||||
new LabelConfig(Vector2.Zero, "", DrawAnchor.Center, DrawAnchor.Center)
|
||||
);
|
||||
|
||||
NewClassFieldConverter<LabelConfig, NumericLabelConfig> time = new NewClassFieldConverter<LabelConfig, NumericLabelConfig>(
|
||||
"CastTimeLabel",
|
||||
new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right),
|
||||
(oldValue) =>
|
||||
{
|
||||
NumericLabelConfig label = new NumericLabelConfig(oldValue.Position, "", oldValue.FrameAnchor, oldValue.TextAnchor);
|
||||
label.Enabled = oldValue.Enabled;
|
||||
label.FontID = oldValue.FontID;
|
||||
label.NumberFormat = 1;
|
||||
label.Color = oldValue.Color;
|
||||
label.OutlineColor = oldValue.OutlineColor;
|
||||
label.ShadowConfig = oldValue.ShadowConfig;
|
||||
label.UseJobColor = oldValue.UseJobColor;
|
||||
|
||||
return label;
|
||||
});
|
||||
|
||||
FieldConvertersMap.Add("CastNameConfig", name);
|
||||
FieldConvertersMap.Add("CastTimeConfig", time);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(CastbarConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Dalamud.Utility;
|
||||
using HSUI.Config;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using HSUI.Interface.EnemyList;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using LuminaAction = Lumina.Excel.Sheets.Action;
|
||||
using StructsBattleChara = FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class CastbarHud : ParentAnchoredDraggableHudElement, IHudElementWithActor, IHudElementWithAnchorableParent, IHudElementWithPreview
|
||||
{
|
||||
private CastbarConfig Config => (CastbarConfig)_config;
|
||||
private readonly LabelHud _castNameLabel;
|
||||
private readonly LabelHud _castTimeLabel;
|
||||
|
||||
protected LastUsedCast? LastUsedCast;
|
||||
|
||||
public IGameObject? Actor { get; set; }
|
||||
|
||||
protected override bool AnchorToParent => Config is UnitFrameCastbarConfig { AnchorToUnitFrame: true };
|
||||
protected override DrawAnchor ParentAnchor => Config is UnitFrameCastbarConfig config ? config.UnitFrameAnchor : DrawAnchor.Center;
|
||||
|
||||
public CastbarHud(CastbarConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
_castNameLabel = new LabelHud(config.CastNameLabel);
|
||||
_castTimeLabel = new LabelHud(config.CastTimeLabel);
|
||||
}
|
||||
|
||||
public void StopPreview()
|
||||
{
|
||||
Config.Preview = false;
|
||||
}
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes() => (new List<Vector2> { Config.Position }, new List<Vector2> { Config.Size });
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
if (!Config.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config.Preview &&
|
||||
(Actor == null || Actor is not ICharacter || Actor.ObjectKind != ObjectKind.Player && Actor.ObjectKind != ObjectKind.BattleNpc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateCurrentCast(out float currentCastTime, out float totalCastTime);
|
||||
if (totalCastTime == 0 || currentCastTime >= totalCastTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ShouldShow() && !Config.Preview)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 size = GetSize();
|
||||
IDalamudTextureWrap? iconTexture = LastUsedCast?.GetIconTexture();
|
||||
bool validIcon = Config.Preview ? true : iconTexture is not null;
|
||||
Vector2 iconSize = Config.ShowIcon && validIcon && !Config.SeparateIcon ? new Vector2(size.Y, size.Y) : Vector2.Zero;
|
||||
|
||||
PluginConfigColor fillColor = GetColor();
|
||||
Rect background = new(Config.Position, size, Config.BackgroundColor);
|
||||
Rect progress = BarUtilities.GetFillRect(Config.Position, size, Config.FillDirection, fillColor, currentCastTime, totalCastTime);
|
||||
|
||||
BarHud bar = new(Config, Actor);/**/
|
||||
bar.SetBackground(background);
|
||||
|
||||
if (Config.UseReverseFill)
|
||||
{
|
||||
Vector2 reverseFillSize = size - BarUtilities.GetFillDirectionOffset(progress.Size, Config.FillDirection);
|
||||
Vector2 reverseFillPos = Config.FillDirection.IsInverted()
|
||||
? Config.Position
|
||||
: Config.Position + BarUtilities.GetFillDirectionOffset(progress.Size, Config.FillDirection);
|
||||
|
||||
PluginConfigColor reverseFillColor = Config.ReverseFillColor;
|
||||
bar.AddForegrounds(new Rect(reverseFillPos, reverseFillSize, reverseFillColor));
|
||||
}
|
||||
|
||||
AddExtras(bar, totalCastTime, iconTexture);
|
||||
|
||||
bar.AddForegrounds(progress);
|
||||
|
||||
Vector2 pos = origin + ParentPos();
|
||||
AddDrawActions(bar.GetDrawActions(pos, Config.StrataLevel));
|
||||
|
||||
// icon
|
||||
Vector2 startPos = Config.Position + Utils.GetAnchoredPosition(pos, size, Config.Anchor);
|
||||
if (Config.ShowIcon && validIcon)
|
||||
{
|
||||
Vector2 finalIconPos = Config.SeparateIcon ? startPos + Config.CustomIconPosition : startPos;
|
||||
Vector2 finalIconSize = Config.SeparateIcon ? Config.CustomIconSize : iconSize;
|
||||
|
||||
AddDrawAction(Config.StrataLevel, () =>
|
||||
{
|
||||
DrawHelper.DrawInWindow(ID + "_icon", finalIconPos, finalIconSize, false, (drawList) =>
|
||||
{
|
||||
ImGui.SetCursorPos(finalIconPos);
|
||||
|
||||
IDalamudTextureWrap? texture = Config.Preview ? TexturesHelper.GetTexture<LuminaAction>(3577) : iconTexture;
|
||||
if (texture != null)
|
||||
{
|
||||
ImGui.Image(texture.Handle, finalIconSize);
|
||||
}
|
||||
|
||||
if (Config.DrawBorder)
|
||||
{
|
||||
drawList.AddRect(finalIconPos, finalIconPos + finalIconSize, Config.BorderColor.Base, 0, ImDrawFlags.None, Config.BorderThickness);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// cast time
|
||||
bool isTimeLeftAnchored = Config.CastTimeLabel.TextAnchor is DrawAnchor.Left or DrawAnchor.TopLeft or DrawAnchor.BottomLeft;
|
||||
Vector2 timePos = Config.ShowIcon && isTimeLeftAnchored ? startPos + new Vector2(iconSize.X, 0) : startPos;
|
||||
float value = Config.Preview ? 0.5f : totalCastTime - currentCastTime;
|
||||
|
||||
if (Config.ShowMaxCastTime)
|
||||
{
|
||||
string format = Config.CastTimeLabel.NumberFormat.ToString();
|
||||
Config.CastTimeLabel.SetText(
|
||||
value.ToString("N" + format, ConfigurationManager.Instance.ActiveCultreInfo) +
|
||||
" / " +
|
||||
totalCastTime.ToString("N" + format, ConfigurationManager.Instance.ActiveCultreInfo)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Config.CastTimeLabel.SetValue(value);
|
||||
}
|
||||
|
||||
AddDrawAction(Config.CastTimeLabel.StrataLevel, () =>
|
||||
{
|
||||
_castTimeLabel.Draw(timePos, size, Actor);
|
||||
});
|
||||
|
||||
// cast name
|
||||
bool isNameLeftAnchored = Config.CastNameLabel.TextAnchor is DrawAnchor.Left or DrawAnchor.TopLeft or DrawAnchor.BottomLeft;
|
||||
Vector2 namePos = Config.ShowIcon && isNameLeftAnchored ? startPos + new Vector2(iconSize.X, 0) : startPos;
|
||||
|
||||
string original = CustomCastName() ?? (LastUsedCast?.ActionText ?? "");
|
||||
string castName = EncryptedStringsHelper.GetString(original).CheckForUpperCase() ?? original;
|
||||
|
||||
if (Config.TruncateCastName)
|
||||
{
|
||||
castName = TruncatedCastName(castName) ?? castName;
|
||||
}
|
||||
|
||||
Config.CastNameLabel.SetText(Config.Preview ? "Cast Name" : castName);
|
||||
|
||||
AddDrawAction(Config.CastNameLabel.StrataLevel, () =>
|
||||
{
|
||||
_castNameLabel.Draw(namePos, size, Actor);
|
||||
});
|
||||
}
|
||||
|
||||
private unsafe void UpdateCurrentCast(out float currentCastTime, out float totalCastTime)
|
||||
{
|
||||
if (Config.Preview || Actor is not IBattleChara battleChara)
|
||||
{
|
||||
currentCastTime = Config.Preview ? 0.5f : 0f;
|
||||
totalCastTime = 1f;
|
||||
return;
|
||||
}
|
||||
|
||||
float current = 0;
|
||||
float total = 0;
|
||||
|
||||
try
|
||||
{
|
||||
current = battleChara.CurrentCastTime;
|
||||
StructsBattleChara* chara = (StructsBattleChara*)battleChara.Address;
|
||||
CastInfo* castInfo = chara->GetCastInfo();
|
||||
|
||||
if (castInfo != null)
|
||||
{
|
||||
total = castInfo->TotalCastTime;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
currentCastTime = 0;
|
||||
totalCastTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Utils.IsActorCasting(battleChara) && current <= 0)
|
||||
{
|
||||
currentCastTime = 0;
|
||||
totalCastTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
currentCastTime = current;
|
||||
totalCastTime = total;
|
||||
|
||||
uint currentCastId = battleChara.CastActionId;
|
||||
ActionType currentCastType = (ActionType)battleChara.CastActionType;
|
||||
|
||||
if (LastUsedCast == null || LastUsedCast.CastId != currentCastId || LastUsedCast.ActionType != currentCastType)
|
||||
{
|
||||
LastUsedCast = new LastUsedCast(currentCastId, currentCastType, battleChara.IsCastInterruptible);
|
||||
}
|
||||
}
|
||||
|
||||
private string? TruncatedCastName(string text)
|
||||
{
|
||||
if (text.Length <= 5)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
LabelConfig castNamelabel = Config.CastNameLabel;
|
||||
LabelConfig castTimeLabel = Config.CastTimeLabel;
|
||||
|
||||
|
||||
Vector2 size;
|
||||
|
||||
using (FontsManager.Instance.PushFont(castNamelabel.FontID))
|
||||
{
|
||||
size = ImGui.CalcTextSize(text) * castNamelabel.GetFontScale();
|
||||
}
|
||||
|
||||
float maxWidth = Config.Size.X;
|
||||
|
||||
if (!Config.SeparateIcon)
|
||||
{
|
||||
maxWidth -= Config.Size.Y;
|
||||
}
|
||||
|
||||
if (Config.CastTimeLabel.Enabled)
|
||||
{
|
||||
using (FontsManager.Instance.PushFont(Config.CastTimeLabel.FontID))
|
||||
{
|
||||
maxWidth -= (ImGui.CalcTextSize("XX.X") * castTimeLabel.GetFontScale()).X;
|
||||
}
|
||||
}
|
||||
|
||||
if (size.X > maxWidth)
|
||||
{
|
||||
return TruncatedCastName(text.Substring(0, text.Length - 5) + "...");
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public virtual void AddExtras(BarHud bar, float totalCastTime, IDalamudTextureWrap? iconTexture)
|
||||
{
|
||||
// override
|
||||
}
|
||||
|
||||
public virtual string? CustomCastName()
|
||||
{
|
||||
// override
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual PluginConfigColor GetColor() => Config.FillColor;
|
||||
public virtual Vector2 GetSize() => Config.Size;
|
||||
|
||||
public virtual bool ShouldShow() => true;
|
||||
}
|
||||
|
||||
public class PlayerCastbarHud : CastbarHud
|
||||
{
|
||||
private PlayerCastbarConfig Config => (PlayerCastbarConfig)_config;
|
||||
|
||||
public PlayerCastbarHud(PlayerCastbarConfig config, string displayName) : base(config, displayName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe string? CustomCastName()
|
||||
{
|
||||
AddonCastBar* castBar = (AddonCastBar*)Plugin.GameGui.GetAddonByName("_CastBar", 1).Address;
|
||||
if (castBar == null) { return null; }
|
||||
|
||||
AtkTextNode* node = castBar->GetTextNodeById(4);
|
||||
if (node == null) { return null; }
|
||||
|
||||
return node->GetText().ExtractText();
|
||||
}
|
||||
|
||||
public override void AddExtras(BarHud bar, float totalCastTime, IDalamudTextureWrap? iconTexture)
|
||||
{
|
||||
if (!Config.ShowSlideCast || Config.SlideCastTime <= 0 || Config.Preview)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rect slideCast;
|
||||
|
||||
if (Config.FillDirection.IsHorizontal())
|
||||
{
|
||||
float slideCastWidth = Math.Min(Config.Size.X, Config.SlideCastTime / 1000f * Config.Size.X / totalCastTime);
|
||||
Vector2 size = new(slideCastWidth, Config.Size.Y);
|
||||
slideCast = new(Config.Position + Config.Size - size, size, Config.SlideCastColor);
|
||||
|
||||
if (Config.FillDirection is BarDirection.Left)
|
||||
{
|
||||
bool validIcon = iconTexture is not null;
|
||||
Vector2 iconSize = Config.ShowIcon && validIcon ? new Vector2(Config.Size.Y, Config.Size.Y) : Vector2.Zero;
|
||||
slideCast = Config.ShowIcon ? new Rect(Config.Position, size + new Vector2(iconSize.X, 0), Config.SlideCastColor) : new Rect(Config.Position, size, Config.SlideCastColor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float slideCastHeight = Math.Min(Config.Size.Y, Config.SlideCastTime / 1000f * Config.Size.Y / totalCastTime);
|
||||
Vector2 size = new(Config.Size.X, slideCastHeight);
|
||||
slideCast = new(Config.Position + Config.Size - size, size, Config.SlideCastColor);
|
||||
|
||||
if (Config.FillDirection is BarDirection.Up)
|
||||
{
|
||||
slideCast = new(Config.Position, size, Config.SlideCastColor);
|
||||
}
|
||||
}
|
||||
|
||||
bar.AddForegrounds(slideCast);
|
||||
}
|
||||
|
||||
public override PluginConfigColor GetColor()
|
||||
{
|
||||
if (!Config.UseJobColor || Actor is not ICharacter)
|
||||
{
|
||||
return Config.FillColor;
|
||||
}
|
||||
|
||||
ICharacter? chara = (ICharacter)Actor;
|
||||
PluginConfigColor? color = GlobalColors.Instance.ColorForJobId(chara.ClassJob.RowId);
|
||||
return color ?? Config.FillColor;
|
||||
}
|
||||
}
|
||||
|
||||
public class TargetCastbarHud : CastbarHud
|
||||
{
|
||||
private TargetCastbarConfig Config => (TargetCastbarConfig)_config;
|
||||
|
||||
public TargetCastbarHud(TargetCastbarConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override PluginConfigColor GetColor()
|
||||
{
|
||||
if (Config.ShowInterruptableColor && LastUsedCast?.Interruptible == true)
|
||||
{
|
||||
return Config.InterruptableColor;
|
||||
}
|
||||
|
||||
if (!Config.UseColorForDamageTypes)
|
||||
{
|
||||
return Config.FillColor;
|
||||
}
|
||||
|
||||
if (LastUsedCast != null)
|
||||
{
|
||||
switch (LastUsedCast.DamageType)
|
||||
{
|
||||
case DamageType.Physical:
|
||||
case DamageType.Blunt:
|
||||
case DamageType.Slashing:
|
||||
case DamageType.Piercing:
|
||||
return Config.PhysicalDamageColor;
|
||||
|
||||
case DamageType.Magic:
|
||||
return Config.MagicalDamageColor;
|
||||
|
||||
case DamageType.Darkness:
|
||||
return Config.DarknessDamageColor;
|
||||
}
|
||||
}
|
||||
|
||||
return Config.FillColor;
|
||||
}
|
||||
|
||||
public override unsafe bool ShouldShow()
|
||||
{
|
||||
bool? targetCasting = Utils.IsTargetCasting();
|
||||
if (targetCasting.HasValue)
|
||||
{
|
||||
return targetCasting.Value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class FocusTargetCastbarHud : TargetCastbarHud
|
||||
{
|
||||
private TargetCastbarConfig Config => (TargetCastbarConfig)_config;
|
||||
|
||||
public FocusTargetCastbarHud(TargetCastbarConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe bool ShouldShow()
|
||||
{
|
||||
bool? focusTargetCasting = Utils.IsFocusTargetCasting();
|
||||
if (focusTargetCasting.HasValue)
|
||||
{
|
||||
return focusTargetCasting.Value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class TargetOfTargetCastbarHud : TargetCastbarHud
|
||||
{
|
||||
private TargetCastbarConfig Config => (TargetCastbarConfig)_config;
|
||||
|
||||
public TargetOfTargetCastbarHud(TargetCastbarConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe bool ShouldShow()
|
||||
{
|
||||
IGameObject? target = Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target;
|
||||
if (Actor == target)
|
||||
{
|
||||
bool? targetCasting = Utils.IsTargetCasting();
|
||||
if (targetCasting.HasValue)
|
||||
{
|
||||
return targetCasting.Value;
|
||||
}
|
||||
}
|
||||
|
||||
IGameObject? focusTarget = Plugin.TargetManager.FocusTarget;
|
||||
if (Actor == focusTarget)
|
||||
{
|
||||
bool? focusTargetCasting = Utils.IsFocusTargetCasting();
|
||||
if (focusTargetCasting.HasValue)
|
||||
{
|
||||
return focusTargetCasting.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class EnemyListCastbarHud : TargetCastbarHud
|
||||
{
|
||||
private EnemyListCastbarConfig Config => (EnemyListCastbarConfig)_config;
|
||||
|
||||
public int EnemyListIndex = 0;
|
||||
|
||||
public EnemyListCastbarHud(EnemyListCastbarConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe bool ShouldShow()
|
||||
{
|
||||
bool? casting = Utils.IsEnemyInListCasting(EnemyListIndex);
|
||||
if (casting.HasValue)
|
||||
{
|
||||
return casting.Value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class NameplateCastbarHud : TargetOfTargetCastbarHud
|
||||
{
|
||||
private NameplateCastbarConfig Config => (NameplateCastbarConfig)_config;
|
||||
|
||||
private Vector2 _customSize = new Vector2(0);
|
||||
public Vector2 ParentSize { get; set; } = new Vector2(0);
|
||||
|
||||
public NameplateCastbarHud(NameplateCastbarConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
_customSize = Config.Size;
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
// calculate size
|
||||
float x = Config.MatchWidth ? ParentSize.X : Config.Size.X;
|
||||
float y = Config.MatchHeight ? ParentSize.Y : Config.Size.Y;
|
||||
_customSize = new Vector2(x, y);
|
||||
|
||||
// draw
|
||||
base.DrawChildren(origin);
|
||||
}
|
||||
|
||||
public override Vector2 GetSize() => _customSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Dalamud.Interface;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Section("Other Elements")]
|
||||
[SubSection("Experience Bar", 0)]
|
||||
public class ExperienceBarConfig : BarConfig
|
||||
{
|
||||
[Checkbox("Hide When Downsynced")]
|
||||
[Order(44, collapseWith = nameof(HideWhenInactive))]
|
||||
public bool HideWhenDownsynced = false;
|
||||
|
||||
[Checkbox("Use Job Color")]
|
||||
[Order(45)]
|
||||
public bool UseJobColor = false;
|
||||
|
||||
[Checkbox("Show Rested Exp")]
|
||||
[Order(50)]
|
||||
public bool ShowRestedExp = true;
|
||||
|
||||
[ColorEdit4("Rested Exp Color")]
|
||||
[Order(55, collapseWith = nameof(ShowRestedExp))]
|
||||
public PluginConfigColor RestedExpColor = new PluginConfigColor(new Vector4(110f / 255f, 197f / 255f, 207f / 255f, 50f / 100f));
|
||||
|
||||
[NestedConfig("Left Text", 60)]
|
||||
public EditableLabelConfig LeftLabel;
|
||||
|
||||
[NestedConfig("Right Text", 61)]
|
||||
public EditableLabelConfig RightLabel;
|
||||
|
||||
[NestedConfig("Sanctuary Icon", 62)]
|
||||
public IconLabelConfig SanctuaryLabel = new IconLabelConfig(new Vector2(5, 0), FontAwesomeIcon.Moon, DrawAnchor.Right, DrawAnchor.Left);
|
||||
|
||||
[NestedConfig("Visibility", 70)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public ExperienceBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor) : base(position, size, fillColor)
|
||||
{
|
||||
LeftLabel = new EditableLabelConfig(new Vector2(5, 0), "[job] Lv[level] EXP [exp:current-short]/[exp:required-short]", DrawAnchor.BottomLeft, DrawAnchor.TopLeft);
|
||||
RightLabel = new EditableLabelConfig(new Vector2(-5, 0), "([exp:percent]%)", DrawAnchor.BottomRight, DrawAnchor.TopRight);
|
||||
}
|
||||
|
||||
public new static ExperienceBarConfig DefaultConfig()
|
||||
{
|
||||
return new ExperienceBarConfig(
|
||||
new Vector2(0, -ImGui.GetMainViewport().Size.Y * 0.45f),
|
||||
new Vector2(860, 10),
|
||||
new PluginConfigColor(new Vector4(211f / 255f, 166f / 255f, 79f / 255f, 100f / 100f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Interface;
|
||||
using HSUI.Config;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class ExperienceBarHud : DraggableHudElement, IHudElementWithActor, IHudElementWithVisibilityConfig
|
||||
{
|
||||
private ExperienceBarConfig Config => (ExperienceBarConfig)_config;
|
||||
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
|
||||
|
||||
public IGameObject? Actor { get; set; } = null;
|
||||
|
||||
private ExperienceHelper _helper = new ExperienceHelper();
|
||||
private IconLabelHud _sanctuaryLabel;
|
||||
|
||||
public ExperienceBarHud(ExperienceBarConfig config, string displayName) : base(config, displayName)
|
||||
{
|
||||
Config.SanctuaryLabel.IconId = FontAwesomeIcon.Moon;
|
||||
_sanctuaryLabel = new IconLabelHud(Config.SanctuaryLabel);
|
||||
}
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
return (new List<Vector2>() { Config.Position }, new List<Vector2>() { Config.Size });
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
if (!Config.Enabled ||
|
||||
Actor is null ||
|
||||
Config.HideWhenInactive && (Plugin.ObjectTable.LocalPlayer?.Level ?? 0) >= 100 ||
|
||||
(Config.HideWhenInactive && Config.HideWhenDownsynced && _helper.IsMaxLevel()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint current = ExperienceHelper.Instance.CurrentExp;
|
||||
uint required = ExperienceHelper.Instance.RequiredExp;
|
||||
uint rested = Config.ShowRestedExp ? ExperienceHelper.Instance.RestedExp : 0;
|
||||
|
||||
// Exp progress bar
|
||||
PluginConfigColor expFillColor = Config.UseJobColor ? ColorUtils.ColorForActor(Actor) : Config.FillColor;
|
||||
Rect expBar = BarUtilities.GetFillRect(Config.Position, Config.Size, Config.FillDirection, expFillColor, current, required);
|
||||
|
||||
// Rested exp bar
|
||||
var restedPos = Config.FillDirection.IsInverted() ? Config.Position : Config.Position + BarUtilities.GetFillDirectionOffset(expBar.Size, Config.FillDirection);
|
||||
var restedSize = Config.Size - BarUtilities.GetFillDirectionOffset(expBar.Size, Config.FillDirection);
|
||||
Rect restedBar = BarUtilities.GetFillRect(restedPos, restedSize, Config.FillDirection, Config.RestedExpColor, rested, required, 0f);
|
||||
|
||||
BarHud bar = new BarHud(Config, Actor);
|
||||
bar.AddForegrounds(expBar, restedBar);
|
||||
bar.AddLabels(Config.LeftLabel, Config.RightLabel);
|
||||
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.StrataLevel));
|
||||
|
||||
// sanctuary icon
|
||||
if (IsInSanctuary())
|
||||
{
|
||||
AddDrawAction(Config.SanctuaryLabel.StrataLevel, () =>
|
||||
{
|
||||
var pos = Utils.GetAnchoredPosition(origin, Config.Size, Config.Anchor);
|
||||
_sanctuaryLabel.Draw(pos + Config.Position, Config.Size, Actor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe bool IsInSanctuary()
|
||||
{
|
||||
AddonExp* addon = ExperienceHelper.Instance.GetExpAddon();
|
||||
if (addon == null) { return false; }
|
||||
AtkImageNode* sanctuaryNode = addon->GetImageNodeById(3);
|
||||
if (sanctuaryNode == null) { return false; }
|
||||
|
||||
return sanctuaryNode->IsVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.GameFonts;
|
||||
using Dalamud.Logging;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public struct FontData
|
||||
{
|
||||
public string Name;
|
||||
public int Size;
|
||||
|
||||
public FontData(string name, int size)
|
||||
{
|
||||
Name = name;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Customization")]
|
||||
[SubSection("Fonts", 0)]
|
||||
public class FontsConfig : PluginConfigObject
|
||||
{
|
||||
public new static FontsConfig DefaultConfig() { return new FontsConfig(); }
|
||||
|
||||
public string FontsPath = "C:\\";
|
||||
[JsonIgnore] public string ValidatedFontsPath => ValidatePath(FontsPath);
|
||||
|
||||
public SortedList<string, FontData> Fonts = new SortedList<string, FontData>();
|
||||
public bool SupportChineseCharacters = false;
|
||||
public bool SupportKoreanCharacters = false;
|
||||
public bool SupportCyrillicCharacters = false;
|
||||
[JsonIgnore] public readonly Dictionary<string, string> GameFontMap = new Dictionary<string, string>()
|
||||
{
|
||||
{"Axis", "axis-ffxiv"},
|
||||
{"Jupiter", "jupiter-ffxiv"},
|
||||
{"JupiterNumeric", "jupiter-numeric-ffxiv"},
|
||||
{"MiedingerMid", "meidinger-ffxiv"},
|
||||
{"Meidinger", "meidinger-numberic-ffxiv"},
|
||||
{"TrumpGothic", "trumpgothic-ffxiv"},
|
||||
|
||||
};
|
||||
|
||||
[JsonIgnore] public static readonly List<string> DefaultFontsKeys = new List<string>() { "Expressway_18", "Expressway_14", "Expressway_12" };
|
||||
|
||||
[JsonIgnore] public static string DefaultBigFontKey => DefaultFontsKeys[0];
|
||||
[JsonIgnore] public static string DefaultMediumFontKey => DefaultFontsKeys[1];
|
||||
[JsonIgnore] public static string DefaultSmallFontKey => DefaultFontsKeys[2];
|
||||
|
||||
[JsonIgnore] private int _inputFont = 0;
|
||||
[JsonIgnore] private int _inputSize = 23;
|
||||
|
||||
[JsonIgnore] private string[] _fonts = null!;
|
||||
[JsonIgnore] private string[] _sizes = null!;
|
||||
|
||||
[JsonIgnore] private int _removingIndex = -1;
|
||||
[JsonIgnore] private int _applyingIndex = -1!;
|
||||
|
||||
[JsonIgnore] private FileDialogManager _fileDialogManager = new FileDialogManager();
|
||||
|
||||
public FontsConfig()
|
||||
{
|
||||
ReloadFonts();
|
||||
|
||||
// default fonts
|
||||
foreach (string key in DefaultFontsKeys)
|
||||
{
|
||||
if (!Fonts.ContainsKey(key))
|
||||
{
|
||||
string[] str = key.Split("_", StringSplitOptions.RemoveEmptyEntries);
|
||||
var defaultFont = new FontData(str[0], int.Parse(str[1]));
|
||||
Fonts.Add(key, defaultFont);
|
||||
}
|
||||
}
|
||||
|
||||
// sizes
|
||||
_sizes = new string[100];
|
||||
for (int i = 0; i < _sizes.Length; i++)
|
||||
{
|
||||
_sizes[i] = (i + 1).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsDefaultFont(string key)
|
||||
{
|
||||
return DefaultFontsKeys.Contains(key);
|
||||
}
|
||||
|
||||
private string ValidatePath(string path)
|
||||
{
|
||||
if (path.EndsWith("\\") || path.EndsWith("/"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return path + "\\";
|
||||
}
|
||||
|
||||
private string[] FontsFromPath(string path)
|
||||
{
|
||||
string[] fonts;
|
||||
try
|
||||
{
|
||||
fonts = Directory.GetFiles(path, "*.ttf");
|
||||
}
|
||||
catch
|
||||
{
|
||||
fonts = new string[0];
|
||||
}
|
||||
|
||||
for (int i = 0; i < fonts.Length; i++)
|
||||
{
|
||||
fonts[i] = fonts[i]
|
||||
.Replace(path, "")
|
||||
.Replace(".ttf", "")
|
||||
.Replace(".TTF", "");
|
||||
}
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
private string[] FontsFromGame()
|
||||
{
|
||||
string[] gameFontArray = Enum.GetNames(typeof(GameFontFamily)).Skip(1).ToArray();
|
||||
string[] fonts = new string[gameFontArray.Length];
|
||||
|
||||
for (int i = 0; i < gameFontArray.Length; i++)
|
||||
{
|
||||
fonts[i] = GameFontMap[gameFontArray[i]];
|
||||
}
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
private void ReloadFonts()
|
||||
{
|
||||
string defaultFontsPath = ValidatePath(FontsManager.Instance.DefaultFontsPath);
|
||||
string[] defaultFonts = FontsFromPath(defaultFontsPath);
|
||||
string[] gameFonts = FontsFromGame();
|
||||
string[] userFonts = FontsFromPath(ValidatedFontsPath);
|
||||
|
||||
_fonts = new string[defaultFonts.Length + gameFonts.Length + userFonts.Length];
|
||||
defaultFonts.CopyTo(_fonts, 0);
|
||||
gameFonts.CopyTo(_fonts, defaultFonts.Length);
|
||||
userFonts.CopyTo(_fonts, defaultFonts.Length + gameFonts.Length);
|
||||
}
|
||||
|
||||
private bool AddNewEntry(int font, int size)
|
||||
{
|
||||
if (font < 0 || font > _fonts.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0 || size > _sizes.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string fontName = _fonts[font];
|
||||
string key = fontName + "_" + size.ToString();
|
||||
|
||||
if (Fonts.ContainsKey(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FontData fontData = new FontData(fontName, size);
|
||||
Fonts.Add(key, fontData);
|
||||
|
||||
FontsManager.Instance.BuildFonts();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SelectFolder()
|
||||
{
|
||||
Action<bool, string> callback = (finished, path) =>
|
||||
{
|
||||
if (finished && path.Length > 0)
|
||||
{
|
||||
FontsPath = path;
|
||||
ReloadFonts();
|
||||
}
|
||||
};
|
||||
|
||||
_fileDialogManager.OpenFolderDialog("Select Fonts Folder", callback);
|
||||
}
|
||||
|
||||
[ManualDraw]
|
||||
public bool Draw(ref bool changed)
|
||||
{
|
||||
ImGuiTableFlags flags =
|
||||
ImGuiTableFlags.RowBg |
|
||||
ImGuiTableFlags.Borders |
|
||||
ImGuiTableFlags.BordersOuter |
|
||||
ImGuiTableFlags.BordersInner |
|
||||
ImGuiTableFlags.ScrollY |
|
||||
ImGuiTableFlags.SizingFixedSame;
|
||||
|
||||
if (ImGui.BeginChild("Fonts", new Vector2(800, 500), false, ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
|
||||
{
|
||||
if (_fonts.Length == 0)
|
||||
{
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Text("Default font not found in \"%appdata%/Roaming/XIVLauncher/InstalledPlugins/HSUI/Media/Fonts/Expressway.ttf\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.InputText("Path", ref FontsPath, 200, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
changed = true;
|
||||
ReloadFonts();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button(FontAwesomeIcon.Folder.ToIconString(), new Vector2(0, 0)))
|
||||
{
|
||||
SelectFolder();
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Combo("Font ##font", ref _inputFont, _fonts, 10);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button("\uf2f9", new Vector2(0, 0)))
|
||||
{
|
||||
ReloadFonts();
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Combo("Size ##size", ref _inputSize, _sizes, 10);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), new Vector2(0, 0)))
|
||||
{
|
||||
changed |= AddNewEntry(_inputFont, _inputSize + 1);
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.BeginTable("table", 3, flags, new Vector2(326, 300)))
|
||||
{
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch, 0, 0);
|
||||
ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, 0, 1);
|
||||
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 0, 2);
|
||||
|
||||
ImGui.TableSetupScrollFreeze(0, 1);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < Fonts.Count; i++)
|
||||
{
|
||||
var key = Fonts.Keys[i];
|
||||
var fontData = Fonts.Values[i];
|
||||
|
||||
ImGui.PushID(i.ToString());
|
||||
ImGui.TableNextRow(ImGuiTableRowFlags.None);
|
||||
|
||||
// icon
|
||||
if (ImGui.TableSetColumnIndex(0))
|
||||
{
|
||||
ImGui.Text(fontData.Name);
|
||||
}
|
||||
|
||||
// id
|
||||
if (ImGui.TableSetColumnIndex(1))
|
||||
{
|
||||
ImGui.Text(fontData.Size.ToString());
|
||||
}
|
||||
|
||||
// remove
|
||||
if (ImGui.TableSetColumnIndex(2))
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero);
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.ArrowAltCircleUp.ToIconString()))
|
||||
{
|
||||
_applyingIndex = i;
|
||||
}
|
||||
|
||||
if (!IsDefaultFont(key))
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button(FontAwesomeIcon.Trash.ToIconString()))
|
||||
{
|
||||
_removingIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
ImGui.PopStyleColor(3);
|
||||
}
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.Checkbox("Support Chinese", ref SupportChineseCharacters))
|
||||
{
|
||||
changed = true;
|
||||
FontsManager.Instance.BuildFonts();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Checkbox("Support Korean", ref SupportKoreanCharacters))
|
||||
{
|
||||
changed = true;
|
||||
FontsManager.Instance.BuildFonts();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Checkbox("Support Cyrillic", ref SupportCyrillicCharacters))
|
||||
{
|
||||
changed = true;
|
||||
FontsManager.Instance.BuildFonts();
|
||||
}
|
||||
}
|
||||
|
||||
// apply confirmation
|
||||
if (_applyingIndex >= 0)
|
||||
{
|
||||
string[] lines = new string[] { "Are you sure you want to apply this font", "to all labels using a font with the same size?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("Apply to all labels?", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
var (key, font) = Fonts.ElementAt(_applyingIndex);
|
||||
|
||||
List<LabelConfig> labelConfigs = ConfigurationManager.Instance.GetObjects<LabelConfig>();
|
||||
foreach (LabelConfig label in labelConfigs)
|
||||
{
|
||||
if (label.FontID != null && Fonts.TryGetValue(label.FontID, out FontData value))
|
||||
{
|
||||
if (font.Size == value.Size)
|
||||
{
|
||||
label.FontID = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed = true;
|
||||
ConfigurationManager.Instance.SaveConfigurations(forced: true);
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_applyingIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// delete confirmation
|
||||
if (_removingIndex >= 0)
|
||||
{
|
||||
string[] lines = new string[] { "Are you sure you want to remove this font?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("Remove custom font?", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
Fonts.RemoveAt(_removingIndex);
|
||||
FontsManager.Instance.BuildFonts();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_removingIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
_fileDialogManager.Draw();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[DisableParentSettings("Size")]
|
||||
[Section("Other Elements")]
|
||||
[SubSection("GCD Indicator", 0)]
|
||||
public class GCDIndicatorConfig : AnchorablePluginConfigObject
|
||||
{
|
||||
[Checkbox("Always Show")]
|
||||
[Order(3)]
|
||||
public bool AlwaysShow = false;
|
||||
|
||||
[Checkbox("Anchor To Mouse")]
|
||||
[Order(4)]
|
||||
public bool AnchorToMouse = false;
|
||||
|
||||
[ColorEdit4("Background Color")]
|
||||
[Order(16)]
|
||||
public PluginConfigColor BackgroundColor = new PluginConfigColor(new Vector4(0f / 255f, 0f / 255f, 0f / 255f, 50f / 100f));
|
||||
|
||||
[ColorEdit4("Color")]
|
||||
[Order(17)]
|
||||
public PluginConfigColor FillColor = new PluginConfigColor(new(220f / 255f, 220f / 255f, 220f / 255f, 100f / 100f));
|
||||
|
||||
[Checkbox("Show Border")]
|
||||
[Order(18)]
|
||||
public bool ShowBorder = true;
|
||||
|
||||
[Checkbox("Instant GCDs only", spacing = true)]
|
||||
[Order(19)]
|
||||
public bool InstantGCDsOnly = false;
|
||||
|
||||
[Checkbox("Only show when under GCD Threshold", spacing = true)]
|
||||
[Order(20)]
|
||||
public bool LimitGCDThreshold = false;
|
||||
|
||||
[DragFloat("GCD Threshold", velocity = 0.01f)]
|
||||
[Order(21, collapseWith = nameof(LimitGCDThreshold))]
|
||||
public float GCDThreshold = 1.50f;
|
||||
|
||||
[Checkbox("Show GCD Queue Indicator", spacing = true)]
|
||||
[Order(24)]
|
||||
public bool ShowGCDQueueIndicator = true;
|
||||
|
||||
[ColorEdit4("GCD Queue Color")]
|
||||
[Order(25, collapseWith = nameof(ShowGCDQueueIndicator))]
|
||||
public PluginConfigColor QueueColor = new PluginConfigColor(new(13f / 255f, 207f / 255f, 31f / 255f, 100f / 100f));
|
||||
|
||||
[Checkbox("Circular Mode", spacing = true)]
|
||||
[Order(30)]
|
||||
public bool CircularMode = false;
|
||||
|
||||
[DragInt("Radius")]
|
||||
[Order(35, collapseWith = nameof(CircularMode))]
|
||||
public int CircleRadius = 40;
|
||||
|
||||
[DragInt("Thickness")]
|
||||
[Order(40, collapseWith = nameof(CircularMode))]
|
||||
public int CircleThickness = 10;
|
||||
|
||||
[DragInt("Start Angle", min = 0, max = 359)]
|
||||
[Order(45, collapseWith = nameof(CircularMode))]
|
||||
public int CircleStartAngle = 0;
|
||||
|
||||
[Checkbox("Rotate CCW")]
|
||||
[Order(50, collapseWith = nameof(CircularMode))]
|
||||
public bool RotateCCW = false;
|
||||
|
||||
[NestedConfig("Bar Mode", 45, collapsingHeader = false)]
|
||||
public GCDBarConfig Bar = new GCDBarConfig(
|
||||
new Vector2(0, HUDConstants.BaseHUDOffsetY + 21),
|
||||
new Vector2(254, 8),
|
||||
PluginConfigColor.Empty
|
||||
);
|
||||
|
||||
[NestedConfig("Visibility", 70)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public new static GCDIndicatorConfig DefaultConfig() { return new GCDIndicatorConfig() { Enabled = false, Strata = StrataLevel.MID_HIGH }; }
|
||||
}
|
||||
|
||||
[DisableParentSettings("Position", "Anchor", "HideWhenInactive", "FillColor", "BackgroundColor", "DrawBorder")]
|
||||
[Exportable(false)]
|
||||
public class GCDBarConfig : BarConfig
|
||||
{
|
||||
public GCDBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor, BarDirection fillDirection = BarDirection.Right)
|
||||
: base(position, size, fillColor, fillDirection)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
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;
|
||||
using Dalamud.Logging;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class GCDIndicatorHud : DraggableHudElement, IHudElementWithActor, IHudElementWithVisibilityConfig
|
||||
{
|
||||
private GCDIndicatorConfig Config => (GCDIndicatorConfig)_config;
|
||||
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
|
||||
|
||||
public IGameObject? Actor { get; set; } = null;
|
||||
|
||||
private bool _wasBarEnabled = true;
|
||||
private bool _wasCircularModeEnabled = false;
|
||||
private float _lastTotalCastTime = 0;
|
||||
|
||||
public GCDIndicatorHud(GCDIndicatorConfig config, string displayName) : base(config, displayName) { }
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
var (pos, size) = GetPositionAndSize(Vector2.Zero);
|
||||
|
||||
if (Config.CircularMode)
|
||||
{
|
||||
pos -= size / 2f;
|
||||
}
|
||||
|
||||
return (new List<Vector2>() { pos }, new List<Vector2>() { size });
|
||||
}
|
||||
|
||||
private (Vector2, Vector2) GetPositionAndSize(Vector2 origin)
|
||||
{
|
||||
Vector2 pos = Config.AnchorToMouse ? ImGui.GetMousePos() + Config.Position : origin + Config.Position;
|
||||
Vector2 size = Config.Bar.Size;
|
||||
|
||||
if (Config.CircularMode)
|
||||
{
|
||||
size = new Vector2(Config.CircleRadius * 2, Config.CircleRadius * 2);
|
||||
pos += size / 2f;
|
||||
}
|
||||
|
||||
return (pos, size);
|
||||
}
|
||||
|
||||
protected override void DrawDraggableArea(Vector2 origin)
|
||||
{
|
||||
if (Config.AnchorToMouse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
base.DrawDraggableArea(origin);
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
CheckToggles();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Config.Bar.Position = Config.Position;
|
||||
Config.Bar.Anchor = Config.Anchor;
|
||||
Config.Bar.BackgroundColor = Config.BackgroundColor;
|
||||
Config.Bar.FillColor = Config.FillColor;
|
||||
Config.Bar.DrawBorder = Config.ShowBorder;
|
||||
|
||||
if (Config.Bar.Enabled)
|
||||
{
|
||||
DrawNormalBar(origin, elapsed, total);
|
||||
}
|
||||
else
|
||||
{
|
||||
var (pos, size) = GetPositionAndSize(origin);
|
||||
pos = Utils.GetAnchoredPosition(pos, size, Config.Anchor);
|
||||
|
||||
AddDrawAction(_config.StrataLevel, () =>
|
||||
{
|
||||
DrawCircularIndicator(pos, Config.CircleRadius, elapsed, total);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckToggles()
|
||||
{
|
||||
bool barEnabledChanged = _wasBarEnabled != Config.Bar.Enabled;
|
||||
if (barEnabledChanged)
|
||||
{
|
||||
Config.CircularMode = !Config.Bar.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool circularModeChanged = _wasCircularModeEnabled != Config.CircularMode;
|
||||
if (circularModeChanged)
|
||||
{
|
||||
Config.Bar.Enabled = !Config.CircularMode;
|
||||
}
|
||||
}
|
||||
|
||||
_wasBarEnabled = Config.Bar.Enabled;
|
||||
_wasCircularModeEnabled = Config.CircularMode;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// controls how smooth the arc looks
|
||||
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
|
||||
{
|
||||
// always draw until the queue threshold
|
||||
float progressAngle = Math.Min(current, total - (Config.ShowGCDQueueIndicator ? queueTime : 0f)) / total * endAngle;
|
||||
|
||||
// drawing an arc with thickness to make it look like an annular sector
|
||||
drawList.PathArcTo(position, radius, startAngle + offset, progressAngle + offset, segments);
|
||||
drawList.PathStroke(Config.FillColor.Base, ImDrawFlags.None, Config.CircleThickness);
|
||||
|
||||
// draw the queue indicator
|
||||
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);
|
||||
}
|
||||
|
||||
// anything that remains is background
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawNormalBar(Vector2 origin, float current, float total)
|
||||
{
|
||||
GCDBarConfig config = Config.Bar;
|
||||
|
||||
Rect mainRect = BarUtilities.GetFillRect(config.Position, config.Size, config.FillDirection, config.FillColor, current, total, 0);
|
||||
BarHud bar = new BarHud(config, null, null);
|
||||
bar.AddForegrounds(mainRect);
|
||||
|
||||
float currentPercent = current / total;
|
||||
float percentNonQueue = total != 0 ? 1F - (500f / 1000f) / total : 0;
|
||||
|
||||
if (percentNonQueue > 0 && currentPercent >= percentNonQueue && Config.ShowGCDQueueIndicator)
|
||||
{
|
||||
float scale = 1 - percentNonQueue;
|
||||
Vector2 size = config.FillDirection.IsHorizontal() ?
|
||||
new Vector2(config.Size.X * scale, config.Size.Y) :
|
||||
new Vector2(config.Size.X, config.Size.Y * scale);
|
||||
|
||||
Vector2 pos = config.Position;
|
||||
if (config.FillDirection == BarDirection.Right)
|
||||
{
|
||||
pos.X += config.Size.X * percentNonQueue;
|
||||
}
|
||||
else if (config.FillDirection == BarDirection.Down)
|
||||
{
|
||||
pos.Y += config.Size.Y * percentNonQueue;
|
||||
}
|
||||
|
||||
Rect foreground = BarUtilities.GetFillRect(pos, size, config.FillDirection, Config.QueueColor, currentPercent - percentNonQueue, scale, 0);
|
||||
bar.AddForegrounds(foreground);
|
||||
}
|
||||
|
||||
AddDrawActions(bar.GetDrawActions(origin, _config.StrataLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Party;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class GlobalColors : IDisposable
|
||||
{
|
||||
#region Singleton
|
||||
private MiscColorConfig _miscColorConfig = null!;
|
||||
private RolesColorConfig _rolesColorConfig = null!;
|
||||
|
||||
private Dictionary<uint, PluginConfigColor> ColorMap = null!;
|
||||
|
||||
private GlobalColors()
|
||||
{
|
||||
ConfigurationManager.Instance.ResetEvent += OnConfigReset;
|
||||
OnConfigReset(ConfigurationManager.Instance);
|
||||
}
|
||||
|
||||
private void OnConfigReset(ConfigurationManager sender)
|
||||
{
|
||||
_miscColorConfig = sender.GetConfigObject<MiscColorConfig>();
|
||||
_rolesColorConfig = sender.GetConfigObject<RolesColorConfig>();
|
||||
|
||||
var tanksColorConfig = sender.GetConfigObject<TanksColorConfig>();
|
||||
var healersColorConfig = sender.GetConfigObject<HealersColorConfig>();
|
||||
var meleeColorConfig = sender.GetConfigObject<MeleeColorConfig>();
|
||||
var rangedColorConfig = sender.GetConfigObject<RangedColorConfig>();
|
||||
var castersColorConfig = sender.GetConfigObject<CastersColorConfig>();
|
||||
|
||||
ColorMap = new Dictionary<uint, PluginConfigColor>()
|
||||
{
|
||||
// tanks
|
||||
[JobIDs.GLA] = tanksColorConfig.GLAColor,
|
||||
[JobIDs.MRD] = tanksColorConfig.MRDColor,
|
||||
[JobIDs.PLD] = tanksColorConfig.PLDColor,
|
||||
[JobIDs.WAR] = tanksColorConfig.WARColor,
|
||||
[JobIDs.DRK] = tanksColorConfig.DRKColor,
|
||||
[JobIDs.GNB] = tanksColorConfig.GNBColor,
|
||||
|
||||
// healers
|
||||
[JobIDs.CNJ] = healersColorConfig.CNJColor,
|
||||
[JobIDs.WHM] = healersColorConfig.WHMColor,
|
||||
[JobIDs.SCH] = healersColorConfig.SCHColor,
|
||||
[JobIDs.AST] = healersColorConfig.ASTColor,
|
||||
[JobIDs.SGE] = healersColorConfig.SGEColor,
|
||||
|
||||
// melee
|
||||
[JobIDs.PGL] = meleeColorConfig.PGLColor,
|
||||
[JobIDs.LNC] = meleeColorConfig.LNCColor,
|
||||
[JobIDs.ROG] = meleeColorConfig.ROGColor,
|
||||
[JobIDs.MNK] = meleeColorConfig.MNKColor,
|
||||
[JobIDs.DRG] = meleeColorConfig.DRGColor,
|
||||
[JobIDs.NIN] = meleeColorConfig.NINColor,
|
||||
[JobIDs.SAM] = meleeColorConfig.SAMColor,
|
||||
[JobIDs.RPR] = meleeColorConfig.RPRColor,
|
||||
[JobIDs.VPR] = meleeColorConfig.VPRColor,
|
||||
|
||||
// ranged
|
||||
[JobIDs.ARC] = rangedColorConfig.ARCColor,
|
||||
[JobIDs.BRD] = rangedColorConfig.BRDColor,
|
||||
[JobIDs.MCH] = rangedColorConfig.MCHColor,
|
||||
[JobIDs.DNC] = rangedColorConfig.DNCColor,
|
||||
|
||||
// casters
|
||||
[JobIDs.THM] = castersColorConfig.THMColor,
|
||||
[JobIDs.ACN] = castersColorConfig.ACNColor,
|
||||
[JobIDs.BLM] = castersColorConfig.BLMColor,
|
||||
[JobIDs.SMN] = castersColorConfig.SMNColor,
|
||||
[JobIDs.RDM] = castersColorConfig.RDMColor,
|
||||
[JobIDs.PCT] = castersColorConfig.PCTColor,
|
||||
[JobIDs.BLU] = castersColorConfig.BLUColor,
|
||||
|
||||
// crafters
|
||||
[JobIDs.CRP] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.BSM] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.ARM] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.GSM] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.LTW] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.WVR] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.ALC] = _rolesColorConfig.HANDColor,
|
||||
[JobIDs.CUL] = _rolesColorConfig.HANDColor,
|
||||
|
||||
// gatherers
|
||||
[JobIDs.MIN] = _rolesColorConfig.LANDColor,
|
||||
[JobIDs.BOT] = _rolesColorConfig.LANDColor,
|
||||
[JobIDs.FSH] = _rolesColorConfig.LANDColor
|
||||
};
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Instance = new GlobalColors();
|
||||
}
|
||||
|
||||
public static GlobalColors Instance { get; private set; } = null!;
|
||||
|
||||
~GlobalColors()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationManager.Instance.ResetEvent -= OnConfigReset;
|
||||
Instance = null!;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public PluginConfigColor? ColorForJobId(uint jobId) => ColorMap.TryGetValue(jobId, out PluginConfigColor? color) ? color : null;
|
||||
|
||||
public PluginConfigColor SafeColorForJobId(uint jobId) => ColorForJobId(jobId) ?? _miscColorConfig.NPCNeutralColor;
|
||||
|
||||
public PluginConfigColor? RoleColorForJobId(uint jobId)
|
||||
{
|
||||
JobRoles role = JobsHelper.RoleForJob(jobId);
|
||||
|
||||
return role switch
|
||||
{
|
||||
JobRoles.Tank => _rolesColorConfig.TankRoleColor,
|
||||
JobRoles.Healer => _rolesColorConfig.HealerRoleColor,
|
||||
JobRoles.DPSMelee => _rolesColorConfig.UseSpecificDPSColors ? _rolesColorConfig.MeleeDPSRoleColor : _rolesColorConfig.DPSRoleColor,
|
||||
JobRoles.DPSRanged => _rolesColorConfig.UseSpecificDPSColors ? _rolesColorConfig.RangedDPSRoleColor : _rolesColorConfig.DPSRoleColor,
|
||||
JobRoles.DPSCaster => _rolesColorConfig.UseSpecificDPSColors ? _rolesColorConfig.CasterDPSRoleColor : _rolesColorConfig.DPSRoleColor,
|
||||
JobRoles.Gatherer => _rolesColorConfig.LANDColor,
|
||||
JobRoles.Crafter => _rolesColorConfig.HANDColor,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public PluginConfigColor SafeRoleColorForJobId(uint jobId) => RoleColorForJobId(jobId) ?? _miscColorConfig.NPCNeutralColor;
|
||||
|
||||
public PluginConfigColor EmptyUnitFrameColor => _miscColorConfig.EmptyUnitFrameColor;
|
||||
public PluginConfigColor EmptyColor => _miscColorConfig.EmptyColor;
|
||||
public PluginConfigColor PartialFillColor => _miscColorConfig.PartialFillColor;
|
||||
public PluginConfigColor NPCFriendlyColor => _miscColorConfig.NPCFriendlyColor;
|
||||
public PluginConfigColor NPCHostileColor => _miscColorConfig.NPCHostileColor;
|
||||
public PluginConfigColor NPCNeutralColor => _miscColorConfig.NPCNeutralColor;
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Tanks", 0)]
|
||||
public class TanksColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static TanksColorConfig DefaultConfig() { return new TanksColorConfig(); }
|
||||
|
||||
[ColorEdit4("Paladin", spacing = true)]
|
||||
[Order(5)]
|
||||
public PluginConfigColor PLDColor = new PluginConfigColor(new(168f / 255f, 210f / 255f, 230f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Dark Knight")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor DRKColor = new PluginConfigColor(new(209f / 255f, 38f / 255f, 204f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Warrior")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor WARColor = new PluginConfigColor(new(207f / 255f, 38f / 255f, 33f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Gunbreaker")]
|
||||
[Order(20)]
|
||||
public PluginConfigColor GNBColor = new PluginConfigColor(new(121f / 255f, 109f / 255f, 48f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Gladiator", spacing = true)]
|
||||
[Order(25)]
|
||||
public PluginConfigColor GLAColor = new PluginConfigColor(new(168f / 255f, 210f / 255f, 230f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Marauder")]
|
||||
[Order(30)]
|
||||
public PluginConfigColor MRDColor = new PluginConfigColor(new(207f / 255f, 38f / 255f, 33f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Healers", 0)]
|
||||
public class HealersColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static HealersColorConfig DefaultConfig() { return new HealersColorConfig(); }
|
||||
|
||||
[ColorEdit4("Scholar", spacing = true)]
|
||||
[Order(5)]
|
||||
public PluginConfigColor SCHColor = new PluginConfigColor(new(134f / 255f, 87f / 255f, 255f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("White Mage")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor WHMColor = new PluginConfigColor(new(255f / 255f, 240f / 255f, 220f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Astrologian")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor ASTColor = new PluginConfigColor(new(255f / 255f, 231f / 255f, 74f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Sage")]
|
||||
[Order(20)]
|
||||
public PluginConfigColor SGEColor = new PluginConfigColor(new(144f / 255f, 176f / 255f, 255f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Conjurer", spacing = true)]
|
||||
[Order(25)]
|
||||
public PluginConfigColor CNJColor = new PluginConfigColor(new(255f / 255f, 240f / 255f, 220f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Melee", 0)]
|
||||
public class MeleeColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static MeleeColorConfig DefaultConfig() { return new MeleeColorConfig(); }
|
||||
|
||||
[ColorEdit4("Monk", spacing = true)]
|
||||
[Order(5)]
|
||||
public PluginConfigColor MNKColor = new PluginConfigColor(new(214f / 255f, 156f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Ninja")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor NINColor = new PluginConfigColor(new(175f / 255f, 25f / 255f, 100f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Dragoon")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor DRGColor = new PluginConfigColor(new(65f / 255f, 100f / 255f, 205f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Samurai")]
|
||||
[Order(20)]
|
||||
public PluginConfigColor SAMColor = new PluginConfigColor(new(228f / 255f, 109f / 255f, 4f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Reaper")]
|
||||
[Order(25)]
|
||||
public PluginConfigColor RPRColor = new PluginConfigColor(new(150f / 255f, 90f / 255f, 144f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Viper")]
|
||||
[Order(25)]
|
||||
public PluginConfigColor VPRColor = new PluginConfigColor(new(16f / 255f, 130f / 255f, 16f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Pugilist", spacing = true)]
|
||||
[Order(30)]
|
||||
public PluginConfigColor PGLColor = new PluginConfigColor(new(214f / 255f, 156f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Rogue")]
|
||||
[Order(35)]
|
||||
public PluginConfigColor ROGColor = new PluginConfigColor(new(175f / 255f, 25f / 255f, 100f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Lancer")]
|
||||
[Order(40)]
|
||||
public PluginConfigColor LNCColor = new PluginConfigColor(new(65f / 255f, 100f / 255f, 205f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Ranged", 0)]
|
||||
public class RangedColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static RangedColorConfig DefaultConfig() { return new RangedColorConfig(); }
|
||||
|
||||
[ColorEdit4("Bard", spacing = true)]
|
||||
[Order(5)]
|
||||
public PluginConfigColor BRDColor = new PluginConfigColor(new(145f / 255f, 186f / 255f, 94f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Machinist")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor MCHColor = new PluginConfigColor(new(110f / 255f, 225f / 255f, 214f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Dancer")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor DNCColor = new PluginConfigColor(new(226f / 255f, 176f / 255f, 175f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Archer", separator = true)]
|
||||
[Order(20)]
|
||||
public PluginConfigColor ARCColor = new PluginConfigColor(new(145f / 255f, 186f / 255f, 94f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Caster", 0)]
|
||||
public class CastersColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static CastersColorConfig DefaultConfig() { return new CastersColorConfig(); }
|
||||
|
||||
[ColorEdit4("Black Mage", spacing = true)]
|
||||
[Order(5)]
|
||||
public PluginConfigColor BLMColor = new PluginConfigColor(new(165f / 255f, 121f / 255f, 214f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Summoner")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor SMNColor = new PluginConfigColor(new(45f / 255f, 155f / 255f, 120f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Red Mage")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor RDMColor = new PluginConfigColor(new(232f / 255f, 123f / 255f, 123f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Pictomancer")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor PCTColor = new PluginConfigColor(new(252f / 255f, 146f / 255f, 225f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Blue Mage", spacing = true)]
|
||||
[Order(20)]
|
||||
public PluginConfigColor BLUColor = new PluginConfigColor(new(0f / 255f, 185f / 255f, 247f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Thaumaturge")]
|
||||
[Order(25)]
|
||||
public PluginConfigColor THMColor = new PluginConfigColor(new(165f / 255f, 121f / 255f, 214f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Arcanist")]
|
||||
[Order(30)]
|
||||
public PluginConfigColor ACNColor = new PluginConfigColor(new(45f / 255f, 155f / 255f, 120f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Roles", 0)]
|
||||
public class RolesColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static RolesColorConfig DefaultConfig() { return new RolesColorConfig(); }
|
||||
|
||||
[ColorEdit4("Tank")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor TankRoleColor = new PluginConfigColor(new(21f / 255f, 28f / 255f, 100f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("DPS")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor DPSRoleColor = new PluginConfigColor(new(153f / 255f, 23f / 255f, 23f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Healer")]
|
||||
[Order(20)]
|
||||
public PluginConfigColor HealerRoleColor = new PluginConfigColor(new(46f / 255f, 125f / 255f, 50f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Disciple of the Land", spacing = true)]
|
||||
[Order(25)]
|
||||
public PluginConfigColor LANDColor = new PluginConfigColor(new(99f / 255f, 172f / 255f, 14f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Disciple of the Hand")]
|
||||
[Order(30)]
|
||||
public PluginConfigColor HANDColor = new PluginConfigColor(new(99f / 255f, 172f / 255f, 14f / 255f, 100f / 100f));
|
||||
|
||||
[Checkbox("Use Specific DPS Colors", spacing = true)]
|
||||
[Order(35)]
|
||||
public bool UseSpecificDPSColors = false;
|
||||
|
||||
[ColorEdit4("Melee DPS")]
|
||||
[Order(40, collapseWith = nameof(UseSpecificDPSColors))]
|
||||
public PluginConfigColor MeleeDPSRoleColor = new PluginConfigColor(new(151f / 255f, 56f / 255f, 56f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Ranged DPS")]
|
||||
[Order(40, collapseWith = nameof(UseSpecificDPSColors))]
|
||||
public PluginConfigColor RangedDPSRoleColor = new PluginConfigColor(new(250f / 255f, 185f / 255f, 67f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Caster DPS")]
|
||||
[Order(40, collapseWith = nameof(UseSpecificDPSColors))]
|
||||
public PluginConfigColor CasterDPSRoleColor = new PluginConfigColor(new(154f / 255f, 82f / 255f, 193f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Colors")]
|
||||
[SubSection("Misc", 0)]
|
||||
public class MiscColorConfig : PluginConfigObject
|
||||
{
|
||||
public new static MiscColorConfig DefaultConfig() { return new MiscColorConfig(); }
|
||||
|
||||
[Combo("Gradient Type For Bars", "Flat Color", "Right", "Left", "Up", "Down", "Centered Horizontal", spacing = true)]
|
||||
[Order(4)]
|
||||
public GradientDirection GradientDirection = GradientDirection.Down;
|
||||
|
||||
[ColorEdit4("Empty Unit Frame", separator = true)]
|
||||
[Order(5)]
|
||||
public PluginConfigColor EmptyUnitFrameColor = new PluginConfigColor(new(0f / 255f, 0f / 255f, 0f / 255f, 95f / 100f));
|
||||
|
||||
[ColorEdit4("Empty Bar")]
|
||||
[Order(10)]
|
||||
public PluginConfigColor EmptyColor = new PluginConfigColor(new(0f / 255f, 0f / 255f, 0f / 255f, 50f / 100f));
|
||||
|
||||
[ColorEdit4("Partially Filled Bar")]
|
||||
[Order(15)]
|
||||
public PluginConfigColor PartialFillColor = new PluginConfigColor(new(180f / 255f, 180f / 255f, 180f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("NPC Friendly", separator = true)]
|
||||
[Order(20)]
|
||||
public PluginConfigColor NPCFriendlyColor = new PluginConfigColor(new(99f / 255f, 172f / 255f, 14f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("NPC Hostile")]
|
||||
[Order(25)]
|
||||
public PluginConfigColor NPCHostileColor = new PluginConfigColor(new(233f / 255f, 4f / 255f, 4f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("NPC Neutral")]
|
||||
[Order(30)]
|
||||
public PluginConfigColor NPCNeutralColor = new PluginConfigColor(new(218f / 255f, 157f / 255f, 46f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class ColorByHealthValueConfig : PluginConfigObject
|
||||
{
|
||||
|
||||
[Checkbox("Use Max Health Color")]
|
||||
[Order(5)]
|
||||
public bool UseMaxHealthColor = false;
|
||||
|
||||
[ColorEdit4("Max Health Color")]
|
||||
[Order(10, collapseWith = nameof(UseMaxHealthColor))]
|
||||
public PluginConfigColor MaxHealthColor = new PluginConfigColor(new(18f / 255f, 18f / 255f, 18f / 255f, 100f / 100f));
|
||||
|
||||
[Checkbox("Job Color as Max Health Color")]
|
||||
[Order(15, collapseWith = nameof(UseMaxHealthColor))]
|
||||
public bool UseJobColorAsMaxHealth = false;
|
||||
|
||||
[Checkbox("Job Role as Max Health Color")]
|
||||
[Order(20, collapseWith = nameof(UseMaxHealthColor))]
|
||||
public bool UseRoleColorAsMaxHealth = false;
|
||||
|
||||
[ColorEdit4("High Health Color")]
|
||||
[Order(25)]
|
||||
public PluginConfigColor FullHealthColor = new PluginConfigColor(new(0f / 255f, 255f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Low Health Color")]
|
||||
[Order(30)]
|
||||
public PluginConfigColor LowHealthColor = new PluginConfigColor(new(255f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[DragFloat("Max Health Color Above Health %", min = 50f, max = 100f, velocity = 1f)]
|
||||
[Order(35)]
|
||||
public float FullHealthColorThreshold = 75f;
|
||||
|
||||
[DragFloat("Low Health Color Below Health %", min = 0f, max = 50f, velocity = 1f)]
|
||||
[Order(40)]
|
||||
public float LowHealthColorThreshold = 25f;
|
||||
|
||||
[Combo("Blend Mode", "LAB", "LChab", "XYZ", "RGB", "LChuv", "Luv", "Jzazbz", "JzCzhz")]
|
||||
[Order(45)]
|
||||
public BlendMode BlendMode = BlendMode.LAB;
|
||||
}
|
||||
|
||||
public class ColorByHealthFieldsConverter : PluginConfigObjectConverter
|
||||
{
|
||||
public ColorByHealthFieldsConverter()
|
||||
{
|
||||
SameTypeFieldConverter<bool> enabled =
|
||||
new SameTypeFieldConverter<bool>("ColorByHealth.Enabled", false);
|
||||
FieldConvertersMap.Add("UseColorBasedOnHealthValue", enabled);
|
||||
|
||||
SameClassFieldConverter<PluginConfigColor> fullHealth =
|
||||
new SameClassFieldConverter<PluginConfigColor>("ColorByHealth.FullHealthColor", new PluginConfigColor(new(0f / 255f, 255f / 255f, 0f / 255f, 100f / 100f)));
|
||||
FieldConvertersMap.Add("FullHealthColor", fullHealth);
|
||||
|
||||
SameClassFieldConverter<PluginConfigColor> lowHealth =
|
||||
new SameClassFieldConverter<PluginConfigColor>("ColorByHealth.LowHealthColor", new PluginConfigColor(new(255f / 255f, 0f / 255f, 0f / 255f, 100f / 100f)));
|
||||
FieldConvertersMap.Add("LowHealthColor", lowHealth);
|
||||
|
||||
SameTypeFieldConverter<float> fullThreshold = new SameTypeFieldConverter<float>("ColorByHealth.FullHealthColorThreshold", 75f);
|
||||
FieldConvertersMap.Add("FullHealthColorThreshold", fullThreshold);
|
||||
|
||||
SameTypeFieldConverter<float> lowThreshold = new SameTypeFieldConverter<float>("ColorByHealth.LowHealthColorThreshold", 25f);
|
||||
FieldConvertersMap.Add("LowHealthColorThreshold", lowThreshold);
|
||||
|
||||
SameTypeFieldConverter<BlendMode> blendMode = new SameTypeFieldConverter<BlendMode>("ColorByHealth.BlendMode", BlendMode.LAB);
|
||||
FieldConvertersMap.Add("blendMode", blendMode);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(PartyFramesColorsConfig) ||
|
||||
objectType == typeof(UnitFrameConfig) ||
|
||||
objectType == typeof(PlayerUnitFrameConfig) ||
|
||||
objectType == typeof(TargetUnitFrameConfig) ||
|
||||
objectType == typeof(TargetOfTargetUnitFrameConfig) ||
|
||||
objectType == typeof(FocusTargetUnitFrameConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Disableable(false)]
|
||||
[Exportable(false)]
|
||||
[Section("Visibility")]
|
||||
[SubSection("Global", 0)]
|
||||
public class GlobalVisibilityConfig : PluginConfigObject
|
||||
{
|
||||
public new static GlobalVisibilityConfig DefaultConfig() { return new GlobalVisibilityConfig(); }
|
||||
|
||||
[NestedConfig("Visibility", 50, collapsingHeader = false)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
[JsonIgnore]
|
||||
private bool _applying = false;
|
||||
|
||||
[ManualDraw]
|
||||
public bool Draw(ref bool changed)
|
||||
{
|
||||
ImGui.NewLine();
|
||||
|
||||
if (ImGui.Button("Apply to all elements", new Vector2(200, 30)))
|
||||
{
|
||||
_applying = true;
|
||||
}
|
||||
|
||||
if (_applying)
|
||||
{
|
||||
string[] lines = new string[] { "This will replace the visibility settings", "for ALL HSUI elements!", "Are you sure?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("Apply?", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
ConfigurationManager.Instance.OnGlobalVisibilityChanged(VisibilityConfig);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_applying = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Exportable(false)]
|
||||
[Section("Misc")]
|
||||
[SubSection("Grid", 0)]
|
||||
public class GridConfig : PluginConfigObject
|
||||
{
|
||||
public new static GridConfig DefaultConfig()
|
||||
{
|
||||
var config = new GridConfig();
|
||||
config.Enabled = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
[DragFloat("Background Alpha", min = 0, max = 1, velocity = .05f)]
|
||||
[Order(10)]
|
||||
public float BackgroundAlpha = 0.3f;
|
||||
|
||||
[Checkbox("Show Center Lines")]
|
||||
[Order(15)]
|
||||
public bool ShowCenterLines = true;
|
||||
[Checkbox("Show Anchor Points")]
|
||||
[Order(20)]
|
||||
|
||||
public bool ShowAnchorPoints = true;
|
||||
[Checkbox("Grid Divisions", spacing = true)]
|
||||
[Order(25)]
|
||||
public bool ShowGrid = true;
|
||||
|
||||
[DragInt("Divisions Distance", min = 50, max = 500)]
|
||||
[Order(30, collapseWith = nameof(ShowGrid))]
|
||||
public int GridDivisionsDistance = 50;
|
||||
|
||||
[DragInt("Subdivision Count", min = 1, max = 10)]
|
||||
[Order(35, collapseWith = nameof(ShowGrid))]
|
||||
public int GridSubdivisionCount = 4;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Disableable(false)]
|
||||
[Section("Misc")]
|
||||
[SubSection("HUD Options", 0)]
|
||||
public class HUDOptionsConfig : PluginConfigObject
|
||||
{
|
||||
[Checkbox("Global HUD Position")]
|
||||
[Order(5)]
|
||||
public bool UseGlobalHudShift = false;
|
||||
|
||||
[DragInt2("Position", min = -4000, max = 4000)]
|
||||
[Order(6, collapseWith = nameof(UseGlobalHudShift))]
|
||||
public Vector2 HudOffset = new(0, 0);
|
||||
|
||||
[Checkbox("Dim HSUI's settings window when not focused")]
|
||||
[Order(10)]
|
||||
public bool DimConfigWindow = false;
|
||||
|
||||
[Checkbox("Automatically disable HUD elements preview", help = "If enabled, all HUD elements preview modes are disabled when HSUI's setting window is closed.")]
|
||||
[Order(11)]
|
||||
public bool AutomaticPreviewDisabling = true;
|
||||
|
||||
[Checkbox("Use HSUI style", help = "If enabled, HSUI will use its own style for the setting window instead of the general Dalamud style.")]
|
||||
[Order(12)]
|
||||
public bool OverrideDalamudStyle = true;
|
||||
|
||||
[Checkbox("Mouseover", separator = true)]
|
||||
[Order(15)]
|
||||
public bool MouseoverEnabled = true;
|
||||
|
||||
[Checkbox("Automatic Mode", help =
|
||||
"When enabled: All your actions will automatically assume mouseover when your cursor is on top of a unit frame.\n" +
|
||||
"Mouseover macros or other mouseover plugins are not necessary and WON'T WORK in this mode!\n\n" +
|
||||
"When disabled: HSUI unit frames will behave like the game's ones.\n" +
|
||||
"You'll need to use mouseover macros or other mouseover related plugins in this mode.")]
|
||||
[Order(16, collapseWith = nameof(MouseoverEnabled))]
|
||||
public bool MouseoverAutomaticMode = true;
|
||||
|
||||
//[Checkbox("Support Special Mouse Clicks", isMonitored = true, spacing = true, help =
|
||||
// "When enabled HSUI will attempt to support special mouse binds (mousewheel, M4, M5, etc) when the cursor\n" +
|
||||
// "is hovering on top of HSUI's unit frames.\n\n" +
|
||||
// "If you don't have actions bound to these mouse buttons, it is adviced that you leave this feature disabled.\n\n" +
|
||||
// "This feature can cause some issues such as click inputs not working in HSUI, or through out the game.\n" +
|
||||
// "If you run into these kinds of issues, you can try reloading HSUI, restarting the game, or disabling this feature.")]
|
||||
//[Order(17)]
|
||||
public bool InputsProxyEnabled = false;
|
||||
|
||||
[Checkbox("Hide Default HUD When Replaced", isMonitored = true, separator = true, help =
|
||||
"When enabled, HSUI automatically hides the default game HUD elements that HSUI replaces.\n" +
|
||||
"For example: when HSUI hotbars are on, game hotbars are hidden; when HSUI unit frames are on, game parameter/target bars are hidden; etc.")]
|
||||
[Order(38)]
|
||||
public bool HideDefaultHudWhenReplaced = true;
|
||||
|
||||
[Checkbox("Hide Default Job Gauges", isMonitored = true)]
|
||||
[Order(40)]
|
||||
public bool HideDefaultJobGauges = false;
|
||||
|
||||
[Checkbox("Hide Default Castbar", isMonitored = true)]
|
||||
[Order(45)]
|
||||
public bool HideDefaultCastbar = false;
|
||||
|
||||
[Checkbox("Hide Default Pulltimer", isMonitored = true)]
|
||||
[Order(50)]
|
||||
public bool HideDefaultPulltimer = false;
|
||||
|
||||
[Checkbox("Use Regional Number Format", help = "When enabled, HSUI will use your system's regional format settings when showing numbers.\nWhen disabled, HSUI will use English number formatting instead.", separator = true)]
|
||||
[Order(60)]
|
||||
public bool UseRegionalNumberFormats = true;
|
||||
|
||||
public new static HUDOptionsConfig DefaultConfig() => new();
|
||||
}
|
||||
|
||||
public class HUDOptionsConfigConverter : PluginConfigObjectConverter
|
||||
{
|
||||
public HUDOptionsConfigConverter()
|
||||
{
|
||||
Func<Vector2, Vector2[]> func = (value) =>
|
||||
{
|
||||
Vector2[] array = new Vector2[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
TypeToClassFieldConverter<Vector2, Vector2[]> castBar = new TypeToClassFieldConverter<Vector2, Vector2[]>(
|
||||
"CastBarOriginalPositions",
|
||||
new Vector2[] { Vector2.Zero, Vector2.Zero, Vector2.Zero, Vector2.Zero },
|
||||
func
|
||||
);
|
||||
|
||||
TypeToClassFieldConverter<Vector2, Vector2[]> pullTimer = new TypeToClassFieldConverter<Vector2, Vector2[]>(
|
||||
"PulltimerOriginalPositions",
|
||||
new Vector2[] { Vector2.Zero, Vector2.Zero, Vector2.Zero, Vector2.Zero },
|
||||
func
|
||||
);
|
||||
|
||||
NewClassFieldConverter<Dictionary<string, Vector2>, Dictionary<string, Vector2>[]> jobGauge =
|
||||
new NewClassFieldConverter<Dictionary<string, Vector2>, Dictionary<string, Vector2>[]>(
|
||||
"JobGaugeOriginalPositions",
|
||||
new Dictionary<string, Vector2>[] { new(), new(), new(), new() },
|
||||
(oldValue) =>
|
||||
{
|
||||
Dictionary<string, Vector2>[] array = new Dictionary<string, Vector2>[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
array[i] = oldValue;
|
||||
}
|
||||
|
||||
return array;
|
||||
});
|
||||
|
||||
FieldConvertersMap.Add("CastBarOriginalPosition", castBar);
|
||||
FieldConvertersMap.Add("PulltimerOriginalPosition", pullTimer);
|
||||
FieldConvertersMap.Add("JobGaugeOriginalPosition", jobGauge);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(HUDOptionsConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Config for a single hotbar (1-10). HotbarIndex is set by the containing config.
|
||||
/// </summary>
|
||||
public class HotbarBarConfig : AnchorablePluginConfigObject
|
||||
{
|
||||
internal int HotbarIndex { get; set; } = 1;
|
||||
|
||||
[RadioSelector("12×1", "6×2", "4×3", "3×4", "2×6", "1×12", Label = "Bar Layout")]
|
||||
[Order(20)]
|
||||
public int BarLayout = 0; // 0=12x1, 1=6x2, 2=4x3, 3=3x4, 4=2x6, 5=1x12
|
||||
|
||||
/// <summary>Get (columns, rows) for the current BarLayout.</summary>
|
||||
public (int Cols, int Rows) GetLayoutGrid() => BarLayout switch
|
||||
{
|
||||
0 => (12, 1),
|
||||
1 => (6, 2),
|
||||
2 => (4, 3),
|
||||
3 => (3, 4),
|
||||
4 => (2, 6),
|
||||
5 => (1, 12),
|
||||
_ => (12, 1)
|
||||
};
|
||||
|
||||
[DragInt("Slot Count", min = 1, max = 12)]
|
||||
[Order(21)]
|
||||
public int SlotCount = 12;
|
||||
|
||||
[DragInt2("Slot Size", min = 24, max = 96)]
|
||||
[Order(22)]
|
||||
public Vector2 SlotSize = new Vector2(40, 40);
|
||||
|
||||
[DragInt("Slot Padding", min = 0, max = 16)]
|
||||
[Order(23)]
|
||||
public int SlotPadding = 2;
|
||||
|
||||
[Checkbox("Show Cooldown Overlay")]
|
||||
[Order(24)]
|
||||
public bool ShowCooldownOverlay = true;
|
||||
|
||||
[Checkbox("Show Cooldown Numbers")]
|
||||
[Order(25)]
|
||||
public bool ShowCooldownNumbers = true;
|
||||
|
||||
[Checkbox("Show Border")]
|
||||
[Order(26)]
|
||||
public bool ShowBorder = true;
|
||||
|
||||
[Checkbox("Show Tooltips")]
|
||||
[Order(27)]
|
||||
public bool ShowTooltips = true;
|
||||
|
||||
[Checkbox("Show Keybinds")]
|
||||
[Order(28)]
|
||||
public bool ShowSlotNumbers = true;
|
||||
|
||||
[Checkbox("Show Combo Highlight")]
|
||||
[Order(29)]
|
||||
public bool ShowComboHighlight = true;
|
||||
|
||||
[Checkbox("Debug Drag & Drop")]
|
||||
[Order(30)]
|
||||
public bool DebugDragDrop = false;
|
||||
|
||||
[NestedConfig("Visibility", 70)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public static HotbarBarConfig DefaultConfig(int hotbarIndex)
|
||||
{
|
||||
var config = new HotbarBarConfig { HotbarIndex = hotbarIndex };
|
||||
ApplyDefaults(config, hotbarIndex);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected static void ApplyDefaults(HotbarBarConfig config, int hotbarIndex)
|
||||
{
|
||||
var viewport = ImGui.GetMainViewport().Size;
|
||||
float yOffset = 60 + (hotbarIndex - 1) * 50;
|
||||
config.Position = new Vector2(0, -viewport.Y * 0.5f + yOffset);
|
||||
config.Anchor = DrawAnchor.Top;
|
||||
config.Size = new Vector2(12 * 40 + 11 * 2, 40);
|
||||
config.HotbarIndex = hotbarIndex;
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("General", 0)]
|
||||
public class HotbarsConfig : PluginConfigObject
|
||||
{
|
||||
[Checkbox("Use HSUI Hotbars", help = "When enabled, HSUI hotbars replace the default game hotbars.")]
|
||||
[Order(1, collapseWith = null)]
|
||||
public new bool Enabled = true;
|
||||
|
||||
[NestedConfig("Drag & Drop Options", 5, separator = true, collapseWith = null)]
|
||||
public HotbarsGeneralOptionsConfig GeneralOptions = new();
|
||||
|
||||
public new static HotbarsConfig DefaultConfig() => new HotbarsConfig();
|
||||
}
|
||||
|
||||
public class HotbarsGeneralOptionsConfig : PluginConfigObject
|
||||
{
|
||||
[Checkbox("Enable drag and drop from game UI", help = "When enabled, you can drag actions, macros, and items from the Actions menu, Macro menu, and Inventory onto HSUI hotbars.")]
|
||||
[Order(1)]
|
||||
public bool EnableDragDropFromGame = true;
|
||||
|
||||
[Checkbox("Enable Shift+drag to rearrange", help = "When enabled, holding Shift and dragging a hotbar slot lets you swap it with another slot or rearrange your hotbar.")]
|
||||
[Order(2)]
|
||||
public bool EnableShiftDragToRearrange = true;
|
||||
|
||||
[Checkbox("Enable release outside to clear slot", help = "When enabled, releasing a picked-up icon outside of HSUI hotbars clears that slot.")]
|
||||
[Order(3)]
|
||||
public bool EnableReleaseOutsideToClear = true;
|
||||
|
||||
public new static HotbarsGeneralOptionsConfig DefaultConfig() => new();
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 1", 0)]
|
||||
public class Hotbar1BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar1BarConfig() => HotbarIndex = 1;
|
||||
public new static Hotbar1BarConfig DefaultConfig() { var c = new Hotbar1BarConfig(); ApplyDefaults(c, 1); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 2", 0)]
|
||||
public class Hotbar2BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar2BarConfig() => HotbarIndex = 2;
|
||||
public new static Hotbar2BarConfig DefaultConfig() { var c = new Hotbar2BarConfig(); ApplyDefaults(c, 2); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 3", 0)]
|
||||
public class Hotbar3BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar3BarConfig() => HotbarIndex = 3;
|
||||
public new static Hotbar3BarConfig DefaultConfig() { var c = new Hotbar3BarConfig(); ApplyDefaults(c, 3); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 4", 0)]
|
||||
public class Hotbar4BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar4BarConfig() => HotbarIndex = 4;
|
||||
public new static Hotbar4BarConfig DefaultConfig() { var c = new Hotbar4BarConfig(); ApplyDefaults(c, 4); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 5", 0)]
|
||||
public class Hotbar5BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar5BarConfig() => HotbarIndex = 5;
|
||||
public new static Hotbar5BarConfig DefaultConfig() { var c = new Hotbar5BarConfig(); ApplyDefaults(c, 5); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 6", 0)]
|
||||
public class Hotbar6BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar6BarConfig() => HotbarIndex = 6;
|
||||
public new static Hotbar6BarConfig DefaultConfig() { var c = new Hotbar6BarConfig(); ApplyDefaults(c, 6); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 7", 0)]
|
||||
public class Hotbar7BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar7BarConfig() => HotbarIndex = 7;
|
||||
public new static Hotbar7BarConfig DefaultConfig() { var c = new Hotbar7BarConfig(); ApplyDefaults(c, 7); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 8", 0)]
|
||||
public class Hotbar8BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar8BarConfig() => HotbarIndex = 8;
|
||||
public new static Hotbar8BarConfig DefaultConfig() { var c = new Hotbar8BarConfig(); ApplyDefaults(c, 8); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 9", 0)]
|
||||
public class Hotbar9BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar9BarConfig() => HotbarIndex = 9;
|
||||
public new static Hotbar9BarConfig DefaultConfig() { var c = new Hotbar9BarConfig(); ApplyDefaults(c, 9); return c; }
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Section("Hotbars", true)]
|
||||
[SubSection("Hotbar 10", 0)]
|
||||
public class Hotbar10BarConfig : HotbarBarConfig
|
||||
{
|
||||
public Hotbar10BarConfig() => HotbarIndex = 10;
|
||||
public new static Hotbar10BarConfig DefaultConfig() { var c = new Hotbar10BarConfig(); ApplyDefaults(c, 10); return c; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Disableable(false)]
|
||||
[Exportable(false)]
|
||||
[Section("Visibility")]
|
||||
[SubSection("Hotbars", 0)]
|
||||
public class HotbarsVisibilityConfig : PluginConfigObject
|
||||
{
|
||||
public new static HotbarsVisibilityConfig DefaultConfig() { return new HotbarsVisibilityConfig(); }
|
||||
|
||||
[NestedConfig("Hotbar 1", 50)]
|
||||
public VisibilityConfig HotbarConfig1 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 2", 51)]
|
||||
public VisibilityConfig HotbarConfig2 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 3", 52)]
|
||||
public VisibilityConfig HotbarConfig3 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 4", 53)]
|
||||
public VisibilityConfig HotbarConfig4 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 5", 54)]
|
||||
public VisibilityConfig HotbarConfig5 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 6", 55)]
|
||||
public VisibilityConfig HotbarConfig6 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 7", 56)]
|
||||
public VisibilityConfig HotbarConfig7 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 8", 57)]
|
||||
public VisibilityConfig HotbarConfig8 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 9", 58)]
|
||||
public VisibilityConfig HotbarConfig9 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Hotbar 10", 59)]
|
||||
public VisibilityConfig HotbarConfig10 = new VisibilityConfig();
|
||||
|
||||
[NestedConfig("Cross Hotbar", 60)]
|
||||
public VisibilityConfig HotbarConfigCross = new VisibilityConfig();
|
||||
|
||||
private List<VisibilityConfig> _configs;
|
||||
public List<VisibilityConfig> GetHotbarConfigs() => _configs;
|
||||
|
||||
public HotbarsVisibilityConfig()
|
||||
{
|
||||
_configs = new List<VisibilityConfig>() {
|
||||
HotbarConfig1,
|
||||
HotbarConfig2,
|
||||
HotbarConfig3,
|
||||
HotbarConfig4,
|
||||
HotbarConfig5,
|
||||
HotbarConfig6,
|
||||
HotbarConfig7,
|
||||
HotbarConfig8,
|
||||
HotbarConfig9,
|
||||
HotbarConfig10
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Party;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class IconConfig : AnchorablePluginConfigObject
|
||||
{
|
||||
[Anchor("Frame Anchor")]
|
||||
[Order(16)]
|
||||
public DrawAnchor FrameAnchor = DrawAnchor.Center;
|
||||
|
||||
// don't remove (used by json converter)
|
||||
public IconConfig()
|
||||
{
|
||||
Strata = StrataLevel.MID_HIGH;
|
||||
}
|
||||
|
||||
public IconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
{
|
||||
Position = position;
|
||||
Size = size;
|
||||
Anchor = anchor;
|
||||
FrameAnchor = frameAnchor;
|
||||
|
||||
Strata = StrataLevel.MID_HIGH;
|
||||
}
|
||||
}
|
||||
|
||||
public class IconWithLabelConfig : IconConfig
|
||||
{
|
||||
[NestedConfig("Label", 20)]
|
||||
public NumericLabelConfig NumericLabel = new NumericLabelConfig(Vector2.Zero, "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
|
||||
public IconWithLabelConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RoleJobIconConfig : IconConfig
|
||||
{
|
||||
public RoleJobIconConfig() : base() { }
|
||||
|
||||
public RoleJobIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
[Combo("Style", "Style 1", "Style 2", "Style 3", spacing = true)]
|
||||
[Order(25)]
|
||||
public int Style = 0;
|
||||
|
||||
[Checkbox("Use Role Icons", spacing = true)]
|
||||
[Order(30)]
|
||||
public bool UseRoleIcons = false;
|
||||
|
||||
[Checkbox("Use Specific DPS Role Icons")]
|
||||
[Order(35, collapseWith = nameof(UseRoleIcons))]
|
||||
public bool UseSpecificDPSRoleIcons = false;
|
||||
}
|
||||
|
||||
public class SignIconConfig : IconConfig
|
||||
{
|
||||
public SignIconConfig() : base() { }
|
||||
|
||||
public SignIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
[Checkbox("Preview")]
|
||||
[Order(35)]
|
||||
public bool Preview = false;
|
||||
|
||||
public uint? IconID(IGameObject? actor)
|
||||
{
|
||||
if (Preview)
|
||||
{
|
||||
return 61231;
|
||||
}
|
||||
|
||||
return Utils.SignIconIDForActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
public class NameplateIconConfig : IconConfig
|
||||
{
|
||||
public NameplateIconConfig() : base() { }
|
||||
|
||||
public NameplateIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
[Combo("Nameplate Label Anchor", new string[] { "Name", "Title", "Highest", "Lowest" }, spacing = true)]
|
||||
[Order(17)]
|
||||
public NameplateLabelAnchor NameplateLabelAnchor = NameplateLabelAnchor.Name;
|
||||
|
||||
[Checkbox("Prioritize Health Bar as Anchor when visible", help = "When enabled, the icon will anchor to the Health Bar if it's visible.\nIf the Health Bar disappears, it will anchor back to the desired label.")]
|
||||
[Order(18)]
|
||||
public bool PrioritizeHealthBarAnchor = false;
|
||||
}
|
||||
|
||||
public class NameplatePlayerIconConfig : NameplateIconConfig
|
||||
{
|
||||
public NameplatePlayerIconConfig() : base() { }
|
||||
|
||||
public NameplatePlayerIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
[Checkbox("Only show disconnected icon", spacing = true)]
|
||||
[Order(19)]
|
||||
public bool OnlyShowDisconnected = false;
|
||||
|
||||
public bool ShouldDrawIcon(int iconId)
|
||||
{
|
||||
if (!OnlyShowDisconnected) { return true; }
|
||||
|
||||
return (iconId >= 61503 && iconId <= 61505) ||
|
||||
(iconId >= 61553 && iconId <= 61555);
|
||||
}
|
||||
}
|
||||
|
||||
public class NameplateRoleJobIconConfig : RoleJobIconConfig
|
||||
{
|
||||
public NameplateRoleJobIconConfig() : base() { }
|
||||
|
||||
public NameplateRoleJobIconConfig(Vector2 position, Vector2 size, DrawAnchor anchor, DrawAnchor frameAnchor)
|
||||
: base(position, size, anchor, frameAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
[Combo("Nameplate Label Anchor", new string[] { "Name", "Title", "Highest", "Lowest" }, spacing = true)]
|
||||
[Order(17)]
|
||||
public NameplateLabelAnchor NameplateLabelAnchor = NameplateLabelAnchor.Name;
|
||||
|
||||
[Checkbox("Prioritize Health Bar as Anchor when visible", help = "When enabled, the icon will anchor to the Health Bar if it's visible.\nIf the Health Bar disappears, it will anchor back to the desired label.")]
|
||||
[Order(18)]
|
||||
public bool PrioritizeHealthBarAnchor = false;
|
||||
}
|
||||
|
||||
public class PartyFramesIconsConverter : PluginConfigObjectConverter
|
||||
{
|
||||
public PartyFramesIconsConverter()
|
||||
{
|
||||
SameTypeFieldConverter<DrawAnchor> converter = new SameTypeFieldConverter<DrawAnchor>("FrameAnchor", DrawAnchor.Center);
|
||||
FieldConvertersMap.Add("HealthBarAnchor", converter);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(PartyFramesRoleIconConfig) ||
|
||||
objectType == typeof(PartyFramesLeaderIconConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public enum NameplateLabelAnchor
|
||||
{
|
||||
Name = 0,
|
||||
Title = 1,
|
||||
Highest = 2,
|
||||
Lowest = 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
using Dalamud.Interface;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Exportable(false)]
|
||||
public class EditableLabelConfig : LabelConfig
|
||||
{
|
||||
[InputText("Text")]
|
||||
[Order(10)]
|
||||
public string Text;
|
||||
|
||||
public EditableLabelConfig(Vector2 position, string text, DrawAnchor frameAnchor, DrawAnchor textAnchor)
|
||||
: base(position, text, frameAnchor, textAnchor)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public override string GetText() => Text;
|
||||
|
||||
public override void SetText(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class EditableNonFormattableLabelConfig : LabelConfig
|
||||
{
|
||||
[InputText("Text", formattable = false)]
|
||||
[Order(10)]
|
||||
public string Text;
|
||||
|
||||
public EditableNonFormattableLabelConfig(Vector2 position, string text, DrawAnchor frameAnchor, DrawAnchor textAnchor)
|
||||
: base(position, text, frameAnchor, textAnchor)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public override string GetText() => Text;
|
||||
|
||||
public override void SetText(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class NumericLabelConfig : LabelConfig
|
||||
{
|
||||
[Combo("Number Format", "No Decimals (i.e. \"12\")", "One Decimal (i.e. \"12.3\")", "Two Decimals (i.e. \"12.34\")")]
|
||||
[Order(10)]
|
||||
public int NumberFormat;
|
||||
|
||||
[Combo("Rounding Mode", "Truncate", "Floor", "Ceil", "Round")]
|
||||
[Order(15)]
|
||||
public int NumberFunction;
|
||||
|
||||
[Checkbox("Hide Text When Zero")]
|
||||
[Order(65)]
|
||||
public bool HideIfZero = false;
|
||||
|
||||
public NumericLabelConfig(Vector2 position, string text, DrawAnchor frameAnchor, DrawAnchor textAnchor)
|
||||
: base(position, text, frameAnchor, textAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetValue(float value)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
_text = HideIfZero ? string.Empty : "0";
|
||||
return;
|
||||
}
|
||||
|
||||
int aux = (int)Math.Pow(10, NumberFormat);
|
||||
double textValue = value * aux;
|
||||
|
||||
textValue = NumberFunction switch
|
||||
{
|
||||
0 => Math.Truncate(textValue),
|
||||
1 => Math.Floor(textValue),
|
||||
2 => Math.Ceiling(textValue),
|
||||
3 => Math.Round(textValue),
|
||||
var _ => Math.Truncate(textValue)
|
||||
};
|
||||
|
||||
double v = textValue / aux;
|
||||
_text = v.ToString($"F{NumberFormat}", ConfigurationManager.Instance.ActiveCultreInfo);
|
||||
}
|
||||
|
||||
public override NumericLabelConfig Clone(int index) =>
|
||||
new NumericLabelConfig(Position, _text, FrameAnchor, TextAnchor)
|
||||
{
|
||||
Color = Color,
|
||||
OutlineColor = OutlineColor,
|
||||
ShadowConfig = ShadowConfig,
|
||||
ShowOutline = ShowOutline,
|
||||
FontID = FontID,
|
||||
UseJobColor = UseJobColor,
|
||||
Enabled = Enabled,
|
||||
HideIfZero = HideIfZero,
|
||||
ID = ID + "_{index}"
|
||||
};
|
||||
}
|
||||
|
||||
[DisableParentSettings("FontID")]
|
||||
[Exportable(false)]
|
||||
public class IconLabelConfig : LabelConfig
|
||||
{
|
||||
[DragFloat("Scale", min = 1, max = 5, velocity = 0.05f)]
|
||||
[Order(11)]
|
||||
public float FontScale = 1;
|
||||
|
||||
public FontAwesomeIcon IconId;
|
||||
|
||||
public IconLabelConfig(Vector2 position, FontAwesomeIcon iconId, DrawAnchor frameAnchor, DrawAnchor textAnchor) : base(position, "", frameAnchor, textAnchor)
|
||||
{
|
||||
IconId = iconId;
|
||||
}
|
||||
|
||||
public override string GetText() => IconId.ToIconString();
|
||||
public override float GetFontScale() => FontScale;
|
||||
}
|
||||
|
||||
[DisableParentSettings("FontID")]
|
||||
[Exportable(false)]
|
||||
public class DefaultFontLabelConfig : LabelConfig
|
||||
{
|
||||
[DragFloat("Scale", min = 1, max = 5, velocity = 0.05f)]
|
||||
[Order(11)]
|
||||
public float FontScale = 1;
|
||||
|
||||
public DefaultFontLabelConfig(Vector2 position, string text, DrawAnchor frameAnchor, DrawAnchor textAnchor)
|
||||
: base(position, text, frameAnchor, textAnchor)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool UseSystemFont() => true;
|
||||
public override float GetFontScale() => FontScale;
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class LabelConfig : MovablePluginConfigObject
|
||||
{
|
||||
[JsonIgnore] protected string _text;
|
||||
|
||||
[Font]
|
||||
[Order(15)]
|
||||
public string? FontID = null;
|
||||
|
||||
[Anchor("Frame Anchor")]
|
||||
[Order(20)]
|
||||
public DrawAnchor FrameAnchor = DrawAnchor.Center;
|
||||
|
||||
[Anchor("Text Anchor")]
|
||||
[Order(25)]
|
||||
public DrawAnchor TextAnchor = DrawAnchor.TopLeft;
|
||||
|
||||
[ColorEdit4("Color ##Text")]
|
||||
[Order(30)]
|
||||
public PluginConfigColor Color = new PluginConfigColor(Vector4.One);
|
||||
|
||||
[Checkbox("Outline")]
|
||||
[Order(35)]
|
||||
public bool ShowOutline = true;
|
||||
|
||||
[ColorEdit4("Color ##Outline")]
|
||||
[Order(40, collapseWith = nameof(ShowOutline))]
|
||||
public PluginConfigColor OutlineColor = new PluginConfigColor(Vector4.UnitW);
|
||||
|
||||
[NestedConfig("Shadow", 45)]
|
||||
public ShadowConfig ShadowConfig = new ShadowConfig() { Enabled = false };
|
||||
|
||||
[Checkbox("Use Job Color", spacing = true)]
|
||||
[Order(60)]
|
||||
public bool UseJobColor = false;
|
||||
|
||||
[Checkbox("Use Role Color")]
|
||||
[Order(65)]
|
||||
public bool UseRoleColor = false;
|
||||
|
||||
public LabelConfig(Vector2 position, string text, DrawAnchor frameAnchor, DrawAnchor textAnchor)
|
||||
{
|
||||
Position = position;
|
||||
_text = text;
|
||||
FrameAnchor = frameAnchor;
|
||||
TextAnchor = textAnchor;
|
||||
Position = position;
|
||||
|
||||
Strata = StrataLevel.HIGHEST;
|
||||
}
|
||||
|
||||
public virtual string GetText() => _text;
|
||||
|
||||
public virtual void SetText(string text)
|
||||
{
|
||||
_text = text;
|
||||
}
|
||||
|
||||
public virtual PluginConfigColor GetColor() => Color;
|
||||
|
||||
public virtual PluginConfigColor GetOutlineColor() => OutlineColor;
|
||||
|
||||
public virtual bool UseSystemFont() => false;
|
||||
public virtual float GetFontScale() => 1;
|
||||
|
||||
public virtual LabelConfig Clone(int index) =>
|
||||
new LabelConfig(Position, _text, FrameAnchor, TextAnchor)
|
||||
{
|
||||
Color = Color,
|
||||
OutlineColor = OutlineColor,
|
||||
ShadowConfig = ShadowConfig,
|
||||
ShowOutline = ShowOutline,
|
||||
FontID = FontID,
|
||||
UseJobColor = UseJobColor,
|
||||
Enabled = Enabled,
|
||||
ID = ID + "_{index}"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Interface;
|
||||
using HSUI.Config;
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Lumina.Excel.Sheets;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class LabelHud : HudElement
|
||||
{
|
||||
private LabelConfig Config => (LabelConfig)_config;
|
||||
|
||||
public LabelHud(LabelConfig config) : base(config)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateDrawActions(Vector2 origin)
|
||||
{
|
||||
// unused
|
||||
}
|
||||
|
||||
public override void Draw(Vector2 origin)
|
||||
{
|
||||
Draw(origin);
|
||||
}
|
||||
|
||||
public virtual void Draw(
|
||||
Vector2 origin,
|
||||
Vector2? parentSize = null,
|
||||
IGameObject? actor = null,
|
||||
string? actorName = null,
|
||||
uint? actorCurrentHp = null,
|
||||
uint? actorMaxHp = null,
|
||||
bool? isPlayerName = null,
|
||||
string? title = null)
|
||||
{
|
||||
if (!Config.Enabled || Config.GetText() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string? text = actor == null && actorName == null && actorCurrentHp == null && actorMaxHp == null && title == null ?
|
||||
Config.GetText() :
|
||||
TextTagsHelper.FormattedText(Config.GetText(), actor, actorName, actorCurrentHp, actorMaxHp, isPlayerName, title);
|
||||
|
||||
DrawLabel(text, origin, parentSize ?? Vector2.Zero, actor);
|
||||
}
|
||||
|
||||
protected virtual void DrawLabel(string text, Vector2 parentPos, Vector2 parentSize, IGameObject? actor = null)
|
||||
{
|
||||
Vector2 size;
|
||||
Vector2 pos;
|
||||
|
||||
if (Config.UseSystemFont())
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.DefaultFont);
|
||||
size = ImGui.CalcTextSize(text) * Config.GetFontScale();
|
||||
pos = Utils.GetAnchoredPosition(Utils.GetAnchoredPosition(parentPos + Config.Position, -parentSize, Config.FrameAnchor), size, Config.TextAnchor);
|
||||
ImGui.PopFont();
|
||||
}
|
||||
else
|
||||
{
|
||||
using (FontsManager.Instance.PushFont(Config.FontID))
|
||||
{
|
||||
size = ImGui.CalcTextSize(text) * Config.GetFontScale();
|
||||
pos = Utils.GetAnchoredPosition(Utils.GetAnchoredPosition(parentPos + Config.Position, -parentSize, Config.FrameAnchor), size, Config.TextAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
DrawLabel(text, pos, size, Color(actor));
|
||||
}
|
||||
|
||||
public void DrawLabel(string text, Vector2 pos, Vector2 size, PluginConfigColor color, float? alpha = null)
|
||||
{
|
||||
if (!Config.Enabled) { return; }
|
||||
|
||||
PluginConfigColor fillColor = color;
|
||||
PluginConfigColor shadowColor = Config.ShadowConfig.Color;
|
||||
PluginConfigColor outlineColor = Config.GetOutlineColor();
|
||||
|
||||
if (alpha.HasValue)
|
||||
{
|
||||
fillColor = fillColor.WithAlpha(alpha.Value);
|
||||
shadowColor = shadowColor.WithAlpha(alpha.Value);
|
||||
outlineColor = outlineColor.WithAlpha(alpha.Value);
|
||||
}
|
||||
|
||||
Action<ImDrawListPtr> action = (ImDrawListPtr drawList) =>
|
||||
{
|
||||
if (Config.ShadowConfig.Enabled)
|
||||
{
|
||||
DrawHelper.DrawShadowText(text, pos, fillColor.Base, shadowColor.Base, drawList, Config.ShadowConfig.Offset, Config.ShadowConfig.Thickness);
|
||||
}
|
||||
|
||||
if (Config.ShowOutline)
|
||||
{
|
||||
DrawHelper.DrawOutlinedText(text, pos, fillColor.Base, outlineColor.Base, drawList);
|
||||
}
|
||||
|
||||
if (!Config.ShowOutline && !Config.ShadowConfig.Enabled)
|
||||
{
|
||||
drawList.AddText(pos, fillColor.Base, text);
|
||||
}
|
||||
};
|
||||
|
||||
DrawHelper.DrawInWindow(ID, pos, size, false, (drawList) =>
|
||||
{
|
||||
if (Config.UseSystemFont())
|
||||
{
|
||||
ImGui.SetWindowFontScale(Config.GetFontScale());
|
||||
ImGui.PushFont(UiBuilder.DefaultFont);
|
||||
action(drawList);
|
||||
ImGui.PopFont();
|
||||
ImGui.SetWindowFontScale(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (FontsManager.Instance.PushFont(Config.FontID))
|
||||
{
|
||||
action(drawList);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public virtual PluginConfigColor Color(IGameObject? actor = null)
|
||||
{
|
||||
switch (Config.UseJobColor)
|
||||
{
|
||||
case true when (actor is ICharacter || actor is IBattleNpc battleNpc && battleNpc.ClassJob.RowId > 0):
|
||||
return ColorUtils.ColorForActor(actor);
|
||||
case true when actor is not ICharacter:
|
||||
return GlobalColors.Instance.NPCFriendlyColor;
|
||||
}
|
||||
|
||||
switch (Config.UseRoleColor)
|
||||
{
|
||||
case true when (actor is ICharacter || actor is IBattleNpc battleNpc && battleNpc.ClassJob.RowId > 0):
|
||||
{
|
||||
ICharacter? character = actor as ICharacter;
|
||||
return character != null && character.ClassJob.RowId > 0 ?
|
||||
GlobalColors.Instance.SafeRoleColorForJobId(character.ClassJob.RowId) :
|
||||
ColorUtils.ColorForActor(character);
|
||||
}
|
||||
case true when actor is not ICharacter:
|
||||
return GlobalColors.Instance.NPCFriendlyColor;
|
||||
default:
|
||||
return Config.GetColor();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual (string, Vector2, Vector2, PluginConfigColor) PreCalculate(
|
||||
Vector2 origin,
|
||||
Vector2? parentSize = null,
|
||||
IGameObject? actor = null,
|
||||
string? actorName = null,
|
||||
uint? actorCurrentHp = null,
|
||||
uint? actorMaxHp = null,
|
||||
bool? isPlayerName = null,
|
||||
string? title = null)
|
||||
{
|
||||
if (!Config.Enabled || Config.GetText() == null)
|
||||
{
|
||||
return ("", Vector2.Zero, Vector2.Zero, Color(null));
|
||||
}
|
||||
|
||||
string? text = actor == null && actorName == null && actorCurrentHp == null && actorMaxHp == null && title == null ?
|
||||
Config.GetText() :
|
||||
TextTagsHelper.FormattedText(Config.GetText(), actor, actorName, actorCurrentHp, actorMaxHp, isPlayerName, title);
|
||||
|
||||
Vector2 pSize = parentSize ?? Vector2.Zero;
|
||||
Vector2 size;
|
||||
Vector2 pos;
|
||||
|
||||
if (Config.UseSystemFont())
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.DefaultFont);
|
||||
size = ImGui.CalcTextSize(text) * Config.GetFontScale();
|
||||
pos = Utils.GetAnchoredPosition(Utils.GetAnchoredPosition(origin + Config.Position, -pSize, Config.FrameAnchor), size, Config.TextAnchor);
|
||||
ImGui.PopFont();
|
||||
}
|
||||
else
|
||||
{
|
||||
using (FontsManager.Instance.PushFont(Config.FontID))
|
||||
{
|
||||
size = ImGui.CalcTextSize(text) * Config.GetFontScale();
|
||||
pos = Utils.GetAnchoredPosition(Utils.GetAnchoredPosition(origin + Config.Position, -pSize, Config.FrameAnchor), size, Config.TextAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
return (text, pos, size, Color(actor));
|
||||
}
|
||||
}
|
||||
|
||||
public class IconLabelHud : LabelHud
|
||||
{
|
||||
private IconLabelConfig Config => (IconLabelConfig)_config;
|
||||
|
||||
public IconLabelHud(IconLabelConfig config) : base(config)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Draw(Vector2 origin,
|
||||
Vector2? parentSize = null,
|
||||
IGameObject? actor = null,
|
||||
string? actorName = null,
|
||||
uint? actorCurrentHp = null,
|
||||
uint? actorMaxHp = null,
|
||||
bool? isPlayerName = null,
|
||||
string? title = null)
|
||||
{
|
||||
string? text = Config.GetText();
|
||||
if (!Config.Enabled || text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrawLabel(text, origin, parentSize ?? Vector2.Zero, actor);
|
||||
}
|
||||
|
||||
protected override void DrawLabel(string text, Vector2 parentPos, Vector2 parentSize, IGameObject? actor = null)
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
Vector2 size = ImGui.CalcTextSize(text) * Config.GetFontScale();
|
||||
Vector2 pos = Utils.GetAnchoredPosition(Utils.GetAnchoredPosition(parentPos + Config.Position, -parentSize, Config.FrameAnchor), size, Config.TextAnchor);
|
||||
ImGui.PopFont();
|
||||
|
||||
DrawHelper.DrawInWindow(ID, pos, size, false, (drawList) =>
|
||||
{
|
||||
ImGui.SetWindowFontScale(Config.GetFontScale());
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
|
||||
PluginConfigColor? color = Color(actor);
|
||||
|
||||
if (Config.ShadowConfig.Enabled)
|
||||
{
|
||||
DrawHelper.DrawShadowText(text, pos, color.Base, Config.ShadowConfig.Color.Base, drawList, Config.ShadowConfig.Offset, Config.ShadowConfig.Thickness);
|
||||
}
|
||||
|
||||
if (Config.ShowOutline)
|
||||
{
|
||||
DrawHelper.DrawOutlinedText(text, pos, color.Base, Config.OutlineColor.Base, drawList);
|
||||
}
|
||||
|
||||
if (!Config.ShowOutline && !Config.ShadowConfig.Enabled)
|
||||
{
|
||||
drawList.AddText(pos, color.Base, text);
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
ImGui.SetWindowFontScale(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Section("Other Elements")]
|
||||
[SubSection("Limit Break", 0)]
|
||||
public class LimitBreakConfig : ChunkedProgressBarConfig
|
||||
{
|
||||
[NestedConfig("Visibility", 70)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public LimitBreakConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor) : base(position, size, fillColor)
|
||||
{
|
||||
}
|
||||
|
||||
public new static LimitBreakConfig DefaultConfig()
|
||||
{
|
||||
var config = new LimitBreakConfig(
|
||||
new Vector2(0, -ImGui.GetMainViewport().Size.Y * 0.4f),
|
||||
new Vector2(500, 10),
|
||||
new PluginConfigColor(new Vector4(255f / 255f, 255f / 255f, 0f / 255f, 100f / 100f)));
|
||||
|
||||
config.HideWhenInactive = true;
|
||||
config.UsePartialFillColor = true;
|
||||
config.PartialFillColor = new PluginConfigColor(new Vector4(0f / 255f, 181f / 255f, 255f / 255f, 100f / 100f));
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class LimitBreakHud : DraggableHudElement, IHudElementWithActor, IHudElementWithVisibilityConfig
|
||||
{
|
||||
private LimitBreakConfig Config => (LimitBreakConfig)_config;
|
||||
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
|
||||
|
||||
public IGameObject? Actor { get; set; } = null;
|
||||
|
||||
public LimitBreakHud(LimitBreakConfig config, string displayName) : base(config, displayName) { }
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
return (new List<Vector2>() { Config.Position }, new List<Vector2>() { Config.Size });
|
||||
}
|
||||
|
||||
public override unsafe void DrawChildren(Vector2 origin)
|
||||
{
|
||||
Config.Label.SetText("");
|
||||
|
||||
if (!Config.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LimitBreakController* lbController = LimitBreakController.Instance();
|
||||
AddonHWDAetherGauge* caGauge = (AddonHWDAetherGauge*) Plugin.GameGui.GetAddonByName("HWDAetherGauge", 1).Address;
|
||||
|
||||
int currentLimitBreak = lbController->CurrentUnits;
|
||||
int maxLimitBreak = lbController->BarUnits * lbController->BarCount;
|
||||
int limitBreakChunks = lbController->BarCount;
|
||||
|
||||
if (caGauge != null)
|
||||
{
|
||||
currentLimitBreak = caGauge->MaxGaugeValue;
|
||||
maxLimitBreak = 1000;
|
||||
limitBreakChunks = 5;
|
||||
}
|
||||
|
||||
int valuePerChunk = limitBreakChunks == 0 ? 0 : maxLimitBreak / limitBreakChunks;
|
||||
int currentChunksFilled = valuePerChunk == 0 ? 0 : currentLimitBreak / valuePerChunk;
|
||||
|
||||
if (Config.HideWhenInactive && limitBreakChunks == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Config.Label.SetValue(currentChunksFilled);
|
||||
|
||||
BarHud[] bars = BarUtilities.GetChunkedProgressBars(Config, limitBreakChunks, currentLimitBreak, maxLimitBreak);
|
||||
foreach (BarHud bar in bars)
|
||||
{
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.StrataLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[DisableParentSettings("Position")]
|
||||
[Section("Other Elements")]
|
||||
[SubSection("MP Ticker", 0)]
|
||||
public class MPTickerConfig : MovablePluginConfigObject
|
||||
{
|
||||
[Checkbox("Hide on Full MP", spacing = false)]
|
||||
[Order(15)]
|
||||
public bool HideOnFullMP = true;
|
||||
|
||||
[Checkbox("Enable Only for BLM")]
|
||||
[Order(20)]
|
||||
public bool EnableOnlyForBLM = false;
|
||||
|
||||
[Checkbox("Show Only During Umbral Ice")]
|
||||
[Order(25, collapseWith = nameof(EnableOnlyForBLM))]
|
||||
public bool ShowOnlyDuringUmbralIce = true;
|
||||
|
||||
[NestedConfig("MP Ticker Bar", 30)]
|
||||
public MPTickerBarConfig Bar = new MPTickerBarConfig(
|
||||
Vector2.Zero,
|
||||
new Vector2(254, 8),
|
||||
new PluginConfigColor(new(240f / 255f, 92f / 255f, 232f / 255f, 100f / 100f))
|
||||
);
|
||||
|
||||
[NestedConfig("Visibility", 70)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public new static MPTickerConfig DefaultConfig()
|
||||
{
|
||||
var config = new MPTickerConfig();
|
||||
config.Enabled = false;
|
||||
config.Bar.Position = new Vector2(0, HUDConstants.BaseHUDOffsetY + 27);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[DisableParentSettings("HideWhenInactive")]
|
||||
[Exportable(false)]
|
||||
public class MPTickerBarConfig : BarConfig
|
||||
{
|
||||
[NestedConfig("Fire III Threshold (BLM only)", 50, separator = false, spacing = true)]
|
||||
public MPTickerFire3ThresholdConfig Fire3Threshold = new MPTickerFire3ThresholdConfig();
|
||||
|
||||
public MPTickerBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor)
|
||||
: base(position, size, fillColor)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[DisableParentSettings("Value")]
|
||||
public class MPTickerFire3ThresholdConfig : ThresholdConfig
|
||||
{
|
||||
[DragFloat("Estimated Fire III Cast Time", min = 0f, max = 10)]
|
||||
[Order(11)]
|
||||
public float Fire3CastTime = 1.5f;
|
||||
|
||||
public MPTickerFire3ThresholdConfig()
|
||||
{
|
||||
Enabled = false;
|
||||
ThresholdType = ThresholdType.Above;
|
||||
ShowMarker = true;
|
||||
MarkerColor = new(new Vector4(255f / 255f, 136f / 255f, 0 / 255f, 90f / 100f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using HSUI.Interface.Bars;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.JobGauge.Types;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class MPTickerHud : DraggableHudElement, IHudElementWithActor, IHudElementWithVisibilityConfig
|
||||
{
|
||||
private MPTickerConfig Config => (MPTickerConfig)_config;
|
||||
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
|
||||
|
||||
private MPTickHelper _mpTickHelper = null!;
|
||||
public IGameObject? Actor { get; set; } = null;
|
||||
|
||||
public MPTickerHud(MPTickerConfig config, string displayName) : base(config, displayName) { }
|
||||
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
_mpTickHelper?.Dispose();
|
||||
}
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
return (new List<Vector2>() { Config.Position + Config.Bar.Position },
|
||||
new List<Vector2>() { Config.Bar.Size });
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
if (!Config.Enabled || Actor == null || Actor is not IPlayerCharacter player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// full mp
|
||||
if (Config.HideOnFullMP && player.CurrentMp >= player.MaxMp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// BLM specific settings
|
||||
if (Config.EnableOnlyForBLM)
|
||||
{
|
||||
if (player.ClassJob.RowId != JobIDs.BLM)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var gauge = Plugin.JobGauges.Get<BLMGauge>();
|
||||
if (Config.ShowOnlyDuringUmbralIce && !gauge.InUmbralIce)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_mpTickHelper ??= new MPTickHelper();
|
||||
|
||||
var now = ImGui.GetTime();
|
||||
var scale = (float)((now - _mpTickHelper.LastTick) / MPTickHelper.ServerTickRate);
|
||||
|
||||
if (scale <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (scale > 1)
|
||||
{
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
MPTickerFire3ThresholdConfig? thresholdConfig = GetFire3ThresholdConfig();
|
||||
BarHud bar = BarUtilities.GetProgressBar(Config.Bar, thresholdConfig, null, scale, 1, 0, fillColor: Config.Bar.FillColor);
|
||||
|
||||
AddDrawActions(bar.GetDrawActions(origin + Config.Position, _config.StrataLevel));
|
||||
}
|
||||
|
||||
private MPTickerFire3ThresholdConfig? GetFire3ThresholdConfig()
|
||||
{
|
||||
if (Actor is not IPlayerCharacter player || player.ClassJob.RowId != JobIDs.BLM)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MPTickerFire3ThresholdConfig config = Config.Bar.Fire3Threshold;
|
||||
if (!config.Enabled)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
bool leyLinesActive = Utils.StatusListForBattleChara(player).Any(e => e.StatusId == 738);
|
||||
float castTime = config.Fire3CastTime * (leyLinesActive ? 0.85f : 1f);
|
||||
|
||||
// tick rate is 3s
|
||||
// adding 0.3f as "safety net"
|
||||
config.Value = (3 - castTime + 0.3f) / 3;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[DisableParentSettings("HideWhenInactive", "Label")]
|
||||
[Section("Mana Bars")]
|
||||
[SubSection("Player", 0)]
|
||||
public class PlayerPrimaryResourceConfig : UnitFramePrimaryResourceConfig
|
||||
{
|
||||
public PlayerPrimaryResourceConfig(Vector2 position, Vector2 size)
|
||||
: base(position, size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new static PlayerPrimaryResourceConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(HUDConstants.DefaultBigUnitFrameSize.X, 10);
|
||||
var pos = new Vector2(0, 0);
|
||||
|
||||
var config = new PlayerPrimaryResourceConfig(pos, size);
|
||||
config.Anchor = DrawAnchor.Bottom;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive", "Label")]
|
||||
[Section("Mana Bars")]
|
||||
[SubSection("Target", 0)]
|
||||
public class TargetPrimaryResourceConfig : UnitFramePrimaryResourceConfig
|
||||
{
|
||||
public TargetPrimaryResourceConfig(Vector2 position, Vector2 size)
|
||||
: base(position, size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new static TargetPrimaryResourceConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(HUDConstants.DefaultBigUnitFrameSize.X, 10);
|
||||
var pos = new Vector2(0, 0);
|
||||
|
||||
var config = new TargetPrimaryResourceConfig(pos, size);
|
||||
config.Anchor = DrawAnchor.Bottom;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive", "Label")]
|
||||
[Section("Mana Bars")]
|
||||
[SubSection("Target of Target", 0)]
|
||||
public class TargetOfTargetPrimaryResourceConfig : UnitFramePrimaryResourceConfig
|
||||
{
|
||||
public TargetOfTargetPrimaryResourceConfig(Vector2 position, Vector2 size)
|
||||
: base(position, size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new static TargetOfTargetPrimaryResourceConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(HUDConstants.DefaultSmallUnitFrameSize.X, 10);
|
||||
var pos = new Vector2(0, 0);
|
||||
|
||||
var config = new TargetOfTargetPrimaryResourceConfig(pos, size);
|
||||
config.Anchor = DrawAnchor.Bottom;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive", "Label")]
|
||||
[Section("Mana Bars")]
|
||||
[SubSection("Focus Target", 0)]
|
||||
public class FocusTargetPrimaryResourceConfig : UnitFramePrimaryResourceConfig
|
||||
{
|
||||
public FocusTargetPrimaryResourceConfig(Vector2 position, Vector2 size)
|
||||
: base(position, size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new static FocusTargetPrimaryResourceConfig DefaultConfig()
|
||||
{
|
||||
var size = new Vector2(HUDConstants.DefaultSmallUnitFrameSize.X, 10);
|
||||
var pos = new Vector2(0, 0);
|
||||
|
||||
var config = new FocusTargetPrimaryResourceConfig(pos, size);
|
||||
config.Anchor = DrawAnchor.Bottom;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class UnitFramePrimaryResourceConfig : PrimaryResourceConfig
|
||||
{
|
||||
[Checkbox("Anchor to Unit Frame")]
|
||||
[Order(16)]
|
||||
public bool AnchorToUnitFrame = true;
|
||||
|
||||
[Anchor("Unit Frame Anchor")]
|
||||
[Order(17, collapseWith = nameof(AnchorToUnitFrame))]
|
||||
public DrawAnchor UnitFrameAnchor = DrawAnchor.Bottom;
|
||||
|
||||
[NestedConfig("Visibility", 1200)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public UnitFramePrimaryResourceConfig(Vector2 position, Vector2 size)
|
||||
: base(position, size)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class PrimaryResourceConfig : ProgressBarConfig
|
||||
{
|
||||
[Checkbox("Use Job Color", spacing = true)]
|
||||
[Order(19)]
|
||||
public bool UseJobColor = false;
|
||||
|
||||
[Checkbox("Hide When Full", spacing = true)]
|
||||
[Order(41)]
|
||||
public bool HidePrimaryResourceWhenFull = false;
|
||||
|
||||
[NestedConfig("Label", 1000, separator = false, spacing = true)]
|
||||
public EditableLabelConfig ValueLabel = new EditableLabelConfig(Vector2.Zero, "[mana:current]", DrawAnchor.Center, DrawAnchor.Center);
|
||||
|
||||
public PrimaryResourceConfig(Vector2 position, Vector2 size)
|
||||
: base(position, size, new(new(0 / 255f, 162f / 255f, 252f / 255f, 100f / 100f)))
|
||||
{
|
||||
Strata = StrataLevel.LOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using System;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using HSUI.Interface.Party;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class PrimaryResourceHud : ParentAnchoredDraggableHudElement, IHudElementWithActor, IHudElementWithAnchorableParent, IHudElementWithVisibilityConfig
|
||||
{
|
||||
private PrimaryResourceConfig Config => (PrimaryResourceConfig)_config;
|
||||
public VisibilityConfig? VisibilityConfig => Config is UnitFramePrimaryResourceConfig config ? config.VisibilityConfig : null;
|
||||
|
||||
public PrimaryResourceTypes ResourceType = PrimaryResourceTypes.MP;
|
||||
|
||||
private IGameObject? _actor;
|
||||
public IGameObject? Actor
|
||||
{
|
||||
get => _actor;
|
||||
set
|
||||
{
|
||||
if (value is IPlayerCharacter chara)
|
||||
{
|
||||
_actor = value;
|
||||
|
||||
JobRoles role = JobsHelper.RoleForJob(chara.ClassJob.RowId);
|
||||
ResourceType = JobsHelper.PrimaryResourceTypesByRole[role];
|
||||
}
|
||||
else
|
||||
{
|
||||
_actor = null;
|
||||
ResourceType = PrimaryResourceTypes.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IPartyFramesMember? PartyMember;
|
||||
|
||||
protected override bool AnchorToParent => Config is UnitFramePrimaryResourceConfig config ? config.AnchorToUnitFrame : false;
|
||||
protected override DrawAnchor ParentAnchor => Config is UnitFramePrimaryResourceConfig config ? config.UnitFrameAnchor : DrawAnchor.Center;
|
||||
|
||||
public PrimaryResourceHud(PrimaryResourceConfig config, string? displayName = null) : base(config, displayName)
|
||||
{
|
||||
}
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
return (new List<Vector2>() { Config.Position }, new List<Vector2>() { Config.Size });
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
if (!Config.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (PartyMember == null && (ResourceType == PrimaryResourceTypes.None || Actor == null || Actor is not IPlayerCharacter))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ICharacter? chara = Actor != null ? (ICharacter)Actor : null;
|
||||
uint current = chara == null ? PartyMember?.MP ?? 0 : 0;
|
||||
uint max = chara == null ? PartyMember?.MaxMP ?? 0 : 0;
|
||||
|
||||
if (chara != null)
|
||||
{
|
||||
GetResources(ref current, ref max, chara);
|
||||
}
|
||||
|
||||
if (Config.HidePrimaryResourceWhenFull && current == max)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BarHud bar = BarUtilities.GetProgressBar(
|
||||
Config,
|
||||
Config.ThresholdConfig,
|
||||
new LabelConfig[] { Config.ValueLabel },
|
||||
current,
|
||||
max,
|
||||
0,
|
||||
chara,
|
||||
GetColor()
|
||||
);
|
||||
|
||||
Vector2 pos = origin + ParentPos();
|
||||
AddDrawActions(bar.GetDrawActions(pos, Config.StrataLevel));
|
||||
}
|
||||
|
||||
private void GetResources(ref uint current, ref uint max, ICharacter actor)
|
||||
{
|
||||
switch (ResourceType)
|
||||
{
|
||||
case PrimaryResourceTypes.MP:
|
||||
current = actor.CurrentMp;
|
||||
max = actor.MaxMp;
|
||||
break;
|
||||
|
||||
case PrimaryResourceTypes.CP:
|
||||
current = actor.CurrentCp;
|
||||
max = actor.MaxCp;
|
||||
break;
|
||||
|
||||
case PrimaryResourceTypes.GP:
|
||||
current = actor.CurrentGp;
|
||||
max = actor.MaxGp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual PluginConfigColor GetColor()
|
||||
{
|
||||
if (!Config.UseJobColor)
|
||||
{
|
||||
return Config.FillColor;
|
||||
}
|
||||
|
||||
if (PartyMember != null)
|
||||
{
|
||||
return GlobalColors.Instance.SafeColorForJobId(PartyMember.JobId);
|
||||
}
|
||||
|
||||
return ColorUtils.ColorForActor(Actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Section("Other Elements")]
|
||||
[SubSection("Pull Timer", 0)]
|
||||
public class PullTimerConfig : ProgressBarConfig
|
||||
{
|
||||
[Checkbox("Use Job Color")]
|
||||
[Order(45)]
|
||||
public bool UseJobColor = false;
|
||||
|
||||
public PullTimerConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor) : base(position, size, fillColor)
|
||||
{
|
||||
}
|
||||
|
||||
public new static PullTimerConfig DefaultConfig()
|
||||
{
|
||||
var config = new PullTimerConfig(
|
||||
new Vector2(0, HUDConstants.BaseHUDOffsetY - 35),
|
||||
new Vector2(254, 20),
|
||||
new PluginConfigColor(new Vector4(233f / 255f, 4f / 255f, 4f / 255f, 100f / 100f)));
|
||||
|
||||
config.HideWhenInactive = true;
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using HSUI.Config;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public class PullTimerHud : DraggableHudElement, IHudElementWithActor
|
||||
{
|
||||
private PullTimerConfig Config => (PullTimerConfig)_config;
|
||||
|
||||
public IGameObject? Actor { get; set; } = null;
|
||||
|
||||
public PullTimerHud(PullTimerConfig config, string displayName) : base(config, displayName) { }
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
return (new List<Vector2>() { Config.Position }, new List<Vector2>() { Config.Size });
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
PullTimerState helper = PullTimerHelper.Instance.PullTimerState;
|
||||
|
||||
Config.Label.SetValue(helper.CountDownValue);
|
||||
|
||||
if (!helper.CountingDown)
|
||||
{
|
||||
Config.Label.SetText("");
|
||||
}
|
||||
|
||||
if (!Config.Enabled || Actor is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config.HideWhenInactive && !helper.CountingDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PluginConfigColor? fillColor = Config.UseJobColor ? ColorUtils.ColorForActor(Actor) : null;
|
||||
|
||||
BarHud bar = BarUtilities.GetProgressBar(Config,
|
||||
helper.CountDownValue,
|
||||
helper.CountDownMax, 0F, Actor, fillColor);
|
||||
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.StrataLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Numerics;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[Exportable(false)]
|
||||
public class ShadowConfig : PluginConfigObject
|
||||
{
|
||||
[ColorEdit4("Color")]
|
||||
[Order(5)]
|
||||
public PluginConfigColor Color = new PluginConfigColor(new Vector4(0f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[DragInt("Thickness", min = 1, max = 20)]
|
||||
[Order(10)]
|
||||
public int Thickness = 1;
|
||||
|
||||
[DragInt("Offset", min = 0, max = 20)]
|
||||
[Order(15)]
|
||||
public int Offset = 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
[DisableParentSettings("HideWhenInactive", "HideHealthIfPossible", "RangeConfig", "EnemyRangeConfig")]
|
||||
[Section("Unit Frames")]
|
||||
[SubSection("Player", 0)]
|
||||
public class PlayerUnitFrameConfig : UnitFrameConfig
|
||||
{
|
||||
[NestedConfig("Tank Stance Indicator", 122, spacing = true)]
|
||||
public TankStanceIndicatorConfig TankStanceIndicatorConfig = new TankStanceIndicatorConfig();
|
||||
|
||||
public PlayerUnitFrameConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
|
||||
: base(position, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig)
|
||||
{
|
||||
}
|
||||
|
||||
public new static PlayerUnitFrameConfig DefaultConfig()
|
||||
{
|
||||
var size = HUDConstants.DefaultBigUnitFrameSize;
|
||||
var pos = new Vector2(-HUDConstants.UnitFramesOffsetX - size.X / 2f, HUDConstants.BaseHUDOffsetY);
|
||||
|
||||
var leftLabelConfig = new EditableLabelConfig(new Vector2(5, 0), "[name]", DrawAnchor.TopLeft, DrawAnchor.BottomLeft);
|
||||
var rightLabelConfig = new EditableLabelConfig(new Vector2(-5, 0), "[health:current-short] | [health:percent]", DrawAnchor.TopRight, DrawAnchor.BottomRight);
|
||||
var optionalLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
|
||||
var config = new PlayerUnitFrameConfig(pos, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TankStanceCorner
|
||||
{
|
||||
TopLeft = 0,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class TankStanceIndicatorConfig : PluginConfigObject
|
||||
{
|
||||
[Combo("Corner", "Top Left", "Top Right", "Bottom Left", "Bottom Right")]
|
||||
[Order(5)]
|
||||
public TankStanceCorner Corner = TankStanceCorner.BottomLeft;
|
||||
|
||||
[DragFloat2("Size", min = 1, max = 500)]
|
||||
[Order(10)]
|
||||
public Vector2 Size = new Vector2(HUDConstants.DefaultBigUnitFrameSize.Y - 20, HUDConstants.DefaultBigUnitFrameSize.Y - 20);
|
||||
|
||||
[DragInt("Thickness", min = 2, max = 20)]
|
||||
[Order(15)]
|
||||
public int Thickess = 4;
|
||||
|
||||
[ColorEdit4("Active Color")]
|
||||
[Order(20)]
|
||||
public PluginConfigColor ActiveColor = new PluginConfigColor(new Vector4(0f / 255f, 255f / 255f, 255f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Inactive Color")]
|
||||
[Order(25)]
|
||||
public PluginConfigColor InactiveColor = new PluginConfigColor(new Vector4(255f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive")]
|
||||
[Section("Unit Frames")]
|
||||
[SubSection("Target", 0)]
|
||||
public class TargetUnitFrameConfig : UnitFrameConfig
|
||||
{
|
||||
public TargetUnitFrameConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
|
||||
: base(position, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig)
|
||||
{
|
||||
}
|
||||
|
||||
public new static TargetUnitFrameConfig DefaultConfig()
|
||||
{
|
||||
var size = HUDConstants.DefaultBigUnitFrameSize;
|
||||
var pos = new Vector2(HUDConstants.UnitFramesOffsetX + size.X / 2f, HUDConstants.BaseHUDOffsetY);
|
||||
|
||||
var leftLabelConfig = new EditableLabelConfig(new Vector2(5, 0), "[health:current-short] | [health:percent]", DrawAnchor.TopLeft, DrawAnchor.BottomLeft);
|
||||
var rightLabelConfig = new EditableLabelConfig(new Vector2(-5, 0), "[name]", DrawAnchor.TopRight, DrawAnchor.BottomRight);
|
||||
var optionalLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
|
||||
return new TargetUnitFrameConfig(pos, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig);
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive")]
|
||||
[Section("Unit Frames")]
|
||||
[SubSection("Target of Target", 0)]
|
||||
public class TargetOfTargetUnitFrameConfig : UnitFrameConfig
|
||||
{
|
||||
public TargetOfTargetUnitFrameConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
|
||||
: base(position, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig)
|
||||
{
|
||||
}
|
||||
|
||||
public new static TargetOfTargetUnitFrameConfig DefaultConfig()
|
||||
{
|
||||
var size = HUDConstants.DefaultSmallUnitFrameSize;
|
||||
var pos = new Vector2(
|
||||
HUDConstants.UnitFramesOffsetX + HUDConstants.DefaultBigUnitFrameSize.X + 6 + size.X / 2f,
|
||||
HUDConstants.BaseHUDOffsetY - 15
|
||||
);
|
||||
|
||||
var leftLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "[name]", DrawAnchor.Top, DrawAnchor.Bottom);
|
||||
var rightLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.TopLeft);
|
||||
var optionalLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.BottomLeft);
|
||||
|
||||
return new TargetOfTargetUnitFrameConfig(pos, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig);
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive")]
|
||||
[Section("Unit Frames")]
|
||||
[SubSection("Focus Target", 0)]
|
||||
public class FocusTargetUnitFrameConfig : UnitFrameConfig
|
||||
{
|
||||
public FocusTargetUnitFrameConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
|
||||
: base(position, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig)
|
||||
{
|
||||
}
|
||||
|
||||
public new static FocusTargetUnitFrameConfig DefaultConfig()
|
||||
{
|
||||
var size = HUDConstants.DefaultSmallUnitFrameSize;
|
||||
var pos = new Vector2(
|
||||
-HUDConstants.UnitFramesOffsetX - HUDConstants.DefaultBigUnitFrameSize.X - 6 - size.X / 2f,
|
||||
HUDConstants.BaseHUDOffsetY - 15
|
||||
);
|
||||
|
||||
var leftLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "[name]", DrawAnchor.Top, DrawAnchor.Bottom);
|
||||
var rightLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center);
|
||||
var optionalLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Bottom, DrawAnchor.Bottom);
|
||||
|
||||
return new FocusTargetUnitFrameConfig(pos, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig);
|
||||
}
|
||||
}
|
||||
|
||||
[DisableParentSettings("HideWhenInactive")]
|
||||
public class UnitFrameConfig : BarConfig
|
||||
{
|
||||
[Checkbox("Use Job Color", spacing = true)]
|
||||
[Order(45)]
|
||||
public bool UseJobColor = true;
|
||||
|
||||
[Checkbox("Use Role Color")]
|
||||
[Order(46)]
|
||||
public bool UseRoleColor = false;
|
||||
|
||||
[NestedConfig("Color Based On Health Value", 50, collapsingHeader = false)]
|
||||
public ColorByHealthValueConfig ColorByHealth = new ColorByHealthValueConfig();
|
||||
|
||||
[Checkbox("Job Color As Background Color", spacing = true)]
|
||||
[Order(50)]
|
||||
public bool UseJobColorAsBackgroundColor = false;
|
||||
|
||||
[Checkbox("Role Color As Background Color")]
|
||||
[Order(51)]
|
||||
public bool UseRoleColorAsBackgroundColor = false;
|
||||
|
||||
[Checkbox("Missing Health Color")]
|
||||
[Order(55)]
|
||||
public bool UseMissingHealthBar = false;
|
||||
|
||||
[Checkbox("Job Color As Missing Health Color")]
|
||||
[Order(56, collapseWith = nameof(UseMissingHealthBar))]
|
||||
public bool UseJobColorAsMissingHealthColor = false;
|
||||
|
||||
[Checkbox("Role Color As Missing Health Color")]
|
||||
[Order(57, collapseWith = nameof(UseMissingHealthBar))]
|
||||
public bool UseRoleColorAsMissingHealthColor = false;
|
||||
|
||||
[ColorEdit4("Color" + "##MissingHealth")]
|
||||
[Order(60, collapseWith = nameof(UseMissingHealthBar))]
|
||||
public PluginConfigColor HealthMissingColor = new PluginConfigColor(new Vector4(255f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
|
||||
[Checkbox("Death Indicator Background Color", spacing = true)]
|
||||
[Order(61)]
|
||||
public bool UseDeathIndicatorBackgroundColor = false;
|
||||
|
||||
[ColorEdit4("Color" + "##DeathIndicator")]
|
||||
[Order(62, collapseWith = nameof(UseDeathIndicatorBackgroundColor))]
|
||||
public PluginConfigColor DeathIndicatorBackgroundColor = new PluginConfigColor(new Vector4(204f / 255f, 3f / 255f, 3f / 255f, 50f / 100f));
|
||||
|
||||
[Checkbox("Tank Invulnerability", spacing = true)]
|
||||
[Order(95)]
|
||||
public bool ShowTankInvulnerability = true;
|
||||
|
||||
[Checkbox("Tank Invulnerability Custom Color")]
|
||||
[Order(100, collapseWith = nameof(ShowTankInvulnerability))]
|
||||
public bool UseCustomInvulnerabilityColor = true;
|
||||
|
||||
[ColorEdit4("Tank Invulnerability Color ##TankInvulnerabilityCustom")]
|
||||
[Order(105, collapseWith = nameof(UseCustomInvulnerabilityColor))]
|
||||
public PluginConfigColor CustomInvulnerabilityColor = new PluginConfigColor(new Vector4(211f / 255f, 235f / 255f, 215f / 245f, 50f / 100f));
|
||||
|
||||
[Checkbox("Walking Dead Custom Color")]
|
||||
[Order(110, collapseWith = nameof(ShowTankInvulnerability))]
|
||||
public bool UseCustomWalkingDeadColor = true;
|
||||
|
||||
[ColorEdit4("Walking Dead Color ##TankWalkingDeadCustom")]
|
||||
[Order(115, collapseWith = nameof(UseCustomWalkingDeadColor))]
|
||||
public PluginConfigColor CustomWalkingDeadColor = new PluginConfigColor(new Vector4(158f / 255f, 158f / 255f, 158f / 255f, 50f / 100f));
|
||||
|
||||
[NestedConfig("Use Smooth Transitions", 120, collapsingHeader = false)]
|
||||
public SmoothHealthConfig SmoothHealthConfig = new SmoothHealthConfig();
|
||||
|
||||
[Checkbox("Hide Health if Possible", spacing = true, help = "This will hide any label that has a health tag if the character doesn't have health (ie minions, friendly npcs, etc)")]
|
||||
[Order(121)]
|
||||
public bool HideHealthIfPossible = true;
|
||||
|
||||
[NestedConfig("Left Text", 125)]
|
||||
public EditableLabelConfig LeftLabelConfig = null!;
|
||||
|
||||
[NestedConfig("Right Text", 130)]
|
||||
public EditableLabelConfig RightLabelConfig = null!;
|
||||
|
||||
[NestedConfig("Optional Text", 131)]
|
||||
public EditableLabelConfig OptionalLabelConfig = null!;
|
||||
|
||||
[NestedConfig("Role/Job Icon", 135)]
|
||||
public RoleJobIconConfig RoleIconConfig = new RoleJobIconConfig(
|
||||
new Vector2(5, 0),
|
||||
new Vector2(30, 30),
|
||||
DrawAnchor.Left,
|
||||
DrawAnchor.Left
|
||||
);
|
||||
|
||||
[NestedConfig("Sign Icon", 136)]
|
||||
public SignIconConfig SignIconConfig = new SignIconConfig(
|
||||
new Vector2(0, 0),
|
||||
new Vector2(30, 30),
|
||||
DrawAnchor.Center,
|
||||
DrawAnchor.Top
|
||||
);
|
||||
|
||||
[NestedConfig("Shields", 140)]
|
||||
public ShieldConfig ShieldConfig = new ShieldConfig();
|
||||
|
||||
[NestedConfig("Change Friendly Alpha Based on Range", 145)]
|
||||
public UnitFramesRangeConfig RangeConfig = new();
|
||||
|
||||
[NestedConfig("Change Enemy Alpha Based on Range", 146)]
|
||||
public UnitFramesRangeConfig EnemyRangeConfig = new();
|
||||
|
||||
[NestedConfig("Custom Mouseover Area", 150)]
|
||||
public MouseoverAreaConfig MouseoverAreaConfig = new MouseoverAreaConfig();
|
||||
|
||||
[NestedConfig("Visibility", 200)]
|
||||
public VisibilityConfig VisibilityConfig = new VisibilityConfig();
|
||||
|
||||
public UnitFrameConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
|
||||
: base(position, size, new PluginConfigColor(new(40f / 255f, 40f / 255f, 40f / 255f, 100f / 100f)))
|
||||
{
|
||||
Position = position;
|
||||
Size = size;
|
||||
LeftLabelConfig = leftLabelConfig;
|
||||
RightLabelConfig = rightLabelConfig;
|
||||
OptionalLabelConfig = optionalLabelConfig;
|
||||
BackgroundColor = new PluginConfigColor(new(0f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
|
||||
RoleIconConfig.Enabled = false;
|
||||
SignIconConfig.Enabled = false;
|
||||
ColorByHealth.Enabled = false;
|
||||
MouseoverAreaConfig.Enabled = false;
|
||||
}
|
||||
|
||||
public UnitFrameConfig() : base(Vector2.Zero, Vector2.Zero, PluginConfigColor.Empty) { } // don't remove
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class ShieldConfig : PluginConfigObject
|
||||
{
|
||||
[DragInt("Thickness")]
|
||||
[Order(5)]
|
||||
public int Height = 26; // Should be 'Size' instead of 'Height' but leaving as is to avoid breaking configs
|
||||
|
||||
[Checkbox("Thickness in Pixels")]
|
||||
[Order(10)]
|
||||
public bool HeightInPixels = false;
|
||||
|
||||
[Checkbox("Fill Health First")]
|
||||
[Order(15)]
|
||||
public bool FillHealthFirst = true;
|
||||
|
||||
[ColorEdit4("Color ##Shields")]
|
||||
[Order(20)]
|
||||
public PluginConfigColor Color = new PluginConfigColor(new Vector4(198f / 255f, 210f / 255f, 255f / 255f, 70f / 100f));
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class SmoothHealthConfig : PluginConfigObject
|
||||
{
|
||||
[DragFloat("Velocity", min = 1f, max = 100f)]
|
||||
[Order(5)]
|
||||
public float Velocity = 25f;
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class MouseoverAreaConfig : PluginConfigObject
|
||||
{
|
||||
[Checkbox("Preview")]
|
||||
[Order(5)]
|
||||
public bool Preview = false;
|
||||
|
||||
[Checkbox("Ignore Mouseover", help = "Enabling this will make it so this element is ignored by mouseover completely.\nThe area can still be defined for left and right clicks.")]
|
||||
[Order(6)]
|
||||
public bool Ignore = false;
|
||||
|
||||
[DragInt2("Top Left Offset", min = -500, max = 500)]
|
||||
[Order(10)]
|
||||
public Vector2 TopLeftOffset = Vector2.Zero;
|
||||
|
||||
[DragInt2("Bottom Right Offset", min = -500, max = 500)]
|
||||
[Order(11)]
|
||||
public Vector2 BottomRightOffset = Vector2.Zero;
|
||||
|
||||
public MouseoverAreaConfig()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
public (Vector2, Vector2) GetArea(Vector2 pos, Vector2 size)
|
||||
{
|
||||
if (!Enabled) { return (pos, pos + size); }
|
||||
|
||||
Vector2 start = pos + TopLeftOffset;
|
||||
Vector2 end = pos + size + BottomRightOffset;
|
||||
|
||||
return (start, end);
|
||||
}
|
||||
|
||||
public BarHud? GetBar(Vector2 pos, Vector2 size, string id, DrawAnchor anchor = DrawAnchor.TopLeft)
|
||||
{
|
||||
if (!Enabled || !Preview) { return null; }
|
||||
|
||||
BarHud bar = new BarHud(
|
||||
id,
|
||||
true,
|
||||
new(Vector4.One),
|
||||
2
|
||||
);
|
||||
|
||||
var barPos = Utils.GetAnchoredPosition(Vector2.Zero, size, anchor);
|
||||
var (start, end) = GetArea(barPos + pos, size);
|
||||
Rect background = new Rect(start, end - start, new(new(1, 1, 1, 0.5f)));
|
||||
bar.SetBackground(background);
|
||||
|
||||
return bar;
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class UnitFramesRangeConfig : 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 = 24;
|
||||
|
||||
[Checkbox("Use Additional Range Check")]
|
||||
[Order(15)]
|
||||
public bool UseAdditionalRangeCheck = false;
|
||||
|
||||
[DragInt("Additional Range (yalms)", min = 1, max = 500)]
|
||||
[Order(20, collapseWith = nameof(UseAdditionalRangeCheck))]
|
||||
public int AdditionalRange = 15;
|
||||
|
||||
[DragFloat("Additional Alpha", min = 1, max = 100)]
|
||||
[Order(25, collapseWith = nameof(UseAdditionalRangeCheck))]
|
||||
public float AdditionalAlpha = 60;
|
||||
|
||||
public float AlphaForDistance(int distance, float alpha = 100f)
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
return 100f;
|
||||
}
|
||||
|
||||
if (!UseAdditionalRangeCheck)
|
||||
{
|
||||
return distance > Range ? Alpha : alpha;
|
||||
}
|
||||
|
||||
if (Range > AdditionalRange)
|
||||
{
|
||||
return distance > Range ? Alpha : (distance > AdditionalRange ? AdditionalAlpha : alpha);
|
||||
}
|
||||
|
||||
return distance > AdditionalRange ? AdditionalAlpha : (distance > Range ? Alpha : alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,528 @@
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.ClientState.Statuses;
|
||||
using HSUI.Config;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using BattleChara = Dalamud.Game.ClientState.Objects.Types.IBattleChara;
|
||||
using BattleNpcSubKind = Dalamud.Game.ClientState.Objects.Enums.BattleNpcSubKind;
|
||||
using Character = Dalamud.Game.ClientState.Objects.Types.ICharacter;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public unsafe class UnitFrameHud(UnitFrameConfig config, string displayName)
|
||||
: DraggableHudElement(config, displayName), IHudElementWithActor, IHudElementWithMouseOver, IHudElementWithPreview, IHudElementWithVisibilityConfig
|
||||
{
|
||||
public UnitFrameConfig Config => (UnitFrameConfig)_config;
|
||||
public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
|
||||
|
||||
private SmoothHPHelper _smoothHPHelper = new SmoothHPHelper();
|
||||
|
||||
public IGameObject? Actor { get; set; }
|
||||
|
||||
private bool _wasHovering = false;
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
return (new List<Vector2>() { Config.Position }, new List<Vector2>() { Config.Size });
|
||||
}
|
||||
|
||||
public void StopPreview()
|
||||
{
|
||||
Config.MouseoverAreaConfig.Preview = false;
|
||||
Config.SignIconConfig.Preview = false;
|
||||
}
|
||||
|
||||
public void StopMouseover()
|
||||
{
|
||||
if (_wasHovering)
|
||||
{
|
||||
InputsHelper.Instance.ClearTarget();
|
||||
_wasHovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawChildren(Vector2 origin)
|
||||
{
|
||||
if (!Config.Enabled || Actor == null)
|
||||
{
|
||||
StopMouseover();
|
||||
return;
|
||||
}
|
||||
|
||||
DrawExtras(origin, Actor);
|
||||
|
||||
if (Actor is Character character)
|
||||
{
|
||||
DrawCharacter(origin, character);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawFriendlyNPC(origin, Actor);
|
||||
}
|
||||
|
||||
// Check if mouse is hovering over the box properly
|
||||
var startPos = Utils.GetAnchoredPosition(origin + Config.Position, Config.Size, Config.Anchor);
|
||||
var (areaStart, areaEnd) = Config.MouseoverAreaConfig.GetArea(startPos, Config.Size);
|
||||
bool isHovering = ImGui.IsMouseHoveringRect(areaStart, areaEnd);
|
||||
bool ignoreMouseover = Config.MouseoverAreaConfig.Enabled && Config.MouseoverAreaConfig.Ignore;
|
||||
|
||||
if (isHovering && !DraggingEnabled)
|
||||
{
|
||||
_wasHovering = true;
|
||||
InputsHelper.Instance.SetTarget(Actor, ignoreMouseover);
|
||||
|
||||
if (InputsHelper.Instance.LeftButtonClicked)
|
||||
{
|
||||
Plugin.TargetManager.Target = Actor;
|
||||
}
|
||||
else if (InputsHelper.Instance.RightButtonClicked)
|
||||
{
|
||||
AgentModule.Instance()->GetAgentHUD()->OpenContextMenuFromTarget((GameObject*)Actor.Address);
|
||||
}
|
||||
}
|
||||
else if (_wasHovering)
|
||||
{
|
||||
InputsHelper.Instance.ClearTarget();
|
||||
_wasHovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DrawExtras(Vector2 origin, IGameObject? actor)
|
||||
{
|
||||
// override
|
||||
}
|
||||
|
||||
private void DrawCharacter(Vector2 pos, Character character)
|
||||
{
|
||||
uint currentHp = character.CurrentHp;
|
||||
uint maxHp = character.MaxHp;
|
||||
|
||||
// fixes weird bug with npcs
|
||||
if (maxHp == 1)
|
||||
{
|
||||
currentHp = 1;
|
||||
}
|
||||
else if (Config.SmoothHealthConfig.Enabled)
|
||||
{
|
||||
currentHp = _smoothHPHelper.GetNextHp((int)currentHp, (int)maxHp, Config.SmoothHealthConfig.Velocity);
|
||||
}
|
||||
|
||||
PluginConfigColor fillColor = ColorUtils.ColorForCharacter(
|
||||
character,
|
||||
currentHp,
|
||||
maxHp,
|
||||
Config.UseJobColor,
|
||||
Config.UseRoleColor,
|
||||
Config.ColorByHealth
|
||||
) ?? Config.FillColor;
|
||||
|
||||
Rect background = new Rect(Config.Position, Config.Size, BackgroundColor(character));
|
||||
if (Config.RangeConfig.Enabled || Config.EnemyRangeConfig.Enabled)
|
||||
{
|
||||
fillColor = GetDistanceColor(character, fillColor);
|
||||
background.Color = GetDistanceColor(character, background.Color);
|
||||
}
|
||||
|
||||
Rect healthFill = BarUtilities.GetFillRect(Config.Position, Config.Size, Config.FillDirection, fillColor, currentHp, maxHp);
|
||||
|
||||
BarHud bar = new BarHud(Config, character);
|
||||
bar.NeedsInputs = true;
|
||||
bar.SetBackground(background);
|
||||
bar.AddForegrounds(healthFill);
|
||||
bar.AddLabels(GetLabels(maxHp));
|
||||
|
||||
if (Config.UseMissingHealthBar)
|
||||
{
|
||||
Vector2 healthMissingSize = Config.Size - BarUtilities.GetFillDirectionOffset(healthFill.Size, Config.FillDirection);
|
||||
Vector2 healthMissingPos = Config.FillDirection.IsInverted()
|
||||
? Config.Position
|
||||
: Config.Position + BarUtilities.GetFillDirectionOffset(healthFill.Size, Config.FillDirection);
|
||||
|
||||
PluginConfigColor missingHealthColor = Config.UseJobColorAsMissingHealthColor && character is BattleChara
|
||||
? GlobalColors.Instance.SafeColorForJobId(character!.ClassJob.RowId)
|
||||
: Config.UseRoleColorAsMissingHealthColor && character is BattleChara
|
||||
? GlobalColors.Instance.SafeRoleColorForJobId(character!.ClassJob.RowId)
|
||||
: Config.HealthMissingColor;
|
||||
|
||||
if (Config.UseDeathIndicatorBackgroundColor && character is BattleChara { CurrentHp: <= 0 })
|
||||
{
|
||||
missingHealthColor = Config.DeathIndicatorBackgroundColor;
|
||||
}
|
||||
|
||||
if (Config.UseCustomInvulnerabilityColor && character is BattleChara battleChara)
|
||||
{
|
||||
IStatus? tankInvuln = Utils.GetTankInvulnerabilityID(battleChara);
|
||||
if (tankInvuln is not null)
|
||||
{
|
||||
missingHealthColor = Config.CustomInvulnerabilityColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.RangeConfig.Enabled || Config.EnemyRangeConfig.Enabled)
|
||||
{
|
||||
missingHealthColor = GetDistanceColor(character, missingHealthColor);
|
||||
}
|
||||
|
||||
bar.AddForegrounds(new Rect(healthMissingPos, healthMissingSize, missingHealthColor));
|
||||
}
|
||||
|
||||
// shield
|
||||
BarUtilities.AddShield(bar, Config, Config.ShieldConfig, character, healthFill.Size);
|
||||
|
||||
// draw action
|
||||
AddDrawActions(bar.GetDrawActions(pos, Config.StrataLevel));
|
||||
|
||||
// mouseover area
|
||||
BarHud? mouseoverAreaBar = Config.MouseoverAreaConfig.GetBar(
|
||||
Config.Position,
|
||||
Config.Size,
|
||||
Config.ID + "_mouseoverArea",
|
||||
Config.Anchor
|
||||
);
|
||||
|
||||
if (mouseoverAreaBar != null)
|
||||
{
|
||||
AddDrawActions(mouseoverAreaBar.GetDrawActions(pos, StrataLevel.HIGHEST));
|
||||
}
|
||||
|
||||
// role/job icon
|
||||
if (Config.RoleIconConfig.Enabled && character is IPlayerCharacter)
|
||||
{
|
||||
uint jobId = character.ClassJob.RowId;
|
||||
uint iconId = Config.RoleIconConfig.UseRoleIcons ?
|
||||
JobsHelper.RoleIconIDForJob(jobId, Config.RoleIconConfig.UseSpecificDPSRoleIcons) :
|
||||
JobsHelper.IconIDForJob(jobId, (uint)Config.RoleIconConfig.Style);
|
||||
|
||||
if (iconId > 0)
|
||||
{
|
||||
var barPos = Utils.GetAnchoredPosition(pos, Config.Size, Config.Anchor);
|
||||
var parentPos = Utils.GetAnchoredPosition(barPos + Config.Position, -Config.Size, Config.RoleIconConfig.FrameAnchor);
|
||||
var iconPos = Utils.GetAnchoredPosition(parentPos + Config.RoleIconConfig.Position, Config.RoleIconConfig.Size, Config.RoleIconConfig.Anchor);
|
||||
|
||||
AddDrawAction(Config.RoleIconConfig.StrataLevel, () =>
|
||||
{
|
||||
DrawHelper.DrawInWindow(ID + "_jobIcon", iconPos, Config.RoleIconConfig.Size, false, (drawList) =>
|
||||
{
|
||||
DrawHelper.DrawIcon(iconId, iconPos, Config.RoleIconConfig.Size, false, drawList);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// sign icon
|
||||
if (Config.SignIconConfig.Enabled)
|
||||
{
|
||||
uint? iconId = Config.SignIconConfig.IconID(character);
|
||||
if (iconId.HasValue)
|
||||
{
|
||||
var barPos = Utils.GetAnchoredPosition(pos, Config.Size, Config.Anchor);
|
||||
var parentPos = Utils.GetAnchoredPosition(barPos + Config.Position, -Config.Size, Config.SignIconConfig.FrameAnchor);
|
||||
var iconPos = Utils.GetAnchoredPosition(parentPos + Config.SignIconConfig.Position, Config.SignIconConfig.Size, Config.SignIconConfig.Anchor);
|
||||
|
||||
AddDrawAction(Config.SignIconConfig.StrataLevel, () =>
|
||||
{
|
||||
DrawHelper.DrawInWindow(ID + "_signIcon", iconPos, Config.SignIconConfig.Size, false, (drawList) =>
|
||||
{
|
||||
DrawHelper.DrawIcon(iconId.Value, iconPos, Config.SignIconConfig.Size, false, drawList);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LabelConfig[] GetLabels(uint maxHp)
|
||||
{
|
||||
List<LabelConfig> labels = new List<LabelConfig>();
|
||||
|
||||
if (Config.HideHealthIfPossible && maxHp <= 1)
|
||||
{
|
||||
if (!Utils.IsHealthLabel(Config.LeftLabelConfig))
|
||||
{
|
||||
labels.Add(Config.LeftLabelConfig);
|
||||
}
|
||||
|
||||
if (!Utils.IsHealthLabel(Config.RightLabelConfig))
|
||||
{
|
||||
labels.Add(Config.RightLabelConfig);
|
||||
}
|
||||
|
||||
if (!Utils.IsHealthLabel(Config.OptionalLabelConfig))
|
||||
{
|
||||
labels.Add(Config.OptionalLabelConfig);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
labels.Add(Config.LeftLabelConfig);
|
||||
labels.Add(Config.RightLabelConfig);
|
||||
labels.Add(Config.OptionalLabelConfig);
|
||||
}
|
||||
|
||||
return labels.ToArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PluginConfigColor GetDistanceColor(Character? character, PluginConfigColor color)
|
||||
{
|
||||
byte distance = character != null ? character.YalmDistanceX : byte.MaxValue;
|
||||
float currentAlpha = color.Vector.W * 100f;
|
||||
float alpha = Config.RangeConfig.AlphaForDistance(distance, currentAlpha) / 100f;
|
||||
|
||||
if (character is IBattleNpc { BattleNpcKind: BattleNpcSubKind.Enemy or BattleNpcSubKind.BattleNpcPart } && Config.EnemyRangeConfig.Enabled)
|
||||
{
|
||||
alpha = Config.EnemyRangeConfig.AlphaForDistance(distance, currentAlpha) / 100f;
|
||||
}
|
||||
|
||||
return color.WithAlpha(alpha);
|
||||
}
|
||||
|
||||
private unsafe void GetNPCHpValues(IGameObject? actor, out uint currentHp, out uint maxHp)
|
||||
{
|
||||
currentHp = 0;
|
||||
maxHp = 0;
|
||||
|
||||
var player = Plugin.ObjectTable.LocalPlayer;
|
||||
if (player == null || actor == null || player.TargetObject == null || actor.GameObjectId != player.TargetObject.GameObjectId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AtkUnitBase* TargetWidget = (AtkUnitBase*)Plugin.GameGui.GetAddonByName("_TargetInfoMainTarget", 1).Address;
|
||||
if (TargetWidget != null)
|
||||
{
|
||||
AtkTextNode* textNode = TargetWidget->GetTextNodeById(11);
|
||||
string integrityText = textNode->NodeText.ToString();
|
||||
|
||||
// not a gathering node or node at 100%, nothing to do
|
||||
if (!integrityText.Contains("%"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
currentHp = Convert.ToUInt32((integrityText.Replace("%", "")));
|
||||
maxHp = 100;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFriendlyNPC(Vector2 pos, IGameObject? actor)
|
||||
{
|
||||
GetNPCHpValues(actor, out uint currentHp, out uint maxHp);
|
||||
|
||||
BarHud bar = new BarHud(Config, actor);
|
||||
bar.AddLabels(GetLabels(0));
|
||||
|
||||
if (maxHp == 0)
|
||||
{
|
||||
bar.AddForegrounds(new Rect(Config.Position, Config.Size, ColorUtils.ColorForActor(actor)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Config.SmoothHealthConfig.Enabled)
|
||||
{
|
||||
currentHp = _smoothHPHelper.GetNextHp((int)currentHp, (int)maxHp, Config.SmoothHealthConfig.Velocity);
|
||||
}
|
||||
|
||||
PluginConfigColor fillColor = ColorUtils.ColorForCharacter(
|
||||
actor,
|
||||
currentHp,
|
||||
maxHp,
|
||||
colorByHealthConfig: Config.ColorByHealth
|
||||
) ?? Config.FillColor;
|
||||
|
||||
Rect background = new Rect(Config.Position, Config.Size, Config.BackgroundColor);
|
||||
Rect healthFill = BarUtilities.GetFillRect(Config.Position, Config.Size, Config.FillDirection, fillColor, currentHp, maxHp);
|
||||
|
||||
bar.NeedsInputs = true;
|
||||
bar.SetBackground(background);
|
||||
bar.AddForegrounds(healthFill);
|
||||
}
|
||||
|
||||
AddDrawActions(bar.GetDrawActions(pos, Config.StrataLevel));
|
||||
}
|
||||
|
||||
private PluginConfigColor BackgroundColor(Character? chara)
|
||||
{
|
||||
if (Config.ShowTankInvulnerability &&
|
||||
!Config.UseMissingHealthBar &&
|
||||
chara is BattleChara battleChara)
|
||||
{
|
||||
IStatus? tankInvuln = Utils.GetTankInvulnerabilityID(battleChara);
|
||||
|
||||
if (tankInvuln != null)
|
||||
{
|
||||
PluginConfigColor color;
|
||||
if (Config.UseCustomInvulnerabilityColor)
|
||||
{
|
||||
color = Config.CustomInvulnerabilityColor;
|
||||
}
|
||||
else if (tankInvuln.StatusId == 811 && Config.UseCustomWalkingDeadColor)
|
||||
{
|
||||
color = Config.CustomWalkingDeadColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = new PluginConfigColor(GlobalColors.Instance.SafeColorForJobId(chara.ClassJob.RowId).Vector.AdjustColor(-.8f));
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
if (chara is BattleChara)
|
||||
{
|
||||
if (Config.UseJobColorAsBackgroundColor)
|
||||
{
|
||||
return GlobalColors.Instance.SafeColorForJobId(chara.ClassJob.RowId);
|
||||
}
|
||||
else if (Config.UseRoleColorAsBackgroundColor)
|
||||
{
|
||||
return GlobalColors.Instance.SafeRoleColorForJobId(chara.ClassJob.RowId);
|
||||
}
|
||||
else if (Config.UseDeathIndicatorBackgroundColor && chara.CurrentHp <= 0)
|
||||
{
|
||||
return Config.DeathIndicatorBackgroundColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Config.BackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
return GlobalColors.Instance.EmptyUnitFrameColor;
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerUnitFrameHud : UnitFrameHud
|
||||
{
|
||||
public new PlayerUnitFrameConfig Config => (PlayerUnitFrameConfig)_config;
|
||||
|
||||
public PlayerUnitFrameHud(PlayerUnitFrameConfig config, string displayName) : base(config, displayName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void DrawExtras(Vector2 origin, IGameObject? actor)
|
||||
{
|
||||
TankStanceIndicatorConfig config = Config.TankStanceIndicatorConfig;
|
||||
|
||||
if (!config.Enabled || actor is not IPlayerCharacter chara) { return; }
|
||||
|
||||
uint jobId = chara.ClassJob.RowId;
|
||||
if (JobsHelper.RoleForJob(jobId) != JobRoles.Tank) { return; }
|
||||
|
||||
var tankStanceBuff = Utils.StatusListForBattleChara(chara).Where(o =>
|
||||
o.StatusId == 79 || // IRON WILL
|
||||
o.StatusId == 91 || // DEFIANCE
|
||||
o.StatusId == 392 || // ROYAL GUARD
|
||||
o.StatusId == 393 || // IRON WILL
|
||||
o.StatusId == 743 || // GRIT
|
||||
o.StatusId == 1396 || // DEFIANCE
|
||||
o.StatusId == 1397 || // GRIT
|
||||
o.StatusId == 1833 // ROYAL GUARD
|
||||
);
|
||||
|
||||
PluginConfigColor color = tankStanceBuff.Any() ? config.ActiveColor : config.InactiveColor;
|
||||
|
||||
Vector2 pos = GetTankStanceCornerOrigin(origin);
|
||||
var (verticalDir, horizontalDir) = GetTankStanceLinesDirections();
|
||||
|
||||
pos = new Vector2(pos.X + config.Thickess * -horizontalDir, pos.Y + config.Thickess * -verticalDir);
|
||||
Vector2 vSize = new Vector2(config.Thickess * horizontalDir, (config.Size.Y + config.Thickess) * verticalDir);
|
||||
Vector2 vEndPos = pos + vSize;
|
||||
Vector2 hSize = new Vector2((config.Size.X + config.Thickess) * horizontalDir, config.Thickess * verticalDir);
|
||||
Vector2 hEndPos = pos + hSize;
|
||||
|
||||
Vector2 startPos = new Vector2(Math.Min(pos.X, hEndPos.X), Math.Min(pos.Y, hEndPos.Y));
|
||||
Vector2 endPos = new Vector2(Math.Max(pos.X, hEndPos.X), Math.Max(pos.Y, hEndPos.Y)); ;
|
||||
|
||||
AddDrawAction(StrataLevel.LOWEST, () =>
|
||||
{
|
||||
DrawHelper.DrawInWindow(ID + "_TankStance", startPos, endPos - startPos, false, (drawList) =>
|
||||
{
|
||||
// TODO: clean up hacky math
|
||||
// there's some 1px errors prob due to negative sizes
|
||||
// couldn't figure it out so I did the hacky fixes
|
||||
|
||||
// vertical
|
||||
|
||||
drawList.AddRectFilled(pos, vEndPos, color.Base);
|
||||
|
||||
if (config.Corner == TankStanceCorner.TopRight)
|
||||
{
|
||||
drawList.AddLine(pos, pos + new Vector2(0, vSize.Y + 1), 0xFF000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawList.AddLine(pos, pos + new Vector2(0, vSize.Y), 0xFF000000);
|
||||
}
|
||||
|
||||
drawList.AddLine(pos + vSize, pos + vSize + new Vector2(-vSize.X, 0), 0xFF000000);
|
||||
|
||||
// horizontal
|
||||
drawList.AddRectFilled(pos, hEndPos, color.Base);
|
||||
|
||||
if (config.Corner == TankStanceCorner.BottomLeft)
|
||||
{
|
||||
drawList.AddLine(pos, pos + new Vector2(hSize.X + 1, 0), 0xFF000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawList.AddLine(pos, pos + new Vector2(hSize.X, 0), 0xFF000000);
|
||||
}
|
||||
|
||||
if (config.Corner == TankStanceCorner.BottomRight)
|
||||
{
|
||||
drawList.AddLine(pos + new Vector2(0, 1), pos + new Vector2(0, hSize.Y), 0xFF000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawList.AddLine(pos, pos + new Vector2(0, hSize.Y), 0xFF000000);
|
||||
}
|
||||
|
||||
drawList.AddLine(pos + hSize, pos + hSize + new Vector2(0, -hSize.Y), 0xFF000000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Vector2 GetTankStanceCornerOrigin(Vector2 origin)
|
||||
{
|
||||
var topLeft = Utils.GetAnchoredPosition(origin + Config.Position, Config.Size, Config.Anchor);
|
||||
|
||||
return Config.TankStanceIndicatorConfig.Corner switch
|
||||
{
|
||||
TankStanceCorner.TopRight => topLeft + new Vector2(Config.Size.X - 1, 0),
|
||||
TankStanceCorner.BottomLeft => topLeft + new Vector2(0, Config.Size.Y - 1),
|
||||
TankStanceCorner.BottomRight => topLeft + Config.Size - Vector2.One,
|
||||
_ => topLeft
|
||||
};
|
||||
}
|
||||
|
||||
private (int, int) GetTankStanceLinesDirections()
|
||||
{
|
||||
return Config.TankStanceIndicatorConfig.Corner switch
|
||||
{
|
||||
TankStanceCorner.TopLeft => (1, 1),
|
||||
TankStanceCorner.TopRight => (1, -1),
|
||||
TankStanceCorner.BottomLeft => (-1, 1),
|
||||
_ => (-1, -1)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Interface.GeneralElements;
|
||||
using HSUI.Interface.Party;
|
||||
using System.Linq;
|
||||
|
||||
namespace HSUI.Interface
|
||||
{
|
||||
[Exportable(false)]
|
||||
public class VisibilityConfig : PluginConfigObject
|
||||
{
|
||||
[Checkbox("Hide outside of combat")]
|
||||
[Order(5)]
|
||||
public bool HideOutsideOfCombat = false;
|
||||
|
||||
[Checkbox("Hide in combat")]
|
||||
[Order(6)]
|
||||
public bool HideInCombat = false;
|
||||
|
||||
[Checkbox("Hide in Gold Saucer")]
|
||||
[Order(7)]
|
||||
public bool HideInGoldSaucer = false;
|
||||
|
||||
[Checkbox("Hide while at full HP")]
|
||||
[Order(8)]
|
||||
public bool HideOnFullHP = false;
|
||||
|
||||
[Checkbox("Hide when in duty")]
|
||||
[Order(9)]
|
||||
public bool HideInDuty = false;
|
||||
|
||||
[Checkbox("Hide in Island Sanctuary")]
|
||||
[Order(10)]
|
||||
public bool HideInIslandSanctuary = false;
|
||||
|
||||
[Checkbox("Hide in PvP")]
|
||||
[Order(11)]
|
||||
public bool HideInPvP = false;
|
||||
|
||||
[Checkbox("Always show when in duty")]
|
||||
[Order(20)]
|
||||
public bool ShowInDuty = false;
|
||||
|
||||
[Checkbox("Always show when weapon is drawn")]
|
||||
[Order(21)]
|
||||
public bool ShowOnWeaponDrawn = false;
|
||||
|
||||
[Checkbox("Always show when crafting")]
|
||||
[Order(22)]
|
||||
public bool ShowWhileCrafting = false;
|
||||
|
||||
[Checkbox("Always show when gathering")]
|
||||
[Order(23)]
|
||||
public bool ShowWhileGathering = false;
|
||||
|
||||
[Checkbox("Always show while in a party")]
|
||||
[Order(24)]
|
||||
public bool ShowInParty = false;
|
||||
|
||||
[Checkbox("Always show while in Island Sanctuary")]
|
||||
[Order(25)]
|
||||
public bool ShowInIslandSanctuary = false;
|
||||
|
||||
[Checkbox("Always show while in PvP")]
|
||||
[Order(26)]
|
||||
public bool ShowInPvP = false;
|
||||
|
||||
[Checkbox("Always show while target exists")]
|
||||
[Order(27)]
|
||||
public bool ShowWhileTargetExists = false;
|
||||
|
||||
|
||||
private bool IsInCombat() => Plugin.Condition[ConditionFlag.InCombat];
|
||||
|
||||
private bool IsInDuty() => Plugin.Condition[ConditionFlag.BoundByDuty];
|
||||
|
||||
private bool IsCrafting() => Plugin.Condition[ConditionFlag.Crafting] || Plugin.Condition[ConditionFlag.ExecutingCraftingAction];
|
||||
|
||||
private bool IsGathering() => Plugin.Condition[ConditionFlag.Gathering] || Plugin.Condition[ConditionFlag.ExecutingGatheringAction];
|
||||
|
||||
private bool HasWeaponDrawn() => (Plugin.ObjectTable.LocalPlayer != null && Plugin.ObjectTable.LocalPlayer.StatusFlags.HasFlag(StatusFlags.WeaponOut));
|
||||
|
||||
private bool IsInGoldSaucer() => _goldSaucerIDs.Any(id => id == Plugin.ClientState.TerritoryType);
|
||||
|
||||
private bool IsInIslandSanctuary() => Plugin.ClientState.TerritoryType == 1055;
|
||||
|
||||
private readonly uint[] _goldSaucerIDs = { 144, 388, 389, 390, 391, 579, 792, 899, 941 };
|
||||
|
||||
public bool IsElementVisible(HudElement? element = null)
|
||||
{
|
||||
if (!Enabled) { return true; }
|
||||
if (!ConfigurationManager.Instance.LockHUD) { return true; }
|
||||
if (element != null && element.GetType() == typeof(PlayerCastbarHud)) { return true; }
|
||||
if (element != null && !element.GetConfig().Enabled) { return false; }
|
||||
|
||||
bool isInIslandSanctuary = IsInIslandSanctuary();
|
||||
bool isInDuty = IsInDuty() && !isInIslandSanctuary;
|
||||
IPlayerCharacter? player = Plugin.ObjectTable.LocalPlayer;
|
||||
|
||||
// show
|
||||
if (ShowInDuty && isInDuty) { return true; }
|
||||
|
||||
if (ShowOnWeaponDrawn && HasWeaponDrawn()) { return true; }
|
||||
|
||||
if (ShowWhileCrafting && IsCrafting()) { return true; }
|
||||
|
||||
if (ShowWhileGathering && IsGathering()) { return true; }
|
||||
|
||||
if (ShowInParty && PartyManager.Instance.MemberCount > 1) { return true; }
|
||||
|
||||
if (ShowInIslandSanctuary && isInIslandSanctuary) { return true; }
|
||||
|
||||
if (ShowInPvP && Plugin.ClientState.IsPvP) { return true; }
|
||||
|
||||
if (ShowWhileTargetExists && player != null && player.TargetObject != null) { return true; }
|
||||
|
||||
|
||||
// hide
|
||||
if (HideOutsideOfCombat && !IsInCombat()) { return false; }
|
||||
|
||||
if (HideInCombat && IsInCombat()) { return false; }
|
||||
|
||||
if (HideInGoldSaucer && IsInGoldSaucer()) { return false; }
|
||||
|
||||
if (HideOnFullHP && player != null && player.CurrentHp == player.MaxHp) { return false; }
|
||||
|
||||
if (HideInDuty && isInDuty) { return false; }
|
||||
|
||||
if (HideInIslandSanctuary && isInIslandSanctuary) { return false; }
|
||||
|
||||
if (HideInPvP && Plugin.ClientState.IsPvP) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CopyFrom(VisibilityConfig config)
|
||||
{
|
||||
Enabled = config.Enabled;
|
||||
|
||||
HideOutsideOfCombat = config.HideOutsideOfCombat;
|
||||
HideInCombat = config.HideInCombat;
|
||||
HideInGoldSaucer = config.HideInGoldSaucer;
|
||||
HideOnFullHP = config.HideOnFullHP;
|
||||
HideInDuty = config.HideInDuty;
|
||||
HideInIslandSanctuary = config.HideInIslandSanctuary;
|
||||
HideInPvP = config.HideInPvP;
|
||||
|
||||
ShowInDuty = config.ShowInDuty;
|
||||
ShowOnWeaponDrawn = config.ShowOnWeaponDrawn;
|
||||
ShowWhileCrafting = config.ShowWhileCrafting;
|
||||
ShowWhileGathering = config.ShowWhileGathering;
|
||||
ShowInParty = config.ShowInParty;
|
||||
ShowInIslandSanctuary = config.ShowInIslandSanctuary;
|
||||
ShowInPvP = config.ShowInPvP;
|
||||
ShowWhileTargetExists = config.ShowWhileTargetExists;
|
||||
}
|
||||
|
||||
public VisibilityConfig()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public enum WindowClippingMode
|
||||
{
|
||||
Full,
|
||||
Hide,
|
||||
Performance
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
[Disableable(false)]
|
||||
[Section("Misc")]
|
||||
[SubSection("Window Clipping", 0)]
|
||||
public class WindowClippingConfig : PluginConfigObject
|
||||
{
|
||||
public new static WindowClippingConfig DefaultConfig() => new WindowClippingConfig();
|
||||
|
||||
public WindowClippingMode Mode = WindowClippingMode.Full;
|
||||
|
||||
public bool NameplatesClipRectsEnabled = true;
|
||||
public bool TargetCastbarClipRectEnabled = false;
|
||||
public bool HotbarsClipRectsEnabled = false;
|
||||
public bool ChatBubblesPlayersClipRectsEnabled = true;
|
||||
public bool ChatBubblesNPCClipRectsEnabled = true;
|
||||
|
||||
public bool ThirdPartyClipRectsEnabled = true;
|
||||
|
||||
private bool _showConfirmationDialog = false;
|
||||
|
||||
[ManualDraw]
|
||||
public bool Draw(ref bool changed)
|
||||
{
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
|
||||
if (ImGui.Checkbox("Enabled", ref Enabled))
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
Enabled = false;
|
||||
_showConfirmationDialog = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// confirmation dialog
|
||||
if (_showConfirmationDialog)
|
||||
{
|
||||
string[] lines = new string[] { "THIS FEATURE IS KNOWN TO CAUSE RANDOM", "CRASHES TO A SMALL PORTION OF USERS!!!", "Are you sure you want to enable it?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("WARNING!", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
Enabled = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_showConfirmationDialog = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Enabled) { return changed; }
|
||||
|
||||
// mode
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
ImGui.SameLine();
|
||||
ImGui.Text("Mode: ");
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Full", Mode == WindowClippingMode.Full))
|
||||
{
|
||||
Mode = WindowClippingMode.Full;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Hide", Mode == WindowClippingMode.Hide))
|
||||
{
|
||||
Mode = WindowClippingMode.Hide;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Performance", Mode == WindowClippingMode.Performance))
|
||||
{
|
||||
Mode = WindowClippingMode.Performance;
|
||||
}
|
||||
|
||||
// nameplates
|
||||
ImGui.NewLine();
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
changed |= ImGui.Checkbox("Enable special clipping for Nameplates", ref NameplatesClipRectsEnabled);
|
||||
ImGuiHelper.SetTooltip("When enabled, Nameplates will get covered by game UI elements that wouldn't normally cover HSUI elements.");
|
||||
|
||||
if (NameplatesClipRectsEnabled)
|
||||
{
|
||||
ImGuiHelper.Tab(); ImGuiHelper.Tab();
|
||||
changed |= ImGui.Checkbox("Default Target Castbar", ref TargetCastbarClipRectEnabled);
|
||||
ImGuiHelper.SetTooltip("When enabled, the game's target castbar will not be covered by HSUI Nameplates.\nFor players that prefer to use the default target cast bar over HSUI's.");
|
||||
|
||||
ImGuiHelper.Tab(); ImGuiHelper.Tab();
|
||||
changed |= ImGui.Checkbox("Hotbars", ref HotbarsClipRectsEnabled);
|
||||
ImGuiHelper.SetTooltip("When enabled, active hotbar will not be covered by HSUI Nameplates.\nNote that the way this is calculated is not perfect and it might not work well for hotbars that have empty slots.");
|
||||
|
||||
ImGuiHelper.Tab(); ImGuiHelper.Tab();
|
||||
changed |= ImGui.Checkbox("NPC Chat Bubbles", ref ChatBubblesNPCClipRectsEnabled);
|
||||
|
||||
ImGuiHelper.Tab(); ImGuiHelper.Tab();
|
||||
changed |= ImGui.Checkbox("Player Chat Bubbles", ref ChatBubblesPlayersClipRectsEnabled);
|
||||
}
|
||||
|
||||
// third party
|
||||
ImGui.NewLine();
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
changed |= ImGui.Checkbox("Enable clipping for other plugins", ref ThirdPartyClipRectsEnabled);
|
||||
ImGuiHelper.SetTooltip("When enabled, other plugins' windows can also be clipped so HSUI elements don't cover them.\nPlease note that this requires the developer of each third party plugin to implement the feature.");
|
||||
|
||||
// text
|
||||
ImGui.NewLine();
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
ImGui.SameLine();
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case WindowClippingMode.Full:
|
||||
ImGui.Text("HSUI will attempt to not cover game windows in this mode by clipping around them.");
|
||||
break;
|
||||
|
||||
case WindowClippingMode.Hide:
|
||||
ImGui.Text("HSUI will attempt to not cover game windows in this mode by not drawing an element if its touching a game window.");
|
||||
break;
|
||||
|
||||
case WindowClippingMode.Performance:
|
||||
ImGui.Text("Window Clipping functionality will be reduced in favor of performance.\nOnly one game window will be clipped at a time. This might yield unexpected / ugly results.\n\nNote: This mode won't work well with Nameplates.");
|
||||
break;
|
||||
}
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
ImGui.Text("If you're experiencing random crashes or bad performance, we recommend you try a different mode\nor disable Window Clipping altogether");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user