diff --git a/Pal.Client/Configuration.cs b/Pal.Client/Configuration.cs
index c90dc76..d3d2477 100644
--- a/Pal.Client/Configuration.cs
+++ b/Pal.Client/Configuration.cs
@@ -1,7 +1,4 @@
using Dalamud.Configuration;
-using Dalamud.Plugin;
-using FFXIVClientStructs.FFXIV.Client.Game.Event;
-using FFXIVClientStructs.FFXIV.Client.Graphics;
using System.Numerics;
namespace Pal.Client
@@ -18,8 +15,12 @@ namespace Pal.Client
public bool ShowTraps { get; set; } = true;
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 Vector4 HoardColor { get; set; } = new Vector4(0, 1, 1, 0.4f);
+ public bool OnlyVisibleHoardAfterPomander { get; set; } = true;
+
public bool ShowSilverCoffers { get; set; } = false;
public Vector4 SilverCofferColor { get; set; } = new Vector4(1, 1, 1, 0.4f);
public bool FillSilverCoffers { get; set; } = true;
diff --git a/Pal.Client/Pal.Client.csproj b/Pal.Client/Pal.Client.csproj
index 70f3f93..63070a4 100644
--- a/Pal.Client/Pal.Client.csproj
+++ b/Pal.Client/Pal.Client.csproj
@@ -3,7 +3,7 @@
net6.0-windows
9.0
- 1.5.0.0
+ 1.6.0.0
diff --git a/Pal.Client/Plugin.cs b/Pal.Client/Plugin.cs
index ffdc715..e9687d7 100644
--- a/Pal.Client/Plugin.cs
+++ b/Pal.Client/Plugin.cs
@@ -2,13 +2,18 @@
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Command;
+using Dalamud.Game.Text;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Interface.Colors;
using Dalamud.Interface.Windowing;
+using Dalamud.Logging;
using Dalamud.Plugin;
using ECommons;
using ECommons.Schedulers;
using ECommons.SplatoonAPI;
using Grpc.Core;
using ImGuiNET;
+using Lumina.Excel.GeneratedSheets;
using Pal.Client.Windows;
using System;
using System.Collections.Concurrent;
@@ -18,6 +23,7 @@ using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text.Json;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Pal.Client
@@ -25,6 +31,7 @@ namespace Pal.Client
public class Plugin : IDalamudPlugin
{
private const long ON_TERRITORY_CHANGE = -2;
+ private const uint COLOR_INVISIBLE = 0;
private readonly ConcurrentQueue<(ushort territoryId, bool success, IList markers)> _remoteDownloads = new();
private readonly static Dictionary _markerConfig = new Dictionary
@@ -34,11 +41,15 @@ namespace Pal.Client
{ Marker.EType.SilverCoffer, new MarkerConfig { Radius = 1f } },
};
private bool _configUpdated = false;
+ private bool _pomandersUpdated = false;
+ private LocalizedChatMessages _localizedChatMessages = new();
internal ConcurrentDictionary> FloorMarkers { get; } = new();
internal ConcurrentBag EphemeralMarkers { get; set; } = new();
internal ushort LastTerritory { get; private 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 Name => "Palace Pal";
@@ -75,10 +86,13 @@ namespace Pal.Client
pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi;
Service.Framework.Update += OnFrameworkUpdate;
Service.Configuration.Saved += OnConfigSaved;
+ Service.Chat.ChatMessage += OnChatMessage;
Service.CommandManager.AddHandler("/pal", new CommandInfo(OnCommand)
{
HelpMessage = "Open the configuration/debug window"
});
+
+ ReloadLanguageStrings();
}
public void OnOpenConfigUi()
@@ -123,6 +137,7 @@ namespace Pal.Client
Service.PluginInterface.UiBuilder.OpenConfigUi -= OnOpenConfigUi;
Service.Framework.Update -= OnFrameworkUpdate;
Service.Configuration.Saved -= OnConfigSaved;
+ Service.Chat.ChatMessage -= OnChatMessage;
Service.WindowSystem.RemoveAllWindows();
@@ -142,6 +157,43 @@ namespace Pal.Client
_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)
{
try
@@ -177,6 +229,8 @@ namespace Pal.Client
if (IsInPotdOrHoh())
FloorMarkers[LastTerritory] = new ConcurrentBag(LoadSavedMarkers());
EphemeralMarkers.Clear();
+ PomanderOfSight = PomanderState.Inactive;
+ PomanderOfIntuition = PomanderState.Inactive;
recreateLayout = true;
DebugMessage = null;
}
@@ -212,6 +266,7 @@ namespace Pal.Client
private void HandlePersistentMarkers(ConcurrentBag currentFloorMarkers, IList visibleMarkers, bool saveMarkers, bool recreateLayout)
{
+ var config = Service.Configuration;
foreach (var visibleMarker in visibleMarkers)
{
@@ -231,6 +286,35 @@ namespace Pal.Client
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)
{
SaveMarkers();
@@ -246,8 +330,6 @@ namespace Pal.Client
{
Splatoon.RemoveDynamicElements("PalacePal.TrapHoard");
- var config = Service.Configuration;
-
List elements = new List();
foreach (var marker in currentFloorMarkers)
{
@@ -255,13 +337,13 @@ namespace Pal.Client
{
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;
elements.Add(element);
}
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;
elements.Add(element);
}
@@ -286,6 +368,24 @@ namespace Pal.Client
}
}
+ private uint DetermineColor(Marker marker, IList 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 visibleMarkers, bool recreateLayout)
{
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 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)
{
@@ -470,11 +573,29 @@ namespace Pal.Client
Filled = fill,
radius = _markerConfig[type].Radius,
FillStep = 1,
- color = ImGui.ColorConvertFloat4ToU32(color),
+ color = color,
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().GetRow(id).Text?.ToString() ?? "Unknown";
+ }
+
public enum SyncState
{
NotAttempted,
@@ -483,10 +604,28 @@ namespace Pal.Client
Failed,
}
+ public enum PomanderState
+ {
+ Inactive,
+ Active,
+ FoundOnCurrentFloor,
+ PomanderOfSafetyUsed,
+ }
+
private class MarkerConfig
{
public float OffsetY { get; set; } = 0;
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+)$");
+ }
}
}
diff --git a/Pal.Client/Service.cs b/Pal.Client/Service.cs
index 4024e5e..1f375ab 100644
--- a/Pal.Client/Service.cs
+++ b/Pal.Client/Service.cs
@@ -1,4 +1,5 @@
-using Dalamud.Game;
+using Dalamud.Data;
+using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects;
@@ -19,6 +20,7 @@ namespace Pal.Client
[PluginService] public static Framework Framework { get; set; } = null!;
[PluginService] public static Condition Condition { 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 WindowSystem WindowSystem { get; set; } = new(typeof(Service).AssemblyQualifiedName);
diff --git a/Pal.Client/Windows/ConfigWindow.cs b/Pal.Client/Windows/ConfigWindow.cs
index 92c8969..7046f46 100644
--- a/Pal.Client/Windows/ConfigWindow.cs
+++ b/Pal.Client/Windows/ConfigWindow.cs
@@ -15,16 +15,20 @@ namespace Pal.Client.Windows
private int _mode;
private bool _showTraps;
private Vector4 _trapColor;
+ private bool _onlyVisibleTrapsAfterPomander;
private bool _showHoard;
private Vector4 _hoardColor;
+ private bool _onlyVisibleHoardAfterPomander;
private bool _showSilverCoffers;
private Vector4 _silverCofferColor;
private bool _fillSilverCoffers;
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);
SizeCondition = ImGuiCond.FirstUseEver;
Position = new Vector2(300, 300);
@@ -37,8 +41,10 @@ namespace Pal.Client.Windows
_mode = (int)config.Mode;
_showTraps = config.ShowTraps;
_trapColor = config.TrapColor;
+ _onlyVisibleTrapsAfterPomander = config.OnlyVisibleTrapsAfterPomander;
_showHoard = config.ShowHoard;
_hoardColor = config.HoardColor;
+ _onlyVisibleHoardAfterPomander = config.OnlyVisibleHoardAfterPomander;
_showSilverCoffers = config.ShowSilverCoffers;
_silverCofferColor = config.SilverCofferColor;
_fillSilverCoffers = config.FillSilverCoffers;
@@ -58,6 +64,9 @@ namespace Pal.Client.Windows
ImGui.BeginDisabled(!_showTraps);
ImGui.Spacing();
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.Unindent();
@@ -68,6 +77,9 @@ namespace Pal.Client.Windows
ImGui.BeginDisabled(!_showHoard);
ImGui.Spacing();
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.Unindent();
@@ -154,6 +166,9 @@ namespace Pal.Client.Windows
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($"Pomander of Sight: {plugin.PomanderOfSight}");
+ ImGui.Text($"Pomander of Intuition: {plugin.PomanderOfIntuition}");
}
else
ImGui.Text("Could not query current trap/coffer count.");
@@ -199,8 +214,10 @@ namespace Pal.Client.Windows
config.Mode = (Configuration.EMode)_mode;
config.ShowTraps = _showTraps;
config.TrapColor = _trapColor;
+ config.OnlyVisibleTrapsAfterPomander = _onlyVisibleTrapsAfterPomander;
config.ShowHoard = _showHoard;
config.HoardColor = _hoardColor;
+ config.OnlyVisibleHoardAfterPomander = _onlyVisibleHoardAfterPomander;
config.ShowSilverCoffers = _showSilverCoffers;
config.SilverCofferColor = _silverCofferColor;
config.FillSilverCoffers = _fillSilverCoffers;