Compare commits

...

53 Commits

Author SHA1 Message Date
2ebc4b5a0d
Fix 'Operation Archon' step order 2025-01-24 20:04:32 +01:00
d85b204c79
Automatically close job bar tutorials + Lv49 novice guide 2025-01-24 19:53:20 +01:00
7731dd0658
Use Vesper Bay aetheryte tickets for 'Operation Archon' if you left the Waking Sands 2025-01-24 19:40:36 +01:00
4f61ea45ed
Update colors for some specific status/error messages 2025-01-23 01:43:20 +01:00
4e427e4309
Minor ARR updates 2025-01-23 01:42:46 +01:00
e0580239e4
Enable flight for turning in 'The Wind's Blessing' 2025-01-22 19:16:56 +01:00
5e45af38d1
Fix target switching logic in combat 2025-01-22 18:38:24 +01:00
05d6394264
Minor ARR MSQ updates 2025-01-22 18:38:08 +01:00
2cf059ec38
CodeGen update 2025-01-22 18:37:15 +01:00
b3d9ce382d
Version bump 2025-01-21 21:50:05 +01:00
3a3196d869
No longer accept the level 30 job quest if relevant aetherytes aren't unlocked 2025-01-21 21:45:01 +01:00
325d5368a5
Interrupts: Add a special case for certain movement tasks 2025-01-21 21:44:08 +01:00
3a763d625a
New experimental interrupt handler 2025-01-21 19:32:28 +01:00
f12b777d12
Update ARR Mor Dhona quests 2025-01-21 19:28:02 +01:00
4b9eae916a
Add logic for using items on the Spotted Mudpuppy in 'Factual Folklore' 2025-01-19 23:00:43 +01:00
e0f416a5cd Merge pull request '[Qitari] last qitari daily quest' (#129) from pot0to/Questionable:master into master
Reviewed-on: liza/Questionable#129
2025-01-18 17:10:01 +00:00
pot0to
b2d57ae5a7 adding new qitari quest 2025-01-17 23:48:03 -08:00
pot0to
99b5ef42a6 Merge branch 'master' of https://git.carvel.li/liza/Questionable 2025-01-17 23:35:55 -08:00
7734692b0f
Throw an exception if using aethernet doesn't work and the destination is in another territory 2025-01-16 22:55:22 +01:00
16b62316c5
Leave TextAdvance active if waiting for a new quest sequence from the server 2025-01-13 18:38:53 +01:00
a2a36c5156
Version bump 2025-01-12 17:59:10 +01:00
10b8c1ddc2
Set minimum StopDistance to navmesh step size (0.25) 2025-01-12 11:35:46 +01:00
76e8ac4995
Set minimum StopDistance to navmesh step size (0.25) 2025-01-12 02:40:09 +01:00
2ffedfa72c
Specify loop count for AD 2025-01-12 02:36:17 +01:00
a111a4f75b
Optimize combat for overworld enemies 2025-01-12 02:28:31 +01:00
97cbeada2a
Minor Azys Lla adjustments 2025-01-12 02:13:23 +01:00
a1d02cceea Merge pull request '[HW][Side Quests][Azys Lla] 14/14 remaining Azys Lla side quests' (#127) from goatzone/Questionable:azys-lla into master
Reviewed-on: liza/Questionable#127
2025-01-11 16:09:44 +00:00
ad76ccf057
Make 'CompleteQuest' work with ItemId → UseItem 2025-01-11 17:00:04 +01:00
108d103fd8
Add some extra flight steps to avoid vnav issues; fix bad NextQuestId 2025-01-11 16:54:55 +01:00
eeebebb28c Merge pull request 'New set of sidequests for Triple Triad NPCs' (#125) from Thaksin/Questionable:master into master
Reviewed-on: liza/Questionable#125
2025-01-11 14:29:34 +00:00
8200342f2f
Update icon for journal 2025-01-10 17:01:37 +01:00
93e6b6ec02
+1992 2025-01-10 15:42:38 +00:00
ec813ce9f4
+1991 2025-01-10 15:20:27 +00:00
7fe5acbaca
+1990 2025-01-10 15:07:11 +00:00
250cb44f48
+1989 2025-01-10 14:30:20 +00:00
8d4b2320fb
+1988 2025-01-10 13:58:21 +00:00
880082da0e
+1987 2025-01-10 13:35:19 +00:00
9c5fd2d3fe
+1986 2025-01-09 20:50:18 +00:00
4dc89d8ed3
GatheringPathRenderer: minor updates 2025-01-09 19:48:27 +01:00
1773afea46
GatheringPathRenderer: minor updates 2025-01-09 19:34:16 +01:00
8d18b24352
+1985 2025-01-09 16:52:15 +00:00
6e19630e60
+1984 2025-01-09 11:39:45 +00:00
8d64475f0a
+1983 2025-01-09 06:34:20 +00:00
ba5975e6ff
+1982 2025-01-09 06:15:46 +00:00
b917cd4e90
+1981 2025-01-09 06:03:06 +00:00
3889fbfb69
+1980, de-rust 1979 2025-01-09 05:51:09 +00:00
1f4dc134ef
Add third Nitowikwe quest 2025-01-08 21:49:03 +01:00
2cfc5256b9
Add second Nitowikwe quest 2025-01-08 21:38:34 +01:00
65df686329
+1979 2025-01-08 14:02:05 +00:00
90f92b9aa9
Add some Thavnair side quests 2025-01-05 15:51:20 +01:00
69e05722c8
Rework IsMainScenarioQuest to be less reliant on actual journal ids 2025-01-05 14:26:51 +01:00
563a11d47d
Override journal genre for some Radz-at-Han/Thavnair side quests 2025-01-05 14:23:38 +01:00
pot0to
3c9e14e891 Merge branch 'master' of https://git.carvel.li/liza/Questionable 2024-12-19 21:29:03 -08:00
118 changed files with 3600 additions and 114 deletions

View File

@ -1,5 +1,5 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup Condition="$(MSBuildProjectName) != 'GatheringPathRenderer'">
<Version>4.13</Version> <Version>4.15</Version>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

1
GatheringPathRenderer/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/dist

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Target Name="PackagePluginDebug" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<DalamudPackager
ProjectDir="$(ProjectDir)"
OutputPath="$(OutputPath)"
AssemblyName="$(AssemblyName)"
MakeZip="false"
VersionComponents="2"/>
</Target>
<Target Name="PackagePlugin" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
<DalamudPackager
ProjectDir="$(ProjectDir)"
OutputPath="$(OutputPath)"
AssemblyName="$(AssemblyName)"
MakeZip="true"
VersionComponents="2"
Exclude="GatheringPathRenderer.deps.json;ECommons.xml;ECommons.pdb;LLib.pdb"/>
</Target>
</Project>

View File

@ -1,4 +1,11 @@
<Project Sdk="Dalamud.NET.Sdk/11.0.0"> <Project Sdk="Dalamud.NET.Sdk/11.0.0">
<PropertyGroup>
<Version>0.1</Version>
<OutputPath>dist</OutputPath>
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LLib\LLib.csproj" /> <ProjectReference Include="..\LLib\LLib.csproj" />
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj" /> <ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj" />
@ -6,4 +13,5 @@
</ItemGroup> </ItemGroup>
<Import Project="..\LLib\LLib.targets"/> <Import Project="..\LLib\LLib.targets"/>
<Import Project="..\LLib\RenameZip.targets"/>
</Project> </Project>

View File

@ -1,6 +1,7 @@
{ {
"Name": "GatheringPathRenderer", "Name": "GatheringPathRenderer",
"Author": "Liza Carvelli", "Author": "Liza Carvelli",
"Punchline": "dev only plugin: Renders gathering location.", "Punchline": "[Questionable dev plugin]: Renders gathering location.",
"Description": "dev only plugin: Renders gathering location (without ECommons polluting the entire normal project)." "Description": "[Questionable dev plugin]: Renders gathering location using Splatoon.",
"RepoUrl": "https://git.carvel.li/liza/Questionable/src/branch/master/GatheringPathRenderer"
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
@ -17,11 +18,11 @@ using ECommons.Schedulers;
using ECommons.SplatoonAPI; using ECommons.SplatoonAPI;
using GatheringPathRenderer.Windows; using GatheringPathRenderer.Windows;
using LLib.GameData; using LLib.GameData;
using Questionable.Model;
using Questionable.Model.Gathering; using Questionable.Model.Gathering;
namespace GatheringPathRenderer; namespace GatheringPathRenderer;
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
public sealed class RendererPlugin : IDalamudPlugin public sealed class RendererPlugin : IDalamudPlugin
{ {
private const long OnTerritoryChange = -2; private const long OnTerritoryChange = -2;
@ -56,8 +57,10 @@ public sealed class RendererPlugin : IDalamudPlugin
_editorCommands = new EditorCommands(this, dataManager, commandManager, targetManager, clientState, chatGui, _editorCommands = new EditorCommands(this, dataManager, commandManager, targetManager, clientState, chatGui,
configuration); configuration);
_editorWindow = new EditorWindow(this, _editorCommands, dataManager, targetManager, clientState, objectTable) var configWindow = new ConfigWindow(pluginInterface, configuration);
_editorWindow = new EditorWindow(this, _editorCommands, dataManager, targetManager, clientState, objectTable, configWindow)
{ IsOpen = true }; { IsOpen = true };
_windowSystem.AddWindow(configWindow);
_windowSystem.AddWindow(_editorWindow); _windowSystem.AddWindow(_editorWindow);
_currentClassJob = (EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId ?? EClassJob.Adventurer; _currentClassJob = (EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId ?? EClassJob.Adventurer;
@ -78,6 +81,7 @@ public sealed class RendererPlugin : IDalamudPlugin
{ {
get get
{ {
#if DEBUG
DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Parent; DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Parent;
if (solutionDirectory != null) if (solutionDirectory != null)
{ {
@ -88,6 +92,12 @@ public sealed class RendererPlugin : IDalamudPlugin
} }
throw new Exception("Unable to resolve project path"); throw new Exception("Unable to resolve project path");
#else
var allPluginsDirectory = _pluginInterface.ConfigFile.Directory ?? throw new Exception("Unknown directory for plugin configs");
return allPluginsDirectory
.CreateSubdirectory("Questionable")
.CreateSubdirectory("GatheringPaths");
#endif
} }
} }
@ -103,12 +113,18 @@ public sealed class RendererPlugin : IDalamudPlugin
try try
{ {
foreach (var expansionFolder in ExpansionData.ExpansionFolders.Values) #if DEBUG
foreach (var expansionFolder in Questionable.Model.ExpansionData.ExpansionFolders.Values)
LoadFromDirectory( LoadFromDirectory(
new DirectoryInfo(Path.Combine(PathsDirectory.FullName, expansionFolder))); new DirectoryInfo(Path.Combine(PathsDirectory.FullName, expansionFolder)));
_pluginLog.Information( _pluginLog.Information(
$"Loaded {_gatheringLocations.Count} gathering root locations from project directory"); $"Loaded {_gatheringLocations.Count} gathering root locations from project directory");
#else
LoadFromDirectory(PathsDirectory);
_pluginLog.Information(
$"Loaded {_gatheringLocations.Count} gathering root locations from {PathsDirectory.FullName} directory");
#endif
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -0,0 +1,33 @@
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using ImGuiNET;
namespace GatheringPathRenderer.Windows;
internal sealed class ConfigWindow : Window
{
private readonly IDalamudPluginInterface _pluginInterface;
private readonly Configuration _configuration;
public ConfigWindow(IDalamudPluginInterface pluginInterface, Configuration configuration)
: base("Gathering Path Config", ImGuiWindowFlags.AlwaysAutoResize)
{
_pluginInterface = pluginInterface;
_configuration = configuration;
AllowPinning = false;
AllowClickthrough = false;
}
public override void Draw()
{
string authorName = _configuration.AuthorName;
if (ImGui.InputText("Author name for new files", ref authorName, 256))
{
_configuration.AuthorName = authorName;
Save();
}
}
private void Save() => _pluginInterface.SavePluginConfig(_configuration);
}

View File

@ -6,6 +6,7 @@ using System.Numerics;
using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
@ -32,8 +33,8 @@ internal sealed class EditorWindow : Window
_targetLocation; _targetLocation;
public EditorWindow(RendererPlugin plugin, EditorCommands editorCommands, IDataManager dataManager, public EditorWindow(RendererPlugin plugin, EditorCommands editorCommands, IDataManager dataManager,
ITargetManager targetManager, IClientState clientState, IObjectTable objectTable) ITargetManager targetManager, IClientState clientState, IObjectTable objectTable, ConfigWindow configWindow)
: base("Gathering Path Editor###QuestionableGatheringPathEditor", : base($"Gathering Path Editor {typeof(EditorWindow).Assembly.GetName().Version!.ToString(2)}###QuestionableGatheringPathEditor",
ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoNavFocus | ImGuiWindowFlags.AlwaysAutoResize) ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoNavFocus | ImGuiWindowFlags.AlwaysAutoResize)
{ {
_plugin = plugin; _plugin = plugin;
@ -48,6 +49,20 @@ internal sealed class EditorWindow : Window
MinimumSize = new Vector2(300, 100), MinimumSize = new Vector2(300, 100),
}; };
TitleBarButtons.Add(new TitleBarButton
{
Icon = FontAwesomeIcon.Cog,
IconOffset = new Vector2(1.5f, 1),
Click = _ => configWindow.IsOpen = true,
Priority = int.MinValue,
ShowTooltip = () =>
{
ImGui.BeginTooltip();
ImGui.Text("Open Configuration");
ImGui.EndTooltip();
}
});
RespectCloseHotkey = false; RespectCloseHotkey = false;
ShowCloseButton = false; ShowCloseButton = false;
AllowPinning = false; AllowPinning = false;

View File

@ -0,0 +1,138 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
"Author": "liza",
"Steps": [
{
"TerritoryId": 1190,
"InteractionType": "None"
}
],
"Groups": [
{
"Nodes": [
{
"DataId": 34920,
"Locations": [
{
"Position": {
"X": 192.6021,
"Y": 12.31054,
"Z": 631.2545
}
},
{
"Position": {
"X": 194.8373,
"Y": 12.50387,
"Z": 646.5401
}
},
{
"Position": {
"X": 180.8447,
"Y": 12.43262,
"Z": 610.7131
}
}
]
},
{
"DataId": 34919,
"Locations": [
{
"Position": {
"X": 186.171,
"Y": 12.54104,
"Z": 634.9042
}
}
]
}
]
},
{
"Nodes": [
{
"DataId": 34917,
"Locations": [
{
"Position": {
"X": 39.45634,
"Y": -0.06042051,
"Z": 502.3853
}
}
]
},
{
"DataId": 34918,
"Locations": [
{
"Position": {
"X": 46.03248,
"Y": -0.7049216,
"Z": 491.6059
}
},
{
"Position": {
"X": 36.15481,
"Y": -0.0501074,
"Z": 505.9388
}
},
{
"Position": {
"X": 24.72226,
"Y": 0.5922582,
"Z": 528.0809
}
}
]
}
]
},
{
"Nodes": [
{
"DataId": 34922,
"Locations": [
{
"Position": {
"X": 2.302937,
"Y": -4.586716,
"Z": 687.4797
}
},
{
"Position": {
"X": 30.02284,
"Y": -2.447479,
"Z": 704.4326
}
},
{
"Position": {
"X": 41.59287,
"Y": -0.8454803,
"Z": 692.0099
}
}
]
},
{
"DataId": 34921,
"Locations": [
{
"Position": {
"X": 18.47237,
"Y": -2.987581,
"Z": 690.8011
}
}
]
}
]
}
]
}

View File

@ -0,0 +1,29 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Questionable.Model.Questing;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using static Questionable.QuestPathGenerator.RoslynShortcuts;
namespace Questionable.QuestPathGenerator.RoslynElements;
internal static class CombatItemUseExtensions
{
public static ExpressionSyntax ToExpressionSyntax(this CombatItemUse combatItemuse)
{
var emptyItemuse = new CombatItemUse();
return ObjectCreationExpression(
IdentifierName(nameof(CombatItemUse)))
.WithInitializer(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(
SyntaxNodeList(
Assignment(nameof(CombatItemUse.ItemId), combatItemuse.ItemId,
emptyItemuse.ItemId)
.AsSyntaxNodeOrToken(),
Assignment(nameof(CombatItemUse.Condition), combatItemuse.Condition, emptyItemuse.Condition)
.AsSyntaxNodeOrToken(),
Assignment(nameof(combatItemuse.Value), combatItemuse.Value, emptyItemuse.Value)
.AsSyntaxNodeOrToken()))));
}
}

View File

@ -107,6 +107,9 @@ internal static class QuestStepExtensions
.AsSyntaxNodeOrToken(), .AsSyntaxNodeOrToken(),
AssignmentList(nameof(QuestStep.ComplexCombatData), step.ComplexCombatData) AssignmentList(nameof(QuestStep.ComplexCombatData), step.ComplexCombatData)
.AsSyntaxNodeOrToken(), .AsSyntaxNodeOrToken(),
Assignment(nameof(QuestStep.CombatItemUse), step.CombatItemUse,
emptyStep.CombatItemUse)
.AsSyntaxNodeOrToken(),
Assignment(nameof(QuestStep.CombatDelaySecondsAtStart), Assignment(nameof(QuestStep.CombatDelaySecondsAtStart),
step.CombatDelaySecondsAtStart, step.CombatDelaySecondsAtStart,
emptyStep.CombatDelaySecondsAtStart) emptyStep.CombatDelaySecondsAtStart)

View File

@ -71,6 +71,7 @@ public static class RoslynShortcuts
GatheringNodeGroup nodeGroup => nodeGroup.ToExpressionSyntax(), GatheringNodeGroup nodeGroup => nodeGroup.ToExpressionSyntax(),
GatheringNode nodeLocation => nodeLocation.ToExpressionSyntax(), GatheringNode nodeLocation => nodeLocation.ToExpressionSyntax(),
GatheringLocation location => location.ToExpressionSyntax(), GatheringLocation location => location.ToExpressionSyntax(),
CombatItemUse combatItemUse => combatItemUse.ToExpressionSyntax(),
not null when value.GetType().IsEnum => MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, not null when value.GetType().IsEnum => MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(value.GetType().Name), IdentifierName(value.GetType().GetEnumName(value)!)), IdentifierName(value.GetType().Name), IdentifierName(value.GetType().GetEnumName(value)!)),
_ => throw new Exception($"Unsupported data type {value.GetType()} = {value}") _ => throw new Exception($"Unsupported data type {value.GetType()} = {value}")

View File

@ -112,9 +112,18 @@
"SkipConditions": { "SkipConditions": {
"AetheryteShortcutIf": { "AetheryteShortcutIf": {
"InSameTerritory": true "InSameTerritory": true
},
"StepIf": {
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
} }
}, }
"Comment": "TODO Verify enemy id"
}, },
{ {
"DataId": 2002309, "DataId": 2002309,

View File

@ -36,6 +36,16 @@
"InteractionType": "WalkTo", "InteractionType": "WalkTo",
"TargetTerritoryId": 146 "TargetTerritoryId": 146
}, },
{
"Position": {
"X": -47.50145,
"Y": 16.362688,
"Z": -439.62503
},
"TerritoryId": 146,
"InteractionType": "WalkTo",
"$": "vnav sometimes attempts to walk to the aetheryte using exactly one waypoint between zone boundary and aetheryte, which means walking into walls"
},
{ {
"TerritoryId": 146, "TerritoryId": 146,
"InteractionType": "AttuneAetheryte", "InteractionType": "AttuneAetheryte",

View File

@ -103,7 +103,8 @@
}, },
"TerritoryId": 155, "TerritoryId": 155,
"InteractionType": "WalkTo", "InteractionType": "WalkTo",
"$": "NW Skyfire Locks door (inside)" "$": "NW Skyfire Locks door (inside)",
"Mount": true
}, },
{ {
"Position": { "Position": {

View File

@ -49,7 +49,8 @@
}, },
"TerritoryId": 155, "TerritoryId": 155,
"InteractionType": "WalkTo", "InteractionType": "WalkTo",
"Comment": "North Whitebrim, Stairs (bottom)" "Comment": "North Whitebrim, Stairs (bottom)",
"Mount": true
}, },
{ {
"Position": { "Position": {

View File

@ -35,10 +35,13 @@
"Z": 89.58569 "Z": 89.58569
}, },
"TerritoryId": 155, "TerritoryId": 155,
"InteractionType": "Instruction", "InteractionType": "Combat",
"Comment": "Use Quest item on enemy to weaken it first",
"$": "Status Effects: 22 (HP Penalty) + 62 (Damage Down)",
"EnemySpawnType": "AfterInteraction", "EnemySpawnType": "AfterInteraction",
"CombatItemUse": {
"ItemId": 2000961,
"Condition": "MissingStatus",
"Value": 22
},
"ComplexCombatData": [ "ComplexCombatData": [
{ {
"DataId": 2196 "DataId": 2196

View File

@ -76,6 +76,15 @@
{ {
"Sequence": 3, "Sequence": 3,
"Steps": [ "Steps": [
{
"Position": {
"X": 303.96317,
"Y": -36.40591,
"Z": 316.74185
},
"TerritoryId": 138,
"InteractionType": "WalkTo"
},
{ {
"DataId": 1006501, "DataId": 1006501,
"Position": { "Position": {

View File

@ -26,6 +26,15 @@
{ {
"Sequence": 1, "Sequence": 1,
"Steps": [ "Steps": [
{
"Position": {
"X": 303.96317,
"Y": -36.40591,
"Z": 316.74185
},
"TerritoryId": 138,
"InteractionType": "WalkTo"
},
{ {
"DataId": 1007640, "DataId": 1007640,
"Position": { "Position": {

View File

@ -19,6 +19,7 @@
}, },
{ {
"Sequence": 1, "Sequence": 1,
"Comment": "'Invalid target' messages can just be bad positioning?",
"Steps": [ "Steps": [
{ {
"Position": { "Position": {
@ -50,9 +51,9 @@
}, },
"TerritoryId": 156, "TerritoryId": 156,
"InteractionType": "Combat", "InteractionType": "Combat",
"DelaySecondsAtStart": 2,
"EnemySpawnType": "AfterItemUse", "EnemySpawnType": "AfterItemUse",
"ItemId": 2000766, "ItemId": 2000766,
"GroundTarget": true,
"KillEnemyDataIds": [ "KillEnemyDataIds": [
46 46
], ],
@ -86,6 +87,27 @@
64 64
] ]
}, },
{
"Position": {
"X": -219.34567,
"Y": 4.551038,
"Z": -637.8296
},
"TerritoryId": 156,
"InteractionType": "WalkTo",
"SkipConditions": {
"StepIf": {
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
8
]
}
}
},
{ {
"DataId": 2002234, "DataId": 2002234,
"Position": { "Position": {
@ -159,9 +181,9 @@
}, },
"TerritoryId": 156, "TerritoryId": 156,
"InteractionType": "Combat", "InteractionType": "Combat",
"DelaySecondsAtStart": 2,
"EnemySpawnType": "AfterItemUse", "EnemySpawnType": "AfterItemUse",
"ItemId": 2000766, "ItemId": 2000766,
"GroundTarget": true,
"KillEnemyDataIds": [ "KillEnemyDataIds": [
46 46
], ],
@ -218,7 +240,8 @@
}, },
"TerritoryId": 156, "TerritoryId": 156,
"InteractionType": "UseItem", "InteractionType": "UseItem",
"ItemId": 2000766 "ItemId": 2000766,
"DelaySecondsAtStart": 2
} }
] ]
}, },

View File

@ -72,7 +72,7 @@
"Z": -609.4606 "Z": -609.4606
}, },
"TerritoryId": 156, "TerritoryId": 156,
"InteractionType": "UseItem", "InteractionType": "SinglePlayerDuty",
"ItemId": 2000771 "ItemId": 2000771
} }
] ]

View File

@ -5,6 +5,71 @@
{ {
"Sequence": 0, "Sequence": 0,
"Steps": [ "Steps": [
{
"TerritoryId": 132,
"InteractionType": "UseItem",
"ItemId": 30362,
"TargetTerritoryId": 140,
"SkipConditions": {
"StepIf": {
"InTerritory": [
140,
212
]
}
}
},
{
"Position": {
"X": -492.96475,
"Y": 20.999884,
"Z": -380.82272
},
"TerritoryId": 140,
"InteractionType": "WalkTo",
"$": "Avoid walking around Waking Sands table",
"SkipConditions": {
"StepIf": {
"InTerritory": [
212
]
}
}
},
{
"DataId": 2001711,
"Position": {
"X": -480.9181,
"Y": 18.00103,
"Z": -386.862
},
"TerritoryId": 140,
"InteractionType": "Interact",
"TargetTerritoryId": 212,
"SkipConditions": {
"StepIf": {
"InTerritory": [
212
]
}
}
},
{
"DataId": 2001715,
"Position": {
"X": 23.23944,
"Y": 2.090454,
"Z": -0.015319824
},
"TerritoryId": 212,
"InteractionType": "Interact",
"TargetTerritoryId": 212,
"SkipConditions": {
"StepIf": {
"ExtraCondition": "WakingSandsSolar"
}
}
},
{ {
"DataId": 1006690, "DataId": 1006690,
"Position": { "Position": {
@ -29,7 +94,14 @@
}, },
"TerritoryId": 212, "TerritoryId": 212,
"InteractionType": "Interact", "InteractionType": "Interact",
"TargetTerritoryId": 212 "TargetTerritoryId": 212,
"SkipConditions": {
"StepIf": {
"InTerritory": [
140
]
}
}
}, },
{ {
"DataId": 2001716, "DataId": 2001716,
@ -40,7 +112,14 @@
}, },
"TerritoryId": 212, "TerritoryId": 212,
"InteractionType": "Interact", "InteractionType": "Interact",
"TargetTerritoryId": 140 "TargetTerritoryId": 140,
"SkipConditions": {
"StepIf": {
"InTerritory": [
140
]
}
}
}, },
{ {
"DataId": 1006578, "DataId": 1006578,

View File

@ -57,7 +57,7 @@
}, },
"TerritoryId": 152, "TerritoryId": 152,
"InteractionType": "Interact", "InteractionType": "Interact",
"StopDistance": 0.1, "StopDistance": 0.25,
"AetheryteShortcut": "East Shroud - Hawthorne Hut", "AetheryteShortcut": "East Shroud - Hawthorne Hut",
"Fly": true, "Fly": true,
"SkipConditions": { "SkipConditions": {
@ -83,7 +83,7 @@
}, },
"TerritoryId": 152, "TerritoryId": 152,
"InteractionType": "Interact", "InteractionType": "Interact",
"StopDistance": 0.1, "StopDistance": 0.25,
"AetheryteShortcut": "East Shroud - Hawthorne Hut", "AetheryteShortcut": "East Shroud - Hawthorne Hut",
"Fly": true, "Fly": true,
"SkipConditions": { "SkipConditions": {
@ -109,7 +109,7 @@
}, },
"TerritoryId": 152, "TerritoryId": 152,
"InteractionType": "Interact", "InteractionType": "Interact",
"StopDistance": 0.1, "StopDistance": 0.25,
"AetheryteShortcut": "East Shroud - Hawthorne Hut", "AetheryteShortcut": "East Shroud - Hawthorne Hut",
"Fly": true, "Fly": true,
"SkipConditions": { "SkipConditions": {

View File

@ -0,0 +1,61 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012145,
"Position": {
"X": -607.7516,
"Y": -176.4502,
"Z": -527.5502
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -441.42657,
"Y": -167.25401,
"Z": -432.4462
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4093,
"MinimumKillCount": 5
}
],
"Fly": true,
"$": "5 in close range here, so if any dead it might be a little slower.",
"$.1": "this is the area the quest suggests; there /are/ spinner-rooks sooner, and walking there at level w/o flying might cause interruption, but they're more spread out everywhere else - YMMV."
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012145,
"Position": {
"X": -607.7516,
"Y": -176.4502,
"Z": -527.5502
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,60 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012146,
"Position": {
"X": -643.76294,
"Y": -176.4502,
"Z": -527.3976
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -439.6144,
"Y": -186.3405,
"Z": -617.2911
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4092,
"MinimumKillCount": 5
}
],
"Fly": true,
"$": "by starting here we can guarantee a more sane straightline progression instead of starting in the middle, going all the way to one side, then running all the way to the other side."
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012146,
"Position": {
"X": -643.76294,
"Y": -176.4502,
"Z": -527.3976
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Azys Lla - Helix"
}
]
}
]
}

View File

@ -0,0 +1,55 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012147,
"Position": {
"X": -426.627,
"Y": -162.1281,
"Z": -328.6031
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -528.74396,
"Y": -143.65883,
"Z": -580.686
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [4503],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012147,
"Position": {
"X": -426.627,
"Y": -162.1281,
"Z": -328.6031
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,65 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012148,
"Position": {
"X": -173.2663,
"Y": -162.03395,
"Z": -510.39905
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -189.43037,
"Y": -160.1837,
"Z": -499.3027
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4091,
"MinimumKillCount": 3,
"$": "Slay clockwork paladins."
},
{
"DataId": 4090,
"MinimumKillCount": 3,
"$": "Slay clockwork engineers."
}
],
"$": "they're all around so we can just start here. possible issue with a FATE spawning here, YMMV."
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012148,
"Position": {
"X": -173.2663,
"Y": -162.03395,
"Z": -510.39905
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,61 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012289,
"Position": {
"X": 231.18933,
"Y": -72.92926,
"Z": -603.1434
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 517.51276,
"Y": -40.378292,
"Z": -785.99677
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4141,
"MinimumKillCount": 2
}
],
"Fly": true,
"$": "FATE spawns on top of the suggested area, so we move a bit east."
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012289,
"Position": {
"X": 231.18933,
"Y": -72.92926,
"Z": -603.1434
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,60 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012290,
"Position": {
"X": 760.5248,
"Y": -30.307041,
"Z": -579.67505
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 668.9029,
"Y": -86.006,
"Z": -775.5664
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4046,
"MinimumKillCount": 4
}
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012290,
"Position": {
"X": 760.5248,
"Y": -30.307041,
"Z": -579.67505
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,60 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012291,
"Position": {
"X": 804.074,
"Y": -26.326342,
"Z": -527.48914
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 355.31863,
"Y": -46.22946,
"Z": -507.70428
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4072,
"MinimumKillCount": 4
}
],
"Fly": true,
"$": "we go to the west of the marked area to avoid idling in the FATE that spawns on the east of it; we'll still path through it when we expend all the westward mobs, but that's just how they spawn, shrugging emoji."
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012291,
"Position": {
"X": 804.074,
"Y": -26.326342,
"Z": -527.48914
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,55 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012292,
"Position": {
"X": 583.9779,
"Y": 10.93506,
"Z": 100.02283
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 773.4017,
"Y": -0.06258035,
"Z": 147.04689
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"KillEnemyDataIds": [4669, 4970, 4671, 4672, 4673],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012292,
"Position": {
"X": 583.9779,
"Y": 10.93506,
"Z": 100.02283
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,60 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012293,
"Position": {
"X": 573.4187,
"Y": 13.072888,
"Z": 329.2439
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 495.16974,
"Y": 31.67624,
"Z": 517.37463
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4083,
"MinimumKillCount": 4
}
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012293,
"Position": {
"X": 573.4187,
"Y": 13.072888,
"Z": 329.2439
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,156 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012294,
"Position": {
"X": 366.4148,
"Y": 20.214104,
"Z": 756.7101
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 505.4667,
"Y": 16.87959,
"Z": 751.14856
},
"TerritoryId": 402,
"InteractionType": "WalkTo",
"Fly": true,
"$": "can get stuck on the spire structure when trying to land. could land elsewhere but we want to start with this one because it's the first on foot, so if done before flying unlocked that would necessitate walking directly past it.",
"SkipConditions": {
"StepIf": {
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
}
}
},
{
"DataId": 2005900,
"Position": {
"X": 506.76733,
"Y": 16.861145,
"Z": 750.24023
},
"TerritoryId": 402,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 2005903,
"Position": {
"X": 544.64014,
"Y": 15.945618,
"Z": 760.61633
},
"TerritoryId": 402,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
8
]
},
{
"DataId": 2005899,
"Position": {
"X": 545.4031,
"Y": 20.2182,
"Z": 802.8534
},
"TerritoryId": 402,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 2005902,
"Position": {
"X": 614.6791,
"Y": 20.2182,
"Z": 758.938
},
"TerritoryId": 402,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
]
},
{
"DataId": 2005901,
"Position": {
"X": 605.3406,
"Y": 15.945618,
"Z": 708.06433
},
"TerritoryId": 402,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012294,
"Position": {
"X": 366.4148,
"Y": 20.214104,
"Z": 756.7101
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,60 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012295,
"Position": {
"X": 214.64856,
"Y": 13.75853,
"Z": 536.9801
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 144.31177,
"Y": 5.9740877,
"Z": 387.8086
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4630,
"MinimumKillCount": 3
}
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012295,
"Position": {
"X": 214.64856,
"Y": 13.75853,
"Z": 536.9801
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,85 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012296,
"Position": {
"X": -658.32,
"Y": -75.48534,
"Z": 699.1531
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -345.30673,
"Y": -89.61499,
"Z": 353.53
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4075,
"MinimumKillCount": 3
}
],
"CompletionQuestVariablesFlags": [
{ "Low": 3 },
null,
null,
null,
null,
null
],
"Fly": true
},
{
"Position": {
"X": -553.4664,
"Y": -104.895905,
"Z": 175.68343
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4668,
"MinimumKillCount": 3
}
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012296,
"Position": {
"X": -658.32,
"Y": -75.48534,
"Z": 699.1531
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,60 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012297,
"Position": {
"X": -554.95544,
"Y": -89.69182,
"Z": 771.87756
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -679.16223,
"Y": -48.151093,
"Z": 542.7097
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"ComplexCombatData": [
{
"DataId": 4095,
"MinimumKillCount": 4
}
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012297,
"Position": {
"X": -554.95544,
"Y": -89.69182,
"Z": 771.87756
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,116 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "goatzone",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1012298,
"Position": {
"X": -192.67572,
"Y": -102.749916,
"Z": 476.9817
},
"TerritoryId": 402,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -375.98807,
"Y": -106.10026,
"Z": 710.48956
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "AutoOnEnterArea",
"ComplexCombatData": [
{
"DataId": 4493,
"MinimumKillCount": 1
}
],
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
],
"Fly": true
},
{
"Position": {
"X": -372.88766,
"Y": -105.78837,
"Z": 746.95245
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "AutoOnEnterArea",
"ComplexCombatData": [
{
"DataId": 4493,
"MinimumKillCount": 1
}
],
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"Position": {
"X": -321.94852,
"Y": -106.57244,
"Z": 716.5662
},
"TerritoryId": 402,
"InteractionType": "Combat",
"EnemySpawnType": "AutoOnEnterArea",
"ComplexCombatData": [
{
"DataId": 4493,
"MinimumKillCount": 1
}
],
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1012298,
"Position": {
"X": -192.67572,
"Y": -102.749916,
"Z": 476.9817
},
"TerritoryId": 402,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -117,9 +117,10 @@
"Z": 4.5318604 "Z": 4.5318604
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "CompleteQuest" "InteractionType": "CompleteQuest",
"NextQuestId": 1764
} }
] ]
} }
] ]
} }

View File

@ -28,7 +28,8 @@
"Z": -244.1596 "Z": -244.1596
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "Interact" "InteractionType": "Interact",
"Fly": true
} }
] ]
}, },
@ -89,9 +90,10 @@
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "CompleteQuest", "InteractionType": "CompleteQuest",
"NextQuestId": 1766 "NextQuestId": 1766,
"Fly": true
} }
] ]
} }
] ]
} }

View File

@ -28,7 +28,8 @@
"Z": -244.1596 "Z": -244.1596
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "Interact" "InteractionType": "Interact",
"Fly": true
} }
] ]
}, },
@ -58,12 +59,14 @@
"Y": 100.08534, "Y": 100.08534,
"Z": -603.926 "Z": -603.926
}, },
"StopDistance": 0.5,
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "Combat", "InteractionType": "Combat",
"KillEnemyDataIds": [ "KillEnemyDataIds": [
4468 4468
], ],
"EnemySpawnType": "AutoOnEnterArea" "EnemySpawnType": "AutoOnEnterArea",
"Fly": true
} }
] ]
}, },
@ -78,7 +81,8 @@
"Z": -503.7156 "Z": -503.7156
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "Interact" "InteractionType": "Interact",
"Fly": true
} }
] ]
}, },
@ -100,4 +104,4 @@
] ]
} }
] ]
} }

View File

@ -34,7 +34,8 @@
"DataId": 3992, "DataId": 3992,
"MinimumKillCount": 5 "MinimumKillCount": 5
} }
] ],
"Fly": true
} }
] ]
}, },
@ -50,13 +51,29 @@
"Z": 791.37854 "Z": 791.37854
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "Interact" "InteractionType": "Interact",
"AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest"
} }
] ]
}, },
{ {
"Sequence": 255, "Sequence": 255,
"Steps": [ "Steps": [
{
"Position": {
"X": -110.26132,
"Y": 153.61101,
"Z": 10.394781
},
"TerritoryId": 397,
"InteractionType": "WalkTo",
"Fly": true,
"SkipConditions": {
"StepIf": {
"Flying": "Locked"
}
}
},
{ {
"Fly": true, "Fly": true,
"DataId": 1014146, "DataId": 1014146,
@ -72,4 +89,4 @@
] ]
} }
] ]
} }

View File

@ -75,9 +75,9 @@
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "CompleteQuest", "InteractionType": "CompleteQuest",
"NextQuestId": 1983 "NextQuestId": 1893
} }
] ]
} }
] ]
} }

View File

@ -104,9 +104,10 @@
"Z": 3.829956 "Z": 3.829956
}, },
"TerritoryId": 397, "TerritoryId": 397,
"InteractionType": "CompleteQuest" "InteractionType": "CompleteQuest",
"NextQuestId": 1898
} }
] ]
} }
] ]
} }

View File

@ -36,6 +36,21 @@
{ {
"Sequence": 255, "Sequence": 255,
"Steps": [ "Steps": [
{
"Position": {
"X": -110.26132,
"Y": 153.61101,
"Z": 10.394781
},
"TerritoryId": 397,
"InteractionType": "WalkTo",
"Fly": true,
"SkipConditions": {
"StepIf": {
"Flying": "Locked"
}
}
},
{ {
"DataId": 1014719, "DataId": 1014719,
"Position": { "Position": {
@ -50,4 +65,4 @@
] ]
} }
] ]
} }

View File

@ -1,7 +1,6 @@
{ {
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json", "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza", "Author": "pot0to",
"Disabled": true,
"QuestSequence": [ "QuestSequence": [
{ {
"Sequence": 0, "Sequence": 0,
@ -9,9 +8,9 @@
{ {
"DataId": 1032643, "DataId": 1032643,
"Position": { "Position": {
"X": 787.0145, "X": 787.0145,
"Y": -45.82774, "Y": -45.82774,
"Z": -218.555 "Z": -218.555
}, },
"TerritoryId": 817, "TerritoryId": 817,
"InteractionType": "AcceptQuest" "InteractionType": "AcceptQuest"
@ -22,26 +21,56 @@
"Sequence": 255, "Sequence": 255,
"Steps": [ "Steps": [
{ {
"DataId": 33005,
"Position": { "Position": {
"X": 788.1569, "X": 214.7744,
"Y": -45.82557, "Y": -19.57758,
"Z": -212.9306 "Z": 623.6767
}, },
"TerritoryId": 817, "TerritoryId": 817,
"InteractionType": "WalkTo", "InteractionType": "Gather",
"AetheryteShortcut": "Rak'tika - Fanow", "RequiredQuestAcceptedJob": [
"Miner"
],
"ItemsToGather": [
{
"ItemId": 29537,
"ItemCount": 3
}
],
"Fly": true
},
{
"DataId": 33020,
"Position": {
"X": 226.1767,
"Y": -20.10281,
"Z": 643.5543
},
"TerritoryId": 817,
"InteractionType": "Gather",
"RequiredQuestAcceptedJob": [
"Botanist"
],
"ItemsToGather": [
{
"ItemId": 29563,
"ItemCount": 3
}
],
"Fly": true "Fly": true
}, },
{ {
"DataId": 1032643, "DataId": 1032643,
"Position": { "Position": {
"X": 787.0145, "X": 787.0145,
"Y": -45.82774, "Y": -45.82774,
"Z": -218.555 "Z": -218.555
}, },
"StopDistance": 7,
"TerritoryId": 817, "TerritoryId": 817,
"InteractionType": "CompleteQuest" "InteractionType": "CompleteQuest",
"AetheryteShortcut": "Rak'tika - Fanow",
"Fly": true
} }
] ]
} }

View File

@ -0,0 +1,72 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"Position": {
"X": 193.6185,
"Y": 1.9123514,
"Z": 713.436
},
"TerritoryId": 957,
"InteractionType": "WalkTo"
},
{
"DataId": 1037622,
"Position": {
"X": 189.94562,
"Y": 0.8560083,
"Z": 702.7896
},
"StopDistance": 0.25,
"TerritoryId": 957,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2011979,
"Position": {
"X": 236.1333,
"Y": 10.666016,
"Z": 613.27527
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"Position": {
"X": 193.6185,
"Y": 1.9123514,
"Z": 713.436
},
"TerritoryId": 957,
"InteractionType": "WalkTo",
"Fly": true
},
{
"DataId": 1037622,
"Position": {
"X": 189.94562,
"Y": 0.8560083,
"Z": 702.7896
},
"StopDistance": 0.25,
"TerritoryId": 957,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -0,0 +1,59 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1037625,
"Position": {
"X": 176.47058,
"Y": 1.8742183,
"Z": 799.2217
},
"StopDistance": 1,
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": 13.657948,
"Y": 1.6567476,
"Z": 631.81714
},
"TerritoryId": 957,
"InteractionType": "Combat",
"EnemySpawnType": "OverworldEnemies",
"KillEnemyDataIds": [
13527
],
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1037625,
"Position": {
"X": 176.47058,
"Y": 1.8742183,
"Z": 799.2217
},
"StopDistance": 1,
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,74 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1037682,
"Position": {
"X": -564.1108,
"Y": 11.802608,
"Z": 124.28467
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039378,
"Position": {
"X": -103.25781,
"Y": 2.5712337,
"Z": 597.589
},
"TerritoryId": 957,
"InteractionType": "Combat",
"EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
14119,
14120
],
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 2011933,
"Position": {
"X": -102.61694,
"Y": 3.0059814,
"Z": 598.9319
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1037682,
"Position": {
"X": -564.1108,
"Y": 11.802608,
"Z": 124.28467
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,65 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1037671,
"Position": {
"X": -554.37555,
"Y": 1.120665,
"Z": 22.690125
},
"StopDistance": 0.5,
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039384,
"Position": {
"X": 223.22424,
"Y": 10.211119,
"Z": 562.4321
},
"TerritoryId": 957,
"InteractionType": "Interact",
"AetheryteShortcut": "Thavnair - Yedlihmad",
"Fly": true,
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_AKTKZA021_04200_Q1_000_000",
"Answer": "TEXT_AKTKZA021_04200_A1_000_002"
}
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1037671,
"Position": {
"X": -554.37555,
"Y": 1.120665,
"Z": 22.690125
},
"StopDistance": 0.5,
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,104 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1039516,
"Position": {
"X": -554.89435,
"Y": 11.402609,
"Z": 125.10864
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1037680,
"Position": {
"X": -550.1946,
"Y": 1.6023201,
"Z": 50.766724
},
"StopDistance": 1,
"TerritoryId": 957,
"InteractionType": "Emote",
"Emote": "greeting",
"Fly": true,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 1037670,
"Position": {
"X": -508.84262,
"Y": -3.7109916E-05,
"Z": -20.767578
},
"TerritoryId": 957,
"InteractionType": "Emote",
"Emote": "greeting",
"Fly": true,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 1037676,
"Position": {
"X": -502.95264,
"Y": 12.375282,
"Z": 116.31946
},
"TerritoryId": 957,
"InteractionType": "Emote",
"Emote": "greeting",
"Fly": true,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1039516,
"Position": {
"X": -554.89435,
"Y": 11.402609,
"Z": 125.10864
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,110 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1039379,
"Position": {
"X": -478.3246,
"Y": 39.636753,
"Z": 95.47571
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true,
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_AKTKZA023_04202_Q1_000_000",
"Answer": "TEXT_AKTKZA023_04202_A1_000_001"
}
]
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039380,
"Position": {
"X": -386.862,
"Y": 21.832859,
"Z": 206.77502
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1039380,
"Position": {
"X": -386.862,
"Y": 21.832859,
"Z": 206.77502
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 2011911,
"Position": {
"X": -387.28925,
"Y": 21.744019,
"Z": 208.88062
},
"TerritoryId": 957,
"InteractionType": "Combat",
"EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
14118
]
}
]
},
{
"Sequence": 4,
"Steps": [
{
"DataId": 1039380,
"Position": {
"X": -386.862,
"Y": 21.832859,
"Z": 206.77502
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1039379,
"Position": {
"X": -478.3246,
"Y": 39.636753,
"Z": 95.47571
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,149 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1039365,
"Position": {
"X": -490.37924,
"Y": 5.667216,
"Z": 63.553833
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039366,
"Position": {
"X": -385.24457,
"Y": 15.095761,
"Z": 62.974
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1039367,
"Position": {
"X": -161.85254,
"Y": 32.732735,
"Z": 210.74231
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 2011903,
"Position": {
"X": -161.5473,
"Y": 32.211792,
"Z": 225.36047
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"DataId": 2011904,
"Position": {
"X": -148.57715,
"Y": 34.10388,
"Z": 207.84314
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 2011902,
"Position": {
"X": -170.21442,
"Y": 31.814941,
"Z": 193.1029
},
"TerritoryId": 957,
"InteractionType": "Combat",
"EnemySpawnType": "AfterInteraction",
"KillEnemyDataIds": [
14117
],
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
}
]
},
{
"Sequence": 4,
"Steps": [
{
"DataId": 1039367,
"Position": {
"X": -161.85254,
"Y": 32.732735,
"Z": 210.74231
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1039365,
"Position": {
"X": -490.37924,
"Y": 5.667216,
"Z": 63.553833
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,185 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1039371,
"Position": {
"X": -409.93365,
"Y": 10.751212,
"Z": 33.035767
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039372,
"Position": {
"X": 195.91052,
"Y": 4.763736,
"Z": 658.2893
},
"TerritoryId": 957,
"InteractionType": "Interact",
"AetheryteShortcut": "Thavnair - Yedlihmad"
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1039373,
"Position": {
"X": -314.6258,
"Y": 0.70631444,
"Z": 561.12
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true,
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_AKTKZA026_04205_Q1_000_000",
"Answer": "TEXT_AKTKZA026_04205_A1_000_001"
}
]
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 2011905,
"Position": {
"X": -443.04572,
"Y": -0.22894287,
"Z": 800.7781
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 2011906,
"Position": {
"X": -458.42682,
"Y": -0.19836426,
"Z": 830.8689
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Mount": false,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
},
{
"Position": {
"X": -458.42682,
"Y": -0.19836426,
"Z": 830.8689
},
"StopDistance": 5,
"TerritoryId": 957,
"InteractionType": "Dive"
},
{
"DataId": 2011908,
"Position": {
"X": -484.85547,
"Y": -72.22095,
"Z": 814.35876
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
]
},
{
"DataId": 2011907,
"Position": {
"X": -452.90308,
"Y": -67.00244,
"Z": 776.2417
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 2011909,
"Position": {
"X": -513.51184,
"Y": -52.689453,
"Z": 773.73914
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
8
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1039371,
"Position": {
"X": -409.93365,
"Y": 10.751212,
"Z": 33.035767
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,74 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1037685,
"Position": {
"X": -468.864,
"Y": 6.2912574,
"Z": 3.463745
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -568.1513,
"Y": 40.91181,
"Z": -451.32486
},
"StopDistance": 0.5,
"TerritoryId": 957,
"InteractionType": "Combat",
"EnemySpawnType": "AutoOnEnterArea",
"KillEnemyDataIds": [
14116
],
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1039383,
"Position": {
"X": -567.6509,
"Y": 41.313267,
"Z": -448.41687
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1037685,
"Position": {
"X": -468.864,
"Y": 6.2912574,
"Z": 3.463745
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,246 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1039385,
"Position": {
"X": -480.12518,
"Y": 5.362214,
"Z": 37.582886
},
"StopDistance": 0.5,
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039386,
"Position": {
"X": -431.7846,
"Y": 72.61802,
"Z": -555.3826
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"Position": {
"X": -477.78827,
"Y": 73.67918,
"Z": -542.7145
},
"TerritoryId": 957,
"InteractionType": "WalkTo",
"SkipConditions": {
"StepIf": {
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
}
}
},
{
"DataId": 2011962,
"Position": {
"X": -477.16492,
"Y": 74.75391,
"Z": -544.5792
},
"TerritoryId": 957,
"InteractionType": "UseItem",
"ItemId": 2003199,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 2011963,
"Position": {
"X": -479.2401,
"Y": 74.784424,
"Z": -541.619
},
"TerritoryId": 957,
"InteractionType": "UseItem",
"ItemId": 2003199,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
],
"DelaySecondsAtStart": 3
},
{
"Position": {
"X": -482.98328,
"Y": 73.32367,
"Z": -521.75024
},
"TerritoryId": 957,
"InteractionType": "WalkTo",
"SkipConditions": {
"StepIf": {
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
]
}
}
},
{
"DataId": 2011964,
"Position": {
"X": -484.67236,
"Y": 74.021484,
"Z": -523.15564
},
"TerritoryId": 957,
"InteractionType": "UseItem",
"ItemId": 2003199,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 2011965,
"Position": {
"X": -483.6042,
"Y": 74.35718,
"Z": -519.7986
},
"TerritoryId": 957,
"InteractionType": "UseItem",
"ItemId": 2003199,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
16
],
"DelaySecondsAtStart": 3
},
{
"Position": {
"X": -475.0877,
"Y": 73.24273,
"Z": -512.62787
},
"TerritoryId": 957,
"InteractionType": "WalkTo"
},
{
"DataId": 2011967,
"Position": {
"X": -476.92078,
"Y": 74.08252,
"Z": -511.43665
},
"TerritoryId": 957,
"InteractionType": "UseItem",
"ItemId": 2003199,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
4
]
},
{
"DataId": 2011966,
"Position": {
"X": -473.0144,
"Y": 74.32666,
"Z": -512.3827
},
"TerritoryId": 957,
"InteractionType": "UseItem",
"ItemId": 2003199,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
8
],
"DelaySecondsAtStart": 3
}
]
},
{
"Sequence": 3,
"Steps": [
{
"DataId": 1039386,
"Position": {
"X": -431.7846,
"Y": 72.61802,
"Z": -555.3826
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1039385,
"Position": {
"X": -480.12518,
"Y": 5.362214,
"Z": 37.582886
},
"StopDistance": 0.5,
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,98 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1037673,
"Position": {
"X": -517.0215,
"Y": 11.975277,
"Z": 100.541626
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 1039370,
"Position": {
"X": -106.21808,
"Y": 95.53504,
"Z": -700.4959
},
"TerritoryId": 957,
"InteractionType": "Interact",
"Fly": true,
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
32
]
},
{
"DataId": 1039368,
"Position": {
"X": -65.07977,
"Y": 89.860886,
"Z": -659.8764
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
128
]
},
{
"DataId": 1039369,
"Position": {
"X": -66.14789,
"Y": 89.4264,
"Z": -635.8892
},
"TerritoryId": 957,
"InteractionType": "Interact",
"CompletionQuestVariablesFlags": [
null,
null,
null,
null,
null,
64
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1037673,
"Position": {
"X": -517.0215,
"Y": 11.975277,
"Z": 100.541626
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,64 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1037681,
"Position": {
"X": -554.74176,
"Y": 11.402611,
"Z": 137.31592
},
"TerritoryId": 957,
"InteractionType": "AcceptQuest",
"Fly": true
}
]
},
{
"Sequence": 1,
"Steps": [
{
"Position": {
"X": -281.16296,
"Y": 94.31451,
"Z": -289.12802
},
"TerritoryId": 957,
"InteractionType": "WalkTo",
"Fly": true
},
{
"DataId": 2011910,
"Position": {
"X": -280.99493,
"Y": 95.87244,
"Z": -287.64783
},
"TerritoryId": 957,
"InteractionType": "Interact"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1037681,
"Position": {
"X": -554.74176,
"Y": 11.402611,
"Z": 137.31592
},
"TerritoryId": 957,
"InteractionType": "CompleteQuest",
"AetheryteShortcut": "Thavnair - Great Work",
"Fly": true
}
]
}
]
}

View File

@ -0,0 +1,76 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1048605,
"Position": {
"X": -358.38867,
"Y": 19.728025,
"Z": -105.02789
},
"TerritoryId": 1190,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Shaaloani - Sheshenewezi Springs",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
}
}
}
]
},
{
"Sequence": 1,
"Steps": [
{
"DataId": 2014456,
"Position": {
"X": -128.64886,
"Y": 16.311829,
"Z": -290.69965
},
"TerritoryId": 1190,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 2,
"Steps": [
{
"DataId": 1048608,
"Position": {
"X": -126.57361,
"Y": 15.67948,
"Z": -369.46674
},
"TerritoryId": 1190,
"InteractionType": "Interact",
"Fly": true
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1048605,
"Position": {
"X": -358.38867,
"Y": 19.728025,
"Z": -105.02789
},
"TerritoryId": 1190,
"InteractionType": "CompleteQuest",
"Fly": true,
"NextQuestId": 5241
}
]
}
]
}

View File

@ -0,0 +1,65 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "liza",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"Position": {
"X": -363.2864,
"Y": 20.16234,
"Z": -90.06508
},
"TerritoryId": 1190,
"InteractionType": "WalkTo"
},
{
"DataId": 1051495,
"Position": {
"X": -365.28577,
"Y": 20.14268,
"Z": -88.51758
},
"TerritoryId": 1190,
"InteractionType": "AcceptQuest"
}
]
},
{
"Sequence": 255,
"Steps": [
{
"Position": {
"X": -354.53677,
"Y": 19.32763,
"Z": -99.326805
},
"TerritoryId": 1190,
"InteractionType": "WalkTo",
"Mount": true
},
{
"Position": {
"X": -91.25145,
"Y": 17.80576,
"Z": -267.2748
},
"TerritoryId": 1190,
"InteractionType": "WalkTo",
"Fly": true
},
{
"DataId": 1051497,
"Position": {
"X": -91.5694,
"Y": 17.7503,
"Z": -268.54352
},
"TerritoryId": 1190,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -96,6 +96,7 @@
}, },
"TerritoryId": 1188, "TerritoryId": 1188,
"InteractionType": "CompleteQuest", "InteractionType": "CompleteQuest",
"Fly": true,
"NextQuestId": 5084 "NextQuestId": 5084
} }
] ]

View File

@ -80,7 +80,7 @@
"null" "null"
], ],
"description": "Set if pathfinding should stop closer or further away from the default stop distance", "description": "Set if pathfinding should stop closer or further away from the default stop distance",
"exclusiveMinimum": 0 "minimum": 0.25
}, },
"IgnoreDistanceToObject": { "IgnoreDistanceToObject": {
"type": "boolean", "type": "boolean",
@ -183,7 +183,8 @@
"null" "null"
], ],
"description": "The Item to use", "description": "The Item to use",
"exclusiveMinimum": 0 "exclusiveMinimum": 0,
"maximum": 2010000
}, },
"SkipConditions": { "SkipConditions": {
"type": "object", "type": "object",
@ -291,6 +292,7 @@
"type": "string", "type": "string",
"enum": [ "enum": [
"WakingSandsMainArea", "WakingSandsMainArea",
"WakingSandsSolar",
"RisingStonesSolar", "RisingStonesSolar",
"RoguesGuild", "RoguesGuild",
"DockStorehouse" "DockStorehouse"
@ -648,13 +650,15 @@
"type": "object", "type": "object",
"properties": { "properties": {
"ItemId": { "ItemId": {
"type": "integer" "type": "integer",
"maximum": 2010000
}, },
"Condition": { "Condition": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Incapacitated", "Incapacitated",
"Health%" "Health%",
"MissingStatus"
] ]
}, },
"Value": { "Value": {
@ -859,7 +863,8 @@
"joy", "joy",
"mogdance", "mogdance",
"salute", "salute",
"laugh" "laugh",
"greeting"
] ]
} }
} }

View File

@ -9,5 +9,6 @@ public sealed class CombatItemUseConditionConverter() : EnumConverter<ECombatIte
{ {
{ ECombatItemUseCondition.Incapacitated, "Incapacitated" }, { ECombatItemUseCondition.Incapacitated, "Incapacitated" },
{ ECombatItemUseCondition.HealthPercent, "Health%" }, { ECombatItemUseCondition.HealthPercent, "Health%" },
{ ECombatItemUseCondition.MissingStatus, "MissingStatus" },
}; };
} }

View File

@ -43,6 +43,7 @@ public sealed class EmoteConverter() : EnumConverter<EEmote>(Values)
{ EEmote.Flex, "flex" }, { EEmote.Flex, "flex" },
{ EEmote.Respect, "respect" }, { EEmote.Respect, "respect" },
{ EEmote.Box, "box" }, { EEmote.Box, "box" },
{ EEmote.Uchiwasshoi, "uchiwasshoi" } { EEmote.Greeting, "greeting" },
{ EEmote.Uchiwasshoi, "uchiwasshoi" },
}; };
} }

View File

@ -8,6 +8,7 @@ public sealed class SkipConditionConverter() : EnumConverter<EExtraSkipCondition
private static readonly Dictionary<EExtraSkipCondition, string> Values = new() private static readonly Dictionary<EExtraSkipCondition, string> Values = new()
{ {
{ EExtraSkipCondition.WakingSandsMainArea, "WakingSandsMainArea" }, { EExtraSkipCondition.WakingSandsMainArea, "WakingSandsMainArea" },
{ EExtraSkipCondition.WakingSandsSolar, "WakingSandsSolar" },
{ EExtraSkipCondition.RisingStonesSolar, "RisingStonesSolar"}, { EExtraSkipCondition.RisingStonesSolar, "RisingStonesSolar"},
{ EExtraSkipCondition.RoguesGuild, "RoguesGuild"}, { EExtraSkipCondition.RoguesGuild, "RoguesGuild"},
{ EExtraSkipCondition.DockStorehouse, "DockStorehouse"}, { EExtraSkipCondition.DockStorehouse, "DockStorehouse"},

View File

@ -5,4 +5,5 @@ public enum ECombatItemUseCondition
None, None,
Incapacitated, Incapacitated,
HealthPercent, HealthPercent,
MissingStatus,
} }

View File

@ -44,6 +44,7 @@ public enum EEmote
Flex = 139, Flex = 139,
Respect = 140, Respect = 140,
Box = 166, Box = 166,
Greeting = 172,
Uchiwasshoi = 278 Uchiwasshoi = 278
} }

View File

@ -8,6 +8,7 @@ public enum EExtraSkipCondition
{ {
None, None,
WakingSandsMainArea, WakingSandsMainArea,
WakingSandsSolar,
RisingStonesSolar, RisingStonesSolar,
/// <summary> /// <summary>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Enums;
@ -10,7 +11,8 @@ using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Common.Math; using FFXIVClientStructs.FFXIV.Client.System.Framework;
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Controller.CombatModules; using Questionable.Controller.CombatModules;
using Questionable.Controller.Steps; using Questionable.Controller.Steps;
@ -38,6 +40,7 @@ internal sealed class CombatController : IDisposable
private CurrentFight? _currentFight; private CurrentFight? _currentFight;
private bool _wasInCombat; private bool _wasInCombat;
private ulong? _lastTargetId; private ulong? _lastTargetId;
private List<byte>? _previousQuestVariables;
public CombatController( public CombatController(
IEnumerable<ICombatModule> combatModules, IEnumerable<ICombatModule> combatModules,
@ -79,7 +82,9 @@ internal sealed class CombatController : IDisposable
Data = combatData, Data = combatData,
LastDistanceCheck = DateTime.Now, LastDistanceCheck = DateTime.Now,
}; };
_wasInCombat = combatData.SpawnType is EEnemySpawnType.QuestInterruption or EEnemySpawnType.FinishCombatIfAny; _wasInCombat =
combatData.SpawnType is EEnemySpawnType.QuestInterruption or EEnemySpawnType.FinishCombatIfAny;
UpdateLastTargetAndQuestVariables(null);
return true; return true;
} }
else else
@ -115,7 +120,31 @@ internal sealed class CombatController : IDisposable
{ {
// wait until the game cleans up the target // wait until the game cleans up the target
if (lastTarget.IsDead) if (lastTarget.IsDead)
return EStatus.InCombat; {
ElementId? elementId = _currentFight.Data.ElementId;
QuestProgressInfo? questProgressInfo = elementId != null
? _questFunctions.GetQuestProgressInfo(elementId)
: null;
if (questProgressInfo != null &&
questProgressInfo.Sequence == _currentFight.Data.Sequence &&
QuestWorkUtils.HasCompletionFlags(_currentFight.Data.CompletionQuestVariablesFlags) &&
QuestWorkUtils.MatchesQuestWork(_currentFight.Data.CompletionQuestVariablesFlags,
questProgressInfo))
{
// would be the final enemy of the bunch
return EStatus.InCombat;
}
else if (questProgressInfo != null &&
questProgressInfo.Sequence == _currentFight.Data.Sequence &&
_previousQuestVariables != null &&
!questProgressInfo.Variables.SequenceEqual(_previousQuestVariables))
{
UpdateLastTargetAndQuestVariables(null);
}
else
return EStatus.InCombat;
}
} }
else else
_lastTargetId = null; _lastTargetId = null;
@ -128,7 +157,7 @@ internal sealed class CombatController : IDisposable
{ {
int currentTargetPriority = GetKillPriority(target); int currentTargetPriority = GetKillPriority(target);
var nextTarget = FindNextTarget(); var nextTarget = FindNextTarget();
int nextTargetPriority = GetKillPriority(target); int nextTargetPriority = nextTarget != null ? GetKillPriority(nextTarget) : 0;
if (nextTarget != null && nextTarget.Equals(target)) if (nextTarget != null && nextTarget.Equals(target))
{ {
@ -147,7 +176,7 @@ internal sealed class CombatController : IDisposable
} }
else if (nextTarget != null) else if (nextTarget != null)
{ {
if (nextTargetPriority > currentTargetPriority) if (nextTargetPriority > currentTargetPriority || currentTargetPriority == 0)
SetTarget(nextTarget); SetTarget(nextTarget);
} }
else else
@ -372,9 +401,18 @@ internal sealed class CombatController : IDisposable
float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius; float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
float actualDistance = Vector3.Distance(player.Position, gameObject.Position); float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
float maxDistance = player.ClassJob.ValueNullable?.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) bool outOfRange = actualDistance - hitboxOffset >= maxDistance;
bool isInLineOfSight = IsInLineOfSight(gameObject);
if (outOfRange || !isInLineOfSight)
{ {
if (actualDistance - hitboxOffset <= 5) bool useNavmesh = actualDistance - hitboxOffset > 5f;
if (!outOfRange && !isInLineOfSight)
{
maxDistance = Math.Min(maxDistance, actualDistance) / 2;
useNavmesh = true;
}
if (!useNavmesh)
{ {
_logger.LogInformation("Moving to {TargetName} ({DataId}) to attack", gameObject.Name, _logger.LogInformation("Moving to {TargetName} ({DataId}) to attack", gameObject.Name,
gameObject.DataId); gameObject.DataId);
@ -391,6 +429,44 @@ internal sealed class CombatController : IDisposable
} }
} }
internal unsafe bool IsInLineOfSight(IGameObject target)
{
Vector3 sourcePos = _clientState.LocalPlayer!.Position;
sourcePos.Y += 2;
Vector3 targetPos = target.Position;
targetPos.Y += 2;
Vector3 direction = targetPos - sourcePos;
float distance = direction.Length();
direction = Vector3.Normalize(direction);
Vector3 originVect = new Vector3(sourcePos.X, sourcePos.Y, sourcePos.Z);
Vector3 directionVect = new Vector3(direction.X, direction.Y, direction.Z);
RaycastHit hit;
var flags = stackalloc int[] { 0x4000, 0, 0x4000, 0 };
var isLoSBlocked =
Framework.Instance()->BGCollisionModule->RaycastMaterialFilter(&hit, &originVect, &directionVect, distance,
1, flags);
return isLoSBlocked == false;
}
private void UpdateLastTargetAndQuestVariables(IGameObject? target)
{
_lastTargetId = target?.GameObjectId;
_previousQuestVariables = _currentFight!.Data.ElementId != null
? _questFunctions.GetQuestProgressInfo(_currentFight.Data.ElementId)?.Variables
: null;
/*
_logger.LogTrace("UpdateTargetData: {TargetId}; {QuestVariables}",
target?.GameObjectId.ToString("X8", CultureInfo.InvariantCulture) ?? "null",
_previousQuestVariables != null ? string.Join(", ", _previousQuestVariables) : "null");
*/
}
public void Stop(string label) public void Stop(string label)
{ {
using var scope = _logger.BeginScope(label); using var scope = _logger.BeginScope(label);
@ -422,6 +498,8 @@ internal sealed class CombatController : IDisposable
public sealed class CombatData public sealed class CombatData
{ {
public required ElementId? ElementId { get; init; } public required ElementId? ElementId { get; init; }
public required int Sequence { get; init; }
public required IList<QuestWorkValue?> CompletionQuestVariablesFlags { get; init; }
public required EEnemySpawnType SpawnType { get; init; } public required EEnemySpawnType SpawnType { get; init; }
public required List<uint> KillEnemyDataIds { get; init; } public required List<uint> KillEnemyDataIds { get; init; }
public required List<ComplexCombatData> ComplexCombatDatas { get; init; } public required List<ComplexCombatData> ComplexCombatDatas { get; init; }

View File

@ -108,6 +108,7 @@ internal sealed class ItemUseModule : ICombatModule
_delegate.Stop(); _delegate.Stop();
unsafe unsafe
{ {
_logger.LogInformation("Using item {ItemId}", _combatData.CombatItemUse.ItemId);
AgentInventoryContext.Instance()->UseItem(_combatData.CombatItemUse.ItemId); AgentInventoryContext.Instance()->UseItem(_combatData.CombatItemUse.ItemId);
} }
_continueAt = DateTime.Now.AddSeconds(2); _continueAt = DateTime.Now.AddSeconds(2);
@ -147,6 +148,9 @@ internal sealed class ItemUseModule : ICombatModule
if (_combatData.CombatItemUse.Condition == ECombatItemUseCondition.HealthPercent) if (_combatData.CombatItemUse.Condition == ECombatItemUseCondition.HealthPercent)
return (100f * battleChara->Health / battleChara->MaxHealth) < _combatData.CombatItemUse.Value; return (100f * battleChara->Health / battleChara->MaxHealth) < _combatData.CombatItemUse.Value;
if (_combatData.CombatItemUse.Condition == ECombatItemUseCondition.MissingStatus)
return !battleChara->StatusManager.HasStatus((uint)_combatData.CombatItemUse.Value);
} }
return false; return false;

View File

@ -3,6 +3,7 @@ using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib.GameUI;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Questionable.Controller.GameUi; namespace Questionable.Controller.GameUi;
@ -11,17 +12,45 @@ internal sealed class HelpUiController : IDisposable
{ {
private readonly QuestController _questController; private readonly QuestController _questController;
private readonly IAddonLifecycle _addonLifecycle; private readonly IAddonLifecycle _addonLifecycle;
private readonly IGameGui _gameGui;
private readonly ILogger<HelpUiController> _logger; private readonly ILogger<HelpUiController> _logger;
public HelpUiController(QuestController questController, IAddonLifecycle addonLifecycle, ILogger<HelpUiController> logger) public HelpUiController(
QuestController questController,
IAddonLifecycle addonLifecycle,
IGameGui gameGui,
ILogger<HelpUiController> logger)
{ {
_questController = questController; _questController = questController;
_addonLifecycle = addonLifecycle; _addonLifecycle = addonLifecycle;
_gameGui = gameGui;
_logger = logger; _logger = logger;
_questController.AutomationTypeChanged += CloseHelpWindowsWhenStartingQuests;
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "AkatsukiNote", UnendingCodexPostSetup); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "AkatsukiNote", UnendingCodexPostSetup);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "ContentsTutorial", ContentsTutorialPostSetup); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "ContentsTutorial", ContentsTutorialPostSetup);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "MultipleHelpWindow", MultipleHelpWindowPostSetup); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "MultipleHelpWindow", MultipleHelpWindowPostSetup);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "JobHudNotice", JobHudNoticePostSetup);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "Guide", GuidePostSetup);
}
private unsafe void CloseHelpWindowsWhenStartingQuests(object sender, QuestController.EAutomationType e)
{
if (e is QuestController.EAutomationType.Manual)
return;
if (_gameGui.TryGetAddonByName("Guide", out AtkUnitBase* addonGuide))
{
_logger.LogInformation("Guide window is open");
GuidePostSetup(addonGuide);
}
if (_gameGui.TryGetAddonByName("JobHudNotice", out AtkUnitBase* addonJobHudNotice))
{
_logger.LogInformation("JobHudNotice window is open");
JobHudNoticePostSetup(addonJobHudNotice);
}
} }
private unsafe void UnendingCodexPostSetup(AddonEvent type, AddonArgs args) private unsafe void UnendingCodexPostSetup(AddonEvent type, AddonArgs args)
@ -36,7 +65,7 @@ internal sealed class HelpUiController : IDisposable
private unsafe void ContentsTutorialPostSetup(AddonEvent type, AddonArgs args) private unsafe void ContentsTutorialPostSetup(AddonEvent type, AddonArgs args)
{ {
if (_questController.StartedQuest?.Quest.Id.Value == 245) if (_questController.StartedQuest?.Quest.Id.Value is 245 or 3872)
{ {
_logger.LogInformation("Closing ContentsTutorial"); _logger.LogInformation("Closing ContentsTutorial");
AtkUnitBase* addon = (AtkUnitBase*)args.Addon; AtkUnitBase* addon = (AtkUnitBase*)args.Addon;
@ -58,10 +87,38 @@ internal sealed class HelpUiController : IDisposable
} }
} }
private unsafe void JobHudNoticePostSetup(AddonEvent type, AddonArgs args)
{
if (_questController.IsRunning || _questController.AutomationType != QuestController.EAutomationType.Manual)
JobHudNoticePostSetup((AtkUnitBase*)args.Addon);
}
private unsafe void JobHudNoticePostSetup(AtkUnitBase* addon)
{
_logger.LogInformation("Clicking the JobHudNotice window to open the relevant Guide page");
addon->FireCallbackInt(0);
}
private unsafe void GuidePostSetup(AddonEvent type, AddonArgs args)
{
if (_questController.IsRunning || _questController.AutomationType != QuestController.EAutomationType.Manual)
GuidePostSetup((AtkUnitBase*)args.Addon);
}
private unsafe void GuidePostSetup(AtkUnitBase* addon)
{
_logger.LogInformation("Closing Guide window");
addon->FireCallbackInt(-1);
}
public void Dispose() public void Dispose()
{ {
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "Guide", GuidePostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "JobHudNotice", JobHudNoticePostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "MultipleHelpWindow", MultipleHelpWindowPostSetup); _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "MultipleHelpWindow", MultipleHelpWindowPostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "ContentsTutorial", ContentsTutorialPostSetup); _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "ContentsTutorial", ContentsTutorialPostSetup);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "AkatsukiNote", UnendingCodexPostSetup); _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "AkatsukiNote", UnendingCodexPostSetup);
_questController.AutomationTypeChanged -= CloseHelpWindowsWhenStartingQuests;
} }
} }

View File

@ -49,9 +49,10 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
ILogger<GatheringController> logger, ILogger<GatheringController> logger,
ICondition condition, ICondition condition,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
InterruptHandler interruptHandler,
IDataManager dataManager, IDataManager dataManager,
IPluginLog pluginLog) IPluginLog pluginLog)
: base(chatGui, condition, serviceProvider, dataManager, logger) : base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
{ {
_movementController = movementController; _movementController = movementController;
_gatheringPointRegistry = gatheringPointRegistry; _gatheringPointRegistry = gatheringPointRegistry;

View File

@ -0,0 +1,165 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Dalamud.Game;
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Common.Math;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Questionable.Data;
namespace Questionable.Controller;
internal sealed unsafe class InterruptHandler : IDisposable
{
private readonly Hook<ProcessActionEffect> _processActionEffectHook;
private readonly IClientState _clientState;
private readonly TerritoryData _territoryData;
private readonly ILogger<InterruptHandler> _logger;
private delegate void ProcessActionEffect(uint sourceId, Character* sourceCharacter, Vector3* pos,
EffectHeader* effectHeader, EffectEntry* effectArray, ulong* effectTail);
public InterruptHandler(IGameInteropProvider gameInteropProvider, IClientState clientState,
TerritoryData territoryData, ILogger<InterruptHandler> logger)
{
_clientState = clientState;
_territoryData = territoryData;
_logger = logger;
_processActionEffectHook =
gameInteropProvider.HookFromSignature<ProcessActionEffect>(Signatures.ActionEffect,
HandleProcessActionEffect);
_processActionEffectHook.Enable();
}
public event EventHandler? Interrupted;
private void HandleProcessActionEffect(uint sourceId, Character* sourceCharacter, Vector3* pos,
EffectHeader* effectHeader, EffectEntry* effectArray, ulong* effectTail)
{
try
{
if (!_territoryData.IsDutyInstance(_clientState.TerritoryType))
{
for (int i = 0; i < effectHeader->TargetCount; i++)
{
uint targetId = (uint)(effectTail[i] & uint.MaxValue);
EffectEntry* effect = effectArray + 8 * i;
if (targetId == _clientState.LocalPlayer?.GameObjectId &&
effect->Type is EActionEffectType.Damage or EActionEffectType.BlockedDamage
or EActionEffectType.ParriedDamage)
{
_logger.LogTrace("Damage action effect on self, from {SourceId} ({EffectType})", sourceId,
effect->Type);
Interrupted?.Invoke(this, EventArgs.Empty);
break;
}
}
}
}
catch (Exception e)
{
_logger.LogWarning(e, "Unable to process action effect");
}
finally
{
_processActionEffectHook.Original(sourceId, sourceCharacter, pos, effectHeader, effectArray, effectTail);
}
}
public void Dispose()
{
_processActionEffectHook.Disable();
_processActionEffectHook.Dispose();
}
private static class Signatures
{
internal const string ActionEffect = "40 ?? 56 57 41 ?? 41 ?? 41 ?? 48 ?? ?? ?? ?? ?? ?? ?? 48";
}
[StructLayout(LayoutKind.Explicit)]
private struct EffectEntry
{
[FieldOffset(0)] public EActionEffectType Type;
[FieldOffset(1)] public byte Param0;
[FieldOffset(2)] public byte Param1;
[FieldOffset(3)] public byte Param2;
[FieldOffset(4)] public byte Mult;
[FieldOffset(5)] public byte Flags;
[FieldOffset(6)] public ushort Value;
public byte AttackType => (byte)(Param1 & 0xF);
public uint Damage => Mult == 0 ? Value : Value + ((uint)ushort.MaxValue + 1) * Mult;
public override string ToString()
{
return
$"Type: {Type}, p0: {Param0:D3}, p1: {Param1:D3}, p2: {Param2:D3} 0x{Param2:X2} '{Convert.ToString(Param2, 2).PadLeft(8, '0')}', mult: {Mult:D3}, flags: {Flags:D3} | {Convert.ToString(Flags, 2).PadLeft(8, '0')}, value: {Value:D6} ATTACK TYPE: {AttackType}";
}
}
[StructLayout(LayoutKind.Explicit)]
private struct EffectHeader
{
[FieldOffset(0)] public ulong AnimationTargetId;
[FieldOffset(8)] public uint ActionID;
[FieldOffset(12)] public uint GlobalEffectCounter;
[FieldOffset(16)] public float AnimationLockTime;
[FieldOffset(20)] public uint SomeTargetID;
[FieldOffset(24)] public ushort SourceSequence;
[FieldOffset(26)] public ushort Rotation;
[FieldOffset(28)] public ushort AnimationId;
[FieldOffset(30)] public byte Variation;
[FieldOffset(31)] public ActionType ActionType;
[FieldOffset(33)] public byte TargetCount;
}
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
private enum EActionEffectType : byte
{
None = 0,
Miss = 1,
FullResist = 2,
Damage = 3,
Heal = 4,
BlockedDamage = 5,
ParriedDamage = 6,
Invulnerable = 7,
NoEffectText = 8,
Unknown0 = 9,
MpLoss = 10,
MpGain = 11,
TpLoss = 12,
TpGain = 13,
ApplyStatusEffectTarget = 14,
ApplyStatusEffectSource = 15,
RecoveredFromStatusEffect = 16,
LoseStatusEffectTarget = 17,
LoseStatusEffectSource = 18,
StatusNoEffect = 20,
ThreatPosition = 24,
EnmityAmountUp = 25,
EnmityAmountDown = 26,
StartActionCombo = 27,
ComboSucceed = 28,
Retaliation = 29,
Knockback = 32,
Attract1 = 33, //Here is an issue bout knockback. some is 32 some is 33.
Attract2 = 34,
Mount = 40,
FullResistStatus = 52,
FullResistStatus2 = 55,
VFX = 59,
Gauge = 60,
JobGauge = 61,
SetModelState = 72,
SetHP = 73,
PartialInvulnerable = 74,
Interrupt = 75,
}
}

View File

@ -17,26 +17,31 @@ using Mount = Questionable.Controller.Steps.Common.Mount;
namespace Questionable.Controller; namespace Questionable.Controller;
internal abstract class MiniTaskController<T> internal abstract class MiniTaskController<T> : IDisposable
{ {
protected readonly TaskQueue _taskQueue = new(); protected readonly TaskQueue _taskQueue = new();
private readonly IChatGui _chatGui; private readonly IChatGui _chatGui;
private readonly ICondition _condition; private readonly ICondition _condition;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly InterruptHandler _interruptHandler;
private readonly ILogger<T> _logger; private readonly ILogger<T> _logger;
private readonly string _actionCanceledText; private readonly string _actionCanceledText;
private readonly string _cantExecuteDueToStatusText;
protected MiniTaskController(IChatGui chatGui, ICondition condition, IServiceProvider serviceProvider, protected MiniTaskController(IChatGui chatGui, ICondition condition, IServiceProvider serviceProvider,
IDataManager dataManager, ILogger<T> logger) InterruptHandler interruptHandler, IDataManager dataManager, ILogger<T> logger)
{ {
_chatGui = chatGui; _chatGui = chatGui;
_logger = logger; _logger = logger;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_interruptHandler = interruptHandler;
_condition = condition; _condition = condition;
_actionCanceledText = dataManager.GetString<LogMessage>(1314, x => x.Text)!; _actionCanceledText = dataManager.GetString<LogMessage>(1314, x => x.Text)!;
_cantExecuteDueToStatusText = dataManager.GetString<LogMessage>(7728, x => x.Text)!;
_interruptHandler.Interrupted += HandleInterruption;
} }
protected virtual void UpdateCurrentTask() protected virtual void UpdateCurrentTask()
@ -65,7 +70,7 @@ internal abstract class MiniTaskController<T>
{ {
_logger.LogError(e, "Failed to start task {TaskName}", upcomingTask.ToString()); _logger.LogError(e, "Failed to start task {TaskName}", upcomingTask.ToString());
_chatGui.PrintError( _chatGui.PrintError(
$"[Questionable] Failed to start task '{upcomingTask}', please check /xllog for details."); $"Failed to start task '{upcomingTask}', please check /xllog for details.", CommandHandler.MessageTag, CommandHandler.TagColor);
Stop("Task failed to start"); Stop("Task failed to start");
return; return;
} }
@ -90,7 +95,7 @@ internal abstract class MiniTaskController<T>
_logger.LogError(e, "Failed to update task {TaskName}", _logger.LogError(e, "Failed to update task {TaskName}",
_taskQueue.CurrentTaskExecutor.CurrentTask.ToString()); _taskQueue.CurrentTaskExecutor.CurrentTask.ToString());
_chatGui.PrintError( _chatGui.PrintError(
$"[Questionable] Failed to update task '{_taskQueue.CurrentTaskExecutor.CurrentTask}', please check /xllog for details."); $"Failed to update task '{_taskQueue.CurrentTaskExecutor.CurrentTask}', please check /xllog for details.", CommandHandler.MessageTag, CommandHandler.TagColor);
Stop("Task failed to update"); Stop("Task failed to update");
return; return;
} }
@ -173,13 +178,26 @@ internal abstract class MiniTaskController<T>
if (_condition[ConditionFlag.Mounted]) if (_condition[ConditionFlag.Mounted])
tasks.Add(new Mount.UnmountTask()); tasks.Add(new Mount.UnmountTask());
tasks.Add(Combat.Factory.CreateTask(null, false, EEnemySpawnType.QuestInterruption, [], [], [], null)); tasks.Add(Combat.Factory.CreateTask(null, -1, false, EEnemySpawnType.QuestInterruption, [], [], [], null));
tasks.Add(new WaitAtEnd.WaitDelay()); tasks.Add(new WaitAtEnd.WaitDelay());
_taskQueue.InterruptWith(tasks); _taskQueue.InterruptWith(tasks);
} }
else else
_taskQueue.InterruptWith([new WaitAtEnd.WaitDelay()]); _taskQueue.InterruptWith([new WaitAtEnd.WaitDelay()]);
LogTasksAfterInterruption();
}
private void InterruptWithoutCombat()
{
_logger.LogWarning("Interrupted, attempting to redo previous tasks (not in combat)");
_taskQueue.InterruptWith([new WaitAtEnd.WaitDelay()]);
LogTasksAfterInterruption();
}
private void LogTasksAfterInterruption()
{
_logger.LogInformation("Remaining tasks after interruption:"); _logger.LogInformation("Remaining tasks after interruption:");
foreach (ITask task in _taskQueue.RemainingTasks) foreach (ITask task in _taskQueue.RemainingTasks)
_logger.LogInformation("- {TaskName}", task); _logger.LogInformation("- {TaskName}", task);
@ -198,8 +216,23 @@ internal abstract class MiniTaskController<T>
if (!isHandled) if (!isHandled)
{ {
if (GameFunctions.GameStringEquals(_actionCanceledText, message.TextValue) && if (GameFunctions.GameStringEquals(_actionCanceledText, message.TextValue) &&
!_condition[ConditionFlag.InFlight]) !_condition[ConditionFlag.InFlight] &&
_taskQueue.CurrentTaskExecutor?.ShouldInterruptOnDamage() == true)
InterruptQueueWithCombat(); InterruptQueueWithCombat();
else if (GameFunctions.GameStringEquals(_cantExecuteDueToStatusText, message.TextValue))
InterruptWithoutCombat();
} }
} }
protected virtual void HandleInterruption(object? sender, EventArgs e)
{
if (!_condition[ConditionFlag.InFlight] &&
_taskQueue.CurrentTaskExecutor?.ShouldInterruptOnDamage() == true)
InterruptQueueWithCombat();
}
public virtual void Dispose()
{
_interruptHandler.Interrupted -= HandleInterruption;
}
} }

View File

@ -75,8 +75,9 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
YesAlreadyIpc yesAlreadyIpc, YesAlreadyIpc yesAlreadyIpc,
TaskCreator taskCreator, TaskCreator taskCreator,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
InterruptHandler interruptHandler,
IDataManager dataManager) IDataManager dataManager)
: base(chatGui, condition, serviceProvider, dataManager, logger) : base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
{ {
_clientState = clientState; _clientState = clientState;
_gameFunctions = gameFunctions; _gameFunctions = gameFunctions;
@ -110,9 +111,13 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
_logger.LogInformation("Setting automation type to {NewAutomationType} (previous: {OldAutomationType})", _logger.LogInformation("Setting automation type to {NewAutomationType} (previous: {OldAutomationType})",
value, _automationType); value, _automationType);
_automationType = value; _automationType = value;
AutomationTypeChanged?.Invoke(this, value);
} }
} }
public delegate void AutomationTypeChangedEventHandler(object sender, EAutomationType e);
public event AutomationTypeChangedEventHandler? AutomationTypeChanged;
public (QuestProgress Progress, ECurrentQuestType Type)? CurrentQuestDetails public (QuestProgress Progress, ECurrentQuestType Type)? CurrentQuestDetails
{ {
get get
@ -622,7 +627,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Failed to create tasks"); _logger.LogError(e, "Failed to create tasks");
_chatGui.PrintError("[Questionable] Failed to start next task sequence, please check /xllog for details."); _chatGui.PrintError("Failed to start next task sequence, please check /xllog for details.", CommandHandler.MessageTag, CommandHandler.TagColor);
Stop("Tasks failed to create"); Stop("Tasks failed to create");
} }
} }
@ -801,11 +806,23 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
_gatheringController.OnNormalToast(message); _gatheringController.OnNormalToast(message);
} }
public void Dispose() protected override void HandleInterruption(object? sender, EventArgs e)
{
if (!IsRunning)
return;
if (AutomationType == EAutomationType.Manual)
return;
base.HandleInterruption(sender, e);
}
public override void Dispose()
{ {
_toastGui.ErrorToast -= OnErrorToast; _toastGui.ErrorToast -= OnErrorToast;
_toastGui.Toast -= OnNormalToast; _toastGui.Toast -= OnNormalToast;
_condition.ConditionChange -= OnConditionChange; _condition.ConditionChange -= OnConditionChange;
base.Dispose();
} }
public sealed record StepProgress( public sealed record StepProgress(

View File

@ -234,7 +234,11 @@ internal sealed class QuestRegistry
public List<QuestInfo> GetKnownClassJobQuests(EClassJob classJob) public List<QuestInfo> GetKnownClassJobQuests(EClassJob classJob)
{ {
return _questData.GetClassJobQuests(classJob) List<QuestInfo> allQuests = [.._questData.GetClassJobQuests(classJob)];
if (classJob.AsJob() != classJob)
allQuests.AddRange(_questData.GetClassJobQuests(classJob.AsJob()));
return allQuests
.Where(x => IsKnownQuest(x.QuestId)) .Where(x => IsKnownQuest(x.QuestId))
.ToList(); .ToList();
} }

View File

@ -110,6 +110,8 @@ internal static class Mount
? ETaskResult.TaskComplete ? ETaskResult.TaskComplete
: ETaskResult.StillRunning; : ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal enum MountResult internal enum MountResult
@ -197,6 +199,8 @@ internal static class Mount
return false; return false;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
public enum EMountIf public enum EMountIf

View File

@ -61,5 +61,7 @@ internal static class NextQuest
} }
public override ETaskResult Update() => ETaskResult.TaskComplete; public override ETaskResult Update() => ETaskResult.TaskComplete;
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -104,5 +104,7 @@ internal static class SendNotification
} }
public override ETaskResult Update() => ETaskResult.TaskComplete; public override ETaskResult Update() => ETaskResult.TaskComplete;
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -25,5 +25,7 @@ internal static class WaitCondition
return DateTime.Now >= _continueAt ? ETaskResult.TaskComplete : ETaskResult.StillRunning; return DateTime.Now >= _continueAt ? ETaskResult.TaskComplete : ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -236,6 +236,8 @@ internal static class DoGather
EAction action = PickAction(minerAction, botanistAction); EAction action = PickAction(minerAction, botanistAction);
return ActionManager.Instance()->GetActionStatus(ActionType.Action, (uint)action) == 0; return ActionManager.Instance()->GetActionStatus(ActionType.Action, (uint)action) == 0;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
[SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Local")] [SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Local")]

View File

@ -198,6 +198,8 @@ internal static class DoGatherCollectable
else else
return botanistAction; return botanistAction;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
[SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Local")] [SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Local")]

View File

@ -59,5 +59,6 @@ internal static class MoveToLandingLocation
public override ETaskResult Update() => moveExecutor.Update(); public override ETaskResult Update() => moveExecutor.Update();
public bool OnErrorToast(SeString message) => moveExecutor.OnErrorToast(message); public bool OnErrorToast(SeString message) => moveExecutor.OnErrorToast(message);
public override bool ShouldInterruptOnDamage() => moveExecutor.ShouldInterruptOnDamage();
} }
} }

View File

@ -80,5 +80,8 @@ internal static class TurnInDelivery
addon->FireCallback(2, pickGatheringItem); addon->FireCallback(2, pickGatheringItem);
return ETaskResult.StillRunning; return ETaskResult.StillRunning;
} }
// not even sure if any turn-in npcs are NEAR mobs; but we also need to be on a gathering/crafting job
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -124,6 +124,8 @@ internal static class Action
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal sealed record UseMudraOnObject(uint DataId, EAction Action) : ITask internal sealed record UseMudraOnObject(uint DataId, EAction Action) : ITask
@ -187,5 +189,7 @@ internal static class Action
logger.LogError("Unable to find relevant combo for {Action}", Task.Action); logger.LogError("Unable to find relevant combo for {Action}", Task.Action);
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -26,7 +26,8 @@ internal static class AetherCurrent
if (!aetherCurrentData.IsValidAetherCurrent(step.TerritoryId, step.AetherCurrentId.Value)) if (!aetherCurrentData.IsValidAetherCurrent(step.TerritoryId, step.AetherCurrentId.Value))
{ {
chatGui.PrintError( chatGui.PrintError(
$"[Questionable] Aether current with id {step.AetherCurrentId} is referencing an invalid aether current, will skip attunement"); $"Aether current with id {step.AetherCurrentId} is referencing an invalid aether current, will skip attunement",
CommandHandler.MessageTag, CommandHandler.TagColor);
return null; return null;
} }
@ -65,5 +66,7 @@ internal static class AetherCurrent
gameFunctions.IsAetherCurrentUnlocked(Task.AetherCurrentId) gameFunctions.IsAetherCurrentUnlocked(Task.AetherCurrentId)
? ETaskResult.TaskComplete ? ETaskResult.TaskComplete
: ETaskResult.StillRunning; : ETaskResult.StillRunning;
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -53,5 +53,7 @@ internal static class AethernetShard
aetheryteFunctions.IsAetheryteUnlocked(Task.AetheryteLocation) aetheryteFunctions.IsAetheryteUnlocked(Task.AetheryteLocation)
? ETaskResult.TaskComplete ? ETaskResult.TaskComplete
: ETaskResult.StillRunning; : ETaskResult.StillRunning;
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -52,5 +52,7 @@ internal static class Aetheryte
aetheryteFunctions.IsAetheryteUnlocked(Task.AetheryteLocation) aetheryteFunctions.IsAetheryteUnlocked(Task.AetheryteLocation)
? ETaskResult.TaskComplete ? ETaskResult.TaskComplete
: ETaskResult.StillRunning; : ETaskResult.StillRunning;
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -102,17 +102,30 @@ internal static class Combat
ArgumentNullException.ThrowIfNull(step.EnemySpawnType); ArgumentNullException.ThrowIfNull(step.EnemySpawnType);
bool isLastStep = sequence.Steps.Last() == step; bool isLastStep = sequence.Steps.Last() == step;
return CreateTask(quest.Id, isLastStep, step.EnemySpawnType.Value, step.KillEnemyDataIds, return CreateTask(quest.Id,
step.CompletionQuestVariablesFlags, step.ComplexCombatData, step.CombatItemUse); sequence.Sequence,
isLastStep,
step.EnemySpawnType.Value,
step.KillEnemyDataIds,
step.CompletionQuestVariablesFlags,
step.ComplexCombatData,
step.CombatItemUse);
} }
internal static Task CreateTask(ElementId? elementId, bool isLastStep, EEnemySpawnType enemySpawnType, internal static Task CreateTask(ElementId? elementId,
IList<uint> killEnemyDataIds, IList<QuestWorkValue?> completionQuestVariablesFlags, int sequence,
IList<ComplexCombatData> complexCombatData, CombatItemUse? combatItemUse) bool isLastStep,
EEnemySpawnType enemySpawnType,
IList<uint> killEnemyDataIds,
IList<QuestWorkValue?> completionQuestVariablesFlags,
IList<ComplexCombatData> complexCombatData,
CombatItemUse? combatItemUse)
{ {
return new Task(new CombatController.CombatData return new Task(new CombatController.CombatData
{ {
ElementId = elementId, ElementId = elementId,
Sequence = sequence,
CompletionQuestVariablesFlags = completionQuestVariablesFlags,
SpawnType = enemySpawnType, SpawnType = enemySpawnType,
KillEnemyDataIds = killEnemyDataIds.ToList(), KillEnemyDataIds = killEnemyDataIds.ToList(),
ComplexCombatDatas = complexCombatData.ToList(), ComplexCombatDatas = complexCombatData.ToList(),
@ -177,5 +190,7 @@ internal static class Combat
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
} }
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -71,6 +71,8 @@ internal static class Dive
return base.Update(); return base.Update();
} }
public override bool ShouldInterruptOnDamage() => false;
protected override ETaskResult UpdateInternal() protected override ETaskResult UpdateInternal()
{ {
if (condition[ConditionFlag.Diving]) if (condition[ConditionFlag.Diving])

View File

@ -93,6 +93,8 @@ internal static class Duty
? ETaskResult.TaskComplete ? ETaskResult.TaskComplete
: ETaskResult.StillRunning; : ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal sealed record WaitAutoDutyTask(uint ContentFinderConditionId) : ITask internal sealed record WaitAutoDutyTask(uint ContentFinderConditionId) : ITask
@ -117,6 +119,8 @@ internal static class Duty
? ETaskResult.TaskComplete ? ETaskResult.TaskComplete
: ETaskResult.StillRunning; : ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal sealed record OpenDutyFinderTask(uint ContentFinderConditionId) : ITask internal sealed record OpenDutyFinderTask(uint ContentFinderConditionId) : ITask
@ -138,5 +142,7 @@ internal static class Duty
} }
public override ETaskResult Update() => ETaskResult.TaskComplete; public override ETaskResult Update() => ETaskResult.TaskComplete;
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -51,6 +51,8 @@ internal static class Emote
chatFunctions.UseEmote(Task.DataId, Task.Emote); chatFunctions.UseEmote(Task.DataId, Task.Emote);
return true; return true;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
internal sealed record UseOnSelf(EEmote Emote) : ITask internal sealed record UseOnSelf(EEmote Emote) : ITask
@ -65,5 +67,7 @@ internal static class Emote
chatFunctions.UseEmote(Task.Emote); chatFunctions.UseEmote(Task.Emote);
return true; return true;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -183,5 +183,7 @@ internal static class EquipItem
return false; return false;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -40,7 +40,8 @@ internal static class EquipRecommended
public override string ToString() => "EquipRecommended"; public override string ToString() => "EquipRecommended";
} }
internal sealed unsafe class DoEquipRecommended(IClientState clientState, IChatGui chatGui, ICondition condition) : TaskExecutor<EquipTask> internal sealed unsafe class DoEquipRecommended(IClientState clientState, IChatGui chatGui, ICondition condition)
: TaskExecutor<EquipTask>
{ {
private bool _equipped; private bool _equipped;
@ -88,7 +89,7 @@ internal static class EquipRecommended
if (!isAllEquipped) if (!isAllEquipped)
{ {
chatGui.Print("Equipping recommended gear.", "Questionable"); chatGui.Print("Equipping recommended gear.", CommandHandler.MessageTag, CommandHandler.TagColor);
recommendedEquipModule->EquipRecommendedGear(); recommendedEquipModule->EquipRecommendedGear();
} }
@ -98,5 +99,7 @@ internal static class EquipRecommended
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -228,6 +228,8 @@ internal static class Interact
} }
} }
public override bool ShouldInterruptOnDamage() => true;
private enum EInteractionState private enum EInteractionState
{ {
None, None,

View File

@ -80,6 +80,8 @@ internal static class Jump
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
internal sealed class DoSingleJump( internal sealed class DoSingleJump(

View File

@ -48,5 +48,7 @@ internal static class Say
chatFunctions.ExecuteCommand($"/say {Task.ChatMessage}"); chatFunctions.ExecuteCommand($"/say {Task.ChatMessage}");
return true; return true;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
} }

View File

@ -43,5 +43,7 @@ internal static class StatusOff
{ {
return gameFunctions.HasStatus(Task.Status) ? ETaskResult.StillRunning : ETaskResult.TaskComplete; return gameFunctions.HasStatus(Task.Status) ? ETaskResult.StillRunning : ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -29,7 +29,7 @@ internal static class UseItem
{ {
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step) public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{ {
if (step.InteractionType is EInteractionType.SinglePlayerDuty) if (step.InteractionType is EInteractionType.SinglePlayerDuty or EInteractionType.CompleteQuest)
{ {
if (step.ItemId == null) if (step.ItemId == null)
return []; return [];
@ -205,6 +205,8 @@ internal static class UseItem
else else
return TimeSpan.FromSeconds(5); return TimeSpan.FromSeconds(5);
} }
public override bool ShouldInterruptOnDamage() => true;
} }
internal sealed record UseOnGround( internal sealed record UseOnGround(

View File

@ -50,6 +50,8 @@ internal static class InitiateLeve
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal sealed record OpenJournal(ElementId ElementId) : ITask internal sealed record OpenJournal(ElementId ElementId) : ITask
@ -85,6 +87,8 @@ internal static class InitiateLeve
return ETaskResult.StillRunning; return ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal sealed record Initiate(ElementId ElementId) : ITask internal sealed record Initiate(ElementId ElementId) : ITask
@ -111,6 +115,8 @@ internal static class InitiateLeve
return ETaskResult.StillRunning; return ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
internal sealed class SelectDifficulty : ITask internal sealed class SelectDifficulty : ITask
@ -138,5 +144,7 @@ internal static class InitiateLeve
return ETaskResult.StillRunning; return ETaskResult.StillRunning;
} }
public override bool ShouldInterruptOnDamage() => false;
} }
} }

View File

@ -179,10 +179,12 @@ internal static class AethernetShortcut
} }
} }
} }
else else if (clientState.TerritoryType == aetheryteData.TerritoryIds[Task.To])
logger.LogWarning( logger.LogWarning(
"Aethernet shortcut not unlocked (from: {FromAetheryte}, to: {ToAetheryte}), walking manually", "Aethernet shortcut not unlocked (from: {FromAetheryte}, to: {ToAetheryte}), skipping as we are already in the destination territory",
Task.From, Task.To); Task.From, Task.To);
else
throw new TaskException($"Aethernet shortcut not unlocked (from: {Task.From}, to: {Task.To})");
return false; return false;
} }
@ -267,5 +269,7 @@ internal static class AethernetShortcut
return ETaskResult.TaskComplete; return ETaskResult.TaskComplete;
} }
public override bool ShouldInterruptOnDamage() => true;
} }
} }

Some files were not shown because too many files have changed in this diff Show More