2022-10-23 02:38:58 +00:00
|
|
|
|
using Dalamud.Game;
|
|
|
|
|
using Dalamud.Game.ClientState.Conditions;
|
|
|
|
|
using Dalamud.Game.ClientState.Objects.Types;
|
2022-10-25 17:28:11 +00:00
|
|
|
|
using Dalamud.Game.Command;
|
2022-11-30 21:15:26 +00:00
|
|
|
|
using Dalamud.Game.Gui;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
using Dalamud.Game.Text;
|
|
|
|
|
using Dalamud.Game.Text.SeStringHandling;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
using Dalamud.Interface.Windowing;
|
2022-11-30 20:17:47 +00:00
|
|
|
|
using Dalamud.Logging;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
using Dalamud.Plugin;
|
2022-10-26 18:43:24 +00:00
|
|
|
|
using Grpc.Core;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
using ImGuiNET;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
using Lumina.Excel.GeneratedSheets;
|
2023-02-08 15:06:43 +00:00
|
|
|
|
using Pal.Client.Rendering;
|
2022-12-22 00:01:09 +00:00
|
|
|
|
using Pal.Client.Scheduled;
|
2022-10-26 18:43:24 +00:00
|
|
|
|
using Pal.Client.Windows;
|
2022-11-30 10:37:34 +00:00
|
|
|
|
using Pal.Common;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
using System.Collections.Generic;
|
2023-02-10 19:48:14 +00:00
|
|
|
|
using System.Globalization;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Numerics;
|
|
|
|
|
using System.Runtime.InteropServices;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
using System.Text.RegularExpressions;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2023-02-10 19:48:14 +00:00
|
|
|
|
using Pal.Client.Extensions;
|
|
|
|
|
using Pal.Client.Properties;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
|
|
|
|
namespace Pal.Client
|
|
|
|
|
{
|
|
|
|
|
public class Plugin : IDalamudPlugin
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
internal const uint ColorInvisible = 0;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-26 21:38:29 +00:00
|
|
|
|
private LocalizedChatMessages _localizedChatMessages = new();
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-29 22:21:17 +00:00
|
|
|
|
internal ConcurrentDictionary<ushort, LocalState> FloorMarkers { get; } = new();
|
2022-10-25 21:31:35 +00:00
|
|
|
|
internal ConcurrentBag<Marker> EphemeralMarkers { get; set; } = new();
|
2022-12-22 00:01:09 +00:00
|
|
|
|
internal ushort LastTerritory { get; set; }
|
2022-10-23 02:38:58 +00:00
|
|
|
|
public SyncState TerritorySyncState { get; set; }
|
2022-10-26 21:38:29 +00:00
|
|
|
|
public PomanderState PomanderOfSight { get; set; } = PomanderState.Inactive;
|
|
|
|
|
public PomanderState PomanderOfIntuition { get; set; } = PomanderState.Inactive;
|
2022-10-30 10:02:49 +00:00
|
|
|
|
public string? DebugMessage { get; set; }
|
2022-12-22 00:01:09 +00:00
|
|
|
|
internal Queue<IQueueOnFrameworkThread> EarlyEventQueue { get; } = new();
|
|
|
|
|
internal Queue<IQueueOnFrameworkThread> LateEventQueue { get; } = new();
|
2023-02-05 03:21:24 +00:00
|
|
|
|
internal ConcurrentQueue<nint> NextUpdateObjects { get; } = new();
|
2023-02-08 15:06:43 +00:00
|
|
|
|
internal IRenderer Renderer { get; private set; } = null!;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2023-02-10 19:48:14 +00:00
|
|
|
|
public string Name => Localization.Palace_Pal;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-11-30 21:15:26 +00:00
|
|
|
|
public Plugin(DalamudPluginInterface pluginInterface, ChatGui chat)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
LanguageChanged(pluginInterface.UiLanguage);
|
|
|
|
|
|
2022-11-30 21:15:26 +00:00
|
|
|
|
PluginLog.Information($"Install source: {pluginInterface.SourceRepository}");
|
|
|
|
|
|
|
|
|
|
#if RELEASE
|
|
|
|
|
// You're welcome to remove this code in your fork, as long as:
|
|
|
|
|
// - none of the links accessible within FFXIV open the original repo (e.g. in the plugin installer), and
|
|
|
|
|
// - you host your own server instance
|
2022-12-07 16:29:50 +00:00
|
|
|
|
if (!pluginInterface.IsDev
|
|
|
|
|
&& !pluginInterface.SourceRepository.StartsWith("https://raw.githubusercontent.com/carvelli/")
|
|
|
|
|
&& !pluginInterface.SourceRepository.StartsWith("https://github.com/carvelli/"))
|
2022-11-30 21:15:26 +00:00
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
chat.PalError(string.Format(Localization.Error_WrongRepository, "https://github.com/carvelli/Dalamud-Plugins"));
|
2022-11-30 21:15:26 +00:00
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
pluginInterface.Create<Service>();
|
|
|
|
|
Service.Plugin = this;
|
2022-10-30 10:02:49 +00:00
|
|
|
|
Service.Configuration = (Configuration?)pluginInterface.GetPluginConfig() ?? pluginInterface.Create<Configuration>()!;
|
2022-10-31 15:21:27 +00:00
|
|
|
|
Service.Configuration.Migrate();
|
2023-02-08 15:06:43 +00:00
|
|
|
|
|
|
|
|
|
ResetRenderer();
|
|
|
|
|
|
2023-02-05 03:21:24 +00:00
|
|
|
|
Service.Hooks = new Hooks();
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
|
|
|
|
var agreementWindow = pluginInterface.Create<AgreementWindow>();
|
|
|
|
|
if (agreementWindow is not null)
|
|
|
|
|
{
|
|
|
|
|
agreementWindow.IsOpen = Service.Configuration.FirstUse;
|
|
|
|
|
Service.WindowSystem.AddWindow(agreementWindow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var configWindow = pluginInterface.Create<ConfigWindow>();
|
|
|
|
|
if (configWindow is not null)
|
|
|
|
|
{
|
|
|
|
|
Service.WindowSystem.AddWindow(configWindow);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 18:43:24 +00:00
|
|
|
|
var statisticsWindow = pluginInterface.Create<StatisticsWindow>();
|
|
|
|
|
if (statisticsWindow is not null)
|
|
|
|
|
{
|
|
|
|
|
Service.WindowSystem.AddWindow(statisticsWindow);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
pluginInterface.UiBuilder.Draw += Draw;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
pluginInterface.UiBuilder.OpenConfigUi += OnOpenConfigUi;
|
2023-02-10 19:48:14 +00:00
|
|
|
|
pluginInterface.LanguageChanged += LanguageChanged;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
Service.Framework.Update += OnFrameworkUpdate;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
Service.Chat.ChatMessage += OnChatMessage;
|
2022-10-25 17:28:11 +00:00
|
|
|
|
Service.CommandManager.AddHandler("/pal", new CommandInfo(OnCommand)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
HelpMessage = Localization.Command_pal_HelpText
|
2022-10-25 17:28:11 +00:00
|
|
|
|
});
|
2022-10-26 21:38:29 +00:00
|
|
|
|
|
|
|
|
|
ReloadLanguageStrings();
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnOpenConfigUi()
|
|
|
|
|
{
|
2022-10-30 10:02:49 +00:00
|
|
|
|
Window? configWindow;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
if (Service.Configuration.FirstUse)
|
|
|
|
|
configWindow = Service.WindowSystem.GetWindow<AgreementWindow>();
|
|
|
|
|
else
|
|
|
|
|
configWindow = Service.WindowSystem.GetWindow<ConfigWindow>();
|
|
|
|
|
|
|
|
|
|
if (configWindow != null)
|
|
|
|
|
configWindow.IsOpen = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 17:28:11 +00:00
|
|
|
|
private void OnCommand(string command, string arguments)
|
|
|
|
|
{
|
|
|
|
|
if (Service.Configuration.FirstUse)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.PalError(Localization.Error_FirstTimeSetupRequired);
|
2022-10-25 17:28:11 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-29 22:21:17 +00:00
|
|
|
|
try
|
2022-10-26 18:43:24 +00:00
|
|
|
|
{
|
2022-11-30 10:53:26 +00:00
|
|
|
|
arguments = arguments.Trim();
|
2022-10-29 22:21:17 +00:00
|
|
|
|
switch (arguments)
|
|
|
|
|
{
|
|
|
|
|
case "stats":
|
|
|
|
|
Task.Run(async () => await FetchFloorStatistics());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-11-25 08:43:24 +00:00
|
|
|
|
case "test-connection":
|
|
|
|
|
case "tc":
|
|
|
|
|
var configWindow = Service.WindowSystem.GetWindow<ConfigWindow>();
|
|
|
|
|
if (configWindow == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
configWindow.IsOpen = true;
|
|
|
|
|
configWindow.TestConnection();
|
|
|
|
|
break;
|
|
|
|
|
|
2022-10-29 22:21:17 +00:00
|
|
|
|
#if DEBUG
|
|
|
|
|
case "update-saves":
|
|
|
|
|
LocalState.UpdateAll();
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.Print(Localization.Command_pal_updatesaves);
|
2022-10-29 22:21:17 +00:00
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-11-30 10:53:26 +00:00
|
|
|
|
case "":
|
2022-11-30 15:39:50 +00:00
|
|
|
|
case "config":
|
2022-10-29 22:21:17 +00:00
|
|
|
|
Service.WindowSystem.GetWindow<ConfigWindow>()?.Toggle();
|
|
|
|
|
break;
|
2022-11-30 10:53:26 +00:00
|
|
|
|
|
2023-02-02 16:16:03 +00:00
|
|
|
|
case "near":
|
|
|
|
|
DebugNearest(m => true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case "tnear":
|
|
|
|
|
DebugNearest(m => m.Type == Marker.EType.Trap);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case "hnear":
|
|
|
|
|
DebugNearest(m => m.Type == Marker.EType.Hoard);
|
|
|
|
|
break;
|
|
|
|
|
|
2022-11-30 10:53:26 +00:00
|
|
|
|
default:
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.PalError(string.Format(Localization.Command_pal_UnknownSubcommand, arguments, command));
|
2022-11-30 10:53:26 +00:00
|
|
|
|
break;
|
2022-10-29 22:21:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.PalError(e.ToString());
|
2022-10-26 18:43:24 +00:00
|
|
|
|
}
|
2022-10-25 17:28:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
#region IDisposable Support
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (!disposing) return;
|
|
|
|
|
|
2022-10-25 17:28:11 +00:00
|
|
|
|
Service.CommandManager.RemoveHandler("/pal");
|
2023-02-08 15:06:43 +00:00
|
|
|
|
Service.PluginInterface.UiBuilder.Draw -= Draw;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
Service.PluginInterface.UiBuilder.OpenConfigUi -= OnOpenConfigUi;
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.PluginInterface.LanguageChanged -= LanguageChanged;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
Service.Framework.Update -= OnFrameworkUpdate;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
Service.Chat.ChatMessage -= OnChatMessage;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
|
|
|
|
Service.WindowSystem.RemoveAllWindows();
|
|
|
|
|
|
|
|
|
|
Service.RemoteApi.Dispose();
|
2023-02-05 03:21:24 +00:00
|
|
|
|
Service.Hooks.Dispose();
|
2022-10-28 18:31:33 +00:00
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
if (Renderer is IDisposable disposable)
|
|
|
|
|
disposable.Dispose();
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2022-10-26 21:38:29 +00:00
|
|
|
|
private void OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString seMessage, ref bool isHandled)
|
|
|
|
|
{
|
2022-11-01 18:20:43 +00:00
|
|
|
|
if (Service.Configuration.FirstUse)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-10-26 21:38:29 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 19:48:14 +00:00
|
|
|
|
private void LanguageChanged(string langcode)
|
|
|
|
|
=> Localization.Culture = new CultureInfo(langcode);
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
private void OnFrameworkUpdate(Framework framework)
|
|
|
|
|
{
|
2022-11-01 18:20:43 +00:00
|
|
|
|
if (Service.Configuration.FirstUse)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2022-10-25 21:31:35 +00:00
|
|
|
|
bool recreateLayout = false;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
bool saveMarkers = false;
|
2022-12-22 00:01:09 +00:00
|
|
|
|
|
|
|
|
|
while (EarlyEventQueue.TryDequeue(out IQueueOnFrameworkThread? queued))
|
|
|
|
|
queued?.Run(this, ref recreateLayout, ref saveMarkers);
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
if (LastTerritory != Service.ClientState.TerritoryType)
|
|
|
|
|
{
|
|
|
|
|
LastTerritory = Service.ClientState.TerritoryType;
|
|
|
|
|
TerritorySyncState = SyncState.NotAttempted;
|
2023-02-05 03:21:24 +00:00
|
|
|
|
NextUpdateObjects.Clear();
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-11-30 10:37:34 +00:00
|
|
|
|
if (IsInDeepDungeon())
|
2022-12-22 00:01:09 +00:00
|
|
|
|
GetFloorMarkers(LastTerritory);
|
2022-10-25 21:31:35 +00:00
|
|
|
|
EphemeralMarkers.Clear();
|
2022-10-26 21:38:29 +00:00
|
|
|
|
PomanderOfSight = PomanderState.Inactive;
|
|
|
|
|
PomanderOfIntuition = PomanderState.Inactive;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
recreateLayout = true;
|
2022-10-24 07:29:46 +00:00
|
|
|
|
DebugMessage = null;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 10:37:34 +00:00
|
|
|
|
if (!IsInDeepDungeon())
|
2022-10-23 02:38:58 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (Service.Configuration.Mode == Configuration.EMode.Online && TerritorySyncState == SyncState.NotAttempted)
|
|
|
|
|
{
|
|
|
|
|
TerritorySyncState = SyncState.Started;
|
|
|
|
|
Task.Run(async () => await DownloadMarkersForTerritory(LastTerritory));
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-22 00:01:09 +00:00
|
|
|
|
while (LateEventQueue.TryDequeue(out IQueueOnFrameworkThread? queued))
|
|
|
|
|
queued?.Run(this, ref recreateLayout, ref saveMarkers);
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-12-22 00:01:09 +00:00
|
|
|
|
var currentFloor = GetFloorMarkers(LastTerritory);
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
|
|
|
|
IList<Marker> visibleMarkers = GetRelevantGameObjects();
|
2022-10-29 22:21:17 +00:00
|
|
|
|
HandlePersistentMarkers(currentFloor, visibleMarkers.Where(x => x.IsPermanent()).ToList(), saveMarkers, recreateLayout);
|
2022-10-25 21:31:35 +00:00
|
|
|
|
HandleEphemeralMarkers(visibleMarkers.Where(x => !x.IsPermanent()).ToList(), recreateLayout);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DebugMessage = $"{DateTime.Now}\n{e}";
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-12-22 00:01:09 +00:00
|
|
|
|
internal LocalState GetFloorMarkers(ushort territoryType)
|
|
|
|
|
{
|
|
|
|
|
return FloorMarkers.GetOrAdd(territoryType, tt => LocalState.Load(tt) ?? new LocalState(tt));
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
#region Rendering markers
|
2022-10-29 22:21:17 +00:00
|
|
|
|
private void HandlePersistentMarkers(LocalState currentFloor, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout)
|
2022-10-25 21:31:35 +00:00
|
|
|
|
{
|
2022-10-26 21:38:29 +00:00
|
|
|
|
var config = Service.Configuration;
|
2022-10-29 22:21:17 +00:00
|
|
|
|
var currentFloorMarkers = currentFloor.Markers;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-31 16:34:47 +00:00
|
|
|
|
bool updateSeenMarkers = false;
|
2023-02-06 21:00:38 +00:00
|
|
|
|
var partialAccountId = Service.RemoteApi.PartialAccountId;
|
2022-10-25 21:31:35 +00:00
|
|
|
|
foreach (var visibleMarker in visibleMarkers)
|
|
|
|
|
{
|
2022-10-30 10:02:49 +00:00
|
|
|
|
Marker? knownMarker = currentFloorMarkers.SingleOrDefault(x => x == visibleMarker);
|
2022-10-25 21:31:35 +00:00
|
|
|
|
if (knownMarker != null)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2022-10-25 21:31:35 +00:00
|
|
|
|
if (!knownMarker.Seen)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2022-10-25 21:31:35 +00:00
|
|
|
|
knownMarker.Seen = true;
|
|
|
|
|
saveMarkers = true;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
2022-10-31 16:34:47 +00:00
|
|
|
|
|
|
|
|
|
// This requires you to have seen a trap/hoard marker once per floor to synchronize this for older local states,
|
|
|
|
|
// markers discovered afterwards are automatically marked seen.
|
2023-02-06 21:00:38 +00:00
|
|
|
|
if (partialAccountId != null && knownMarker.NetworkId != null && !knownMarker.RemoteSeenRequested && !knownMarker.RemoteSeenOn.Contains(partialAccountId))
|
2022-10-31 16:34:47 +00:00
|
|
|
|
updateSeenMarkers = true;
|
2022-12-01 16:56:26 +00:00
|
|
|
|
|
2022-10-25 21:31:35 +00:00
|
|
|
|
continue;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 21:31:35 +00:00
|
|
|
|
currentFloorMarkers.Add(visibleMarker);
|
|
|
|
|
recreateLayout = true;
|
|
|
|
|
saveMarkers = true;
|
|
|
|
|
}
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-26 22:25:09 +00:00
|
|
|
|
if (!recreateLayout && currentFloorMarkers.Count > 0 && (config.OnlyVisibleTrapsAfterPomander || config.OnlyVisibleHoardAfterPomander))
|
2022-10-26 21:38:29 +00:00
|
|
|
|
{
|
|
|
|
|
|
2022-10-26 22:25:09 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
foreach (var marker in currentFloorMarkers)
|
2022-10-26 21:38:29 +00:00
|
|
|
|
{
|
2022-10-26 22:25:09 +00:00
|
|
|
|
uint desiredColor = DetermineColor(marker, visibleMarkers);
|
2023-02-08 15:06:43 +00:00
|
|
|
|
if (marker.RenderElement == null || !marker.RenderElement.IsValid)
|
2022-10-26 21:38:29 +00:00
|
|
|
|
{
|
2022-10-26 22:25:09 +00:00
|
|
|
|
recreateLayout = true;
|
|
|
|
|
break;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
}
|
2022-10-26 22:25:09 +00:00
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
if (marker.RenderElement.Color != desiredColor)
|
|
|
|
|
marker.RenderElement.Color = desiredColor;
|
2022-10-26 21:38:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-26 22:25:09 +00:00
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DebugMessage = $"{DateTime.Now}\n{e}";
|
|
|
|
|
recreateLayout = true;
|
|
|
|
|
}
|
2022-10-26 21:38:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 21:00:38 +00:00
|
|
|
|
if (updateSeenMarkers && partialAccountId != null)
|
2022-10-31 16:34:47 +00:00
|
|
|
|
{
|
2023-02-06 21:00:38 +00:00
|
|
|
|
var markersToUpdate = currentFloorMarkers.Where(x => x.Seen && x.NetworkId != null && !x.RemoteSeenRequested && !x.RemoteSeenOn.Contains(partialAccountId)).ToList();
|
2022-10-31 16:34:47 +00:00
|
|
|
|
foreach (var marker in markersToUpdate)
|
|
|
|
|
marker.RemoteSeenRequested = true;
|
|
|
|
|
Task.Run(async () => await SyncSeenMarkersForTerritory(LastTerritory, markersToUpdate));
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 21:31:35 +00:00
|
|
|
|
if (saveMarkers)
|
|
|
|
|
{
|
2022-10-29 22:21:17 +00:00
|
|
|
|
currentFloor.Save();
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-25 21:31:35 +00:00
|
|
|
|
if (TerritorySyncState == SyncState.Complete)
|
|
|
|
|
{
|
2022-10-31 16:34:47 +00:00
|
|
|
|
var markersToUpload = currentFloorMarkers.Where(x => x.IsPermanent() && x.NetworkId == null && !x.UploadRequested).ToList();
|
2022-10-31 18:27:54 +00:00
|
|
|
|
if (markersToUpload.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (var marker in markersToUpload)
|
|
|
|
|
marker.UploadRequested = true;
|
|
|
|
|
Task.Run(async () => await UploadMarkersForTerritory(LastTerritory, markersToUpload));
|
|
|
|
|
}
|
2022-10-25 21:31:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-25 21:31:35 +00:00
|
|
|
|
if (recreateLayout)
|
|
|
|
|
{
|
2023-02-08 15:06:43 +00:00
|
|
|
|
Renderer.ResetLayer(ELayer.TrapHoard);
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
List<IRenderElement> elements = new();
|
2022-10-25 21:31:35 +00:00
|
|
|
|
foreach (var marker in currentFloorMarkers)
|
|
|
|
|
{
|
2022-12-22 00:01:09 +00:00
|
|
|
|
if (marker.Seen || config.Mode == Configuration.EMode.Online || (marker.WasImported && marker.Imports.Count > 0))
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2022-10-25 21:31:35 +00:00
|
|
|
|
if (marker.Type == Marker.EType.Trap && config.ShowTraps)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2023-02-08 15:06:43 +00:00
|
|
|
|
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers));
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
2022-10-25 21:31:35 +00:00
|
|
|
|
else if (marker.Type == Marker.EType.Hoard && config.ShowHoard)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2023-02-08 15:06:43 +00:00
|
|
|
|
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers));
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
2022-10-25 21:31:35 +00:00
|
|
|
|
}
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
2022-10-25 21:31:35 +00:00
|
|
|
|
|
|
|
|
|
if (elements.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
Renderer.SetLayer(ELayer.TrapHoard, elements);
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
2022-10-25 21:31:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleEphemeralMarkers(IList<Marker> visibleMarkers, bool recreateLayout)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
recreateLayout |= EphemeralMarkers.Any(existingMarker => visibleMarkers.All(x => x != existingMarker));
|
|
|
|
|
recreateLayout |= visibleMarkers.Any(visibleMarker => EphemeralMarkers.All(x => x != visibleMarker));
|
2022-10-25 21:31:35 +00:00
|
|
|
|
|
|
|
|
|
if (recreateLayout)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2023-02-08 15:06:43 +00:00
|
|
|
|
Renderer.ResetLayer(ELayer.RegularCoffers);
|
2022-10-25 21:31:35 +00:00
|
|
|
|
EphemeralMarkers.Clear();
|
|
|
|
|
|
|
|
|
|
var config = Service.Configuration;
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
List<IRenderElement> elements = new();
|
2022-10-26 18:43:24 +00:00
|
|
|
|
foreach (var marker in visibleMarkers)
|
|
|
|
|
{
|
2022-10-25 21:31:35 +00:00
|
|
|
|
EphemeralMarkers.Add(marker);
|
|
|
|
|
|
|
|
|
|
if (marker.Type == Marker.EType.SilverCoffer && config.ShowSilverCoffers)
|
|
|
|
|
{
|
2023-02-08 15:06:43 +00:00
|
|
|
|
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers), config.FillSilverCoffers);
|
2022-10-25 21:31:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (elements.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
Renderer.SetLayer(ELayer.RegularCoffers, elements);
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
private uint DetermineColor(Marker marker, IList<Marker> visibleMarkers)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
switch (marker.Type)
|
2023-02-08 15:06:43 +00:00
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
case Marker.EType.Trap when PomanderOfSight == PomanderState.Inactive || !Service.Configuration.OnlyVisibleTrapsAfterPomander || visibleMarkers.Any(x => x == marker):
|
2023-02-08 15:06:43 +00:00
|
|
|
|
return ImGui.ColorConvertFloat4ToU32(Service.Configuration.TrapColor);
|
2023-02-10 19:48:14 +00:00
|
|
|
|
case Marker.EType.Hoard when PomanderOfIntuition == PomanderState.Inactive || !Service.Configuration.OnlyVisibleHoardAfterPomander || visibleMarkers.Any(x => x == marker):
|
2023-02-08 15:06:43 +00:00
|
|
|
|
return ImGui.ColorConvertFloat4ToU32(Service.Configuration.HoardColor);
|
2023-02-10 19:48:14 +00:00
|
|
|
|
case Marker.EType.SilverCoffer:
|
|
|
|
|
return ImGui.ColorConvertFloat4ToU32(Service.Configuration.SilverCofferColor);
|
|
|
|
|
case Marker.EType.Trap:
|
|
|
|
|
case Marker.EType.Hoard:
|
2023-02-10 20:25:28 +00:00
|
|
|
|
return ColorInvisible;
|
2023-02-10 19:48:14 +00:00
|
|
|
|
default:
|
|
|
|
|
return ImGui.ColorConvertFloat4ToU32(new Vector4(1, 0.5f, 1, 0.4f));
|
2023-02-08 15:06:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CreateRenderElement(Marker marker, List<IRenderElement> elements, uint color, bool fill = false)
|
|
|
|
|
{
|
|
|
|
|
var element = Renderer.CreateElement(marker.Type, marker.Position, color, fill);
|
|
|
|
|
marker.RenderElement = element;
|
|
|
|
|
elements.Add(element);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-02-02 16:16:03 +00:00
|
|
|
|
#region Up-/Download
|
2022-10-23 02:38:58 +00:00
|
|
|
|
private async Task DownloadMarkersForTerritory(ushort territoryId)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var (success, downloadedMarkers) = await Service.RemoteApi.DownloadRemoteMarkers(territoryId);
|
2022-12-22 00:01:09 +00:00
|
|
|
|
LateEventQueue.Enqueue(new QueuedSyncResponse
|
2022-10-31 16:34:47 +00:00
|
|
|
|
{
|
|
|
|
|
Type = SyncType.Download,
|
|
|
|
|
TerritoryType = territoryId,
|
|
|
|
|
Success = success,
|
|
|
|
|
Markers = downloadedMarkers
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DebugMessage = $"{DateTime.Now}\n{e}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task UploadMarkersForTerritory(ushort territoryId, List<Marker> markersToUpload)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var (success, uploadedMarkers) = await Service.RemoteApi.UploadMarker(territoryId, markersToUpload);
|
2022-12-22 00:01:09 +00:00
|
|
|
|
LateEventQueue.Enqueue(new QueuedSyncResponse
|
2022-10-31 16:34:47 +00:00
|
|
|
|
{
|
|
|
|
|
Type = SyncType.Upload,
|
|
|
|
|
TerritoryType = territoryId,
|
|
|
|
|
Success = success,
|
|
|
|
|
Markers = uploadedMarkers
|
|
|
|
|
});
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DebugMessage = $"{DateTime.Now}\n{e}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-31 16:34:47 +00:00
|
|
|
|
private async Task SyncSeenMarkersForTerritory(ushort territoryId, List<Marker> markersToUpdate)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var success = await Service.RemoteApi.MarkAsSeen(territoryId, markersToUpdate);
|
2022-12-22 00:01:09 +00:00
|
|
|
|
LateEventQueue.Enqueue(new QueuedSyncResponse
|
2022-10-31 16:34:47 +00:00
|
|
|
|
{
|
|
|
|
|
Type = SyncType.MarkSeen,
|
|
|
|
|
TerritoryType = territoryId,
|
|
|
|
|
Success = success,
|
|
|
|
|
Markers = markersToUpdate,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DebugMessage = $"{DateTime.Now}\n{e}";
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-02 16:16:03 +00:00
|
|
|
|
#endregion
|
2022-10-31 16:34:47 +00:00
|
|
|
|
|
2023-02-02 16:16:03 +00:00
|
|
|
|
#region Command Handling
|
2022-10-26 18:43:24 +00:00
|
|
|
|
private async Task FetchFloorStatistics()
|
|
|
|
|
{
|
2022-12-11 14:22:41 +00:00
|
|
|
|
if (!Service.RemoteApi.HasRoleOnCurrentServer("statistics:view"))
|
2022-10-26 18:43:24 +00:00
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.PalError(Localization.Command_pal_stats_CurrentFloor);
|
2022-10-26 18:43:24 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var (success, floorStatistics) = await Service.RemoteApi.FetchStatistics();
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
2022-10-30 10:02:49 +00:00
|
|
|
|
var statisticsWindow = Service.WindowSystem.GetWindow<StatisticsWindow>()!;
|
2022-10-26 18:43:24 +00:00
|
|
|
|
statisticsWindow.SetFloorData(floorStatistics);
|
|
|
|
|
statisticsWindow.IsOpen = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.PalError(Localization.Command_pal_stats_UnableToFetchStatistics);
|
2022-10-26 18:43:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (RpcException e) when (e.StatusCode == StatusCode.PermissionDenied)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.Print(Localization.Command_pal_stats_CurrentFloor);
|
2022-10-26 18:43:24 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2023-02-10 19:48:14 +00:00
|
|
|
|
Service.Chat.PalError(e.ToString());
|
2022-10-26 18:43:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-02 16:16:03 +00:00
|
|
|
|
private void DebugNearest(Predicate<Marker> predicate)
|
|
|
|
|
{
|
|
|
|
|
if (!IsInDeepDungeon())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var state = GetFloorMarkers(Service.ClientState.TerritoryType);
|
|
|
|
|
var playerPosition = Service.ClientState.LocalPlayer?.Position;
|
|
|
|
|
if (playerPosition == null)
|
|
|
|
|
return;
|
2023-02-05 03:21:24 +00:00
|
|
|
|
Service.Chat.Print($"[Palace Pal] {playerPosition}");
|
2023-02-02 16:16:03 +00:00
|
|
|
|
|
|
|
|
|
var nearbyMarkers = state.Markers
|
|
|
|
|
.Where(m => predicate(m))
|
2023-02-10 19:48:14 +00:00
|
|
|
|
.Where(m => m.RenderElement != null && m.RenderElement.Color != ColorInvisible)
|
2023-02-02 16:16:03 +00:00
|
|
|
|
.Select(m => new { m = m, distance = (playerPosition - m.Position)?.Length() ?? float.MaxValue })
|
|
|
|
|
.OrderBy(m => m.distance)
|
|
|
|
|
.Take(5)
|
|
|
|
|
.ToList();
|
|
|
|
|
foreach (var nearbyMarker in nearbyMarkers)
|
|
|
|
|
Service.Chat.Print($"{nearbyMarker.distance:F2} - {nearbyMarker.m.Type} {nearbyMarker.m.NetworkId?.ToString()?.Substring(0, 8)} - {nearbyMarker.m.Position}");
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
private IList<Marker> GetRelevantGameObjects()
|
|
|
|
|
{
|
|
|
|
|
List<Marker> result = new();
|
2023-02-05 00:18:21 +00:00
|
|
|
|
for (int i = 246; i < Service.ObjectTable.Length; i++)
|
2022-10-23 02:38:58 +00:00
|
|
|
|
{
|
2022-10-30 10:02:49 +00:00
|
|
|
|
GameObject? obj = Service.ObjectTable[i];
|
2022-10-23 02:38:58 +00:00
|
|
|
|
if (obj == null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
switch ((uint)Marshal.ReadInt32(obj.Address + 128))
|
|
|
|
|
{
|
|
|
|
|
case 2007182:
|
|
|
|
|
case 2007183:
|
|
|
|
|
case 2007184:
|
|
|
|
|
case 2007185:
|
|
|
|
|
case 2007186:
|
|
|
|
|
case 2009504:
|
2022-10-25 21:31:35 +00:00
|
|
|
|
result.Add(new Marker(Marker.EType.Trap, obj.Position) { Seen = true });
|
2023-02-05 00:18:21 +00:00
|
|
|
|
break;
|
2022-12-01 16:56:26 +00:00
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
case 2007542:
|
|
|
|
|
case 2007543:
|
2022-10-25 21:31:35 +00:00
|
|
|
|
result.Add(new Marker(Marker.EType.Hoard, obj.Position) { Seen = true });
|
2023-02-05 00:18:21 +00:00
|
|
|
|
break;
|
2022-10-25 21:31:35 +00:00
|
|
|
|
|
|
|
|
|
case 2007357:
|
|
|
|
|
result.Add(new Marker(Marker.EType.SilverCoffer, obj.Position) { Seen = true });
|
2023-02-05 00:18:21 +00:00
|
|
|
|
break;
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-05 03:21:24 +00:00
|
|
|
|
while (NextUpdateObjects.TryDequeue(out nint address))
|
|
|
|
|
{
|
|
|
|
|
var obj = Service.ObjectTable.FirstOrDefault(x => x.Address == address);
|
|
|
|
|
if (obj != null && obj.Position.Length() > 0.1)
|
2023-02-08 19:41:45 +00:00
|
|
|
|
result.Add(new Marker(Marker.EType.Trap, obj.Position) { Seen = true });
|
2023-02-05 03:21:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 02:38:58 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 10:37:34 +00:00
|
|
|
|
internal bool IsInDeepDungeon() =>
|
2022-12-01 16:56:26 +00:00
|
|
|
|
Service.ClientState.IsLoggedIn
|
2022-11-30 10:37:34 +00:00
|
|
|
|
&& Service.Condition[ConditionFlag.InDeepDungeon]
|
|
|
|
|
&& typeof(ETerritoryType).IsEnumDefined(Service.ClientState.TerritoryType);
|
2022-10-23 02:38:58 +00:00
|
|
|
|
|
2022-10-26 21:38:29 +00:00
|
|
|
|
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+)") + "$"),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 15:06:43 +00:00
|
|
|
|
internal void ResetRenderer()
|
|
|
|
|
{
|
|
|
|
|
if (Renderer is SplatoonRenderer && Service.Configuration.Renderer == Configuration.ERenderer.Splatoon)
|
|
|
|
|
return;
|
|
|
|
|
else if (Renderer is SimpleRenderer && Service.Configuration.Renderer == Configuration.ERenderer.Simple)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (Renderer is IDisposable disposable)
|
|
|
|
|
disposable.Dispose();
|
|
|
|
|
|
|
|
|
|
if (Service.Configuration.Renderer == Configuration.ERenderer.Splatoon)
|
|
|
|
|
Renderer = new SplatoonRenderer(Service.PluginInterface, this);
|
|
|
|
|
else
|
|
|
|
|
Renderer = new SimpleRenderer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Draw()
|
|
|
|
|
{
|
|
|
|
|
if (Renderer is SimpleRenderer sr)
|
|
|
|
|
sr.DrawLayers();
|
|
|
|
|
|
|
|
|
|
Service.WindowSystem.Draw();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 21:38:29 +00:00
|
|
|
|
private string GetLocalizedString(uint id)
|
|
|
|
|
{
|
2022-10-30 10:02:49 +00:00
|
|
|
|
return Service.DataManager.GetExcelSheet<LogMessage>()?.GetRow(id)?.Text?.ToString() ?? "Unknown";
|
2022-10-26 21:38:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum PomanderState
|
|
|
|
|
{
|
|
|
|
|
Inactive,
|
|
|
|
|
Active,
|
|
|
|
|
FoundOnCurrentFloor,
|
|
|
|
|
PomanderOfSafetyUsed,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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+)$");
|
|
|
|
|
}
|
2022-10-23 02:38:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|