Compare commits

..

1 Commits

Author SHA1 Message Date
bb7fec09d8 Added 1555_The Newer King on the Block 2025-02-26 18:34:41 +00:00
40 changed files with 158 additions and 590 deletions

View File

@ -29,7 +29,13 @@
},
"TerritoryId": 129,
"InteractionType": "Interact",
"TargetTerritoryId": 129
"DialogueChoices": [
{
"Type": "YesNo",
"Prompt": "TEXT_CLSROG011_00102_Q9_000_901",
"Yes": true
}
]
},
{
"DataId": 1009943,

View File

@ -5,26 +5,6 @@
{
"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": {
@ -34,12 +14,16 @@
},
"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"
}
@ -61,25 +45,6 @@
{
"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,

View File

@ -152,9 +152,15 @@
"TerritoryId": 129,
"InteractionType": "Interact",
"TargetTerritoryId": 129,
"AethernetShortcut": [
"[Limsa Lominsa] Fishermens' Guild",
"[Limsa Lominsa] The Aftcastle"
],
"SkipConditions": {
"StepIf": {
"ExtraCondition": "NotRoguesGuild"
"InTerritory": [
128
]
}
}
},
@ -167,10 +173,6 @@
},
"TerritoryId": 128,
"InteractionType": "Interact",
"AethernetShortcut": [
"[Limsa Lominsa] Fishermens' Guild",
"[Limsa Lominsa] The Aftcastle"
],
"DialogueChoices": [
{
"Type": "List",

View File

@ -291,17 +291,7 @@
"Z": 239.30713
},
"TerritoryId": 129,
"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"
]
}
"InteractionType": "SinglePlayerDuty"
}
]
},

View File

@ -0,0 +1,48 @@
{
"$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
"Author": "Redacted",
"QuestSequence": [
{
"Sequence": 0,
"Steps": [
{
"DataId": 1025721,
"Position": {
"X": -75.94415,
"Y": 11.800039,
"Z": -115.617676
},
"TerritoryId": 628,
"InteractionType": "AcceptQuest",
"AetheryteShortcut": "Kugane",
"AethernetShortcut": [
"[Kugane] Aetheryte Plaza",
"[Kugane] Bokairo Inn"
],
"DialogueChoices": [
{
"Type": "List",
"Prompt": "TEXT_STMBDY992_01555_Q1_000_000",
"Answer": "TEXT_STMBDY992_01555_A1_000_001"
}
]
}
]
},
{
"Sequence": 255,
"Steps": [
{
"DataId": 1025721,
"Position": {
"X": -75.94415,
"Y": 11.800039,
"Z": -115.617676
},
"TerritoryId": 628,
"InteractionType": "CompleteQuest"
}
]
}
]
}

View File

@ -78,14 +78,6 @@
},
"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": [
{

View File

@ -84,10 +84,7 @@
},
"TerritoryId": 180,
"InteractionType": "SinglePlayerDuty",
"SinglePlayerDutyOptions": {
"Enabled": true,
"TestedBossModVersion": 292
}
"Comment": "Great Ship Vylbrand"
}
]
},

View File

@ -46,15 +46,6 @@
"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"
}
]

View File

@ -99,9 +99,6 @@
}
]
},
{
"Sequence": 5
},
{
"Sequence": 255,
"Steps": [

View File

@ -54,11 +54,6 @@
},
"TerritoryId": 816,
"InteractionType": "SinglePlayerDuty",
"SinglePlayerDutyOptions": {
"Enabled": true,
"TestedBossModVersion": 293,
"$": "test: Redacted"
},
"ItemId": 2002569
}
]

View File

@ -153,7 +153,7 @@
"Y": -14.169313,
"Z": 114.76306
},
"StopDistance": 6.9,
"StopDistance": 7,
"TerritoryId": 962,
"InteractionType": "Interact"
}

View File

@ -146,8 +146,7 @@
"TerritoryId": 956,
"InteractionType": "UseItem",
"ItemId": 2003129,
"Mount": false,
"DelaySecondsAtStart": 2
"Mount": false
}
]
},

View File

@ -30,13 +30,6 @@
"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",

View File

@ -59,15 +59,7 @@
},
"TerritoryId": 958,
"InteractionType": "SinglePlayerDuty",
"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"
]
},
"Comment": "In from the Cold",
"DialogueChoices": [
{
"Type": "YesNo",

View File

@ -54,10 +54,7 @@
},
"TerritoryId": 961,
"InteractionType": "SinglePlayerDuty",
"SinglePlayerDutyOptions": {
"Enabled": true,
"TestedBossModVersion": 294
}
"Comment": "Venat"
}
]
},

View File

@ -29,11 +29,8 @@
},
"TerritoryId": 958,
"InteractionType": "SinglePlayerDuty",
"SinglePlayerDutyOptions": {
"Enabled": true,
"TestedBossModVersion": 294
},
"AetheryteShortcut": "Garlemald - Camp Broken Glass"
"AetheryteShortcut": "Garlemald - Camp Broken Glass",
"Comment": "As the Heavens Burn"
}
]
},

View File

@ -302,7 +302,6 @@
"WakingSandsSolar",
"RisingStonesSolar",
"RoguesGuild",
"NotRoguesGuild",
"DockStorehouse"
]
}

View File

@ -11,7 +11,6 @@ public sealed class SkipConditionConverter() : EnumConverter<EExtraSkipCondition
{ EExtraSkipCondition.WakingSandsSolar, "WakingSandsSolar" },
{ EExtraSkipCondition.RisingStonesSolar, "RisingStonesSolar"},
{ EExtraSkipCondition.RoguesGuild, "RoguesGuild"},
{ EExtraSkipCondition.NotRoguesGuild, "NotRoguesGuild"},
{ EExtraSkipCondition.DockStorehouse, "DockStorehouse"},
};
}

View File

@ -15,7 +15,6 @@ 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.

View File

@ -113,15 +113,12 @@ public sealed class QuestStep
public float CalculateActualStopDistance()
{
if (StopDistance is { } stopDistance)
return stopDistance;
return InteractionType switch
{
EInteractionType.WalkTo => 0.25f,
EInteractionType.AttuneAetheryte => 10f,
_ => DefaultStopDistance
};
if (InteractionType == EInteractionType.WalkTo)
return StopDistance ?? 0.25f;
if (InteractionType == EInteractionType.AttuneAetheryte)
return StopDistance ?? 10f;
else
return StopDistance ?? DefaultStopDistance;
}
/// <summary>

View File

@ -37,7 +37,6 @@
<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>

View File

@ -1,7 +1,14 @@
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;
@ -12,6 +19,8 @@ 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,
@ -34,7 +43,12 @@ internal sealed class BossModModule : ICombatModule, IDisposable
{
try
{
_bossModIpc.SetPreset(BossModIpc.EPreset.Overworld);
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");
return true;
}
catch (IpcError e)

View File

@ -1,5 +1,5 @@
{
"Name": "Questionable - Quest Battles",
"Name": "Questionable",
"Modules": {
"BossMod.Autorotation.MiscAI.AutoFarm": [],
"BossMod.Autorotation.MiscAI.AutoPull": [

View File

@ -1,293 +0,0 @@
{
"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"
}
]
}
}

View File

@ -89,7 +89,6 @@ 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()
{

View File

@ -687,17 +687,6 @@ 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; }

View File

@ -1,27 +0,0 @@
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;
}
}
}

View File

@ -96,9 +96,7 @@ internal static class SinglePlayerDuty
}
internal sealed class WaitSinglePlayerDutyExecutor(
BossModIpc bossModIpc,
MovementController movementController)
: TaskExecutor<WaitSinglePlayerDuty>, IStoppableTaskExecutor, IDebugStateProvider
BossModIpc bossModIpc) : TaskExecutor<WaitSinglePlayerDuty>, IStoppableTaskExecutor
{
protected override bool Start() => true;
@ -112,14 +110,6 @@ 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

View File

@ -45,13 +45,12 @@ internal static class QuestCleanUp
}
// have any of the previous sequences interacted with the issuer?
var previousSteps =
var previousSequences =
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 (!previousSteps.Any(x => x.DataId != null && mountConfiguration.IssuerDataIds.Contains(x.DataId.Value)))
if (previousSequences.SelectMany(x => x.Steps).All(x => x.DataId != mountConfiguration.IssuerDataId))
{
// 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);

View File

@ -20,6 +20,7 @@ namespace Questionable.Controller.Steps.Shared;
internal static class AethernetShortcut
{
internal sealed class Factory(
MovementController movementController,
AetheryteData aetheryteData,
TerritoryData territoryData,
IClientState clientState)
@ -30,7 +31,8 @@ internal static class AethernetShortcut
if (step.AethernetShortcut == null)
yield break;
yield return new WaitNavmesh.Task();
yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
"Wait(navmesh ready)");
yield return new Task(step.AethernetShortcut.From, step.AethernetShortcut.To,
step.SkipConditions?.AethernetShortcutIf ?? new());

View File

@ -38,6 +38,7 @@ internal static class Gather
}
internal sealed class DelayedGatheringExecutor(
MovementController movementController,
GatheringData gatheringData,
GatheringPointRegistry gatheringPointRegistry,
TerritoryData territoryData,
@ -84,7 +85,8 @@ internal static class Gather
yield return new WaitCondition.Task(() => clientState.TerritoryType == territoryId,
$"Wait(territory: {territoryData.GetNameAndId(territoryId)})");
yield return new WaitNavmesh.Task();
yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
"Wait(navmesh ready)");
yield return new GatheringTask(gatheringPointId, Task.GatheredItem);
yield return new WaitAtEnd.WaitDelay();

View File

@ -25,6 +25,7 @@ namespace Questionable.Controller.Steps.Shared;
internal static class MoveTo
{
internal sealed class Factory(
MovementController movementController,
IClientState clientState,
AetheryteData aetheryteData,
TerritoryData territoryData,
@ -66,7 +67,10 @@ internal static class MoveTo
$"Wait(territory: {territoryData.GetNameAndId(step.TerritoryId)})");
if (!step.DisableNavmesh)
yield return new WaitNavmesh.Task();
{
yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
"Wait(navmesh ready)");
}
yield return new MoveTask(step, destination);

View File

@ -310,7 +310,6 @@ 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)
};

View File

@ -30,11 +30,6 @@ internal interface IStoppableTaskExecutor : ITaskExecutor
void StopNow();
}
internal interface IDebugStateProvider : ITaskExecutor
{
string? GetDebugState();
}
internal abstract class TaskExecutor<T> : ITaskExecutor
where T : class, ITask
{

View File

@ -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, 1017432], 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, 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(List<uint> IssuerDataIds, EAetheryteLocation ClosestAetheryte);
public sealed record AlliedSocietyMountConfiguration(uint IssuerDataId, EAetheryteLocation ClosestAetheryte);

View File

@ -1,7 +1,3 @@
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;
@ -13,13 +9,7 @@ namespace Questionable.External;
internal sealed class BossModIpc
{
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 const string Name = "BossMod";
private readonly Configuration _configuration;
private readonly ICommandManager _commandManager;
@ -39,10 +29,10 @@ internal sealed class BossModIpc
_commandManager = commandManager;
_territoryData = territoryData;
_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");
_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");
}
public bool IsSupported()
@ -57,13 +47,19 @@ internal sealed class BossModIpc
}
}
public void SetPreset(EPreset preset)
public string? GetPreset(string name)
{
var definition = PresetDefinitions[preset];
if (_getPreset.InvokeFunc(definition.Name) == null)
_createPreset.InvokeFunc(definition.Content, true);
return _getPreset.InvokeFunc(name);
}
_setPreset.InvokeFunc(definition.Name);
public bool CreatePreset(string name, bool overwrite)
{
return _createPreset.InvokeFunc(name, overwrite);
}
public void SetPreset(string name)
{
_setPreset.InvokeFunc(name);
}
public void ClearPreset()
@ -72,11 +68,11 @@ internal sealed class BossModIpc
}
// TODO this should use your actual rotation plugin, not always vbm
public void EnableAi()
public void EnableAi(string presetName = "VBM Default")
{
_commandManager.ProcessCommand("/vbmai on");
_commandManager.ProcessCommand("/vbm cfg ZoneModuleConfig EnableQuestBattles true");
SetPreset(EPreset.QuestBattle);
SetPreset(presetName);
}
public void DisableAi()
@ -98,36 +94,12 @@ 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();
}
}
}

View File

@ -20,7 +20,6 @@ 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)
{
@ -36,7 +35,6 @@ 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
@ -138,19 +136,4 @@ 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;
}
}
}

View File

@ -10,28 +10,24 @@
<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_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>
<ItemGroup>
<None Remove="Controller\CombatModules\BossModPreset.json" />
<EmbeddedResource Include="Controller\CombatModules\BossModPreset.json">
<LogicalName>Questionable.Controller.CombatModules.BossModPreset</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -235,7 +235,6 @@ 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>();

View File

@ -73,34 +73,25 @@ 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
{
using var _ = ImRaii.Disabled();
ImGui.BeginDisabled();
ImGui.TextUnformatted(_questController.DebugState ?? string.Empty);
ImGui.EndDisabled();
}
QuestSequence? currentSequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
QuestStep? currentStep = currentSequence?.FindStep(currentQuest.Step);
if (!isMinimized)
{
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);
}
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();
//var nextStep = _questController.GetNextStep();
//ImGui.BeginDisabled(nextStep.Step == null);