qstbak/Questionable/Questionable.Controller.Steps.Shared/WaitAtEnd.cs
2025-10-09 07:47:19 +10:00

405 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using Questionable.Controller.Steps.Common;
using Questionable.Controller.Utils;
using Questionable.Data;
using Questionable.External;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Controller.Steps.Shared;
internal static class WaitAtEnd
{
internal sealed class Factory(IClientState clientState, ICondition condition, TerritoryData territoryData, AutoDutyIpc autoDutyIpc, BossModIpc bossModIpc) : ITaskFactory
{
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.CompletionQuestVariablesFlags.Count == 6 && QuestWorkUtils.HasCompletionFlags(step.CompletionQuestVariablesFlags))
{
WaitForCompletionFlags waitForCompletionFlags = new WaitForCompletionFlags((QuestId)quest.Id, step);
WaitDelay waitDelay = new WaitDelay();
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
{
waitForCompletionFlags,
waitDelay,
Next(quest, sequence)
});
}
ITask task;
switch (step.InteractionType)
{
case EInteractionType.Combat:
{
if (step.EnemySpawnType == EEnemySpawnType.FinishCombatIfAny)
{
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(Next(quest, sequence));
}
WaitCondition.Task task2 = new WaitCondition.Task(() => !condition[ConditionFlag.InCombat], "Wait(not in combat)");
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[4]
{
new WaitDelay(),
task2,
new WaitDelay(),
Next(quest, sequence)
});
}
case EInteractionType.WaitForManualProgress:
case EInteractionType.Snipe:
case EInteractionType.Instruction:
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new WaitNextStepOrSequence());
case EInteractionType.Duty:
if (autoDutyIpc.IsConfiguredToRunContent(step.DutyOptions))
{
break;
}
goto IL_019d;
case EInteractionType.SinglePlayerDuty:
if (bossModIpc.IsConfiguredToRunSoloInstance(quest.Id, step.SinglePlayerDutyOptions))
{
break;
}
goto IL_019d;
case EInteractionType.WalkTo:
case EInteractionType.Jump:
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(Next(quest, sequence));
case EInteractionType.WaitForObjectAtPosition:
ArgumentNullException.ThrowIfNull(step.DataId, "step.DataId");
ArgumentNullException.ThrowIfNull(step.Position, "step.Position");
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
{
new WaitObjectAtPosition(step.DataId.Value, step.Position.Value, step.NpcWaitDistance ?? 0.5f),
new WaitDelay(),
Next(quest, sequence)
});
case EInteractionType.Interact:
if (!step.TargetTerritoryId.HasValue)
{
break;
}
goto IL_0284;
case EInteractionType.UseItem:
if (!step.TargetTerritoryId.HasValue)
{
break;
}
goto IL_0284;
case EInteractionType.AcceptQuest:
{
WaitQuestAccepted waitQuestAccepted = new WaitQuestAccepted(step.PickUpQuestId ?? quest.Id);
WaitDelay waitDelay3 = new WaitDelay();
if (step.PickUpQuestId != null)
{
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
{
waitQuestAccepted,
waitDelay3,
Next(quest, sequence)
});
}
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[2] { waitQuestAccepted, waitDelay3 });
}
case EInteractionType.CompleteQuest:
{
WaitQuestCompleted waitQuestCompleted = new WaitQuestCompleted(step.TurnInQuestId ?? quest.Id);
WaitDelay waitDelay2 = new WaitDelay();
if (step.TurnInQuestId != null)
{
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
{
waitQuestCompleted,
waitDelay2,
Next(quest, sequence)
});
}
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[2] { waitQuestCompleted, waitDelay2 });
}
IL_019d:
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new EndAutomation());
IL_0284:
if (step.TerritoryId != step.TargetTerritoryId)
{
task = new WaitCondition.Task(() => clientState.TerritoryType == step.TargetTerritoryId, "Wait(tp to territory: " + territoryData.GetNameAndId(step.TargetTerritoryId.Value) + ")");
}
else
{
Vector3 lastPosition = step.Position ?? clientState.LocalPlayer?.Position ?? Vector3.Zero;
task = new WaitCondition.Task(delegate
{
Vector3? vector = clientState.LocalPlayer?.Position;
return vector.HasValue && (lastPosition - vector.Value).Length() > 2f;
}, "Wait(tp away from " + lastPosition.ToString("G", CultureInfo.InvariantCulture) + ")");
}
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
{
task,
new WaitDelay(),
Next(quest, sequence)
});
}
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[2]
{
new WaitDelay(),
Next(quest, sequence)
});
}
private static NextStep Next(Quest quest, QuestSequence sequence)
{
return new NextStep(quest.Id, sequence.Sequence);
}
}
internal sealed record WaitDelay(TimeSpan Delay) : ITask
{
public WaitDelay()
: this(TimeSpan.FromSeconds(1L))
{
}
public bool ShouldRedoOnInterrupt()
{
return true;
}
public override string ToString()
{
return $"Wait(seconds: {Delay.TotalSeconds})";
}
}
internal sealed class WaitDelayExecutor : AbstractDelayedTaskExecutor<WaitDelay>
{
protected override bool StartInternal()
{
base.Delay = base.Task.Delay;
return true;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed class WaitNextStepOrSequence : ITask
{
public override string ToString()
{
return "Wait(next step or sequence)";
}
}
internal sealed class WaitNextStepOrSequenceExecutor : TaskExecutor<WaitNextStepOrSequence>
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
return ETaskResult.StillRunning;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed record WaitForCompletionFlags(QuestId Quest, QuestStep Step) : ITask
{
public override string ToString()
{
return "Wait(QW: " + string.Join(", ", Step.CompletionQuestVariablesFlags.Select((QuestWorkValue x) => x?.ToString() ?? "-")) + ")";
}
}
internal sealed class WaitForCompletionFlagsExecutor(QuestFunctions questFunctions) : TaskExecutor<WaitForCompletionFlags>()
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
QuestProgressInfo questProgressInfo = questFunctions.GetQuestProgressInfo(base.Task.Quest);
if (questProgressInfo == null || !QuestWorkUtils.MatchesQuestWork(base.Task.Step.CompletionQuestVariablesFlags, questProgressInfo))
{
return ETaskResult.StillRunning;
}
return ETaskResult.TaskComplete;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed record WaitObjectAtPosition(uint DataId, Vector3 Destination, float Distance) : ITask
{
public override string ToString()
{
return $"WaitObj({DataId} at {Destination.ToString("G", CultureInfo.InvariantCulture)} < {Distance})";
}
}
internal sealed class WaitObjectAtPositionExecutor(GameFunctions gameFunctions) : TaskExecutor<WaitObjectAtPosition>()
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
if (!gameFunctions.IsObjectAtPosition(base.Task.DataId, base.Task.Destination, base.Task.Distance))
{
return ETaskResult.StillRunning;
}
return ETaskResult.TaskComplete;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed record WaitQuestAccepted(ElementId ElementId) : ITask
{
public override string ToString()
{
return $"WaitQuestAccepted({ElementId})";
}
}
internal sealed class WaitQuestAcceptedExecutor(QuestFunctions questFunctions) : TaskExecutor<WaitQuestAccepted>()
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
if (!questFunctions.IsQuestAccepted(base.Task.ElementId))
{
return ETaskResult.StillRunning;
}
return ETaskResult.TaskComplete;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed record WaitQuestCompleted(ElementId ElementId) : ITask
{
public override string ToString()
{
return $"WaitQuestComplete({ElementId})";
}
}
internal sealed class WaitQuestCompletedExecutor(QuestFunctions questFunctions) : TaskExecutor<WaitQuestCompleted>()
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
if (!questFunctions.IsQuestComplete(base.Task.ElementId))
{
return ETaskResult.StillRunning;
}
return ETaskResult.TaskComplete;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed record NextStep(ElementId ElementId, int Sequence) : ILastTask, ITask
{
public override string ToString()
{
return "NextStep";
}
}
internal sealed class NextStepExecutor : TaskExecutor<NextStep>
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
return ETaskResult.NextStep;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
internal sealed class EndAutomation : ILastTask, ITask
{
public ElementId ElementId
{
get
{
throw new InvalidOperationException();
}
}
public int Sequence
{
get
{
throw new InvalidOperationException();
}
}
public override string ToString()
{
return "EndAutomation";
}
}
internal sealed class EndAutomationExecutor : TaskExecutor<EndAutomation>
{
protected override bool Start()
{
return true;
}
public override ETaskResult Update()
{
return ETaskResult.End;
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
}