Skip to content

Commit

Permalink
Merge branch 'lab' of https://github.com/Akechi-kun/ffxiv_bossmod int…
Browse files Browse the repository at this point in the history
…o lab
  • Loading branch information
Akechi-kun committed Feb 11, 2025
2 parents 50cbb72 + 1099ac0 commit 015b23d
Show file tree
Hide file tree
Showing 38 changed files with 526 additions and 80 deletions.
2 changes: 1 addition & 1 deletion BossMod/ActionTweaks/ActionTweaksConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ public enum GroundTargetingMode
[PropertyDisplay("Automatic target selection for ground-targeted abilities")]
public GroundTargetingMode GTMode = GroundTargetingMode.Manual;

[PropertyDisplay("Try to prevent dashing into AOEs", tooltip: "Prevent automatic use of damaging gap closers (like WAR Onslaught) if they would move you into a dangerous area. May not work as expected in instances that do not have modules.")]
[PropertyDisplay("Try to prevent dashing into AOEs", tooltip: "Prevent automatic use of damaging gap closers (like WAR Onslaught) if they would move you into a dangerous area. May not work as expected in instances that do not have modules.", since: "0.0.0.290")]
public bool PreventDangerousDash = false;
}
4 changes: 3 additions & 1 deletion BossMod/ActionTweaks/AutoAutosTweak.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ public bool GetDesiredState(bool currentState, ulong targetId)
if (_config.PyreticThreshold > 0 && hints.ImminentSpecialMode.mode == AIHints.SpecialMode.Pyretic && hints.ImminentSpecialMode.activation < ws.FutureTime(_config.PyreticThreshold))
return false; // pyretic => disable autos

if (hints.FindEnemy(target)?.Priority == AIHints.Enemy.PriorityForbidden)
var enemy = hints.FindEnemy(target);

if (enemy?.Priority == AIHints.Enemy.PriorityForbidden || enemy?.Spikes == true)
return false;

return player.InCombat || ws.Client.CountdownRemaining <= PrePullThreshold; // no reason not to enable autos!
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/MiscAI/AutoFarm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void prioritize(AIHints.Enemy e, int prio)
// first deal with pulling new enemies
if (allowPulling)
{
if (World.Client.ActiveFate.ID != 0 && Player.Level <= Service.LuminaRow<Lumina.Excel.Sheets.Fate>(World.Client.ActiveFate.ID)?.ClassJobLevelMax && strategy.Option(Track.Fate).As<PriorityStrategy>() == PriorityStrategy.Prioritize)
if (Utils.IsPlayerSyncedToFate(World) && strategy.Option(Track.Fate).As<PriorityStrategy>() == PriorityStrategy.Prioritize)
{
foreach (var e in Hints.PotentialTargets)
{
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 @@ -13,7 +13,7 @@ public static RotationModuleDefinition Definition()
def.AbilityTrack(Track.QuestBattle, "Automatically attack solo duty bosses");
def.AbilityTrack(Track.DeepDungeon, "Automatically attack deep dungeon bosses when solo");
def.AbilityTrack(Track.EpicEcho, "Automatically attack all targets if the Epic Echo status is present (i.e. when unsynced)");
def.AbilityTrack(Track.Hunt, "Automatically attack hunt marks once they have already been pulled");
def.AbilityTrack(Track.Hunt, "Automatically attack hunt marks once they are below 95% HP");

return def;
}
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Standard/xan/AI/TrackPartyHealth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ private PartyHealthState CalculatePartyHealthState(Func<Actor, bool> filter)

private PartyHealthState CalcPartyHealthInArea(WPos center, float radius) => CalculatePartyHealthState(act => act.Position.InCircle(center, radius));

public (Actor Target, PartyMemberState State)? BestSTHealTarget => PartyHealth.StdDev > AOEBreakpointHPVariance ? (World.Party[PartyHealth.LowestHPSlot]!, PartyMemberStates[PartyHealth.LowestHPSlot]) : null;
public (Actor Target, PartyMemberState State)? BestSTHealTarget => PartyHealth.StdDev > AOEBreakpointHPVariance || PartyHealth.Count == 1 ? (World.Party[PartyHealth.LowestHPSlot]!, PartyMemberStates[PartyHealth.LowestHPSlot]) : null;

public bool ShouldHealInArea(WPos center, float radius, float hpThreshold)
{
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Standard/xan/Basexan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,9 @@ public static RotationModuleDefinition DefineSharedTA(this RotationModuleDefinit
return def;
}

public static RotationModuleDefinition.ConfigRef<OffensiveStrategy> DefineSimple<Index>(this RotationModuleDefinition def, Index track, string name, int minLevel = 1) where Index : Enum
public static RotationModuleDefinition.ConfigRef<OffensiveStrategy> DefineSimple<Index>(this RotationModuleDefinition def, Index track, string name, int minLevel = 1, float uiPriority = 0) where Index : Enum
{
return def.Define(track).As<OffensiveStrategy>(name)
return def.Define(track).As<OffensiveStrategy>(name, uiPriority: uiPriority)
.AddOption(OffensiveStrategy.Automatic, "Auto", "Use when optimal", minLevel: minLevel)
.AddOption(OffensiveStrategy.Delay, "Delay", "Don't use", minLevel: minLevel)
.AddOption(OffensiveStrategy.Force, "Force", "Use ASAP", minLevel: minLevel);
Expand Down
2 changes: 2 additions & 0 deletions BossMod/Autorotation/Standard/xan/Casters/RDM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
if (primaryTarget is { } tar && (Swordplay > 0 || LowestMana >= comboMana || InCombo))
Hints.GoalZones.Add(Hints.GoalSingleTarget(tar.Actor, 3));

GoalZoneSingle(25);

OGCD(strategy, primaryTarget);

if (ComboLastMove is AID.Scorch)
Expand Down
5 changes: 1 addition & 4 deletions BossMod/Autorotation/Standard/xan/Healers/WHM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public static RotationModuleDefinition Definition()
public int NumHolyTargets;
public int NumAssizeTargets;
public int NumMiseryTargets;
public int NumSolaceTargets;

private Enemy? BestDotTarget;
private Enemy? BestMiseryTarget;
Expand All @@ -59,8 +58,6 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
(BestMiseryTarget, NumMiseryTargets) = SelectTarget(strategy, primaryTarget, 25, IsSplashTarget);
(BestDotTarget, TargetDotLeft) = SelectDotTarget(strategy, primaryTarget, DotLeft, 2);

NumSolaceTargets = World.Party.WithoutSlot(excludeAlliance: true).Count(x => Player.DistanceToHitbox(x) <= 20);

if (CountdownRemaining > 0)
{
if (CountdownRemaining < GetCastTime(AID.Stone1))
Expand Down Expand Up @@ -93,7 +90,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)

// TODO make a track for this
if (Lily == 3 || !CanFitGCD(NextLily, 2) && Lily == 2)
PushGCD(AID.AfflatusSolace, World.Party.WithoutSlot(excludeAlliance: true).Where(m => Player.DistanceToHitbox(m) <= 30).MinBy(PredictedHPRatio));
PushGCD(AID.AfflatusSolace, Player);

if (SacredSight > 0)
PushGCD(AID.GlareIV, primaryTarget);
Expand Down
122 changes: 79 additions & 43 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 { Potion = SharedTrack.Buffs, SSS, Meditation, FormShift, FiresReply, Nadi, RoF, RoW, PB, BH, TC, Blitz, Engage, TN }
public enum Track { BH = SharedTrack.Buffs, RoF, FiresReply, RoW, WindsReply, PB, Nadi, Blitz, SSS, FormShift, Meditation, TC, Potion, Engage, TN, Positional }
public enum PotionStrategy
{
Manual,
Expand All @@ -27,6 +27,12 @@ public enum FRStrategy
Force,
Delay
}
public enum WRStrategy
{
Automatic,
Force,
PreDowntime
}
public enum NadiStrategy
{
Automatic,
Expand Down Expand Up @@ -62,6 +68,11 @@ public enum TCStrategy
None,
GapClose
}
public enum PositionalStrategy
{
Automatic,
Ignore
}
public enum BlitzStrategy
{
Automatic,
Expand All @@ -83,73 +94,84 @@ public static RotationModuleDefinition Definition()
var def = new RotationModuleDefinition("xan MNK", "Monk", "Standard rotation (xan)|Melee", "xan", RotationModuleQuality.Good, BitMask.Build(Class.MNK, Class.PGL), 100);

def.DefineSharedTA();
def.Define(Track.Potion).As<PotionStrategy>("Pot")
.AddOption(PotionStrategy.Manual, "Do not automatically use")
.AddOption(PotionStrategy.PreBuffs, "Use ~4 GCDs before raid buff window")
.AddOption(PotionStrategy.Now, "Use ASAP");

def.DefineSimple(Track.SSS, "SixSidedStar", minLevel: 80).AddAssociatedActions(AID.SixSidedStar);

def.Define(Track.Meditation).As<MeditationStrategy>("Meditate")
.AddOption(MeditationStrategy.Safe, "Use out of combat, during countdown, or if no enemies are targetable")
.AddOption(MeditationStrategy.Greedy, "Allow using when primary enemy is targetable, but out of range")
.AddOption(MeditationStrategy.Force, "Use even if enemy is in melee range")
.AddOption(MeditationStrategy.Delay, "Do not use")
.AddAssociatedActions(AID.SteeledMeditation);

def.DefineSimple(Track.FormShift, "FormShift", minLevel: 52).AddAssociatedActions(AID.FormShift);
// buffs
def.DefineSimple(Track.BH, "BH", minLevel: 70, uiPriority: 99).AddAssociatedActions(AID.Brotherhood);

def.Define(Track.FiresReply).As<FRStrategy>("FiresReply")
def.Define(Track.RoF).As<RoFStrategy>("RoF", uiPriority: 96)
.AddOption(RoFStrategy.Automatic, "Auto", "Automatically use RoF during burst window", minLevel: 68)
.AddOption(RoFStrategy.Force, "Force", "Use ASAP", minLevel: 68)
.AddOption(RoFStrategy.ForceMidWeave, "ForceMid", "Use ASAP, but retain late-weave to ensure maximum GCDs covered", minLevel: 68)
.AddOption(RoFStrategy.Delay, "Delay", "Do not use", minLevel: 68)
.AddAssociatedActions(AID.RiddleOfFire);
def.Define(Track.FiresReply).As<FRStrategy>("FiresReply", uiPriority: 95)
.AddOption(FRStrategy.Automatic, "Use after Opo GCD", minLevel: 100)
.AddOption(FRStrategy.Ranged, "Use when out of melee range, or if about to expire", minLevel: 100)
.AddOption(FRStrategy.Force, "Use ASAP", minLevel: 100)
.AddOption(FRStrategy.Delay, "Do not use", minLevel: 100)
.AddAssociatedActions(AID.FiresReply);

def.Define(Track.Nadi).As<NadiStrategy>("Nadi")
.AddOption(NadiStrategy.Automatic, "Automatically choose best nadi (double lunar opener, otherwise alternate)", minLevel: 60)
.AddOption(NadiStrategy.Lunar, "Lunar", minLevel: 60)
.AddOption(NadiStrategy.Solar, "Solar", minLevel: 60);

def.Define(Track.RoF).As<RoFStrategy>("RoF")
.AddOption(RoFStrategy.Automatic, "Auto", "Automatically use RoF during burst window", minLevel: 68)
.AddOption(RoFStrategy.Force, "Force", "Use ASAP", minLevel: 68)
.AddOption(RoFStrategy.ForceMidWeave, "ForceMid", "Use ASAP, but retain late-weave to ensure maximum GCDs covered", minLevel: 68)
.AddOption(RoFStrategy.Delay, "Delay", "Do not use", minLevel: 68)
.AddAssociatedActions(AID.RiddleOfFire);
def.DefineSimple(Track.RoW, "RoW", minLevel: 72, uiPriority: 94).AddAssociatedActions(AID.RiddleOfWind);
def.Define(Track.WindsReply).As<WRStrategy>("WindsReply", uiPriority: 93)
.AddOption(WRStrategy.Automatic, "Use out of melee range, or if about to expire", minLevel: 96)
.AddOption(WRStrategy.Force, "Use ASAP", minLevel: 96)
.AddOption(WRStrategy.PreDowntime, "Ensure usage at least 2 GCDs before next downtime", minLevel: 96)
.AddAssociatedActions(AID.WindsReply);

def.DefineSimple(Track.RoW, "RoW", minLevel: 72).AddAssociatedActions(AID.RiddleOfWind);

def.Define(Track.PB).As<PBStrategy>("PB")
// 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)
.AddOption(PBStrategy.ForceOpo, "Use ASAP after next Opo", minLevel: 50)
.AddOption(PBStrategy.Force, "Use ASAP", minLevel: 50)
.AddOption(PBStrategy.Delay, "Do not use", minLevel: 50)
.AddOption(PBStrategy.DowntimeSolar, "Downtime prep: Solar", minLevel: 60, effect: 39)
.AddOption(PBStrategy.DowntimeLunar, "Downtime prep: Lunar", minLevel: 60, effect: 39)
.AddAssociatedActions(AID.PerfectBalance);

def.DefineSimple(Track.BH, "BH", minLevel: 70).AddAssociatedActions(AID.Brotherhood);
def.Define(Track.TC).As<TCStrategy>("TC")
.AddOption(TCStrategy.None, "Do not use", minLevel: 35)
.AddOption(TCStrategy.GapClose, "Use if outside melee range", minLevel: 35)
.AddAssociatedActions(AID.Thunderclap);

def.Define(Track.Blitz).As<BlitzStrategy>("Blitz")
def.Define(Track.Nadi).As<NadiStrategy>("Nadi", uiPriority: 88)
.AddOption(NadiStrategy.Automatic, "Automatically choose best nadi (double lunar opener, otherwise alternate)", minLevel: 60)
.AddOption(NadiStrategy.Lunar, "Lunar", minLevel: 60)
.AddOption(NadiStrategy.Solar, "Solar", minLevel: 60);
def.Define(Track.Blitz).As<BlitzStrategy>("Blitz", uiPriority: 87)
.AddOption(BlitzStrategy.Automatic, "Use ASAP", minLevel: 60)
.AddOption(BlitzStrategy.RoF, "Hold blitz until Riddle of Fire is active", minLevel: 60)
.AddOption(BlitzStrategy.Multi, "Hold blitz until at least two targets will be hit", minLevel: 60)
.AddOption(BlitzStrategy.MultiRoF, "Hold blitz until Riddle of Fire and 2+ targets", minLevel: 60)
.AddOption(BlitzStrategy.Delay, "Do not use", minLevel: 60)
.AddAssociatedActions(AID.ElixirField, AID.FlintStrike, AID.TornadoKick, AID.ElixirBurst, AID.RisingPhoenix, AID.PhantomRush);

def.Define(Track.Engage).As<EngageStrategy>("Engage")
// downtime stuff
def.DefineSimple(Track.SSS, "SixSidedStar", minLevel: 80, uiPriority: 79).AddAssociatedActions(AID.SixSidedStar);
def.DefineSimple(Track.FormShift, "FormShift", minLevel: 52, uiPriority: 78).AddAssociatedActions(AID.FormShift);
def.Define(Track.Meditation).As<MeditationStrategy>("Meditate", uiPriority: 77)
.AddOption(MeditationStrategy.Safe, "Use out of combat, during countdown, or if no enemies are targetable")
.AddOption(MeditationStrategy.Greedy, "Allow using when primary enemy is targetable, but out of range")
.AddOption(MeditationStrategy.Force, "Use even if enemy is in melee range")
.AddOption(MeditationStrategy.Delay, "Do not use")
.AddAssociatedActions(AID.SteeledMeditation);

// other utils
def.Define(Track.TC).As<TCStrategy>("TC", uiPriority: 69)
.AddOption(TCStrategy.None, "Do not use", minLevel: 35)
.AddOption(TCStrategy.GapClose, "Use if outside melee range", minLevel: 35)
.AddAssociatedActions(AID.Thunderclap);

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");

def.Define(Track.Engage).As<EngageStrategy>("Engage", uiPriority: 49)
.AddOption(EngageStrategy.TC, "Thunderclap to target")
.AddOption(EngageStrategy.Sprint, "Sprint to melee range")
.AddOption(EngageStrategy.FacepullDK, "Precast Dragon Kick from melee range")
.AddOption(EngageStrategy.FacepullDemo, "Precast Demolish from melee range");

def.DefineSimple(Track.TN, "TrueNorth", minLevel: 50).AddAssociatedActions(AID.TrueNorth);
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 @@ -191,6 +213,8 @@ public enum Form { None, OpoOpo, Raptor, Coeurl }

protected override float GetCastTime(AID aid) => 0;

public float EffectiveDowntimeIn => MathF.Max(0, DowntimeIn - GetApplicationDelay(AID.SixSidedStar));

private (AID action, bool isTargeted) GetCurrentBlitz()
{
if (BeastCount != 3)
Expand Down Expand Up @@ -344,7 +368,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)

UseBlitz(strategy, currentBlitz);
FiresReply(strategy);
WindsReply();
WindsReply(strategy);

if (UseAOE)
{
Expand Down Expand Up @@ -379,14 +403,15 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)
PushGCD(AID.SixSidedStar, primaryTarget, GCDPriority.SSS);
break;
case OffensiveStrategy.Automatic:
if (DowntimeIn > 0 && !CanFitGCD(DowntimeIn - GetApplicationDelay(AID.SixSidedStar), 1))
if (EffectiveDowntimeIn > 0 && !CanFitGCD(EffectiveDowntimeIn, 1))
PushGCD(AID.SixSidedStar, primaryTarget, GCDPriority.SSS);
break;
}

Prep(strategy);

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

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

GoalZoneCombined(strategy, 3, Hints.GoalAOECircle(5), AID.ArmOfTheDestroyer, AOEBreakpoint, positional: pos.Item1, maximumActionRange: 20);
Expand Down Expand Up @@ -664,7 +689,7 @@ private void FiresReply(StrategyValues strategy)
PushGCD(AID.FiresReply, BestRangedTarget, prio);
}

private void WindsReply()
private void WindsReply(StrategyValues strategy)
{
if (WindsReplyLeft <= GCD)
return;
Expand All @@ -676,6 +701,17 @@ private void WindsReply()
if (FireLeft > GCD && !CanFitGCD(FireLeft, 1) || !CanFitGCD(WindsReplyLeft, 1))
prio = GCDPriority.WindsReply;

switch (strategy.Option(Track.WindsReply).As<WRStrategy>())
{
case WRStrategy.Force:
prio = GCDPriority.WindsReply;
break;
case WRStrategy.PreDowntime:
if (EffectiveDowntimeIn < WindsReplyLeft && !CanFitGCD(EffectiveDowntimeIn, 2))
prio = GCDPriority.WindsReply;
break;
}

PushGCD(AID.WindsReply, BestLineTarget, prio);
}

Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Standard/xan/Ranged/MCH.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public override void Exec(StrategyValues strategy, Enemy? primaryTarget)

private void OGCD(StrategyValues strategy, Enemy? primaryTarget)
{
if (CountdownRemaining == null && !Player.InCombat && Player.DistanceToHitbox(primaryTarget) <= 25 && ReassembleLeft == 0 && !Overheated && AlwaysReassemble(NextGCD))
if (CountdownRemaining == null && !Player.InCombat && Player.DistanceToHitbox(primaryTarget) <= 25 && ReassembleLeft == 0 && ShouldReassemble(strategy, primaryTarget))
PushGCD(AID.Reassemble, Player, priority: 50);

if (!Player.InCombat || primaryTarget == null)
Expand Down
Loading

0 comments on commit 015b23d

Please sign in to comment.