368 lines
9 KiB
C#
368 lines
9 KiB
C#
using System;
|
|
using Dalamud.Game.ClientState.Conditions;
|
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
|
using Dalamud.Plugin.Services;
|
|
|
|
namespace QuestionableCompanion.Services;
|
|
|
|
public class CombatDutyDetectionService : IDisposable
|
|
{
|
|
private readonly ICondition condition;
|
|
|
|
private readonly IPluginLog log;
|
|
|
|
private readonly IClientState clientState;
|
|
|
|
private readonly ICommandManager commandManager;
|
|
|
|
private readonly IFramework framework;
|
|
|
|
private readonly Configuration config;
|
|
|
|
private bool wasInCombat;
|
|
|
|
private bool wasInDuty;
|
|
|
|
private DateTime dutyExitTime = DateTime.MinValue;
|
|
|
|
private DateTime dutyEntryTime = DateTime.MinValue;
|
|
|
|
private DateTime lastStateChange = DateTime.MinValue;
|
|
|
|
private bool combatCommandsActive;
|
|
|
|
private bool hasCombatCommandsForDuty;
|
|
|
|
private bool isInAutoDutyDungeon;
|
|
|
|
private uint currentQuestId;
|
|
|
|
private bool isRotationActive;
|
|
|
|
public bool JustEnteredDuty { get; private set; }
|
|
|
|
public bool JustExitedDuty { get; private set; }
|
|
|
|
public DateTime DutyExitTime => dutyExitTime;
|
|
|
|
public bool IsInCombat { get; private set; }
|
|
|
|
public bool IsInDuty { get; private set; }
|
|
|
|
public bool IsInDutyQueue { get; private set; }
|
|
|
|
public bool ShouldPauseAutomation
|
|
{
|
|
get
|
|
{
|
|
if (!IsInCombat && !IsInDuty)
|
|
{
|
|
return IsInDutyQueue;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public void AcknowledgeDutyEntry()
|
|
{
|
|
JustEnteredDuty = false;
|
|
}
|
|
|
|
public void AcknowledgeDutyExit()
|
|
{
|
|
JustExitedDuty = false;
|
|
}
|
|
|
|
public CombatDutyDetectionService(ICondition condition, IPluginLog log, IClientState clientState, ICommandManager commandManager, IFramework framework, Configuration config)
|
|
{
|
|
this.condition = condition;
|
|
this.log = log;
|
|
this.clientState = clientState;
|
|
this.commandManager = commandManager;
|
|
this.framework = framework;
|
|
this.config = config;
|
|
log.Information("[CombatDuty] Service initialized");
|
|
}
|
|
|
|
public void SetRotationActive(bool active)
|
|
{
|
|
isRotationActive = active;
|
|
}
|
|
|
|
public void SetAutoDutyDungeon(bool isAutoDuty)
|
|
{
|
|
isInAutoDutyDungeon = isAutoDuty;
|
|
}
|
|
|
|
public void SetCurrentQuestId(uint questId)
|
|
{
|
|
currentQuestId = questId;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (clientState.LocalPlayer == null || !clientState.IsLoggedIn)
|
|
{
|
|
return;
|
|
}
|
|
if (isRotationActive)
|
|
{
|
|
bool inCombat = condition[ConditionFlag.InCombat];
|
|
if (inCombat != wasInCombat)
|
|
{
|
|
IsInCombat = inCombat;
|
|
wasInCombat = inCombat;
|
|
lastStateChange = DateTime.Now;
|
|
if (inCombat)
|
|
{
|
|
log.Information("[CombatDuty] Combat started - pausing automation");
|
|
if (currentQuestId == 811)
|
|
{
|
|
log.Information("[CombatDuty] Quest 811 - combat commands DISABLED (RSR off)");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log.Information("[CombatDuty] Combat ended - resuming automation");
|
|
if (combatCommandsActive && !IsInDuty)
|
|
{
|
|
log.Information("[CombatDuty] Not in duty - disabling combat commands");
|
|
DisableCombatCommands();
|
|
}
|
|
else if (combatCommandsActive && IsInDuty)
|
|
{
|
|
log.Information("[CombatDuty] In duty - keeping combat commands active");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (isRotationActive && config.EnableCombatHandling && IsInCombat && !combatCommandsActive && currentQuestId != 811)
|
|
{
|
|
IPlayerCharacter player = clientState.LocalPlayer;
|
|
if (player != null)
|
|
{
|
|
float hpPercent = (float)player.CurrentHp / (float)player.MaxHp * 100f;
|
|
if (hpPercent <= (float)config.CombatHPThreshold)
|
|
{
|
|
log.Warning($"[CombatDuty] HP at {hpPercent:F1}% (threshold: {config.CombatHPThreshold}%) - enabling combat commands");
|
|
EnableCombatCommands();
|
|
}
|
|
}
|
|
}
|
|
bool inDuty = condition[ConditionFlag.BoundByDuty] || condition[ConditionFlag.BoundByDuty56] || condition[ConditionFlag.BoundByDuty95];
|
|
if (inDuty != wasInDuty)
|
|
{
|
|
IsInDuty = inDuty;
|
|
wasInDuty = inDuty;
|
|
lastStateChange = DateTime.Now;
|
|
if (inDuty)
|
|
{
|
|
log.Information("[CombatDuty] Duty started - pausing automation");
|
|
JustEnteredDuty = true;
|
|
JustExitedDuty = false;
|
|
dutyEntryTime = DateTime.Now;
|
|
hasCombatCommandsForDuty = false;
|
|
}
|
|
else
|
|
{
|
|
log.Information("[CombatDuty] Duty completed - resuming automation");
|
|
JustEnteredDuty = false;
|
|
JustExitedDuty = true;
|
|
dutyExitTime = DateTime.Now;
|
|
dutyEntryTime = DateTime.MinValue;
|
|
hasCombatCommandsForDuty = false;
|
|
if (combatCommandsActive)
|
|
{
|
|
log.Information("[CombatDuty] Duty ended - disabling combat commands");
|
|
DisableCombatCommands();
|
|
}
|
|
}
|
|
}
|
|
if (isRotationActive && IsInDuty && !isInAutoDutyDungeon && !hasCombatCommandsForDuty && dutyEntryTime != DateTime.MinValue)
|
|
{
|
|
if (currentQuestId == 811)
|
|
{
|
|
log.Information("[CombatDuty] Quest 811 - skipping combat commands (RSR disabled)");
|
|
hasCombatCommandsForDuty = true;
|
|
return;
|
|
}
|
|
if (currentQuestId == 4591)
|
|
{
|
|
log.Information("[CombatDuty] Quest 4591 (Steps of Faith) - skipping combat commands (handler does it)");
|
|
hasCombatCommandsForDuty = true;
|
|
return;
|
|
}
|
|
if ((DateTime.Now - dutyEntryTime).TotalSeconds >= 8.0)
|
|
{
|
|
log.Information("[CombatDuty] 8 seconds in Solo Duty - enabling combat commands");
|
|
EnableCombatCommands();
|
|
hasCombatCommandsForDuty = true;
|
|
}
|
|
}
|
|
bool inQueue = condition[ConditionFlag.WaitingForDuty] || condition[ConditionFlag.WaitingForDutyFinder];
|
|
if (inQueue != IsInDutyQueue)
|
|
{
|
|
IsInDutyQueue = inQueue;
|
|
lastStateChange = DateTime.Now;
|
|
if (inQueue)
|
|
{
|
|
log.Information("[CombatDuty] Duty queue active - pausing automation");
|
|
}
|
|
else
|
|
{
|
|
log.Information("[CombatDuty] Duty queue ended - resuming automation");
|
|
}
|
|
}
|
|
}
|
|
|
|
public TimeSpan TimeSinceLastStateChange()
|
|
{
|
|
if (lastStateChange == DateTime.MinValue)
|
|
{
|
|
return TimeSpan.Zero;
|
|
}
|
|
return DateTime.Now - lastStateChange;
|
|
}
|
|
|
|
private void EnableCombatCommands()
|
|
{
|
|
if (combatCommandsActive)
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
log.Information("[CombatDuty] ========================================");
|
|
log.Information("[CombatDuty] === ENABLING COMBAT AUTOMATION ===");
|
|
log.Information("[CombatDuty] ========================================");
|
|
framework.RunOnTick(delegate
|
|
{
|
|
try
|
|
{
|
|
commandManager.ProcessCommand("/rsr auto");
|
|
log.Information("[CombatDuty] /rsr auto sent");
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
log.Error("[CombatDuty] Failed to send /rsr auto: " + ex2.Message);
|
|
}
|
|
}, TimeSpan.Zero);
|
|
framework.RunOnTick(delegate
|
|
{
|
|
try
|
|
{
|
|
commandManager.ProcessCommand("/vbmai on");
|
|
log.Information("[CombatDuty] /vbmai on sent");
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
log.Error("[CombatDuty] Failed to send /vbmai on: " + ex2.Message);
|
|
}
|
|
}, TimeSpan.FromMilliseconds(100L, 0L));
|
|
framework.RunOnTick(delegate
|
|
{
|
|
try
|
|
{
|
|
commandManager.ProcessCommand("/bmrai on");
|
|
log.Information("[CombatDuty] /bmrai on sent");
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
log.Error("[CombatDuty] Failed to send /bmrai on: " + ex2.Message);
|
|
}
|
|
}, TimeSpan.FromMilliseconds(200L, 0L));
|
|
combatCommandsActive = true;
|
|
log.Information("[CombatDuty] Combat automation enabled");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("[CombatDuty] Error enabling combat commands: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private void DisableCombatCommands()
|
|
{
|
|
if (!combatCommandsActive)
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
log.Information("[CombatDuty] ========================================");
|
|
log.Information("[CombatDuty] === DISABLING COMBAT AUTOMATION ===");
|
|
log.Information("[CombatDuty] ========================================");
|
|
framework.RunOnTick(delegate
|
|
{
|
|
try
|
|
{
|
|
commandManager.ProcessCommand("/rsr off");
|
|
log.Information("[CombatDuty] /rsr off sent");
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
log.Error("[CombatDuty] Failed to send /rsr off: " + ex2.Message);
|
|
}
|
|
}, TimeSpan.Zero);
|
|
framework.RunOnTick(delegate
|
|
{
|
|
try
|
|
{
|
|
commandManager.ProcessCommand("/vbmai off");
|
|
log.Information("[CombatDuty] /vbmai off sent");
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
log.Error("[CombatDuty] Failed to send /vbmai off: " + ex2.Message);
|
|
}
|
|
}, TimeSpan.FromMilliseconds(100L, 0L));
|
|
framework.RunOnTick(delegate
|
|
{
|
|
try
|
|
{
|
|
commandManager.ProcessCommand("/bmrai off");
|
|
log.Information("[CombatDuty] /bmrai off sent");
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
log.Error("[CombatDuty] Failed to send /bmrai off: " + ex2.Message);
|
|
}
|
|
}, TimeSpan.FromMilliseconds(200L, 0L));
|
|
combatCommandsActive = false;
|
|
log.Information("[CombatDuty] Combat automation disabled");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Error("[CombatDuty] Error disabling combat commands: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
public void ClearDutyExitFlag()
|
|
{
|
|
JustExitedDuty = false;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
IsInCombat = false;
|
|
IsInDuty = false;
|
|
IsInDutyQueue = false;
|
|
wasInCombat = false;
|
|
wasInDuty = false;
|
|
combatCommandsActive = false;
|
|
hasCombatCommandsForDuty = false;
|
|
JustEnteredDuty = false;
|
|
JustExitedDuty = false;
|
|
dutyExitTime = DateTime.MinValue;
|
|
dutyEntryTime = DateTime.MinValue;
|
|
log.Information("[CombatDuty] State reset");
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (combatCommandsActive)
|
|
{
|
|
DisableCombatCommands();
|
|
}
|
|
}
|
|
}
|