Initial release: HSUI v1.0.0.0 - HUD replacement with configurable hotbars
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
using Dalamud.Game.ClientState.JobGauge.Types;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Helpers;
|
||||
using HSUI.Interface.Bars;
|
||||
using HSUI.Interface.GeneralElements;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace HSUI.Interface.Jobs
|
||||
{
|
||||
public class ViperHud : JobHud
|
||||
{
|
||||
private new ViperConfig Config => (ViperConfig)_config;
|
||||
|
||||
public ViperHud(ViperConfig config, string? displayName = null) : base(config, displayName) { }
|
||||
|
||||
protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
|
||||
{
|
||||
List<Vector2> positions = new List<Vector2>();
|
||||
List<Vector2> sizes = new List<Vector2>();
|
||||
|
||||
if (Config.RattlingCoilGauge.Enabled)
|
||||
{
|
||||
positions.Add(Config.Position + Config.RattlingCoilGauge.Position);
|
||||
sizes.Add(Config.RattlingCoilGauge.Size);
|
||||
}
|
||||
|
||||
if (Config.Vipersight.Enabled)
|
||||
{
|
||||
positions.Add(Config.Position + Config.Vipersight.Position);
|
||||
sizes.Add(Config.Vipersight.Size);
|
||||
}
|
||||
|
||||
if (Config.AnguineTribute.Enabled)
|
||||
{
|
||||
positions.Add(Config.Position + Config.AnguineTribute.Position);
|
||||
sizes.Add(Config.AnguineTribute.Size);
|
||||
}
|
||||
|
||||
if (Config.SerpentOfferings.Enabled)
|
||||
{
|
||||
positions.Add(Config.Position + Config.SerpentOfferings.Position);
|
||||
sizes.Add(Config.SerpentOfferings.Size);
|
||||
}
|
||||
|
||||
return (positions, sizes);
|
||||
}
|
||||
|
||||
public override void DrawJobHud(Vector2 origin, IPlayerCharacter player)
|
||||
{
|
||||
if (Config.RattlingCoilGauge.Enabled)
|
||||
{
|
||||
DrawRattlingCoilGauge(origin + Config.Position, player);
|
||||
}
|
||||
|
||||
if (Config.Vipersight.Enabled)
|
||||
{
|
||||
DrawVipersightBar(origin + Config.Position, player);
|
||||
}
|
||||
|
||||
if (Config.SerpentOfferings.Enabled)
|
||||
{
|
||||
DrawSerpentOfferingsBar(origin + Config.Position, player);
|
||||
}
|
||||
|
||||
if (Config.AnguineTribute.Enabled)
|
||||
{
|
||||
DrawAnguineTributeGauge(origin + Config.Position, player);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DrawVipersightBar(Vector2 origin, IPlayerCharacter player)
|
||||
{
|
||||
ViperCombo lastUsedActionId = (ViperCombo)SpellHelper.Instance.GetLastUsedActionId();
|
||||
ViperComboState comboState;
|
||||
bool isAoE = false;
|
||||
|
||||
switch (lastUsedActionId)
|
||||
{
|
||||
case ViperCombo.SteelMaw:
|
||||
case ViperCombo.DreadMaw:
|
||||
isAoE = true;
|
||||
comboState = ViperComboState.Started;
|
||||
break;
|
||||
case ViperCombo.SteelFangs:
|
||||
case ViperCombo.DreadFangs:
|
||||
comboState = ViperComboState.Started;
|
||||
break;
|
||||
case ViperCombo.HuntersBite:
|
||||
case ViperCombo.SwiftskinsBite:
|
||||
isAoE = true;
|
||||
comboState = ViperComboState.Finisher;
|
||||
break;
|
||||
case ViperCombo.HuntersSting:
|
||||
case ViperCombo.SwiftskinsSting:
|
||||
comboState = ViperComboState.Finisher;
|
||||
break;
|
||||
default:
|
||||
comboState = ViperComboState.None;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Config.Vipersight.HideWhenInactive && comboState == ViperComboState.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint leftId = SpellHelper.Instance.GetSpellActionId(isAoE ? (uint)ViperCombo.SteelMaw : (uint)ViperCombo.SteelFangs);
|
||||
bool isLeftGlowing = SpellHelper.Instance.IsActionHighlighted(leftId);
|
||||
|
||||
uint rightId = SpellHelper.Instance.GetSpellActionId(isAoE ? (uint)ViperCombo.DreadMaw : (uint)ViperCombo.DreadFangs);
|
||||
bool isRightGlowing = SpellHelper.Instance.IsActionHighlighted(rightId);
|
||||
|
||||
List<Tuple<PluginConfigColor, float, LabelConfig?>> chunks = new();
|
||||
List<bool> glows = new();
|
||||
|
||||
Tuple<PluginConfigColor, float, LabelConfig?> empty = new(PluginConfigColor.Empty, 1, null);
|
||||
Tuple<PluginConfigColor, float, LabelConfig?> start = new(Config.Vipersight.ComboStartColor, 1, null);
|
||||
Tuple<PluginConfigColor, float, LabelConfig?> endFlank = new(Config.Vipersight.ComboEndFlankColor, 1, null);
|
||||
Tuple<PluginConfigColor, float, LabelConfig?> endHind = new(Config.Vipersight.ComboEndHindColor, 1, null);
|
||||
Tuple<PluginConfigColor, float, LabelConfig?> endAoE = new(Config.Vipersight.ComboEndAOEColor, 1, null);
|
||||
|
||||
bool isFlankEnder = Utils.StatusListForBattleChara(player).Any(o => o.StatusId is 3645 or 3646);
|
||||
bool isHindEnder = Utils.StatusListForBattleChara(player).Any(o => o.StatusId is 3647 or 3648);
|
||||
bool noEnder = !isFlankEnder && !isHindEnder;
|
||||
|
||||
switch (comboState)
|
||||
{
|
||||
case ViperComboState.None:
|
||||
{
|
||||
chunks = [empty, empty, empty, empty];
|
||||
glows = [false, isLeftGlowing, isRightGlowing, false];
|
||||
break;
|
||||
}
|
||||
case ViperComboState.Started:
|
||||
{
|
||||
chunks = [empty, start, start, empty];
|
||||
glows = [false, isLeftGlowing || isAoE, isRightGlowing || isAoE, false];
|
||||
break;
|
||||
}
|
||||
case ViperComboState.Finisher:
|
||||
{
|
||||
bool isFlankChain = lastUsedActionId == ViperCombo.HuntersSting;
|
||||
bool isHindChain = lastUsedActionId == ViperCombo.SwiftskinsSting;
|
||||
|
||||
Tuple<PluginConfigColor, float, LabelConfig?> end;
|
||||
|
||||
if (isFlankEnder)
|
||||
{
|
||||
end = isHindChain ? endHind : endFlank;
|
||||
}
|
||||
else if (isHindEnder)
|
||||
{
|
||||
end = isFlankChain ? endFlank : endHind;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = isFlankChain ? endFlank : isHindChain ? endHind : endAoE;
|
||||
}
|
||||
|
||||
chunks = [end, start, start, end];
|
||||
glows = [isLeftGlowing, isLeftGlowing, isRightGlowing, isRightGlowing];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.Vipersight.Invert)
|
||||
{
|
||||
chunks.Reverse();
|
||||
glows.Reverse();
|
||||
}
|
||||
|
||||
BarHud[] bars = BarUtilities.GetChunkedBars(
|
||||
Config.Vipersight,
|
||||
chunks.ToArray(),
|
||||
player,
|
||||
Config.Vipersight.GlowConfig,
|
||||
glows.ToArray()
|
||||
);
|
||||
|
||||
foreach (BarHud bar in bars)
|
||||
{
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.Vipersight.StrataLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DrawRattlingCoilGauge(Vector2 origin, IPlayerCharacter player)
|
||||
{
|
||||
VPRGauge gauge = Plugin.JobGauges.Get<VPRGauge>();
|
||||
|
||||
if (Config.RattlingCoilGauge.HideWhenInactive && gauge.RattlingCoilStacks <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int maxStacks = player.Level >= 88 ? 3 : 2;
|
||||
BarHud[] bars = BarUtilities.GetChunkedBars(Config.RattlingCoilGauge, maxStacks, gauge.RattlingCoilStacks, maxStacks, 0, player);
|
||||
foreach (BarHud bar in bars)
|
||||
{
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.RattlingCoilGauge.StrataLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DrawAnguineTributeGauge(Vector2 origin, IPlayerCharacter player)
|
||||
{
|
||||
VPRGauge gauge = Plugin.JobGauges.Get<VPRGauge>();
|
||||
|
||||
if (Config.AnguineTribute.HideWhenInactive && gauge.AnguineTribute <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int maxStacks = player.Level >= 96 ? 5 : 4;
|
||||
BarHud[] bars = BarUtilities.GetChunkedBars(Config.AnguineTribute, maxStacks, gauge.AnguineTribute, maxStacks, 0, player);
|
||||
foreach (BarHud bar in bars)
|
||||
{
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.AnguineTribute.StrataLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DrawSerpentOfferingsBar(Vector2 origin, IPlayerCharacter player)
|
||||
{
|
||||
ViperConfig.SerpentOfferingsBarConfig config = Config.SerpentOfferings;
|
||||
VPRGauge gauge = Plugin.JobGauges.Get<VPRGauge>();
|
||||
|
||||
float reawakenedDuration = Utils.StatusListForBattleChara(player).FirstOrDefault(o => o.StatusId is 3670 or 4094 && o.RemainingTime > 0f)?.RemainingTime ?? 0f;
|
||||
bool reAwakenedReady = Utils.StatusListForBattleChara(player).Any(o => o.StatusId is 3671) || gauge.SerpentOffering >= 50;
|
||||
bool isReawakened = reawakenedDuration > 0;
|
||||
bool showReawakened = isReawakened && config.EnableAwakenedTimer;
|
||||
|
||||
float serpentOffering = showReawakened && isReawakened ? reawakenedDuration : gauge.SerpentOffering;
|
||||
|
||||
if (Config.SerpentOfferings.HideWhenInactive && gauge.SerpentOffering <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Config.SerpentOfferings.Label.SetValue(serpentOffering);
|
||||
|
||||
BarHud[] bars = BarUtilities.GetChunkedProgressBars(
|
||||
config,
|
||||
showReawakened ? 1 : 2,
|
||||
showReawakened ? reawakenedDuration : serpentOffering,
|
||||
showReawakened ? 30f : 100f,
|
||||
fillColor: reAwakenedReady ? config.AwakenedColor : config.FillColor
|
||||
); ;
|
||||
|
||||
foreach (BarHud bar in bars)
|
||||
{
|
||||
AddDrawActions(bar.GetDrawActions(origin, Config.SerpentOfferings.StrataLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ViperCombo
|
||||
{
|
||||
SteelFangs = 34606,
|
||||
DreadFangs = 34607,
|
||||
HuntersSting = 34608,
|
||||
SwiftskinsSting = 34609,
|
||||
SteelMaw = 34614,
|
||||
DreadMaw = 34615,
|
||||
HuntersBite = 34616,
|
||||
SwiftskinsBite = 34617
|
||||
}
|
||||
|
||||
public enum ViperComboState
|
||||
{
|
||||
None,
|
||||
Started,
|
||||
Finisher
|
||||
}
|
||||
|
||||
[Section("Job Specific Bars")]
|
||||
[SubSection("Melee", 0)]
|
||||
[SubSection("Viper", 1)]
|
||||
public class ViperConfig : JobConfig
|
||||
{
|
||||
[JsonIgnore] public override uint JobId => JobIDs.VPR;
|
||||
|
||||
public new static ViperConfig DefaultConfig()
|
||||
{
|
||||
var config = new ViperConfig();
|
||||
config.SerpentOfferings.UseChunks = false;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
[NestedConfig("Vipersight Bar", 30)]
|
||||
public VipersightBarConfig Vipersight = new VipersightBarConfig(
|
||||
new(0, -10),
|
||||
new(254, 10),
|
||||
new(new Vector4(237f / 255f, 141f / 255f, 7f / 255f, 100f / 100f))
|
||||
);
|
||||
|
||||
[NestedConfig("Rattling Coil Bar", 40)]
|
||||
public ChunkedBarConfig RattlingCoilGauge = new ChunkedBarConfig(
|
||||
new(0, -34),
|
||||
new(254, 10),
|
||||
new(new Vector4(204f / 255f, 40f / 255f, 40f / 255f, 1f))
|
||||
);
|
||||
|
||||
[NestedConfig("Serpent Offerings Bar", 45)]
|
||||
public SerpentOfferingsBarConfig SerpentOfferings = new SerpentOfferingsBarConfig(
|
||||
new(0, -46),
|
||||
new(254, 10),
|
||||
new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f))
|
||||
);
|
||||
|
||||
[NestedConfig("Anguine Tribute Bar", 50)]
|
||||
public ChunkedBarConfig AnguineTribute = new ChunkedBarConfig(
|
||||
new(0, -58),
|
||||
new(254, 10),
|
||||
new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f))
|
||||
);
|
||||
|
||||
[Exportable(false)]
|
||||
public class VipersightBarConfig : ChunkedBarConfig
|
||||
{
|
||||
[NestedConfig("Show Glow", 39, separator = false, spacing = true)]
|
||||
public BarGlowConfig GlowConfig = new BarGlowConfig();
|
||||
|
||||
[ColorEdit4("Combo Start", spacing = true)]
|
||||
[Order(41)]
|
||||
public PluginConfigColor ComboStartColor = new(new Vector4(230f / 255f, 33f / 255f, 33f / 255f, 100f / 100f));
|
||||
|
||||
[ColorEdit4("Flank Ender")]
|
||||
[Order(42)]
|
||||
public PluginConfigColor ComboEndFlankColor = new(new Vector4(46f / 255f, 228f / 255f, 42f / 255f, 1f));
|
||||
|
||||
[ColorEdit4("Hind Ender")]
|
||||
[Order(43)]
|
||||
public PluginConfigColor ComboEndHindColor = new(new Vector4(230f / 255f, 33f / 255f, 33f / 255f, 1f));
|
||||
|
||||
[ColorEdit4("Grim/Default Ender")]
|
||||
[Order(44)]
|
||||
public PluginConfigColor ComboEndAOEColor = new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f));
|
||||
|
||||
[Checkbox("Invert", spacing = true)]
|
||||
[Order(45)]
|
||||
public bool Invert = false;
|
||||
|
||||
public VipersightBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor)
|
||||
: base(position, size, fillColor)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Exportable(false)]
|
||||
public class SerpentOfferingsBarConfig : ChunkedProgressBarConfig
|
||||
{
|
||||
[Checkbox("Enable Awakened Timer", spacing = true)]
|
||||
[Order(46)]
|
||||
public bool EnableAwakenedTimer = true;
|
||||
|
||||
[ColorEdit4("Ready to Reawaken Color")]
|
||||
[Order(47)]
|
||||
public PluginConfigColor AwakenedColor = new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f));
|
||||
|
||||
public SerpentOfferingsBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor)
|
||||
: base(position, size, fillColor)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user