using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using Microsoft.Extensions.DependencyInjection; using Questionable.Controller; using Questionable.Controller.Conditions; using Questionable.Controller.Steps; using Questionable.Data; using Questionable.Functions; using Questionable.Model; using Questionable.Model.Questing; using Questionable.Windows.JournalComponents; using Questionable.Windows.QuestComponents; namespace Questionable.External; internal sealed class QuestionableIpc : IDisposable { public sealed class StepData { public required string QuestId { get; init; } public required byte Sequence { get; init; } public required int Step { get; init; } public required string InteractionType { get; init; } public required Vector3? Position { get; init; } public required ushort TerritoryId { get; init; } } public sealed class TaskData { public required string TaskName { get; init; } public required int RemainingTaskCount { get; init; } } public sealed class StopConditionData { public required bool Enabled { get; init; } public required int TargetValue { get; init; } } public sealed class MsqLevelLockData { public required bool IsLevelLocked { get; init; } public required int LevelsNeeded { get; init; } public required int RequiredLevel { get; init; } public required string? QuestName { get; init; } } private const string IpcGetAlliedSocietyRemainingAllowances = "Questionable.AlliedSociety.GetRemainingAllowances"; private const string IpcGetAlliedSocietyTimeUntilReset = "Questionable.AlliedSociety.GetTimeUntilReset"; private const string IpcGetAlliedSocietyAvailableQuestIds = "Questionable.AlliedSociety.GetAvailableQuestIds"; private const string IpcGetAlliedSocietyAllAvailableQuestCounts = "Questionable.AlliedSociety.GetAllAvailableQuestCounts"; private const string IpcGetAlliedSocietyIsMaxRank = "Questionable.AlliedSociety.IsMaxRank"; private const string IpcGetAlliedSocietyCurrentRank = "Questionable.AlliedSociety.GetCurrentRank"; private const string IpcGetAlliedSocietiesWithAvailableQuests = "Questionable.AlliedSociety.GetSocietiesWithAvailableQuests"; private const string IpcAddAlliedSocietyOptimalQuests = "Questionable.AlliedSociety.AddOptimalQuests"; private const string IpcGetAlliedSocietyOptimalQuests = "Questionable.AlliedSociety.GetOptimalQuests"; private const string IpcGetBlacklistedQuests = "Questionable.GetBlacklistedQuests"; private const string IpcAddBlacklistedQuest = "Questionable.AddBlacklistedQuest"; private const string IpcRemoveBlacklistedQuest = "Questionable.RemoveBlacklistedQuest"; private const string IpcClearBlacklistedQuests = "Questionable.ClearBlacklistedQuests"; private const string IpcIsQuestBlacklisted = "Questionable.IsQuestBlacklisted"; private readonly QuestController _questController; private readonly EventInfoComponent _eventInfoComponent; private readonly QuestRegistry _questRegistry; private readonly QuestFunctions _questFunctions; private readonly QuestData _questData; private readonly ManualPriorityComponent _manualPriorityComponent; private readonly Configuration _configuration; private readonly IDalamudPluginInterface _pluginInterface; private readonly IServiceProvider _serviceProvider; private readonly AutoDutyIpc _autoDutyIpc; private readonly IObjectTable _objectTable; private readonly List _unregisterActions = new List(); private const string IpcGetDefaultDutyMode = "Questionable.GetDefaultDutyMode"; private const string IpcSetDefaultDutyMode = "Questionable.SetDefaultDutyMode"; private const string IpcGetDutyModeOverride = "Questionable.GetDutyModeOverride"; private const string IpcSetDutyModeOverride = "Questionable.SetDutyModeOverride"; private const string IpcClearDutyModeOverride = "Questionable.ClearDutyModeOverride"; private const string IpcClearAllDutyModeOverrides = "Questionable.ClearAllDutyModeOverrides"; private const string IpcIsLevelingModeEnabled = "Questionable.IsLevelingModeEnabled"; private const string IpcSetLevelingModeEnabled = "Questionable.SetLevelingModeEnabled"; private const string IpcGetMsqLevelLockInfo = "Questionable.GetMsqLevelLockInfo"; private const string IpcStartLevelingMode = "Questionable.StartLevelingMode"; private const string IpcStopLevelingMode = "Questionable.StopLevelingMode"; private static readonly (int Major, int Minor) ApiVersion = (Major: 1, Minor: 0); private const string IpcApiVersion = "Questionable.ApiVersion"; private const string IpcGetMsqPriorityMode = "Questionable.GetMsqPriorityMode"; private const string IpcSetMsqPriorityMode = "Questionable.SetMsqPriorityMode"; private const string IpcImportQuestPriority = "Questionable.ImportQuestPriority"; private const string IpcClearQuestPriority = "Questionable.ClearQuestPriority"; private const string IpcAddQuestPriority = "Questionable.AddQuestPriority"; private const string IpcInsertQuestPriority = "Questionable.InsertQuestPriority"; private const string IpcExportQuestPriority = "Questionable.ExportQuestPriority"; private const string IpcGetPriorityQuests = "Questionable.GetPriorityQuests"; private const string IpcRemovePriorityQuest = "Questionable.RemovePriorityQuest"; private const string IpcReorderPriorityQuest = "Questionable.ReorderPriorityQuest"; private const string IpcGetAvailablePresets = "Questionable.GetAvailablePresets"; private const string IpcGetPresetQuests = "Questionable.GetPresetQuests"; private const string IpcAddPresetToPriority = "Questionable.AddPresetToPriority"; private const string IpcIsPresetAvailable = "Questionable.IsPresetAvailable"; private const string IpcIsQuestInPriority = "Questionable.IsQuestInPriority"; private const string IpcGetQuestPriorityIndex = "Questionable.GetQuestPriorityIndex"; private const string IpcHasAvailablePriorityQuests = "Questionable.HasAvailablePriorityQuests"; private const string IpcIsRunning = "Questionable.IsRunning"; private const string IpcGetCurrentQuestId = "Questionable.GetCurrentQuestId"; private const string IpcGetCurrentStepData = "Questionable.GetCurrentStepData"; private const string IpcGetCurrentTask = "Questionable.GetCurrentTask"; private const string IpcGetCurrentlyActiveEventQuests = "Questionable.GetCurrentlyActiveEventQuests"; private const string IpcStartQuest = "Questionable.StartQuest"; private const string IpcStartSingleQuest = "Questionable.StartSingleQuest"; private const string IpcIsQuestLocked = "Questionable.IsQuestLocked"; private const string IpcIsQuestComplete = "Questionable.IsQuestComplete"; private const string IpcIsReadyToAcceptQuest = "Questionable.IsReadyToAcceptQuest"; private const string IpcIsQuestAccepted = "Questionable.IsQuestAccepted"; private const string IpcIsQuestUnobtainable = "Questionable.IsQuestUnobtainable"; private const string IpcGetStopConditionsEnabled = "Questionable.GetStopConditionsEnabled"; private const string IpcSetStopConditionsEnabled = "Questionable.SetStopConditionsEnabled"; private const string IpcGetStopQuestList = "Questionable.GetStopQuestList"; private const string IpcAddStopQuest = "Questionable.AddStopQuest"; private const string IpcRemoveStopQuest = "Questionable.RemoveStopQuest"; private const string IpcClearStopQuests = "Questionable.ClearStopQuests"; private const string IpcGetLevelStopCondition = "Questionable.GetLevelStopCondition"; private const string IpcSetLevelStopCondition = "Questionable.SetLevelStopCondition"; private const string IpcGetSequenceStopCondition = "Questionable.GetSequenceStopCondition"; private const string IpcSetSequenceStopCondition = "Questionable.SetSequenceStopCondition"; private const string IpcGetQuestSequenceStopCondition = "Questionable.GetQuestSequenceStopCondition"; private const string IpcSetQuestSequenceStopCondition = "Questionable.SetQuestSequenceStopCondition"; private const string IpcRemoveQuestSequenceStopCondition = "Questionable.RemoveQuestSequenceStopCondition"; private const string IpcGetAllQuestSequenceStopConditions = "Questionable.GetAllQuestSequenceStopConditions"; private const string IpcGetLevelStopMode = "Questionable.GetLevelStopMode"; private const string IpcSetLevelStopMode = "Questionable.SetLevelStopMode"; private const string IpcGetSequenceStopMode = "Questionable.GetSequenceStopMode"; private const string IpcSetSequenceStopMode = "Questionable.SetSequenceStopMode"; private const string IpcGetQuestStopMode = "Questionable.GetQuestStopMode"; private const string IpcSetQuestStopMode = "Questionable.SetQuestStopMode"; private void RegisterAlliedSocietyIpc() { Register("Questionable.AlliedSociety.GetRemainingAllowances", GetAlliedSocietyRemainingAllowances); Register("Questionable.AlliedSociety.GetTimeUntilReset", GetAlliedSocietyTimeUntilReset); Register>("Questionable.AlliedSociety.GetAvailableQuestIds", GetAlliedSocietyAvailableQuestIds); Register("Questionable.AlliedSociety.GetAllAvailableQuestCounts", GetAlliedSocietyAllAvailableQuestCounts); Register("Questionable.AlliedSociety.IsMaxRank", GetAlliedSocietyIsMaxRank); Register("Questionable.AlliedSociety.GetCurrentRank", GetAlliedSocietyCurrentRank); Register("Questionable.AlliedSociety.GetSocietiesWithAvailableQuests", GetAlliedSocietiesWithAvailableQuests); Register("Questionable.AlliedSociety.AddOptimalQuests", AddAlliedSocietyOptimalQuests); Register>("Questionable.AlliedSociety.GetOptimalQuests", GetAlliedSocietyOptimalQuests); } private unsafe int GetAlliedSocietyRemainingAllowances() { QuestManager* ptr = QuestManager.Instance(); if (ptr == null) { return 12; } return (int)ptr->GetBeastTribeAllowance(); } private long GetAlliedSocietyTimeUntilReset() { TimeSpan item = AlliedSocietyJournalComponent.CalculateTimeUntilReset().TimeUntilReset; return item.Ticks; } private List GetAlliedSocietyAvailableQuestIds(byte alliedSocietyId) { if (alliedSocietyId == 0 || !Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId)) { return new List(); } EAlliedSociety alliedSociety = (EAlliedSociety)alliedSocietyId; return (from q in _serviceProvider.GetRequiredService().GetAvailableAlliedSocietyQuests(alliedSociety) select q.ToString()).ToList(); } private Dictionary GetAlliedSocietyAllAvailableQuestCounts() { Dictionary dictionary = new Dictionary(); AlliedSocietyQuestFunctions requiredService = _serviceProvider.GetRequiredService(); EAlliedSociety[] values = Enum.GetValues(); foreach (EAlliedSociety eAlliedSociety in values) { if (eAlliedSociety != EAlliedSociety.None) { int count = requiredService.GetAvailableAlliedSocietyQuests(eAlliedSociety).Count; if (count > 0) { dictionary[(byte)eAlliedSociety] = count; } } } return dictionary; } private unsafe bool GetAlliedSocietyIsMaxRank(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return false; } QuestManager* ptr = QuestManager.Instance(); if (ptr == null) { return false; } byte b = (byte)(ptr->BeastReputation[alliedSocietyId - 1].Rank & 0x7F); return b >= (EAlliedSociety)alliedSocietyId switch { EAlliedSociety.Amaljaa => 3, EAlliedSociety.Sylphs => 3, EAlliedSociety.Kobolds => 3, EAlliedSociety.Sahagin => 3, EAlliedSociety.Ixal => 7, _ => 8, }; } private unsafe int GetAlliedSocietyCurrentRank(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return -1; } QuestManager* ptr = QuestManager.Instance(); if (ptr == null) { return -1; } return (byte)(ptr->BeastReputation[alliedSocietyId - 1].Rank & 0x7F); } private List GetAlliedSocietiesWithAvailableQuests() { List list = new List(); AlliedSocietyQuestFunctions requiredService = _serviceProvider.GetRequiredService(); EAlliedSociety[] values = Enum.GetValues(); foreach (EAlliedSociety eAlliedSociety in values) { if (eAlliedSociety != EAlliedSociety.None && requiredService.GetAvailableAlliedSocietyQuests(eAlliedSociety).Count > 0) { list.Add((byte)eAlliedSociety); } } return list; } private int AddAlliedSocietyOptimalQuests(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return 0; } EAlliedSociety eAlliedSociety = (EAlliedSociety)alliedSocietyId; List availableAlliedSocietyQuests = _serviceProvider.GetRequiredService().GetAvailableAlliedSocietyQuests(eAlliedSociety); if (availableAlliedSocietyQuests.Count == 0) { return 0; } IQuestInfo questInfo; Quest quest; List list = (from questInfo in availableAlliedSocietyQuests.Select((QuestId questId) => (!_questData.TryGetQuestInfo(questId, out questInfo)) ? null : questInfo).OfType() where _questRegistry.TryGetQuest(questInfo.QuestId, out quest) && !quest.Root.Disabled where !_questController.ManualPriorityQuests.Any((Quest pq) => pq.Id.Equals(questInfo.QuestId)) orderby questInfo.AlliedSocietyRank descending select questInfo).ToList(); if (list.Count == 0) { return 0; } int val = (((int)eAlliedSociety <= 5) ? 12 : 3); int alliedSocietyRemainingAllowances = GetAlliedSocietyRemainingAllowances(); int count = Math.Min(Math.Min(val, alliedSocietyRemainingAllowances), list.Count); int num = 0; foreach (QuestInfo item in list.Take(count)) { if (_questController.AddQuestPriority(item.QuestId)) { num++; } } return num; } private List GetAlliedSocietyOptimalQuests(byte alliedSocietyId) { if (!Enum.IsDefined(typeof(EAlliedSociety), alliedSocietyId) || alliedSocietyId == 0) { return new List(); } EAlliedSociety eAlliedSociety = (EAlliedSociety)alliedSocietyId; List availableAlliedSocietyQuests = _serviceProvider.GetRequiredService().GetAvailableAlliedSocietyQuests(eAlliedSociety); if (availableAlliedSocietyQuests.Count == 0) { return new List(); } IQuestInfo questInfo; Quest quest; List list = (from questInfo in availableAlliedSocietyQuests.Select((QuestId questId) => (!_questData.TryGetQuestInfo(questId, out questInfo)) ? null : questInfo).OfType() where _questRegistry.TryGetQuest(questInfo.QuestId, out quest) && !quest.Root.Disabled where !_questController.ManualPriorityQuests.Any((Quest pq) => pq.Id.Equals(questInfo.QuestId)) orderby questInfo.AlliedSocietyRank descending select questInfo).ToList(); if (list.Count == 0) { return new List(); } int val = (((int)eAlliedSociety <= 5) ? 12 : 3); int alliedSocietyRemainingAllowances = GetAlliedSocietyRemainingAllowances(); int count = Math.Min(Math.Min(val, alliedSocietyRemainingAllowances), list.Count); return (from q in list.Take(count) select q.QuestId.ToString()).ToList(); } private void RegisterBlacklistIpc() { Register("Questionable.GetBlacklistedQuests", GetBlacklistedQuests); Register("Questionable.AddBlacklistedQuest", AddBlacklistedQuest); Register("Questionable.RemoveBlacklistedQuest", RemoveBlacklistedQuest); Register("Questionable.ClearBlacklistedQuests", ClearBlacklistedQuests); Register("Questionable.IsQuestBlacklisted", IsQuestBlacklistedIpc); } private List GetBlacklistedQuests() { return _configuration.General.BlacklistedQuests.Select((ElementId q) => q.ToString()).ToList(); } private bool AddBlacklistedQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _configuration.General.BlacklistedQuests.Add(elementId)) { _pluginInterface.SavePluginConfig(_configuration); return true; } return false; } private bool RemoveBlacklistedQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { bool num = _configuration.General.BlacklistedQuests.Remove(elementId); if (num) { _pluginInterface.SavePluginConfig(_configuration); } return num; } return false; } private bool ClearBlacklistedQuests() { _configuration.General.BlacklistedQuests.Clear(); _pluginInterface.SavePluginConfig(_configuration); return true; } private bool IsQuestBlacklistedIpc(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestBlacklisted(elementId); } return false; } public QuestionableIpc(QuestController questController, EventInfoComponent eventInfoComponent, QuestRegistry questRegistry, QuestFunctions questFunctions, QuestData questData, ManualPriorityComponent manualPriorityComponent, Configuration configuration, IDalamudPluginInterface pluginInterface, IServiceProvider serviceProvider, AutoDutyIpc autoDutyIpc, IObjectTable objectTable) { _questController = questController; _eventInfoComponent = eventInfoComponent; _questRegistry = questRegistry; _questFunctions = questFunctions; _questData = questData; _manualPriorityComponent = manualPriorityComponent; _configuration = configuration; _pluginInterface = pluginInterface; _serviceProvider = serviceProvider; _autoDutyIpc = autoDutyIpc; _objectTable = objectTable; RegisterMetaIpc(); RegisterQuestStateIpc(); RegisterDutyModeIpc(); RegisterPriorityQuestIpc(); RegisterStopConditionIpc(); RegisterAlliedSocietyIpc(); RegisterLevelingModeIpc(); RegisterBlacklistIpc(); RegisterMsqPriorityIpc(); } private void Register(string name, Func handler) { ICallGateProvider ipcProvider = _pluginInterface.GetIpcProvider(name); ipcProvider.RegisterFunc(handler); _unregisterActions.Add(ipcProvider.UnregisterFunc); } private void Register(string name, Func handler) { ICallGateProvider ipcProvider = _pluginInterface.GetIpcProvider(name); ipcProvider.RegisterFunc(handler); _unregisterActions.Add(ipcProvider.UnregisterFunc); } private void Register(string name, Func handler) { ICallGateProvider ipcProvider = _pluginInterface.GetIpcProvider(name); ipcProvider.RegisterFunc(handler); _unregisterActions.Add(ipcProvider.UnregisterFunc); } public void Dispose() { foreach (Action unregisterAction in _unregisterActions) { unregisterAction(); } _unregisterActions.Clear(); } private void RegisterDutyModeIpc() { Register("Questionable.GetDefaultDutyMode", GetDefaultDutyMode); Register("Questionable.SetDefaultDutyMode", SetDefaultDutyMode); Register("Questionable.GetDutyModeOverride", GetDutyModeOverride); Register("Questionable.SetDutyModeOverride", SetDutyModeOverride); Register("Questionable.ClearDutyModeOverride", ClearDutyModeOverride); Register("Questionable.ClearAllDutyModeOverrides", ClearAllDutyModeOverrides); } private int GetDefaultDutyMode() { return (int)_configuration.Duties.DefaultDutyMode; } private bool SetDefaultDutyMode(int dutyMode) { if (!Enum.IsDefined(typeof(EDutyMode), dutyMode)) { return false; } _configuration.Duties.DefaultDutyMode = (EDutyMode)dutyMode; _pluginInterface.SavePluginConfig(_configuration); return true; } private int GetDutyModeOverride(uint contentFinderConditionId) { if (_configuration.Duties.DutyModeOverrides.TryGetValue(contentFinderConditionId, out var value)) { return (int)value; } return -1; } private bool SetDutyModeOverride(uint contentFinderConditionId, int dutyMode) { if (!Enum.IsDefined(typeof(EDutyMode), dutyMode)) { return false; } _configuration.Duties.DutyModeOverrides[contentFinderConditionId] = (EDutyMode)dutyMode; _pluginInterface.SavePluginConfig(_configuration); return true; } private bool ClearDutyModeOverride(uint contentFinderConditionId) { bool num = _configuration.Duties.DutyModeOverrides.Remove(contentFinderConditionId); if (num) { _pluginInterface.SavePluginConfig(_configuration); } return num; } private bool ClearAllDutyModeOverrides() { _configuration.Duties.DutyModeOverrides.Clear(); _pluginInterface.SavePluginConfig(_configuration); return true; } private void RegisterLevelingModeIpc() { Register("Questionable.IsLevelingModeEnabled", IsLevelingModeEnabled); Register("Questionable.SetLevelingModeEnabled", SetLevelingModeEnabled); Register("Questionable.GetMsqLevelLockInfo", GetMsqLevelLockInfo); Register("Questionable.StartLevelingMode", StartLevelingMode); Register("Questionable.StopLevelingMode", StopLevelingMode); } private bool IsLevelingModeEnabled() { return _configuration.Duties.RunLevelingModeWhenUnderleveled; } private bool SetLevelingModeEnabled(bool enabled) { _configuration.Duties.RunLevelingModeWhenUnderleveled = enabled; _pluginInterface.SavePluginConfig(_configuration); return true; } private MsqLevelLockData? GetMsqLevelLockInfo() { var (flag, levelsNeeded, requiredLevel, questName) = _questFunctions.GetMsqLevelLockInfo(); if (!flag) { return null; } return new MsqLevelLockData { IsLevelLocked = flag, LevelsNeeded = levelsNeeded, RequiredLevel = requiredLevel, QuestName = questName }; } private bool StartLevelingMode() { if (!_autoDutyIpc.IsConfiguredToRunLevelingMode(_objectTable.LocalPlayer?.Level ?? 0)) { return false; } return _autoDutyIpc.StartLevelingMode(); } private bool StopLevelingMode() { return _autoDutyIpc.Stop(); } private void RegisterMetaIpc() { Register("Questionable.ApiVersion", () => ((int, int))ApiVersion); } private void RegisterMsqPriorityIpc() { Register("Questionable.GetMsqPriorityMode", GetMsqPriorityMode); Register("Questionable.SetMsqPriorityMode", SetMsqPriorityMode); } private int GetMsqPriorityMode() { return (int)_configuration.General.MsqPriority; } private bool SetMsqPriorityMode(int mode) { if (!Enum.IsDefined(typeof(Configuration.EMsqPriorityMode), mode)) { return false; } _configuration.General.MsqPriority = (Configuration.EMsqPriorityMode)mode; _pluginInterface.SavePluginConfig(_configuration); return true; } private void RegisterPriorityQuestIpc() { Register("Questionable.ImportQuestPriority", ImportQuestPriority); Register("Questionable.AddQuestPriority", AddQuestPriority); Register("Questionable.ClearQuestPriority", ClearQuestPriority); Register("Questionable.InsertQuestPriority", InsertQuestPriority); Register("Questionable.ExportQuestPriority", _manualPriorityComponent.EncodeQuestPriority); Register("Questionable.GetPriorityQuests", GetPriorityQuests); Register("Questionable.RemovePriorityQuest", RemovePriorityQuest); Register("Questionable.ReorderPriorityQuest", ReorderPriorityQuest); Register("Questionable.GetAvailablePresets", GetAvailablePresets); Register>("Questionable.GetPresetQuests", GetPresetQuests); Register("Questionable.AddPresetToPriority", AddPresetToPriority); Register("Questionable.IsPresetAvailable", IsPresetAvailable); Register("Questionable.IsQuestInPriority", IsQuestInPriority); Register("Questionable.GetQuestPriorityIndex", GetQuestPriorityIndex); Register("Questionable.HasAvailablePriorityQuests", HasAvailablePriorityQuests); } private bool ImportQuestPriority(string encodedQuestPriority) { List list = ManualPriorityComponent.DecodeQuestPriority(encodedQuestPriority); if (list.Count > 0) { return _questController.ImportQuestPriority(list); } return false; } private bool ClearQuestPriority() { _questController.ClearQuestPriority(); return true; } private bool AddQuestPriority(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { return _questController.AddQuestPriority(elementId); } return false; } private bool InsertQuestPriority(int index, string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { return _questController.InsertQuestPriority(index, elementId); } return false; } private List GetPriorityQuests() { return _questController.ManualPriorityQuests.Select((Quest q) => q.Id.ToString()).ToList(); } private bool RemovePriorityQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { Quest quest = _questController.ManualPriorityQuests.FirstOrDefault((Quest q) => q.Id.Equals(elementId)); if (quest != null) { _questController.ManualPriorityQuests.Remove(quest); _questController.SavePriorityQuests(); return true; } } return false; } private bool ReorderPriorityQuest(string questId, int newIndex) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { Quest quest = _questController.ManualPriorityQuests.FirstOrDefault((Quest q) => q.Id.Equals(elementId)); if (quest != null && newIndex >= 0 && newIndex < _questController.ManualPriorityQuests.Count) { _questController.ManualPriorityQuests.Remove(quest); _questController.ManualPriorityQuests.Insert(newIndex, quest); _questController.SavePriorityQuests(); return true; } } return false; } private List GetAvailablePresets() { return new List { "crystal_tower", "hard_primals" }; } private List GetPresetQuests(string presetName) { List source = ((presetName == "crystal_tower") ? QuestData.CrystalTowerQuests.Cast().ToList() : ((!(presetName == "hard_primals")) ? new List() : QuestData.HardModePrimals.Cast().ToList())); return source.Select((ElementId q) => q.ToString()).ToList(); } private int AddPresetToPriority(string presetName) { List presetQuests = GetPresetQuests(presetName); int num = 0; foreach (string item in presetQuests) { if (ElementId.TryFromString(item, out ElementId elementId) && elementId != null && (_questFunctions.IsReadyToAcceptQuest(elementId) || _questFunctions.IsQuestAccepted(elementId)) && !_questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(elementId)) && _questRegistry.IsKnownQuest(elementId) && _questController.AddQuestPriority(elementId)) { num++; } } return num; } private bool IsPresetAvailable(string presetName) { return GetAvailablePresets().Contains(presetName); } private bool IsQuestInPriority(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(elementId)); } return false; } private int GetQuestPriorityIndex(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { Quest quest = _questController.ManualPriorityQuests.FirstOrDefault((Quest q) => q.Id.Equals(elementId)); if (quest != null) { return _questController.ManualPriorityQuests.IndexOf(quest); } } return -1; } private bool HasAvailablePriorityQuests() { return _questFunctions.GetNextPriorityQuestsThatCanBeAccepted().Any((PriorityQuestInfo x) => x.IsAvailable); } private void RegisterQuestStateIpc() { Register("Questionable.IsRunning", () => _questController.AutomationType != QuestController.EAutomationType.Manual || _questController.IsRunning); Register("Questionable.GetCurrentQuestId", () => _questController.CurrentQuest?.Quest.Id.ToString()); Register("Questionable.GetCurrentStepData", GetStepData); Register("Questionable.GetCurrentTask", GetCurrentTask); Register("Questionable.GetCurrentlyActiveEventQuests", () => (from q in _eventInfoComponent.GetCurrentlyActiveEventQuests() select q.ToString()).ToList()); Register("Questionable.StartQuest", (string questId) => StartQuest(questId, single: false)); Register("Questionable.StartSingleQuest", (string questId) => StartQuest(questId, single: true)); Register("Questionable.IsQuestLocked", IsQuestLocked); Register("Questionable.IsQuestComplete", IsQuestComplete); Register("Questionable.IsReadyToAcceptQuest", IsReadyToAcceptQuest); Register("Questionable.IsQuestAccepted", IsQuestAccepted); Register("Questionable.IsQuestUnobtainable", IsQuestUnobtainable); } private bool StartQuest(string questId, bool single) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.TryGetQuest(elementId, out Quest quest)) { _questController.SetNextQuest(quest); if (single) { _questController.StartSingleQuest("IPCQuestSelection"); } else { _questController.Start("IPCQuestSelection"); } return true; } return false; } private StepData? GetStepData() { QuestController.QuestProgress currentQuest = _questController.CurrentQuest; if (currentQuest == null) { return null; } string text = currentQuest.Quest.Id.ToString(); if (string.IsNullOrEmpty(text)) { return null; } QuestStep questStep = currentQuest.Quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step); if (questStep == null) { return null; } return new StepData { QuestId = text, Sequence = currentQuest.Sequence, Step = currentQuest.Step, InteractionType = questStep.InteractionType.ToString(), Position = questStep.Position, TerritoryId = questStep.TerritoryId }; } private TaskData? GetCurrentTask() { ITask task = _questController.TaskQueue.CurrentTaskExecutor?.CurrentTask; if (task == null) { return null; } int remainingTaskCount = _questController.TaskQueue.RemainingTasks.Count(); string taskName = task.ToString() ?? "Unknown"; return new TaskData { TaskName = taskName, RemainingTaskCount = remainingTaskCount }; } private bool IsQuestLocked(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.TryGetQuest(elementId, out Quest _)) { return _questFunctions.IsQuestLocked(elementId); } return true; } private bool IsQuestComplete(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestComplete(elementId); } return false; } private bool IsReadyToAcceptQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsReadyToAcceptQuest(elementId); } return false; } private bool IsQuestAccepted(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestAccepted(elementId); } return false; } private bool IsQuestUnobtainable(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { return _questFunctions.IsQuestUnobtainable(elementId); } return false; } private void RegisterStopConditionIpc() { Register("Questionable.GetStopConditionsEnabled", GetStopConditionsEnabled); Register("Questionable.SetStopConditionsEnabled", SetStopConditionsEnabled); Register("Questionable.GetStopQuestList", GetStopQuestList); Register("Questionable.AddStopQuest", AddStopQuest); Register("Questionable.RemoveStopQuest", RemoveStopQuest); Register("Questionable.ClearStopQuests", ClearStopQuests); Register("Questionable.GetLevelStopCondition", GetLevelStopCondition); Register("Questionable.SetLevelStopCondition", SetLevelStopCondition); Register("Questionable.GetSequenceStopCondition", GetSequenceStopCondition); Register("Questionable.SetSequenceStopCondition", SetSequenceStopCondition); Register("Questionable.GetQuestSequenceStopCondition", GetQuestSequenceStopCondition); Register("Questionable.SetQuestSequenceStopCondition", SetQuestSequenceStopCondition); Register("Questionable.RemoveQuestSequenceStopCondition", RemoveQuestSequenceStopCondition); Register("Questionable.GetAllQuestSequenceStopConditions", GetAllQuestSequenceStopConditions); Register("Questionable.GetLevelStopMode", GetLevelStopMode); Register("Questionable.SetLevelStopMode", SetLevelStopMode); Register("Questionable.GetSequenceStopMode", GetSequenceStopMode); Register("Questionable.SetSequenceStopMode", SetSequenceStopMode); Register("Questionable.GetQuestStopMode", GetQuestStopMode); Register("Questionable.SetQuestStopMode", SetQuestStopMode); } private bool GetStopConditionsEnabled() { return _configuration.Stop.Enabled; } private bool SetStopConditionsEnabled(bool enabled) { _configuration.Stop.Enabled = enabled; _pluginInterface.SavePluginConfig(_configuration); return true; } private List GetStopQuestList() { return (from c in _configuration.Stop.Conditions.OfType() select c.QuestId.ToString()).ToList(); } private bool AddStopQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId) && !_configuration.Stop.Conditions.OfType().Any((QuestCompleteCondition c) => c.QuestId.Equals(elementId))) { _configuration.Stop.Conditions.Add(new QuestCompleteCondition { QuestId = elementId, Mode = EStopConditionMode.Stop }); _pluginInterface.SavePluginConfig(_configuration); return true; } return false; } private bool RemoveStopQuest(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { QuestCompleteCondition questCompleteCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault((QuestCompleteCondition c) => c.QuestId.Equals(elementId)); if (questCompleteCondition != null) { _configuration.Stop.Conditions.Remove(questCompleteCondition); _pluginInterface.SavePluginConfig(_configuration); return true; } } return false; } private bool ClearStopQuests() { _configuration.Stop.Conditions.RemoveAll((StopCondition c) => c is QuestCompleteCondition); _pluginInterface.SavePluginConfig(_configuration); return true; } private StopConditionData GetLevelStopCondition() { LevelCondition levelCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault(); return new StopConditionData { Enabled = (levelCondition != null), TargetValue = (levelCondition?.TargetLevel ?? 50) }; } private bool SetLevelStopCondition(bool enabled, int targetLevel) { if (targetLevel < 1 || targetLevel > 100) { return false; } LevelCondition levelCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault(); if (!enabled) { if (levelCondition != null) { _configuration.Stop.Conditions.Remove(levelCondition); } } else if (levelCondition != null) { levelCondition.TargetLevel = targetLevel; levelCondition.Mode = EStopConditionMode.Stop; } else { _configuration.Stop.Conditions.Add(new LevelCondition { TargetLevel = targetLevel, Mode = EStopConditionMode.Stop }); } _pluginInterface.SavePluginConfig(_configuration); return true; } private StopConditionData GetSequenceStopCondition() { GlobalSequenceCondition globalSequenceCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault(); return new StopConditionData { Enabled = (globalSequenceCondition != null), TargetValue = (globalSequenceCondition?.TargetSequence ?? 1) }; } private bool SetSequenceStopCondition(bool enabled, int targetSequence) { if (targetSequence < 0 || targetSequence > 255) { return false; } GlobalSequenceCondition globalSequenceCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault(); if (!enabled) { if (globalSequenceCondition != null) { _configuration.Stop.Conditions.Remove(globalSequenceCondition); } } else if (globalSequenceCondition != null) { globalSequenceCondition.TargetSequence = targetSequence; globalSequenceCondition.Mode = EStopConditionMode.Stop; } else { _configuration.Stop.Conditions.Add(new GlobalSequenceCondition { TargetSequence = targetSequence, Mode = EStopConditionMode.Stop }); } _pluginInterface.SavePluginConfig(_configuration); return true; } private int GetQuestSequenceStopCondition(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { QuestCompleteCondition questCompleteCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault((QuestCompleteCondition c) => c.QuestId.Equals(elementId)); if (questCompleteCondition != null) { return questCompleteCondition.Sequence ?? (-1); } } return -1; } private bool SetQuestSequenceStopCondition(string questId, int targetSequence) { if (targetSequence < 0 || targetSequence > 255) { return false; } if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { QuestCompleteCondition questCompleteCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault((QuestCompleteCondition c) => c.QuestId.Equals(elementId)); if (questCompleteCondition != null) { questCompleteCondition.Sequence = targetSequence; } else { _configuration.Stop.Conditions.Add(new QuestCompleteCondition { QuestId = elementId, Sequence = targetSequence, Mode = EStopConditionMode.Stop }); } _pluginInterface.SavePluginConfig(_configuration); return true; } return false; } private bool RemoveQuestSequenceStopCondition(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { QuestCompleteCondition questCompleteCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault((QuestCompleteCondition c) => c.QuestId.Equals(elementId) && c.Sequence.HasValue); if (questCompleteCondition != null) { _configuration.Stop.Conditions.Remove(questCompleteCondition); _pluginInterface.SavePluginConfig(_configuration); return true; } } return false; } private Dictionary GetAllQuestSequenceStopConditions() { return (from c in _configuration.Stop.Conditions.OfType() where c.Sequence.HasValue select c).ToDictionary((QuestCompleteCondition c) => c.QuestId.ToString(), (QuestCompleteCondition c) => c.Sequence.Value); } private int GetLevelStopMode() { return (int)(_configuration.Stop.Conditions.OfType().FirstOrDefault()?.Mode ?? EStopConditionMode.Off); } private bool SetLevelStopMode(int mode) { if (!Enum.IsDefined(typeof(EStopConditionMode), mode)) { return false; } LevelCondition levelCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault(); if (mode == 0) { if (levelCondition != null) { _configuration.Stop.Conditions.Remove(levelCondition); } } else if (levelCondition != null) { levelCondition.Mode = (EStopConditionMode)mode; } else { _configuration.Stop.Conditions.Add(new LevelCondition { TargetLevel = 50, Mode = (EStopConditionMode)mode }); } _pluginInterface.SavePluginConfig(_configuration); return true; } private int GetSequenceStopMode() { return (int)(_configuration.Stop.Conditions.OfType().FirstOrDefault()?.Mode ?? EStopConditionMode.Off); } private bool SetSequenceStopMode(int mode) { if (!Enum.IsDefined(typeof(EStopConditionMode), mode)) { return false; } GlobalSequenceCondition globalSequenceCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault(); if (mode == 0) { if (globalSequenceCondition != null) { _configuration.Stop.Conditions.Remove(globalSequenceCondition); } } else if (globalSequenceCondition != null) { globalSequenceCondition.Mode = (EStopConditionMode)mode; } else { _configuration.Stop.Conditions.Add(new GlobalSequenceCondition { TargetSequence = 1, Mode = (EStopConditionMode)mode }); } _pluginInterface.SavePluginConfig(_configuration); return true; } private int GetQuestStopMode(string questId) { if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null) { QuestCompleteCondition questCompleteCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault((QuestCompleteCondition c) => c.QuestId.Equals(elementId)); if (questCompleteCondition != null) { return (int)questCompleteCondition.Mode; } } return -1; } private bool SetQuestStopMode(string questId, int mode) { if (!Enum.IsDefined(typeof(EStopConditionMode), mode)) { return false; } if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && _questRegistry.IsKnownQuest(elementId)) { QuestCompleteCondition questCompleteCondition = _configuration.Stop.Conditions.OfType().FirstOrDefault((QuestCompleteCondition c) => c.QuestId.Equals(elementId)); if (mode == 0) { if (questCompleteCondition != null) { _configuration.Stop.Conditions.Remove(questCompleteCondition); } } else if (questCompleteCondition != null) { questCompleteCondition.Mode = (EStopConditionMode)mode; } else { _configuration.Stop.Conditions.Add(new QuestCompleteCondition { QuestId = elementId, Mode = (EStopConditionMode)mode }); } _pluginInterface.SavePluginConfig(_configuration); return true; } return false; } }