Add Vanu Vanu quest pooling for talking to npcs on the island

This commit is contained in:
Liza 2024-12-01 21:54:23 +01:00
parent fadc80eaff
commit 286f2c4d77
Signed by: liza
GPG Key ID: 8DD6D21C03BB0848
4 changed files with 135 additions and 28 deletions

View File

@ -12,14 +12,7 @@ namespace Questionable.Controller.Steps;
internal static class QuestCleanUp internal static class QuestCleanUp
{ {
private static readonly Dictionary<ushort, MountConfiguration> AlliedSocietyMountConfiguration = new() internal sealed class CheckAlliedSocietyMount(GameFunctions gameFunctions, AetheryteData aetheryteData, AlliedSocietyData alliedSocietyData, ILogger<CheckAlliedSocietyMount> logger) : SimpleTaskFactory
{
{ 66, new(1016093, EAetheryteLocation.SeaOfCloudsOkZundu) },
{ 79, new(1017031, EAetheryteLocation.DravanianForelandsAnyxTrine) },
{ 369, new(1051798, EAetheryteLocation.KozamaukaDockPoga) },
};
internal sealed class CheckAlliedSocietyMount(GameFunctions gameFunctions, AetheryteData aetheryteData, ILogger<CheckAlliedSocietyMount> logger) : SimpleTaskFactory
{ {
public override ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step) public override ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
{ {
@ -28,7 +21,7 @@ internal static class QuestCleanUp
// if you are on a allied society mount // if you are on a allied society mount
if (gameFunctions.GetMountId() is { } mountId && if (gameFunctions.GetMountId() is { } mountId &&
AlliedSocietyMountConfiguration.TryGetValue(mountId, out var mountConfiguration)) alliedSocietyData.Mounts.TryGetValue(mountId, out var mountConfiguration))
{ {
logger.LogInformation("We are on a known allied society mount with id = {MountId}", mountId); logger.LogInformation("We are on a known allied society mount with id = {MountId}", mountId);
@ -68,6 +61,4 @@ internal static class QuestCleanUp
return null; return null;
} }
} }
private sealed record MountConfiguration(uint IssuerDataId, EAetheryteLocation ClosestAetheryte);
} }

View File

@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using Questionable.Model;
using Questionable.Model.Common;
using Questionable.Model.Questing;
namespace Questionable.Data;
[SuppressMessage("Performance", "CA1822")]
internal sealed class AlliedSocietyData
{
public ReadOnlyDictionary<ushort, AlliedSocietyMountConfiguration> Mounts { get; } =
new Dictionary<ushort, AlliedSocietyMountConfiguration>
{
{ 66, new(1016093, EAetheryteLocation.SeaOfCloudsOkZundu) },
{ 79, new(1017031, EAetheryteLocation.DravanianForelandsAnyxTrine) },
{ 369, new(1051798, EAetheryteLocation.KozamaukaDockPoga) },
}.AsReadOnly();
public EAlliedSociety GetCommonAlliedSocietyTurnIn(ElementId elementId)
{
if (elementId is QuestId questId)
{
return questId.Value switch
{
>= 2171 and <= 2200 => EAlliedSociety.VanuVanu,
>= 2261 and <= 2280 => EAlliedSociety.Vath,
>= 5199 and <= 5226 => EAlliedSociety.Pelupelu,
_ => EAlliedSociety.None,
};
}
return EAlliedSociety.None;
}
public void GetCommonAlliedSocietyNpcs(EAlliedSociety alliedSociety, out uint[] normalNpcs, out uint[] mountNpcs)
{
if (alliedSociety == EAlliedSociety.VanuVanu)
{
normalNpcs = [1016088, 1016091, 1016092];
mountNpcs = [1016093];
}
else if (alliedSociety == EAlliedSociety.Vath)
{
normalNpcs = [];
mountNpcs = [1017031];
}
else
{
normalNpcs = [];
mountNpcs = [];
}
}
}
public sealed record AlliedSocietyMountConfiguration(uint IssuerDataId, EAetheryteLocation ClosestAetheryte);

View File

@ -6,6 +6,7 @@ using Dalamud.Memory;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
@ -27,6 +28,7 @@ internal sealed unsafe class QuestFunctions
private readonly QuestRegistry _questRegistry; private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData; private readonly QuestData _questData;
private readonly AetheryteFunctions _aetheryteFunctions; private readonly AetheryteFunctions _aetheryteFunctions;
private readonly AlliedSocietyData _alliedSocietyData;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly IDataManager _dataManager; private readonly IDataManager _dataManager;
private readonly IClientState _clientState; private readonly IClientState _clientState;
@ -36,6 +38,7 @@ internal sealed unsafe class QuestFunctions
QuestRegistry questRegistry, QuestRegistry questRegistry,
QuestData questData, QuestData questData,
AetheryteFunctions aetheryteFunctions, AetheryteFunctions aetheryteFunctions,
AlliedSocietyData alliedSocietyData,
Configuration configuration, Configuration configuration,
IDataManager dataManager, IDataManager dataManager,
IClientState clientState, IClientState clientState,
@ -44,6 +47,7 @@ internal sealed unsafe class QuestFunctions
_questRegistry = questRegistry; _questRegistry = questRegistry;
_questData = questData; _questData = questData;
_aetheryteFunctions = aetheryteFunctions; _aetheryteFunctions = aetheryteFunctions;
_alliedSocietyData = alliedSocietyData;
_configuration = configuration; _configuration = configuration;
_dataManager = dataManager; _dataManager = dataManager;
_clientState = clientState; _clientState = clientState;
@ -138,7 +142,8 @@ internal sealed unsafe class QuestFunctions
case 2: // leve case 2: // leve
currentQuest = new LeveId(questManager->LeveQuests[trackedQuest.Index].LeveId); currentQuest = new LeveId(questManager->LeveQuests[trackedQuest.Index].LeveId);
if (_questRegistry.IsKnownQuest(currentQuest)) if (_questRegistry.IsKnownQuest(currentQuest))
trackedQuests.Add((currentQuest, questManager->GetLeveQuestById(currentQuest.Value)->Sequence)); trackedQuests.Add((currentQuest,
questManager->GetLeveQuestById(currentQuest.Value)->Sequence));
break; break;
} }
} }
@ -147,14 +152,63 @@ internal sealed unsafe class QuestFunctions
{ {
// if we have multiple quests to turn in for an allied society, try and complete all of them // if we have multiple quests to turn in for an allied society, try and complete all of them
var (firstTrackedQuest, firstTrackedSequence) = trackedQuests.First(); var (firstTrackedQuest, firstTrackedSequence) = trackedQuests.First();
EAlliedSociety firstTrackedAlliedSociety = GetCommonAlliedSocietyTurnIn(firstTrackedQuest); EAlliedSociety firstTrackedAlliedSociety = _alliedSocietyData.GetCommonAlliedSocietyTurnIn(firstTrackedQuest);
if (firstTrackedAlliedSociety != EAlliedSociety.None && firstTrackedSequence == 255) if (firstTrackedAlliedSociety != EAlliedSociety.None)
{ {
foreach (var (quest, sequence) in trackedQuests.Skip(1)) var alliedQuestsForSameSociety = trackedQuests.Skip(1)
.Where(quest => _alliedSocietyData.GetCommonAlliedSocietyTurnIn(quest.Quest) == firstTrackedAlliedSociety)
.ToList();
if (alliedQuestsForSameSociety.Count > 0)
{ {
// only if the other quest isn't ready to be turned in if (firstTrackedSequence == 255)
if (GetCommonAlliedSocietyTurnIn(quest) == firstTrackedAlliedSociety && sequence != 255) {
return (quest, sequence); foreach (var (quest, sequence) in alliedQuestsForSameSociety)
{
// only if the other quest isn't ready to be turned in
if (sequence != 255)
return (quest, sequence);
}
}
else if (!IsOnAlliedSocietyMount())
{
// a few of the vanu quests require you to talk to one of the npcs near the issuer, so we
// give priority to those
// also include the first quest in the list for those
alliedQuestsForSameSociety.Insert(0, (firstTrackedQuest, firstTrackedSequence));
_alliedSocietyData.GetCommonAlliedSocietyNpcs(firstTrackedAlliedSociety, out uint[]? normalNpcs,
out uint[]? mountNpcs);
if (normalNpcs.Length > 0)
{
var talkToNormalNpcs = alliedQuestsForSameSociety
.Where(x => x.Sequence < 255)
.Where(x => IsInteractStep(x.Quest, x.Sequence, normalNpcs))
.Cast<(ElementId, byte)?>()
.FirstOrDefault();
if (talkToNormalNpcs != null)
return talkToNormalNpcs.Value;
}
/*
* TODO: If you have e.g. a mount quest in the middle of 3, it should temporarily make you
* do that quest first, even if it isn't the first in the list. Otherwise, the logic
* here won't make much sense.
*
* TODO: This also won't work if two or three daily quests use a mount.
if (mountNpcs.Length > 0)
{
var talkToMountNpc = alliedQuestsForSameSociety
.Where(x => x.Sequence < 255)
.Where(x => IsInteractStep(x.Quest, x.Sequence, mountNpcs))
.Cast<(ElementId, byte)?>()
.FirstOrDefault();
if (talkToMountNpc != null)
return talkToMountNpc.Value;
}
*/
}
} }
} }
@ -237,20 +291,24 @@ internal sealed unsafe class QuestFunctions
return (currentQuest, QuestManager.GetQuestSequence(currentQuest.Value)); return (currentQuest, QuestManager.GetQuestSequence(currentQuest.Value));
} }
private static EAlliedSociety GetCommonAlliedSocietyTurnIn(ElementId elementId) private bool IsOnAlliedSocietyMount()
{ {
if (elementId is QuestId questId) BattleChara* battleChara = (BattleChara*)(_clientState.LocalPlayer?.Address ?? 0);
return battleChara != null &&
battleChara->Mount.MountId != 0 &&
_alliedSocietyData.Mounts.ContainsKey(battleChara->Mount.MountId);
}
private bool IsInteractStep(ElementId questId, byte sequence, uint[] dataIds)
{
if (_questRegistry.TryGetQuest(questId, out var quest))
{ {
return questId.Value switch QuestStep? firstStepOfSequence = quest.FindSequence(sequence)?.FindStep(0);
{ return firstStepOfSequence is { InteractionType: EInteractionType.Interact, DataId: { } dataId } &&
>= 2171 and <= 2200 => EAlliedSociety.VanuVanu, dataIds.Contains(dataId);
>= 2261 and <= 2280 => EAlliedSociety.Vath,
>= 5199 and <= 5226 => EAlliedSociety.Pelupelu,
_ => EAlliedSociety.None,
};
} }
return EAlliedSociety.None; return false;
} }
public QuestProgressInfo? GetQuestProgressInfo(ElementId elementId) public QuestProgressInfo? GetQuestProgressInfo(ElementId elementId)

View File

@ -115,6 +115,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<AetherCurrentData>(); serviceCollection.AddSingleton<AetherCurrentData>();
serviceCollection.AddSingleton<AetheryteData>(); serviceCollection.AddSingleton<AetheryteData>();
serviceCollection.AddSingleton<AlliedSocietyData>();
serviceCollection.AddSingleton<GatheringData>(); serviceCollection.AddSingleton<GatheringData>();
serviceCollection.AddSingleton<LeveData>(); serviceCollection.AddSingleton<LeveData>();
serviceCollection.AddSingleton<JournalData>(); serviceCollection.AddSingleton<JournalData>();