diff --git a/BossMod/Components/BaitAway.cs b/BossMod/Components/BaitAway.cs index 33cb1dc6c2..ce52c99b1e 100644 --- a/BossMod/Components/BaitAway.cs +++ b/BossMod/Components/BaitAway.cs @@ -28,9 +28,51 @@ public Bait(Actor source, Actor target, AOEShape shape, DateTime activation, Ang public List CurrentBaits = []; public const string BaitAwayHint = "Bait away from raid!"; - public IEnumerable ActiveBaits => AllowDeadTargets ? CurrentBaits.Where(b => !b.Source.IsDead) : CurrentBaits.Where(b => !b.Source.IsDead && !b.Target.IsDead); - public IEnumerable ActiveBaitsOn(Actor target) => ActiveBaits.Where(b => b.Target == target); - public IEnumerable ActiveBaitsNotOn(Actor target) => ActiveBaits.Where(b => b.Target != target); + public List ActiveBaits + { + get + { + var count = CurrentBaits.Count; + List activeBaits = new(count); + for (var i = 0; i < count; ++i) + { + var bait = CurrentBaits[i]; + if (!bait.Source.IsDead) + { + if (AllowDeadTargets || !bait.Target.IsDead) + activeBaits.Add(bait); + } + } + return activeBaits; + } + } + + public List ActiveBaitsOn(Actor target) + { + var count = CurrentBaits.Count; + List activeBaitsOnTarget = new(count); + for (var i = 0; i < count; ++i) + { + var bait = CurrentBaits[i]; + if (!bait.Source.IsDead && bait.Target == target) + activeBaitsOnTarget.Add(bait); + } + return activeBaitsOnTarget; + } + + public List ActiveBaitsNotOn(Actor target) + { + var count = CurrentBaits.Count; + List activeBaitsNotOnTarget = new(count); + for (var i = 0; i < count; ++i) + { + var bait = CurrentBaits[i]; + if (!bait.Source.IsDead && bait.Target != target) + activeBaitsNotOnTarget.Add(bait); + } + return activeBaitsNotOnTarget; + } + public WPos BaitOrigin(Bait bait) => (CenterAtTarget ? bait.Target : bait.Source).Position; public bool IsClippedBy(Actor actor, Bait bait) => bait.Shape.Check(actor.Position, BaitOrigin(bait), bait.Rotation); public IEnumerable PlayersClippedBy(Bait bait) => Raid.WithoutSlot().Exclude(bait.Target).InShape(bait.Shape, BaitOrigin(bait), bait.Rotation); @@ -42,7 +84,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) if (ForbiddenPlayers[slot]) { - if (ActiveBaitsOn(actor).Any()) + if (ActiveBaitsOn(actor).Count != 0) hints.Add("Avoid baiting!"); } else @@ -57,7 +99,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; foreach (var bait in ActiveBaitsNotOn(actor)) @@ -90,7 +132,7 @@ private void AddTargetSpecificHints(Actor actor, Bait bait, AIHints hints) } } - public override PlayerPriority CalcPriority(int pcSlot, Actor pc, int playerSlot, Actor player, ref uint customColor) => ActiveBaitsOn(player).Any() ? BaiterPriority : PlayerPriority.Irrelevant; + public override PlayerPriority CalcPriority(int pcSlot, Actor pc, int playerSlot, Actor player, ref uint customColor) => ActiveBaitsOn(player).Count != 0 ? BaiterPriority : PlayerPriority.Irrelevant; public override void DrawArenaBackground(int pcSlot, Actor pc) { @@ -289,7 +331,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) public override void AddHints(int slot, Actor actor, TextHints hints) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; base.AddHints(slot, actor, hints); if (ActiveBaitsOn(actor).Any(b => PlayersClippedBy(b).Any())) diff --git a/BossMod/Components/StackSpread.cs b/BossMod/Components/StackSpread.cs index 7cdfdbed59..5c3b100362 100644 --- a/BossMod/Components/StackSpread.cs +++ b/BossMod/Components/StackSpread.cs @@ -473,7 +473,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; var isBaitTarget = ActiveBaits.Any(x => x.Target == actor); var isBaitNotTarget = ActiveBaits.Any(x => x.Target != actor); @@ -501,7 +501,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme public override void AddHints(int slot, Actor actor, TextHints hints) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; var isBaitTarget = ActiveBaits.Any(x => x.Target == actor); @@ -513,7 +513,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) else if ((isBaitNotTarget || isBaitTarget) && isInBaitShape) hints.Add(HintStack, false); - if (ActiveBaits.Count() > 1 && isBaitTarget) + if (ActiveBaits.Count > 1 && isBaitTarget) { var isInOtherBaitShape = ActiveBaits.Any(x => x.Target != actor && actor.Position.InRect(x.Source.Position, x.Rotation, Range, 0, 2 * HalfWidth)); if (isInOtherBaitShape) @@ -526,7 +526,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) public override void DrawArenaBackground(int pcSlot, Actor pc) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; var isBaitTarget = ActiveBaits.Any(x => x.Target == pc); diff --git a/BossMod/Components/Tethers.cs b/BossMod/Components/Tethers.cs index d131f0adb6..cddb16107b 100644 --- a/BossMod/Components/Tethers.cs +++ b/BossMod/Components/Tethers.cs @@ -382,7 +382,7 @@ public override void OnStatusLose(Actor actor, ActorStatus status) public override void DrawArenaForeground(int pcSlot, Actor pc) { base.DrawArenaForeground(pcSlot, pc); - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; if (!IsImmune(pcSlot, ActiveBaits.FirstOrDefault(x => x.Target == pc).Activation)) { @@ -471,12 +471,12 @@ public override void AddHints(int slot, Actor actor, TextHints hints) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; var immunity = IsImmune(slot, ActiveBaits.FirstOrDefault(x => x.Target == actor).Activation); var isImmune = immunity && KnockbackImmunity; var couldBeImmune = !immunity && KnockbackImmunity; - if (couldBeImmune && ActivationDelayOnActor.Any(x => x.Item1 == actor && x.Item2.AddSeconds(-6) <= WorldState.CurrentTime)) + if (couldBeImmune && ActivationDelayOnActor.Any(x => x.Item1 == actor && x.Item2.AddSeconds(-6d) <= WorldState.CurrentTime)) { hints.ActionsToExecute.Push(ActionID.MakeSpell(ClassShared.AID.ArmsLength), actor, ActionQueue.Priority.High); hints.ActionsToExecute.Push(ActionID.MakeSpell(ClassShared.AID.Surecast), actor, ActionQueue.Priority.High); @@ -495,7 +495,7 @@ public class StretchTetherSingle(BossModule module, uint tetherID, float minimum { public override void AddHints(int slot, Actor actor, TextHints hints) { - if (!ActiveBaits.Any()) + if (ActiveBaits.Count == 0) return; if (needToKite && TetherOnActor.Contains((actor, TIDBad))) hints.Add("Kite the add!"); diff --git a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat1.cs b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat1.cs index b9155b5670..616360398a 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat1.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat1.cs @@ -21,18 +21,29 @@ public D040VanguardAerostat1States(BossModule module) : base(module) { TrivialPhase() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D040VanguardAerostat1.Trash).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D040VanguardAerostat1.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed) + return false; + } + return true; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 831, NameID = 12780, SortOrder = 4)] -public class D040VanguardAerostat1(WorldState ws, Actor primary) : BossModule(ws, primary, new(-50, -15), new ArenaBoundsRect(7.7f, 25)) +public class D040VanguardAerostat1(WorldState ws, Actor primary) : BossModule(ws, primary, new(-50f, -15f), new ArenaBoundsRect(7.7f, 25f)) { public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.Aerostat2]; protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.Aerostat2)); + Arena.Actors(Enemies((uint)OID.Aerostat2)); } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat2.cs b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat2.cs index a6e7722026..88c906aee4 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat2.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardAerostat2.cs @@ -20,9 +20,9 @@ public enum AID : uint SpreadShot = 39017, // SentryS7->self, 4.0s cast, range 12 90-degree cone } -class IncendiaryRing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IncendiaryRing), new AOEShapeDonut(3, 12)); -class Electrobeam(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Electrobeam), new AOEShapeRect(50, 2)); -class SpreadShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpreadShot), new AOEShapeCone(12, 45.Degrees())); +class IncendiaryRing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IncendiaryRing), new AOEShapeDonut(3f, 12f)); +class Electrobeam(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Electrobeam), new AOEShapeRect(50f, 2f)); +class SpreadShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpreadShot), new AOEShapeCone(12f, 45f.Degrees())); class D040VanguardAerostat2States : StateMachineBuilder { @@ -32,7 +32,18 @@ public D040VanguardAerostat2States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D040VanguardAerostat2.Trash).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D040VanguardAerostat2.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardLeptocyon.cs b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardLeptocyon.cs index 4f5f105cef..fc64957796 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardLeptocyon.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardLeptocyon.cs @@ -15,7 +15,7 @@ public enum AID : uint AutoAttack3 = 870, // VanguardSentryS7->player, no cast, single-target Levinbite = 39019, // Boss->player, no cast, single-target - SpreadShot = 39017, // VanguardSentryG7->self, 4.0s cast, range 12 90,000-degree cone + SpreadShot = 39017, // VanguardSentryG7->self, 4.0s cast, range 12 90-degree cone } class SpreadShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpreadShot), new AOEShapeCone(12, 45.Degrees())); @@ -26,7 +26,18 @@ public D040VanguardLeptocyonStates(BossModule module) : base(module) { TrivialPhase() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D040VanguardLeptocyon.Trash).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D040VanguardLeptocyon.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardSentryR7.cs b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardSentryR7.cs index 3c7dccb43d..f59b0b174a 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardSentryR7.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D04Vanguard/D040VanguardSentryR7.cs @@ -16,8 +16,8 @@ public enum AID : uint } class Swoop(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.Swoop), 2.5f); -class FloaterTurn(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FloaterTurn), new AOEShapeDonut(4, 10)); -class SpinningAxle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningAxle), 6); +class FloaterTurn(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FloaterTurn), new AOEShapeDonut(4f, 10f)); +class SpinningAxle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningAxle), 6f); class D040VanguardSentryR7States : StateMachineBuilder { @@ -27,7 +27,18 @@ public D040VanguardSentryR7States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D040VanguardSentryR7.Trash).All(e => e.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D040VanguardSentryR7.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -52,7 +63,7 @@ public class D040VanguardSentryR7(WorldState ws, Actor primary) : BossModule(ws, new(-63.71f, 337.46f), new(-64.16f, 337.69f), new(-64.88f, 337.86f), new(-66.28f, 337.76f), new(-66.94f, 337.83f), new(-68.31f, 337.72f), new(-70.32f, 337.8f), new(-70.92f, 337.87f), new(-71.61f, 337.81f), new(-72.24f, 338.11f), new(-72.51f, 339.51f), new(-74.39f, 339.68f), new(-82.01f, 339.66f), new(-82.7f, 339.51f), new(-85.92f, 336.18f), - new(-96.32f, 335.99f), new(-96.94f, 335.95f), new(-97.81f, 335.96f), new(-98, 333.99f), new(-97.9f, 333.37f), + new(-96.32f, 335.99f), new(-96.94f, 335.95f), new(-97.81f, 335.96f), new(-98f, 333.99f), new(-97.9f, 333.37f), new(-97.88f, 332.78f), new(-97.94f, 332.15f), new(-98.06f, 331.57f), new(-105.24f, 331.38f), new(-105.63f, 331.06f), new(-108.96f, 326.19f), new(-109.2f, 311.78f), new(-109.26f, 311.13f), new(-110.74f, 310.93f), new(-110.74f, 310.1f), new(-110.51f, 309.02f), new(-110.79f, 308.4f), new(-111.16f, 308.03f), new(-110.61f, 306.2f), new(-110.59f, 295.17f), diff --git "a/BossMod/Modules/Dawntrail/Dungeon/D08StrayboroughDeadwalk/D083Tr\303\244umerei.cs" "b/BossMod/Modules/Dawntrail/Dungeon/D08StrayboroughDeadwalk/D083Tr\303\244umerei.cs" index 8e87bc4957..034c5ebc17 100644 --- "a/BossMod/Modules/Dawntrail/Dungeon/D08StrayboroughDeadwalk/D083Tr\303\244umerei.cs" +++ "b/BossMod/Modules/Dawntrail/Dungeon/D08StrayboroughDeadwalk/D083Tr\303\244umerei.cs" @@ -96,17 +96,17 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) if (_avoid.ActiveSpreads.Count != 0) { shape = IsGhostly(actor) ? circlesInverted : circlesAvoid; - activation = _avoid.ActiveSpreads.First().Activation; + activation = _avoid.ActiveSpreads[0].Activation; } else if (fleshbuster.isActive) { shape = IsGhostly(actor) ? circlesAvoid : circlesInverted; activation = fleshbuster.activation; } - else if (_seek.ActiveBaits.Any()) + else if (_seek.ActiveBaits.Count != 0) shape = IsGhostly(actor) ? circlesAvoid : circlesInverted; - yield return new(shape, Module.Center, default, activation, shape == circlesInverted ? Colors.SafeFromAOE : Colors.AOE); + yield return new(shape, Module.Center, default, activation, shape == circlesInverted ? Colors.SafeFromAOE : 0); } public override void OnEventEnvControl(byte index, uint state) @@ -130,7 +130,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) public override void AddHints(int slot, Actor actor, TextHints hints) { var isGhostly = IsGhostly(actor); - if (fleshbuster.isActive || _seek.ActiveBaits.Any()) + if (fleshbuster.isActive || _seek.ActiveBaits.Count != 0) hints.Add(GhostHint, !isGhostly); else if (_avoid.ActiveSpreads.Count != 0) hints.Add(FleshHint, isGhostly); diff --git a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestBat.cs b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestBat.cs index 4faa57630c..73eda7318b 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestBat.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestBat.cs @@ -16,8 +16,8 @@ public enum AID : uint LineVoltage = 40665 // Electrogolem2->self, 4.0s cast, range 14 width 4 rect } -class FlashFlood(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SweepingGouge), new AOEShapeCone(9, 45.Degrees())); -class LineVoltage(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LineVoltage), new AOEShapeRect(14, 2)); +class FlashFlood(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SweepingGouge), new AOEShapeCone(9f, 45f.Degrees())); +class LineVoltage(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LineVoltage), new AOEShapeRect(14f, 2f)); class D90ForestBatStates : StateMachineBuilder { @@ -28,7 +28,6 @@ public D90ForestBatStates(BossModule module) : base(module) .ActivateOnEnter() .Raw.Update = () => { - var allDeadOrDestroyed = true; var enemies = module.Enemies(D90ForestBat.Trash); var center = module.Arena.Center; var radius = module.Bounds.Radius; @@ -37,12 +36,9 @@ public D90ForestBatStates(BossModule module) : base(module) { var enemy = enemies[i]; if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) - { - allDeadOrDestroyed = false; - break; - } + return false; } - return allDeadOrDestroyed; + return true; }; } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestWoolback.cs b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestWoolback.cs index cfdebf93da..ee8e8a1fbc 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestWoolback.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90ForestWoolback.cs @@ -16,7 +16,7 @@ public enum AID : uint Thunderball = 40666 // ForestAxeBeak->location, 4.0s cast, range 8 circle } -class SweepingGouge(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SweepingGouge), new AOEShapeCone(9, 45.Degrees())); +class SweepingGouge(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SweepingGouge), new AOEShapeCone(9f, 45f.Degrees())); class Thunderball(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Thunderball), 8); class D90ForestWoolbackStates : StateMachineBuilder @@ -26,7 +26,20 @@ public D90ForestWoolbackStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D90ForestWoolback.Trash).Where(x => x.Position.AlmostEqual(module.Arena.Center, module.Bounds.Radius)).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D90ForestWoolback.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } @@ -75,10 +88,34 @@ public class D90ForestWoolback(WorldState ws, Actor primary) : BossModule(ws, pr private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.ForestAxeBeak, (uint)OID.ForestWoolback, (uint)OID.Electrogolem]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90RottenHound.cs b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90RottenHound.cs index 9a5ef7f2f6..f90b0b3074 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90RottenHound.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90RottenHound.cs @@ -23,7 +23,20 @@ class D90RottenResearcherStates : StateMachineBuilder public D90RottenResearcherStates(BossModule module) : base(module) { TrivialPhase() - .Raw.Update = () => Module.Enemies(D90RottenResearcher.Trash).Where(x => x.Position.AlmostEqual(module.Arena.Center, module.Bounds.Radius)).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D90RottenResearcher.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } @@ -78,10 +91,34 @@ public class D90RottenResearcher(WorldState ws, Actor primary) : BossModule(ws, public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.RottenResearcher1, (uint)OID.RottenResearcher2, (uint)OID.RottenResearcher3, (uint)OID.RottenHound1, (uint)OID.RottenHound2]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyClayGolem.cs b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyClayGolem.cs index f8e159f7e0..bc92ed02d2 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyClayGolem.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyClayGolem.cs @@ -27,7 +27,20 @@ public D90SprightlyClayGolemStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D90SprightlyClayGolem.Trash).Where(x => x.Position.AlmostEqual(module.Arena.Center, module.Bounds.Radius)).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D90SprightlyClayGolem.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } @@ -80,10 +93,34 @@ public class D90SprightlyClayGolem(WorldState ws, Actor primary) : BossModule(ws private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.SprightlyStone1, (uint)OID.SprightlyStone2, (uint)OID.SprightlyDhara]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyPhoebad.cs b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyPhoebad.cs index 7c7357c6b0..88ae4ba320 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyPhoebad.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90SprightlyPhoebad.cs @@ -28,7 +28,20 @@ public D90SprightlyPhoebadStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D90SprightlyPhoebad.Trash).Where(x => x.Position.AlmostEqual(module.Arena.Center, module.Bounds.Radius)).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D90SprightlyPhoebad.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } @@ -58,10 +71,34 @@ public class D90SprightlyPhoebad(WorldState ws, Actor primary) : BossModule(ws, private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]); public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.SprightlyMole, (uint)OID.SprightlyStone, (uint)OID.SprightlyLoamkeep]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90StationSpecter.cs b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90StationSpecter.cs index ad51c2ee8f..edf160c749 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90StationSpecter.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D09YuweyawataFieldStation/D90StationSpecter.cs @@ -29,7 +29,20 @@ public D90StationSpecterStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D90StationSpecter.Trash).Where(x => x.Position.AlmostEqual(module.Arena.Center, module.Bounds.Radius)).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D90StationSpecter.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } @@ -77,10 +90,34 @@ public class D90StationSpecter(WorldState ws, Actor primary) : BossModule(ws, pr public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.RottenResearcher1, (uint)OID.RottenResearcher2, (uint)OID.RottenResearcher3, (uint)OID.GiantCorse, (uint)OID.StationSpecter]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/BullApollyon.cs b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/BullApollyon.cs index ec45419cd9..c4469f3b76 100644 --- a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/BullApollyon.cs +++ b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/BullApollyon.cs @@ -52,25 +52,25 @@ public enum AID : uint class Blade(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Blade)); class Pyreburst(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Pyreburst)); -abstract class RectWide(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40, 5)); +abstract class RectWide(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40f, 5f)); class FlameBlade1(BossModule module) : RectWide(module, AID.FlameBlade1); class FlameBlade2(BossModule module) : RectWide(module, AID.FlameBlade2); -abstract class RectNarrow(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40, 2.5f)); +abstract class RectNarrow(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40f, 2.5f)); class CrossfireBlade3(BossModule module) : RectNarrow(module, AID.CrossfireBlade3); class FlameBlade3(BossModule module) : RectNarrow(module, AID.FlameBlade3); -abstract class Crosses(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCross(20, 5)); +abstract class Crosses(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCross(20f, 5f)); class CrossfireBlade1(BossModule module) : Crosses(module, AID.CrossfireBlade1); class CrossfireBlade2(BossModule module) : Crosses(module, AID.CrossfireBlade2); -class BlazingBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlazingBreath), new AOEShapeRect(44, 5)); -class BlazingBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlazingBlast), 6); +class BlazingBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlazingBreath), new AOEShapeRect(44f, 5f)); +class BlazingBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlazingBlast), 6f); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class RottenSpores(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RottenSpores), 6); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class RottenSpores(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RottenSpores), 6f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -99,7 +99,17 @@ public BullApollyonStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(BullApollyon.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(BullApollyon.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/GoldenMolter.cs b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/GoldenMolter.cs index 2c12f381b2..6f36e188a1 100644 --- a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/GoldenMolter.cs +++ b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/GoldenMolter.cs @@ -86,55 +86,55 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID is AID.Crypsis1 or AID.Crypsis2) + if (spell.Action.ID is (uint)AID.Crypsis1 or (uint)AID.Crypsis2) IsConcealed = true; } public override void OnStatusLose(Actor actor, ActorStatus status) { - if ((SID)status.ID == SID.Concealed) + if (status.ID == (uint)SID.Concealed) IsConcealed = false; } } -class GoldenGall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldenGall), new AOEShapeCone(40, 90.Degrees())); -class GoldenRadiance(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldenRadiance), 5); -class BlindingLight(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.BlindingLight), 6); +class GoldenGall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldenGall), new AOEShapeCone(40f, 90f.Degrees())); +class GoldenRadiance(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldenRadiance), 5f); +class BlindingLight(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.BlindingLight), 6f); class AetherialLight : Components.SimpleAOEs { - public AetherialLight(BossModule module) : base(module, ActionID.MakeSpell(AID.AetherialLight), new AOEShapeCone(40, 30.Degrees()), 4) { MaxDangerColor = 2; } + public AetherialLight(BossModule module) : base(module, ActionID.MakeSpell(AID.AetherialLight), new AOEShapeCone(40f, 30f.Degrees()), 4) { MaxDangerColor = 2; } } -abstract class Vasoconstrictor(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6); +abstract class Vasoconstrictor(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6f); class Vasoconstrictor1(BossModule module) : Vasoconstrictor(module, AID.Vasoconstrictor1); class Vasoconstrictor2(BossModule module) : Vasoconstrictor(module, AID.Vasoconstrictor2); class Vasoconstrictor3(BossModule module) : Vasoconstrictor(module, AID.Vasoconstrictor3); class VasoconstrictorPool(BossModule module) : Components.GenericAOEs(module) { - private readonly List _aoes = []; - private readonly AOEShapeCircle circle = new(17); + private readonly List _aoes = new(3); + private readonly AOEShapeCircle circle = new(17f); public override IEnumerable ActiveAOEs(int slot, Actor actor) => _aoes; public override void OnActorEState(Actor actor, ushort state) { - if (state == 0x004) - _aoes.RemoveAll(x => x.Origin == actor.Position); + if (_aoes.Count != 0 && state == 0x004) + _aoes.RemoveAt(0); } public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.VasoconstrictorPool) - _aoes.Add(new(circle, actor.Position)); + if (actor.OID == (uint)OID.VasoconstrictorPool) + _aoes.Add(new(circle, WPos.ClampToGrid(actor.Position))); } } -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class RottenSpores(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RottenSpores), 6); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class RottenSpores(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RottenSpores), 6f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -164,7 +164,17 @@ public GoldenMolterStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GoldenMolter.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GoldenMolter.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room1.cs b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room1.cs index 5ab848ca6a..6b437fd322 100644 --- a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room1.cs +++ b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room1.cs @@ -54,23 +54,23 @@ public enum AID : uint Telega = 9630 // BonusAdds->self, no cast, single-target, bonus adds disappear } -class NepenthicPlunge(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.NepenthicPlunge), new AOEShapeCone(10, 45.Degrees())); -class CreepingHush(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CreepingHush), new AOEShapeCone(12, 60.Degrees())); -class Ovation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Ovation), new AOEShapeRect(14, 2)); -class BestialFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BestialFire), 5); -class HeadButt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeadButt), new AOEShapeCone(6, 60.Degrees())); -class AetherialBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherialBlast), new AOEShapeRect(20, 2)); +class NepenthicPlunge(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.NepenthicPlunge), new AOEShapeCone(10f, 45f.Degrees())); +class CreepingHush(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CreepingHush), new AOEShapeCone(12f, 60f.Degrees())); +class Ovation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Ovation), new AOEShapeRect(14f, 2f)); +class BestialFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BestialFire), 5f); +class HeadButt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeadButt), new AOEShapeCone(6f, 60f.Degrees())); +class AetherialBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherialBlast), new AOEShapeRect(20f, 2f)); class Envenomate(BossModule module) : Components.BaitAwayChargeCast(module, ActionID.MakeSpell(AID.Envenomate), 1.5f); -class SyrupSpout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SyrupSpout), new AOEShapeCone(10, 60.Degrees())); -class SpinningAttack(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningAttack), new AOEShapeRect(10, 2)); +class SyrupSpout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SyrupSpout), new AOEShapeCone(10f, 60f.Degrees())); +class SpinningAttack(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningAttack), new AOEShapeRect(10f, 2f)); -abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6); +abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6f); class IsleDrop(BossModule module) : CircleLoc6(module, AID.IsleDrop); class RottenSpores(BossModule module) : CircleLoc6(module, AID.RottenSpores); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -99,19 +99,29 @@ public Room1States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Room1.All).All(x => x.IsDeadOrDestroyed) || module.PrimaryActor.EventState == 7; + .Raw.Update = () => + { + var enemies = module.Enemies(Room1.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return module.PrimaryActor.EventState == 7; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 993, NameID = 5057)] public class Room1(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaBounds.Center, ArenaBounds) { - private static readonly WPos arenaCenter = new(0, 377); + private static readonly WPos arenaCenter = new(default, 377f); private static readonly Angle a135 = 135.Degrees(); private static readonly WDir dir135 = a135.ToDirection(), dirM135 = (-a135).ToDirection(); - public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20, 6.15f, a135), - new Rectangle(arenaCenter + 8.65f * dirM135, 20, 6.15f, -a135), new Rectangle(arenaCenter + 12 * dir135, 20, 4.3f, a135), new Rectangle(arenaCenter + 12 * dirM135, 20, 4.3f, -a135), - new Rectangle(arenaCenter + 14.3f * dir135, 20, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20, 3.5f, -a135)], [new Rectangle(new(0, 397), 20, 1.4f)]); + public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20f, 6.15f, a135), + new Rectangle(arenaCenter + 8.65f * dirM135, 20f, 6.15f, -a135), new Rectangle(arenaCenter + 12f * dir135, 20f, 4.3f, a135), new Rectangle(arenaCenter + 12f * dirM135, 20f, 4.3f, -a135), + new Rectangle(arenaCenter + 14.3f * dir135, 20f, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20f, 3.5f, -a135)], [new Rectangle(new(default, 397f), 20f, 1.4f)]); private static readonly uint[] bonusAdds = [(uint)OID.TuligoraQueen, (uint)OID.TuraliTomato, (uint)OID.TuraliOnion, (uint)OID.TuraliEggplant, (uint)OID.TuraliGarlic, (uint)OID.UolonOfFortune, (uint)OID.AlpacaOfFortune]; private static readonly uint[] trash = [(uint)OID.CenoteNetzach, (uint)OID.CenotePitcherWeed, (uint)OID.CenoteWoodsman, (uint)OID.CenoteSilverLobo, (uint)OID.CenoteGedan, diff --git a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room2.cs b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room2.cs index 453ba075bd..ba5abe94d9 100644 --- a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room2.cs +++ b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room2.cs @@ -51,29 +51,29 @@ public enum AID : uint Telega = 9630 // BonusAdds->self, no cast, single-target, bonus adds disappear } -class SwiftwindSerenade(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SwiftwindSerenade), new AOEShapeRect(40, 4)); -class Ovation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Ovation), new AOEShapeRect(14, 2)); -class GravelShower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GravelShower), new AOEShapeRect(10, 2)); -class Flatten(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Flatten), new AOEShapeCone(8, 45.Degrees())); -class PollenCorona(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PollenCorona), 8); -class WaterIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WaterIII), 8); - -abstract class Cone1045(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(10, 45.Degrees())); +class SwiftwindSerenade(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SwiftwindSerenade), new AOEShapeRect(40f, 4f)); +class Ovation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Ovation), new AOEShapeRect(14f, 2f)); +class GravelShower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GravelShower), new AOEShapeRect(10f, 2f)); +class Flatten(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Flatten), new AOEShapeCone(8f, 45f.Degrees())); +class PollenCorona(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PollenCorona), 8f); +class WaterIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WaterIII), 8f); + +abstract class Cone1045(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(10f, 45f.Degrees())); class Dissever(BossModule module) : Cone1045(module, AID.Dissever); class NepenthicPlunge(BossModule module) : Cone1045(module, AID.NepenthicPlunge); -abstract class Cone1060(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(10, 60.Degrees())); +abstract class Cone1060(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(10f, 60f.Degrees())); class DoubleSmash(BossModule module) : Cone1060(module, AID.DoubleSmash); class CriticalBite(BossModule module) : Cone1060(module, AID.CriticalBite); -abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6); +abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6f); class Tornado(BossModule module) : CircleLoc6(module, AID.Tornado); class TornadicSerenade(BossModule module) : CircleLoc6(module, AID.TornadicSerenade); class RottenSpores(BossModule module) : CircleLoc6(module, AID.RottenSpores); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -104,19 +104,29 @@ public Room2States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Room2.All).All(x => x.IsDeadOrDestroyed) || module.PrimaryActor.EventState == 7; + .Raw.Update = () => + { + var enemies = module.Enemies(Room2.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return module.PrimaryActor.EventState == 7; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 993, NameID = 5057)] public class Room2(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaBounds.Center, ArenaBounds) { - private static readonly WPos arenaCenter = new(0, 192); + private static readonly WPos arenaCenter = new(default, 192f); private static readonly Angle a135 = 135.Degrees(); private static readonly WDir dir135 = a135.ToDirection(), dirM135 = (-a135).ToDirection(); - public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20, 6.15f, a135), - new Rectangle(arenaCenter + 8.65f * dirM135, 20, 6.15f, -a135), new Rectangle(arenaCenter + 12 * dir135, 20, 4.3f, a135), new Rectangle(arenaCenter + 12 * dirM135, 20, 4.3f, -a135), - new Rectangle(arenaCenter + 14.3f * dir135, 20, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20, 3.5f, -a135)], [new Rectangle(new(0, 212), 20, 1.7f)]); + public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20f, 6.15f, a135), + new Rectangle(arenaCenter + 8.65f * dirM135, 20f, 6.15f, -a135), new Rectangle(arenaCenter + 12f * dir135, 20f, 4.3f, a135), new Rectangle(arenaCenter + 12f * dirM135, 20f, 4.3f, -a135), + new Rectangle(arenaCenter + 14.3f * dir135, 20f, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20f, 3.5f, -a135)], [new Rectangle(new(default, 212f), 20f, 1.7f)]); private static readonly uint[] bonusAdds = [(uint)OID.TuligoraQueen, (uint)OID.TuraliTomato, (uint)OID.TuraliOnion, (uint)OID.TuraliEggplant, (uint)OID.TuraliGarlic, (uint)OID.UolonOfFortune, (uint)OID.AlpacaOfFortune]; private static readonly uint[] trash = [(uint)OID.CenoteWoodsman, (uint)OID.CenoteBranchbearer, (uint)OID.CenoteSlammer, (uint)OID.CenoteAlligator, (uint)OID.CenoteMonstera, diff --git a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room3.cs b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room3.cs index fb7689f484..ad6751f104 100644 --- a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room3.cs +++ b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room3.cs @@ -54,25 +54,25 @@ public enum AID : uint Telega = 9630 // BonusAdds->self, no cast, single-target, bonus adds disappear } -class Wingbeat(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wingbeat), new AOEShapeCone(18, 30.Degrees())); -class Feathercut(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Feathercut), new AOEShapeRect(40, 4)); -class GoldDust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldDust), 8); -class BloodyCaress(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BloodyCaress), new AOEShapeCone(12, 60.Degrees())); -class SwiftSough(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SwiftSough), new AOEShapeCone(13, 30.Degrees())); -class FireBreak(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FireBreak), new AOEShapeCone(8, 45.Degrees())); +class Wingbeat(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wingbeat), new AOEShapeCone(18f, 30f.Degrees())); +class Feathercut(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Feathercut), new AOEShapeRect(40f, 4f)); +class GoldDust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldDust), 8f); +class BloodyCaress(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BloodyCaress), new AOEShapeCone(12f, 60f.Degrees())); +class SwiftSough(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SwiftSough), new AOEShapeCone(13f, 30f.Degrees())); +class FireBreak(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FireBreak), new AOEShapeCone(8f, 45f.Degrees())); -abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6); +abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6f); class Tornado(BossModule module) : CircleLoc6(module, AID.Tornado); class Incubus(BossModule module) : CircleLoc6(module, AID.Incubus); class RottenSpores(BossModule module) : CircleLoc6(module, AID.RottenSpores); -abstract class CircleLoc5(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 5); +abstract class CircleLoc5(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 5f); class FireII(BossModule module) : CircleLoc5(module, AID.FireII); class BitterNectar(BossModule module) : CircleLoc5(module, AID.BitterNectar); class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -101,19 +101,29 @@ public Room3States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Room3.All).All(x => x.IsDeadOrDestroyed) || module.PrimaryActor.EventState == 7; + .Raw.Update = () => + { + var enemies = module.Enemies(Room3.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return module.PrimaryActor.EventState == 7; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 993, NameID = 5057)] public class Room3(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaBounds.Center, ArenaBounds) { - private static readonly WPos arenaCenter = new(160, 19); + private static readonly WPos arenaCenter = new(160f, 19f); private static readonly Angle a135 = 135.Degrees(); private static readonly WDir dir135 = a135.ToDirection(), dirM135 = (-a135).ToDirection(); - public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20, 6.15f, a135), - new Rectangle(arenaCenter + 8.65f * dirM135, 20, 6.15f, -a135), new Rectangle(arenaCenter + 12 * dir135, 20, 4.3f, a135), new Rectangle(arenaCenter + 12 * dirM135, 20, 4.3f, -a135), - new Rectangle(arenaCenter + 14.3f * dir135, 20, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20, 3.5f, -a135)], [new Rectangle(new(160, 39), 20, 1.7f)]); + public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20f, 6.15f, a135), + new Rectangle(arenaCenter + 8.65f * dirM135, 20f, 6.15f, -a135), new Rectangle(arenaCenter + 12f * dir135, 20f, 4.3f, a135), new Rectangle(arenaCenter + 12f * dirM135, 20f, 4.3f, -a135), + new Rectangle(arenaCenter + 14.3f * dir135, 20f, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20f, 3.5f, -a135)], [new Rectangle(new(160f, 39f), 20f, 1.7f)]); private static readonly uint[] bonusAdds = [(uint)OID.TuligoraQueen, (uint)OID.TuraliTomato, (uint)OID.TuraliOnion, (uint)OID.TuraliEggplant, (uint)OID.TuraliGarlic, (uint)OID.UolonOfFortune, (uint)OID.AlpacaOfFortune]; private static readonly uint[] trash = [(uint)OID.BirdOfTheCenote1, (uint)OID.BirdOfTheCenote2, (uint)OID.CenoteTocoToco, (uint)OID.CenoteToucalibri, diff --git a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room4.cs b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room4.cs index 5888742124..fb844718fb 100644 --- a/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room4.cs +++ b/BossMod/Modules/Dawntrail/TreasureHunt/CenoteJaJaGural/Room4.cs @@ -48,25 +48,25 @@ public enum AID : uint Telega = 9630 // BonusAdds->self, no cast, single-target, bonus adds disappear } -abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6); +abstract class CircleLoc6(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6f); class Lumisphere(BossModule module) : CircleLoc6(module, AID.Lumisphere); class Tornado(BossModule module) : CircleLoc6(module, AID.Tornado); class RootsOfAtopy(BossModule module) : CircleLoc6(module, AID.RootsOfAtopy); class RottenSpores(BossModule module) : CircleLoc6(module, AID.RottenSpores); -class AetherialBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherialBlast), new AOEShapeRect(20, 2)); -class SerratedSpin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SerratedSpin), 8); -class SyrupSpout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SyrupSpout), new AOEShapeCone(10, 60.Degrees())); -class SpinningAttack(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningAttack), new AOEShapeRect(10, 2)); -class OdiousAir(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OdiousAir), new AOEShapeCone(12, 60.Degrees())); +class AetherialBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherialBlast), new AOEShapeRect(20f, 2f)); +class SerratedSpin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SerratedSpin), 8f); +class SyrupSpout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SyrupSpout), new AOEShapeCone(10f, 60f.Degrees())); +class SpinningAttack(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningAttack), new AOEShapeRect(10f, 2f)); +class OdiousAir(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OdiousAir), new AOEShapeCone(12f, 60f.Degrees())); -abstract class Wingblade(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(8, 90.Degrees())); +abstract class Wingblade(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(8f, 90f.Degrees())); class LeftWingblade(BossModule module) : Wingblade(module, AID.LeftWingblade); class RightWingblade(BossModule module) : Wingblade(module, AID.RightWingblade); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -95,19 +95,29 @@ public Room4States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Room4.All).All(x => x.IsDeadOrDestroyed) || module.PrimaryActor.EventState == 7; + .Raw.Update = () => + { + var enemies = module.Enemies(Room4.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return module.PrimaryActor.EventState == 7; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 993, NameID = 5057)] public class Room4(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaBounds.Center, ArenaBounds) { - private static readonly WPos arenaCenter = new(-197, -145); + private static readonly WPos arenaCenter = new(-197f, -145f); private static readonly Angle a135 = 135.Degrees(); private static readonly WDir dir135 = a135.ToDirection(), dirM135 = (-a135).ToDirection(); - public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20, 6.15f, a135), - new Rectangle(arenaCenter + 8.65f * dirM135, 20, 6.15f, -a135), new Rectangle(arenaCenter + 12 * dir135, 20, 4.3f, a135), new Rectangle(arenaCenter + 12 * dirM135, 20, 4.3f, -a135), - new Rectangle(arenaCenter + 14.3f * dir135, 20, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20, 3.5f, -a135)], [new Rectangle(new(-197, -125), 20, 1.7f)]); + public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(arenaCenter, 19.5f * CosPI.Pi36th, 36), new Rectangle(arenaCenter + 8.65f * dir135, 20f, 6.15f, a135), + new Rectangle(arenaCenter + 8.65f * dirM135, 20f, 6.15f, -a135), new Rectangle(arenaCenter + 12f * dir135, 20f, 4.3f, a135), new Rectangle(arenaCenter + 12f * dirM135, 20f, 4.3f, -a135), + new Rectangle(arenaCenter + 14.3f * dir135, 20f, 3.5f, a135), new Rectangle(arenaCenter + 14.3f * dirM135, 20f, 3.5f, -a135)], [new Rectangle(new(-197f, -125f), 20f, 1.7f)]); private static readonly uint[] bonusAdds = [(uint)OID.TuligoraQueen, (uint)OID.TuraliTomato, (uint)OID.TuraliOnion, (uint)OID.TuraliEggplant, (uint)OID.TuraliGarlic, (uint)OID.UolonOfFortune, (uint)OID.AlpacaOfFortune]; private static readonly uint[] trash = [(uint)OID.CenoteQeziigural, (uint)OID.CenoteTohsoq, (uint)OID.CenoteMegamaguey, (uint)OID.CenoteTyaitya, (uint)OID.CenoteTulichu, diff --git a/BossMod/Modules/Dawntrail/Ultimate/FRU/P2LightRampant.cs b/BossMod/Modules/Dawntrail/Ultimate/FRU/P2LightRampant.cs index e9e95e38de..8cb2371e64 100644 --- a/BossMod/Modules/Dawntrail/Ultimate/FRU/P2LightRampant.cs +++ b/BossMod/Modules/Dawntrail/Ultimate/FRU/P2LightRampant.cs @@ -280,8 +280,8 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme // - if actor and partner are north and south, stay on current side // - if both are on the same side, the 'more clockwise' one (NE/SW) moves to the opposite side // TODO: last rule is fuzzy in practice, see if we can adjust better - var north = actor.Position.Z < Module.Center.Z; - if (north == (partner.Position.Z < Module.Center.Z)) + var north = actor.Position.Z < Arena.Center.Z; + if (north == (partner.Position.Z < Arena.Center.Z)) { // same side, see if we need to swap var moreRight = actor.Position.X > partner.Position.X; @@ -296,9 +296,9 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme { // each next bait is just previous position rotated CW by 45 degrees // note that this is only really relevant for second and third puddles - after that towers resolve and we use different component - //var nextSpot = Module.Center + BaitOffset * _puddles.PrevBaitOffset[slot].Normalized().Rotate(-45.Degrees()); + //var nextSpot = Arena.Center + BaitOffset * _puddles.PrevBaitOffset[slot].Normalized().Rotate(-45.Degrees()); //hints.AddForbiddenZone(ShapeDistance.InvertedCircle(nextSpot, 3)); - var shape = ShapeDistance.DonutSector(Module.Center, BaitOffset - 1, BaitOffset + 2, Angle.FromDirection(_puddles.PrevBaitOffset[slot]) - 45.Degrees(), 30.Degrees()); + var shape = ShapeDistance.DonutSector(Arena.Center, BaitOffset - 1, BaitOffset + 2, Angle.FromDirection(_puddles.PrevBaitOffset[slot]) - 45.Degrees(), 30.Degrees()); hints.AddForbiddenZone(p => -shape(p), DateTime.MaxValue); } } @@ -309,7 +309,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme if (assignedTowerIndex >= 0 && _towers.Towers.FindIndex(assignedTowerIndex + 1, t => !t.ForbiddenSoakers[slot]) < 0) { ref var t = ref _towers.Towers.Ref(assignedTowerIndex); - hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Module.Center + (t.Position - Module.Center) * 1.125f, 2), t.Activation); // center is at R16, x1.125 == R18 + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Arena.Center + (t.Position - Arena.Center) * 1.125f, 2), t.Activation); // center is at R16, x1.125 == R18 } // else: we either have no towers assigned (== doing puddles), or have multiple assigned (== assignments failed), so do nothing } @@ -323,7 +323,7 @@ class P2LightRampantAIStackPrepos(BossModule module) : BossComponent(module) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - var isPuddleBaiter = _puddles?.ActiveBaitsOn(actor).Any() ?? false; + var isPuddleBaiter = _puddles?.ActiveBaitsOn(actor).Count != 0; var northCamp = isPuddleBaiter ? actor.Position.X < Arena.Center.X : actor.Position.Z < Module.Center.Z; // this assumes CW movement for baiter var dest = Module.Center + new WDir(0, northCamp ? -18 : 18); if (isPuddleBaiter) diff --git a/BossMod/Modules/Endwalker/Savage/P12S1Athena/Palladion.cs b/BossMod/Modules/Endwalker/Savage/P12S1Athena/Palladion.cs index f422b11b87..8c3679e783 100644 --- a/BossMod/Modules/Endwalker/Savage/P12S1Athena/Palladion.cs +++ b/BossMod/Modules/Endwalker/Savage/P12S1Athena/Palladion.cs @@ -190,7 +190,7 @@ public override void Update() public override void AddHints(int slot, Actor actor, TextHints hints) { if (NumCasts < 4 && !ForbiddenPlayers[slot]) - hints.Add("Bait next aoe", CurrentBaits.Count != 0 && !ActiveBaitsOn(actor).Any()); + hints.Add("Bait next aoe", CurrentBaits.Count != 0 && ActiveBaitsOn(actor).Count == 0); base.AddHints(slot, actor, hints); } diff --git a/BossMod/Modules/Endwalker/Savage/P9SKokytos/DualityOfDeath.cs b/BossMod/Modules/Endwalker/Savage/P9SKokytos/DualityOfDeath.cs index 710faf3873..bf67cec337 100644 --- a/BossMod/Modules/Endwalker/Savage/P9SKokytos/DualityOfDeath.cs +++ b/BossMod/Modules/Endwalker/Savage/P9SKokytos/DualityOfDeath.cs @@ -8,7 +8,7 @@ class DualityOfDeath(BossModule module) : Components.GenericBaitAway(module, Act public override void AddHints(int slot, Actor actor, TextHints hints) { - if (ActiveBaitsOn(actor).Any()) + if (ActiveBaitsOn(actor).Count != 0) { if (Raid.WithoutSlot(false, true, true).InRadiusExcluding(actor, _shape.Radius).Any()) hints.Add("GTFO from raid!"); diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheExcitatron6000/LuckyFace.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheExcitatron6000/LuckyFace.cs index 8e30b640ff..876ec983d8 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheExcitatron6000/LuckyFace.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheExcitatron6000/LuckyFace.cs @@ -58,13 +58,13 @@ public enum AID : uint Telega = 9630 // Mandragoras->self, no cast, single-target, mandragoras disappear } -abstract class InTheDark(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(20, 90f.Degrees())); +abstract class InTheDark(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(20f, 90f.Degrees())); class LeftInTheDark1(BossModule module) : InTheDark(module, AID.LeftInTheDark1); class LeftInTheDark2(BossModule module) : InTheDark(module, AID.LeftInTheDark2); class RightInTheDark1(BossModule module) : InTheDark(module, AID.RightInTheDark1); class RightInTheDark2(BossModule module) : InTheDark(module, AID.RightInTheDark2); -abstract class QuakeCircle(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 10); +abstract class QuakeCircle(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 10f); class QuakeMeAwayCircle(BossModule module) : QuakeCircle(module, AID.QuakeMeAwayCircle); class QuakeInYourBootsCircle(BossModule module) : QuakeCircle(module, AID.QuakeInYourBootsCircle); @@ -106,21 +106,31 @@ public LuckyFaceStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(LuckyFace.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(LuckyFace.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 819, NameID = 10831)] public class LuckyFace(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly ArenaBoundsComplex arena = new([new Polygon(new(0f, -460f), 19.5f, 32)], [new Rectangle(new(0f, -440f), 20f, 1f)]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(default, -460f), 19.5f, 32)], [new Rectangle(new(default, -440f), 20f, 1f)]); private static readonly uint[] bonusAdds = [(uint)OID.ExcitingEgg, (uint)OID.ExcitingQueen, (uint)OID.ExcitingOnion, (uint)OID.ExcitingTomato, (uint)OID.ExcitingGarlic]; public static readonly uint[] All = [(uint)OID.Boss, .. bonusAdds]; protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.Boss)); + Arena.Actor(PrimaryActor); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouAcheloios.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouAcheloios.cs index 99bde00a9a..0d8c558312 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouAcheloios.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouAcheloios.cs @@ -48,7 +48,7 @@ public enum AID : uint class DoubleHammer(BossModule module) : Components.GenericAOEs(module) { private readonly List _aoes = []; - public static readonly AOEShapeCone Cone = new(30, 90.Degrees()); + public static readonly AOEShapeCone Cone = new(30f, 90f.Degrees()); private static readonly Angle[] angles = [89.999f.Degrees(), -90.004f.Degrees()]; public override IEnumerable ActiveAOEs(int slot, Actor actor) @@ -56,40 +56,39 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) var count = _aoes.Count; if (count == 0) return []; - List aoes = new(count); + var aoes = new AOEInstance[count]; for (var i = 0; i < count; ++i) { var aoe = _aoes[i]; if (i == 0) - aoes.Add(count > 1 ? aoe with { Color = Colors.Danger } : aoe); + aoes[i] = count > 1 ? aoe with { Color = Colors.Danger } : aoe; else - aoes.Add(aoe with { Risky = false }); + aoes[i] = aoe with { Risky = false }; } return aoes; } public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - switch ((AID)spell.Action.ID) + void AddAOEs(ReadOnlySpan angles) { - case AID.DoubleHammerVisualLR: - AddAOEs(caster, spell, angles[1], angles[0]); + _aoes.Add(new(Cone, spell.LocXZ, angles[0], Module.CastFinishAt(spell, 0.8f))); + _aoes.Add(new(Cone, spell.LocXZ, angles[1], Module.CastFinishAt(spell, 3.7f))); + } + switch (spell.Action.ID) + { + case (uint)AID.DoubleHammerVisualLR: + AddAOEs([angles[1], angles[0]]); break; - case AID.DoubleHammerVisualRL: - AddAOEs(caster, spell, angles[0], angles[1]); + case (uint)AID.DoubleHammerVisualRL: + AddAOEs([angles[0], angles[1]]); break; } } - private void AddAOEs(Actor caster, ActorCastInfo spell, Angle first, Angle second) - { - _aoes.Add(new(Cone, spell.LocXZ, first, Module.CastFinishAt(spell, 0.8f))); - _aoes.Add(new(Cone, spell.LocXZ, second, Module.CastFinishAt(spell, 3.7f))); - } - public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.LeftHammer or AID.RightHammer or AID.DoubleHammerFirst) + if (_aoes.Count != 0 && spell.Action.ID is (uint)AID.LeftHammer or (uint)AID.RightHammer or (uint)AID.DoubleHammerFirst) _aoes.RemoveAt(0); } } @@ -102,15 +101,15 @@ class QuadrupleHammer(BossModule module) : Components.GenericRotatingAOE(module) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - switch ((AID)spell.Action.ID) + switch (spell.Action.ID) { - case AID.QuadrupleHammerVisualCW: // note that boss switches hands, so CW rotation means CCW aoe sequence and vice versa + case (uint)AID.QuadrupleHammerVisualCW: // note that boss switches hands, so CW rotation means CCW aoe sequence and vice versa _increment = 90.Degrees(); break; - case AID.QuadrupleHammerVisualCCW: + case (uint)AID.QuadrupleHammerVisualCCW: _increment = -90.Degrees(); break; - case AID.QuadrupleHammerFirst: + case (uint)AID.QuadrupleHammerFirst: _rotation = spell.Rotation; break; } @@ -120,7 +119,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID is AID.QuadrupleHammerFirst or AID.LeftHammer or AID.RightHammer) + if (spell.Action.ID is (uint)AID.QuadrupleHammerFirst or (uint)AID.LeftHammer or (uint)AID.RightHammer) AdvanceSequence(0, WorldState.CurrentTime); } @@ -128,7 +127,7 @@ private void InitIfReady(Actor source) { if (_rotation != default && _increment != default) { - Sequences.Add(new(DoubleHammer.Cone, source.Position, _rotation, _increment, _activation.AddSeconds(0.8f), 3.3f, 4)); + Sequences.Add(new(DoubleHammer.Cone, source.Position, _rotation, _increment, _activation.AddSeconds(0.8d), 3.3f, 4)); _rotation = default; _increment = default; } @@ -136,19 +135,19 @@ private void InitIfReady(Actor source) } class VolcanicHowl(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.VolcanicHowl)); -class Earthbreak(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthbreak), 5); +class Earthbreak(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthbreak), 5f); class DeadlyHold(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.DeadlyHold)); -class TailSwing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSwing), 13); -class CriticalBite(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CriticalBite), new AOEShapeCone(10, 60.Degrees())); +class TailSwing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSwing), 13f); +class CriticalBite(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CriticalBite), new AOEShapeCone(10f, 60f.Degrees())); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouAcheloiosStates : StateMachineBuilder { @@ -168,7 +167,17 @@ public GymnasiouAcheloiosStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouAcheloios.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouAcheloios.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -182,7 +191,7 @@ public class GymnasiouAcheloios(WorldState ws, Actor primary) : THTemplate(ws, p protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouSouchos)); + Arena.Actors(Enemies((uint)OID.GymnasiouSouchos)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouLeon.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouLeon.cs index 4d136344fb..88775f027f 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouLeon.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouLeon.cs @@ -35,24 +35,24 @@ public enum AID : uint Telega = 9630 // Mandragoras/GymnasiouLyssa->self, no cast, single-target, bonus add disappear } -class InfernoBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.InfernoBlast), new AOEShapeRect(46, 10)); +class InfernoBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.InfernoBlast), new AOEShapeRect(46f, 10f)); -abstract class Circles(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 12); +abstract class Circles(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 12f); class Roar(BossModule module) : Circles(module, AID.Roar); class FlareStar(BossModule module) : Circles(module, AID.FlareStar); -class MarkOfTheBeast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MarkOfTheBeast), new AOEShapeCone(8, 60.Degrees())); +class MarkOfTheBeast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MarkOfTheBeast), new AOEShapeCone(8f, 60f.Degrees())); class Pounce(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Pounce)); -class MagmaChamber(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagmaChamber), 8); +class MagmaChamber(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagmaChamber), 8f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouLeonStates : StateMachineBuilder { @@ -71,7 +71,17 @@ public GymnasiouLeonStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouLeon.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouLeon.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMegakantha.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMegakantha.cs index 672839d8f5..99e8169745 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMegakantha.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMegakantha.cs @@ -41,32 +41,32 @@ public enum AID : uint Telega = 9630 // Mandragoras/Lyssa/Lampas->self, no cast, single-target, bonus add disappear } -class SludgeBomb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SludgeBomb2), 8); -class RustlingWind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RustlingWind), new AOEShapeRect(15, 2)); -class AcidMist(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AcidMist), 6); -class OdiousAir(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OdiousAir), new AOEShapeCone(12, 60.Degrees())); +class SludgeBomb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SludgeBomb2), 8f); +class RustlingWind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RustlingWind), new AOEShapeRect(15f, 2f)); +class AcidMist(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AcidMist), 6f); +class OdiousAir(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OdiousAir), new AOEShapeCone(12f, 60f.Degrees())); class VineWhip(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.VineWhip)); class OdiousAtmosphere(BossModule module) : Components.GenericAOEs(module) { private AOEInstance? _aoe; - private static readonly AOEShapeCone cone = new(40, 90.Degrees()); + private static readonly AOEShapeCone cone = new(40f, 90f.Degrees()); 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.OdiousAtmosphere1) - _aoe = new(cone, caster.Position, spell.Rotation, Module.CastFinishAt(spell)); + if (spell.Action.ID == (uint)AID.OdiousAtmosphere1) + _aoe = new(cone, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - switch ((AID)spell.Action.ID) + switch (spell.Action.ID) { - case AID.OdiousAtmosphere1: - case AID.OdiousAtmosphere2: - case AID.OdiousAtmosphere3: + case (uint)AID.OdiousAtmosphere1: + case (uint)AID.OdiousAtmosphere2: + case (uint)AID.OdiousAtmosphere3: if (++NumCasts == 5) { _aoe = null; @@ -77,14 +77,14 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } } -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouMegakanthaStates : StateMachineBuilder { @@ -103,7 +103,17 @@ public GymnasiouMegakanthaStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouMegakantha.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouMegakantha.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMeganereis.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMeganereis.cs index c39b37bb89..19a0de64ef 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMeganereis.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouMeganereis.cs @@ -43,43 +43,55 @@ public enum AID : uint class Ceras(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Ceras)); -class WaveOfTurmoil(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.WaveOfTurmoil), 20, stopAtWall: true) +class WaveOfTurmoil(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.WaveOfTurmoil), 20f, stopAtWall: true) { private readonly Hydrobomb _aoe = module.FindComponent()!; + private static readonly Angle cone = 30f.Degrees(); - public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => _aoe?.ActiveAOEs(slot, actor).Any(z => z.Shape.Check(pos, z.Origin, z.Rotation)) ?? false; + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + var count = _aoe.Casters.Count; + for (var i = 0; i < count; ++i) + { + var caster = _aoe.Casters[i]; + if (caster.Check(pos)) + return true; + } + return false; + } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - var forbidden = new List>(); - var source = Sources(slot, actor).FirstOrDefault(); - if (source != default) + var source = Casters.Count != 0 ? Casters[0] : null; + if (source != null) { - foreach (var c in _aoe.ActiveAOEs(slot, actor)) + var count = _aoe.Casters.Count; + var forbidden = new Func[count]; + for (var i = 0; i < count; ++i) { - forbidden.Add(ShapeDistance.Cone(Arena.Center, 20, Angle.FromDirection(c.Origin - Module.Center), 30.Degrees())); + forbidden[i] = ShapeDistance.Cone(Arena.Center, 20f, Angle.FromDirection(_aoe.Casters[i].Origin - Arena.Center), cone); } - if (forbidden.Count != 0) - hints.AddForbiddenZone(ShapeDistance.Union(forbidden), source.Activation); + if (forbidden.Length != 0) + hints.AddForbiddenZone(ShapeDistance.Union(forbidden), Module.CastFinishAt(source.CastInfo)); } } } -class Hydrobomb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrobomb), 10); -class Waterspout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Waterspout), 8); -class Hydrocannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon), new AOEShapeRect(17, 1.5f)); -class Hydrocannon2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon2), new AOEShapeRect(27, 3)); -class FallingWater(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FallingWater), 8); +class Hydrobomb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrobomb), 10f); +class Waterspout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Waterspout), 8f); +class Hydrocannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon), new AOEShapeRect(17f, 1.5f)); +class Hydrocannon2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon2), new AOEShapeRect(27f, 3f)); +class FallingWater(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FallingWater), 8f); class Immersion(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Immersion)); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouMeganereisStates : StateMachineBuilder { @@ -100,7 +112,17 @@ public GymnasiouMeganereisStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouMeganereis.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouMeganereis.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -114,7 +136,7 @@ public class GymnasiouMeganereis(WorldState ws, Actor primary) : THTemplate(ws, protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouNereis)); + Arena.Actors(Enemies((uint)OID.GymnasiouNereis)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouPithekos.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouPithekos.cs index 50abb55def..bc5922ab92 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouPithekos.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouPithekos.cs @@ -42,13 +42,13 @@ public enum IconID : uint Thundercall = 111 // Thundercall marker } -class Spark(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spark), new AOEShapeDonut(14, 30)); +class Spark(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spark), new AOEShapeDonut(14f, 30f)); class SweepingGouge(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.SweepingGouge)); -class Thundercall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Thundercall), 3); +class Thundercall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Thundercall), 3f); class Thundercall2(BossModule module) : Components.GenericBaitAway(module) { - private static readonly AOEShapeCircle circle = new(18); + private static readonly AOEShapeCircle circle = new(18f); public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { @@ -58,38 +58,40 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.Thundercall) + if (spell.Action.ID == (uint)AID.Thundercall) CurrentBaits.Clear(); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == actor) hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 17.5f)); } public override void AddHints(int slot, Actor actor, TextHints hints) { - if (CurrentBaits.Any(x => x.Target != actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) base.AddHints(slot, actor, hints); - else if (CurrentBaits.Any(x => x.Target == actor)) + else hints.Add("Bait levinorb away!"); } } -class RockThrow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RockThrow), 6); -class LightningBolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightningBolt), 6); -class ThunderIV(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ThunderIV), 18); +class RockThrow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RockThrow), 6f); +class LightningBolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightningBolt), 6f); +class ThunderIV(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ThunderIV), 18f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouPithekosStates : StateMachineBuilder { @@ -109,7 +111,17 @@ public GymnasiouPithekosStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouPithekos.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouPithekos.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -123,7 +135,7 @@ public class GymnasiouPithekos(WorldState ws, Actor primary) : THTemplate(ws, pr protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouPithekosMikros)); + Arena.Actors(Enemies((uint)OID.GymnasiouPithekosMikros)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSatyros.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSatyros.cs index d4a9dc9c8d..d8c5cef61e 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSatyros.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSatyros.cs @@ -30,13 +30,16 @@ public enum AID : uint Telega = 9630 // GymnasiouLyssa->self, no cast, single-target, bonus add disappear } -class StormWing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.StormWing), new AOEShapeCone(40, 45.Degrees())); +class StormWing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.StormWing), new AOEShapeCone(40f, 45f.Degrees())); class FlashGale(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlashGale), 6); -class WindCutter(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(OID.StormsGrip)); -class Wingblow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wingblow), 15); +class WindCutter(BossModule module) : Components.PersistentVoidzone(module, 4f, GetVoidzones) +{ + private static List GetVoidzones(BossModule module) => module.Enemies((uint)OID.StormsGrip); +} +class Wingblow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wingblow), 15f); class DreadDive(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.DreadDive)); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouSatyrosStates : StateMachineBuilder { @@ -49,7 +52,17 @@ public GymnasiouSatyrosStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouSatyros.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouSatyros.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -62,7 +75,7 @@ public class GymnasiouSatyros(WorldState ws, Actor primary) : THTemplate(ws, pri protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouElaphos)); + Arena.Actors(Enemies((uint)OID.GymnasiouElaphos)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSphinx.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSphinx.cs index 00038fa6e2..979f21adc9 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSphinx.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouSphinx.cs @@ -42,22 +42,22 @@ public enum AID : uint } class Scratch(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Scratch)); -class Explosion(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeDonut(3, 12)); -class FrigidPulse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrigidPulse), new AOEShapeDonut(12, 60)); -class FervidPulse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FervidPulse), new AOEShapeCross(50, 7)); +class Explosion(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeDonut(3f, 12f)); +class FrigidPulse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrigidPulse), new AOEShapeDonut(12f, 60f)); +class FervidPulse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FervidPulse), new AOEShapeCross(50f, 7f)); class MoltingPlumage(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.MoltingPlumage)); -class AlpineDraft(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AlpineDraft), new AOEShapeRect(45, 2.5f)); -class FeatherRain(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FeatherRain), 6); -class AeroII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AeroII), 4); +class AlpineDraft(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AlpineDraft), new AOEShapeRect(45f, 2.5f)); +class FeatherRain(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FeatherRain), 6f); +class AeroII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AeroII), 4f); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouSphinxStates : StateMachineBuilder { @@ -78,7 +78,17 @@ public GymnasiouSphinxStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouSphinx.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouSphinx.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -92,7 +102,7 @@ public class GymnasiouSphinx(WorldState ws, Actor primary) : THTemplate(ws, prim protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouGryps)); + Arena.Actors(Enemies((uint)OID.GymnasiouGryps)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouStyphnolobion.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouStyphnolobion.cs index b074e544df..b78628febb 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouStyphnolobion.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouStyphnolobion.cs @@ -23,8 +23,8 @@ public enum AID : uint EarthQuaker1 = 32248, // Helper->self, 4.0s cast, range 10 circle EarthQuaker2 = 32249, // Helper->self, 6.0s cast, range 10-20 donut Rake = 32245, // Boss->player, 5.0s cast, single-target - EarthShaker = 32250, // Boss->self, 3.5s cast, single-target - EarthShaker2 = 32251, // Helper->players, 4.0s cast, range 60 30-degree cone + EarthShakerVisual = 32250, // Boss->self, 3.5s cast, single-target + EarthShaker = 32251, // Helper->players, 4.0s cast, range 60 30-degree cone StoneIII = 32252, // Boss->self, 2.5s cast, single-target StoneIII2 = 32253, // Helper->location, 3.0s cast, range 6 circle BeakSnap = 32254, // GymnasiouHippogryph->player, no cast, single-target @@ -41,8 +41,8 @@ public enum AID : uint class Rake(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Rake)); class Tiiimbeeer(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Tiiimbeeer)); -class StoneIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.StoneIII2), 6); -class EarthShaker(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.EarthShaker2), new AOEShapeCone(60, 15.Degrees()), endsOnCastEvent: true); +class StoneIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.StoneIII2), 6f); +class EarthShaker(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.EarthShaker), new AOEShapeCone(60f, 15f.Degrees()), endsOnCastEvent: true); class EarthQuaker(BossModule module) : Components.ConcentricAOEs(module, _shapes) { @@ -50,33 +50,33 @@ class EarthQuaker(BossModule module) : Components.ConcentricAOEs(module, _shapes public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.EarthQuakerVisual2) - AddSequence(Module.Center, Module.CastFinishAt(spell, 0.5f)); + if (spell.Action.ID == (uint)AID.EarthQuakerVisual2) + AddSequence(WPos.ClampToGrid(Arena.Center), Module.CastFinishAt(spell, 0.5f)); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { if (Sequences.Count != 0) { - var order = (AID)spell.Action.ID switch + var order = spell.Action.ID switch { - AID.EarthQuaker1 => 0, - AID.EarthQuaker2 => 1, + (uint)AID.EarthQuaker1 => 0, + (uint)AID.EarthQuaker2 => 1, _ => -1 }; - AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2)); + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2d)); } } } -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouStyphnolobionStates : StateMachineBuilder { @@ -94,7 +94,17 @@ public GymnasiouStyphnolobionStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouStyphnolobion.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouStyphnolobion.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -108,7 +118,7 @@ public class GymnasiouStyphnolobion(WorldState ws, Actor primary) : THTemplate(w protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouHippogryph)); + Arena.Actors(Enemies((uint)OID.GymnasiouHippogryph)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTigris.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTigris.cs index 1e19319884..6d4be7271b 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTigris.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTigris.cs @@ -32,20 +32,20 @@ public enum AID : uint Telega = 9630 // GymnasiouLyssa/Mandragoras->self, no cast, single-target, bonus add disappear } -class AbsoluteZero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbsoluteZero), new AOEShapeCone(45, 45.Degrees())); +class AbsoluteZero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbsoluteZero), new AOEShapeCone(45f, 45f.Degrees())); class FrumiousJaws(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.FrumiousJaws)); -class BlizzardIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlizzardIII), 6); +class BlizzardIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlizzardIII), 6f); class Eyeshine(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.Eyeshine)); -class CatchingClaws(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CatchingClaws), new AOEShapeCone(12, 45.Degrees())); +class CatchingClaws(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CatchingClaws), new AOEShapeCone(12f, 45f.Degrees())); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class GymnasiouTigrisStates : StateMachineBuilder { @@ -63,7 +63,17 @@ public GymnasiouTigrisStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouTigris.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouTigris.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -77,7 +87,7 @@ public class GymnasiouTigris(WorldState ws, Actor primary) : THTemplate(ws, prim protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouTigrisMikra)); + Arena.Actors(Enemies((uint)OID.GymnasiouTigrisMikra)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTriton.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTriton.cs index d7b0327921..10ef24e049 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTriton.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/GymnasiouTriton.cs @@ -34,12 +34,15 @@ public enum AID : uint Telega = 9630 // GymnasiouLyssa/Mandragoras->self, no cast, single-target, bonus add disappear } -class PelagicCleaver(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PelagicCleaver), new AOEShapeCone(40, 30.Degrees())); -class FoulWaters(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 5, ActionID.MakeSpell(AID.FoulWaters), m => m.Enemies(OID.Bubble), 0); -class AquaticLance(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaticLance), 13); +class PelagicCleaver(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PelagicCleaver), new AOEShapeCone(40f, 30f.Degrees())); +class FoulWaters(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 5f, ActionID.MakeSpell(AID.FoulWaters), GetVoidzones, 1.4f) +{ + private static List GetVoidzones(BossModule module) => module.Enemies((uint)OID.Bubble); +} +class AquaticLance(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaticLance), 13f); class ProtolithicPuncture(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.ProtolithicPuncture)); -abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7); +abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 7f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); class TearyTwirl(BossModule module) : Mandragoras(module, AID.TearyTwirl); class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream); @@ -60,7 +63,17 @@ public GymnasiouTritonStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GymnasiouTriton.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GymnasiouTriton.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -74,7 +87,7 @@ public class GymnasiouTriton(WorldState ws, Actor primary) : THTemplate(ws, prim protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouEcheneis)); + Arena.Actors(Enemies((uint)OID.GymnasiouEcheneis)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LampasChrysine.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LampasChrysine.cs index 5144edaaab..73483bdd4e 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LampasChrysine.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LampasChrysine.cs @@ -16,17 +16,17 @@ public enum AID : uint unknown = 32236, // Boss->self, no cast, single-target, seems to be connected to Aetherial Light LightburstVisual = 32289, // Boss->self, 3.3s cast, single-target Lightburst = 32290, // Helper->player, 5.0s cast, single-target - Shine = 32291, // Boss->self, 1.3s cast, single-target - Shine2 = 32292, // Helper->location, 3.0s cast, range 5 circle + ShineVisual = 32291, // Boss->self, 1.3s cast, single-target + Shine = 32292, // Helper->location, 3.0s cast, range 5 circle Summon = 32288, // Boss->self, 1.3s cast, single-target, spawns bonus loot adds Telega = 9630 // GymnasiouLampas->self, no cast, single-target, bonus loot add despawn } -class Shine(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Shine2), 5); +class Shine(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Shine), 5f); class AetherialLight : Components.SimpleAOEs { - public AetherialLight(BossModule module) : base(module, ActionID.MakeSpell(AID.AetherialLight), new AOEShapeCone(40, 30.Degrees()), 4) { MaxDangerColor = 2; } + public AetherialLight(BossModule module) : base(module, ActionID.MakeSpell(AID.AetherialLight), new AOEShapeCone(40f, 30f.Degrees()), 4) { MaxDangerColor = 2; } } class Lightburst(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Lightburst)); @@ -41,7 +41,17 @@ public LampasChrysineStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(LampasChrysine.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(LampasChrysine.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -53,7 +63,7 @@ public class LampasChrysine(WorldState ws, Actor primary) : THTemplate(ws, prima protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GymnasiouLampas), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.GymnasiouLampas), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LyssaChrysine.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LyssaChrysine.cs index d0b2d638c9..11bc611b72 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LyssaChrysine.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/LyssaChrysine.cs @@ -32,62 +32,62 @@ public enum AID : uint Telega = 9630 // GymnasiouLyssa/Lampas->self, no cast, single-target, bonus add disappear } -class HeavySmash2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash2), 6); -class FrigidStone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrigidStone), 5); +class HeavySmash2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash2), 6f); +class FrigidStone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrigidStone), 5f); class FrigidNeedle(BossModule module) : Components.ConcentricAOEs(module, _shapes) { - private static readonly AOEShape[] _shapes = [new AOEShapeCircle(10), new AOEShapeDonut(10, 20)]; + private static readonly AOEShape[] _shapes = [new AOEShapeCircle(10f), new AOEShapeDonut(10f, 20f)]; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.FrigidNeedleVisual) - AddSequence(Arena.Center, Module.CastFinishAt(spell, 0.5f)); + if (spell.Action.ID == (uint)AID.FrigidNeedleVisual) + AddSequence(WPos.ClampToGrid(Arena.Center), Module.CastFinishAt(spell, 0.5f)); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { if (Sequences.Count != 0) { - var order = (AID)spell.Action.ID switch + var order = spell.Action.ID switch { - AID.FrigidNeedle => 0, - AID.CircleOfIce => 1, + (uint)AID.FrigidNeedle => 0, + (uint)AID.CircleOfIce => 1, _ => -1 }; - AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2)); + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2d)); } } } class CircleOfIce(BossModule module) : Components.ConcentricAOEs(module, _shapes) { - private static readonly AOEShape[] _shapes = [new AOEShapeDonut(10, 20), new AOEShapeCircle(10)]; + private static readonly AOEShape[] _shapes = [new AOEShapeDonut(10f, 20f), new AOEShapeCircle(10f)]; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.CircleOfIceVisual) - AddSequence(Arena.Center, Module.CastFinishAt(spell, 0.5f)); + if (spell.Action.ID == (uint)AID.CircleOfIceVisual) + AddSequence(WPos.ClampToGrid(Arena.Center), Module.CastFinishAt(spell, 0.5f)); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { if (Sequences.Count != 0) { - var order = (AID)spell.Action.ID switch + var order = spell.Action.ID switch { - AID.CircleOfIce => 0, - AID.FrigidNeedle => 1, + (uint)AID.CircleOfIce => 0, + (uint)AID.FrigidNeedle => 1, _ => -1 }; - AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2)); + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2d)); } } } -class PillarPierce(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PillarPierce), new AOEShapeRect(80, 2)); +class PillarPierce(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PillarPierce), new AOEShapeRect(80f, 2f)); class SkullDasher(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.SkullDasher)); -class HeavySmash(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.HeavySmash), 6, 8, 8); +class HeavySmash(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.HeavySmash), 6f, 8, 8); class IcePillar(BossModule module) : Components.GenericAOEs(module) { @@ -98,12 +98,12 @@ class IcePillar(BossModule module) : Components.GenericAOEs(module) public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.IcePillar) - _aoes.Add(new(circle, actor.Position, default, WorldState.FutureTime(3.7f))); + if (actor.OID == (uint)OID.IcePillar) + _aoes.Add(new(circle, WPos.ClampToGrid(actor.Position), default, WorldState.FutureTime(3.7d))); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.IcePillar) + if (spell.Action.ID == (uint)AID.IcePillar) _aoes.Clear(); } } @@ -124,7 +124,17 @@ public LyssaChrysineStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(LyssaChrysine.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(LyssaChrysine.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/Narkissos.cs b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/Narkissos.cs index 03763b4b1e..48109c3660 100644 --- a/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/Narkissos.cs +++ b/BossMod/Modules/Endwalker/TreasureHunt/TheShiftingGymnasionAgonon/Narkissos.cs @@ -40,12 +40,24 @@ public enum SID : uint class Brainstorm(BossModule module) : Components.StatusDrivenForcedMarch(module, 2, (uint)SID.ForwardMarch, (uint)SID.AboutFace, (uint)SID.LeftFace, (uint)SID.RightFace) { - 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; + private readonly SapShower _aoe = module.FindComponent()!; + + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + var count = _aoe.Casters.Count; + for (var i = 0; i < count; ++i) + { + var caster = _aoe.Casters[i]; + if (caster.Check(pos)) + return true; + } + return false; + } } class FetchingFulgence(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.FetchingFulgence)); class Lash(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Lash)); -class PotentPerfume(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PotentPerfume), 8); +class PotentPerfume(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PotentPerfume), 8f); class SapShowerTendrilsHint(BossModule module) : BossComponent(module) { @@ -54,7 +66,7 @@ class SapShowerTendrilsHint(BossModule module) : BossComponent(module) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.SapShower) + if (spell.Action.ID == (uint)AID.SapShower) { active = true; ++NumCasts; @@ -63,7 +75,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.SapShower) + if (spell.Action.ID == (uint)AID.SapShower) active = false; } @@ -81,30 +93,30 @@ public override void AddGlobalHints(GlobalHints hints) class SapShower : Components.SimpleAOEs { - public SapShower(BossModule module) : base(module, ActionID.MakeSpell(AID.SapShower), 8) + public SapShower(BossModule module) : base(module, ActionID.MakeSpell(AID.SapShower), 8f) { Color = Colors.Danger; } } -class ExtensibleTendrils(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ExtensibleTendrils), new AOEShapeCross(25, 3)); -class PutridBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PutridBreath), new AOEShapeCone(25, 45.Degrees())); -class RockHard(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.RockHard), 6); +class ExtensibleTendrils(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ExtensibleTendrils), new AOEShapeCross(25f, 3f)); +class PutridBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PutridBreath), new AOEShapeCone(25f, 45f.Degrees())); +class RockHard(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.RockHard), 6f); class BeguilingGasTM(BossModule module) : Components.TemporaryMisdirection(module, ActionID.MakeSpell(AID.BeguilingGas)); class BeguilingGas(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.BeguilingGas)); -class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6); +class HeavySmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavySmash), 6f); class NarkissosStates : StateMachineBuilder { public NarkissosStates(BossModule module) : base(module) { TrivialPhase() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() @@ -112,7 +124,17 @@ public NarkissosStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Narkissos.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(Narkissos.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Endwalker/Ultimate/DSW2/P6HallowedWings.cs b/BossMod/Modules/Endwalker/Ultimate/DSW2/P6HallowedWings.cs index 0b18b74edf..eb469e7541 100644 --- a/BossMod/Modules/Endwalker/Ultimate/DSW2/P6HallowedWings.cs +++ b/BossMod/Modules/Endwalker/Ultimate/DSW2/P6HallowedWings.cs @@ -69,7 +69,7 @@ public override void Update() public override void AddHints(int slot, Actor actor, TextHints hints) { var shouldBait = actor.Role == Role.Tank; - var isBaiting = ActiveBaitsOn(actor).Any(); + var isBaiting = ActiveBaitsOn(actor).Count != 0; var stayFar = shouldBait == _far; hints.Add(stayFar ? "Stay far!" : "Stay close!", shouldBait != isBaiting); diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs index f99d68941b..760a3ab21f 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060BiocultureNode.cs @@ -48,27 +48,27 @@ public override void OnActorEAnim(Actor actor, uint state) { if (state == 0x00040008) { - if ((OID)actor.OID == OID.Boss1Hole) + if (actor.OID == (uint)OID.Boss1Hole) Arena.Bounds = D060BiocultureNode.Arena1b; - else if ((OID)actor.OID == OID.Boss2Hole) + else if (actor.OID == (uint)OID.Boss2Hole) Arena.Bounds = D060BiocultureNode.Arena2b; } } } class Puncture(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Puncture), new AOEShapeRect(5.5f, 1.5f)); -class TailSlap(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSlap), new AOEShapeCone(7, 60.Degrees())); -class CalcifyingMist(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CalcifyingMist), new AOEShapeCone(6.9f, 45.Degrees())); +class TailSlap(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSlap), new AOEShapeCone(7f, 60f.Degrees())); +class CalcifyingMist(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CalcifyingMist), new AOEShapeCone(6.9f, 45f.Degrees())); class EerieSoundwave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EerieSoundwave), 7.5f); -abstract class MarrowDrain(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(9.7f, 60.Degrees())); +abstract class MarrowDrain(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(9.7f, 60f.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.SimpleAOEs(module, ActionID.MakeSpell(AID.TheRamsVoice), 9.7f); -class Sideswipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Sideswipe), new AOEShapeCone(9, 45.Degrees())); -class Gust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gust), 3); +class Sideswipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Sideswipe), new AOEShapeCone(9f, 45f.Degrees())); +class Gust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gust), 3f); class D060BiocultureNodeStates : StateMachineBuilder { @@ -86,14 +86,25 @@ public D060BiocultureNodeStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(module.Bounds == D060BiocultureNode.Arena1 || module.Bounds == D060BiocultureNode.Arena1b ? D060BiocultureNode.Trash1 : D060BiocultureNode.Trash2).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(module.Bounds == D060BiocultureNode.Arena1 || module.Bounds == D060BiocultureNode.Arena1b ? D060BiocultureNode.Trash1 : D060BiocultureNode.Trash2); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed) + return false; + } + return true; + }; } } [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; + public static bool IsArena1(Actor primary) => primary.Position.Z < 250f; private static readonly WPos[] vertices1 = [new(26.19f, 163.9f), new(29.99f, 164.07f), new(30.59f, 164.12f), new(31.3f, 164.26f), new(31.59f, 164.85f), new(31.81f, 165.42f), new(32, 166.01f), new(32.24f, 166.6f), new(34.76f, 168.55f), new(34.99f, 169.17f), @@ -131,7 +142,7 @@ public class D060BiocultureNode(WorldState ws, Actor primary) : BossModule(ws, p 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.3f), new(159.31f, 246.46f), new(160.21f, 247.35f), new(160.81f, 247.64f), new(164.01f, 250.87f), new(164.5f, 251.29f), new(168.2f, 255.04f), - new(168.7f, 255.43f), new(169.29f, 255.76f), new(169.76f, 256.22f), new(171.24f, 257.54f), new(171.72f, 258), + new(168.7f, 255.43f), new(169.29f, 255.76f), new(169.76f, 256.22f), new(171.24f, 257.54f), new(171.72f, 258f), 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), @@ -181,10 +192,11 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - if ((OID)e.Actor.OID == OID.Boss) + if (e.Actor.OID == (uint)OID.Boss) { e.Priority = 0; break; diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs index 57127e117d..cbb293629f 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060ClonedConjurer.cs @@ -15,7 +15,7 @@ public enum AID : uint Drain = 2339 // ClonedThaumaturge->player, 4.0s cast, single-target } -class Tornado(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Tornado), 6); +class Tornado(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Tornado), 6f); class D060ClonedConjurerStates : StateMachineBuilder { @@ -23,7 +23,17 @@ public D060ClonedConjurerStates(BossModule module) : base(module) { TrivialPhase() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D060ClonedConjurer.Trash).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D060ClonedConjurer.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs index 1b66765dc8..1b2b839f2e 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060CulturedShabti.cs @@ -13,8 +13,8 @@ public enum AID : uint DeathsDoor = 1260 // Boss->self, 2.0s cast, range 20+R width 2 rect } -class Spellsword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spellsword), new AOEShapeCone(8.2f, 60.Degrees())); -class DeathsDoor(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DeathsDoor), new AOEShapeRect(22.2f, 1)); +class Spellsword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spellsword), new AOEShapeCone(8.2f, 60f.Degrees())); +class DeathsDoor(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DeathsDoor), new AOEShapeRect(22.2f, 1f)); class D060CulturedShabtiStates : StateMachineBuilder { @@ -23,7 +23,17 @@ public D060CulturedShabtiStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(OID.Boss).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies((uint)OID.Boss); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -71,6 +81,6 @@ public class D060CulturedShabti(WorldState ws, Actor primary) : BossModule(ws, p protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(OID.Boss)); + Arena.Actors(Enemies((uint)OID.Boss)); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs index 901feffc47..be54a3ea15 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060FacilityDreadnaught.cs @@ -15,9 +15,9 @@ public enum AID : uint WreckingBall = 4557 // Boss->location, 4.0s cast, range 8 circle } -class Rotoswipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Rotoswipe), new AOEShapeCone(11, 60.Degrees())); +class Rotoswipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Rotoswipe), new AOEShapeCone(11f, 60f.Degrees())); class AutoCannons(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AutoCannons), new AOEShapeRect(42.4f, 2.5f)); -class WreckingBall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WreckingBall), 8); +class WreckingBall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WreckingBall), 8f); class D060FacilityDreadnaughtStates : StateMachineBuilder { @@ -27,14 +27,24 @@ public D060FacilityDreadnaughtStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D060FacilityDreadnaught.Trash).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D060FacilityDreadnaught.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 38, NameID = 3836, SortOrder = 7)] 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)]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-360f, -250f), 9f, 6)]); public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.MonitoringDrone]; protected override void DrawEnemies(int pcSlot, Actor pc) diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs index ccca6ae8c2..a8177b32c3 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060SixthLegionMagitekVanguardH1.cs @@ -40,7 +40,17 @@ public D060SixthLegionMagitekVanguardH1States(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D060SixthLegionMagitekVanguardH1.Trash).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D060SixthLegionMagitekVanguardH1.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -60,7 +70,18 @@ public class D060SixthLegionMagitekVanguardH1(WorldState ws, Actor primary) : Bo 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 bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs index a4ec0566d8..dffded27d9 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs @@ -27,7 +27,7 @@ public enum AID : uint 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); +class PassiveInfraredGuidanceSystem(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.PassiveInfraredGuidanceSystem), new AOEShapeCircle(6f), [(uint)OID.Boss], originAtTarget: true); abstract class HeadSpin(BossModule module, AID aid, OID oid) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCircle(5.225f), [(uint)oid]) { @@ -52,8 +52,8 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) class Headspin1(BossModule module) : HeadSpin(module, AID.Headspin1, OID.ScrambledPaladin); class Headspin2(BossModule module) : HeadSpin(module, AID.Headspin2, OID.ScrambledEngineer); -class GrandSword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GrandSword), new AOEShapeCone(16, 60.Degrees())); -class TheHand(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheHand), new AOEShapeCone(7.5f, 60.Degrees())); +class GrandSword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GrandSword), new AOEShapeCone(16f, 60f.Degrees())); +class TheHand(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheHand), new AOEShapeCone(7.5f, 60f.Degrees())); class D060EnforcementDroid210States : StateMachineBuilder { @@ -61,7 +61,17 @@ public D060EnforcementDroid210States(BossModule module) : base(module) { TrivialPhase() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D060Trash1.TrashP1).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D060Trash1.TrashP1); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -77,7 +87,17 @@ public D060ScrambledIronGiantStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D060Trash1.TrashP2).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D060Trash1.TrashP2); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -97,7 +117,18 @@ public abstract class D060Trash1(WorldState ws, Actor primary) : BossModule(ws, 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 bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs index 62793637ad..6fbc8af3fb 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D061Regula.cs @@ -34,13 +34,13 @@ public enum TetherID : uint } class SelfDetonate(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.SelfDetonate)); -class AetherochemicalGrenado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherochemicalGrenado), 8); +class AetherochemicalGrenado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherochemicalGrenado), 8f); class AetherochemicalLaser(BossModule module) : Components.BaitAwayTethers(module, new AOEShapeRect(50, 2), (uint)TetherID.BaitAway, ActionID.MakeSpell(AID.AetherochemicalLaser)); -class AetherochemicalLaserAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherochemicalLaser), new AOEShapeRect(50, 2)); +class AetherochemicalLaserAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherochemicalLaser), new AOEShapeRect(50f, 2f)); -class JudgmentAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.JudgmentAOE), 8); -class MagitekSlug(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSlug), new AOEShapeRect(61.65f, 2)); -class MagitekSpread(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSpread), new AOEShapeCone(31.65f, 120.Degrees())); +class JudgmentAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.JudgmentAOE), 8f); +class MagitekSlug(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSlug), new AOEShapeRect(61.65f, 2f)); +class MagitekSpread(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSpread), new AOEShapeCone(31.65f, 120f.Degrees())); class D061RegulaStates : StateMachineBuilder { @@ -68,6 +68,6 @@ public class D061Regula(WorldState ws, Actor primary) : BossModule(ws, primary, protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.MagitekTurretI)); + Arena.Actors(Enemies((uint)OID.MagitekTurretI)); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs index 445245e137..bd1c558ad2 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D062Harmachis.cs @@ -33,38 +33,34 @@ public enum AID : uint public enum SID : uint { - Transfiguration = 705, // Boss->Boss, extra=0x1D/0x1E/0x1F - DamageUp = 443, // Boss->Boss, extra=0x1 - Poison = 2104, // Boss->player, extra=0x0 Bind = 2518 // Boss->player, extra=0x0 } public enum IconID : uint { - Enumeration = 382, // Helper Stack = 93 // player } -class Paradox(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Paradox), 5); +class Paradox(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Paradox), 5f); class Petrifaction(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.Petrifaction)); -class Ka(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Ka), new AOEShapeCone(45, 30.Degrees())); -class GaseousBomb(BossModule module) : Components.StackWithIcon(module, (uint)IconID.Stack, ActionID.MakeSpell(AID.GaseousBomb), 5, 4.1f, 4, 4); -class BallisticMissile(BossModule module) : Components.UniformStackSpread(module, 4, 0, 2, 2) +class Ka(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Ka), new AOEShapeCone(45f, 30f.Degrees())); +class GaseousBomb(BossModule module) : Components.StackWithIcon(module, (uint)IconID.Stack, ActionID.MakeSpell(AID.GaseousBomb), 5f, 4.1f, 4, 4); +class BallisticMissile(BossModule module) : Components.UniformStackSpread(module, 4f, default, 2, 2) { public override void OnStatusGain(Actor actor, ActorStatus status) { - if ((SID)status.ID == SID.Bind) - AddStack(actor, WorldState.FutureTime(6.2f)); + if (status.ID == (uint)SID.Bind) + AddStack(actor, WorldState.FutureTime(6.2d)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.BallisticMissile2) + if (spell.Action.ID == (uint)AID.BallisticMissile2) Stacks.Clear(); } } -class ChthonicHush(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ChthonicHush), new AOEShapeCone(13.3f, 60.Degrees())) +class ChthonicHush(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ChthonicHush), new AOEShapeCone(13.3f, 60f.Degrees())) { private readonly GaseousBomb _stack1 = module.FindComponent()!; private readonly BallisticMissile _stack2 = module.FindComponent()!; @@ -105,5 +101,6 @@ 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, SortOrder = 6)] public class D062Harmachis(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - 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())]); + public static readonly ArenaBoundsComplex arena = new([new Polygon(new(248f, 272f), 19.25f, 44)], [new Rectangle(new(228f, 272f), 20f, 1.8f, 90f.Degrees()), + new Rectangle(new(268.25f, 272f), 20f, 2f, 90f.Degrees())]); } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs index 5fd56c4415..d79320de0f 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D063LahabreaIgeyorhm.cs @@ -52,16 +52,16 @@ public enum TetherID : uint } class ShadowFlare(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.ShadowFlare)); -class GripOfNight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GripOfNight), new AOEShapeCone(40, 75.Degrees())); -class DarkFireIIAOE(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.DarkFireIIAOE), 6); +class GripOfNight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GripOfNight), new AOEShapeCone(40f, 75f.Degrees())); +class DarkFireIIAOE(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.DarkFireIIAOE), 6f); class EndOfDays(BossModule module) : Components.LineStack(module, ActionID.MakeSpell(AID.EndOfDays), ActionID.MakeSpell(AID.EndOfDays2), 5.1f); class Stars(BossModule module) : Components.GenericAOEs(module) { - 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 static readonly AOEShapeDonut donutSmall = new(5f, 15f), donutBig = new(5f, 40f); + private static readonly AOEShapeCircle circleSmall = new(8f), circleBig = new(16f); + private readonly List _aoes = new(5); + private readonly List _stars = new(8); private bool _tutorialFire, _tutorialIce; @@ -73,7 +73,7 @@ public override void OnTethered(Actor source, ActorTetherInfo tether) { var target = WorldState.Actors.Find(tether.Target)!; var targetPos = target.Position; - var midpoint = new WPos((source.Position.X + targetPos.X) / 2, (source.Position.Z + targetPos.Z) / 2); + var midpoint = WPos.ClampToGrid(new WPos((source.Position.X + targetPos.X) / 2, (source.Position.Z + targetPos.Z) / 2)); switch (source.OID) { case (uint)OID.FrozenStar: @@ -90,11 +90,27 @@ private void ActivateAOE(AOEShape smallShape, AOEShape bigShape, WPos midpoint, { _stars.Remove(source); _stars.Remove(target); - var activation = WorldState.FutureTime(10.6f); + var activation = WorldState.FutureTime(10.6d); _aoes.Add(new(bigShape, midpoint, default, activation)); - if (_aoes.Any(x => x.Shape == donutBig) || _aoes.Count(x => x.Shape == circleBig) == 2) + var hasDonutBig = false; + var circleBigCount = 0; + + var count = _aoes.Count; + for (var i = 0; i < count; ++i) { - for (var i = 0; i < _stars.Count; ++i) + if (_aoes[i].Shape == donutBig) + { + hasDonutBig = true; + break; + } + else + ++circleBigCount; + } + + if (hasDonutBig || circleBigCount == 2) + { + var countS = _stars.Count; + for (var i = 0; i < countS; ++i) _aoes.Add(new(smallShape, _stars[i].Position, default, activation)); _stars.Clear(); } @@ -102,25 +118,45 @@ private void ActivateAOE(AOEShape smallShape, AOEShape bigShape, WPos midpoint, public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID is OID.FrozenStar or OID.BurningStar) + if (actor.OID is ((uint)OID.FrozenStar) or ((uint)OID.BurningStar)) + { _stars.Add(actor); - if (!_tutorialIce && _stars.Count(x => (OID)x.OID == OID.FrozenStar) == 4) - Tutorial(donutSmall, ref _tutorialIce); - else if (!_tutorialFire && _stars.Count(x => (OID)x.OID == OID.BurningStar) == 5) - Tutorial(circleSmall, ref _tutorialFire); + + var frozenStarCount = 0; + var burningStarCount = 0; + + if (_tutorialIce && _tutorialFire) + return; + var count = _stars.Count; + for (var i = 0; i < count; ++i) + { + var star = _stars[i]; + if (star.OID == (uint)OID.FrozenStar) + ++frozenStarCount; + else if (star.OID == (uint)OID.BurningStar) + ++burningStarCount; + } + + if (!_tutorialIce && frozenStarCount == 4) + Tutorial(donutSmall, ref _tutorialIce); + else if (!_tutorialFire && burningStarCount == 5) + Tutorial(circleSmall, ref _tutorialFire); + } } private void Tutorial(AOEShape shape, ref bool tutorialFlag) { tutorialFlag = true; - for (var i = 0; i < _stars.Count; ++i) - _aoes.Add(new(shape, _stars[i].Position, default, WorldState.FutureTime(7.8f))); + var activation = WorldState.FutureTime(7.8d); + var count = _stars.Count; + for (var i = 0; i < count; ++i) + _aoes.Add(new(shape, _stars[i].Position, default, activation)); _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) + if (spell.Action.ID is (uint)AID.CircleOfIceAOE or (uint)AID.CircleOfIcePrimeAOE or (uint)AID.FireSphereAOE or (uint)AID.FireSpherePrime1) { _aoes.Clear(); ++NumCasts; @@ -144,10 +180,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, SortOrder = 10)] public class D063LahabreaIgeyorhm(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - public static readonly ArenaBoundsComplex arena = new([new Polygon(new(230, -181), 20.26f, 24)], [new Rectangle(new(230, -160), 20, 1.94f)]); + public static readonly ArenaBoundsComplex arena = new([new Polygon(new(230f, -181f), 20.26f, 24)], [new Rectangle(new(230f, -160f), 20f, 1.94f)]); protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.Igeyorhm)); + Arena.Actors(Enemies((uint)OID.Igeyorhm)); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs index 48ad41f281..89ffa83f3f 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D064AscianPrime.cs @@ -73,17 +73,6 @@ public enum AID : uint UniversalManipulation2 = 33044 // Boss->player, no cast, single-target } -public enum SID : uint -{ - AncientCircle = 3534, // none->player, extra=0x0 Player targeted donut AOE - AncientFrost = 3506, // none->player, extra=0x0 Stack marker - Bleeding = 2088, // Boss->player, extra=0x0 - BurningChains1 = 3505, // none->player, extra=0x0 - BurningChains2 = 769, // none->player, extra=0x0 - DarkWhispers = 3535, // none->player, extra=0x0 Spread marker - Untargetable = 2056 // Boss->Boss, extra=0x231, before limitbreak phase -} - public enum IconID : uint { AncientCircle = 384, // player @@ -96,63 +85,63 @@ public enum TetherID : uint BurningChains = 9 // player->player } -class AncientCircle(BossModule module) : Components.DonutStack(module, ActionID.MakeSpell(AID.AncientCircle), (uint)IconID.AncientCircle, 10, 20, 8, 4, 4); +class AncientCircle(BossModule module) : Components.DonutStack(module, ActionID.MakeSpell(AID.AncientCircle), (uint)IconID.AncientCircle, 10f, 20f, 8f, 4, 4); -class DarkWhispers(BossModule module) : Components.UniformStackSpread(module, 0, 6, alwaysShowSpreads: true) +class DarkWhispers(BossModule module) : Components.UniformStackSpread(module, default, 6f, alwaysShowSpreads: true) { // regular spread component won't work because this is self targeted public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { if (iconID == (uint)IconID.DarkWhispers) - AddSpread(actor, WorldState.FutureTime(5)); + AddSpread(actor, WorldState.FutureTime(5d)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.AncientDarkness) + if (Spreads.Count != 0 && spell.Action.ID == (uint)AID.AncientDarkness) Spreads.Clear(); } } -class AncientFrost(BossModule module) : Components.StackWithIcon(module, (uint)IconID.AncientFrost, ActionID.MakeSpell(AID.AncientFrost), 6, 5, 4, 4); +class AncientFrost(BossModule module) : Components.StackWithIcon(module, (uint)IconID.AncientFrost, ActionID.MakeSpell(AID.AncientFrost), 6f, 5f, 4, 4); class ShadowFlare(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.ShadowFlare1)); class ShadowFlareLBPhase(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.ShadowFlare2), "Raidwide x2"); class Annihilation(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.AnnihilationAOE)); class UniversalManipulation(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.UniversalManipulation), "Raidwide + Apply debuffs for later"); -class HeightOfChaos(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.HeightOfChaos), new AOEShapeCircle(5), true) +class HeightOfChaos(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.HeightOfChaos), new AOEShapeCircle(5f), true) { public override void AddGlobalHints(GlobalHints hints) { - if (CurrentBaits.Count > 0) + if (CurrentBaits.Count != 0) hints.Add("Tankbuster cleave"); } } -class AncientEruption(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientEruption), 5); +class AncientEruption(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientEruption), 5f); -abstract class ChillingCross(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCross(40, 2.5f)); +abstract class ChillingCross(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCross(40f, 2.5f)); class ChillingCross1(BossModule module) : ChillingCross(module, AID.ChillingCross1); class ChillingCross2(BossModule module) : ChillingCross(module, AID.ChillingCross2); -abstract class DarkBlizzard(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(41, 10.Degrees())); +abstract class DarkBlizzard(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(41f, 10f.Degrees())); class DarkBlizzardIIIAOE1(BossModule module) : DarkBlizzard(module, AID.DarkBlizzardIII1); class DarkBlizzardIIIAOE2(BossModule module) : DarkBlizzard(module, AID.DarkBlizzardIII2); class DarkBlizzardIIIAOE3(BossModule module) : DarkBlizzard(module, AID.DarkBlizzardIII3); class DarkBlizzardIIIAOE4(BossModule module) : DarkBlizzard(module, AID.DarkBlizzardIII4); class DarkBlizzardIIIAOE5(BossModule module) : DarkBlizzard(module, AID.DarkBlizzardIII5); -class DarkFireII(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.DarkFireII), 6); +class DarkFireII(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.DarkFireII), 6f); class BurningChains(BossModule module) : Components.Chains(module, (uint)TetherID.BurningChains, ActionID.MakeSpell(AID.BurningChains)); class EntropicFlame(BossModule module) : Components.LineStack(module, ActionID.MakeSpell(AID.EntropicFlame), ActionID.MakeSpell(AID.EntropicFlame3), 5.2f); 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 _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); + private static readonly AOEShapeDonut donut = new(5f, 40f); + private static readonly AOEShapeCircle circle = new(16f); + private readonly List _aoes = new(3); + private static readonly WPos _frozenStarShortTether = new(230f, 86f), _frozenStarLongTether = new(230f, 92f); + private static readonly WPos _donut = WPos.ClampToGrid(new(230f, 79f)), _circle1 = WPos.ClampToGrid(new(241f, 79f)), _circle2 = WPos.ClampToGrid(new(219f, 79f)); public override IEnumerable ActiveAOEs(int slot, Actor actor) { @@ -163,7 +152,7 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) for (var i = 0; i < count; ++i) { var aoe = _aoes[i]; - if ((aoe.Activation - _aoes[0].Activation).TotalSeconds <= 1) + if ((aoe.Activation - _aoes[0].Activation).TotalSeconds <= 1d) aoes.Add(aoe); } return aoes; @@ -171,32 +160,29 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) public override void OnActorCreated(Actor actor) { - var activation1 = WorldState.FutureTime(11.8f); - var activation2 = WorldState.FutureTime(14.8f); - if ((OID)actor.OID == OID.FrozenStar) + void AddAOEs(bool reverse) + { + AddAOE(circle, _circle1, !reverse); + AddAOE(circle, _circle2, !reverse); + AddAOE(donut, _donut, reverse); + if (reverse) + _aoes.Reverse(); + void AddAOE(AOEShape shape, WPos pos, bool first) => _aoes.Add(new(shape, pos, default, WorldState.FutureTime(first ? 11.8d : 14.8f))); + } + + if (actor.OID == (uint)OID.FrozenStar) { if (actor.Position == _frozenStarLongTether) - { - _aoes.Add(new(circle, _circle1, default, activation1)); - _aoes.Add(new(circle, _circle2, default, activation1)); - _aoes.Add(new(donut, _donut, default, activation2)); - } + AddAOEs(false); else if (actor.Position == _frozenStarShortTether) - { - _aoes.Add(new(donut, _donut, default, activation1)); - _aoes.Add(new(circle, _circle1, default, activation2)); - _aoes.Add(new(circle, _circle2, default, activation2)); - } + AddAOEs(true); } } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.CircleOfIcePrime or AID.FireSpherePrime) - { - ++NumCasts; + if (_aoes.Count != 0 && spell.Action.ID is (uint)AID.CircleOfIcePrime or (uint)AID.FireSpherePrime) _aoes.RemoveAt(0); - } } } @@ -231,11 +217,11 @@ 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, SortOrder = 11)] public class D064AscianPrime(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - 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)]); + public static readonly ArenaBoundsComplex arena = new([new Polygon(new(230f, 79f), 20.26f, 24)], [new Rectangle(new(230f, 98f), 5, 1.5f)], [new Rectangle(new(228.95f, 97f), 6.55f, 1.7f)]); protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.ArcaneSphere)); + Arena.Actors(Enemies((uint)OID.ArcaneSphere)); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs index 4b16c92c03..f2314662e8 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130BlizzardDragon.cs @@ -24,7 +24,7 @@ class BridgeCreation(BossModule module) : BossComponent(module) { public override void OnActorEAnim(Actor actor, uint state) { - if (state == 0x00040008 && (OID)actor.OID == OID.Bridge) + if (state == 0x00040008 && actor.OID == (uint)OID.Bridge) { Arena.Bounds = D130BlizzardDragon.Arena2; Arena.Center = D130BlizzardDragon.Arena2.Center; @@ -34,27 +34,27 @@ public override void OnActorEAnim(Actor actor, uint state) class Touchdown(BossModule module) : Components.GenericAOEs(module) { - private static readonly AOEShapeCircle circle = new(10); + private static readonly AOEShapeCircle circle = new(10f); 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.Cauterize) + if (spell.Action.ID == (uint)AID.Cauterize) _aoe = new(circle, new(364.523f, -225.727f), default, Module.CastFinishAt(spell, 6.7f)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.Touchdown) + if (spell.Action.ID == (uint)AID.Touchdown) _aoe = null; } } -class Cauterize(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cauterize), new AOEShapeRect(53, 10)); -class Fireball(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Fireball), 4); -class SheetOfIce(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SheetOfIce), 5); +class Cauterize(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cauterize), new AOEShapeRect(53f, 10f)); +class Fireball(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Fireball), 4f); +class SheetOfIce(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SheetOfIce), 5f); class D130BlizzardDragonStates : StateMachineBuilder { @@ -66,7 +66,18 @@ public D130BlizzardDragonStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(OID.BlizzardDragon1).Any(x => x.IsDead) || module.PrimaryActor.IsDestroyed; + .Raw.Update = () => + { + var enemies = module.Enemies((uint)OID.BlizzardDragon1); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDead) + return false; + } + return module.PrimaryActor.IsDestroyed; + }; } } @@ -131,7 +142,18 @@ public class D130BlizzardDragon(WorldState ws, Actor primary) : BossModule(ws, p public static readonly uint[] Trash = [(uint)OID.HolyWyvern, (uint)OID.BlizzardDragon1]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs index 92df9ddaf9..37b1ffd59c 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs @@ -23,10 +23,10 @@ public enum AID : uint DarkBlizzardIII = 6236, // Boss->location, 3.0s cast, range 5 circle } -class RiseAndFall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RiseAndFall), new AOEShapeCone(9, 135.Degrees())); -class TightTornado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TightTornado), new AOEShapeRect(18, 2)); -class Venom(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Venom), new AOEShapeCone(10.9f, 60.Degrees()), [(uint)OID.SanctuarySkipper]); -class DarkBlizzardIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DarkBlizzardIII), 5); +class RiseAndFall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RiseAndFall), new AOEShapeCone(9f, 135f.Degrees())); +class TightTornado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TightTornado), new AOEShapeRect(18f, 2f)); +class Venom(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Venom), new AOEShapeCone(10.9f, 60f.Degrees()), [(uint)OID.SanctuarySkipper]); +class DarkBlizzardIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DarkBlizzardIII), 5f); class D130CloudGardenerStates : StateMachineBuilder { @@ -37,14 +37,27 @@ public D130CloudGardenerStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D130CloudGardener.Trash).Where(x => x.Position.AlmostEqual(module.Arena.Center, module.Bounds.Radius)).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D130CloudGardener.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 171, NameID = 4928, SortOrder = 1)] public class D130CloudGardener(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? arena1.Center : arena2.Center, IsArena1(primary) ? arena1 : arena2) { - private static bool IsArena1(Actor primary) => primary.Position.Z > 80; + private static bool IsArena1(Actor primary) => primary.Position.Z > 80f; private static readonly WPos[] vertices1 = [new(-397.21f, 80.53f), new(-396.7f, 80.92f), new(-395.75f, 81.87f), new(-395.65f, 83.98f), new(-395.55f, 84.54f), new(-393.56f, 84.66f), new(-392.7f, 84.66f), new(-392.24f, 84.41f), new(-392.2f, 82.13f), new(-384.32f, 81.86f), new(-383.38f, 82.76f), new(-383.32f, 83.44f), new(-383.42f, 84.07f), new(-383.54f, 84.69f), new(-383.68f, 85.35f), @@ -160,15 +173,27 @@ public class D130CloudGardener(WorldState ws, Actor primary) : BossModule(ws, pr protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - if ((OID)e.Actor.OID == OID.Boss) + if (e.Actor.OID == (uint)OID.Boss) { e.Priority = 0; } diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130Kargas.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130Kargas.cs index 94a6a3ab7d..b962ec3e91 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130Kargas.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130Kargas.cs @@ -5,7 +5,7 @@ public enum OID : uint Boss = 0x160E, // R2.875 SanctuaryTsanahale = 0x160F, // R1.2 SohrKhaiAnzu = 0x160C, // R3.6 - SohrKhaiCockerel = 0x160A, // R0.4 + SohrKhaiCockerel = 0x160A // R0.4 } public enum AID : uint @@ -15,11 +15,11 @@ public enum AID : uint BreathWing = 6107, // SohrKhaiAnzu->self, 4.0s cast, range 50 circle GoldenTalons = 4690, // Boss->player, no cast, single-target - WingsOfWoe = 2478, // SanctuaryTsanahale->location, 2.5s cast, range 6 circle + WingsOfWoe = 2478 // SanctuaryTsanahale->location, 2.5s cast, range 6 circle } class BreathWing(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.BreathWing)); -class WingsOfWoe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WingsOfWoe), 6); +class WingsOfWoe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WingsOfWoe), 6f); class D130KargasStates : StateMachineBuilder { @@ -28,7 +28,18 @@ public D130KargasStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(D130Kargas.Trash).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D130Kargas.Trash); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -88,7 +99,20 @@ public class D130Kargas(WorldState ws, Actor primary) : BossModule(ws, primary, public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.SohrKhaiAnzu, (uint)OID.SohrKhaiCockerel, (uint)OID.SanctuaryTsanahale]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D131ChieftainMoglin.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D131ChieftainMoglin.cs index 3a70e0c1bc..39082006b0 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D131ChieftainMoglin.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D131ChieftainMoglin.cs @@ -44,37 +44,37 @@ public enum SID : uint class PomBom(BossModule module) : Components.GenericAOEs(module) { - private static readonly AOEShapeCross cross = new(40.5f, 2); + private static readonly AOEShapeCross cross = new(40.5f, 2f); private AOEInstance? _aoe; public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.DemoniacalMogcane) - _aoe = new(cross, actor.Position, default, WorldState.FutureTime(6.3f)); + if (actor.OID == (uint)OID.DemoniacalMogcane) + _aoe = new(cross, WPos.ClampToGrid(actor.Position), default, WorldState.FutureTime(6.3d)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.PomBom) + if (spell.Action.ID == (uint)AID.PomBom) _aoe = null; } } -class ThousandKuponzeCharge(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ThousandKuponzeCharge), new AOEShapeCone(9.8f, 60.Degrees())) +class ThousandKuponzeCharge(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ThousandKuponzeCharge), new AOEShapeCone(9.8f, 60f.Degrees())) { private bool active = true; // cleave happens near the start of the fight then again after every demoniacal mogcane cast public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.DemoniacalMogcane) + if (spell.Action.ID == (uint)AID.DemoniacalMogcane) active = true; } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.ThousandKuponzeCharge) + if (spell.Action.ID == (uint)AID.ThousandKuponzeCharge) active = false; } @@ -100,36 +100,61 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) class PomPraise(BossModule module) : BossComponent(module) { private readonly List positions = []; - public IEnumerable RelevantMoogles = []; + public List RelevantMoogles = []; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.PomPraise) + if (spell.Action.ID == (uint)AID.PomPraise) positions.Add(spell.LocXZ); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.PomPraiseVisual) + if (spell.Action.ID == (uint)AID.PomPraiseVisual) + { positions.Clear(); + RelevantMoogles.Clear(); + } } public override void Update() { - if (positions.Count != 0) // it is assumed that the moogle hitbox must not intersect the circle, as usual for NPCs - RelevantMoogles = Module.Enemies(D131ChieftainMoglin.SmallMoogles).Where(e => e.FindStatus(SID.OffBalance) != null && positions.Any(p => e.Position.InCircle(p, 4.9f))); + var countP = positions.Count; + if (countP != 0) // it is assumed that the moogle hitbox must not intersect the circle, as usual for NPCs + { + var smallMoogles = Module.Enemies(D131ChieftainMoglin.SmallMoogles); + var count = smallMoogles.Count; + var relevantMoogles = new List(count); + for (var i = 0; i < count; ++i) + { + var moogle = smallMoogles[i]; + if (moogle.FindStatus((uint)SID.OffBalance) != null) + { + for (var j = 0; j < countP; ++j) + { + if (moogle.Position.InCircle(positions[j], 4.9f)) + { + relevantMoogles.Add(moogle); + break; + } + } + } + } + RelevantMoogles = relevantMoogles; + } } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (positions.Count != 0) + if (RelevantMoogles.Count != 0) { - foreach (var r in RelevantMoogles) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { - var target = hints.PotentialTargets.FirstOrDefault(x => x.Actor == r); - if (target != null) + var t = hints.PotentialTargets[i]; + if (RelevantMoogles.Contains(t.Actor)) { - target.Priority = 3; + t.Priority = 3; } } } @@ -137,19 +162,22 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme public override void AddHints(int slot, Actor actor, TextHints hints) { - if (RelevantMoogles.Any()) + if (RelevantMoogles.Count != 0) hints.Add("Push defeated moogles out of circles!"); } public override void DrawArenaForeground(int pcSlot, Actor pc) { - if (RelevantMoogles.Any()) - for (var i = 0; i < positions.Count; ++i) + if (RelevantMoogles.Count != 0) + { + var count = positions.Count; + for (var i = 0; i < count; ++i) Arena.AddCircle(positions[i], 4.9f, Colors.Vulnerable); + } } } -class HundredKuponzeSwipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HundredKuponzeSwipe), new AOEShapeCone(20.9f, 45.Degrees())); +class HundredKuponzeSwipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HundredKuponzeSwipe), new AOEShapeCone(20.9f, 45f.Degrees())); class PomFlare(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PomFlare), 20.9f); class PomHoly(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.PomHoly)); class SpinningMogshield(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinningMogshield), 6.9f); @@ -172,38 +200,53 @@ public D131ChieftainMoglinStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 171, NameID = 4943, SortOrder = 2)] public class D131ChieftainMoglin(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-400, -158.04f), 19.5f * CosPI.Pi60th, 64)], [new Rectangle(new(-400, -138), 20, 1.05f), - new Rectangle(new(-400, -178), 20, 0.8f)]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-400f, -158.04f), 19.5f * CosPI.Pi60th, 64)], [new Rectangle(new(-400f, -138f), 20f, 1.05f), + new Rectangle(new(-400f, -178f), 20f, 0.8f)]); public static readonly uint[] SmallMoogles = [(uint)OID.CaptainMogsun, (uint)OID.PomguardPomfluffer, (uint)OID.PomguardPomfryer, (uint)OID.PomguardPompincher, (uint)OID.PomguardPomchopper, (uint)OID.PomguardPompiercer, (uint)OID.PomguardPomcrier]; protected override void DrawEnemies(int pcSlot, Actor pc) { - if (PrimaryActor.FindStatus(SID.Invincibility) == null) + if (PrimaryActor.FindStatus((uint)SID.Invincibility) == null) Arena.Actor(PrimaryActor); var smallmoogles = Enemies(SmallMoogles); - Arena.Actors(smallmoogles.Where(x => x.FindStatus(SID.OffBalance) == null)); - Arena.Actors(smallmoogles.Where(x => x.FindStatus(SID.OffBalance) != null), Colors.Vulnerable); + var count = smallmoogles.Count; + List balancedMoogles = new(count); + List offBalanceMoogles = new(count); + for (var i = 0; i < count; ++i) + { + var moogle = smallmoogles[i]; + if (moogle.FindStatus((uint)SID.OffBalance) == null) + balancedMoogles.Add(moogle); + else + offBalanceMoogles.Add(moogle); + } + Arena.Actors(balancedMoogles); + Arena.Actors(offBalanceMoogles, Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (!FindComponent()!.RelevantMoogles.Any()) - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + if (FindComponent()?.RelevantMoogles.Count == 0) + { + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - if (e.Actor.FindStatus(SID.Invincibility) != null) + if (e.Actor.FindStatus((uint)SID.Invincibility) != null) { e.Priority = AIHints.Enemy.PriorityInvincible; continue; } - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.CaptainMogsun => 2, - OID.PomguardPomfluffer or OID.PomguardPomfryer or OID.PomguardPomcrier or OID.PomguardPompincher or OID.PomguardPompiercer or OID.PomguardPomchopper => 1, + (uint)OID.CaptainMogsun => 2, + (uint)OID.PomguardPomfluffer or (uint)OID.PomguardPomfryer or (uint)OID.PomguardPomcrier or + (uint)OID.PomguardPompincher or (uint)OID.PomguardPompiercer or (uint)OID.PomguardPomchopper => 1, _ => 0 }; } + } } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D132Poqhiraj.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D132Poqhiraj.cs index 7cac1e294f..0c4a48db3d 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D132Poqhiraj.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D132Poqhiraj.cs @@ -40,20 +40,21 @@ class ArenaChanges(BossModule module) : BossComponent(module) { private readonly GallopKB _kb = module.FindComponent()!; private static readonly float[] xPositions = [395.25f, 404.75f]; - private static readonly WPos[] wallPositions = new WPos[8]; + private static readonly WPos[] wallPositions = WallPositionz(); private readonly List removedWalls = []; private static readonly Rectangle[] baseArena = [new(D132Poqhiraj.ArenaCenter, 4.5f, 19.75f)]; - private static readonly WDir offset = new(0, 0.125f); + private static readonly WDir offset = new(default, 0.125f); - static ArenaChanges() + private static WPos[] WallPositionz() { const float zStart = 89.161f; const int zStep = 10; var index = 0; - + var walls = new WPos[8]; for (var i = 0; i < 2; ++i) for (var j = 0; j < 4; ++j) - wallPositions[index++] = new(xPositions[i], zStart + j * zStep); + walls[index++] = new(xPositions[i], zStart + j * zStep); + return walls; } public override void OnActorEAnim(Actor actor, uint state) @@ -61,36 +62,36 @@ public override void OnActorEAnim(Actor actor, uint state) if (state != 0x00100020) return; - var wallIndex = (OID)actor.OID switch + var wallIndex = actor.OID switch { - OID.WallHelperNW1 => 0, - OID.WallHelperNE1 => 4, - OID.WallHelperNW2 => 1, - OID.WallHelperNE2 => 5, - OID.WallHelperSW1 => 2, - OID.WallHelperSE1 => 6, - OID.WallHelperSW2 => 3, - OID.WallHelperSE2 => 7, + (uint)OID.WallHelperNW1 => 0, + (uint)OID.WallHelperNE1 => 4, + (uint)OID.WallHelperNW2 => 1, + (uint)OID.WallHelperNE2 => 5, + (uint)OID.WallHelperSW1 => 2, + (uint)OID.WallHelperSE1 => 6, + (uint)OID.WallHelperSW2 => 3, + (uint)OID.WallHelperSE2 => 7, _ => default }; var wallPos = wallPositions[wallIndex]; var adjustment = wallIndex is 0 or 4 ? offset : wallIndex is 3 or 7 ? -offset : default; - removedWalls.Add(new(wallPos + adjustment, 0.25f, adjustment != default ? 4.875f : 5)); - _kb.safeWalls.RemoveAll(x => x.Vertex1 == new WPos(GallopKB.xPositions[wallIndex / 4], wallPos.Z - 5)); + removedWalls.Add(new(wallPos + adjustment, 0.25f, adjustment != default ? 4.875f : 5f)); + _kb.safeWalls.RemoveAll(x => x.Vertex1 == new WPos(GallopKB.xPositions[wallIndex / 4], wallPos.Z - 5f)); ArenaBoundsComplex arena = new([.. baseArena, .. removedWalls]); Arena.Bounds = arena; Arena.Center = arena.Center; } } -class GallopAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GallopAOE), new AOEShapeRect(40.5f, 1)); +class GallopAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GallopAOE), new AOEShapeRect(40.5f, 1f)); class GallopKB(BossModule module) : Components.Knockback(module) { public static readonly float[] xPositions = [395.5f, 404.5f]; - private static readonly AOEShapeRect rect = new(4.5f, 20); - private readonly List _sources = []; + private static readonly AOEShapeRect rect = new(4.5f, 20f); + private readonly List _sources = new(2); public readonly List safeWalls = GenerateSafeWalls(); private static List GenerateSafeWalls() @@ -98,11 +99,11 @@ private static List GenerateSafeWalls() const float zStart = 89.161f; const int zStep = 10; - List list = []; + List list = new(8); for (var i = 0; i < 2; ++i) for (var j = 0; j < 4; ++j) - list.Add(new(new(xPositions[i], zStart + j * zStep - 5), new(xPositions[i], zStart + j * zStep + 5))); + list.Add(new(new(xPositions[i], zStart + j * zStep - 5f), new(xPositions[i], zStart + j * zStep + 5f))); return list; } @@ -110,13 +111,13 @@ private static List GenerateSafeWalls() public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.GallopKB) - _sources.Add(new(spell.LocXZ, 30, Module.CastFinishAt(spell), rect, spell.Rotation, Kind.DirForward, default, safeWalls)); + if (spell.Action.ID == (uint)AID.GallopKB) + _sources.Add(new(spell.LocXZ, 30f, Module.CastFinishAt(spell), rect, spell.Rotation, Kind.DirForward, default, safeWalls)); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.GallopKB) + if (spell.Action.ID == (uint)AID.GallopKB) _sources.Clear(); } } @@ -124,7 +125,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) class GallopKBHint(BossModule module) : Components.GenericAOEs(module) { private readonly GallopKB _kb = module.FindComponent()!; - private const string Risk2Hint = "Walk into safespot for knockback!"; + private const string Hint = "Walk into safespot for knockback!"; private static readonly Angle[] angles = [-89.982f.Degrees(), 89.977f.Degrees()]; private AOEInstance? _aoe; @@ -133,7 +134,7 @@ class GallopKBHint(BossModule module) : Components.GenericAOEs(module) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if (_aoe == null && (AID)spell.Action.ID == AID.GallopKB) + if (_aoe == null && spell.Action.ID == (uint)AID.GallopKB) { var count = _kb.safeWalls.Count; if (count is 0 or 8) @@ -143,8 +144,8 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) { var safeWall = _kb.safeWalls[i].Vertex1; var dir = (safeWall.X == GallopKB.xPositions[0] ? angles[0] : angles[1]).ToDirection(); - var pos = new WPos(safeWall.X, safeWall.Z + 5); - rects.Add(new(pos + dir, pos - 3.5f * dir, 5)); + var pos = new WPos(safeWall.X, safeWall.Z + 5f); + rects.Add(new(pos + dir, pos - 3.5f * dir, 5f)); } AOEShapeCustom aoe = new([.. rects], InvertForbiddenZone: true); _aoe = new(aoe, Arena.Center, default, Module.CastFinishAt(spell), Colors.SafeFromAOE, true); @@ -153,68 +154,74 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.GallopKB) + if (spell.Action.ID == (uint)AID.GallopKB) _aoe = null; } public override void AddHints(int slot, Actor actor, TextHints hints) { - if (_aoe != null) + if (_aoe is AOEInstance aoe) { - if (!ActiveAOEs(slot, actor).Any(c => c.Check(actor.Position))) - hints.Add(Risk2Hint); + var check = true; + if (aoe.Check(actor.Position)) + check = false; + hints.Add(Hint, check); } } } -class Touchdown(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TouchdownVisual), 25); +class Touchdown(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TouchdownVisual), 25f); -class BurningBright(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.BurningBright), new AOEShapeRect(28.5f, 3), endsOnCastEvent: true) +class BurningBright(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.BurningBright), new AOEShapeRect(28.5f, 3f), endsOnCastEvent: true) { public override void DrawArenaForeground(int pcSlot, Actor pc) { base.DrawArenaForeground(pcSlot, pc); - if (!ActiveBaits.Any(x => x.Target == pc)) - return; - var walls = Module.Enemies(OID.PrayerWall); - for (var i = 0; i < walls.Count; ++i) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == pc) { - var a = walls[i]; - Arena.AddCircle(a.Position, a.HitboxRadius, Colors.Danger); + var walls = Module.Enemies((uint)OID.PrayerWall); + var count = walls.Count; + for (var i = 0; i < count; ++i) + { + var a = walls[i]; + Arena.AddCircle(a.Position, a.HitboxRadius, Colors.Danger); + } } } public override void AddHints(int slot, Actor actor, TextHints hints) { - if (CurrentBaits.Any(x => x.Target != actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) base.AddHints(slot, actor, hints); - else if (CurrentBaits.Any(x => x.Target == actor)) + else hints.Add("Bait away, avoid intersecting wall hitboxes!"); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - var bait = ActiveBaitsOn(actor).FirstOrDefault(); - if (bait == default) - return; - var walls = Module.Enemies(OID.PrayerWall); - var count = walls.Count; - if (count <= 4) // don't care if most walls are up plus most of the arena would likely be forbidden anyway depending on player positioning + if (CurrentBaits.Count != 0 && CurrentBaits[0] is var bait && bait.Target == actor) { - var forbidden = new List>(); - for (var i = 0; i < count; ++i) + var walls = Module.Enemies((uint)OID.PrayerWall); + var count = walls.Count; + if (count <= 4) // don't care if most walls are up plus most of the arena would likely be forbidden anyway depending on player positioning { - var a = walls[i]; - forbidden.Add(ShapeDistance.Cone(bait.Source.Position, 100, bait.Source.AngleTo(a), Angle.Asin(8 / (a.Position - bait.Source.Position).Length()))); + var forbidden = new Func[count]; + for (var i = 0; i < count; ++i) + { + var a = walls[i]; + forbidden[i] = ShapeDistance.Cone(bait.Source.Position, 100f, bait.Source.AngleTo(a), Angle.Asin(8f / (a.Position - bait.Source.Position).Length())); + } + if (forbidden.Length != 0) + hints.AddForbiddenZone(ShapeDistance.Union(forbidden), bait.Activation); } - if (forbidden.Count != 0) - hints.AddForbiddenZone(ShapeDistance.Union(forbidden), bait.Activation); } } } -class RearHoof(BossModule module) : Components.SingleTargetInstant(module, ActionID.MakeSpell(AID.RearHoof), 4) +class RearHoof(BossModule module) : Components.SingleTargetInstant(module, ActionID.MakeSpell(AID.RearHoof), 4f) { private bool start, firstKB; @@ -222,74 +229,77 @@ public override void Update() { if (!start) { - Targets.Add((Raid.FindSlot(Module.PrimaryActor.TargetID), WorldState.FutureTime(6.1f))); // its assumed that the tank will aggro the boss first + Targets.Add((Raid.FindSlot(Module.PrimaryActor.TargetID), WorldState.FutureTime(6.1d))); // its assumed that the tank will aggro the boss first start = true; } } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if (!firstKB && (AID)spell.Action.ID == AID.GallopKB) + if (!firstKB && spell.Action.ID == (uint)AID.GallopKB) { - Targets.Add((Raid.FindSlot(Module.PrimaryActor.TargetID), WorldState.FutureTime(7))); + Targets.Add((Raid.FindSlot(Module.PrimaryActor.TargetID), WorldState.FutureTime(7d))); firstKB = true; } } public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.DarkCloud) - Targets.Add((Raid.FindSlot(actor.InstanceID), WorldState.FutureTime(4))); + if (actor.OID == (uint)OID.DarkCloud) + Targets.Add((Raid.FindSlot(actor.InstanceID), WorldState.FutureTime(4d))); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.RearHoof) + if (spell.Action.ID == (uint)AID.RearHoof) Targets.Clear(); } } class CloudCall(BossModule module) : Components.GenericBaitAway(module) { - public static readonly AOEShapeCircle Circle = new(8); + public static readonly AOEShapeCircle Circle = new(8f); public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { if (iconID == (uint)IconID.CloudCall) - CurrentBaits.Add(new(actor, actor, Circle, WorldState.FutureTime(4.9f))); + CurrentBaits.Add(new(actor, actor, Circle, WorldState.FutureTime(4.9d))); } public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.DarkCloud) + if (actor.OID == (uint)OID.DarkCloud) CurrentBaits.Clear(); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (CurrentBaits.Any(x => x.Target == actor)) - hints.AddForbiddenZone(ShapeDistance.Rect(Arena.Center, new WDir(0, 1), 19, 19, 5)); + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == actor) + hints.AddForbiddenZone(ShapeDistance.Rect(Arena.Center, new WDir(default, 1f), 19f, 19f, 5f)); } public override void AddHints(int slot, Actor actor, TextHints hints) { - if (CurrentBaits.Any(x => x.Target != actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) base.AddHints(slot, actor, hints); - else if (CurrentBaits.Any(x => x.Target == actor)) + else hints.Add("Bait cloud away, avoid intersecting wall hitboxes!"); } public override void DrawArenaForeground(int pcSlot, Actor pc) { base.DrawArenaForeground(pcSlot, pc); - if (!ActiveBaits.Any(x => x.Target == pc)) - return; - var walls = Module.Enemies(OID.PrayerWall); - for (var i = 0; i < walls.Count; ++i) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == pc) { - var a = walls[i]; - Arena.AddCircle(a.Position, a.HitboxRadius, Colors.Danger); + var walls = Module.Enemies((uint)OID.PrayerWall); + for (var i = 0; i < walls.Count; ++i) + { + var a = walls[i]; + Arena.AddCircle(a.Position, a.HitboxRadius); + } } } } @@ -302,13 +312,13 @@ class LightningBolt(BossModule module) : Components.GenericAOEs(module) public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.DarkCloud) - _aoe = new(CloudCall.Circle, actor.Position, default, WorldState.FutureTime(7.8f)); + if (actor.OID == (uint)OID.DarkCloud) + _aoe = new(CloudCall.Circle, actor.Position, default, WorldState.FutureTime(7.8d)); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.LightningBolt) + if (spell.Action.ID == (uint)AID.LightningBolt) _aoe = null; } } @@ -333,5 +343,5 @@ public D132PoqhirajStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 171, NameID = 4952, SortOrder = 4)] public class D132Poqhiraj(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaCenter, new ArenaBoundsRect(4.5f, 19.75f)) { - public static readonly WPos ArenaCenter = new(400, 104.166f); + public static readonly WPos ArenaCenter = new(400f, 104.166f); } diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs index 037ec6c2cd..af7e191514 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D133Hraesvelgr.cs @@ -31,7 +31,7 @@ public enum IconID : uint Spreadmarker = 311 // player->self } -abstract class HallowedWings(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(50, 11)); +abstract class HallowedWings(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(50f, 11f)); class HallowedWings1(BossModule module) : HallowedWings(module, AID.HallowedWings1); class HallowedWings2(BossModule module) : HallowedWings(module, AID.HallowedWings2); @@ -39,26 +39,26 @@ class Wyrmclaw(BossModule module) : Components.SingleTargetCast(module, ActionID class HolyStorm(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.HolyStorm)); class DiamondStorm(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.DiamondStorm)); -abstract class Dive(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40, 10)); +abstract class Dive(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40f, 10f)); class HallowedDive(BossModule module) : Dive(module, AID.HallowedDive); class FrigidDive(BossModule module) : Dive(module, AID.FrigidDive); -class FrostedOrb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrostedOrb), 6); +class FrostedOrb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrostedOrb), 6f); -class AkhMorn(BossModule module) : Components.UniformStackSpread(module, 6, 0, 4, 4) +class AkhMorn(BossModule module) : Components.UniformStackSpread(module, 6f, default, 4, 4) { private int numCasts; private bool first = true; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.AkhMornFirst) + if (spell.Action.ID == (uint)AID.AkhMornFirst) AddStack(WorldState.Actors.Find(spell.TargetID)!, Module.CastFinishAt(spell)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID is AID.AkhMornFirst or AID.AkhMornRest) + if (spell.Action.ID is (uint)AID.AkhMornFirst or (uint)AID.AkhMornRest) { ++numCasts; if (first && numCasts == 5 || numCasts == 6) @@ -75,13 +75,13 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.HolyOrbFirst) - Lines.Add(new() { Next = spell.LocXZ, Advance = caster.Rotation.ToDirection() * 6.8f, NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1, ExplosionsLeft = 5, MaxShownExplosions = 3 }); + if (spell.Action.ID == (uint)AID.HolyOrbFirst) + Lines.Add(new() { Next = caster.Position, Advance = caster.Rotation.ToDirection() * 6.8f, NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1f, ExplosionsLeft = 5, MaxShownExplosions = 3 }); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID is AID.HolyOrbFirst or AID.HolyOrbRest) + if (spell.Action.ID is (uint)AID.HolyOrbFirst or (uint)AID.HolyOrbRest) { var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1)); if (index < 0) @@ -93,12 +93,26 @@ 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 HolyBreath(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.Spreadmarker, ActionID.MakeSpell(AID.HolyBreath), 6f, 6f); -class ThinIce(BossModule module) : Components.ThinIce(module, 11, true, stopAtWall: true) +class ThinIce(BossModule module) : Components.ThinIce(module, 11f, 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); + private readonly FrostedOrb _aoe1 = module.FindComponent()!; + private readonly FrigidDive _aoe2 = module.FindComponent()!; + + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + if (_aoe2.Casters.Count != 0 && _aoe2.Casters[0].Check(pos)) + return true; + var count = _aoe1.Casters.Count; + for (var i = 0; i < count; ++i) + { + var aoe = _aoe1.Casters[i]; + if (aoe.Check(pos)) + return true; + } + return false; + } } class D133HraesvelgrStates : StateMachineBuilder @@ -124,5 +138,5 @@ public D133HraesvelgrStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 171, NameID = 4954, SortOrder = 6)] public class D133Hraesvelgr(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly ArenaBoundsComplex arena = new([new Polygon(new(400, -400), 19.5f, 36)]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(400f, -400f), 19.5f, 36)]); } \ No newline at end of file diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150ChasmHarpeia.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150ChasmHarpeia.cs index 5a3d6a54c5..fd20221159 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150ChasmHarpeia.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150ChasmHarpeia.cs @@ -26,10 +26,10 @@ public enum AID : uint WildRattle = 408, // ChasmCobra->player, no cast, single-target } -class FlashFlood(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlashFlood), new AOEShapeCone(8.16f, 60.Degrees())); +class FlashFlood(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlashFlood), new AOEShapeCone(8.16f, 60f.Degrees())); class LaboredLeap(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LaboredLeap), 10.32f); -class FallenRock(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock), 4); -class WingsOfWoe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WingsOfWoe), 6); +class FallenRock(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock), 4f); +class WingsOfWoe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WingsOfWoe), 6f); class D150ChasmHarpeiaStates : StateMachineBuilder { @@ -40,15 +40,27 @@ public D150ChasmHarpeiaStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D150ChasmHarpeia.Trash).Where(x => x.Position.AlmostEqual(Module.Arena.Center, Module.Bounds.Radius)) - .All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D150ChasmHarpeia.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 182, NameID = 5253, SortOrder = 1)] public class D150ChasmHarpeia(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? arena1.Center : arena2.Center, IsArena1(primary) ? arena1 : arena2) { - private static bool IsArena1(Actor primary) => primary.Position.X < -130; + private static bool IsArena1(Actor primary) => primary.Position.X < -130f; private static readonly WPos[] vertices1 = [new(-116.6f, 153.39f), new(-116.25f, 153.86f), new(-114.35f, 154.36f), new(-113.7f, 154.48f), new(-111.05f, 154.59f), new(-110.39f, 154.71f), new(-106.02f, 160.42f), new(-106.51f, 160.64f), new(-106.66f, 161.15f), new(-105.65f, 165.95f), new(-105.49f, 166.42f), new(-106.31f, 170.45f), new(-106.4f, 171.14f), new(-106.59f, 171.61f), new(-106.97f, 172.2f), @@ -194,10 +206,34 @@ public class D150ChasmHarpeia(WorldState ws, Actor primary) : BossModule(ws, pri private static readonly ArenaBoundsComplex arena2 = new([new PolygonCustom(vertices2)]); public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.ChasmCobra, (uint)OID.VelodynaToad, (uint)OID.AbalathianSlug, (uint)OID.SwiftwaterHakulaq]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150SiegeGobbue.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150SiegeGobbue.cs index 0c1488bc62..301c4789db 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150SiegeGobbue.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150SiegeGobbue.cs @@ -23,16 +23,16 @@ public enum AID : uint class ArenaChange(BossModule module) : Components.GenericAOEs(module) { private const int Vertices = 8; - private const int InnerRadius = 11; - private const int OuterRadius = 16; // 15.5 if adjusted for hitbox radius, but not needed here + private const float InnerRadius = 11f; + private const float OuterRadius = 16f; // 15.5 if adjusted for hitbox radius, but not needed here private static readonly Angle a225 = 22.5f.Degrees(); - private static readonly WPos arena1center = new(70.5f, -56); + private static readonly WPos arena1center = new(70.5f, -56f); private static readonly WPos arena2center = new(178.083f, -4.225f); private static readonly PolygonCustom verticesDiff1 = new([new(62.562f, -68.197f), new(58.33f, -63.967f), new(59.195f, -63.239f), new(63.214f, -63.273f), new(63.267f, -67.123f)]); private static readonly PolygonCustom verticesDiff2 = new([new(181.034f, -18.5f), new(175.119f, -18.5f), new(175.522f, -17.112f), new(178.095f, -14.489f), new(180.889f, -17.318f)]); - private static readonly Shape[] difference1 = [new Polygon(arena1center, InnerRadius, Vertices, a225), verticesDiff1, new Rectangle(new(59, -67.5f), 10, 2.1f, 135.Degrees())]; + private static readonly Shape[] difference1 = [new Polygon(arena1center, InnerRadius, Vertices, a225), verticesDiff1, new Rectangle(new(59f, -67.5f), 10f, 2.1f, 135f.Degrees())]; private static readonly Shape[] difference2 = [new Polygon(arena2center, InnerRadius, Vertices, a225), verticesDiff2]; private static readonly AOEShapeCustom poly1 = new([new Polygon(arena1center, OuterRadius, Vertices, a225)], difference1); private static readonly AOEShapeCustom poly2 = new([new Polygon(arena2center, OuterRadius, Vertices, a225)], difference2); @@ -42,19 +42,19 @@ class ArenaChange(BossModule module) : Components.GenericAOEs(module) public override void OnActorNpcYell(Actor actor, ushort id) { - if (_aoe == null && actor.Position.Z < -10) - _aoe = new(poly1, Arena.Center, default, WorldState.FutureTime(4)); + if (_aoe == null && actor.Position.Z < -10f) + _aoe = new(poly1, Arena.Center, default, WorldState.FutureTime(4d)); } public override void Update() { - if (_aoe == null && Module.PrimaryActor.Position.Z > -10) // for some reason NPC yells that are exactly at the start of a module do not get recognized despite appearing in replay? - _aoe = new(poly2, Arena.Center, default, WorldState.FutureTime(4)); + if (_aoe == null && Module.PrimaryActor.Position.Z > -10f) // for some reason NPC yells that are exactly at the start of a module do not get recognized despite appearing in replay? + _aoe = new(poly2, Arena.Center, default, WorldState.FutureTime(4d)); } } -class Overpower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(7.08f, 45.Degrees())); -class Sneeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Sneeze), new AOEShapeCone(20.85f, 45.Degrees())); +class Overpower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(7.08f, 45f.Degrees())); +class Sneeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Sneeze), new AOEShapeCone(20.85f, 45f.Degrees())); class SneezeHint(BossModule module) : Components.CastInterruptHint(module, ActionID.MakeSpell(AID.Sneeze), true, true, showNameInHint: true); class D150SiegeGobbueStates : StateMachineBuilder @@ -66,15 +66,27 @@ public D150SiegeGobbueStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D150SiegeGobbue.Trash).Where(x => x.Position.AlmostEqual(Module.Arena.Center, Module.Bounds.Radius)) - .All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D150SiegeGobbue.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 182, NameID = 5254, SortOrder = 3)] public class D150SiegeGobbue(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? arena1.Center : arena2.Center, IsArena1(primary) ? arena1 : arena2) { - private static bool IsArena1(Actor primary) => primary.Position.Z < -10; + private static bool IsArena1(Actor primary) => primary.Position.Z < -10f; private static readonly WPos[] vertices1 = [new(37.14f, -107.01f), new(38.84f, -105.21f), new(39.33f, -104.79f), new(41.89f, -104.55f), new(42.35f, -104.03f), new(42.82f, -103.73f), new(43.26f, -103.23f), new(43.91f, -102.16f), new(44.17f, -101.58f), new(44.63f, -100.24f), new(45.31f, -97.65f), new(45.54f, -97.07f), new(46.05f, -96.92f), new(47.88f, -96.82f), new(48.35f, -96.39f), @@ -115,10 +127,34 @@ public class D150SiegeGobbue(WorldState ws, Actor primary) : BossModule(ws, prim private static readonly ArenaBoundsComplex arena2 = new([new PolygonCustom(vertices2)]); public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.XelphatolWhirltalon, (uint)OID.XelphatolStrongbeak, (uint)OID.XelphatolBravewing]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSkycaller.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSkycaller.cs index a7568a32f6..0735e8cf09 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSkycaller.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSkycaller.cs @@ -17,12 +17,12 @@ public enum AID : uint IxaliAeroII = 6628 // Boss->self, 3.0s cast, range 40+R width 8 rect } -class Tornado(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Tornado), 6); +class Tornado(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Tornado), 6f); class TornadoHint(BossModule module) : Components.CastInterruptHint(module, ActionID.MakeSpell(AID.Tornado), true, true, showNameInHint: true); class IxaliAeroIII(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.IxaliAeroIII)); class IxaliAeroIIIHint(BossModule module) : Components.CastInterruptHint(module, ActionID.MakeSpell(AID.IxaliAeroIII), true, true, showNameInHint: true); -class IxaliAeroII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IxaliAeroII), new AOEShapeRect(41.8f, 4)); -class Gust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gust), 5); +class IxaliAeroII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IxaliAeroII), new AOEShapeRect(41.8f, 4f)); +class Gust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gust), 5f); class D150XelphatolSkycallerStates : StateMachineBuilder { @@ -35,8 +35,20 @@ public D150XelphatolSkycallerStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D150XelphatolSkycaller.Trash).Where(x => x.Position.AlmostEqual(Module.Arena.Center, Module.Bounds.Radius)) - .All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(D150XelphatolSkycaller.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + return true; + }; } } @@ -62,6 +74,17 @@ public class D150XelphatolSkycaller(WorldState ws, Actor primary) : BossModule(w protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSwiftbeak.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSwiftbeak.cs index aff7e407e1..910b56c91c 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSwiftbeak.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D150XelphatolSwiftbeak.cs @@ -41,8 +41,28 @@ public D150XelphatolSwiftbeakStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(D150XelphatolSwiftbeak.Trash).Where(x => x.Position.AlmostEqual(Module.Arena.Center, Module.Bounds.Radius)) - .All(x => x.IsDestroyed) || Module.Enemies(D150XelphatolSwiftbeak.Keys).Any(x => x.IsTargetable); + .Raw.Update = () => + { + var enemies = module.Enemies(D150XelphatolSwiftbeak.Trash); + var center = module.Arena.Center; + var radius = module.Bounds.Radius; + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (!enemy.IsDeadOrDestroyed && enemy.Position.AlmostEqual(center, radius)) + return false; + } + var keys = module.Enemies(D150XelphatolSwiftbeak.Keys); + var countK = keys.Count; + for (var i = 0; i < countK; ++i) + { + var key = keys[i]; + if (key.IsTargetable) + return true; + } + return true; + }; } } @@ -50,8 +70,8 @@ public D150XelphatolSwiftbeakStates(BossModule module) : base(module) public class D150XelphatolSwiftbeak(WorldState ws, Actor primary) : BossModule(ws, primary, IsArena1(primary) ? arena1.Center : IsArena2(primary) ? arena3.Center : arena2.Center, IsArena1(primary) ? arena1 : IsArena2(primary) ? arena3 : arena2) { - private static bool IsArena1(Actor primary) => primary.Position.X < 200 && primary.Position.Z > -200; - private static bool IsArena2(Actor primary) => primary.Position.Z < -200; + private static bool IsArena1(Actor primary) => primary.Position.X < 200f && primary.Position.Z > -200f; + private static bool IsArena2(Actor primary) => primary.Position.Z < -200f; private static readonly WPos[] vertices1 = [new(152.49f, -71.52f), new(150.27f, -69.29f), new(149.68f, -68.8f), new(147.76f, -70.72f), new(147.27f, -71.05f), new(146.79f, -70.79f), new(146.28f, -70.33f), new(145.76f, -70.31f), new(145.3f, -69.98f), new(143.97f, -68.28f), new(143.63f, -67.66f), new(144.19f, -67.53f), new(145.39f, -68.3f), new(145.89f, -68.72f), new(146.5f, -69.06f), @@ -195,10 +215,34 @@ public class D150XelphatolSwiftbeak(WorldState ws, Actor primary) : BossModule(w (uint)OID.XelphatolBravewing, (uint)OID.XelphatolFatecaller, (uint)OID.XelphatolStrongbeak, (uint)OID.AbalathianHornbill]; public static readonly uint[] Keys = [(uint)OID.BoneKey, (uint)OID.Airstone1, (uint)OID.Airstone2]; - protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat && x.Position.AlmostEqual(Arena.Center, Bounds.Radius)); + protected override bool CheckPull() + { + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.InCombat && enemy.Position.AlmostEqual(center, radius)) + return true; + } + return false; + } protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(Trash).Where(x => x.Position.AlmostEqual(Arena.Center, Bounds.Radius))); + var filteredEnemies = new List(); + var enemies = Enemies(Trash); + var count = enemies.Count; + var center = Arena.Center; + var radius = Bounds.Radius; + for (var i = 0; i < count; ++i) + { + var enemy = enemies[i]; + if (enemy.Position.AlmostEqual(center, radius)) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } } diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D151NuzalHueloc.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D151NuzalHueloc.cs index 1a038e960b..36aed196dc 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D151NuzalHueloc.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D151NuzalHueloc.cs @@ -37,7 +37,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) } } -class WindBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindBlast), new AOEShapeRect(61.5f, 4)); +class WindBlast(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindBlast), new AOEShapeRect(61.5f, 4f)); class HotBlast(BossModule module) : Components.GenericAOEs(module) { @@ -49,13 +49,13 @@ class HotBlast(BossModule module) : Components.GenericAOEs(module) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.HotBlast) - _aoe = new(circle, Module.PrimaryActor.Position, default, Module.CastFinishAt(spell), Colors.SafeFromAOE); + if (spell.Action.ID == (uint)AID.HotBlast) + _aoe = new(circle, WPos.ClampToGrid(Module.PrimaryActor.Position), default, Module.CastFinishAt(spell), Colors.SafeFromAOE); } public override void Update() { - if (_aoe != null && (WorldState.CurrentTime - _aoe.Value.Activation).TotalSeconds >= 1) + if (_aoe != null && (WorldState.CurrentTime - _aoe.Value.Activation).TotalSeconds >= 1d) _aoe = null; } @@ -95,23 +95,33 @@ public class D151NuzalHueloc(WorldState ws, Actor primary) : BossModule(ws, prim protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(Enemies(opponents).Where(x => x.FindStatus(SID.Invincibility) == null)); + var allEnemies = Enemies(opponents); + var count = allEnemies.Count; + List filteredEnemies = new(count); + for (var i = 0; i < count; ++i) + { + var enemy = allEnemies[i]; + if (enemy.FindStatus((uint)SID.Invincibility) == null) + filteredEnemies.Add(enemy); + } + Arena.Actors(filteredEnemies); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - if (e.Actor.FindStatus(SID.Invincibility) != null) + if (e.Actor.FindStatus((uint)SID.Invincibility) != null) { e.Priority = AIHints.Enemy.PriorityInvincible; continue; } - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.Airstone => 2, - OID.FloatingTurret => 1, + (uint)OID.Airstone => 2, + (uint)OID.FloatingTurret => 1, _ => 0 }; } diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D152DotoliCiloc.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D152DotoliCiloc.cs index 54ef6ae05c..663ec84ee9 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D152DotoliCiloc.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D152DotoliCiloc.cs @@ -1,3 +1,5 @@ +using BossMod.Endwalker.Quest.MSQ.AsTheHeavensBurn.P1TerminusIdolizer; + namespace BossMod.Heavensward.Dungeon.D11Antitower.D152DotoliCiloc; public enum OID : uint @@ -34,7 +36,7 @@ class ArenaChange(BossModule module) : Components.GenericAOEs(module) public override void OnActorEAnim(Actor actor, uint state) { - if (state == 0x00010002 && (OID)actor.OID == OID.ArenaVoidzone) + if (state == 0x00010002 && actor.OID == (uint)OID.ArenaVoidzone) { Arena.Bounds = D152DotoliCiloc.DefaultBounds; _aoe = null; @@ -45,24 +47,27 @@ public override void OnActorEAnim(Actor actor, uint state) public override void Update() { if (!begin && _aoe == null) - _aoe = new(donut, Arena.Center, default, WorldState.FutureTime(4)); + _aoe = new(donut, Arena.Center, default, WorldState.FutureTime(4d)); } } -class DarkWings(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.Spreadmarker, ActionID.MakeSpell(AID.DarkWings), 6, 5.1f); -class Whirlwind(BossModule module) : Components.PersistentVoidzone(module, 6, m => m.Enemies(OID.Whirlwind)); -class Stormcoming(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Stormcoming), 6); -class OnLow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OnLow), new AOEShapeCone(10.98f, 60.Degrees())); +class DarkWings(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.Spreadmarker, ActionID.MakeSpell(AID.DarkWings), 6f, 5.1f); +class Whirlwind(BossModule module) : Components.PersistentVoidzone(module, 6f, GetWhirlwinds) +{ + private static List GetWhirlwinds(BossModule module) => module.Enemies((uint)OID.Whirlwind); +} +class Stormcoming(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Stormcoming), 6f); +class OnLow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OnLow), new AOEShapeCone(10.98f, 60f.Degrees())); -class OnLowHaste(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Swiftfeather), new AOEShapeCone(10.98f, 60.Degrees())) +class OnLowHaste(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Swiftfeather), new AOEShapeCone(10.98f, 60f.Degrees())) { private bool active; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.Swiftfeather) + if (spell.Action.ID == (uint)AID.Swiftfeather) active = true; - else if ((AID)spell.Action.ID == AID.OnLow) + else if (spell.Action.ID == (uint)AID.OnLow) active = false; } @@ -89,13 +94,36 @@ class OnHigh(BossModule module) : Components.Knockback(module) { private Source? _source; private static readonly SafeWall[] safeWallsW = [new(new(227.487f, 16.825f), new(226.567f, 13.39f)), new(new(226.567f, 13.39f), new(227.392f, 10.301f))]; - private static readonly SafeWall[] safeWallsN = GenerateRotatedSafeWalls(safeWallsW, 90); - private static readonly SafeWall[] safeWallsE = GenerateRotatedSafeWalls(safeWallsW, 180); - private static readonly SafeWall[] safeWallsS = GenerateRotatedSafeWalls(safeWallsW, 270); + private static readonly SafeWall[] safeWallsN = GenerateRotatedSafeWalls(ref safeWallsW, 90f); + private static readonly SafeWall[] safeWallsE = GenerateRotatedSafeWalls(ref safeWallsW, 180f); + private static readonly SafeWall[] safeWallsS = GenerateRotatedSafeWalls(ref safeWallsW, 270f); private static readonly SafeWall[] allSafeWalls = [.. safeWallsW, .. safeWallsN, .. safeWallsE, .. safeWallsS]; - private static SafeWall[] GenerateRotatedSafeWalls(SafeWall[] baseWalls, float angle) - => [.. baseWalls.Select(wall => new SafeWall(GenerateRotatedVertice(wall.Vertex1, angle), GenerateRotatedVertice(wall.Vertex2, angle)))]; + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + var whirlwinds = Module.Enemies((uint)OID.Whirlwind); + var count = whirlwinds.Count; + for (var i = 0; i < count; ++i) + { + if (pos.InCircle(whirlwinds[i].Position, 6f)) + return true; + } + return !Arena.InBounds(pos); + } + + private static SafeWall[] GenerateRotatedSafeWalls(ref SafeWall[] baseWalls, float angle) + { + var len = baseWalls.Length; + var rotatedWalls = new SafeWall[len]; + for (var i = 0; i < len; ++i) + { + ref var bw = ref baseWalls[i]; + var rotatedVertex1 = GenerateRotatedVertice(bw.Vertex1, angle); + var rotatedVertex2 = GenerateRotatedVertice(bw.Vertex2, angle); + rotatedWalls[i] = new(rotatedVertex1, rotatedVertex2); + } + return rotatedWalls; + } private static WPos GenerateRotatedVertice(WPos vertex, float rotationAngle) => WPos.RotateAroundOrigin(rotationAngle, D152DotoliCiloc.ArenaCenter, vertex); @@ -103,13 +131,13 @@ private static SafeWall[] GenerateRotatedSafeWalls(SafeWall[] baseWalls, float a public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.OnHigh) - _source = new(caster.Position, 30, Module.CastFinishAt(spell), SafeWalls: allSafeWalls); + if (spell.Action.ID == (uint)AID.OnHigh) + _source = new(spell.LocXZ, 30f, Module.CastFinishAt(spell), SafeWalls: allSafeWalls); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.OnHigh) + if (spell.Action.ID == (uint)AID.OnHigh) _source = null; } } @@ -126,7 +154,7 @@ class OnHighHint(BossModule module) : Components.GenericAOEs(module) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.OnHigh) + if (spell.Action.ID == (uint)AID.OnHigh) { activation = Module.CastFinishAt(spell); GenerateHints(); @@ -137,16 +165,27 @@ private void GenerateHints() { for (var i = 0; i < 4; ++i) { - var deg = (i * 90).Degrees(); - if (!Module.Enemies(OID.Whirlwind).Any(x => x.Position.InCone(D152DotoliCiloc.ArenaCenter, deg, angle))) - cones.Add(new(D152DotoliCiloc.ArenaCenter, 20, deg, angle)); + var deg = (i * 90f).Degrees(); + var enemyInCone = false; + var whirlwinds = Module.Enemies((uint)OID.Whirlwind); + var count = whirlwinds.Count; + for (var j = 0; j < count; ++j) + { + if (whirlwinds[j].Position.InCone(D152DotoliCiloc.ArenaCenter, deg, angle)) + { + enemyInCone = true; + break; + } + } + if (!enemyInCone) + cones.Add(new(D152DotoliCiloc.ArenaCenter, 20f, deg, angle)); } _aoe = new(new AOEShapeCustom([.. cones], InvertForbiddenZone: true), D152DotoliCiloc.ArenaCenter, default, activation, Colors.SafeFromAOE); } public override void OnActorCreated(Actor actor) { - if (cones.Count != 0 && (OID)actor.OID == OID.Whirlwind) // sometimes the creation of whirlwinds is delayed + if (cones.Count != 0 && actor.OID == (uint)OID.Whirlwind) // sometimes the creation of whirlwinds is delayed { cones.Clear(); GenerateHints(); @@ -155,7 +194,7 @@ public override void OnActorCreated(Actor actor) public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.OnHigh) + if (spell.Action.ID == (uint)AID.OnHigh) { cones.Clear(); _aoe = null; @@ -164,12 +203,13 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) public override void AddHints(int slot, Actor actor, TextHints hints) { - if (_aoe == null) - return; - if (ActiveAOEs(slot, actor).Any(c => !c.Check(actor.Position))) - hints.Add(RiskHint); - else - hints.Add(RiskHint, false); + if (_aoe is AOEInstance aoe) + { + var check = true; + if (aoe.Check(actor.Position)) + check = false; + hints.Add(RiskHint, check); + } } } @@ -195,11 +235,11 @@ public class D152DotoliCiloc(WorldState ws, Actor primary) : BossModule(ws, prim public static readonly WPos ArenaCenter = new(245.289f, 13.626f); private const float offset = 0.42f; public static readonly Polygon[] StartingBoundsP = [new Polygon(ArenaCenter, 29.45f * CosPI.Pi16th, 16, 11.25f.Degrees())]; - public static readonly Polygon[] DefaultBoundsP = [new Polygon(ArenaCenter, 20 * CosPI.Pi16th, 16, 11.25f.Degrees())]; - private static readonly WPos[] verticesW = [new(227.1f, 17.333f), new(226.122f, 13.411f), new(227, 10.126f), new(225.087f, 9.583f), new(224.016f, 13.541f), new(225.124f, 17.756f)]; - private static readonly WPos[] verticesN = WPos.GenerateRotatedVertices(ArenaCenter, verticesW, 90); - private static readonly WPos[] verticesE = WPos.GenerateRotatedVertices(ArenaCenter, verticesW, 180); - private static readonly WPos[] verticesS = WPos.GenerateRotatedVertices(ArenaCenter, verticesW, 270); + public static readonly Polygon[] DefaultBoundsP = [new Polygon(ArenaCenter, 20f * CosPI.Pi16th, 16, 11.25f.Degrees())]; + private static readonly WPos[] verticesW = [new(227.1f, 17.333f), new(226.122f, 13.411f), new(227f, 10.126f), new(225.087f, 9.583f), new(224.016f, 13.541f), new(225.124f, 17.756f)]; + private static readonly WPos[] verticesN = WPos.GenerateRotatedVertices(ArenaCenter, verticesW, 90f); + private static readonly WPos[] verticesE = WPos.GenerateRotatedVertices(ArenaCenter, verticesW, 180f); + private static readonly WPos[] verticesS = WPos.GenerateRotatedVertices(ArenaCenter, verticesW, 270f); private static readonly PolygonCustomO[] difference = [new PolygonCustomO(verticesW, offset), new PolygonCustomO(verticesN, offset), new PolygonCustomO(verticesE, offset), new PolygonCustomO(verticesS, offset)]; public static readonly ArenaBoundsComplex StartingBounds = new(StartingBoundsP, difference); diff --git a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D153TozolHuatotl.cs b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D153TozolHuatotl.cs index 3292c790c9..94684564b5 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D153TozolHuatotl.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D15Xelphatol/D153TozolHuatotl.cs @@ -34,13 +34,13 @@ public enum IconID : uint } class AerialBlast(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.AerialBlast)); -class IxaliAeroII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IxaliAeroII), new AOEShapeRect(43, 3)); +class IxaliAeroII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IxaliAeroII), new AOEShapeRect(43f, 3f)); class IxaliAeroIII(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.IxaliAeroIII)); -class Bill(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Bill), 5); -class Ingurgitate(BossModule module) : Components.StackWithIcon(module, (uint)IconID.Stackmarker, ActionID.MakeSpell(AID.Ingurgitate), 5, 5.5f, 4, 4); -class EyeOfTheStorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EyeOfTheStorm), new AOEShapeDonut(10, 20)); -class WickedWheel(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WickedWheel), 7); -class MistralSong(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MistralSong), new AOEShapeCone(32.89f, 60.Degrees())); +class Bill(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Bill), 5f); +class Ingurgitate(BossModule module) : Components.StackWithIcon(module, (uint)IconID.Stackmarker, ActionID.MakeSpell(AID.Ingurgitate), 5f, 5.5f, 4, 4); +class EyeOfTheStorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EyeOfTheStorm), new AOEShapeDonut(10f, 20f)); +class WickedWheel(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WickedWheel), 7f); +class MistralSong(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MistralSong), new AOEShapeCone(32.89f, 60f.Degrees())); class D153TozolHuatotlStates : StateMachineBuilder { @@ -61,5 +61,5 @@ public D153TozolHuatotlStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 182, NameID = 5272, SortOrder = 7)] public class D153TozolHuatotl(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly ArenaBoundsComplex arena = new([new Polygon(new(317.8f, -416.19f), 19.5f * CosPI.Pi48th, 48)], [new Rectangle(new(336.69f, -409.415f), 20, 1, -70.Degrees())]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(317.8f, -416.19f), 19.5f * CosPI.Pi48th, 48)], [new Rectangle(new(336.69f, -409.415f), 20f, 1f, -70f.Degrees())]); } diff --git a/BossMod/Modules/RealmReborn/Dungeon/D08Qarn/D081Teratotaur.cs b/BossMod/Modules/RealmReborn/Dungeon/D08Qarn/D081Teratotaur.cs index 91f7e833d5..2df3013a55 100644 --- a/BossMod/Modules/RealmReborn/Dungeon/D08Qarn/D081Teratotaur.cs +++ b/BossMod/Modules/RealmReborn/Dungeon/D08Qarn/D081Teratotaur.cs @@ -6,7 +6,7 @@ public enum OID : uint DungWespe = 0x6DA, // spawn during fight Platform1 = 0x1E87E2, // x1, EventObj type; eventstate 0 if active, 7 if inactive Platform2 = 0x1E87E3, // x1, EventObj type; eventstate 0 if active, 7 if inactive - Platform3 = 0x1E87E, // x1, EventObj type; eventstate 0 if active, 7 if inactive + Platform3 = 0x1E87E4, // x1, EventObj type; eventstate 0 if active, 7 if inactive } public enum AID : uint @@ -23,11 +23,11 @@ public enum AID : uint public enum SID : uint { - Doom = 21, // Boss->player, extra=0x0 + Doom = 210 // Boss->player, extra=0x0 } -class Triclip(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Triclip), new AOEShapeRect(5.25f, 2)); -class Mow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mow), new AOEShapeCone(8.25f, 60.Degrees())); +class Triclip(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Triclip), new AOEShapeRect(5.25f, 2f)); +class Mow(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mow), new AOEShapeCone(8.25f, 60f.Degrees())); class FrightfulRoar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrightfulRoar), 8.25f); class MortalRay(BossModule module) : BossComponent(module) @@ -41,9 +41,9 @@ class MortalRay(BossModule module) : BossComponent(module) public override void Update() { - _platforms[0] ??= Module.Enemies(OID.Platform1).FirstOrDefault(); - _platforms[1] ??= Module.Enemies(OID.Platform2).FirstOrDefault(); - _platforms[2] ??= Module.Enemies(OID.Platform3).FirstOrDefault(); + _platforms[0] ??= Module.Enemies((uint)OID.Platform1)[0]; + _platforms[1] ??= Module.Enemies((uint)OID.Platform2)[0]; + _platforms[2] ??= Module.Enemies((uint)OID.Platform3)[0]; } public override void AddHints(int slot, Actor actor, TextHints hints) @@ -72,13 +72,13 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) public override void OnStatusGain(Actor actor, ActorStatus status) { - if ((SID)status.ID == SID.Doom) + if (status.ID == (uint)SID.Doom) _dooms.Set(Raid.FindSlot(actor.InstanceID)); } public override void OnStatusLose(Actor actor, ActorStatus status) { - if ((SID)status.ID == SID.Doom) + if (status.ID == (uint)SID.Doom) _dooms.Clear(Raid.FindSlot(actor.InstanceID)); } } @@ -98,19 +98,20 @@ public D081TeratotaurStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 9, NameID = 1567)] public class D081Teratotaur(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly PolygonCustom[] shape = [new ([new(-94.9f, -59), new(-70.2f, -46.1f), new(-55.3f, -46.6f), + private static readonly PolygonCustom[] shape = [new ([new(-94.9f, -59f), new(-70.2f, -46.1f), new(-55.3f, -46.6f), new(-55.7f, -55.6f), new(-51.1f, -60.9f), new(-51.2f, -65), new(-58.1f, -67.7f), new(-64.7f, -70.6f), new(-88.4f, -72.2f), new(-89, -66.2f), new(-94.9f, -65.5f)])]; public static readonly ArenaBoundsComplex arena = new(shape); protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { - e.Priority = (OID)e.Actor.OID switch + var e = hints.PotentialTargets[i]; + e.Priority = e.Actor.OID switch { - OID.DungWespe => 2, - OID.Boss => 1, + (uint)OID.DungWespe => 1, _ => 0 }; } @@ -119,6 +120,6 @@ protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRoles protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.DungWespe)); + Arena.Actors(Enemies((uint)OID.DungWespe)); } } diff --git a/BossMod/Modules/Shadowbringers/Dungeon/D04MalikahsWell/D041GreaterArmadillo.cs b/BossMod/Modules/Shadowbringers/Dungeon/D04MalikahsWell/D041GreaterArmadillo.cs index 370c52e973..6160e2047c 100644 --- a/BossMod/Modules/Shadowbringers/Dungeon/D04MalikahsWell/D041GreaterArmadillo.cs +++ b/BossMod/Modules/Shadowbringers/Dungeon/D04MalikahsWell/D041GreaterArmadillo.cs @@ -32,15 +32,19 @@ class Rehydration(BossModule module) : Components.CastInterruptHint(module, Acti class RightRound(BossModule module) : Components.GenericAOEs(module) { - private static readonly AOEShapeCircle circle = new(9); private AOEInstance? _aoe; public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if (spell.Action.ID == (uint)AID.RightRoundVisual) // TODO: find more precise way to calculate spell location. seems to be neither spell.LocXZ nor morningstar location, instead its somewhere in the middle, seen distances of 0-7.6 away from morningstar - _aoe = new(circle, spell.LocXZ, default, Module.CastFinishAt(spell, 0.9f)); + if (spell.Action.ID == (uint)AID.RightRoundVisual) + { + // approximation of the mechanic with a capsule since the jump seems to behave quite unpredictable for long distances to the morning star + var len = (spell.LocXZ - caster.Position).Length(); + var maxLen = len > 10f ? 10f : len; + _aoe = new(new AOEShapeCapsule(9f, maxLen), spell.LocXZ, spell.Rotation + 180f.Degrees(), Module.CastFinishAt(spell, 0.9f)); + } } public override void OnEventCast(Actor caster, ActorCastEvent spell) diff --git a/BossMod/Modules/Shadowbringers/Dungeon/D11HeroesGauntlet/D112SpectralNecromancer.cs b/BossMod/Modules/Shadowbringers/Dungeon/D11HeroesGauntlet/D112SpectralNecromancer.cs index b686ad6b28..47be3bd743 100644 --- a/BossMod/Modules/Shadowbringers/Dungeon/D11HeroesGauntlet/D112SpectralNecromancer.cs +++ b/BossMod/Modules/Shadowbringers/Dungeon/D11HeroesGauntlet/D112SpectralNecromancer.cs @@ -90,7 +90,7 @@ class Necrobombs(BossModule module) : BossComponent(module) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (_ba.ActiveBaits.Any()) + if (_ba.ActiveBaits.Count != 0) return; var forbidden = new List>(); foreach (var e in WorldState.Actors.Where(x => !x.IsAlly && x.Tether.ID == (uint)TetherID.CrawlingNecrobombs)) diff --git a/BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs b/BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs index 0e85afc0d8..4de02ece86 100644 --- a/BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs @@ -68,15 +68,15 @@ class ZoomIn(BossModule module) : Components.LineStack(module, ActionID.MakeSpel { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (ActiveBaits.Any()) - hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Arena.Center, 3), ActiveBaits.FirstOrDefault().Activation); + if (ActiveBaits.Count != 0) + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Arena.Center, 3f), ActiveBaits[0].Activation); } } class PassageOfArms(BossModule module) : BossComponent(module) { private ActorCastInfo? EnrageCast => Module.PrimaryActor.CastInfo is { Action.ID: 16604 } castInfo ? castInfo : null; - private Actor? Paladin => WorldState.Actors.FirstOrDefault(x => x.FindStatus(SID.WingedShield) != null); + private Actor? Paladin => WorldState.Actors.FirstOrDefault(x => x.FindStatus((uint)SID.WingedShield) != null); public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { @@ -87,12 +87,12 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme public override void DrawArenaBackground(int pcSlot, Actor pc) { if (EnrageCast != null && Paladin != null) - Arena.ZoneCone(Paladin.Position, 0, 8, Paladin.Rotation + 180.Degrees(), 60.Degrees(), Colors.SafeFromAOE); + Arena.ZoneCone(Paladin.Position, 0f, 8f, Paladin.Rotation + 180f.Degrees(), 60f.Degrees(), Colors.SafeFromAOE); } public override void AddHints(int slot, Actor actor, TextHints hints) { - if (EnrageCast != null && Paladin != null && !actor.Position.InCircleCone(Paladin.Position, 8, Paladin.Rotation + 180.Degrees(), 60.Degrees())) + if (EnrageCast != null && Paladin != null && !actor.Position.InCircleCone(Paladin.Position, 8f, Paladin.Rotation + 180.Degrees(), 60.Degrees())) hints.Add("Hide behind tank!"); } } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheDungeonsOfLyheGhiah/Goliath.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheDungeonsOfLyheGhiah/Goliath.cs index 5276c2b8ff..f6bfd4d5f9 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheDungeonsOfLyheGhiah/Goliath.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheDungeonsOfLyheGhiah/Goliath.cs @@ -37,17 +37,17 @@ public enum AID : uint Telega = 9630 // BonusAdds->self, no cast, single-target, bonus adds disappear } -class Wellbore(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wellbore), 15); +class Wellbore(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wellbore), 15f); class Compress1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Compress1), new AOEShapeCross(100, 3.5f)); class Compress2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Compress2), new AOEShapeRect(102.1f, 3.5f)); -class Accelerate(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Accelerate), 6, 8, 8); +class Accelerate(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Accelerate), 6f, 8, 8); class Incinerate(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Incinerate)); -class Fount(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Fount), 4); +class Fount(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Fount), 4f); class MechanicalBlow(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.MechanicalBlow)); class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(15.23f, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(15.23f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -72,7 +72,17 @@ public GoliathStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Goliath.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(Goliath.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -114,23 +124,24 @@ public class Goliath(WorldState ws, Actor primary) : BossModule(ws, primary, are protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GoliathsJavelin)); + Arena.Actors(Enemies((uint)OID.GoliathsJavelin)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.DungeonOnion => 6, - OID.DungeonEgg => 5, - OID.DungeonGarlic => 4, - OID.DungeonTomato => 3, - OID.DungeonQueen or OID.KeeperOfKeys => 2, - OID.GoliathsJavelin => 1, + (uint)OID.DungeonOnion => 6, + (uint)OID.DungeonEgg => 5, + (uint)OID.DungeonGarlic => 4, + (uint)OID.DungeonTomato => 3, + (uint)OID.DungeonQueen or (uint)OID.KeeperOfKeys => 2, + (uint)OID.GoliathsJavelin => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousTyphon.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousTyphon.cs index 130557d62c..4cacec648f 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousTyphon.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousTyphon.cs @@ -46,35 +46,37 @@ public enum AID : uint Telega = 9630 // Mandragoras->self, no cast, single-target, bonus adds disappear } -class AChoo(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AChoo), new AOEShapeCone(12, 45.Degrees())); -class FellSwipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FellSwipe), new AOEShapeCone(8, 60.Degrees())); -class WindShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindShot), new AOEShapeRect(40, 3)); -class LingeringSnort(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LingeringSnort), 20); -class UnpleasantBreeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.UnpleasantBreeze), 6); -class Fireball(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Fireball), 6, 8, 8); - -class SnortsaultKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.SnortsaultKB), 20, stopAtWall: true); +class AChoo(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AChoo), new AOEShapeCone(12f, 45f.Degrees())); +class FellSwipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FellSwipe), new AOEShapeCone(8f, 60f.Degrees())); +class WindShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindShot), new AOEShapeRect(40f, 3f)); +class LingeringSnort(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LingeringSnort), 20f); +class UnpleasantBreeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.UnpleasantBreeze), 6f); +class Fireball(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Fireball), 6f, 8, 8); + +class SnortsaultKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.SnortsaultKB), 20f, stopAtWall: true); class SnortsaultCircle(BossModule module) : Components.GenericAOEs(module) { private readonly LingeringSnort _aoes = module.FindComponent()!; - private static readonly AOEShapeCircle circle = new(5); + private static readonly AOEShapeCircle circle = new(5f); private AOEInstance? _aoe; public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (_aoes.ActiveCasters.Count == 0 && _aoe.HasValue) - yield return _aoe.Value; + if (_aoes.ActiveCasters.Count == 0 && _aoe != null) + return [_aoe.Value]; + else + return []; } public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.DaenOseTheAvaricious2) - _aoe = new(circle, Module.PrimaryActor.Position, default, WorldState.FutureTime(14.3f)); + if (actor.OID == (uint)OID.DaenOseTheAvaricious2) + _aoe = new(circle, WPos.ClampToGrid(Arena.Center), default, WorldState.FutureTime(14.3d)); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.SnortAssaultEnd) + if (spell.Action.ID == (uint)AID.SnortAssaultEnd) _aoe = null; } } @@ -82,33 +84,32 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) class Snortsault(BossModule module) : Components.GenericRotatingAOE(module) { private readonly LingeringSnort _aoe = module.FindComponent()!; - private static readonly Angle increment = 6.Degrees(); - private static readonly AOEShapeCone cone = new(20, 22.5f.Degrees()); + private static readonly Angle increment = 6f.Degrees(); + private static readonly AOEShapeCone cone = new(20f, 22.5f.Degrees()); public override void OnActorCreated(Actor actor) { - switch ((OID)actor.OID) + switch (actor.OID) { - case OID.DaenOseTheAvaricious3: - AddSequences(actor, isClockwise: false); + case (uint)OID.DaenOseTheAvaricious3: + AddSequences(false); break; - case OID.DaenOseTheAvaricious1: - AddSequences(actor, isClockwise: true); + case (uint)OID.DaenOseTheAvaricious1: + AddSequences(true); break; } - } - - private void AddSequences(Actor actor, bool isClockwise) - { - var rotationIncrement = isClockwise ? increment : -increment; - var activation = WorldState.FutureTime(14.5f); - Sequences.Add(new(cone, Arena.Center, actor.Rotation, rotationIncrement, activation, 1.1f, 31, 9)); - Sequences.Add(new(cone, Arena.Center, actor.Rotation + 180.Degrees(), rotationIncrement, activation, 1.1f, 31, 9)); + void AddSequences(bool isClockwise) + { + var rotationIncrement = isClockwise ? increment : -increment; + AddSequence(default); + AddSequence(180f.Degrees()); + void AddSequence(Angle offset) => Sequences.Add(new(cone, WPos.ClampToGrid(Arena.Center), actor.Rotation + offset, rotationIncrement, WorldState.FutureTime(14.5d), 1.1f, 31, 9)); + } } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID == AID.SnortsaultCone) + if (spell.Action.ID == (uint)AID.SnortsaultCone) AdvanceSequence(caster.Position, caster.Rotation, WorldState.CurrentTime); } @@ -157,7 +158,17 @@ public DaenOseTheAvariciousTyphonStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(DaenOseTheAvariciousTyphon.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(DaenOseTheAvariciousTyphon.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -171,23 +182,24 @@ public class DaenOseTheAvariciousTyphon(WorldState ws, Actor primary) : THTempla protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.WrigglingMenace)); + Arena.Actors(Enemies((uint)OID.WrigglingMenace)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 6, - OID.SecretEgg => 5, - OID.SecretGarlic => 4, - OID.SecretTomato => 3, - OID.SecretQueen => 2, - OID.WrigglingMenace => 1, + (uint)OID.SecretOnion => 6, + (uint)OID.SecretEgg => 5, + (uint)OID.SecretGarlic => 4, + (uint)OID.SecretTomato => 3, + (uint)OID.SecretQueen => 2, + (uint)OID.WrigglingMenace => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousUltros.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousUltros.cs index d4082ae769..8831aec799 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousUltros.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/DaenOseTheAvariciousUltros.cs @@ -43,33 +43,45 @@ public enum AID : uint Telega = 9630 // Mandragoras->self, no cast, single-target, bonus adds disappear } -class AquaBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaBreath), new AOEShapeCone(13, 45.Degrees())); -class Tentacle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Tentacle), 8); -class Wallop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wallop), new AOEShapeRect(20, 5)); -class Megavolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Megavolt), 11); -class Waterspout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Waterspout), 4); -class SoakingSplatter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SoakingSplatter), 10); -class FallingWater(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FallingWater), 8); +class AquaBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaBreath), new AOEShapeCone(13f, 45f.Degrees())); +class Tentacle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Tentacle), 8f); +class Wallop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Wallop), new AOEShapeRect(20f, 5f)); +class Megavolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Megavolt), 11f); +class Waterspout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Waterspout), 4f); +class SoakingSplatter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SoakingSplatter), 10f); +class FallingWater(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FallingWater), 8f); class ThunderIII(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.ThunderIII)); -class WaveOfTurmoil(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.WaveOfTurmoil), 20, stopAtWall: true) +class WaveOfTurmoil(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.WaveOfTurmoil), 20f, stopAtWall: true) { private readonly SoakingSplatter _aoe = module.FindComponent()!; + private static readonly Angle cone = 30f.Degrees(); - public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => _aoe?.ActiveAOEs(slot, actor).Any(z => z.Shape.Check(pos, z.Origin, z.Rotation)) ?? false; + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + var count = _aoe.Casters.Count; + for (var i = 0; i < count; ++i) + { + var caster = _aoe.Casters[i]; + if (caster.Check(pos)) + return true; + } + return false; + } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - var forbidden = new List>(); - var source = Sources(slot, actor).FirstOrDefault(); - if (source != default) + var source = Casters.Count != 0 ? Casters[0] : null; + if (source != null) { - foreach (var c in _aoe.ActiveAOEs(slot, actor)) + var count = _aoe.Casters.Count; + var forbidden = new Func[count]; + for (var i = 0; i < count; ++i) { - forbidden.Add(ShapeDistance.Cone(Arena.Center, 20, Angle.FromDirection(c.Origin - Module.Center), 30.Degrees())); + forbidden[i] = ShapeDistance.Cone(Arena.Center, 20f, Angle.FromDirection(_aoe.Casters[i].Origin - Arena.Center), cone); } - if (forbidden.Count != 0) - hints.AddForbiddenZone(ShapeDistance.Union(forbidden), source.Activation); + if (forbidden.Length != 0) + hints.AddForbiddenZone(ShapeDistance.Union(forbidden), Module.CastFinishAt(source.CastInfo)); } } } @@ -100,7 +112,17 @@ public DaenOseTheAvariciousUltrosStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(DaenOseTheAvariciousUltros.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(DaenOseTheAvariciousUltros.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -119,16 +141,17 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 5, - OID.SecretEgg => 4, - OID.SecretGarlic => 3, - OID.SecretTomato => 2, - OID.SecretQueen => 1, + (uint)OID.SecretOnion => 5, + (uint)OID.SecretEgg => 4, + (uint)OID.SecretGarlic => 3, + (uint)OID.SecretTomato => 2, + (uint)OID.SecretQueen => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/FuathTroublemaker.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/FuathTroublemaker.cs index e32aae197e..afdf9d273e 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/FuathTroublemaker.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/FuathTroublemaker.cs @@ -23,10 +23,10 @@ public enum AID : uint } class CroakingChorus(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.CroakingChorus), "Calls adds"); -class FrigidNeedle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrigidNeedle), new AOEShapeCross(40, 2.5f)); -class Spittle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spittle), 8); +class FrigidNeedle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrigidNeedle), new AOEShapeCross(40f, 2.5f)); +class Spittle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spittle), 8f); class ToyHammer(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.ToyHammer)); -class Hydrocannon(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Hydrocannon), 6, 8, 8); +class Hydrocannon(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Hydrocannon), 6f, 8, 8); class FuathTroublemakerStates : StateMachineBuilder { @@ -38,7 +38,17 @@ public FuathTroublemakerStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(FuathTroublemaker.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(FuathTroublemaker.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -50,17 +60,18 @@ public class FuathTroublemaker(WorldState ws, Actor primary) : THTemplate(ws, pr protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.FuathTrickster), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.FuathTrickster), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.FuathTrickster => 1, + (uint)OID.FuathTrickster => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/GreedyPixie.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/GreedyPixie.cs index dd68ea9ce7..7519215b2a 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/GreedyPixie.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/GreedyPixie.cs @@ -41,15 +41,15 @@ public enum AID : uint Telega = 9630 // BonusAdds->self, no cast, single-target, bonus adds disappear } -class Windrune(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindRune), new AOEShapeRect(40, 4)); -class SongRune(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SongRune), 6); +class Windrune(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindRune), new AOEShapeRect(40f, 4f)); +class SongRune(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SongRune), 6f); class StormRune(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.StormRune)); -abstract class BushBash(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 12); +abstract class BushBash(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 12f); class BushBash1(BossModule module) : BushBash(module, AID.BushBash1); class BushBash2(BossModule module) : BushBash(module, AID.BushBash2); -abstract class NatureCall(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(30, 60.Degrees())); +abstract class NatureCall(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(30f, 60f.Degrees())); class NatureCall1(BossModule module) : NatureCall(module, AID.NatureCall1); class NatureCall2(BossModule module) : NatureCall(module, AID.NatureCall2); @@ -60,9 +60,9 @@ class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class GreedyPixieStates : StateMachineBuilder { @@ -84,7 +84,17 @@ public GreedyPixieStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(GreedyPixie.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(GreedyPixie.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -98,23 +108,24 @@ public class GreedyPixie(WorldState ws, Actor primary) : THTemplate(ws, primary) protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SecretMorpho)); + Arena.Actors(Enemies((uint)OID.SecretMorpho)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 6, - OID.SecretEgg => 5, - OID.SecretGarlic => 4, - OID.SecretTomato or OID.FuathTrickster => 3, - OID.SecretQueen or OID.KeeperOfKeys => 2, - OID.SecretMorpho => 1, + (uint)OID.SecretOnion => 6, + (uint)OID.SecretEgg => 5, + (uint)OID.SecretGarlic => 4, + (uint)OID.SecretTomato or (uint)OID.FuathTrickster => 3, + (uint)OID.SecretQueen or (uint)OID.KeeperOfKeys => 2, + (uint)OID.SecretMorpho => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretBasket.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretBasket.cs index 51ef01504d..0f704574d2 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretBasket.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretBasket.cs @@ -49,11 +49,12 @@ class Earthquake(BossModule module) : Components.RaidwideCastDelay(module, Actio class HeavyStrike(BossModule module) : Components.ConcentricAOEs(module, _shapes) { - private static readonly AOEShape[] _shapes = [new AOEShapeCone(6.5f, 135.Degrees()), new AOEShapeDonutSector(6.5f, 12.5f, 135.Degrees()), new AOEShapeDonutSector(12.5f, 18.5f, 135.Degrees())]; + private static readonly Angle a135 = 135f.Degrees(); + private static readonly AOEShape[] _shapes = [new AOEShapeCone(6.5f, a135), new AOEShapeDonutSector(6.5f, 12.5f, a135), new AOEShapeDonutSector(12.5f, 18.5f, a135)]; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.HeavyStrike1) + if (spell.Action.ID == (uint)AID.HeavyStrike1) AddSequence(spell.LocXZ, Module.CastFinishAt(spell), spell.Rotation); } @@ -61,22 +62,22 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) { if (Sequences.Count != 0) { - var order = (AID)spell.Action.ID switch + var order = spell.Action.ID switch { - AID.HeavyStrike1 => 0, - AID.HeavyStrike2 => 1, - AID.HeavyStrike3 => 2, + (uint)AID.HeavyStrike1 => 0, + (uint)AID.HeavyStrike2 => 1, + (uint)AID.HeavyStrike3 => 2, _ => -1 }; - AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(1.1f), caster.Rotation); + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(1.1d), spell.Rotation); } } } -class PollenCorona(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PollenCorona), 8); +class PollenCorona(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PollenCorona), 8f); class StraightPunch(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.StraightPunch)); -class Leafcutter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Leafcutter), new AOEShapeRect(15, 2)); -class EarthCrusher(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EarthCrusher2), new AOEShapeDonut(10, 20)); +class Leafcutter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Leafcutter), new AOEShapeRect(15f, 2f)); +class EarthCrusher(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EarthCrusher2), new AOEShapeDonut(10f, 20f)); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -85,9 +86,9 @@ class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretBasketStates : StateMachineBuilder { @@ -108,7 +109,17 @@ public SecretBasketStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretBasket.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretBasket.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -122,23 +133,24 @@ public class SecretBasket(WorldState ws, Actor primary) : THTemplate(ws, primary protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SecretEchivore)); + Arena.Actors(Enemies((uint)OID.SecretEchivore)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 6, - OID.SecretEgg => 5, - OID.SecretGarlic => 4, - OID.SecretTomato or OID.FuathTrickster => 3, - OID.SecretQueen or OID.KeeperOfKeys => 2, - OID.SecretEchivore => 1, + (uint)OID.SecretOnion => 6, + (uint)OID.SecretEgg => 5, + (uint)OID.SecretGarlic => 4, + (uint)OID.SecretTomato or (uint)OID.FuathTrickster => 3, + (uint)OID.SecretQueen or (uint)OID.KeeperOfKeys => 2, + (uint)OID.SecretEchivore => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretCladoselache.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretCladoselache.cs index 13c233832a..521e9d37c3 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretCladoselache.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretCladoselache.cs @@ -42,14 +42,14 @@ class PelagicCleaverRotation(BossModule module) : Components.GenericRotatingAOE( private Angle _increment; private Angle _rotation; private DateTime _activation; - private static readonly AOEShapeCone _shape = new(40, 30.Degrees()); + private static readonly AOEShapeCone _shape = new(40f, 30f.Degrees()); public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { - var increment = (IconID)iconID switch + var increment = iconID switch { - IconID.RotateCW => -60.Degrees(), - IconID.RotateCCW => 60.Degrees(), + (uint)IconID.RotateCW => -60.Degrees(), + (uint)IconID.RotateCCW => 60.Degrees(), _ => default }; if (increment != default) @@ -61,18 +61,17 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.PelagicCleaverFirst) + if (spell.Action.ID == (uint)AID.PelagicCleaverFirst) { _rotation = spell.Rotation; _activation = Module.CastFinishAt(spell); - } - if (_rotation != default) InitIfReady(caster); + } } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID is AID.PelagicCleaverFirst or AID.PelagicCleaverRest) + if (spell.Action.ID is (uint)AID.PelagicCleaverFirst or (uint)AID.PelagicCleaverRest) AdvanceSequence(0, WorldState.CurrentTime); } @@ -87,15 +86,15 @@ private void InitIfReady(Actor source) } } -class PelagicCleaver(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PelagicCleaver), new AOEShapeCone(40, 30.Degrees())); -class TidalGuillotine(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TidalGuillotine), 13); +class PelagicCleaver(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PelagicCleaver), new AOEShapeCone(40f, 30f.Degrees())); +class TidalGuillotine(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TidalGuillotine), 13f); class ProtolithicPuncture(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.ProtolithicPuncture)); class BiteAndRun(BossModule module) : Components.BaitAwayChargeCast(module, ActionID.MakeSpell(AID.BiteAndRun), 2.5f); -class AquaticLance(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.AquaticLance), 8); +class AquaticLance(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.AquaticLance), 8f); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretCladoselacheStates : StateMachineBuilder { @@ -111,7 +110,17 @@ public SecretCladoselacheStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretCladoselache.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretCladoselache.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -124,20 +133,21 @@ public class SecretCladoselache(WorldState ws, Actor primary) : THTemplate(ws, p protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SecretShark)); + Arena.Actors(Enemies((uint)OID.SecretShark)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.FuathTrickster => 3, - OID.KeeperOfKeys => 2, - OID.SecretShark => 1, + (uint)OID.FuathTrickster => 3, + (uint)OID.KeeperOfKeys => 2, + (uint)OID.SecretShark => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretDjinn.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretDjinn.cs index 8f5fb7d540..e589928ed9 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretDjinn.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretDjinn.cs @@ -27,18 +27,16 @@ public enum AID : uint Scoop = 21768 // KeeperOfKeys->self, 4.0s cast, range 15 120-degree cone } -class Gust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gust), 6); -class ChangelessWinds(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ChangelessWinds), new AOEShapeRect(40, 4)); -class ChangelessWindsKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.ChangelessWinds), 10, shape: new AOEShapeRect(40, 4), kind: Kind.DirForward, stopAtWall: true); -class Whipwind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Whipwind), new AOEShapeRect(55, 20)); -class WhipwindKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Whipwind), 25, shape: new AOEShapeRect(55, 20, 0.5f), kind: Kind.DirForward, stopAtWall: true); -class GentleBreeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GentleBreeze), new AOEShapeRect(15, 2)); +class Gust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gust), 6f); +class ChangelessWinds(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ChangelessWinds), new AOEShapeRect(40f, 4f)); +class Whipwind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Whipwind), new AOEShapeRect(55f, 20f)); +class GentleBreeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GentleBreeze), new AOEShapeRect(15f, 2f)); class WhirlingGaol(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.WhirlingGaol), "Raidwide + Knockback"); -class WhirlingGaolKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.WhirlingGaol), 25, stopAtWall: true); +class WhirlingGaolKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.WhirlingGaol), 25f, stopAtWall: true); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretDjinnStates : StateMachineBuilder { @@ -47,9 +45,7 @@ public SecretDjinnStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() @@ -59,9 +55,12 @@ public SecretDjinnStates(BossModule module) : base(module) .Raw.Update = () => { var enemies = module.Enemies(SecretDjinn.All); - for (var i = 0; i < enemies.Count; ++i) + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { if (!enemies[i].IsDeadOrDestroyed) return false; + } return true; }; } @@ -76,20 +75,21 @@ public class SecretDjinn(WorldState ws, Actor primary) : THTemplate(ws, primary) protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SecretRabbitsTail)); + Arena.Actors(Enemies((uint)OID.SecretRabbitsTail)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.FuathTrickster => 3, - OID.KeeperOfKeys => 2, - OID.SecretRabbitsTail => 1, + (uint)OID.FuathTrickster => 3, + (uint)OID.KeeperOfKeys => 2, + (uint)OID.SecretRabbitsTail => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs index aedd4cb489..42ededabe5 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs @@ -26,16 +26,35 @@ public enum AID : uint Scoop = 21768 // KeeperOfKeys->self, 4.0s cast, range 15 120-degree cone } -class Buffet(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Buffet), new AOEShapeCone(11, 60.Degrees())); -class Inhale(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.InhaleBoss), new AOEShapeCone(20, 60.Degrees())); -class InhalePull(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.InhaleBoss), 20, false, 1, new AOEShapeCone(20, 60.Degrees()), Kind.TowardsOrigin, default, true); -class HeavyScrapline(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavyScrapline), 11); -class MoldyPhlegm(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(AID.MoldyPhlegm), m => m.Enemies(OID.ResinVoidzone).Where(z => z.EventState != 7), 1.4f); -class MoldySneeze(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MoldySneeze), new AOEShapeCone(12, 60.Degrees())); +class Buffet(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Buffet), new AOEShapeCone(11f, 60f.Degrees())); +class Inhale(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.InhaleBoss), new AOEShapeCone(20f, 60f.Degrees())); +class InhalePull(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.InhaleBoss), 20f, false, 1, new AOEShapeCone(20f, 60f.Degrees()), Kind.TowardsOrigin, default, true); +class HeavyScrapline(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavyScrapline), 11f); +class MoldyPhlegm(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6f, ActionID.MakeSpell(AID.MoldyPhlegm), GetVoidzones, 1.4f) +{ + private static Actor[] GetVoidzones(BossModule module) + { + var enemies = module.Enemies((uint)OID.ResinVoidzone); + var count = enemies.Count; + if (count == 0) + return []; -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); + var voidzones = new Actor[count]; + var index = 0; + for (var i = 0; i < count; ++i) + { + var z = enemies[i]; + if (z.EventState != 7) + voidzones[index++] = z; + } + return voidzones[..index]; + } +} +class MoldySneeze(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MoldySneeze), new AOEShapeCone(12f, 60f.Degrees())); + +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretKeeperStates : StateMachineBuilder { @@ -51,7 +70,17 @@ public SecretKeeperStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretKeeper.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretKeeper.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -69,13 +98,14 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.FuathTrickster => 2, - OID.KeeperOfKeys => 1, + (uint)OID.FuathTrickster => 2, + (uint)OID.KeeperOfKeys => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKorrigan.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKorrigan.cs index a75c025f62..897094a0df 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKorrigan.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKorrigan.cs @@ -32,7 +32,7 @@ public enum AID : uint class Hypnotize(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.Hypnotize)); class Ram(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.Ram)); class SaibaiMandragora(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.SaibaiMandragora), "Calls adds"); -class LeafDagger(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LeafDagger), 3); +class LeafDagger(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LeafDagger), 3f); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -55,7 +55,17 @@ public SecretKorriganStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretKorrigan.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretKorrigan.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -69,23 +79,24 @@ public class SecretKorrigan(WorldState ws, Actor primary) : THTemplate(ws, prima protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SecretMandragora)); + Arena.Actors(Enemies((uint)OID.SecretMandragora)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 6, - OID.SecretEgg => 5, - OID.SecretGarlic => 4, - OID.SecretTomato => 3, - OID.SecretQueen => 2, - OID.SecretMandragora => 1, + (uint)OID.SecretOnion => 6, + (uint)OID.SecretEgg => 5, + (uint)OID.SecretGarlic => 4, + (uint)OID.SecretTomato => 3, + (uint)OID.SecretQueen => 2, + (uint)OID.SecretMandragora => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPegasus.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPegasus.cs index 180d4ba955..29de58bb19 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPegasus.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPegasus.cs @@ -36,14 +36,14 @@ public enum AID : uint Telega = 9630 // KeeperOfKeys->self, no cast, single-target, bonus adds disappear } -class BurningBright(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BurningBright), new AOEShapeRect(47, 3)); -class Nicker(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Nicker), 12); +class BurningBright(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BurningBright), new AOEShapeRect(47f, 3f)); +class Nicker(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Nicker), 12f); class CloudCall(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.CloudCall), "Calls thunderclouds"); -class LightningBolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightningBolt), 8); +class LightningBolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightningBolt), 8f); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -70,7 +70,17 @@ public SecretPegasusStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretPegasus.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretPegasus.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -89,16 +99,17 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 5, - OID.SecretEgg => 4, - OID.SecretGarlic => 3, - OID.SecretTomato or OID.FuathTrickster => 2, - OID.SecretQueen or OID.KeeperOfKeys => 1, + (uint)OID.SecretOnion => 5, + (uint)OID.SecretEgg => 4, + (uint)OID.SecretGarlic => 3, + (uint)OID.SecretTomato or (uint)OID.FuathTrickster => 2, + (uint)OID.SecretQueen or (uint)OID.KeeperOfKeys => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPorxie.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPorxie.cs index 1ea752f514..0e9f487b63 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPorxie.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretPorxie.cs @@ -42,26 +42,28 @@ public enum AID : uint TearyTwirl = 6448, // SecretOnion->self, 3.5s cast, range 6+R circle HeirloomScream = 6451, // SecretTomato->self, 3.5s cast, range 6+R circle PluckAndPrune = 6449, // SecretEgg->self, 3.5s cast, range 6+R circle - PungentPirouette = 6450, // SecretGarlic->self, 3.5s cast, range 6+R circle + PungentPirouette = 6450 // SecretGarlic->self, 3.5s cast, range 6+R circle } -class BrewingStorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BrewingStorm), new AOEShapeCone(5, 30.Degrees())); -class HarrowingDream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HarrowingDream), 6); -class BecloudingDust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BecloudingDust), 6); +class BrewingStorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BrewingStorm), new AOEShapeCone(5f, 30f.Degrees())); +class HarrowingDream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HarrowingDream), 6f); +class BecloudingDust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BecloudingDust), 6f); -class Sweep(BossModule module) : Components.Exaflare(module, 6) +class Sweep(BossModule module) : Components.Exaflare(module, 6f) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.SweepStart) - Lines.Add(new() { Next = caster.Position, Advance = 12 * spell.Rotation.ToDirection(), NextExplosion = Module.CastFinishAt(spell, 0.9f), TimeToMove = 4.5f, ExplosionsLeft = 4, MaxShownExplosions = 3 }); + if (spell.Action.ID == (uint)AID.SweepStart) + Lines.Add(new() { Next = caster.Position, Advance = 12f * spell.Rotation.ToDirection(), NextExplosion = Module.CastFinishAt(spell, 0.9f), TimeToMove = 4.5f, ExplosionsLeft = 4, MaxShownExplosions = 3 }); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if (Lines.Count > 0 && (AID)spell.Action.ID == AID.SweepRest) + if (Lines.Count != 0 && spell.Action.ID == (uint)AID.SweepRest) { - var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1)); + var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1f)); + if (index == -1) + return; AdvanceLine(Lines[index], caster.Position); if (Lines[index].ExplosionsLeft == 0) Lines.RemoveAt(index); @@ -69,9 +71,9 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } } -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -97,7 +99,17 @@ public SecretPorxieStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretPorxie.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretPorxie.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -116,16 +128,17 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 5, - OID.SecretEgg => 4, - OID.SecretGarlic => 3, - OID.SecretTomato => 2, - OID.SecretQueen or OID.KeeperOfKeys => 1, + (uint)OID.SecretOnion => 5, + (uint)OID.SecretEgg => 4, + (uint)OID.SecretGarlic => 3, + (uint)OID.SecretTomato => 2, + (uint)OID.SecretQueen or (uint)OID.KeeperOfKeys => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSerpent.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSerpent.cs index 100719576a..90ff15d88a 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSerpent.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSerpent.cs @@ -37,12 +37,31 @@ public enum AID : uint Telega = 9630 // Mandragoras->self, no cast, single-target, bonus adds disappear } -class DouseVoidzone(BossModule module) : Components.PersistentVoidzone(module, 7.5f, m => m.Enemies(OID.WaterVoidzone).Where(z => z.EventState != 7), 0); -class Douse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Douse), 8); +class DouseVoidzone(BossModule module) : Components.PersistentVoidzone(module, 7.5f, GetVoidzones) +{ + private static Actor[] GetVoidzones(BossModule module) + { + var enemies = module.Enemies((uint)OID.WaterVoidzone); + var count = enemies.Count; + if (count == 0) + return []; + + var voidzones = new Actor[count]; + var index = 0; + for (var i = 0; i < count; ++i) + { + var z = enemies[i]; + if (z.EventState != 7) + voidzones[index++] = z; + } + return voidzones[..index]; + } +} +class Douse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Douse), 8f); class FangsEnd(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.FangsEnd)); -class Drench1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Drench1), new AOEShapeCone(15.29f, 45.Degrees())); -class Drench2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Drench2), new AOEShapeCone(13.45f, 45.Degrees())); -class ScaleRipple(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ScaleRipple), 8); +class Drench1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Drench1), new AOEShapeCone(15.29f, 45f.Degrees())); +class Drench2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Drench2), new AOEShapeCone(13.45f, 45f.Degrees())); +class ScaleRipple(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ScaleRipple), 8f); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -51,9 +70,9 @@ class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretSerpentStates : StateMachineBuilder { @@ -74,7 +93,17 @@ public SecretSerpentStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretSerpent.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretSerpent.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -88,23 +117,24 @@ public class SecretSerpent(WorldState ws, Actor primary) : THTemplate(ws, primar protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SerpentHatchling)); + Arena.Actors(Enemies((uint)OID.SerpentHatchling)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 6, - OID.SecretEgg => 5, - OID.SecretGarlic => 4, - OID.SecretTomato => 3, - OID.SecretQueen or OID.KeeperOfKeys => 2, - OID.SerpentHatchling => 1, + (uint)OID.SecretOnion => 6, + (uint)OID.SecretEgg => 5, + (uint)OID.SecretGarlic => 4, + (uint)OID.SecretTomato => 3, + (uint)OID.SecretQueen or (uint)OID.KeeperOfKeys => 2, + (uint)OID.SerpentHatchling => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSwallow.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSwallow.cs index 78609b7188..de3494fc50 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSwallow.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretSwallow.cs @@ -29,21 +29,15 @@ public enum AID : uint Scoop = 21768 // KeeperOfKeys->self, 4.0s cast, range 15 120-degree cone } -class ElectricWhorl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SeventhWave), 11); -class PrevailingCurrent(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PrevailingCurrent), new AOEShapeRect(24, 3)); -class SeventhWave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ElectricWhorl), new AOEShapeDonut(8, 60)); -class Hydrocannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon2), 8); +class ElectricWhorl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SeventhWave), 11f); +class PrevailingCurrent(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PrevailingCurrent), new AOEShapeRect(24f, 3f)); +class SeventhWave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ElectricWhorl), new AOEShapeDonut(8f, 60f)); +class Hydrocannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon2), 8f); class Ceras(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Ceras)); -class BodySlam(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BodySlam), 10); - -class BodySlamKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.BodySlam), 20, shape: new AOEShapeCircle(10), 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; -} - -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class BodySlam(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BodySlam), 10f); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretSwallowStates : StateMachineBuilder { @@ -56,11 +50,20 @@ public SecretSwallowStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretSwallow.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretSwallow.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -73,20 +76,21 @@ public class SecretSwallow(WorldState ws, Actor primary) : THTemplate(ws, primar protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.SwallowHatchling)); + Arena.Actors(Enemies((uint)OID.SwallowHatchling)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.FuathTrickster => 3, - OID.KeeperOfKeys => 2, - OID.SwallowHatchling => 1, + (uint)OID.FuathTrickster => 3, + (uint)OID.KeeperOfKeys => 2, + (uint)OID.SwallowHatchling => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretUndine.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretUndine.cs index 3efb94efb5..0997da8d2e 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretUndine.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretUndine.cs @@ -39,11 +39,11 @@ public enum AID : uint Telega = 9630 // Mandragoras/KeeperOfKeys->self, no cast, single-target, bonus adds disappear } -class Hydrofan(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrofan), new AOEShapeCone(44, 15.Degrees())); -class Hypnowave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hypnowave), new AOEShapeCone(30, 60.Degrees())); -class Hydropins(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydropins), new AOEShapeRect(12, 2)); -class AquaGlobe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaGlobe), 8); -class Hydrowhirl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrowhirl), 8); +class Hydrofan(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrofan), new AOEShapeCone(44f, 15f.Degrees())); +class Hypnowave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hypnowave), new AOEShapeCone(30f, 60f.Degrees())); +class Hydropins(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydropins), new AOEShapeRect(12f, 2f)); +class AquaGlobe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaGlobe), 8f); +class Hydrowhirl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrowhirl), 8f); class Hydrotaph(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Hydrotaph)); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); @@ -53,9 +53,9 @@ class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); -class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); -class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15, 60.Degrees())); +class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11f); +class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13f, 2f)); +class Scoop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Scoop), new AOEShapeCone(15f, 60f.Degrees())); class SecretUndineStates : StateMachineBuilder { @@ -76,7 +76,17 @@ public SecretUndineStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretUndine.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretUndine.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -90,23 +100,24 @@ public class SecretUndine(WorldState ws, Actor primary) : THTemplate(ws, primary protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AqueousAether)); + Arena.Actors(Enemies((uint)OID.AqueousAether)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 6, - OID.SecretEgg => 5, - OID.SecretGarlic => 4, - OID.SecretTomato => 3, - OID.SecretQueen or OID.KeeperOfKeys => 2, - OID.AqueousAether => 1, + (uint)OID.SecretOnion => 6, + (uint)OID.SecretEgg => 5, + (uint)OID.SecretGarlic => 4, + (uint)OID.SecretTomato => 3, + (uint)OID.SecretQueen or (uint)OID.KeeperOfKeys => 2, + (uint)OID.AqueousAether => 1, _ => 0 }; } diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretWorm.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretWorm.cs index 85cc814b2d..8e6a80528e 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretWorm.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretWorm.cs @@ -36,15 +36,34 @@ public enum IconID : uint Baitaway = 23 // player } -class Hydrocannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon), 8); -class FreshwaterCannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FreshwaterCannon), new AOEShapeRect(46, 2)); -class AquaBurst(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaBurst), 10); +class Hydrocannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hydrocannon), 8f); +class FreshwaterCannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FreshwaterCannon), new AOEShapeRect(46f, 2f)); +class AquaBurst(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AquaBurst), 10f); class BrineBreath(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.BrineBreath)); -class Hydroburst(BossModule module) : Components.PersistentVoidzone(module, 10, m => m.Enemies(OID.Bubble).Where(x => !x.IsDead && !(x.CastInfo != null && x.CastInfo.IsSpell(AID.AquaBurst)))); +class Hydroburst(BossModule module) : Components.PersistentVoidzone(module, 10f, GetVoidzones) +{ + private static Actor[] GetVoidzones(BossModule module) + { + var enemies = module.Enemies((uint)OID.Bubble); + var count = enemies.Count; + if (count == 0) + return []; + + var voidzones = new Actor[count]; + var index = 0; + for (var i = 0; i < count; ++i) + { + var z = enemies[i]; + if (!z.IsDead && !(z.CastInfo != null && z.CastInfo.IsSpell(AID.AquaBurst))) + voidzones[index++] = z; + } + return voidzones[..index]; + } +} class Bubble(BossModule module) : Components.GenericBaitAway(module) { - private static readonly AOEShapeCircle circle = new(10); + private static readonly AOEShapeCircle circle = new(10f); public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { @@ -54,21 +73,24 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.Hydrocannon) + if (spell.Action.ID == (uint)AID.Hydrocannon) CurrentBaits.Clear(); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == actor) hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 17.5f)); } public override void AddHints(int slot, Actor actor, TextHints hints) { - base.AddHints(slot, actor, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) + base.AddHints(slot, actor, hints); + else hints.Add("Bait bubble away!"); } } @@ -96,7 +118,17 @@ public SecretWormStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(SecretWorm.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(SecretWorm.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -115,16 +147,17 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.SecretOnion => 5, - OID.SecretEgg => 4, - OID.SecretGarlic => 3, - OID.SecretTomato => 2, - OID.SecretQueen => 1, + (uint)OID.SecretOnion => 5, + (uint)OID.SecretEgg => 4, + (uint)OID.SecretGarlic => 3, + (uint)OID.SecretTomato => 2, + (uint)OID.SecretQueen => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs index d4d5adcded..c43b93e10e 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs @@ -59,21 +59,21 @@ public enum AID : uint Telega = 9630 // Mandragoras/Abharamu/NamazuStickywhisker->self, no cast, single-target, bonus adds disappear } -abstract class Hurl(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6); +abstract class Hurl(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6f); class HurlBoss(BossModule module) : Hurl(module, AID.HurlBoss); class HurlBonusAdd(BossModule module) : Hurl(module, AID.Hurl); -class SpinBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinBoss), new AOEShapeCone(20, 60.Degrees())); -class BarbarousScream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BarbarousScream), 14); +class SpinBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinBoss), new AOEShapeCone(20f, 60f.Degrees())); +class BarbarousScream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BarbarousScream), 14f); class Buffet(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Buffet)); -class DoubleSmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DoubleSmash), new AOEShapeCone(7.95f, 60.Degrees())); -class AncientAero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientAero), new AOEShapeRect(13.6f, 2)); -class RingOfFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RingOfFire), 5); +class DoubleSmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DoubleSmash), new AOEShapeCone(7.95f, 60f.Degrees())); +class AncientAero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientAero), new AOEShapeRect(13.6f, 2f)); +class RingOfFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RingOfFire), 5f); class StoneII(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.StoneII)); -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.Abharamu]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.Abharamu]); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -99,7 +99,17 @@ public AiravataStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Airavata.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(Airavata.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -120,19 +130,20 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.CanalOnion => 7, - OID.CanalEgg => 6, - OID.CanalGarlic => 5, - OID.CanalTomato => 4, - OID.CanalQueen or OID.NamazuStickywhisker => 3, - OID.Abharamu => 2, - OID.CanalFireHomunculus or OID.CanalIceHomunculus or OID.CanalWindHomunculus or OID.CanalLightningHomunculus or OID.CanalAnala or OID.CanalAnila or - OID.GoldenApa or OID.GoldenDhara => 2, + (uint)OID.CanalOnion => 7, + (uint)OID.CanalEgg => 6, + (uint)OID.CanalGarlic => 5, + (uint)OID.CanalTomato => 4, + (uint)OID.CanalQueen or (uint)OID.NamazuStickywhisker => 3, + (uint)OID.Abharamu => 2, + (uint)OID.CanalFireHomunculus or (uint)OID.CanalIceHomunculus or (uint)OID.CanalWindHomunculus or (uint)OID.CanalLightningHomunculus or + (uint)OID.CanalAnala or (uint)OID.CanalAnila or (uint)OID.GoldenApa or (uint)OID.GoldenDhara => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs index b630ffc8b3..7647ff65f9 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs @@ -29,12 +29,12 @@ public enum AID : uint } class Eyeshine(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.Eyeshine)); -class AbsoluteZero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbsoluteZero), new AOEShapeCone(45.5f, 45.Degrees())); -class Freezeover(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Freezeover), 6); +class AbsoluteZero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbsoluteZero), new AOEShapeCone(45.5f, 45f.Degrees())); +class Freezeover(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Freezeover), 6f); class PlainPound(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PlainPound), 4.56f); -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.Abharamu]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.Abharamu]); class CanalIcebeastStates : StateMachineBuilder { @@ -48,7 +48,17 @@ public CanalIcebeastStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(CanalIcebeast.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(CanalIcebeast.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -62,18 +72,19 @@ protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); Arena.Actors(Enemies(trash)); - Arena.Actors(Enemies(OID.Abharamu), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.Abharamu), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.Abharamu => 2, - OID.CanalVindthurs or OID.CanalIceHomunculus => 1, + (uint)OID.Abharamu => 2, + (uint)OID.CanalVindthurs or (uint)OID.CanalIceHomunculus => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs index fa837339c2..97bef94baa 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs @@ -31,12 +31,12 @@ public enum IconID : uint BuffetTarget = 23 // player } -class HurlBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HurlBoss), 6); -class SpinBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinBoss), new AOEShapeCone(30, 60.Degrees())); -class BarbarousScream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BarbarousScream), 13); +class HurlBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HurlBoss), 6f); +class SpinBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpinBoss), new AOEShapeCone(30f, 60f.Degrees())); +class BarbarousScream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BarbarousScream), 13f); class Huff(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.Huff)); -class Buffet(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Buffet), 20, kind: Kind.DirForward, stopAtWall: true) +class Buffet(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Buffet), 20f, kind: Kind.DirForward, stopAtWall: true) { private bool targeted; private Actor? target; @@ -55,7 +55,7 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastFinished(Actor caster, ActorCastInfo spell) { base.OnCastFinished(caster, spell); - if ((AID)spell.Action.ID == AID.Buffet) + if (spell.Action.ID == (uint)AID.Buffet) targeted = false; } @@ -70,11 +70,11 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme { base.AddAIHints(slot, actor, assignment, hints); if (target == actor && targeted) - hints.AddForbiddenZone(ShapeDistance.Circle(Module.Center, 17.5f)); + hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 17.5f)); } } -class Buffet2(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.Buffet), new AOEShapeCone(30, 60.Degrees()), true) +class Buffet2(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.Buffet), new AOEShapeCone(30f, 60f.Degrees()), true) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { @@ -95,9 +95,9 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) } } -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); class AltarAiravataStates : StateMachineBuilder { @@ -113,7 +113,17 @@ public AltarAiravataStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarAiravata.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarAiravata.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -131,13 +141,14 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.GoldWhisker => 2, - OID.AltarMatanga => 1, + (uint)OID.GoldWhisker => 2, + (uint)OID.AltarMatanga => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs index 490f035367..3794ba062c 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs @@ -33,15 +33,15 @@ public enum AID : uint class DarkSpike(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.DarkSpike)); class FrondAffeared(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.FrondAffeared)); -class SilkenSpray(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SilkenSpray), new AOEShapeCone(24, 30.Degrees())); +class SilkenSpray(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SilkenSpray), new AOEShapeCone(24f, 30f.Degrees())); class Implosion(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Implosion)); class Earthquake1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthquake1), 10.5f); -class Earthquake2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthquake2), new AOEShapeDonut(10, 20)); -class Earthquake3(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthquake3), new AOEShapeDonut(20, 30)); +class Earthquake2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthquake2), new AOEShapeDonut(10f, 20f)); +class Earthquake3(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthquake3), new AOEShapeDonut(20f, 30f)); -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); class AltarArachneStates : StateMachineBuilder { @@ -58,7 +58,17 @@ public AltarArachneStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarArachne.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarArachne.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -76,13 +86,14 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.GoldWhisker => 2, - OID.AltarMatanga => 1, + (uint)OID.GoldWhisker => 2, + (uint)OID.AltarMatanga => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs index 4c43d505c7..003d651959 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs @@ -38,11 +38,11 @@ public enum AID : uint Telega = 9630 // AltarMatanga/Mandragoras->self, no cast, single-target, bonus adds disappear } -class RustingClaw(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RustingClaw), new AOEShapeCone(12.6f, 60.Degrees())); -class TailDrive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailDrive), new AOEShapeCone(34.6f, 60.Degrees())); -class TheSpin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheSpin), 15); -class WordsOfWoe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WordsOfWoe), new AOEShapeRect(49.6f, 3)); -class VengefulSoul(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VengefulSoul), 6); +class RustingClaw(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RustingClaw), new AOEShapeCone(12.6f, 60f.Degrees())); +class TailDrive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailDrive), new AOEShapeCone(34.6f, 60f.Degrees())); +class TheSpin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheSpin), 15f); +class WordsOfWoe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WordsOfWoe), new AOEShapeRect(49.6f, 3f)); +class VengefulSoul(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VengefulSoul), 6f); class EyeOfTheFire(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.EyeOfTheFire)); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); @@ -52,9 +52,9 @@ class HeirloomScream(BossModule module) : Mandragoras(module, AID.HeirloomScream class PungentPirouette(BossModule module) : Mandragoras(module, AID.PungentPirouette); class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); class AltarBeastStates : StateMachineBuilder { @@ -75,7 +75,17 @@ public AltarBeastStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarBeast.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarBeast.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -89,23 +99,24 @@ public class AltarBeast(WorldState ws, Actor primary) : THTemplate(ws, primary) protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarKeeper)); + Arena.Actors(Enemies((uint)OID.AltarKeeper)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen or OID.AltarMatanga => 2, - OID.AltarKeeper => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen or (uint)OID.AltarMatanga => 2, + (uint)OID.AltarKeeper => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs index 0fd1547705..b1a03924aa 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs @@ -34,18 +34,37 @@ public enum IconID : uint Baitaway = 23 // player } -class TheScorpionsSting(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheScorpionsSting), new AOEShapeCone(11.92f, 45.Degrees())); +class TheScorpionsSting(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheScorpionsSting), new AOEShapeCone(11.92f, 45f.Degrees())); class TheRamsVoice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheRamsVoice), 9.92f); class TheRamsVoiceHint(BossModule module) : Components.CastInterruptHint(module, ActionID.MakeSpell(AID.TheRamsVoice)); -class TheLionsBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheLionsBreath), new AOEShapeCone(11.92f, 60.Degrees())); -class LanguorousGaze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LanguorousGaze), new AOEShapeCone(8.07f, 45.Degrees())); -class TheDragonsVoice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheDragonsVoice), new AOEShapeDonut(8, 30)); +class TheLionsBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheLionsBreath), new AOEShapeCone(11.92f, 60f.Degrees())); +class LanguorousGaze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LanguorousGaze), new AOEShapeCone(8.07f, 45f.Degrees())); +class TheDragonsVoice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheDragonsVoice), new AOEShapeDonut(8f, 30f)); class TheDragonsVoiceHint(BossModule module) : Components.CastInterruptHint(module, ActionID.MakeSpell(AID.TheDragonsVoice)); -class TheRamsKeeper(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(AID.TheRamsKeeper), m => m.Enemies(OID.IceVoidzone).Where(z => z.EventState != 7), 0.9f); +class TheRamsKeeper(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6f, ActionID.MakeSpell(AID.TheRamsKeeper), GetVoidzones, 0.9f) +{ + private static Actor[] GetVoidzones(BossModule module) + { + var enemies = module.Enemies((uint)OID.IceVoidzone); + var count = enemies.Count; + if (count == 0) + return []; + + var voidzones = new Actor[count]; + var index = 0; + for (var i = 0; i < count; ++i) + { + var z = enemies[i]; + if (z.EventState != 7) + voidzones[index++] = z; + } + return voidzones[..index]; + } +} class TheRamsKeeperBait(BossModule module) : Components.GenericBaitAway(module) { - private static readonly AOEShapeCircle circle = new(6); + private static readonly AOEShapeCircle circle = new(6f); public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { @@ -55,28 +74,31 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.TheRamsKeeper) + if (spell.Action.ID == (uint)AID.TheRamsKeeper) CurrentBaits.Clear(); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == actor) hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 17.5f)); } public override void AddHints(int slot, Actor actor, TextHints hints) { - base.AddHints(slot, actor, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) + base.AddHints(slot, actor, hints); + else hints.Add("Bait away!"); } } -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); class AltarChimeraStates : StateMachineBuilder { @@ -95,7 +117,17 @@ public AltarChimeraStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarChimera.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarChimera.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -107,19 +139,20 @@ public class AltarChimera(WorldState ws, Actor primary) : THTemplate(ws, primary protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarAhriman)); - Arena.Actors(Enemies(OID.AltarMatanga), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.AltarAhriman)); + Arena.Actors(Enemies((uint)OID.AltarMatanga), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarMatanga => 2, - OID.AltarAhriman => 1, + (uint)OID.AltarMatanga => 2, + (uint)OID.AltarAhriman => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs index 4fba571698..e9b3464d91 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs @@ -37,12 +37,31 @@ public enum IconID : uint } class DeadlyHold(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.DeadlyHold)); -class HeatBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeatBreath), new AOEShapeCone(14.6f, 45.Degrees())); -class TailSmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSmash), new AOEShapeCone(26.6f, 45.Degrees())); +class HeatBreath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeatBreath), new AOEShapeCone(14.6f, 45f.Degrees())); +class TailSmash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSmash), new AOEShapeCone(26.6f, 45f.Degrees())); class RagingInferno(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.RagingInferno)); -class Comet(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Comet), 4); -class HardStomp(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HardStomp), 10); -class Fireball(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(AID.Fireball), m => m.Enemies(OID.FireVoidzone).Where(z => z.EventState != 7), 0.7f); +class Comet(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Comet), 4f); +class HardStomp(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HardStomp), 10f); +class Fireball(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6f, ActionID.MakeSpell(AID.Fireball), GetVoidzones, 0.7f) +{ + private static Actor[] GetVoidzones(BossModule module) + { + var enemies = module.Enemies((uint)OID.FireVoidzone); + var count = enemies.Count; + if (count == 0) + return []; + + var voidzones = new Actor[count]; + var index = 0; + for (var i = 0; i < count; ++i) + { + var z = enemies[i]; + if (z.EventState != 7) + voidzones[index++] = z; + } + return voidzones[..index]; + } +} class FireballBait(BossModule module) : Components.GenericBaitAway(module) { @@ -56,7 +75,7 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.Fireball) + if (spell.Action.ID == (uint)AID.Fireball) ++NumCasts; if (NumCasts == 3) { @@ -68,21 +87,24 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == actor) hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 17.5f)); } public override void AddHints(int slot, Actor actor, TextHints hints) { - base.AddHints(slot, actor, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) + base.AddHints(slot, actor, hints); + else hints.Add("Bait away! (3 times)"); } } -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); class AltarDiresaurStates : StateMachineBuilder { @@ -100,7 +122,17 @@ public AltarDiresaurStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarDiresaur.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarDiresaur.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -113,20 +145,21 @@ public class AltarDiresaur(WorldState ws, Actor primary) : THTemplate(ws, primar protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarDragon)); + Arena.Actors(Enemies((uint)OID.AltarDragon)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.GoldWhisker => 3, - OID.AltarMatanga => 2, - OID.AltarDragon => 1, + (uint)OID.GoldWhisker => 3, + (uint)OID.AltarMatanga => 2, + (uint)OID.AltarDragon => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs index e19b2d7ff2..6a086e887a 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs @@ -38,18 +38,30 @@ public enum AID : uint } class IronJustice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IronJustice), new AOEShapeCone(11.8f, 60.Degrees())); -class Cloudcover(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cloudcover), 6); -class TerrorEye(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TerrorEye), 6); -class VillainousRebuke(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.VillainousRebuke), 6, 8, 8); +class Cloudcover(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cloudcover), 6f); +class TerrorEye(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TerrorEye), 6f); +class VillainousRebuke(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.VillainousRebuke), 6f, 8, 8); class StygianRelease(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.StygianRelease)); -class StygianReleaseKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.StygianRelease), 20, stopAtWall: true) +class StygianReleaseKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.StygianRelease), 20f, 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; + private readonly TerrorEye _aoe = module.FindComponent()!; + + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + var count = _aoe.Casters.Count; + for (var i = 0; i < count; ++i) + { + var caster = _aoe.Casters[i]; + if (caster.Check(pos)) + return true; + } + return false; + } } -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -77,7 +89,17 @@ public AltarDullahanStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarDullahan.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarDullahan.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -91,23 +113,24 @@ public class AltarDullahan(WorldState ws, Actor primary) : THTemplate(ws, primar protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarVodoriga)); + Arena.Actors(Enemies((uint)OID.AltarVodoriga)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen or OID.AltarMatanga => 2, - OID.AltarVodoriga => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen or (uint)OID.AltarMatanga => 2, + (uint)OID.AltarVodoriga => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs index c2eb0ed05d..5a8d53766c 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs @@ -44,43 +44,63 @@ class Innocence(BossModule module) : Components.SimpleAOEs(module, ActionID.Make class BloodyPuddle(BossModule module) : Components.GenericAOEs(module) { private static readonly AOEShapeCircle circle = new(11.2f); - private readonly List _spheres = []; - private DateTime _activation; + public readonly List AOEs = new(3); - public override IEnumerable ActiveAOEs(int slot, Actor actor) - { - for (var i = 0; i < _spheres.Count; ++i) - yield return new(circle, _spheres[i].Position, default, _activation); - } + public override IEnumerable ActiveAOEs(int slot, Actor actor) => AOEs; public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.Hydrosphere) - { - _spheres.Add(actor); - _activation = WorldState.FutureTime(8.6f); - } + if (actor.OID == (uint)OID.Hydrosphere) + AOEs.Add(new(circle, WPos.ClampToGrid(actor.Position), default, WorldState.FutureTime(8.6d))); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.BloodyPuddle) - _spheres.Clear(); + if (AOEs.Count != 0 && spell.Action.ID == (uint)AID.BloodyPuddle) + AOEs.Clear(); } } class Torpedo(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.Torpedo)); class RisingSeas(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.RisingSeas)); -class HydroPushKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.HydroPush), 20, shape: new AOEShapeRect(44.4f, 22, 5), kind: Kind.DirForward, stopAtWall: true); -class RisingSeasKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.RisingSeas), 20, stopAtWall: true) +class RisingSeasKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.RisingSeas), 20f, 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; + private readonly BloodyPuddle _aoe = module.FindComponent()!; + private static readonly Angle cone = 37.5f.Degrees(); + + public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) + { + var count = _aoe.AOEs.Count; + for (var i = 0; i < count; ++i) + { + var caster = _aoe.AOEs[i]; + if (caster.Check(pos)) + return true; + } + return false; + } + + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + var source = Casters.Count != 0 ? Casters[0] : null; + if (source != null) + { + var count = _aoe.AOEs.Count; + var forbidden = new Func[count]; + for (var i = 0; i < count; ++i) + { + forbidden[i] = ShapeDistance.Cone(Arena.Center, 20f, Angle.FromDirection(_aoe.AOEs[i].Origin - Arena.Center), cone); + } + if (forbidden.Length != 0) + hints.AddForbiddenZone(ShapeDistance.Union(forbidden), Module.CastFinishAt(source.CastInfo)); + } + } } -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -100,7 +120,6 @@ public AltarKelpieStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() @@ -109,7 +128,17 @@ public AltarKelpieStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarKelpie.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarKelpie.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -128,17 +157,18 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen or OID.GoldWhisker => 2, - OID.AltarMatanga => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen or (uint)OID.GoldWhisker => 2, + (uint)OID.AltarMatanga => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarMandragora.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarMandragora.cs index 31183569e6..9bdce476b7 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarMandragora.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarMandragora.cs @@ -31,9 +31,9 @@ public enum AID : uint } class OpticalIntrusion(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.OpticalIntrusion)); -class Hypnotize(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hypnotize), new AOEShapeCone(22.85f, 45.Degrees())); +class Hypnotize(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hypnotize), new AOEShapeCone(22.85f, 45f.Degrees())); class SaibaiMandragora(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.SaibaiMandragora), "Calls adds"); -class LeafDagger(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LeafDagger), 3); +class LeafDagger(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LeafDagger), 3f); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); @@ -56,7 +56,17 @@ public AltarMandragoraStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarMandragora.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarMandragora.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -70,23 +80,24 @@ public class AltarMandragora(WorldState ws, Actor primary) : THTemplate(ws, prim protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarKorrigan)); + Arena.Actors(Enemies((uint)OID.AltarKorrigan)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen => 2, - OID.AltarKorrigan => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen => 2, + (uint)OID.AltarKorrigan => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs index 1b2b6d1dbe..229cfa6ea9 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs @@ -23,17 +23,17 @@ public enum AID : uint Spin = 8599, // AltarMatanga->self, no cast, range 6+R 120-degree cone RaucousScritch = 8598, // AltarMatanga->self, 2.5s cast, range 5+R 120-degree cone Hurl = 5352, // AltarMatanga->location, 3.0s cast, range 6 circle - Telega = 963, // AltarMatanga->self, no cast, single-target, bonus adds disappear + Telega = 963 // AltarMatanga->self, no cast, single-target, bonus adds disappear } class Chirp(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Chirp), 12.48f); -class Tornado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Tornado), 6); +class Tornado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Tornado), 6f); class VoidCall(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.VoidCall), "Calls adds"); class RecklessAbandon(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.RecklessAbandon)); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); class AltarSkateneStates : StateMachineBuilder { @@ -47,7 +47,17 @@ public AltarSkateneStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarSkatene.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarSkatene.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -59,19 +69,20 @@ public class AltarSkatene(WorldState ws, Actor primary) : THTemplate(ws, primary protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarDeepeye)); - Arena.Actors(Enemies(OID.AltarMatanga), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.AltarDeepeye)); + Arena.Actors(Enemies((uint)OID.AltarMatanga), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarMatanga => 2, - OID.AltarDeepeye => 1, + (uint)OID.AltarMatanga => 2, + (uint)OID.AltarDeepeye => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs index d07c4b6778..3c79a432de 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs @@ -33,15 +33,34 @@ public enum IconID : uint Baitaway = 23 // player } -class FlurryOfRage(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlurryOfRage), new AOEShapeCone(13.06f, 60.Degrees())); -class WaveOfMalice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WaveOfMalice), 5); +class FlurryOfRage(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlurryOfRage), new AOEShapeCone(13.06f, 60f.Degrees())); +class WaveOfMalice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WaveOfMalice), 5f); class WhorlOfFrenzy(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WhorlOfFrenzy), 11.06f); -class TheWardensVerdict(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheWardensVerdict), new AOEShapeRect(45.06f, 2)); -class FlamesOfFury(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 10, ActionID.MakeSpell(AID.FlamesOfFury), m => m.Enemies(OID.FireVoidzone).Where(z => z.EventState != 7), 1.2f); +class TheWardensVerdict(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheWardensVerdict), new AOEShapeRect(45.06f, 2f)); +class FlamesOfFury(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 10f, ActionID.MakeSpell(AID.FlamesOfFury), GetVoidzones, 1.2f) +{ + private static Actor[] GetVoidzones(BossModule module) + { + var enemies = module.Enemies((uint)OID.FireVoidzone); + var count = enemies.Count; + if (count == 0) + return []; + + var voidzones = new Actor[count]; + var index = 0; + for (var i = 0; i < count; ++i) + { + var z = enemies[i]; + if (z.EventState != 7) + voidzones[index++] = z; + } + return voidzones[..index]; + } +} class FlamesOfFuryBait(BossModule module) : Components.GenericBaitAway(module) { - private static readonly AOEShapeCircle circle = new(10); + private static readonly AOEShapeCircle circle = new(10f); public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) { @@ -51,7 +70,7 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID) public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID == AID.FlamesOfFury) + if (spell.Action.ID == (uint)AID.FlamesOfFury) ++NumCasts; if (NumCasts == 3) { @@ -63,21 +82,24 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count != 0 && CurrentBaits[0].Target == actor) hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 17.5f)); } public override void AddHints(int slot, Actor actor, TextHints hints) { - base.AddHints(slot, actor, hints); - if (CurrentBaits.Any(x => x.Target == actor)) + if (CurrentBaits.Count == 0) + return; + if (CurrentBaits[0].Target != actor) + base.AddHints(slot, actor, hints); + else hints.Add("Bait away! (3 times)"); } } -class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); +class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60f.Degrees())); +class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6f); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60f.Degrees()), [(uint)OID.AltarMatanga]); class AltarTotemStates : StateMachineBuilder { @@ -93,7 +115,17 @@ public AltarTotemStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(AltarTotem.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(AltarTotem.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -105,19 +137,20 @@ public class AltarTotem(WorldState ws, Actor primary) : THTemplate(ws, primary) protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.TotemsHead)); - Arena.Actors(Enemies(OID.AltarMatanga), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.TotemsHead)); + Arena.Actors(Enemies((uint)OID.AltarMatanga), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarMatanga => 2, - OID.TotemsHead => 1, + (uint)OID.AltarMatanga => 2, + (uint)OID.TotemsHead => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/Hati.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/Hati.cs index 6e19a283fd..eafc48bf64 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/Hati.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/Hati.cs @@ -33,10 +33,10 @@ public enum AID : uint Telega = 9630 // Mandragoras->self, no cast, single-target, bonus adds disappear } -class PolarRoar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PolarRoar), new AOEShapeDonut(9, 40)); -class Hellstorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hellstorm2), 10); -class Netherwind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Netherwind), new AOEShapeRect(18, 2)); -class GlassyNova(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GlassyNova), new AOEShapeRect(45.4f, 4)); +class PolarRoar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PolarRoar), new AOEShapeDonut(9f, 40f)); +class Hellstorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hellstorm2), 10f); +class Netherwind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Netherwind), new AOEShapeRect(18f, 2f)); +class GlassyNova(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GlassyNova), new AOEShapeRect(45.4f, 4f)); class BrainFreeze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BrainFreeze), 15.4f); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); @@ -61,7 +61,17 @@ public HatiStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(Hati.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(Hati.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -75,23 +85,24 @@ public class Hati(WorldState ws, Actor primary) : THTemplate(ws, primary) protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.AltarKatasharin)); + Arena.Actors(Enemies((uint)OID.AltarKatasharin)); Arena.Actors(Enemies(bonusAdds), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen => 2, - OID.AltarKatasharin => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen => 2, + (uint)OID.AltarKatasharin => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheGreatGoldWhisker.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheGreatGoldWhisker.cs index ab75267cb7..22228bffdb 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheGreatGoldWhisker.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheGreatGoldWhisker.cs @@ -29,7 +29,17 @@ public TheGreatGoldWhiskerStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(TheGreatGoldWhisker.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(TheGreatGoldWhisker.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -41,17 +51,18 @@ public class TheGreatGoldWhisker(WorldState ws, Actor primary) : THTemplate(ws, protected override void DrawEnemies(int pcSlot, Actor pc) { Arena.Actor(PrimaryActor); - Arena.Actors(Enemies(OID.GoldWhisker), Colors.Vulnerable); + Arena.Actors(Enemies((uint)OID.GoldWhisker), Colors.Vulnerable); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.GoldWhisker => 1, + (uint)OID.GoldWhisker => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs index 19e82d6e7b..71725c00f1 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs @@ -80,7 +80,17 @@ public TheOlderOneStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(TheOlderOne.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(TheOlderOne.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -99,17 +109,18 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen or OID.GoldWhisker => 2, - OID.AltarMatanga => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen or (uint)OID.GoldWhisker => 2, + (uint)OID.AltarMatanga => 1, _ => 0 }; } diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs index 9e19a590f8..7227e873f1 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs @@ -75,7 +75,17 @@ public TheWingedStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => module.Enemies(TheWinged.All).All(x => x.IsDeadOrDestroyed); + .Raw.Update = () => + { + var enemies = module.Enemies(TheWinged.All); + var count = enemies.Count; + for (var i = 0; i < count; ++i) + { + if (!enemies[i].IsDeadOrDestroyed) + return false; + } + return true; + }; } } @@ -94,17 +104,18 @@ protected override void DrawEnemies(int pcSlot, Actor pc) protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - for (var i = 0; i < hints.PotentialTargets.Count; ++i) + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) { var e = hints.PotentialTargets[i]; - e.Priority = (OID)e.Actor.OID switch + e.Priority = e.Actor.OID switch { - OID.AltarOnion => 6, - OID.AltarEgg => 5, - OID.AltarGarlic => 4, - OID.AltarTomato => 3, - OID.AltarQueen or OID.GoldWhisker => 2, - OID.AltarMatanga => 1, + (uint)OID.AltarOnion => 6, + (uint)OID.AltarEgg => 5, + (uint)OID.AltarGarlic => 4, + (uint)OID.AltarTomato => 3, + (uint)OID.AltarQueen or (uint)OID.GoldWhisker => 2, + (uint)OID.AltarMatanga => 1, _ => 0 }; }