muffin v7.4.7
This commit is contained in:
parent
1cc65e495d
commit
63f975ff4f
16 changed files with 1659 additions and 939 deletions
|
|
@ -252,4 +252,140 @@ internal static class Duty
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed record StartLevelingModeTask(int RequiredLevel, string? QuestName) : ITask
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"StartLevelingMode(target: Lv{RequiredLevel} for '{QuestName}')";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class StartLevelingModeExecutor(AutoDutyIpc autoDutyIpc, ICondition condition, ILogger<StartLevelingModeExecutor> logger) : TaskExecutor<StartLevelingModeTask>(), IStoppableTaskExecutor, ITaskExecutor
|
||||||
|
{
|
||||||
|
private bool _started;
|
||||||
|
|
||||||
|
private DateTime _startTime;
|
||||||
|
|
||||||
|
private DateTime _lastRetryTime = DateTime.MinValue;
|
||||||
|
|
||||||
|
protected override bool Start()
|
||||||
|
{
|
||||||
|
logger.LogInformation("Starting AutoDuty Leveling mode to reach level {RequiredLevel} for quest '{QuestName}'", base.Task.RequiredLevel, base.Task.QuestName);
|
||||||
|
_started = autoDutyIpc.StartLevelingMode();
|
||||||
|
_startTime = DateTime.Now;
|
||||||
|
return _started;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ETaskResult Update()
|
||||||
|
{
|
||||||
|
bool flag = condition[ConditionFlag.BoundByDuty];
|
||||||
|
bool flag2 = condition[ConditionFlag.InDutyQueue];
|
||||||
|
if (flag || flag2)
|
||||||
|
{
|
||||||
|
logger.LogInformation("AutoDuty started successfully (inDuty={InDuty}, inQueue={InQueue})", flag, flag2);
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
if (!autoDutyIpc.IsStopped())
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
if (DateTime.Now - _lastRetryTime > TimeSpan.FromSeconds(5L))
|
||||||
|
{
|
||||||
|
logger.LogWarning("AutoDuty stopped before entering duty, retrying...");
|
||||||
|
_started = autoDutyIpc.StartLevelingMode();
|
||||||
|
_lastRetryTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
if (DateTime.Now - _startTime > TimeSpan.FromSeconds(60L))
|
||||||
|
{
|
||||||
|
logger.LogError("AutoDuty failed to start after 60 seconds");
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopNow()
|
||||||
|
{
|
||||||
|
autoDutyIpc.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldInterruptOnDamage()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed record WaitLevelingModeTask(int RequiredLevel) : ITask
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"WaitLevelingMode(until Lv{RequiredLevel})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class WaitLevelingModeExecutor(AutoDutyIpc autoDutyIpc, IObjectTable objectTable, ICondition condition, IChatGui chatGui, ILogger<WaitLevelingModeExecutor> logger) : TaskExecutor<WaitLevelingModeTask>(), IStoppableTaskExecutor, ITaskExecutor
|
||||||
|
{
|
||||||
|
private bool _wasInDuty;
|
||||||
|
|
||||||
|
private DateTime _lastStatusMessage = DateTime.MinValue;
|
||||||
|
|
||||||
|
private DateTime _idleStartTime = DateTime.MinValue;
|
||||||
|
|
||||||
|
protected override bool Start()
|
||||||
|
{
|
||||||
|
_wasInDuty = false;
|
||||||
|
_idleStartTime = DateTime.MinValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ETaskResult Update()
|
||||||
|
{
|
||||||
|
bool flag = condition[ConditionFlag.BoundByDuty];
|
||||||
|
bool flag2 = condition[ConditionFlag.InDutyQueue];
|
||||||
|
if (flag && !_wasInDuty)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Entered duty for leveling");
|
||||||
|
_wasInDuty = true;
|
||||||
|
_idleStartTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
if (flag || flag2)
|
||||||
|
{
|
||||||
|
_idleStartTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
byte b = objectTable.LocalPlayer?.Level ?? 0;
|
||||||
|
if (b >= base.Task.RequiredLevel)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Reached required level {RequiredLevel} (current: {CurrentLevel})", base.Task.RequiredLevel, b);
|
||||||
|
chatGui.Print($"Reached level {b}, can now continue MSQ.", "Questionable", 576);
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
if (autoDutyIpc.IsStopped() && !flag && !flag2)
|
||||||
|
{
|
||||||
|
if (_idleStartTime == DateTime.MinValue)
|
||||||
|
{
|
||||||
|
_idleStartTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
if (_wasInDuty && DateTime.Now - _idleStartTime > TimeSpan.FromSeconds(3L))
|
||||||
|
{
|
||||||
|
_ = base.Task.RequiredLevel;
|
||||||
|
_lastStatusMessage = DateTime.Now;
|
||||||
|
logger.LogInformation("Starting another leveling run (current: {CurrentLevel}, need: {RequiredLevel})", b, base.Task.RequiredLevel);
|
||||||
|
autoDutyIpc.StartLevelingMode();
|
||||||
|
_wasInDuty = false;
|
||||||
|
_idleStartTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopNow()
|
||||||
|
{
|
||||||
|
autoDutyIpc.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldInterruptOnDamage()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,10 @@ internal abstract class MiniTaskController<T> : IDisposable
|
||||||
|
|
||||||
public void OnErrorToast(ref SeString message, ref bool isHandled)
|
public void OnErrorToast(ref SeString message, ref bool isHandled)
|
||||||
{
|
{
|
||||||
|
if (_taskQueue.AllTasksComplete)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_taskQueue.CurrentTaskExecutor is IToastAware toastAware && toastAware.OnErrorToast(message))
|
if (_taskQueue.CurrentTaskExecutor is IToastAware toastAware && toastAware.OnErrorToast(message))
|
||||||
{
|
{
|
||||||
isHandled = true;
|
isHandled = true;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ using Questionable.Controller.Steps;
|
||||||
using Questionable.Controller.Steps.Interactions;
|
using Questionable.Controller.Steps.Interactions;
|
||||||
using Questionable.Controller.Steps.Shared;
|
using Questionable.Controller.Steps.Shared;
|
||||||
using Questionable.Data;
|
using Questionable.Data;
|
||||||
|
using Questionable.External;
|
||||||
using Questionable.Functions;
|
using Questionable.Functions;
|
||||||
using Questionable.Model;
|
using Questionable.Model;
|
||||||
using Questionable.Model.Questing;
|
using Questionable.Model.Questing;
|
||||||
|
|
@ -115,6 +116,8 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
|
|
||||||
private readonly SinglePlayerDutyConfigComponent _singlePlayerDutyConfigComponent;
|
private readonly SinglePlayerDutyConfigComponent _singlePlayerDutyConfigComponent;
|
||||||
|
|
||||||
|
private readonly AutoDutyIpc _autoDutyIpc;
|
||||||
|
|
||||||
private readonly ILogger<QuestController> _logger;
|
private readonly ILogger<QuestController> _logger;
|
||||||
|
|
||||||
private readonly object _progressLock = new object();
|
private readonly object _progressLock = new object();
|
||||||
|
|
@ -155,6 +158,8 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
|
|
||||||
private static readonly TimeSpan EscDoublePressWindow = TimeSpan.FromSeconds(1L);
|
private static readonly TimeSpan EscDoublePressWindow = TimeSpan.FromSeconds(1L);
|
||||||
|
|
||||||
|
private HashSet<string> _stopConditionsMetAtStart = new HashSet<string>();
|
||||||
|
|
||||||
private const char ClipboardSeparator = ';';
|
private const char ClipboardSeparator = ';';
|
||||||
|
|
||||||
public EAutomationType AutomationType
|
public EAutomationType AutomationType
|
||||||
|
|
@ -236,7 +241,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
|
|
||||||
public event AutomationTypeChangedEventHandler? AutomationTypeChanged;
|
public event AutomationTypeChangedEventHandler? AutomationTypeChanged;
|
||||||
|
|
||||||
public QuestController(IClientState clientState, IObjectTable objectTable, GameFunctions gameFunctions, QuestFunctions questFunctions, MovementController movementController, CombatController combatController, GatheringController gatheringController, ILogger<QuestController> logger, QuestRegistry questRegistry, JournalData journalData, IKeyState keyState, IChatGui chatGui, ICondition condition, IToastGui toastGui, Configuration configuration, TaskCreator taskCreator, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, SinglePlayerDutyConfigComponent singlePlayerDutyConfigComponent)
|
public QuestController(IClientState clientState, IObjectTable objectTable, GameFunctions gameFunctions, QuestFunctions questFunctions, MovementController movementController, CombatController combatController, GatheringController gatheringController, ILogger<QuestController> logger, QuestRegistry questRegistry, JournalData journalData, IKeyState keyState, IChatGui chatGui, ICondition condition, IToastGui toastGui, Configuration configuration, TaskCreator taskCreator, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, SinglePlayerDutyConfigComponent singlePlayerDutyConfigComponent, AutoDutyIpc autoDutyIpc)
|
||||||
: base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
|
: base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
|
||||||
{
|
{
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
|
|
@ -255,6 +260,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_taskCreator = taskCreator;
|
_taskCreator = taskCreator;
|
||||||
_singlePlayerDutyConfigComponent = singlePlayerDutyConfigComponent;
|
_singlePlayerDutyConfigComponent = singlePlayerDutyConfigComponent;
|
||||||
|
_autoDutyIpc = autoDutyIpc;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_toastGui.ErrorToast += base.OnErrorToast;
|
_toastGui.ErrorToast += base.OnErrorToast;
|
||||||
_toastGui.Toast += OnNormalToast;
|
_toastGui.Toast += OnNormalToast;
|
||||||
|
|
@ -361,17 +367,25 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
if (_configuration.Stop.Enabled && _startedQuest != null)
|
if (_configuration.Stop.Enabled && _startedQuest != null)
|
||||||
{
|
{
|
||||||
string text = _startedQuest.Quest.Id.ToString();
|
string text = _startedQuest.Quest.Id.ToString();
|
||||||
if (_configuration.Stop.LevelToStopAfter && IsRunning && _objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level >= _configuration.Stop.TargetLevel)
|
if (_configuration.Stop.LevelStopMode != Configuration.EStopConditionMode.Off && IsRunning && _objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level >= _configuration.Stop.TargetLevel)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Reached level stop condition (current: {CurrentLevel}, target: {TargetLevel})", playerCharacter.Level, _configuration.Stop.TargetLevel);
|
string item = $"level:{_configuration.Stop.TargetLevel}";
|
||||||
|
if (_configuration.Stop.LevelStopMode != Configuration.EStopConditionMode.Pause || !_stopConditionsMetAtStart.Contains(item))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Reached level stop condition (current: {CurrentLevel}, target: {TargetLevel}, mode: {Mode})", playerCharacter.Level, _configuration.Stop.TargetLevel, _configuration.Stop.LevelStopMode);
|
||||||
_chatGui.Print($"Character level {playerCharacter.Level} reached target level {_configuration.Stop.TargetLevel}.", "Questionable", 576);
|
_chatGui.Print($"Character level {playerCharacter.Level} reached target level {_configuration.Stop.TargetLevel}.", "Questionable", 576);
|
||||||
Stop($"Level stop condition reached [{playerCharacter.Level}]");
|
Stop($"Level stop condition reached [{playerCharacter.Level}]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (_configuration.Stop.QuestSequences.TryGetValue(text, out var value) && value.HasValue)
|
if (_configuration.Stop.QuestSequences.TryGetValue(text, out var value) && value.HasValue)
|
||||||
{
|
{
|
||||||
int sequence = _startedQuest.Sequence;
|
int sequence = _startedQuest.Sequence;
|
||||||
if (sequence >= value.Value && IsRunning)
|
if (sequence >= value.Value && IsRunning)
|
||||||
|
{
|
||||||
|
Configuration.EStopConditionMode valueOrDefault = _configuration.Stop.QuestStopModes.GetValueOrDefault(text, Configuration.EStopConditionMode.Pause);
|
||||||
|
string item2 = $"questseq:{text}:{sequence}";
|
||||||
|
if (valueOrDefault != Configuration.EStopConditionMode.Pause || !_stopConditionsMetAtStart.Contains(item2))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Reached quest-specific sequence stop condition (quest: {QuestId}, sequence: {CurrentSequence}, target: {TargetSequence})", _startedQuest.Quest.Id, sequence, value.Value);
|
_logger.LogInformation("Reached quest-specific sequence stop condition (quest: {QuestId}, sequence: {CurrentSequence}, target: {TargetSequence})", _startedQuest.Quest.Id, sequence, value.Value);
|
||||||
_chatGui.Print($"Quest '{_startedQuest.Quest.Info.Name}' reached sequence {sequence}, configured stop sequence is {value.Value}.", "Questionable", 576);
|
_chatGui.Print($"Quest '{_startedQuest.Quest.Info.Name}' reached sequence {sequence}, configured stop sequence is {value.Value}.", "Questionable", 576);
|
||||||
|
|
@ -379,18 +393,23 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_configuration.Stop.SequenceToStopAfter && CurrentQuest != null)
|
}
|
||||||
|
else if (_configuration.Stop.SequenceStopMode != Configuration.EStopConditionMode.Off && CurrentQuest != null)
|
||||||
{
|
{
|
||||||
int sequence2 = CurrentQuest.Sequence;
|
int sequence2 = CurrentQuest.Sequence;
|
||||||
if (sequence2 >= _configuration.Stop.TargetSequence && IsRunning)
|
if (sequence2 >= _configuration.Stop.TargetSequence && IsRunning)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Reached global quest sequence stop condition (sequence: {CurrentSequence}, target: {TargetSequence})", sequence2, _configuration.Stop.TargetSequence);
|
string item3 = $"sequence:{text}:{sequence2}";
|
||||||
|
if (_configuration.Stop.SequenceStopMode != Configuration.EStopConditionMode.Pause || !_stopConditionsMetAtStart.Contains(item3))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Reached global quest sequence stop condition (sequence: {CurrentSequence}, target: {TargetSequence}, mode: {Mode})", sequence2, _configuration.Stop.TargetSequence, _configuration.Stop.SequenceStopMode);
|
||||||
_chatGui.Print($"Quest sequence {sequence2} reached target sequence {_configuration.Stop.TargetSequence}.", "Questionable", 576);
|
_chatGui.Print($"Quest sequence {sequence2} reached target sequence {_configuration.Stop.TargetSequence}.", "Questionable", 576);
|
||||||
Stop($"Sequence stop condition reached [{sequence2}]");
|
Stop($"Sequence stop condition reached [{sequence2}]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
bool flag = AutomationType == EAutomationType.Automatic && (_taskQueue.AllTasksComplete || _taskQueue.CurrentTaskExecutor?.CurrentTask is WaitAtEnd.WaitQuestAccepted);
|
bool flag = AutomationType == EAutomationType.Automatic && (_taskQueue.AllTasksComplete || _taskQueue.CurrentTaskExecutor?.CurrentTask is WaitAtEnd.WaitQuestAccepted);
|
||||||
bool flag2;
|
bool flag2;
|
||||||
if (flag)
|
if (flag)
|
||||||
|
|
@ -402,17 +421,14 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
if (step == 0 || step == 255)
|
if (step == 0 || step == 255)
|
||||||
{
|
{
|
||||||
flag2 = true;
|
flag2 = true;
|
||||||
goto IL_0691;
|
goto IL_07e7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flag2 = false;
|
flag2 = false;
|
||||||
goto IL_0691;
|
goto IL_07e7;
|
||||||
}
|
}
|
||||||
goto IL_0695;
|
goto IL_07eb;
|
||||||
IL_0691:
|
IL_07eb:
|
||||||
flag = flag2;
|
|
||||||
goto IL_0695;
|
|
||||||
IL_0695:
|
|
||||||
if (flag && DateTime.Now >= CurrentQuest.StepProgress.StartedAt.AddSeconds(15.0))
|
if (flag && DateTime.Now >= CurrentQuest.StepProgress.StartedAt.AddSeconds(15.0))
|
||||||
{
|
{
|
||||||
lock (_progressLock)
|
lock (_progressLock)
|
||||||
|
|
@ -427,6 +443,10 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
CheckAutoRefreshCondition();
|
CheckAutoRefreshCondition();
|
||||||
UpdateCurrentTask();
|
UpdateCurrentTask();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
IL_07e7:
|
||||||
|
flag = flag2;
|
||||||
|
goto IL_07eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckAutoRefreshCondition()
|
private void CheckAutoRefreshCondition()
|
||||||
|
|
@ -563,7 +583,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
int num = ManualPriorityQuests.RemoveAll((Quest q) => _questFunctions.IsQuestComplete(q.Id));
|
int num = ManualPriorityQuests.RemoveAll((Quest q) => _questFunctions.IsQuestComplete(q.Id));
|
||||||
if (num > 0)
|
if (num > 0)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Removed {Count} completed priority quest(s)", num);
|
_logger.LogInformation("Removed {Count} completed priority {QuestWord}", num, (num == 1) ? "quest" : "quests");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_pendingQuest != null)
|
if (_pendingQuest != null)
|
||||||
|
|
@ -632,6 +652,19 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
}
|
}
|
||||||
if (elementId == null || elementId.Value == 0)
|
if (elementId == null || elementId.Value == 0)
|
||||||
{
|
{
|
||||||
|
(bool isLevelLocked, int levelsNeeded, int requiredLevel, string? questName) msqLevelLockInfo = _questFunctions.GetMsqLevelLockInfo();
|
||||||
|
bool item = msqLevelLockInfo.isLevelLocked;
|
||||||
|
int item2 = msqLevelLockInfo.levelsNeeded;
|
||||||
|
int item3 = msqLevelLockInfo.requiredLevel;
|
||||||
|
string item4 = msqLevelLockInfo.questName;
|
||||||
|
int currentPlayerLevel = (_objectTable[0] as IPlayerCharacter)?.Level ?? 0;
|
||||||
|
if (item && _autoDutyIpc.IsConfiguredToRunLevelingMode(currentPlayerLevel) && AutomationType == EAutomationType.Automatic && !_condition[ConditionFlag.BoundByDuty] && _taskQueue.AllTasksComplete)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("MSQ '{QuestName}' requires level {RequiredLevel}, current level is {CurrentLevel} ({LevelsNeeded} levels needed). Starting AutoDuty Leveling mode.", item4, item3, item3 - item2, item2);
|
||||||
|
_taskQueue.Enqueue(new Duty.StartLevelingModeTask(item3, item4));
|
||||||
|
_taskQueue.Enqueue(new Duty.WaitLevelingModeTask(item3));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_startedQuest != null)
|
if (_startedQuest != null)
|
||||||
{
|
{
|
||||||
switch (mainScenarioQuestState)
|
switch (mainScenarioQuestState)
|
||||||
|
|
@ -668,10 +701,21 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
_startedQuest = new QuestProgress(quest, b);
|
_startedQuest = new QuestProgress(quest, b);
|
||||||
if (_objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level < quest.Info.Level)
|
if (_objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level < quest.Info.Level)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Stopping automation, player level ({PlayerLevel}) < quest level ({QuestLevel}", playerCharacter.Level, quest.Info.Level);
|
if (_autoDutyIpc.IsConfiguredToRunLevelingMode(playerCharacter.Level) && AutomationType == EAutomationType.Automatic && !_condition[ConditionFlag.BoundByDuty])
|
||||||
Stop("Quest level too high");
|
{
|
||||||
return;
|
_logger.LogInformation("Player level ({PlayerLevel}) < quest level ({QuestLevel}), starting AutoDuty Leveling mode", playerCharacter.Level, quest.Info.Level);
|
||||||
|
ClearTasksInternal();
|
||||||
|
_taskQueue.Enqueue(new Duty.StartLevelingModeTask(quest.Info.Level, quest.Info.Name));
|
||||||
|
_taskQueue.Enqueue(new Duty.WaitLevelingModeTask(quest.Info.Level));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Stopping automation, player level ({PlayerLevel}) < quest level ({QuestLevel})", playerCharacter.Level, quest.Info.Level);
|
||||||
|
Stop("Quest level too high");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (AutomationType == EAutomationType.SingleQuestB)
|
if (AutomationType == EAutomationType.SingleQuestB)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Single quest is finished");
|
_logger.LogInformation("Single quest is finished");
|
||||||
|
|
@ -679,6 +723,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
}
|
}
|
||||||
CheckNextTasks("Different Quest");
|
CheckNextTasks("Different Quest");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (_startedQuest != null)
|
else if (_startedQuest != null)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("No active quest anymore? Not sure what happened...");
|
_logger.LogInformation("No active quest anymore? Not sure what happened...");
|
||||||
|
|
@ -853,6 +898,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
_nextQuest = null;
|
_nextQuest = null;
|
||||||
_gatheringQuest = null;
|
_gatheringQuest = null;
|
||||||
_lastTaskUpdate = DateTime.Now;
|
_lastTaskUpdate = DateTime.Now;
|
||||||
|
_stopConditionsMetAtStart.Clear();
|
||||||
ResetAutoRefreshState();
|
ResetAutoRefreshState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -967,6 +1013,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
{
|
{
|
||||||
if (!CheckAndBlockForStopConditions())
|
if (!CheckAndBlockForStopConditions())
|
||||||
{
|
{
|
||||||
|
RecordStopConditionsMetAtStart();
|
||||||
AutomationType = EAutomationType.Automatic;
|
AutomationType = EAutomationType.Automatic;
|
||||||
ExecuteNextStep();
|
ExecuteNextStep();
|
||||||
}
|
}
|
||||||
|
|
@ -979,6 +1026,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
{
|
{
|
||||||
if (!CheckAndBlockForStopConditions())
|
if (!CheckAndBlockForStopConditions())
|
||||||
{
|
{
|
||||||
|
RecordStopConditionsMetAtStart();
|
||||||
AutomationType = EAutomationType.GatheringOnly;
|
AutomationType = EAutomationType.GatheringOnly;
|
||||||
ExecuteNextStep();
|
ExecuteNextStep();
|
||||||
}
|
}
|
||||||
|
|
@ -991,6 +1039,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
{
|
{
|
||||||
if (!CheckAndBlockForStopConditions())
|
if (!CheckAndBlockForStopConditions())
|
||||||
{
|
{
|
||||||
|
RecordStopConditionsMetAtStart();
|
||||||
AutomationType = EAutomationType.SingleQuestA;
|
AutomationType = EAutomationType.SingleQuestA;
|
||||||
ExecuteNextStep();
|
ExecuteNextStep();
|
||||||
}
|
}
|
||||||
|
|
@ -1006,13 +1055,53 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RecordStopConditionsMetAtStart()
|
||||||
|
{
|
||||||
|
_stopConditionsMetAtStart.Clear();
|
||||||
|
if (!_configuration.Stop.Enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_configuration.Stop.LevelStopMode == Configuration.EStopConditionMode.Pause && _objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level >= _configuration.Stop.TargetLevel)
|
||||||
|
{
|
||||||
|
_stopConditionsMetAtStart.Add($"level:{_configuration.Stop.TargetLevel}");
|
||||||
|
_logger.LogDebug("Recording level stop condition as already met at start: {Level}", _configuration.Stop.TargetLevel);
|
||||||
|
}
|
||||||
|
if (_configuration.Stop.SequenceStopMode == Configuration.EStopConditionMode.Pause && _startedQuest != null)
|
||||||
|
{
|
||||||
|
string text = _startedQuest.Quest.Id.ToString();
|
||||||
|
if (!_configuration.Stop.QuestSequences.ContainsKey(text))
|
||||||
|
{
|
||||||
|
int sequence = _startedQuest.Sequence;
|
||||||
|
if (sequence >= _configuration.Stop.TargetSequence)
|
||||||
|
{
|
||||||
|
_stopConditionsMetAtStart.Add($"sequence:{text}:{sequence}");
|
||||||
|
_logger.LogDebug("Recording global sequence stop condition as already met at start: quest {QuestId}, sequence {Sequence}", text, sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (ElementId item in _configuration.Stop.QuestsToStopAfter)
|
||||||
|
{
|
||||||
|
string text2 = item.ToString();
|
||||||
|
if (_configuration.Stop.QuestStopModes.GetValueOrDefault(text2, Configuration.EStopConditionMode.Pause) == Configuration.EStopConditionMode.Pause && _configuration.Stop.QuestSequences.TryGetValue(text2, out var value) && value.HasValue && _questFunctions.IsQuestAccepted(item))
|
||||||
|
{
|
||||||
|
QuestProgressInfo questProgressInfo = _questFunctions.GetQuestProgressInfo(item);
|
||||||
|
if (questProgressInfo != null && questProgressInfo.Sequence >= value.Value)
|
||||||
|
{
|
||||||
|
_stopConditionsMetAtStart.Add($"questseq:{text2}:{questProgressInfo.Sequence}");
|
||||||
|
_logger.LogDebug("Recording quest sequence stop condition as already met at start: quest {QuestId}, sequence {Sequence}", text2, questProgressInfo.Sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool CheckAndBlockForStopConditions()
|
private bool CheckAndBlockForStopConditions()
|
||||||
{
|
{
|
||||||
if (!_configuration.Stop.Enabled)
|
if (!_configuration.Stop.Enabled)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_configuration.Stop.LevelToStopAfter && _objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level >= _configuration.Stop.TargetLevel)
|
if (_configuration.Stop.LevelStopMode == Configuration.EStopConditionMode.Stop && _objectTable[0] is IPlayerCharacter playerCharacter && playerCharacter.Level >= _configuration.Stop.TargetLevel)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Blocking start: Level stop condition already met (current: {CurrentLevel}, target: {TargetLevel})", playerCharacter.Level, _configuration.Stop.TargetLevel);
|
_logger.LogInformation("Blocking start: Level stop condition already met (current: {CurrentLevel}, target: {TargetLevel})", playerCharacter.Level, _configuration.Stop.TargetLevel);
|
||||||
_chatGui.Print($"Cannot start: Character level {playerCharacter.Level} has reached target level {_configuration.Stop.TargetLevel}.", "Questionable", 576);
|
_chatGui.Print($"Cannot start: Character level {playerCharacter.Level} has reached target level {_configuration.Stop.TargetLevel}.", "Questionable", 576);
|
||||||
|
|
@ -1021,6 +1110,10 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
foreach (ElementId item in _configuration.Stop.QuestsToStopAfter)
|
foreach (ElementId item in _configuration.Stop.QuestsToStopAfter)
|
||||||
{
|
{
|
||||||
string key = item.ToString();
|
string key = item.ToString();
|
||||||
|
if (_configuration.Stop.QuestStopModes.GetValueOrDefault(key, Configuration.EStopConditionMode.Pause) != Configuration.EStopConditionMode.Stop)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (_configuration.Stop.QuestSequences.TryGetValue(key, out var value) && value.HasValue)
|
if (_configuration.Stop.QuestSequences.TryGetValue(key, out var value) && value.HasValue)
|
||||||
{
|
{
|
||||||
if (!_questFunctions.IsQuestAccepted(item))
|
if (!_questFunctions.IsQuestAccepted(item))
|
||||||
|
|
@ -1048,7 +1141,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_configuration.Stop.SequenceToStopAfter && _startedQuest != null)
|
if (_configuration.Stop.SequenceStopMode == Configuration.EStopConditionMode.Stop && _startedQuest != null)
|
||||||
{
|
{
|
||||||
string key2 = _startedQuest.Quest.Id.ToString();
|
string key2 = _startedQuest.Quest.Id.ToString();
|
||||||
if (!_configuration.Stop.QuestSequences.ContainsKey(key2))
|
if (!_configuration.Stop.QuestSequences.ContainsKey(key2))
|
||||||
|
|
@ -1075,6 +1168,23 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
var (questSequence, step, flag) = GetNextStep();
|
var (questSequence, step, flag) = GetNextStep();
|
||||||
if (CurrentQuest == null || questSequence == null)
|
if (CurrentQuest == null || questSequence == null)
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("ExecuteNextStep: No current quest or sequence. Checking leveling mode conditions.");
|
||||||
|
if (AutomationType == EAutomationType.Automatic && !_condition[ConditionFlag.BoundByDuty])
|
||||||
|
{
|
||||||
|
(bool isLevelLocked, int levelsNeeded, int requiredLevel, string? questName) msqLevelLockInfo = _questFunctions.GetMsqLevelLockInfo();
|
||||||
|
bool item = msqLevelLockInfo.isLevelLocked;
|
||||||
|
int item2 = msqLevelLockInfo.levelsNeeded;
|
||||||
|
int item3 = msqLevelLockInfo.requiredLevel;
|
||||||
|
string item4 = msqLevelLockInfo.questName;
|
||||||
|
int currentPlayerLevel = (_objectTable[0] as IPlayerCharacter)?.Level ?? 0;
|
||||||
|
if (item && _autoDutyIpc.IsConfiguredToRunLevelingMode(currentPlayerLevel))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("MSQ '{QuestName}' requires level {RequiredLevel}, current level is {CurrentLevel} ({LevelsNeeded} levels needed). Starting AutoDuty Leveling mode.", item4, item3, item3 - item2, item2);
|
||||||
|
_taskQueue.Enqueue(new Duty.StartLevelingModeTask(item3, item4));
|
||||||
|
_taskQueue.Enqueue(new Duty.WaitLevelingModeTask(item3));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (CurrentQuestDetails?.Progress.Quest.Id is SatisfactionSupplyNpcId && CurrentQuestDetails?.Progress.Sequence == 1)
|
if (CurrentQuestDetails?.Progress.Quest.Id is SatisfactionSupplyNpcId && CurrentQuestDetails?.Progress.Sequence == 1)
|
||||||
{
|
{
|
||||||
(QuestProgress, ECurrentQuestType)? currentQuestDetails = CurrentQuestDetails;
|
(QuestProgress, ECurrentQuestType)? currentQuestDetails = CurrentQuestDetails;
|
||||||
|
|
@ -1086,23 +1196,23 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
_logger.LogInformation("Completed delivery quest");
|
_logger.LogInformation("Completed delivery quest");
|
||||||
SetGatheringQuest(null);
|
SetGatheringQuest(null);
|
||||||
Stop("Gathering quest complete");
|
Stop("Gathering quest complete");
|
||||||
goto IL_01dc;
|
goto IL_02d0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_logger.LogWarning("Could not retrieve next quest step, not doing anything [{QuestId}, {Sequence}, {Step}]", CurrentQuest?.Quest.Id, CurrentQuest?.Sequence, CurrentQuest?.Step);
|
_logger.LogWarning("Could not retrieve next quest step, not doing anything [{QuestId}, {Sequence}, {Step}]", CurrentQuest?.Quest.Id, CurrentQuest?.Sequence, CurrentQuest?.Step);
|
||||||
goto IL_01dc;
|
goto IL_02d0;
|
||||||
}
|
}
|
||||||
goto IL_01e8;
|
goto IL_02dc;
|
||||||
IL_01e8:
|
IL_02dc:
|
||||||
_movementController.Stop();
|
_movementController.Stop();
|
||||||
_combatController.Stop("Execute next step");
|
_combatController.Stop("Execute next step");
|
||||||
_gatheringController.Stop("Execute next step");
|
_gatheringController.Stop("Execute next step");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (ITask item in _taskCreator.CreateTasks(CurrentQuest.Quest, CurrentQuest.Sequence, questSequence, step))
|
foreach (ITask item5 in _taskCreator.CreateTasks(CurrentQuest.Quest, CurrentQuest.Sequence, questSequence, step))
|
||||||
{
|
{
|
||||||
_taskQueue.Enqueue(item);
|
_taskQueue.Enqueue(item5);
|
||||||
}
|
}
|
||||||
ResetAutoRefreshState();
|
ResetAutoRefreshState();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1114,12 +1224,12 @@ internal sealed class QuestController : MiniTaskController<QuestController>
|
||||||
Stop("Tasks failed to create");
|
Stop("Tasks failed to create");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IL_01dc:
|
IL_02d0:
|
||||||
if (CurrentQuest == null || !flag)
|
if (CurrentQuest == null || !flag)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goto IL_01e8;
|
goto IL_02dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToStatString()
|
public string ToStatString()
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -35,6 +35,10 @@ internal sealed class AutoDutyIpc
|
||||||
|
|
||||||
private bool _loggedContentHasPathQueryWarning;
|
private bool _loggedContentHasPathQueryWarning;
|
||||||
|
|
||||||
|
private bool _loggedLevelingModeWarning;
|
||||||
|
|
||||||
|
public const int MinimumLevelForLevelingMode = 15;
|
||||||
|
|
||||||
public AutoDutyIpc(IDalamudPluginInterface pluginInterface, Configuration configuration, TerritoryData territoryData, ILogger<AutoDutyIpc> logger)
|
public AutoDutyIpc(IDalamudPluginInterface pluginInterface, Configuration configuration, TerritoryData territoryData, ILogger<AutoDutyIpc> logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
|
|
@ -46,6 +50,7 @@ internal sealed class AutoDutyIpc
|
||||||
_isStopped = pluginInterface.GetIpcSubscriber<bool>("AutoDuty.IsStopped");
|
_isStopped = pluginInterface.GetIpcSubscriber<bool>("AutoDuty.IsStopped");
|
||||||
_stop = pluginInterface.GetIpcSubscriber<object>("AutoDuty.Stop");
|
_stop = pluginInterface.GetIpcSubscriber<object>("AutoDuty.Stop");
|
||||||
_loggedContentHasPathQueryWarning = false;
|
_loggedContentHasPathQueryWarning = false;
|
||||||
|
_loggedLevelingModeWarning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsConfiguredToRunContent(DutyOptions? dutyOptions)
|
public bool IsConfiguredToRunContent(DutyOptions? dutyOptions)
|
||||||
|
|
@ -73,6 +78,24 @@ internal sealed class AutoDutyIpc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsConfiguredToRunLevelingMode()
|
||||||
|
{
|
||||||
|
return _configuration.Duties.RunLevelingModeWhenUnderleveled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsConfiguredToRunLevelingMode(int currentPlayerLevel)
|
||||||
|
{
|
||||||
|
if (!_configuration.Duties.RunLevelingModeWhenUnderleveled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentPlayerLevel < 15)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool HasPath(uint cfcId)
|
public bool HasPath(uint cfcId)
|
||||||
{
|
{
|
||||||
if (!_territoryData.TryGetContentFinderCondition(cfcId, out TerritoryData.ContentFinderConditionData contentFinderConditionData))
|
if (!_territoryData.TryGetContentFinderCondition(cfcId, out TerritoryData.ContentFinderConditionData contentFinderConditionData))
|
||||||
|
|
@ -118,6 +141,35 @@ internal sealed class AutoDutyIpc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool StartLevelingMode()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Starting AutoDuty Leveling mode (Support) - AutoDuty will select the best dungeon");
|
||||||
|
_setConfig.InvokeAction("leveling", "Support");
|
||||||
|
_run.InvokeAction(0u, 1, !_configuration.Advanced.DisableAutoDutyBareMode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (IpcError ipcError)
|
||||||
|
{
|
||||||
|
if (!_loggedLevelingModeWarning)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Unable to start AutoDuty Leveling mode: {Message}", ipcError.Message);
|
||||||
|
_loggedLevelingModeWarning = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
if (!_loggedLevelingModeWarning)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(exception, "Unable to start AutoDuty Leveling mode");
|
||||||
|
_loggedLevelingModeWarning = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsStopped()
|
public bool IsStopped()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,17 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
public required int TargetValue { get; init; }
|
public required int TargetValue { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class MsqLevelLockData
|
||||||
|
{
|
||||||
|
public required bool IsLevelLocked { get; init; }
|
||||||
|
|
||||||
|
public required int LevelsNeeded { get; init; }
|
||||||
|
|
||||||
|
public required int RequiredLevel { get; init; }
|
||||||
|
|
||||||
|
public required string? QuestName { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
private const string IpcIsRunning = "Questionable.IsRunning";
|
private const string IpcIsRunning = "Questionable.IsRunning";
|
||||||
|
|
||||||
private const string IpcGetCurrentQuestId = "Questionable.GetCurrentQuestId";
|
private const string IpcGetCurrentQuestId = "Questionable.GetCurrentQuestId";
|
||||||
|
|
@ -145,6 +156,18 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
|
|
||||||
private const string IpcGetAllQuestSequenceStopConditions = "Questionable.GetAllQuestSequenceStopConditions";
|
private const string IpcGetAllQuestSequenceStopConditions = "Questionable.GetAllQuestSequenceStopConditions";
|
||||||
|
|
||||||
|
private const string IpcGetLevelStopMode = "Questionable.GetLevelStopMode";
|
||||||
|
|
||||||
|
private const string IpcSetLevelStopMode = "Questionable.SetLevelStopMode";
|
||||||
|
|
||||||
|
private const string IpcGetSequenceStopMode = "Questionable.GetSequenceStopMode";
|
||||||
|
|
||||||
|
private const string IpcSetSequenceStopMode = "Questionable.SetSequenceStopMode";
|
||||||
|
|
||||||
|
private const string IpcGetQuestStopMode = "Questionable.GetQuestStopMode";
|
||||||
|
|
||||||
|
private const string IpcSetQuestStopMode = "Questionable.SetQuestStopMode";
|
||||||
|
|
||||||
private const string IpcGetAlliedSocietyRemainingAllowances = "Questionable.AlliedSociety.GetRemainingAllowances";
|
private const string IpcGetAlliedSocietyRemainingAllowances = "Questionable.AlliedSociety.GetRemainingAllowances";
|
||||||
|
|
||||||
private const string IpcGetAlliedSocietyTimeUntilReset = "Questionable.AlliedSociety.GetTimeUntilReset";
|
private const string IpcGetAlliedSocietyTimeUntilReset = "Questionable.AlliedSociety.GetTimeUntilReset";
|
||||||
|
|
@ -163,6 +186,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
|
|
||||||
private const string IpcGetAlliedSocietyOptimalQuests = "Questionable.AlliedSociety.GetOptimalQuests";
|
private const string IpcGetAlliedSocietyOptimalQuests = "Questionable.AlliedSociety.GetOptimalQuests";
|
||||||
|
|
||||||
|
private const string IpcIsLevelingModeEnabled = "Questionable.IsLevelingModeEnabled";
|
||||||
|
|
||||||
|
private const string IpcSetLevelingModeEnabled = "Questionable.SetLevelingModeEnabled";
|
||||||
|
|
||||||
|
private const string IpcGetMsqLevelLockInfo = "Questionable.GetMsqLevelLockInfo";
|
||||||
|
|
||||||
|
private const string IpcStartLevelingMode = "Questionable.StartLevelingMode";
|
||||||
|
|
||||||
|
private const string IpcStopLevelingMode = "Questionable.StopLevelingMode";
|
||||||
|
|
||||||
private readonly QuestController _questController;
|
private readonly QuestController _questController;
|
||||||
|
|
||||||
private readonly QuestRegistry _questRegistry;
|
private readonly QuestRegistry _questRegistry;
|
||||||
|
|
@ -181,6 +214,8 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
private readonly AutoDutyIpc _autoDutyIpc;
|
||||||
|
|
||||||
private readonly ICallGateProvider<bool> _isRunning;
|
private readonly ICallGateProvider<bool> _isRunning;
|
||||||
|
|
||||||
private readonly ICallGateProvider<string?> _getCurrentQuestId;
|
private readonly ICallGateProvider<string?> _getCurrentQuestId;
|
||||||
|
|
@ -275,6 +310,18 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
|
|
||||||
private readonly ICallGateProvider<Dictionary<string, int>> _getAllQuestSequenceStopConditions;
|
private readonly ICallGateProvider<Dictionary<string, int>> _getAllQuestSequenceStopConditions;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<int> _getLevelStopMode;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<int, bool> _setLevelStopMode;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<int> _getSequenceStopMode;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<int, bool> _setSequenceStopMode;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<string, int> _getQuestStopMode;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<string, int, bool> _setQuestStopMode;
|
||||||
|
|
||||||
private readonly ICallGateProvider<int> _getAlliedSocietyRemainingAllowances;
|
private readonly ICallGateProvider<int> _getAlliedSocietyRemainingAllowances;
|
||||||
|
|
||||||
private readonly ICallGateProvider<long> _getAlliedSocietyTimeUntilReset;
|
private readonly ICallGateProvider<long> _getAlliedSocietyTimeUntilReset;
|
||||||
|
|
@ -293,7 +340,17 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
|
|
||||||
private readonly ICallGateProvider<byte, List<string>> _getAlliedSocietyOptimalQuests;
|
private readonly ICallGateProvider<byte, List<string>> _getAlliedSocietyOptimalQuests;
|
||||||
|
|
||||||
public QuestionableIpc(QuestController questController, EventInfoComponent eventInfoComponent, QuestRegistry questRegistry, QuestFunctions questFunctions, QuestData questData, ManualPriorityComponent manualPriorityComponent, PresetBuilderComponent presetBuilderComponent, Configuration configuration, IDalamudPluginInterface pluginInterface, IServiceProvider serviceProvider)
|
private readonly ICallGateProvider<bool> _isLevelingModeEnabled;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<bool, bool> _setLevelingModeEnabled;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<MsqLevelLockData?> _getMsqLevelLockInfo;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<bool> _startLevelingMode;
|
||||||
|
|
||||||
|
private readonly ICallGateProvider<bool> _stopLevelingMode;
|
||||||
|
|
||||||
|
public QuestionableIpc(QuestController questController, EventInfoComponent eventInfoComponent, QuestRegistry questRegistry, QuestFunctions questFunctions, QuestData questData, ManualPriorityComponent manualPriorityComponent, PresetBuilderComponent presetBuilderComponent, Configuration configuration, IDalamudPluginInterface pluginInterface, IServiceProvider serviceProvider, AutoDutyIpc autoDutyIpc)
|
||||||
{
|
{
|
||||||
QuestionableIpc questionableIpc = this;
|
QuestionableIpc questionableIpc = this;
|
||||||
_questController = questController;
|
_questController = questController;
|
||||||
|
|
@ -305,6 +362,7 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
|
_autoDutyIpc = autoDutyIpc;
|
||||||
_isRunning = pluginInterface.GetIpcProvider<bool>("Questionable.IsRunning");
|
_isRunning = pluginInterface.GetIpcProvider<bool>("Questionable.IsRunning");
|
||||||
_isRunning.RegisterFunc(() => questController.AutomationType != QuestController.EAutomationType.Manual || questController.IsRunning);
|
_isRunning.RegisterFunc(() => questController.AutomationType != QuestController.EAutomationType.Manual || questController.IsRunning);
|
||||||
_getCurrentQuestId = pluginInterface.GetIpcProvider<string>("Questionable.GetCurrentQuestId");
|
_getCurrentQuestId = pluginInterface.GetIpcProvider<string>("Questionable.GetCurrentQuestId");
|
||||||
|
|
@ -400,6 +458,62 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
_removeQuestSequenceStopCondition.RegisterFunc(RemoveQuestSequenceStopCondition);
|
_removeQuestSequenceStopCondition.RegisterFunc(RemoveQuestSequenceStopCondition);
|
||||||
_getAllQuestSequenceStopConditions = pluginInterface.GetIpcProvider<Dictionary<string, int>>("Questionable.GetAllQuestSequenceStopConditions");
|
_getAllQuestSequenceStopConditions = pluginInterface.GetIpcProvider<Dictionary<string, int>>("Questionable.GetAllQuestSequenceStopConditions");
|
||||||
_getAllQuestSequenceStopConditions.RegisterFunc(GetAllQuestSequenceStopConditions);
|
_getAllQuestSequenceStopConditions.RegisterFunc(GetAllQuestSequenceStopConditions);
|
||||||
|
_getLevelStopMode = pluginInterface.GetIpcProvider<int>("Questionable.GetLevelStopMode");
|
||||||
|
_getLevelStopMode.RegisterFunc(() => (int)questionableIpc._configuration.Stop.LevelStopMode);
|
||||||
|
_setLevelStopMode = pluginInterface.GetIpcProvider<int, bool>("Questionable.SetLevelStopMode");
|
||||||
|
_setLevelStopMode.RegisterFunc(delegate(int mode)
|
||||||
|
{
|
||||||
|
if (!Enum.IsDefined(typeof(Configuration.EStopConditionMode), mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
questionableIpc._configuration.Stop.LevelStopMode = (Configuration.EStopConditionMode)mode;
|
||||||
|
questionableIpc._pluginInterface.SavePluginConfig(questionableIpc._configuration);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
_getSequenceStopMode = pluginInterface.GetIpcProvider<int>("Questionable.GetSequenceStopMode");
|
||||||
|
_getSequenceStopMode.RegisterFunc(() => (int)questionableIpc._configuration.Stop.SequenceStopMode);
|
||||||
|
_setSequenceStopMode = pluginInterface.GetIpcProvider<int, bool>("Questionable.SetSequenceStopMode");
|
||||||
|
_setSequenceStopMode.RegisterFunc(delegate(int mode)
|
||||||
|
{
|
||||||
|
if (!Enum.IsDefined(typeof(Configuration.EStopConditionMode), mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
questionableIpc._configuration.Stop.SequenceStopMode = (Configuration.EStopConditionMode)mode;
|
||||||
|
questionableIpc._pluginInterface.SavePluginConfig(questionableIpc._configuration);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
_getQuestStopMode = pluginInterface.GetIpcProvider<string, int>("Questionable.GetQuestStopMode");
|
||||||
|
_getQuestStopMode.RegisterFunc((string questId) => (int)(questionableIpc._configuration.Stop.QuestStopModes.TryGetValue(questId, out var value) ? value : ((Configuration.EStopConditionMode)(-1))));
|
||||||
|
_setQuestStopMode = pluginInterface.GetIpcProvider<string, int, bool>("Questionable.SetQuestStopMode");
|
||||||
|
_setQuestStopMode.RegisterFunc(delegate(string questId, int mode)
|
||||||
|
{
|
||||||
|
if (!Enum.IsDefined(typeof(Configuration.EStopConditionMode), mode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ElementId.TryFromString(questId, out ElementId elementId) && elementId != null && questionableIpc._questRegistry.IsKnownQuest(elementId))
|
||||||
|
{
|
||||||
|
if (mode == 0)
|
||||||
|
{
|
||||||
|
questionableIpc._configuration.Stop.QuestsToStopAfter.Remove(elementId);
|
||||||
|
questionableIpc._configuration.Stop.QuestStopModes.Remove(questId);
|
||||||
|
questionableIpc._configuration.Stop.QuestSequences.Remove(questId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!questionableIpc._configuration.Stop.QuestsToStopAfter.Contains(elementId))
|
||||||
|
{
|
||||||
|
questionableIpc._configuration.Stop.QuestsToStopAfter.Add(elementId);
|
||||||
|
}
|
||||||
|
questionableIpc._configuration.Stop.QuestStopModes[questId] = (Configuration.EStopConditionMode)mode;
|
||||||
|
}
|
||||||
|
questionableIpc._pluginInterface.SavePluginConfig(questionableIpc._configuration);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
_getAlliedSocietyRemainingAllowances = pluginInterface.GetIpcProvider<int>("Questionable.AlliedSociety.GetRemainingAllowances");
|
_getAlliedSocietyRemainingAllowances = pluginInterface.GetIpcProvider<int>("Questionable.AlliedSociety.GetRemainingAllowances");
|
||||||
_getAlliedSocietyRemainingAllowances.RegisterFunc(GetAlliedSocietyRemainingAllowances);
|
_getAlliedSocietyRemainingAllowances.RegisterFunc(GetAlliedSocietyRemainingAllowances);
|
||||||
_getAlliedSocietyTimeUntilReset = pluginInterface.GetIpcProvider<long>("Questionable.AlliedSociety.GetTimeUntilReset");
|
_getAlliedSocietyTimeUntilReset = pluginInterface.GetIpcProvider<long>("Questionable.AlliedSociety.GetTimeUntilReset");
|
||||||
|
|
@ -418,6 +532,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
_addAlliedSocietyOptimalQuests.RegisterFunc(AddAlliedSocietyOptimalQuests);
|
_addAlliedSocietyOptimalQuests.RegisterFunc(AddAlliedSocietyOptimalQuests);
|
||||||
_getAlliedSocietyOptimalQuests = pluginInterface.GetIpcProvider<byte, List<string>>("Questionable.AlliedSociety.GetOptimalQuests");
|
_getAlliedSocietyOptimalQuests = pluginInterface.GetIpcProvider<byte, List<string>>("Questionable.AlliedSociety.GetOptimalQuests");
|
||||||
_getAlliedSocietyOptimalQuests.RegisterFunc(GetAlliedSocietyOptimalQuests);
|
_getAlliedSocietyOptimalQuests.RegisterFunc(GetAlliedSocietyOptimalQuests);
|
||||||
|
_isLevelingModeEnabled = pluginInterface.GetIpcProvider<bool>("Questionable.IsLevelingModeEnabled");
|
||||||
|
_isLevelingModeEnabled.RegisterFunc(IsLevelingModeEnabled);
|
||||||
|
_setLevelingModeEnabled = pluginInterface.GetIpcProvider<bool, bool>("Questionable.SetLevelingModeEnabled");
|
||||||
|
_setLevelingModeEnabled.RegisterFunc(SetLevelingModeEnabled);
|
||||||
|
_getMsqLevelLockInfo = pluginInterface.GetIpcProvider<MsqLevelLockData>("Questionable.GetMsqLevelLockInfo");
|
||||||
|
_getMsqLevelLockInfo.RegisterFunc(GetMsqLevelLockInfo);
|
||||||
|
_startLevelingMode = pluginInterface.GetIpcProvider<bool>("Questionable.StartLevelingMode");
|
||||||
|
_startLevelingMode.RegisterFunc(StartLevelingMode);
|
||||||
|
_stopLevelingMode = pluginInterface.GetIpcProvider<bool>("Questionable.StopLevelingMode");
|
||||||
|
_stopLevelingMode.RegisterFunc(StopLevelingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool StartQuest(string questId, bool single)
|
private bool StartQuest(string questId, bool single)
|
||||||
|
|
@ -969,7 +1093,7 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
{
|
{
|
||||||
return new StopConditionData
|
return new StopConditionData
|
||||||
{
|
{
|
||||||
Enabled = _configuration.Stop.LevelToStopAfter,
|
Enabled = (_configuration.Stop.LevelStopMode != Configuration.EStopConditionMode.Off),
|
||||||
TargetValue = _configuration.Stop.TargetLevel
|
TargetValue = _configuration.Stop.TargetLevel
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -980,7 +1104,7 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_configuration.Stop.LevelToStopAfter = enabled;
|
_configuration.Stop.LevelStopMode = (enabled ? Configuration.EStopConditionMode.Pause : Configuration.EStopConditionMode.Off);
|
||||||
_configuration.Stop.TargetLevel = targetLevel;
|
_configuration.Stop.TargetLevel = targetLevel;
|
||||||
_pluginInterface.SavePluginConfig(_configuration);
|
_pluginInterface.SavePluginConfig(_configuration);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -990,7 +1114,7 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
{
|
{
|
||||||
return new StopConditionData
|
return new StopConditionData
|
||||||
{
|
{
|
||||||
Enabled = _configuration.Stop.SequenceToStopAfter,
|
Enabled = (_configuration.Stop.SequenceStopMode != Configuration.EStopConditionMode.Off),
|
||||||
TargetValue = _configuration.Stop.TargetSequence
|
TargetValue = _configuration.Stop.TargetSequence
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1001,7 +1125,7 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_configuration.Stop.SequenceToStopAfter = enabled;
|
_configuration.Stop.SequenceStopMode = (enabled ? Configuration.EStopConditionMode.Pause : Configuration.EStopConditionMode.Off);
|
||||||
_configuration.Stop.TargetSequence = targetSequence;
|
_configuration.Stop.TargetSequence = targetSequence;
|
||||||
_pluginInterface.SavePluginConfig(_configuration);
|
_pluginInterface.SavePluginConfig(_configuration);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1213,6 +1337,56 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
select q.QuestId.ToString()).ToList();
|
select q.QuestId.ToString()).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsLevelingModeEnabled()
|
||||||
|
{
|
||||||
|
return _configuration.Duties.RunLevelingModeWhenUnderleveled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SetLevelingModeEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
_configuration.Duties.RunLevelingModeWhenUnderleveled = enabled;
|
||||||
|
_pluginInterface.SavePluginConfig(_configuration);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MsqLevelLockData? GetMsqLevelLockInfo()
|
||||||
|
{
|
||||||
|
var (flag, levelsNeeded, requiredLevel, questName) = _questFunctions.GetMsqLevelLockInfo();
|
||||||
|
if (!flag)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new MsqLevelLockData
|
||||||
|
{
|
||||||
|
IsLevelLocked = flag,
|
||||||
|
LevelsNeeded = levelsNeeded,
|
||||||
|
RequiredLevel = requiredLevel,
|
||||||
|
QuestName = questName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool StartLevelingMode()
|
||||||
|
{
|
||||||
|
if (!_autoDutyIpc.IsConfiguredToRunLevelingMode())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _autoDutyIpc.StartLevelingMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool StopLevelingMode()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_autoDutyIpc.Stop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_exportQuestPriority.UnregisterFunc();
|
_exportQuestPriority.UnregisterFunc();
|
||||||
|
|
@ -1262,6 +1436,12 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
_getStopQuestList.UnregisterFunc();
|
_getStopQuestList.UnregisterFunc();
|
||||||
_setStopConditionsEnabled.UnregisterFunc();
|
_setStopConditionsEnabled.UnregisterFunc();
|
||||||
_getStopConditionsEnabled.UnregisterFunc();
|
_getStopConditionsEnabled.UnregisterFunc();
|
||||||
|
_setQuestStopMode.UnregisterFunc();
|
||||||
|
_getQuestStopMode.UnregisterFunc();
|
||||||
|
_setSequenceStopMode.UnregisterFunc();
|
||||||
|
_getSequenceStopMode.UnregisterFunc();
|
||||||
|
_setLevelStopMode.UnregisterFunc();
|
||||||
|
_getLevelStopMode.UnregisterFunc();
|
||||||
_getAlliedSocietiesWithAvailableQuests.UnregisterFunc();
|
_getAlliedSocietiesWithAvailableQuests.UnregisterFunc();
|
||||||
_getAlliedSocietyCurrentRank.UnregisterFunc();
|
_getAlliedSocietyCurrentRank.UnregisterFunc();
|
||||||
_getAlliedSocietyIsMaxRank.UnregisterFunc();
|
_getAlliedSocietyIsMaxRank.UnregisterFunc();
|
||||||
|
|
@ -1271,5 +1451,10 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
_getAlliedSocietyRemainingAllowances.UnregisterFunc();
|
_getAlliedSocietyRemainingAllowances.UnregisterFunc();
|
||||||
_addAlliedSocietyOptimalQuests.UnregisterFunc();
|
_addAlliedSocietyOptimalQuests.UnregisterFunc();
|
||||||
_getAlliedSocietyOptimalQuests.UnregisterFunc();
|
_getAlliedSocietyOptimalQuests.UnregisterFunc();
|
||||||
|
_stopLevelingMode.UnregisterFunc();
|
||||||
|
_startLevelingMode.UnregisterFunc();
|
||||||
|
_getMsqLevelLockInfo.UnregisterFunc();
|
||||||
|
_setLevelingModeEnabled.UnregisterFunc();
|
||||||
|
_isLevelingModeEnabled.UnregisterFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,10 @@ internal sealed class QuestFunctions
|
||||||
|
|
||||||
private ElementId? _lastLoggedAcceptedHiddenMsq;
|
private ElementId? _lastLoggedAcceptedHiddenMsq;
|
||||||
|
|
||||||
|
private bool _loggedNoClassQuestsAvailable;
|
||||||
|
|
||||||
|
private bool _loggedAdventurerClass;
|
||||||
|
|
||||||
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, JournalData journalData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, AetheryteData aetheryteData, Configuration configuration, IDataManager dataManager, IObjectTable objectTable, IClientState clientState, IGameGui gameGui, IAetheryteList aetheryteList, ILogger<QuestFunctions> logger)
|
public QuestFunctions(QuestRegistry questRegistry, QuestData questData, JournalData journalData, AetheryteFunctions aetheryteFunctions, AlliedSocietyQuestFunctions alliedSocietyQuestFunctions, AlliedSocietyData alliedSocietyData, AetheryteData aetheryteData, Configuration configuration, IDataManager dataManager, IObjectTable objectTable, IClientState clientState, IGameGui gameGui, IAetheryteList aetheryteList, ILogger<QuestFunctions> logger)
|
||||||
{
|
{
|
||||||
_questRegistry = questRegistry;
|
_questRegistry = questRegistry;
|
||||||
|
|
@ -195,6 +199,8 @@ internal sealed class QuestFunctions
|
||||||
{
|
{
|
||||||
_logger.LogInformation("MSQ {MsqId} requires level {RequiredLevel}, current level {CurrentLevel}. Checking for early class quests to level up.", questReference.CurrentQuest, quest.Info.Level, currentLevel);
|
_logger.LogInformation("MSQ {MsqId} requires level {RequiredLevel}, current level {CurrentLevel}. Checking for early class quests to level up.", questReference.CurrentQuest, quest.Info.Level, currentLevel);
|
||||||
_lastLoggedLevelLockedMsq = questReference.CurrentQuest;
|
_lastLoggedLevelLockedMsq = questReference.CurrentQuest;
|
||||||
|
_loggedNoClassQuestsAvailable = false;
|
||||||
|
_loggedAdventurerClass = false;
|
||||||
}
|
}
|
||||||
if (valueOrDefault != EClassJob.Adventurer)
|
if (valueOrDefault != EClassJob.Adventurer)
|
||||||
{
|
{
|
||||||
|
|
@ -222,10 +228,10 @@ internal sealed class QuestFunctions
|
||||||
return new QuestReference(questId2, QuestManager.GetQuestSequence(questId2.Value), questReference.State);
|
return new QuestReference(questId2, QuestManager.GetQuestSequence(questId2.Value), questReference.State);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_lastLoggedLevelLockedMsq == questReference.CurrentQuest && _lastLoggedForcedClassQuest == null)
|
else if (!_loggedNoClassQuestsAvailable)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No class quests passed the filter for {ClassJob} at level {CurrentLevel}", valueOrDefault, currentLevel);
|
_logger.LogWarning("No class quests passed the filter for {ClassJob} at level {CurrentLevel}", valueOrDefault, currentLevel);
|
||||||
_lastLoggedLevelLockedMsq = null;
|
_loggedNoClassQuestsAvailable = true;
|
||||||
}
|
}
|
||||||
List<QuestInfo> list2 = (from x in _questRegistry.GetKnownClassJobQuests(valueOrDefault, includeRoleQuests: false)
|
List<QuestInfo> list2 = (from x in _questRegistry.GetKnownClassJobQuests(valueOrDefault, includeRoleQuests: false)
|
||||||
where x.Level <= currentLevel && x.Level <= 5 && !IsQuestAcceptedOrComplete(x.QuestId) && IsReadyToAcceptQuest(x.QuestId)
|
where x.Level <= currentLevel && x.Level <= 5 && !IsQuestAcceptedOrComplete(x.QuestId) && IsReadyToAcceptQuest(x.QuestId)
|
||||||
|
|
@ -237,11 +243,16 @@ internal sealed class QuestFunctions
|
||||||
_logger.LogInformation("MSQ level locked. Prioritizing class quest {ClassQuestId} for {ClassJob} (level {QuestLevel}) from registry", questId3, valueOrDefault, list2.First().Level);
|
_logger.LogInformation("MSQ level locked. Prioritizing class quest {ClassQuestId} for {ClassJob} (level {QuestLevel}) from registry", questId3, valueOrDefault, list2.First().Level);
|
||||||
return new QuestReference(questId3, QuestManager.GetQuestSequence(questId3.Value), questReference.State);
|
return new QuestReference(questId3, QuestManager.GetQuestSequence(questId3.Value), questReference.State);
|
||||||
}
|
}
|
||||||
|
if (!_loggedNoClassQuestsAvailable)
|
||||||
|
{
|
||||||
_logger.LogWarning("MSQ level locked but no available early class quests found for {ClassJob} at level {CurrentLevel}", valueOrDefault, currentLevel);
|
_logger.LogWarning("MSQ level locked but no available early class quests found for {ClassJob} at level {CurrentLevel}", valueOrDefault, currentLevel);
|
||||||
|
_loggedNoClassQuestsAvailable = true;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else if (!_loggedAdventurerClass)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Current class is Adventurer, cannot find class quests");
|
_logger.LogWarning("Current class is Adventurer, cannot find class quests");
|
||||||
|
_loggedAdventurerClass = true;
|
||||||
}
|
}
|
||||||
Questionable.Model.Quest quest2;
|
Questionable.Model.Quest quest2;
|
||||||
ElementId elementId = (from x in GetNextPriorityQuestsThatCanBeAccepted()
|
ElementId elementId = (from x in GetNextPriorityQuestsThatCanBeAccepted()
|
||||||
|
|
@ -253,11 +264,17 @@ internal sealed class QuestFunctions
|
||||||
_logger.LogInformation("MSQ {MsqId} requires level {RequiredLevel}, current level {CurrentLevel}. Prioritizing early class quest {ClassQuestId} (from priority list)", questReference.CurrentQuest, quest.Info.Level, currentLevel, elementId);
|
_logger.LogInformation("MSQ {MsqId} requires level {RequiredLevel}, current level {CurrentLevel}. Prioritizing early class quest {ClassQuestId} (from priority list)", questReference.CurrentQuest, quest.Info.Level, currentLevel, elementId);
|
||||||
return new QuestReference(elementId, QuestManager.GetQuestSequence(elementId.Value), questReference.State);
|
return new QuestReference(elementId, QuestManager.GetQuestSequence(elementId.Value), questReference.State);
|
||||||
}
|
}
|
||||||
|
if (!_loggedNoClassQuestsAvailable)
|
||||||
|
{
|
||||||
_logger.LogWarning("MSQ {MsqId} is level locked (requires {RequiredLevel}, current {CurrentLevel}) and no early class quests available. Cannot proceed.", questReference.CurrentQuest, quest.Info.Level, currentLevel);
|
_logger.LogWarning("MSQ {MsqId} is level locked (requires {RequiredLevel}, current {CurrentLevel}) and no early class quests available. Cannot proceed.", questReference.CurrentQuest, quest.Info.Level, currentLevel);
|
||||||
|
_loggedNoClassQuestsAvailable = true;
|
||||||
|
}
|
||||||
return QuestReference.NoQuest(MainScenarioQuestState.Unavailable);
|
return QuestReference.NoQuest(MainScenarioQuestState.Unavailable);
|
||||||
}
|
}
|
||||||
_lastLoggedLevelLockedMsq = null;
|
_lastLoggedLevelLockedMsq = null;
|
||||||
_lastLoggedForcedClassQuest = null;
|
_lastLoggedForcedClassQuest = null;
|
||||||
|
_loggedNoClassQuestsAvailable = false;
|
||||||
|
_loggedAdventurerClass = false;
|
||||||
}
|
}
|
||||||
if (questReference.CurrentQuest != null && !IsQuestAccepted(questReference.CurrentQuest))
|
if (questReference.CurrentQuest != null && !IsQuestAccepted(questReference.CurrentQuest))
|
||||||
{
|
{
|
||||||
|
|
@ -931,7 +948,7 @@ internal sealed class QuestFunctions
|
||||||
|
|
||||||
private static bool IsQuestLocked(UnlockLinkId unlockLinkId)
|
private static bool IsQuestLocked(UnlockLinkId unlockLinkId)
|
||||||
{
|
{
|
||||||
return IsQuestUnobtainable(unlockLinkId);
|
return IsQuestUnobtainableStatic(unlockLinkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsQuestLocked(AethernetId aethernetId)
|
private bool IsQuestLocked(AethernetId aethernetId)
|
||||||
|
|
@ -995,11 +1012,24 @@ internal sealed class QuestFunctions
|
||||||
}
|
}
|
||||||
if (elementId is UnlockLinkId unlockLinkId)
|
if (elementId is UnlockLinkId unlockLinkId)
|
||||||
{
|
{
|
||||||
return IsQuestUnobtainable(unlockLinkId);
|
return IsQuestUnobtainableStatic(unlockLinkId);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsQuestUnobtainableStatic(UnlockLinkId unlockLinkId)
|
||||||
|
{
|
||||||
|
if (unlockLinkId.Value == 506)
|
||||||
|
{
|
||||||
|
return !IsFestivalActive(160, (ushort)2);
|
||||||
|
}
|
||||||
|
if (unlockLinkId.Value == 568)
|
||||||
|
{
|
||||||
|
return !IsFestivalActive(160, (ushort)3);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe bool IsQuestUnobtainable(QuestId questId, ElementId? extraCompletedQuest = null)
|
public unsafe bool IsQuestUnobtainable(QuestId questId, ElementId? extraCompletedQuest = null)
|
||||||
{
|
{
|
||||||
IQuestInfo questInfo = _questData.GetQuestInfo(questId);
|
IQuestInfo questInfo = _questData.GetQuestInfo(questId);
|
||||||
|
|
@ -1024,10 +1054,6 @@ internal sealed class QuestFunctions
|
||||||
}
|
}
|
||||||
if (DateTime.UtcNow > dateTime)
|
if (DateTime.UtcNow > dateTime)
|
||||||
{
|
{
|
||||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("UnlockLink quest {QuestId} unobtainable: expiry {ExpiryUtc} (UTC) is before now {NowUtc}", questId, dateTime.ToString("o"), DateTime.UtcNow.ToString("o"));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1043,7 +1069,7 @@ internal sealed class QuestFunctions
|
||||||
List<QuestSequence> list = quest?.Root?.QuestSequence;
|
List<QuestSequence> list = quest?.Root?.QuestSequence;
|
||||||
if (list != null && list.Count > 0)
|
if (list != null && list.Count > 0)
|
||||||
{
|
{
|
||||||
goto IL_027a;
|
goto IL_0228;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
||||||
|
|
@ -1053,8 +1079,8 @@ internal sealed class QuestFunctions
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
goto IL_027a;
|
goto IL_0228;
|
||||||
IL_027a:
|
IL_0228:
|
||||||
if (questInfo2.QuestLocks.Count > 0)
|
if (questInfo2.QuestLocks.Count > 0)
|
||||||
{
|
{
|
||||||
int num = questInfo2.QuestLocks.Count((QuestId x) => IsQuestComplete(x) || x.Equals(extraCompletedQuest));
|
int num = questInfo2.QuestLocks.Count((QuestId x) => IsQuestComplete(x) || x.Equals(extraCompletedQuest));
|
||||||
|
|
@ -1073,42 +1099,16 @@ internal sealed class QuestFunctions
|
||||||
DateTime valueOrDefault = seasonalQuestExpiry.GetValueOrDefault();
|
DateTime valueOrDefault = seasonalQuestExpiry.GetValueOrDefault();
|
||||||
TimeSpan timeOfDay2 = valueOrDefault.TimeOfDay;
|
TimeSpan timeOfDay2 = valueOrDefault.TimeOfDay;
|
||||||
TimeSpan timeSpan2 = new TimeSpan(23, 59, 59);
|
TimeSpan timeSpan2 = new TimeSpan(23, 59, 59);
|
||||||
bool flag2 = false;
|
DateTime dateTime2 = ((!(timeOfDay2 == TimeSpan.Zero) && !(timeOfDay2 == timeSpan2)) ? ((valueOrDefault.Kind == DateTimeKind.Utc) ? valueOrDefault : valueOrDefault.ToUniversalTime()) : EventInfoComponent.AtDailyReset(DateOnly.FromDateTime(valueOrDefault)));
|
||||||
DateTime dateTime2;
|
|
||||||
if (timeOfDay2 == TimeSpan.Zero || timeOfDay2 == timeSpan2)
|
|
||||||
{
|
|
||||||
dateTime2 = EventInfoComponent.AtDailyReset(DateOnly.FromDateTime(valueOrDefault));
|
|
||||||
flag2 = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dateTime2 = ((valueOrDefault.Kind == DateTimeKind.Utc) ? valueOrDefault : valueOrDefault.ToUniversalTime());
|
|
||||||
}
|
|
||||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Quest {QuestId} seasonal expiry raw={ExpiryRaw} Kind={Kind} TimeOfDay={TimeOfDay} treatedAsDailyReset={TreatedAsDailyReset}", questId, valueOrDefault.ToString("o"), valueOrDefault.Kind, valueOrDefault.TimeOfDay, flag2);
|
|
||||||
_logger.LogDebug("Quest {QuestId} expiry check: nowUtc={Now:o}, expiryUtc={Expiry:o}, expired={Expired}", questId, DateTime.UtcNow, dateTime2, DateTime.UtcNow > dateTime2);
|
|
||||||
}
|
|
||||||
if (DateTime.UtcNow > dateTime2)
|
if (DateTime.UtcNow > dateTime2)
|
||||||
{
|
{
|
||||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Quest {QuestId} unobtainable: seasonal expiry {ExpiryUtc} (UTC) is before now {NowUtc}", questId, dateTime2.ToString("o"), DateTime.UtcNow.ToString("o"));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((questInfo2.IsSeasonalEvent || questInfo2.IsSeasonalQuest) && !(questInfo2.SeasonalQuestExpiry is DateTime))
|
if ((questInfo2.IsSeasonalEvent || questInfo2.IsSeasonalQuest) && !questInfo2.SeasonalQuestExpiry.HasValue && !_configuration.General.ShowIncompleteSeasonalEvents)
|
||||||
{
|
|
||||||
if (_alreadyLoggedUnobtainableQuestsDetailed.Add(questId.Value))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Quest {QuestId} is seasonal/event with no expiry; ShowIncompleteSeasonalEvents={ShowIncomplete}", questId, _configuration.General.ShowIncompleteSeasonalEvents);
|
|
||||||
}
|
|
||||||
if (!_configuration.General.ShowIncompleteSeasonalEvents)
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (_questData.GetLockedClassQuests().Contains(questId))
|
if (_questData.GetLockedClassQuests().Contains(questId))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1172,19 +1172,6 @@ internal sealed class QuestFunctions
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsQuestUnobtainable(UnlockLinkId unlockLinkId)
|
|
||||||
{
|
|
||||||
if (unlockLinkId.Value == 506)
|
|
||||||
{
|
|
||||||
return !IsFestivalActive(160, (ushort)2);
|
|
||||||
}
|
|
||||||
if (unlockLinkId.Value == 568)
|
|
||||||
{
|
|
||||||
return !IsFestivalActive(160, (ushort)3);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe static bool IsFestivalActive(ushort id, ushort? phase = null)
|
private unsafe static bool IsFestivalActive(ushort id, ushort? phase = null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < GameMain.Instance()->ActiveFestivals.Length; i++)
|
for (int i = 0; i < GameMain.Instance()->ActiveFestivals.Length; i++)
|
||||||
|
|
@ -1310,4 +1297,43 @@ internal sealed class QuestFunctions
|
||||||
{
|
{
|
||||||
return IsQuestComplete(_questData.LastMainScenarioQuestId);
|
return IsQuestComplete(_questData.LastMainScenarioQuestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public (bool isLevelLocked, int levelsNeeded, int requiredLevel, string? questName) GetMsqLevelLockInfo()
|
||||||
|
{
|
||||||
|
byte b = _objectTable.LocalPlayer?.Level ?? 0;
|
||||||
|
if (b == 0)
|
||||||
|
{
|
||||||
|
return (isLevelLocked: false, levelsNeeded: 0, requiredLevel: 0, questName: null);
|
||||||
|
}
|
||||||
|
QuestReference item = GetMainScenarioQuest().Item1;
|
||||||
|
if (item.CurrentQuest == null)
|
||||||
|
{
|
||||||
|
return (isLevelLocked: false, levelsNeeded: 0, requiredLevel: 0, questName: null);
|
||||||
|
}
|
||||||
|
if (IsQuestAccepted(item.CurrentQuest))
|
||||||
|
{
|
||||||
|
return (isLevelLocked: false, levelsNeeded: 0, requiredLevel: 0, questName: null);
|
||||||
|
}
|
||||||
|
if (_questRegistry.TryGetQuest(item.CurrentQuest, out Questionable.Model.Quest quest))
|
||||||
|
{
|
||||||
|
int level = quest.Info.Level;
|
||||||
|
if (level <= b)
|
||||||
|
{
|
||||||
|
return (isLevelLocked: false, levelsNeeded: 0, requiredLevel: level, questName: null);
|
||||||
|
}
|
||||||
|
int item2 = level - b;
|
||||||
|
return (isLevelLocked: true, levelsNeeded: item2, requiredLevel: level, questName: quest.Info.Name);
|
||||||
|
}
|
||||||
|
if (item.CurrentQuest is QuestId elementId && _questData.TryGetQuestInfo(elementId, out IQuestInfo questInfo) && questInfo is QuestInfo questInfo2)
|
||||||
|
{
|
||||||
|
int level2 = questInfo2.Level;
|
||||||
|
if (level2 <= b)
|
||||||
|
{
|
||||||
|
return (isLevelLocked: false, levelsNeeded: 0, requiredLevel: level2, questName: null);
|
||||||
|
}
|
||||||
|
int item3 = level2 - b;
|
||||||
|
return (isLevelLocked: true, levelsNeeded: item3, requiredLevel: level2, questName: questInfo2.Name);
|
||||||
|
}
|
||||||
|
return (isLevelLocked: false, levelsNeeded: 0, requiredLevel: 0, questName: null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ internal sealed class QuestValidator
|
||||||
AlliedSociety = x.Key,
|
AlliedSociety = x.Key,
|
||||||
Type = EIssueType.QuestDisabled,
|
Type = EIssueType.QuestDisabled,
|
||||||
Severity = EIssueSeverity.None,
|
Severity = EIssueSeverity.None,
|
||||||
Description = $"{x.Value.Count} disabled quest(s): {value}"
|
Description = $"{x.Value.Count} disabled {((x.Value.Count == 1) ? "quest" : "quests")}: {value}"
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,29 +39,27 @@ internal sealed class DutyConfigComponent : ConfigComponent
|
||||||
|
|
||||||
private readonly Dictionary<EExpansionVersion, List<DutyInfo>> _allTrialNames;
|
private readonly Dictionary<EExpansionVersion, List<DutyInfo>> _allTrialNames;
|
||||||
|
|
||||||
|
private readonly Dictionary<EExpansionVersion, List<DutyInfo>> _allNormalRaidNames;
|
||||||
|
|
||||||
|
private readonly Dictionary<EExpansionVersion, List<DutyInfo>> _allAllianceRaidNames;
|
||||||
|
|
||||||
public DutyConfigComponent(IDalamudPluginInterface pluginInterface, Configuration configuration, IDataManager dataManager, QuestRegistry questRegistry, AutoDutyIpc autoDutyIpc, TerritoryData territoryData)
|
public DutyConfigComponent(IDalamudPluginInterface pluginInterface, Configuration configuration, IDataManager dataManager, QuestRegistry questRegistry, AutoDutyIpc autoDutyIpc, TerritoryData territoryData)
|
||||||
: base(pluginInterface, configuration)
|
: base(pluginInterface, configuration)
|
||||||
{
|
{
|
||||||
_questRegistry = questRegistry;
|
_questRegistry = questRegistry;
|
||||||
_autoDutyIpc = autoDutyIpc;
|
_autoDutyIpc = autoDutyIpc;
|
||||||
var source = (from x in dataManager.GetExcelSheet<DawnContent>()
|
_contentFinderConditionNames = (from x in dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||||
where x.RowId != 0 && !x.Unknown16
|
where x.RowId != 0 && x.Content.RowId != 0 && x.ContentType.RowId == 2
|
||||||
orderby x.Unknown15
|
|
||||||
select x.Content.ValueNullable into x
|
|
||||||
where x.HasValue
|
|
||||||
select x.Value into x
|
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
Expansion = (EExpansionVersion)x.TerritoryType.Value.ExVersion.RowId,
|
Expansion = (EExpansionVersion)x.TerritoryType.Value.ExVersion.RowId,
|
||||||
CfcId = x.RowId,
|
CfcId = x.RowId,
|
||||||
Name = (territoryData.GetContentFinderCondition(x.RowId)?.Name ?? "?"),
|
Name = (territoryData.GetContentFinderCondition(x.RowId)?.Name ?? x.Name.ToDalamudString().ToString()),
|
||||||
TerritoryId = x.TerritoryType.RowId,
|
TerritoryId = x.TerritoryType.RowId,
|
||||||
ContentType = x.ContentType.RowId,
|
|
||||||
Level = x.ClassJobLevelRequired,
|
Level = x.ClassJobLevelRequired,
|
||||||
SortKey = x.SortKey
|
SortKey = x.SortKey
|
||||||
}).ToList();
|
} into x
|
||||||
_contentFinderConditionNames = (from x in source
|
orderby x.SortKey
|
||||||
where x.ContentType == 2
|
|
||||||
group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList());
|
group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList());
|
||||||
_allTrialNames = (from x in dataManager.GetExcelSheet<ContentFinderCondition>()
|
_allTrialNames = (from x in dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||||
where x.RowId != 0 && x.Content.RowId != 0 && x.ContentType.RowId == 4
|
where x.RowId != 0 && x.Content.RowId != 0 && x.ContentType.RowId == 4
|
||||||
|
|
@ -76,6 +74,34 @@ internal sealed class DutyConfigComponent : ConfigComponent
|
||||||
} into x
|
} into x
|
||||||
orderby x.SortKey
|
orderby x.SortKey
|
||||||
group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList());
|
group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList());
|
||||||
|
_allNormalRaidNames = (from x in dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||||
|
where x.RowId != 0 && x.Content.RowId != 0 && x.ContentType.RowId == 5
|
||||||
|
where x.ContentMemberType.RowId == 3
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
Expansion = (EExpansionVersion)x.TerritoryType.Value.ExVersion.RowId,
|
||||||
|
CfcId = x.RowId,
|
||||||
|
Name = (territoryData.GetContentFinderCondition(x.RowId)?.Name ?? x.Name.ToDalamudString().ToString()),
|
||||||
|
TerritoryId = x.TerritoryType.RowId,
|
||||||
|
Level = x.ClassJobLevelRequired,
|
||||||
|
SortKey = x.SortKey
|
||||||
|
} into x
|
||||||
|
orderby x.SortKey
|
||||||
|
group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList());
|
||||||
|
_allAllianceRaidNames = (from x in dataManager.GetExcelSheet<ContentFinderCondition>()
|
||||||
|
where x.RowId != 0 && x.Content.RowId != 0 && x.ContentType.RowId == 5
|
||||||
|
where x.ContentMemberType.RowId == 4
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
Expansion = (EExpansionVersion)x.TerritoryType.Value.ExVersion.RowId,
|
||||||
|
CfcId = x.RowId,
|
||||||
|
Name = (territoryData.GetContentFinderCondition(x.RowId)?.Name ?? x.Name.ToDalamudString().ToString()),
|
||||||
|
TerritoryId = x.TerritoryType.RowId,
|
||||||
|
Level = x.ClassJobLevelRequired,
|
||||||
|
SortKey = x.SortKey
|
||||||
|
} into x
|
||||||
|
orderby x.SortKey
|
||||||
|
group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawTab()
|
public override void DrawTab()
|
||||||
|
|
@ -106,6 +132,15 @@ internal sealed class DutyConfigComponent : ConfigComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
|
bool v2 = base.Configuration.Duties.RunLevelingModeWhenUnderleveled;
|
||||||
|
if (ImGui.Checkbox("Run AutoDuty Leveling mode when underleveled for MSQ", ref v2))
|
||||||
|
{
|
||||||
|
base.Configuration.Duties.RunLevelingModeWhenUnderleveled = v2;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGuiComponents.HelpMarker("When enabled, Questionable will automatically run AutoDuty's Leveling mode when your character is underleveled for the next Main Scenario Quest.\n\nLeveling mode runs the highest available dungeon for your level to gain XP.\n\nThis is useful for characters without the Road to 90 XP buff who may not have enough XP to continue the MSQ.");
|
||||||
|
ImGui.Spacing();
|
||||||
ImGui.Text("Default duty mode:");
|
ImGui.Text("Default duty mode:");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
int currentItem = (int)base.Configuration.Duties.DefaultDutyMode;
|
int currentItem = (int)base.Configuration.Duties.DefaultDutyMode;
|
||||||
|
|
@ -128,7 +163,7 @@ internal sealed class DutyConfigComponent : ConfigComponent
|
||||||
Util.OpenLink("https://docs.google.com/spreadsheets/d/151RlpqRcCpiD_VbQn6Duf-u-S71EP7d0mx3j1PDNoNA/edit?pli=1#gid=0");
|
Util.OpenLink("https://docs.google.com/spreadsheets/d/151RlpqRcCpiD_VbQn6Duf-u-S71EP7d0mx3j1PDNoNA/edit?pli=1#gid=0");
|
||||||
}
|
}
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.Text("You can override the settings for each individual dungeon/trial:");
|
ImGui.Text("You can override the settings for each individual duty:");
|
||||||
using ImRaii.IEndObject endObject2 = ImRaii.TabBar("DutyTypeTabs");
|
using ImRaii.IEndObject endObject2 = ImRaii.TabBar("DutyTypeTabs");
|
||||||
if (endObject2)
|
if (endObject2)
|
||||||
{
|
{
|
||||||
|
|
@ -139,12 +174,26 @@ internal sealed class DutyConfigComponent : ConfigComponent
|
||||||
DrawConfigTable(v, _contentFinderConditionNames);
|
DrawConfigTable(v, _contentFinderConditionNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using ImRaii.IEndObject endObject4 = ImRaii.TabItem("Trials");
|
using (ImRaii.IEndObject endObject4 = ImRaii.TabItem("Trials"))
|
||||||
|
{
|
||||||
if (endObject4)
|
if (endObject4)
|
||||||
{
|
{
|
||||||
DrawConfigTable(v, _allTrialNames);
|
DrawConfigTable(v, _allTrialNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
using (ImRaii.IEndObject endObject5 = ImRaii.TabItem("Normal Raids"))
|
||||||
|
{
|
||||||
|
if (endObject5)
|
||||||
|
{
|
||||||
|
DrawConfigTable(v, _allNormalRaidNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using ImRaii.IEndObject endObject6 = ImRaii.TabItem("Alliance Raids");
|
||||||
|
if (endObject6)
|
||||||
|
{
|
||||||
|
DrawConfigTable(v, _allAllianceRaidNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
DrawEnableAllButton();
|
DrawEnableAllButton();
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
DrawClipboardButtons();
|
DrawClipboardButtons();
|
||||||
|
|
@ -375,7 +424,7 @@ internal sealed class DutyConfigComponent : ConfigComponent
|
||||||
{
|
{
|
||||||
base.Configuration.Duties.BlacklistedDutyCfcIds.Clear();
|
base.Configuration.Duties.BlacklistedDutyCfcIds.Clear();
|
||||||
base.Configuration.Duties.WhitelistedDutyCfcIds.Clear();
|
base.Configuration.Duties.WhitelistedDutyCfcIds.Clear();
|
||||||
foreach (List<DutyInfo> item2 in _contentFinderConditionNames.Values.Concat<List<DutyInfo>>(_allTrialNames.Values))
|
foreach (List<DutyInfo> item2 in _contentFinderConditionNames.Values.Concat<List<DutyInfo>>(_allTrialNames.Values).Concat<List<DutyInfo>>(_allNormalRaidNames.Values).Concat<List<DutyInfo>>(_allAllianceRaidNames.Values))
|
||||||
{
|
{
|
||||||
foreach (var (item, _, _) in item2)
|
foreach (var (item, _, _) in item2)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ namespace Questionable.Windows.ConfigComponents;
|
||||||
|
|
||||||
internal sealed class StopConditionComponent : ConfigComponent
|
internal sealed class StopConditionComponent : ConfigComponent
|
||||||
{
|
{
|
||||||
|
private static readonly string[] StopModeNames = new string[3] { "Off", "Pause", "Stop" };
|
||||||
|
|
||||||
private readonly IDalamudPluginInterface _pluginInterface;
|
private readonly IDalamudPluginInterface _pluginInterface;
|
||||||
|
|
||||||
private readonly QuestSelector _questSelector;
|
private readonly QuestSelector _questSelector;
|
||||||
|
|
@ -55,6 +57,7 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
_questSelector.QuestSelected = delegate(Quest quest)
|
_questSelector.QuestSelected = delegate(Quest quest)
|
||||||
{
|
{
|
||||||
configuration.Stop.QuestsToStopAfter.Add(quest.Id);
|
configuration.Stop.QuestsToStopAfter.Add(quest.Id);
|
||||||
|
configuration.Stop.QuestStopModes[quest.Id.ToString()] = Questionable.Configuration.EStopConditionMode.Stop;
|
||||||
stopConditionComponent.Save();
|
stopConditionComponent.Save();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -67,26 +70,30 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool v = base.Configuration.Stop.Enabled;
|
bool v = base.Configuration.Stop.Enabled;
|
||||||
if (ImGui.Checkbox("Stop Questionable when any of the conditions below are met", ref v))
|
if (ImGui.Checkbox("Enable stop conditions", ref v))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.Enabled = v;
|
base.Configuration.Stop.Enabled = v;
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGuiComponents.HelpMarker("Pause: Stops automation when condition is met, but allows resuming past it.\nStop: True stop, blocks automation from starting/resuming if condition is already met.");
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
using (ImRaii.Disabled(!v))
|
using (ImRaii.Disabled(!v))
|
||||||
{
|
{
|
||||||
ImGui.Text("Stop when character level reaches:");
|
ImGui.Text("Stop when character level reaches:");
|
||||||
bool v2 = base.Configuration.Stop.LevelToStopAfter;
|
int currentItem = (int)base.Configuration.Stop.LevelStopMode;
|
||||||
if (ImGui.Checkbox("Enable level stop condition", ref v2))
|
ImGui.SetNextItemWidth(100f);
|
||||||
|
if (ImGui.Combo((ImU8String)"##LevelMode", ref currentItem, (ReadOnlySpan<string>)StopModeNames, StopModeNames.Length))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.LevelToStopAfter = v2;
|
base.Configuration.Stop.LevelStopMode = (Configuration.EStopConditionMode)currentItem;
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
using (ImRaii.Disabled(!v2))
|
ImGui.SameLine();
|
||||||
|
using (ImRaii.Disabled(base.Configuration.Stop.LevelStopMode == Questionable.Configuration.EStopConditionMode.Off))
|
||||||
{
|
{
|
||||||
int data = base.Configuration.Stop.TargetLevel;
|
int data = base.Configuration.Stop.TargetLevel;
|
||||||
ImGui.SetNextItemWidth(100f);
|
ImGui.SetNextItemWidth(100f);
|
||||||
if (ImGui.InputInt("Stop at level", ref data, 1, 5))
|
if (ImGui.InputInt("Target level", ref data, 1, 5))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.TargetLevel = Math.Max(1, Math.Min(100, data));
|
base.Configuration.Stop.TargetLevel = Math.Max(1, Math.Min(100, data));
|
||||||
Save();
|
Save();
|
||||||
|
|
@ -103,18 +110,20 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.Text("Stop on quest sequence:");
|
ImGui.Text("Stop on quest sequence (global):");
|
||||||
bool v3 = base.Configuration.Stop.SequenceToStopAfter;
|
int currentItem2 = (int)base.Configuration.Stop.SequenceStopMode;
|
||||||
if (ImGui.Checkbox("Enable global quest sequence stop condition", ref v3))
|
ImGui.SetNextItemWidth(100f);
|
||||||
|
if (ImGui.Combo((ImU8String)"##SequenceMode", ref currentItem2, (ReadOnlySpan<string>)StopModeNames, StopModeNames.Length))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.SequenceToStopAfter = v3;
|
base.Configuration.Stop.SequenceStopMode = (Configuration.EStopConditionMode)currentItem2;
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
using (ImRaii.Disabled(!v3))
|
ImGui.SameLine();
|
||||||
|
using (ImRaii.Disabled(base.Configuration.Stop.SequenceStopMode == Questionable.Configuration.EStopConditionMode.Off))
|
||||||
{
|
{
|
||||||
int data2 = base.Configuration.Stop.TargetSequence;
|
int data2 = base.Configuration.Stop.TargetSequence;
|
||||||
ImGui.SetNextItemWidth(100f);
|
ImGui.SetNextItemWidth(100f);
|
||||||
if (ImGui.InputInt("Stop at sequence", ref data2, 1, 1))
|
if (ImGui.InputInt("Target sequence", ref data2, 1, 1))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.TargetSequence = Math.Max(0, Math.Min(255, data2));
|
base.Configuration.Stop.TargetSequence = Math.Max(0, Math.Min(255, data2));
|
||||||
Save();
|
Save();
|
||||||
|
|
@ -130,8 +139,8 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
text2.AppendLiteral(")");
|
text2.AppendLiteral(")");
|
||||||
ImGui.TextDisabled(text2);
|
ImGui.TextDisabled(text2);
|
||||||
}
|
}
|
||||||
ImGui.TextWrapped("Note: Individual quest sequences below override this global setting.");
|
|
||||||
}
|
}
|
||||||
|
ImGui.TextWrapped("Note: Individual quest sequences below override this global setting.");
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.Text("Stop when completing quests (or reaching specific sequences):");
|
ImGui.Text("Stop when completing quests (or reaching specific sequences):");
|
||||||
DrawCurrentlyAcceptedQuests();
|
DrawCurrentlyAcceptedQuests();
|
||||||
|
|
@ -143,11 +152,13 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
{
|
{
|
||||||
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Trash, "Clear All"))
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Trash, "Clear All"))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.QuestsToStopAfter.Clear();
|
|
||||||
foreach (ElementId item in questsToStopAfter)
|
foreach (ElementId item in questsToStopAfter)
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.QuestSequences.Remove(item.ToString());
|
string key = item.ToString();
|
||||||
|
base.Configuration.Stop.QuestSequences.Remove(key);
|
||||||
|
base.Configuration.Stop.QuestStopModes.Remove(key);
|
||||||
}
|
}
|
||||||
|
base.Configuration.Stop.QuestsToStopAfter.Clear();
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,16 +197,34 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
{
|
{
|
||||||
_questTooltipComponent.Draw(quest2.Info);
|
_questTooltipComponent.Draw(quest2.Info);
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
|
||||||
string text3 = elementId.ToString();
|
string text3 = elementId.ToString();
|
||||||
base.Configuration.Stop.QuestSequences.TryGetValue(text3, out var value);
|
int currentItem3 = (int)base.Configuration.Stop.QuestStopModes.GetValueOrDefault(text3, Questionable.Configuration.EStopConditionMode.Stop);
|
||||||
bool v4 = value.HasValue;
|
ImGui.SameLine();
|
||||||
ImU8String label = new ImU8String(8, 1);
|
ImGui.SetNextItemWidth(70f);
|
||||||
label.AppendLiteral("##UseSeq");
|
ImU8String label = new ImU8String(6, 1);
|
||||||
|
label.AppendLiteral("##Mode");
|
||||||
label.AppendFormatted(text3);
|
label.AppendFormatted(text3);
|
||||||
if (ImGui.Checkbox(label, ref v4))
|
if (ImGui.Combo(label, ref currentItem3, (ReadOnlySpan<string>)StopModeNames, StopModeNames.Length))
|
||||||
{
|
{
|
||||||
if (v4)
|
if (currentItem3 == 0)
|
||||||
|
{
|
||||||
|
quest = quest2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base.Configuration.Stop.QuestStopModes[text3] = (Configuration.EStopConditionMode)currentItem3;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
base.Configuration.Stop.QuestSequences.TryGetValue(text3, out var value);
|
||||||
|
bool v2 = value.HasValue;
|
||||||
|
ImU8String label2 = new ImU8String(8, 1);
|
||||||
|
label2.AppendLiteral("##UseSeq");
|
||||||
|
label2.AppendFormatted(text3);
|
||||||
|
if (ImGui.Checkbox(label2, ref v2))
|
||||||
|
{
|
||||||
|
if (v2)
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.QuestSequences[text3] = 1;
|
base.Configuration.Stop.QuestSequences[text3] = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -209,17 +238,17 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
{
|
{
|
||||||
ImGui.SetTooltip("Stop at specific sequence (unchecked = stop on quest completion)");
|
ImGui.SetTooltip("Stop at specific sequence (unchecked = stop on quest completion)");
|
||||||
}
|
}
|
||||||
using (ImRaii.Disabled(!v4))
|
using (ImRaii.Disabled(!v2))
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Text("Seq:");
|
ImGui.Text("Seq:");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.SetNextItemWidth(85f);
|
ImGui.SetNextItemWidth(85f);
|
||||||
int data3 = value ?? 1;
|
int data3 = value ?? 1;
|
||||||
ImU8String label2 = new ImU8String(10, 1);
|
ImU8String label3 = new ImU8String(10, 1);
|
||||||
label2.AppendLiteral("##SeqValue");
|
label3.AppendLiteral("##SeqValue");
|
||||||
label2.AppendFormatted(text3);
|
label3.AppendFormatted(text3);
|
||||||
if (ImGui.InputInt(label2, ref data3, 1, 1) && v4)
|
if (ImGui.InputInt(label3, ref data3, 1, 1) && v2)
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.QuestSequences[text3] = Math.Max(0, Math.Min(255, data3));
|
base.Configuration.Stop.QuestSequences[text3] = Math.Max(0, Math.Min(255, data3));
|
||||||
Save();
|
Save();
|
||||||
|
|
@ -237,8 +266,10 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
}
|
}
|
||||||
if (quest != null)
|
if (quest != null)
|
||||||
{
|
{
|
||||||
|
string key2 = quest.Id.ToString();
|
||||||
base.Configuration.Stop.QuestsToStopAfter.Remove(quest.Id);
|
base.Configuration.Stop.QuestsToStopAfter.Remove(quest.Id);
|
||||||
base.Configuration.Stop.QuestSequences.Remove(quest.Id.ToString());
|
base.Configuration.Stop.QuestSequences.Remove(key2);
|
||||||
|
base.Configuration.Stop.QuestStopModes.Remove(key2);
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,6 +317,7 @@ internal sealed class StopConditionComponent : ConfigComponent
|
||||||
if (ImGuiComponents.IconButton($"##Add{item.Id}", FontAwesomeIcon.Plus))
|
if (ImGuiComponents.IconButton($"##Add{item.Id}", FontAwesomeIcon.Plus))
|
||||||
{
|
{
|
||||||
base.Configuration.Stop.QuestsToStopAfter.Add(item.Id);
|
base.Configuration.Stop.QuestsToStopAfter.Add(item.Id);
|
||||||
|
base.Configuration.Stop.QuestStopModes[item.Id.ToString()] = Questionable.Configuration.EStopConditionMode.Stop;
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ internal sealed class QuestJournalUtils
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.SetTooltip((incompletePrerequisiteQuests.Count == 1) ? "Add this quest to the priority list" : $"Add this quest and {incompletePrerequisiteQuests.Count - 1} required quest(s) to the priority list in completion order");
|
ImGui.SetTooltip((incompletePrerequisiteQuests.Count == 1) ? "Add this quest to the priority list" : $"Add this quest and {incompletePrerequisiteQuests.Count - 1} required {((incompletePrerequisiteQuests.Count - 1 == 1) ? "quest" : "quests")} to the priority list in completion order");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool flag = _commandManager.Commands.ContainsKey("/questinfo");
|
bool flag = _commandManager.Commands.ContainsKey("/questinfo");
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ using Dalamud.Plugin.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Questionable.Controller;
|
using Questionable.Controller;
|
||||||
using Questionable.Controller.Steps.Shared;
|
using Questionable.Controller.Steps.Shared;
|
||||||
|
using Questionable.External;
|
||||||
using Questionable.Functions;
|
using Questionable.Functions;
|
||||||
using Questionable.Model;
|
using Questionable.Model;
|
||||||
using Questionable.Model.Questing;
|
using Questionable.Model.Questing;
|
||||||
|
|
@ -49,6 +50,8 @@ internal sealed class ActiveQuestComponent
|
||||||
|
|
||||||
private readonly IChatGui _chatGui;
|
private readonly IChatGui _chatGui;
|
||||||
|
|
||||||
|
private readonly AutoDutyIpc _autoDutyIpc;
|
||||||
|
|
||||||
private readonly ILogger<ActiveQuestComponent> _logger;
|
private readonly ILogger<ActiveQuestComponent> _logger;
|
||||||
|
|
||||||
public event EventHandler? Reload;
|
public event EventHandler? Reload;
|
||||||
|
|
@ -60,7 +63,7 @@ internal sealed class ActiveQuestComponent
|
||||||
return _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0.Instance;
|
return _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActiveQuestComponent(QuestController questController, MovementController movementController, CombatController combatController, GatheringController gatheringController, QuestFunctions questFunctions, ICommandManager commandManager, Configuration configuration, QuestRegistry questRegistry, PriorityWindow priorityWindow, UiUtils uiUtils, IObjectTable objectTable, IClientState clientState, IChatGui chatGui, ILogger<ActiveQuestComponent> logger)
|
public ActiveQuestComponent(QuestController questController, MovementController movementController, CombatController combatController, GatheringController gatheringController, QuestFunctions questFunctions, ICommandManager commandManager, Configuration configuration, QuestRegistry questRegistry, PriorityWindow priorityWindow, UiUtils uiUtils, IObjectTable objectTable, IClientState clientState, IChatGui chatGui, AutoDutyIpc autoDutyIpc, ILogger<ActiveQuestComponent> logger)
|
||||||
{
|
{
|
||||||
_questController = questController;
|
_questController = questController;
|
||||||
_movementController = movementController;
|
_movementController = movementController;
|
||||||
|
|
@ -75,6 +78,7 @@ internal sealed class ActiveQuestComponent
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_chatGui = chatGui;
|
_chatGui = chatGui;
|
||||||
|
_autoDutyIpc = autoDutyIpc;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,23 +150,91 @@ internal sealed class ActiveQuestComponent
|
||||||
_logger.LogError(ex, "Could not handle active quest buttons");
|
_logger.LogError(ex, "Could not handle active quest buttons");
|
||||||
}
|
}
|
||||||
DrawSimulationControls();
|
DrawSimulationControls();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(bool isLevelLocked, int levelsNeeded, int requiredLevel, string? questName) msqLevelLockInfo = _questFunctions.GetMsqLevelLockInfo();
|
||||||
|
bool item = msqLevelLockInfo.isLevelLocked;
|
||||||
|
int item2 = msqLevelLockInfo.levelsNeeded;
|
||||||
|
int item3 = msqLevelLockInfo.requiredLevel;
|
||||||
|
string item4 = msqLevelLockInfo.questName;
|
||||||
|
int currentPlayerLevel = _objectTable.LocalPlayer?.Level ?? 0;
|
||||||
|
if (item && _autoDutyIpc.IsConfiguredToRunLevelingMode(currentPlayerLevel) && item4 != null)
|
||||||
|
{
|
||||||
|
Vector4 col = ImGuiColors.DalamudYellow;
|
||||||
|
ImU8String text = new ImU8String(22, 2);
|
||||||
|
text.AppendLiteral("MSQ '");
|
||||||
|
text.AppendFormatted(item4);
|
||||||
|
text.AppendLiteral("' requires level ");
|
||||||
|
text.AppendFormatted(item3);
|
||||||
|
ImGui.TextColored(in col, text);
|
||||||
|
col = ImGuiColors.DalamudGrey;
|
||||||
|
ImU8String text2 = new ImU8String(61, 2);
|
||||||
|
text2.AppendLiteral("You need ");
|
||||||
|
text2.AppendFormatted(item2);
|
||||||
|
text2.AppendLiteral(" more level");
|
||||||
|
text2.AppendFormatted((item2 == 1) ? string.Empty : "s");
|
||||||
|
text2.AppendLiteral(" - Leveling mode will start automatically");
|
||||||
|
ImGui.TextColored(in col, text2);
|
||||||
|
using (ImRaii.Disabled(_questController.IsRunning || !_autoDutyIpc.IsStopped()))
|
||||||
|
{
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Start button clicked with MSQ level-locked. Starting AutoDuty leveling mode.");
|
||||||
|
if (_autoDutyIpc.StartLevelingMode())
|
||||||
|
{
|
||||||
|
_chatGui.Print($"Starting AutoDuty Leveling mode to reach level {item3} for MSQ '{item4}'.", "Questionable", 576);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_chatGui.PrintError("Failed to start AutoDuty Leveling mode. Please check that AutoDuty is installed and configured.", "Questionable", 576);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
{
|
||||||
|
if (!_autoDutyIpc.IsStopped())
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip("AutoDuty is currently running.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImU8String tooltip = new ImU8String(53, 1);
|
||||||
|
tooltip.AppendLiteral("Start AutoDuty Leveling mode to reach level ");
|
||||||
|
tooltip.AppendFormatted(item3);
|
||||||
|
tooltip.AppendLiteral(" for MSQ.");
|
||||||
|
ImGui.SetTooltip(tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.Text("No active quest");
|
ImGui.Text("No active quest");
|
||||||
|
}
|
||||||
if (!isMinimized)
|
if (!isMinimized)
|
||||||
{
|
{
|
||||||
Vector4 col = ImGuiColors.DalamudGrey;
|
Vector4 col = ImGuiColors.DalamudGrey;
|
||||||
ImU8String text = new ImU8String(14, 1);
|
ImU8String text3 = new ImU8String(14, 1);
|
||||||
text.AppendFormatted(_questRegistry.Count);
|
text3.AppendFormatted(_questRegistry.Count);
|
||||||
text.AppendLiteral(" quests loaded");
|
text3.AppendLiteral(" quests loaded");
|
||||||
ImGui.TextColored(in col, text);
|
ImGui.TextColored(in col, text3);
|
||||||
}
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
|
||||||
{
|
{
|
||||||
_movementController.Stop();
|
_movementController.Stop();
|
||||||
_questController.Stop("Manual (no active quest)");
|
_questController.Stop("Manual (no active quest)");
|
||||||
_gatheringController.Stop("Manual (no active quest)");
|
_gatheringController.Stop("Manual (no active quest)");
|
||||||
|
if (!_autoDutyIpc.IsStopped())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_autoDutyIpc.Stop();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(exception, "Failed to stop AutoDuty");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.SortAmountDown))
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.SortAmountDown))
|
||||||
|
|
@ -170,7 +242,6 @@ internal sealed class ActiveQuestComponent
|
||||||
_priorityWindow.ToggleOrUncollapse();
|
_priorityWindow.ToggleOrUncollapse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawQuestNames(QuestController.QuestProgress currentQuest, QuestController.ECurrentQuestType? currentQuestType)
|
private void DrawQuestNames(QuestController.QuestProgress currentQuest, QuestController.ECurrentQuestType? currentQuestType)
|
||||||
{
|
{
|
||||||
|
|
@ -237,9 +308,9 @@ internal sealed class ActiveQuestComponent
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.TextColored(ImGuiColors.DalamudRed, "Disabled");
|
ImGui.TextColored(ImGuiColors.DalamudRed, "Disabled");
|
||||||
}
|
}
|
||||||
bool flag = _configuration.Stop.Enabled && _configuration.Stop.LevelToStopAfter;
|
bool flag = _configuration.Stop.Enabled && _configuration.Stop.LevelStopMode != Configuration.EStopConditionMode.Off;
|
||||||
bool flag2 = _configuration.Stop.Enabled && _configuration.Stop.QuestsToStopAfter.Any((ElementId x) => !_questFunctions.IsQuestComplete(x) && !_questFunctions.IsQuestUnobtainable(x));
|
bool flag2 = _configuration.Stop.Enabled && _configuration.Stop.QuestsToStopAfter.Any((ElementId x) => !_questFunctions.IsQuestComplete(x) && !_questFunctions.IsQuestUnobtainable(x));
|
||||||
bool flag3 = _configuration.Stop.Enabled && _configuration.Stop.SequenceToStopAfter;
|
bool flag3 = _configuration.Stop.Enabled && _configuration.Stop.SequenceStopMode != Configuration.EStopConditionMode.Off;
|
||||||
if (flag || flag2 || flag3)
|
if (flag || flag2 || flag3)
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
|
||||||
|
|
@ -253,12 +253,9 @@ internal sealed class EventInfoComponent
|
||||||
}
|
}
|
||||||
if (_questFunctions.IsQuestUnobtainable(questInfo.QuestId))
|
if (_questFunctions.IsQuestUnobtainable(questInfo.QuestId))
|
||||||
{
|
{
|
||||||
if (_alreadyLoggedActiveSeasonalSkip.Add(questInfo.QuestId.Value))
|
continue;
|
||||||
{
|
|
||||||
_logger.LogDebug("Skipping quest {QuestId} '{Name}': marked unobtainable", questInfo.QuestId, questInfo.Name);
|
|
||||||
}
|
}
|
||||||
}
|
if (questInfo is UnlockLinkQuestInfo { QuestExpiry: var questExpiry })
|
||||||
else if (questInfo is UnlockLinkQuestInfo { QuestExpiry: var questExpiry })
|
|
||||||
{
|
{
|
||||||
if (questExpiry.HasValue)
|
if (questExpiry.HasValue)
|
||||||
{
|
{
|
||||||
|
|
@ -287,15 +284,10 @@ internal sealed class EventInfoComponent
|
||||||
if (seasonalQuestExpiry.HasValue)
|
if (seasonalQuestExpiry.HasValue)
|
||||||
{
|
{
|
||||||
DateTime valueOrDefault2 = seasonalQuestExpiry.GetValueOrDefault();
|
DateTime valueOrDefault2 = seasonalQuestExpiry.GetValueOrDefault();
|
||||||
DateTime dateTime2 = NormalizeExpiry(valueOrDefault2);
|
if (NormalizeExpiry(valueOrDefault2) > DateTime.UtcNow)
|
||||||
if (dateTime2 > DateTime.UtcNow)
|
|
||||||
{
|
{
|
||||||
yield return questInfo;
|
yield return questInfo;
|
||||||
}
|
}
|
||||||
else if (_alreadyLoggedActiveSeasonalSkip.Add(questInfo.QuestId.Value))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Skipping quest {QuestId} '{Name}': seasonal expiry {Expiry:o} UTC is not in the future", questInfo.QuestId, questInfo.Name, dateTime2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (questInfo2.IsSeasonalQuest && !questInfo2.SeasonalQuestExpiry.HasValue)
|
else if (questInfo2.IsSeasonalQuest && !questInfo2.SeasonalQuestExpiry.HasValue)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -103,10 +103,12 @@ internal sealed class PresetBuilderComponent
|
||||||
ImGui.SetTooltip("No preset quests are currently in the priority list.");
|
ImGui.SetTooltip("No preset quests are currently in the priority list.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ImU8String tooltip = new ImU8String(59, 1);
|
ImU8String tooltip = new ImU8String(51, 2);
|
||||||
tooltip.AppendLiteral("Remove all ");
|
tooltip.AppendLiteral("Remove all ");
|
||||||
tooltip.AppendFormatted(list.Count);
|
tooltip.AppendFormatted(list.Count);
|
||||||
tooltip.AppendLiteral(" preset-related quest(s) from the priority list.");
|
tooltip.AppendLiteral(" preset-related ");
|
||||||
|
tooltip.AppendFormatted((list.Count == 1) ? "quest" : "quests");
|
||||||
|
tooltip.AppendLiteral(" from the priority list.");
|
||||||
ImGui.SetTooltip(tooltip);
|
ImGui.SetTooltip(tooltip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,13 @@ internal sealed class Configuration : IPluginConfiguration
|
||||||
|
|
||||||
public Dictionary<string, int?> QuestSequences { get; set; } = new Dictionary<string, int?>();
|
public Dictionary<string, int?> QuestSequences { get; set; } = new Dictionary<string, int?>();
|
||||||
|
|
||||||
public bool LevelToStopAfter { get; set; }
|
public Dictionary<string, EStopConditionMode> QuestStopModes { get; set; } = new Dictionary<string, EStopConditionMode>();
|
||||||
|
|
||||||
|
public EStopConditionMode LevelStopMode { get; set; }
|
||||||
|
|
||||||
public int TargetLevel { get; set; } = 50;
|
public int TargetLevel { get; set; } = 50;
|
||||||
|
|
||||||
public bool SequenceToStopAfter { get; set; }
|
public EStopConditionMode SequenceStopMode { get; set; }
|
||||||
|
|
||||||
public int TargetSequence { get; set; } = 1;
|
public int TargetSequence { get; set; } = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +82,8 @@ internal sealed class Configuration : IPluginConfiguration
|
||||||
public Dictionary<uint, EDutyMode> DutyModeOverrides { get; set; } = new Dictionary<uint, EDutyMode>();
|
public Dictionary<uint, EDutyMode> DutyModeOverrides { get; set; } = new Dictionary<uint, EDutyMode>();
|
||||||
|
|
||||||
public Dictionary<string, bool> ExpansionHeaderStates { get; set; } = new Dictionary<string, bool>();
|
public Dictionary<string, bool> ExpansionHeaderStates { get; set; } = new Dictionary<string, bool>();
|
||||||
|
|
||||||
|
public bool RunLevelingModeWhenUnderleveled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class SinglePlayerDutyConfiguration
|
internal sealed class SinglePlayerDutyConfiguration
|
||||||
|
|
@ -135,6 +139,13 @@ internal sealed class Configuration : IPluginConfiguration
|
||||||
RotationSolverReborn
|
RotationSolverReborn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal enum EStopConditionMode
|
||||||
|
{
|
||||||
|
Off,
|
||||||
|
Pause,
|
||||||
|
Stop
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class ElementIdNConverter : JsonConverter<ElementId>
|
public sealed class ElementIdNConverter : JsonConverter<ElementId>
|
||||||
{
|
{
|
||||||
public override void WriteJson(JsonWriter writer, ElementId? value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, ElementId? value, JsonSerializer serializer)
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,8 @@ public sealed class QuestionablePlugin : IDalamudPlugin, IDisposable
|
||||||
serviceCollection.AddTaskExecutor<Duty.WaitForPartyTask, Duty.WaitForPartyExecutor>();
|
serviceCollection.AddTaskExecutor<Duty.WaitForPartyTask, Duty.WaitForPartyExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<Duty.StartAutoDutyTask, Duty.StartAutoDutyExecutor>();
|
serviceCollection.AddTaskExecutor<Duty.StartAutoDutyTask, Duty.StartAutoDutyExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<Duty.WaitAutoDutyTask, Duty.WaitAutoDutyExecutor>();
|
serviceCollection.AddTaskExecutor<Duty.WaitAutoDutyTask, Duty.WaitAutoDutyExecutor>();
|
||||||
|
serviceCollection.AddTaskExecutor<Duty.StartLevelingModeTask, Duty.StartLevelingModeExecutor>();
|
||||||
|
serviceCollection.AddTaskExecutor<Duty.WaitLevelingModeTask, Duty.WaitLevelingModeExecutor>();
|
||||||
serviceCollection.AddTaskFactory<Emote.Factory>();
|
serviceCollection.AddTaskFactory<Emote.Factory>();
|
||||||
serviceCollection.AddTaskExecutor<Emote.UseOnObject, Emote.UseOnObjectExecutor>();
|
serviceCollection.AddTaskExecutor<Emote.UseOnObject, Emote.UseOnObjectExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<Emote.UseOnSelf, Emote.UseOnSelfExecutor>();
|
serviceCollection.AddTaskExecutor<Emote.UseOnSelf, Emote.UseOnSelfExecutor>();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue