Hide traps/coffer locations if a pomander is used and they're not currently shown

This commit is contained in:
Liza 2022-10-26 23:38:29 +02:00
parent 4bd37bdefd
commit 16a2305892
5 changed files with 171 additions and 12 deletions

View File

@ -1,7 +1,4 @@
using Dalamud.Configuration; using Dalamud.Configuration;
using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Client.Game.Event;
using FFXIVClientStructs.FFXIV.Client.Graphics;
using System.Numerics; using System.Numerics;
namespace Pal.Client namespace Pal.Client
@ -18,8 +15,12 @@ namespace Pal.Client
public bool ShowTraps { get; set; } = true; public bool ShowTraps { get; set; } = true;
public Vector4 TrapColor { get; set; } = new Vector4(1, 0, 0, 0.4f); public Vector4 TrapColor { get; set; } = new Vector4(1, 0, 0, 0.4f);
public bool OnlyVisibleTrapsAfterPomander { get; set; } = true;
public bool ShowHoard { get; set; } = true; public bool ShowHoard { get; set; } = true;
public Vector4 HoardColor { get; set; } = new Vector4(0, 1, 1, 0.4f); public Vector4 HoardColor { get; set; } = new Vector4(0, 1, 1, 0.4f);
public bool OnlyVisibleHoardAfterPomander { get; set; } = true;
public bool ShowSilverCoffers { get; set; } = false; public bool ShowSilverCoffers { get; set; } = false;
public Vector4 SilverCofferColor { get; set; } = new Vector4(1, 1, 1, 0.4f); public Vector4 SilverCofferColor { get; set; } = new Vector4(1, 1, 1, 0.4f);
public bool FillSilverCoffers { get; set; } = true; public bool FillSilverCoffers { get; set; } = true;

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<LangVersion>9.0</LangVersion> <LangVersion>9.0</LangVersion>
<Version>1.5.0.0</Version> <Version>1.6.0.0</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View File

@ -2,13 +2,18 @@
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Dalamud.Plugin; using Dalamud.Plugin;
using ECommons; using ECommons;
using ECommons.Schedulers; using ECommons.Schedulers;
using ECommons.SplatoonAPI; using ECommons.SplatoonAPI;
using Grpc.Core; using Grpc.Core;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using Pal.Client.Windows; using Pal.Client.Windows;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -18,6 +23,7 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.Json; using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Pal.Client namespace Pal.Client
@ -25,6 +31,7 @@ namespace Pal.Client
public class Plugin : IDalamudPlugin public class Plugin : IDalamudPlugin
{ {
private const long ON_TERRITORY_CHANGE = -2; private const long ON_TERRITORY_CHANGE = -2;
private const uint COLOR_INVISIBLE = 0;
private readonly ConcurrentQueue<(ushort territoryId, bool success, IList<Marker> markers)> _remoteDownloads = new(); private readonly ConcurrentQueue<(ushort territoryId, bool success, IList<Marker> markers)> _remoteDownloads = new();
private readonly static Dictionary<Marker.EType, MarkerConfig> _markerConfig = new Dictionary<Marker.EType, MarkerConfig> private readonly static Dictionary<Marker.EType, MarkerConfig> _markerConfig = new Dictionary<Marker.EType, MarkerConfig>
@ -34,11 +41,15 @@ namespace Pal.Client
{ Marker.EType.SilverCoffer, new MarkerConfig { Radius = 1f } }, { Marker.EType.SilverCoffer, new MarkerConfig { Radius = 1f } },
}; };
private bool _configUpdated = false; private bool _configUpdated = false;
private bool _pomandersUpdated = false;
private LocalizedChatMessages _localizedChatMessages = new();
internal ConcurrentDictionary<ushort, ConcurrentBag<Marker>> FloorMarkers { get; } = new(); internal ConcurrentDictionary<ushort, ConcurrentBag<Marker>> FloorMarkers { get; } = new();
internal ConcurrentBag<Marker> EphemeralMarkers { get; set; } = new(); internal ConcurrentBag<Marker> EphemeralMarkers { get; set; } = new();
internal ushort LastTerritory { get; private set; } internal ushort LastTerritory { get; private set; }
public SyncState TerritorySyncState { get; set; } public SyncState TerritorySyncState { get; set; }
public PomanderState PomanderOfSight { get; set; } = PomanderState.Inactive;
public PomanderState PomanderOfIntuition { get; set; } = PomanderState.Inactive;
public string DebugMessage { get; set; } public string DebugMessage { get; set; }
public string Name => "Palace Pal"; public string Name => "Palace Pal";
@ -75,10 +86,13 @@ namespace Pal.Client
pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi; pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi;
Service.Framework.Update += OnFrameworkUpdate; Service.Framework.Update += OnFrameworkUpdate;
Service.Configuration.Saved += OnConfigSaved; Service.Configuration.Saved += OnConfigSaved;
Service.Chat.ChatMessage += OnChatMessage;
Service.CommandManager.AddHandler("/pal", new CommandInfo(OnCommand) Service.CommandManager.AddHandler("/pal", new CommandInfo(OnCommand)
{ {
HelpMessage = "Open the configuration/debug window" HelpMessage = "Open the configuration/debug window"
}); });
ReloadLanguageStrings();
} }
public void OnOpenConfigUi() public void OnOpenConfigUi()
@ -123,6 +137,7 @@ namespace Pal.Client
Service.PluginInterface.UiBuilder.OpenConfigUi -= OnOpenConfigUi; Service.PluginInterface.UiBuilder.OpenConfigUi -= OnOpenConfigUi;
Service.Framework.Update -= OnFrameworkUpdate; Service.Framework.Update -= OnFrameworkUpdate;
Service.Configuration.Saved -= OnConfigSaved; Service.Configuration.Saved -= OnConfigSaved;
Service.Chat.ChatMessage -= OnChatMessage;
Service.WindowSystem.RemoveAllWindows(); Service.WindowSystem.RemoveAllWindows();
@ -142,6 +157,43 @@ namespace Pal.Client
_configUpdated = true; _configUpdated = true;
} }
private void OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString seMessage, ref bool isHandled)
{
if (type != (XivChatType)2105)
return;
string message = seMessage.ToString();
if (_localizedChatMessages.FloorChanged.IsMatch(message))
{
PomanderOfSight = PomanderState.Inactive;
if (PomanderOfIntuition == PomanderState.FoundOnCurrentFloor)
PomanderOfIntuition = PomanderState.Inactive;
}
else if (message.EndsWith(_localizedChatMessages.MapRevealed))
{
PomanderOfSight = PomanderState.Active;
}
else if (message.EndsWith(_localizedChatMessages.AllTrapsRemoved))
{
PomanderOfSight = PomanderState.PomanderOfSafetyUsed;
}
else if (message.EndsWith(_localizedChatMessages.HoardNotOnCurrentFloor) || message.EndsWith(_localizedChatMessages.HoardOnCurrentFloor))
{
// There is no functional difference between these - if you don't open the marked coffer,
// going to higher floors will keep the pomander active.
PomanderOfIntuition = PomanderState.Active;
}
else if (message.EndsWith(_localizedChatMessages.HoardCofferOpened))
{
PomanderOfIntuition = PomanderState.FoundOnCurrentFloor;
}
else
return;
_pomandersUpdated = true;
}
private void OnFrameworkUpdate(Framework framework) private void OnFrameworkUpdate(Framework framework)
{ {
try try
@ -177,6 +229,8 @@ namespace Pal.Client
if (IsInPotdOrHoh()) if (IsInPotdOrHoh())
FloorMarkers[LastTerritory] = new ConcurrentBag<Marker>(LoadSavedMarkers()); FloorMarkers[LastTerritory] = new ConcurrentBag<Marker>(LoadSavedMarkers());
EphemeralMarkers.Clear(); EphemeralMarkers.Clear();
PomanderOfSight = PomanderState.Inactive;
PomanderOfIntuition = PomanderState.Inactive;
recreateLayout = true; recreateLayout = true;
DebugMessage = null; DebugMessage = null;
} }
@ -212,6 +266,7 @@ namespace Pal.Client
private void HandlePersistentMarkers(ConcurrentBag<Marker> currentFloorMarkers, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout) private void HandlePersistentMarkers(ConcurrentBag<Marker> currentFloorMarkers, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout)
{ {
var config = Service.Configuration;
foreach (var visibleMarker in visibleMarkers) foreach (var visibleMarker in visibleMarkers)
{ {
@ -231,6 +286,35 @@ namespace Pal.Client
saveMarkers = true; saveMarkers = true;
} }
if (_pomandersUpdated)
{
if (currentFloorMarkers.Count > 0 && (config.OnlyVisibleTrapsAfterPomander || config.OnlyVisibleHoardAfterPomander))
{
try
{
foreach (var marker in currentFloorMarkers)
{
uint desiredColor = DetermineColor(marker, visibleMarkers);
if (marker.SplatoonElement == null || !marker.SplatoonElement.IsValid())
{
recreateLayout = true;
break;
}
if (marker.SplatoonElement.color != desiredColor)
marker.SplatoonElement.color = desiredColor;
}
}
catch (Exception e)
{
DebugMessage = $"{DateTime.Now}\n{e}";
recreateLayout = true;
}
}
_pomandersUpdated = false;
}
if (saveMarkers) if (saveMarkers)
{ {
SaveMarkers(); SaveMarkers();
@ -246,8 +330,6 @@ namespace Pal.Client
{ {
Splatoon.RemoveDynamicElements("PalacePal.TrapHoard"); Splatoon.RemoveDynamicElements("PalacePal.TrapHoard");
var config = Service.Configuration;
List<Element> elements = new List<Element>(); List<Element> elements = new List<Element>();
foreach (var marker in currentFloorMarkers) foreach (var marker in currentFloorMarkers)
{ {
@ -255,13 +337,13 @@ namespace Pal.Client
{ {
if (marker.Type == Marker.EType.Trap && config.ShowTraps) if (marker.Type == Marker.EType.Trap && config.ShowTraps)
{ {
var element = CreateSplatoonElement(marker.Type, marker.Position, config.TrapColor); var element = CreateSplatoonElement(marker.Type, marker.Position, DetermineColor(marker, visibleMarkers));
marker.SplatoonElement = element; marker.SplatoonElement = element;
elements.Add(element); elements.Add(element);
} }
else if (marker.Type == Marker.EType.Hoard && config.ShowHoard) else if (marker.Type == Marker.EType.Hoard && config.ShowHoard)
{ {
var element = CreateSplatoonElement(marker.Type, marker.Position, config.HoardColor); var element = CreateSplatoonElement(marker.Type, marker.Position, DetermineColor(marker, visibleMarkers));
marker.SplatoonElement = element; marker.SplatoonElement = element;
elements.Add(element); elements.Add(element);
} }
@ -286,6 +368,24 @@ namespace Pal.Client
} }
} }
private uint DetermineColor(Marker marker, IList<Marker> visibleMarkers)
{
if (marker.Type == Marker.EType.Trap)
{
if (PomanderOfSight == PomanderState.Inactive || !Service.Configuration.OnlyVisibleTrapsAfterPomander || visibleMarkers.Any(x => x == marker))
return ImGui.ColorConvertFloat4ToU32(Service.Configuration.TrapColor);
else
return COLOR_INVISIBLE;
}
else
{
if (PomanderOfIntuition == PomanderState.Inactive || !Service.Configuration.OnlyVisibleHoardAfterPomander || visibleMarkers.Any(x => x == marker))
return ImGui.ColorConvertFloat4ToU32(Service.Configuration.HoardColor);
else
return COLOR_INVISIBLE;
}
}
private void HandleEphemeralMarkers(IList<Marker> visibleMarkers, bool recreateLayout) private void HandleEphemeralMarkers(IList<Marker> visibleMarkers, bool recreateLayout)
{ {
recreateLayout |= EphemeralMarkers.Any(existingMarker => !visibleMarkers.Any(x => x == existingMarker)); recreateLayout |= EphemeralMarkers.Any(existingMarker => !visibleMarkers.Any(x => x == existingMarker));
@ -457,7 +557,10 @@ namespace Pal.Client
internal bool IsInPotdOrHoh() => Service.ClientState.IsLoggedIn && Service.Condition[ConditionFlag.InDeepDungeon]; internal bool IsInPotdOrHoh() => Service.ClientState.IsLoggedIn && Service.Condition[ConditionFlag.InDeepDungeon];
internal static Element CreateSplatoonElement(Marker.EType type, Vector3 pos, Vector4 color, bool fill = false) internal static Element CreateSplatoonElement(Marker.EType type, Vector3 pos, Vector4 color, bool fill = false)
=> CreateSplatoonElement(type, pos, ImGui.ColorConvertFloat4ToU32(color), fill);
internal static Element CreateSplatoonElement(Marker.EType type, Vector3 pos, uint color, bool fill = false)
{ {
return new Element(ElementType.CircleAtFixedCoordinates) return new Element(ElementType.CircleAtFixedCoordinates)
{ {
@ -470,11 +573,29 @@ namespace Pal.Client
Filled = fill, Filled = fill,
radius = _markerConfig[type].Radius, radius = _markerConfig[type].Radius,
FillStep = 1, FillStep = 1,
color = ImGui.ColorConvertFloat4ToU32(color), color = color,
thicc = 2, thicc = 2,
}; };
} }
private void ReloadLanguageStrings()
{
_localizedChatMessages = new LocalizedChatMessages
{
MapRevealed = GetLocalizedString(7256),
AllTrapsRemoved = GetLocalizedString(7255),
HoardOnCurrentFloor = GetLocalizedString(7272),
HoardNotOnCurrentFloor = GetLocalizedString(7273),
HoardCofferOpened = GetLocalizedString(7274),
FloorChanged = new Regex("^" + GetLocalizedString(7270).Replace("\u0002 \u0003\ufffd\u0002\u0003", @"(\d+)") + "$"),
};
}
private string GetLocalizedString(uint id)
{
return Service.DataManager.GetExcelSheet<LogMessage>().GetRow(id).Text?.ToString() ?? "Unknown";
}
public enum SyncState public enum SyncState
{ {
NotAttempted, NotAttempted,
@ -483,10 +604,28 @@ namespace Pal.Client
Failed, Failed,
} }
public enum PomanderState
{
Inactive,
Active,
FoundOnCurrentFloor,
PomanderOfSafetyUsed,
}
private class MarkerConfig private class MarkerConfig
{ {
public float OffsetY { get; set; } = 0; public float OffsetY { get; set; } = 0;
public float Radius { get; set; } = 0.25f; public float Radius { get; set; } = 0.25f;
} }
private class LocalizedChatMessages
{
public string MapRevealed { get; set; } = "???"; //"The map for this floor has been revealed!";
public string AllTrapsRemoved { get; set; } = "???"; // "All the traps on this floor have disappeared!";
public string HoardOnCurrentFloor { get; set; } = "???"; // "You sense the Accursed Hoard calling you...";
public string HoardNotOnCurrentFloor { get; set; } = "???"; // "You do not sense the call of the Accursed Hoard on this floor...";
public string HoardCofferOpened { get; set; } = "???"; // "You discover a piece of the Accursed Hoard!";
public Regex FloorChanged { get; set; } = new Regex(@"This isn't a game message, but will be replaced"); // new Regex(@"^Floor (\d+)$");
}
} }
} }

View File

@ -1,4 +1,5 @@
using Dalamud.Game; using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState; using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects;
@ -19,6 +20,7 @@ namespace Pal.Client
[PluginService] public static Framework Framework { get; set; } = null!; [PluginService] public static Framework Framework { get; set; } = null!;
[PluginService] public static Condition Condition { get; set; } = null!; [PluginService] public static Condition Condition { get; set; } = null!;
[PluginService] public static CommandManager CommandManager { get; set; } = null!; [PluginService] public static CommandManager CommandManager { get; set; } = null!;
[PluginService] public static DataManager DataManager { get; set; } = null!;
public static Plugin Plugin { get; set; } = null!; public static Plugin Plugin { get; set; } = null!;
public static WindowSystem WindowSystem { get; set; } = new(typeof(Service).AssemblyQualifiedName); public static WindowSystem WindowSystem { get; set; } = new(typeof(Service).AssemblyQualifiedName);

View File

@ -15,16 +15,20 @@ namespace Pal.Client.Windows
private int _mode; private int _mode;
private bool _showTraps; private bool _showTraps;
private Vector4 _trapColor; private Vector4 _trapColor;
private bool _onlyVisibleTrapsAfterPomander;
private bool _showHoard; private bool _showHoard;
private Vector4 _hoardColor; private Vector4 _hoardColor;
private bool _onlyVisibleHoardAfterPomander;
private bool _showSilverCoffers; private bool _showSilverCoffers;
private Vector4 _silverCofferColor; private Vector4 _silverCofferColor;
private bool _fillSilverCoffers; private bool _fillSilverCoffers;
private string _connectionText; private string _connectionText;
public ConfigWindow() : base("Palace Pal - Configuration###PalPalaceConfig") public ConfigWindow() : base("Palace Pal###PalPalaceConfig")
{ {
var version = typeof(Plugin).Assembly.GetName().Version.ToString(2);
WindowName = $"Palace Pal v{version}###PalPalaceConfig";
Size = new Vector2(500, 400); Size = new Vector2(500, 400);
SizeCondition = ImGuiCond.FirstUseEver; SizeCondition = ImGuiCond.FirstUseEver;
Position = new Vector2(300, 300); Position = new Vector2(300, 300);
@ -37,8 +41,10 @@ namespace Pal.Client.Windows
_mode = (int)config.Mode; _mode = (int)config.Mode;
_showTraps = config.ShowTraps; _showTraps = config.ShowTraps;
_trapColor = config.TrapColor; _trapColor = config.TrapColor;
_onlyVisibleTrapsAfterPomander = config.OnlyVisibleTrapsAfterPomander;
_showHoard = config.ShowHoard; _showHoard = config.ShowHoard;
_hoardColor = config.HoardColor; _hoardColor = config.HoardColor;
_onlyVisibleHoardAfterPomander = config.OnlyVisibleHoardAfterPomander;
_showSilverCoffers = config.ShowSilverCoffers; _showSilverCoffers = config.ShowSilverCoffers;
_silverCofferColor = config.SilverCofferColor; _silverCofferColor = config.SilverCofferColor;
_fillSilverCoffers = config.FillSilverCoffers; _fillSilverCoffers = config.FillSilverCoffers;
@ -58,6 +64,9 @@ namespace Pal.Client.Windows
ImGui.BeginDisabled(!_showTraps); ImGui.BeginDisabled(!_showTraps);
ImGui.Spacing(); ImGui.Spacing();
ImGui.ColorEdit4("Trap color", ref _trapColor, ImGuiColorEditFlags.NoInputs); ImGui.ColorEdit4("Trap color", ref _trapColor, ImGuiColorEditFlags.NoInputs);
ImGui.Checkbox("Hide traps not on current floor", ref _onlyVisibleTrapsAfterPomander);
ImGui.SameLine();
ImGuiComponents.HelpMarker("When using a Pomander of sight, only the actual trap locations are visible, all other traps are hidden.");
ImGui.EndDisabled(); ImGui.EndDisabled();
ImGui.Unindent(); ImGui.Unindent();
@ -68,6 +77,9 @@ namespace Pal.Client.Windows
ImGui.BeginDisabled(!_showHoard); ImGui.BeginDisabled(!_showHoard);
ImGui.Spacing(); ImGui.Spacing();
ImGui.ColorEdit4("Hoard Coffer color", ref _hoardColor, ImGuiColorEditFlags.NoInputs); ImGui.ColorEdit4("Hoard Coffer color", ref _hoardColor, ImGuiColorEditFlags.NoInputs);
ImGui.Checkbox("Hide hoard coffers not on current floor", ref _onlyVisibleHoardAfterPomander);
ImGui.SameLine();
ImGuiComponents.HelpMarker("When using a Pomander of intuition, only the actual hoard coffer location is visible, all other (potential) hoard coffers are hidden.");
ImGui.EndDisabled(); ImGui.EndDisabled();
ImGui.Unindent(); ImGui.Unindent();
@ -154,6 +166,9 @@ namespace Pal.Client.Windows
int silverCoffers = plugin.EphemeralMarkers.Count(x => x != null && x.Type == Marker.EType.SilverCoffer); int silverCoffers = plugin.EphemeralMarkers.Count(x => x != null && x.Type == Marker.EType.SilverCoffer);
ImGui.Text($"{silverCoffers} silver coffer{(silverCoffers == 1 ? "" : "s")} visible on current floor"); ImGui.Text($"{silverCoffers} silver coffer{(silverCoffers == 1 ? "" : "s")} visible on current floor");
} }
ImGui.Text($"Pomander of Sight: {plugin.PomanderOfSight}");
ImGui.Text($"Pomander of Intuition: {plugin.PomanderOfIntuition}");
} }
else else
ImGui.Text("Could not query current trap/coffer count."); ImGui.Text("Could not query current trap/coffer count.");
@ -199,8 +214,10 @@ namespace Pal.Client.Windows
config.Mode = (Configuration.EMode)_mode; config.Mode = (Configuration.EMode)_mode;
config.ShowTraps = _showTraps; config.ShowTraps = _showTraps;
config.TrapColor = _trapColor; config.TrapColor = _trapColor;
config.OnlyVisibleTrapsAfterPomander = _onlyVisibleTrapsAfterPomander;
config.ShowHoard = _showHoard; config.ShowHoard = _showHoard;
config.HoardColor = _hoardColor; config.HoardColor = _hoardColor;
config.OnlyVisibleHoardAfterPomander = _onlyVisibleHoardAfterPomander;
config.ShowSilverCoffers = _showSilverCoffers; config.ShowSilverCoffers = _showSilverCoffers;
config.SilverCofferColor = _silverCofferColor; config.SilverCofferColor = _silverCofferColor;
config.FillSilverCoffers = _fillSilverCoffers; config.FillSilverCoffers = _fillSilverCoffers;