Skip to content

Commit

Permalink
Better cast cancellation.
Browse files Browse the repository at this point in the history
  • Loading branch information
awgil committed Jul 14, 2024
1 parent e7931b7 commit f73e6bb
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 2 deletions.
2 changes: 1 addition & 1 deletion BossMod/AI/AIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public void Update(Actor? player)
else
{
_amex.InputOverride.GamepadOverridesEnabled = false;
_axisForward.CurDirection = ForceCancelCast && castInProgress ? 1 : 0; // this is a hack to cancel any cast...
_amex.ForceCancelCastNextFrame |= ForceCancelCast && castInProgress;
_keyJump.Held = false;
}

Expand Down
3 changes: 3 additions & 0 deletions BossMod/ActionTweaks/ActionTweaksConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public sealed class ActionTweaksConfig : ConfigNode
[PropertyDisplay("Prevent movement while casting")]
public bool PreventMovingWhileCasting = false;

[PropertyDisplay("Automatically cancel a cast when target is dead")]
public bool CancelCastOnDeadTarget = false;

[PropertyDisplay("Restore character orientation after action use (no effect if 'auto face target' in game settings is disabled)")]
public bool RestoreRotation = false;

Expand Down
23 changes: 23 additions & 0 deletions BossMod/ActionTweaks/CancelCastTweak.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace BossMod;

// Utility for automatically cancelling casts in some conditions (when target dies, when ai wants it, etc).
// Since the game API is sending a packet, this implements some rate limiting.
public sealed class CancelCastTweak(WorldState ws)
{
private readonly ActionTweaksConfig _config = Service.Config.Get<ActionTweaksConfig>();
private readonly WorldState _ws = ws;
private DateTime _nextCancelAllowed;

public bool ShouldCancel(DateTime currentTime, bool force)
{
if (currentTime < _nextCancelAllowed)
return false;

var cancel = force || _config.CancelCastOnDeadTarget && (_ws.Actors.Find(_ws.Party.Player()?.CastInfo?.TargetID ?? 0)?.IsDead ?? false);
if (!cancel)
return false;

_nextCancelAllowed = currentTime.AddSeconds(0.2f);
return true;
}
}
2 changes: 1 addition & 1 deletion BossMod/Autorotation/UIRotationWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public override void Draw()

// TODO: more fancy action history/queue...
ImGui.TextUnformatted($"Modules: {_mgr}");
ImGui.TextUnformatted($"GCD={_mgr.WorldState.Client.Cooldowns[ActionDefinitions.GCDGroup].Remaining:f3}, AnimLock={_mgr.ActionManager.EffectiveAnimationLock:f3}+{_mgr.ActionManager.AnimationLockDelayEstimate:f3}, Combo={_mgr.ActionManager.ComboTimeLeft:f3}");
ImGui.TextUnformatted($"GCD={_mgr.WorldState.Client.Cooldowns[ActionDefinitions.GCDGroup].Remaining:f3}, AnimLock={_mgr.ActionManager.EffectiveAnimationLock:f3}+{_mgr.ActionManager.AnimationLockDelayEstimate:f3}, Combo={_mgr.ActionManager.ComboTimeLeft:f3}, RBIn={_mgr.Bossmods.RaidCooldowns.NextDamageBuffIn(_mgr.WorldState.CurrentTime):f3}");
foreach (var a in _mgr.Hints.ActionsToExecute.Entries)
{
ImGui.TextUnformatted($"> {a.Action} ({a.Priority:f2})");
Expand Down
8 changes: 8 additions & 0 deletions BossMod/Framework/ActionManagerEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace BossMod;
// 6. ground-targeted action queueing
// ground-targeted actions can't be queued, making using them efficiently tricky
// this feature allows queueing them, plus provides options to execute them automatically either at target's position or at cursor's position
// 7. auto cancel cast utility
// TODO: should not be public!
public unsafe sealed class ActionManagerEx : IDisposable
{
Expand All @@ -44,13 +45,15 @@ public unsafe sealed class ActionManagerEx : IDisposable
public ActionTweaksConfig Config = Service.Config.Get<ActionTweaksConfig>();
public ActionQueue.Entry AutoQueue { get; private set; }
public bool MoveMightInterruptCast { get; private set; } // if true, moving now might cause cast interruption (for current or queued cast)
public bool ForceCancelCastNextFrame;
private readonly ActionManager* _inst = ActionManager.Instance();
private readonly WorldState _ws;
private readonly AIHints _hints;
private readonly ManualActionQueueTweak _manualQueue;
private readonly AnimationLockTweak _animLockTweak = new();
private readonly CooldownDelayTweak _cooldownTweak = new();
private readonly RestoreRotationTweak _restoreRotTweak = new();
private readonly CancelCastTweak _cancelCastTweak;

private readonly HookAddress<ActionManager.Delegates.Update> _updateHook;
private readonly HookAddress<ActionManager.Delegates.UseAction> _useActionHook;
Expand All @@ -63,6 +66,7 @@ public ActionManagerEx(WorldState ws, AIHints hints)
_ws = ws;
_hints = hints;
_manualQueue = new(ws, hints);
_cancelCastTweak = new(ws);

Service.Log($"[AMEx] ActionManager singleton address = 0x{(ulong)_inst:X}");
_updateHook = new(ActionManager.Addresses.Update, UpdateDetour);
Expand Down Expand Up @@ -279,6 +283,10 @@ private void UpdateDetour(ActionManager* self)
InputOverride.BlockMovement();
else
InputOverride.UnblockMovement();

if (_ws.Party.Player()?.CastInfo != null && _cancelCastTweak.ShouldCancel(_ws.CurrentTime, ForceCancelCastNextFrame))
UIState.Instance()->Hotbar.CancelCast();
ForceCancelCastNextFrame = false;
}

// note: targetId is usually your current primary target (or 0xE0000000 if you don't target anyone), unless you do something like /ac XXX <f> etc
Expand Down

0 comments on commit f73e6bb

Please sign in to comment.