Skip to content

Commit

Permalink
Merge branch 'awgil:master' into lab
Browse files Browse the repository at this point in the history
  • Loading branch information
Akechi-kun authored Feb 20, 2025
2 parents f1e9118 + b577ebf commit bb9fd42
Show file tree
Hide file tree
Showing 37 changed files with 503 additions and 99 deletions.
27 changes: 19 additions & 8 deletions BossMod/Autorotation/MiscAI/AutoFarm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

public sealed class AutoFarm(RotationModuleManager manager, Actor player) : RotationModule(manager, player)
{
public enum Track { General, Fate, Specific }
public enum Track { General, Fate, Specific, Mount }
public enum GeneralStrategy { FightBack, AllowPull, Aggressive, Passive }
public enum PriorityStrategy { None, Prioritize }
public enum MountedStrategy { None, DisableFightBack, DisableAll }

public static RotationModuleDefinition Definition()
{
Expand All @@ -24,6 +25,11 @@ public static RotationModuleDefinition Definition()
.AddOption(PriorityStrategy.None, "None", "Do not do anything special")
.AddOption(PriorityStrategy.Prioritize, "Prioritize", "Prioritize specific mobs by targeting criterion");

res.Define(Track.Mount).As<MountedStrategy>("Mount")
.AddOption(MountedStrategy.None, "None", "Do not do anything special")
.AddOption(MountedStrategy.DisableFightBack, "NoFightBack", "Do not engage previously uninteresting mobs if they aggro on player")
.AddOption(MountedStrategy.DisableAll, "NoAll", "Do not engage anything while mounted");

return res;
}

Expand All @@ -34,6 +40,11 @@ public override void Execute(StrategyValues strategy, ref Actor? primaryTarget,
if (generalStrategy == GeneralStrategy.Passive)
return;

var mountStrategy = strategy.Option(Track.Mount).As<MountedStrategy>();
var mounted = Player.MountId > 0;
if (mounted && mountStrategy == MountedStrategy.DisableAll)
return;

var allowPulling = generalStrategy switch
{
GeneralStrategy.AllowPull => !Player.InCombat,
Expand All @@ -58,14 +69,12 @@ void prioritize(AIHints.Enemy e, int prio)
// first deal with pulling new enemies
if (allowPulling)
{
if (Utils.IsPlayerSyncedToFate(World) && strategy.Option(Track.Fate).As<PriorityStrategy>() == PriorityStrategy.Prioritize)
var allowFate = Utils.IsPlayerSyncedToFate(World) && strategy.Option(Track.Fate).As<PriorityStrategy>() == PriorityStrategy.Prioritize;
foreach (var e in Hints.PotentialTargets)
{
foreach (var e in Hints.PotentialTargets)
if (allowFate && e.Actor.FateID == World.Client.ActiveFate.ID && e.Priority == AIHints.Enemy.PriorityUndesirable)
{
if (e.Actor.FateID == World.Client.ActiveFate.ID && e.Priority == AIHints.Enemy.PriorityUndesirable)
{
prioritize(e, 1);
}
prioritize(e, 1);
}
}

Expand All @@ -85,7 +94,9 @@ void prioritize(AIHints.Enemy e, int prio)
}

// if we did not select an enemy to pull, see if we can target something higher-priority than what we have now
if (switchTarget == null && Player.InCombat)
// if mounted, check if the "fight back" strategy is undesired
var mountNoFightBack = mounted && mountStrategy == MountedStrategy.DisableFightBack;
if (switchTarget == null && Player.InCombat && !mountNoFightBack)
{
var curTargetPrio = Hints.FindEnemy(primaryTarget)?.Priority ?? int.MinValue;
switchTarget = ResolveTargetOverride(generalOpt.Value) ?? (curTargetPrio < Hints.HighestPotentialTargetPriority ? Hints.PriorityTargets.MinBy(e => (e.Actor.Position - Player.Position).LengthSq())?.Actor : null);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/MiscAI/AutoPull.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public enum Track { QuestBattle, DeepDungeon, EpicEcho, Hunt }

public static RotationModuleDefinition Definition()
{
var def = new RotationModuleDefinition("Misc AI: Auto-pull", "Automatically attack passive mobs in certain circumstances", "Misc", "xan", RotationModuleQuality.Basic, new(~0ul), 1000, Order: RotationModuleOrder.HighLevel, CanUseWhileRoleplaying: true);
var def = new RotationModuleDefinition("Auto-pull", "Automatically attack passive mobs in certain circumstances", "AI", "xan", RotationModuleQuality.Basic, new(~0ul), 1000, Order: RotationModuleOrder.HighLevel, CanUseWhileRoleplaying: true);

def.AbilityTrack(Track.QuestBattle, "Automatically attack solo duty bosses");
def.AbilityTrack(Track.DeepDungeon, "Automatically attack deep dungeon bosses when solo");
Expand Down
7 changes: 6 additions & 1 deletion BossMod/Autorotation/RotationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,14 @@ public int FindDutyActionSlot(ActionID action, ActionID other)

protected (Actor? Target, P Priority) FindBetterTargetBy<P>(Actor? initial, float maxDistanceFromPlayer, Func<Actor, P> prioFunc, Func<AIHints.Enemy, bool>? filterFunc = null) where P : struct, IComparable
{
bool inRange(Actor tar) => tar.Position.InCircle(Player.Position, maxDistanceFromPlayer + tar.HitboxRadius + 0.5f);

if (initial != null && !inRange(initial))
initial = null;

var bestTarget = initial;
var bestPrio = initial != null ? prioFunc(initial) : default;
foreach (var enemy in Hints.PriorityTargets.Where(x => x.Actor != initial && x.Actor.Position.InCircle(Player.Position, maxDistanceFromPlayer + x.Actor.HitboxRadius) && (filterFunc?.Invoke(x) ?? true)))
foreach (var enemy in Hints.PriorityTargets.Where(x => x.Actor != initial && inRange(x.Actor) && (filterFunc?.Invoke(x) ?? true)))
{
var newPrio = prioFunc(enemy.Actor);
if (newPrio.CompareTo(bestPrio) > 0)
Expand Down
19 changes: 16 additions & 3 deletions BossMod/Autorotation/Standard/xan/AI/Healer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ public class HealerAI(RotationModuleManager manager, Actor player) : AIBase(mana
private readonly TrackPartyHealth Health = new(manager.WorldState);

public enum Track { Raise, RaiseTarget, Heal, Esuna, StayNearParty }
public enum EsunaStrategy
{
None,
Hinted,
All
}
public enum RaiseStrategy
{
None,
Expand Down Expand Up @@ -48,7 +54,12 @@ public static RotationModuleDefinition Definition()
.AddOption(RaiseTarget.Everyone, "Any dead player");

def.AbilityTrack(Track.Heal, "Heal");
def.AbilityTrack(Track.Esuna, "Esuna");

def.Define(Track.Esuna).As<EsunaStrategy>("Esuna")
.AddOption(EsunaStrategy.None, "Don't cleanse")
.AddOption(EsunaStrategy.Hinted, "Cleanse targets suggested by active module")
.AddOption(EsunaStrategy.All, "Cleanse all party members that have a removable debuff");

def.AbilityTrack(Track.StayNearParty, "Stay near party");

return def;
Expand Down Expand Up @@ -97,11 +108,13 @@ public override void Execute(StrategyValues strategy, ref Actor? primaryTarget,

AutoRaise(strategy);

if (strategy.Enabled(Track.Esuna))
var esuna = strategy.Option(Track.Esuna).As<EsunaStrategy>();

if (esuna != EsunaStrategy.None)
{
foreach (var st in Health.PartyMemberStates)
{
if (st.EsunableStatusRemaining > GCD + 2f)
if (st.EsunableStatusRemaining > GCD + 1.14f && (esuna == EsunaStrategy.All || Hints.ShouldCleanse[st.Slot]))
{
UseGCD(BossMod.WHM.AID.Esuna, World.Party[st.Slot]);
break;
Expand Down
24 changes: 12 additions & 12 deletions BossMod/Autorotation/Standard/xan/AI/Tank.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,21 +202,21 @@ private void AutoProtect()

private void AutoMit()
{
if (EnemiesAutoingMe.Any())
{
if (Player.PredictedHPRatio < 0.8)
{
var delay = 0f;
if (JobActions.ShortMit.ID == ActionID.MakeSpell(WAR.AID.RawIntuition))
delay = GCD - 0.8f;
Hints.ActionsToExecute.Push(JobActions.ShortMit.ID, Player, ActionQueue.Priority.Minimal, delay: delay);
}
if (Player.PredictedHPRaw == Player.HPMP.CurHP && !Player.InCombat)
return;

if (Player.PredictedHPRatio < 0.6)
// set arbitrary deadline to 1 second in the future
UseOneMit(1);
if (Player.PredictedHPRatio < 0.8)
{
var delay = 0f;
if (JobActions.ShortMit.ID == ActionID.MakeSpell(WAR.AID.RawIntuition))
delay = GCD - 0.8f;
Hints.ActionsToExecute.Push(JobActions.ShortMit.ID, Player, ActionQueue.Priority.Minimal, delay: delay);
}

if (Player.PredictedHPRatio < 0.6)
// set arbitrary deadline to 1 second in the future
UseOneMit(1);

// TODO figure out how consistent this is or if we should use predictively instead
if (Player.PredictedHPRaw <= 0)
Hints.ActionsToExecute.Push(JobActions.Invuln.ID, Player, ActionQueue.Priority.VeryHigh);
Expand Down
11 changes: 7 additions & 4 deletions BossMod/Autorotation/Standard/xan/Basexan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ P targetPrio(Actor potentialTarget)
targeting = Targeting.Manual;

if (targeting == Targeting.AutoTryPri)
targeting = primaryTarget == null ? Targeting.Auto : Targeting.AutoPrimary;
targeting = Player.DistanceToHitbox(primaryTarget) <= range ? Targeting.AutoPrimary : Targeting.Auto;

var (newtarget, newprio) = targeting switch
{
Expand Down Expand Up @@ -288,8 +288,10 @@ protected void GoalZoneSingle(float range)
Hints.GoalZones.Add(Hints.GoalSingleTarget(PlayerTarget.Actor, range));
}

protected void GoalZoneCombined(StrategyValues strategy, float range, Func<WPos, float> fAoe, AID firstUnlockedAoeAction, int minAoe, Positional positional = Positional.Any, float? maximumActionRange = null)
protected void GoalZoneCombined(StrategyValues strategy, float range, Func<WPos, float> fAoe, AID firstUnlockedAoeAction, int minAoe, float? maximumActionRange = null)
{
var (_, positional, imminent, _) = Hints.RecommendedPositional;

if (!strategy.AOEOk() || !Unlocked(firstUnlockedAoeAction))
minAoe = 50;

Expand All @@ -300,7 +302,7 @@ protected void GoalZoneCombined(StrategyValues strategy, float range, Func<WPos,
}
else
{
Hints.GoalZones.Add(Hints.GoalCombined(Hints.GoalSingleTarget(PlayerTarget.Actor, positional, range), fAoe, minAoe));
Hints.GoalZones.Add(Hints.GoalCombined(Hints.GoalSingleTarget(PlayerTarget.Actor, imminent ? positional : Positional.Any, range), fAoe, minAoe));
if (maximumActionRange is float r)
Hints.GoalZones.Add(Hints.GoalSingleTarget(PlayerTarget.Actor, r, 0.5f));
}
Expand Down Expand Up @@ -350,8 +352,9 @@ protected int AdjustNumTargets(StrategyValues strategy, int reported)
protected bool NextPositionalImminent;
protected bool NextPositionalCorrect;

protected void UpdatePositionals(Enemy? enemy, ref (Positional pos, bool imm) positional, bool trueNorth)
protected void UpdatePositionals(Enemy? enemy, ref (Positional pos, bool imm) positional)
{
var trueNorth = TrueNorthLeft > GCD;
var target = enemy?.Actor;
if ((target?.Omnidirectional ?? true) || target?.TargetID == Player.InstanceID && target?.CastInfo == null && positional.pos != Positional.Front && target?.NameID != 541)
positional = (Positional.Any, false);
Expand Down
3 changes: 2 additions & 1 deletion BossMod/Autorotation/Standard/xan/Casters/RDM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ private void OGCD(StrategyValues strategy, Enemy? primaryTarget)
if (strategy.BuffsOk())
{
PushOGCD(AID.Embolden, Player);
PushOGCD(AID.Manafication, Player);
if (!InCombo)
PushOGCD(AID.Manafication, Player);
}

PushOGCD(AID.ContreSixte, BestAOETarget);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Standard/xan/Healers/WHM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
PushGCD(AID.Holy1, Player);

// TODO make a track for this
if (Lily == 3 || !CanFitGCD(NextLily, 2) && Lily == 2)
if (Unlocked(AID.AfflatusMisery) && (Lily == 3 || !CanFitGCD(NextLily, 2) && Lily == 2))
PushGCD(AID.AfflatusSolace, Player);

if (SacredSight > 0)
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Standard/xan/Melee/DRG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
(BestDiveTarget, NumDiveTargets) = SelectTarget(strategy, primaryTarget, 20, IsSplashTarget);

var pos = GetPositional(strategy, primaryTarget);
UpdatePositionals(primaryTarget, ref pos, TrueNorthLeft > GCD);
UpdatePositionals(primaryTarget, ref pos);

if (primaryTarget == null)
return;
Expand All @@ -94,7 +94,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
return;
}

GoalZoneCombined(strategy, 3, Hints.GoalAOERect(primaryTarget.Actor, 10, 2), AID.DoomSpike, minAoe: 3, positional: pos.Item1, maximumActionRange: 20);
GoalZoneCombined(strategy, 3, Hints.GoalAOERect(primaryTarget.Actor, 10, 2), AID.DoomSpike, minAoe: 3, maximumActionRange: 20);

if (NumAOETargets > 2)
{
Expand Down
26 changes: 12 additions & 14 deletions BossMod/Autorotation/Standard/xan/Melee/MNK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace BossMod.Autorotation.xan;

public sealed class MNK(RotationModuleManager manager, Actor player) : Attackxan<AID, TraitID>(manager, player)
{
public enum Track { BH = SharedTrack.Buffs, RoF, FiresReply, RoW, WindsReply, PB, Nadi, Blitz, SSS, FormShift, Meditation, TC, Potion, Engage, TN, Positional }
public enum Track { BH = SharedTrack.Buffs, RoF, FiresReply, RoW, WindsReply, PB, Nadi, Blitz, SSS, FormShift, Meditation, TC, Potion, Engage, TN }
public enum PotionStrategy
{
Manual,
Expand Down Expand Up @@ -118,7 +118,6 @@ public static RotationModuleDefinition Definition()
.AddOption(WRStrategy.PreDowntime, "Ensure usage at least 2 GCDs before next downtime", minLevel: 96)
.AddAssociatedActions(AID.WindsReply);


// PB-related settings
def.Define(Track.PB).As<PBStrategy>("PB", uiPriority: 89)
.AddOption(PBStrategy.Automatic, "Automatically use after Opo before or during Riddle of Fire", minLevel: 50)
Expand Down Expand Up @@ -159,7 +158,8 @@ public static RotationModuleDefinition Definition()
def.Define(Track.Potion).As<PotionStrategy>("Pot", uiPriority: 59)
.AddOption(PotionStrategy.Manual, "Do not automatically use")
.AddOption(PotionStrategy.PreBuffs, "Use ~4 GCDs before raid buff window")
.AddOption(PotionStrategy.Now, "Use ASAP");
.AddOption(PotionStrategy.Now, "Use ASAP")
.AddAssociatedAction(ActionDefinitions.IDPotionStr);

def.Define(Track.Engage).As<EngageStrategy>("Engage", uiPriority: 49)
.AddOption(EngageStrategy.TC, "Thunderclap to target")
Expand All @@ -168,10 +168,6 @@ public static RotationModuleDefinition Definition()
.AddOption(EngageStrategy.FacepullDemo, "Precast Demolish from melee range");

def.DefineSimple(Track.TN, "TrueNorth", minLevel: 50, uiPriority: 48).AddAssociatedActions(AID.TrueNorth);
def.Define(Track.Positional).As<PositionalStrategy>("Pos (AI)", uiPriority: 45)
.AddOption(PositionalStrategy.Automatic, "Tell AI mode to navigate to hit positionals")
.AddOption(PositionalStrategy.Ignore, "Tell AI mode to ignore positionals")
.AddAssociatedActions(AID.Demolish, AID.SnapPunch, AID.PouncingCoeurl);

return def;
}
Expand Down Expand Up @@ -410,11 +406,11 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)

Prep(strategy);

var pos = strategy.Option(Track.Positional).As<PositionalStrategy>() == PositionalStrategy.Automatic ? NextPositional : (Positional.Any, false);
var pos = NextPositional;

UpdatePositionals(primaryTarget, ref pos, TrueNorthLeft > GCD);
UpdatePositionals(primaryTarget, ref pos);

GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.ArmOfTheDestroyer, AOEBreakpoint, positional: pos.Item1, maximumActionRange: 20);
GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.ArmOfTheDestroyer, AOEBreakpoint, maximumActionRange: 20);

if (Player.InCombat)
OGCD(strategy, primaryTarget);
Expand Down Expand Up @@ -548,14 +544,16 @@ private void QueuePB(StrategyValues strategy, Enemy? primaryTarget)

private void OGCD(StrategyValues strategy, Enemy? primaryTarget)
{
switch (strategy.Option(Track.Potion).As<PotionStrategy>())
var potionTrack = strategy.Option(Track.Potion);
var potionPrio = potionTrack.Priority(ActionQueue.Priority.Low + 100 + (float)OGCDPriority.Potion);
switch (potionTrack.As<PotionStrategy>())
{
case PotionStrategy.Now:
Potion();
Potion(potionPrio);
break;
case PotionStrategy.PreBuffs:
if (HaveTarget && CanWeave(AID.Brotherhood, 4))
Potion();
Potion(potionPrio);
break;
}

Expand Down Expand Up @@ -718,7 +716,7 @@ private void WindsReply(StrategyValues strategy)
private float DesiredFireWindow => GCDLength * 10;
private float EarliestRoF(float estimatedDelay) => MathF.Max(estimatedDelay + 0.8f, 20.6f - DesiredFireWindow);

private void Potion() => Hints.ActionsToExecute.Push(ActionDefinitions.IDPotionStr, Player, ActionQueue.Priority.Low + 100 + (float)OGCDPriority.Potion);
private void Potion(float priority) => Hints.ActionsToExecute.Push(ActionDefinitions.IDPotionStr, Player, priority);

private (bool Use, bool LateWeave) ShouldRoF(StrategyValues strategy, int extraGCDs = 0)
{
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Standard/xan/Melee/NIN.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
NumAOETargets = NumMeleeAOETargets(strategy);

var pos = GetNextPositional(primaryTarget?.Actor);
UpdatePositionals(primaryTarget, ref pos, TrueNorthLeft > GCD);
UpdatePositionals(primaryTarget, ref pos);

OGCD(strategy, primaryTarget);

Expand All @@ -133,7 +133,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
return;
}

GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.DeathBlossom, minAoe: 3, positional: pos.Item1, maximumActionRange: 20);
GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.DeathBlossom, minAoe: 3, maximumActionRange: 20);

if (TenChiJin.Left > GCD)
{
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Standard/xan/Melee/RPR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
(BestRangedAOETarget, NumRangedAOETargets) = SelectTarget(strategy, primaryTarget, 25, IsSplashTarget);

var pos = GetNextPositional(primaryTarget?.Actor);
UpdatePositionals(primaryTarget, ref pos, TrueNorthLeft > GCD);
UpdatePositionals(primaryTarget, ref pos);

OGCD(strategy, primaryTarget);

Expand All @@ -136,7 +136,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
return;
}

GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.SpinningScythe, 3, pos.Item1, maximumActionRange: 25);
GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.SpinningScythe, 3, maximumActionRange: 25);

if (SoulReaver > GCD || Executioner > GCD)
{
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Standard/xan/Melee/SAM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
}

var pos = GetNextPositional(strategy);
UpdatePositionals(primaryTarget, ref pos, TrueNorthLeft > GCD);
UpdatePositionals(primaryTarget, ref pos);

OGCD(strategy, primaryTarget);

Expand All @@ -171,7 +171,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
return;
}

GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(NumStickers == 2 ? 8 : 5), AID.Fuga, 3, pos.Item1, 20);
GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(NumStickers == 2 ? 8 : 5), AID.Fuga, 3, 20);

EmergencyMeikyo(strategy, primaryTarget);
UseKaeshi(primaryTarget);
Expand Down
Loading

0 comments on commit bb9fd42

Please sign in to comment.