using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.Types; using HSUI.Config; using HSUI.Enums; using HSUI.Helpers; using HSUI.Interface.Bars; using HSUI.Interface.GeneralElements; using HSUI.Interface.StatusEffects; using Dalamud.Bindings.ImGui; using System.Collections.Generic; using System.Numerics; using Action = System.Action; using Character = Dalamud.Game.ClientState.Objects.Types.ICharacter; using StructsCharacter = FFXIVClientStructs.FFXIV.Client.Game.Character.Character; namespace HSUI.Interface.Nameplates { public class Nameplate { protected NameplateConfig _config; public bool Enabled => _config.Enabled; protected LabelHud _nameLabelHud; protected LabelHud _titleLabelHud; public Nameplate(NameplateConfig config) { _config = config; _nameLabelHud = new LabelHud(config.NameLabelConfig); _titleLabelHud = new LabelHud(config.TitleLabelConfig); } protected bool IsVisible(IGameObject? actor) { if (!_config.Enabled || actor == null || !_config.VisibilityConfig.IsElementVisible(null) || (_config.OnlyShowWhenTargeted && actor.Address != Plugin.TargetManager.Target?.Address)) { return false; } return true; } public virtual List<(StrataLevel, Action)> GetElementsDrawActions(NameplateData data) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); if (!IsVisible(data.GameObject)) { return drawActions; } drawActions.AddRange(GetMainLabelDrawActions(data)); return drawActions; } protected List<(StrataLevel, Action)> GetMainLabelDrawActions(NameplateData data, NameplateAnchor? barAnchor = null) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); Vector2 origin = _config.Position + (barAnchor?.Position ?? data.ScreenPosition); Vector2 swapOffset = Vector2.Zero; if (_config.SwapLabelsWhenNeeded && (data.IsTitlePrefix || data.Title.Length == 0)) { swapOffset = _config.TitleLabelConfig.Position - _config.NameLabelConfig.Position; } // name float nameAlpha = _config.RangeConfig.AlphaForDistance(data.Distance, _config.NameLabelConfig.Color.Vector.W); var (nameText, namePos, nameSize, nameColor) = _nameLabelHud.PreCalculate(origin + swapOffset, barAnchor?.Size, data.GameObject, data.Name, isPlayerName: data.Kind == ObjectKind.Player); drawActions.Add((_config.NameLabelConfig.StrataLevel, () => { _nameLabelHud.DrawLabel(nameText, namePos, nameSize, nameColor, nameAlpha); } )); // title float titleAlpha = _config.RangeConfig.AlphaForDistance(data.Distance, _config.TitleLabelConfig.Color.Vector.W); var (titleText, titlePos, titleSize, titleColor) = _titleLabelHud.PreCalculate(origin - swapOffset, barAnchor?.Size, data.GameObject, title: data.Title); if (data.Title.Length > 0) { drawActions.Add((_config.TitleLabelConfig.StrataLevel, () => { _titleLabelHud.DrawLabel(titleText, titlePos, titleSize, titleColor, titleAlpha); } )); } return drawActions; } } public class NameplateWithBar : Nameplate { protected NameplateBarConfig BarConfig => ((NameplateWithBarConfig)_config).GetBarConfig(); private LabelHud _leftLabelHud; private LabelHud _rightLabelHud; private LabelHud _optionalLabelHud; public NameplateWithBar(NameplateConfig config) : base(config) { _leftLabelHud = new LabelHud(BarConfig.LeftLabelConfig); _rightLabelHud = new LabelHud(BarConfig.RightLabelConfig); _optionalLabelHud = new LabelHud(BarConfig.OptionalLabelConfig); } public (bool, bool) GetMouseoverState(NameplateData data) { if (data.GameObject is not ICharacter character) { return (false, false); } if (!BarConfig.IsVisible(character.CurrentHp, character.MaxHp) || BarConfig.DisableInteraction) { return (false, false); } bool targeted = Plugin.TargetManager.Target?.Address == character.Address; Vector2 barSize = BarConfig.GetSize(targeted); Vector2 origin = _config.Position + data.ScreenPosition; Vector2 barPos = Utils.GetAnchoredPosition(origin, barSize, BarConfig.Anchor) + BarConfig.Position; var (areaStart, areaEnd) = BarConfig.MouseoverAreaConfig.GetArea(barPos, barSize); bool isHovering = ImGui.IsMouseHoveringRect(areaStart, areaEnd); bool ignoreMouseover = BarConfig.MouseoverAreaConfig.Enabled && BarConfig.MouseoverAreaConfig.Ignore; return (isHovering, ignoreMouseover); } public unsafe List<(StrataLevel, Action)> GetBarDrawActions(NameplateData data) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); if (!IsVisible(data.GameObject)) { return drawActions; } if (data.GameObject is not Character character) { return drawActions; } uint currentHp = character.CurrentHp; uint maxHp = character.MaxHp; if (!BarConfig.IsVisible(currentHp, maxHp)) { return drawActions; } // colors PluginConfigColor fillColor = GetFillColor(character, currentHp, maxHp); fillColor = fillColor.WithAlpha(_config.RangeConfig.AlphaForDistance(data.Distance, fillColor.Vector.W)); PluginConfigColor bgColor = GetBackgroundColor(character); bgColor = bgColor.WithAlpha(_config.RangeConfig.AlphaForDistance(data.Distance, bgColor.Vector.W)); bool targeted = character.Address == Plugin.TargetManager.Target?.Address; PluginConfigColor borderColor = targeted ? BarConfig.TargetedBorderColor : BarConfig.BorderColor; borderColor = borderColor.WithAlpha( _config.RangeConfig.AlphaForDistance(data.Distance, BarConfig.BorderColor.Vector.W) ); // bar Vector2 barSize = BarConfig.GetSize(targeted); Rect background = new Rect(BarConfig.Position, barSize, bgColor); Rect healthFill = BarUtilities.GetFillRect(BarConfig.Position, barSize, BarConfig.FillDirection, fillColor, currentHp, maxHp); BarHud bar = new BarHud( BarConfig.ID, BarConfig.DrawBorder, borderColor, targeted ? BarConfig.TargetedBorderThickness : BarConfig.BorderThickness, BarConfig.Anchor, character, current: currentHp, max: maxHp, shadowConfig: BarConfig.ShadowConfig, barTextureName: BarConfig.BarTextureName, barTextureDrawMode: BarConfig.BarTextureDrawMode ); bar.NeedsInputs = true; bar.SetBackground(background); bar.AddForegrounds(healthFill); // shield PluginConfigColor shieldColor = BarConfig.ShieldConfig.Color.WithAlpha( _config.RangeConfig.AlphaForDistance(data.Distance, BarConfig.ShieldConfig.Color.Vector.W) ); BarUtilities.AddShield(bar, BarConfig, BarConfig.ShieldConfig, character, healthFill.Size, shieldColor); // draw bar Vector2 origin = _config.Position + data.ScreenPosition; drawActions.AddRange(bar.GetDrawActions(origin, _config.StrataLevel)); // mouseover area BarHud? mouseoverAreaBar = BarConfig.MouseoverAreaConfig.GetBar( BarConfig.Position, barSize, BarConfig.ID + "_mouseoverArea", BarConfig.Anchor ); if (mouseoverAreaBar != null) { drawActions.AddRange(mouseoverAreaBar.GetDrawActions(origin, StrataLevel.HIGHEST)); } // labels Vector2 barPos = Utils.GetAnchoredPosition(origin, barSize, BarConfig.Anchor) + BarConfig.Position; LabelHud[] labels = GetLabels(maxHp); foreach (LabelHud label in labels) { LabelConfig labelConfig = (LabelConfig)label.GetConfig(); float alpha = _config.RangeConfig.AlphaForDistance(data.Distance, labelConfig.Color.Vector.W); var (labelText, labelPos, labelSize, labelColor) = label.PreCalculate(barPos, barSize, data.GameObject, data.Name, currentHp, maxHp, data.Kind == ObjectKind.Player); drawActions.Add((labelConfig.StrataLevel, () => { label.DrawLabel(labelText, labelPos, labelSize, labelColor, alpha); } )); } return drawActions; } public override List<(StrataLevel, Action)> GetElementsDrawActions(NameplateData data) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); if (!IsVisible(data.GameObject)) { return drawActions; } NameplateAnchor? barAnchor = GetBarAnchor(data); drawActions.AddRange(GetMainLabelDrawActions(data, barAnchor)); // Quest/state icon (e.g. ! ? above NPCs) - drawn when we have icon config and game provided icon ID if (_config is NameplateWithNPCBarConfig npcConfig && npcConfig.IconConfig.Enabled && data.NamePlateIconId > 0) { float alpha = _config.RangeConfig.AlphaForDistance(data.Distance, 1f); Vector2 anchorPos = barAnchor?.Position ?? (_config.Position + data.ScreenPosition); Vector2 anchorSize = barAnchor?.Size ?? Vector2.Zero; var pos = Utils.GetAnchoredPosition(anchorPos, -anchorSize, npcConfig.IconConfig.FrameAnchor); Vector2 iconPos = Utils.GetAnchoredPosition(pos + npcConfig.IconConfig.Position, npcConfig.IconConfig.Size, npcConfig.IconConfig.Anchor); drawActions.Add((npcConfig.IconConfig.StrataLevel, () => { DrawHelper.DrawInWindow(_config.ID + "_npcIcon", iconPos, npcConfig.IconConfig.Size, false, (drawList) => { DrawHelper.DrawIcon((uint)data.NamePlateIconId, iconPos, npcConfig.IconConfig.Size, false, alpha, drawList); }); })); } return drawActions; } protected virtual NameplateAnchor? GetBarAnchor(NameplateData data) { if (data.GameObject is Character chara && BarConfig.IsVisible(chara.CurrentHp, chara.MaxHp)) { bool targeted = Plugin.TargetManager.Target?.Address == data.GameObject.Address; Vector2 size = BarConfig.GetSize(targeted); Vector2 pos = Utils.GetAnchoredPosition(data.ScreenPosition + BarConfig.Position, size, BarConfig.Anchor); return new NameplateAnchor(pos, size); } return null; } private LabelHud[] GetLabels(uint maxHp) { List labels = new List(); if (BarConfig.HideHealthIfPossible && maxHp <= 0) { if (!Utils.IsHealthLabel(BarConfig.LeftLabelConfig)) { labels.Add(_leftLabelHud); } if (!Utils.IsHealthLabel(BarConfig.RightLabelConfig)) { labels.Add(_rightLabelHud); } if (!Utils.IsHealthLabel(BarConfig.OptionalLabelConfig)) { labels.Add(_optionalLabelHud); } } else { labels.Add(_leftLabelHud); labels.Add(_rightLabelHud); labels.Add(_optionalLabelHud); } return labels.ToArray(); } protected virtual PluginConfigColor GetFillColor(Character character, uint currentHp, uint maxHp) { return ColorUtils.ColorForCharacter( character, currentHp, maxHp, false, false, BarConfig.ColorByHealth ) ?? BarConfig.FillColor; } protected virtual PluginConfigColor GetBackgroundColor(Character character) { return BarConfig.BackgroundColor; } } public class NameplateWithBarAndExtras : NameplateWithBar { public NameplateWithBarAndExtras(NameplateConfig config) : base(config) { } public override List<(StrataLevel, Action)> GetElementsDrawActions(NameplateData data) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); if (!IsVisible(data.GameObject)) { return drawActions; } NameplateAnchor? barAnchor = GetBarAnchor(data); Vector2 origin = _config.Position + (barAnchor?.Position ?? data.ScreenPosition); Vector2 swapOffset = Vector2.Zero; if (_config.SwapLabelsWhenNeeded && (data.IsTitlePrefix || data.Title.Length == 0)) { swapOffset = _config.TitleLabelConfig.Position - _config.NameLabelConfig.Position; } // name float nameAlpha = _config.RangeConfig.AlphaForDistance(data.Distance, _config.NameLabelConfig.Color.Vector.W); var (nameText, namePos, nameSize, nameColor) = _nameLabelHud.PreCalculate(origin + swapOffset, barAnchor?.Size, data.GameObject, data.Name, isPlayerName: data.Kind == ObjectKind.Player); drawActions.Add((_config.NameLabelConfig.StrataLevel, () => { _nameLabelHud.DrawLabel(nameText, namePos, nameSize, nameColor, nameAlpha); } )); // title float titleAlpha = _config.RangeConfig.AlphaForDistance(data.Distance, _config.TitleLabelConfig.Color.Vector.W); var (titleText, titlePos, titleSize, titleColor) = _titleLabelHud.PreCalculate(origin - swapOffset, barAnchor?.Size, data.GameObject, title: data.Title); if (data.Title.Length > 0) { drawActions.Add((_config.TitleLabelConfig.StrataLevel, () => { _titleLabelHud.DrawLabel(titleText, titlePos, titleSize, titleColor, titleAlpha); } )); } // extras anchor NameplateExtrasAnchors extrasAnchors = new NameplateExtrasAnchors( barAnchor, _config.NameLabelConfig.Enabled ? new NameplateAnchor(namePos, nameSize) : null, _config.TitleLabelConfig.Enabled && data.Title.Length > 0 ? new NameplateAnchor(titlePos, titleSize) : null ); drawActions.AddRange(GetExtrasDrawActions(data, extrasAnchors)); return drawActions; } protected virtual List<(StrataLevel, Action)> GetExtrasDrawActions(NameplateData data, NameplateExtrasAnchors anchors) { // override return new List<(StrataLevel, Action)>(); } } public class NameplateWithPlayerBar : NameplateWithBarAndExtras { private NameplateWithPlayerBarConfig Config => (NameplateWithPlayerBarConfig)_config; public NameplateWithPlayerBar(NameplateWithPlayerBarConfig config) : base(config) { } protected override List<(StrataLevel, Action)> GetExtrasDrawActions(NameplateData data, NameplateExtrasAnchors anchors) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); if (data.GameObject is not IPlayerCharacter character) { return drawActions; } float alpha = _config.RangeConfig.AlphaForDistance(data.Distance); // role/job icon if (Config.RoleIconConfig.Enabled) { NameplateAnchor? anchor = anchors.GetAnchor(Config.RoleIconConfig.NameplateLabelAnchor, Config.RoleIconConfig.PrioritizeHealthBarAnchor); anchor = anchor ?? new NameplateAnchor(data.ScreenPosition, Vector2.Zero); 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 pos = Utils.GetAnchoredPosition(anchor.Value.Position, -anchor.Value.Size, Config.RoleIconConfig.FrameAnchor); var iconPos = Utils.GetAnchoredPosition(pos + Config.RoleIconConfig.Position, Config.RoleIconConfig.Size, Config.RoleIconConfig.Anchor); drawActions.Add((Config.RoleIconConfig.StrataLevel, () => { DrawHelper.DrawInWindow(_config.ID + "_jobIcon", iconPos, Config.RoleIconConfig.Size, false, (drawList) => { DrawHelper.DrawIcon(iconId, iconPos, Config.RoleIconConfig.Size, false, alpha, drawList); }); } )); } } // state icon if (Config.StateIconConfig.Enabled && data.NamePlateIconId > 0 && Config.StateIconConfig.ShouldDrawIcon(data.NamePlateIconId)) { NameplateAnchor? anchor = anchors.GetAnchor(Config.StateIconConfig.NameplateLabelAnchor, Config.StateIconConfig.PrioritizeHealthBarAnchor); anchor = anchor ?? new NameplateAnchor(data.ScreenPosition, Vector2.Zero); var pos = Utils.GetAnchoredPosition(anchor.Value.Position, -anchor.Value.Size, Config.StateIconConfig.FrameAnchor); var iconPos = Utils.GetAnchoredPosition(pos + Config.StateIconConfig.Position, Config.StateIconConfig.Size, Config.StateIconConfig.Anchor); drawActions.Add((Config.StateIconConfig.StrataLevel, () => { DrawHelper.DrawInWindow(_config.ID + "_stateIcon", iconPos, Config.StateIconConfig.Size, false, (drawList) => { DrawHelper.DrawIcon((uint)data.NamePlateIconId, iconPos, Config.StateIconConfig.Size, false, alpha, drawList); }); } )); } return drawActions; } protected override PluginConfigColor GetFillColor(Character character, uint currentHp, uint maxHp) { NameplatePlayerBarConfig config = (NameplatePlayerBarConfig)BarConfig; return ColorUtils.ColorForCharacter( character, currentHp, maxHp, config.UseJobColor, config.UseRoleColor, config.ColorByHealth ) ?? config.FillColor; } protected override PluginConfigColor GetBackgroundColor(Character character) { NameplatePlayerBarConfig config = (NameplatePlayerBarConfig)BarConfig; if (config.UseJobColorAsBackgroundColor) { return GlobalColors.Instance.SafeColorForJobId(character.ClassJob.RowId); } else if (config.UseRoleColorAsBackgroundColor) { return GlobalColors.Instance.SafeRoleColorForJobId(character.ClassJob.RowId); } return config.BackgroundColor; } } public class NameplateWithEnemyBar : NameplateWithBarAndExtras { private NameplateWithEnemyBarConfig Config => (NameplateWithEnemyBarConfig)_config; private LabelHud _orderLabelHud; private StatusEffectsListHud _debuffsHud; private NameplateCastbarHud _castbarHud; public NameplateWithEnemyBar(NameplateWithEnemyBarConfig config) : base(config) { _orderLabelHud = new LabelHud(config.BarConfig.OrderLabelConfig); _debuffsHud = new StatusEffectsListHud(config.DebuffsConfig); _castbarHud = new NameplateCastbarHud(config.CastbarConfig); } public void StopPreview() { _debuffsHud.StopPreview(); _castbarHud.StopPreview(); } protected override List<(StrataLevel, Action)> GetExtrasDrawActions(NameplateData data, NameplateExtrasAnchors anchors) { List<(StrataLevel, Action)> drawActions = new List<(StrataLevel, Action)>(); if (data.GameObject is not Character character) { return drawActions; } NameplateEnemyBarConfig barConfig = Config.BarConfig; NameplateAnchor? anchor = barConfig.IsVisible(character.CurrentHp, character.MaxHp) ? anchors.BarAnchor : anchors.NameLabelAnchor; anchor = anchor ?? new NameplateAnchor(_config.Position + data.ScreenPosition, Vector2.Zero); // order label float alpha = _config.RangeConfig.AlphaForDistance(data.Distance, barConfig.OrderLabelConfig.Color.Vector.W); barConfig.OrderLabelConfig.SetText(data.Order); var (labelText, labelPos, labelSize, labelColor) = _orderLabelHud.PreCalculate(anchor.Value.Position, anchor.Value.Size, data.GameObject); drawActions.Add((barConfig.OrderLabelConfig.StrataLevel, () => { _orderLabelHud.DrawLabel(labelText, labelPos, labelSize, labelColor, alpha); } )); // debuffs Vector2 buffsPos = Utils.GetAnchoredPosition(anchor.Value.Position, -anchor.Value.Size, Config.DebuffsConfig.HealthBarAnchor); drawActions.Add((Config.DebuffsConfig.StrataLevel, () => { _debuffsHud.Actor = character; _debuffsHud.PrepareForDraw(buffsPos); _debuffsHud.Draw(buffsPos); } )); // castbar Vector2 castbarPos = Utils.GetAnchoredPosition(anchor.Value.Position, -anchor.Value.Size, Config.CastbarConfig.HealthBarAnchor); drawActions.Add((Config.CastbarConfig.StrataLevel, () => { _castbarHud.ParentSize = anchor.Value.Size; _castbarHud.Actor = character; _castbarHud.PrepareForDraw(castbarPos); _castbarHud.Draw(castbarPos); } )); // icon if (Config.IconConfig.Enabled && data.NamePlateIconId > 0) { anchor = anchors.GetAnchor(Config.IconConfig.NameplateLabelAnchor, Config.IconConfig.PrioritizeHealthBarAnchor); anchor = anchor ?? new NameplateAnchor(data.ScreenPosition, Vector2.Zero); var pos = Utils.GetAnchoredPosition(_config.Position + anchor.Value.Position, -anchor.Value.Size, Config.IconConfig.FrameAnchor); var iconPos = Utils.GetAnchoredPosition(pos + Config.IconConfig.Position, Config.IconConfig.Size, Config.IconConfig.Anchor); drawActions.Add((Config.IconConfig.StrataLevel, () => { DrawHelper.DrawInWindow(_config.ID + "_enemyIcon", iconPos, Config.IconConfig.Size, false, (drawList) => { DrawHelper.DrawIcon((uint)data.NamePlateIconId, iconPos, Config.IconConfig.Size, false, alpha, drawList); }); } )); } // company icon (PvP Frontline: Maelstrom, Flames, Adders) var gcIconOverrides = (Config.CompanyIconConfig.IconIdTeam1, Config.CompanyIconConfig.IconIdTeam2, Config.CompanyIconConfig.IconIdTeam3); if (Config.CompanyIconConfig.Enabled && Utils.GrandCompanyIconIdForPvPEnemy(data.GameObject, gcIconOverrides) is uint gcIconId) { anchor = anchors.GetAnchor(Config.CompanyIconConfig.NameplateLabelAnchor, Config.CompanyIconConfig.PrioritizeHealthBarAnchor); anchor = anchor ?? new NameplateAnchor(data.ScreenPosition, Vector2.Zero); var pos = Utils.GetAnchoredPosition(_config.Position + anchor.Value.Position, -anchor.Value.Size, Config.CompanyIconConfig.FrameAnchor); var iconPos = Utils.GetAnchoredPosition(pos + Config.CompanyIconConfig.Position, Config.CompanyIconConfig.Size, Config.CompanyIconConfig.Anchor); drawActions.Add((Config.CompanyIconConfig.StrataLevel, () => { DrawHelper.DrawInWindow(_config.ID + "_enemyCompanyIcon", iconPos, Config.CompanyIconConfig.Size, false, (drawList) => { DrawHelper.DrawIcon(gcIconId, iconPos, Config.CompanyIconConfig.Size, false, alpha, drawList); }); } )); } // role/job icon (enemy players only; has ClassJob) if (Config.RoleIconConfig.Enabled && data.GameObject is IPlayerCharacter playerCharacter) { uint jobId = playerCharacter.ClassJob.RowId; uint iconId = Config.RoleIconConfig.UseRoleIcons ? JobsHelper.RoleIconIDForJob(jobId, Config.RoleIconConfig.UseSpecificDPSRoleIcons) : JobsHelper.IconIDForJob(jobId, (uint)Config.RoleIconConfig.Style); if (iconId > 0) { anchor = anchors.GetAnchor(Config.RoleIconConfig.NameplateLabelAnchor, Config.RoleIconConfig.PrioritizeHealthBarAnchor); anchor = anchor ?? new NameplateAnchor(data.ScreenPosition, Vector2.Zero); var pos = Utils.GetAnchoredPosition(_config.Position + anchor.Value.Position, -anchor.Value.Size, Config.RoleIconConfig.FrameAnchor); var iconPos = Utils.GetAnchoredPosition(pos + Config.RoleIconConfig.Position, Config.RoleIconConfig.Size, Config.RoleIconConfig.Anchor); drawActions.Add((Config.RoleIconConfig.StrataLevel, () => { DrawHelper.DrawInWindow(_config.ID + "_enemyRoleJobIcon", iconPos, Config.RoleIconConfig.Size, false, (drawList) => { DrawHelper.DrawIcon(iconId, iconPos, Config.RoleIconConfig.Size, false, alpha, drawList); }); } )); } } return drawActions; } protected override unsafe PluginConfigColor GetFillColor(Character character, uint currentHp, uint maxHp) { NameplateEnemyBarConfig config = (NameplateEnemyBarConfig)BarConfig; bool targetingPlayer = character.TargetObjectId == Plugin.ObjectTable.LocalPlayer?.GameObjectId; if (targetingPlayer && config.UseCustomColorWhenBeingTargeted) { return config.CustomColorWhenBeingTargeted; } if (config.UseStateColor) { StructsCharacter* chara = (StructsCharacter*)character.Address; byte nameplateColorId = chara->GetNamePlateColorType(); switch (nameplateColorId) { case 7: return (character.StatusFlags & StatusFlags.Hostile) != 0 ? config.UnengagedHostileColor : config.UnengagedColor; case 9: return config.EngagedColor; case 10: return config.ClaimedColor; case 11: return config.UnclaimedColor; default: break; } } return base.GetFillColor(character, currentHp, maxHp); } } #region utils public struct NameplateAnchor { public Vector2 Position; public Vector2 Size; internal NameplateAnchor(Vector2 position, Vector2 size) { Position = position; Size = size; } } public struct NameplateExtrasAnchors { public NameplateAnchor? BarAnchor; public NameplateAnchor? NameLabelAnchor; public NameplateAnchor? TitleLabelAnchor; public NameplateAnchor? HighestLabelAnchor; public NameplateAnchor? LowestLabelAnchor; private NameplateAnchor? DefaultLabelAnchor; internal NameplateExtrasAnchors(NameplateAnchor? barAnchor, NameplateAnchor? nameLabelAnchor, NameplateAnchor? titleLabelAnchor) { BarAnchor = barAnchor; NameLabelAnchor = nameLabelAnchor; TitleLabelAnchor = titleLabelAnchor; DefaultLabelAnchor = nameLabelAnchor; float nameY = -1; if (nameLabelAnchor.HasValue) { nameY = nameLabelAnchor.Value.Position.Y; } float titleY = -1; if (titleLabelAnchor.HasValue) { titleY = titleLabelAnchor.Value.Position.Y; } if (nameY == -1) { DefaultLabelAnchor = titleLabelAnchor; } else if (nameY < titleY) { HighestLabelAnchor = nameLabelAnchor; LowestLabelAnchor = titleLabelAnchor; } else if (nameY > titleY) { HighestLabelAnchor = titleLabelAnchor; LowestLabelAnchor = nameLabelAnchor; } } internal NameplateAnchor? GetAnchor(NameplateLabelAnchor label, bool prioritizeHealthBar) { if (prioritizeHealthBar && BarAnchor != null) { return BarAnchor; } NameplateAnchor? labelAnchor = null; switch (label) { case NameplateLabelAnchor.Name: labelAnchor = NameLabelAnchor; break; case NameplateLabelAnchor.Title: labelAnchor = TitleLabelAnchor; break; case NameplateLabelAnchor.Highest: labelAnchor = HighestLabelAnchor; break; case NameplateLabelAnchor.Lowest: labelAnchor = LowestLabelAnchor; break; } return labelAnchor ?? DefaultLabelAnchor; } #endregion } }