From 39e389b0257e7354e1a61a83dd7a1a19d93906c3 Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:29:39 +0100 Subject: [PATCH] aetherochemical research lab trash modules --- BossMod/Components/TemporaryMisdirection.cs | 23 ++- BossMod/Components/ThinIce.cs | 21 +- .../Dawntrail/Ultimate/FRU/P2DiamondDust.cs | 2 +- .../D05GreatGubalLibrary/D051DemonTome.cs | 3 + .../D05GreatGubalLibrary/D052Byblos.cs | 73 +++---- .../D053TheEverlivingBibliotaph.cs | 12 +- .../D060BiocultureNode.cs | 194 ++++++++++++++++++ .../D060ClonedConjurer.cs | 51 +++++ .../D060CulturedShabti.cs | 76 +++++++ .../D060FacilityDreadnaught.cs | 44 ++++ .../D060SixthLegionMagitekVanguardH1.cs | 69 +++++++ .../D060Trash1.cs | 106 ++++++++++ .../D061Regula.cs | 8 +- .../D062Harmachis.cs | 4 +- .../D063LahabreaIgeyorhm.cs | 61 +++--- .../D064AscianPrime.cs | 58 +++--- .../SharedBounds.cs | 54 +++++ .../D13SohrKhai/D0130BlizzardDragon.cs | 2 +- .../Dungeon/D13SohrKhai/D0130CloudGardener.cs | 1 + .../Dungeon/D13SohrKhai/D133Hraesvelgr.cs | 2 +- BossMod/Replay/ReplayBuilder.cs | 7 +- BossMod/Replay/Visualization/OpList.cs | 2 +- 22 files changed, 736 insertions(+), 137 deletions(-) create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs create mode 100644 BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/SharedBounds.cs diff --git a/BossMod/Components/TemporaryMisdirection.cs b/BossMod/Components/TemporaryMisdirection.cs index c888302b2c..63e4a014dc 100644 --- a/BossMod/Components/TemporaryMisdirection.cs +++ b/BossMod/Components/TemporaryMisdirection.cs @@ -3,14 +3,23 @@ namespace BossMod.Components; // generic temporary misdirection component public class TemporaryMisdirection(BossModule module, ActionID aid, string hint = "Applies temporary misdirection") : CastHint(module, aid, hint) { - private static readonly uint[] tempMisdirectionSIDs = [1422, 2936, 3694, 3909]; + public BitMask Mask; + + public override void OnStatusGain(Actor actor, ActorStatus status) + { + if (status.ID is 1422 or 2936 or 3694 or 3909) + Mask.Set(Raid.FindSlot(actor.InstanceID)); + } + + public override void OnStatusLose(Actor actor, ActorStatus status) + { + if (status.ID is 1422 or 2936 or 3694 or 3909) + Mask[Raid.FindSlot(actor.InstanceID)] = default; + } + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < 4; ++i) - if (actor.FindStatus(tempMisdirectionSIDs[i]) != null) - { - hints.AddSpecialMode(AIHints.SpecialMode.Misdirection, default); - break; - } + if (Mask[slot] != default) + hints.AddSpecialMode(AIHints.SpecialMode.Misdirection, default); } } diff --git a/BossMod/Components/ThinIce.cs b/BossMod/Components/ThinIce.cs index bd716572ce..f51c2c4b4f 100644 --- a/BossMod/Components/ThinIce.cs +++ b/BossMod/Components/ThinIce.cs @@ -2,18 +2,31 @@ namespace BossMod.Components; // component for ThinIce mechanic // observation: for SID 911 the distance is 0.1 * status extra -public abstract class ThinIce(BossModule module, bool createforbiddenzones, uint statusID = 911, float distance = 11, bool stopAtWall = false, bool stopAfterWall = false) : Knockback(module, stopAtWall: stopAtWall, stopAfterWall: stopAfterWall) +public abstract class ThinIce(BossModule module, float distance, bool createforbiddenzones = false, uint statusID = 911, bool stopAtWall = false, bool stopAfterWall = false) : Knockback(module, stopAtWall: stopAtWall, stopAfterWall: stopAfterWall) { public readonly uint StatusID = statusID; public readonly float Distance = distance; private static readonly WDir offset = new(0, 1); + public BitMask Mask; public override IEnumerable Sources(int slot, Actor actor) { - if (actor.FindStatus(StatusID) != null) + if (Mask[slot] != default) yield return new(actor.Position, Distance, default, default, actor.Rotation, Kind.DirForward); } + public override void OnStatusGain(Actor actor, ActorStatus status) + { + if (status.ID == StatusID) + Mask.Set(Raid.FindSlot(actor.InstanceID)); + } + + public override void OnStatusLose(Actor actor, ActorStatus status) + { + if (status.ID == StatusID) + Mask[Raid.FindSlot(actor.InstanceID)] = default; + } + public override void AddHints(int slot, Actor actor, TextHints hints) { if (CalculateMovements(slot, actor).Any(e => DestinationUnsafe(slot, actor, e.to))) @@ -23,13 +36,13 @@ public override void AddHints(int slot, Actor actor, TextHints hints) public override void DrawArenaForeground(int pcSlot, Actor pc) { base.DrawArenaForeground(pcSlot, pc); - if (pc.FindStatus(StatusID) != null) + if (Mask[pcSlot] != default) Arena.AddCircle(pc.Position, Distance, Colors.Vulnerable); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (createforbiddenzones && actor.FindStatus(StatusID) != null) + if (createforbiddenzones && Mask[slot] != default) { var pos = actor.Position; var ddistance = 2 * Distance; diff --git a/BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs b/BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs index 6d476d87e4..a2081bba67 100644 --- a/BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs +++ b/BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs @@ -222,7 +222,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } } -class P2ThinIce(BossModule module) : Components.ThinIce(module, true, distance: 32) +class P2ThinIce(BossModule module) : Components.ThinIce(module, 32, true) { 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.InBounds(pos); diff --git a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D051DemonTome.cs b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D051DemonTome.cs index 22b6ea5483..75f1e66bdb 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D051DemonTome.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D051DemonTome.cs @@ -58,11 +58,14 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } } +class ThinIce(BossModule module) : Components.ThinIce(module, 15, stopAtWall: true); + class D051DemonTomeStates : StateMachineBuilder { public D051DemonTomeStates(BossModule module) : base(module) { TrivialPhase() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() diff --git a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D052Byblos.cs b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D052Byblos.cs index 980ce3105b..c604e75e87 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D052Byblos.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D052Byblos.cs @@ -94,52 +94,55 @@ public D052ByblosStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 31, NameID = 3925)] public class D052Byblos(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly WPos[] vertices = [new(182.26f, 3.32f), new(182.73f, 3.56f), new(183.19f, 3.90f), new(183.75f, 3.97f), new(184.83f, 3.93f), - new(185.39f, 3.94f), new(186.84f, 4.77f), new(187.35f, 4.97f), new(187.86f, 5.11f), new(188.42f, 5.24f), - new(188.97f, 5.45f), new(190.39f, 6.58f), new(191.87f, 7.27f), new(192.3f, 7.56f), new(193.11f, 8.43f), - new(193.52f, 8.86f), new(195, 9.83f), new(195.3f, 10.24f), new(195.94f, 11.22f), new(196.26f, 11.63f), - new(197.51f, 12.78f), new(198.19f, 14.29f), new(198.47f, 14.71f), new(199.54f, 16.05f), new(199.97f, 17.64f), - new(200.16f, 18.14f), new(200.77f, 19.2f), new(200.99f, 19.68f), new(201.11f, 20.75f), new(201.2f, 21.28f), - new(201.32f, 21.79f), new(201.89f, 23.34f), new(201.8f, 25.04f), new(201.87f, 25.56f), new(202.12f, 26.73f), - new(202.16f, 27.25f), new(201.83f, 28.83f), new(201.82f, 29.37f), new(201.88f, 30.56f), new(201.85f, 31.06f), - new(201.23f, 32.68f), new(201.06f, 34.28f), new(200.9f, 34.84f), new(200.02f, 36.35f), new(199.64f, 37.84f), - new(199.45f, 38.33f), new(198.42f, 39.59f), new(198.14f, 40.07f), new(197.67f, 41.13f), new(197.42f, 41.56f), - new(196.24f, 42.62f), new(195.91f, 43.04f), new(195.33f, 43.96f), new(194.95f, 44.44f), new(193.52f, 45.37f), - new(193.12f, 45.78f), new(192.34f, 46.65f), new(191.86f, 46.99f), new(190.44f, 47.63f), new(190.03f, 47.92f), - new(189.22f, 48.58f), new(188.75f, 48.89f), new(187.09f, 49.33f), new(185.59f, 50.19f), new(185.02f, 50.31f), - new(183.39f, 50.25f), new(182.89f, 50.56f), new(182.4f, 50.92f), new(181.39f, 50.94f), new(173.37f, 50.97f), - new(172.93f, 50.66f), new(172.48f, 50.39f), new(171.93f, 50.26f), new(170.21f, 50.33f), new(168.68f, 49.44f), - new(168.17f, 49.25f), new(167.17f, 49.01f), new(166.66f, 48.84f), new(165.43f, 47.84f), new(164.9f, 47.52f), - new(163.83f, 47.04f), new(163.35f, 46.77f), new(162.21f, 45.5f), new(161.78f, 45.2f), new(160.9f, 44.63f), - new(160.45f, 44.26f), new(159.58f, 42.92f), new(159.21f, 42.52f), new(158.42f, 41.81f), new(158.01f, 41.39f), - new(157.38f, 39.98f), new(157.07f, 39.47f), new(156.04f, 38.21f), new(155.6f, 36.57f), new(155.36f, 36.04f), - new(154.83f, 35.13f), new(154.56f, 34.58f), new(154.37f, 32.85f), new(154.19f, 32.25f), new(153.78f, 31.19f), - new(153.71f, 30.69f), new(153.76f, 29.55f), new(153.76f, 28.96f), new(153.43f, 27.37f), new(153.44f, 26.86f), - new(153.78f, 25.25f), new(153.7f, 23.69f), new(153.76f, 23.1f), new(154.31f, 21.66f), new(154.41f, 21.08f), - new(154.53f, 19.94f), new(154.69f, 19.4f), new(155.53f, 17.93f), new(155.98f, 16.27f), new(156.23f, 15.81f), - new(157.2f, 14.6f), new(157.91f, 13.06f), new(158.2f, 12.64f), new(159.4f, 11.54f), new(159.72f, 11.13f), - new(160.01f, 10.69f), new(160.28f, 10.23f), new(160.64f, 9.8f), new(162.06f, 8.87f), new(162.48f, 8.46f), - new(163.23f, 7.63f), new(163.72f, 7.27f), new(165.24f, 6.59f), new(165.65f, 6.22f), new(166.52f, 5.52f), - new(166.99f, 5.29f), new(168.49f, 4.88f), new(169, 4.63f), new(169.53f, 4.31f), new(170.06f, 4.02f), - new(170.65f, 3.94f), new(172.25f, 3.99f), new(173.17f, 3.37f), new(173.8f, 3.28f), new(181.12f, 3.27f)]; + private static readonly WPos[] vertices = [new(182.36f, 3.29f), new(182.89f, 3.68f), new(183.4f, 3.98f), new(185.25f, 3.93f), new(185.87f, 4.23f), + new(187, 4.87f), new(187.68f, 5.04f), new(188.36f, 5.23f), new(189, 5.48f), new(190.01f, 6.3f), + new(190.52f, 6.64f), new(191.63f, 7.14f), new(192.21f, 7.45f), new(193.13f, 8.47f), new(193.62f, 8.91f), + new(194.81f, 9.7f), new(195.26f, 10.2f), new(195.97f, 11.28f), new(196.41f, 11.75f), new(197.46f, 12.7f), + new(197.77f, 13.3f), new(198.31f, 14.52f), new(199.19f, 15.61f), new(199.55f, 16.13f), new(199.91f, 17.43f), + new(200.11f, 18), new(200.78f, 19.17f), new(201.03f, 19.82f), new(201.18f, 21.12f), new(201.31f, 21.74f), + new(201.79f, 23), new(201.88f, 23.68f), new(201.82f, 24.95f), new(201.88f, 25.56f), new(202.15f, 26.85f), + new(202.11f, 27.53f), new(201.85f, 28.75f), new(201.83f, 29.37f), new(201.89f, 30.66f), new(201.76f, 31.3f), + new(201.31f, 32.48f), new(201.18f, 33.07f), new(201.04f, 34.44f), new(200.77f, 35.07f), new(200.13f, 36.19f), + new(199.91f, 36.76f), new(199.6f, 37.94f), new(199.28f, 38.51f), new(198.45f, 39.53f), new(198.13f, 40.07f), + new(197.9f, 40.67f), new(197.64f, 41.27f), new(197.19f, 41.79f), new(196.2f, 42.67f), new(195.83f, 43.15f), + new(195.16f, 44.18f), new(194.67f, 44.61f), new(193.64f, 45.27f), new(193.2f, 45.69f), new(192.37f, 46.61f), + new(191.85f, 47.01f), new(190.73f, 47.5f), new(190.19f, 47.79f), new(189.19f, 48.59f), new(188.63f, 48.93f), + new(187.41f, 49.25f), new(186.82f, 49.44f), new(186.28f, 49.8f), new(185.7f, 50.14f), new(185.06f, 50.31f), + new(183.78f, 50.26f), new(183.21f, 50.32f), new(182.73f, 50.68f), new(182.15f, 50.96f), new(173.51f, 50.96f), + new(172.88f, 50.62f), new(172.34f, 50.3f), new(171.74f, 50.27f), new(170.48f, 50.32f), new(169.83f, 50.1f), + new(168.68f, 49.42f), new(168.09f, 49.22f), new(166.79f, 48.87f), new(166.28f, 48.49f), new(165.3f, 47.7f), + new(163.58f, 46.95f), new(163.08f, 46.48f), new(162.21f, 45.51f), new(161.71f, 45.13f), new(160.58f, 44.4f), + new(160.22f, 43.87f), new(159.51f, 42.78f), new(159.05f, 42.39f), new(158.05f, 41.49f), new(157.26f, 39.73f), + new(156.88f, 39.22f), new(156.07f, 38.25f), new(155.88f, 37.61f), new(155.55f, 36.39f), new(155.25f, 35.81f), + new(154.59f, 34.67f), new(154.39f, 32.77f), new(154.18f, 32.15f), new(153.93f, 31.52f), new(153.72f, 30.86f), + new(153.81f, 28.96f), new(153.64f, 28.34f), new(153.5f, 27.68f), new(153.41f, 26.98f), new(153.79f, 25.15f), + new(153.73f, 23.82f), new(153.76f, 23.16f), new(154.21f, 21.98f), new(154.38f, 21.37f), new(154.51f, 20.13f), + new(154.64f, 19.48f), new(155.56f, 17.86f), new(155.92f, 16.56f), new(156.18f, 15.9f), new(156.95f, 14.94f), + new(157.28f, 14.46f), new(157.83f, 13.24f), new(158.19f, 12.65f), new(159.55f, 11.41f), new(160.23f, 10.36f), + new(160.64f, 9.79f), new(161.79f, 9.03f), new(162.3f, 8.63f), new(163.16f, 7.69f), new(163.7f, 7.27f), + new(164.8f, 6.77f), new(165.35f, 6.46f), new(166.46f, 5.57f), new(167.11f, 5.27f), new(168.4f, 4.92f), + new(168.92f, 4.66f), new(170.08f, 4), new(170.72f, 3.95f), new(171.94f, 3.99f), new(172.48f, 3.84f), + new(173.01f, 3.48f), new(179.1f, 3.26f), new(182.13f, 3.26f)]; + private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actor(PrimaryActor); + if (PrimaryActor.FindStatus(SID.Invincibility) == null) + Arena.Actor(PrimaryActor); Arena.Actors(Enemies(OID.Page64)); } 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) { - e.Priority = (OID)e.Actor.OID switch + var e = hints.PotentialTargets[i]; + if (e.Actor.FindStatus(SID.Invincibility) != null) { - OID.Page64 => 2, - OID.Boss => 1, - _ => 0 - }; + e.Priority = AIHints.Enemy.PriorityForbidFully; + break; + } } } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs index 0729562ee8..eeb1a809e4 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs @@ -147,21 +147,23 @@ public D053EverlivingBibliotaphStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 31, NameID = 3930)] public class D053EverlivingBibliotaph(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly ArenaBoundsComplex arena = new([new Circle(new(377.8f, -59.7f), 24.5f)], [new Rectangle(new(353.541f, -59.553f), 20, 1.25f, 89.977f.Degrees())]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(377.8f, -59.7f), 24.5f, 80)], [new Rectangle(new(353.541f, -59.553f), 20, 1.25f, 89.977f.Degrees())]); + private static readonly uint[] adds = [(uint)OID.Bibliophile, (uint)OID.Biblioklept, (uint)OID.Bibliomancer]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.Bibliophile).Concat([PrimaryActor]).Concat(Enemies(OID.Biblioklept)).Concat(Enemies(OID.Bibliomancer))); + Arena.Actor(PrimaryActor); + Arena.Actors(Enemies(adds)); } 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.Biblioklept or OID.Bibliophile or OID.Bibliomancer => 2, - OID.Boss => 1, + OID.Biblioklept or OID.Bibliophile or OID.Bibliomancer => 1, _ => 0 }; } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs new file mode 100644 index 0000000000..b64538f50b --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs @@ -0,0 +1,194 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility.D060BiocultureNode; + +public enum OID : uint +{ + Boss = 0xF4D, // R2.3 + Boss1Hole = 0x1E9934, // R2.0 + Boss2Hole = 0x1E9935, // R2.0 + PreculturedBiomass = 0xF4E, // R1.0 + CulturedNaga = 0x10B0, // R0.9 + CulturedEmpuse = 0xF50, // R1.5 + CulturedCobra = 0x10B1, // R1.2 + CulturedDancer = 0xF4F, // R1.0 + CulturedBowyer = 0x10AF, // R1.0 + BiocultureNode = 0xF4D, // R2.3 + CulturedReptoid = 0xF51, // R3.0 + Biohazard = 0xF53, // R1.8 + CulturedMirrorknight = 0x10B2, // R1.7 + CulturedChimera = 0x10B3 // R3.7 +} + +public enum AID : uint +{ + AutoAttack1 = 872, // Biohazard/CulturedChimera/PreculturedBiomass/CulturedNaga->player, no cast, single-target + AutoAttack2 = 870, // CulturedEmpuse/CulturedCobra/CulturedDancer->player, no cast, single-target + AutoAttack3 = 871, // CulturedReptoid/CulturedMirrorknight->player, no cast, single-target + + Electrify = 4824, // BiocultureNode->self, no cast, range 30+R circle + Shot = 4704, // CulturedBowyer->player, no cast, single-target + Puncture = 4465, // CulturedEmpuse->self, 3.0s cast, range 4+R width 3 rect + TailSlap = 4703, // CulturedDancer->self, 3.0s cast, range 6+R 120-degree cone + CalcifyingMist = 4666, // CulturedNaga->self, 3.0s cast, range 6+R 90-degree cone, gaze + StandingChine = 939, // CulturedEmpuse->player, no cast, single-target + EerieSoundwave = 4464, // CulturedEmpuse->self, 3.0s cast, range 6+R circle + + HardThrust = 4518, // CulturedReptoid->player, no cast, single-target + Gust = 917, // CulturedMirrorknight->location, 2.5s cast, range 3 circle + Sideswipe = 4519, // CulturedReptoid->self, 3.0s cast, range 6+R 90-degree cone + Bearclaw = 915, // CulturedMirrorknight->player, no cast, single-target + MarrowDrain1 = 3342, // CulturedChimera->self, 3.0s cast, range 6+R 120-degree cone + MarrowDrain2 = 3341, // CulturedChimera->self, 3.0s cast, range 6+R 120-degree cone + MarrowDrain3 = 3340, // CulturedChimera->self, 3.0s cast, range 6+R 120-degree cone + TheRamsVoice = 3343, // CulturedChimera->self, 3.0s cast, range 6+R circle +} + +class Hole(BossModule module) : BossComponent(module) +{ + public override void OnActorEAnim(Actor actor, uint state) + { + if (state == 0x00040008) + { + if ((OID)actor.OID == OID.Boss1Hole) + Arena.Bounds = D060BiocultureNode.Arena1b; + else if ((OID)actor.OID == OID.Boss2Hole) + Arena.Bounds = D060BiocultureNode.Arena2b; + } + } +} + +class Puncture(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Puncture), new AOEShapeRect(5.5f, 1.5f)); +class TailSlap(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TailSlap), new AOEShapeCone(7, 60.Degrees())); +class CalcifyingMist(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CalcifyingMist), new AOEShapeCone(6.9f, 45.Degrees())); +class EerieSoundwave(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EerieSoundwave), new AOEShapeCircle(7.5f)); + +abstract class MarrowDrain(BossModule module, AID aid) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(9.7f, 60.Degrees())); +class MarrowDrain1(BossModule module) : MarrowDrain(module, AID.MarrowDrain1); +class MarrowDrain2(BossModule module) : MarrowDrain(module, AID.MarrowDrain2); +class MarrowDrain3(BossModule module) : MarrowDrain(module, AID.MarrowDrain3); + +class TheRamsVoice(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TheRamsVoice), new AOEShapeCircle(9.7f)); +class Sideswipe(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Sideswipe), new AOEShapeCone(9, 45.Degrees())); +class Gust(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Gust), 3); + +class D060BiocultureNodeStates : StateMachineBuilder +{ + public D060BiocultureNodeStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(module.Bounds == D060BiocultureNode.Arena1 || module.Bounds == D060BiocultureNode.Arena1b ? D060BiocultureNode.Trash1 : D060BiocultureNode.Trash2).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3830, SortOrder = 5)] +public class D060BiocultureNode(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? Arena1.Center : arena2.Center, IsArena1(primary) ? Arena1 : arena2) +{ + public static bool IsArena1(Actor primary) => primary.Position.Z < 250; + + private static readonly WPos[] vertices1 = [new(26.19f, 163.90f), new(29.99f, 164.07f), new(30.59f, 164.12f), new(31.30f, 164.26f), new(31.59f, 164.85f), + new(31.81f, 165.42f), new(32.00f, 166.01f), new(32.24f, 166.60f), new(34.76f, 168.55f), new(34.99f, 169.17f), + new(35.98f, 170.85f), new(36.08f, 193.26f), new(36.16f, 193.81f), new(40.19f, 197.85f), new(40.60f, 198.35f), + new(40.94f, 198.88f), new(41.12f, 199.36f), new(41.23f, 200.02f), new(41.62f, 200.51f), new(43.27f, 202.40f), + new(43.77f, 202.77f), new(45.92f, 205.07f), new(46.41f, 205.39f), new(49.02f, 208.15f), new(49.53f, 208.52f), + new(51.69f, 210.84f), new(52.20f, 211.19f), new(54.38f, 213.51f), new(54.87f, 213.92f), new(57.07f, 216.22f), + new(57.55f, 216.67f), new(58.04f, 217.10f), new(60.25f, 219.38f), new(60.79f, 219.82f), new(60.60f, 220.29f), + new(60.15f, 220.72f), new(59.71f, 221.13f), new(59.38f, 221.68f), new(57.08f, 223.79f), new(56.72f, 224.31f), + new(54.40f, 226.46f), new(53.98f, 226.87f), new(53.62f, 227.39f), new(51.31f, 229.56f), new(50.87f, 230.09f), + new(48.55f, 232.30f), new(48.28f, 232.83f), new(45.86f, 235.02f), new(45.45f, 235.48f), new(45.00f, 235.97f), + new(42.68f, 238.14f), new(42.29f, 238.66f), new(40.94f, 240.01f), new(40.50f, 240.48f), new(40.09f, 240.97f), + new(40.02f, 241.50f), new(38.84f, 243.09f), new(38.44f, 243.61f), new(38.02f, 244.11f), new(36.30f, 246.04f), + new(36.08f, 246.79f), new(36.06f, 264.86f), new(20.21f, 264.97f), new(19.92f, 246.65f), new(19.80f, 246.14f), + new(15.65f, 241.99f), new(14.94f, 240.92f), new(15.02f, 240.28f), new(14.65f, 239.81f), new(14.25f, 239.32f), + new(13.01f, 237.90f), new(12.56f, 237.47f), new(12.05f, 237.04f), new(9.90f, 234.74f), new(9.35f, 234.37f), + new(7.18f, 232.05f), new(6.68f, 231.70f), new(2.77f, 227.51f), new(-1.34f, 223.50f), new(-1.84f, 223.11f), + new(-2.28f, 222.66f), new(-3.74f, 221.09f), new(-4.21f, 220.64f), new(-4.84f, 220.68f), new(-5.37f, 220.98f), + new(-5.14f, 220.44f), new(1.82f, 213.35f), new(2.04f, 212.83f), new(2.51f, 212.38f), new(2.96f, 211.96f), + new(4.78f, 210.36f), new(5.08f, 209.80f), new(7.38f, 207.77f), new(7.77f, 207.32f), new(8.69f, 206.48f), + new(9.13f, 206.05f), new(10.41f, 204.73f), new(10.39f, 204.20f), new(10.68f, 203.60f), new(11.97f, 202.08f), + new(12.38f, 201.63f), new(12.91f, 201.22f), new(13.41f, 201.18f), new(15.82f, 199.07f), new(16.04f, 198.53f), + new(16.36f, 198.09f), new(16.40f, 197.47f), new(16.77f, 196.88f), new(19.79f, 193.86f), new(19.95f, 167.03f), + new(20.80f, 166.14f), new(20.85f, 164.66f), new(21.34f, 164.33f), new(25.24f, 164.32f), new(25.73f, 164.04f)]; + private static readonly WPos[] vertices2 = [new(119.47f, 228.45f), new(119.98f, 228.57f), new(119.98f, 245.60f), new(120.27f, 246.05f), new(125.43f, 251.12f), + new(125.92f, 251.71f), new(124.05f, 253.58f), new(123.61f, 254.06f), new(123.35f, 254.57f), new(123.53f, 255.12f), + new(123.93f, 255.62f), new(124.41f, 256.05f), new(125.88f, 257.35f), new(126.39f, 257.74f), new(126.92f, 258.12f), + new(127.43f, 258.55f), new(127.82f, 259.09f), new(127.95f, 259.75f), new(127.97f, 260.28f), new(124.69f, 262.50f), + new(124.26f, 262.91f), new(124.31f, 263.56f), new(124.11f, 264.21f), new(123.92f, 264.76f), new(124.35f, 265.16f), + new(124.88f, 265.40f), new(125.56f, 265.41f), new(136.78f, 265.41f), new(137.21f, 265.12f), new(137.39f, 264.49f), + new(137.50f, 263.91f), new(137.43f, 263.31f), new(137.16f, 262.78f), new(136.65f, 262.60f), new(134.43f, 262.60f), + new(133.83f, 262.61f), new(133.18f, 262.66f), new(132.49f, 262.79f), new(131.88f, 262.59f), new(131.45f, 262.23f), + new(139.71f, 253.95f), new(140.15f, 253.53f), new(142.37f, 251.45f), new(142.79f, 251.02f), new(143.22f, 250.58f), + new(144.87f, 248.79f), new(146.17f, 247.50f), new(154.88f, 238.78f), new(155.37f, 238.33f), new(155.84f, 237.86f), + new(156.34f, 238.01f), new(157.31f, 238.99f), new(157.72f, 239.59f), new(157.25f, 240.09f), new(155.91f, 241.41f), + new(155.48f, 241.89f), new(155.35f, 242.44f), new(155.74f, 242.88f), new(156.18f, 243.30f), new(159.31f, 246.46f), + new(160.21f, 247.35f), new(160.81f, 247.64f), new(164.01f, 250.87f), new(164.50f, 251.29f), new(168.20f, 255.04f), + new(168.70f, 255.43f), new(169.29f, 255.76f), new(169.76f, 256.22f), new(171.24f, 257.54f), new(171.72f, 258.00f), + new(172.65f, 258.95f), new(173.15f, 259.33f), new(173.69f, 259.77f), new(176.39f, 262.67f), new(176.84f, 263.15f), + new(177.31f, 263.53f), new(177.83f, 263.44f), new(178.29f, 263.02f), new(179.62f, 261.69f), new(180.23f, 261.89f), + new(182.18f, 263.84f), new(202.04f, 263.92f), new(209.08f, 279.77f), new(208.68f, 280.07f), new(182.47f, 280.07f), + new(181.97f, 280.37f), new(180.63f, 281.71f), new(180.17f, 281.52f), new(177.97f, 279.31f), new(177.53f, 278.89f), + new(177.04f, 278.56f), new(176.44f, 278.95f), new(175.99f, 279.42f), new(172.23f, 283.16f), new(171.83f, 283.65f), + new(171.85f, 284.30f), new(170.55f, 285.59f), new(168.59f, 287.39f), new(168.12f, 287.87f), new(167.67f, 288.36f), + new(166.69f, 289.25f), new(163.89f, 292.04f), new(163.60f, 292.51f), new(163.71f, 293.14f), new(161.48f, 295.39f), + new(160.06f, 296.77f), new(159.67f, 297.26f), new(159.29f, 297.84f), new(158.82f, 298.29f), new(158.33f, 298.73f), + new(155.93f, 300.84f), new(155.50f, 301.27f), new(155.40f, 301.83f), new(155.71f, 302.44f), new(154.08f, 304.28f), + new(153.62f, 303.97f), new(130.76f, 281.41f), new(131.31f, 281.08f), new(133.19f, 281.34f), new(133.81f, 281.39f), + new(136.69f, 281.40f), new(137.16f, 281.22f), new(137.24f, 279.01f), new(136.77f, 278.59f), new(125.01f, 278.59f), + new(124.46f, 278.69f), new(124.35f, 279.48f), new(124.20f, 280.12f), new(124.22f, 280.77f), new(124.46f, 281.33f), + new(127.64f, 281.43f), new(128.05f, 281.73f), new(128.48f, 282.25f), new(128.89f, 282.79f), new(129.31f, 283.38f), + new(129.05f, 283.82f), new(124.47f, 288.62f), new(124.06f, 289.09f), new(123.68f, 289.59f), new(123.55f, 290.15f), + new(123.87f, 290.62f), new(125.26f, 292.01f), new(125.65f, 292.62f), new(120.19f, 297.99f), new(119.98f, 315.39f), + new(105.88f, 315.48f), new(104.09f, 315.45f), new(103.83f, 298.43f), new(103.60f, 297.96f), new(100.27f, 294.62f), + new(99.85f, 294.15f), new(100.00f, 293.58f), new(101.46f, 292.12f), new(102.05f, 291.77f), new(102.03f, 291.14f), + new(101.61f, 290.68f), new(101.13f, 290.28f), new(98.12f, 286.99f), new(97.66f, 286.56f), new(97.19f, 286.18f), + new(96.61f, 286.09f), new(96.13f, 286.47f), new(94.78f, 287.82f), new(94.29f, 288.25f), new(93.64f, 287.97f), + new(87.55f, 281.88f), new(87.29f, 281.26f), new(86.52f, 278.24f), new(85.79f, 276.54f), new(85.41f, 276.19f), + new(83.53f, 276.03f), new(82.90f, 275.88f), new(82.28f, 275.82f), new(75.10f, 278.11f), new(73.53f, 273.24f), + new(73.51f, 272.74f), new(74.46f, 271.85f), new(75.01f, 271.49f), new(75.63f, 271.27f), new(76.29f, 271.09f), + new(77.51f, 270.97f), new(78.15f, 270.98f), new(78.74f, 270.92f), new(91.57f, 258.12f), new(92.08f, 257.66f), + new(92.72f, 257.66f), new(95.36f, 260.29f), new(95.81f, 260.65f), new(96.33f, 260.56f), new(96.78f, 260.21f), + new(99.38f, 257.43f), new(99.83f, 256.97f), new(100.31f, 256.55f), new(100.76f, 256.12f), new(101.19f, 255.70f), + new(101.16f, 255.18f), new(100.78f, 254.71f), new(98.07f, 252.00f), new(98.20f, 251.49f), new(98.72f, 250.97f), + new(99.20f, 250.46f), new(103.70f, 245.95f), new(103.85f, 228.55f), new(119.47f, 228.45f)]; + public static readonly ArenaBoundsComplex Arena1 = new([new PolygonCustom(vertices1)], [new Polygon(new(28.122f, 220.05f), 2.5f, 16)]); + public static readonly ArenaBoundsComplex Arena1b = new([new PolygonCustom(vertices1)]); + private static readonly ArenaBoundsComplex arena2 = new([new PolygonCustom(vertices2)], [new Polygon(new(111.925f, 271.931f), 2.5f, 16)]); + public static readonly ArenaBoundsComplex Arena2b = new([new PolygonCustom(vertices2)]); + + public static readonly uint[] Trash1 = [(uint)OID.Boss, (uint)OID.PreculturedBiomass, (uint)OID.CulturedCobra, (uint)OID.CulturedNaga, + (uint)OID.CulturedBowyer, (uint)OID.CulturedEmpuse, (uint)OID.CulturedDancer]; + public static readonly uint[] Trash2 = [(uint)OID.Boss, (uint)OID.CulturedChimera, (uint)OID.BiocultureNode, (uint)OID.CulturedReptoid, (uint)OID.CulturedMirrorknight, + (uint)OID.Biohazard]; + + protected override bool CheckPull() => InBounds(Raid.Player()!.Position); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + if (Bounds == Arena1 || Bounds == Arena1b) + Arena.Actors(Enemies(Trash1)); + else + Arena.Actors(Enemies(Trash2)); + } + + 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]; + if ((OID)e.Actor.OID == OID.Boss) + { + e.Priority = 0; + break; + } + } + } +} diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs new file mode 100644 index 0000000000..3f6afa8f68 --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs @@ -0,0 +1,51 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility.D060ClonedConjurer; + +public enum OID : uint +{ + Boss = 0xF56, // R0.6 + ClonedThaumaturge = 0xF57, // R0.6 +} + +public enum AID : uint +{ + Fire = 966, // ClonedThaumaturge->player, 1.0s cast, single-target + Aero = 969, // Boss->player, 1.0s cast, single-target + Tornado = 900, // Boss->player, 5.0s cast, range 6 circle + Breakga = 2340, // ClonedThaumaturge->player, 4.0s cast, range 5 circle + Drain = 2339, // ClonedThaumaturge->player, 4.0s cast, single-target +} + +class Tornado(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Tornado), 6); + +class D060ClonedConjurerStates : StateMachineBuilder +{ + public D060ClonedConjurerStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(D060ClonedConjurer.Trash).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3838, SortOrder = 9)] +public class D060ClonedConjurer(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? arena1.Center : ShabtiConjurer2Bounds.Arena.Center, IsArena1(primary) ? arena1 : ShabtiConjurer2Bounds.Arena) +{ + private static bool IsArena1(Actor primary) => primary.Position.Z > 200; + private static readonly WPos[] vertices1 = [new(266.39f, 227.51f), new(274.35f, 232.12f), new(274.55f, 232.58f), new(274.59f, 237.89f), new(274.8f, 238.36f), + new(275.3f, 238.28f), new(278.46f, 236.46f), new(278.89f, 236.76f), new(281.09f, 238.03f), new(281.5f, 241.98f), + new(281.8f, 242.4f), new(284.99f, 244.22f), new(285.46f, 244.4f), new(288.59f, 242.6f), new(289.1f, 242.61f), + new(291.76f, 244.15f), new(291.91f, 247.73f), new(291.99f, 248.24f), new(292.41f, 248.51f), new(294.63f, 249.8f), + new(294.26f, 250.15f), new(285.84f, 255.3f), new(285.33f, 255.5f), new(282.58f, 253.91f), new(282.31f, 249.97f), + new(282, 249.58f), new(278.86f, 247.78f), new(278.37f, 247.61f), new(277.92f, 247.84f), new(275.27f, 249.37f), + new(274.76f, 249.41f), new(272.08f, 247.86f), new(271.92f, 243.95f), new(271.62f, 243.54f), new(271.12f, 243.7f), + new(266.63f, 246.27f), new(266.12f, 246.35f), new(261.58f, 243.76f), new(261.12f, 243.54f), new(260.64f, 243.34f), + new(258.42f, 242.05f), new(258.01f, 238.19f), new(258.08f, 237.6f), new(258.1f, 232.2f), new(266.15f, 227.56f)]; + private static readonly ArenaBoundsComplex arena1 = new([new PolygonCustom(vertices1)]); + + public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.ClonedThaumaturge]; + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(Trash)); + } +} diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs new file mode 100644 index 0000000000..8ed5612ff4 --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs @@ -0,0 +1,76 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility.D060CulturedShabti; + +public enum OID : uint +{ + Boss = 0xF58, // R2.2 +} + +public enum AID : uint +{ + AutoAttack = 870, // Boss->player, no cast, single-target + + Spellsword = 1259, // Boss->self, 3.0s cast, range 6+R 120-degree cone + DeathsDoor = 1260, // Boss->self, 2.0s cast, range 20+R width 2 rect +} + +class Spellsword(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Spellsword), new AOEShapeCone(8.2f, 60.Degrees())); +class DeathsDoor(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DeathsDoor), new AOEShapeRect(22.2f, 1)); + +class D060CulturedShabtiStates : StateMachineBuilder +{ + public D060CulturedShabtiStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(OID.Boss).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3838, SortOrder = 10)] +public class D060CulturedShabti(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? arena1.Center : ShabtiConjurer2Bounds.Arena.Center, IsArena1(primary) ? arena1 : ShabtiConjurer2Bounds.Arena) +{ + private static bool IsArena1(Actor primary) => primary.Position.Z > 200; + private static readonly WPos[] vertices1 = [new(226.49f, 196.43f), new(238.31f, 203.26f), new(238.76f, 203.54f), new(239.63f, 204.05f), new(239.86f, 218.33f), + new(239.83f, 219.46f), new(239.52f, 219.88f), new(235.07f, 222.4f), new(234.6f, 222.66f), new(234.1f, 222.82f), + new(233.63f, 223.09f), new(233.23f, 223.41f), new(232.96f, 223.83f), new(233.29f, 224.28f), new(238.73f, 227.52f), + new(239.2f, 227.82f), new(239.63f, 228.09f), new(239.89f, 228.65f), new(239.9f, 231.48f), new(239.91f, 232), + new(240.29f, 232.35f), new(240.76f, 232.17f), new(243.52f, 230.58f), new(244.05f, 230.57f), new(245.91f, 231.66f), + new(246.35f, 231.92f), new(246.82f, 232.15f), new(246.83f, 235.98f), new(247.08f, 236.47f), new(246.49f, 237.38f), + new(243.93f, 240.88f), new(243.6f, 241.31f), new(243.27f, 241.71f), new(242.85f, 242.04f), new(241.03f, 243.09f), + new(240.58f, 243.32f), new(240.07f, 243.37f), new(238.69f, 242.57f), new(238.28f, 242.29f), new(237.34f, 241.75f), + new(237.44f, 240.16f), new(237.45f, 239.64f), new(237.43f, 239.11f), new(237.38f, 238.59f), new(237.3f, 238.08f), + new(237.06f, 237.62f), new(236.55f, 237.66f), new(233.45f, 239.44f), new(232.96f, 239.26f), new(228.29f, 236.57f), + new(227.86f, 236.25f), new(227.44f, 235.96f), new(226.96f, 235.75f), new(226.47f, 235.56f), new(226.04f, 235.87f), + new(226.02f, 236.68f), new(226, 243.71f), new(216.15f, 249.4f), new(215.71f, 249.67f), new(213.5f, 250.94f), + new(213.04f, 251.16f), new(212.6f, 251.41f), new(212.12f, 251.21f), new(199.2f, 243.76f), new(199.1f, 230.55f), + new(199.13f, 228.17f), new(204.9f, 224.8f), new(205.36f, 224.55f), new(205.8f, 224.3f), new(206.18f, 223.94f), + new(212.16f, 220.48f), new(212.63f, 220.26f), new(212.9f, 211.95f), new(212.95f, 204.34f), new(213.29f, 203.95f), + new(226.02f, 196.6f)]; + private static readonly WPos[] vertices1h1 = [new(211.37f, 231.27f), new(211.85f, 231.42f), new(212.3f, 231.66f), new(213.35f, 231.72f), new(213.87f, 231.87f), + new(214.34f, 232.06f), new(214.8f, 232.26f), new(215.3f, 232.3f), new(215.83f, 232.36f), new(216.14f, 232.76f), + new(216.4f, 233.24f), new(217.24f, 234.58f), new(217.23f, 235.12f), new(217.07f, 235.61f), new(216.87f, 236.08f), + new(216.84f, 236.61f), new(216.75f, 237.11f), new(216.37f, 238.06f), new(216.15f, 238.51f), new(216.29f, 239.01f), + new(216.02f, 239.47f), new(215.58f, 239.77f), new(215.11f, 239.97f), new(214.24f, 240.52f), new(213.76f, 240.74f), + new(213.29f, 240.56f), new(212.83f, 240.34f), new(211.8f, 240.27f), new(211.3f, 240.13f), new(210.32f, 239.74f), + new(209.82f, 239.72f), new(209.32f, 239.64f), new(208.89f, 239.36f), new(208.7f, 238.84f), new(208.47f, 238.39f), + new(207.93f, 237.54f), new(207.84f, 237.03f), new(208.01f, 236.54f), new(208.23f, 236.05f), new(208.28f, 235.53f), + new(208.31f, 235.01f), new(208.69f, 234.03f), new(208.96f, 233.59f), new(208.81f, 233.09f), new(209.05f, 232.63f), + new(210.82f, 231.51f), new(211.28f, 231.26f)]; + private static readonly WPos[] vertices1h2 = [new(226.96f, 206.41f), new(227.45f, 206.57f), new(229.4f, 207.38f), new(229.68f, 207.82f), new(229.75f, 208.33f), + new(229.96f, 208.82f), new(230.23f, 209.27f), new(230.48f, 209.72f), new(230.72f, 210.73f), new(230.77f, 211.23f), + new(231.18f, 211.54f), new(231.23f, 212.07f), new(231.21f, 212.58f), new(230.99f, 213.04f), new(230.62f, 213.42f), + new(230.42f, 213.9f), new(230.21f, 214.36f), new(229.73f, 214.56f), new(229.23f, 214.65f), new(228.75f, 214.87f), + new(228.29f, 215.16f), new(227.79f, 215.34f), new(226.79f, 215.58f), new(226.33f, 215.83f), new(225.87f, 216.12f), + new(225.37f, 215.94f), new(223.45f, 215.15f), new(223.06f, 214.8f), new(222.72f, 214.4f), new(222.44f, 213.96f), + new(222.42f, 213.43f), new(222.35f, 212.94f), new(222.13f, 211.93f), new(222.05f, 211.41f), new(221.68f, 211.05f), + new(221.57f, 210.53f), new(221.6f, 210.01f), new(221.83f, 209.54f), new(222.16f, 209.14f), new(222.55f, 208.2f), + new(223.03f, 207.97f), new(223.55f, 207.95f), new(224.44f, 207.4f), new(224.89f, 207.17f), new(225.39f, 207.07f), + new(225.91f, 206.95f), new(226.4f, 206.86f), new(226.71f, 206.46f)]; + private static readonly ArenaBoundsComplex arena1 = new([new PolygonCustom(vertices1)], [new PolygonCustom(vertices1h1), new PolygonCustom(vertices1h2)]); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(OID.Boss)); + } +} diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs new file mode 100644 index 0000000000..4a4237bfcb --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs @@ -0,0 +1,44 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility.D060FacilityDreadnaught; + +public enum OID : uint +{ + Boss = 0xF54, // R3.0 + MonitoringDrone = 0xF55 // R2.4 +} + +public enum AID : uint +{ + AutoAttack = 872, // Boss->player, no cast, single-target + + AutoCannons = 4825, // MonitoringDrone->self, 3.0s cast, range 40+R width 5 rect + Rotoswipe = 4556, // Boss->self, 3.0s cast, range 8+R 120-degree cone + WreckingBall = 4557, // Boss->location, 4.0s cast, range 8 circle +} + +class Rotoswipe(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Rotoswipe), new AOEShapeCone(11, 60.Degrees())); +class AutoCannons(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AutoCannons), new AOEShapeRect(42.4f, 2.5f)); +class WreckingBall(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.WreckingBall), 8); + +class D060FacilityDreadnaughtStates : StateMachineBuilder +{ + public D060FacilityDreadnaughtStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(D060FacilityDreadnaught.Trash).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3836, SortOrder = 8)] +public class D060FacilityDreadnaught(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-360, -250), 9, 6)]); + public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.MonitoringDrone]; + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(Trash)); + } +} diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs new file mode 100644 index 0000000000..4d485c6fc7 --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs @@ -0,0 +1,69 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility.D060SixthLegionMagitekVanguardH1; + +public enum OID : uint +{ + Boss = 0x1350, // R2.8 + SixthLegionOptio = 0xF4A, // R0.5 + SixthLegionMedicus = 0xF4C, // R0.5 + SixthLegionTesserarius = 0xF4B // R0.5 +} + +public enum AID : uint +{ + AutoAttack1 = 871, // Boss/SixthLegionTesserarius->player, no cast, single-target + AutoAttack2 = 870, // SixthLegionOptio->player, no cast, single-target + + Aero = 969, // SixthLegionMedicus->player, 1.0s cast, single-target + Celeris = 404, // SixthLegionOptio->self, 2.5s cast, single-target + Fortis = 403, // SixthLegionMedicus/SixthLegionTesserarius->self, 2.5s cast, single-target + TrueThrust = 722, // SixthLegionTesserarius->player, no cast, single-target + CermetDrill = 526, // Boss->self, 2.5s cast, range 6+R width 5 rect + FastBlade = 717, // SixthLegionOptio->player, no cast, single-target + Stoneskin = 316, // SixthLegionMedicus->self, 2.5s cast, single-target + Rampart = 10, // SixthLegionOptio->self, no cast, single-target + Heartstopper = 866, // SixthLegionTesserarius->self, 2.5s cast, range 3+R width 3 rect + Feint = 76, // SixthLegionTesserarius->player, no cast, single-target + ShieldBash = 718, // SixthLegionOptio->player, no cast, single-target + Cure = 120, // SixthLegionMedicus->self, 1.5s cast, single-target + FightOrFlight = 20, // SixthLegionOptio->self, no cast, single-target +} + +class CermetDrill(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CermetDrill), new AOEShapeRect(8.8f, 2.5f)); +class Heartstopper(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Heartstopper), new AOEShapeRect(3.5f, 1.5f)); +class Stoneskin(BossModule module) : Components.CastInterruptHint(module, ActionID.MakeSpell(AID.Stoneskin), canBeStunned: true, showNameInHint: true); + +class D060SixthLegionMagitekVanguardH1States : StateMachineBuilder +{ + public D060SixthLegionMagitekVanguardH1States(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(D060SixthLegionMagitekVanguardH1.Trash).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 4341, SortOrder = 3)] +public class D060SixthLegionMagitekVanguardH1(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly WPos[] vertices = [new(-168.92f, -310.29f), new(-168.68f, -309.78f), new(-164.6f, -305.63f), new(-162.22f, -303.37f), new(-161.69f, -302.98f), + new(-161.64f, -301.71f), new(-161.53f, -301.12f), new(-159.39f, -300.13f), new(-158.74f, -300.31f), new(-158.74f, -291.19f), + new(-158.97f, -290.71f), new(-159.61f, -290.99f), new(-160.25f, -291.07f), new(-160.88f, -291.13f), new(-161.47f, -291.04f), + new(-162.21f, -288.69f), new(-161.91f, -288.19f), new(-162.36f, -287.96f), new(-165.75f, -284.37f), new(-168.27f, -281.82f), + new(-168.74f, -281.31f), new(-168.8f, -268.16f), new(-169.41f, -267.78f), new(-171.51f, -267.35f), new(-172.17f, -267.39f), + new(-176, -267.69f), new(-177.9f, -267.75f), new(-178.55f, -267.76f), new(-181.11f, -266.96f), new(-181.78f, -267.05f), + new(-183.14f, -267.29f), new(-183.35f, -281.21f), new(-183.73f, -281.67f), new(-195.59f, -293.6f), new(-196.02f, -294.06f), + new(-196.96f, -295.01f), new(-197.43f, -295.57f), new(-183.31f, -309.76f), new(-183.05f, -322.95f), new(-183.05f, -329.17f), + new(-182.5f, -329.47f), new(-174.49f, -329.12f), new(-173.76f, -329.12f), new(-170.86f, -329.22f), new(-170.15f, -329.34f), + new(-169.46f, -329.55f), new(-168.92f, -329.66f), new(-168.92f, -310.29f)]; + private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.SixthLegionTesserarius, (uint)OID.SixthLegionOptio, (uint)OID.SixthLegionMedicus]; + + protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(Trash)); + } +} diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs new file mode 100644 index 0000000000..f8a6de8c3e --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs @@ -0,0 +1,106 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility.D060Trash1; + +public enum OID : uint +{ + Boss = 0xFA5, // R3.0 + ClockworkHunter = 0xF48, // R1.25 + ClockworkAvenger = 0xF49, // R1.5 + ScrambledEngineer = 0xF59, // R1.225 + ScrambledPaladin = 0xF5A, // R1.225 + ScrambledIronClaw = 0xFA4, // R1.5 + ScrambledIronGiant = 0xFA3, // R2.3 +} + +public enum AID : uint +{ + AutoAttack1 = 870, // ClockworkHunter/ClockworkAvenger/ScrambledIronGiant->player, no cast, single-target + AutoAttack2 = 872, // ScrambledPaladin/ScrambledIronClaw/ScrambledEngineer->player, no cast, single-target + + AetherochemicalAmplification = 4550, // Boss->player, no cast, single-target + PassiveInfraredGuidanceSystem = 4549, // Boss->players, no cast, range 6 circle + + Shred = 608, // ScrambledIronClaw->player, no cast, single-target + Headspin1 = 4665, // ScrambledPaladin->self, no cast, range 4+R circle + Headspin2 = 4664, // ScrambledEngineer->self, no cast, range 4+R circle + GrandSword = 33030, // ScrambledIronGiant->self, 3.0s cast, range 16 120-degree cone + TheHand = 609, // ScrambledIronClaw->self, 3.0s cast, range 6+R 120-degree cone + DefensiveManeuvers = 607, // ScrambledIronClaw->self, 3.0s cast, single-target, apply stoneskin +} + +class PassiveInfraredGuidanceSystem(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.PassiveInfraredGuidanceSystem), new AOEShapeCircle(6), (uint)OID.Boss, originAtTarget: true); + +abstract class HeadSpin(BossModule module, AID aid, uint enemy) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCircle(5.225f), enemy) +{ + public override void AddHints(int slot, Actor actor, TextHints hints) + { + if (actor.Role is not Role.Melee and not Role.Tank) + base.AddHints(slot, actor, hints); + } + + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + if (actor.Role is not Role.Melee and not Role.Tank) + base.AddAIHints(slot, actor, assignment, hints); + } + + public override void DrawArenaForeground(int pcSlot, Actor pc) + { + if (pc.Role is not Role.Melee and not Role.Tank) + base.DrawArenaForeground(pcSlot, pc); + } +} +class Headspin1(BossModule module) : HeadSpin(module, AID.Headspin1, (uint)OID.ScrambledPaladin); +class Headspin2(BossModule module) : HeadSpin(module, AID.Headspin2, (uint)OID.ScrambledEngineer); + +class GrandSword(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GrandSword), new AOEShapeCone(16, 60.Degrees())); +class TheHand(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TheHand), new AOEShapeCone(7.5f, 60.Degrees())); + +class D060EnforcementDroid210States : StateMachineBuilder +{ + public D060EnforcementDroid210States(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(D060Trash1.TrashP1).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 4390, SortOrder = 1)] +public class D060EnforcementDroid210(WorldState ws, Actor primary) : D060Trash1(ws, primary); + +class D060ScrambledIronGiantStates : StateMachineBuilder +{ + public D060ScrambledIronGiantStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(D060Trash1.TrashP2).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", PrimaryActorOID = (uint)OID.ScrambledIronGiant, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 4337, SortOrder = 2)] +public class D060ScrambledIronGiant(WorldState ws, Actor primary) : D060Trash1(ws, primary); + +public abstract class D060Trash1(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly WPos[] vertices = [new(-161.42f, -387.38f), new(-160.94f, -387.16f), new(-160.94f, -357.32f), new(-161.56f, -357.04f), new(-168.47f, -357.05f), + new(-168.92f, -356.77f), new(-173.49f, -356.49f), new(-182.88f, -356.52f), new(-183.27f, -357), new(-191.29f, -357.04f), + new(-191.6f, -357.44f), new(-191.59f, -364.77f), new(-191.74f, -365.29f), new(-192.26f, -365.39f), new(-208.3f, -365.39f), + new(-208.56f, -366.03f), new(-208.63f, -376.44f), new(-208.68f, -377.15f), new(-208.91f, -379.31f), new(-191.94f, -379.47f), + new(-191.32f, -379.56f), new(-191.13f, -387.25f), new(-161.42f, -387.38f)]; + private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + + public static readonly uint[] TrashP1 = [(uint)OID.Boss, (uint)OID.ClockworkHunter, (uint)OID.ClockworkAvenger]; + public static readonly uint[] TrashP2 = [(uint)OID.ScrambledEngineer, (uint)OID.ScrambledIronClaw, (uint)OID.ScrambledIronGiant, (uint)OID.ScrambledPaladin]; + public static readonly uint[] Trash = [.. TrashP1, .. TrashP2]; + + protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(Trash)); + } +} diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs index a7fbb33a3b..b6eda8e3d4 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs @@ -57,13 +57,13 @@ public D061RegulaStates(BossModule module) : base(module) } } -[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3818)] +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3818, SortOrder = 4)] public class D061Regula(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly PolygonCustom[] shape = [new ([new(-89.11f, -301.95f), new(-93.32f, -310.37f), new(-106.99f, -318.19f), new(-115.01f, -318.19f), + private static readonly WPos[] vertices = [new(-89.11f, -301.95f), new(-93.32f, -310.37f), new(-106.99f, -318.19f), new(-115.01f, -318.19f), new(-128.64f, -310.32f), new(-132.28f, -303.07f), new(-132.29f, -287.96f), new(-128.64f, -280.69f), new(-115.04f, -272.8f), new(-107.04f, -272.8f), - new(-93.35f, -280.7f), new(-89.11f, -289.1f)])]; - public static readonly ArenaBoundsComplex arena = new(shape); + new(-93.35f, -280.7f), new(-89.11f, -289.1f)]; + public static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs index 520a28864c..46a4f343b0 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs @@ -102,8 +102,8 @@ public D062HarmachisStates(BossModule module) : base(module) } } -[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3821)] +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3821, SortOrder = 7)] public class D062Harmachis(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - public static readonly ArenaBoundsComplex arena = new([new Circle(new(248, 272), 19.5f)], [new Rectangle(new(228, 272), 20, 1.8f, 90.Degrees()), new Rectangle(new(268.25f, 272), 20, 2, 90.Degrees())]); + public static readonly ArenaBoundsComplex arena = new([new Polygon(new(248, 272), 19.25f, 44)], [new Rectangle(new(228, 272), 20, 1.8f, 90.Degrees()), new Rectangle(new(268.25f, 272), 20, 2, 90.Degrees())]); } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs index fcaf908400..827b3e8d93 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs @@ -58,28 +58,20 @@ class EndOfDays(BossModule module) : Components.LineStack(module, ActionID.MakeS class Stars(BossModule module) : Components.GenericAOEs(module) { - private static readonly AOEShapeDonut donutSmall = new(5, 15); - private static readonly AOEShapeDonut donutBig = new(5, 40); - private static readonly AOEShapeCircle circleSmall = new(8); - private static readonly AOEShapeCircle circleBig = new(16); - + private static readonly AOEShapeDonut donutSmall = new(5, 15), donutBig = new(5, 40); + private static readonly AOEShapeCircle circleSmall = new(8), circleBig = new(16); private readonly List _aoes = []; private readonly List _stars = []; - private bool _tutorialFire; - private bool _tutorialIce; - private DateTime _activation; - private AOEShape? _shape; - private bool _active; + private bool _tutorialFire, _tutorialIce; public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (_shape != null && _active) + var count = _aoes.Count; + if (count != 0) { - foreach (var star in _stars) - yield return new(_shape, star.Position, default, _activation); - foreach (var aoe in _aoes) - yield return new(aoe.Shape, aoe.Origin, default, aoe.Activation); + for (var i = 0; i < count; ++i) + yield return _aoes[i]; } } @@ -104,41 +96,42 @@ public override void OnTethered(Actor source, ActorTetherInfo tether) private void ActivateAOE(AOEShape smallShape, AOEShape bigShape, WPos midpoint, Actor source, Actor target) { - _shape = smallShape; - _active = true; _stars.Remove(source); _stars.Remove(target); - _activation = WorldState.FutureTime(10.6f); - _aoes.Add(new AOEInstance(bigShape, midpoint, default, _activation)); + var activation = WorldState.FutureTime(10.6f); + _aoes.Add(new(bigShape, midpoint, default, activation)); + if (_aoes.Any(x => x.Shape == donutBig) || _aoes.Count(x => x.Shape == circleBig) == 2) + { + for (var i = 0; i < _stars.Count; ++i) + _aoes.Add(new(smallShape, _stars[i].Position, default, activation)); + _stars.Clear(); + } } public override void OnActorCreated(Actor actor) { if ((OID)actor.OID is OID.FrozenStar or OID.BurningStar) _stars.Add(actor); - if ((OID)actor.OID == OID.FrozenStar && !_tutorialIce) + if (!_tutorialIce && _stars.Count(x => (OID)x.OID == OID.FrozenStar) == 4) Tutorial(donutSmall, ref _tutorialIce); - else if ((OID)actor.OID == OID.BurningStar && !_tutorialFire) + else if (!_tutorialFire && _stars.Count(x => (OID)x.OID == OID.BurningStar) == 5) Tutorial(circleSmall, ref _tutorialFire); } private void Tutorial(AOEShape shape, ref bool tutorialFlag) { - _activation = WorldState.FutureTime(7.8f); tutorialFlag = true; - _shape = shape; - _active = true; + for (var i = 0; i < _stars.Count; ++i) + _aoes.Add(new(shape, _stars[i].Position, default, WorldState.FutureTime(7.8f))); + _stars.Clear(); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { if ((AID)spell.Action.ID is AID.CircleOfIceAOE or AID.CircleOfIcePrimeAOE or AID.FireSphereAOE or AID.FireSpherePrime1) { - _shape = null; - _stars.Clear(); _aoes.Clear(); - NumCasts++; - _active = false; + ++NumCasts; } } } @@ -156,18 +149,10 @@ public D063LahabreaIgeyorhmStates(BossModule module) : base(module) } } -[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 2143)] +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 2143, SortOrder = 11)] public class D063LahabreaIgeyorhm(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly WPos[] vertices = [new(230.1f, -201.34f), new(234.87f, -200.71f), new(235.38f, -200.61f), new(240.02f, -198.69f), new(240.45f, -198.41f), - new(244.38f, -195.4f), new(247.63f, -191.14f), new(249.61f, -186.38f), new(249.71f, -185.81f), new(250.29f, -181.43f), - new(250.33f, -180.92f), new(249.62f, -175.65f), new(247.73f, -171.08f), new(247.43f, -170.58f), new(244.36f, -166.6f), - new(240.13f, -163.36f), new(236.08f, -161.86f), new(223.25f, -161.84f), new(222.41f, -161.88f), new(221.95f, -162.24f), - new(220.03f, -163.28f), new(219.54f, -163.61f), new(215.6f, -166.65f), new(212.39f, -170.8f), new(210.35f, -175.71f), - new(209.66f, -180.9f), new(209.71f, -181.43f), new(210.29f, -185.84f), new(210.39f, -186.39f), new(212.37f, -191.13f), - new(212.72f, -191.62f), new(215.54f, -195.29f), new(215.93f, -195.64f), new(219.66f, -198.5f), new(220.15f, -198.76f), - new(224.76f, -200.66f), new(229.87f, -201.33f)]; - public static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + public static readonly ArenaBoundsComplex arena = new([new Polygon(new(230, -181), 20.26f, 24)], [new Rectangle(new(230, -160), 20, 1.94f)]); protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs index f37c74e2e4..a21108f228 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs @@ -155,20 +155,20 @@ class Stars(BossModule module) : Components.GenericAOEs(module) { private static readonly AOEShapeDonut donut = new(5, 40); private static readonly AOEShapeCircle circle = new(16); - - private readonly List _aoesLongTether = []; - private readonly List _aoesShortTether = []; - private static readonly WPos _frozenStarShortTether = new(230, 86); - private static readonly WPos _frozenStarLongTether = new(230, 92); - private static readonly WPos _donut = new(230, 79); - private static readonly WPos _circle1 = new(241, 79); - private static readonly WPos _circle2 = new(219, 79); + private readonly List _aoes = []; + private static readonly WPos _frozenStarShortTether = new(230, 86), _frozenStarLongTether = new(230, 92); + private static readonly WPos _donut = new(230, 79), _circle1 = new(241, 79), _circle2 = new(219, 79); public override IEnumerable ActiveAOEs(int slot, Actor actor) { - var aoes = _aoesShortTether.Count > 0 ? _aoesShortTether : _aoesLongTether; - foreach (var aoe in aoes) - yield return new AOEInstance(aoe.Shape, aoe.Origin, default, aoe.Activation); + var count = _aoes.Count; + if (count != 0) + for (var i = 0; i < count; ++i) + { + var aoe = _aoes[i]; + if ((aoe.Activation - _aoes[0].Activation).TotalSeconds <= 1) + yield return aoe; + } } public override void OnActorCreated(Actor actor) @@ -179,28 +179,25 @@ public override void OnActorCreated(Actor actor) { if (actor.Position == _frozenStarLongTether) { - _aoesShortTether.Add(new(circle, _circle1, default, activation1)); - _aoesShortTether.Add(new(circle, _circle2, default, activation1)); - _aoesLongTether.Add(new(donut, _donut, default, activation2)); + _aoes.Add(new(circle, _circle1, default, activation1)); + _aoes.Add(new(circle, _circle2, default, activation1)); + _aoes.Add(new(donut, _donut, default, activation2)); } else if (actor.Position == _frozenStarShortTether) { - _aoesShortTether.Add(new(donut, _donut, default, activation1)); - _aoesLongTether.Add(new(circle, _circle1, default, activation2)); - _aoesLongTether.Add(new(circle, _circle2, default, activation2)); + _aoes.Add(new(donut, _donut, default, activation1)); + _aoes.Add(new(circle, _circle1, default, activation2)); + _aoes.Add(new(circle, _circle2, default, activation2)); } } } - public override void OnEventCast(Actor caster, ActorCastEvent spell) + public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID is AID.CircleOfIcePrime or AID.FireSpherePrime) + if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.CircleOfIcePrime or AID.FireSpherePrime) { - NumCasts++; - if (_aoesShortTether.Count != 0) - _aoesShortTether.RemoveAt(0); - else - _aoesLongTether.Clear(); + ++NumCasts; + _aoes.RemoveAt(0); } } } @@ -233,19 +230,10 @@ public D064AscianPrimeStates(BossModule module) : base(module) } } -[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3823)] +[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3823, SortOrder = 12)] public class D064AscianPrime(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly WPos[] vertices = [new(230.1f, 58.66f), new(234.87f, 59.29f), new(235.46f, 59.42f), new(240.04f, 61.32f), new(240.54f, 61.66f), - new(244.09f, 64.38f), new(244.52f, 64.77f), new(247.63f, 68.83f), new(249.53f, 73.43f), new(249.69f, 74), - new(250.3f, 78.68f), new(250.33f, 79.19f), new(249.72f, 83.76f), new(249.62f, 84.35f), new(247.73f, 88.91f), - new(247.47f, 89.37f), new(244.53f, 93.2f), new(244.15f, 93.57f), new(240.69f, 96.23f), new(240.26f, 96.52f), - new(239.77f, 96.74f), new(235.7f, 98.28f), new(235.4f, 98.77f), new(222.57f, 98.77f), new(222.38f, 98.2f), - new(222.04f, 97.81f), new(219.9f, 96.66f), new(215.6f, 93.36f), new(212.6f, 89.45f), new(212.28f, 88.91f), - new(210.39f, 84.36f), new(210.29f, 83.78f), new(209.66f, 79.02f), new(210.34f, 73.83f), new(210.54f, 73.27f), - new(212.22f, 69.21f), new(212.47f, 68.7f), new(215.59f, 64.64f), new(219.87f, 61.36f), new(224.41f, 59.48f), - new(224.99f, 59.31f), new(229.86f, 58.67f)]; - public static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); + public static readonly ArenaBoundsComplex arena = new([new Polygon(new(230, 79), 20.26f, 24)], [new Rectangle(new(230, 98), 5, 1.5f)], [new Rectangle(new(228.95f, 97), 6.55f, 1.7f)]); protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/SharedBounds.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/SharedBounds.cs new file mode 100644 index 0000000000..66b81173cd --- /dev/null +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/SharedBounds.cs @@ -0,0 +1,54 @@ +namespace BossMod.Heavensward.Dungeon.D06AetherochemicalResearchFacility; + +public static class ShabtiConjurer2Bounds +{ + private static readonly WPos[] vertices2 = [new(193.02f, 94.99f), new(201.06f, 99.63f), new(201.14f, 100.29f), new(201.14f, 100.95f), new(201.13f, 101.69f), + new(201.13f, 102.4f), new(201.15f, 102.93f), new(201.16f, 109.28f), new(201.28f, 109.79f), new(205.42f, 112.15f), + new(205.91f, 112.37f), new(209.04f, 114.17f), new(209.48f, 114.47f), new(212.14f, 116.01f), new(212.57f, 116.27f), + new(214.82f, 117.57f), new(215.04f, 118.25f), new(215.04f, 123.26f), new(215.06f, 123.78f), new(215.61f, 123.89f), + new(216.06f, 123.65f), new(223.69f, 119.26f), new(224.2f, 119.08f), new(232.37f, 123.79f), new(232.33f, 133.26f), + new(225.68f, 137.1f), new(225.21f, 137.34f), new(224.32f, 137.85f), new(223.78f, 137.82f), new(215.84f, 133.24f), + new(215.37f, 133.06f), new(205.83f, 138.55f), new(205.38f, 138.77f), new(204.96f, 139.05f), new(204.68f, 139.47f), + new(205, 139.86f), new(207.68f, 141.41f), new(208.11f, 141.7f), new(208.13f, 145.26f), new(207.65f, 145.48f), + new(205.44f, 146.76f), new(204.94f, 146.89f), new(201.74f, 145.05f), new(201.25f, 145.2f), new(198.1f, 147.05f), + new(197.77f, 150.38f), new(197.75f, 151.26f), new(194.57f, 153.13f), new(194.32f, 153.63f), new(193.95f, 153.99f), + new(193.49f, 153.77f), new(191.37f, 151.91f), new(191.67f, 151.49f), new(191.66f, 147.7f), new(194.84f, 145.86f), new(195.11f, 145.25f), + new(195.11f, 144.54f), new(195.13f, 143.72f), new(195.12f, 141.67f), new(198.33f, 139.82f), new(198.58f, 139.37f), + new(198.21f, 139.01f), new(187.87f, 133.08f), new(187.38f, 133.21f), new(180.53f, 137.06f), new(180.05f, 137.29f), + new(179.13f, 137.81f), new(178.66f, 137.59f), new(171.89f, 133.68f), new(171.47f, 133.4f), new(171.02f, 133.15f), + new(170.89f, 125.72f), new(170.92f, 123.59f), new(173.59f, 122.04f), new(174.05f, 121.8f), new(178.93f, 118.98f), + new(179.44f, 119.04f), new(186.82f, 123.3f), new(187.26f, 123.57f), new(187.71f, 123.78f), new(188.14f, 123.49f), + new(188.15f, 122.7f), new(188.15f, 118.15f), new(188.24f, 117.64f), new(193.19f, 114.78f), new(193.26f, 114.27f), + new(192.85f, 113.97f), new(192.4f, 113.71f), new(191.96f, 113.43f), new(191.5f, 113.18f), new(191.04f, 112.91f), + new(190.6f, 112.61f), new(184.68f, 109.13f), new(184.68f, 99.94f), new(184.97f, 99.5f), new(192.11f, 95.37f), + new(192.57f, 95.15f)]; + private static readonly WPos[] vertices2h1 = [new(190.91f, 99.94f), new(191.38f, 100.19f), new(192.93f, 99.94f), new(193.44f, 100.01f), new(193.95f, 100.09f), + new(194.45f, 100.23f), new(194.91f, 100.02f), new(195.43f, 100.12f), new(195.81f, 100.49f), new(197.26f, 101.94f), + new(197.37f, 102.44f), new(197.1f, 102.87f), new(197.24f, 103.37f), new(197.28f, 103.86f), new(197.36f, 104.36f), + new(197.32f, 104.88f), new(197.24f, 105.38f), new(197.1f, 105.88f), new(197.29f, 106.39f), new(197.22f, 106.91f), + new(195.37f, 108.76f), new(194.87f, 108.89f), new(194.44f, 108.6f), new(193.94f, 108.71f), new(192.92f, 108.87f), + new(192.42f, 108.82f), new(191.43f, 108.66f), new(190.92f, 108.8f), new(190.4f, 108.72f), new(189.99f, 108.4f), + new(189.66f, 108.01f), new(188.55f, 106.91f), new(188.44f, 106.4f), new(188.69f, 105.93f), new(188.45f, 104.39f), + new(188.51f, 103.87f), new(188.59f, 103.35f), new(188.75f, 102.85f), new(188.51f, 102.4f), new(188.61f, 101.88f), + new(190.45f, 100.04f)]; + private static readonly WPos[] vertices2h2 = [new(222.11f, 124.13f), new(222.54f, 124.45f), new(223.03f, 124.28f), new(223.54f, 124.25f), new(224.04f, 124.17f), + new(224.55f, 124.2f), new(225.06f, 124.28f), new(225.57f, 124.42f), new(226.03f, 124.2f), new(226.57f, 124.3f), + new(228.43f, 126.15f), new(228.41f, 126.69f), new(228.29f, 127.2f), new(228.34f, 127.7f), new(228.42f, 128.21f), + new(228.45f, 128.72f), new(228.22f, 130.25f), new(228.43f, 130.72f), new(228.16f, 131.13f), new(226.7f, 132.6f), + new(226.25f, 132.88f), new(225.79f, 132.67f), new(225.27f, 132.68f), new(224.26f, 132.84f), new(223.72f, 132.8f), + new(222.7f, 132.64f), new(222.21f, 132.76f), new(221.7f, 132.74f), new(221.32f, 132.39f), new(219.84f, 130.92f), + new(219.78f, 130.4f), new(220.02f, 129.95f), new(219.88f, 129.46f), new(219.8f, 128.95f), new(219.76f, 128.45f), + new(219.92f, 127.43f), new(220.06f, 126.92f), new(219.81f, 126.46f), new(219.97f, 125.97f), new(221.43f, 124.51f), + new(221.79f, 124.17f)]; + private static readonly WPos[] vertices2h3 = [new(177.03f, 124.04f), new(177.53f, 124.26f), new(178.04f, 124.22f), new(179.07f, 124.06f), new(179.57f, 124.11f), + new(180.1f, 124.2f), new(180.6f, 124.35f), new(181.09f, 124.13f), new(181.6f, 124.26f), new(183.43f, 126.09f), + new(183.36f, 126.61f), new(183.24f, 127.11f), new(183.33f, 127.61f), new(183.41f, 128.13f), new(183.42f, 128.67f), + new(183.26f, 129.7f), new(183.28f, 130.21f), new(183.38f, 130.71f), new(183.04f, 131.14f), new(181.56f, 132.63f), + new(181.05f, 132.78f), new(180.6f, 132.55f), new(180.09f, 132.65f), new(179.07f, 132.8f), new(178.57f, 132.7f), + new(178.06f, 132.62f), new(177.57f, 132.51f), new(177.09f, 132.7f), new(176.57f, 132.59f), new(175.1f, 131.12f), + new(174.75f, 130.75f), new(174.7f, 130.25f), new(174.79f, 129.74f), new(174.82f, 129.21f), new(174.74f, 128.71f), + new(174.75f, 128.19f), new(174.92f, 127.16f), new(174.91f, 126.65f), new(174.78f, 126.15f), new(175.09f, 125.72f), + new(176.55f, 124.25f), new(177.02f, 124.04f)]; + + public static readonly ArenaBoundsComplex Arena = new([new PolygonCustom(vertices2)], [new PolygonCustom(vertices2h1), new PolygonCustom(vertices2h2), new PolygonCustom(vertices2h3)]); +} \ No newline at end of file diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs index 8404d1584f..0fca25d777 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs @@ -66,7 +66,7 @@ public D130BlizzardDragonStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D130BlizzardDragon.Trash).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => module.Enemies(OID.BlizzardDragon1).Any(x => x.IsDead) || module.PrimaryActor.IsDestroyed; } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs index 837b6d8cc0..697b64f6da 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs @@ -19,6 +19,7 @@ public enum AID : uint AdventitiousLash = 4502, // GardenSankchinni->player, no cast, single-target TightTornado = 6237, // EnchantedFan->self, 3.0s cast, range 15+R width 4 rect Venom = 1911, // SanctuarySkipper->player, no cast, range 10+R 120-degree cone + CursedSphere = 1912, // SanctuarySkipper->players, no cast, range 3 circle, targets seemingly random players DarkBlizzardIII = 6236, // Boss->location, 3.0s cast, range 5 circle } diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs index 62594cb620..a231920707 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs @@ -95,7 +95,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) class HolyBreath(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.Spreadmarker, ActionID.MakeSpell(AID.HolyBreath), 6, 6); -class ThinIce(BossModule module) : Components.ThinIce(module, true, stopAtWall: true) +class ThinIce(BossModule module) : Components.ThinIce(module, 11, true, stopAtWall: true) { 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); diff --git a/BossMod/Replay/ReplayBuilder.cs b/BossMod/Replay/ReplayBuilder.cs index 962edc418c..3b38958ab3 100644 --- a/BossMod/Replay/ReplayBuilder.cs +++ b/BossMod/Replay/ReplayBuilder.cs @@ -437,14 +437,15 @@ private void ClientActionRejected(ClientState.OpActionReject op) private void ModuleLoaded(BossModule module) { - _modules.Add(module.PrimaryActor.InstanceID, new(module, new(module.PrimaryActor.InstanceID, module.PrimaryActor.OID, _ws.CurrentZone))); + _modules.TryAdd(module.PrimaryActor.InstanceID, new(module, new(module.PrimaryActor.InstanceID, module.PrimaryActor.OID, _ws.CurrentZone))); } private void ModuleUnloaded(BossModule module) { if (!_modules.Remove(module.PrimaryActor.InstanceID, out var data)) - throw new InvalidOperationException($"Module unloaded without being loaded before"); - + Service.Log($"Module not found for {module.PrimaryActor.InstanceID}"); + if (data == null) + return; if (data.ActiveState != null) { data.Encounter.Phases.Add(new(data.ActivePhaseIndex, data.ActiveState.ID, _ws.CurrentTime)); diff --git a/BossMod/Replay/Visualization/OpList.cs b/BossMod/Replay/Visualization/OpList.cs index 68f3647380..6ccf9691b0 100644 --- a/BossMod/Replay/Visualization/OpList.cs +++ b/BossMod/Replay/Visualization/OpList.cs @@ -14,7 +14,7 @@ class OpList(Replay replay, Replay.Encounter? enc, BossModuleRegistry.Info? modu 0x2630, 0x2611, 0x2610, 0x2617, 0x2608, 0x2613, 0x2618, 0x2609, 0x261A, 0x262F, 0x2609, 0x2614, 0x2664, 0x2668, 0x2619, 0x2631, 0x2632, 0x260A, 0x2616, 0x2667, 0x2E7F, 0x2F33, 0x2F32, 0x2F38, 0x2E80, 0x2E82, 0x2E81, 0x2F36, 0x2E7D, 0x2F35, 0x2EB0, 0x2F31, 0x2F37, 0x2E7C, 0x2E7B, 0x2EAE, 0x2F3A, 0x2F30, 0x2E7E, 0x2EAF, 0x428B, 0x44B8, 0x43D2, 0x43D1, 0x41FD, 0x42A4, 0x41C5, 0x30B7, 0x4021, 0x4019, 0x401C, 0x401B, 0x401F, 0x40FB, 0x4105, 0x401D, 0x4102, 0x4629, 0x4628, 0x4631, - 0x4630, 0x46D6]; + 0x4630, 0x46D6, 0xF5B, 0xF5C]; private readonly HashSet _filteredActions = []; private readonly HashSet _filteredStatuses = []; private readonly HashSet _filteredDirectorUpdateTypes = [];