Skip to content

Commit

Permalink
Merge pull request #557 from Akechi-kun/hmph
Browse files Browse the repository at this point in the history
[akechi/Utility] fixes, adjustments, & new additions
  • Loading branch information
awgil authored Dec 30, 2024
2 parents a7f1716 + df2559d commit e8aba80
Show file tree
Hide file tree
Showing 20 changed files with 2,051 additions and 910 deletions.
10 changes: 9 additions & 1 deletion BossMod/ActionQueue/Healers/SCH.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,18 @@ public enum SID : uint
Sleep = 3, // applied by Repose to target
BanefulImpaction = 3883, // applied by Baneful Impaction to target
ImpactImminent = 3882, // applied by Chain Stratagem to self
ChainStratagem = 1221, // applied by Chain Stratagem to target
FeyUnion = 1222, // applied by Aetherpact to target
Seraphism = 3884, // applied by Seraphism to self

//Shared
Swiftcast = ClassShared.SID.Swiftcast, // applied by Swiftcast to self
}

public sealed class Definitions : IDisposable
{
private readonly SCHConfig _config = Service.Config.Get<SCHConfig>();

public Definitions(ActionDefinitions d)
{
d.RegisterSpell(AID.AngelFeathers, castAnimLock: 8.10f); // animLock=8.100s?
Expand Down Expand Up @@ -159,6 +164,9 @@ public void Dispose() { }

private void Customize(ActionDefinitions d)
{
// *** add any properties that can't be autogenerated here ***
d.Spell(AID.Broil1)!.ForbidExecute = (ws, player, _, _) => _config.ForbidEarlyBroil && !player.InCombat && ws.Client.CountdownRemaining > 1.5f;
d.Spell(AID.Broil2)!.ForbidExecute = (ws, player, _, _) => _config.ForbidEarlyBroil && !player.InCombat && ws.Client.CountdownRemaining > 1.5f;
d.Spell(AID.Broil3)!.ForbidExecute = (ws, player, _, _) => _config.ForbidEarlyBroil && !player.InCombat && ws.Client.CountdownRemaining > 1.5f;
d.Spell(AID.Broil4)!.ForbidExecute = (ws, player, _, _) => _config.ForbidEarlyBroil && !player.InCombat && ws.Client.CountdownRemaining > 1.5f;
}
}
1 change: 1 addition & 0 deletions BossMod/ActionQueue/Melee/DRG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public enum SID : uint
NastrondReady = 3844, // applied by Geirskogul to self
DragonsFlight = 3845, // applied by Dragonfire Dive to self
StarcrossReady = 3846, // applied by Stardiver to self
EnhancedPiercingTalon = 1870, // applied by Elusive Jump to self

//Shared
Feint = ClassShared.SID.Feint, // applied by Feint to target
Expand Down
1 change: 1 addition & 0 deletions BossMod/ActionQueue/Melee/SAM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public enum SID : uint
Tengentsu = 3853, // applied by Tengentsu to self
ZanshinReady = 3855, // applied by Ikishoten to self
Tendo = 3856, // applied by Meikyo Shisui to self
TsubameReady = 4216, // applied by Midare Setsugekka to self

//Shared
Feint = ClassShared.SID.Feint, // applied by Feint to target
Expand Down
15 changes: 8 additions & 7 deletions BossMod/ActionQueue/Tanks/DRK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,14 @@ public enum TraitID : uint
public enum SID : uint
{
None = 0,
Oblation = 2682,
BloodWeapon = 742,
Grit = 743,
SaltedEarth = 749,
Delirium = 1972,
EnhancedDelirium = 3836,
Scorn = 3837,
BloodWeapon = 742, // applied by BloodWeapon to self
Grit = 743, // applied by Grit to self
SaltedEarth = 749, // applied by Salted Earth
TheBlackestNight = 1308, // applied by The Blackest Night to target
Delirium = 1972, // applied by Delirium to self
Oblation = 2682, // applied by Oblation to target
EnhancedDelirium = 3836, // applied by Delirium to self (Lv96+)
Scorn = 3837, // applied by Living Shadow to self

//Shared
Reprisal = ClassShared.SID.Reprisal, // applied by Reprisal to target
Expand Down
8 changes: 8 additions & 0 deletions BossMod/ActionTweaks/ClassActions/SCHConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BossMod;

[ConfigDisplay(Parent = typeof(ActionTweaksConfig))]
class SCHConfig : ConfigNode
{
[PropertyDisplay("Prevent use of 'Broil' too early when in pre-pull")]
public bool ForbidEarlyBroil = true;
}
101 changes: 90 additions & 11 deletions BossMod/Autorotation/Utility/ClassASTUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

public sealed class ClassASTUtility(RotationModuleManager manager, Actor player) : RoleHealerUtility(manager, player)
{
public enum Track { Helios = SharedTrack.Count, Lightspeed, BeneficII, EssentialDignity, AspectedBenefic, AspectedHelios, Synastry, CollectiveUnconscious, CelestialOpposition, CelestialIntersection, Horoscope, NeutralSect, Exaltation, Macrocosmos, SunSign }
public enum Track { Helios = SharedTrack.Count, Lightspeed, BeneficII, EssentialDignity, AspectedBenefic, AspectedHelios, Synastry, CollectiveUnconscious, CelestialOpposition, EarthlyStar, CelestialIntersection, Horoscope, NeutralSect, Exaltation, Macrocosmos, SunSign }
public enum StarOption { None, Use, End }
public enum HoroscopeOption { None, Use, End }
public enum MacrocosmosOption { None, Use, End }
public enum HeliosOption { None, Use, UseEx }
public bool HasEffect<SID>(SID sid) where SID : Enum => Player.FindStatus((uint)(object)sid, Player.InstanceID) != null; //Checks if Status effect is on self
public float GetStatusDetail(Actor target, AST.SID sid) => StatusDetails(target, sid, Player.InstanceID).Left; //Checks if Status effect is on target
public bool HasEffect(Actor target, AST.SID sid, float duration) => GetStatusDetail(target, sid) < duration; //Checks if anyone has a status effect
public Actor? TargetChoice(StrategyValues.OptionRef strategy) => ResolveTargetOverride(strategy.Value);

public static readonly ActionID IDLimitBreak3 = ActionID.MakeSpell(AST.AID.AstralStasis);

Expand All @@ -30,6 +33,13 @@ public static RotationModuleDefinition Definition()
DefineSimpleConfig(res, Track.Synastry, "Synastry", "", 200, AST.AID.Synastry, 20); //ST oGCD "kardia"-like heal, 120s CD, 20s effect duration
DefineSimpleConfig(res, Track.CollectiveUnconscious, "CollectiveUnconscious", "C.Uncon", 100, AST.AID.CollectiveUnconscious, 5); //AoE oGCD mit/regen, 60s CD, 5s mitigation / 15s regen effect durations
DefineSimpleConfig(res, Track.CelestialOpposition, "CelestialOpposition", "C.Oppo", 100, AST.AID.CelestialOpposition, 15); //AoE oGCD heal/regen, 60s CD, 15s effect duration

res.Define(Track.EarthlyStar).As<StarOption>("EarthlyStar", "E.Star", 200) //AoE GCD heal, 60s CD, 10s + 10s effect duration
.AddOption(StarOption.None, "None", "Do not use automatically")
.AddOption(StarOption.Use, "Earthly Star", "Use Earthly Star", 60, 10, ActionTargets.Hostile, 62)
.AddOption(StarOption.End, "Stellar Detonation", "Use Stellar Detonation", 0, 1, ActionTargets.Hostile, 62)
.AddAssociatedActions(AST.AID.EarthlyStar, AST.AID.StellarDetonation);

DefineSimpleConfig(res, Track.CelestialIntersection, "CelestialIntersection", "C.Inter", 100, AST.AID.CelestialIntersection, 30); //ST oGCD heal/shield, 30s CD (60s Total), 2 charges

res.Define(Track.Horoscope).As<HoroscopeOption>("Horoscope", "Horo", 130) //Conditional AoE heal, 60s CD, 30s effect duration
Expand All @@ -56,19 +66,29 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
{
ExecuteShared(strategy, IDLimitBreak3, primaryTarget);
ExecuteSimple(strategy.Option(Track.Lightspeed), AST.AID.Lightspeed, Player);
ExecuteSimple(strategy.Option(Track.BeneficII), AST.AID.BeneficII, primaryTarget ?? Player);
ExecuteSimple(strategy.Option(Track.EssentialDignity), AST.AID.EssentialDignity, primaryTarget ?? Player);
ExecuteSimple(strategy.Option(Track.AspectedBenefic), AST.AID.AspectedBenefic, primaryTarget ?? Player);
ExecuteSimple(strategy.Option(Track.Synastry), AST.AID.Synastry, primaryTarget ?? Player);
ExecuteSimple(strategy.Option(Track.BeneficII), AST.AID.BeneficII, TargetChoice(strategy.Option(Track.BeneficII)) ?? Player);
ExecuteSimple(strategy.Option(Track.EssentialDignity), AST.AID.EssentialDignity, TargetChoice(strategy.Option(Track.EssentialDignity)) ?? Player);
ExecuteSimple(strategy.Option(Track.AspectedBenefic), AST.AID.AspectedBenefic, TargetChoice(strategy.Option(Track.AspectedBenefic)) ?? Player);
ExecuteSimple(strategy.Option(Track.Synastry), AST.AID.Synastry, TargetChoice(strategy.Option(Track.Synastry)) ?? Player);
ExecuteSimple(strategy.Option(Track.CollectiveUnconscious), AST.AID.CollectiveUnconscious, Player);
ExecuteSimple(strategy.Option(Track.CelestialOpposition), AST.AID.CelestialOpposition, Player);
ExecuteSimple(strategy.Option(Track.CelestialIntersection), AST.AID.CelestialIntersection, Player);
ExecuteSimple(strategy.Option(Track.NeutralSect), AST.AID.NeutralSect, Player);
ExecuteSimple(strategy.Option(Track.Exaltation), AST.AID.Exaltation, primaryTarget ?? Player);
ExecuteSimple(strategy.Option(Track.Exaltation), AST.AID.Exaltation, TargetChoice(strategy.Option(Track.Exaltation)) ?? Player);
ExecuteSimple(strategy.Option(Track.SunSign), AST.AID.SunSign, Player);

var star = strategy.Option(Track.EarthlyStar);
var starAction = star.As<StarOption>() switch
{
StarOption.Use => AST.AID.EarthlyStar,
StarOption.End => AST.AID.StellarDetonation,
_ => default
};
if (starAction != default)
QueueOGCD(starAction, TargetChoice(star) ?? primaryTarget ?? Player);

//Aspected Helios full execution
var heliosUp = HasEffect(AST.SID.AspectedHelios) || HasEffect(AST.SID.HeliosConjunction);
var heliosUp = HasEffect(Player, AST.SID.AspectedHelios, 15) || HasEffect(Player, AST.SID.HeliosConjunction, 15);
var helios = strategy.Option(Track.AspectedHelios);
var heliosAction = helios.As<HeliosOption>() switch
{
Expand All @@ -77,7 +97,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
_ => default
};
if (heliosAction != default && !heliosUp)
Hints.ActionsToExecute.Push(ActionID.MakeSpell(heliosAction), Player, helios.Priority(), helios.Value.ExpireIn);
QueueGCD(heliosAction, Player);

//Horoscope full execution
var horo = strategy.Option(Track.Horoscope);
Expand All @@ -88,7 +108,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
_ => default
};
if (horoAction != default)
Hints.ActionsToExecute.Push(ActionID.MakeSpell(horoAction), Player, horo.Priority(), horo.Value.ExpireIn);
QueueOGCD(horoAction, Player);

var cosmos = strategy.Option(Track.Macrocosmos);
var cosmosAction = cosmos.As<MacrocosmosOption>() switch
Expand All @@ -98,7 +118,66 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
_ => default
};
if (cosmosAction != default)
Hints.ActionsToExecute.Push(ActionID.MakeSpell(cosmosAction), Player, cosmos.Priority(), cosmos.Value.ExpireIn);
QueueOGCD(cosmosAction, primaryTarget);
}

#region Core Execution Helpers

public AST.AID NextGCD; //Next global cooldown action to be used
public void QueueGCD<P>(AST.AID aid, Actor? target, P priority, float delay = 0) where P : Enum
=> QueueGCD(aid, target, (int)(object)priority, delay);

public void QueueGCD(AST.AID aid, Actor? target, int priority = 8, float delay = 0)
{
var NextGCDPrio = 0;

if (priority == 0)
return;

if (QueueAction(aid, target, ActionQueue.Priority.High, delay) && priority > NextGCDPrio)
{
NextGCD = aid;
}
}

public void QueueOGCD<P>(AST.AID aid, Actor? target, P priority, float delay = 0) where P : Enum
=> QueueOGCD(aid, target, (int)(object)priority, delay);

public void QueueOGCD(AST.AID aid, Actor? target, int priority = 4, float delay = 0)
{
if (priority == 0)
return;

QueueAction(aid, target, ActionQueue.Priority.Medium + priority, delay);
}

public bool QueueAction(AST.AID aid, Actor? target, float priority, float delay)
{
if ((uint)(object)aid == 0)
return false;

var def = ActionDefinitions.Instance.Spell(aid);
if (def == null)
return false;

if (def.Range != 0 && target == null)
{
return false;
}

Vector3 targetPos = default;

if (def.AllowedTargets.HasFlag(ActionTargets.Area))
{
if (def.Range == 0)
targetPos = Player.PosRot.XYZ();
else if (target != null)
targetPos = target.PosRot.XYZ();
}

Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), target, priority, delay: delay, targetPos: targetPos);
return true;
}
#endregion

}
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassBLMUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
var dashTarget = ResolveTargetOverride(dash.Value) ?? primaryTarget; //Smart-Targeting
var dashStrategy = strategy.Option(Track.AetherialManipulation).As<DashStrategy>();
if (ShouldUseDash(dashStrategy, dashTarget))
Hints.ActionsToExecute.Push(ActionID.MakeSpell(BLM.AID.AetherialManipulation), dashTarget, dash.Priority());
Hints.ActionsToExecute.Push(ActionID.MakeSpell(BLM.AID.AetherialManipulation), dashTarget, dash.Priority(), dash.Value.ExpireIn);
}
private bool ShouldUseDash(DashStrategy strategy, Actor? primaryTarget) => strategy switch
{
Expand Down
12 changes: 7 additions & 5 deletions BossMod/Autorotation/Utility/ClassDRGUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
public sealed class ClassDRGUtility(RotationModuleManager manager, Actor player) : RoleMeleeUtility(manager, player)
{
public enum Track { WingedGlide = SharedTrack.Count }
public enum DashStrategy { None, GapClose }
public bool InMeleeRange(Actor? target) => Player.DistanceToHitbox(target) <= 3; //Checks if we're inside melee range
public enum DashStrategy { None, GapClose, GapCloseHold1 }

public static readonly ActionID IDLimitBreak3 = ActionID.MakeSpell(DRG.AID.DragonsongDive);

Expand All @@ -15,7 +14,8 @@ public static RotationModuleDefinition Definition()

res.Define(Track.WingedGlide).As<DashStrategy>("Winged Glide", "Dash", 20)
.AddOption(DashStrategy.None, "Automatic", "No use.")
.AddOption(DashStrategy.GapClose, "GapClose", "Use as gapcloser if outside melee range", 60, 0, ActionTargets.Hostile, 45)
.AddOption(DashStrategy.GapClose, "GapClose", "Use Winged Glide as gapcloser if outside melee range", 60, 0, ActionTargets.Hostile, 45)
.AddOption(DashStrategy.GapCloseHold1, "GapCloseHold1", "Use Winged Glide as gapcloser if outside melee range; conserves 1 charge for manual usage", 60, 0, ActionTargets.Hostile, 84)
.AddAssociatedActions(DRG.AID.WingedGlide);

return res;
Expand All @@ -26,14 +26,16 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
ExecuteShared(strategy, IDLimitBreak3, primaryTarget);

var dash = strategy.Option(Track.WingedGlide);
var dashTarget = ResolveTargetOverride(dash.Value) ?? primaryTarget;
var dashStrategy = strategy.Option(Track.WingedGlide).As<DashStrategy>();
if (ShouldUseDash(dashStrategy, primaryTarget))
Hints.ActionsToExecute.Push(ActionID.MakeSpell(DRG.AID.WingedGlide), primaryTarget, dash.Priority());
Hints.ActionsToExecute.Push(ActionID.MakeSpell(DRG.AID.WingedGlide), dashTarget, dash.Priority(), dash.Value.ExpireIn);
}
private bool ShouldUseDash(DashStrategy strategy, Actor? primaryTarget) => strategy switch
{
DashStrategy.None => false,
DashStrategy.GapClose => !InMeleeRange(primaryTarget),
DashStrategy.GapClose => Player.DistanceToHitbox(primaryTarget) is > 3 and <= 20,
DashStrategy.GapCloseHold1 => Player.DistanceToHitbox(primaryTarget) is > 3 and <= 20 && World.Client.Cooldowns[ActionDefinitions.Instance.Spell(DRG.AID.WingedGlide)!.MainCooldownGroup].Remaining <= 59.9f,
_ => false,
};
}
36 changes: 18 additions & 18 deletions BossMod/Autorotation/Utility/ClassDRKUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
public sealed class ClassDRKUtility(RotationModuleManager manager, Actor player) : RoleTankUtility(manager, player)
{
public enum Track { DarkMind = SharedTrack.Count, ShadowWall, LivingDead, TheBlackestNight, Oblation, DarkMissionary, Shadowstride }
public enum WallOption { None, ShadowWall, ShadowedVigil }
public enum TBNStrategy { None, Force }
public enum OblationStrategy { None, Force }
public enum WallOption { None, ShadowWall, ShadowedVigil } //ShadowWall strategy
public enum TBNStrategy { None, Force } //TheBlackestNight strategy
public enum OblationStrategy { None, Force } //Oblation strategy
public enum DashStrategy { None, GapClose } //GapCloser strategy
public bool InMeleeRange(Actor? target) => Player.DistanceToHitbox(target) <= 3; //Checks if we're inside melee range
public bool TargetHasEffect<SID>(Actor target, SID sid) where SID : Enum => target?.FindStatus((uint)(object)sid, Player.InstanceID) != null; //Checks if Status effect is on target
public float GetStatusDetail(Actor target, DRK.SID sid) => StatusDetails(target, sid, Player.InstanceID).Left; //Checks if Status effect is on target
public bool HasEffect(Actor target, DRK.SID sid, float duration) => GetStatusDetail(target, sid) < duration; //Checks if anyone has a status effect

public static readonly ActionID IDLimitBreak3 = ActionID.MakeSpell(DRK.AID.DarkForce);
public static readonly ActionID IDStanceApply = ActionID.MakeSpell(DRK.AID.Grit);
Expand Down Expand Up @@ -57,28 +58,24 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
ExecuteSimple(strategy.Option(Track.DarkMissionary), DRK.AID.DarkMissionary, Player); //Execution of DarkMissionary

//TBN execution
var canTBN = ActionUnlocked(ActionID.MakeSpell(DRK.AID.TheBlackestNight)) && Player.HPMP.CurMP >= 3000;
var tbn = strategy.Option(Track.TheBlackestNight);
var tbnTarget = ResolveTargetOverride(tbn.Value) ?? CoTank() ?? primaryTarget ?? Player; //Smart-Targets Co-Tank if set to Automatic, if no Co-Tank then targets self
var tbnight = tbn.As<TBNStrategy>() switch
{
TBNStrategy.Force => DRK.AID.TheBlackestNight,
_ => default
};
if (tbnight != default && Player.HPMP.CurMP >= 3000)
if (tbn.As<TBNStrategy>() == TBNStrategy.Force &&
canTBN &&
!HasEffect(tbnTarget, DRK.SID.TheBlackestNight, 7))
Hints.ActionsToExecute.Push(ActionID.MakeSpell(DRK.AID.TheBlackestNight), tbnTarget, tbn.Priority(), tbn.Value.ExpireIn);

//Oblation execution
var canObl = ActionUnlocked(ActionID.MakeSpell(DRK.AID.Oblation));
var obl = strategy.Option(Track.Oblation);
var oblTarget = ResolveTargetOverride(obl.Value) ?? primaryTarget ?? Player; //Smart-Targets Co-Tank if set to Automatic, if no Co-Tank then targets self
var oblStatus = TargetHasEffect(oblTarget, DRK.SID.Oblation); //Checks if status is present
var oblat = obl.As<OblationStrategy>() switch
{
OblationStrategy.Force => DRK.AID.Oblation,
_ => default
};
if (oblat != default && !oblStatus)
if (obl.As<OblationStrategy>() == OblationStrategy.Force &&
canObl &&
!HasEffect(oblTarget, DRK.SID.Oblation, 9))
Hints.ActionsToExecute.Push(ActionID.MakeSpell(DRK.AID.Oblation), oblTarget, obl.Priority(), obl.Value.ExpireIn);

//Shadow Wall / Vigil execution
var wall = strategy.Option(Track.ShadowWall);
var wallAction = wall.As<WallOption>() switch
{
Expand All @@ -89,9 +86,12 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
if (wallAction != default)
Hints.ActionsToExecute.Push(ActionID.MakeSpell(wallAction), Player, wall.Priority(), wall.Value.ExpireIn); //Checking proper use of said option

//Shadowstride execution
var dash = strategy.Option(Track.Shadowstride);
var dashTarget = ResolveTargetOverride(dash.Value) ?? primaryTarget;
var dashStrategy = strategy.Option(Track.Shadowstride).As<DashStrategy>();
if (ShouldUseDash(dashStrategy, primaryTarget))
Hints.ActionsToExecute.Push(ActionID.MakeSpell(DRK.AID.Shadowstride), primaryTarget, obl.Priority());
Hints.ActionsToExecute.Push(ActionID.MakeSpell(DRK.AID.Shadowstride), dashTarget, dash.Priority(), dash.Value.ExpireIn);
}
private bool ShouldUseDash(DashStrategy strategy, Actor? primaryTarget) => strategy switch
{
Expand Down
Loading

0 comments on commit e8aba80

Please sign in to comment.