--- /dev/null
+[submodule "LLib"]
+ path = LLib
+ url = https://git.carvel.li/liza/LLib.git
--- /dev/null
+Subproject commit b5125d4b3f7cdc0c7514a01764e5b5d4d85f80a7
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
{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
}
}
else if (!Destination.IsFlying && !_condition[ConditionFlag.Mounted] && navPoints.Count > 0 &&
- !_gameFunctions.HasStatusPreventingSprintOrMount())
+ !_gameFunctions.HasStatusPreventingSprintOrMount() && Destination.CanSprint)
{
float actualDistance = 0;
foreach (Vector3 end in navPoints)
{
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
{
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);
}
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);
}
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;
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;
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;
_condition = condition;
_chatGui = chatGui;
_framework = framework;
+ _gameGui = gameGui;
_aetheryteData = aetheryteData;
_lifestreamIpc = lifestreamIpc;
_territoryData = new TerritoryData(dataManager);
}
}
- 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)
}
else
_movementController.NavigateTo(EMovementType.Quest, (uint)from, _aetheryteData.Locations[from],
- false,
+ false, true,
AetheryteConverter.IsLargeAetheryte(from) ? 10.9f : 6.9f);
return;
{
_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;
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;
}
}
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;
}
}
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));
}
// 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;
{ EInteractionType.Duty, "Duty" },
{ EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" },
{ EInteractionType.Jump, "Jump" },
+ { EInteractionType.CutsceneSelectString, "CutsceneSelectString" },
{ EInteractionType.ShouldBeAJump, "ShouldBeAJump" },
{ EInteractionType.Instruction, "Instruction" },
};
{
private static readonly Dictionary<ESkipCondition, string> Values = new()
{
+ { ESkipCondition.Never, "Never" },
{ ESkipCondition.FlyingUnlocked, "FlyingUnlocked" },
};
}
--- /dev/null
+namespace Questionable.Model.V1;
+
+public sealed class DialogueChoice
+{
+ public string ExcelSheet { get; set; } = null!;
+ public string Answer { get; set; } = null!;
+}
Duty,
SinglePlayerDuty,
Jump,
+ CutsceneSelectString,
/// <summary>
/// Needs to be adjusted for coords etc. in the quest data.
public enum ESkipCondition
{
None,
+ Never,
FlyingUnlocked,
}
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;
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; }
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;
+ }
}
"Z": -239.7956
},
"TerritoryId": 957,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "Mount": false,
+ "Sprint": false
}
]
},
},
"TerritoryId": 957,
"InteractionType": "Interact",
+ "CompletionQuestVariablesFlags": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ 64
+ ],
"$": "QuestVariables after: 17 0 0 0 0 64"
},
{
"KillEnemyDataIds": [
14111
],
+ "CompletionQuestVariablesFlags": [
+ null,
+ 1,
+ null,
+ null,
+ null,
+ null
+ ],
"$": "QuestVariables after killing enemy: 17 1 0 0 0 64"
},
{
},
"TerritoryId": 957,
"InteractionType": "Interact",
+ "CompletionQuestVariablesFlags": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ 32
+ ],
"$": "QuestVariables after: 33 2 0 0 0 96"
},
{
"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"
}
]
},
"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"
+ }
+ ]
}
]
},
"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"
+ }
+ ]
}
]
},
"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"
+ }
+ ]
}
]
},
"Y": 4.357494,
"Z": 0.7476196
},
+ "StopDistance": 5,
"TerritoryId": 962,
"InteractionType": "Interact",
- "StopDistance": 5,
"AethernetShortcut": [
"[Old Sharlayan] The Rostra",
"[Old Sharlayan] The Baldesion Annex"
"AethernetShortcut": [
"[Old Sharlayan] Scholar's Harbor",
"[Old Sharlayan] The Studium"
- ]
+ ],
+ "$.1": "QuestVariables if done first: 16 16 128 0 0 128"
},
{
"DataId": 1039825,
},
"TerritoryId": 962,
"InteractionType": "Interact",
- "Comment": "Unsure why this is on the same Sequence No",
"AethernetShortcut": [
"[Old Sharlayan] The Studium",
"[Old Sharlayan] The Leveilleur Estate"
"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,
"Z": 665.5221
},
"TerritoryId": 960,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "$.0": "[3]",
+ "$.2": "QuestVariables if done first: 16 16 0 0 0 32"
}
]
},
"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"
},
"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"
},
{
},
"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"
}
]
},
},
"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,
},
"TerritoryId": 960,
"InteractionType": "Interact",
+ "CompletionQuestVariablesFlags": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ 64
+ ],
"$.0": "[1]",
"$.1": "QuestVariables if done after [1]: 2 0 0 0 0 ??"
},
"Z": -20.676025
},
"TerritoryId": 960,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "CompletionQuestVariablesFlags": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ 128
+ ],
+ "Comment": "TODO Verify quest variables flags"
}
]
},
"Y": 64.78333,
"Z": -200.3357
},
+ "StopDistance": 8,
"TerritoryId": 960,
"InteractionType": "Interact"
}
},
"TerritoryId": 960,
"InteractionType": "Interact",
+ "Mount": true,
"DisableNavmesh": true
}
]
"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"
},
"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"
},
"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,
"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"
}
]
},
"TerritoryId": 960,
"InteractionType": "AttuneAetherCurrent",
"AetheryteShortcut": "Ultima Thule - Abode of the Ea",
- "AetherCurrentId": 2818390,
- "Comment": "TODO Verify"
+ "AetherCurrentId": 2818390
},
{
"DataId": 1039778,
"Y": 269.0203,
"Z": -633.5393
},
- "StopDistance": 5,
+ "StopDistance": 6,
"TerritoryId": 960,
"InteractionType": "Interact"
}
"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,
"Y": 417.0675,
"Z": 414.66382
},
+ "StopDistance": 5,
"TerritoryId": 960,
"InteractionType": "Interact"
}
},
"TerritoryId": 960,
"InteractionType": "Interact",
+ "CompletionQuestVariablesFlags": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ 128
+ ],
"$.0": "[1]",
"$.1": "QuestVariables if done first: 16 0 0 16 0 128"
},
},
"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"
},
},
"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"
},
},
"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"
},
},
"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"
},
"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"
}
]
},
"Y": 637.10297,
"Z": 5.2338257
},
+ "StopDistance": 5,
"TerritoryId": 960,
"InteractionType": "Interact"
}
"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"
},
"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"
},
},
"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"
},
"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"
},
},
"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"
},
},
"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"
},
},
"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"
},
"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"
}
]
},
"Z": -631.281
},
"TerritoryId": 156,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "DisableNavmesh": true
},
{
"DataId": 1041232,
"Duty",
"SinglePlayerDuty",
"Jump",
+ "CutsceneSelectString",
"ShouldBeAJump",
"Instruction"
]
"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)",
]
},
"ContentFinderConditionId": {
- "type": "number",
+ "type": "integer",
"exclusiveMinimum": 0
},
"SkipIf": {
"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"
}
</Reference>
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\LLib\LLib.csproj" />
+ </ItemGroup>
+
<!--
<ItemGroup>
<EmbeddedResource Include="QuestPaths/**/*.json"/>
_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));
out Vector3 worldPos))
{
_movementController.NavigateTo(EMovementType.Shortcut, null, worldPos,
- _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType));
+ _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), true);
}
}
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
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
+ },
+ "llib": {
+ "type": "Project"
}
}
}