1
0
Fork 0
forked from aly/qstbak

muffin v6.35

This commit is contained in:
alydev 2025-10-29 06:43:45 +10:00
parent a10041e3fd
commit ac85599236
7 changed files with 5916 additions and 5158 deletions

View file

@ -56,6 +56,14 @@ internal sealed class QuestFunctions
private readonly HashSet<ushort> _alreadyLoggedLevelRequirements = new HashSet<ushort>();
private ElementId? _lastLoggedLevelLockedMsq;
private ElementId? _lastLoggedForcedClassQuest;
private bool _lastLoggedFallbackLookup;
private ElementId? _lastLoggedNotReadyQuest;
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, AetheryteData aetheryteData, Configuration configuration, IDataManager dataManager, IClientState clientState, IGameGui gameGui, IAetheryteList aetheryteList, ILogger<QuestFunctions> logger)
{
_questRegistry = questRegistry;
@ -145,8 +153,99 @@ internal sealed class QuestFunctions
QuestReference questReference = GetMainScenarioQuest().Item1;
if (questReference.CurrentQuest != null && !_questRegistry.IsKnownQuest(questReference.CurrentQuest))
{
_logger.LogWarning("MSQ {MsqQuestId} is not in the quest registry, resetting to NoQuest", questReference.CurrentQuest);
questReference = QuestReference.NoQuest(questReference.State);
}
byte currentLevel = _clientState.LocalPlayer?.Level ?? 0;
if (questReference.CurrentQuest != null)
{
Questionable.Model.Quest quest;
bool flag = _questRegistry.TryGetQuest(questReference.CurrentQuest, out quest);
bool flag2 = IsQuestAccepted(questReference.CurrentQuest);
_logger.LogTrace("MSQ check: QuestId={QuestId}, InRegistry={InRegistry}, Level={QuestLevel}, CurrentLevel={CurrentLevel}, IsAccepted={IsAccepted}", questReference.CurrentQuest, flag, ((int?)quest?.Info.Level) ?? (-1), currentLevel, flag2);
EClassJob valueOrDefault = ((EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
if (valueOrDefault != EClassJob.Adventurer)
{
QuestInfo questInfo = (from x in _questData.GetClassJobQuests(valueOrDefault)
where x.Level <= 5 && IsQuestAccepted(x.QuestId) && !IsQuestComplete(x.QuestId)
orderby x.Level
select x).FirstOrDefault();
if (questInfo != null)
{
_logger.LogTrace("Found in-progress class quest {QuestId}, continuing it", questInfo.QuestId);
return new QuestReference(questInfo.QuestId, QuestManager.GetQuestSequence(questInfo.QuestId.Value), questReference.State);
}
}
if (flag && quest.Info.Level > currentLevel && !flag2)
{
if (_lastLoggedLevelLockedMsq != questReference.CurrentQuest)
{
_logger.LogInformation("MSQ {MsqId} requires level {RequiredLevel}, current level {CurrentLevel}. Checking for early class quests to level up.", questReference.CurrentQuest, quest.Info.Level, currentLevel);
_lastLoggedLevelLockedMsq = questReference.CurrentQuest;
}
if (valueOrDefault != EClassJob.Adventurer)
{
List<QuestInfo> classJobQuests = _questData.GetClassJobQuests(valueOrDefault);
List<QuestId> lockedQuests = _questData.GetLockedClassQuests();
List<QuestInfo> list = (from x in classJobQuests.Where(delegate(QuestInfo x)
{
bool num2 = x.Level <= currentLevel && x.Level <= 5;
bool flag3 = !IsQuestComplete(x.QuestId);
bool flag4 = !lockedQuests.Contains(x.QuestId);
return num2 && flag3 && flag4;
})
orderby x.Level
select x).ToList();
if (list.Count > 0)
{
ElementId questId = list.First().QuestId;
if (!IsQuestComplete(questId))
{
if (_lastLoggedForcedClassQuest != questId)
{
_logger.LogInformation("MSQ level locked. Forcing class quest {ClassQuestId} for {ClassJob} (level {QuestLevel})", questId, valueOrDefault, list.First().Level);
_lastLoggedForcedClassQuest = questId;
}
return new QuestReference(questId, QuestManager.GetQuestSequence(questId.Value), questReference.State);
}
}
else if (_lastLoggedLevelLockedMsq == questReference.CurrentQuest && _lastLoggedForcedClassQuest == null)
{
_logger.LogWarning("No class quests passed the filter for {ClassJob} at level {CurrentLevel}", valueOrDefault, currentLevel);
_lastLoggedLevelLockedMsq = null;
}
List<QuestInfo> list2 = (from x in _questRegistry.GetKnownClassJobQuests(valueOrDefault, includeRoleQuests: false)
where x.Level <= currentLevel && x.Level <= 5 && !IsQuestAcceptedOrComplete(x.QuestId) && IsReadyToAcceptQuest(x.QuestId)
orderby x.Level
select x).ToList();
if (list2.Count > 0)
{
ElementId questId2 = list2.First().QuestId;
_logger.LogInformation("MSQ level locked. Prioritizing class quest {ClassQuestId} for {ClassJob} (level {QuestLevel}) from registry", questId2, valueOrDefault, list2.First().Level);
return new QuestReference(questId2, QuestManager.GetQuestSequence(questId2.Value), questReference.State);
}
_logger.LogWarning("MSQ level locked but no available early class quests found for {ClassJob} at level {CurrentLevel}", valueOrDefault, currentLevel);
}
else
{
_logger.LogWarning("Current class is Adventurer, cannot find class quests");
}
Questionable.Model.Quest quest2;
ElementId elementId = (from x in GetNextPriorityQuestsThatCanBeAccepted()
where x.IsAvailable
where _questRegistry.TryGetQuest(x.QuestId, out quest2) && quest2.Info.Level <= currentLevel && quest2.Info.Level <= 5 && quest2.Info is QuestInfo questInfo2 && questInfo2.ClassJobs.Count > 0 && questInfo2.ClassJobs.Any((EClassJob job) => !job.IsCrafter() && !job.IsGatherer())
select x.QuestId).FirstOrDefault();
if (elementId != null)
{
_logger.LogInformation("MSQ {MsqId} requires level {RequiredLevel}, current level {CurrentLevel}. Prioritizing early class quest {ClassQuestId} (from priority list)", questReference.CurrentQuest, quest.Info.Level, currentLevel, elementId);
return new QuestReference(elementId, QuestManager.GetQuestSequence(elementId.Value), questReference.State);
}
_logger.LogWarning("MSQ {MsqId} is level locked (requires {RequiredLevel}, current {CurrentLevel}) and no early class quests available. Cannot proceed.", questReference.CurrentQuest, quest.Info.Level, currentLevel);
return QuestReference.NoQuest(MainScenarioQuestState.Unavailable);
}
_lastLoggedLevelLockedMsq = null;
_lastLoggedForcedClassQuest = null;
}
if (questReference.CurrentQuest != null && !IsQuestAccepted(questReference.CurrentQuest))
{
if (allowNewMsq)
@ -155,7 +254,7 @@ internal sealed class QuestFunctions
}
questReference = QuestReference.NoQuest(questReference.State);
}
List<(ElementId, byte)> list = new List<(ElementId, byte)>();
List<(ElementId, byte)> list3 = new List<(ElementId, byte)>();
for (int num = ptr->TrackedQuests.Length - 1; num >= 0; num--)
{
TrackingWork trackingWork = ptr->TrackedQuests[num];
@ -163,36 +262,36 @@ internal sealed class QuestFunctions
{
case 1:
{
ElementId elementId = new QuestId(ptr->NormalQuests[trackingWork.Index].QuestId);
if (_questRegistry.IsKnownQuest(elementId))
ElementId elementId2 = new QuestId(ptr->NormalQuests[trackingWork.Index].QuestId);
if (_questRegistry.IsKnownQuest(elementId2))
{
list.Add((elementId, QuestManager.GetQuestSequence(elementId.Value)));
list3.Add((elementId2, QuestManager.GetQuestSequence(elementId2.Value)));
}
break;
}
}
}
if (_configuration.General.SkipLowPriorityDuties && list.Count > 0)
if (_configuration.General.SkipLowPriorityDuties && list3.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));
list3.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 (list.Count > 0)
if (list3.Count > 0)
{
(ElementId, byte) tuple = list.First();
(ElementId, byte) tuple = list3.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)
List<(ElementId, byte)> list4 = (from tuple4 in list3.Skip(1)
where _alliedSocietyData.GetCommonAlliedSocietyTurnIn(tuple4.Quest) == firstTrackedAlliedSociety
select tuple4).ToList();
if (list4.Count > 0)
{
if (item2 == byte.MaxValue)
{
foreach (var (currentQuest, b) in list2)
foreach (var (currentQuest, b) in list4)
{
if (b != byte.MaxValue)
{
@ -202,11 +301,11 @@ internal sealed class QuestFunctions
}
else if (!IsOnAlliedSocietyMount())
{
list2.Insert(0, (item, item2));
list4.Insert(0, (item, item2));
_alliedSocietyData.GetCommonAlliedSocietyNpcs(firstTrackedAlliedSociety, out uint[] normalNpcs, out uint[] _);
if (normalNpcs.Length != 0)
{
(ElementId, byte)? tuple3 = (from x in list2
(ElementId, byte)? tuple3 = (from x in list4
where x.Sequence < byte.MaxValue
where IsInteractSequence(x.Quest, x.Sequence, normalNpcs)
select x).Cast<(ElementId, byte)?>().FirstOrDefault();
@ -220,12 +319,12 @@ internal sealed class QuestFunctions
}
return new QuestReference(item, item2, questReference.State);
}
ElementId elementId2 = (from x in GetNextPriorityQuestsThatCanBeAccepted()
ElementId elementId3 = (from x in GetNextPriorityQuestsThatCanBeAccepted()
where x.IsAvailable
select x.QuestId).FirstOrDefault();
if (elementId2 != null)
if (elementId3 != null)
{
return new QuestReference(elementId2, QuestManager.GetQuestSequence(elementId2.Value), questReference.State);
return new QuestReference(elementId3, QuestManager.GetQuestSequence(elementId3.Value), questReference.State);
}
if (questReference.CurrentQuest != null)
{
@ -259,10 +358,12 @@ internal sealed class QuestFunctions
AgentScenarioTree* ptr = AgentScenarioTree.Instance();
if (ptr == null)
{
_logger.LogTrace("GetMainScenarioQuest: scenarioTree is null");
return (QuestReference.NoQuest(MainScenarioQuestState.Unavailable), "No Scenario Tree");
}
if (ptr->Data == null)
{
_logger.LogTrace("GetMainScenarioQuest: scenarioTree->Data is null");
return (QuestReference.NoQuest(MainScenarioQuestState.LoadingScreen), "Scenario Tree Data is null");
}
QuestId questId = new QuestId(ptr->Data->CurrentScenarioQuest);
@ -273,11 +374,20 @@ internal sealed class QuestFunctions
{
return (QuestReference.NoQuest(MainScenarioQuestState.Complete), "Main Scenario is complete");
}
if (!_lastLoggedFallbackLookup)
{
_logger.LogInformation("GetMainScenarioQuest: MSQ from scenario tree is 0, using fallback lookup");
_lastLoggedFallbackLookup = true;
}
PlayerState* playerState = PlayerState.Instance();
List<QuestInfo> list = (from q in _questData.MainScenarioQuests
where q.StartingCity == 0 || q.StartingCity == playerState->StartTown
where IsReadyToAcceptQuest(q.QuestId, ignoreLevel: true)
select q).ToList();
if (!_lastLoggedFallbackLookup || list.Count > 0)
{
_logger.LogTrace("GetMainScenarioQuest: Found {Count} potential quests from fallback", list.Count);
}
if (list.Count == 0)
{
return (QuestReference.NoQuest(MainScenarioQuestState.Unavailable), "No potential quests found");
@ -314,6 +424,7 @@ internal sealed class QuestFunctions
}
if (list.Count != 1)
{
_logger.LogWarning("GetMainScenarioQuest: Multiple potential quests found: {Quests}", string.Join(", ", list.Select((QuestInfo x) => x.QuestId.Value)));
return (QuestReference.NoQuest(MainScenarioQuestState.Unavailable), "Multiple potential quests found: " + string.Join(", ", list.Select((QuestInfo x) => x.QuestId.Value)));
}
}
@ -321,29 +432,35 @@ internal sealed class QuestFunctions
{
questId = (QuestId)list.Single().QuestId;
}
_logger.LogInformation("GetMainScenarioQuest: Selected quest from fallback = {QuestId}", questId);
_lastLoggedFallbackLookup = false;
}
QuestManager* ptr2 = QuestManager.Instance();
if (IsQuestAccepted(questId) && ptr2->GetQuestById(questId.Value)->IsHidden)
{
_logger.LogInformation("GetMainScenarioQuest: Quest {QuestId} is accepted but hidden", questId);
return (QuestReference.NoQuest(MainScenarioQuestState.Available), "Quest accepted but hidden");
}
if (IsQuestComplete(questId))
{
_logger.LogInformation("GetMainScenarioQuest: Quest {QuestId} is already complete", questId);
return (new QuestReference(questId, byte.MaxValue, MainScenarioQuestState.Available), $"Quest {questId.Value} complete");
}
if (!IsReadyToAcceptQuest(questId))
if (!IsReadyToAcceptQuest(questId, ignoreLevel: true))
{
if (_lastLoggedNotReadyQuest != questId)
{
_logger.LogInformation("GetMainScenarioQuest: Quest {QuestId} is not ready to accept (ignoring level)", questId);
_lastLoggedNotReadyQuest = questId;
}
return (QuestReference.NoQuest(MainScenarioQuestState.Unavailable), $"Not readdy to accept quest {questId.Value}");
}
byte? b = _clientState.LocalPlayer?.Level;
if (!b.HasValue)
_lastLoggedNotReadyQuest = null;
if (!(_clientState.LocalPlayer?.Level).HasValue)
{
_logger.LogTrace("GetMainScenarioQuest: In loading screen");
return (QuestReference.NoQuest(MainScenarioQuestState.LoadingScreen), "In loading screen");
}
if (_questRegistry.TryGetQuest(questId, out Questionable.Model.Quest quest) && quest.Info.Level > b)
{
return (QuestReference.NoQuest(MainScenarioQuestState.Unavailable), "Low level");
}
return (new QuestReference(questId, QuestManager.GetQuestSequence(questId.Value), MainScenarioQuestState.Available), item);
}
@ -413,7 +530,7 @@ internal sealed class QuestFunctions
{
return new PriorityQuestInfo(x, "No sequence 0 with steps");
}
if (!_aetheryteFunctions.IsTeleportUnlocked())
if ((quest.Info.Level > 5 || !(quest.Info is QuestInfo questInfo) || questInfo.ClassJobs.Count <= 0 || !questInfo.ClassJobs.Any((EClassJob classJob) => !classJob.IsCrafter() && !classJob.IsGatherer())) && !_aetheryteFunctions.IsTeleportUnlocked())
{
return new PriorityQuestInfo(x, "Teleport not unlocked");
}