forked from aly/qstbak
muffin v7.5.12
This commit is contained in:
parent
3102923ce2
commit
911ed68baa
65 changed files with 2356 additions and 1539 deletions
|
|
@ -32,6 +32,7 @@ internal static class AethernetRide
|
|||
private enum EAethernetPhase
|
||||
{
|
||||
None,
|
||||
WaitingForPlayer,
|
||||
Mounting,
|
||||
Moving,
|
||||
Unmounting,
|
||||
|
|
@ -72,6 +73,12 @@ internal static class AethernetRide
|
|||
return Environment.TickCount64 - _phaseStartedAt > (long)(timeoutSeconds * 1000f);
|
||||
}
|
||||
|
||||
public override void ResetTimeout()
|
||||
{
|
||||
base.ResetTimeout();
|
||||
_phaseStartedAt = Environment.TickCount64;
|
||||
}
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
SetPhase(EAethernetPhase.None);
|
||||
|
|
@ -79,56 +86,60 @@ internal static class AethernetRide
|
|||
aethernetTeleportService.Reset();
|
||||
if (aetheryteFunctions.IsAetheryteUnlocked(base.Task.From) && aetheryteFunctions.IsAetheryteUnlocked(base.Task.To))
|
||||
{
|
||||
uint territoryType = clientState.TerritoryType;
|
||||
IPlayerCharacter localPlayer = objectTable.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Vector3 playerPosition = localPlayer.Position;
|
||||
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.To))
|
||||
{
|
||||
float num = (base.Task.From.IsFirmamentAetheryte() ? 11f : (AetheryteConverter.IsLargeAetheryte(base.Task.From) ? 11f : 4f));
|
||||
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < num)
|
||||
{
|
||||
BeginTeleport();
|
||||
return true;
|
||||
}
|
||||
if (base.Task.From == EAetheryteLocation.SolutionNine)
|
||||
{
|
||||
logger.LogDebug("Moving to S9 aetheryte");
|
||||
int num2 = 4;
|
||||
List<Vector3> list = new List<Vector3>(num2);
|
||||
CollectionsMarshal.SetCount(list, num2);
|
||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
||||
span[0] = new Vector3(0f, 8.442986f, 9f);
|
||||
span[1] = new Vector3(9f, 8.442986f, 0f);
|
||||
span[2] = new Vector3(-9f, 8.442986f, 0f);
|
||||
span[3] = new Vector3(0f, 8.442986f, -9f);
|
||||
Vector3 to = list.MinBy((Vector3 x) => Vector3.Distance(playerPosition, x));
|
||||
SetPhase(EAethernetPhase.Moving);
|
||||
movementController.NavigateTo(EMovementType.Quest, (uint)base.Task.From, to, fly: false, sprint: true, 0.25f);
|
||||
return true;
|
||||
}
|
||||
if (territoryData.CanUseMount(territoryType) && aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) > 30f && !gameFunctions.HasStatusPreventingMount() && gameFunctions.Mount())
|
||||
{
|
||||
SetPhase(EAethernetPhase.Mounting);
|
||||
_continueAt = Environment.TickCount64 + 500;
|
||||
return true;
|
||||
}
|
||||
StartMoving();
|
||||
SetPhase(EAethernetPhase.WaitingForPlayer);
|
||||
return true;
|
||||
}
|
||||
Vector3 position = localPlayer.Position;
|
||||
if (HasArrived(position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
StartFromCurrentPosition(position);
|
||||
return true;
|
||||
}
|
||||
if (clientState.TerritoryType == aetheryteData.TerritoryIds[base.Task.To])
|
||||
{
|
||||
logger.LogWarning("Aethernet ride not unlocked (from: {FromAetheryte}, to: {ToAetheryte}), skipping as we are already in the destination territory", base.Task.From, base.Task.To);
|
||||
return false;
|
||||
}
|
||||
throw new TaskException($"Aethernet ride not unlocked (from: {base.Task.From}, to: {base.Task.To})");
|
||||
}
|
||||
|
||||
private void StartFromCurrentPosition(Vector3 playerPosition)
|
||||
{
|
||||
uint territoryType = clientState.TerritoryType;
|
||||
float num = (base.Task.From.IsFirmamentAetheryte() ? 11f : (AetheryteConverter.IsLargeAetheryte(base.Task.From) ? 11f : 4f));
|
||||
if (aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) < num)
|
||||
{
|
||||
BeginTeleport();
|
||||
}
|
||||
else if (base.Task.From == EAetheryteLocation.SolutionNine)
|
||||
{
|
||||
logger.LogDebug("Moving to S9 aetheryte");
|
||||
int num2 = 4;
|
||||
List<Vector3> list = new List<Vector3>(num2);
|
||||
CollectionsMarshal.SetCount(list, num2);
|
||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
||||
span[0] = new Vector3(0f, 8.442986f, 9f);
|
||||
span[1] = new Vector3(9f, 8.442986f, 0f);
|
||||
span[2] = new Vector3(-9f, 8.442986f, 0f);
|
||||
span[3] = new Vector3(0f, 8.442986f, -9f);
|
||||
Vector3 to = list.MinBy((Vector3 x) => Vector3.Distance(playerPosition, x));
|
||||
SetPhase(EAethernetPhase.Moving);
|
||||
movementController.NavigateTo(EMovementType.Quest, (uint)base.Task.From, to, fly: false, sprint: true, 0.25f);
|
||||
}
|
||||
else if (territoryData.CanUseMount(territoryType) && aetheryteData.CalculateDistance(playerPosition, territoryType, base.Task.From) > 30f && !gameFunctions.HasStatusPreventingMount() && gameFunctions.Mount())
|
||||
{
|
||||
SetPhase(EAethernetPhase.Mounting);
|
||||
_continueAt = Environment.TickCount64 + 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (clientState.TerritoryType != aetheryteData.TerritoryIds[base.Task.To])
|
||||
{
|
||||
throw new TaskException($"Aethernet ride not unlocked (from: {base.Task.From}, to: {base.Task.To})");
|
||||
}
|
||||
logger.LogWarning("Aethernet ride not unlocked (from: {FromAetheryte}, to: {ToAetheryte}), skipping as we are already in the destination territory", base.Task.From, base.Task.To);
|
||||
StartMoving();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void StartMoving()
|
||||
|
|
@ -178,6 +189,20 @@ internal static class AethernetRide
|
|||
}
|
||||
switch (_phase)
|
||||
{
|
||||
case EAethernetPhase.WaitingForPlayer:
|
||||
{
|
||||
Vector3? vector2 = objectTable.LocalPlayer?.Position;
|
||||
if (!vector2.HasValue)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (HasArrived(vector2.Value))
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
StartFromCurrentPosition(vector2.Value);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
case EAethernetPhase.Mounting:
|
||||
if (condition[ConditionFlag.Mounted])
|
||||
{
|
||||
|
|
@ -228,21 +253,7 @@ internal static class AethernetRide
|
|||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (aetheryteData.IsAirshipLanding(base.Task.To))
|
||||
{
|
||||
if (aetheryteData.CalculateAirshipLandingDistance(vector.Value, clientState.TerritoryType, base.Task.To) > 5f)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
}
|
||||
else if (aetheryteData.IsCityAetheryte(base.Task.To) || aetheryteData.IsGoldSaucerAetheryte(base.Task.To))
|
||||
{
|
||||
if (aetheryteData.CalculateDistance(vector.Value, clientState.TerritoryType, base.Task.To) > 20f)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
}
|
||||
else if (clientState.TerritoryType != aetheryteData.TerritoryIds[base.Task.To])
|
||||
if (!HasArrived(vector.Value))
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
|
@ -254,6 +265,15 @@ internal static class AethernetRide
|
|||
}
|
||||
}
|
||||
|
||||
private bool HasArrived(Vector3 position)
|
||||
{
|
||||
if (!aetheryteData.IsAirshipLanding(base.Task.To))
|
||||
{
|
||||
return aetheryteData.CalculateDistance(position, clientState.TerritoryType, base.Task.To) <= 20f;
|
||||
}
|
||||
return aetheryteData.CalculateAirshipLandingDistance(position, clientState.TerritoryType, base.Task.To) <= 5f;
|
||||
}
|
||||
|
||||
public override bool ShouldInterruptOnDamage()
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -16,33 +16,85 @@ namespace Questionable.Controller.Steps.Shared;
|
|||
|
||||
internal static class RedeemRewardItems
|
||||
{
|
||||
internal sealed class Factory(QuestData questData, Configuration configuration) : ITaskFactory
|
||||
internal sealed class Factory(QuestData questData, Configuration configuration, ILogger<Factory> logger) : ITaskFactory
|
||||
{
|
||||
public unsafe IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
if (step.InteractionType != EInteractionType.AcceptQuest)
|
||||
{
|
||||
return Array.Empty<ITask>();
|
||||
}
|
||||
List<ITask> list = new List<ITask>();
|
||||
InventoryManager* ptr = InventoryManager.Instance();
|
||||
if (ptr == null)
|
||||
return CreateTasks(questData, configuration, logger);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CompletionFactory : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
if (step.InteractionType != EInteractionType.CompleteQuest)
|
||||
{
|
||||
return list;
|
||||
return Array.Empty<ITask>();
|
||||
}
|
||||
bool hasFreeInventorySlot = InventoryHelper.HasFreeInventorySlot();
|
||||
foreach (ItemReward redeemableItem in questData.RedeemableItems)
|
||||
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new ScanAfterQuestCompletion(step.TurnInQuestId ?? quest.Id));
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record ScanAfterQuestCompletion(ElementId ElementId) : ITask
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ScanRewardsAfterQuestCompletion({ElementId})";
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ScanAfterQuestCompletionExecutor(QuestFunctions questFunctions, QuestData questData, Configuration configuration, ILogger<ScanAfterQuestCompletionExecutor> logger) : TaskExecutor<ScanAfterQuestCompletion>(), IExtraTaskCreator, ITaskExecutor
|
||||
{
|
||||
private const long InventorySettleDelayMs = 1000L;
|
||||
|
||||
private long? _scanAt;
|
||||
|
||||
private List<ITask> _tasks = new List<ITask>();
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
_scanAt = null;
|
||||
_tasks = new List<ITask>();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override ETaskResult Update()
|
||||
{
|
||||
if (!questFunctions.IsQuestComplete(base.Task.ElementId))
|
||||
{
|
||||
if (ptr->GetInventoryItemCount(redeemableItem.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0) != 0 && !redeemableItem.IsUnlocked() && PassesRedemptionFilters(redeemableItem.Type, redeemableItem.IsUntradable, configuration.General, hasFreeInventorySlot))
|
||||
{
|
||||
list.Add(new Task(redeemableItem));
|
||||
}
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (list.Count > 0)
|
||||
long tickCount = Environment.TickCount64;
|
||||
if (!_scanAt.HasValue)
|
||||
{
|
||||
list.Insert(0, new Mount.UnmountTask());
|
||||
_scanAt = tickCount + 1000;
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
return list;
|
||||
if (tickCount < _scanAt)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
_tasks = CreateTasks(questData, configuration, logger);
|
||||
if (_tasks.Count <= 0)
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
return ETaskResult.CreateNewTasks;
|
||||
}
|
||||
|
||||
public IEnumerable<ITask> CreateExtraTasks()
|
||||
{
|
||||
return _tasks;
|
||||
}
|
||||
|
||||
public override bool ShouldInterruptOnDamage()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +234,36 @@ internal static class RedeemRewardItems
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe static List<ITask> CreateTasks(QuestData questData, Configuration configuration, ILogger logger)
|
||||
{
|
||||
List<ITask> list = new List<ITask>();
|
||||
InventoryManager* ptr = InventoryManager.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
bool flag = InventoryHelper.HasFreeInventorySlot();
|
||||
foreach (ItemReward redeemableItem in questData.RedeemableItems)
|
||||
{
|
||||
if (ptr->GetInventoryItemCount(redeemableItem.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0) != 0 && !redeemableItem.IsUnlocked())
|
||||
{
|
||||
if (!PassesRedemptionFilters(redeemableItem.Type, redeemableItem.IsUntradable, configuration.General, flag))
|
||||
{
|
||||
logger.LogDebug("Skipping quest reward {ItemName}: type={RewardType}, untradable={IsUntradable}, freeInventorySlot={HasFreeInventorySlot}", redeemableItem.Name, redeemableItem.Type, redeemableItem.IsUntradable, flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(new Task(redeemableItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list.Count > 0)
|
||||
{
|
||||
list.Insert(0, new Mount.UnmountTask());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal static bool PassesRedemptionFilters(EItemRewardType type, bool isUntradable, Configuration.GeneralConfiguration general, bool hasFreeInventorySlot)
|
||||
{
|
||||
if (general.DisabledRewardTypes.Contains(type))
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LLib.GameData;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
using Questionable.Controller.Utils;
|
||||
using Questionable.Data;
|
||||
|
|
@ -61,19 +62,19 @@ internal static class WaitAtEnd
|
|||
{
|
||||
break;
|
||||
}
|
||||
goto IL_01bf;
|
||||
goto IL_01ad;
|
||||
case EInteractionType.SinglePlayerDuty:
|
||||
if (bossModIpc.IsConfiguredToRunSoloInstance(quest.Id, step.SinglePlayerDutyOptions))
|
||||
{
|
||||
break;
|
||||
}
|
||||
goto IL_01bf;
|
||||
goto IL_01ad;
|
||||
case EInteractionType.Fish:
|
||||
if (autoHookIpc.IsAvailable())
|
||||
if (!autoHookIpc.IsAvailable())
|
||||
{
|
||||
break;
|
||||
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new EndAutomation());
|
||||
}
|
||||
goto IL_01bf;
|
||||
break;
|
||||
case EInteractionType.WalkTo:
|
||||
case EInteractionType.Jump:
|
||||
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(Next(quest, sequence));
|
||||
|
|
@ -91,13 +92,13 @@ internal static class WaitAtEnd
|
|||
{
|
||||
break;
|
||||
}
|
||||
goto IL_02a6;
|
||||
goto IL_02ca;
|
||||
case EInteractionType.UseItem:
|
||||
if (!step.TargetTerritoryId.HasValue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
goto IL_02a6;
|
||||
goto IL_02ca;
|
||||
case EInteractionType.AcceptQuest:
|
||||
{
|
||||
WaitQuestAccepted waitQuestAccepted = new WaitQuestAccepted(step.PickUpQuestId ?? quest.Id);
|
||||
|
|
@ -128,9 +129,14 @@ internal static class WaitAtEnd
|
|||
}
|
||||
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[2] { waitQuestCompleted, waitDelay2 });
|
||||
}
|
||||
IL_01bf:
|
||||
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new EndAutomation());
|
||||
IL_02a6:
|
||||
IL_01ad:
|
||||
return new global::_003C_003Ez__ReadOnlyArray<ITask>(new ITask[3]
|
||||
{
|
||||
new WaitManualDuty(),
|
||||
new WaitDelay(),
|
||||
Next(quest, sequence)
|
||||
});
|
||||
IL_02ca:
|
||||
if (step.TerritoryId != step.TargetTerritoryId)
|
||||
{
|
||||
task2 = new WaitCondition.Task(() => clientState.TerritoryType == step.TargetTerritoryId, "Wait(tp to territory: " + territoryData.GetNameAndId(step.TargetTerritoryId.Value) + ")");
|
||||
|
|
@ -369,6 +375,58 @@ internal static class WaitAtEnd
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed record WaitManualDuty : IDutyTask, ITask
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "Wait(manual duty)";
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class WaitManualDutyExecutor(IClientState clientState, ICondition condition, TerritoryData territoryData) : TaskExecutor<WaitManualDuty>(), IDebugStateProvider, ITaskExecutor
|
||||
{
|
||||
private bool _enteredDuty;
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
_enteredDuty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override ETaskResult Update()
|
||||
{
|
||||
uint territoryType = clientState.TerritoryType;
|
||||
bool flag = territoryData.IsDutyInstance(territoryType) && !territoryData.IsFieldOperation(territoryType);
|
||||
if (!_enteredDuty)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
_enteredDuty = true;
|
||||
}
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (flag || ConditionHelper.IsBetweenAreas(condition))
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
public override bool ShouldInterruptOnDamage()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string? GetDebugState()
|
||||
{
|
||||
if (!_enteredDuty)
|
||||
{
|
||||
return "Waiting for you to enter the duty";
|
||||
}
|
||||
return "Waiting for the duty to finish";
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record NextStep(ElementId ElementId, int Sequence) : ILastTask, ITask
|
||||
{
|
||||
public override string ToString()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue