diff --git a/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D080YokHuyAttestant.cs b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D080YokHuyAttestant.cs new file mode 100644 index 0000000000..e2c6d8ca27 --- /dev/null +++ b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D080YokHuyAttestant.cs @@ -0,0 +1,45 @@ +namespace BossMod.Dawntrail.Dungeon.D08TenderValley.D080YokHuyAttestant; + +public enum OID : uint +{ + Boss = 0x4253, + YokHuyOrb = 0x424F, + YokHuyAltar = 0x4251, + YokHuyAltar2 = 0x448D +} + +public enum AID : uint +{ + AutoAttack = 872, + + SunToss = 38539, + BoulderToss = 38540, + TectonicShift = 39221 +} + +class SunToss(BossModule module) : Components.StandardAOEs(module, AID.SunToss, 6); +class BoulderToss(BossModule module) : Components.SingleTargetDelayableCast(module, AID.BoulderToss); +class TectonicShift(BossModule module) : Components.StandardAOEs(module, AID.TectonicShift, 8); + +class D080YokHuyAttestantStates : StateMachineBuilder +{ + public D080YokHuyAttestantStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.WIP, Contributors = "CerQ", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 834, NameID = 12801, SortOrder = -1)] +public class D080YokHuyAttestant(WorldState ws, Actor primary) : BossModule(ws, primary, new(-130, -475.25f), new ArenaBoundsRect(17.5f, 24.5f)) +{ + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actor(PrimaryActor, ArenaColor.Enemy); + Arena.Actors(Enemies(OID.YokHuyOrb), ArenaColor.Object); + Arena.Actors(Enemies(OID.YokHuyAltar), ArenaColor.Object); + Arena.Actors(Enemies(OID.YokHuyAltar2), ArenaColor.Object); + } +} diff --git a/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D081Barreltender.cs b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D081Barreltender.cs new file mode 100644 index 0000000000..2c4ac8065e --- /dev/null +++ b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D081Barreltender.cs @@ -0,0 +1,76 @@ +namespace BossMod.Dawntrail.Dungeon.D08TenderValley.D081Barreltender; + +public enum OID : uint +{ + Boss = 0x4234, + SmallTenderDrop = 0x1EBBF0, + LargeTenderDrop = 0x1EBBF1, + Helper = 0x233C +} + +public enum AID : uint +{ + AutoAttack = 872, + + HeavyweightNeedlesVisual = 37384, + HeavyweightNeedles = 37386, + TenderDrop = 37387, + NeedleStorm = 37388, + NeedleSuperstorm = 37389, + BarrelBreaker = 37390, + SucculentStomp = 37391, + BarbedBellow = 37392, + BarrelBreakerAOE = 37393, + PricklyRight = 39154, + PricklyLeft = 39155, + TenderFury = 39242 +} + +class BarbedBellow(BossModule module) : Components.RaidwideCast(module, AID.BarbedBellow); +class NeedleStorm(BossModule module) : Components.StandardAOEs(module, AID.NeedleStorm, 6); +class NeedleSuperstorm(BossModule module) : Components.StandardAOEs(module, AID.NeedleSuperstorm, 11); +class SucculentStomp(BossModule module) : Components.StackWithCastTargets(module, AID.SucculentStomp, 6, 4); +class TenderFury(BossModule module) : Components.SingleTargetCast(module, AID.TenderFury); + +class HeavyweightNeedles(BossModule module) : Components.StandardAOEs(module, AID.HeavyweightNeedles, new AOEShapeCone(36, 25.Degrees())); +class PricklyRight(BossModule module) : Components.StandardAOEs(module, AID.PricklyRight, new AOEShapeCone(36, 165.Degrees())); +class PricklyLeft(BossModule module) : Components.StandardAOEs(module, AID.PricklyLeft, new AOEShapeCone(36, 165.Degrees())); + +class BarrelBreaker(BossModule module) : Components.Knockback(module) +{ + private readonly List _sources = []; + + public override IEnumerable Sources(int slot, Actor actor) => _sources; + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.BarrelBreaker) + _sources.Add(new(Module.Center, 15, Module.CastFinishAt(spell))); + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.BarrelBreaker) + _sources.Clear(); + } +} + +class D081BarreltenderStates : StateMachineBuilder +{ + public D081BarreltenderStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "CerQ", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 834, NameID = 12889)] +public class D081Barreltender(WorldState ws, Actor primary) : BossModule(ws, primary, new(-65, 470), new ArenaBoundsRect(17, 15.5f)); diff --git a/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D082Anthracite.cs b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D082Anthracite.cs new file mode 100644 index 0000000000..f70611df16 --- /dev/null +++ b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D082Anthracite.cs @@ -0,0 +1,90 @@ +namespace BossMod.Dawntrail.Dungeon.D08TenderValley.D082Anthracite; + +public enum OID : uint +{ + Boss = 0x41BE, + Helper = 0x233C +} + +public enum AID : uint +{ + AutoAttack = 872, + + AnthrabombLong = 36401, + AnthrabombShort = 36402, + AnthrabombSetup = 36542, + AnthrabombMid = 36543, + AnthrabombMidResolve = 36544, + HotBlastLong = 36545, + HotBlastLongResolve = 36546, + Carniflagration = 36547, + CarniflagrationVisual = 36548, + AnthrabombFast = 36549, + AnthrabombFastResolve = 36550, + HotBlastShort = 36551, + HotBlastShortResolve = 36552, + AnthrabombSpread = 36553, + BurningCoalsVisual = 36554, + BurningCoals = 36555, + CarbonaceousCombustion = 36556, + CarbonaceousCombustionAOE = 36557, + ChimneySmack = 38467, + ChimneySmackTarget = 38468 +} + +class CarbonaceousCombustion(BossModule module) : Components.RaidwideCastDelay(module, AID.CarbonaceousCombustion, AID.CarbonaceousCombustionAOE, 0.5f); +class BurningCoals(BossModule module) : Components.StackWithCastTargets(module, AID.BurningCoals, 6, 4); +class ChimneySmack(BossModule module) : Components.SingleTargetCast(module, AID.ChimneySmackTarget); +class AnthrabombSpread(BossModule module) : Components.SpreadFromCastTargets(module, AID.AnthrabombSpread, 6); +class CarniflagrationHint(BossModule module) : Components.CastHint(module, AID.Carniflagration, "Bomb sequence + spreads"); + +class Anthrabombs(BossModule module) : Components.GenericAOEs(module) +{ + private static readonly AOEShapeCircle _circle = new(10); + private static readonly AOEShapeRect _line = new(40, 3); + private readonly List<(AID aid, ulong caster, AOEInstance aoe)> _aoes = []; + + public override IEnumerable ActiveAOEs(int slot, Actor actor) => _aoes.Select(e => e.aoe); + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + switch ((AID)spell.Action.ID) + { + case AID.AnthrabombLong: + case AID.AnthrabombShort: + case AID.AnthrabombMid: + case AID.AnthrabombFast: + _aoes.Add(((AID)spell.Action.ID, caster.InstanceID, new(_circle, caster.Position, Activation: Module.CastFinishAt(spell)))); + break; + case AID.HotBlastLong: + case AID.HotBlastShort: + _aoes.Add(((AID)spell.Action.ID, caster.InstanceID, new(_line, caster.Position, spell.Rotation, Module.CastFinishAt(spell)))); + break; + } + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + var aid = (AID)spell.Action.ID; + var index = _aoes.FindIndex(e => e.aid == aid && e.caster == caster.InstanceID); + if (index >= 0) + _aoes.RemoveAt(index); + } +} + +class D082AnthraciteStates : StateMachineBuilder +{ + public D082AnthraciteStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "CerQ", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 834, NameID = 12853)] +public class D082Anthracite(WorldState ws, Actor primary) : BossModule(ws, primary, new(-130, -57), new ArenaBoundsRect(15, 20)); diff --git a/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D083GreatestSerpentOfTural.cs b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D083GreatestSerpentOfTural.cs new file mode 100644 index 0000000000..1f034f451e --- /dev/null +++ b/BossMod/Modules/Dawntrail/Dungeon/D08TenderValley/D083GreatestSerpentOfTural.cs @@ -0,0 +1,169 @@ +namespace BossMod.Dawntrail.Dungeon.D08TenderValley.D083GreatestSerpentOfTural; + +public enum OID : uint +{ + Boss = 0x4164, + LesserSerpentOfTural = 0x41DE, + GreatSerpentOfTural = 0x41E0, + MightyBlorpPuddle1 = 0x1EBA86, + MightyBlorpPuddle2 = 0x1EBA87, + MightyBlorpPuddle3 = 0x1EBA88, + Helper = 0x233C +} + +public enum SID : uint +{ + Bind = 2518, + GreatestCurse = 3825 +} + +public enum AID : uint +{ + AutoAttack = 872, + + GreatTorrentVisual = 36741, + GreatestFloodVisual = 36742, + MoistSummoning = 36743, + ScreesOfFuryVisual = 36744, + GreatestLabyrinth = 36745, + BouncyCouncil = 36746, + BouncyCouncilResolve = 36747, + DubiousTulidisaster = 36748, + ExaltedWobble = 36749, + MisplacedMystery = 36750, + MightyBlorpVisual1 = 36751, + MightyBlorpVisual2 = 36752, + MightyBlorpVisual3 = 36753, + GreatTorrentAOE = 36754, + GreatTorrentSpread = 36755, + GreatestFloodAOE = 36756, + ScreesOfFury = 36757, + MightyBlorp1 = 39981, + MightyBlorp2 = 39982, + MightyBlorp3 = 39983 +} + +class DubiousTulidisaster(BossModule module) : Components.RaidwideCast(module, AID.DubiousTulidisaster); +class GreatestLabyrinth(BossModule module) : BossComponent(module) +{ + private static readonly Dictionary _tiles = new() + { + [0x04000200] = new(-128.0483f, -560.11017f), + [0x10000800] = new(-131.8944f, -547.8202f), + [0x01000080] = new(-124.125694f, -551.9294f), + [0x00020001] = new(-135.9524f, -560.0384f), + }; + + private BitMask _cursed; + private WPos? _tile; + + public override void AddHints(int slot, Actor actor, TextHints hints) + { + if (_tile is { } tile && _cursed[slot] && !actor.Position.InRect(tile, default(Angle), 2, 2, 2)) + hints.Add("Go to marked tile!"); + } + + public override void AddMovementHints(int slot, Actor actor, MovementHints movementHints) + { + if (_tile is { } tile && _cursed[slot]) + movementHints.Add(actor.Position, tile, ArenaColor.Safe); + } + + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + if (_tile is { } tile && _cursed[slot]) + hints.GoalZones.Add(p => p.InRect(tile, default(Angle), 2, 2, 2) ? 10 : 0); + } + + public override void DrawArenaBackground(int pcSlot, Actor pc) + { + if (_tile is { } tile && _cursed[pcSlot]) + Arena.ZoneRect(tile, default(Angle), 2, 2, 2, ArenaColor.SafeFromAOE); + } + + public override void DrawArenaForeground(int pcSlot, Actor pc) + { + if (_tile is { } tile && _cursed[pcSlot]) + { + Arena.AddRect(tile, new WDir(1, 0), 2, 2, 2, ArenaColor.Safe, 2); + Arena.AddLine(pc.Position, tile, ArenaColor.Safe); + } + } + + public override void OnStatusGain(Actor actor, ActorStatus status) + { + if ((SID)status.ID == SID.GreatestCurse && Raid.TryFindSlot(actor, out var slot)) + _cursed.Set(slot); + } + + public override void OnStatusLose(Actor actor, ActorStatus status) + { + if ((SID)status.ID == SID.GreatestCurse && Raid.TryFindSlot(actor, out var slot)) + { + _cursed.Clear(slot); + if (_cursed.None()) + _tile = null; + } + } + + public override void OnMapEffect(byte index, uint state) + { + if (index == 0x01 && _tiles.TryGetValue(state, out var tile)) + _tile = tile; + } +} +class MoistSummoning(BossModule module) : Components.CastHint(module, AID.MoistSummoning, "Summon jumps + puddles"); +class ScreesOfFury(BossModule module) : Components.SingleTargetCastDelay(module, AID.ScreesOfFuryVisual, AID.ScreesOfFury, 0.6f); +class GreatTorrentAOEs(BossModule module) : Components.StandardAOEs(module, AID.GreatTorrentAOE, 6); +class GreatTorrentSpread(BossModule module) : Components.UniformStackSpread(module, 0, 6, alwaysShowSpreads: true) +{ + private int _numAOEs; + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.GreatTorrentVisual) + { + _numAOEs = 0; + Spreads.Clear(); + } + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + switch ((AID)spell.Action.ID) + { + case AID.GreatTorrentAOE: + if (++_numAOEs == 12) + AddSpreads(Raid.WithoutSlot(true), WorldState.FutureTime(2.8f)); + break; + case AID.GreatTorrentSpread: + Spreads.Clear(); + break; + } + } +} +class ExaltedWobble(BossModule module) : Components.StandardAOEs(module, AID.ExaltedWobble, 9); +class MisplacedMystery(BossModule module) : Components.StandardAOEs(module, AID.MisplacedMystery, new AOEShapeRect(52, 2.5f)); +class GreatestFlood(BossModule module) : Components.KnockbackFromCastTarget(module, AID.GreatestFloodAOE, 20, shape: new AOEShapeCircle(40)); +class MightyBlorpPuddles(BossModule module) : Components.PersistentVoidzone(module, 6, m => m.Enemies(OID.MightyBlorpPuddle1).Concat(m.Enemies(OID.MightyBlorpPuddle2)).Concat(m.Enemies(OID.MightyBlorpPuddle3))); + +class D083GreatestSerpentOfTuralStates : StateMachineBuilder +{ + public D083GreatestSerpentOfTuralStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "CerQ", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 834, NameID = 12709)] +public class D083GreatestSerpentOfTural(WorldState ws, Actor primary) : BossModule(ws, primary, new(-130, -554), new ArenaBoundsSquare(12));