Skip to content

Commit

Permalink
Merge pull request #2 from LeontopodiumNivale14/POTD-Dungeons
Browse files Browse the repository at this point in the history
Potd dungeons
  • Loading branch information
LeontopodiumNivale14 authored Sep 27, 2024
2 parents 615ec8b + c80f4e1 commit bfbceea
Show file tree
Hide file tree
Showing 14 changed files with 569 additions and 28 deletions.
103 changes: 103 additions & 0 deletions BossMod/Modules/Endwalker/DeepDungeon/EurekaOrthos/DD20CloningNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
namespace BossMod.Endwalker.DeepDungeon.EurekaOrthos.DD20CloningNode;

public enum OID : uint
{
Boss = 0x3E77, // R6.0
ClonedShieldDragon = 0x3E78, // R3.445
Helper = 0x233C
}

public enum AID : uint
{
AutoAttack = 32817, // Boss->player, no cast, single-target
Teleport = 32554, // ClonedShieldDragon->location, no cast, single-target

FlameBreath = 32864, // Helper->self, 3.5s cast, range 50 30-degree cone
FlameBreathVisual1 = 32544, // ClonedShieldDragon->self, 2.0+1,5s cast, single-target
FlameBreathVisual2 = 32553, // ClonedShieldDragon->self, no cast, single-target
FlameBreathVisual3 = 32552, // ClonedShieldDragon->self, no cast, single-target
OffensiveCommand = 32543, // Boss->self, 5.0s cast, single-target
OrderRelay = 32545, // Boss->self, 8.0s cast, single-target // problematic child
PiercingLaser = 32547, // Boss->self, 2.5s cast, range 40 width 5 rect
}
class PiercingLaser(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.PiercingLaser), new AOEShapeRect(40, 2.5f));
class FlameBreath(BossModule module) : Components.GenericAOEs(module)
{
private readonly List<AOEInstance> _aoes = [];
private static readonly AOEShapeCone cone = new(50, 15.Degrees());
private static readonly float intercardinalDistance = 16 * MathF.Sqrt(2);
private static readonly Angle[] AnglesIntercardinals = [-45.003f.Degrees(), 44.998f.Degrees(), 134.999f.Degrees(), -135.005f.Degrees()];

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
if (_aoes.Count > 0)
foreach (var a in _aoes)
if ((a.Activation - _aoes[0].Activation).TotalSeconds <= 1)
yield return a;
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID == AID.FlameBreathVisual3)
{
var activation = WorldState.FutureTime(9.6f);

if ((caster.Position - Arena.Center).LengthSq() > 625)
_aoes.Add(new(cone, CalculatePosition(caster), caster.Rotation, activation));
else
_aoes.Add(new(cone, RoundPosition(caster.Position), caster.Rotation, activation));
}
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if (_aoes.Count > 0 && (AID)spell.Action.ID == AID.FlameBreath)
_aoes.RemoveAt(0);
}

private static WPos CalculatePosition(Actor caster)
{
var isIntercardinal = IsCasterIntercardinal(caster);
var distance = isIntercardinal ? intercardinalDistance : 22;
var position = caster.Position + distance * caster.Rotation.ToDirection();
return RoundPosition(position);
}

private static bool IsCasterIntercardinal(Actor caster)
{
foreach (var angle in AnglesIntercardinals)
if (caster.Rotation.AlmostEqual(angle, Angle.DegToRad))
return true;
return false;
}

private static WPos RoundPosition(WPos position) => new(MathF.Round(position.X * 2) / 2, MathF.Round(position.Z * 2) / 2);
}

class EncounterHints(BossModule module) : BossComponent(module)
{
public override void AddGlobalHints(GlobalHints hints)
{
hints.Add($"{Module.PrimaryActor.Name} will tether to the clones on the edge of the arena. Those are the dragons that will be casting a cone.\nAfter a certain point, the boss will tether x2 sets of adds, find the first safe spot, rotate into the next.");
}
}

class DD20CloningNodeStates : StateMachineBuilder
{
public DD20CloningNodeStates(BossModule module) : base(module)
{
TrivialPhase()
.ActivateOnEnter<FlameBreath>()
.ActivateOnEnter<PiercingLaser>()
.DeactivateOnEnter<EncounterHints>();
}
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman, Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 898, NameID = 12261)]
public class DD20CloningNode : BossModule
{
public DD20CloningNode(WorldState ws, Actor primary) : base(ws, primary, new(-300, -300), new ArenaBoundsCircle(19.5f))
{
ActivateComponent<EncounterHints>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
namespace BossMod.Endwalker.DeepDungeon.EurekaOrthos.DD40TwintaniasClone;

public enum OID : uint
{
Boss = 0x3D1D, // R6.0
Twister = 0x1E8910, // R0.5
BitingWind = 0x3D1E, // R1.0
Helper = 0x233C
}

public enum AID : uint
{
AutoAttack = 6497, // Boss->player, no cast, single-target

BitingWind = 31464, // BitingWind->self, no cast, range 5 circle
Gust = 31463, // Helper->location, 4.0s cast, range 5 circle
MeracydianCyclone = 31462, // Boss->self, 3.0s cast, single-target
MeracydianSquall = 31466, // Helper->location, 5.0s cast, range 5 circle
MeracydianSquallVisual = 31465, // Boss->self, 3.0s cast, single-target
Turbine = 31467, // Boss->self, 6.0s cast, range 60 circle, knockback 15, away from source
TwisterTouch = 31470, // Helper->player, no cast, single-target, player got hit by twister
TwisterVisual = 31468, // Boss->self, 5.0s cast, single-target
TwistingDive = 31471 // Boss->self, 5.0s cast, range 50 width 15 rect
}

class Twister(BossModule module) : Components.CastTwister(module, 1, (uint)OID.Twister, ActionID.MakeSpell(AID.TwisterVisual), 0.4f, 0.25f);
class BitingWind(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 5, ActionID.MakeSpell(AID.BitingWind), m => m.Enemies(OID.BitingWind).Where(z => z.EventState != 7), 0.9f);
class MeracydianSquall(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.MeracydianSquall), 5);
class TwistersHint(BossModule module, AID aid) : Components.CastHint(module, ActionID.MakeSpell(aid), "Twisters spawning, keep moving!");
class Twisters1(BossModule module) : TwistersHint(module, AID.TwisterVisual);
class Twisters2(BossModule module) : TwistersHint(module, AID.TwistingDive);

class TwistingDive(BossModule module) : Components.GenericAOEs(module)
{
private AOEInstance? _aoe;
private static readonly AOEShapeRect rect = new(50, 7.5f);
private bool preparing;

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe);

public override void OnActorPlayActionTimelineEvent(Actor actor, ushort id)
{
if (actor == Module.PrimaryActor)
{
if (id == 0x1E3A)
preparing = true;
else if (preparing && id == 0x1E43)
_aoe = new(rect, actor.Position, actor.Rotation, WorldState.FutureTime(6.9f));
}
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.TwistingDive)
{
_aoe = null;
preparing = false;
}
}
}

class Turbine(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Turbine), 15)
{
public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
var forbidden = new List<Func<WPos, float>>();
var component = Module.FindComponent<BitingWind>()?.ActiveAOEs(slot, actor)?.ToList();
var source = Sources(slot, actor).FirstOrDefault();
if (source != default && component != null)
{
forbidden.Add(ShapeDistance.InvertedCircle(Arena.Center, 5));
forbidden.AddRange(component.Select(c => ShapeDistance.Cone(Arena.Center, 20, Angle.FromDirection(c.Origin - Arena.Center), 20.Degrees())));
if (forbidden.Count > 0)
hints.AddForbiddenZone(p => forbidden.Select(f => f(p)).Min(), source.Activation);
}
}

public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => (Module.FindComponent<BitingWind>()?.ActiveAOEs(slot, actor).Any(z => z.Shape.Check(pos, z.Origin, z.Rotation)) ?? false) || !Module.InBounds(pos);
}

class DD40TwintaniasCloneStates : StateMachineBuilder
{
public DD40TwintaniasCloneStates(BossModule module) : base(module)
{
TrivialPhase()
.ActivateOnEnter<Twister>()
.ActivateOnEnter<Twisters1>()
.ActivateOnEnter<Twisters2>()
.ActivateOnEnter<BitingWind>()
.ActivateOnEnter<MeracydianSquall>()
.ActivateOnEnter<Turbine>()
.ActivateOnEnter<TwistingDive>();
}
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman, Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 900, NameID = 12263)]
public class DD40TwintaniasClone(WorldState ws, Actor primary) : BossModule(ws, primary, new(-600, -300), new ArenaBoundsCircle(20));
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,54 @@ public enum OID : uint
public enum AID : uint
{
AutoAttack = 6499, // Boss->player, no cast, single-target
//Weaponskill_ = 31867, // Helper->self, 1.0s cast, range 40 ?-degree cone // Displays the order of the aoe's going off
OctupleSwipe = 31872, // Boss->self, 10.8s cast, range 40 ?-degree cone // Windup Cast for N/E/S/W
BullishSwipe4 = 31871, // Boss->self, no cast, range 40 ?-degree cone
BullishSwipe3 = 31870, // Boss->self, no cast, range 40 ?-degree cone
BullishSwipe2 = 31869, // Boss->self, no cast, range 40 ?-degree cone
BullishSwing = 31875, // Boss->self, 5.0s cast, range 13 circle, PB Circle AOE
BullishSwipeSingle = 32795, // Boss->self, 5.0s cast, range 40 90-degree cone, usually used after KB to try and catch off guard
DisorientingGroan = 31876, // Boss->self, 5.0s cast, range 60 circle, 15 yalm KB
Shock = 31874, // BallOfLevin->self, 2.5s cast, range 5 circle // Cast, but going to be a persistent void zone
Thundercall = 31873, // Boss->self, 5.0s cast, range 60 circle

// Boss telegraphs with the helper, then cast Swipes 1-4 in a pattern. (Either same pattern twice, or 1-4 -> 4->1)
BullishSwipe1 = 31868, // Boss->self, no cast, range 40 ?-degree cone
DisorientingGroan = 31876, // Boss->self, 5.0s cast, range 60 circle, 15 yalm KB // done
BullishSwipeSingle = 32795, // Boss->self, 5.0s cast, range 40 90-degree cone, usually used after KB to try and catch off guard // done
Thundercall = 31873, // Boss->self, 5.0s cast, range 60 circle
Shock = 31874, // BallOfLevin->self, 2.5s cast, range 5 circle
BullishSwing = 31875, // Boss->self, 5.0s cast, range 13 circle, PB Circle AOE // done
BullishSwipe2 = 31869, // Boss->self, no cast, range 40 ?-degree cone
BullishSwipe3 = 31870, // Boss->self, no cast, range 40 ?-degree cone
BullishSwipe4 = 31871, // Boss->self, no cast, range 40 ?-degree cone
OctupleSwipe = 31872, // Boss->self, 10.8s cast, range 40 ?-degree cone // Windup Cast for N/E/S/W
OctupleSwipeTelegraph = 31867, // Helper->self, 1.0s cast, range 40 ?-degree cone // Displays the order of the aoe's going off
}

class BullishSwing(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BullishSwing), new AOEShapeCircle(13));
class BullishSwipeSingle(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BullishSwipeSingle), new AOEShapeCone(40, 45.Degrees()));
class DisorientingGroan(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.DisorientingGroan), 15, true);
class Shock(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Shock), new AOEShapeCircle(5));
class Shock(BossModule module) : Components.PersistentVoidzone(module, 5, m => m.Enemies(OID.BallOfLevin));
class Thundercall(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Thundercall), "Raidwide + Summoning Orbs");

class OctupleSwipe(BossModule module) : Components.GenericAOEs(module)
{
private readonly List<AOEInstance> _aoes = [];
private static readonly AOEShapeCone cone = new(40, 45.Degrees());
private static readonly HashSet<AID> castEnd = [AID.OctupleSwipe, AID.BullishSwipe1, AID.BullishSwipe2, AID.BullishSwipe3, AID.BullishSwipe4];

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
if (_aoes.Count > 0)
yield return _aoes[0] with { Color = ArenaColor.Danger };
if (_aoes.Count > 1)
for (var i = 1; i < Math.Clamp(_aoes.Count, 0, 3); ++i)
yield return _aoes[i];
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.OctupleSwipeTelegraph)
_aoes.Add(new(cone, caster.Position, spell.Rotation, _aoes.Count == 0 ? Module.CastFinishAt(spell, 8.7f + 2 * _aoes.Count) : _aoes[0].Activation.AddSeconds(_aoes.Count * 2)));
}

// Need to figure out how to telegraph the 8 cleaves going off still
public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if (_aoes.Count > 0 && castEnd.Contains((AID)spell.Action.ID))
_aoes.RemoveAt(0);
}
}

class DD60ServomechanicalMinotaurStates : StateMachineBuilder
{
Expand All @@ -38,9 +67,10 @@ public DD60ServomechanicalMinotaurStates(BossModule module) : base(module)
.ActivateOnEnter<BullishSwipeSingle>()
.ActivateOnEnter<BullishSwing>()
.ActivateOnEnter<DisorientingGroan>()
.ActivateOnEnter<OctupleSwipe>()
.ActivateOnEnter<Shock>();
}
}

[ModuleInfo(BossModuleInfo.Maturity.WIP, Contributors = "Puni.sh Team", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 902, NameID = 12267)]
[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman, Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 902, NameID = 12267)]
public class DD60ServomechanicalMinotaur(WorldState ws, Actor primary) : BossModule(ws, primary, new(-600, -300), new ArenaBoundsCircle(20));
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ public enum AID : uint
Abyss = 6872, // Boss->player, 2.0s cast, range 6 circle // kinda like a tankbuster? It's a circle on the player
ButterflyFloat = 6879, // IronCorse->player, 3.0s cast, single-target
Catapult = 6878, // BicephalicCorse->location, 3.0s cast, range 6 circle
Doom = 6875, // Boss->self, 5.0s cast, range 45+R 120-degree cone, feels like this is wrong,
Doom = 6875, // Boss->self, 5.0s cast, range 45+R 120-degree cone, feels like this is wrong,
GlassPunch = 6877, // GiantCorse/BicephalicCorse->self, no cast, range 6+R ?-degree cone
Shackle = 6874, // Boss->self, 3.0s cast, range 50+R width 8 rect
SummonDarkness = 6876, // Boss->self, 3.0s cast, ???, Summons Corse's,
SummonDarkness = 6876, // Boss->self, 3.0s cast, ???, Summons Corse's,
WordOfPain = 6873, // Boss->self, no cast, range 40+R circle
}

Expand All @@ -27,7 +27,15 @@ class Catapult(BossModule module) : Components.LocationTargetedAOEs(module, Acti
class CorseAdds(BossModule module) : Components.AddsMulti(module, [(uint)OID.BicephalicCorse, (uint)OID.GiantCorse, (uint)OID.IronCorse]);
class Doom(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Doom), new AOEShapeCone(47.4f, 60.Degrees()));
class Shackle(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Shackle), new AOEShapeRect(52.4f, 4, 0));
class SummonDarkness(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.SummonDarkness), "Summoning the corses, use Resolution if you want them permanently dead");
class SummonDarkness(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.SummonDarkness), "Summoning the corse, incoming Adds! \nRemember to use a resolution to make them permanently disappear");

class EncounterHints(BossModule module) : BossComponent(module)
{
public override void AddGlobalHints(GlobalHints hints)
{
hints.Add($"There is 3 sets of adds that spawn at HP %'s -> (90%, 65%, 40%) \nA resolution can make the adds permanently disappear once they are at 0% HP/the corpse are just laying on the floor.\nResolution is also does high damage to the adds + 0.3% to the Boss\nSolo tip: Either pop a resolution on all add packs, or pop lust -> resolution on 2nd ad pack. Make sure to keep regen up!");
}
}

class D100NybethObdilordStates : StateMachineBuilder
{
Expand All @@ -39,9 +47,16 @@ public D100NybethObdilordStates(BossModule module) : base(module)
.ActivateOnEnter<CorseAdds>()
.ActivateOnEnter<Doom>()
.ActivateOnEnter<Shackle>()
.ActivateOnEnter<SummonDarkness>();
.ActivateOnEnter<SummonDarkness>()
.DeactivateOnEnter<EncounterHints>();
}
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 208, NameID = 5356)]
public class D100NybethObdilord(WorldState ws, Actor primary) : BossModule(ws, primary, new(300, 300), new ArenaBoundsCircle(24));
public class D100NybethObdilord : BossModule
{
public D100NybethObdilord(WorldState ws, Actor primary) : base(ws, primary, new(300, 300), new ArenaBoundsCircle(24))
{
ActivateComponent<EncounterHints>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ public D110AlicantoStates(BossModule module) : base(module)
}
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 209, NameID = 5371)]
[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 209, NameID = 5371)]
public class D110Alicanto(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300, -235), new ArenaBoundsCircle(25));
Loading

0 comments on commit bfbceea

Please sign in to comment.