using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.UI; using ImGuiNET; using System; using System.Collections.Generic; using System.Numerics; using Dalamud.Interface.Utility; using Dalamud.Plugin.Services; namespace ZodiacFinder { public class Plugin : IDalamudPlugin { private readonly DalamudPluginInterface _pluginInterface; private readonly IClientState _clientState; private readonly IObjectTable _objectTable; private readonly IDataManager _dataManager; private readonly IGameGui _gameGui; private readonly IDictionary _books = new Dictionary(); private readonly ISet _atmaWeapons = new HashSet { 7824, // Curtana Atma 7825, // Sphairai Atma 7826, // Bravura Atma 7827, // Gae Bolg Atma 7828, // Artemis Bow Atma 7829, // Thyrus Atma 7830, // Stardust Rod Atma 7831, // Veil of Wiyu Atma 7832, // Omnilex Atma 7833, // Holy Shield Atma 9251, // Yoshimitsu Atma }; public Plugin( DalamudPluginInterface pi, IChatGui chat, IClientState clientState, IObjectTable objectTable, IDataManager dataManager, IGameGui gameGui) { this._pluginInterface = pi; this._clientState = clientState; this._objectTable = objectTable; this._dataManager = dataManager; this._gameGui = gameGui; this._pluginInterface.UiBuilder.Draw += this.Draw; this.PopulateBooks(); } #region IDisposable Support protected virtual void Dispose(bool disposing) { if (!disposing) return; this._pluginInterface.UiBuilder.Draw -= this.Draw; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion private unsafe void Draw() { if (!_clientState.IsLoggedIn || _clientState.IsPvP || _objectTable == null || !HasAtmaWeaponEquipped()) return; var bookId = GetCurrentBook(); if (bookId == 0) return; var relicNote = RelicNote.Instance(); if (relicNote == null) return; var book = _books[bookId]; for (int index = 0; index < _objectTable.Length; ++index) { GameObject obj = _objectTable[index]; if (!(obj is BattleNpc npc) || npc.CurrentHp == 0) continue; var indexInBook = book.Enemies.IndexOf(npc.NameId); if (indexInBook == -1) continue; if (relicNote->GetMonsterProgress(indexInBook) >= 3) continue; if (!_gameGui.WorldToScreen(new Vector3(obj.Position.X, obj.Position.Y, obj.Position.Z), out var pos)) continue; ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0)); ImGuiHelpers.ForceNextWindowMainViewport(); ImGuiHelpers.SetNextWindowPosRelativeMainViewport(new Vector2(0, 0)); ImGui.Begin($"zodiac###{index}", ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoSavedSettings); ImGui.SetWindowSize(ImGui.GetIO().DisplaySize); ImGui.GetWindowDrawList().AddCircleFilled(new Vector2(pos.X, pos.Y), 5f, ImGui.GetColorU32(0xff0000ff), 100); //ImGui.GetWindowDrawList().AddText(new Vector2(pos.X, pos.Y), ImGui.GetColorU32(0xffffffff), $"{npc.NameId} - {obj.Name.TextValue}"); ImGui.End(); ImGui.PopStyleVar(); } } private bool HasAtmaWeaponEquipped() { return _atmaWeapons.Contains(GetEquippedItem(0)) || _atmaWeapons.Contains(GetEquippedItem(1)); } private unsafe uint GetCurrentBook() { var im = InventoryManager.Instance(); if (im == null) return 0; var keyItems = im->GetInventoryContainer(InventoryType.KeyItems); for (int i = 0; i < keyItems->Size; ++i) { var slot = keyItems->GetInventorySlot(i); if (slot == null) continue; uint itemId = slot->ItemID; if (_books.ContainsKey(itemId)) return itemId; } return 0; } private unsafe uint GetEquippedItem(int index) { var im = InventoryManager.Instance(); if (im == null) return 0; var equipped = im->GetInventoryContainer(InventoryType.EquippedItems); if (equipped == null) return 0; var slot = equipped->GetInventorySlot(index); if (slot == null) return 0; return slot->ItemID; } private void PopulateBooks() { var relicNoteSheet = this._dataManager.GetExcelSheet()!; foreach (var row in relicNoteSheet) { if (row.EventItem == null || row.EventItem.Row == 0) continue; var book = new Book(); for (int i = 0; i < row.MonsterNoteTargetCommon.Length; i++) { book.Enemies.Add(row.MonsterNoteTargetCommon[i].MonsterNoteTargetCommon.Value!.BNpcName.Row); } //chat.Print($"{row.EventItem.Row} - {book}"); _books.Add(row.EventItem.Row, book); } } internal sealed class Book { public IList Enemies = new List(); public override string ToString() { return string.Join(",", Enemies); } } } }