Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera-relative Elusive Jump #339

Merged
merged 7 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions BossMod/Autorotation/CommonActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ abstract class CommonActions : IDisposable

public enum ActionSource { Automatic, Planned, Manual, Emergency }

public record struct NextAction(ActionID Action, Actor? Target, Vector3 TargetPos, ActionSource Source);
public record struct NextAction(ActionID Action, Actor? Target, Vector3 TargetPos, Angle? FacingAngle, ActionSource Source);
public record struct Targeting(AIHints.Enemy Target, float PreferredRange = 3, Positional PreferredPosition = Positional.Any, bool PreferTanking = false);

public class SupportedAction(ActionDefinition definition, bool isGT)
Expand All @@ -22,6 +22,7 @@ public class SupportedAction(ActionDefinition definition, bool isGT)
public int PlaceholderForAuto; // if set, attempting to execute this action would instead initiate auto-strategy
public Func<ActionID>? TransformAction;
public Func<Actor?, Actor?>? TransformTarget;
public Func<Angle?>? TransformAngle;

public bool Allowed(Actor player, Actor target)
{
Expand Down Expand Up @@ -199,7 +200,7 @@ public bool HandleUserActionRequest(ActionID action, Actor? target, Vector3? for
{
if (forcedGTPos != null)
{
_mq.Push(action, null, forcedGTPos.Value, supportedAction.Definition, supportedAction.Condition);
_mq.Push(action, null, forcedGTPos.Value, null, supportedAction.Definition, supportedAction.Condition);
return true;
}

Expand All @@ -211,7 +212,7 @@ public bool HandleUserActionRequest(ActionID action, Actor? target, Vector3? for
var pos = ActionManagerEx.Instance!.GetWorldPosUnderCursor();
if (pos == null)
return false; // same as manual...
_mq.Push(action, null, pos.Value, supportedAction.Definition, supportedAction.Condition);
_mq.Push(action, null, pos.Value, null, supportedAction.Definition, supportedAction.Condition);
return true;
}
}
Expand All @@ -220,7 +221,12 @@ public bool HandleUserActionRequest(ActionID action, Actor? target, Vector3? for
{
target = supportedAction.TransformTarget(target);
}
_mq.Push(action, target, new(), supportedAction.Definition, supportedAction.Condition);

Angle? angleOverride = null;
if (supportedAction.TransformAngle != null)
angleOverride = supportedAction.TransformAngle();

_mq.Push(action, target, new(), angleOverride, supportedAction.Definition, supportedAction.Condition);
return true;
}

Expand All @@ -229,26 +235,26 @@ public NextAction CalculateNextAction()
// check emergency mode
var mqEmergency = _mq.PeekEmergency();
if (mqEmergency != null)
return new(mqEmergency.Action, mqEmergency.Target, mqEmergency.TargetPos, ActionSource.Emergency);
return new(mqEmergency.Action, mqEmergency.Target, mqEmergency.TargetPos, mqEmergency.FacingAngle, ActionSource.Emergency);

var effAnimLock = Autorot.EffAnimLock;
var animLockDelay = Autorot.AnimLockDelay;

// see if we have any GCD (queued or automatic)
var mqGCD = _mq.PeekGCD();
var nextGCD = mqGCD != null ? new NextAction(mqGCD.Action, mqGCD.Target, mqGCD.TargetPos, ActionSource.Manual) : AutoAction != AutoActionNone ? CalculateAutomaticGCD() : new();
var nextGCD = mqGCD != null ? new NextAction(mqGCD.Action, mqGCD.Target, mqGCD.TargetPos, mqGCD.FacingAngle, ActionSource.Manual) : AutoAction != AutoActionNone ? CalculateAutomaticGCD() : new();
float ogcdDeadline = nextGCD.Action ? Autorot.WorldState.Client.Cooldowns[CommonDefinitions.GCDGroup].Remaining : float.MaxValue;
//Log($"{nextGCD.Action} = {ogcdDeadline}");

// search for any oGCDs that we can execute without delaying GCD
var mqOGCD = _mq.PeekOGCD(effAnimLock, animLockDelay, ogcdDeadline);
if (mqOGCD != null)
return new(mqOGCD.Action, mqOGCD.Target, mqOGCD.TargetPos, ActionSource.Manual);
return new(mqOGCD.Action, mqOGCD.Target, mqOGCD.TargetPos, mqOGCD.FacingAngle, ActionSource.Manual);

// see if there is anything high-priority from cooldown plan to be executed
var cpActionHigh = Autorot.Hints.PlannedActions.FirstOrDefault(x => !x.lowPriority && CanExecutePlannedAction(x.action, x.target, effAnimLock, animLockDelay, ogcdDeadline));
if (cpActionHigh.action)
return new(cpActionHigh.action, cpActionHigh.target, new(), ActionSource.Planned);
return new(cpActionHigh.action, cpActionHigh.target, new(), null, ActionSource.Planned);

// note: we intentionally don't check that automatic oGCD really does not clip GCD - we provide utilities that allow module checking that, but also allow overriding if needed
var nextOGCD = AutoAction != AutoActionNone ? CalculateAutomaticOGCD(ogcdDeadline) : new();
Expand All @@ -258,7 +264,7 @@ public NextAction CalculateNextAction()
// finally see whether there are any low-priority planned actions
var cpActionLow = Autorot.Hints.PlannedActions.FirstOrDefault(x => x.lowPriority && CanExecutePlannedAction(x.action, x.target, effAnimLock, animLockDelay, ogcdDeadline));
if (cpActionLow.action)
return new(cpActionLow.action, cpActionLow.target, new(), ActionSource.Planned);
return new(cpActionLow.action, cpActionLow.target, new(), null, ActionSource.Planned);

// no ogcds, execute gcd instead
return nextGCD;
Expand Down Expand Up @@ -296,7 +302,7 @@ protected NextAction MakeResult(ActionID action, Actor? target)
return new();
if (data.Definition.Range == 0)
target = Player; // override range-0 actions to always target player
return target != null && data.Allowed(Player, target) ? new(action, target, new(), ActionSource.Automatic) : new();
return target != null && data.Allowed(Player, target) ? new(action, target, new(), null, ActionSource.Automatic) : new();
}
protected NextAction MakeResult<AID>(AID aid, Actor? target) where AID : Enum => MakeResult(ActionID.MakeSpell(aid), target);

Expand All @@ -305,7 +311,7 @@ protected void SimulateManualActionForAI(ActionID action, Actor? target, bool en
if (enable)
{
var data = SupportedActions[action];
_mq.Push(action, target, new(), data.Definition, data.Condition, true);
_mq.Push(action, target, new(), null, data.Definition, data.Condition, true);
}
else
{
Expand Down
9 changes: 9 additions & 0 deletions BossMod/Autorotation/DRG/DRGActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ private void OnConfigModified()

// smart targets
SupportedSpell(AID.DragonSight).TransformTarget = _config.SmartDragonSightTarget ? SmartTargetDragonSight : null;

// elusive jump aiming
SupportedSpell(AID.ElusiveJump).TransformAngle = _config.ElusiveJump switch
{
DRGConfig.ElusiveJumpBehavior.CharacterForward => () => Player.Rotation + 180.Degrees(),
DRGConfig.ElusiveJumpBehavior.CameraBackward => () => new Angle(Camera.Instance!.CameraAzimuth + MathF.PI),
DRGConfig.ElusiveJumpBehavior.CameraForward => () => new Angle(Camera.Instance!.CameraAzimuth),
_ => null
};
}

private bool WithoutDOT(Actor a) => Rotation.RefreshDOT(_state, StatusDetails(a, SID.ChaosThrust, Player.InstanceID).Left);
Expand Down
15 changes: 15 additions & 0 deletions BossMod/Autorotation/DRG/DRGConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,19 @@ class DRGConfig : ConfigNode

[PropertyDisplay("Smart targeting for Dragon Sight (target if friendly, otherwise mouseover if friendly, otherwise best player by class ranking)")]
public bool SmartDragonSightTarget = true;

public enum ElusiveJumpBehavior : uint
{
[PropertyDisplay("Unchanged (character-relative, backwards)")]
Default = 0,
[PropertyDisplay("Character-relative, forwards")]
CharacterForward = 1,
[PropertyDisplay("Camera-relative, backwards")]
CameraBackward = 2,
[PropertyDisplay("Camera-relative, forwards")]
CameraForward = 3,
}

[PropertyDisplay("Elusive Jump behavior")]
public ElusiveJumpBehavior ElusiveJump = ElusiveJumpBehavior.Default;
}
11 changes: 6 additions & 5 deletions BossMod/Autorotation/ManualActionOverride.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
// - trying to queue an oGCD action while it is already queued (double tapping) activates 'emergency mode': all preceeding queued actions are removed and this action is returned even if it would delay GCD
class ManualActionOverride(WorldState ws)
{
public class Entry(ActionID action, Actor? target, Vector3 targetPos, ActionDefinition definition, Func<Actor?, bool>? condition, DateTime expireAt)
public class Entry(ActionID action, Actor? target, Vector3 targetPos, Angle? facingAngle, ActionDefinition definition, Func<Actor?, bool>? condition, DateTime expireAt)
{
public ActionID Action = action;
public Actor? Target = target;
public Vector3 TargetPos = targetPos;
public Angle? FacingAngle = facingAngle;
public ActionDefinition Definition = definition;
public Func<Actor?, bool>? Condition = condition;
public DateTime ExpireAt = expireAt;
Expand Down Expand Up @@ -49,7 +50,7 @@ public void RemoveExpired()
_queue.RemoveAll(CheckExpired);
}

public void Push(ActionID action, Actor? target, Vector3 targetPos, ActionDefinition def, Func<Actor?, bool>? condition, bool simulated = false)
public void Push(ActionID action, Actor? target, Vector3 targetPos, Angle? facingAngle, ActionDefinition def, Func<Actor?, bool>? condition, bool simulated = false)
{
bool isGCD = def.CooldownGroup == CommonDefinitions.GCDGroup;
float expire = isGCD ? 1.0f : 3.0f;
Expand All @@ -63,7 +64,7 @@ public void Push(ActionID action, Actor? target, Vector3 targetPos, ActionDefini
if (index < 0)
{
Service.Log($"[MAO] Queueing {action} @ {target}");
_queue.Add(new(action, target, targetPos, def, condition, expireAt));
_queue.Add(new(action, target, targetPos, facingAngle, def, condition, expireAt));
return;
}

Expand All @@ -72,7 +73,7 @@ public void Push(ActionID action, Actor? target, Vector3 targetPos, ActionDefini
{
Service.Log($"[MAO] Replacing queued {e.Action} with {action} @ {target}");
_queue.RemoveAt(index);
_queue.Add(new(action, target, targetPos, def, condition, expireAt));
_queue.Add(new(action, target, targetPos, facingAngle, def, condition, expireAt));
}
else if (isGCD)
{
Expand All @@ -84,7 +85,7 @@ public void Push(ActionID action, Actor? target, Vector3 targetPos, ActionDefini
Service.Log($"[MAO] Entering emergency mode for {e.Action}");
// spamming oGCD - enter emergency mode
_queue.Clear();
_queue.Add(new(action, target, targetPos, def, condition, expireAt));
_queue.Add(new(action, target, targetPos, facingAngle, def, condition, expireAt));
_emergencyMode = true;
}
}
Expand Down
11 changes: 8 additions & 3 deletions BossMod/Framework/ActionManagerEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,13 @@ public bool UseAction(ActionID action, ulong targetID, uint itemLocation, uint c
=> _inst->UseAction((FFXIVClientStructs.FFXIV.Client.Game.ActionType)action.Type, action.ID, targetID, itemLocation, callType, comboRouteID, outOptGTModeStarted);

// skips queueing etc
public bool UseActionRaw(ActionID action, ulong targetID = GameObject.InvalidGameObjectId, Vector3 targetPos = new(), uint itemLocation = 0)
=> UseActionLocationDetour(_inst, action.Type, action.ID, targetID, &targetPos, itemLocation);
public bool UseActionRaw(ActionID action, ulong targetID = GameObject.InvalidGameObjectId, Vector3 targetPos = new(), uint itemLocation = 0, Angle? facingAngleOverride = null)
{
if (facingAngleOverride != null)
FaceDirection(facingAngleOverride.Value.ToDirection());

return UseActionLocationDetour(_inst, action.Type, action.ID, targetID, &targetPos, itemLocation);
}

// does all the sanity checks (that status is on actor, is a buff that can be canceled, etc.)
// on success, the status manager is updated immediately, meaning that no rate limiting is needed
Expand Down Expand Up @@ -342,7 +347,7 @@ private void UpdateDetour(ActionManager* self)
ActionType.Item => UseActionRaw(actionAdj, targetID, AutoQueue.TargetPos, 65535),
ActionType.BozjaHolsterSlot0 => BozjaInterop.UseFromHolster(AutoQueue.Action.As<BozjaHolsterID>(), 0),
ActionType.BozjaHolsterSlot1 => BozjaInterop.UseFromHolster(AutoQueue.Action.As<BozjaHolsterID>(), 1),
_ => UseActionRaw(actionAdj, targetID, AutoQueue.TargetPos)
_ => UseActionRaw(actionAdj, targetID, AutoQueue.TargetPos, 0, AutoQueue.FacingAngle)
};
//Service.Log($"[AMEx] Auto-execute {AutoQueue.Source} action {AutoQueue.Action} (=> {actionAdj}) @ {targetID:X} {Utils.Vec3String(AutoQueue.TargetPos)} => {res}");
}
Expand Down
Loading