f37369cdda
Co-authored-by: Cursor <cursoragent@cursor.com>
342 lines
12 KiB
C#
342 lines
12 KiB
C#
using Dalamud.Game.ClientState.JobGauge.Types;
|
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
|
using Dalamud.Game.ClientState.Objects.Types;
|
|
using Dalamud.Game.ClientState.Statuses;
|
|
using HSUI.Config;
|
|
using HSUI.Config.Attributes;
|
|
using HSUI.Helpers;
|
|
using HSUI.Interface.Bars;
|
|
using HSUI.Interface.GeneralElements;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.Gauge;
|
|
using Newtonsoft.Json;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
|
|
namespace HSUI.Interface.Jobs
|
|
{
|
|
public class NinjaHud : JobHud
|
|
{
|
|
private new NinjaConfig Config => (NinjaConfig)_config;
|
|
|
|
public NinjaHud(NinjaConfig 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.KazematoiBar.Enabled)
|
|
{
|
|
positions.Add(Config.Position + Config.KazematoiBar.Position);
|
|
sizes.Add(Config.KazematoiBar.Size);
|
|
}
|
|
|
|
if (Config.NinkiBar.Enabled)
|
|
{
|
|
positions.Add(Config.Position + Config.NinkiBar.Position);
|
|
sizes.Add(Config.NinkiBar.Size);
|
|
}
|
|
|
|
if (Config.TrickAttackBar.Enabled)
|
|
{
|
|
positions.Add(Config.Position + Config.TrickAttackBar.Position);
|
|
sizes.Add(Config.TrickAttackBar.Size);
|
|
}
|
|
|
|
if (Config.SuitonBar.Enabled)
|
|
{
|
|
positions.Add(Config.Position + Config.SuitonBar.Position);
|
|
sizes.Add(Config.SuitonBar.Size);
|
|
}
|
|
|
|
if (Config.MudraBar.Enabled)
|
|
{
|
|
positions.Add(Config.Position + Config.MudraBar.Position);
|
|
sizes.Add(Config.MudraBar.Size);
|
|
}
|
|
|
|
return (positions, sizes);
|
|
}
|
|
|
|
public override void DrawJobHud(Vector2 origin, IPlayerCharacter player)
|
|
{
|
|
var pos = origin + Config.Position;
|
|
if (Config.MudraBar.Enabled)
|
|
{
|
|
DrawMudraBars(pos, player);
|
|
}
|
|
|
|
if (Config.KazematoiBar.Enabled)
|
|
{
|
|
DrawKazematoiBar(pos, player);
|
|
}
|
|
|
|
if (Config.NinkiBar.Enabled)
|
|
{
|
|
DrawNinkiGauge(pos, player);
|
|
}
|
|
|
|
if (Config.TrickAttackBar.Enabled)
|
|
{
|
|
DrawTrickAttackBar(pos, player);
|
|
}
|
|
|
|
if (Config.SuitonBar.Enabled)
|
|
{
|
|
DrawSuitonBar(pos, player);
|
|
}
|
|
}
|
|
|
|
public (bool, bool, bool) GetMudraBuffs(IPlayerCharacter? player, out IStatus? ninjutsuBuff, out IStatus? kassatsuBuff, out IStatus? tcjBuff)
|
|
{
|
|
ninjutsuBuff = null;
|
|
kassatsuBuff = null;
|
|
tcjBuff = null;
|
|
|
|
if (player is not null)
|
|
{
|
|
var statusList = Utils.StatusListForBattleChara(player);
|
|
foreach (IStatus status in statusList)
|
|
{
|
|
if (status.StatusId == 496) { ninjutsuBuff = status; }
|
|
if (status.StatusId == 497) { kassatsuBuff = status; }
|
|
if (status.StatusId == 1186) { tcjBuff = status; }
|
|
}
|
|
}
|
|
|
|
return (ninjutsuBuff is not null, kassatsuBuff is not null, tcjBuff is not null);
|
|
}
|
|
|
|
private void DrawMudraBars(Vector2 origin, IPlayerCharacter player)
|
|
{
|
|
var (hasNinjutsuBuff, hasKassatsuBuff, hasTCJBuff) = GetMudraBuffs(player, out IStatus? ninjutsuBuff, out IStatus? kassatsuBuff, out IStatus? tcjBuff);
|
|
|
|
int mudraStacks = SpellHelper.Instance.GetStackCount(2, 2259);
|
|
float mudraCooldown = SpellHelper.Instance.GetSpellCooldown(2259);
|
|
|
|
float current = 0f;
|
|
float max = 0f;
|
|
|
|
// For some reason, the mudras may be on cooldown before the "Mudra" buff is applied.
|
|
// Mudra stack count is set to -2 when a mudra is in the middle of its re-cast timer, so we can check for that instead.
|
|
bool inNinjutsu = mudraStacks == -2 || hasNinjutsuBuff;
|
|
|
|
if (hasTCJBuff || hasKassatsuBuff || inNinjutsu)
|
|
{
|
|
if (hasTCJBuff)
|
|
{
|
|
max = 6f;
|
|
current = tcjBuff is null || tcjBuff.RemainingTime < 0 ? max : tcjBuff.RemainingTime;
|
|
Config.MudraBar.Label.SetText(GenerateNinjutsuText(tcjBuff?.Param ?? 0, hasKassatsuBuff, hasTCJBuff));
|
|
}
|
|
else if (hasKassatsuBuff)
|
|
{
|
|
max = 15f;
|
|
current = kassatsuBuff is null || kassatsuBuff.RemainingTime < 0 ? max : kassatsuBuff.RemainingTime;
|
|
Config.MudraBar.Label.SetText("KASSATSU");
|
|
}
|
|
|
|
if (inNinjutsu)
|
|
{
|
|
max = 6f;
|
|
current = ninjutsuBuff is null || ninjutsuBuff.RemainingTime < 0 ? max : ninjutsuBuff.RemainingTime;
|
|
Config.MudraBar.Label.SetText(GenerateNinjutsuText(ninjutsuBuff?.Param ?? 0, hasKassatsuBuff, hasTCJBuff));
|
|
}
|
|
|
|
PluginConfigColor fillColor = hasTCJBuff ? Config.MudraBar.TCJBarColor : hasKassatsuBuff ? Config.MudraBar.KassatsuBarColor : Config.MudraBar.FillColor;
|
|
Rect foreground = BarUtilities.GetFillRect(Config.MudraBar.Position, Config.MudraBar.Size, Config.MudraBar.FillDirection, fillColor, current, max);
|
|
|
|
BarHud bar = new BarHud(Config.MudraBar, player);
|
|
bar.AddForegrounds(foreground);
|
|
bar.AddLabels(Config.MudraBar.Label);
|
|
|
|
AddDrawActions(bar.GetDrawActions(origin, Config.MudraBar.StrataLevel));
|
|
}
|
|
else
|
|
{
|
|
max = 40f;
|
|
current = max - mudraCooldown;
|
|
|
|
if (!Config.MudraBar.HideWhenInactive || current < max)
|
|
{
|
|
Config.MudraBar.Label.SetValue((max - current) % 20);
|
|
|
|
BarHud[] bars = BarUtilities.GetChunkedProgressBars(Config.MudraBar, 2, current, max, 0f, player);
|
|
foreach (BarHud bar in bars)
|
|
{
|
|
AddDrawActions(bar.GetDrawActions(origin, Config.MudraBar.StrataLevel));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private unsafe void DrawKazematoiBar(Vector2 origin, IPlayerCharacter player)
|
|
{
|
|
NinjaGauge* gauge = (NinjaGauge*)Plugin.JobGauges.Get<NINGauge>().Address;
|
|
int stacks = gauge->Kazematoi;
|
|
|
|
if (Config.KazematoiBar.HideWhenInactive && stacks == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BarHud[] bars = BarUtilities.GetChunkedBars(Config.KazematoiBar, 5, stacks, 5, 0, player);
|
|
foreach (BarHud bar in bars)
|
|
{
|
|
AddDrawActions(bar.GetDrawActions(origin, Config.KazematoiBar.StrataLevel));
|
|
}
|
|
}
|
|
|
|
private unsafe void DrawNinkiGauge(Vector2 origin, IPlayerCharacter player)
|
|
{
|
|
NinjaGauge* gauge = (NinjaGauge*)Plugin.JobGauges.Get<NINGauge>().Address;
|
|
int ninki = gauge->Ninki;
|
|
|
|
if (Config.NinkiBar.HideWhenInactive && ninki == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Config.NinkiBar.Label.SetValue(ninki);
|
|
|
|
BarHud[] bars = BarUtilities.GetChunkedProgressBars(Config.NinkiBar, 2, ninki, 100, 0, player);
|
|
foreach (BarHud bar in bars)
|
|
{
|
|
AddDrawActions(bar.GetDrawActions(origin, Config.NinkiBar.StrataLevel));
|
|
}
|
|
}
|
|
|
|
private void DrawTrickAttackBar(Vector2 origin, IPlayerCharacter player)
|
|
{
|
|
IGameObject? actor = Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target;
|
|
|
|
float trickDuration = Utils.StatusListForActor(actor).FirstOrDefault(
|
|
o => o.StatusId is 3254 or 3906 && o.SourceId == player.GameObjectId && o.RemainingTime > 0
|
|
)?.RemainingTime ?? 0f;
|
|
|
|
if (Config.TrickAttackBar.HideWhenInactive && trickDuration == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Config.TrickAttackBar.Label.SetValue(trickDuration);
|
|
|
|
BarHud bar = BarUtilities.GetProgressBar(Config.TrickAttackBar, trickDuration, 15f, 0f, player);
|
|
AddDrawActions(bar.GetDrawActions(origin, Config.TrickAttackBar.StrataLevel));
|
|
}
|
|
|
|
private void DrawSuitonBar(Vector2 origin, IPlayerCharacter player)
|
|
{
|
|
float suitonDuration = Utils.StatusListForBattleChara(player).FirstOrDefault(
|
|
o => o.StatusId == 3848 && o.RemainingTime > 0
|
|
)?.RemainingTime ?? 0f;
|
|
|
|
if (Config.SuitonBar.HideWhenInactive && suitonDuration == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Config.SuitonBar.Label.SetValue(suitonDuration);
|
|
|
|
BarHud bar = BarUtilities.GetProgressBar(Config.SuitonBar, suitonDuration, 20f, 0f, player);
|
|
AddDrawActions(bar.GetDrawActions(origin, Config.SuitonBar.StrataLevel));
|
|
}
|
|
|
|
private string GenerateNinjutsuText(ushort param, bool haveKassatsuBuff, bool haveTCJBuff)
|
|
{
|
|
return param switch
|
|
{
|
|
1 or 2 or 3 => "FUMA SHURIKEN",
|
|
6 or 7 => haveKassatsuBuff ? "GOKA MEKKYAKU" : "KATON",
|
|
9 or 11 => "RAITON",
|
|
13 or 14 => haveKassatsuBuff ? "HYOSHO RANRYU" : "HYOTON",
|
|
27 or 30 => "HUTON",
|
|
39 or 45 => "DOTON",
|
|
54 or 57 => "SUITON",
|
|
_ => haveTCJBuff ? "TEN CHI JIN" : "",
|
|
};
|
|
}
|
|
}
|
|
|
|
[Section("Job Specific Bars")]
|
|
[SubSection("Melee", 0)]
|
|
[SubSection("Ninja", 1)]
|
|
public class NinjaConfig : JobConfig
|
|
{
|
|
[JsonIgnore] public override uint JobId => JobIDs.NIN;
|
|
|
|
public new static NinjaConfig DefaultConfig()
|
|
{
|
|
var config = new NinjaConfig();
|
|
|
|
config.MudraBar.Label.FontID = FontsConfig.DefaultMediumFontKey;
|
|
config.MudraBar.LabelMode = LabelMode.ActiveChunk;
|
|
|
|
config.TrickAttackBar.Label.FontID = FontsConfig.DefaultMediumFontKey;
|
|
config.TrickAttackBar.Enabled = false;
|
|
|
|
config.SuitonBar.Label.FontID = FontsConfig.DefaultMediumFontKey;
|
|
config.SuitonBar.Enabled = false;
|
|
|
|
config.NinkiBar.UsePartialFillColor = true;
|
|
|
|
return config;
|
|
}
|
|
|
|
[NestedConfig("Mudra Bar", 30)]
|
|
public NinjaMudraBarConfig MudraBar = new NinjaMudraBarConfig(
|
|
new(0, -50),
|
|
new(254, 10),
|
|
new PluginConfigColor(new Vector4(211f / 255f, 166f / 255f, 75f / 242f, 100f / 100f))
|
|
);
|
|
|
|
[NestedConfig("Kazematoi Bar", 35)]
|
|
public ChunkedBarConfig KazematoiBar = new ChunkedBarConfig(
|
|
new(0, -10),
|
|
new(254, 20),
|
|
PluginConfigColor.FromHex(0xFFABB6BD)
|
|
);
|
|
|
|
|
|
[NestedConfig("Ninki Bar", 40)]
|
|
public ChunkedProgressBarConfig NinkiBar = new ChunkedProgressBarConfig(
|
|
new(0, -32),
|
|
new(254, 20),
|
|
new PluginConfigColor(new Vector4(137f / 255f, 82f / 255f, 236f / 255f, 100f / 100f))
|
|
);
|
|
|
|
[NestedConfig("Trick Attack Bar", 45)]
|
|
public ProgressBarConfig TrickAttackBar = new ProgressBarConfig(
|
|
new(0, -63),
|
|
new(254, 10),
|
|
new PluginConfigColor(new Vector4(191f / 255f, 40f / 255f, 0f / 255f, 100f / 100f))
|
|
);
|
|
|
|
[NestedConfig("Shadow Walker Bar", 50)]
|
|
public ProgressBarConfig SuitonBar = new ProgressBarConfig(
|
|
new(0, -75),
|
|
new(254, 10),
|
|
new PluginConfigColor(new Vector4(202f / 255f, 228f / 255f, 246f / 242f, 100f / 100f))
|
|
);
|
|
}
|
|
|
|
[Exportable(false)]
|
|
public class NinjaMudraBarConfig : ChunkedProgressBarConfig
|
|
{
|
|
[ColorEdit4("Kassatsu Color", spacing = true)]
|
|
[Order(60)]
|
|
public PluginConfigColor KassatsuBarColor = new(new Vector4(239 / 255f, 123 / 255f, 222 / 242f, 100f / 100f));
|
|
|
|
[ColorEdit4("Ten Chi Jin Color")]
|
|
[Order(65)]
|
|
public PluginConfigColor TCJBarColor = new(new Vector4(181 / 255f, 33 / 255f, 41 / 242f, 100f / 100f));
|
|
|
|
public NinjaMudraBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor) : base(position, size, fillColor, 2)
|
|
{
|
|
Label.Enabled = true;
|
|
UsePartialFillColor = true;
|
|
}
|
|
}
|
|
}
|