Add special handling for Lahabrea fight
authorLiza Carvelli <liza@carvel.li>
Sat, 22 Feb 2025 00:06:41 +0000 (01:06 +0100)
committerLiza Carvelli <liza@carvel.li>
Sat, 22 Feb 2025 00:06:41 +0000 (01:06 +0100)
QuestPaths/2.x - A Realm Reborn/MSQ-2/C9-Ultimate Weapon/4522_The Ultimate Weapon.json
Questionable/Controller/QuestController.cs
Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs
Questionable/Functions/GameFunctions.cs
Questionable/QuestionablePlugin.cs

index 8d6f72e..ffa07f4 100644 (file)
           "TerritoryId": 1053,
           "InteractionType": "SinglePlayerDuty",
           "SinglePlayerDutyOptions": {
-            "Enabled": false,
-            "Notes": [
-              "Doesn't handle death properly"
-            ]
+            "Enabled": true
           }
         }
       ]
index 9fbaadf..b509de1 100644 (file)
@@ -10,6 +10,7 @@ using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game;
 using Microsoft.Extensions.Logging;
 using Questionable.Controller.Steps;
+using Questionable.Controller.Steps.Interactions;
 using Questionable.Controller.Steps.Shared;
 using Questionable.External;
 using Questionable.Functions;
@@ -200,7 +201,13 @@ internal sealed class QuestController : MiniTaskController<QuestController>
 
         if (!_clientState.IsLoggedIn || _condition[ConditionFlag.Unconscious])
         {
-            if (!_taskQueue.AllTasksComplete)
+            if (_condition[ConditionFlag.Unconscious] &&
+                _condition[ConditionFlag.SufferingStatusAffliction63] &&
+                _clientState.TerritoryType == SinglePlayerDuty.LahabreaTerritoryId)
+            {
+                // ignore, we're in the lahabrea fight
+            }
+            else if (!_taskQueue.AllTasksComplete)
             {
                 Stop("HP = 0");
                 _movementController.Stop();
index 188729b..7bf43b8 100644 (file)
@@ -1,7 +1,12 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
+using Dalamud.Game.ClientState.Conditions;
+using Dalamud.Game.ClientState.Objects;
+using Dalamud.Game.ClientState.Objects.Types;
 using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game;
+using Questionable.Controller.Steps.Common;
 using Questionable.Controller.Steps.Shared;
 using Questionable.Data;
 using Questionable.External;
@@ -12,9 +17,13 @@ namespace Questionable.Controller.Steps.Interactions;
 
 internal static class SinglePlayerDuty
 {
+    public const int LahabreaTerritoryId = 1052;
+
     internal sealed class Factory(
         BossModIpc bossModIpc,
-        TerritoryData territoryData) : ITaskFactory
+        TerritoryData territoryData,
+        ICondition condition,
+        IClientState clientState) : ITaskFactory
     {
         public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
         {
@@ -28,6 +37,14 @@ internal static class SinglePlayerDuty
 
                 yield return new StartSinglePlayerDuty(cfcData.ContentFinderConditionId);
                 yield return new EnableAi();
+                if (cfcData.TerritoryId == LahabreaTerritoryId)
+                {
+                    yield return new SetTarget(14643);
+                    yield return new WaitCondition.Task(() => condition[ConditionFlag.Unconscious] || clientState.TerritoryType != LahabreaTerritoryId, "Wait(death)");
+                    yield return new DisableAi();
+                    yield return new WaitCondition.Task(() => !condition[ConditionFlag.Unconscious] || clientState.TerritoryType != LahabreaTerritoryId, "Wait(resurrection)");
+                    yield return new EnableAi();
+                }
                 yield return new WaitSinglePlayerDuty(cfcData.ContentFinderConditionId);
                 yield return new DisableAi();
                 yield return new WaitAtEnd.WaitNextStepOrSequence();
@@ -113,4 +130,32 @@ internal static class SinglePlayerDuty
 
         public override bool ShouldInterruptOnDamage() => false;
     }
+
+    // TODO this should be handled in VBM
+    internal sealed record SetTarget(uint DataId) : ITask
+    {
+        public override string ToString() => $"SetTarget({DataId})";
+    }
+
+    internal sealed class SetTargetExecutor(
+        ITargetManager targetManager,
+        IObjectTable objectTable) : TaskExecutor<SetTarget>
+    {
+        protected override bool Start() => true;
+
+        public override ETaskResult Update()
+        {
+            if (targetManager.Target?.DataId == Task.DataId)
+                return ETaskResult.TaskComplete;
+
+            IGameObject? gameObject = objectTable.FirstOrDefault(x => x.DataId == Task.DataId);
+            if (gameObject == null)
+                return ETaskResult.StillRunning;
+
+            targetManager.Target = gameObject;
+            return ETaskResult.StillRunning;
+        }
+
+        public override bool ShouldInterruptOnDamage() => false;
+    }
 }
index 09a9be2..27c5fc8 100644 (file)
@@ -16,6 +16,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI;
 using LLib.GameUI;
 using Lumina.Excel.Sheets;
 using Microsoft.Extensions.Logging;
+using Questionable.Controller.Steps.Interactions;
 using Questionable.Model;
 using Questionable.Model.Questing;
 using Action = Lumina.Excel.Sheets.Action;
@@ -427,6 +428,11 @@ internal sealed unsafe class GameFunctions
                 return true;
         }
 
+        if (_condition[ConditionFlag.Unconscious] &&
+            _condition[ConditionFlag.SufferingStatusAffliction63] &&
+            _clientState.TerritoryType == SinglePlayerDuty.LahabreaTerritoryId)
+            return false; // needed to process the tasks
+
         return _condition[ConditionFlag.Occupied] || _condition[ConditionFlag.Occupied30] ||
                _condition[ConditionFlag.Occupied33] || _condition[ConditionFlag.Occupied38] ||
                _condition[ConditionFlag.Occupied39] || _condition[ConditionFlag.OccupiedInEvent] ||
index e6a82af..753ddb1 100644 (file)
@@ -231,6 +231,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
         serviceCollection
             .AddTaskExecutor<SinglePlayerDuty.WaitSinglePlayerDuty, SinglePlayerDuty.WaitSinglePlayerDutyExecutor>();
         serviceCollection.AddTaskExecutor<SinglePlayerDuty.DisableAi, SinglePlayerDuty.DisableAiExecutor>();
+        serviceCollection.AddTaskExecutor<SinglePlayerDuty.SetTarget, SinglePlayerDuty.SetTargetExecutor>();
 
         serviceCollection.AddTaskExecutor<WaitCondition.Task, WaitCondition.WaitConditionExecutor>();
         serviceCollection.AddTaskFactory<WaitAtEnd.Factory>();