using System; using System.Linq; using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.Types; using FFXIVClientStructs.FFXIV.Client.Game.Event; using FFXIVClientStructs.FFXIV.Client.Game.Group; using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using KamiLib.Extensions; using Lumina.Excel.Sheets; using Mappy.Classes; using Mappy.Extensions; using BattleNpcSubKind = Dalamud.Game.ClientState.Objects.Enums.BattleNpcSubKind; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Mappy.MapRenderer; public partial class MapRenderer { private unsafe void DrawMinimapGameObjects( Vector2 contentTopLeft, Func texToContent, Vector2 size, float scaleFactor, float offsetX, float offsetY) { if (!System.SystemConfig.MinimapShowPlayersAndNpcs) return; if (Service.ObjectTable is not { LocalPlayer: { } player }) return; foreach (var obj in Service.ObjectTable.Reverse()) { if (!obj.IsTargetable) continue; if (GroupManager.Instance()->MainGroup.IsEntityIdInParty(obj.EntityId)) continue; if (GroupManager.Instance()->MainGroup.IsEntityIdInAlliance(obj.EntityId)) continue; if (Vector3.Distance(obj.Position, player.Position) >= 150.0f) continue; var iconId = obj.ObjectKind switch { ObjectKind.Player when System.SystemConfig.ShowPlayers => System.SystemConfig.MinimapOtherPlayerIconId, ObjectKind.BattleNpc when IsBoss(obj) && obj.TargetObject is null => 60402u, ObjectKind.BattleNpc when IsBoss(obj) && obj.TargetObject is not null => 60401u, ObjectKind.BattleNpc when obj is { SubKind: (int)BattleNpcSubKind.Enemy, TargetObject: not null } => 60422u, ObjectKind.BattleNpc when obj is { SubKind: (int)BattleNpcSubKind.Enemy, TargetObject: null } => 60424u, ObjectKind.BattleNpc when obj.SubKind == (int)BattleNpcSubKind.Pet => 60961u, ObjectKind.Treasure => 60003u, ObjectKind.GatheringPoint => System.GatheringPointIconCache.GetValue(obj.BaseId), ObjectKind.EventObj when IsAetherCurrent(obj) => 60653u, _ => 0u }; if (iconId is 0) continue; if (System.IconConfig.IconSettingMap.TryGetValue(iconId, out var setting) && setting.Hide) continue; var pos = new Vector2(obj.Position.X, obj.Position.Z); var tx = 1024.0f + (pos.X - offsetX) * scaleFactor; var ty = 1024.0f + (pos.Y - offsetY) * scaleFactor; var contentPos = texToContent(tx, ty); if (!IsInMinimapBounds(contentPos, size, MinimapBoundsMargin)) continue; var tooltip = GetTooltipForGameObject(obj); DrawMinimapIcon(iconId, contentPos + contentTopLeft, sizeScale: 1.5f, tooltip); } } private unsafe void DrawGameObjects() { if (AgentMap.Instance()->SelectedMapId != AgentMap.Instance()->CurrentMapId) return; if (Service.ObjectTable is not { LocalPlayer: { } player }) return; if (System.SystemConfig.ShowRadar) { if ((Service.Condition.IsBoundByDuty() && System.SystemConfig.ShowRadarInDuties) || !Service.Condition.IsBoundByDuty()) { DrawRadar(player); } } foreach (var obj in Service.ObjectTable.Reverse()) { if (!obj.IsTargetable) continue; if (GroupManager.Instance()->MainGroup.IsEntityIdInParty(obj.EntityId)) continue; if (GroupManager.Instance()->MainGroup.IsEntityIdInAlliance(obj.EntityId)) continue; if (Vector3.Distance(obj.Position, player.Position) >= 150.0f) continue; DrawHelpers.DrawMapMarker(new MarkerInfo { Position = (obj.GetMapPosition() - DrawHelpers.GetMapOffsetVector() + DrawHelpers.GetMapCenterOffsetVector()) * Scale, Offset = DrawPosition, Scale = Scale, IconId = obj.ObjectKind switch { ObjectKind.Player when GroupManager.Instance()->MainGroup.MemberCount is 0 && System.SystemConfig.ShowPlayers => 60421, ObjectKind.Player when System.SystemConfig.ShowPlayers => 60444, ObjectKind.BattleNpc when IsBoss(obj) && obj.TargetObject is null => 60402, ObjectKind.BattleNpc when IsBoss(obj) && obj.TargetObject is not null => 60401, ObjectKind.BattleNpc when obj is { SubKind: (int)BattleNpcSubKind.Enemy, TargetObject: not null } => 60422, ObjectKind.BattleNpc when obj is { SubKind: (int)BattleNpcSubKind.Enemy, TargetObject: null } => 60424, ObjectKind.BattleNpc when obj.SubKind == (int)BattleNpcSubKind.Pet => 60961, ObjectKind.Treasure => 60003, ObjectKind.GatheringPoint => System.GatheringPointIconCache.GetValue(obj.BaseId), ObjectKind.EventObj when IsAetherCurrent(obj) => 60653, _ => 0 }, PrimaryText = () => GetTooltipForGameObject(obj), }); } } private void DrawRadar(IPlayerCharacter gameObjectCenter) { var position = ImGui.GetWindowPos() + DrawPosition + (gameObjectCenter.GetMapPosition() - DrawHelpers.GetMapOffsetVector() + DrawHelpers.GetMapCenterOffsetVector()) * Scale; ImGui.GetWindowDrawList().AddCircleFilled(position, 150.0f * Scale, ImGui.GetColorU32(System.SystemConfig.RadarColor)); ImGui.GetWindowDrawList().AddCircle(position, 150.0f * Scale, ImGui.GetColorU32(System.SystemConfig.RadarOutlineColor)); } private string GetTooltipForGameObject(IGameObject obj) { return obj switch { IBattleNpc { Level: > 0 } battleNpc => $"Lv. {battleNpc.Level} {battleNpc.Name}", IPlayerCharacter { Level: > 0 } playerCharacter => $"Lv. {playerCharacter.Level} {playerCharacter.Name}", _ => obj.ObjectKind switch { ObjectKind.GatheringPoint => System.GatheringPointNameCache.GetValue((obj.BaseId, obj.Name.ToString())) ?? string.Empty, ObjectKind.Treasure => obj.Name.ToString(), ObjectKind.EventObj when IsAetherCurrent(obj) => obj.Name.ToString(), _ => string.Empty }, }; } private unsafe bool IsAetherCurrent(IGameObject gameObject) { if (gameObject.ObjectKind is not ObjectKind.EventObj) return false; var csEventObject = (GameObject*)gameObject.Address; if (csEventObject is null) return false; if (csEventObject->EventHandler is null) return false; return csEventObject->EventHandler->Info.EventId.ContentId == EventHandlerContent.AetherCurrent; } private bool IsBoss(IGameObject chara) => Service.DataManager.GetExcelSheet().GetRow(chara.BaseId).Rank is 2 or 6; }