Add quest battle preset

This commit is contained in:
Liza 2025-02-24 17:50:16 +01:00
parent c7f4865201
commit b213e872da
Signed by: liza
GPG Key ID: 2C41B84815CF6445
12 changed files with 435 additions and 67 deletions

View File

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

View File

@ -5,6 +5,26 @@
{ {
"Sequence": 0, "Sequence": 0,
"Steps": [ "Steps": [
{
"TerritoryId": 129,
"InteractionType": "EquipItem",
"ItemId": 7952,
"AetheryteShortcut": "Limsa Lominsa",
"SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
},
"StepIf": {
"Item": {
"NotInInventory": true
}
}
}
},
{
"TerritoryId": 129,
"InteractionType": "EquipRecommended"
},
{ {
"DataId": 1009944, "DataId": 1009944,
"Position": { "Position": {
@ -14,16 +34,12 @@
}, },
"TerritoryId": 129, "TerritoryId": 129,
"InteractionType": "Interact", "InteractionType": "Interact",
"AetheryteShortcut": "Limsa Lominsa",
"TargetTerritoryId": 129, "TargetTerritoryId": 129,
"AethernetShortcut": [ "AethernetShortcut": [
"[Limsa Lominsa] Aetheryte Plaza", "[Limsa Lominsa] Aetheryte Plaza",
"[Limsa Lominsa] Fishermens' Guild" "[Limsa Lominsa] Fishermens' Guild"
], ],
"SkipConditions": { "SkipConditions": {
"AetheryteShortcutIf": {
"InSameTerritory": true
},
"StepIf": { "StepIf": {
"ExtraCondition": "RoguesGuild" "ExtraCondition": "RoguesGuild"
} }
@ -45,6 +61,25 @@
{ {
"Sequence": 1, "Sequence": 1,
"Steps": [ "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": { "Position": {
"X": 31.662792, "X": 31.662792,

View File

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

View File

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

View File

@ -78,6 +78,14 @@
}, },
"TerritoryId": 918, "TerritoryId": 918,
"InteractionType": "SinglePlayerDuty", "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", "Comment": "Fight NPCs, then Elidibus",
"DialogueChoices": [ "DialogueChoices": [
{ {

View File

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

View File

@ -46,6 +46,15 @@
"StopDistance": 7, "StopDistance": 7,
"TerritoryId": 132, "TerritoryId": 132,
"InteractionType": "SinglePlayerDuty", "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" "Comment": "Death Unto Dawn"
} }
] ]

View File

@ -1,14 +1,7 @@
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Ipc.Exceptions; using Dalamud.Plugin.Ipc.Exceptions;
using Dalamud.Plugin.Services;
using Json.Schema;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Model;
using System; using System;
using System.IO;
using System.Numerics;
using Questionable.External; using Questionable.External;
namespace Questionable.Controller.CombatModules; namespace Questionable.Controller.CombatModules;
@ -19,8 +12,6 @@ internal sealed class BossModModule : ICombatModule, IDisposable
private readonly BossModIpc _bossModIpc; private readonly BossModIpc _bossModIpc;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private static Stream Preset => typeof(BossModModule).Assembly.GetManifestResourceStream("Questionable.Controller.CombatModules.BossModPreset")!;
public BossModModule( public BossModModule(
ILogger<BossModModule> logger, ILogger<BossModModule> logger,
BossModIpc bossModIpc, BossModIpc bossModIpc,
@ -43,12 +34,7 @@ internal sealed class BossModModule : ICombatModule, IDisposable
{ {
try try
{ {
if (_bossModIpc.GetPreset("Questionable") == null) _bossModIpc.SetPreset(BossModIpc.EPreset.Overworld);
{
using var reader = new StreamReader(Preset);
_logger.LogInformation("Loading Questionable BossMod Preset: {LoadedState}", _bossModIpc.CreatePreset(reader.ReadToEnd(), true));
}
_bossModIpc.SetPreset("Questionable");
return true; return true;
} }
catch (IpcError e) catch (IpcError e)

View File

@ -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"
}
]
}
}

View File

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

View File

@ -1,3 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Ipc.Exceptions; using Dalamud.Plugin.Ipc.Exceptions;
@ -9,7 +13,13 @@ namespace Questionable.External;
internal sealed class BossModIpc 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 Configuration _configuration;
private readonly ICommandManager _commandManager; private readonly ICommandManager _commandManager;
@ -29,10 +39,10 @@ internal sealed class BossModIpc
_commandManager = commandManager; _commandManager = commandManager;
_territoryData = territoryData; _territoryData = territoryData;
_getPreset = pluginInterface.GetIpcSubscriber<string, string?>($"{Name}.Presets.Get"); _getPreset = pluginInterface.GetIpcSubscriber<string, string?>($"{PluginName}.Presets.Get");
_createPreset = pluginInterface.GetIpcSubscriber<string, bool, bool>($"{Name}.Presets.Create"); _createPreset = pluginInterface.GetIpcSubscriber<string, bool, bool>($"{PluginName}.Presets.Create");
_setPreset = pluginInterface.GetIpcSubscriber<string, bool>($"{Name}.Presets.SetActive"); _setPreset = pluginInterface.GetIpcSubscriber<string, bool>($"{PluginName}.Presets.SetActive");
_clearPreset = pluginInterface.GetIpcSubscriber<bool>($"{Name}.Presets.ClearActive"); _clearPreset = pluginInterface.GetIpcSubscriber<bool>($"{PluginName}.Presets.ClearActive");
} }
public bool IsSupported() 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) _setPreset.InvokeFunc(definition.Name);
{
return _createPreset.InvokeFunc(name, overwrite);
}
public void SetPreset(string name)
{
_setPreset.InvokeFunc(name);
} }
public void ClearPreset() public void ClearPreset()
@ -68,11 +72,11 @@ internal sealed class BossModIpc
} }
// TODO this should use your actual rotation plugin, not always vbm // 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("/vbmai on");
_commandManager.ProcessCommand("/vbm cfg ZoneModuleConfig EnableQuestBattles true"); _commandManager.ProcessCommand("/vbm cfg ZoneModuleConfig EnableQuestBattles true");
SetPreset(presetName); SetPreset(EPreset.QuestBattle);
} }
public void DisableAi() public void DisableAi()
@ -94,12 +98,36 @@ internal sealed class BossModIpc
if (!_territoryData.TryGetContentFinderConditionForSoloInstance(questId, dutyOptions.Index, out var cfcData)) if (!_territoryData.TryGetContentFinderConditionForSoloInstance(questId, dutyOptions.Index, out var cfcData))
return false; return false;
if (_configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(cfcData.ContentFinderConditionId)) if (_configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(cfcData
.ContentFinderConditionId))
return false; return false;
if (_configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(cfcData.ContentFinderConditionId)) if (_configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(cfcData
.ContentFinderConditionId))
return true; return true;
return dutyOptions.Enabled; 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

@ -10,24 +10,28 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="4.0.1"/> <PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="4.0.1"/>
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" ExcludeAssets="runtime" /> <PackageReference Include="JetBrains.Annotations" Version="2024.2.0" ExcludeAssets="runtime"/>
<PackageReference Include="JsonSchema.Net" Version="7.1.2" /> <PackageReference Include="JsonSchema.Net" Version="7.1.2"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/> <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>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\GatheringPaths\GatheringPaths.csproj" /> <ProjectReference Include="..\GatheringPaths\GatheringPaths.csproj"/>
<ProjectReference Include="..\LLib\LLib.csproj"/> <ProjectReference Include="..\LLib\LLib.csproj"/>
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj"/> <ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj"/>
<ProjectReference Include="..\QuestPaths\QuestPaths.csproj"/> <ProjectReference Include="..\QuestPaths\QuestPaths.csproj"/>
<ProjectReference Include="..\vendor\NotificationMasterAPI\NotificationMasterAPI\NotificationMasterAPI.csproj" /> <ProjectReference Include="..\vendor\NotificationMasterAPI\NotificationMasterAPI\NotificationMasterAPI.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Controller\CombatModules\BossModPreset.json" /> <None Remove="Controller\CombatModules\BossModPreset_Overworld.json"/>
<EmbeddedResource Include="Controller\CombatModules\BossModPreset.json"> <None Remove="Controller\CombatModules\BossModPreset.QuestBattle.json"/>
<LogicalName>Questionable.Controller.CombatModules.BossModPreset</LogicalName> <EmbeddedResource Include="Controller\CombatModules\BossModPreset_Overworld.json">
</EmbeddedResource> <LogicalName>Questionable.Controller.CombatModules.BossModPreset.Overworld</LogicalName>
</ItemGroup> </EmbeddedResource>
<EmbeddedResource Include="Controller\CombatModules\BossModPreset_QuestBattle.json">
<LogicalName>Questionable.Controller.CombatModules.BossModPreset.QuestBattle</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project> </Project>