--- /dev/null
+{
+ "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+ "Author": "liza",
+ "QuestSequence": [
+ {
+ "Sequence": 0,
+ "Steps": [
+ {
+ "DataId": 1016089,
+ "Position": {
+ "X": -799.46594,
+ "Y": -133.2695,
+ "Z": -404.1352
+ },
+ "StopDistance": 3,
+ "TerritoryId": 401,
+ "InteractionType": "WalkTo",
+ "AetheryteShortcut": "The Sea of Clouds - Ok' Zundu",
+ "Fly": true,
+ "SkipConditions": {
+ "AetheryteShortcutIf": {
+ "InSameTerritory": true
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
"Sequence": 2,
"Steps": [
{
- "DataId": 1016089,
"Position": {
"X": -799.46594,
"Y": -133.2695,
"Z": -404.1352
},
"TerritoryId": 401,
- "InteractionType": "Interact",
+ "InteractionType": "WalkTo",
"AetheryteShortcut": "The Sea of Clouds - Ok' Zundu",
"Fly": true
+ },
+ {
+ "DataId": 1016089,
+ "Position": {
+ "X": -799.46594,
+ "Y": -133.2695,
+ "Z": -404.1352
+ },
+ "TerritoryId": 401,
+ "InteractionType": "Interact",
+ "Mount": false
}
]
},
--- /dev/null
+{
+ "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+ "Author": "liza",
+ "QuestSequence": [
+ {
+ "Sequence": 0,
+ "Steps": [
+ {
+ "Position": {
+ "X": 58.39701,
+ "Y": -48.000008,
+ "Z": -172.36507
+ },
+ "TerritoryId": 398,
+ "InteractionType": "WalkTo",
+ "AetheryteShortcut": "The Dravanian Forelands - Anyx Trine",
+ "Fly": true,
+ "SkipConditions": {
+ "AetheryteShortcutIf": {
+ "InSameTerritory": true
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
return new LeveId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture));
else if (value.StartsWith("S"))
return new SatisfactionSupplyNpcId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture));
+ else if (value.StartsWith("A"))
+ {
+ value = value.Substring(1);
+ string[] parts = value.Split('x');
+ if (parts.Length == 2)
+ {
+ return new AlliedSocietyDailyId(
+ byte.Parse(parts[0], CultureInfo.InvariantCulture),
+ byte.Parse(parts[1], CultureInfo.InvariantCulture));
+ }
+ else
+ return new AlliedSocietyDailyId(byte.Parse(value, CultureInfo.InvariantCulture));
+ }
else
return new QuestId(ushort.Parse(value, CultureInfo.InvariantCulture));
}
catch (Exception)
{
elementId = null;
- return false;
+ //return false;
+ throw;
}
}
}
return "S" + Value.ToString(CultureInfo.InvariantCulture);
}
}
+
+public sealed class AlliedSocietyDailyId(byte alliedSociety, byte rank = 0) : ElementId((ushort)(alliedSociety * 10 + rank))
+{
+ public byte AlliedSociety { get; } = alliedSociety;
+ public byte Rank { get; } = rank;
+
+ public override string ToString()
+ {
+ return "A" + AlliedSociety + "x" + Rank;
+ }
+}
using Dalamud.Game.Command;
using Dalamud.Plugin.Services;
using Lumina.Excel.Sheets;
+using Microsoft.Extensions.Logging;
using Questionable.Functions;
using Questionable.Model.Questing;
using Questionable.Windows;
.Where(x => x.LevelLevemete.RowId != 0)
.Select(x => new LeveInfo(x)),
];
+
+ quests.AddRange(
+ dataManager.GetExcelSheet<BeastTribe>()
+ .Where(x => x.RowId > 0 && !x.Name.IsEmpty)
+ .SelectMany(x =>
+ {
+ if (x.RowId < 5)
+ {
+ return ((IEnumerable<byte>)
+ [
+ 0,
+ ..quests.Where(y => y.AlliedSociety == (EAlliedSociety)x.RowId && y.IsRepeatable)
+ .Cast<QuestInfo>()
+ .Select(y => (byte)y.AlliedSocietyRank).Distinct()
+ ])
+ .Select(rank => new AlliedSocietyDailyInfo(x, rank));
+ }
+ else
+ {
+ return [new AlliedSocietyDailyInfo(x, 0)];
+ }
+ }));
+
_quests = quests.ToDictionary(x => x.QuestId, x => x);
// workaround because the game doesn't require completion of the CT questline through normal means
using LLib.GameUI;
using Lumina.Excel.Sheets;
using Questionable.Controller;
-using Questionable.Controller.Steps.Interactions;
using Questionable.Data;
using Questionable.Model;
using Questionable.Model.Questing;
return IsQuestAccepted(leveId);
else if (elementId is SatisfactionSupplyNpcId)
return false;
+ else if (elementId is AlliedSocietyDailyId)
+ return false;
else
throw new ArgumentOutOfRangeException(nameof(elementId));
}
return IsQuestComplete(leveId);
else if (elementId is SatisfactionSupplyNpcId)
return false;
+ else if (elementId is AlliedSocietyDailyId)
+ return false;
else
throw new ArgumentOutOfRangeException(nameof(elementId));
}
return IsQuestLocked(leveId);
else if (elementId is SatisfactionSupplyNpcId satisfactionSupplyNpcId)
return IsQuestLocked(satisfactionSupplyNpcId);
+ else if (elementId is AlliedSocietyDailyId alliedSocietyDailyId)
+ return IsQuestLocked(alliedSocietyDailyId);
else
throw new ArgumentOutOfRangeException(nameof(elementId));
}
return !HasCompletedPreviousQuests(questInfo, null);
}
+ private bool IsQuestLocked(AlliedSocietyDailyId alliedSocietyDailyId)
+ {
+ PlayerState* playerState = PlayerState.Instance();
+ byte currentRank = playerState->GetBeastTribeRank(alliedSocietyDailyId.AlliedSociety);
+ return currentRank == 0 || currentRank < alliedSocietyDailyId.Rank;
+ }
+
public bool IsDailyAlliedSocietyQuest(QuestId questId)
{
var questInfo = (QuestInfo)_questData.GetQuestInfo(questId);
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using LLib.GameData;
+using Lumina.Excel.Sheets;
+using Questionable.Data;
+using Questionable.Model.Questing;
+
+namespace Questionable.Model;
+
+internal sealed class AlliedSocietyDailyInfo : IQuestInfo
+{
+ public AlliedSocietyDailyInfo(BeastTribe beastTribe, byte rank)
+ {
+ QuestId = new AlliedSocietyDailyId((byte)beastTribe.RowId, rank);
+ Name = beastTribe.Name.ToString();
+ ClassJobs = (EAlliedSociety)beastTribe.RowId switch
+ {
+ EAlliedSociety.Amaljaa or EAlliedSociety.Sylphs or EAlliedSociety.Kobolds or EAlliedSociety.Sahagin or
+ EAlliedSociety.VanuVanu or EAlliedSociety.Vath or
+ EAlliedSociety.Kojin or EAlliedSociety.Ananta or
+ EAlliedSociety.Pixies or
+ EAlliedSociety.Arkasodara or
+ EAlliedSociety.Pelupelu =>
+ [
+ ..ClassJobUtils.AsIndividualJobs(EExtendedClassJob.DoW),
+ ..ClassJobUtils.AsIndividualJobs(EExtendedClassJob.DoM)
+ ],
+ EAlliedSociety.Ixal or EAlliedSociety.Moogles or EAlliedSociety.Dwarves or EAlliedSociety.Loporrits =>
+ ClassJobUtils.AsIndividualJobs(EExtendedClassJob.DoH).ToList(),
+
+ EAlliedSociety.Qitari or EAlliedSociety.Omicrons =>
+ ClassJobUtils.AsIndividualJobs(EExtendedClassJob.DoL).ToList(),
+
+ EAlliedSociety.Namazu =>
+ [
+ ..ClassJobUtils.AsIndividualJobs(EExtendedClassJob.DoH),
+ ..ClassJobUtils.AsIndividualJobs(EExtendedClassJob.DoL)
+ ],
+
+ _ => throw new ArgumentOutOfRangeException(nameof(beastTribe))
+ };
+ Expansion = (EExpansionVersion)beastTribe.Expansion.RowId;
+ }
+
+ public ElementId QuestId { get; }
+ public string Name { get; }
+ public uint IssuerDataId => 0;
+ public ImmutableList<PreviousQuestInfo> PreviousQuests { get; } = [];
+ public EQuestJoin PreviousQuestJoin => EQuestJoin.All;
+ public bool IsRepeatable => true;
+ public ushort Level => 1;
+ public EAlliedSociety AlliedSociety => EAlliedSociety.None;
+ public uint? JournalGenre => null;
+ public ushort SortKey => 0;
+ public bool IsMainScenarioQuest => false;
+ public IReadOnlyList<EClassJob> ClassJobs { get; }
+ public EExpansionVersion Expansion { get; }
+}
if (!string.IsNullOrEmpty(_searchString))
{
foundQuests = _questRegistry.AllQuests
- .Where(x => x.Id is not SatisfactionSupplyNpcId)
+ .Where(x => x.Id is not SatisfactionSupplyNpcId and not AlliedSocietyDailyId)
.Where(x => x.Info.Name.Contains(_searchString, StringComparison.CurrentCultureIgnoreCase))
.Where(x => !_questFunctions.IsQuestUnobtainable(x.Id));
}