muffin v7.5.13
This commit is contained in:
parent
911ed68baa
commit
acf3e3cb18
69 changed files with 2731 additions and 1425 deletions
|
|
@ -56,19 +56,19 @@ internal sealed class BossModModule : ICombatModule, IDisposable
|
|||
if ((uint)(valueOrDefault - 3) <= 1u)
|
||||
{
|
||||
flag = true;
|
||||
goto IL_00bd;
|
||||
goto IL_00be;
|
||||
}
|
||||
}
|
||||
flag = false;
|
||||
goto IL_00bd;
|
||||
goto IL_00be;
|
||||
}
|
||||
goto IL_012e;
|
||||
IL_00bd:
|
||||
goto IL_012f;
|
||||
IL_00be:
|
||||
bool flag2 = flag;
|
||||
_logger.LogDebug("BossModModule.Start: isRanged={IsRanged}, job role={Role}", flag2, localPlayer.ClassJob.ValueNullable?.Role);
|
||||
_bossModIpc.SetRangeStrategy(BossModIpc.EPreset.Active, flag2);
|
||||
goto IL_012e;
|
||||
IL_012e:
|
||||
goto IL_012f;
|
||||
IL_012f:
|
||||
return true;
|
||||
}
|
||||
catch (IpcError exception)
|
||||
|
|
|
|||
|
|
@ -29,12 +29,28 @@ internal sealed class ItemUseModule : ICombatModule
|
|||
|
||||
private long _continueAt;
|
||||
|
||||
private bool _isWaitingToUseItem;
|
||||
|
||||
private bool _itemUsePending;
|
||||
|
||||
private long _itemUsePendingUntil;
|
||||
|
||||
private int _itemCountBeforeUse;
|
||||
|
||||
public ICombatModule? Delegate => _delegate;
|
||||
|
||||
public bool IsItemUseInProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_isWaitingToUseItem || _itemUsePending)
|
||||
{
|
||||
return Environment.TickCount64 < _itemUsePendingUntil;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemUseModule(IServiceProvider serviceProvider, ICondition condition, ILogger<ItemUseModule> logger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
|
|
@ -62,6 +78,7 @@ internal sealed class ItemUseModule : ICombatModule
|
|||
_combatData = combatData;
|
||||
_isDoingRotation = true;
|
||||
_continueAt = Environment.TickCount64;
|
||||
_isWaitingToUseItem = false;
|
||||
_itemUsePending = false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -73,11 +90,13 @@ internal sealed class ItemUseModule : ICombatModule
|
|||
if (_isDoingRotation)
|
||||
{
|
||||
_delegate.Stop();
|
||||
_isDoingRotation = false;
|
||||
_combatData = null;
|
||||
_delegate = null;
|
||||
_continueAt = Environment.TickCount64;
|
||||
}
|
||||
_isDoingRotation = false;
|
||||
_isWaitingToUseItem = false;
|
||||
_itemUsePending = false;
|
||||
_combatData = null;
|
||||
_delegate = null;
|
||||
_continueAt = Environment.TickCount64;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -93,43 +112,78 @@ internal sealed class ItemUseModule : ICombatModule
|
|||
}
|
||||
else if (_combatData.KillEnemyDataIds.Contains(nextTarget.BaseId) || _combatData.ComplexCombatDatas.Any((ComplexCombatData x) => x.DataId == nextTarget.BaseId && (!x.NameId.HasValue || (nextTarget is ICharacter character && x.NameId == character.NameId))))
|
||||
{
|
||||
if (_isDoingRotation)
|
||||
int inventoryItemCount = InventoryManager.Instance()->GetInventoryItemCount(_combatData.CombatItemUse.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0);
|
||||
if (_itemUsePending)
|
||||
{
|
||||
int inventoryItemCount = InventoryManager.Instance()->GetInventoryItemCount(_combatData.CombatItemUse.ItemId, isHq: false, checkEquipped: true, checkArmory: true, 0);
|
||||
if (_itemUsePending)
|
||||
if (inventoryItemCount < _itemCountBeforeUse)
|
||||
{
|
||||
if (Environment.TickCount64 < _itemUsePendingUntil)
|
||||
{
|
||||
_logger.LogDebug("Item use pending; ignoring temporary inventory count={Count}", inventoryItemCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
_itemUsePending = false;
|
||||
}
|
||||
_itemUsePending = false;
|
||||
return;
|
||||
}
|
||||
if (!_itemUsePending && inventoryItemCount == 0)
|
||||
if (_condition[ConditionFlag.Casting])
|
||||
{
|
||||
_itemUsePendingUntil = Environment.TickCount64 + 1000;
|
||||
}
|
||||
if (Environment.TickCount64 < _itemUsePendingUntil)
|
||||
{
|
||||
_logger.LogDebug("Item use pending; inventory count={Count}", inventoryItemCount);
|
||||
return;
|
||||
}
|
||||
_logger.LogDebug("Item use was not observed; retrying");
|
||||
_itemUsePending = false;
|
||||
_isWaitingToUseItem = true;
|
||||
_itemUsePendingUntil = Environment.TickCount64 + 4000;
|
||||
_continueAt = Environment.TickCount64 + 1000;
|
||||
}
|
||||
else if (_isDoingRotation)
|
||||
{
|
||||
if (inventoryItemCount == 0)
|
||||
{
|
||||
_delegate.Update(nextTarget);
|
||||
}
|
||||
else if (ShouldUseItem(nextTarget))
|
||||
{
|
||||
_logger.LogDebug("Attempting to use item {ItemId}", _combatData.CombatItemUse.ItemId);
|
||||
_itemUsePending = true;
|
||||
_itemUsePendingUntil = Environment.TickCount64 + 3000;
|
||||
AgentInventoryContext.Instance()->UseItem(_combatData.CombatItemUse.ItemId, InventoryType.Invalid, 0u, 0);
|
||||
_continueAt = Environment.TickCount64 + 2000;
|
||||
_logger.LogDebug("Pausing rotation before using item {ItemId}", _combatData.CombatItemUse.ItemId);
|
||||
_isDoingRotation = false;
|
||||
_isWaitingToUseItem = true;
|
||||
_delegate.Stop();
|
||||
_continueAt = Environment.TickCount64 + 3000;
|
||||
_itemUsePendingUntil = Environment.TickCount64 + 4000;
|
||||
}
|
||||
else
|
||||
{
|
||||
_delegate.Update(nextTarget);
|
||||
}
|
||||
}
|
||||
else if (_isWaitingToUseItem)
|
||||
{
|
||||
if (_condition[ConditionFlag.Casting])
|
||||
{
|
||||
_continueAt = Environment.TickCount64 + 500;
|
||||
_itemUsePendingUntil = Environment.TickCount64 + 4000;
|
||||
return;
|
||||
}
|
||||
if (!ShouldUseItem(nextTarget) || inventoryItemCount == 0)
|
||||
{
|
||||
_isWaitingToUseItem = false;
|
||||
return;
|
||||
}
|
||||
_logger.LogDebug("Attempting to use item {ItemId}", _combatData.CombatItemUse.ItemId);
|
||||
long num = AgentInventoryContext.Instance()->UseItem(_combatData.CombatItemUse.ItemId, InventoryType.Invalid, 0u, 0);
|
||||
_logger.LogDebug("UseItem result: {Result}", num);
|
||||
bool itemUsePending = (((ulong)num <= 1uL) ? true : false);
|
||||
_itemUsePending = itemUsePending;
|
||||
_isWaitingToUseItem = !_itemUsePending;
|
||||
_itemCountBeforeUse = inventoryItemCount;
|
||||
_itemUsePendingUntil = Environment.TickCount64 + 3000;
|
||||
_continueAt = Environment.TickCount64 + (_itemUsePending ? 2000 : 500);
|
||||
}
|
||||
else if (_condition[ConditionFlag.Casting])
|
||||
{
|
||||
long num = Environment.TickCount64 + 500;
|
||||
if (num > _continueAt)
|
||||
long num2 = Environment.TickCount64 + 500;
|
||||
if (num2 > _continueAt)
|
||||
{
|
||||
_continueAt = num;
|
||||
_continueAt = num2;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ internal static class Dive
|
|||
|
||||
internal sealed class Task : ITask
|
||||
{
|
||||
public bool SmartNavRouted { get; init; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Dive";
|
||||
|
|
@ -51,6 +53,10 @@ internal static class Dive
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (base.Task.SmartNavRouted && !condition[ConditionFlag.Swimming])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (condition[ConditionFlag.Mounted] || condition[ConditionFlag.Swimming])
|
||||
{
|
||||
Descend();
|
||||
|
|
|
|||
|
|
@ -80,14 +80,14 @@ internal static class Duty
|
|||
|
||||
private EDutyMode GetEffectiveEDutyMode(uint cfcId, EDutyMode? registryDutyMode)
|
||||
{
|
||||
if (registryDutyMode.HasValue)
|
||||
{
|
||||
return registryDutyMode.Value;
|
||||
}
|
||||
if (configuration.Duties.DutyModeOverrides.TryGetValue(cfcId, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
if (registryDutyMode.HasValue)
|
||||
{
|
||||
return registryDutyMode.Value;
|
||||
}
|
||||
EDutyMode defaultDutyMode = configuration.Duties.DefaultDutyMode;
|
||||
if (defaultDutyMode == EDutyMode.Support && configuration.Duties.AutoUnsyncOverleveled && IsSafelyOverleveled(cfcId))
|
||||
{
|
||||
|
|
@ -380,7 +380,7 @@ internal static class Duty
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed record EnableBossModForDutyTask : ITask
|
||||
internal sealed record EnableBossModForDutyTask(bool ActivateAi = true) : ITask
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
@ -392,7 +392,7 @@ internal static class Duty
|
|||
{
|
||||
protected override bool Start()
|
||||
{
|
||||
bossModIpc.EnableAi(BossModIpc.EPreset.Active);
|
||||
bossModIpc.EnableAi(BossModIpc.EPreset.Active, base.Task.ActivateAi);
|
||||
IPlayerCharacter localPlayer = objectTable.LocalPlayer;
|
||||
bool flag;
|
||||
if (localPlayer != null)
|
||||
|
|
@ -404,18 +404,18 @@ internal static class Duty
|
|||
if ((uint)(valueOrDefault - 3) <= 1u)
|
||||
{
|
||||
flag = true;
|
||||
goto IL_0077;
|
||||
goto IL_0082;
|
||||
}
|
||||
}
|
||||
flag = false;
|
||||
goto IL_0077;
|
||||
goto IL_0082;
|
||||
}
|
||||
goto IL_0087;
|
||||
IL_0077:
|
||||
goto IL_0092;
|
||||
IL_0082:
|
||||
bool isRanged = flag;
|
||||
bossModIpc.SetRangeStrategy(BossModIpc.EPreset.Active, isRanged);
|
||||
goto IL_0087;
|
||||
IL_0087:
|
||||
goto IL_0092;
|
||||
IL_0092:
|
||||
logger.LogDebug("Enabled BossMod Active preset for AutoDuty run");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -463,7 +463,7 @@ internal static class Duty
|
|||
}
|
||||
}
|
||||
|
||||
internal sealed record EnableBossModPassiveForDutyTask : ITask
|
||||
internal sealed record EnableBossModPassiveForDutyTask(bool ActivateAi = true) : ITask
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
@ -475,7 +475,7 @@ internal static class Duty
|
|||
{
|
||||
protected override bool Start()
|
||||
{
|
||||
bossModIpc.EnableAi(BossModIpc.EPreset.Passive);
|
||||
bossModIpc.EnableAi(BossModIpc.EPreset.Passive, base.Task.ActivateAi);
|
||||
logger.LogDebug("Enabled BossMod Passive preset for AutoDuty run (hazard avoidance)");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ internal static class EquipRecommended
|
|||
|
||||
private bool _checkedOrTriggeredEquipmentUpdate;
|
||||
|
||||
private List<uint>? _gameRecommendedItemIds;
|
||||
|
||||
private long _timeoutAt;
|
||||
|
||||
private List<(int Slot, BestItemRef Item)>? _smartUpgrades;
|
||||
|
|
@ -177,8 +179,7 @@ internal static class EquipRecommended
|
|||
{
|
||||
if (!TryStartMove(pendingMove))
|
||||
{
|
||||
chatGui.Print($"Equip move {_smartMoveCursor + 1}/{smartMoves.Count} rejected; skipping equip step.", "Questionable", 576);
|
||||
return ETaskResult.TaskComplete;
|
||||
throw EquipFailure($"Equip move {_smartMoveCursor + 1}/{smartMoves.Count} was rejected");
|
||||
}
|
||||
_currentMoveStarted = true;
|
||||
_timeoutAt = Environment.TickCount64 + 2000;
|
||||
|
|
@ -196,8 +197,7 @@ internal static class EquipRecommended
|
|||
}
|
||||
if (Environment.TickCount64 >= _timeoutAt)
|
||||
{
|
||||
chatGui.Print($"Equip move {_smartMoveCursor + 1}/{smartMoves.Count} timed out; skipping equip step.", "Questionable", 576);
|
||||
return ETaskResult.TaskComplete;
|
||||
throw EquipFailure($"Equip move {_smartMoveCursor + 1}/{smartMoves.Count} timed out");
|
||||
}
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
|
@ -227,11 +227,11 @@ internal static class EquipRecommended
|
|||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
if (Environment.TickCount64 < _timeoutAt)
|
||||
if (Environment.TickCount64 >= _timeoutAt)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
throw EquipFailure("Recommended gear was not equipped before the timeout");
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
||||
private ETaskResult DirectEquipPhase()
|
||||
|
|
@ -247,20 +247,18 @@ internal static class EquipRecommended
|
|||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
if (Environment.TickCount64 < _timeoutAt)
|
||||
if (Environment.TickCount64 >= _timeoutAt)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
throw EquipFailure("Recommended gear was not equipped before the timeout");
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
var (num, item) = smartUpgrades[_directEquipCursor];
|
||||
if (!_directEquipStarted)
|
||||
{
|
||||
if (!TryStartDirectEquip(item, num))
|
||||
{
|
||||
chatGui.Print($"Direct equip for slot {num} rejected, skipping.", "Questionable", 576);
|
||||
_directEquipCursor++;
|
||||
return ETaskResult.StillRunning;
|
||||
throw EquipFailure($"Direct equip for slot {num} was rejected");
|
||||
}
|
||||
_directEquipStarted = true;
|
||||
_timeoutAt = Environment.TickCount64 + 2000;
|
||||
|
|
@ -274,8 +272,7 @@ internal static class EquipRecommended
|
|||
}
|
||||
if (Environment.TickCount64 >= _timeoutAt)
|
||||
{
|
||||
_directEquipCursor++;
|
||||
_directEquipStarted = false;
|
||||
throw EquipFailure($"Direct equip for slot {num} timed out");
|
||||
}
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
|
@ -366,7 +363,8 @@ internal static class EquipRecommended
|
|||
}
|
||||
if (!_checkedOrTriggeredEquipmentUpdate)
|
||||
{
|
||||
if (IsAllRecommendedGearEquipped())
|
||||
_gameRecommendedItemIds = SnapshotRecommendedItemIds(ptr);
|
||||
if (AreAllItemsEquipped(_gameRecommendedItemIds))
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
|
@ -376,15 +374,15 @@ internal static class EquipRecommended
|
|||
_checkedOrTriggeredEquipmentUpdate = true;
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (IsAllRecommendedGearEquipped())
|
||||
if (_gameRecommendedItemIds != null && AreAllItemsEquipped(_gameRecommendedItemIds))
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
if (Environment.TickCount64 < _timeoutAt)
|
||||
if (Environment.TickCount64 >= _timeoutAt)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
throw EquipFailure("EquipRecommendedGear did not finish before the timeout");
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
||||
private unsafe bool AreUpgradesApplied(IReadOnlyList<(int Slot, BestItemRef Item)> upgrades)
|
||||
|
|
@ -621,19 +619,70 @@ internal static class EquipRecommended
|
|||
return (byte)classJobLevel;
|
||||
}
|
||||
|
||||
private unsafe bool IsAllRecommendedGearEquipped()
|
||||
private unsafe static List<uint> SnapshotRecommendedItemIds(RecommendEquipModule* recommendedEquipModule)
|
||||
{
|
||||
Span<Pointer<InventoryItem>> recommendedItems = RecommendEquipModule.Instance()->RecommendedItems;
|
||||
List<uint> list = new List<uint>();
|
||||
Span<Pointer<InventoryItem>> recommendedItems = recommendedEquipModule->RecommendedItems;
|
||||
for (int i = 0; i < recommendedItems.Length; i++)
|
||||
{
|
||||
Pointer<InventoryItem> pointer = recommendedItems[i];
|
||||
InventoryItem* value = pointer.Value;
|
||||
if (value != null && value->ItemId != 0 && !InventoryHelper.IsItemEquipped(value->ItemId))
|
||||
if (value != null && value->ItemId != 0)
|
||||
{
|
||||
return false;
|
||||
list.Add(((ItemHandle)value->ItemId).Id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return list;
|
||||
}
|
||||
|
||||
private unsafe static bool AreAllItemsEquipped(IReadOnlyList<uint> expectedItemIds)
|
||||
{
|
||||
InventoryManager* ptr = InventoryManager.Instance();
|
||||
if (ptr == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
InventoryContainer* inventoryContainer = ptr->GetInventoryContainer(InventoryType.EquippedItems);
|
||||
if (inventoryContainer == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Dictionary<uint, int> dictionary = new Dictionary<uint, int>();
|
||||
foreach (uint expectedItemId in expectedItemIds)
|
||||
{
|
||||
dictionary[expectedItemId] = dictionary.GetValueOrDefault(expectedItemId) + 1;
|
||||
}
|
||||
for (int i = 0; i < inventoryContainer->Size; i++)
|
||||
{
|
||||
if (dictionary.Count <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
InventoryItem* inventorySlot = inventoryContainer->GetInventorySlot(i);
|
||||
if (inventorySlot == null || inventorySlot->ItemId == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint id = ItemHandle.FromInventorySlot(inventorySlot).Id;
|
||||
if (dictionary.TryGetValue(id, out var value))
|
||||
{
|
||||
if (value == 1)
|
||||
{
|
||||
dictionary.Remove(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionary[id] = value - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dictionary.Count == 0;
|
||||
}
|
||||
|
||||
private TaskException EquipFailure(string message)
|
||||
{
|
||||
chatGui.PrintError(message + "; stopping automation.", "Questionable", 576);
|
||||
return new TaskException(message);
|
||||
}
|
||||
|
||||
public override bool ShouldInterruptOnDamage()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
|
|
@ -16,12 +17,13 @@ using Questionable.Controller.Utils;
|
|||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
using SmartNav.Data;
|
||||
|
||||
namespace Questionable.Controller.Steps.Interactions;
|
||||
|
||||
internal static class Interact
|
||||
{
|
||||
internal sealed class Factory(Configuration configuration) : ITaskFactory
|
||||
internal sealed class Factory(Configuration configuration, WarpDataService warpDataService) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
|
|
@ -63,6 +65,25 @@ internal static class Interact
|
|||
{
|
||||
yield return new WaitAtEnd.WaitDelay();
|
||||
}
|
||||
ushort? targetTerritoryId = step.TargetTerritoryId;
|
||||
List<uint> list;
|
||||
if (targetTerritoryId.HasValue)
|
||||
{
|
||||
ushort targetTerritoryId2 = targetTerritoryId.GetValueOrDefault();
|
||||
list = (from x in warpDataService.Warps
|
||||
where x.NpcDataId == step.DataId && x.SourceTerritoryId == step.TerritoryId && x.DestTerritoryId == targetTerritoryId2
|
||||
select x.RowId).Distinct().Take(2).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
list = new List<uint>();
|
||||
}
|
||||
List<uint> list2 = list;
|
||||
if (list2.Count == 1)
|
||||
{
|
||||
yield return new WarpInteract.Task(step.DataId.Value, list2[0], step.TerritoryId, step.TargetTerritoryId.Value);
|
||||
yield break;
|
||||
}
|
||||
uint value = step.DataId.Value;
|
||||
EInteractionType interactionType2 = step.InteractionType;
|
||||
int skipMarkerCheck;
|
||||
|
|
@ -74,20 +95,17 @@ internal static class Interact
|
|||
SkipStepConditions stepIf = skipConditions.StepIf;
|
||||
if (stepIf != null && stepIf.Never)
|
||||
{
|
||||
goto IL_024a;
|
||||
goto IL_03d7;
|
||||
}
|
||||
}
|
||||
if (step.InteractionType != EInteractionType.PurchaseItem)
|
||||
{
|
||||
skipMarkerCheck = ((step.DataId == 1052475) ? 1 : 0);
|
||||
goto IL_024b;
|
||||
goto IL_03d8;
|
||||
}
|
||||
}
|
||||
goto IL_024a;
|
||||
IL_024a:
|
||||
skipMarkerCheck = 1;
|
||||
goto IL_024b;
|
||||
IL_024b:
|
||||
goto IL_03d7;
|
||||
IL_03d8:
|
||||
uint? pickUpItemId = step.PickUpItemId ?? step.GCPurchase?.ItemId;
|
||||
byte? taxiStandId = step.TaxiStandId;
|
||||
SkipStepConditions? skipConditions2 = step.SkipConditions?.StepIf;
|
||||
|
|
@ -95,6 +113,10 @@ internal static class Interact
|
|||
uint? purchaseItemId = ((step.InteractionType == EInteractionType.PurchaseItem) ? step.ItemId : ((uint?)null));
|
||||
int purchaseItemCount = ((step.InteractionType == EInteractionType.PurchaseItem) ? step.ItemCount.GetValueOrDefault() : 0);
|
||||
yield return new Task(value, quest, interactionType2, (byte)skipMarkerCheck != 0, pickUpItemId, taxiStandId, skipConditions2, completionQuestVariablesFlags, null, purchaseItemId, purchaseItemCount);
|
||||
yield break;
|
||||
IL_03d7:
|
||||
skipMarkerCheck = 1;
|
||||
goto IL_03d8;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ internal static class SinglePlayerDuty
|
|||
public const ushort Naadam = 688;
|
||||
}
|
||||
|
||||
internal sealed class Factory(BossModIpc bossModIpc, WrathComboModule wrathComboModule, RotationSolverRebornModule rsrModule, Configuration configuration, TerritoryData territoryData, QuestFunctions questFunctions, DutyRetryState dutyRetryState, ICondition condition, IClientState clientState, IObjectTable objectTable) : ITaskFactory
|
||||
internal sealed class Factory(BossModIpc bossModIpc, WrathComboModule wrathComboModule, RotationSolverRebornModule rsrModule, Configuration configuration, TerritoryData territoryData, QuestFunctions questFunctions, GameFunctions gameFunctions, DutyRetryState dutyRetryState, ICondition condition, IClientState clientState, IObjectTable objectTable) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
|
|
@ -54,7 +54,12 @@ internal static class SinglePlayerDuty
|
|||
byte seqBefore = questProgressInfo?.Sequence ?? 0;
|
||||
IReadOnlyList<byte> varsBefore = questProgressInfo?.Variables.ToArray();
|
||||
dutyRetryState.Reset();
|
||||
List<ITask> dutyTasks = new List<ITask>();
|
||||
List<ITask> dutyTasks = new List<ITask>
|
||||
{
|
||||
new StartSinglePlayerDuty(contentFinderConditionData.ContentFinderConditionId),
|
||||
new WaitAtStart.WaitDelay(TimeSpan.FromSeconds(10L)),
|
||||
new WaitCondition.Task(() => !gameFunctions.IsOccupied(), "Wait(solo duty ready)")
|
||||
};
|
||||
if (wrathComboModule.IsAvailable())
|
||||
{
|
||||
dutyTasks.Add(new Duty.EnableWrathForDutyTask());
|
||||
|
|
@ -65,14 +70,12 @@ internal static class SinglePlayerDuty
|
|||
}
|
||||
if (configuration.General.CombatModule == Configuration.ECombatModule.BossMod && bossModIpc.IsSupported())
|
||||
{
|
||||
dutyTasks.Add(new Duty.EnableBossModForDutyTask());
|
||||
dutyTasks.Add(new Duty.EnableBossModForDutyTask(configuration.SinglePlayerDuties.EnableBossModAi));
|
||||
}
|
||||
else if (bossModIpc.IsSupported())
|
||||
{
|
||||
dutyTasks.Add(new Duty.EnableBossModPassiveForDutyTask());
|
||||
dutyTasks.Add(new Duty.EnableBossModPassiveForDutyTask(configuration.SinglePlayerDuties.EnableBossModAi));
|
||||
}
|
||||
dutyTasks.Add(new StartSinglePlayerDuty(contentFinderConditionData.ContentFinderConditionId));
|
||||
dutyTasks.Add(new WaitAtStart.WaitDelay(TimeSpan.FromSeconds(2L)));
|
||||
dutyTasks.Add(new EnableAi());
|
||||
if (contentFinderConditionData.TerritoryId == 1052)
|
||||
{
|
||||
|
|
@ -132,8 +135,6 @@ internal static class SinglePlayerDuty
|
|||
|
||||
internal sealed class StartSinglePlayerDutyExecutor(ICondition condition) : TaskExecutor<StartSinglePlayerDuty>()
|
||||
{
|
||||
private long _enteredAtMs;
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
return true;
|
||||
|
|
@ -149,14 +150,6 @@ internal static class SinglePlayerDuty
|
|||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (_enteredAtMs == 0L)
|
||||
{
|
||||
_enteredAtMs = Environment.TickCount64;
|
||||
}
|
||||
if (Environment.TickCount64 - _enteredAtMs < 2000)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,10 +130,10 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
};
|
||||
}
|
||||
}
|
||||
float num2 = base.Task.StopDistance ?? 3f;
|
||||
float stopDistance = base.Task.StopDistance ?? 3f;
|
||||
Vector3? vector = _objectTable.LocalPlayer?.Position;
|
||||
float num3 = ((!vector.HasValue) ? float.MaxValue : Vector3.Distance(vector.Value, _destination));
|
||||
if (num3 > num2)
|
||||
float num2 = ((!vector.HasValue) ? float.MaxValue : Vector3.Distance(vector.Value, _destination));
|
||||
if (!vector.HasValue || !IsWithinInteractionRange(vector.Value, _destination, stopDistance, GetVerticalStopDistance()))
|
||||
{
|
||||
PrepareMovementIfNeeded();
|
||||
}
|
||||
|
|
@ -176,7 +176,7 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
else if (!base.Task.DisableNavmesh)
|
||||
{
|
||||
bool flag = _gameFunctions.IsFlyingUnlocked(base.Task.TerritoryId);
|
||||
if (!base.Task.SmartNavRouted && !base.Task.Fly && flag && num3 > _configuration.Navigation.MountFlyDistance)
|
||||
if (!base.Task.SmartNavRouted && !base.Task.Fly && flag && num2 > _configuration.Navigation.MountFlyDistance)
|
||||
{
|
||||
base.Task = base.Task with
|
||||
{
|
||||
|
|
@ -184,8 +184,8 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
Land = true
|
||||
};
|
||||
}
|
||||
float num4 = (base.Task.Fly ? _configuration.Navigation.MountFlyDistance : _configuration.Navigation.MountGroundDistance);
|
||||
Questionable.Controller.Steps.Common.Mount.EMountIf mountIf = ((!(num3 > num4)) ? Questionable.Controller.Steps.Common.Mount.EMountIf.AwayFromPosition : Questionable.Controller.Steps.Common.Mount.EMountIf.Always);
|
||||
float num3 = (base.Task.Fly ? _configuration.Navigation.MountFlyDistance : _configuration.Navigation.MountGroundDistance);
|
||||
Questionable.Controller.Steps.Common.Mount.EMountIf mountIf = ((!(num2 > num3)) ? Questionable.Controller.Steps.Common.Mount.EMountIf.AwayFromPosition : Questionable.Controller.Steps.Common.Mount.EMountIf.Always);
|
||||
Questionable.Controller.Steps.Common.Mount.MountTask mountTask3 = new Questionable.Controller.Steps.Common.Mount.MountTask(base.Task.TerritoryId, mountIf, _destination);
|
||||
long retryAtMs = 0L;
|
||||
(Questionable.Controller.Steps.Common.Mount.MountExecutor, Questionable.Controller.Steps.Common.Mount.MountTask)? tuple;
|
||||
|
|
@ -244,7 +244,7 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
}
|
||||
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
||||
float num = base.Task.StopDistance ?? 3f;
|
||||
if (base.Task.Fly && base.Task.Land && _canRestart && localPlayer != null && _clientState.TerritoryType == base.Task.TerritoryId && Vector3.Distance(localPlayer.Position, _destination) > num)
|
||||
if (base.Task.Fly && base.Task.Land && _canRestart && localPlayer != null && _clientState.TerritoryType == base.Task.TerritoryId && (_condition[ConditionFlag.InFlight] || Vector3.Distance(localPlayer.Position, _destination) > num))
|
||||
{
|
||||
if (_condition[ConditionFlag.InFlight])
|
||||
{
|
||||
|
|
@ -255,20 +255,25 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
}
|
||||
if (!_movementController.IsNavmeshReady)
|
||||
{
|
||||
_logger.LogDebug("Airborne outside stop distance, waiting for navmesh to descend");
|
||||
_logger.LogDebug("Still airborne after fly-and-land movement, waiting for navmesh to descend");
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
Vector3 position = localPlayer.Position;
|
||||
position.Y = localPlayer.Position.Y - 100f;
|
||||
Vector3 vector = position;
|
||||
Vector3 destination = _destination;
|
||||
destination.Y = localPlayer.Position.Y;
|
||||
Vector3 vector = destination;
|
||||
destination = _destination;
|
||||
destination.Y = _destination.Y - 100f;
|
||||
Vector3 vector2 = destination;
|
||||
_descendAttempted = true;
|
||||
_logger.LogDebug("Outside stop distance but still airborne, descending to {Target}", vector.ToString("G", CultureInfo.InvariantCulture));
|
||||
_logger.LogDebug("Still airborne, moving above {LandingTarget} and descending to {DescendTarget}", _destination.ToString("G", CultureInfo.InvariantCulture), vector2.ToString("G", CultureInfo.InvariantCulture));
|
||||
MovementController movementController = _movementController;
|
||||
uint? dataId = base.Task.DataId;
|
||||
int num2 = 1;
|
||||
int num2 = 2;
|
||||
List<Vector3> list = new List<Vector3>(num2);
|
||||
CollectionsMarshal.SetCount(list, num2);
|
||||
CollectionsMarshal.AsSpan(list)[0] = vector;
|
||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
||||
span[0] = vector;
|
||||
span[1] = vector2;
|
||||
movementController.NavigateTo(EMovementType.Landing, dataId, list, fly: true, sprint: false, null);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
|
@ -276,22 +281,29 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
_logger.LogDebug("Landed outside stop distance, closing gap on foot");
|
||||
MovementController movementController2 = _movementController;
|
||||
uint? dataId2 = base.Task.DataId;
|
||||
Vector3 destination = _destination;
|
||||
Vector3 destination2 = _destination;
|
||||
float? stopDistance = base.Task.StopDistance;
|
||||
bool smartNavRouted = base.Task.SmartNavRouted;
|
||||
movementController2.NavigateTo(EMovementType.Quest, dataId2, destination, fly: false, sprint: false, stopDistance, null, land: false, smartNavRouted);
|
||||
movementController2.NavigateTo(EMovementType.Quest, dataId2, destination2, fly: false, sprint: false, stopDistance, null, land: false, smartNavRouted);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (base.Task.DataId.HasValue && !_adjustedToObject && localPlayer != null && !_condition[ConditionFlag.InFlight] && _clientState.TerritoryType == base.Task.TerritoryId)
|
||||
if (base.Task.DataId.HasValue && localPlayer != null && !_condition[ConditionFlag.InFlight] && _clientState.TerritoryType == base.Task.TerritoryId)
|
||||
{
|
||||
IGameObject gameObject = _gameFunctions.FindObjectByDataId(base.Task.DataId.Value, null, warnIfMissing: false);
|
||||
if (gameObject != null)
|
||||
{
|
||||
float num3 = Vector3.Distance(localPlayer.Position, gameObject.Position);
|
||||
if (num3 > num)
|
||||
float num4 = Math.Abs(localPlayer.Position.Y - gameObject.Position.Y);
|
||||
if (!IsWithinInteractionRange(localPlayer.Position, gameObject.Position, num, GetVerticalStopDistance()))
|
||||
{
|
||||
if (_adjustedToObject)
|
||||
{
|
||||
_logger.LogWarning("Movement to actual object position ended out of interaction range ({Distance:F1}y away, vertical difference {VerticalDistance:F1}y), treating as unreachable", num3, num4);
|
||||
throw new MovementController.PathfindingFailedException($"Movement to object ended {num3:F1}y away with a {num4:F1}y vertical difference");
|
||||
}
|
||||
_adjustedToObject = true;
|
||||
_logger.LogDebug("Adjusting to actual object position ({Distance:F1}y away)", num3);
|
||||
_canRestart = false;
|
||||
_logger.LogDebug("Adjusting to actual object position ({Distance:F1}y away, vertical difference {VerticalDistance:F1}y)", num3, num4);
|
||||
_movementController.NavigateTo(EMovementType.Quest, base.Task.DataId, gameObject.Position, fly: false, sprint: false, base.Task.StopDistance);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
|
@ -316,13 +328,31 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
|||
}
|
||||
if (base.Task.SmartNavRouted && !_adjustedToObject && localPlayer != null && _clientState.TerritoryType == base.Task.TerritoryId && Vector3.Distance(localPlayer.Position, _destination) > num + 5f)
|
||||
{
|
||||
float num4 = Vector3.Distance(localPlayer.Position, _destination);
|
||||
_logger.LogWarning("SmartNav movement ended {Distance:F1}y from target (stop distance {StopDistance:F1}y), treating as unreachable", num4, num);
|
||||
throw new MovementController.PathfindingFailedException($"SmartNav movement ended {num4:F1}y from target (stop distance {num:F1}y)");
|
||||
float num5 = Vector3.Distance(localPlayer.Position, _destination);
|
||||
_logger.LogWarning("SmartNav movement ended {Distance:F1}y from target (stop distance {StopDistance:F1}y), treating as unreachable", num5, num);
|
||||
throw new MovementController.PathfindingFailedException($"SmartNav movement ended {num5:F1}y from target (stop distance {num:F1}y)");
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
private float GetVerticalStopDistance()
|
||||
{
|
||||
if (!base.Task.IgnoreDistanceToObject)
|
||||
{
|
||||
return 1.95f;
|
||||
}
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
internal static bool IsWithinInteractionRange(Vector3 playerPosition, Vector3 targetPosition, float stopDistance, float verticalStopDistance)
|
||||
{
|
||||
if (Vector3.Distance(playerPosition, targetPosition) <= stopDistance)
|
||||
{
|
||||
return Math.Abs(playerPosition.Y - targetPosition.Y) <= verticalStopDistance;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ETaskResult? UpdateMountState()
|
||||
{
|
||||
(Questionable.Controller.Steps.Common.Mount.MountExecutor, Questionable.Controller.Steps.Common.Mount.MountTask)? mountBeforeMovement = _mountBeforeMovement;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,64 @@ namespace Questionable.Controller.Steps.Movement;
|
|||
internal sealed record MoveTask(ushort TerritoryId, Vector3 Destination, bool? Mount = null, bool MountRequired = false, bool DismountRequired = false, float? StopDistance = null, uint? DataId = null, bool DisableNavmesh = false, bool? Sprint = null, bool Fly = false, bool Land = false, bool IgnoreDistanceToObject = false, bool RestartNavigation = true, EInteractionType InteractionType = EInteractionType.None, bool SmartNavRouted = false, bool AllowZoneTransition = false, string? RouteTargetNodeId = null, string? RouteApproachNodeId = null) : ITask
|
||||
{
|
||||
public MoveTask(QuestStep step, Vector3 destination)
|
||||
: this(step.TerritoryId, destination, step.Mount, step.MountRequired, step.DismountRequired, step.CalculateActualStopDistance(), step.DataId, step.DisableNavmesh, step.Sprint, step.Fly == true, step.Land == true, step.IgnoreDistanceToObject == true, step.RestartNavigationIfCancelled != false, step.InteractionType)
|
||||
: this(step.TerritoryId, destination, ResolveMount(step), step.MountRequired, step.DismountRequired, step.CalculateActualStopDistance(), step.DataId, step.DisableNavmesh, step.Sprint, ResolveFly(step), ResolveLand(step), step.IgnoreDistanceToObject == true, step.RestartNavigationIfCancelled != false, step.InteractionType)
|
||||
{
|
||||
}
|
||||
|
||||
private static bool? ResolveMount(QuestStep step)
|
||||
{
|
||||
if (step.MountRequired)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (step.DismountRequired)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
switch (step.TravelMode)
|
||||
{
|
||||
case ETravelMode.OnFoot:
|
||||
return false;
|
||||
case ETravelMode.GroundMount:
|
||||
case ETravelMode.Flying:
|
||||
return true;
|
||||
default:
|
||||
return step.Mount;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ResolveFly(QuestStep step)
|
||||
{
|
||||
if (step.DismountRequired)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
switch (step.TravelMode)
|
||||
{
|
||||
case ETravelMode.OnFoot:
|
||||
case ETravelMode.GroundMount:
|
||||
return false;
|
||||
case ETravelMode.Flying:
|
||||
return true;
|
||||
default:
|
||||
return step.Fly == true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ResolveLand(QuestStep step)
|
||||
{
|
||||
ETravelMode travelMode = step.TravelMode;
|
||||
bool flag = (uint)(travelMode - 1) <= 1u;
|
||||
bool flag2 = !flag;
|
||||
if (flag2)
|
||||
{
|
||||
EArrivalMode arrivalMode = step.ArrivalMode;
|
||||
bool flag3 = (uint)(arrivalMode - 2) <= 1u;
|
||||
flag2 = flag3 || step.Land == true;
|
||||
}
|
||||
return flag2;
|
||||
}
|
||||
|
||||
public bool ShouldRedoOnInterrupt()
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,14 @@ internal static class MoveTo
|
|||
yield return new LandTask();
|
||||
}
|
||||
}
|
||||
if (step.ArrivalMode == EArrivalMode.StayMounted && !step.DismountRequired)
|
||||
{
|
||||
yield return new Mount.MountTask(step.TerritoryId, Mount.EMountIf.Always);
|
||||
}
|
||||
else if (step.ArrivalMode == EArrivalMode.Dismount && !step.MountRequired)
|
||||
{
|
||||
yield return new Mount.UnmountTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ internal static class SmartNavStep
|
|||
{
|
||||
yield break;
|
||||
}
|
||||
(bool AllowMount, bool AllowFlight) capabilities = SmartNavReRouteService.GetCapabilities(step.TravelMode);
|
||||
bool item = capabilities.AllowMount;
|
||||
bool item2 = capabilities.AllowFlight;
|
||||
playerNavState = playerNavState.WithTravelCapabilities(item, item2);
|
||||
RouteResult routeResult = navRouter.FindRoute(playerNavState, step.TerritoryId, vector.Value);
|
||||
if (routeResult.Segments.Count == 0)
|
||||
{
|
||||
|
|
@ -37,10 +41,10 @@ internal static class SmartNavStep
|
|||
}
|
||||
HandledRouting = true;
|
||||
logger.LogDebug("SmartNav routing to {Territory} with {Count} segments", territoryData.GetNameAndId(step.TerritoryId), routeResult.Segments.Count);
|
||||
reRouteService.SetDestination(step.TerritoryId, vector.Value);
|
||||
foreach (ITask item in taskMapper.MapInstructions(instructionBuilder.Build(routeResult, step.TerritoryId, step.DisableNavmesh), step))
|
||||
reRouteService.SetDestination(step.TerritoryId, vector.Value, step.TravelMode);
|
||||
foreach (ITask item3 in taskMapper.MapInstructions(instructionBuilder.Build(routeResult, step.TerritoryId, step.DisableNavmesh), step, step.TravelMode))
|
||||
{
|
||||
yield return item;
|
||||
yield return item3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -261,6 +261,10 @@ internal sealed class CombatController : IDisposable
|
|||
SetTarget(gameObject3);
|
||||
}
|
||||
}
|
||||
if (_currentFight.Module is ItemUseModule { IsItemUseInProgress: not false })
|
||||
{
|
||||
return EStatus.InCombat;
|
||||
}
|
||||
if (_condition[ConditionFlag.InCombat])
|
||||
{
|
||||
_wasInCombat = true;
|
||||
|
|
@ -362,43 +366,39 @@ internal sealed class CombatController : IDisposable
|
|||
int num = 0;
|
||||
float num2 = float.MaxValue;
|
||||
bool flag5 = _logger.IsEnabled(LogLevel.Debug);
|
||||
foreach (IGameObject item in _objectTable)
|
||||
foreach (IGameObject item2 in _objectTable)
|
||||
{
|
||||
var (num3, text) = GetKillPriority(item, localPlayer);
|
||||
if (num3 <= 0)
|
||||
int item = GetKillPriority(item2, localPlayer).Priority;
|
||||
if (item <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (_losIgnoreList.TryGetValue(item.GameObjectId, out var value2))
|
||||
if (_losIgnoreList.TryGetValue(item2.GameObjectId, out var value2))
|
||||
{
|
||||
if (Environment.TickCount64 < value2)
|
||||
{
|
||||
if (flag5)
|
||||
{
|
||||
_logger.LogDebug("Target {Name} ({Id:X8}) skipped - LoS ignore list ({Remaining}ms left)", item.Name, item.GameObjectId, value2 - Environment.TickCount64);
|
||||
_logger.LogDebug("Target {Name} ({Id:X8}) skipped - LoS ignore list ({Remaining}ms left)", item2.Name, item2.GameObjectId, value2 - Environment.TickCount64);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_losIgnoreList.Remove(item.GameObjectId);
|
||||
_losIgnoreList.Remove(item2.GameObjectId);
|
||||
if (flag5)
|
||||
{
|
||||
_logger.LogDebug("Target {Name} ({Id:X8}) - LoS ignore expired", item.Name, item.GameObjectId);
|
||||
_logger.LogDebug("Target {Name} ({Id:X8}) - LoS ignore expired", item2.Name, item2.GameObjectId);
|
||||
}
|
||||
}
|
||||
float num4 = Vector3.Distance(item.Position, value);
|
||||
if (flag5)
|
||||
float num3 = Vector3.Distance(item2.Position, value);
|
||||
if (item > num || (item == num && num3 < num2))
|
||||
{
|
||||
_logger.LogDebug("Target candidate: {Name} ({Id:X8}) BaseId={BaseId} Priority={Priority} ({Reason}) Distance={Distance:N1}", item.Name, item.GameObjectId, item.BaseId, num3, text, num4);
|
||||
}
|
||||
if (num3 > num || (num3 == num && num4 < num2))
|
||||
{
|
||||
gameObject = item;
|
||||
num = num3;
|
||||
num2 = num4;
|
||||
gameObject = item2;
|
||||
num = item;
|
||||
num2 = num3;
|
||||
}
|
||||
}
|
||||
ulong? num5 = gameObject?.GameObjectId;
|
||||
if (num5 != _lastTargetId)
|
||||
ulong? num4 = gameObject?.GameObjectId;
|
||||
if (num4 != _lastTargetId)
|
||||
{
|
||||
if (gameObject != null)
|
||||
{
|
||||
|
|
@ -408,7 +408,7 @@ internal sealed class CombatController : IDisposable
|
|||
{
|
||||
_logger.LogDebug("No valid target found");
|
||||
}
|
||||
_lastTargetId = num5;
|
||||
_lastTargetId = num4;
|
||||
}
|
||||
if (gameObject != null && num <= 15 && !_condition[ConditionFlag.InCombat])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ internal sealed class MovementController : IDisposable
|
|||
}
|
||||
else if ((vector4 - Destination.Position).Length() < Destination.StopDistance)
|
||||
{
|
||||
if (vector4.Y - Destination.Position.Y <= Destination.VerticalStopDistance)
|
||||
if (Math.Abs(vector4.Y - Destination.Position.Y) <= Destination.VerticalStopDistance)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1538,6 +1538,10 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (_startedQuest != null && QuestFunctions.IsStartingCityOpeningQuest(_startedQuest.Quest.Id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ElementId elementId = (from x in _questFunctions.GetNextPriorityQuestsThatCanBeAccepted()
|
||||
where x.IsAvailable
|
||||
select x.QuestId).FirstOrDefault();
|
||||
|
|
|
|||
|
|
@ -103,15 +103,10 @@ internal sealed class QuestPriorityResolver
|
|||
QuestResolution valueOrDefault2 = questResolution.GetValueOrDefault();
|
||||
return ApplyQuestRedirects(valueOrDefault2);
|
||||
}
|
||||
uint territoryType = _clientState.TerritoryType;
|
||||
bool flag2 = territoryType - 181 <= 2;
|
||||
if (flag2 && flag && _configuration.General.MsqPriority != Configuration.EMsqPriorityMode.Manual)
|
||||
QuestId activeStartingCityOpeningQuest = _questFunctions.GetActiveStartingCityOpeningQuest();
|
||||
if ((object)activeStartingCityOpeningQuest != null && (_questFunctions.IsQuestAccepted(activeStartingCityOpeningQuest) || (flag && _configuration.General.MsqPriority != Configuration.EMsqPriorityMode.Manual)))
|
||||
{
|
||||
ElementId currentQuest = resolvedMsqQuest.CurrentQuest;
|
||||
if ((object)currentQuest != null && currentQuest.Value > 0 && !_questFunctions.IsQuestAccepted(currentQuest))
|
||||
{
|
||||
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, currentQuest, resolvedMsqQuest.Sequence, resolvedMsqQuest.State, $"Starting city opening MSQ {currentQuest}");
|
||||
}
|
||||
return QuestResolution.ForQuest(EQuestResolutionType.MsqImmediate, activeStartingCityOpeningQuest, _questFunctions.GetStartingCityOpeningSequence(activeStartingCityOpeningQuest), resolvedMsqQuest.State, $"Starting city opening MSQ {activeStartingCityOpeningQuest}");
|
||||
}
|
||||
questResolution = TryResolveInProgressClassQuest(valueOrDefault, resolvedMsqQuest.State);
|
||||
if (questResolution.HasValue)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -391,7 +391,7 @@ internal sealed class BossModIpc : IDisposable
|
|||
AddTransientStrategy(preset, "BossMod.Autorotation.MiscAI.StayCloseToTarget", "Range", isRanged ? "15" : "3");
|
||||
}
|
||||
|
||||
public bool EnableAi(EPreset preset)
|
||||
public bool EnableAi(EPreset preset, bool activateAi = true)
|
||||
{
|
||||
if (!CreateShellPreset(preset))
|
||||
{
|
||||
|
|
@ -411,6 +411,10 @@ internal sealed class BossModIpc : IDisposable
|
|||
_logger.LogWarning("Unable to set BossMod preset {Preset}: {Message}", preset, ipcError.Message);
|
||||
return false;
|
||||
}
|
||||
if (!activateAi)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
string aiCommand = GetAiCommand();
|
||||
if (aiCommand != null)
|
||||
{
|
||||
|
|
@ -424,7 +428,7 @@ internal sealed class BossModIpc : IDisposable
|
|||
|
||||
public void EnableQuestBattleAi()
|
||||
{
|
||||
EnableAi(EPreset.Active);
|
||||
EnableAi(EPreset.Active, _configuration.SinglePlayerDuties.EnableBossModAi);
|
||||
ConfigureSoloDutyZone();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,22 @@ namespace Questionable.Functions;
|
|||
|
||||
internal sealed class QuestFunctions
|
||||
{
|
||||
private static readonly Dictionary<byte, QuestId> ComingToStartingCityQuests = new Dictionary<byte, QuestId>
|
||||
{
|
||||
{
|
||||
1,
|
||||
new QuestId(107)
|
||||
},
|
||||
{
|
||||
2,
|
||||
new QuestId(39)
|
||||
},
|
||||
{
|
||||
3,
|
||||
new QuestId(594)
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly Dictionary<ushort, EClassJob> CloseToHomeQuests = new Dictionary<ushort, EClassJob>
|
||||
{
|
||||
{
|
||||
|
|
@ -95,6 +111,56 @@ internal sealed class QuestFunctions
|
|||
|
||||
private static readonly HashSet<ushort> RemovedQuestIds = new HashSet<ushort> { 487, 1428, 1429 };
|
||||
|
||||
public static bool IsStartingCityOpeningQuest(ElementId elementId)
|
||||
{
|
||||
if (elementId is QuestId questId)
|
||||
{
|
||||
if (!ComingToStartingCityQuests.ContainsValue(questId))
|
||||
{
|
||||
return CloseToHomeQuests.ContainsKey(questId.Value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public QuestId? GetActiveStartingCityOpeningQuest()
|
||||
{
|
||||
QuestId questId = ComingToStartingCityQuests.Values.Concat(CloseToHomeQuests.Keys.Select((ushort x) => new QuestId(x))).Where(IsQuestAccepted).Cast<QuestId>()
|
||||
.FirstOrDefault();
|
||||
if (questId != null)
|
||||
{
|
||||
return questId;
|
||||
}
|
||||
EClassJob startingClass = ((EClassJob?)_objectTable.LocalPlayer?.ClassJob.RowId).GetValueOrDefault();
|
||||
ushort num = (from x in CloseToHomeQuests
|
||||
where x.Value == startingClass
|
||||
select x.Key).FirstOrDefault();
|
||||
if (num != 0)
|
||||
{
|
||||
QuestId questId2 = new QuestId(num);
|
||||
if (IsReadyToAcceptQuest(questId2, ignoreLevel: true))
|
||||
{
|
||||
return questId2;
|
||||
}
|
||||
}
|
||||
if (ComingToStartingCityQuests.TryGetValue(PlayerStateHelper.GetStartTown(), out QuestId value) && IsReadyToAcceptQuest(value, ignoreLevel: true))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte GetStartingCityOpeningSequence(QuestId questId)
|
||||
{
|
||||
byte questSequence = QuestManager.GetQuestSequence(questId.Value);
|
||||
if (ComingToStartingCityQuests.ContainsValue(questId) && IsQuestAccepted(questId) && questSequence == 0)
|
||||
{
|
||||
return byte.MaxValue;
|
||||
}
|
||||
return questSequence;
|
||||
}
|
||||
|
||||
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, JournalData journalData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, Configuration configuration, IDataManager dataManager, IObjectTable objectTable, IGameGui gameGui, ILogger<QuestFunctions> logger)
|
||||
{
|
||||
_questRegistry = questRegistry;
|
||||
|
|
|
|||
|
|
@ -5,21 +5,28 @@ using Microsoft.Extensions.Logging;
|
|||
using Questionable.Controller.CustomDelivery;
|
||||
using Questionable.Controller.Steps;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
using Questionable.Controller.Steps.Movement;
|
||||
using Questionable.Controller.Steps.Shared;
|
||||
using Questionable.Model.Questing;
|
||||
using SmartNav;
|
||||
|
||||
namespace Questionable.Navigation;
|
||||
|
||||
internal sealed class SmartNavReRouteService(ReRoutePolicy reRoutePolicy, SmartNavTaskMapper taskMapper, Configuration configuration, ILogger<SmartNavReRouteService> logger)
|
||||
{
|
||||
public void SetDestination(uint territoryId, Vector3 position)
|
||||
private ETravelMode _travelMode;
|
||||
|
||||
public void SetDestination(uint territoryId, Vector3 position, ETravelMode travelMode = ETravelMode.Auto)
|
||||
{
|
||||
reRoutePolicy.SetDestination(territoryId, position);
|
||||
_travelMode = travelMode;
|
||||
var (allowMount, allowFlight) = GetCapabilities(travelMode);
|
||||
reRoutePolicy.SetDestination(territoryId, position, allowMount, allowFlight);
|
||||
}
|
||||
|
||||
public void ClearDestination()
|
||||
{
|
||||
_travelMode = ETravelMode.Auto;
|
||||
reRoutePolicy.ClearDestination();
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +58,7 @@ internal sealed class SmartNavReRouteService(ReRoutePolicy reRoutePolicy, SmartN
|
|||
if (reRouteDecision is ReRouteDecision.Replan replan)
|
||||
{
|
||||
taskQueue.Reset();
|
||||
foreach (ITask item2 in taskMapper.MapInstructions(replan.Instructions))
|
||||
foreach (ITask item2 in taskMapper.MapInstructions(replan.Instructions, null, _travelMode))
|
||||
{
|
||||
taskQueue.Enqueue(item2);
|
||||
}
|
||||
|
|
@ -79,10 +86,33 @@ internal sealed class SmartNavReRouteService(ReRoutePolicy reRoutePolicy, SmartN
|
|||
|
||||
private static bool IsMovementTask(ITask task)
|
||||
{
|
||||
if (task is MoveTask || task is LandTask || task is Mount.MountTask || task is AetheryteTeleport.Task || task is AethernetRide.Task || task is WaitNavmesh.Task || task is WaitCondition.Task || task is WarpInteract.Task || task is TaxiInteract.Task || task is SubRegionTransport.Task || task is TicketTeleport.Task)
|
||||
if (!(task is MoveTask))
|
||||
{
|
||||
return true;
|
||||
if (task is Dive.Task task2)
|
||||
{
|
||||
if (task2.SmartNavRouted)
|
||||
{
|
||||
goto IL_006c;
|
||||
}
|
||||
}
|
||||
else if (task is LandTask || task is Mount.MountTask || task is AetheryteTeleport.Task || task is AethernetRide.Task || task is WaitNavmesh.Task || task is WaitCondition.Task || task is WarpInteract.Task || task is TaxiInteract.Task || task is SubRegionTransport.Task || task is TicketTeleport.Task)
|
||||
{
|
||||
goto IL_006c;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
goto IL_006c;
|
||||
IL_006c:
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static (bool AllowMount, bool AllowFlight) GetCapabilities(ETravelMode travelMode)
|
||||
{
|
||||
return travelMode switch
|
||||
{
|
||||
ETravelMode.OnFoot => (AllowMount: false, AllowFlight: false),
|
||||
ETravelMode.GroundMount => (AllowMount: true, AllowFlight: false),
|
||||
_ => (AllowMount: true, AllowFlight: true),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,27 @@ internal sealed class SmartNavRouteEnqueuer(NavRouter navRouter, PlayerNavStateB
|
|||
{
|
||||
return false;
|
||||
}
|
||||
List<NavInstruction> list = instructionBuilder.Build(routeResult, territoryId).TakeWhile((NavInstruction x) => !(x is NavInstruction.Move move) || !move.IsFinal).ToList();
|
||||
List<NavInstruction> list = instructionBuilder.Build(routeResult, territoryId).TakeWhile(delegate(NavInstruction x)
|
||||
{
|
||||
if (x is NavInstruction.Move move)
|
||||
{
|
||||
if (move.IsFinal)
|
||||
{
|
||||
goto IL_0026;
|
||||
}
|
||||
}
|
||||
else if (x is NavInstruction.Swim { IsFinal: not false })
|
||||
{
|
||||
goto IL_0026;
|
||||
}
|
||||
bool flag = false;
|
||||
goto IL_002c;
|
||||
IL_0026:
|
||||
flag = true;
|
||||
goto IL_002c;
|
||||
IL_002c:
|
||||
return !flag;
|
||||
}).ToList();
|
||||
if (list.Count == 0)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -120,6 +140,18 @@ internal sealed class SmartNavRouteEnqueuer(NavRouter navRouter, PlayerNavStateB
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (instruction is NavInstruction.Swim)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (instruction is NavInstruction.DiveEntry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (instruction is NavInstruction.Surface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (instruction is NavInstruction.AethernetHop)
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Numerics;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Questionable.Controller.Steps;
|
||||
using Questionable.Controller.Steps.Common;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
using Questionable.Controller.Steps.Movement;
|
||||
using Questionable.Controller.Steps.Shared;
|
||||
using Questionable.Data;
|
||||
|
|
@ -15,13 +16,22 @@ namespace Questionable.Navigation;
|
|||
|
||||
internal sealed class SmartNavTaskMapper(IClientState clientState, TerritoryData territoryData)
|
||||
{
|
||||
public IEnumerable<ITask> MapInstructions(IReadOnlyList<NavInstruction> instructions, QuestStep? step = null)
|
||||
private const float SurfaceExitRise = 3f;
|
||||
|
||||
public IEnumerable<ITask> MapInstructions(IReadOnlyList<NavInstruction> instructions, QuestStep? step = null, ETravelMode travelMode = ETravelMode.Auto)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
{
|
||||
foreach (ITask item in Map(instructions[i], NextTravelInstruction(instructions, i), step))
|
||||
{
|
||||
yield return item;
|
||||
if (item is MoveTask task && !(instructions[i] is NavInstruction.Swim))
|
||||
{
|
||||
yield return ApplyTravelMode(task, travelMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,66 +58,131 @@ internal sealed class SmartNavTaskMapper(IClientState clientState, TerritoryData
|
|||
{
|
||||
if (!(instruction is NavInstruction.Move move))
|
||||
{
|
||||
if (!(instruction is NavInstruction.Land))
|
||||
if (!(instruction is NavInstruction.Swim swim))
|
||||
{
|
||||
if (!(instruction is NavInstruction.Unmount))
|
||||
if (!(instruction is NavInstruction.DiveEntry dive))
|
||||
{
|
||||
NavInstruction.WaitForTerritory waitForTerritory = instruction as NavInstruction.WaitForTerritory;
|
||||
if ((object)waitForTerritory == null)
|
||||
if (!(instruction is NavInstruction.Surface surface))
|
||||
{
|
||||
if (!(instruction is NavInstruction.WaitForNavmesh))
|
||||
if (!(instruction is NavInstruction.Land))
|
||||
{
|
||||
if (!(instruction is NavInstruction.InteractWarp interactWarp))
|
||||
if (!(instruction is NavInstruction.Unmount))
|
||||
{
|
||||
if (!(instruction is NavInstruction.UseTeleportTicket useTeleportTicket))
|
||||
NavInstruction.WaitForTerritory waitForTerritory = instruction as NavInstruction.WaitForTerritory;
|
||||
if ((object)waitForTerritory == null)
|
||||
{
|
||||
if (!(instruction is NavInstruction.SubRegionTransport subRegionTransport))
|
||||
if (!(instruction is NavInstruction.WaitForNavmesh))
|
||||
{
|
||||
throw new InvalidOperationException($"Unmapped NavInstruction: {instruction}");
|
||||
if (!(instruction is NavInstruction.InteractWarp interactWarp))
|
||||
{
|
||||
if (!(instruction is NavInstruction.UseTeleportTicket useTeleportTicket))
|
||||
{
|
||||
if (!(instruction is NavInstruction.SubRegionTransport subRegionTransport))
|
||||
{
|
||||
throw new InvalidOperationException($"Unmapped NavInstruction: {instruction}");
|
||||
}
|
||||
yield return new SubRegionTransport.Task(subRegionTransport.From, subRegionTransport.To, subRegionTransport.Territory);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new TicketTeleport.Task(useTeleportTicket.ItemId, useTeleportTicket.Territory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new WarpInteract.Task(interactWarp.NpcDataId, interactWarp.WarpRowId, interactWarp.FromTerritory, interactWarp.ToTerritory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new WaitNavmesh.Task();
|
||||
}
|
||||
yield return new SubRegionTransport.Task(subRegionTransport.From, subRegionTransport.To, subRegionTransport.Territory);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new TicketTeleport.Task(useTeleportTicket.ItemId, useTeleportTicket.Territory);
|
||||
yield return new WaitCondition.Task(() => waitForTerritory.Acceptable.Contains(clientState.TerritoryType), waitForTerritory.Description);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new WarpInteract.Task(interactWarp.NpcDataId, interactWarp.WarpRowId, interactWarp.FromTerritory, interactWarp.ToTerritory);
|
||||
yield return new Mount.UnmountTask();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new WaitNavmesh.Task();
|
||||
yield return new LandTask();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new WaitCondition.Task(() => waitForTerritory.Acceptable.Contains(clientState.TerritoryType), waitForTerritory.Description);
|
||||
ushort territory = surface.Territory;
|
||||
Vector3 position = surface.Position;
|
||||
position.Y = surface.Position.Y + 3f;
|
||||
Vector3 destination = position;
|
||||
bool? mount = true;
|
||||
string targetNodeId = surface.TargetNodeId;
|
||||
string approachNodeId = surface.ApproachNodeId;
|
||||
yield return new MoveTask(territory, destination, mount, MountRequired: false, DismountRequired: false, null, null, DisableNavmesh: true, null, Fly: true, Land: false, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, AllowZoneTransition: false, targetNodeId, approachNodeId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new Mount.UnmountTask();
|
||||
yield return new Dive.Task
|
||||
{
|
||||
SmartNavRouted = true
|
||||
};
|
||||
ushort territory2 = dive.Territory;
|
||||
Vector3 position = dive.Position;
|
||||
position.Y = dive.Position.Y - 25f;
|
||||
Vector3 destination2 = position;
|
||||
string approachNodeId = dive.TargetNodeId;
|
||||
string targetNodeId = dive.ApproachNodeId;
|
||||
yield return new MoveTask(territory2, destination2, null, MountRequired: false, DismountRequired: false, null, null, DisableNavmesh: true, null, Fly: true, Land: false, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, AllowZoneTransition: false, approachNodeId, targetNodeId);
|
||||
}
|
||||
}
|
||||
else if (swim.IsFinal && step != null)
|
||||
{
|
||||
Vector3 destination3 = step.Position ?? swim.Position;
|
||||
yield return new MoveTask(step, destination3)with
|
||||
{
|
||||
Fly = true,
|
||||
Land = false,
|
||||
SmartNavRouted = true,
|
||||
RouteTargetNodeId = swim.TargetNodeId,
|
||||
RouteApproachNodeId = swim.ApproachNodeId
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new LandTask();
|
||||
NavInstruction.Swim swim2 = swim;
|
||||
ushort territory3 = swim2.Territory;
|
||||
Vector3 position2 = swim2.Position;
|
||||
float? stopDistance = swim2.StopDistance;
|
||||
string targetNodeId = swim2.TargetNodeId;
|
||||
string approachNodeId = swim2.ApproachNodeId;
|
||||
yield return new MoveTask(territory3, position2, null, MountRequired: false, DismountRequired: false, stopDistance, null, DisableNavmesh: false, null, Fly: true, Land: false, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, AllowZoneTransition: false, targetNodeId, approachNodeId);
|
||||
}
|
||||
}
|
||||
else if (move.IsFinal && step != null)
|
||||
{
|
||||
Vector3 destination = step.Position ?? move.Position;
|
||||
yield return new MoveTask(step, destination)with
|
||||
Vector3 destination4 = step.Position ?? move.Position;
|
||||
MoveTask moveTask = new MoveTask(step, destination4)with
|
||||
{
|
||||
Fly = (move.Fly || step.Fly == true),
|
||||
Land = (move.Fly || step.Land == true),
|
||||
SmartNavRouted = true,
|
||||
RouteTargetNodeId = move.TargetNodeId,
|
||||
RouteApproachNodeId = move.ApproachNodeId
|
||||
Fly = (move.Fly || step.Fly == true)
|
||||
};
|
||||
MoveTask moveTask2 = moveTask;
|
||||
bool flag = move.Fly || step.Land == true;
|
||||
if (!flag)
|
||||
{
|
||||
EArrivalMode arrivalMode = step.ArrivalMode;
|
||||
bool flag2 = (uint)(arrivalMode - 2) <= 1u;
|
||||
flag = flag2;
|
||||
}
|
||||
moveTask2.Land = flag;
|
||||
moveTask.SmartNavRouted = true;
|
||||
moveTask.RouteTargetNodeId = move.TargetNodeId;
|
||||
moveTask.RouteApproachNodeId = move.ApproachNodeId;
|
||||
yield return moveTask;
|
||||
if (step != null)
|
||||
{
|
||||
bool? fly = step.Fly;
|
||||
|
|
@ -116,22 +191,30 @@ internal sealed class SmartNavTaskMapper(IClientState clientState, TerritoryData
|
|||
yield return new LandTask();
|
||||
}
|
||||
}
|
||||
if (step.ArrivalMode == EArrivalMode.StayMounted && !step.DismountRequired)
|
||||
{
|
||||
yield return new Mount.MountTask(step.TerritoryId, Mount.EMountIf.Always);
|
||||
}
|
||||
else if (step.ArrivalMode == EArrivalMode.Dismount && !step.MountRequired)
|
||||
{
|
||||
yield return new Mount.UnmountTask();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NavInstruction.Move move2 = move;
|
||||
ushort territory = move2.Territory;
|
||||
Vector3 position = move2.Position;
|
||||
bool? mount = move2.Mount;
|
||||
float? stopDistance = move2.StopDistance;
|
||||
ushort territory4 = move2.Territory;
|
||||
Vector3 position3 = move2.Position;
|
||||
bool? mount2 = move2.Mount;
|
||||
float? stopDistance2 = move2.StopDistance;
|
||||
uint? dataId = move2.DataId;
|
||||
bool disableNavmesh = move2.DisableNavmesh;
|
||||
bool fly2 = move2.Fly;
|
||||
bool landAtTarget = move2.LandAtTarget;
|
||||
bool flag = move2.Fly;
|
||||
bool flag2 = move2.LandAtTarget;
|
||||
bool allowZoneTransition = move2.AllowZoneTransition;
|
||||
string targetNodeId = move2.TargetNodeId;
|
||||
string approachNodeId = move2.ApproachNodeId;
|
||||
yield return new MoveTask(territory, position, mount, MountRequired: false, DismountRequired: false, stopDistance, dataId, disableNavmesh, null, fly2, landAtTarget, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, allowZoneTransition, targetNodeId, approachNodeId);
|
||||
string approachNodeId = move2.TargetNodeId;
|
||||
string targetNodeId = move2.ApproachNodeId;
|
||||
yield return new MoveTask(territory4, position3, mount2, MountRequired: false, DismountRequired: false, stopDistance2, dataId, disableNavmesh, null, flag, flag2, IgnoreDistanceToObject: false, RestartNavigation: true, EInteractionType.None, SmartNavRouted: true, allowZoneTransition, approachNodeId, targetNodeId);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -147,4 +230,50 @@ internal sealed class SmartNavTaskMapper(IClientState clientState, TerritoryData
|
|||
yield return new AetheryteTeleport.MoveAwayFromAetheryte(teleport.Target);
|
||||
}
|
||||
}
|
||||
|
||||
private static MoveTask ApplyTravelMode(MoveTask task, ETravelMode travelMode)
|
||||
{
|
||||
if (travelMode == ETravelMode.Auto)
|
||||
{
|
||||
return task;
|
||||
}
|
||||
if (task.MountRequired)
|
||||
{
|
||||
return task with
|
||||
{
|
||||
Mount = true,
|
||||
Fly = (travelMode == ETravelMode.Flying && task.Fly),
|
||||
Land = (travelMode == ETravelMode.Flying && task.Land)
|
||||
};
|
||||
}
|
||||
if (task.DismountRequired)
|
||||
{
|
||||
return task with
|
||||
{
|
||||
Mount = false,
|
||||
Fly = false,
|
||||
Land = false
|
||||
};
|
||||
}
|
||||
return travelMode switch
|
||||
{
|
||||
ETravelMode.OnFoot => task with
|
||||
{
|
||||
Mount = false,
|
||||
Fly = false,
|
||||
Land = false
|
||||
},
|
||||
ETravelMode.GroundMount => task with
|
||||
{
|
||||
Mount = true,
|
||||
Fly = false,
|
||||
Land = false
|
||||
},
|
||||
ETravelMode.Flying => task with
|
||||
{
|
||||
Mount = true
|
||||
},
|
||||
_ => task,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,6 +317,13 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
|||
}
|
||||
using (ImRaii.Disabled(!value))
|
||||
{
|
||||
ImGui.Spacing();
|
||||
bool value2 = base.Configuration.SinglePlayerDuties.EnableBossModAi;
|
||||
if (UiThemeUtils.WrappedCheckbox("Activate BossMod AI during quest battles", ref value2, "When disabled, Questionable still loads its BossMod preset for combat, but does not issue the /vbmai on or /bmrai on command for autonomous movement and targeting."))
|
||||
{
|
||||
base.Configuration.SinglePlayerDuties.EnableBossModAi = value2;
|
||||
Save();
|
||||
}
|
||||
ImGui.Spacing();
|
||||
int currentItem = (int)base.Configuration.SinglePlayerDuties.RetryDifficulty;
|
||||
ImGui.SetNextItemWidth(MathF.Min(ImGui.GetContentRegionAvail().X * 0.4f, 260f));
|
||||
|
|
|
|||
|
|
@ -338,30 +338,27 @@ internal sealed class QuestSequenceComponent
|
|||
ImGui.Spacing();
|
||||
try
|
||||
{
|
||||
Lumina.Excel.Sheets.Quest? quest = _dataManager.GetExcelSheet<Lumina.Excel.Sheets.Quest>()?.GetRowOrDefault((uint)(questId.Value + 65536));
|
||||
if (!quest.HasValue)
|
||||
if (!(_dataManager.GetExcelSheet<Lumina.Excel.Sheets.Quest>()?.GetRowOrDefault((uint)(questId.Value + 65536))).HasValue)
|
||||
{
|
||||
DrawErrorState("Quest Not Found in Game Data", "Unable to load quest information from Lumina.");
|
||||
return;
|
||||
}
|
||||
List<int> list = (from result in quest.Value.TodoParams.Where((Lumina.Excel.Sheets.Quest.TodoParamsStruct todoParamsStruct) => todoParamsStruct.ToDoCompleteSeq > 0 && todoParamsStruct.ToDoCompleteSeq < byte.MaxValue).Select((Func<Lumina.Excel.Sheets.Quest.TodoParamsStruct, int>)((Lumina.Excel.Sheets.Quest.TodoParamsStruct todoParamsStruct) => todoParamsStruct.ToDoCompleteSeq)).Distinct()
|
||||
orderby result
|
||||
select result).ToList();
|
||||
if (list.Count == 0)
|
||||
List<int> completionSequences = GameQuestSequences.GetCompletionSequences(_dataManager, questId);
|
||||
if (completionSequences.Count == 0)
|
||||
{
|
||||
DrawErrorState("No Sequence Data Available", "This quest may not have traditional sequences.");
|
||||
return;
|
||||
}
|
||||
int num8 = list.Max();
|
||||
int num8 = completionSequences.Where((int num13) => num13 != 255).DefaultIfEmpty(0).Max();
|
||||
int num9 = num8 + 1;
|
||||
Questionable.Model.Quest quest2;
|
||||
bool flag = _questRegistry.TryGetQuest(questElementId, out quest2);
|
||||
Questionable.Model.Quest quest;
|
||||
bool flag = _questRegistry.TryGetQuest(questElementId, out quest);
|
||||
HashSet<int> hashSet = new HashSet<int>();
|
||||
Dictionary<int, (int, string)> dictionary = new Dictionary<int, (int, string)>();
|
||||
bool flag2 = false;
|
||||
if (flag && quest2 != null && quest2.Root.QuestSequence.Count > 0)
|
||||
if (flag && quest != null && quest.Root.QuestSequence.Count > 0)
|
||||
{
|
||||
foreach (QuestSequence item in quest2.Root.QuestSequence)
|
||||
foreach (QuestSequence item in quest.Root.QuestSequence)
|
||||
{
|
||||
if (item.Sequence == byte.MaxValue)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Dalamud.Configuration;
|
||||
using Dalamud.Game.Text;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
|
|
@ -14,7 +13,6 @@ using Questionable.Model.Questing;
|
|||
|
||||
namespace Questionable;
|
||||
|
||||
[Obfuscation(Feature = "-rename", Exclude = false, ApplyToMembers = true)]
|
||||
internal sealed class Configuration : IPluginConfiguration
|
||||
{
|
||||
internal sealed class GeneralConfiguration
|
||||
|
|
@ -160,6 +158,8 @@ internal sealed class Configuration : IPluginConfiguration
|
|||
{
|
||||
public bool RunSoloInstancesWithBossMod { get; set; }
|
||||
|
||||
public bool EnableBossModAi { get; set; } = true;
|
||||
|
||||
public ERetryDifficulty RetryDifficulty { get; set; }
|
||||
|
||||
public int MaxRetries { get; set; }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -53,7 +52,6 @@ using SmartNav.Data;
|
|||
|
||||
namespace Questionable;
|
||||
|
||||
[Obfuscation(Feature = "-ctrl flow", Exclude = false, ApplyToMembers = true)]
|
||||
public sealed class QuestionablePlugin : IAsyncDalamudPlugin, IAsyncDisposable
|
||||
{
|
||||
private ServiceProvider? _serviceProvider;
|
||||
|
|
@ -326,6 +324,8 @@ public sealed class QuestionablePlugin : IAsyncDalamudPlugin, IAsyncDisposable
|
|||
serviceCollection.AddSingleton<TeleportTicketService>();
|
||||
serviceCollection.AddSingleton((IServiceProvider sp) => new LgbZoneBoundarySource(sp.GetRequiredService<ILogger<LgbZoneBoundarySource>>(), sp.GetRequiredService<SmartNavDataOptions>()));
|
||||
((IServiceCollection)serviceCollection).AddSingleton((Func<IServiceProvider, IZoneBoundarySource>)((IServiceProvider sp) => sp.GetRequiredService<LgbZoneBoundarySource>()));
|
||||
serviceCollection.AddSingleton<WaterMapService>();
|
||||
serviceCollection.AddSingleton<WaterRoutePlanner>();
|
||||
((IServiceCollection)serviceCollection).AddSingleton((Func<IServiceProvider, ITerritoryInfo>)((IServiceProvider sp) => sp.GetRequiredService<TerritoryData>()));
|
||||
serviceCollection.AddSingleton<IPlayerContext, QuestionablePlayerContext>();
|
||||
serviceCollection.AddSingleton<CostCalculator>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue