muffin v6.12
This commit is contained in:
parent
060278c1b7
commit
155fbee291
59 changed files with 40083 additions and 58104 deletions
|
@ -16,11 +16,13 @@ using FFXIVClientStructs.FFXIV.Component.GUI;
|
|||
using LLib.GameData;
|
||||
using LLib.GameUI;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Data;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Common;
|
||||
using Questionable.Model.Questing;
|
||||
using Questionable.Windows.QuestComponents;
|
||||
|
||||
namespace Questionable.Functions;
|
||||
|
||||
|
@ -36,6 +38,8 @@ internal sealed class QuestFunctions
|
|||
|
||||
private readonly AlliedSocietyData _alliedSocietyData;
|
||||
|
||||
private readonly AetheryteData _aetheryteData;
|
||||
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
private readonly IDataManager _dataManager;
|
||||
|
@ -46,18 +50,24 @@ internal sealed class QuestFunctions
|
|||
|
||||
private readonly IAetheryteList _aetheryteList;
|
||||
|
||||
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, Configuration configuration, IDataManager dataManager, IClientState clientState, IGameGui gameGui, IAetheryteList aetheryteList)
|
||||
private readonly ILogger<QuestFunctions> _logger;
|
||||
|
||||
private readonly HashSet<ushort> _alreadyLoggedUnobtainableQuestsDetailed = new HashSet<ushort>();
|
||||
|
||||
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;
|
||||
_questData = questData;
|
||||
_aetheryteFunctions = aetheryteFunctions;
|
||||
_alliedSocietyQuestFunctions = alliedSocietyQuestFunctions;
|
||||
_alliedSocietyData = alliedSocietyData;
|
||||
_aetheryteData = aetheryteData;
|
||||
_configuration = configuration;
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
_gameGui = gameGui;
|
||||
_aetheryteList = aetheryteList;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public unsafe QuestReference GetCurrentQuest(bool allowNewMsq = true)
|
||||
|
@ -558,10 +568,20 @@ internal sealed class QuestFunctions
|
|||
if (!ignoreLevel)
|
||||
{
|
||||
byte b = _clientState.LocalPlayer?.Level ?? 0;
|
||||
if (b != 0 && quest != null && quest.Info.Level > b)
|
||||
if (b == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (quest != null && quest.Info.Level > b)
|
||||
{
|
||||
_logger.LogDebug("Quest {QuestId} level requirement not met: required {RequiredLevel}, current {CurrentLevel}", questId, quest.Info.Level, b);
|
||||
return false;
|
||||
}
|
||||
if (quest == null && questId is QuestId questId3 && _questData.TryGetQuestInfo(questId3, out IQuestInfo questInfo) && questInfo is QuestInfo questInfo2 && questInfo2.Level > b)
|
||||
{
|
||||
_logger.LogDebug("Quest {QuestId} (from data) level requirement not met: required {RequiredLevel}, current {CurrentLevel}", questId3, questInfo2.Level, b);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -593,6 +613,14 @@ internal sealed class QuestFunctions
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (elementId is AethernetId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (elementId is AetherCurrentId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("elementId");
|
||||
}
|
||||
|
||||
|
@ -619,6 +647,14 @@ internal sealed class QuestFunctions
|
|||
{
|
||||
return IsQuestComplete(unlockLinkId);
|
||||
}
|
||||
if (elementId is AethernetId aethernetId)
|
||||
{
|
||||
return IsQuestComplete(aethernetId);
|
||||
}
|
||||
if (elementId is AetherCurrentId aetherCurrentId)
|
||||
{
|
||||
return IsQuestComplete(aetherCurrentId);
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("elementId");
|
||||
}
|
||||
|
||||
|
@ -632,6 +668,29 @@ internal sealed class QuestFunctions
|
|||
return UIState.Instance()->IsUnlockLinkUnlocked(unlockLinkId.Value);
|
||||
}
|
||||
|
||||
public bool IsQuestComplete(AethernetId aethernetId)
|
||||
{
|
||||
if (!_questRegistry.TryGetQuest(aethernetId, out Questionable.Model.Quest quest))
|
||||
{
|
||||
_logger.LogWarning("Aethernet quest {AethernetId} not found in registry", aethernetId);
|
||||
return false;
|
||||
}
|
||||
List<(QuestSequence, int, QuestStep)> list = (from x in quest.AllSteps()
|
||||
where x.Step.InteractionType == EInteractionType.AttuneAethernetShard && x.Step.AethernetShard.HasValue
|
||||
select x).ToList();
|
||||
if (list.Count == 0)
|
||||
{
|
||||
_logger.LogWarning("Aethernet quest {AethernetId} has no aethernet shard attunement steps", aethernetId);
|
||||
return false;
|
||||
}
|
||||
return list.All<(QuestSequence, int, QuestStep)>(((QuestSequence Sequence, int StepId, QuestStep Step) step) => _aetheryteFunctions.IsAetheryteUnlocked(step.Step.AethernetShard.Value));
|
||||
}
|
||||
|
||||
public bool IsQuestComplete(AetherCurrentId aetherCurrentId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsQuestLocked(ElementId elementId, ElementId? extraCompletedQuest = null)
|
||||
{
|
||||
if (elementId is QuestId questId)
|
||||
|
@ -650,6 +709,14 @@ internal sealed class QuestFunctions
|
|||
{
|
||||
return IsQuestLocked(unlockLinkId);
|
||||
}
|
||||
if (elementId is AethernetId aethernetId)
|
||||
{
|
||||
return IsQuestLocked(aethernetId);
|
||||
}
|
||||
if (elementId is AetherCurrentId aetherCurrentId)
|
||||
{
|
||||
return IsQuestLocked(aetherCurrentId);
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("elementId");
|
||||
}
|
||||
|
||||
|
@ -708,6 +775,39 @@ internal sealed class QuestFunctions
|
|||
return IsQuestUnobtainable(unlockLinkId);
|
||||
}
|
||||
|
||||
private bool IsQuestLocked(AethernetId aethernetId)
|
||||
{
|
||||
EAetheryteLocation aetheryteLocation = aethernetId.Value switch
|
||||
{
|
||||
1 => EAetheryteLocation.Limsa,
|
||||
2 => EAetheryteLocation.Gridania,
|
||||
3 => EAetheryteLocation.Uldah,
|
||||
4 => EAetheryteLocation.GoldSaucer,
|
||||
5 => EAetheryteLocation.Ishgard,
|
||||
6 => EAetheryteLocation.Idyllshire,
|
||||
7 => EAetheryteLocation.RhalgrsReach,
|
||||
8 => EAetheryteLocation.Kugane,
|
||||
9 => EAetheryteLocation.DomanEnclave,
|
||||
10 => EAetheryteLocation.Crystarium,
|
||||
11 => EAetheryteLocation.Eulmore,
|
||||
12 => EAetheryteLocation.OldSharlayan,
|
||||
13 => EAetheryteLocation.RadzAtHan,
|
||||
14 => EAetheryteLocation.Tuliyollal,
|
||||
15 => EAetheryteLocation.SolutionNine,
|
||||
_ => throw new ArgumentOutOfRangeException("aethernetId", $"Unknown AethernetId: {aethernetId.Value}"),
|
||||
};
|
||||
if (!_aetheryteFunctions.IsAetheryteUnlocked(aetheryteLocation))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsQuestLocked(AetherCurrentId aetherCurrentId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsDailyAlliedSocietyQuest(QuestId questId)
|
||||
{
|
||||
QuestInfo questInfo = (QuestInfo)_questData.GetQuestInfo(questId);
|
||||
|
@ -743,19 +843,110 @@ internal sealed class QuestFunctions
|
|||
|
||||
public unsafe bool IsQuestUnobtainable(QuestId questId, ElementId? extraCompletedQuest = null)
|
||||
{
|
||||
QuestInfo questInfo = (QuestInfo)_questData.GetQuestInfo(questId);
|
||||
if ((int)questInfo.Expansion > (int)PlayerState.Instance()->MaxExpansion)
|
||||
IQuestInfo questInfo = _questData.GetQuestInfo(questId);
|
||||
if (questInfo is UnlockLinkQuestInfo { QuestExpiry: { TimeOfDay: var timeOfDay } questExpiry })
|
||||
{
|
||||
TimeSpan timeSpan = new TimeSpan(23, 59, 59);
|
||||
bool flag = false;
|
||||
DateTime dateTime;
|
||||
if (timeOfDay == TimeSpan.Zero || timeOfDay == timeSpan)
|
||||
{
|
||||
dateTime = EventInfoComponent.AtDailyReset(DateOnly.FromDateTime(questExpiry));
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dateTime = ((questExpiry.Kind == DateTimeKind.Utc) ? questExpiry : questExpiry.ToUniversalTime());
|
||||
}
|
||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||
{
|
||||
_logger.LogDebug("UnlockLink quest {QuestId} expiry raw={ExpiryRaw} Kind={Kind} TimeOfDay={TimeOfDay}", questId, questExpiry.ToString("o"), questExpiry.Kind, questExpiry.TimeOfDay);
|
||||
_logger.LogDebug("UnlockLink quest {QuestId} normalized expiryUtc={ExpiryUtc:o} treatedAsDailyReset={TreatedAsDailyReset}", questId, dateTime, flag);
|
||||
}
|
||||
if (DateTime.UtcNow > dateTime)
|
||||
{
|
||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||
{
|
||||
_logger.LogDebug("UnlockLink quest {QuestId} unobtainable: expiry {ExpiryUtc} (UTC) is before now {NowUtc}", questId, dateTime.ToString("o"), DateTime.UtcNow.ToString("o"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
QuestInfo questInfo2 = (QuestInfo)questInfo;
|
||||
if ((int)questInfo2.Expansion > (int)PlayerState.Instance()->MaxExpansion)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (questInfo.QuestLocks.Count > 0)
|
||||
if (questInfo2.JournalGenre >= 234 && questInfo2.JournalGenre <= 247)
|
||||
{
|
||||
int num = questInfo.QuestLocks.Count((QuestId x) => IsQuestComplete(x) || x.Equals(extraCompletedQuest));
|
||||
if (questInfo.QuestLockJoin == EQuestJoin.All && questInfo.QuestLocks.Count == num)
|
||||
if (_questRegistry.TryGetQuest(questId, out Questionable.Model.Quest quest))
|
||||
{
|
||||
List<QuestSequence> list = quest?.Root?.QuestSequence;
|
||||
if (list != null && list.Count > 0)
|
||||
{
|
||||
goto IL_0288;
|
||||
}
|
||||
}
|
||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||
{
|
||||
_questData.ApplySeasonalOverride(questId, isSeasonal: true, null);
|
||||
_logger.LogDebug("Quest {QuestId} unobtainable: journal genre is 'event (seasonal)' and no quest path", questId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
goto IL_0288;
|
||||
IL_0288:
|
||||
if (questInfo2.QuestLocks.Count > 0)
|
||||
{
|
||||
int num = questInfo2.QuestLocks.Count((QuestId x) => IsQuestComplete(x) || x.Equals(extraCompletedQuest));
|
||||
if (questInfo2.QuestLockJoin == EQuestJoin.All && questInfo2.QuestLocks.Count == num)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (questInfo.QuestLockJoin == EQuestJoin.AtLeastOne && num > 0)
|
||||
if (questInfo2.QuestLockJoin == EQuestJoin.AtLeastOne && num > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DateTime? seasonalQuestExpiry = questInfo2.SeasonalQuestExpiry;
|
||||
if (seasonalQuestExpiry.HasValue)
|
||||
{
|
||||
DateTime valueOrDefault = seasonalQuestExpiry.GetValueOrDefault();
|
||||
TimeSpan timeOfDay2 = valueOrDefault.TimeOfDay;
|
||||
TimeSpan timeSpan2 = new TimeSpan(23, 59, 59);
|
||||
bool flag2 = false;
|
||||
DateTime dateTime2;
|
||||
if (timeOfDay2 == TimeSpan.Zero || timeOfDay2 == timeSpan2)
|
||||
{
|
||||
dateTime2 = EventInfoComponent.AtDailyReset(DateOnly.FromDateTime(valueOrDefault));
|
||||
flag2 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dateTime2 = ((valueOrDefault.Kind == DateTimeKind.Utc) ? valueOrDefault : valueOrDefault.ToUniversalTime());
|
||||
}
|
||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||
{
|
||||
_logger.LogDebug("Quest {QuestId} seasonal expiry raw={ExpiryRaw} Kind={Kind} TimeOfDay={TimeOfDay}", questId, valueOrDefault.ToString("o"), valueOrDefault.Kind, valueOrDefault.TimeOfDay);
|
||||
_logger.LogDebug("Quest {QuestId} normalized expiryUtc={ExpiryUtc:o} treatedAsDailyReset={TreatedAsDailyReset}", questId, dateTime2, flag2);
|
||||
_logger.LogTrace("Quest {QuestId} expiry check: nowUtc={Now:o}, expiryUtc={Expiry:o}, expired={Expired}", questId, DateTime.UtcNow, dateTime2, DateTime.UtcNow > dateTime2);
|
||||
}
|
||||
if (DateTime.UtcNow > dateTime2)
|
||||
{
|
||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||
{
|
||||
_logger.LogDebug("Quest {QuestId} unobtainable: seasonal expiry {ExpiryUtc} (UTC) is before now {NowUtc}", questId, dateTime2.ToString("o"), DateTime.UtcNow.ToString("o"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ((questInfo2.IsSeasonalEvent || questInfo2.IsSeasonalQuest) && !(questInfo2.SeasonalQuestExpiry is DateTime))
|
||||
{
|
||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||
{
|
||||
_logger.LogDebug("Quest {QuestId} is seasonal/event with no expiry; ShowIncompleteSeasonalEvents={ShowIncomplete}", questId, _configuration.General.ShowIncompleteSeasonalEvents);
|
||||
}
|
||||
if (!_configuration.General.ShowIncompleteSeasonalEvents)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -765,7 +956,7 @@ internal sealed class QuestFunctions
|
|||
return true;
|
||||
}
|
||||
byte startTown = PlayerState.Instance()->StartTown;
|
||||
if (questInfo.StartingCity > 0 && questInfo.StartingCity != startTown)
|
||||
if (questInfo2.StartingCity > 0 && questInfo2.StartingCity != startTown)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue