forked from liza/Questionable
master #3
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/10.0.0">
|
||||
<Project Sdk="Dalamud.NET.Sdk/11.0.0">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LLib\LLib.csproj" />
|
||||
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj" />
|
||||
|
2
LLib
2
LLib
@ -1 +1 @@
|
||||
Subproject commit fde09c705b648f03c287814191a554f0a4b92cc4
|
||||
Subproject commit 538329a1e80acbcd09e28bd6dd459c35b5563c0a
|
@ -142,7 +142,7 @@ internal sealed class ItemUseModule : ICombatModule
|
||||
{
|
||||
BattleChara* battleChara = (BattleChara*)gameObject.Address;
|
||||
if (_combatData.CombatItemUse.Condition == ECombatItemUseCondition.Incapacitated)
|
||||
return (battleChara->Flags2 & 128u) != 0;
|
||||
return (battleChara->CombatTagType & 128u) != 0; // FIXME 7.1
|
||||
|
||||
if (_combatData.CombatItemUse.Condition == ECombatItemUseCondition.HealthPercent)
|
||||
return (100f * battleChara->Health / battleChara->MaxHealth) < _combatData.CombatItemUse.Value;
|
||||
|
@ -82,7 +82,7 @@ internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
|
||||
|
||||
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
|
||||
float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
|
||||
float maxDistance = player.ClassJob.GameData?.Role is 3 or 4 ? 20f : 2.9f;
|
||||
float maxDistance = player.ClassJob.ValueNullable?.Role is 3 or 4 ? 20f : 2.9f;
|
||||
if (actualDistance - hitboxOffset >= maxDistance)
|
||||
{
|
||||
if (actualDistance - hitboxOffset <= 5)
|
||||
|
@ -3,11 +3,10 @@ using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model.Questing;
|
||||
using Questionable.Windows;
|
||||
using Questionable.Windows.QuestComponents;
|
||||
using Quest = Questionable.Model.Quest;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
@ -240,7 +239,7 @@ internal sealed class CommandHandler : IDisposable
|
||||
ushort? mountId = _gameFunctions.GetMountId();
|
||||
if (mountId != null)
|
||||
{
|
||||
var row = _dataManager.GetExcelSheet<Mount>()!.GetRow(mountId.Value);
|
||||
var row = _dataManager.GetExcelSheet<Mount>().GetRowOrDefault(mountId.Value);
|
||||
_chatGui.Print(
|
||||
$"Mount ID: {mountId}, Name: {row?.Singular}, Obtainable: {(row?.Order == -1 ? "No" : "Yes")}",
|
||||
MessageTag, TagColor);
|
||||
|
@ -79,7 +79,7 @@ internal sealed class ContextMenuController : IDisposable
|
||||
private void AddContextMenuEntry(IMenuOpenedArgs args, uint itemId, uint npcId, EExtendedClassJob extendedClassJob,
|
||||
string verb)
|
||||
{
|
||||
EClassJob currentClassJob = (EClassJob)_clientState.LocalPlayer!.ClassJob.Id;
|
||||
EClassJob currentClassJob = (EClassJob)_clientState.LocalPlayer!.ClassJob.RowId;
|
||||
EClassJob classJob = ClassJobUtils.AsIndividualJobs(extendedClassJob).Single();
|
||||
if (classJob != currentClassJob && currentClassJob is EClassJob.Miner or EClassJob.Botanist)
|
||||
return;
|
||||
|
@ -16,7 +16,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using LLib;
|
||||
using LLib.GameData;
|
||||
using LLib.GameUI;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
using Questionable.Data;
|
||||
@ -90,7 +90,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
_shopController = shopController;
|
||||
_logger = logger;
|
||||
|
||||
_returnRegex = _dataManager.GetExcelSheet<Addon>()!.GetRow(196)!.GetRegex(addon => addon.Text, pluginLog)!;
|
||||
_returnRegex = _dataManager.GetExcelSheet<Addon>().GetRow(196).GetRegex(addon => addon.Text, pluginLog)!;
|
||||
|
||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectString", SelectStringPostSetup);
|
||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "CutSceneSelectString", CutsceneSelectStringPostSetup);
|
||||
@ -713,7 +713,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
step.InteractionType == EInteractionType.Gather)
|
||||
{
|
||||
if (_gatheringData.TryGetGatheringPointId(step.ItemsToGather[0].ItemId,
|
||||
(EClassJob?)_clientState.LocalPlayer?.ClassJob.Id ?? EClassJob.Adventurer,
|
||||
(EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId ?? EClassJob.Adventurer,
|
||||
out GatheringPointId? gatheringPointId) &&
|
||||
_gatheringPointRegistry.TryGetGatheringPoint(gatheringPointId, out GatheringRoot? root))
|
||||
{
|
||||
@ -757,19 +757,19 @@ internal sealed class InteractionUiController : IDisposable
|
||||
[NotNullWhen(true)] out string? warpText)
|
||||
{
|
||||
var warps = _dataManager.GetExcelSheet<Warp>()!
|
||||
.Where(x => x.RowId > 0 && x.TerritoryType.Row == targetTerritoryId);
|
||||
.Where(x => x.RowId > 0 && x.TerritoryType.RowId == targetTerritoryId);
|
||||
foreach (var entry in warps)
|
||||
{
|
||||
string? excelName = entry.Name?.ToString();
|
||||
string? excelQuestion = entry.Question?.ToString();
|
||||
string? excelName = entry.Name.ToString();
|
||||
string? excelQuestion = entry.Question.ToString();
|
||||
|
||||
if (excelQuestion != null && GameFunctions.GameStringEquals(excelQuestion, actualPrompt))
|
||||
if (!string.IsNullOrEmpty(excelQuestion) && GameFunctions.GameStringEquals(excelQuestion, actualPrompt))
|
||||
{
|
||||
warpId = entry.RowId;
|
||||
warpText = excelQuestion;
|
||||
return true;
|
||||
}
|
||||
else if (excelName != null && GameFunctions.GameStringEquals(excelName, actualPrompt))
|
||||
else if (!string.IsNullOrEmpty(excelName) && GameFunctions.GameStringEquals(excelName, actualPrompt))
|
||||
{
|
||||
warpId = entry.RowId;
|
||||
warpText = excelName;
|
||||
|
@ -12,7 +12,7 @@ using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Event;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using LLib;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps;
|
||||
using Questionable.Controller.Steps.Gathering;
|
||||
|
@ -5,7 +5,7 @@ using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LLib;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps;
|
||||
|
@ -8,20 +8,14 @@ using Dalamud.Game.Gui.Toast;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using LLib;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
using Questionable.Controller.Steps.Shared;
|
||||
using Questionable.Data;
|
||||
using Questionable.External;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
using Quest = Questionable.Model.Quest;
|
||||
using Mount = Questionable.Controller.Steps.Common.Mount;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
|
||||
|
@ -225,7 +225,7 @@ internal static class DoGather
|
||||
|
||||
private EAction PickAction(EAction minerAction, EAction botanistAction)
|
||||
{
|
||||
if ((EClassJob?)clientState.LocalPlayer?.ClassJob.Id == EClassJob.Miner)
|
||||
if ((EClassJob?)clientState.LocalPlayer?.ClassJob.RowId == EClassJob.Miner)
|
||||
return minerAction;
|
||||
else
|
||||
return botanistAction;
|
||||
|
@ -193,7 +193,7 @@ internal static class DoGatherCollectable
|
||||
|
||||
private EAction PickAction(EAction minerAction, EAction botanistAction)
|
||||
{
|
||||
if ((EClassJob?)clientState.LocalPlayer?.ClassJob.Id == EClassJob.Miner)
|
||||
if ((EClassJob?)clientState.LocalPlayer?.ClassJob.RowId == EClassJob.Miner)
|
||||
return minerAction;
|
||||
else
|
||||
return botanistAction;
|
||||
|
@ -5,8 +5,7 @@ using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using LLib;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model.Questing;
|
||||
@ -63,13 +62,13 @@ internal static class EquipItem
|
||||
];
|
||||
|
||||
private int _attempts;
|
||||
private Item _item = null!;
|
||||
private Item? _item;
|
||||
private List<ushort> _targetSlots = null!;
|
||||
private DateTime _continueAt = DateTime.MaxValue;
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
_item = dataManager.GetExcelSheet<Item>()!.GetRow(Task.ItemId) ??
|
||||
_item = dataManager.GetExcelSheet<Item>().GetRowOrDefault(Task.ItemId) ??
|
||||
throw new ArgumentOutOfRangeException(nameof(Task.ItemId));
|
||||
_targetSlots = GetEquipSlot(_item) ?? throw new InvalidOperationException("Not a piece of equipment");
|
||||
|
||||
@ -118,7 +117,7 @@ internal static class EquipItem
|
||||
var itemSlot = equippedContainer->GetInventorySlot(slot);
|
||||
if (itemSlot != null && itemSlot->ItemId == Task.ItemId)
|
||||
{
|
||||
logger.LogInformation("Already equipped {Item}, skipping step", _item.Name?.ToString());
|
||||
logger.LogInformation("Already equipped {Item}, skipping step", _item?.Name.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -162,11 +161,13 @@ internal static class EquipItem
|
||||
throw new TaskException($"Could not equip item {Task.ItemId}.");
|
||||
}
|
||||
|
||||
private static List<ushort>? GetEquipSlot(Item item)
|
||||
private static List<ushort>? GetEquipSlot(Item? item)
|
||||
{
|
||||
return item.EquipSlotCategory.Row switch
|
||||
if (item == null)
|
||||
return [];
|
||||
return item.Value.EquipSlotCategory.RowId switch
|
||||
{
|
||||
>= 1 and <= 11 => [(ushort)(item.EquipSlotCategory.Row - 1)],
|
||||
>= 1 and <= 11 => [(ushort)(item.Value.EquipSlotCategory.RowId - 1)],
|
||||
12 => [11, 12], // rings
|
||||
13 => [0],
|
||||
17 => [13], // soul crystal
|
||||
|
@ -45,7 +45,7 @@ internal static class EquipRecommended
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
RecommendEquipModule.Instance()->SetupForClassJob((byte)clientState.LocalPlayer!.ClassJob.Id);
|
||||
RecommendEquipModule.Instance()->SetupForClassJob((byte)clientState.LocalPlayer!.ClassJob.RowId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.External;
|
||||
using Questionable.Model.Questing;
|
||||
@ -55,20 +55,20 @@ internal static class Craft
|
||||
return false;
|
||||
}
|
||||
|
||||
RecipeLookup? recipeLookup = dataManager.GetExcelSheet<RecipeLookup>()!.GetRow(Task.ItemId);
|
||||
RecipeLookup? recipeLookup = dataManager.GetExcelSheet<RecipeLookup>().GetRowOrDefault(Task.ItemId);
|
||||
if (recipeLookup == null)
|
||||
throw new TaskException($"Item {Task.ItemId} is not craftable");
|
||||
|
||||
uint recipeId = (EClassJob)clientState.LocalPlayer!.ClassJob.Id switch
|
||||
uint recipeId = (EClassJob)clientState.LocalPlayer!.ClassJob.RowId switch
|
||||
{
|
||||
EClassJob.Carpenter => recipeLookup.CRP.Row,
|
||||
EClassJob.Blacksmith => recipeLookup.BSM.Row,
|
||||
EClassJob.Armorer => recipeLookup.ARM.Row,
|
||||
EClassJob.Goldsmith => recipeLookup.GSM.Row,
|
||||
EClassJob.Leatherworker => recipeLookup.LTW.Row,
|
||||
EClassJob.Weaver => recipeLookup.WVR.Row,
|
||||
EClassJob.Alchemist => recipeLookup.ALC.Row,
|
||||
EClassJob.Culinarian => recipeLookup.CUL.Row,
|
||||
EClassJob.Carpenter => recipeLookup.Value.CRP.RowId,
|
||||
EClassJob.Blacksmith => recipeLookup.Value.BSM.RowId,
|
||||
EClassJob.Armorer => recipeLookup.Value.ARM.RowId,
|
||||
EClassJob.Goldsmith => recipeLookup.Value.GSM.RowId,
|
||||
EClassJob.Leatherworker => recipeLookup.Value.LTW.RowId,
|
||||
EClassJob.Weaver => recipeLookup.Value.WVR.RowId,
|
||||
EClassJob.Alchemist => recipeLookup.Value.ALC.RowId,
|
||||
EClassJob.Culinarian => recipeLookup.Value.CUL.RowId,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
@ -76,14 +76,14 @@ internal static class Craft
|
||||
{
|
||||
recipeId = new[]
|
||||
{
|
||||
recipeLookup.CRP.Row,
|
||||
recipeLookup.BSM.Row,
|
||||
recipeLookup.ARM.Row,
|
||||
recipeLookup.GSM.Row,
|
||||
recipeLookup.LTW.Row,
|
||||
recipeLookup.WVR.Row,
|
||||
recipeLookup.ALC.Row,
|
||||
recipeLookup.WVR.Row
|
||||
recipeLookup.Value.CRP.RowId,
|
||||
recipeLookup.Value.BSM.RowId,
|
||||
recipeLookup.Value.ARM.RowId,
|
||||
recipeLookup.Value.GSM.RowId,
|
||||
recipeLookup.Value.LTW.RowId,
|
||||
recipeLookup.Value.WVR.RowId,
|
||||
recipeLookup.Value.ALC.RowId,
|
||||
recipeLookup.Value.WVR.RowId
|
||||
}
|
||||
.FirstOrDefault(x => x != 0);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ internal static class Gather
|
||||
|
||||
foreach (var itemToGather in step.ItemsToGather)
|
||||
{
|
||||
EClassJob currentClassJob = (EClassJob)clientState.LocalPlayer!.ClassJob.Id;
|
||||
EClassJob currentClassJob = (EClassJob)clientState.LocalPlayer!.ClassJob.RowId;
|
||||
if (!gatheringData.TryGetGatheringPointId(itemToGather.ItemId, currentClassJob,
|
||||
out GatheringPointId? gatheringPointId))
|
||||
throw new TaskException($"No gathering point found for item {itemToGather.ItemId}");
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
@ -10,7 +9,7 @@ using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using LLib;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
using Questionable.Data;
|
||||
|
@ -239,7 +239,7 @@ internal static class SkipCondition
|
||||
{
|
||||
List<EClassJob> expectedJobs =
|
||||
step.RequiredCurrentJob.SelectMany(ClassJobUtils.AsIndividualJobs).ToList();
|
||||
EClassJob currentJob = (EClassJob)clientState.LocalPlayer!.ClassJob.Id;
|
||||
EClassJob currentJob = (EClassJob)clientState.LocalPlayer!.ClassJob.RowId;
|
||||
logger.LogInformation("Checking current job {CurrentJob} against {ExpectedJobs}", currentJob,
|
||||
string.Join(",", expectedJobs));
|
||||
if (!expectedJobs.Contains(currentJob))
|
||||
|
@ -31,7 +31,7 @@ internal static class SwitchClassJob
|
||||
{
|
||||
protected override unsafe bool StartInternal()
|
||||
{
|
||||
if (clientState.LocalPlayer!.ClassJob.Id == (uint)Task.ClassJob)
|
||||
if (clientState.LocalPlayer!.ClassJob.RowId == (uint)Task.ClassJob)
|
||||
return false;
|
||||
|
||||
var gearsetModule = RaptureGearsetModule.Instance();
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.GeneratedSheets2;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Questionable.Data;
|
||||
|
||||
@ -13,12 +13,12 @@ internal sealed class AetherCurrentData
|
||||
{
|
||||
_overworldCurrents = dataManager.GetExcelSheet<AetherCurrentCompFlgSet>()!
|
||||
.Where(x => x.RowId > 0)
|
||||
.Where(x => x.Territory.Value != null)
|
||||
.Where(x => x.Territory.IsValid)
|
||||
.ToImmutableDictionary(
|
||||
x => (ushort)x.Territory.Row,
|
||||
x => (ushort)x.Territory.RowId,
|
||||
x => x.AetherCurrents
|
||||
.Where(y => y.Row > 0 && y.Value?.Quest.Row == 0)
|
||||
.Select(y => y.Row)
|
||||
.Where(y => y.RowId > 0 && y.Value.Quest.RowId == 0)
|
||||
.Select(y => y.RowId)
|
||||
.ToImmutableList());
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Model.Common;
|
||||
|
||||
namespace Questionable.Data;
|
||||
@ -29,19 +29,19 @@ internal sealed class AetheryteData
|
||||
void ConfigureAetheryteWithPlaceName(EAetheryteLocation aetheryteLocation, uint placeNameId, ushort territoryId)
|
||||
{
|
||||
ConfigureAetheryte(aetheryteLocation,
|
||||
dataManager.GetExcelSheet<PlaceName>()!.GetRow(placeNameId)!.Name.ToDalamudString().TextValue,
|
||||
dataManager.GetExcelSheet<PlaceName>().GetRow(placeNameId).Name.ToDalamudString().TextValue,
|
||||
territoryId,
|
||||
(ushort)((int)aetheryteLocation / 100));
|
||||
}
|
||||
|
||||
foreach (var aetheryte in dataManager.GetExcelSheet<Aetheryte>()!.Where(x => x.RowId > 0))
|
||||
foreach (var aetheryte in dataManager.GetExcelSheet<Aetheryte>().Where(x => x.RowId > 0))
|
||||
{
|
||||
string? aethernetName = aetheryte.AethernetName?.Value?.Name.ToString();
|
||||
string? aethernetName = aetheryte.AethernetName.ValueNullable?.Name.ToString();
|
||||
if (!string.IsNullOrEmpty(aethernetName))
|
||||
aethernetNames[(EAetheryteLocation)aetheryte.RowId] = aethernetName;
|
||||
|
||||
if (aetheryte.Territory != null && aetheryte.Territory.Row > 0)
|
||||
territoryIds[(EAetheryteLocation)aetheryte.RowId] = (ushort)aetheryte.Territory.Row;
|
||||
if (aetheryte.Territory.RowId > 0)
|
||||
territoryIds[(EAetheryteLocation)aetheryte.RowId] = (ushort)aetheryte.Territory.RowId;
|
||||
|
||||
if (aetheryte.AethernetGroup > 0)
|
||||
aethernetGroups[(EAetheryteLocation)aetheryte.RowId] = aetheryte.AethernetGroup;
|
||||
@ -62,8 +62,8 @@ internal sealed class AetheryteData
|
||||
TerritoryIds = territoryIds.AsReadOnly();
|
||||
AethernetGroups = aethernetGroups.AsReadOnly();
|
||||
|
||||
TownTerritoryIds = dataManager.GetExcelSheet<TerritoryType>()!
|
||||
.Where(x => x.RowId > 0 && !string.IsNullOrEmpty(x.Name) && x.TerritoryIntendedUse == 0)
|
||||
TownTerritoryIds = dataManager.GetExcelSheet<TerritoryType>()
|
||||
.Where(x => x.RowId > 0 && !string.IsNullOrEmpty(x.Name.ToString()) && x.TerritoryIntendedUse.RowId == 0)
|
||||
.Select(x => (ushort)x.RowId)
|
||||
.ToList();
|
||||
}
|
||||
|
@ -3,8 +3,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Model.Gathering;
|
||||
|
||||
namespace Questionable.Data;
|
||||
@ -18,43 +17,45 @@ internal sealed class GatheringData
|
||||
|
||||
public GatheringData(IDataManager dataManager)
|
||||
{
|
||||
Dictionary<uint, uint> gatheringItemToItem = dataManager.GetExcelSheet<GatheringItem>()!
|
||||
.Where(x => x.RowId != 0 && x.Item != 0)
|
||||
.ToDictionary(x => x.RowId, x => (uint)x.Item);
|
||||
Dictionary<uint, uint> gatheringItemToItem = dataManager.GetExcelSheet<GatheringItem>()
|
||||
.Where(x => x.RowId != 0 && x.Item.RowId != 0)
|
||||
.ToDictionary(x => x.RowId, x => x.Item.RowId);
|
||||
|
||||
foreach (var gatheringPointBase in dataManager.GetExcelSheet<GatheringPointBase>()!)
|
||||
foreach (var gatheringPointBase in dataManager.GetExcelSheet<GatheringPointBase>())
|
||||
{
|
||||
foreach (var gatheringItemId in gatheringPointBase.Item.Where(x => x != 0))
|
||||
foreach (var gatheringItem in gatheringPointBase.Item.Where(x => x.RowId != 0))
|
||||
{
|
||||
if (gatheringItemToItem.TryGetValue((uint)gatheringItemId, out uint itemId))
|
||||
if (gatheringItemToItem.TryGetValue(gatheringItem.RowId, out uint itemId))
|
||||
{
|
||||
if (gatheringPointBase.GatheringType.Row is 0 or 1)
|
||||
if (gatheringPointBase.GatheringType.RowId is 0 or 1)
|
||||
_minerGatheringPoints[itemId] = new GatheringPointId((ushort)gatheringPointBase.RowId);
|
||||
else if (gatheringPointBase.GatheringType.Row is 2 or 3)
|
||||
else if (gatheringPointBase.GatheringType.RowId is 2 or 3)
|
||||
_botanistGatheringPoints[itemId] = new GatheringPointId((ushort)gatheringPointBase.RowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_itemIdToCollectability = dataManager.GetExcelSheet<SatisfactionSupply>()!
|
||||
_itemIdToCollectability = dataManager.GetSubrowExcelSheet<SatisfactionSupply>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.SelectMany(x => x)
|
||||
.Where(x => x.Slot is 2)
|
||||
.Select(x => new
|
||||
{
|
||||
ItemId = x.Item.Row,
|
||||
ItemId = x.Item.RowId,
|
||||
Collectability = x.CollectabilityHigh,
|
||||
})
|
||||
.Distinct()
|
||||
.ToDictionary(x => x.ItemId, x => x.Collectability);
|
||||
|
||||
_npcForCustomDeliveries = dataManager.GetExcelSheet<SatisfactionNpc>()!
|
||||
_npcForCustomDeliveries = dataManager.GetExcelSheet<SatisfactionNpc>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.SelectMany(x => dataManager.GetExcelSheet<SatisfactionSupply>()!
|
||||
.Where(y => y.RowId == x.SupplyIndex.Last())
|
||||
.SelectMany(x => dataManager.GetSubrowExcelSheet<SatisfactionSupply>()
|
||||
.Where(y => y.RowId == x.SatisfactionNpcParams.Last().SupplyIndex)
|
||||
.SelectMany(y => y)
|
||||
.Select(y => new
|
||||
{
|
||||
ItemId = y.Item.Row,
|
||||
NpcId = x.Npc.Row
|
||||
ItemId = y.Item.RowId,
|
||||
NpcId = x.Npc.RowId
|
||||
}))
|
||||
.Where(x => x.ItemId > 0)
|
||||
.Distinct()
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
@ -9,28 +10,36 @@ namespace Questionable.Data;
|
||||
|
||||
internal sealed class JournalData
|
||||
{
|
||||
public JournalData(IDataManager dataManager, QuestData questData)
|
||||
public JournalData(IDataManager dataManager, QuestData questData, ILogger<JournalData> logger)
|
||||
{
|
||||
var genres = dataManager.GetExcelSheet<JournalGenre>()!
|
||||
var genres = dataManager.GetExcelSheet<JournalGenre>()
|
||||
.Where(x => x.RowId > 0 && x.Icon > 0)
|
||||
.Select(x => new Genre(x, questData.GetAllByJournalGenre(x.RowId)))
|
||||
.ToList();
|
||||
foreach (var genre in genres)
|
||||
{
|
||||
logger.LogInformation("Genre {GenreId}: {GenreName} has {QuestCount} quests",
|
||||
genre.Id, genre.Name, genre.QuestCount);
|
||||
}
|
||||
logger.LogInformation("Genre count: {GenreCount}", genres.Count);
|
||||
var quest = questData.GetQuestInfo(new QuestId(5193));
|
||||
logger.LogInformation("Q: {N}, {A}, {B}", quest.Name, quest.JournalGenre, quest.IssuerDataId);
|
||||
|
||||
var limsaStart = dataManager.GetExcelSheet<QuestRedo>()!.GetRow(1)!;
|
||||
var gridaniaStart = dataManager.GetExcelSheet<QuestRedo>()!.GetRow(2)!;
|
||||
var uldahStart = dataManager.GetExcelSheet<QuestRedo>()!.GetRow(3)!;
|
||||
var limsaStart = dataManager.GetExcelSheet<QuestRedo>().GetRow(1);
|
||||
var gridaniaStart = dataManager.GetExcelSheet<QuestRedo>().GetRow(2);
|
||||
var uldahStart = dataManager.GetExcelSheet<QuestRedo>().GetRow(3);
|
||||
var genreLimsa = new Genre(uint.MaxValue - 3, "Starting in Limsa Lominsa", 1,
|
||||
new uint[] { 108, 109 }.Concat(limsaStart.Quest.Select(x => x.Row))
|
||||
new uint[] { 108, 109 }.Concat(limsaStart.QuestRedoParam.Select(x => x.Quest.RowId))
|
||||
.Where(x => x != 0)
|
||||
.Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
|
||||
.ToList());
|
||||
var genreGridania = new Genre(uint.MaxValue - 2, "Starting in Gridania", 1,
|
||||
new uint[] { 85, 123, 124 }.Concat(gridaniaStart.Quest.Select(x => x.Row))
|
||||
new uint[] { 85, 123, 124 }.Concat(gridaniaStart.QuestRedoParam.Select(x => x.Quest.RowId))
|
||||
.Where(x => x != 0)
|
||||
.Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
|
||||
.ToList());
|
||||
var genreUldah = new Genre(uint.MaxValue - 1, "Starting in Ul'dah", 1,
|
||||
new uint[] { 568, 569, 570 }.Concat(uldahStart.Quest.Select(x => x.Row))
|
||||
new uint[] { 568, 569, 570 }.Concat(uldahStart.QuestRedoParam.Select(x => x.Quest.RowId))
|
||||
.Where(x => x != 0)
|
||||
.Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
|
||||
.ToList());
|
||||
@ -41,12 +50,12 @@ internal sealed class JournalData
|
||||
genreLimsa.Quests.Contains(x) || genreGridania.Quests.Contains(x) || genreUldah.Quests.Contains(x));
|
||||
|
||||
Genres = genres.AsReadOnly();
|
||||
Categories = dataManager.GetExcelSheet<JournalCategory>()!
|
||||
Categories = dataManager.GetExcelSheet<JournalCategory>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Select(x => new Category(x, Genres.Where(y => y.CategoryId == x.RowId).ToList()))
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
Sections = dataManager.GetExcelSheet<JournalSection>()!
|
||||
Sections = dataManager.GetExcelSheet<JournalSection>()
|
||||
.Select(x => new Section(x, Categories.Where(y => y.SectionId == x.RowId).ToList()))
|
||||
.ToList();
|
||||
}
|
||||
@ -61,7 +70,7 @@ internal sealed class JournalData
|
||||
{
|
||||
Id = journalGenre.RowId;
|
||||
Name = journalGenre.Name.ToString();
|
||||
CategoryId = journalGenre.JournalCategory.Row;
|
||||
CategoryId = journalGenre.JournalCategory.RowId;
|
||||
Quests = quests;
|
||||
}
|
||||
|
||||
@ -84,7 +93,7 @@ internal sealed class JournalData
|
||||
{
|
||||
public uint Id { get; } = journalCategory.RowId;
|
||||
public string Name { get; } = journalCategory.Name.ToString();
|
||||
public uint SectionId { get; } = journalCategory.JournalSection.Row;
|
||||
public uint SectionId { get; } = journalCategory.JournalSection.RowId;
|
||||
public IReadOnlyList<Genre> Genres { get; } = genres;
|
||||
public int QuestCount => Genres.Sum(x => x.QuestCount);
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Data.Sheets;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
using Leve = Lumina.Excel.GeneratedSheets2.Leve;
|
||||
using Quest = Lumina.Excel.GeneratedSheets2.Quest;
|
||||
using Quest = Lumina.Excel.Sheets.Quest;
|
||||
|
||||
namespace Questionable.Data;
|
||||
|
||||
@ -18,13 +18,13 @@ internal sealed class QuestData
|
||||
public static readonly IReadOnlyList<QuestId> CrystalTowerQuests =
|
||||
[new(1709), new(1200), new(1201), new(1202), new(1203), new(1474), new(494), new(495)];
|
||||
|
||||
public static readonly IReadOnlyList<ushort> TankRoleQuests = [136, 154, 178];
|
||||
public static readonly IReadOnlyList<ushort> HealerRoleQuests = [137, 155, 179];
|
||||
public static readonly IReadOnlyList<ushort> MeleeRoleQuests = [138, 156, 180];
|
||||
public static readonly IReadOnlyList<ushort> PhysicalRangedRoleQuests = [138, 157, 181];
|
||||
public static readonly IReadOnlyList<ushort> CasterRoleQuests = [139, 158, 182];
|
||||
public static readonly IReadOnlyList<uint> TankRoleQuests = [136, 154, 178];
|
||||
public static readonly IReadOnlyList<uint> HealerRoleQuests = [137, 155, 179];
|
||||
public static readonly IReadOnlyList<uint> MeleeRoleQuests = [138, 156, 180];
|
||||
public static readonly IReadOnlyList<uint> PhysicalRangedRoleQuests = [138, 157, 181];
|
||||
public static readonly IReadOnlyList<uint> CasterRoleQuests = [139, 158, 182];
|
||||
|
||||
public static readonly IReadOnlyList<IReadOnlyList<ushort>> AllRoleQuestChapters =
|
||||
public static readonly IReadOnlyList<IReadOnlyList<uint>> AllRoleQuestChapters =
|
||||
[
|
||||
TankRoleQuests,
|
||||
HealerRoleQuests,
|
||||
@ -40,33 +40,33 @@ internal sealed class QuestData
|
||||
|
||||
public QuestData(IDataManager dataManager)
|
||||
{
|
||||
Dictionary<uint, ushort> questChapters =
|
||||
Dictionary<uint, uint> questChapters =
|
||||
dataManager.GetExcelSheet<QuestChapter>()!
|
||||
.Where(x => x.RowId > 0 && x.Quest.Row > 0)
|
||||
.ToDictionary(x => x.Quest.Row, x => x.Redo);
|
||||
.Where(x => x.RowId > 0 && x.Quest.RowId > 0)
|
||||
.ToDictionary(x => x.Quest.RowId, x => x.Redo.RowId);
|
||||
|
||||
Dictionary<uint, byte> startingCities = new();
|
||||
for (byte redoChapter = 1; redoChapter <= 3; ++redoChapter)
|
||||
{
|
||||
var questRedo = dataManager.GetExcelSheet<QuestRedo>()!.GetRow(redoChapter)!;
|
||||
foreach (var quest in questRedo.Quest.Where(x => x.Row > 0))
|
||||
startingCities[quest.Row] = redoChapter;
|
||||
var questRedo = dataManager.GetExcelSheet<QuestRedo>().GetRow(redoChapter);
|
||||
foreach (var quest in questRedo.QuestRedoParam.Where(x => x.Quest.IsValid))
|
||||
startingCities[quest.Quest.RowId] = redoChapter;
|
||||
}
|
||||
|
||||
List<IQuestInfo> quests =
|
||||
[
|
||||
..dataManager.GetExcelSheet<Quest>()!
|
||||
..dataManager.GetExcelSheet<QuestEx>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Where(x => x.IssuerLocation.Row > 0)
|
||||
.Where(x => x.IssuerLocation.RowId > 0)
|
||||
.Select(x => new QuestInfo(x, questChapters.GetValueOrDefault(x.RowId),
|
||||
startingCities.GetValueOrDefault(x.RowId)))
|
||||
.Where(x => x.QuestId.Value != 1428),
|
||||
..dataManager.GetExcelSheet<SatisfactionNpc>()!
|
||||
.Where(x => x.RowId > 0)
|
||||
..dataManager.GetExcelSheet<SatisfactionNpc>()
|
||||
.Where(x => x is { RowId: > 0, Npc.RowId: > 0 })
|
||||
.Select(x => new SatisfactionSupplyInfo(x)),
|
||||
..dataManager.GetExcelSheet<Leve>()!
|
||||
..dataManager.GetExcelSheet<Leve>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Where(x => x.LevelLevemete.Row != 0)
|
||||
.Where(x => x.LevelLevemete.RowId != 0)
|
||||
.Select(x => new LeveInfo(x)),
|
||||
];
|
||||
_quests = quests.ToDictionary(x => x.QuestId, x => x);
|
||||
@ -230,7 +230,7 @@ internal sealed class QuestData
|
||||
|
||||
public List<QuestInfo> GetClassJobQuests(EClassJob classJob)
|
||||
{
|
||||
List<ushort> chapterIds = classJob switch
|
||||
List<uint> chapterIds = classJob switch
|
||||
{
|
||||
EClassJob.Adventurer => throw new ArgumentOutOfRangeException(nameof(classJob)),
|
||||
|
||||
@ -308,7 +308,7 @@ internal sealed class QuestData
|
||||
return GetQuestsInNewGamePlusChapters(chapterIds);
|
||||
}
|
||||
|
||||
private List<QuestInfo> GetQuestsInNewGamePlusChapters(List<ushort> chapterIds)
|
||||
private List<QuestInfo> GetQuestsInNewGamePlusChapters(List<uint> chapterIds)
|
||||
{
|
||||
return _quests.Values
|
||||
.Where(x => x is QuestInfo)
|
||||
|
45
Questionable/Data/Sheets/QuestEx.cs
Normal file
45
Questionable/Data/Sheets/QuestEx.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
namespace Questionable.Data.Sheets;
|
||||
|
||||
// TODO Remove once fixed in dalamud
|
||||
[Sheet("Quest", 0x1F8C7430)]
|
||||
public readonly unsafe struct QuestEx(ExcelPage page, uint offset, uint row) : IExcelRow<QuestEx>
|
||||
{
|
||||
public uint RowId => row;
|
||||
|
||||
public Quest Original { get; } = new(page, offset, row);
|
||||
|
||||
public RowRef IssuerStart => RowRef.GetFirstValidRowOrUntyped(page.Module, page.ReadUInt32(offset + 2456), [typeof(EObjName), typeof(ENpcResident)], 882056187, page.Language);
|
||||
public RowRef<Level> IssuerLocation => new(page.Module, page.ReadUInt32(offset + 2460), page.Language);
|
||||
public RowRef<JournalGenre> JournalGenre => new(page.Module, page.ReadUInt32(offset + 2468), page.Language);
|
||||
public ushort SortKey => page.ReadUInt16(offset + 2502);
|
||||
public readonly RowRef<ExVersion> Expansion => new(page.Module, (uint)page.ReadUInt8(offset + 2504), page.Language);
|
||||
public readonly byte PreviousQuestJoin => page.ReadUInt8(offset + 2508);
|
||||
public readonly RowRef<ClassJobCategory> ClassJobCategory0 => new(page.Module, (uint)page.ReadUInt8(offset + 2505), page.Language);
|
||||
public readonly RowRef<ClassJobCategory> ClassJobCategory1 => new(page.Module, (uint)page.ReadUInt8(offset + 2507), page.Language);
|
||||
public readonly RowRef<Festival> Festival => new(page.Module, (uint)page.ReadUInt8(offset + 2517), page.Language);
|
||||
public readonly byte Unknown7 => page.ReadUInt8(offset + 2509);
|
||||
public readonly byte QuestLockJoin => page.ReadUInt8(offset + 2510);
|
||||
public readonly RowRef<GrandCompany> GrandCompany => new(page.Module, (uint)page.ReadUInt8(offset + 2514), page.Language);
|
||||
public readonly byte InstanceContentJoin => page.ReadUInt8(offset + 2516);
|
||||
public readonly RowRef<BeastTribe> BeastTribe => new(page.Module, (uint)page.ReadUInt8(offset + 2520), page.Language);
|
||||
public bool IsRepeatable => page.ReadPackedBool(offset + 2535, 1);
|
||||
|
||||
public readonly Collection<RowRef<Quest>> PreviousQuest => new(page, offset, offset, &PreviousQuestCtor, 3);
|
||||
private static RowRef<Quest> PreviousQuestCtor(ExcelPage page, uint parentOffset, uint offset, uint i) => new(page.Module, page.ReadUInt32(offset + 2424 + i * 4), page.Language);
|
||||
|
||||
public readonly Collection<RowRef<Quest>> QuestLock => new(page, offset, offset, &QuestLockCtor, 2);
|
||||
private static RowRef<Quest> QuestLockCtor(ExcelPage page, uint parentOffset, uint offset, uint i) => new(page.Module, page.ReadUInt32(offset + 2436 + i * 4), page.Language);
|
||||
|
||||
public readonly Collection<ushort> ClassJobLevel => new(page, offset, offset, &ClassJobLevelCtor, 2);
|
||||
private static ushort ClassJobLevelCtor(ExcelPage page, uint parentOffset, uint offset, uint i) => page.ReadUInt16(offset + 2484 + i * 2);
|
||||
|
||||
public Collection<RowRef<InstanceContent>> InstanceContent => new(page, offset, offset, &InstanceContentCtor, 3);
|
||||
private static RowRef<InstanceContent> InstanceContentCtor(ExcelPage page, uint parentOffset, uint offset, uint i) => new(page.Module, page.ReadUInt32(offset + 2444 + i * 4), page.Language);
|
||||
|
||||
static QuestEx IExcelRow<QuestEx>.Create(ExcelPage page, uint offset, uint row) =>
|
||||
new(page, offset, row);
|
||||
}
|
@ -4,7 +4,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Questionable.Data;
|
||||
|
||||
@ -13,37 +13,37 @@ internal sealed class TerritoryData
|
||||
private readonly ImmutableDictionary<uint, string> _territoryNames;
|
||||
private readonly ImmutableHashSet<ushort> _territoriesWithMount;
|
||||
private readonly ImmutableDictionary<ushort, uint> _dutyTerritories;
|
||||
private readonly ImmutableDictionary<ushort, string> _instanceNames;
|
||||
private readonly ImmutableDictionary<uint, string> _instanceNames;
|
||||
private readonly ImmutableDictionary<uint, string> _contentFinderConditionNames;
|
||||
|
||||
public TerritoryData(IDataManager dataManager)
|
||||
{
|
||||
_territoryNames = dataManager.GetExcelSheet<TerritoryType>()!
|
||||
_territoryNames = dataManager.GetExcelSheet<TerritoryType>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Select(x =>
|
||||
new
|
||||
{
|
||||
x.RowId,
|
||||
Name = x.PlaceName.Value?.Name?.ToString() ?? x.PlaceNameZone?.Value?.Name?.ToString(),
|
||||
Name = x.PlaceName.ValueNullable?.Name.ToString() ?? x.PlaceNameZone.ValueNullable?.Name.ToString(),
|
||||
})
|
||||
.Where(x => !string.IsNullOrEmpty(x.Name))
|
||||
.ToImmutableDictionary(x => x.RowId, x => x.Name!);
|
||||
|
||||
_territoriesWithMount = dataManager.GetExcelSheet<TerritoryType>()!
|
||||
_territoriesWithMount = dataManager.GetExcelSheet<TerritoryType>()
|
||||
.Where(x => x.RowId > 0 && x.Mount)
|
||||
.Select(x => (ushort)x.RowId)
|
||||
.ToImmutableHashSet();
|
||||
|
||||
_dutyTerritories = dataManager.GetExcelSheet<TerritoryType>()!
|
||||
.Where(x => x.RowId > 0 && x.ContentFinderCondition.Row != 0)
|
||||
.ToImmutableDictionary(x => (ushort)x.RowId, x => x.ContentFinderCondition.Value!.ContentType.Row);
|
||||
_dutyTerritories = dataManager.GetExcelSheet<TerritoryType>()
|
||||
.Where(x => x.RowId > 0 && x.ContentFinderCondition.RowId != 0)
|
||||
.ToImmutableDictionary(x => (ushort)x.RowId, x => x.ContentFinderCondition.Value.ContentType.RowId);
|
||||
|
||||
_instanceNames = dataManager.GetExcelSheet<ContentFinderCondition>()!
|
||||
.Where(x => x.RowId > 0 && x.Content != 0 && x.ContentLinkType == 1 && x.ContentType.Row != 6)
|
||||
.ToImmutableDictionary(x => x.Content, x => x.Name.ToString());
|
||||
_instanceNames = dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||
.Where(x => x.RowId > 0 && x.Content.RowId != 0 && x.ContentLinkType == 1 && x.ContentType.RowId != 6)
|
||||
.ToImmutableDictionary(x => x.Content.RowId, x => x.Name.ToString());
|
||||
|
||||
_contentFinderConditionNames = dataManager.GetExcelSheet<ContentFinderCondition>()!
|
||||
.Where(x => x.RowId > 0 && x.Content != 0 && x.ContentLinkType == 1 && x.ContentType.Row != 6)
|
||||
_contentFinderConditionNames = dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||
.Where(x => x.RowId > 0 && x.Content.RowId != 0 && x.ContentLinkType == 1 && x.ContentType.RowId != 6)
|
||||
.ToImmutableDictionary(x => x.RowId, x => x.Name.ToString());
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Model.Common;
|
||||
using Questionable.Model.Questing;
|
||||
using Action = Lumina.Excel.GeneratedSheets.Action;
|
||||
using Action = Lumina.Excel.Sheets.Action;
|
||||
|
||||
namespace Questionable.Functions;
|
||||
|
||||
@ -57,9 +55,10 @@ internal sealed unsafe class AetheryteFunctions
|
||||
|
||||
public bool IsTeleportUnlocked()
|
||||
{
|
||||
uint unlockLink = _dataManager.GetExcelSheet<Action>()!
|
||||
.GetRow(5)!
|
||||
.UnlockLink;
|
||||
uint unlockLink = _dataManager.GetExcelSheet<Action>()
|
||||
.GetRow(5)
|
||||
.UnlockLink
|
||||
.RowId;
|
||||
return UIState.Instance()->IsUnlockLinkUnlocked(unlockLink);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
@ -41,11 +41,11 @@ internal sealed unsafe class ChatFunctions
|
||||
_sanitiseString =
|
||||
(delegate* unmanaged<Utf8String*, int, IntPtr, void>)sigScanner.ScanText(Signatures.SanitiseString);
|
||||
|
||||
_emoteCommands = dataManager.GetExcelSheet<Emote>()!
|
||||
_emoteCommands = dataManager.GetExcelSheet<Emote>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Where(x => x.TextCommand != null && x.TextCommand.Value != null)
|
||||
.Select(x => (x.RowId, Command: x.TextCommand.Value!.Command?.ToString()))
|
||||
.Where(x => x.Command != null && x.Command.StartsWith('/'))
|
||||
.Where(x => x.TextCommand.IsValid)
|
||||
.Select(x => (x.RowId, Command: x.TextCommand.Value.Command.ToString()))
|
||||
.Where(x => !string.IsNullOrEmpty(x.Command) && x.Command.StartsWith('/'))
|
||||
.ToDictionary(x => (EEmote)x.RowId, x => x.Command!)
|
||||
.AsReadOnly();
|
||||
}
|
||||
@ -156,8 +156,8 @@ internal sealed unsafe class ChatFunctions
|
||||
|
||||
private static class Signatures
|
||||
{
|
||||
internal const string SendChat = "48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9";
|
||||
internal const string SanitiseString = "E8 ?? ?? ?? ?? 48 8D 4C 24 ?? 0F B6 F0 E8 ?? ?? ?? ?? 48 8D 4D C0";
|
||||
internal const string SendChat = "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F2 48 8B F9 45 84 C9";
|
||||
internal const string SanitiseString = "E8 ?? ?? ?? ?? EB 0A 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D AE";
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
|
@ -3,13 +3,13 @@ using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using LLib;
|
||||
using Lumina.Excel.CustomSheets;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Lumina.Text;
|
||||
using Lumina.Text.ReadOnly;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Model;
|
||||
using Quest = Questionable.Model.Quest;
|
||||
using GimmickYesNo = Lumina.Excel.GeneratedSheets2.GimmickYesNo;
|
||||
using GimmickYesNo = Lumina.Excel.Sheets.GimmickYesNo;
|
||||
|
||||
namespace Questionable.Functions;
|
||||
|
||||
@ -33,12 +33,12 @@ internal sealed class ExcelFunctions
|
||||
return new StringOrRegex(seString?.ToDalamudString().ToString());
|
||||
}
|
||||
|
||||
public SeString? GetRawDialogueText(Quest? currentQuest, string? excelSheetName, string key)
|
||||
public ReadOnlySeString? GetRawDialogueText(Quest? currentQuest, string? excelSheetName, string key)
|
||||
{
|
||||
if (currentQuest != null && excelSheetName == null)
|
||||
{
|
||||
var questRow =
|
||||
_dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets2.Quest>()!.GetRow((uint)currentQuest.Id.Value +
|
||||
_dataManager.GetExcelSheet<Lumina.Excel.Sheets.Quest>().GetRowOrDefault((uint)currentQuest.Id.Value +
|
||||
0x10000);
|
||||
if (questRow == null)
|
||||
{
|
||||
@ -46,18 +46,13 @@ internal sealed class ExcelFunctions
|
||||
return null;
|
||||
}
|
||||
|
||||
excelSheetName = $"quest/{(currentQuest.Id.Value / 100):000}/{questRow.Id}";
|
||||
excelSheetName = $"quest/{(currentQuest.Id.Value / 100):000}/{questRow.Value.RowId}";
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(excelSheetName);
|
||||
var excelSheet = _dataManager.Excel.GetSheet<QuestDialogueText>(excelSheetName);
|
||||
if (excelSheet == null)
|
||||
{
|
||||
_logger.LogError("Unknown excel sheet '{SheetName}'", excelSheetName);
|
||||
return null;
|
||||
}
|
||||
|
||||
return excelSheet.FirstOrDefault(x => x.Key == key)?.Value;
|
||||
var excelSheet = _dataManager.GetExcelSheet<QuestDialogueText>(name: excelSheetName);
|
||||
return excelSheet.Cast<QuestDialogueText?>()
|
||||
.FirstOrDefault(x => x!.Value.Key == key)?.Value;
|
||||
}
|
||||
|
||||
public StringOrRegex GetDialogueTextByRowId(string? excelSheet, uint rowId, bool isRegex)
|
||||
@ -69,36 +64,36 @@ internal sealed class ExcelFunctions
|
||||
return new StringOrRegex(seString?.ToDalamudString().ToString());
|
||||
}
|
||||
|
||||
public SeString? GetRawDialogueTextByRowId(string? excelSheet, uint rowId)
|
||||
public ReadOnlySeString? GetRawDialogueTextByRowId(string? excelSheet, uint rowId)
|
||||
{
|
||||
if (excelSheet == "GimmickYesNo")
|
||||
{
|
||||
var questRow = _dataManager.GetExcelSheet<GimmickYesNo>()!.GetRow(rowId);
|
||||
var questRow = _dataManager.GetExcelSheet<GimmickYesNo>().GetRowOrDefault(rowId);
|
||||
return questRow?.Unknown0;
|
||||
}
|
||||
else if (excelSheet == "Warp")
|
||||
{
|
||||
var questRow = _dataManager.GetExcelSheet<Warp>()!.GetRow(rowId);
|
||||
var questRow = _dataManager.GetExcelSheet<Warp>().GetRowOrDefault(rowId);
|
||||
return questRow?.Name;
|
||||
}
|
||||
else if (excelSheet is "Addon")
|
||||
{
|
||||
var questRow = _dataManager.GetExcelSheet<Addon>()!.GetRow(rowId);
|
||||
var questRow = _dataManager.GetExcelSheet<Addon>().GetRowOrDefault(rowId);
|
||||
return questRow?.Text;
|
||||
}
|
||||
else if (excelSheet is "EventPathMove")
|
||||
{
|
||||
var questRow = _dataManager.GetExcelSheet<EventPathMove>()!.GetRow(rowId);
|
||||
return questRow?.Unknown10;
|
||||
var questRow = _dataManager.GetExcelSheet<EventPathMove>().GetRowOrDefault(rowId);
|
||||
return questRow?.Unknown0;
|
||||
}
|
||||
else if (excelSheet is "GilShop")
|
||||
{
|
||||
var questRow = _dataManager.GetExcelSheet<GilShop>()!.GetRow(rowId);
|
||||
var questRow = _dataManager.GetExcelSheet<GilShop>().GetRowOrDefault(rowId);
|
||||
return questRow?.Name;
|
||||
}
|
||||
else if (excelSheet is "ContentTalk" or null)
|
||||
{
|
||||
var questRow = _dataManager.GetExcelSheet<ContentTalk>()!.GetRow(rowId);
|
||||
var questRow = _dataManager.GetExcelSheet<ContentTalk>().GetRowOrDefault(rowId);
|
||||
return questRow?.Text;
|
||||
}
|
||||
else
|
||||
|
@ -14,23 +14,22 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using LLib.GameUI;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Common;
|
||||
using Questionable.Model.Questing;
|
||||
using Action = Lumina.Excel.GeneratedSheets2.Action;
|
||||
using Action = Lumina.Excel.Sheets.Action;
|
||||
using BattleChara = FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara;
|
||||
using ContentFinderCondition = Lumina.Excel.GeneratedSheets.ContentFinderCondition;
|
||||
using ContentFinderCondition = Lumina.Excel.Sheets.ContentFinderCondition;
|
||||
using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind;
|
||||
using Quest = Questionable.Model.Quest;
|
||||
using TerritoryType = Lumina.Excel.GeneratedSheets.TerritoryType;
|
||||
|
||||
namespace Questionable.Functions;
|
||||
|
||||
internal sealed unsafe class GameFunctions
|
||||
{
|
||||
private readonly ReadOnlyDictionary<ushort, byte> _territoryToAetherCurrentCompFlgSet;
|
||||
private readonly ReadOnlyDictionary<uint, ushort> _contentFinderConditionToContentId;
|
||||
private readonly ReadOnlyDictionary<uint, uint> _contentFinderConditionToContentId;
|
||||
|
||||
private readonly QuestFunctions _questFunctions;
|
||||
private readonly IDataManager _dataManager;
|
||||
@ -63,14 +62,15 @@ internal sealed unsafe class GameFunctions
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
|
||||
_territoryToAetherCurrentCompFlgSet = dataManager.GetExcelSheet<TerritoryType>()!
|
||||
_territoryToAetherCurrentCompFlgSet = dataManager.GetExcelSheet<TerritoryType>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Where(x => x.Unknown32 > 0)
|
||||
.ToDictionary(x => (ushort)x.RowId, x => x.Unknown32)
|
||||
.Where(x => x.Unknown3 > 0)
|
||||
.ToDictionary(x => (ushort)x.RowId, x => x.Unknown4)
|
||||
.AsReadOnly();
|
||||
_contentFinderConditionToContentId = dataManager.GetExcelSheet<ContentFinderCondition>()!
|
||||
.Where(x => x.RowId > 0 && x.Content > 0)
|
||||
.ToDictionary(x => x.RowId, x => x.Content)
|
||||
_territoryToAetherCurrentCompFlgSet = new Dictionary<ushort, byte>().AsReadOnly();
|
||||
_contentFinderConditionToContentId = dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||
.Where(x => x.RowId > 0 && x.Content.RowId > 0)
|
||||
.ToDictionary(x => x.RowId, x => x.Content.RowId)
|
||||
.AsReadOnly();
|
||||
}
|
||||
|
||||
@ -220,7 +220,7 @@ internal sealed unsafe class GameFunctions
|
||||
|
||||
public bool UseAction(IGameObject gameObject, EAction action, bool checkCanUse = true)
|
||||
{
|
||||
var actionRow = _dataManager.GetExcelSheet<Action>()!.GetRow((uint)action)!;
|
||||
var actionRow = _dataManager.GetExcelSheet<Action>().GetRow((uint)action);
|
||||
if (checkCanUse && !ActionManager.CanUseActionOnTarget((uint)action, (GameObject*)gameObject.Address))
|
||||
{
|
||||
_logger.LogWarning("Can not use action {Action} on target {Target}", action, gameObject);
|
||||
@ -378,7 +378,7 @@ internal sealed unsafe class GameFunctions
|
||||
|
||||
public void OpenDutyFinder(uint contentFinderConditionId)
|
||||
{
|
||||
if (_contentFinderConditionToContentId.TryGetValue(contentFinderConditionId, out ushort contentId))
|
||||
if (_contentFinderConditionToContentId.TryGetValue(contentFinderConditionId, out uint contentId))
|
||||
{
|
||||
if (UIState.IsInstanceContentUnlocked(contentId))
|
||||
AgentContentsFinder.Instance()->OpenRegularDuty(contentFinderConditionId);
|
||||
|
@ -11,7 +11,7 @@ using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using LLib.GameData;
|
||||
using LLib.GameUI;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
using Questionable.Data;
|
||||
@ -311,8 +311,8 @@ internal sealed unsafe class QuestFunctions
|
||||
..QuestData.CrystalTowerQuests
|
||||
];
|
||||
|
||||
EClassJob classJob = (EClassJob?)_clientState.LocalPlayer?.ClassJob.Id ?? EClassJob.Adventurer;
|
||||
ushort[] shadowbringersRoleQuestChapters = QuestData.AllRoleQuestChapters.Select(x => x[0]).ToArray();
|
||||
EClassJob classJob = (EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId ?? EClassJob.Adventurer;
|
||||
uint[] shadowbringersRoleQuestChapters = QuestData.AllRoleQuestChapters.Select(x => x[0]).ToArray();
|
||||
if (classJob != EClassJob.Adventurer)
|
||||
{
|
||||
priorityQuests.AddRange(_questRegistry.GetKnownClassJobQuests(classJob)
|
||||
@ -460,7 +460,7 @@ internal sealed unsafe class QuestFunctions
|
||||
|
||||
// this only checks for the current class
|
||||
IQuestInfo questInfo = _questData.GetQuestInfo(leveId);
|
||||
if (!questInfo.ClassJobs.Contains((EClassJob)_clientState.LocalPlayer!.ClassJob.Id) ||
|
||||
if (!questInfo.ClassJobs.Contains((EClassJob)_clientState.LocalPlayer!.ClassJob.RowId) ||
|
||||
questInfo.Level > _clientState.LocalPlayer.Level)
|
||||
return true;
|
||||
|
||||
@ -597,7 +597,7 @@ internal sealed unsafe class QuestFunctions
|
||||
public bool IsClassJobUnlocked(EClassJob classJob)
|
||||
{
|
||||
var classJobRow = _dataManager.GetExcelSheet<ClassJob>()!.GetRow((uint)classJob)!;
|
||||
var questId = (ushort)classJobRow.UnlockQuest.Row;
|
||||
var questId = (ushort)classJobRow.UnlockQuest.RowId;
|
||||
if (questId != 0)
|
||||
return IsQuestComplete(new QuestId(questId));
|
||||
|
||||
@ -608,7 +608,7 @@ internal sealed unsafe class QuestFunctions
|
||||
public bool IsJobUnlocked(EClassJob classJob)
|
||||
{
|
||||
var classJobRow = _dataManager.GetExcelSheet<ClassJob>()!.GetRow((uint)classJob)!;
|
||||
return IsClassJobUnlocked((EClassJob)classJobRow.ClassJobParent.Row);
|
||||
return IsClassJobUnlocked((EClassJob)classJobRow.ClassJobParent.RowId);
|
||||
}
|
||||
|
||||
public GrandCompany GetGrandCompany()
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets2;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Model;
|
||||
@ -11,13 +11,13 @@ internal sealed class LeveInfo : IQuestInfo
|
||||
public LeveInfo(Leve leve)
|
||||
{
|
||||
QuestId = new LeveId((ushort)leve.RowId);
|
||||
Name = leve.Name;
|
||||
Name = leve.Name.ToString();
|
||||
Level = leve.ClassJobLevel;
|
||||
JournalGenre = leve.JournalGenre.Row;
|
||||
JournalGenre = leve.JournalGenre.RowId;
|
||||
SortKey = QuestId.Value;
|
||||
IssuerDataId = leve.LevelLevemete.Value!.Object.Row;
|
||||
ClassJobs = QuestInfoUtils.AsList(leve.ClassJobCategory.Value!);
|
||||
Expansion = (EExpansionVersion)leve.LevelLevemete.Value.Territory.Value!.ExVersion.Row;
|
||||
IssuerDataId = leve.LevelLevemete.Value.Object.RowId;
|
||||
ClassJobs = QuestInfoUtils.AsList(leve.ClassJobCategory.Value);
|
||||
Expansion = (EExpansionVersion)leve.LevelLevemete.Value.Territory.Value.ExVersion.RowId;
|
||||
}
|
||||
|
||||
public ElementId QuestId { get; }
|
||||
|
@ -3,16 +3,15 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using JetBrains.Annotations;
|
||||
using LLib.GameData;
|
||||
using Questionable.Data.Sheets;
|
||||
using Questionable.Model.Questing;
|
||||
using ExcelQuest = Lumina.Excel.GeneratedSheets2.Quest;
|
||||
|
||||
namespace Questionable.Model;
|
||||
|
||||
internal sealed class QuestInfo : IQuestInfo
|
||||
{
|
||||
public QuestInfo(ExcelQuest quest, ushort newGamePlusChapter, byte startingCity)
|
||||
public QuestInfo(QuestEx quest, uint newGamePlusChapter, byte startingCity)
|
||||
{
|
||||
QuestId = new QuestId((ushort)(quest.RowId & 0xFFFF));
|
||||
|
||||
@ -34,38 +33,38 @@ internal sealed class QuestInfo : IQuestInfo
|
||||
_ => "",
|
||||
};
|
||||
|
||||
Name = $"{quest.Name}{suffix}";
|
||||
Name = $"{quest.Original.Name}{suffix}";
|
||||
Level = quest.ClassJobLevel[0];
|
||||
IssuerDataId = quest.IssuerStart.Row;
|
||||
IssuerDataId = quest.IssuerStart.RowId;
|
||||
IsRepeatable = quest.IsRepeatable;
|
||||
PreviousQuests =
|
||||
new List<PreviousQuestInfo>
|
||||
{
|
||||
new(new QuestId((ushort)(quest.PreviousQuest[0].Row & 0xFFFF)), quest.Unknown7),
|
||||
new(new QuestId((ushort)(quest.PreviousQuest[1].Row & 0xFFFF))),
|
||||
new(new QuestId((ushort)(quest.PreviousQuest[2].Row & 0xFFFF)))
|
||||
new(new QuestId((ushort)(quest.PreviousQuest[0].RowId & 0xFFFF)), quest.Unknown7),
|
||||
new(new QuestId((ushort)(quest.PreviousQuest[1].RowId & 0xFFFF))),
|
||||
new(new QuestId((ushort)(quest.PreviousQuest[2].RowId & 0xFFFF)))
|
||||
}
|
||||
.Where(x => x.QuestId.Value != 0)
|
||||
.ToImmutableList();
|
||||
PreviousQuestJoin = (EQuestJoin)quest.PreviousQuestJoin;
|
||||
QuestLocks = quest.QuestLock
|
||||
.Select(x => new QuestId((ushort)(x.Row & 0xFFFFF)))
|
||||
.Select(x => new QuestId((ushort)(x.RowId & 0xFFFFF)))
|
||||
.Where(x => x.Value != 0)
|
||||
.ToImmutableList();
|
||||
QuestLockJoin = (EQuestJoin)quest.QuestLockJoin;
|
||||
JournalGenre = quest.JournalGenre?.Row;
|
||||
JournalGenre = quest.JournalGenre.ValueNullable?.RowId;
|
||||
SortKey = quest.SortKey;
|
||||
IsMainScenarioQuest = quest.JournalGenre?.Value?.JournalCategory?.Value?.JournalSection?.Row is 0 or 1;
|
||||
CompletesInstantly = quest.TodoParams[0].ToDoCompleteSeq == 0;
|
||||
PreviousInstanceContent = quest.InstanceContent.Select(x => (ushort)x.Row).Where(x => x != 0).ToList();
|
||||
IsMainScenarioQuest = quest.JournalGenre.ValueNullable?.JournalCategory.ValueNullable?.JournalSection.ValueNullable?.RowId is 0 or 1;
|
||||
CompletesInstantly = quest.Original.TodoParams[0].ToDoCompleteSeq == 0;
|
||||
PreviousInstanceContent = quest.InstanceContent.Select(x => (ushort)x.RowId).Where(x => x != 0).ToList();
|
||||
PreviousInstanceContentJoin = (EQuestJoin)quest.InstanceContentJoin;
|
||||
GrandCompany = (GrandCompany)quest.GrandCompany.Row;
|
||||
AlliedSociety = (EAlliedSociety)quest.BeastTribe.Row;
|
||||
ClassJobs = QuestInfoUtils.AsList(quest.ClassJobCategory0.Value!);
|
||||
IsSeasonalEvent = quest.Festival.Row != 0;
|
||||
GrandCompany = (GrandCompany)quest.GrandCompany.RowId;
|
||||
AlliedSociety = (EAlliedSociety)quest.BeastTribe.RowId;
|
||||
ClassJobs = QuestInfoUtils.AsList(quest.ClassJobCategory0.ValueNullable!);
|
||||
IsSeasonalEvent = quest.Festival.RowId != 0;
|
||||
NewGamePlusChapter = newGamePlusChapter;
|
||||
StartingCity = startingCity;
|
||||
Expansion = (EExpansionVersion)quest.Expansion.Row;
|
||||
Expansion = (EExpansionVersion)quest.Expansion.RowId;
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +87,7 @@ internal sealed class QuestInfo : IQuestInfo
|
||||
public EAlliedSociety AlliedSociety { get; }
|
||||
public IReadOnlyList<EClassJob> ClassJobs { get; }
|
||||
public bool IsSeasonalEvent { get; }
|
||||
public ushort NewGamePlusChapter { get; }
|
||||
public uint NewGamePlusChapter { get; }
|
||||
public byte StartingCity { get; set; }
|
||||
public EExpansionVersion Expansion { get; }
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets2;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Questionable.Model;
|
||||
|
||||
@ -9,8 +10,12 @@ internal static class QuestInfoUtils
|
||||
{
|
||||
private static readonly Dictionary<uint, IReadOnlyList<EClassJob>> CachedClassJobs = new();
|
||||
|
||||
internal static IReadOnlyList<EClassJob> AsList(ClassJobCategory classJobCategory)
|
||||
internal static IReadOnlyList<EClassJob> AsList(ClassJobCategory? optionalClassJobCategory)
|
||||
{
|
||||
if (optionalClassJobCategory == null)
|
||||
return Enum.GetValues<EClassJob>();
|
||||
|
||||
ClassJobCategory classJobCategory = optionalClassJobCategory.Value;
|
||||
if (CachedClassJobs.TryGetValue(classJobCategory.RowId, out IReadOnlyList<EClassJob>? classJobs))
|
||||
return classJobs;
|
||||
|
||||
@ -57,8 +62,8 @@ internal static class QuestInfoUtils
|
||||
{ EClassJob.Dancer, classJobCategory.DNC },
|
||||
{ EClassJob.Reaper, classJobCategory.RPR },
|
||||
{ EClassJob.Sage, classJobCategory.SGE },
|
||||
{ EClassJob.Viper, classJobCategory.Unknown1 },
|
||||
{ EClassJob.Pictomancer, classJobCategory.Unknown2 }
|
||||
{ EClassJob.Viper, classJobCategory.VPR },
|
||||
{ EClassJob.Pictomancer, classJobCategory.PCT }
|
||||
}
|
||||
.Where(y => y.Value)
|
||||
.Select(y => y.Key)
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Model;
|
||||
@ -11,12 +11,12 @@ internal sealed class SatisfactionSupplyInfo : IQuestInfo
|
||||
public SatisfactionSupplyInfo(SatisfactionNpc npc)
|
||||
{
|
||||
QuestId = new SatisfactionSupplyNpcId((ushort)npc.RowId);
|
||||
Name = npc.Npc.Value!.Singular;
|
||||
IssuerDataId = npc.Npc.Row;
|
||||
Name = npc.Npc.Value.Singular.ToString();
|
||||
IssuerDataId = npc.Npc.RowId;
|
||||
Level = npc.LevelUnlock;
|
||||
SortKey = QuestId.Value;
|
||||
Expansion = (EExpansionVersion)npc.QuestRequired.Value!.Expansion.Row;
|
||||
PreviousQuests = [new PreviousQuestInfo(new QuestId((ushort)(npc.QuestRequired.Row & 0xFFFF)))];
|
||||
Expansion = (EExpansionVersion)npc.QuestRequired.Value!.Expansion.RowId;
|
||||
PreviousQuests = [new PreviousQuestInfo(new QuestId((ushort)(npc.QuestRequired.RowId & 0xFFFF)))];
|
||||
}
|
||||
|
||||
public ElementId QuestId { get; }
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/10.0.0">
|
||||
<Project Sdk="Dalamud.NET.Sdk/11.0.0">
|
||||
<PropertyGroup>
|
||||
<OutputPath>dist</OutputPath>
|
||||
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.Text;
|
||||
@ -10,7 +11,7 @@ using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
using LLib.ImGui;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.External;
|
||||
using GrandCompany = FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany;
|
||||
|
||||
@ -36,7 +37,7 @@ internal sealed class ConfigWindow : LWindow, IPersistableWindowConfig
|
||||
_notificationMasterIpc = notificationMasterIpc;
|
||||
_configuration = configuration;
|
||||
|
||||
var mounts = dataManager.GetExcelSheet<Mount>()!
|
||||
var mounts = dataManager.GetExcelSheet<Mount>()
|
||||
.Where(x => x is { RowId: > 0, Icon: > 0 })
|
||||
.Select(x => (MountId: x.RowId, Name: x.Singular.ToString()))
|
||||
.Where(x => !string.IsNullOrEmpty(x.Name))
|
||||
|
@ -10,7 +10,7 @@ using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using ImGuiNET;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Gathering;
|
||||
@ -44,24 +44,24 @@ internal sealed class GatheringJournalComponent
|
||||
_gatheringPointRegistry = gatheringPointRegistry;
|
||||
|
||||
// TODO some of the logic here would be better suited elsewhere, in particular the [item] → [gathering item] → [location] lookup
|
||||
var routeToGatheringPoint = dataManager.GetExcelSheet<GatheringLeveRoute>()!
|
||||
.Where(x => x.UnkData0[0].GatheringPoint != 0)
|
||||
.SelectMany(x => x.UnkData0
|
||||
.Where(y => y.GatheringPoint != 0)
|
||||
var routeToGatheringPoint = dataManager.GetExcelSheet<GatheringLeveRoute>()
|
||||
.Where(x => x.GatheringPoint[0].RowId != 0)
|
||||
.SelectMany(x => x.GatheringPoint
|
||||
.Where(y => y.RowId != 0)
|
||||
.Select(y => new
|
||||
{
|
||||
RouteId = x.RowId,
|
||||
GatheringPointId = y.GatheringPoint
|
||||
GatheringPointId = y.RowId
|
||||
}))
|
||||
.GroupBy(x => x.RouteId)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.GatheringPointId).ToList());
|
||||
var gatheringLeveSheet = dataManager.GetExcelSheet<GatheringLeve>()!;
|
||||
var territoryTypeSheet = dataManager.GetExcelSheet<TerritoryType>()!;
|
||||
var gatheringPointToLeve = dataManager.GetExcelSheet<Leve>()!
|
||||
var gatheringLeveSheet = dataManager.GetExcelSheet<GatheringLeve>();
|
||||
var territoryTypeSheet = dataManager.GetExcelSheet<TerritoryType>();
|
||||
var gatheringPointToLeve = dataManager.GetExcelSheet<Leve>()
|
||||
.Where(x => x.RowId > 0)
|
||||
.Select(x =>
|
||||
{
|
||||
uint startZonePlaceName = x.PlaceNameStartZone.Row;
|
||||
uint startZonePlaceName = x.PlaceNameStartZone.RowId;
|
||||
startZonePlaceName = startZonePlaceName switch
|
||||
{
|
||||
27 => 28, // limsa
|
||||
@ -71,16 +71,17 @@ internal sealed class GatheringJournalComponent
|
||||
_ => startZonePlaceName
|
||||
};
|
||||
|
||||
var territoryType = territoryTypeSheet.FirstOrDefault(y => startZonePlaceName == y.PlaceName.Row)
|
||||
var territoryType = territoryTypeSheet.Cast<TerritoryType?>()
|
||||
.FirstOrDefault(y => startZonePlaceName == y!.Value.PlaceName.RowId)
|
||||
?? throw new InvalidOperationException($"Unable to use {startZonePlaceName}");
|
||||
return new
|
||||
{
|
||||
LeveId = x.RowId,
|
||||
LeveName = x.Name.ToString(),
|
||||
TerritoryType = (ushort)territoryType.RowId,
|
||||
TerritoryName = territoryType.PlaceName.Value?.Name.ToString(),
|
||||
Expansion = (EExpansionVersion)territoryType.ExVersion.Row,
|
||||
GatheringLeve = gatheringLeveSheet.GetRow((uint)x.DataId),
|
||||
TerritoryName = territoryType.PlaceName.ValueNullable?.Name.ToString(),
|
||||
Expansion = (EExpansionVersion)territoryType.ExVersion.RowId,
|
||||
GatheringLeve = gatheringLeveSheet.GetRowOrDefault(x.DataId.RowId),
|
||||
};
|
||||
})
|
||||
.Where(x => x.GatheringLeve != null)
|
||||
@ -91,9 +92,9 @@ internal sealed class GatheringJournalComponent
|
||||
x.TerritoryType,
|
||||
x.TerritoryName,
|
||||
x.Expansion,
|
||||
GatheringPoints = x.GatheringLeve!.Route
|
||||
.Where(y => y.Row != 0)
|
||||
.SelectMany(y => routeToGatheringPoint[y.Row]),
|
||||
GatheringPoints = x.GatheringLeve!.Value.Route
|
||||
.Where(y => y.RowId != 0)
|
||||
.SelectMany(y => routeToGatheringPoint[y.RowId]),
|
||||
})
|
||||
.SelectMany(x => x.GatheringPoints.Select(y => new
|
||||
{
|
||||
@ -110,40 +111,40 @@ internal sealed class GatheringJournalComponent
|
||||
var itemSheet = dataManager.GetExcelSheet<Item>()!;
|
||||
|
||||
_gatheringItems = dataManager.GetExcelSheet<GatheringItem>()!
|
||||
.Where(x => x.RowId != 0 && x.GatheringItemLevel.Row != 0)
|
||||
.Where(x => x.RowId != 0 && x.GatheringItemLevel.RowId != 0)
|
||||
.Select(x => new
|
||||
{
|
||||
GatheringItemId = (int)x.RowId,
|
||||
Name = itemSheet.GetRow((uint)x.Item)?.Name.ToString()
|
||||
Name = itemSheet.GetRowOrDefault(x.Item.RowId)?.Name.ToString()
|
||||
})
|
||||
.Where(x => !string.IsNullOrEmpty(x.Name))
|
||||
.ToDictionary(x => x.GatheringItemId, x => x.Name!);
|
||||
|
||||
_gatheringPointsByExpansion = dataManager.GetExcelSheet<GatheringPoint>()!
|
||||
.Where(x => x.GatheringPointBase.Row != 0)
|
||||
.Where(x => x.GatheringPointBase.Row is < 653 or > 680) // exclude ishgard restoration phase 1
|
||||
.DistinctBy(x => x.GatheringPointBase.Row)
|
||||
.Where(x => x.GatheringPointBase.RowId != 0)
|
||||
.Where(x => x.GatheringPointBase.RowId is < 653 or > 680) // exclude ishgard restoration phase 1
|
||||
.DistinctBy(x => x.GatheringPointBase.RowId)
|
||||
.Select(x => new
|
||||
{
|
||||
GatheringPointId = x.RowId,
|
||||
Point = new DefaultGatheringPoint(new GatheringPointId((ushort)x.GatheringPointBase.Row),
|
||||
x.GatheringPointBase.Value!.GatheringType.Row switch
|
||||
Point = new DefaultGatheringPoint(new GatheringPointId((ushort)x.GatheringPointBase.RowId),
|
||||
x.GatheringPointBase.Value!.GatheringType.RowId switch
|
||||
{
|
||||
0 or 1 => EClassJob.Miner,
|
||||
2 or 3 => EClassJob.Botanist,
|
||||
_ => EClassJob.Fisher
|
||||
},
|
||||
x.GatheringPointBase.Value.GatheringLevel,
|
||||
x.GatheringPointBase.Value.Item.Where(y => y != 0).Select(y => (ushort)y).ToList(),
|
||||
(EExpansionVersion?)x.TerritoryType.Value?.ExVersion.Row ?? (EExpansionVersion)byte.MaxValue,
|
||||
(ushort)x.TerritoryType.Row,
|
||||
x.TerritoryType.Value?.PlaceName.Value?.Name.ToString(),
|
||||
$"{x.GatheringPointBase.Row} - {x.PlaceName.Value?.Name}")
|
||||
x.GatheringPointBase.Value.Item.Where(y => y.RowId != 0).Select(y => (ushort)y.RowId).ToList(),
|
||||
(EExpansionVersion?)x.TerritoryType.ValueNullable?.ExVersion.RowId ?? (EExpansionVersion)byte.MaxValue,
|
||||
(ushort)x.TerritoryType.RowId,
|
||||
x.TerritoryType.ValueNullable?.PlaceName.ValueNullable?.Name.ToString(),
|
||||
$"{x.GatheringPointBase.RowId} - {x.PlaceName.ValueNullable?.Name}")
|
||||
})
|
||||
.Where(x => x.Point.ClassJob != EClassJob.Fisher)
|
||||
.Select(x =>
|
||||
{
|
||||
if (gatheringPointToLeve.TryGetValue((int)x.GatheringPointId, out var leve))
|
||||
if (gatheringPointToLeve.TryGetValue(x.GatheringPointId, out var leve))
|
||||
{
|
||||
// it's a leve
|
||||
return x.Point with
|
||||
@ -161,9 +162,9 @@ internal sealed class GatheringJournalComponent
|
||||
var territoryType = territoryTypeSheet.GetRow(gatheringRoot.Steps.Last().TerritoryId)!;
|
||||
return x.Point with
|
||||
{
|
||||
Expansion = (EExpansionVersion)territoryType.ExVersion.Row,
|
||||
Expansion = (EExpansionVersion)territoryType.ExVersion.RowId,
|
||||
TerritoryType = (ushort)territoryType.RowId,
|
||||
TerritoryName = territoryType.PlaceName.Value?.Name.ToString(),
|
||||
TerritoryName = territoryType.PlaceName.ValueNullable?.Name.ToString(),
|
||||
};
|
||||
}
|
||||
else
|
||||
@ -429,7 +430,7 @@ internal sealed class GatheringJournalComponent
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearCounts()
|
||||
public void ClearCounts(int type, int code)
|
||||
{
|
||||
foreach (var expansion in _gatheringPointsByExpansion)
|
||||
{
|
||||
|
@ -368,7 +368,7 @@ internal sealed class QuestJournalComponent
|
||||
}
|
||||
}
|
||||
|
||||
internal void ClearCounts()
|
||||
internal void ClearCounts(int type, int code)
|
||||
{
|
||||
foreach (var genreCount in _genreCounts.ToList())
|
||||
_genreCounts[genreCount.Key] = genreCount.Value with { Completed = 0 };
|
||||
|
@ -67,7 +67,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
|
||||
#endif
|
||||
SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(200, 30),
|
||||
MinimumSize = new Vector2(230, 30),
|
||||
MaximumSize = default
|
||||
};
|
||||
RespectCloseHotkey = false;
|
||||
|
2
vendor/ECommons
vendored
2
vendor/ECommons
vendored
@ -1 +1 @@
|
||||
Subproject commit 147e12e95f2fb781f2c8ddac31d948700ed9051c
|
||||
Subproject commit 71ee09f7cc2230a73503b945422760da1368405c
|
Loading…
Reference in New Issue
Block a user