punish v6.8.18.0

This commit is contained in:
alydev 2025-10-09 07:47:19 +10:00
commit 060278c1b7
317 changed files with 554155 additions and 0 deletions

View file

@ -0,0 +1,91 @@
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 ElementId QuestId { get; }
public string Name { get; }
public uint IssuerDataId => 0u;
public ImmutableList<PreviousQuestInfo> PreviousQuests { get; } = ImmutableList.Create(default(ReadOnlySpan<PreviousQuestInfo>));
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; }
public AlliedSocietyDailyInfo(BeastTribe beastTribe, byte rank, ClassJobUtils classJobUtils)
{
QuestId = new AlliedSocietyDailyId((byte)beastTribe.RowId, rank);
Name = beastTribe.Name.ToString();
List<EClassJob> list2;
switch ((EAlliedSociety)(byte)beastTribe.RowId)
{
case EAlliedSociety.Amaljaa:
case EAlliedSociety.Sylphs:
case EAlliedSociety.Kobolds:
case EAlliedSociety.Sahagin:
case EAlliedSociety.VanuVanu:
case EAlliedSociety.Vath:
case EAlliedSociety.Kojin:
case EAlliedSociety.Ananta:
case EAlliedSociety.Pixies:
case EAlliedSociety.Arkasodara:
case EAlliedSociety.Pelupelu:
{
List<EClassJob> list3 = new List<EClassJob>();
list3.AddRange(classJobUtils.AsIndividualJobs(EExtendedClassJob.DoW, null));
list3.AddRange(classJobUtils.AsIndividualJobs(EExtendedClassJob.DoM, null));
list2 = list3;
break;
}
case EAlliedSociety.Ixal:
case EAlliedSociety.Moogles:
case EAlliedSociety.Dwarves:
case EAlliedSociety.Loporrits:
case EAlliedSociety.YokHuy:
list2 = classJobUtils.AsIndividualJobs(EExtendedClassJob.DoH, null).ToList();
break;
case EAlliedSociety.Qitari:
case EAlliedSociety.Omicrons:
case EAlliedSociety.MamoolJa:
list2 = classJobUtils.AsIndividualJobs(EExtendedClassJob.DoL, null).ToList();
break;
case EAlliedSociety.Namazu:
{
List<EClassJob> list = new List<EClassJob>();
list.AddRange(classJobUtils.AsIndividualJobs(EExtendedClassJob.DoH, null));
list.AddRange(classJobUtils.AsIndividualJobs(EExtendedClassJob.DoL, null));
list2 = list;
break;
}
default:
throw new ArgumentOutOfRangeException("beastTribe");
}
ClassJobs = list2;
Expansion = (EExpansionVersion)beastTribe.Expansion.RowId;
}
}

View file

@ -0,0 +1,26 @@
namespace Questionable.Model;
public enum EAlliedSociety : byte
{
None,
Amaljaa,
Sylphs,
Kobolds,
Sahagin,
Ixal,
VanuVanu,
Vath,
Moogles,
Kojin,
Ananta,
Namazu,
Pixies,
Qitari,
Dwarves,
Arkasodara,
Omicrons,
Loporrits,
Pelupelu,
MamoolJa,
YokHuy
}

View file

@ -0,0 +1,10 @@
namespace Questionable.Model;
public enum EItemRewardType
{
Mount,
Minion,
OrchestrionRoll,
TripleTriadCard,
FashionAccessory
}

View file

@ -0,0 +1,11 @@
namespace Questionable.Model;
public enum EMovementType
{
None,
Quest,
DebugWindow,
Shortcut,
Landing,
Combat
}

View file

@ -0,0 +1,8 @@
namespace Questionable.Model;
internal enum EQuestJoin : byte
{
None,
All,
AtLeastOne
}

View file

@ -0,0 +1,29 @@
using System.Runtime.CompilerServices;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
namespace Questionable.Model;
public sealed record FashionAccessoryReward : ItemReward
{
public uint AccessoryId { get; init; }
public override EItemRewardType Type => EItemRewardType.FashionAccessory;
public FashionAccessoryReward(ItemRewardDetails Item, uint AccessoryId)
{
this.AccessoryId = AccessoryId;
base._002Ector(Item);
}
public unsafe override bool IsUnlocked()
{
return PlayerState.Instance()->IsOrnamentUnlocked(AccessoryId);
}
[CompilerGenerated]
public void Deconstruct(out ItemRewardDetails Item, out uint AccessoryId)
{
Item = base.Item;
AccessoryId = this.AccessoryId;
}
}

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Dalamud.Game.Text;
using LLib.GameData;
using Questionable.Model.Questing;
namespace Questionable.Model;
internal interface IQuestInfo
{
ElementId QuestId { get; }
string Name { get; }
uint IssuerDataId { get; }
bool IsRepeatable { get; }
ImmutableList<PreviousQuestInfo> PreviousQuests { get; }
EQuestJoin PreviousQuestJoin { get; }
ushort Level { get; }
EAlliedSociety AlliedSociety { get; }
uint? JournalGenre { get; }
ushort SortKey { get; }
bool IsMainScenarioQuest { get; }
IReadOnlyList<EClassJob> ClassJobs { get; }
EExpansionVersion Expansion { get; }
string SimplifiedName => Name.Replace(".", "", StringComparison.Ordinal).Replace("*", "", StringComparison.Ordinal).Replace("\"", "", StringComparison.Ordinal)
.Replace("/", "", StringComparison.Ordinal)
.Replace("\\", "", StringComparison.Ordinal)
.Replace("<", "", StringComparison.Ordinal)
.Replace(">", "", StringComparison.Ordinal)
.Replace("|", "", StringComparison.Ordinal)
.Replace(":", "", StringComparison.Ordinal)
.Replace("?", "", StringComparison.Ordinal)
.TrimStart(SeIconChar.QuestSync.ToIconChar(), SeIconChar.QuestRepeatable.ToIconChar(), ' ');
}

View file

@ -0,0 +1,52 @@
using System;
using Lumina.Excel.Sheets;
using Questionable.Model.Questing;
namespace Questionable.Model;
public abstract record ItemReward(ItemRewardDetails Item)
{
public uint ItemId => Item.ItemId;
public string Name => Item.Name;
public ElementId ElementId => Item.ElementId;
public TimeSpan CastTime => Item.CastTime;
public abstract EItemRewardType Type { get; }
internal static ItemReward? CreateFromItem(Item item, ElementId elementId)
{
ushort? num = item.ItemAction.ValueNullable?.Type;
if (num.HasValue && num == 1322)
{
return new MountReward(new ItemRewardDetails(item, elementId), item.ItemAction.Value.Data[0]);
}
num = item.ItemAction.ValueNullable?.Type;
if (num.HasValue && num == 853)
{
return new MinionReward(new ItemRewardDetails(item, elementId), item.ItemAction.Value.Data[0]);
}
Orchestrion? valueOrDefault = item.AdditionalData.GetValueOrDefault<Orchestrion>();
if (valueOrDefault.HasValue)
{
Orchestrion valueOrDefault2 = valueOrDefault.GetValueOrDefault();
return new OrchestrionRollReward(new ItemRewardDetails(item, elementId), valueOrDefault2.RowId);
}
TripleTriadCard? valueOrDefault3 = item.AdditionalData.GetValueOrDefault<TripleTriadCard>();
if (valueOrDefault3.HasValue)
{
TripleTriadCard valueOrDefault4 = valueOrDefault3.GetValueOrDefault();
return new TripleTriadCardReward(new ItemRewardDetails(item, elementId), (ushort)valueOrDefault4.RowId);
}
num = item.ItemAction.ValueNullable?.Type;
if (num.HasValue && num == 20086)
{
return new FashionAccessoryReward(new ItemRewardDetails(item, elementId), item.ItemAction.Value.Data[0]);
}
return null;
}
public abstract bool IsUnlocked();
}

View file

@ -0,0 +1,23 @@
using System;
using Dalamud.Utility;
using Lumina.Excel.Sheets;
using Questionable.Model.Questing;
namespace Questionable.Model;
public sealed class ItemRewardDetails
{
public uint ItemId { get; } = item.RowId;
public string Name { get; } = item.Name.ToDalamudString().ToString();
public TimeSpan CastTime { get; } = TimeSpan.FromSeconds(item.CastTimeSeconds);
public ElementId ElementId { get; }
public ItemRewardDetails(Item item, ElementId elementId)
{
ElementId = elementId;
base._002Ector();
}
}

View file

@ -0,0 +1,10 @@
namespace Questionable.Model;
internal sealed class JournalGenreOverrides
{
public required uint ARelicRebornQuests { get; init; }
public required uint ThavnairSideQuests { get; init; }
public required uint RadzAtHanSideQuests { get; init; }
}

View file

@ -0,0 +1,29 @@
using System.Runtime.CompilerServices;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
namespace Questionable.Model;
public sealed record MinionReward : ItemReward
{
public uint MinionId { get; init; }
public override EItemRewardType Type => EItemRewardType.Minion;
public MinionReward(ItemRewardDetails Item, uint MinionId)
{
this.MinionId = MinionId;
base._002Ector(Item);
}
public unsafe override bool IsUnlocked()
{
return UIState.Instance()->IsCompanionUnlocked(MinionId);
}
[CompilerGenerated]
public void Deconstruct(out ItemRewardDetails Item, out uint MinionId)
{
Item = base.Item;
MinionId = this.MinionId;
}
}

View file

@ -0,0 +1,29 @@
using System.Runtime.CompilerServices;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
namespace Questionable.Model;
public sealed record MountReward : ItemReward
{
public uint MountId { get; init; }
public override EItemRewardType Type => EItemRewardType.Mount;
public MountReward(ItemRewardDetails Item, uint MountId)
{
this.MountId = MountId;
base._002Ector(Item);
}
public unsafe override bool IsUnlocked()
{
return PlayerState.Instance()->IsMountUnlocked(MountId);
}
[CompilerGenerated]
public void Deconstruct(out ItemRewardDetails Item, out uint MountId)
{
Item = base.Item;
MountId = this.MountId;
}
}

View file

@ -0,0 +1,29 @@
using System.Runtime.CompilerServices;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
namespace Questionable.Model;
public sealed record OrchestrionRollReward : ItemReward
{
public uint OrchestrionRollId { get; init; }
public override EItemRewardType Type => EItemRewardType.OrchestrionRoll;
public OrchestrionRollReward(ItemRewardDetails Item, uint OrchestrionRollId)
{
this.OrchestrionRollId = OrchestrionRollId;
base._002Ector(Item);
}
public unsafe override bool IsUnlocked()
{
return PlayerState.Instance()->IsOrchestrionRollUnlocked(OrchestrionRollId);
}
[CompilerGenerated]
public void Deconstruct(out ItemRewardDetails Item, out uint OrchestrionRollId)
{
Item = base.Item;
OrchestrionRollId = this.OrchestrionRollId;
}
}

View file

@ -0,0 +1,5 @@
using Questionable.Model.Questing;
namespace Questionable.Model;
internal sealed record PreviousQuestInfo(QuestId QuestId, byte Sequence = 0);

View file

@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Linq;
using Questionable.Model.Questing;
namespace Questionable.Model;
internal sealed class Quest
{
public enum ESource
{
Assembly,
ProjectDirectory,
UserDirectory
}
public required ElementId Id { get; init; }
public required QuestRoot Root { get; init; }
public required IQuestInfo Info { get; init; }
public required ESource Source { get; init; }
public QuestSequence? FindSequence(byte currentSequence)
{
return Root.QuestSequence.SingleOrDefault((QuestSequence seq) => seq.Sequence == currentSequence);
}
public IEnumerable<QuestSequence> AllSequences()
{
return Root.QuestSequence;
}
public IEnumerable<(QuestSequence Sequence, int StepId, QuestStep Step)> AllSteps()
{
foreach (QuestSequence sequence in Root.QuestSequence)
{
int i = 0;
while (i < sequence.Steps.Count)
{
QuestStep item = sequence.Steps[i];
yield return (Sequence: sequence, StepId: i, Step: item);
int num = i + 1;
i = num;
}
}
}
}

View file

@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using LLib.GameData;
using Lumina.Excel;
using Lumina.Excel.Sheets;
using Questionable.Model.Questing;
namespace Questionable.Model;
internal sealed class QuestInfo : IQuestInfo
{
public ElementId QuestId { get; }
public string Name { get; }
public ushort Level { get; }
public uint IssuerDataId { get; }
public bool IsRepeatable { get; }
public ImmutableList<PreviousQuestInfo> PreviousQuests { get; private set; }
public EQuestJoin PreviousQuestJoin { get; }
public ImmutableList<QuestId> QuestLocks { get; private set; }
public EQuestJoin QuestLockJoin { get; private set; }
public List<ushort> PreviousInstanceContent { get; }
public EQuestJoin PreviousInstanceContentJoin { get; }
public uint? JournalGenre { get; set; }
public ushort SortKey { get; set; }
public bool IsMainScenarioQuest { get; }
public bool CompletesInstantly { get; }
public FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany GrandCompany { get; }
public EAlliedSociety AlliedSociety { get; }
public byte AlliedSocietyQuestGroup { get; }
public int AlliedSocietyRank { get; }
public IReadOnlyList<EClassJob> ClassJobs { get; }
public bool IsSeasonalEvent { get; }
public uint NewGamePlusChapter { get; }
public byte StartingCity { get; set; }
public byte MoogleDeliveryLevel { get; }
public bool IsMoogleDeliveryQuest => JournalGenre == 87;
public IReadOnlyList<ItemReward> ItemRewards { get; }
public EExpansionVersion Expansion { get; }
public QuestInfo(Lumina.Excel.Sheets.Quest quest, uint newGamePlusChapter, byte startingCity, JournalGenreOverrides journalGenreOverrides)
{
QuestId = Questionable.Model.Questing.QuestId.FromRowId(quest.RowId);
string value = QuestId.Value switch
{
85 => " (Lancer)",
108 => " (Marauder)",
109 => " (Arcanist)",
123 => " (Archer)",
124 => " (Conjurer)",
568 => " (Gladiator)",
569 => " (Pugilist)",
570 => " (Thaumaturge)",
673 => " (Ul'dah)",
674 => " (Limsa/Gridania)",
1432 => " (Gridania)",
1433 => " (Limsa)",
1434 => " (Ul'dah)",
_ => "",
};
Name = $"{quest.Name}{value}";
Level = quest.ClassJobLevel[0];
IssuerDataId = quest.IssuerStart.RowId;
IsRepeatable = quest.IsRepeatable;
PreviousQuests = new List<PreviousQuestInfo>
{
new PreviousQuestInfo(ReplaceOldQuestIds(Questionable.Model.Questing.QuestId.FromRowId(quest.PreviousQuest[0].RowId)), quest.Unknown7),
new PreviousQuestInfo(ReplaceOldQuestIds(Questionable.Model.Questing.QuestId.FromRowId(quest.PreviousQuest[1].RowId)), 0),
new PreviousQuestInfo(ReplaceOldQuestIds(Questionable.Model.Questing.QuestId.FromRowId(quest.PreviousQuest[2].RowId)), 0)
}.Where((PreviousQuestInfo x) => x.QuestId.Value != 0).ToImmutableList();
PreviousQuestJoin = (EQuestJoin)quest.PreviousQuestJoin;
QuestLocks = (from x in quest.QuestLock
select Questionable.Model.Questing.QuestId.FromRowId(x.RowId) into x
where x.Value != 0
select x).ToImmutableList();
QuestLockJoin = (EQuestJoin)quest.QuestLockJoin;
(uint?, ushort?) tuple;
switch (QuestId.Value)
{
case 1119:
case 1120:
case 1121:
case 1122:
case 1123:
case 1124:
case 1125:
case 1126:
case 1127:
case 1579:
tuple = (journalGenreOverrides.ARelicRebornQuests, (ushort)0);
break;
case 4196:
case 4197:
case 4198:
case 4199:
case 4200:
case 4201:
case 4202:
case 4203:
case 4204:
case 4205:
case 4206:
case 4207:
case 4208:
case 4209:
tuple = (journalGenreOverrides.ThavnairSideQuests, null);
break;
case 4173:
tuple = (journalGenreOverrides.RadzAtHanSideQuests, null);
break;
default:
tuple = (quest.JournalGenre.ValueNullable?.RowId, null);
break;
}
(uint?, ushort?) tuple2 = tuple;
JournalGenre = tuple2.Item1;
SortKey = tuple2.Item2 ?? quest.SortKey;
JournalGenre? valueNullable = quest.JournalGenre.ValueNullable;
IsMainScenarioQuest = valueNullable.HasValue && valueNullable.GetValueOrDefault().Icon == 61412;
CompletesInstantly = quest.TodoParams[0].ToDoCompleteSeq == 0;
PreviousInstanceContent = (from x in quest.InstanceContent
select (ushort)x.RowId into x
where x != 0
select x).ToList();
PreviousInstanceContentJoin = (EQuestJoin)quest.InstanceContentJoin;
GrandCompany = (FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany)quest.GrandCompany.RowId;
AlliedSociety = (EAlliedSociety)quest.BeastTribe.RowId;
AlliedSocietyQuestGroup = quest.DailyQuestPool;
AlliedSocietyRank = (int)quest.BeastReputationRank.RowId;
ClassJobs = QuestInfoUtils.AsList(quest.ClassJobCategory0.ValueNullable);
IsSeasonalEvent = quest.Festival.RowId != 0;
NewGamePlusChapter = newGamePlusChapter;
StartingCity = startingCity;
MoogleDeliveryLevel = (byte)quest.DeliveryQuest.RowId;
ItemRewards = (from Item x in from x in quest.Reward
where x.RowId != 0 && x.Is<Item>()
select x.GetValueOrDefault<Item>() into x
where x.HasValue
select x
where x.IsUntradable
select ItemReward.CreateFromItem(x, QuestId) into x
where x != null
select x).Cast<ItemReward>().ToList();
Expansion = (EExpansionVersion)quest.Expansion.RowId;
}
private static QuestId ReplaceOldQuestIds(QuestId questId)
{
if (questId.Value == 524)
{
return new QuestId(4522);
}
return questId;
}
public void AddPreviousQuest(PreviousQuestInfo questId)
{
ImmutableList<PreviousQuestInfo> previousQuests = PreviousQuests;
int num = 0;
PreviousQuestInfo[] array = new PreviousQuestInfo[1 + previousQuests.Count];
foreach (PreviousQuestInfo item in previousQuests)
{
array[num] = item;
num++;
}
array[num] = questId;
PreviousQuests = ImmutableList.Create(new ReadOnlySpan<PreviousQuestInfo>(array));
}
public void AddQuestLocks(EQuestJoin questJoin, params QuestId[] questId)
{
if (QuestLocks.Count > 0 && QuestLockJoin != questJoin)
{
throw new InvalidOperationException();
}
QuestLockJoin = questJoin;
ImmutableList<QuestId> questLocks = QuestLocks;
int num = 0;
QuestId[] array = new QuestId[questLocks.Count + questId.Length];
foreach (QuestId item in questLocks)
{
array[num] = item;
num++;
}
ReadOnlySpan<QuestId> readOnlySpan = new ReadOnlySpan<QuestId>(questId);
readOnlySpan.CopyTo(new Span<QuestId>(array).Slice(num, readOnlySpan.Length));
num += readOnlySpan.Length;
QuestLocks = ImmutableList.Create(new ReadOnlySpan<QuestId>(array));
}
}

View file

@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LLib.GameData;
using Lumina.Excel.Sheets;
namespace Questionable.Model;
internal static class QuestInfoUtils
{
private static readonly Dictionary<uint, IReadOnlyList<EClassJob>> CachedClassJobs = new Dictionary<uint, IReadOnlyList<EClassJob>>();
internal static IReadOnlyList<EClassJob> AsList(ClassJobCategory? optionalClassJobCategory)
{
if (!optionalClassJobCategory.HasValue)
{
return Enum.GetValues<EClassJob>();
}
ClassJobCategory value = optionalClassJobCategory.Value;
if (CachedClassJobs.TryGetValue(value.RowId, out IReadOnlyList<EClassJob> value2))
{
return value2;
}
value2 = (from y in new Dictionary<EClassJob, bool>
{
{
EClassJob.Adventurer,
value.ADV
},
{
EClassJob.Gladiator,
value.GLA
},
{
EClassJob.Pugilist,
value.PGL
},
{
EClassJob.Marauder,
value.MRD
},
{
EClassJob.Lancer,
value.LNC
},
{
EClassJob.Archer,
value.ARC
},
{
EClassJob.Conjurer,
value.CNJ
},
{
EClassJob.Thaumaturge,
value.THM
},
{
EClassJob.Carpenter,
value.CRP
},
{
EClassJob.Blacksmith,
value.BSM
},
{
EClassJob.Armorer,
value.ARM
},
{
EClassJob.Goldsmith,
value.GSM
},
{
EClassJob.Leatherworker,
value.LTW
},
{
EClassJob.Weaver,
value.WVR
},
{
EClassJob.Alchemist,
value.ALC
},
{
EClassJob.Culinarian,
value.CUL
},
{
EClassJob.Miner,
value.MIN
},
{
EClassJob.Botanist,
value.BTN
},
{
EClassJob.Fisher,
value.FSH
},
{
EClassJob.Paladin,
value.PLD
},
{
EClassJob.Monk,
value.MNK
},
{
EClassJob.Warrior,
value.WAR
},
{
EClassJob.Dragoon,
value.DRG
},
{
EClassJob.Bard,
value.BRD
},
{
EClassJob.WhiteMage,
value.WHM
},
{
EClassJob.BlackMage,
value.BLM
},
{
EClassJob.Arcanist,
value.ACN
},
{
EClassJob.Summoner,
value.SMN
},
{
EClassJob.Scholar,
value.SCH
},
{
EClassJob.Rogue,
value.ROG
},
{
EClassJob.Ninja,
value.NIN
},
{
EClassJob.Machinist,
value.MCH
},
{
EClassJob.DarkKnight,
value.DRK
},
{
EClassJob.Astrologian,
value.AST
},
{
EClassJob.Samurai,
value.SAM
},
{
EClassJob.RedMage,
value.RDM
},
{
EClassJob.BlueMage,
value.BLU
},
{
EClassJob.Gunbreaker,
value.GNB
},
{
EClassJob.Dancer,
value.DNC
},
{
EClassJob.Reaper,
value.RPR
},
{
EClassJob.Sage,
value.SGE
},
{
EClassJob.Viper,
value.VPR
},
{
EClassJob.Pictomancer,
value.PCT
}
}
where y.Value
select y.Key).ToList().AsReadOnly();
CachedClassJobs[value.RowId] = value2;
return value2;
}
}

View file

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using LLib.GameData;
using Questionable.Model.Questing;
namespace Questionable.Model;
internal sealed class QuestProgressInfo
{
private readonly string _asString;
public ElementId Id { get; }
public byte Sequence { get; }
public ushort Flags { get; init; }
public List<byte> Variables { get; }
public bool IsHidden { get; }
public EClassJob ClassJob { get; }
public string Tooltip { get; }
public QuestProgressInfo(QuestWork questWork)
{
Id = new QuestId(questWork.QuestId);
Sequence = questWork.Sequence;
Flags = questWork.Flags;
Variables = questWork.Variables.ToArray().ToList();
IsHidden = questWork.IsHidden;
ClassJob = (EClassJob)questWork.AcceptClassJob;
Tooltip = "";
Span<byte> variables = questWork.Variables;
string text = "";
for (int i = 0; i < variables.Length; i++)
{
byte b = variables[i];
Tooltip = Tooltip + Convert.ToString(b, 2).PadLeft(8).Replace(" ", "0") + "\n";
int num = b & 0xF;
text += b;
if (num != 0)
{
text += $"({num})";
}
text += " ";
if (i % 2 == 1)
{
text += " ";
}
}
_asString = "QW: " + text.Trim();
}
public override string ToString()
{
return _asString;
}
}

View file

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using LLib.GameData;
using Lumina.Excel.Sheets;
using Questionable.Model.Questing;
namespace Questionable.Model;
internal sealed class SatisfactionSupplyInfo : IQuestInfo
{
public ElementId QuestId { get; }
public string Name { get; }
public uint IssuerDataId { get; }
public bool IsRepeatable => true;
public ImmutableList<PreviousQuestInfo> PreviousQuests { get; }
public EQuestJoin PreviousQuestJoin => EQuestJoin.All;
public ushort Level { get; }
public EAlliedSociety AlliedSociety => EAlliedSociety.None;
public uint? JournalGenre => null;
public ushort SortKey { get; }
public bool IsMainScenarioQuest => false;
public EExpansionVersion Expansion { get; }
public IReadOnlyList<EClassJob> ClassJobs { get; } = new global::_003C_003Ez__ReadOnlyArray<EClassJob>(new EClassJob[2]
{
EClassJob.Miner,
EClassJob.Botanist
});
public SatisfactionSupplyInfo(SatisfactionNpc npc)
{
QuestId = new SatisfactionSupplyNpcId((ushort)npc.RowId);
Name = npc.Npc.Value.Singular.ToString();
IssuerDataId = npc.Npc.RowId;
Level = npc.LevelUnlock;
SortKey = QuestId.Value;
Expansion = (EExpansionVersion)npc.QuestRequired.Value.Expansion.RowId;
PreviousQuestInfo reference = new PreviousQuestInfo(Questionable.Model.Questing.QuestId.FromRowId(npc.QuestRequired.RowId), 0);
PreviousQuests = ImmutableList.Create(new ReadOnlySpan<PreviousQuestInfo>(in reference));
}
}

View file

@ -0,0 +1,49 @@
using System;
using System.Text.RegularExpressions;
using Questionable.Functions;
namespace Questionable.Model;
internal sealed class StringOrRegex
{
private readonly Regex? _regex;
private readonly string? _stringValue;
public StringOrRegex(Regex? regex)
{
ArgumentNullException.ThrowIfNull(regex, "regex");
_regex = regex;
_stringValue = null;
}
public StringOrRegex(string? str)
{
ArgumentNullException.ThrowIfNull(str, "str");
_regex = null;
_stringValue = str;
}
public bool IsMatch(string other)
{
if (_regex != null)
{
return _regex.IsMatch(other);
}
return GameFunctions.GameStringEquals(_stringValue, other);
}
public string? GetString()
{
if (_stringValue == null)
{
throw new InvalidOperationException();
}
return _stringValue;
}
public override string? ToString()
{
return _regex?.ToString() ?? _stringValue;
}
}

View file

@ -0,0 +1,29 @@
using System.Runtime.CompilerServices;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
namespace Questionable.Model;
public sealed record TripleTriadCardReward : ItemReward
{
public ushort TripleTriadCardId { get; init; }
public override EItemRewardType Type => EItemRewardType.TripleTriadCard;
public TripleTriadCardReward(ItemRewardDetails Item, ushort TripleTriadCardId)
{
this.TripleTriadCardId = TripleTriadCardId;
base._002Ector(Item);
}
public unsafe override bool IsUnlocked()
{
return UIState.Instance()->IsTripleTriadCardUnlocked(TripleTriadCardId);
}
[CompilerGenerated]
public void Deconstruct(out ItemRewardDetails Item, out ushort TripleTriadCardId)
{
Item = base.Item;
TripleTriadCardId = this.TripleTriadCardId;
}
}

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using LLib.GameData;
using Questionable.Model.Questing;
namespace Questionable.Model;
internal sealed class UnlockLinkQuestInfo : IQuestInfo
{
public ElementId QuestId { get; }
public string Name { get; }
public uint IssuerDataId { get; }
public bool IsRepeatable => false;
public ImmutableList<PreviousQuestInfo> PreviousQuests => ImmutableList.Create(default(ReadOnlySpan<PreviousQuestInfo>));
public EQuestJoin PreviousQuestJoin => EQuestJoin.All;
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 => Array.Empty<EClassJob>();
public EExpansionVersion Expansion => EExpansionVersion.ARealmReborn;
public UnlockLinkQuestInfo(UnlockLinkId unlockLinkId, string name, uint issuerDataId)
{
QuestId = unlockLinkId;
Name = name;
IssuerDataId = issuerDataId;
}
}