From 869aba180f3993b9a11365b146bcae1499c03933 Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Sun, 8 Dec 2024 05:34:44 +0100 Subject: [PATCH] some P3S improvements --- BossMod/Components/Gaze.cs | 15 +--- .../FlightOfTheGriffin.cs | 7 +- .../JanquetilaquesPortrait.cs | 1 - .../SomewhereOnlySheKnows/TheWingedSteed.cs | 5 +- .../Quest/JobQuests/Viper/FangsOfTheViper.cs | 3 +- .../JobQuests/Viper/VengeanceOfTheViper.cs | 3 +- .../Dawntrail/Quest/MSQ/TakingAStand.cs | 23 +++++- .../Quest/MSQ/TheFeatOfBrotherhood.cs | 4 +- .../E1OtisOathbroken.cs | 7 +- .../TheProtectorAndTheDestroyer/E2Gwyddrud.cs | 36 ++++----- .../TheWarmthOfTheFamily/AlphaAlligator.cs | 11 +-- .../MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs | 4 +- .../Quest/RoleQuests/TheMightiestShield.cs | 2 +- .../Dungeon/D01TowerOfZot/D012Sanduruva.cs | 6 +- .../Dungeon/D01TowerOfZot/D013MagusSisters.cs | 14 ++-- .../Savage/P3SPhoinix/BrightenedFire.cs | 2 +- .../Endwalker/Savage/P3SPhoinix/Cinderwing.cs | 32 -------- .../Savage/P3SPhoinix/DarkblazeTwister.cs | 57 ++++--------- .../Savage/P3SPhoinix/FlamesOfAsphodelos.cs | 80 ++++--------------- .../Savage/P3SPhoinix/FledglingFlight.cs | 2 +- .../Endwalker/Savage/P3SPhoinix/P3S.cs | 28 ++++++- .../Endwalker/Savage/P3SPhoinix/P3SEnums.cs | 15 ++-- .../Endwalker/Savage/P3SPhoinix/P3SStates.cs | 40 ++++++---- .../Savage/P3SPhoinix/TrailOfCondemnation.cs | 33 -------- 24 files changed, 169 insertions(+), 261 deletions(-) delete mode 100644 BossMod/Modules/Endwalker/Savage/P3SPhoinix/Cinderwing.cs diff --git a/BossMod/Components/Gaze.cs b/BossMod/Components/Gaze.cs index 91c238d14d..75faf83c6d 100644 --- a/BossMod/Components/Gaze.cs +++ b/BossMod/Components/Gaze.cs @@ -49,7 +49,7 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) foreach (var eye in ActiveEyes(pcSlot, pc)) { var danger = HitByEye(pc, eye) != Inverted; - var eyeCenter = IndicatorScreenPos(eye.Position); + var eyeCenter = Arena.WorldPositionToScreenPosition(eye.Position); DrawEye(eyeCenter, danger); if (pc.Position.InCircle(eye.Position, eye.Range)) @@ -71,19 +71,6 @@ public static void DrawEye(Vector2 eyeCenter, bool danger) } private static bool HitByEye(Actor actor, Eye eye) => (actor.Rotation + eye.Forward).ToDirection().Dot((eye.Position - actor.Position).Normalized()) >= 0.707107f; // 45-degree - - private Vector2 IndicatorScreenPos(WPos eye) - { - if (Arena.InBounds(eye)) - { - return Arena.WorldPositionToScreenPosition(eye); - } - else - { - var dir = (eye - Arena.Center).Normalized(); - return Arena.ScreenCenter + Arena.RotatedCoords(dir.ToVec2()) * (Arena.ScreenHalfSize + Arena.ScreenMarginSize * 0.5f); - } - } } // gaze that happens on cast end diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs b/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs index 8e4d6e7cc3..bd0a291801 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs +++ b/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs @@ -33,7 +33,7 @@ public FlightOfTheGriffinStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(OID.TheBirdOfPrey).Concat([module.PrimaryActor]).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => module.Enemies(FlightOfTheGriffin.All).All(e => e.IsDeadOrDestroyed); } } @@ -79,11 +79,12 @@ public class FlightOfTheGriffin(WorldState ws, Actor primary) : BossModule(ws, p new(-8.3f, -292.66f), new(-7.07f, -292.66f), new(-7.07f, -292.13f), new(-7.01f, -291.61f), new(-5.11f, -291.43f), new(-4.58f, -291.43f), new(-4.08f, -291.51f), new(-3.91f, -291.99f), new(-3.67f, -292.43f), new(-3.58f, -292.94f), new(-3.58f, -294.47f)]; - private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + public static readonly uint[] All = [(uint)OID.Boss, (uint)OID.TheBirdOfPrey]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.TheBirdOfPrey).Concat([PrimaryActor])); + Arena.Actor(PrimaryActor); + Arena.Actors(Enemies(OID.TheBirdOfPrey)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs b/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs index 72cd9927cf..ab5c9feb1e 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs +++ b/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs @@ -2,7 +2,6 @@ namespace BossMod.Dawntrail.Quest.JobQuests.Pictomancer.SomewhereOnlySheKnows.Ja public enum OID : uint { - Boss = 0x4298, // R4.000, x1 AFlowerInTheSun = 0x4299, // R2.72 OerTheAncientArbor = 0x429A, // R2.6 diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs b/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs index bd7f4cf3ac..d27a115c76 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs +++ b/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs @@ -27,7 +27,7 @@ public TheWingedSteedStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(OID.SonOfTheKingdom1).Concat([module.PrimaryActor]).Concat(module.Enemies(OID.SonOfTheKingdom2)).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => module.Enemies(TheWingedSteed.All).All(e => e.IsDeadOrDestroyed); } } @@ -59,9 +59,10 @@ public class TheWingedSteed(WorldState ws, Actor primary) : BossModule(ws, prima new(25.8f, -229.2f), new(26.32f, -229.19f), new(26.58f, -230.24f), new(26.95f, -230.62f), new(27.47f, -230.59f), new(27.9f, -230.94f), new(27.9f, -232.19f)]; private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + public static readonly uint[] All = [(uint)OID.Boss, (uint)OID.SonOfTheKingdom1, (uint)OID.SonOfTheKingdom2]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.SonOfTheKingdom1).Concat([PrimaryActor]).Concat(Enemies(OID.SonOfTheKingdom2))); + Arena.Actors(Enemies(All)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs b/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs index d174f6b8df..eec013f7fa 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs +++ b/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs @@ -54,10 +54,11 @@ public FangsOfTheViperStates(BossModule module) : base(module) public class FangsOfTheViper(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { private static readonly ArenaBoundsComplex arena = new([new Polygon(new(264, 480), 19.5f, 20)]); + private static readonly uint[] all = [(uint)OID.FawningWivre, (uint)OID.FawningPeiste, (uint)OID.FawningRaptor, (uint)OID.WanderingGowrow]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.FawningWivre).Concat(Enemies(OID.FawningPeiste)).Concat(Enemies(OID.FawningRaptor)).Concat(Enemies(OID.WanderingGowrow))); + Arena.Actors(Enemies(all)); } protected override bool CheckPull() => Raid.WithoutSlot().Any(x => x.InCombat); diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs b/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs index fe9e5c7d19..257e92ff76 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs +++ b/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs @@ -187,9 +187,10 @@ public VengeanceOfTheViperStates(BossModule module) : base(module) public class VengeanceOfTheViper(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-402, 738), 19.5f, 20)]); + private static readonly uint[] all = [(uint)OID.Boss, (uint)OID.RightWing, (uint)OID.LeftWing]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.RightWing).Concat(Enemies(OID.LeftWing)).Concat([PrimaryActor])); + Arena.Actors(Enemies(all)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TakingAStand.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TakingAStand.cs index a522d638e6..b49f4a964d 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TakingAStand.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TakingAStand.cs @@ -3,7 +3,7 @@ namespace BossMod.Dawntrail.Quest.MSQ.TakingAStand; public enum OID : uint { Boss = 0x4211, // R=3.5 - BakoolJaJaShade = 0x4215, // R3.500, x3 + BakoolJaJaShade = 0x4215, // R3.5 Deathwall = 0x1EBA1F, MagickedStandardOrange = 0x4212, // R1.0 MagickedStandardGreen = 0x4213, // R1.0 @@ -24,6 +24,7 @@ public enum AID : uint AutoAttack2 = 871, // HoobigoLancer->player, no cast, single-target AutoAttack3 = 873, // HiredThug3->player, no cast, single-target Teleport = 37089, // Boss->location, no cast, single-target + Roar1 = 37090, // Boss->self, 5.0s cast, range 45 circle, spawns death wall Roar2 = 37091, // Boss->self, 5.0s cast, range 45 circle LethalSwipe = 37092, // Boss->self, 6.0s cast, range 45 180-degree cone @@ -213,15 +214,31 @@ public TakingAStandStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter(); + .ActivateOnEnter() + .Raw.Update = () => module.PrimaryActor.IsDestroyed || module.PrimaryActor.HPMP.CurHP == 1; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.Quest, GroupID = 70438, NameID = 12677)] public class TakingAStand(WorldState ws, Actor primary) : BossModule(ws, primary, new(500, -175), new ArenaBoundsCircle(24.5f)) { + private static readonly uint[] all = [(uint)OID.Boss, (uint)OID.HiredThug1, (uint)OID.HiredThug2, (uint)OID.HiredThug3, (uint)OID.HiredThug3, (uint)OID.HoobigoGuardian, + (uint)OID.HoobigoLancer, (uint)OID.DopproIllusionist]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + Arena.Actors(Enemies(all)); + } + + protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; + e.Priority = (OID)e.Actor.OID switch + { + OID.BakoolJaJaShade => AIHints.Enemy.PriorityForbidFully, + _ => 0 + }; + } } } diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TheFeatOfBrotherhood.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TheFeatOfBrotherhood.cs index 285f6cfec1..a6e6b19110 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TheFeatOfBrotherhood.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TheFeatOfBrotherhood.cs @@ -3,7 +3,6 @@ namespace BossMod.Dawntrail.Quest.MSQ.TheFeatOfBrotherhood; public enum OID : uint { Boss = 0x4206, // R5.0 - WukLamat = 0x4209, // R1.0 EphemeralSword = 0x4228, // R2.5 BallOfFire = 0x44B6, // R1.0-2.5 OathOfFire = 0x4229, // R2.500 @@ -257,6 +256,7 @@ public TheFeatOfBrotherhoodStates(BossModule module) : base(module) { protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + Arena.Actor(PrimaryActor); + Arena.Actors(Enemies(OID.OathOfFire)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E1OtisOathbroken.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E1OtisOathbroken.cs index b7f3a6131b..cc6e355829 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E1OtisOathbroken.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E1OtisOathbroken.cs @@ -72,7 +72,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if (_aoes.Count > 0 && (AID)spell.Action.ID == AID.Rush) + if (_aoes.Count != 0 && (AID)spell.Action.ID == AID.Rush) _aoes.RemoveAt(0); } } @@ -101,8 +101,11 @@ public OtisOathbrokenStates(BossModule module) : base(module) { protected override bool CheckPull() => Raid.WithoutSlot().Any(x => x.InCombat); + private static readonly uint[] all = [(uint)OID.Boss, (uint)OID.EverkeepTurret, (uint)OID.EverkeepAerostat, (uint)OID.EverkeepAerostat2, (uint)OID.EverkeepSentryG10, + (uint)OID.EverkeepSentryR10]; + protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + Arena.Actors(Enemies(all)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E2Gwyddrud.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E2Gwyddrud.cs index 601680b987..3ec96d2b4d 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E2Gwyddrud.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TheProtectorAndTheDestroyer/E2Gwyddrud.cs @@ -3,14 +3,10 @@ namespace BossMod.Dawntrail.Quest.MSQ.TheProtectorAndTheDestroyer.Gwyddrud; public enum OID : uint { Boss = 0x4349, // R5.0 - Gwyddrud = 0x3A5E, // R1.000, x24 - LimitBreakHelper = 0x40B5, // R1.000, x1 - WukLamat = 0x4146, // R0.500, x1 - Alisaie = 0x4339, // R0.485, x1 - OtisOathmender = 0x4348, // R1.500, x1 - Sphene = 0x4337, // R0.500, x1 - BallOfLevin = 0x434A, // R1.500, x0 (spawn during fight) - SuperchargedLevin = 0x39C4, // R2.000, x0 (spawn during fight) + LimitBreakHelper = 0x40B5, // R1.0 + BallOfLevin = 0x434A, // R1.5 + SuperchargedLevin = 0x39C4, // R2.0 + Helper2 = 0x3A5E, // R1.0 Helper = 0x233C } @@ -37,16 +33,16 @@ public enum AID : uint LevinStartMoving = 38226, // BallOfLevin/SuperchargedLevin->LimitBreakHelper, no cast, single-target GatheringSurge = 38243, // Boss->self, no cast, single-target UntamedCurrent = 38232, // Boss->self, 3.3+0,7s cast, range 40 circle, knockback 15, away from source - UntamedCurrentAOE1 = 38233, // Gwyddrud->location, 3.1s cast, range 5 circle - UntamedCurrentAOE2 = 19718, // Gwyddrud->location, 3.2s cast, range 5 circle - UntamedCurrentAOE3 = 19719, // Gwyddrud->location, 3.3s cast, range 5 circle - UntamedCurrentAOE4 = 19999, // Gwyddrud->location, 3.0s cast, range 5 circle - UntamedCurrentAOE5 = 38234, // Gwyddrud->location, 3.1s cast, range 5 circle - UntamedCurrentAOE6 = 19720, // Gwyddrud->location, 3.2s cast, range 5 circle - UntamedCurrentAOE7 = 19721, // Gwyddrud->location, 3.3s cast, range 5 circle - UntamedCurrentAOE8 = 19728, // Gwyddrud->location, 3.3s cast, range 5 circle - UntamedCurrentAOE9 = 19727, // Gwyddrud->location, 3.2s cast, range 5 circle - UntamedCurrentAOE10 = 19179, // Gwyddrud->location, 3.1s cast, range 5 circle + UntamedCurrentAOE1 = 38233, // Helper2->location, 3.1s cast, range 5 circle + UntamedCurrentAOE2 = 19718, // Helper2->location, 3.2s cast, range 5 circle + UntamedCurrentAOE3 = 19719, // Helper2->location, 3.3s cast, range 5 circle + UntamedCurrentAOE4 = 19999, // Helper2->location, 3.0s cast, range 5 circle + UntamedCurrentAOE5 = 38234, // Helper2->location, 3.1s cast, range 5 circle + UntamedCurrentAOE6 = 19720, // Helper2->location, 3.2s cast, range 5 circle + UntamedCurrentAOE7 = 19721, // Helper2->location, 3.3s cast, range 5 circle + UntamedCurrentAOE8 = 19728, // Helper2->location, 3.3s cast, range 5 circle + UntamedCurrentAOE9 = 19727, // Helper2->location, 3.2s cast, range 5 circle + UntamedCurrentAOE10 = 19179, // Helper2->location, 3.1s cast, range 5 circle UntamedCurrentSpread = 19181, // Helper->all, 5.0s cast, range 5 circle UntamedCurrentStack = 19276, // Helper->Alisaie, 5.0s cast, range 6 circle } @@ -152,8 +148,10 @@ public GwyddrudStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.Quest, GroupID = 70478, NameID = 13170)] public class Gwyddrud(WorldState ws, Actor primary) : BossModule(ws, primary, new(349, -14), new ArenaBoundsCircle(19.5f)) { + private static readonly uint[] all = [(uint)OID.Boss, (uint)OID.SuperchargedLevin, (uint)OID.BallOfLevin]; + protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + Arena.Actors(Enemies(all)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/AlphaAlligator.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/AlphaAlligator.cs index eba752e270..3753050567 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/AlphaAlligator.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/AlphaAlligator.cs @@ -7,16 +7,17 @@ public enum OID : uint Ceratoraptor = 0x4634, // R1.95 HornedLizard = 0x4635, // R2.2 AlphaAlligator = 0x4637, // R5.13 + Alligator = 0x4636, // R2.7 } public enum AID : uint { - AutoAttack1 = 870, // Yeheheceyaa/Ceratoraptor/AlphaAlligator->player/WukLamat/Koana/Boss, no cast, single-target + AutoAttack1 = 870, // Yeheheceyaa/Ceratoraptor/AlphaAlligator/Alligator->player/WukLamat/Koana/Boss, no cast, single-target AutoAttack2 = 872, // HornedLizard->player/WukLamat/Koana, no cast, single-target ToxicSpitVisual = 40561, // HornedLizard->self, 8.0s cast, single-target ToxicSpit = 40562, // HornedLizard->Boss/Koana/WukLamat, no cast, single-target - CriticalBite = 40563, // 4636->self, 25.0s cast, range 10 120-degree cone + CriticalBite = 40563, // Alligator->self, 25.0s cast, range 10 120-degree cone } class FeedingTime(BossModule module) : Components.InterceptTether(module, ActionID.MakeSpell(AID.ToxicSpit), excludedAllies: [(uint)OID.Boss]) @@ -53,8 +54,7 @@ public AlphaAlligatorStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.WorldState.Actors.Where(x => !x.IsAlly && x.Position.AlmostEqual(Module.Arena.Center, Module.Bounds.Radius)) - .All(x => x.IsDestroyed) || Module.Enemies(OID.AlphaAlligator).Any(x => x.IsDead); + .Raw.Update = () => module.Enemies(AlphaAlligator.All).Any(x => x.IsDestroyed) || module.Enemies(OID.AlphaAlligator).Any(x => x.IsDead); } } @@ -74,9 +74,10 @@ public class AlphaAlligator(WorldState ws, Actor primary) : BossModule(ws, prima new(406.61f, -125.40f), new(407.32f, -126.66f), new(407.47f, -127.25f), new(407.42f, -127.82f), new(406.67f, -128.79f), new(406.44f, -129.39f), new(407.78f, -134.79f), new(408.15f, -135.35f), new(420.82f, -140.11f), new(423.33f, -140.59f)]; private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + public static readonly uint[] All = [(uint)OID.Yeheheceyaa, (uint)OID.AlphaAlligator, (uint)OID.HornedLizard, (uint)OID.Ceratoraptor, (uint)OID.Alligator]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + Arena.Actors(Enemies(All)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs index 4780155abc..0afb73125a 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs @@ -2,7 +2,6 @@ namespace BossMod.Dawntrail.Quest.MSQ.TheWarmthOfTheFamily.Tturuhhetso; public enum OID : uint { - Boss = 0x4638, // R5.95 ScaleArmoredLeg = 0x4648, // R5.95 BallOfFire = 0x4639, // R1.0 @@ -215,6 +214,7 @@ public class Tturuhhetso(WorldState ws, Actor primary) : BossModule(ws, primary, protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + Arena.Actor(PrimaryActor); + Arena.Actors(Enemies(OID.ScaleArmoredLeg)); } } diff --git a/BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs b/BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs index 1d06650c6e..5e94bde19d 100644 --- a/BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs +++ b/BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs @@ -226,7 +226,7 @@ public class TheMightiestShield(WorldState ws, Actor primary) : BossModule(ws, p private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-191, 72), 14.5f, 20)]); private static readonly uint[] all = [(uint)OID.Boss, (uint)OID.CravenFollower1, (uint)OID.CravenFollower2, (uint)OID.CravenFollower3, (uint)OID.CravenFollower4, (uint)OID.CravenFollower5, (uint)OID.CravenFollower6, (uint)OID.CravenFollower7, (uint)OID.CravenFollower8, (uint)OID.MagitekMissile, (uint)OID.UnyieldingMettle2, - (uint)OID.UnyieldingMettle3, (uint)OID.CrackedMettle1, (uint)OID.CrackedMettle2]; + (uint)OID.UnyieldingMettle3]; // except CrackedMettle1/2 since the Parry component is drawing them protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D012Sanduruva.cs b/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D012Sanduruva.cs index 4b07d35255..8fa5d99d19 100644 --- a/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D012Sanduruva.cs +++ b/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D012Sanduruva.cs @@ -92,12 +92,12 @@ public D012SanduruvaStates(BossModule module) : base(module) { protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; e.Priority = (OID)e.Actor.OID switch { - OID.Boss => 1, - OID.BerserkerSphere => -1, + OID.BerserkerSphere => AIHints.Enemy.PriorityForbidFully, _ => 0 }; } diff --git a/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D013MagusSisters.cs b/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D013MagusSisters.cs index 695ee4738c..569d88bfb4 100644 --- a/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D013MagusSisters.cs +++ b/BossMod/Modules/Endwalker/Dungeon/D01TowerOfZot/D013MagusSisters.cs @@ -204,28 +204,28 @@ public D013MagusSistersStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(OID.Sanduruva).Concat(module.Enemies(OID.Minduruva)).Concat([module.PrimaryActor]).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => module.Enemies(D013MagusSisters.Bosses).All(e => e.IsDeadOrDestroyed); } } [ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "dhoggpt, Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 783, NameID = 10265)] class D013MagusSisters(WorldState ws, Actor primary) : BossModule(ws, primary, new(-27.5f, -49.5f), new ArenaBoundsCircle(20)) { + public static readonly uint[] Bosses = [(uint)OID.Boss, (uint)OID.Sanduruva, (uint)OID.Minduruva]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.Minduruva).Concat(Enemies(OID.Sanduruva))); + Arena.Actors(Enemies(Bosses)); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; e.Priority = (OID)e.Actor.OID switch { - OID.Boss => 3, - OID.Minduruva => 2, - OID.Sanduruva => 1, + OID.Boss => 2, + OID.Minduruva => 1, _ => 0 }; } diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/BrightenedFire.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/BrightenedFire.cs index d01ef3ac9c..a77ab8b2ea 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/BrightenedFire.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/BrightenedFire.cs @@ -1,7 +1,7 @@ namespace BossMod.Endwalker.Savage.P3SPhoinix; // state related to brightened fire mechanic -// this helper relies on waymarks 1-4, and assumes they don't change during fight - this is of course quite an assumption, but whatever... +// this helper relies on waymarks 1-4 class BrightenedFire(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.BrightenedFireAOE)) { private readonly int[] _playerOrder = new int[8]; // 0 if unknown, 1-8 otherwise diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/Cinderwing.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/Cinderwing.cs deleted file mode 100644 index 3dccc8f3b7..0000000000 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/Cinderwing.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace BossMod.Endwalker.Savage.P3SPhoinix; - -// state related to cinderwing -class Cinderwing : BossComponent -{ - private readonly AOEShapeCone _aoe; - - public Cinderwing(BossModule module) : base(module) - { - var directionOffset = (AID)(Module.PrimaryActor.CastInfo?.Action.ID ?? 0) switch - { - AID.RightCinderwing => -90.Degrees(), - AID.LeftCinderwing => 90.Degrees(), - _ => default - }; - if (directionOffset == default) - ReportError($"Failed to initialize cinderwing; unexpected boss cast {Module.PrimaryActor.CastInfo?.Action}"); - - _aoe = new(60, 90.Degrees(), directionOffset); - } - - public override void AddHints(int slot, Actor actor, TextHints hints) - { - if (_aoe.Check(actor.Position, Module.PrimaryActor)) - hints.Add("GTFO from wing!"); - } - - public override void DrawArenaBackground(int pcSlot, Actor pc) - { - _aoe.Draw(Arena, Module.PrimaryActor); - } -} diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/DarkblazeTwister.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/DarkblazeTwister.cs index 2ad4a0e77b..fae9d72053 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/DarkblazeTwister.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/DarkblazeTwister.cs @@ -1,58 +1,25 @@ namespace BossMod.Endwalker.Savage.P3SPhoinix; // state related to darkblaze twister mechanics -class DarkblazeTwister(BossModule module) : BossComponent(module) +class TwisterVoidzone(BossModule module) : Components.PersistentVoidzone(module, 5, m => m.Enemies(OID.TwisterVoidzone).Where(z => z.EventState != 7)); +class BurningTwister(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BurningTwister), new AOEShapeDonut(7, 20)); + +class DarkTwister(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.DarkTwister), _knockbackRange, true) { private const float _knockbackRange = 17; private const float _aoeInnerRadius = 5; private const float _aoeMiddleRadius = 7; - private const float _aoeOuterRadius = 20; - - public IEnumerable BurningTwisters() => Module.Enemies(OID.DarkblazeTwister).Where(twister => twister.CastInfo?.IsSpell(AID.BurningTwister) ?? false); - public Actor? DarkTwister() => Module.Enemies(OID.DarkblazeTwister).FirstOrDefault(twister => twister.CastInfo?.IsSpell(AID.DarkTwister) ?? false); - - public override void AddHints(int slot, Actor actor, TextHints hints) - { - var adjPos = Components.Knockback.AwayFromSource(actor.Position, DarkTwister(), _knockbackRange); - if (actor.Position != adjPos && !Module.InBounds(adjPos)) - { - hints.Add("About to be knocked back into wall!"); - } - - foreach (var twister in BurningTwisters()) - { - if (adjPos.InCircle(twister.Position, _aoeInnerRadius) || adjPos.InDonut(twister.Position, _aoeMiddleRadius, _aoeOuterRadius)) - { - hints.Add("GTFO from aoe!"); - break; - } - } - } + private const float safeOffset = _knockbackRange + (_aoeInnerRadius + _aoeMiddleRadius) / 2; + private const float safeRadius = (_aoeMiddleRadius - _aoeInnerRadius) / 2; - public override void DrawArenaBackground(int pcSlot, Actor pc) - { - foreach (var twister in BurningTwisters()) - { - Arena.ZoneCircle(twister.Position, _aoeInnerRadius, Colors.AOE); - Arena.ZoneDonut(twister.Position, _aoeMiddleRadius, _aoeOuterRadius, Colors.AOE); - } - } + public IEnumerable BurningTwisters() => Module.Enemies(OID.DarkblazeTwister).Where(t => t.CastInfo?.IsSpell(AID.BurningTwister) ?? false); public override void DrawArenaForeground(int pcSlot, Actor pc) { - var darkTwister = DarkTwister(); - if (darkTwister == null) + base.DrawArenaForeground(pcSlot, pc); + if (Casters.Count == 0) return; - - var adjPos = Components.Knockback.AwayFromSource(pc.Position, darkTwister, _knockbackRange); - if (adjPos != pc.Position) - { - Arena.AddLine(pc.Position, adjPos, Colors.Danger); - Arena.Actor(adjPos, pc.Rotation, Colors.Danger); - } - - var safeOffset = _knockbackRange + (_aoeInnerRadius + _aoeMiddleRadius) / 2; - var safeRadius = (_aoeMiddleRadius - _aoeInnerRadius) / 2; + var darkTwister = Casters[0]; foreach (var burningTwister in BurningTwisters()) { var dir = burningTwister.Position - darkTwister.Position; @@ -61,4 +28,8 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) Arena.AddCircle(darkTwister.Position + dir * (len - safeOffset), safeRadius, Colors.Safe); } } + + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => (Module.FindComponent()?.ActiveAOEs(slot, actor).Any(z => z.Shape.Check(pos, z.Origin, z.Rotation)) ?? false) || + (Module.FindComponent()?.ActiveAOEs(slot, actor).Any(z => z.Shape.Check(pos, z.Origin, z.Rotation)) ?? false) || !Module.InBounds(pos); + } diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FlamesOfAsphodelos.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FlamesOfAsphodelos.cs index 8f29c7f7dc..f357fecfbb 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FlamesOfAsphodelos.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FlamesOfAsphodelos.cs @@ -1,83 +1,37 @@ namespace BossMod.Endwalker.Savage.P3SPhoinix; // state related to flames of asphodelos mechanic -class FlamesOfAsphodelos(BossModule module) : BossComponent(module) +class FlamesOfAsphodelos(BossModule module) : Components.GenericAOEs(module) { - private readonly Angle?[] _directions = new Angle?[3]; + private static readonly AOEShapeCone cone = new(60, 30.Degrees()); + private readonly List _aoes = []; - public override void AddHints(int slot, Actor actor, TextHints hints) + public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (InAOE(_directions[1], actor.Position) || InAOE(_directions[0] != null ? _directions[0] : _directions[2], actor.Position)) + var count = _aoes.Count; + for (var i = 0; i < count; ++i) { - hints.Add("GTFO from cone!"); - } - } - - public override void DrawArenaBackground(int pcSlot, Actor pc) - { - if (_directions[0] != null) - { - DrawZone(_directions[0], Colors.Danger); - DrawZone(_directions[1], Colors.AOE); - } - else if (_directions[1] != null) - { - DrawZone(_directions[1], Colors.Danger); - DrawZone(_directions[2], Colors.AOE); - } - else - { - DrawZone(_directions[2], Colors.Danger); + var aoe = _aoes[i]; + if (i < 2) + yield return count > 2 ? aoe with { Color = Colors.Danger } : aoe; + else if (i is > 1 and < 4) + yield return aoe; } } public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - switch ((AID)spell.Action.ID) + if ((AID)spell.Action.ID is AID.FlamesOfAsphodelosAOE1 or AID.FlamesOfAsphodelosAOE2 or AID.FlamesOfAsphodelosAOE3) { - case AID.FlamesOfAsphodelosAOE1: - _directions[0] = caster.Rotation; - break; - case AID.FlamesOfAsphodelosAOE2: - _directions[1] = caster.Rotation; - break; - case AID.FlamesOfAsphodelosAOE3: - _directions[2] = caster.Rotation; - break; + _aoes.Add(new(cone, caster.Position, spell.Rotation, Module.CastFinishAt(spell))); + if (_aoes.Count == 6) + _aoes.SortBy(x => x.Activation); } } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - switch ((AID)spell.Action.ID) - { - case AID.FlamesOfAsphodelosAOE1: - _directions[0] = null; - break; - case AID.FlamesOfAsphodelosAOE2: - _directions[1] = null; - break; - case AID.FlamesOfAsphodelosAOE3: - _directions[2] = null; - break; - } - } - - private void DrawZone(Angle? dir, uint color) - { - if (dir != null) - { - Arena.ZoneIsoscelesTri(Arena.Center, dir.Value, 30.Degrees(), 50, color); - Arena.ZoneIsoscelesTri(Arena.Center, dir.Value + 180.Degrees(), 30.Degrees(), 50, color); - } - } - - private bool InAOE(Angle? dir, WPos pos) - { - if (dir == null) - return false; - - var toPos = (pos - Module.Center).Normalized(); - return Math.Abs(dir.Value.ToDirection().Dot(toPos)) >= MathF.Cos(MathF.PI / 6); + if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.FlamesOfAsphodelosAOE1 or AID.FlamesOfAsphodelosAOE2 or AID.FlamesOfAsphodelosAOE3) + _aoes.RemoveAt(0); } } diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FledglingFlight.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FledglingFlight.cs index fbd9032039..ca0a4480cd 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FledglingFlight.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/FledglingFlight.cs @@ -121,6 +121,6 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) return null; var offset = rot.ToDirection() * _eyePlacementOffset; - return _playerDeathTollStacks[slot] > 0 ? Module.Center - offset : Module.Center + offset; + return _playerDeathTollStacks[slot] > 0 ? Arena.Center - offset : Arena.Center + offset; } } diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3S.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3S.cs index 092474f56f..b1525cd3d8 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3S.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3S.cs @@ -1,7 +1,33 @@ namespace BossMod.Endwalker.Savage.P3SPhoinix; class HeatOfCondemnation(BossModule module) : Components.TankbusterTether(module, ActionID.MakeSpell(AID.HeatOfCondemnationAOE), (uint)TetherID.HeatOfCondemnation, 6); -class DevouringBrand(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DevouringBrandAOE), new AOEShapeCross(40, 5)); +class TrailOfCondemnationAOE(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TrailOfCondemnationAOE), new AOEShapeRect(40, 7.5f)); +class SearingBreeze(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.SearingBreezeAOE), 6); + +abstract class Cinderwing(BossModule module, AID aid) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(60, 90.Degrees())); +class LeftCinderwing(BossModule module) : Cinderwing(module, AID.LeftCinderwing); +class RightCinderwing(BossModule module) : Cinderwing(module, AID.RightCinderwing); + +class DevouringBrand(BossModule module) : Components.GenericAOEs(module) +{ + private static readonly AOEShapeCross cross = new(40, 5); + private AOEInstance? _aoe; + + public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.DevouringBrandAOE) + _aoe = new(cross, spell.LocXZ, default, Module.CastFinishAt(spell, 2.2f)); + } + + public override void OnEventEnvControl(byte index, uint state) + { + if (index == 0x00 && state == 0x00080004) + _aoe = null; + } +} + class SunBirdLarge(BossModule module) : Components.Adds(module, (uint)OID.SunbirdLarge) { public int FinishedTethers; diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SEnums.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SEnums.cs index 6a4f665697..911cde7130 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SEnums.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SEnums.cs @@ -10,6 +10,7 @@ public enum OID : uint DarkenedFire = 0x3545, // R2.0, spawned mid fight FountainOfFire = 0x3546, // R2.0, spawned mid fight, towers that healers soak DarkblazeTwister = 0x3547, // R2.5, spawned mid fight, tornadoes + TwisterVoidzone = 0x1EA1FA, // R0.5 SparkfledgedHelper = 0x3800, // R2.3, spawned mid fight, have weird kind... - look like "eyes" during death toll?.. Helper = 0x233C } @@ -47,6 +48,7 @@ public enum AID : uint DevouringBrand = 26318, // Boss->self, 3.0s cast, single-target DevouringBrandExpanding = 26320, // Helper->self, no cast, range 4 width 5 rect DevouringBrandMiniAOE = 26319, // Helper->self, 3.0s cast, range 2 width 5 rect (cardinals) + DevouringBrandAOE = 28035, // Helper->self, 20.0s cast, range 40 width 10 cross (in center) DevouringBrandLargeAOE = 26321, // Helper->self, no cast, range 40 width 10 cross (ones standing on cardinals) GreatWhirlwindSmall = 26323, // SunbirdSmall->self, 3.0s cast, range 60 circle (enrage) GreatWhirlwindLarge = 26325, // SunbirdLarge->self, 3.0s cast, range 60 circle (enrage) @@ -91,20 +93,21 @@ public enum AID : uint SearingBreezeAOE = 26373, // Helper->self, 3.0s cast, range 6 circle ScorchedExaltation = 26374, // Boss->self, 5.0s cast, range 60 circle FinalExaltation = 27691, // Boss->Boss - DevouringBrandAOE = 28035, // Helper->self, 20.0s cast, range 40 width 10 cross (in center) BlazingRain = 26322, // Helper->self, no cast, range 60 circle } public enum SID : uint { DeathsToll = 2762, + Invincibility = 775, // none->DarkenedFire, extra=0x0 } public enum TetherID : uint { - LargeBirdFar = 1, - LargeBirdClose = 57, - HeatOfCondemnation = 89, - BurningTwister = 167, - DarkTwister = 168, + HeatOfCondemnation = 89, // player->Boss + LargeBirdClose = 57, // player/SunbirdLarge/Sunshadow->player + LargeBirdFar = 1, // player/SunbirdLarge/Sunshadow->player + FountainOfFire = 27, // FountainOfFire->player/Boss + BurningTwister = 167, // DarkblazeTwister->Boss + DarkTwister = 168, // DarkblazeTwister->Boss } diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SStates.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SStates.cs index ffd7ec5636..45b20c9eb1 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SStates.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/P3SStates.cs @@ -59,6 +59,8 @@ private void DeadRebirth(uint id, float delay) private void FirestormsOfAsphodelos(uint id, float delay) { Cast(id, AID.FirestormsOfAsphodelos, delay, 5, "Raidwide") + .ActivateOnExit() + .ActivateOnExit() .SetHint(StateMachine.StateHint.Raidwide); } @@ -136,8 +138,10 @@ private void GloryplumeSingle(uint id, float delay) private State Cinderwing(uint id, float delay) { return CastMulti(id, [AID.RightCinderwing, AID.LeftCinderwing], delay, 5, "Side cleave") - .ActivateOnEnter() - .DeactivateOnExit(); + .ActivateOnEnter() + .ActivateOnEnter() + .DeactivateOnExit() + .DeactivateOnExit(); } private void FireplumeCinderwing(uint id, float delay) @@ -153,11 +157,13 @@ private void DevouringBrandFireplumeBreezeCinderwing(uint id, float delay) Cast(id, AID.DevouringBrand, delay, 3, "Devouring Brand"); Fireplume(id + 0x1000, 2.1f); // pos-start CastStart(id + 0x2000, AID.SearingBreeze, 7.2f) + .ActivateOnEnter() .ActivateOnEnter() // start showing brand aoe after fireplume cast is done .DeactivateOnExit(); - CastEnd(id + 0x2001, 3, "Searing Breeze"); + CastEnd(id + 0x2001, 3, "Baited AOEs"); Cinderwing(id + 0x3000, 3.2f) .SetHint(StateMachine.StateHint.PositioningEnd) + .DeactivateOnExit() .OnEnter(Module.DeactivateComponent); // TODO: stop showing brand when aoes finish... } @@ -165,14 +171,14 @@ private void DarkenedFire(uint id, float delay) { // 3s after cast ends, adds start casting 26299 CastStart(id, AID.DarkenedFire, delay) - .SetHint(StateMachine.StateHint.PositioningStart) - .ActivateOnEnter(); + .SetHint(StateMachine.StateHint.PositioningStart); CastEnd(id + 0x1000, 6, "Darkened Fire phase") .ActivateOnEnter() .DeactivateOnExit(); CastStart(id + 0x2000, AID.BrightenedFire, 5.2f) .ActivateOnEnter(); // icons appear just before cast start - CastEnd(id + 0x2001, 5, "Numbers"); // at the end boss starts shooting 1-8 + CastEnd(id + 0x2001, 5, "Numbers") // at the end boss starts shooting 1-8 + .ActivateOnEnter(); ComponentCondition(id + 0x3000, 8.4f, comp => comp.NumCasts == 8) .DeactivateOnExit(); Timeout(id + 0x4000, 6.6f, "Darkened Fire resolve") // this timer is max time to kill adds before enrage, timeout is ok here @@ -185,9 +191,11 @@ private State TrailOfCondemnation(uint id, float delay) // at this point boss teleports to one of the cardinals // parallel to this one of the helpers casts 26365 (actual aoe fire trails) CastMulti(id, [AID.TrailOfCondemnationCenter, AID.TrailOfCondemnationSides], delay, 6) + .ActivateOnEnter() .ActivateOnEnter(); return ComponentCondition(id + 2, 1.5f, comp => comp.Done, "Sides/Center AOE") - .DeactivateOnExit(); + .DeactivateOnExit() + .DeactivateOnExit(); } // note: expects downtime at enter, clears when birds spawn, reset when birds die @@ -281,18 +289,15 @@ private void FountainOfFire(uint id, float delay) private void ConesAshplume(uint id, float delay) { Cast(id, AID.FlamesOfAsphodelos, delay, 3, "Cones") - .ActivateOnEnter() .SetHint(StateMachine.StateHint.PositioningStart); AshplumeCast(id + 0x1000, 2.1f); AshplumeResolve(id + 0x2000, 6.1f) - .DeactivateOnExit() .SetHint(StateMachine.StateHint.PositioningEnd); } private void ConesStorms(uint id, float delay) { Cast(id, AID.FlamesOfAsphodelos, delay, 3, "Cones") - .ActivateOnEnter() .SetHint(StateMachine.StateHint.PositioningStart); Cast(id + 0x1000, AID.StormsOfAsphodelos, 10.2f, 8, "Storms") .ActivateOnEnter() @@ -304,15 +309,20 @@ private void ConesStorms(uint id, float delay) private void DarkblazeTwister(uint id, float delay) { Cast(id, AID.DarkblazeTwister, delay, 4, "Twister") - .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() .SetHint(StateMachine.StateHint.PositioningStart); - Cast(id + 0x1000, AID.SearingBreeze, 4.1f, 3, "Searing Breeze"); + Cast(id + 0x1000, AID.SearingBreeze, 4.1f, 3, "Searing Breeze") + .ActivateOnEnter(); AshplumeCast(id + 0x2000, 4.1f); - ComponentCondition(id + 0x3000, 2.8f, comp => comp.DarkTwister() == null, "Knockback") + ComponentCondition(id + 0x3000, 2.8f, comp => comp.Casters.Count == 0, "Knockback") + .DeactivateOnEnter() + .DeactivateOnExit() .SetHint(StateMachine.StateHint.Knockback); - ComponentCondition(id + 0x4000, 2, comp => !comp.BurningTwisters().Any(), "AOE") - .DeactivateOnExit(); + ComponentCondition(id + 0x4000, 2, comp => comp.NumCasts == 2, "AOE") + .DeactivateOnExit(); AshplumeResolve(id + 0x5000, 2.3f) + .DeactivateOnExit() .SetHint(StateMachine.StateHint.PositioningEnd); } } diff --git a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/TrailOfCondemnation.cs b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/TrailOfCondemnation.cs index 61c6cd0bcd..7787ca3db2 100644 --- a/BossMod/Modules/Endwalker/Savage/P3SPhoinix/TrailOfCondemnation.cs +++ b/BossMod/Modules/Endwalker/Savage/P3SPhoinix/TrailOfCondemnation.cs @@ -5,23 +5,14 @@ class TrailOfCondemnation(BossModule module) : BossComponent(module) { public bool Done { get; private set; } private readonly bool _isCenter = module.PrimaryActor.CastInfo?.IsSpell(AID.TrailOfCondemnationCenter) ?? false; - - private const float _halfWidth = 7.5f; - private const float _sidesOffset = 12.5f; private const float _aoeRadius = 6; public override void AddHints(int slot, Actor actor, TextHints hints) { if (Module.PrimaryActor.Position == Arena.Center) return; - - var dir = (Module.Center - Module.PrimaryActor.Position).Normalized(); if (_isCenter) { - if (actor.Position.InRect(Module.PrimaryActor.Position, dir, 2 * Arena.Bounds.Radius, 0, _halfWidth)) - { - hints.Add("GTFO from aoe!"); - } if (Raid.WithoutSlot().InRadiusExcluding(actor, _aoeRadius).Any()) { hints.Add("Spread!"); @@ -29,12 +20,6 @@ public override void AddHints(int slot, Actor actor, TextHints hints) } else { - var offset = _sidesOffset * dir.OrthoR(); - if (actor.Position.InRect(Module.PrimaryActor.Position + offset, dir, 2 * Arena.Bounds.Radius, 0, _halfWidth) || - actor.Position.InRect(Module.PrimaryActor.Position - offset, dir, 2 * Arena.Bounds.Radius, 0, _halfWidth)) - { - hints.Add("GTFO from aoe!"); - } // note: sparks either target all tanks & healers or all dds - so correct pairings are always dd+tank/healer var numStacked = 0; var goodPair = false; @@ -54,24 +39,6 @@ public override void AddHints(int slot, Actor actor, TextHints hints) } } - public override void DrawArenaBackground(int pcSlot, Actor pc) - { - if (Module.PrimaryActor.Position == Arena.Center) - return; - - var dir = (Arena.Center - Module.PrimaryActor.Position).Normalized(); - if (_isCenter) - { - Arena.ZoneRect(Module.PrimaryActor.Position, dir, 2 * Arena.Bounds.Radius, 0, _halfWidth, Colors.AOE); - } - else - { - var offset = _sidesOffset * dir.OrthoR(); - Arena.ZoneRect(Module.PrimaryActor.Position + offset, dir, 2 * Arena.Bounds.Radius, 0, _halfWidth, Colors.AOE); - Arena.ZoneRect(Module.PrimaryActor.Position - offset, dir, 2 * Arena.Bounds.Radius, 0, _halfWidth, Colors.AOE); - } - } - public override void DrawArenaForeground(int pcSlot, Actor pc) { // draw all raid members, to simplify positioning