qstbak/Questionable/Questionable.Controller/QuestPriorityResolver.cs
2026-08-19 13:19:57 +10:00

613 lines
24 KiB
C#

using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using LLib.GameData;
using Microsoft.Extensions.Logging;
using Questionable.Data;
using Questionable.External;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Controller;
internal sealed class QuestPriorityResolver
{
private readonly QuestFunctions _questFunctions;
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly AlliedSocietyData _alliedSocietyData;
private readonly AlliedSocietyQuestFunctions _alliedSocietyQuestFunctions;
private readonly Configuration _configuration;
private readonly IObjectTable _objectTable;
private readonly ICondition _condition;
private readonly IClientState _clientState;
private readonly AutoDutyIpc _autoDutyIpc;
private readonly ILogger<QuestPriorityResolver> _logger;
private readonly HashSet<ushort> _alreadyLoggedUnobtainableQuests = new HashSet<ushort>();
private ElementId? _lastLoggedLevelLockedMsq;
private ElementId? _lastLoggedForcedClassQuest;
private ElementId? _lastLoggedRegistryClassQuest;
private ElementId? _lastLoggedPriorityClassQuest;
private bool _loggedNoClassQuestsAvailable;
private bool _loggedAdventurerClass;
public QuestPriorityResolver(QuestFunctions questFunctions, QuestRegistry questRegistry, QuestData questData, AlliedSocietyData alliedSocietyData, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, Configuration configuration, IObjectTable objectTable, ICondition condition, IClientState clientState, AutoDutyIpc autoDutyIpc, ILogger<QuestPriorityResolver> logger)
{
_questFunctions = questFunctions;
_questRegistry = questRegistry;
_questData = questData;
_alliedSocietyData = alliedSocietyData;
_alliedSocietyQuestFunctions = alliedSocietyQuestFunctions;
_configuration = configuration;
_objectTable = objectTable;
_condition = condition;
_clientState = clientState;
_autoDutyIpc = autoDutyIpc;
_logger = logger;
}
public QuestReference GetCurrentQuest()
{
QuestResolution questResolution = ResolveFromGameState(new List<Quest>(), QuestController.EAutomationType.Automatic);
if (questResolution.HasQuest)
{
return new QuestReference(questResolution.QuestId, questResolution.Sequence, questResolution.MsqState);
}
return QuestReference.NoQuest(questResolution.MsqState);
}
public QuestResolution Resolve(QuestSlots slots)
{
if (slots.Simulated != null)
{
return QuestResolution.Slot(EQuestResolutionType.Simulated, slots.Simulated, "Simulated quest");
}
if (slots.Next != null && !_questFunctions.IsQuestBlacklisted(slots.Next.Quest.Id))
{
return QuestResolution.Slot(EQuestResolutionType.NextQuest, slots.Next, $"Next quest {slots.Next.Quest.Id}");
}
return ResolveFromGameState(slots.ManualPriorityQuests, slots.AutomationType);
}
private QuestResolution ResolveFromGameState(List<Quest> manualPriorityQuests, QuestController.EAutomationType automationType)
{
bool flag = automationType != QuestController.EAutomationType.SingleQuestB;
QuestReference resolvedMsqQuest = GetResolvedMsqQuest();
int num = _objectTable.LocalPlayer?.Level ?? 0;
EClassJob valueOrDefault = ((EClassJob?)_objectTable.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
QuestResolution? questResolution = TryResolveManualPriority(manualPriorityQuests, resolvedMsqQuest.State);
if (questResolution.HasValue)
{
QuestResolution valueOrDefault2 = questResolution.GetValueOrDefault();
return ApplyQuestRedirects(valueOrDefault2);
}
uint territoryType = _clientState.TerritoryType;
bool flag2 = territoryType - 181 <= 2;
if (flag2 && flag && _configuration.General.MsqPriority != Configuration.EMsqPriorityMode.Manual)
{
ElementId currentQuest = resolvedMsqQuest.CurrentQuest;
if ((object)currentQuest != null && currentQuest.Value > 0 && !_questFunctions.IsQuestAccepted(currentQuest))
{
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, currentQuest, resolvedMsqQuest.Sequence, resolvedMsqQuest.State, $"Starting city opening MSQ {currentQuest}");
}
}
questResolution = TryResolveInProgressClassQuest(valueOrDefault, resolvedMsqQuest.State);
if (questResolution.HasValue)
{
return questResolution.GetValueOrDefault();
}
questResolution = TryResolveClassJobPriority(valueOrDefault, resolvedMsqQuest.State);
if (questResolution.HasValue)
{
return questResolution.GetValueOrDefault();
}
if (resolvedMsqQuest.CurrentQuest != null && IsMsqLevelLocked(resolvedMsqQuest, num, automationType))
{
if (_lastLoggedLevelLockedMsq != resolvedMsqQuest.CurrentQuest)
{
_logger.LogInformation("MSQ {MsqId} requires higher level, current level {CurrentLevel}. Checking for early class quests.", resolvedMsqQuest.CurrentQuest, num);
_lastLoggedLevelLockedMsq = resolvedMsqQuest.CurrentQuest;
_loggedNoClassQuestsAvailable = false;
_loggedAdventurerClass = false;
}
return TryResolveNewClassQuest(valueOrDefault, num, resolvedMsqQuest.State) ?? TryResolveLevelingMode(num, automationType, resolvedMsqQuest.State) ?? QuestResolution.None(MainScenarioQuestState.Unavailable, "MSQ level-locked, no class quests or leveling available");
}
_lastLoggedLevelLockedMsq = null;
_lastLoggedForcedClassQuest = null;
_lastLoggedRegistryClassQuest = null;
_lastLoggedPriorityClassQuest = null;
_loggedNoClassQuestsAvailable = false;
_loggedAdventurerClass = false;
questResolution = TryResolveMsqImmediate(resolvedMsqQuest, flag);
if (questResolution.HasValue)
{
return questResolution.GetValueOrDefault();
}
questResolution = TryResolveTrackedQuest(resolvedMsqQuest.State);
if (questResolution.HasValue)
{
QuestResolution valueOrDefault3 = questResolution.GetValueOrDefault();
return ApplyQuestRedirects(valueOrDefault3);
}
questResolution = TryResolveAutoPriority(resolvedMsqQuest.State);
if (questResolution.HasValue)
{
QuestResolution valueOrDefault4 = questResolution.GetValueOrDefault();
return ApplyQuestRedirects(valueOrDefault4);
}
questResolution = TryResolveMsqFallback(resolvedMsqQuest, flag);
if (questResolution.HasValue)
{
return questResolution.GetValueOrDefault();
}
if (resolvedMsqQuest.CurrentQuest == null || resolvedMsqQuest.CurrentQuest.Value == 0)
{
questResolution = TryResolveStartingCity(resolvedMsqQuest.State);
if (questResolution.HasValue)
{
return questResolution.GetValueOrDefault();
}
}
return QuestResolution.None(resolvedMsqQuest.State, "No quest available");
}
private QuestReference GetResolvedMsqQuest()
{
QuestReference questReference = _questFunctions.GetMainScenarioQuest().Item1;
if (questReference.CurrentQuest != null && !_questRegistry.IsKnownQuest(questReference.CurrentQuest))
{
if (questReference.CurrentQuest is QuestId questId && _alreadyLoggedUnobtainableQuests.Add(questId.Value))
{
_logger.LogWarning("MSQ {MsqQuestId} is not in the quest registry", questReference.CurrentQuest);
}
questReference = QuestReference.NoQuest(questReference.State);
}
return ApplyMsqSpecialCases(questReference);
}
private QuestReference ApplyMsqSpecialCases(QuestReference msqQuest)
{
var (elementId2, sequence, state) = msqQuest;
if (elementId2 == null || elementId2.Value == 0)
{
return msqQuest;
}
if (elementId2.Value == 681)
{
if (_questFunctions.IsQuestAccepted(elementId2) || _questFunctions.IsQuestComplete(elementId2))
{
return new QuestReference(elementId2, sequence, state);
}
GrandCompany grandCompany = _configuration.General.GrandCompany;
if (grandCompany == GrandCompany.None)
{
grandCompany = PlayerStateHelper.GetStartTown() switch
{
1 => GrandCompany.Maelstrom,
2 => GrandCompany.TwinAdder,
3 => GrandCompany.ImmortalFlames,
_ => GrandCompany.None,
};
}
return grandCompany switch
{
GrandCompany.TwinAdder => new QuestReference(new QuestId(680), 0, state),
GrandCompany.Maelstrom => new QuestReference(new QuestId(681), 0, state),
GrandCompany.ImmortalFlames => new QuestReference(new QuestId(682), 0, state),
_ => QuestReference.NoQuest(MainScenarioQuestState.Unavailable),
};
}
if (elementId2.Value == 3856 && !PlayerStateHelper.IsMountUnlocked(1u))
{
ushort num = (GrandCompany)GrandCompanyHelper.GetGrandCompanyId() switch
{
GrandCompany.TwinAdder => 700,
GrandCompany.Maelstrom => 701,
GrandCompany.ImmortalFlames => 702,
_ => 0,
};
if (num != 0 && !QuestManager.IsQuestComplete(num))
{
return new QuestReference(new QuestId(num), QuestManager.GetQuestSequence(num), state);
}
}
if (elementId2.Value == 801)
{
QuestId questId = new QuestId(802);
if (_questFunctions.IsQuestAccepted(questId))
{
return new QuestReference(questId, QuestManager.GetQuestSequence(questId.Value), state);
}
}
return msqQuest;
}
private QuestResolution ApplyQuestRedirects(QuestResolution resolution)
{
ElementId questId = resolution.QuestId;
if ((object)questId != null && questId.Value == 801)
{
QuestId questId2 = new QuestId(802);
if (_questFunctions.IsQuestAccepted(questId2))
{
return resolution with
{
QuestId = questId2,
Sequence = QuestManager.GetQuestSequence(questId2.Value),
DebugReason = "Redirected 801 -> 802 (Broadening Horizons prerequisite)"
};
}
}
return resolution;
}
private QuestResolution? TryResolveManualPriority(List<Quest> manualPriorityQuests, MainScenarioQuestState msqState)
{
if (manualPriorityQuests.Count == 0)
{
return null;
}
(ElementId, byte) tuple = (from x in manualPriorityQuests.Where(delegate(Quest x)
{
if (_questFunctions.IsQuestBlacklisted(x.Id))
{
return false;
}
return _questFunctions.IsQuestAccepted(x.Id) ? ((!_configuration.Advanced.AutoPrioritizeAlliedSocietyRankUp || !(x.Id is QuestId questId) || !_questFunctions.WouldOvercapAlliedSocietyReputation(questId)) ? true : false) : _questFunctions.IsReadyToAcceptQuest(x.Id);
})
select (QuestId: x.Id, Sequence: _questFunctions.GetQuestProgressInfo(x.Id)?.Sequence ?? 0)).FirstOrDefault();
if ((object)tuple.Item1 != null)
{
return QuestResolution.ForQuest(EQuestResolutionType.ManualPriority, tuple.Item1, tuple.Item2, msqState, $"Manual priority quest {tuple.Item1}");
}
return null;
}
private QuestResolution? TryResolveInProgressClassQuest(EClassJob currentClassJob, MainScenarioQuestState msqState)
{
if (_configuration.Advanced.SkipClassJobQuests || currentClassJob == EClassJob.Adventurer)
{
return null;
}
QuestInfo questInfo = (from x in _questData.GetClassJobQuests(currentClassJob)
where !_questFunctions.IsQuestBlacklisted(x.QuestId) && _questFunctions.IsQuestAccepted(x.QuestId) && !_questFunctions.IsQuestComplete(x.QuestId)
orderby x.Level
select x).FirstOrDefault();
if (questInfo == null)
{
return null;
}
_logger.LogTrace("Found in-progress class quest {QuestId}, continuing it", questInfo.QuestId);
return QuestResolution.ForQuest(EQuestResolutionType.InProgressClassQuest, questInfo.QuestId, QuestManager.GetQuestSequence(questInfo.QuestId.Value), msqState, $"In-progress class quest {questInfo.QuestId}");
}
private QuestResolution? TryResolveClassJobPriority(EClassJob currentClassJob, MainScenarioQuestState msqState)
{
if (_configuration.Advanced.SkipClassJobQuests || currentClassJob == EClassJob.Adventurer)
{
return null;
}
HashSet<ElementId> classJobQuestIds = (from x in _questRegistry.GetKnownClassJobQuests(currentClassJob, includeRoleQuests: false)
select x.QuestId).ToHashSet();
ElementId elementId = (from x in _questFunctions.GetNextPriorityQuestsThatCanBeAccepted()
where x.IsAvailable && classJobQuestIds.Contains(x.QuestId)
select x.QuestId).FirstOrDefault();
if (elementId == null)
{
return null;
}
return QuestResolution.ForQuest(EQuestResolutionType.NewClassQuest, elementId, QuestManager.GetQuestSequence(elementId.Value), msqState, $"Class/job priority quest {elementId}");
}
private bool IsMsqLevelLocked(QuestReference msqQuest, int currentLevel, QuestController.EAutomationType automationType)
{
if (msqQuest.CurrentQuest == null)
{
return false;
}
if (!_questRegistry.TryGetQuest(msqQuest.CurrentQuest, out Quest quest))
{
return false;
}
if (_questFunctions.IsQuestAccepted(msqQuest.CurrentQuest))
{
return false;
}
if (_configuration.General.MsqPriority == Configuration.EMsqPriorityMode.Manual)
{
return false;
}
return quest.Info.Level > currentLevel;
}
private QuestResolution? TryResolveNewClassQuest(EClassJob currentClassJob, int currentLevel, MainScenarioQuestState msqState)
{
if (currentClassJob == EClassJob.Adventurer)
{
if (!_loggedAdventurerClass)
{
_logger.LogWarning("Current class is Adventurer, cannot find class quests");
_loggedAdventurerClass = true;
}
return null;
}
List<QuestId> lockedQuests = QuestData.GetLockedClassQuests();
QuestInfo questInfo = (from x in _questData.GetClassJobQuests(currentClassJob)
where x.Level <= currentLevel && x.Level <= 5 && !_questFunctions.IsQuestComplete(x.QuestId) && !lockedQuests.Contains(x.QuestId)
orderby x.Level
select x).FirstOrDefault();
if (questInfo != null && !_questFunctions.IsQuestComplete(questInfo.QuestId))
{
if (_lastLoggedForcedClassQuest != questInfo.QuestId)
{
_logger.LogInformation("MSQ level locked. Forcing class quest {ClassQuestId} for {ClassJob} (level {QuestLevel})", questInfo.QuestId, currentClassJob, questInfo.Level);
_lastLoggedForcedClassQuest = questInfo.QuestId;
}
return QuestResolution.ForQuest(EQuestResolutionType.NewClassQuest, questInfo.QuestId, QuestManager.GetQuestSequence(questInfo.QuestId.Value), msqState, $"New class quest (data) {questInfo.QuestId}");
}
QuestInfo questInfo2 = (from x in _questRegistry.GetKnownClassJobQuests(currentClassJob, includeRoleQuests: false)
where x.Level <= currentLevel && x.Level <= 5 && !_questFunctions.IsQuestAcceptedOrComplete(x.QuestId) && _questFunctions.IsReadyToAcceptQuest(x.QuestId)
orderby x.Level
select x).FirstOrDefault();
if (questInfo2 != null)
{
if (_lastLoggedRegistryClassQuest != questInfo2.QuestId)
{
_logger.LogInformation("MSQ level locked. Prioritizing class quest {ClassQuestId} for {ClassJob} (level {QuestLevel}) from registry", questInfo2.QuestId, currentClassJob, questInfo2.Level);
_lastLoggedRegistryClassQuest = questInfo2.QuestId;
}
return QuestResolution.ForQuest(EQuestResolutionType.NewClassQuest, questInfo2.QuestId, QuestManager.GetQuestSequence(questInfo2.QuestId.Value), msqState, $"New class quest (registry) {questInfo2.QuestId}");
}
Quest quest;
ElementId elementId = (from x in _questFunctions.GetNextPriorityQuestsThatCanBeAccepted()
where x.IsAvailable
where _questRegistry.TryGetQuest(x.QuestId, out quest) && quest.Info.Level <= currentLevel && quest.Info is QuestInfo questInfo3 && questInfo3.ClassJobs.Count > 0 && questInfo3.ClassJobs.Any((EClassJob job) => !job.IsCrafter() && !job.IsGatherer())
select x.QuestId).FirstOrDefault();
if (elementId != null)
{
if (_lastLoggedPriorityClassQuest != elementId)
{
_logger.LogInformation("MSQ level locked. Prioritizing class quest {ClassQuestId} from priority list", elementId);
_lastLoggedPriorityClassQuest = elementId;
}
return QuestResolution.ForQuest(EQuestResolutionType.NewClassQuest, elementId, QuestManager.GetQuestSequence(elementId.Value), msqState, $"New class quest (priority) {elementId}");
}
if (!_loggedNoClassQuestsAvailable)
{
_logger.LogWarning("MSQ level locked but no available early class quests found for {ClassJob} at level {CurrentLevel}", currentClassJob, currentLevel);
_loggedNoClassQuestsAvailable = true;
}
return null;
}
private QuestResolution? TryResolveMsqImmediate(QuestReference msqQuest, bool allowNewMsq)
{
if (msqQuest.CurrentQuest == null || msqQuest.CurrentQuest.Value == 0)
{
return null;
}
if (_questFunctions.IsQuestAccepted(msqQuest.CurrentQuest))
{
return null;
}
if (_configuration.General.MsqPriority != Configuration.EMsqPriorityMode.Always)
{
return null;
}
if (!allowNewMsq)
{
return null;
}
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, msqQuest.CurrentQuest, msqQuest.Sequence, msqQuest.State, $"MSQ immediate (Always mode) {msqQuest.CurrentQuest}");
}
private unsafe QuestResolution? TryResolveTrackedQuest(MainScenarioQuestState msqState)
{
QuestManager* ptr = QuestManager.Instance();
if (ptr == null)
{
return null;
}
List<(ElementId, byte)> list = new List<(ElementId, byte)>();
for (int num = ptr->TrackedQuests.Length - 1; num >= 0; num--)
{
TrackingWork trackingWork = ptr->TrackedQuests[num];
switch (trackingWork.QuestType)
{
case 1:
{
QuestWork questWork = ptr->NormalQuests[trackingWork.Index];
if (!questWork.IsHidden)
{
ElementId elementId = new QuestId(questWork.QuestId);
if (_questRegistry.IsKnownQuest(elementId) && !_questFunctions.IsQuestBlacklisted(elementId))
{
list.Add((elementId, QuestManager.GetQuestSequence(elementId.Value)));
}
}
break;
}
}
}
if (_configuration.General.SkipLowPriorityDuties && list.Count > 0)
{
IReadOnlyList<(uint ContentFinderConditionId, ElementId QuestId, int Sequence)> lowPriorityQuests = _questRegistry.LowPriorityContentFinderConditionQuests;
list.RemoveAll(((ElementId Quest, byte Sequence) x) => lowPriorityQuests.Any<(uint, ElementId, int)>(((uint ContentFinderConditionId, ElementId QuestId, int Sequence) y) => x.Quest == y.QuestId && x.Sequence == y.Sequence));
}
if (_configuration.Advanced.AutoPrioritizeAlliedSocietyRankUp && list.Count > 0)
{
list.RemoveAll(((ElementId Quest, byte Sequence) x) => x.Quest is QuestId questId2 && _questFunctions.WouldOvercapAlliedSocietyReputation(questId2));
}
if (list.Count == 0)
{
return null;
}
(ElementId, byte) tuple = list.First();
ElementId item = tuple.Item1;
byte item2 = tuple.Item2;
EAlliedSociety firstTrackedAlliedSociety = _alliedSocietyData.GetCommonAlliedSocietyTurnIn(item);
if (firstTrackedAlliedSociety != EAlliedSociety.None)
{
List<(ElementId, byte)> list2 = (from quest in list.Skip(1)
where _alliedSocietyData.GetCommonAlliedSocietyTurnIn(quest.Quest) == firstTrackedAlliedSociety
select quest).ToList();
if (list2.Count > 0)
{
if (item2 == byte.MaxValue)
{
foreach (var (elementId2, b) in list2)
{
if (b != byte.MaxValue)
{
return QuestResolution.ForQuest(EQuestResolutionType.TrackedQuest, elementId2, b, msqState, $"Allied society quest needs completing before turn-in {elementId2}");
}
}
if (_configuration.Advanced.AutoPrioritizeAlliedSocietyRankUp)
{
List<(ElementId, byte)> list3 = new List<(ElementId, byte)> { (item, item2) };
list3.AddRange(list2);
list3.Sort(delegate((ElementId Quest, byte Sequence) a, (ElementId Quest, byte Sequence) tuple5)
{
ushort num2 = (ushort)((a.Quest is QuestId questId2) ? _alliedSocietyQuestFunctions.GetQuestReputationReward(questId2) : 0);
ushort value = (ushort)((tuple5.Quest is QuestId questId3) ? _alliedSocietyQuestFunctions.GetQuestReputationReward(questId3) : 0);
return num2.CompareTo(value);
});
foreach (var (elementId3, sequence) in list3)
{
if (elementId3 is QuestId questId && !_alliedSocietyQuestFunctions.WouldOvercapReputation(questId))
{
return QuestResolution.ForQuest(EQuestResolutionType.TrackedQuest, elementId3, sequence, msqState, $"Allied society turn-in (cheapest first) {elementId3}");
}
}
QuestId rankUpQuestIfAtCapacity = _questFunctions.GetRankUpQuestIfAtCapacity(firstTrackedAlliedSociety);
if (rankUpQuestIfAtCapacity != null && !_questFunctions.IsQuestComplete(rankUpQuestIfAtCapacity) && (_questFunctions.IsQuestAccepted(rankUpQuestIfAtCapacity) || _questFunctions.IsReadyToAcceptQuest(rankUpQuestIfAtCapacity)))
{
return QuestResolution.ForQuest(EQuestResolutionType.TrackedQuest, rankUpQuestIfAtCapacity, (byte)(_questFunctions.IsQuestAccepted(rankUpQuestIfAtCapacity) ? QuestManager.GetQuestSequence(rankUpQuestIfAtCapacity.Value) : 0), msqState, $"Allied society rank-up quest {rankUpQuestIfAtCapacity}");
}
return QuestResolution.ForQuest(EQuestResolutionType.TrackedQuest, list3[0].Item1, list3[0].Item2, msqState, $"Allied society turn-in (all would overcap) {list3[0].Item1}");
}
}
else if (!_questFunctions.IsOnAlliedSocietyMount())
{
list2.Insert(0, (item, item2));
_alliedSocietyData.GetCommonAlliedSocietyNpcs(firstTrackedAlliedSociety, out uint[] normalNpcs, out uint[] _);
if (normalNpcs.Length != 0)
{
(ElementId, byte)? tuple4 = (from x in list2
where x.Sequence < byte.MaxValue
where _questFunctions.IsInteractSequence(x.Quest, x.Sequence, normalNpcs)
select x).Cast<(ElementId, byte)?>().FirstOrDefault();
if (tuple4.HasValue)
{
return QuestResolution.ForQuest(EQuestResolutionType.TrackedQuest, tuple4.Value.Item1, tuple4.Value.Item2, msqState, $"Allied society NPC interaction {tuple4.Value.Item1}");
}
}
}
}
}
return QuestResolution.ForQuest(EQuestResolutionType.TrackedQuest, item, item2, msqState, $"Tracked quest {item}");
}
private QuestResolution? TryResolveAutoPriority(MainScenarioQuestState msqState)
{
ElementId elementId = (from x in _questFunctions.GetNextPriorityQuestsThatCanBeAccepted()
where x.IsAvailable
select x.QuestId).FirstOrDefault();
if (elementId == null)
{
return null;
}
return QuestResolution.ForQuest(EQuestResolutionType.AutoPriority, elementId, QuestManager.GetQuestSequence(elementId.Value), msqState, $"Auto priority quest {elementId}");
}
private QuestResolution? TryResolveMsqFallback(QuestReference msqQuest, bool allowNewMsq)
{
if (msqQuest.CurrentQuest == null || msqQuest.CurrentQuest.Value == 0)
{
return null;
}
if (_questFunctions.IsQuestAccepted(msqQuest.CurrentQuest))
{
return null;
}
if (_configuration.General.MsqPriority == Configuration.EMsqPriorityMode.Manual)
{
return null;
}
if (!allowNewMsq)
{
return null;
}
return QuestResolution.ForQuest(EQuestResolutionType.MsqFallback, msqQuest.CurrentQuest, msqQuest.Sequence, msqQuest.State, $"MSQ fallback {msqQuest.CurrentQuest}");
}
private QuestResolution? TryResolveStartingCity(MainScenarioQuestState msqState)
{
if (_clientState.TerritoryType == 181)
{
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, new QuestId(107), 0, MainScenarioQuestState.Available, "Starting city: Limsa Lominsa");
}
if (_clientState.TerritoryType == 182)
{
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, new QuestId(594), 0, MainScenarioQuestState.Available, "Starting city: Ul'dah");
}
if (_clientState.TerritoryType == 183)
{
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, new QuestId(39), 0, MainScenarioQuestState.Available, "Starting city: Gridania");
}
return null;
}
private QuestResolution? TryResolveLevelingMode(int currentPlayerLevel, QuestController.EAutomationType automationType, MainScenarioQuestState msqState)
{
if (!ShouldStartLevelingMode(currentPlayerLevel, automationType))
{
return null;
}
var (flag, _, targetLevel, questName) = _questFunctions.GetMsqLevelLockInfo();
if (!flag)
{
return null;
}
return QuestResolution.Leveling(targetLevel, questName, msqState);
}
public bool ShouldStartLevelingMode(int currentPlayerLevel, QuestController.EAutomationType automationType)
{
if (automationType != QuestController.EAutomationType.Automatic)
{
return false;
}
if (_condition[ConditionFlag.BoundByDuty] || _condition[ConditionFlag.InDutyQueue])
{
return false;
}
if (!_autoDutyIpc.IsConfiguredToRunLevelingMode(currentPlayerLevel))
{
return false;
}
return true;
}
}