Merge branch 'master' of https://git.carvel.li/liza/Questionable
This commit is contained in:
commit
276a97477b
@ -29,13 +29,7 @@
|
||||
},
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "Interact",
|
||||
"DialogueChoices": [
|
||||
{
|
||||
"Type": "YesNo",
|
||||
"Prompt": "TEXT_CLSROG011_00102_Q9_000_901",
|
||||
"Yes": true
|
||||
}
|
||||
]
|
||||
"TargetTerritoryId": 129
|
||||
},
|
||||
{
|
||||
"DataId": 1009943,
|
||||
|
@ -5,6 +5,26 @@
|
||||
{
|
||||
"Sequence": 0,
|
||||
"Steps": [
|
||||
{
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "EquipItem",
|
||||
"ItemId": 7952,
|
||||
"AetheryteShortcut": "Limsa Lominsa",
|
||||
"SkipConditions": {
|
||||
"AetheryteShortcutIf": {
|
||||
"InSameTerritory": true
|
||||
},
|
||||
"StepIf": {
|
||||
"Item": {
|
||||
"NotInInventory": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "EquipRecommended"
|
||||
},
|
||||
{
|
||||
"DataId": 1009944,
|
||||
"Position": {
|
||||
@ -14,16 +34,12 @@
|
||||
},
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "Interact",
|
||||
"AetheryteShortcut": "Limsa Lominsa",
|
||||
"TargetTerritoryId": 129,
|
||||
"AethernetShortcut": [
|
||||
"[Limsa Lominsa] Aetheryte Plaza",
|
||||
"[Limsa Lominsa] Fishermens' Guild"
|
||||
],
|
||||
"SkipConditions": {
|
||||
"AetheryteShortcutIf": {
|
||||
"InSameTerritory": true
|
||||
},
|
||||
"StepIf": {
|
||||
"ExtraCondition": "RoguesGuild"
|
||||
}
|
||||
@ -45,6 +61,25 @@
|
||||
{
|
||||
"Sequence": 1,
|
||||
"Steps": [
|
||||
{
|
||||
"DataId": 2004936,
|
||||
"Position": {
|
||||
"X": -151.90363,
|
||||
"Y": -128.16058,
|
||||
"Z": 256.8551
|
||||
},
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "Interact",
|
||||
"TargetTerritoryId": 129,
|
||||
"SkipConditions": {
|
||||
"StepIf": {
|
||||
"InTerritory": [
|
||||
134
|
||||
],
|
||||
"ExtraCondition": "NotRoguesGuild"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": 31.662792,
|
||||
|
@ -152,15 +152,9 @@
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "Interact",
|
||||
"TargetTerritoryId": 129,
|
||||
"AethernetShortcut": [
|
||||
"[Limsa Lominsa] Fishermens' Guild",
|
||||
"[Limsa Lominsa] The Aftcastle"
|
||||
],
|
||||
"SkipConditions": {
|
||||
"StepIf": {
|
||||
"InTerritory": [
|
||||
128
|
||||
]
|
||||
"ExtraCondition": "NotRoguesGuild"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -173,6 +167,10 @@
|
||||
},
|
||||
"TerritoryId": 128,
|
||||
"InteractionType": "Interact",
|
||||
"AethernetShortcut": [
|
||||
"[Limsa Lominsa] Fishermens' Guild",
|
||||
"[Limsa Lominsa] The Aftcastle"
|
||||
],
|
||||
"DialogueChoices": [
|
||||
{
|
||||
"Type": "List",
|
||||
|
@ -291,7 +291,17 @@
|
||||
"Z": 239.30713
|
||||
},
|
||||
"TerritoryId": 129,
|
||||
"InteractionType": "SinglePlayerDuty"
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": false,
|
||||
"TestedBossModVersion": 292,
|
||||
"Notes": [
|
||||
"(phase 1) AI doesn't move or pick up the stolen firearms",
|
||||
"(phase 1 + 2) AI automatically removes Hidden status",
|
||||
"(phase 2) AI only moves while targeted enemies are in range + gets stuck on corners while trying to get to irrelevant enemies",
|
||||
"(phase 2) AI doesn't even attempt to navigate to the end of the quest"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -78,6 +78,14 @@
|
||||
},
|
||||
"TerritoryId": 918,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": false,
|
||||
"TestedBossModVersion": 292,
|
||||
"Notes": [
|
||||
"(phase 2) AI doesn't target Ardbert to start combat",
|
||||
"(phase 2) VBM module: Elidibus' line cleave only covers half the length of the actual line (survivable)"
|
||||
]
|
||||
},
|
||||
"Comment": "Fight NPCs, then Elidibus",
|
||||
"DialogueChoices": [
|
||||
{
|
||||
|
@ -84,7 +84,10 @@
|
||||
},
|
||||
"TerritoryId": 180,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"Comment": "Great Ship Vylbrand"
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": true,
|
||||
"TestedBossModVersion": 292
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -46,6 +46,15 @@
|
||||
"StopDistance": 7,
|
||||
"TerritoryId": 132,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": false,
|
||||
"TestedBossModVersion": 293,
|
||||
"Notes": [
|
||||
"(Lunar Odin) AI doesn't pull Odin to start combat",
|
||||
"(Lunar Ravana) AI doesn't pull Ravana to start combat",
|
||||
"(Lunar Ravana) AI doesn't move out of directional parry directions"
|
||||
]
|
||||
},
|
||||
"Comment": "Death Unto Dawn"
|
||||
}
|
||||
]
|
||||
|
@ -99,6 +99,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sequence": 5
|
||||
},
|
||||
{
|
||||
"Sequence": 255,
|
||||
"Steps": [
|
||||
|
@ -54,6 +54,11 @@
|
||||
},
|
||||
"TerritoryId": 816,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": true,
|
||||
"TestedBossModVersion": 293,
|
||||
"$": "test: Redacted"
|
||||
},
|
||||
"ItemId": 2002569
|
||||
}
|
||||
]
|
||||
|
@ -153,7 +153,7 @@
|
||||
"Y": -14.169313,
|
||||
"Z": 114.76306
|
||||
},
|
||||
"StopDistance": 7,
|
||||
"StopDistance": 6.9,
|
||||
"TerritoryId": 962,
|
||||
"InteractionType": "Interact"
|
||||
}
|
||||
|
@ -146,7 +146,8 @@
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "UseItem",
|
||||
"ItemId": 2003129,
|
||||
"Mount": false
|
||||
"Mount": false,
|
||||
"DelaySecondsAtStart": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -30,6 +30,13 @@
|
||||
"TerritoryId": 621,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"Comment": "A Frosty Reception",
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": false,
|
||||
"TestedBossModVersion": 293,
|
||||
"Notes": [
|
||||
"(Thancred) How many enemies get pulled during the stealth section is random; if you pull multiple you can die here. Can probably be fixed by retrying on very easy."
|
||||
]
|
||||
},
|
||||
"DialogueChoices": [
|
||||
{
|
||||
"Type": "List",
|
||||
|
@ -59,7 +59,15 @@
|
||||
},
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"Comment": "In from the Cold",
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": false,
|
||||
"Notes": [
|
||||
"Instance probably only works on very easy difficulty",
|
||||
"AI doesn't move to first enemy",
|
||||
"AI doesn't unmount from the Magitek Reaper",
|
||||
"Navmesh takes 5+ minutes to build"
|
||||
]
|
||||
},
|
||||
"DialogueChoices": [
|
||||
{
|
||||
"Type": "YesNo",
|
||||
|
@ -54,7 +54,10 @@
|
||||
},
|
||||
"TerritoryId": 961,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"Comment": "Venat"
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": true,
|
||||
"TestedBossModVersion": 294
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -29,8 +29,11 @@
|
||||
},
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"AetheryteShortcut": "Garlemald - Camp Broken Glass",
|
||||
"Comment": "As the Heavens Burn"
|
||||
"SinglePlayerDutyOptions": {
|
||||
"Enabled": true,
|
||||
"TestedBossModVersion": 294
|
||||
},
|
||||
"AetheryteShortcut": "Garlemald - Camp Broken Glass"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -302,6 +302,7 @@
|
||||
"WakingSandsSolar",
|
||||
"RisingStonesSolar",
|
||||
"RoguesGuild",
|
||||
"NotRoguesGuild",
|
||||
"DockStorehouse"
|
||||
]
|
||||
}
|
||||
|
1
Questionable.IpcTest/.gitignore
vendored
Normal file
1
Questionable.IpcTest/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/dist
|
11
Questionable.IpcTest/DalamudPackager.targets
Normal file
11
Questionable.IpcTest/DalamudPackager.targets
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<Target Name="PackagePlugin" AfterTargets="Build">
|
||||
<DalamudPackager
|
||||
ProjectDir="$(ProjectDir)"
|
||||
OutputPath="$(OutputPath)"
|
||||
AssemblyName="$(AssemblyName)"
|
||||
MakeZip="false"
|
||||
VersionComponents="2"/>
|
||||
</Target>
|
||||
</Project>
|
59
Questionable.IpcTest/IpcTestPlugin.cs
Normal file
59
Questionable.IpcTest/IpcTestPlugin.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
namespace Questionable.IpcTest;
|
||||
|
||||
public sealed class IpcTestPlugin : IDalamudPlugin
|
||||
{
|
||||
//private readonly WindowSystem _windowSystem = new("Questionable/" + nameof(IpcTestPlugin));
|
||||
private readonly IDalamudPluginInterface _pluginInterface;
|
||||
private readonly ICommandManager _commandManager;
|
||||
private readonly IChatGui _chatGui;
|
||||
|
||||
public IpcTestPlugin(
|
||||
IDalamudPluginInterface pluginInterface,
|
||||
ICommandManager commandManager,
|
||||
IChatGui chatGui)
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_commandManager = commandManager;
|
||||
_chatGui = chatGui;
|
||||
|
||||
commandManager.AddHandler("/qipc", new CommandInfo(ProcessCommand));
|
||||
}
|
||||
|
||||
private void ProcessCommand(string command, string arguments)
|
||||
{
|
||||
if (arguments == "stepdata")
|
||||
{
|
||||
var stepData = _pluginInterface.GetIpcSubscriber<IpcStepData?>("Questionable.GetCurrentStepData").InvokeFunc();
|
||||
_chatGui.Print(new SeStringBuilder()
|
||||
.AddUiForeground("[IPC]", 576)
|
||||
.AddText(": Type: ")
|
||||
.AddUiForeground(stepData?.InteractionType ?? "?", 61)
|
||||
.AddText(" - Pos: ")
|
||||
.AddUiForeground(stepData?.Position?.ToString("G", CultureInfo.InvariantCulture) ?? "?", 61)
|
||||
.AddText(" - Territory: ")
|
||||
.AddUiForeground(stepData?.TerritoryId.ToString() ?? "?", 61)
|
||||
.Build());
|
||||
}
|
||||
else
|
||||
_chatGui.PrintError("Unknown subcommand");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_commandManager.RemoveHandler("/qipc");
|
||||
}
|
||||
|
||||
private sealed class IpcStepData
|
||||
{
|
||||
public required string InteractionType { get; set; }
|
||||
public required Vector3? Position { get; set; }
|
||||
public required ushort TerritoryId { get; set; }
|
||||
}
|
||||
}
|
13
Questionable.IpcTest/Questionable.IpcTest.csproj
Normal file
13
Questionable.IpcTest/Questionable.IpcTest.csproj
Normal file
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/11.0.0">
|
||||
<PropertyGroup>
|
||||
<OutputPath>dist</OutputPath>
|
||||
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LLib\LLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\LLib\LLib.targets"/>
|
||||
</Project>
|
7
Questionable.IpcTest/Questionable.IpcTest.json
Normal file
7
Questionable.IpcTest/Questionable.IpcTest.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"Name": "Questionable IPC Test",
|
||||
"Author": "Liza Carvelli",
|
||||
"Punchline": "[Questionable dev plugin]: IPC Tester.",
|
||||
"Description": "[Questionable dev plugin]: IPC Tester",
|
||||
"RepoUrl": "https://git.carvel.li/liza/Questionable/src/branch/master/Questionable.IpcTest"
|
||||
}
|
1050
Questionable.IpcTest/packages.lock.json
Normal file
1050
Questionable.IpcTest/packages.lock.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ public sealed class SkipConditionConverter() : EnumConverter<EExtraSkipCondition
|
||||
{ EExtraSkipCondition.WakingSandsSolar, "WakingSandsSolar" },
|
||||
{ EExtraSkipCondition.RisingStonesSolar, "RisingStonesSolar"},
|
||||
{ EExtraSkipCondition.RoguesGuild, "RoguesGuild"},
|
||||
{ EExtraSkipCondition.NotRoguesGuild, "NotRoguesGuild"},
|
||||
{ EExtraSkipCondition.DockStorehouse, "DockStorehouse"},
|
||||
};
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ public enum EExtraSkipCondition
|
||||
/// Location for ROG quests in Limsa Lominsa; located far underneath the actual lower decks.
|
||||
/// </summary>
|
||||
RoguesGuild,
|
||||
NotRoguesGuild,
|
||||
|
||||
/// <summary>
|
||||
/// Location for NIN quests in Eastern La Noscea; located far underneath the actual zone.
|
||||
|
@ -113,12 +113,15 @@ public sealed class QuestStep
|
||||
|
||||
public float CalculateActualStopDistance()
|
||||
{
|
||||
if (InteractionType == EInteractionType.WalkTo)
|
||||
return StopDistance ?? 0.25f;
|
||||
if (InteractionType == EInteractionType.AttuneAetheryte)
|
||||
return StopDistance ?? 10f;
|
||||
else
|
||||
return StopDistance ?? DefaultStopDistance;
|
||||
if (StopDistance is { } stopDistance)
|
||||
return stopDistance;
|
||||
|
||||
return InteractionType switch
|
||||
{
|
||||
EInteractionType.WalkTo => 0.25f,
|
||||
EInteractionType.AttuneAetheryte => 10f,
|
||||
_ => DefaultStopDistance
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -30,6 +30,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotificationMasterAPI", "ve
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pictomancy", "vendor\pictomancy\Pictomancy\Pictomancy.csproj", "{D1AE2F8C-BDE7-457F-A369-973101044A25}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Questionable.IpcTest", "Questionable.IpcTest\Questionable.IpcTest.csproj", "{8572A8B2-2F31-4D17-B207-6A7A2E0579EF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@ -76,6 +78,10 @@ Global
|
||||
{D1AE2F8C-BDE7-457F-A369-973101044A25}.Debug|x64.Build.0 = Debug|x64
|
||||
{D1AE2F8C-BDE7-457F-A369-973101044A25}.Release|x64.ActiveCfg = Release|x64
|
||||
{D1AE2F8C-BDE7-457F-A369-973101044A25}.Release|x64.Build.0 = Release|x64
|
||||
{8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -37,6 +37,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=tertium/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=tural/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=urqopacha/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=vnavmesh/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=wachumeqimeqi/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=wachunpelo/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=wolekdorf/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -1,14 +1,7 @@
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc;
|
||||
using Dalamud.Plugin.Ipc.Exceptions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Json.Schema;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Model;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using Questionable.External;
|
||||
|
||||
namespace Questionable.Controller.CombatModules;
|
||||
@ -19,8 +12,6 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
||||
private readonly BossModIpc _bossModIpc;
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
private static Stream Preset => typeof(BossModModule).Assembly.GetManifestResourceStream("Questionable.Controller.CombatModules.BossModPreset")!;
|
||||
|
||||
public BossModModule(
|
||||
ILogger<BossModModule> logger,
|
||||
BossModIpc bossModIpc,
|
||||
@ -43,12 +34,7 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_bossModIpc.GetPreset("Questionable") == null)
|
||||
{
|
||||
using var reader = new StreamReader(Preset);
|
||||
_logger.LogInformation("Loading Questionable BossMod Preset: {LoadedState}", _bossModIpc.CreatePreset(reader.ReadToEnd(), true));
|
||||
}
|
||||
_bossModIpc.SetPreset("Questionable");
|
||||
_bossModIpc.SetPreset(BossModIpc.EPreset.Overworld);
|
||||
return true;
|
||||
}
|
||||
catch (IpcError e)
|
||||
|
@ -0,0 +1,293 @@
|
||||
{
|
||||
"Name": "Questionable",
|
||||
"Modules": {
|
||||
"BossMod.Autorotation.xan.DNC": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.MCH": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.MNK": [
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.PCT": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
},
|
||||
{
|
||||
"Track": "Motifs",
|
||||
"Option": "Downtime"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.PLD": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.SAM": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.SGE": [
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.VPR": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.NIN": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.GNB": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.SMN": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.DRK": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.RPR": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.WHM": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.AST": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.BRD": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.SCH": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.BLM": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.RDM": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.xan.DRG": [
|
||||
{
|
||||
"Track": "Buffs",
|
||||
"Option": "Auto"
|
||||
},
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AOE"
|
||||
},
|
||||
{
|
||||
"Track": "Targeting",
|
||||
"Option": "Manual"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.VeynWAR": [
|
||||
{
|
||||
"Track": "AOE",
|
||||
"Option": "AutoFinishCombo"
|
||||
}
|
||||
],
|
||||
"BossMod.Autorotation.MiscAI.NormalMovement": [
|
||||
{
|
||||
"Track": "Destination",
|
||||
"Option": "Pathfind"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"Name": "Questionable",
|
||||
"Name": "Questionable - Quest Battles",
|
||||
"Modules": {
|
||||
"BossMod.Autorotation.MiscAI.AutoFarm": [],
|
||||
"BossMod.Autorotation.MiscAI.AutoPull": [
|
@ -89,6 +89,7 @@ internal sealed class MovementController : IDisposable
|
||||
public bool IsPathfinding => _pathfindTask is { IsCompleted: false };
|
||||
public DestinationData? Destination { get; set; }
|
||||
public DateTime MovementStartedAt { get; private set; } = DateTime.Now;
|
||||
public int BuiltNavmeshPercent => _navmeshIpc.GetBuildProgress();
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
@ -687,6 +687,17 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||
public bool IsRunning => !_taskQueue.AllTasksComplete;
|
||||
public TaskQueue TaskQueue => _taskQueue;
|
||||
|
||||
public string? CurrentTaskState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_taskQueue.CurrentTaskExecutor is IDebugStateProvider debugStateProvider)
|
||||
return debugStateProvider.GetDebugState();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class QuestProgress
|
||||
{
|
||||
public Quest Quest { get; }
|
||||
|
27
Questionable/Controller/Steps/Common/WaitNavmesh.cs
Normal file
27
Questionable/Controller/Steps/Common/WaitNavmesh.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace Questionable.Controller.Steps.Common;
|
||||
|
||||
internal sealed class WaitNavmesh
|
||||
{
|
||||
internal sealed record Task : ITask
|
||||
{
|
||||
public override string ToString() => "Wait(navmesh)";
|
||||
}
|
||||
|
||||
internal sealed class Executor(MovementController movementController) : TaskExecutor<Task>, IDebugStateProvider
|
||||
{
|
||||
protected override bool Start() => true;
|
||||
|
||||
public override ETaskResult Update() =>
|
||||
movementController.IsNavmeshReady ? ETaskResult.TaskComplete : ETaskResult.StillRunning;
|
||||
|
||||
public override bool ShouldInterruptOnDamage() => false;
|
||||
|
||||
public string? GetDebugState()
|
||||
{
|
||||
if (!movementController.IsNavmeshReady)
|
||||
return $"Navmesh: {movementController.BuiltNavmeshPercent}%";
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -96,7 +96,9 @@ internal static class SinglePlayerDuty
|
||||
}
|
||||
|
||||
internal sealed class WaitSinglePlayerDutyExecutor(
|
||||
BossModIpc bossModIpc) : TaskExecutor<WaitSinglePlayerDuty>, IStoppableTaskExecutor
|
||||
BossModIpc bossModIpc,
|
||||
MovementController movementController)
|
||||
: TaskExecutor<WaitSinglePlayerDuty>, IStoppableTaskExecutor, IDebugStateProvider
|
||||
{
|
||||
protected override bool Start() => true;
|
||||
|
||||
@ -110,6 +112,14 @@ internal static class SinglePlayerDuty
|
||||
public void StopNow() => bossModIpc.DisableAi();
|
||||
|
||||
public override bool ShouldInterruptOnDamage() => false;
|
||||
|
||||
public string? GetDebugState()
|
||||
{
|
||||
if (!movementController.IsNavmeshReady)
|
||||
return $"Navmesh: {movementController.BuiltNavmeshPercent}%";
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record DisableAi : ITask
|
||||
|
@ -45,12 +45,13 @@ internal static class QuestCleanUp
|
||||
}
|
||||
|
||||
// have any of the previous sequences interacted with the issuer?
|
||||
var previousSequences =
|
||||
var previousSteps =
|
||||
quest.AllSequences()
|
||||
.Where(x => x.Sequence > 0 // quest accept doesn't ever put us into a mount
|
||||
&& x.Sequence < sequence.Sequence)
|
||||
.SelectMany(x => x.Steps)
|
||||
.ToList();
|
||||
if (previousSequences.SelectMany(x => x.Steps).All(x => x.DataId != mountConfiguration.IssuerDataId))
|
||||
if (!previousSteps.Any(x => x.DataId != null && mountConfiguration.IssuerDataIds.Contains(x.DataId.Value)))
|
||||
{
|
||||
// this quest hasn't given us a mount yet
|
||||
logger.LogInformation("Haven't talked to mount NPC for this allied society quest; {Aetheryte}", mountConfiguration.ClosestAetheryte);
|
||||
|
@ -20,7 +20,6 @@ namespace Questionable.Controller.Steps.Shared;
|
||||
internal static class AethernetShortcut
|
||||
{
|
||||
internal sealed class Factory(
|
||||
MovementController movementController,
|
||||
AetheryteData aetheryteData,
|
||||
TerritoryData territoryData,
|
||||
IClientState clientState)
|
||||
@ -31,8 +30,7 @@ internal static class AethernetShortcut
|
||||
if (step.AethernetShortcut == null)
|
||||
yield break;
|
||||
|
||||
yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
|
||||
"Wait(navmesh ready)");
|
||||
yield return new WaitNavmesh.Task();
|
||||
yield return new Task(step.AethernetShortcut.From, step.AethernetShortcut.To,
|
||||
step.SkipConditions?.AethernetShortcutIf ?? new());
|
||||
|
||||
|
@ -38,7 +38,6 @@ internal static class Gather
|
||||
}
|
||||
|
||||
internal sealed class DelayedGatheringExecutor(
|
||||
MovementController movementController,
|
||||
GatheringData gatheringData,
|
||||
GatheringPointRegistry gatheringPointRegistry,
|
||||
TerritoryData territoryData,
|
||||
@ -85,8 +84,7 @@ internal static class Gather
|
||||
yield return new WaitCondition.Task(() => clientState.TerritoryType == territoryId,
|
||||
$"Wait(territory: {territoryData.GetNameAndId(territoryId)})");
|
||||
|
||||
yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
|
||||
"Wait(navmesh ready)");
|
||||
yield return new WaitNavmesh.Task();
|
||||
|
||||
yield return new GatheringTask(gatheringPointId, Task.GatheredItem);
|
||||
yield return new WaitAtEnd.WaitDelay();
|
||||
|
@ -25,7 +25,6 @@ namespace Questionable.Controller.Steps.Shared;
|
||||
internal static class MoveTo
|
||||
{
|
||||
internal sealed class Factory(
|
||||
MovementController movementController,
|
||||
IClientState clientState,
|
||||
AetheryteData aetheryteData,
|
||||
TerritoryData territoryData,
|
||||
@ -67,10 +66,7 @@ internal static class MoveTo
|
||||
$"Wait(territory: {territoryData.GetNameAndId(step.TerritoryId)})");
|
||||
|
||||
if (!step.DisableNavmesh)
|
||||
{
|
||||
yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
|
||||
"Wait(navmesh ready)");
|
||||
}
|
||||
yield return new WaitNavmesh.Task();
|
||||
|
||||
yield return new MoveTask(step, destination);
|
||||
|
||||
|
@ -310,6 +310,7 @@ internal static class SkipCondition
|
||||
EExtraSkipCondition.WakingSandsSolar => territoryType == 212 && position.X >= 24,
|
||||
EExtraSkipCondition.RisingStonesSolar => territoryType == 351 && position.Z <= -28,
|
||||
EExtraSkipCondition.RoguesGuild => territoryType == 129 && position.Y <= -115,
|
||||
EExtraSkipCondition.NotRoguesGuild => territoryType == 129 && position.Y > -115,
|
||||
EExtraSkipCondition.DockStorehouse => territoryType == 137 && position.Y <= -20,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(condition), condition, null)
|
||||
};
|
||||
|
@ -30,6 +30,11 @@ internal interface IStoppableTaskExecutor : ITaskExecutor
|
||||
void StopNow();
|
||||
}
|
||||
|
||||
internal interface IDebugStateProvider : ITaskExecutor
|
||||
{
|
||||
string? GetDebugState();
|
||||
}
|
||||
|
||||
internal abstract class TaskExecutor<T> : ITaskExecutor
|
||||
where T : class, ITask
|
||||
{
|
||||
|
@ -13,12 +13,12 @@ internal sealed class AlliedSocietyData
|
||||
public ReadOnlyDictionary<ushort, AlliedSocietyMountConfiguration> Mounts { get; } =
|
||||
new Dictionary<ushort, AlliedSocietyMountConfiguration>
|
||||
{
|
||||
{ 66, new(1016093, EAetheryteLocation.SeaOfCloudsOkZundu) },
|
||||
{ 79, new(1017031, EAetheryteLocation.DravanianForelandsAnyxTrine) },
|
||||
{ 88, new(1017470, EAetheryteLocation.ChurningMistsZenith) },
|
||||
{ 89, new(1017322, EAetheryteLocation.ChurningMistsZenith) },
|
||||
{ 147, new(1024777, EAetheryteLocation.FringesPeeringStones) },
|
||||
{ 369, new(1051798, EAetheryteLocation.KozamaukaDockPoga) },
|
||||
{ 66, new([1016093], EAetheryteLocation.SeaOfCloudsOkZundu) },
|
||||
{ 79, new([1017031], EAetheryteLocation.DravanianForelandsAnyxTrine) },
|
||||
{ 88, new([1017470, 1017432], EAetheryteLocation.ChurningMistsZenith) },
|
||||
{ 89, new([1017322], EAetheryteLocation.ChurningMistsZenith) },
|
||||
{ 147, new([1024777], EAetheryteLocation.FringesPeeringStones) },
|
||||
{ 369, new([1051798], EAetheryteLocation.KozamaukaDockPoga) },
|
||||
}.AsReadOnly();
|
||||
|
||||
public EAlliedSociety GetCommonAlliedSocietyTurnIn(ElementId elementId)
|
||||
@ -63,4 +63,4 @@ internal sealed class AlliedSocietyData
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record AlliedSocietyMountConfiguration(uint IssuerDataId, EAetheryteLocation ClosestAetheryte);
|
||||
public sealed record AlliedSocietyMountConfiguration(IReadOnlyList<uint> IssuerDataIds, EAetheryteLocation ClosestAetheryte);
|
||||
|
68
Questionable/External/BossModIpc.cs
vendored
68
Questionable/External/BossModIpc.cs
vendored
@ -1,3 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc;
|
||||
using Dalamud.Plugin.Ipc.Exceptions;
|
||||
@ -9,7 +13,13 @@ namespace Questionable.External;
|
||||
|
||||
internal sealed class BossModIpc
|
||||
{
|
||||
private const string Name = "BossMod";
|
||||
private const string PluginName = "BossMod";
|
||||
|
||||
private static readonly ReadOnlyDictionary<EPreset, PresetDefinition> PresetDefinitions = new Dictionary<EPreset, PresetDefinition>
|
||||
{
|
||||
{ EPreset.Overworld, new PresetDefinition("Questionable", "Overworld") },
|
||||
{ EPreset.QuestBattle, new PresetDefinition("Questionable - Quest Battles", "QuestBattle") },
|
||||
}.AsReadOnly();
|
||||
|
||||
private readonly Configuration _configuration;
|
||||
private readonly ICommandManager _commandManager;
|
||||
@ -29,10 +39,10 @@ internal sealed class BossModIpc
|
||||
_commandManager = commandManager;
|
||||
_territoryData = territoryData;
|
||||
|
||||
_getPreset = pluginInterface.GetIpcSubscriber<string, string?>($"{Name}.Presets.Get");
|
||||
_createPreset = pluginInterface.GetIpcSubscriber<string, bool, bool>($"{Name}.Presets.Create");
|
||||
_setPreset = pluginInterface.GetIpcSubscriber<string, bool>($"{Name}.Presets.SetActive");
|
||||
_clearPreset = pluginInterface.GetIpcSubscriber<bool>($"{Name}.Presets.ClearActive");
|
||||
_getPreset = pluginInterface.GetIpcSubscriber<string, string?>($"{PluginName}.Presets.Get");
|
||||
_createPreset = pluginInterface.GetIpcSubscriber<string, bool, bool>($"{PluginName}.Presets.Create");
|
||||
_setPreset = pluginInterface.GetIpcSubscriber<string, bool>($"{PluginName}.Presets.SetActive");
|
||||
_clearPreset = pluginInterface.GetIpcSubscriber<bool>($"{PluginName}.Presets.ClearActive");
|
||||
}
|
||||
|
||||
public bool IsSupported()
|
||||
@ -47,19 +57,13 @@ internal sealed class BossModIpc
|
||||
}
|
||||
}
|
||||
|
||||
public string? GetPreset(string name)
|
||||
public void SetPreset(EPreset preset)
|
||||
{
|
||||
return _getPreset.InvokeFunc(name);
|
||||
}
|
||||
var definition = PresetDefinitions[preset];
|
||||
if (_getPreset.InvokeFunc(definition.Name) == null)
|
||||
_createPreset.InvokeFunc(definition.Content, true);
|
||||
|
||||
public bool CreatePreset(string name, bool overwrite)
|
||||
{
|
||||
return _createPreset.InvokeFunc(name, overwrite);
|
||||
}
|
||||
|
||||
public void SetPreset(string name)
|
||||
{
|
||||
_setPreset.InvokeFunc(name);
|
||||
_setPreset.InvokeFunc(definition.Name);
|
||||
}
|
||||
|
||||
public void ClearPreset()
|
||||
@ -68,11 +72,11 @@ internal sealed class BossModIpc
|
||||
}
|
||||
|
||||
// TODO this should use your actual rotation plugin, not always vbm
|
||||
public void EnableAi(string presetName = "VBM Default")
|
||||
public void EnableAi()
|
||||
{
|
||||
_commandManager.ProcessCommand("/vbmai on");
|
||||
_commandManager.ProcessCommand("/vbm cfg ZoneModuleConfig EnableQuestBattles true");
|
||||
SetPreset(presetName);
|
||||
SetPreset(EPreset.QuestBattle);
|
||||
}
|
||||
|
||||
public void DisableAi()
|
||||
@ -94,12 +98,36 @@ internal sealed class BossModIpc
|
||||
if (!_territoryData.TryGetContentFinderConditionForSoloInstance(questId, dutyOptions.Index, out var cfcData))
|
||||
return false;
|
||||
|
||||
if (_configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(cfcData.ContentFinderConditionId))
|
||||
if (_configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(cfcData
|
||||
.ContentFinderConditionId))
|
||||
return false;
|
||||
|
||||
if (_configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(cfcData.ContentFinderConditionId))
|
||||
if (_configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(cfcData
|
||||
.ContentFinderConditionId))
|
||||
return true;
|
||||
|
||||
return dutyOptions.Enabled;
|
||||
}
|
||||
|
||||
public enum EPreset
|
||||
{
|
||||
Overworld,
|
||||
QuestBattle,
|
||||
}
|
||||
|
||||
private sealed class PresetDefinition(string name, string fileName)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Content { get; } = LoadPreset(fileName);
|
||||
|
||||
private static string LoadPreset(string name)
|
||||
{
|
||||
Stream stream =
|
||||
typeof(BossModIpc).Assembly.GetManifestResourceStream(
|
||||
$"Questionable.Controller.CombatModules.BossModPreset.{name}") ??
|
||||
throw new InvalidOperationException($"Preset {name} was not found");
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
Questionable/External/NavmeshIpc.cs
vendored
17
Questionable/External/NavmeshIpc.cs
vendored
@ -20,6 +20,7 @@ internal sealed class NavmeshIpc
|
||||
private readonly ICallGateSubscriber<List<Vector3>> _pathListWaypoints;
|
||||
private readonly ICallGateSubscriber<float, object> _pathSetTolerance;
|
||||
private readonly ICallGateSubscriber<Vector3, bool, float, Vector3?> _queryPointOnFloor;
|
||||
private readonly ICallGateSubscriber<float> _buildProgress;
|
||||
|
||||
public NavmeshIpc(IDalamudPluginInterface pluginInterface, ILogger<NavmeshIpc> logger)
|
||||
{
|
||||
@ -35,6 +36,7 @@ internal sealed class NavmeshIpc
|
||||
_pathSetTolerance = pluginInterface.GetIpcSubscriber<float, object>("vnavmesh.Path.SetTolerance");
|
||||
_queryPointOnFloor =
|
||||
pluginInterface.GetIpcSubscriber<Vector3, bool, float, Vector3?>("vnavmesh.Query.Mesh.PointOnFloor");
|
||||
_buildProgress = pluginInterface.GetIpcSubscriber<float>("vnavmesh.Nav.BuildProgress");
|
||||
}
|
||||
|
||||
public bool IsReady
|
||||
@ -136,4 +138,19 @@ internal sealed class NavmeshIpc
|
||||
else
|
||||
return [];
|
||||
}
|
||||
|
||||
public int GetBuildProgress()
|
||||
{
|
||||
try
|
||||
{
|
||||
float progress = _buildProgress.InvokeFunc();
|
||||
if (progress < 0)
|
||||
return 100;
|
||||
return (int)(progress * 100);
|
||||
}
|
||||
catch (IpcError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
Questionable/External/QuestionableIpc.cs
vendored
69
Questionable/External/QuestionableIpc.cs
vendored
@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc;
|
||||
using JetBrains.Annotations;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Model.Questing;
|
||||
using Questionable.Windows.QuestComponents;
|
||||
@ -13,21 +15,30 @@ internal sealed class QuestionableIpc : IDisposable
|
||||
{
|
||||
private const string IpcIsRunning = "Questionable.IsRunning";
|
||||
private const string IpcGetCurrentQuestId = "Questionable.GetCurrentQuestId";
|
||||
private const string IpcGetCurrentStepData = "Questionable.GetCurrentStepData";
|
||||
private const string IpcGetCurrentlyActiveEventQuests = "Questionable.GetCurrentlyActiveEventQuests";
|
||||
private const string IpcStartQuest = "Questionable.StartQuest";
|
||||
private const string IpcStartSingleQuest = "Questionable.StartSingleQuest";
|
||||
|
||||
private readonly QuestController _questController;
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
|
||||
private readonly ICallGateProvider<bool> _isRunning;
|
||||
private readonly ICallGateProvider<string?> _getCurrentQuestId;
|
||||
private readonly ICallGateProvider<StepData?> _getCurrentStepData;
|
||||
private readonly ICallGateProvider<List<string>> _getCurrentlyActiveEventQuests;
|
||||
private readonly ICallGateProvider<string, bool> _startQuest;
|
||||
private readonly ICallGateProvider<string, bool> _startSingleQuest;
|
||||
|
||||
public QuestionableIpc(
|
||||
QuestController questController,
|
||||
EventInfoComponent eventInfoComponent, QuestRegistry questRegistry,
|
||||
EventInfoComponent eventInfoComponent,
|
||||
QuestRegistry questRegistry,
|
||||
IDalamudPluginInterface pluginInterface)
|
||||
{
|
||||
_questController = questController;
|
||||
_questRegistry = questRegistry;
|
||||
|
||||
_isRunning = pluginInterface.GetIpcProvider<bool>(IpcIsRunning);
|
||||
_isRunning.RegisterFunc(() =>
|
||||
questController.AutomationType != QuestController.EAutomationType.Manual || questController.IsRunning);
|
||||
@ -35,38 +46,80 @@ internal sealed class QuestionableIpc : IDisposable
|
||||
_getCurrentQuestId = pluginInterface.GetIpcProvider<string?>(IpcGetCurrentQuestId);
|
||||
_getCurrentQuestId.RegisterFunc(() => questController.CurrentQuest?.Quest.Id.ToString());
|
||||
|
||||
_getCurrentStepData = pluginInterface.GetIpcProvider<StepData?>(IpcGetCurrentStepData);
|
||||
_getCurrentStepData.RegisterFunc(GetStepData);
|
||||
|
||||
_getCurrentlyActiveEventQuests =
|
||||
pluginInterface.GetIpcProvider<List<string>>(IpcGetCurrentlyActiveEventQuests);
|
||||
_getCurrentlyActiveEventQuests.RegisterFunc(() =>
|
||||
eventInfoComponent.GetCurrentlyActiveEventQuests().Select(q => q.ToString()).ToList());
|
||||
|
||||
_startQuest = pluginInterface.GetIpcProvider<string, bool>(IpcStartQuest);
|
||||
_startQuest.RegisterFunc((questId) => StartQuest(questController, questRegistry, questId, false));
|
||||
_startQuest.RegisterFunc(questId => StartQuest(questId, false));
|
||||
|
||||
_startSingleQuest = pluginInterface.GetIpcProvider<string, bool>(IpcStartSingleQuest);
|
||||
_startSingleQuest.RegisterFunc((questId) => StartQuest(questController, questRegistry, questId, true));
|
||||
_startSingleQuest.RegisterFunc(questId => StartQuest(questId, true));
|
||||
}
|
||||
|
||||
private static bool StartQuest(QuestController qc, QuestRegistry qr, string questId, bool single)
|
||||
private bool StartQuest(string questId, bool single)
|
||||
{
|
||||
if (ElementId.TryFromString(questId, out var elementId) && elementId != null && qr.TryGetQuest(elementId, out var quest))
|
||||
if (ElementId.TryFromString(questId, out var elementId) && elementId != null &&
|
||||
_questRegistry.TryGetQuest(elementId, out var quest))
|
||||
{
|
||||
qc.SetNextQuest(quest);
|
||||
_questController.SetNextQuest(quest);
|
||||
if (single)
|
||||
qc.StartSingleQuest("IPCQuestSelection");
|
||||
_questController.StartSingleQuest("IPCQuestSelection");
|
||||
else
|
||||
qc.Start("IPCQuestSelection");
|
||||
_questController.Start("IPCQuestSelection");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private StepData? GetStepData()
|
||||
{
|
||||
var progress = _questController.CurrentQuest;
|
||||
if (progress == null)
|
||||
return null;
|
||||
|
||||
string? questId = progress.Quest.Id.ToString();
|
||||
if (questId == null)
|
||||
return null;
|
||||
|
||||
QuestStep? step = progress.Quest.FindSequence(progress.Sequence)?.FindStep(progress.Step);
|
||||
if (step == null)
|
||||
return null;
|
||||
|
||||
return new StepData
|
||||
{
|
||||
QuestId = questId,
|
||||
Sequence = progress.Sequence,
|
||||
Step = progress.Step,
|
||||
InteractionType = step.InteractionType.ToString(),
|
||||
Position = step.Position,
|
||||
TerritoryId = step.TerritoryId
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_startSingleQuest.UnregisterFunc();
|
||||
_startQuest.UnregisterFunc();
|
||||
_getCurrentlyActiveEventQuests.UnregisterFunc();
|
||||
_getCurrentStepData.UnregisterFunc();
|
||||
_getCurrentQuestId.UnregisterFunc();
|
||||
_isRunning.UnregisterFunc();
|
||||
}
|
||||
|
||||
[UsedImplicitly(ImplicitUseKindFlags.Access, ImplicitUseTargetFlags.WithMembers)]
|
||||
public sealed class StepData
|
||||
{
|
||||
public required string QuestId { get; init; }
|
||||
public required byte Sequence { get; init; }
|
||||
public required int Step { get; init; }
|
||||
public required string InteractionType { get; init; }
|
||||
public required Vector3? Position { get; init; }
|
||||
public required ushort TerritoryId { get; init; }
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,28 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="4.0.1"/>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" ExcludeAssets="runtime" />
|
||||
<PackageReference Include="JsonSchema.Net" Version="7.1.2" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" ExcludeAssets="runtime"/>
|
||||
<PackageReference Include="JsonSchema.Net" Version="7.1.2"/>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GatheringPaths\GatheringPaths.csproj" />
|
||||
<ProjectReference Include="..\GatheringPaths\GatheringPaths.csproj"/>
|
||||
<ProjectReference Include="..\LLib\LLib.csproj"/>
|
||||
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj"/>
|
||||
<ProjectReference Include="..\QuestPaths\QuestPaths.csproj"/>
|
||||
<ProjectReference Include="..\vendor\NotificationMasterAPI\NotificationMasterAPI\NotificationMasterAPI.csproj" />
|
||||
<ProjectReference Include="..\vendor\NotificationMasterAPI\NotificationMasterAPI\NotificationMasterAPI.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Controller\CombatModules\BossModPreset.json" />
|
||||
<EmbeddedResource Include="Controller\CombatModules\BossModPreset.json">
|
||||
<LogicalName>Questionable.Controller.CombatModules.BossModPreset</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Controller\CombatModules\BossModPreset_Overworld.json"/>
|
||||
<None Remove="Controller\CombatModules\BossModPreset.QuestBattle.json"/>
|
||||
<EmbeddedResource Include="Controller\CombatModules\BossModPreset_Overworld.json">
|
||||
<LogicalName>Questionable.Controller.CombatModules.BossModPreset.Overworld</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Controller\CombatModules\BossModPreset_QuestBattle.json">
|
||||
<LogicalName>Questionable.Controller.CombatModules.BossModPreset.QuestBattle</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -235,6 +235,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
||||
serviceCollection.AddTaskExecutor<SinglePlayerDuty.SetTarget, SinglePlayerDuty.SetTargetExecutor>();
|
||||
|
||||
serviceCollection.AddTaskExecutor<WaitCondition.Task, WaitCondition.WaitConditionExecutor>();
|
||||
serviceCollection.AddTaskExecutor<WaitNavmesh.Task, WaitNavmesh.Executor>();
|
||||
serviceCollection.AddTaskFactory<WaitAtEnd.Factory>();
|
||||
serviceCollection.AddTaskExecutor<WaitAtEnd.WaitDelay, WaitAtEnd.WaitDelayExecutor>();
|
||||
serviceCollection.AddTaskExecutor<WaitAtEnd.WaitNextStepOrSequence, WaitAtEnd.WaitNextStepOrSequenceExecutor>();
|
||||
|
@ -73,25 +73,34 @@ internal sealed partial class ActiveQuestComponent
|
||||
|
||||
if (_combatController.IsRunning)
|
||||
ImGui.TextColored(ImGuiColors.DalamudOrange, "In Combat");
|
||||
else if (_questController.CurrentTaskState is { } currentTaskState)
|
||||
{
|
||||
using var _ = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange);
|
||||
ImGui.TextUnformatted(currentTaskState);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.BeginDisabled();
|
||||
using var _ = ImRaii.Disabled();
|
||||
ImGui.TextUnformatted(_questController.DebugState ?? string.Empty);
|
||||
ImGui.EndDisabled();
|
||||
}
|
||||
|
||||
QuestSequence? currentSequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
|
||||
QuestStep? currentStep = currentSequence?.FindStep(currentQuest.Step);
|
||||
if (!isMinimized)
|
||||
{
|
||||
bool colored = currentStep is
|
||||
{ InteractionType: EInteractionType.Instruction or EInteractionType.WaitForManualProgress or EInteractionType.Snipe };
|
||||
if (colored)
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudOrange);
|
||||
ImGui.TextUnformatted(currentStep?.Comment ??
|
||||
currentSequence?.Comment ?? currentQuest.Quest.Root.Comment ?? string.Empty);
|
||||
if (colored)
|
||||
ImGui.PopStyleColor();
|
||||
using (var color = new ImRaii.Color())
|
||||
{
|
||||
bool colored = currentStep is
|
||||
{
|
||||
InteractionType: EInteractionType.Instruction or EInteractionType.WaitForManualProgress
|
||||
or EInteractionType.Snipe
|
||||
};
|
||||
if (colored)
|
||||
color.Push(ImGuiCol.Text, ImGuiColors.DalamudOrange);
|
||||
|
||||
ImGui.TextUnformatted(currentStep?.Comment ??
|
||||
currentSequence?.Comment ?? currentQuest.Quest.Root.Comment ?? string.Empty);
|
||||
}
|
||||
|
||||
//var nextStep = _questController.GetNextStep();
|
||||
//ImGui.BeginDisabled(nextStep.Step == null);
|
||||
|
Loading…
x
Reference in New Issue
Block a user