Add Vanu Vanu quest pooling for talking to npcs on the island
This commit is contained in:
parent
fadc80eaff
commit
286f2c4d77
@ -12,14 +12,7 @@ namespace Questionable.Controller.Steps;
|
||||
|
||||
internal static class QuestCleanUp
|
||||
{
|
||||
private static readonly Dictionary<ushort, MountConfiguration> AlliedSocietyMountConfiguration = new()
|
||||
{
|
||||
{ 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
|
||||
internal sealed class CheckAlliedSocietyMount(GameFunctions gameFunctions, AetheryteData aetheryteData, AlliedSocietyData alliedSocietyData, ILogger<CheckAlliedSocietyMount> logger) : SimpleTaskFactory
|
||||
{
|
||||
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 (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);
|
||||
|
||||
@ -68,6 +61,4 @@ internal static class QuestCleanUp
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record MountConfiguration(uint IssuerDataId, EAetheryteLocation ClosestAetheryte);
|
||||
}
|
||||
|
57
Questionable/Data/AlliedSocietyData.cs
Normal file
57
Questionable/Data/AlliedSocietyData.cs
Normal 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);
|
@ -6,6 +6,7 @@ using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
@ -27,6 +28,7 @@ internal sealed unsafe class QuestFunctions
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
private readonly QuestData _questData;
|
||||
private readonly AetheryteFunctions _aetheryteFunctions;
|
||||
private readonly AlliedSocietyData _alliedSocietyData;
|
||||
private readonly Configuration _configuration;
|
||||
private readonly IDataManager _dataManager;
|
||||
private readonly IClientState _clientState;
|
||||
@ -36,6 +38,7 @@ internal sealed unsafe class QuestFunctions
|
||||
QuestRegistry questRegistry,
|
||||
QuestData questData,
|
||||
AetheryteFunctions aetheryteFunctions,
|
||||
AlliedSocietyData alliedSocietyData,
|
||||
Configuration configuration,
|
||||
IDataManager dataManager,
|
||||
IClientState clientState,
|
||||
@ -44,6 +47,7 @@ internal sealed unsafe class QuestFunctions
|
||||
_questRegistry = questRegistry;
|
||||
_questData = questData;
|
||||
_aetheryteFunctions = aetheryteFunctions;
|
||||
_alliedSocietyData = alliedSocietyData;
|
||||
_configuration = configuration;
|
||||
_dataManager = dataManager;
|
||||
_clientState = clientState;
|
||||
@ -138,7 +142,8 @@ internal sealed unsafe class QuestFunctions
|
||||
case 2: // leve
|
||||
currentQuest = new LeveId(questManager->LeveQuests[trackedQuest.Index].LeveId);
|
||||
if (_questRegistry.IsKnownQuest(currentQuest))
|
||||
trackedQuests.Add((currentQuest, questManager->GetLeveQuestById(currentQuest.Value)->Sequence));
|
||||
trackedQuests.Add((currentQuest,
|
||||
questManager->GetLeveQuestById(currentQuest.Value)->Sequence));
|
||||
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
|
||||
var (firstTrackedQuest, firstTrackedSequence) = trackedQuests.First();
|
||||
EAlliedSociety firstTrackedAlliedSociety = GetCommonAlliedSocietyTurnIn(firstTrackedQuest);
|
||||
if (firstTrackedAlliedSociety != EAlliedSociety.None && firstTrackedSequence == 255)
|
||||
EAlliedSociety firstTrackedAlliedSociety = _alliedSocietyData.GetCommonAlliedSocietyTurnIn(firstTrackedQuest);
|
||||
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 (GetCommonAlliedSocietyTurnIn(quest) == firstTrackedAlliedSociety && sequence != 255)
|
||||
return (quest, sequence);
|
||||
if (firstTrackedSequence == 255)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
>= 2171 and <= 2200 => EAlliedSociety.VanuVanu,
|
||||
>= 2261 and <= 2280 => EAlliedSociety.Vath,
|
||||
>= 5199 and <= 5226 => EAlliedSociety.Pelupelu,
|
||||
_ => EAlliedSociety.None,
|
||||
};
|
||||
QuestStep? firstStepOfSequence = quest.FindSequence(sequence)?.FindStep(0);
|
||||
return firstStepOfSequence is { InteractionType: EInteractionType.Interact, DataId: { } dataId } &&
|
||||
dataIds.Contains(dataId);
|
||||
}
|
||||
|
||||
return EAlliedSociety.None;
|
||||
return false;
|
||||
}
|
||||
|
||||
public QuestProgressInfo? GetQuestProgressInfo(ElementId elementId)
|
||||
|
@ -115,6 +115,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
||||
|
||||
serviceCollection.AddSingleton<AetherCurrentData>();
|
||||
serviceCollection.AddSingleton<AetheryteData>();
|
||||
serviceCollection.AddSingleton<AlliedSocietyData>();
|
||||
serviceCollection.AddSingleton<GatheringData>();
|
||||
serviceCollection.AddSingleton<LeveData>();
|
||||
serviceCollection.AddSingleton<JournalData>();
|
||||
|
Loading…
Reference in New Issue
Block a user