Allied Society daily 'quest', part 1

This commit is contained in:
Liza 2024-12-21 15:04:31 +01:00
parent ad610d6ddc
commit 6b38e37271
Signed by: liza
GPG Key ID: 2C41B84815CF6445
9 changed files with 192 additions and 5 deletions

View File

@ -0,0 +1,29 @@
{
"$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
}
}
}
]
}
]
}

View File

@ -58,6 +58,17 @@
{ {
"Sequence": 2, "Sequence": 2,
"Steps": [ "Steps": [
{
"Position": {
"X": -799.46594,
"Y": -133.2695,
"Z": -404.1352
},
"TerritoryId": 401,
"InteractionType": "WalkTo",
"AetheryteShortcut": "The Sea of Clouds - Ok' Zundu",
"Fly": true
},
{ {
"DataId": 1016089, "DataId": 1016089,
"Position": { "Position": {
@ -67,8 +78,7 @@
}, },
"TerritoryId": 401, "TerritoryId": 401,
"InteractionType": "Interact", "InteractionType": "Interact",
"AetheryteShortcut": "The Sea of Clouds - Ok' Zundu", "Mount": false
"Fly": true
} }
] ]
}, },

View File

@ -0,0 +1,27 @@
{
"$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
}
}
}
]
}
]
}

View File

@ -56,6 +56,19 @@ public abstract class ElementId : IComparable<ElementId>, IEquatable<ElementId>
return new LeveId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture)); return new LeveId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture));
else if (value.StartsWith("S")) else if (value.StartsWith("S"))
return new SatisfactionSupplyNpcId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture)); 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 else
return new QuestId(ushort.Parse(value, CultureInfo.InvariantCulture)); return new QuestId(ushort.Parse(value, CultureInfo.InvariantCulture));
} }
@ -70,7 +83,8 @@ public abstract class ElementId : IComparable<ElementId>, IEquatable<ElementId>
catch (Exception) catch (Exception)
{ {
elementId = null; elementId = null;
return false; //return false;
throw;
} }
} }
} }
@ -98,3 +112,14 @@ public sealed class SatisfactionSupplyNpcId(ushort value) : ElementId(value)
return "S" + Value.ToString(CultureInfo.InvariantCulture); 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;
}
}

View File

@ -4,6 +4,7 @@ using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Lumina.Excel.Sheets; using Lumina.Excel.Sheets;
using Microsoft.Extensions.Logging;
using Questionable.Functions; using Questionable.Functions;
using Questionable.Model.Questing; using Questionable.Model.Questing;
using Questionable.Windows; using Questionable.Windows;

View File

@ -68,6 +68,29 @@ internal sealed class QuestData
.Where(x => x.LevelLevemete.RowId != 0) .Where(x => x.LevelLevemete.RowId != 0)
.Select(x => new LeveInfo(x)), .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); _quests = quests.ToDictionary(x => x.QuestId, x => x);
// workaround because the game doesn't require completion of the CT questline through normal means // workaround because the game doesn't require completion of the CT questline through normal means

View File

@ -14,7 +14,6 @@ using LLib.GameData;
using LLib.GameUI; using LLib.GameUI;
using Lumina.Excel.Sheets; using Lumina.Excel.Sheets;
using Questionable.Controller; using Questionable.Controller;
using Questionable.Controller.Steps.Interactions;
using Questionable.Data; using Questionable.Data;
using Questionable.Model; using Questionable.Model;
using Questionable.Model.Questing; using Questionable.Model.Questing;
@ -487,6 +486,8 @@ internal sealed unsafe class QuestFunctions
return IsQuestAccepted(leveId); return IsQuestAccepted(leveId);
else if (elementId is SatisfactionSupplyNpcId) else if (elementId is SatisfactionSupplyNpcId)
return false; return false;
else if (elementId is AlliedSocietyDailyId)
return false;
else else
throw new ArgumentOutOfRangeException(nameof(elementId)); throw new ArgumentOutOfRangeException(nameof(elementId));
} }
@ -517,6 +518,8 @@ internal sealed unsafe class QuestFunctions
return IsQuestComplete(leveId); return IsQuestComplete(leveId);
else if (elementId is SatisfactionSupplyNpcId) else if (elementId is SatisfactionSupplyNpcId)
return false; return false;
else if (elementId is AlliedSocietyDailyId)
return false;
else else
throw new ArgumentOutOfRangeException(nameof(elementId)); throw new ArgumentOutOfRangeException(nameof(elementId));
} }
@ -540,6 +543,8 @@ internal sealed unsafe class QuestFunctions
return IsQuestLocked(leveId); return IsQuestLocked(leveId);
else if (elementId is SatisfactionSupplyNpcId satisfactionSupplyNpcId) else if (elementId is SatisfactionSupplyNpcId satisfactionSupplyNpcId)
return IsQuestLocked(satisfactionSupplyNpcId); return IsQuestLocked(satisfactionSupplyNpcId);
else if (elementId is AlliedSocietyDailyId alliedSocietyDailyId)
return IsQuestLocked(alliedSocietyDailyId);
else else
throw new ArgumentOutOfRangeException(nameof(elementId)); throw new ArgumentOutOfRangeException(nameof(elementId));
} }
@ -579,6 +584,13 @@ internal sealed unsafe class QuestFunctions
return !HasCompletedPreviousQuests(questInfo, null); 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) public bool IsDailyAlliedSocietyQuest(QuestId questId)
{ {
var questInfo = (QuestInfo)_questData.GetQuestInfo(questId); var questInfo = (QuestInfo)_questData.GetQuestInfo(questId);

View File

@ -0,0 +1,60 @@
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; }
}

View File

@ -106,7 +106,7 @@ internal sealed class PriorityWindow : LWindow
if (!string.IsNullOrEmpty(_searchString)) if (!string.IsNullOrEmpty(_searchString))
{ {
foundQuests = _questRegistry.AllQuests 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 => x.Info.Name.Contains(_searchString, StringComparison.CurrentCultureIgnoreCase))
.Where(x => !_questFunctions.IsQuestUnobtainable(x.Id)); .Where(x => !_questFunctions.IsQuestUnobtainable(x.Id));
} }