Add cutscene talk, update EW parts

arr-p5
Liza 2024-06-01 18:46:57 +02:00
parent a5bb4f15cb
commit ab2c4f505c
Signed by: liza
GPG Key ID: 7199F8D727D55F67
31 changed files with 560 additions and 51 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "LLib"]
path = LLib
url = https://git.carvel.li/liza/LLib.git

1
LLib Submodule

@ -0,0 +1 @@
Subproject commit b5125d4b3f7cdc0c7514a01764e5b5d4d85f80a7

View File

@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Questionable", "Questionable\Questionable.csproj", "{C91EEF13-A1AC-4A40-B695-DD4E378E5989}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLib", "LLib\LLib.csproj", "{EEDE3BBE-E260-445E-8FB3-1264E0CBBE91}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -12,5 +14,9 @@ Global
{C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Release|Any CPU.Build.0 = Release|Any CPU
{EEDE3BBE-E260-445E-8FB3-1264E0CBBE91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEDE3BBE-E260-445E-8FB3-1264E0CBBE91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEDE3BBE-E260-445E-8FB3-1264E0CBBE91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEDE3BBE-E260-445E-8FB3-1264E0CBBE91}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -66,7 +66,7 @@ internal sealed class MovementController : IDisposable
}
}
else if (!Destination.IsFlying && !_condition[ConditionFlag.Mounted] && navPoints.Count > 0 &&
!_gameFunctions.HasStatusPreventingSprintOrMount())
!_gameFunctions.HasStatusPreventingSprintOrMount() && Destination.CanSprint)
{
float actualDistance = 0;
foreach (Vector3 end in navPoints)
@ -118,10 +118,19 @@ internal sealed class MovementController : IDisposable
{
if (AetheryteConverter.IsLargeAetheryte((EAetheryteLocation)Destination.DataId))
{
/*
if ((EAetheryteLocation) Destination.DataId is EAetheryteLocation.OldSharlayan
or EAetheryteLocation.UltimaThuleAbodeOfTheEa)
Stop();
// TODO verify the first part of this, is there any aetheryte like that?
// TODO Unsure if this is per-aetheryte or what; because e.g. old sharlayan is at -1.53;
// but Elpis aetherytes fail at around -0.95
if (localPlayerPosition.Y - gameObject.Position.Y < 2.95f &&
localPlayerPosition.Y - gameObject.Position.Y > -0.9f)
Stop();
*/
Stop();
}
else
{
@ -145,27 +154,27 @@ internal sealed class MovementController : IDisposable
return pointOnFloor != null && Math.Abs(pointOnFloor.Value.Y - p.Y) > 0.5f;
}
private void PrepareNavigation(EMovementType type, uint? dataId, Vector3 to, bool fly, float? stopDistance)
private void PrepareNavigation(EMovementType type, uint? dataId, Vector3 to, bool fly, bool sprint, float? stopDistance)
{
ResetPathfinding();
_gameFunctions.ExecuteCommand("/automove off");
Destination = new DestinationData(dataId, to, stopDistance ?? (DefaultStopDistance - 0.2f), fly);
Destination = new DestinationData(dataId, to, stopDistance ?? (DefaultStopDistance - 0.2f), fly, sprint);
}
public void NavigateTo(EMovementType type, uint? dataId, Vector3 to, bool fly, float? stopDistance = null)
public void NavigateTo(EMovementType type, uint? dataId, Vector3 to, bool fly, bool sprint, float? stopDistance = null)
{
PrepareNavigation(type, dataId, to, fly, stopDistance);
PrepareNavigation(type, dataId, to, fly, sprint, stopDistance);
_cancellationTokenSource = new();
_cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
_pathfindTask =
_navmeshIpc.Pathfind(_clientState.LocalPlayer!.Position, to, fly, _cancellationTokenSource.Token);
}
public void NavigateTo(EMovementType type, uint? dataId, List<Vector3> to, bool fly, float? stopDistance)
public void NavigateTo(EMovementType type, uint? dataId, List<Vector3> to, bool fly, bool sprint, float? stopDistance)
{
PrepareNavigation(type, dataId, to.Last(), fly, stopDistance);
PrepareNavigation(type, dataId, to.Last(), fly, sprint, stopDistance);
_navmeshIpc.MoveTo(to);
}
@ -198,5 +207,5 @@ internal sealed class MovementController : IDisposable
Stop();
}
public sealed record DestinationData(uint? DataId, Vector3 Position, float StopDistance, bool IsFlying);
public sealed record DestinationData(uint? DataId, Vector3 Position, float StopDistance, bool IsFlying, bool CanSprint);
}

View File

@ -3,17 +3,23 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text.Json;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI;
using LLib.GameUI;
using Lumina.Excel.CustomSheets;
using Questionable.Data;
using Questionable.External;
using Questionable.Model.V1;
using Questionable.Model.V1.Converter;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Questionable.Controller;
@ -28,6 +34,7 @@ internal sealed class QuestController
private readonly ICondition _condition;
private readonly IChatGui _chatGui;
private readonly IFramework _framework;
private readonly IGameGui _gameGui;
private readonly AetheryteData _aetheryteData;
private readonly LifestreamIpc _lifestreamIpc;
private readonly TerritoryData _territoryData;
@ -35,7 +42,8 @@ internal sealed class QuestController
public QuestController(DalamudPluginInterface pluginInterface, IDataManager dataManager, IClientState clientState,
GameFunctions gameFunctions, MovementController movementController, IPluginLog pluginLog, ICondition condition,
IChatGui chatGui, IFramework framework, AetheryteData aetheryteData, LifestreamIpc lifestreamIpc)
IChatGui chatGui, IFramework framework, IGameGui gameGui, AetheryteData aetheryteData,
LifestreamIpc lifestreamIpc)
{
_pluginInterface = pluginInterface;
_dataManager = dataManager;
@ -46,6 +54,7 @@ internal sealed class QuestController
_condition = condition;
_chatGui = chatGui;
_framework = framework;
_gameGui = gameGui;
_aetheryteData = aetheryteData;
_lifestreamIpc = lifestreamIpc;
_territoryData = new TerritoryData(dataManager);
@ -318,11 +327,45 @@ internal sealed class QuestController
}
}
if (step.SkipIf.Contains(ESkipCondition.FlyingUnlocked) && _gameFunctions.IsFlyingUnlocked(step.TerritoryId))
if (!step.SkipIf.Contains(ESkipCondition.Never))
{
_pluginLog.Information("Skipping step, as flying is unlocked");
IncreaseStepCount();
return;
_pluginLog.Information("Checking skip conditions");
if (step.SkipIf.Contains(ESkipCondition.FlyingUnlocked) &&
_gameFunctions.IsFlyingUnlocked(step.TerritoryId))
{
_pluginLog.Information("Skipping step, as flying is unlocked");
IncreaseStepCount();
return;
}
if (step is
{
DataId: not null,
InteractionType: EInteractionType.AttuneAetheryte or EInteractionType.AttuneAethernetShard
} &&
_gameFunctions.IsAetheryteUnlocked((EAetheryteLocation)step.DataId.Value))
{
_pluginLog.Information("Skipping step, as aetheryte/aethernet shard is unlocked");
IncreaseStepCount();
return;
}
if (step is { DataId: not null, InteractionType: EInteractionType.AttuneAetherCurrent } &&
_gameFunctions.IsAetherCurrentUnlocked(step.DataId.Value))
{
_pluginLog.Information("Skipping step, as current is unlocked");
IncreaseStepCount();
return;
}
QuestWork? questWork = _gameFunctions.GetQuestEx(CurrentQuest.Quest.QuestId);
if (questWork != null && step.MatchesQuestVariables(questWork.Value))
{
_pluginLog.Information("Skipping step, as quest variables match");
IncreaseStepCount();
return;
}
}
if (!CurrentQuest.StepProgress.AethernetShortcutUsed)
@ -350,7 +393,7 @@ internal sealed class QuestController
}
else
_movementController.NavigateTo(EMovementType.Quest, (uint)from, _aetheryteData.Locations[from],
false,
false, true,
AetheryteConverter.IsLargeAetheryte(from) ? 10.9f : 6.9f);
return;
@ -368,6 +411,11 @@ internal sealed class QuestController
{
_pluginLog.Information("We're at the jump destination, skipping movement");
}
else if (step.InteractionType == EInteractionType.CutsceneSelectString &&
_condition[ConditionFlag.OccupiedInCutSceneEvent])
{
_pluginLog.Information("In cutscene selection, skipping movement");
}
else if (step.Position != null)
{
float distance;
@ -413,7 +461,9 @@ internal sealed class QuestController
if (actualDistance > distance)
{
_movementController.NavigateTo(EMovementType.Quest, step.DataId, step.Position.Value,
step.Fly && _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
fly: step.Fly == true && _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType),
sprint: step.Sprint != false,
stopDistance: distance);
return;
}
}
@ -428,7 +478,9 @@ internal sealed class QuestController
distance /= 2;
_movementController.NavigateTo(EMovementType.Quest, step.DataId, [step.Position.Value],
step.Fly && _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
fly: step.Fly == true && _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType),
sprint: step.Sprint != false,
stopDistance: distance);
return;
}
}
@ -609,8 +661,8 @@ internal sealed class QuestController
else
{
_movementController.NavigateTo(EMovementType.Quest, step.DataId,
[step.JumpDestination.Position],
false, step.JumpDestination.StopDistance ?? stopDistance);
[step.JumpDestination.Position], false, false,
step.JumpDestination.StopDistance ?? stopDistance);
_framework.RunOnTick(() => ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2),
TimeSpan.FromSeconds(step.JumpDestination.DelaySeconds ?? 0.5f));
}
@ -623,6 +675,54 @@ internal sealed class QuestController
// Need to manually forward
break;
case EInteractionType.CutsceneSelectString:
// to do this automatically, should likely be in Addon's post setup
if (_gameGui.TryGetAddonByName<AddonCutSceneSelectString>("CutSceneSelectString", out var addon) &&
LAddon.IsAddonReady(&addon->AtkUnitBase))
{
foreach (DialogueChoice dialogueChoice in step.DialogueChoices)
{
var excelSheet = _dataManager.Excel.GetSheet<QuestDialogueText>(dialogueChoice.ExcelSheet);
if (excelSheet == null)
{
_pluginLog.Error($"Unknown excel sheet '{dialogueChoice.ExcelSheet}'");
continue;
}
string? excelString = excelSheet
.FirstOrDefault(x => x.Key == dialogueChoice.Answer)
?.Value
?.ToString();
if (excelString == null)
{
_pluginLog.Error(
$"Could not extract '{dialogueChoice.Answer}' from sheet '{dialogueChoice.ExcelSheet}'");
return;
}
_pluginLog.Verbose($"Looking for option '{excelString}'");
for (int i = 5; i < addon->AtkUnitBase.AtkValuesCount; ++i)
{
var atkValue = addon->AtkUnitBase.AtkValues[i];
if (atkValue.Type != ValueType.String)
continue;
string? atkString = atkValue.ReadAtkString();
_pluginLog.Verbose($"Option {i}: {atkString}");
if (excelString == atkString)
{
_pluginLog.Information($"Selecting option {i - 5}: {atkString}");
addon->AtkUnitBase.FireCallbackInt(i - 5);
return;
}
}
}
}
else if (step.DataId != null && !_condition[ConditionFlag.OccupiedInCutSceneEvent])
_gameFunctions.InteractWith(step.DataId.Value);
break;
default:
_pluginLog.Warning($"Action '{step.InteractionType}' is not implemented");
break;

View File

@ -20,6 +20,7 @@ public sealed class InteractionTypeConverter() : EnumConverter<EInteractionType>
{ EInteractionType.Duty, "Duty" },
{ EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" },
{ EInteractionType.Jump, "Jump" },
{ EInteractionType.CutsceneSelectString, "CutsceneSelectString" },
{ EInteractionType.ShouldBeAJump, "ShouldBeAJump" },
{ EInteractionType.Instruction, "Instruction" },
};

View File

@ -6,6 +6,7 @@ public sealed class SkipConditionConverter() : EnumConverter<ESkipCondition>(Val
{
private static readonly Dictionary<ESkipCondition, string> Values = new()
{
{ ESkipCondition.Never, "Never" },
{ ESkipCondition.FlyingUnlocked, "FlyingUnlocked" },
};
}

View File

@ -0,0 +1,7 @@
namespace Questionable.Model.V1;
public sealed class DialogueChoice
{
public string ExcelSheet { get; set; } = null!;
public string Answer { get; set; } = null!;
}

View File

@ -20,6 +20,7 @@ public enum EInteractionType
Duty,
SinglePlayerDuty,
Jump,
CutsceneSelectString,
/// <summary>
/// Needs to be adjusted for coords etc. in the quest data.

View File

@ -7,5 +7,6 @@ namespace Questionable.Model.V1;
public enum ESkipCondition
{
None,
Never,
FlyingUnlocked,
}

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Numerics;
using System.Text.Json.Serialization;
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
using Questionable.Model.V1.Converter;
namespace Questionable.Model.V1;
@ -21,7 +22,8 @@ public class QuestStep
public bool Disabled { get; set; }
public bool DisableNavmesh { get; set; }
public bool? Mount { get; set; }
public bool Fly { get; set; }
public bool? Fly { get; set; }
public bool? Sprint { get; set; }
public string? Comment { get; set; }
public EAetheryteLocation? AetheryteShortcut { get; set; }
@ -42,4 +44,28 @@ public class QuestStep
public uint? ContentFinderConditionId { get; set; }
public IList<ESkipCondition> SkipIf { get; set; } = new List<ESkipCondition>();
public IList<short?> CompletionQuestVariablesFlags { get; set; } = new List<short?>();
public IList<DialogueChoice> DialogueChoices { get; set; } = new List<DialogueChoice>();
public unsafe bool MatchesQuestVariables(QuestWork questWork)
{
if (CompletionQuestVariablesFlags.Count != 6)
return false;
for (int i = 0; i < 6; ++i)
{
short? check = CompletionQuestVariablesFlags[i];
if (check == null)
continue;
byte actualValue = questWork.Variables[i];
byte expectedValue = check > 0 ? (byte)check : (byte)0;
byte checkByte = check > 0 ? (byte)check : (byte)-check;
if ((actualValue & checkByte) != expectedValue)
return false;
}
return true;
}
}

View File

@ -44,7 +44,9 @@
"Z": -239.7956
},
"TerritoryId": 957,
"InteractionType": "Interact"
"InteractionType": "Interact",
"Mount": false,
"Sprint": false
}
]
},

View File

@ -44,6 +44,14 @@
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"$": "QuestVariables after: 17 0 0 0 0 64"
},
{
@ -60,6 +68,14 @@
"KillEnemyDataIds": [
14111
],
"CompletionQuestVariablesFlags": [
null,
1,
null,
null,
null,
null
],
"$": "QuestVariables after killing enemy: 17 1 0 0 0 64"
},
{
@ -71,6 +87,14 @@
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
],
"$": "QuestVariables after: 33 2 0 0 0 96"
},
{
@ -81,7 +105,16 @@
"Z": 372.54907
},
"TerritoryId": 957,
"InteractionType": "Interact"
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"$": "QuestVariables if done first: 16 16 16 0 0 128"
}
]
},

View File

@ -43,8 +43,21 @@
"Z": 799.2217
},
"TerritoryId": 957,
"InteractionType": "WaitForManualProgress",
"Comment": "Talk (2, 2, 1)"
"InteractionType": "CutsceneSelectString",
"DialogueChoices": [
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A2_000_088"
},
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A3_000_098"
},
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A5_000_107"
}
]
}
]
},
@ -59,8 +72,21 @@
"Z": 681.7273
},
"TerritoryId": 957,
"InteractionType": "WaitForManualProgress",
"Comment": "Talk (2, 1, 2)"
"InteractionType": "CutsceneSelectString",
"DialogueChoices": [
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A6_000_149"
},
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A7_000_158"
},
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A8_000_164"
}
]
}
]
},
@ -75,8 +101,21 @@
"Z": 517.72327
},
"TerritoryId": 957,
"InteractionType": "WaitForManualProgress",
"Comment": "Talk (2, 2, 2)"
"InteractionType": "CutsceneSelectString",
"DialogueChoices": [
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A9_000_200"
},
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A10_000_209"
},
{
"ExcelSheet": "quest/043/AktKma114_04370",
"Answer": "TEXT_AKTKMA114_04370_A11_000_218"
}
]
}
]
},

View File

@ -77,9 +77,9 @@
"Y": 4.357494,
"Z": 0.7476196
},
"StopDistance": 5,
"TerritoryId": 962,
"InteractionType": "Interact",
"StopDistance": 5,
"AethernetShortcut": [
"[Old Sharlayan] The Rostra",
"[Old Sharlayan] The Baldesion Annex"

View File

@ -86,7 +86,8 @@
"AethernetShortcut": [
"[Old Sharlayan] Scholar's Harbor",
"[Old Sharlayan] The Studium"
]
],
"$.1": "QuestVariables if done first: 16 16 128 0 0 128"
},
{
"DataId": 1039825,
@ -97,7 +98,6 @@
},
"TerritoryId": 962,
"InteractionType": "Interact",
"Comment": "Unsure why this is on the same Sequence No",
"AethernetShortcut": [
"[Old Sharlayan] The Studium",
"[Old Sharlayan] The Leveilleur Estate"

View File

@ -58,7 +58,7 @@
"TerritoryId": 960,
"InteractionType": "Interact",
"$.0": "[2]",
"$.2": "QuestVariables if done after [1]: 33 1 0 0 0 192"
"$.1": "QuestVariables if done after [1]: 33 1 0 0 0 192"
},
{
"DataId": 1040293,
@ -68,7 +68,9 @@
"Z": 665.5221
},
"TerritoryId": 960,
"InteractionType": "Interact"
"InteractionType": "Interact",
"$.0": "[3]",
"$.2": "QuestVariables if done first: 16 16 0 0 0 32"
}
]
},

View File

@ -31,6 +31,14 @@
"StopDistance": 8,
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"$.0": "[1]",
"$.1": "QuestVariables if done first: 1 0 0 0 0 64"
},
@ -45,6 +53,14 @@
"TerritoryId": 960,
"InteractionType": "Interact",
"$.0": "[2]",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
],
"$.1": "QuestVariables if done after [1]: 2 0 0 0 0 96"
},
{
@ -67,7 +83,16 @@
},
"StopDistance": 8,
"TerritoryId": 960,
"InteractionType": "Interact"
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"$.1": "QuestVariables if done first: 1 0 0 0 0 128"
}
]
},
@ -98,8 +123,16 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
],
"$.0": "[1]",
"$.1": "QuestVariables if done first: 1 0 0 0 0 ??"
"$.1": "QuestVariables if done first: 1 0 0 0 0 32"
},
{
"DataId": 2012282,
@ -110,6 +143,14 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"$.0": "[1]",
"$.1": "QuestVariables if done after [1]: 2 0 0 0 0 ??"
},
@ -121,7 +162,16 @@
"Z": -20.676025
},
"TerritoryId": 960,
"InteractionType": "Interact"
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"Comment": "TODO Verify quest variables flags"
}
]
},
@ -170,6 +220,7 @@
"Y": 64.78333,
"Z": -200.3357
},
"StopDistance": 8,
"TerritoryId": 960,
"InteractionType": "Interact"
}

View File

@ -82,6 +82,7 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"Mount": true,
"DisableNavmesh": true
}
]
@ -114,6 +115,14 @@
"StopDistance": 4,
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"$.0": "[1]",
"$.1": "QuestVariables if done first: 1 0 0 0 0 128"
},
@ -127,6 +136,14 @@
"StopDistance": 4,
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"$.0": "[2]",
"$.1": "QuestVariables if done after [1]: 2 0 0 0 0 192"
},
@ -152,7 +169,15 @@
"TerritoryId": 960,
"InteractionType": "Interact",
"$.0": "[3]",
"$.1": "QuestVariables if done after [2]: 3 0 0 0 0 224"
"$.1": "QuestVariables if done after [2]: 3 0 0 0 0 224",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 2012357,
@ -164,8 +189,16 @@
"StopDistance": 4,
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
],
"$.0": "[4]",
"$.1": "QuestVariables if done first: TODO"
"$.1": "QuestVariables if done first: 1 0 0 0 0 16"
}
]
},

View File

@ -101,8 +101,7 @@
"TerritoryId": 960,
"InteractionType": "AttuneAetherCurrent",
"AetheryteShortcut": "Ultima Thule - Abode of the Ea",
"AetherCurrentId": 2818390,
"Comment": "TODO Verify"
"AetherCurrentId": 2818390
},
{
"DataId": 1039778,

View File

@ -12,7 +12,7 @@
"Y": 269.0203,
"Z": -633.5393
},
"StopDistance": 5,
"StopDistance": 6,
"TerritoryId": 960,
"InteractionType": "Interact"
}

View File

@ -116,13 +116,24 @@
"AetherCurrentId": 2818396
},
{
"DataId": 2012038,
"Position": {
"X": 639.9123,
"Y": 438.7276,
"Z": 293.33954
"X": 645.6607,
"Y": 438.6276,
"Z": 291.0269
},
"StopDistance": 1,
"TerritoryId": 960,
"InteractionType": "WalkTo"
"InteractionType": "Jump",
"JumpDestination": {
"DataId": 2012038,
"Position": {
"X": 637.1709,
"Y": 439.23096,
"Z": 289.66187
},
"StopDistance": 3
}
},
{
"DataId": 2012038,

View File

@ -68,6 +68,7 @@
"Y": 417.0675,
"Z": 414.66382
},
"StopDistance": 5,
"TerritoryId": 960,
"InteractionType": "Interact"
}

View File

@ -29,6 +29,14 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"$.0": "[1]",
"$.1": "QuestVariables if done first: 16 0 0 16 0 128"
},
@ -41,6 +49,14 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
],
"$.0": "[2]",
"$.1": "QuestVariables if done after [1]: 32 16 0 16 0 144"
},
@ -53,6 +69,14 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
8
],
"$.0": "[3]",
"$.1": "QuestVariables if done after [1, 2]: 48 17 0 16 0 152"
},
@ -65,6 +89,14 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
],
"$.0": "[4]",
"$.1": "QuestVariables if done after [1, 2, 3]: 65 17 0 16 0 184"
},
@ -77,6 +109,14 @@
},
"TerritoryId": 960,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
4
],
"$.0": "[5]",
"$.1": "QuestVariables if done after [1, 2, 3, 4]: 81 17 16 16 0 188"
},
@ -88,7 +128,17 @@
"Z": 241.9928
},
"TerritoryId": 960,
"InteractionType": "Interact"
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"$.0": "[6]",
"$.1": "QuestVariables if done first: 16 0 1 0 0 64"
}
]
},
@ -146,6 +196,7 @@
"Y": 637.10297,
"Z": 5.2338257
},
"StopDistance": 5,
"TerritoryId": 960,
"InteractionType": "Interact"
}

View File

@ -69,6 +69,14 @@
"StopDistance": 5,
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
1
],
"$.0": "[1]",
"$.1": "QuestVariables if done first: 1 0 0 0 0 1"
},
@ -82,6 +90,14 @@
"StopDistance": 5,
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"$.0": "[2]",
"$.1": "QuestVariables if done after [1]: 2 0 0 0 0 129"
},
@ -94,6 +110,14 @@
},
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"$.0": "[3]",
"$.1": "QuestVariables if done after [1, 2]: 3 0 0 0 0 193"
},
@ -107,6 +131,14 @@
"StopDistance": 5,
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
],
"$.0": "[4]",
"$.1": "QuestVariables if done after [1, 2, 3]: 4 0 0 0 0 209"
},
@ -119,6 +151,14 @@
},
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
],
"$.0": "[5]",
"$.1": "QuestVariables if done after [1, 2, 3, 4]: 5 0 0 0 0 241"
},
@ -131,6 +171,14 @@
},
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
2
],
"$.0": "[6]",
"$.1": "QuestVariables if done after [1, 2, 3, 4, 5]: 6 0 0 0 0 243"
},
@ -143,6 +191,14 @@
},
"TerritoryId": 351,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
8
],
"$.0": "[7]",
"$.1": "QuestVariables if done after [1, 2, 3, 4, 5, 6]: 7 0 0 0 0 251"
},
@ -154,7 +210,16 @@
"Z": 0.1373291
},
"TerritoryId": 351,
"InteractionType": "Interact"
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
4
],
"$.2": "QuestVariables if done first: 1 0 0 0 0 0 4"
}
]
},

View File

@ -13,7 +13,8 @@
"Z": -631.281
},
"TerritoryId": 156,
"InteractionType": "Interact"
"InteractionType": "Interact",
"DisableNavmesh": true
},
{
"DataId": 1041232,

View File

@ -106,6 +106,7 @@
"Duty",
"SinglePlayerDuty",
"Jump",
"CutsceneSelectString",
"ShouldBeAJump",
"Instruction"
]
@ -129,6 +130,12 @@
"type": "boolean",
"description": "If true and flying is unlocked in a zone, will use a flight path"
},
"Sprint": {
"type": [
"boolean",
"null"
]
},
"AetheryteShortcut": {
"type": "string",
"description": "The Aetheryte to teleport to (before moving)",
@ -419,7 +426,7 @@
]
},
"ContentFinderConditionId": {
"type": "number",
"type": "integer",
"exclusiveMinimum": 0
},
"SkipIf": {
@ -428,10 +435,60 @@
"items": {
"type": "string",
"enum": [
"Never",
"FlyingUnlocked"
]
}
},
"CompletionQuestVariablesFlags": {
"type": "array",
"description": "Quest Variables that dictate whether or not this step is skipped: null is don't check, positive values need to be set, negative values need to be unset",
"items": {
"type": [
"integer",
"null"
],
"enum": [
null,
1,
2,
4,
8,
16,
32,
64,
128,
-1,
-2,
-4,
-8,
-16,
-32,
-64,
-128
]
},
"minItems": 6,
"maxItems": 6
},
"DialogueChoices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ExcelSheet": {
"type": "string"
},
"Answer": {
"type": "string"
}
},
"required": [
"ExcelSheet",
"Answer"
]
}
},
"Comment": {
"type": "string"
}

View File

@ -54,6 +54,10 @@
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LLib\LLib.csproj" />
</ItemGroup>
<!--
<ItemGroup>
<EmbeddedResource Include="QuestPaths/**/*.json"/>

View File

@ -53,7 +53,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
_movementController =
new MovementController(navmeshIpc, clientState, _gameFunctions, condition, pluginLog);
_questController = new QuestController(pluginInterface, dataManager, _clientState, _gameFunctions,
_movementController, pluginLog, condition, chatGui, framework, aetheryteData, lifestreamIpc);
_movementController, pluginLog, condition, chatGui, framework, gameGui, aetheryteData, lifestreamIpc);
_windowSystem.AddWindow(new DebugWindow(_movementController, _questController, _gameFunctions, clientState,
targetManager));
@ -88,7 +88,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
out Vector3 worldPos))
{
_movementController.NavigateTo(EMovementType.Shortcut, null, worldPos,
_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType));
_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), true);
}
}

View File

@ -147,7 +147,8 @@ internal sealed class DebugWindow : Window
if (ImGui.Button("Move to Target"))
{
_movementController.NavigateTo(EMovementType.DebugWindow, _targetManager.Target.DataId,
_targetManager.Target.Position, _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType));
_targetManager.Target.Position, _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType),
true);
}
}
else

View File

@ -21,6 +21,9 @@
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
},
"llib": {
"type": "Project"
}
}
}