diff --git a/BossMod/Components/GenericAOEs.cs b/BossMod/Components/GenericAOEs.cs index e2f40c3481..dc91f0e5a8 100644 --- a/BossMod/Components/GenericAOEs.cs +++ b/BossMod/Components/GenericAOEs.cs @@ -38,7 +38,7 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) } } -// For simple AOEs, formerly known as SelfTargetedAOEs andLocationTargetedAOEs, that happens at the end of the cast +// For simple AOEs, formerly known as SelfTargetedAOEs and LocationTargetedAOEs, that happens at the end of the cast public class SimpleAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue, float riskyWithSecondsLeft = 0) : GenericAOEs(module, aid) { public SimpleAOEs(BossModule module, ActionID aid, float radius, int maxCasts = int.MaxValue, float riskyWithSecondsLeft = 0) : this(module, aid, new AOEShapeCircle(radius), maxCasts, riskyWithSecondsLeft) { } @@ -59,12 +59,12 @@ public List ActiveCasters { var count = Casters.Count; var max = count > MaxCasts ? MaxCasts : count; - List result = new(max); + List aoes = new(max); for (var i = 0; i < max; ++i) { - result.Add(Casters[i]); + aoes.Add(Casters[i]); } - return result; + return aoes; } } @@ -75,16 +75,16 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) return []; var time = WorldState.CurrentTime; var max = count > MaxCasts ? MaxCasts : count; - List result = new(max); + List aoes = new(max); for (var i = 0; i < max; ++i) { var caster = Casters[i]; var color = i < MaxDangerColor && count > MaxDangerColor ? Colors.Danger : 0; var risky = Risky && (MaxRisky == null || i < MaxRisky); - result.Add(RiskyWithSecondsLeft == 0 ? caster with { Color = color, Risky = risky } + aoes.Add(RiskyWithSecondsLeft == 0 ? caster with { Color = color, Risky = risky } : caster with { Color = color, Risky = risky && caster.Activation.AddSeconds(-RiskyWithSecondsLeft) <= time }); } - return result; + return aoes; } public override void OnCastStarted(Actor caster, ActorCastInfo spell) diff --git a/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/ActivePivotParticleBeam.cs b/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/ActivePivotParticleBeam.cs index 32a3b594d9..e33ac5c30c 100644 --- a/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/ActivePivotParticleBeam.cs +++ b/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/ActivePivotParticleBeam.cs @@ -2,7 +2,7 @@ class ActivePivotParticleBeam(BossModule module) : Components.GenericRotatingAOE(module) { - private static readonly AOEShapeRect _shape = new(80, 9); + private static readonly AOEShapeRect _shape = new(40, 9, 40); public override void OnCastStarted(Actor caster, ActorCastInfo spell) { diff --git a/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/DelugeOfDarkness.cs b/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/DelugeOfDarkness.cs index 879de3c527..7914ec83f8 100644 --- a/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/DelugeOfDarkness.cs +++ b/BossMod/Modules/Dawntrail/Chaotic/Ch01CloudOfDarkness/DelugeOfDarkness.cs @@ -15,21 +15,23 @@ class Phase2InnerCells(BossModule module) : Components.GenericAOEs(module) public override IEnumerable ActiveAOEs(int slot, Actor actor) { if (!_config.ShowOccupiedTiles) - yield break; + return []; var cell = CellIndex(actor.Position - Arena.Center) - 3; + List tiles = new(16); // 3 * 4 + 4 margin for error for (var i = 0; i < 28; ++i) { if (_breakTime[i] != default) { if (i == cell) { - if (Math.Max(0, (_breakTime[i] - WorldState.CurrentTime).TotalSeconds) < 6) - yield return new(square, CellCenter(i)); + if ((_breakTime[i] - WorldState.CurrentTime).TotalSeconds < 6) + tiles.Add(new(square, CellCenter(i))); } else - yield return new(square, CellCenter(i), Color: Colors.FutureVulnerable); + tiles.Add(new(square, CellCenter(i), Color: Colors.FutureVulnerable)); } } + return tiles; } public override void AddHints(int slot, Actor actor, TextHints hints) diff --git a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ChasmOfVollok.cs b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ChasmOfVollok.cs index 9bd1889687..a58ef465cc 100644 --- a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ChasmOfVollok.cs +++ b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ChasmOfVollok.cs @@ -4,7 +4,7 @@ class ChasmOfVollok(BossModule module) : Components.GenericAOEs(module) { public readonly List AOEs = new(16); private static readonly float platformOffset = 30 / MathF.Sqrt(2); - private static readonly AOEShapeRect rect = new(2.5f, 2.5f, 2.5f); + private static readonly AOEShapeRect rect = new(5, 2.5f); public override IEnumerable ActiveAOEs(int slot, Actor actor) => AOEs; @@ -13,7 +13,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) if ((AID)spell.Action.ID == AID.ChasmOfVollok1) { if (Arena.InBounds(caster.Position)) - AOEs.Add(new(rect, caster.Position, spell.Rotation, Module.CastFinishAt(spell))); + AOEs.Add(new(rect, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell))); else { var pos = spell.LocXZ; diff --git a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/DoubleEdgedSwords.cs b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/DoubleEdgedSwords.cs index 70d3242b91..84524f299c 100644 --- a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/DoubleEdgedSwords.cs +++ b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/DoubleEdgedSwords.cs @@ -9,21 +9,23 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) { var count = _aoes.Count; if (count == 0) - yield break; + return []; + List aoes = new(count); for (var i = 0; i < count; ++i) { var aoe = _aoes[i]; if (i == 0) - yield return count != 1 ? aoe with { Color = Colors.Danger } : aoe; - else if (i == 1) - yield return aoe with { Risky = false }; + aoes.Add(count > 1 ? aoe with { Color = Colors.Danger } : aoe); + else + aoes.Add(aoe with { Risky = false }); } + return aoes; } public override void OnCastStarted(Actor caster, ActorCastInfo spell) { if ((AID)spell.Action.ID == AID.DoubleEdgedSwords) - _aoes.Add(new(cone, caster.Position, spell.Rotation, Module.CastFinishAt(spell))); + _aoes.Add(new(cone, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell))); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) diff --git a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ForgedTrack.cs b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ForgedTrack.cs index e627203a30..04d965ce25 100644 --- a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ForgedTrack.cs +++ b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/ForgedTrack.cs @@ -9,9 +9,12 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) { var count = _aoes.Count; if (count == 0) - yield break; - for (var i = 0; i < (count > 4 ? 4 : count); ++i) - yield return _aoes[i]; + return []; + var max = count > 4 ? 4 : count; + List aoes = new(max); + for (var i = 0; i < max; ++i) + aoes.Add(_aoes[i]); + return aoes; } public override void OnTethered(Actor source, ActorTetherInfo tether) diff --git a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/T02ZoraalJaP2.cs b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/T02ZoraalJaP2.cs index 4d29ab2ce4..73623c6663 100644 --- a/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/T02ZoraalJaP2.cs +++ b/BossMod/Modules/Dawntrail/Trial/T02ZoraalJa/T02ZoraalJaP2.cs @@ -11,17 +11,19 @@ class HalfCircuitCircle(BossModule module) : Circles(module, AID.HalfCircuitCirc class DawnOfAnAge(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.DawnOfAnAge)); class BitterReaping(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.BitterReaping)); class Actualize(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Actualize)); -class HalfFull(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HalfFull), new AOEShapeRect(60, 30)) + +abstract class HalfRect(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(60, 30)); +class HalfFull(BossModule module) : HalfRect(module, AID.HalfFull) { private readonly ChasmOfVollok _aoe = module.FindComponent()!; public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (_aoe.AOEs.Count == 0) - yield return Casters[0]; + return Casters.Count != 0 && _aoe.AOEs.Count != 0 ? [Casters[0]] : []; } } -class HalfCircuitRect(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HalfCircuitRect), new AOEShapeRect(60, 30)); +class HalfCircuitRect(BossModule module) : HalfRect(module, AID.HalfCircuitRect); + class FireIII(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.Spreadmarker, ActionID.MakeSpell(AID.FireIII), 6, 5.1f); class DutysEdge(BossModule module) : Components.LineStack(module, ActionID.MakeSpell(AID.DutysEdgeMarker), ActionID.MakeSpell(AID.DutysEdge), 5.4f, 100, minStackSize: 8, maxStackSize: 8, maxCasts: 4, markerIsFinalTarget: false); diff --git a/BossMod/Modules/Endwalker/FATE/Chi.cs b/BossMod/Modules/Endwalker/FATE/Chi.cs index c7fc5fd69f..39ba902f08 100644 --- a/BossMod/Modules/Endwalker/FATE/Chi.cs +++ b/BossMod/Modules/Endwalker/FATE/Chi.cs @@ -2,13 +2,13 @@ public enum OID : uint { - Boss = 0x34CB, // R=16.0 - Helper1 = 0x34CC, //R=0.5 - Helper2 = 0x34CD, //R=0.5 - Helper3 = 0x361E, //R=0.5 - Helper4 = 0x364C, //R=0.5 - Helper5 = 0x364D, //R=0.5 - Helper6 = 0x3505 //R=0.5 + Boss = 0x34CB, // R16.0 + Helper1 = 0x34CC, // used for thermobaric missiles and freefall bombs + Helper2 = 0x34CD, // used for tankbusters + BouncingBomb1 = 0x364C, // first bomb hit + BouncingBomb2 = 0x364D, // remaining hits + Bunkerbuster1 = 0x361E, // used by BB with 10s casttime + Bunkerbuster2 = 0x3505 // used by BB with 12s casttime } public enum AID : uint @@ -37,223 +37,178 @@ public enum AID : uint MissileShowerVisual = 25969, // Boss->self, 4.0s cast, single-target MissileShower = 25970, // Helper2->self, no cast, range 30 circle Teleport = 25155, // Boss->location, no cast, single-target, boss teleports mid - BunkerBuster = 25975, // Boss->self, 3.0s cast, single-target - BunkerBuster2 = 25101, // Helper3->self, 10.0s cast, range 20 width 20 rect - BunkerBuster3 = 25976, // Helper6->self, 12.0s cast, range 20 width 20 rect - BouncingBomb = 27484, // Boss->self, 3.0s cast, single-target - BouncingBomb2 = 27485, // Helper4->self, 5.0s cast, range 20 width 20 rect - BouncingBomb3 = 27486, // Helper5->self, 1.0s cast, range 20 width 20 rect + + BunkerBusterVisual = 25975, // Boss->self, 3.0s cast, single-target + BunkerBuster1 = 25101, // Helper3->self, 10.0s cast, range 20 width 20 rect + BunkerBuster2 = 25976, // Helper6->self, 12.0s cast, range 20 width 20 rect + + BouncingBombVisual = 27484, // Boss->self, 3.0s cast, single-target + BouncingBombFirst = 27485, // Helper4->self, 5.0s cast, range 20 width 20 rect + BouncingBombRest = 27486, // Helper5->self, 1.0s cast, range 20 width 20 rect + ThermobaricExplosive = 25965, // Boss->self, 3.0s cast, single-target ThermobaricExplosive2 = 25966 // Helper1->location, 10.0s cast, range 55 circle, damage fall off AOE } class Bunkerbuster(BossModule module) : Components.GenericAOEs(module) { - private readonly List _casters = []; - private DateTime _activation; - private int NumCastsStarted; - - private static readonly AOEShapeRect rect = new(10, 10, 10); + private readonly List _aoes = new(9); + public static readonly AOEShapeRect Square = new(10, 10, 10); public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (_casters.Count >= 3) - for (var i = 0; i < 3; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation, Colors.Danger); - if (_casters.Count >= 6) - for (var i = 3; i < 6; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation.AddSeconds(1.9f)); - } - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.BunkerBuster2 && NumCastsStarted == 0) - { - _activation = Module.CastFinishAt(spell); - ++NumCastsStarted; - } - else if ((AID)spell.Action.ID is AID.BunkerBuster3 && NumCastsStarted == 0) + var count = _aoes.Count; + if (count == 0) + return []; + var max = count > 6 ? 6 : count; + List aoes = new(max); + for (var i = 0; i < max; ++i) { - _activation = Module.CastFinishAt(spell); - ++NumCastsStarted; + var aoe = _aoes[i]; + if ((aoe.Activation - _aoes[0].Activation).TotalSeconds <= 1) + aoes.Add(count > 3 ? aoe with { Color = Colors.Danger } : aoe); + else + aoes.Add(aoe); } + return aoes; } - public override void OnCastFinished(Actor caster, ActorCastInfo spell) + public override void OnActorCreated(Actor actor) { - if ((AID)spell.Action.ID is AID.BunkerBuster2 or AID.BunkerBuster3) + var activation = (OID)actor.OID switch { - ++NumCasts; - if (_casters.Count > 0) - _casters.Remove(caster); - if (NumCasts is 3 or 6 or 9 or 12 or 15) - _activation = _activation.AddSeconds(1.9f); - if (_casters.Count == 0 && NumCasts != 0) - { - NumCasts = 0; - NumCastsStarted = 0; - } - } + OID.Bunkerbuster1 => 14.8f, + OID.Bunkerbuster2 => 16.9f, + _ => default + }; + if (activation != default) + _aoes.Add(new(Square, actor.Position, Angle.AnglesCardinals[1], WorldState.FutureTime(activation))); } - public override void OnActorCreated(Actor actor) + public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((OID)actor.OID is OID.Helper3 or OID.Helper6) - { - _casters.Add(actor); - if (_casters.Count == 1) - _activation = WorldState.FutureTime(20); // placeholder value that gets overwritten when cast actually starts - } + if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.BunkerBuster1 or AID.BunkerBuster2) + _aoes.RemoveAt(0); } } class BouncingBomb(BossModule module) : Components.GenericAOEs(module) { - private readonly List _casters = []; - private DateTime _activation; - private int bombcount; - - private static readonly AOEShapeRect rect = new(10, 10, 10); + private readonly List _aoes = new(15); + // either 9 or 15 explosions depending on pattern + // pattern 1: 1, 3, 5 explosions + // pattern 2: 2, 5, 8 explosions public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (bombcount == 1) + var count = _aoes.Count; + if (count == 0) + return []; + var max = count is <= 8 or > 9 and not 15 ? count : count == 9 ? 4 : 7; + var firstact = _aoes[0].Activation; + var lastact = _aoes[count - 1].Activation; + List aoes = new(max); + for (var i = 0; i < max; ++i) { - if (_casters.Count >= 1 && NumCasts == 0) - yield return new(rect, _casters[0].Position, _casters[0].Rotation, _activation, Colors.Danger); - if (_casters.Count >= 4 && NumCasts == 0) - for (var i = 1; i < 4; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation.AddSeconds(2.8f)); - if (_casters.Count >= 3 && NumCasts == 1) - for (var i = 0; i < 3; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation, Colors.Danger); - if (_casters.Count >= 8 && NumCasts == 1) - for (var i = 3; i < 8; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation.AddSeconds(2.8f)); - if (_casters.Count >= 5 && NumCasts == 4) - for (var i = 0; i < 5; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation, Colors.Danger); - } - if (bombcount == 2) - { - if (_casters.Count >= 2 && NumCasts == 0) - for (var i = 0; i < 2; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation, Colors.Danger); - if (_casters.Count >= 7 && NumCasts == 0) - for (var i = 2; i < 7; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation.AddSeconds(2.8f), Risky: false); - if (_casters.Count >= 5 && NumCasts == 2) - for (var i = 0; i < 5; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation, Colors.Danger); - if (_casters.Count >= 13 && NumCasts == 2) - for (var i = 5; i < 13; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation.AddSeconds(2.8f), Risky: false); - if (_casters.Count >= 8 && NumCasts == 7) - for (var i = 0; i < 8; ++i) - yield return new(rect, _casters[i].Position, _casters[i].Rotation, _activation, Colors.Danger); + var aoe = _aoes[i]; + if ((aoe.Activation - firstact).TotalSeconds < 1) + aoes.Add((lastact - aoe.Activation).TotalSeconds > 1 ? aoe with { Color = Colors.Danger } : aoe); + else + aoes.Add(aoe with { Risky = false }); } + return aoes; } public override void OnActorCreated(Actor actor) { - if ((OID)actor.OID == OID.Helper4) + var activation = (OID)actor.OID switch { - _activation = WorldState.FutureTime(10); // placeholder value that gets overwritten when cast actually starts - ++bombcount; - } - if ((OID)actor.OID is OID.Helper4 or OID.Helper5) - _casters.Add(actor); - } - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.BouncingBomb2) - _activation = Module.CastFinishAt(spell); + OID.BouncingBomb1 => 10, + OID.BouncingBomb2 => 5.7f, + _ => default + }; + if (activation != default) + _aoes.Add(new(Bunkerbuster.Square, actor.Position, Angle.AnglesCardinals[1], WorldState.FutureTime(activation))); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if ((AID)spell.Action.ID is AID.BouncingBomb2 or AID.BouncingBomb3) - { - ++NumCasts; - if (_casters.Count > 0) - _casters.Remove(caster); - if (bombcount == 1 && NumCasts is 1 or 4 || bombcount == 2 && NumCasts is 2 or 7) - _activation = _activation.AddSeconds(2.8f); - if (_casters.Count == 0 && bombcount != 0) - { - bombcount = 0; - NumCasts = 0; - } - } + if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.BouncingBombFirst or AID.BouncingBombRest) + _aoes.RemoveAt(0); } } class Combos(BossModule module) : Components.GenericAOEs(module) { + private readonly List _aoes = new(2); private static readonly AOEShapeCone cone = new(45, 90.Degrees()); private static readonly AOEShapeDonut donut = new(16, 60); - private static readonly AOEShapeRect rect = new(60, 16, 60); - private static readonly Angle Angle180 = 180.Degrees(); - private (AOEShape shape1, AOEShape shape2, DateTime activation1, DateTime activation2, bool offset, Angle rotation) combo; + private static readonly AOEShapeRect rect = new(120, 16); + private static readonly HashSet castEnd = [AID.CarapaceForeArms2dot0A, AID.CarapaceForeArms2dot0B, + AID.CarapaceRearGuns2dot0A, AID.CarapaceRearGuns2dot0B, AID.RearGunsForeArms2dot0, AID.ForeArmsRearGuns2dot0, + AID.RearGuns2dot0, AID.ForeArms2dot0]; + private static readonly Angle a90 = 90.Degrees(); public override IEnumerable ActiveAOEs(int slot, Actor actor) { - if (combo != default) + var count = _aoes.Count; + if (count == 0) + return []; + List aoes = new(count); + for (var i = 0; i < count; ++i) { - if (NumCasts == 0) - { - yield return new(combo.shape1, Module.PrimaryActor.Position, combo.rotation, combo.activation1, Colors.Danger); - yield return !combo.offset - ? new(combo.shape2, Module.PrimaryActor.Position, combo.rotation, combo.activation2, Risky: combo.shape1 != combo.shape2) - : new(combo.shape2, Module.PrimaryActor.Position, combo.rotation + Angle180, combo.activation2, Risky: combo.shape1 != combo.shape2); - } - if (NumCasts == 1) - { - yield return !combo.offset - ? new(combo.shape2, Module.PrimaryActor.Position, combo.rotation, combo.activation2, Colors.Danger) - : new(combo.shape2, Module.PrimaryActor.Position, combo.rotation + Angle180, combo.activation2, Colors.Danger); - } + var aoe = _aoes[i]; + if (i == 0) + aoes.Add(count > 1 ? aoe with { Color = Colors.Danger } : aoe); + else + aoes.Add(aoe with { Risky = false }); } + return aoes; } public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - var activation = Module.CastFinishAt(spell, 3.1f); + void AddAOEs(AOEShape shape, bool backwards = false) + { + _aoes.Add(new(shape, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell))); + _aoes.Add(new(cone, shape == rect ? caster.Position : spell.LocXZ, spell.Rotation + (backwards ? 180.Degrees() : default), Module.CastFinishAt(spell, 3.1f))); + } + switch ((AID)spell.Action.ID) { case AID.CarapaceForeArms2dot0A: - combo = (rect, cone, Module.CastFinishAt(spell), activation, false, spell.Rotation); + AddAOEs(rect); break; case AID.CarapaceForeArms2dot0B: - combo = (donut, cone, Module.CastFinishAt(spell), activation, false, spell.Rotation); + AddAOEs(donut); break; case AID.CarapaceRearGuns2dot0A: - combo = (rect, cone, Module.CastFinishAt(spell), activation, true, spell.Rotation); + AddAOEs(rect, true); break; case AID.CarapaceRearGuns2dot0B: - combo = (donut, cone, Module.CastFinishAt(spell), activation, true, spell.Rotation); + AddAOEs(donut, true); break; case AID.RearGunsForeArms2dot0: case AID.ForeArmsRearGuns2dot0: - combo = (cone, cone, Module.CastFinishAt(spell), activation, true, spell.Rotation); + AddAOEs(cone, true); break; } } - public override void OnCastFinished(Actor caster, ActorCastInfo spell) + public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID is AID.CarapaceForeArms2dot0A or AID.CarapaceForeArms2dot0B or AID.CarapaceRearGuns2dot0A or AID.CarapaceRearGuns2dot0B or AID.RearGunsForeArms2dot0 or AID.ForeArmsRearGuns2dot0) - ++NumCasts; + if (_aoes.Count != 0 && castEnd.Contains((AID)spell.Action.ID)) + _aoes.RemoveAt(0); } - public override void OnEventCast(Actor caster, ActorCastEvent spell) + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if ((AID)spell.Action.ID is AID.RearGuns2dot0 or AID.ForeArms2dot0) - { - NumCasts = 0; - combo = default; - } + base.AddAIHints(slot, actor, assignment, hints); + if (_aoes.Count != 2) + return; + // make ai stay close to boss to ensure successfully dodging the combo + var aoe = _aoes[0]; + hints.AddForbiddenZone(ShapeDistance.InvertedRect(aoe.Origin, aoe.Rotation + a90, 20, 20, 5), aoe.Activation); } } @@ -269,9 +224,9 @@ public override void AddGlobalHints(GlobalHints hints) class MissileShower(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.MissileShowerVisual), "Raidwide x2"); class ThermobaricExplosive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ThermobaricExplosive2), 25); -abstract class AssaultCarapaceRect(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(120, 16)); -class AssaultCarapace1(BossModule module) : AssaultCarapaceRect(module, AID.AssaultCarapace1); -class AssaultCarapace2(BossModule module) : AssaultCarapaceRect(module, AID.AssaultCarapace2); +abstract class AssaultCarapace(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(120, 16)); +class AssaultCarapace1(BossModule module) : AssaultCarapace(module, AID.AssaultCarapace1); +class AssaultCarapace2(BossModule module) : AssaultCarapace(module, AID.AssaultCarapace2); class AssaultCarapace3(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AssaultCarapace3), new AOEShapeDonut(16, 60)); diff --git a/BossMod/Modules/Endwalker/FATE/Daivadipa.cs b/BossMod/Modules/Endwalker/FATE/Daivadipa.cs index c6bfd9bde7..682212a23f 100644 --- a/BossMod/Modules/Endwalker/FATE/Daivadipa.cs +++ b/BossMod/Modules/Endwalker/FATE/Daivadipa.cs @@ -59,13 +59,17 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) { var count = AOEs.Count; if (count == 0) - yield break; - for (var i = 0; i < (count > 3 ? 3 : count); ++i) // either 2 or 3 AOEs in a wave, no need to iterate on all 5 + return []; + var max = count > 3 ? 3 : count; + var firstact = AOEs[0].Activation; + List aoes = new(max); + for (var i = 0; i < max; ++i) // either 2 or 3 AOEs in a wave, no need to iterate on all 5 { var aoe = AOEs[i]; - if ((aoe.Activation - AOEs[0].Activation).TotalSeconds <= 1) - yield return aoe; + if ((aoe.Activation - firstact).TotalSeconds < 1) + aoes.Add(aoe); } + return aoes; } public override void OnCastStarted(Actor caster, ActorCastInfo spell) @@ -105,9 +109,12 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) { var count = _aoes.Count; if (count == 0) - yield break; - for (var i = 0; i < (count > 8 ? 8 : count); ++i) // 8 AOEs in a wave, no need to iterate on all 16 - yield return _aoes[i]; + return []; + var max = count > 8 ? 8 : count; + List aoes = new(max); + for (var i = 0; i < max; ++i) // 8 AOEs in a wave, no need to iterate on all 16 + aoes.Add(_aoes[i]); + return aoes; } public override void OnCastStarted(Actor caster, ActorCastInfo spell) diff --git a/BossMod/Modules/Stormblood/Dungeon/D03BardamsMettle/D032HunterOfBardam.cs b/BossMod/Modules/Stormblood/Dungeon/D03BardamsMettle/D032HunterOfBardam.cs index 26b3aab15d..5ff0b5f101 100644 --- a/BossMod/Modules/Stormblood/Dungeon/D03BardamsMettle/D032HunterOfBardam.cs +++ b/BossMod/Modules/Stormblood/Dungeon/D03BardamsMettle/D032HunterOfBardam.cs @@ -146,7 +146,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) AID.HeavyStrike3 => 2, _ => -1 }; - AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(1.3f), caster.Rotation); + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(1.3f), spell.Rotation); } } }