qstbak/QuestionableCompanion/QuestionableCompanion.Services/CombatDutyDetectionService.cs
2025-12-04 04:39:08 +10:00

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();
}
}
}