Skip to content

Commit

Permalink
FRU WIP - P2 fixes, P3 up to apoc
Browse files Browse the repository at this point in the history
  • Loading branch information
awgil committed Dec 10, 2024
1 parent e0a12fc commit f187ebe
Show file tree
Hide file tree
Showing 9 changed files with 534 additions and 43 deletions.
1 change: 1 addition & 0 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/FRU.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
class P2QuadrupleSlap(BossModule module) : Components.TankSwap(module, ActionID.MakeSpell(AID.QuadrupleSlapFirst), ActionID.MakeSpell(AID.QuadrupleSlapFirst), ActionID.MakeSpell(AID.QuadrupleSlapSecond), 4.1f, null, true);
class P2CrystalOfLight(BossModule module) : Components.Adds(module, (uint)OID.CrystalOfLight);
class P3Junction(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Junction));
class P3BlackHalo(BossModule module) : Components.CastSharedTankbuster(module, ActionID.MakeSpell(AID.BlackHalo), new AOEShapeCone(60, 45.Degrees())); // TODO: verify angle

[ModuleInfo(BossModuleInfo.Maturity.WIP, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1006, NameID = 9707, PlanLevel = 100)]
public class FRU(WorldState ws, Actor primary) : BossModule(ws, primary, new(100, 100), new ArenaBoundsCircle(20))
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa

private WPos DragToCenterPosition(FRU module)
{
if (module.PrimaryActor.Position.Z >= 100)
if (module.PrimaryActor.Position.Z >= module.Center.Z - 1)
return module.Center - new WDir(0, 6); // boss is positioned, go to N clockspot
var dragSpot = module.Center + new WDir(0, 7.5f); // we need to stay approx here, it's fine to overshoot a little bit - then when boss teleports, it won't turn
var dragSpot = module.Center + new WDir(0, 7.75f); // we need to stay approx here, it's fine to overshoot a little bit - then when boss teleports, it won't turn
var meleeSpot = ClosestInMelee(dragSpot, module.PrimaryActor);
return UptimeDowntimePos(dragSpot, meleeSpot, 0, GCD);
}
Expand Down
9 changes: 9 additions & 0 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/FRUConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ public class FRUConfig() : ConfigNode()
[GroupDetails(["1", "2", "3", "4"])]
[GroupPreset("HTTH/RMMR", [1, 2, 0, 3, 1, 2, 0, 3])]
public GroupAssignmentDDSupportPairs P3UltimateRelativityAssignment = GroupAssignmentDDSupportPairs.DefaultMeleeTogether();

[PropertyDisplay("P3 Apocalypse: assignments (G1 CCW from N, G2 CW from NE, in case of conflict 'lower' number flexes)")]
[GroupDetails(["G1 prio1", "G1 prio2", "G1 prio3", "G1 prio4", "G2 prio1", "G2 prio2", "G2 prio3", "G2 prio4"])]
[GroupPreset("TTHH/MMRR", [0, 1, 2, 3, 4, 5, 6, 7])]
[GroupPreset("TMRH/TMRH", [0, 4, 3, 7, 1, 5, 2, 6])]
public GroupAssignmentUnique P3ApocalypseAssignments = GroupAssignmentUnique.DefaultRoles();

[PropertyDisplay("P3 Apocalypse: uptime swaps (only consider swaps within prio 1/2 and 3/4, assuming these are melee and ranged)")]
public bool P3ApocalypseUptime;
}
32 changes: 31 additions & 1 deletion BossMod/Modules/Dawntrail/Ultimate/FRU/FRUEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum OID : uint

BossP3 = 0x45A7, // R7.040, x0 (spawn during fight)
DelightsHourglass = 0x45A8, // R1.000, x0 (spawn during fight)
ApocalypseLight = 0x1EB0FF, // R0.500, x0 (spawn during fight), EventObj type
}

public enum AID : uint
Expand Down Expand Up @@ -103,7 +104,7 @@ public enum AID : uint
DiamondDust = 40197, // BossP2->self, 5.0s cast, range 40 circle, raidwide
AxeKick = 40202, // OraclesReflection->self, 6.0s cast, range 16 circle
ScytheKick = 40203, // OraclesReflection/BossP2->self, 6.0s cast, range 4-20 donut
HouseOfLight = 40206, // Helper->self, no cast, range 60 ?-degree cone, baited on 4 closest
HouseOfLight = 40206, // Helper->self, no cast, range 60 30-degree cone, baited on 4 closest
FrigidStone = 40199, // Helper->location, no cast, range 5 circle, baited on icons
IcicleImpact = 40198, // Helper->location, 9.0s cast, range 10 circle, circles at cardinals/intercardinals
FrigidNeedleCircle = 40200, // Helper->self, 5.0s cast, range 5 circle
Expand Down Expand Up @@ -154,6 +155,7 @@ public enum AID : uint
// P3
Junction = 40226, // Helper->self, no cast, range 40 circle, raidwide
HellsJudgment = 40265, // BossP3->self, 4.0s cast, range 100 circle, maxhp-1 raidwide
AutoAttackP3 = 40264, // BossP3->player, no cast, single-target
TeleportP3 = 40117, // BossP3->location, no cast, single-target

UltimateRelativity = 40266, // BossP3->self, 10.0s cast, range 100 circle, raidwide + mechanic start
Expand All @@ -166,6 +168,26 @@ public enum AID : uint
UltimateRelativitySinboundMeltdownAOEFirst = 40235, // Helper->self, no cast, range 60 width 5 rect
UltimateRelativitySinboundMeltdownAOERest = 40292, // Helper->self, no cast, range 50 width 5 rect
UltimateRelativityDarkBlizzard = 40279, // Helper->player, no cast, range ?-12 donut
UltimateRelativityShadoweye = 40278, // Helper->self, no cast, gaze
DarkEruption = 40274, // Helper->player, no cast, range 6 circle
DarkWater = 40271, // Helper->players, no cast, range 6 circle, 4-man stack
ShellCrusher = 40286, // BossP3->self, 3.0s cast, single-target, visual (stack)
ShellCrusherAOE = 40287, // BossP3->players, no cast, range 6 circle stack

ShockwavePulsar = 40282, // BossP3->self, 5.0s cast, range 40 circle, raidwide
BlackHalo = 40290, // BossP3->self/player, 5.0s cast, range 60 ?-degree cone, shared tankbuster

SpellInWaitingRefrain = 40269, // BossP3->self, 2.0s cast, single-target, visual (next dark water is staggered)
ApocalypseDarkWater = 40270, // BossP3->self, 5.0s cast, single-target, visual (apply staggered stacks)
ApocalypseDarkWaterVisual = 40272, // Helper->player, no cast, single-target, visual (player stacks)
Apocalypse = 40296, // BossP3->self, 4.0s cast, single-target, visual (exploding lights)
ApocalypseAOE = 40297, // Helper->self, no cast, range 9 circle
SpiritTaker = 40288, // BossP3->self, 3.0s cast, single-target, visual (jump on random target)
SpiritTakerAOE = 40289, // BossP3->player, no cast, range 5 circle, jump on random target, knockback 40 on everyone else in aoe
ApocalypseDarkEruption = 40273, // BossP3->self, 4.0+1.0s cast, single-target, visual (spread)
DarkestDance = 40181, // BossP3->self, 5.0s cast, single-target, visual (baited tankbuster)
DarkestDanceBait = 40182, // BossP3->players, no cast, range 8 circle, baited tankbuster
DarkestDanceKnockback = 40183, // BossP3->self, no cast, range 40 circle, ???
}

public enum SID : uint
Expand All @@ -188,6 +210,10 @@ public enum SID : uint
SpellInWaitingDarkBlizzard = 2462, // none->player, extra=0x0, donut
SpellInWaitingReturn = 2464, // none->player, extra=0x0
DelightsHourglassRotation = 2970, // none->DelightsHourglass, extra=0x10D (ccw)/0x15C (cw)
Return = 2452, // none->player, extra=0x0
Stun = 4163, // none->player, extra=0x0
//SpellInWaitingRefrain = 4373, // BossP3->BossP3, extra=0x0
//_Gen_ = 2458, // none->player, extra=0x0
}

public enum IconID : uint
Expand All @@ -196,6 +222,10 @@ public enum IconID : uint
FrigidStone = 345, // player->self
HallowedRay = 525, // BossP2->player
LuminousHammer = 375, // player->self
BlackHalo = 259, // player->self
DelayedDarkWater = 62, // player->self
DarkWater = 184, // player->self
DarkEruption = 139, // player->self
}

public enum TetherID : uint
Expand Down
72 changes: 70 additions & 2 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/FRUStates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ private void Phase3(uint id)
{
P3JunctionHellsJudgment(id, 13.3f);
P3UltimateRelativity(id + 0x10000, 4.3f);
P3BlackHalo(id + 0x20000, 3.2f);
P3Apocalypse(id + 0x30000, 7.2f);

SimpleState(id + 0xFF0000, 100, "???");
}
Expand Down Expand Up @@ -358,8 +360,74 @@ private void P3UltimateRelativity(uint id, float delay)
ComponentCondition<P3UltimateRelativity>(id + 0x60, 4.9f, comp => comp.NumCasts >= 5, "Spread/stack 3")
.ActivateOnEnter<P3UltimateRelativityDarkFireUnholyDarkness>()
.DeactivateOnExit<P3UltimateRelativityDarkFireUnholyDarkness>();
ComponentCondition<P3UltimateRelativity>(id + 0x70, 5.1f, comp => comp.NumCasts >= 6, "Lasers 3")
ComponentCondition<P3UltimateRelativity>(id + 0x70, 6.1f, comp => comp.NumCasts >= 6, "Lasers 3")
.DeactivateOnExit<P3UltimateRelativitySinboundMeltdownBait>();
// TODO: resolve > stack > tankbuster
ComponentCondition<P3UltimateRelativity>(id + 0x80, 2.8f, comp => comp.NumReturnStuns > 0, "Return")
.ActivateOnEnter<P3UltimateRelativityShadoweye>() // note: there are no hints for stack or eruption, as they should have been resolved earlier...
.SetHint(StateMachine.StateHint.DowntimeStart);

ActorCastStart(id + 0x90, _module.BossP3, AID.ShellCrusher, 3.9f, true, "Relativity resolve")
.DeactivateOnExit<P3UltimateRelativityShadoweye>()
.DeactivateOnExit<P3UltimateRelativity>()
.SetHint(StateMachine.StateHint.DowntimeEnd);
ActorCastEnd(id + 0x91, _module.BossP3, 3, true)
.ActivateOnEnter<P3ShellCrusher>();
ComponentCondition<P3ShellCrusher>(id + 0x92, 0.4f, comp => comp.Stacks.Count == 0, "Stack")
.DeactivateOnExit<P3ShellCrusher>();

ActorCast(id + 0x1000, _module.BossP3, AID.ShockwavePulsar, 3.5f, 5, true, "Raidwide")
.DeactivateOnExit<P3UltimateRelativitySinboundMeltdownAOE>()
.SetHint(StateMachine.StateHint.Raidwide);
}

private void P3BlackHalo(uint id, float delay)
{
ActorCast(id, _module.BossP3, AID.BlackHalo, delay, 5, true)
.ActivateOnEnter<P3BlackHalo>();
ComponentCondition<P3BlackHalo>(id + 2, 0.2f, comp => comp.NumCasts > 0, "Tankbuster")
.DeactivateOnExit<P3BlackHalo>()
.SetHint(StateMachine.StateHint.Tankbuster);
}

private void P3Apocalypse(uint id, float delay)
{
ActorCast(id, _module.BossP3, AID.SpellInWaitingRefrain, delay, 2, true);
ActorCast(id + 0x10, _module.BossP3, AID.ApocalypseDarkWater, 3.2f, 5, true);
ComponentCondition<P3ApocalypseDarkWater>(id + 0x12, 0.6f, comp => comp.NumStatuses >= 6)
.ActivateOnEnter<P3Apocalypse>()
.ActivateOnEnter<P3ApocalypseDarkWater>()
.ExecOnExit<P3ApocalypseDarkWater>(comp => comp.ShowOrder(1));
ActorCast(id + 0x20, _module.BossP3, AID.Apocalypse, 2.6f, 4, true);
ActorCastStart(id + 0x30, _module.BossP3, AID.SpiritTaker, 2.2f, true);
ComponentCondition<P3ApocalypseDarkWater>(id + 0x31, 1.3f, comp => comp.Stacks.Count == 0, "Stack 1");
ActorCastEnd(id + 0x32, _module.BossP3, 1.7f, true)
.ActivateOnEnter<P3SpiritTaker>();
ComponentCondition<P3SpiritTaker>(id + 0x33, 0.3f, comp => comp.Spreads.Count == 0, "Jump")
.DeactivateOnExit<P3SpiritTaker>();
ActorCastStart(id + 0x40, _module.BossP3, AID.ApocalypseDarkEruption, 6.2f, true)
.ExecOnEnter<P3Apocalypse>(comp => comp.Show(8.5f))
.ActivateOnEnter<P3ApocalypseDarkEruption>();
ComponentCondition<P3Apocalypse>(id + 0x41, 2.4f, comp => comp.NumCasts > 0, "Apocalypse start");
ActorCastEnd(id + 0x42, _module.BossP3, 1.6f, true);
ComponentCondition<P3Apocalypse>(id + 0x43, 0.4f, comp => comp.NumCasts > 4);
ComponentCondition<P3ApocalypseDarkEruption>(id + 0x44, 0.7f, comp => comp.NumFinishedSpreads > 0, "Spread")
.DeactivateOnExit<P3ApocalypseDarkEruption>()
.ExecOnExit<P3ApocalypseDarkWater>(comp => comp.ShowOrder(2));
ComponentCondition<P3Apocalypse>(id + 0x45, 1.3f, comp => comp.NumCasts > 10);
ActorCastStart(id + 0x50, _module.BossP3, AID.DarkestDance, 1.3f, true);
ComponentCondition<P3Apocalypse>(id + 0x51, 0.7f, comp => comp.NumCasts > 16);
ComponentCondition<P3Apocalypse>(id + 0x52, 2.0f, comp => comp.NumCasts > 22);
ComponentCondition<P3ApocalypseDarkWater>(id + 0x53, 0.5f, comp => comp.Stacks.Count == 0, "Stack 2");
ComponentCondition<P3Apocalypse>(id + 0x54, 1.5f, comp => comp.NumCasts > 22)
.ActivateOnEnter<P3DarkestDanceBait>()
.DeactivateOnExit<P3Apocalypse>();
ActorCastEnd(id + 0x55, _module.BossP3, 0.3f, true);
ComponentCondition<P3DarkestDanceBait>(id + 0x56, 0.4f, comp => comp.NumCasts > 0, "Tankbuster")
.DeactivateOnExit<P3DarkestDanceBait>()
.ExecOnExit<P3ApocalypseDarkWater>(comp => comp.ShowOrder(3))
.SetHint(StateMachine.StateHint.Tankbuster);
// +2.8s: kb
// +???: stack 3
// then: shockwave pulsar raidwide > memory end enrage
}
}
2 changes: 1 addition & 1 deletion BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class P2DiamondDustHouseOfLight(BossModule module) : Components.GenericBaitAway(
private Actor? _source;
private DateTime _activation;

private static readonly AOEShapeCone _shape = new(60, 20.Degrees()); // TODO: verify angle
private static readonly AOEShapeCone _shape = new(60, 15.Degrees());

public override void Update()
{
Expand Down
21 changes: 14 additions & 7 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/P2MirrorMirror.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class P2MirrorMirrorReflectedScytheKickBlue(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.ReflectedScytheKickBlue))
{
private WPos _position;
private WDir _blueMirror;
private AOEInstance? _aoe;

private static readonly AOEShapeDonut _shape = new(4, 20);
Expand All @@ -11,20 +11,27 @@ class P2MirrorMirrorReflectedScytheKickBlue(BossModule module) : Components.Gene

public override void DrawArenaForeground(int pcSlot, Actor pc)
{
if (_position != default)
Arena.Actor(_position, Angle.FromDirection(Module.Center - _position), ArenaColor.Object);
if (_blueMirror != default)
{
Arena.Actor(Module.Center + 20 * _blueMirror, Angle.FromDirection(-_blueMirror), ArenaColor.Object);
if (_aoe == null)
{
// draw hint for melees
Arena.AddCircle(Module.Center - 11 * _blueMirror, 1, ArenaColor.Safe);
}
}
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.ScytheKick && _position != default)
_aoe = new(_shape, _position, default, Module.CastFinishAt(spell));
if ((AID)spell.Action.ID == AID.ScytheKick && _blueMirror != default)
_aoe = new(_shape, Module.Center + 20 * _blueMirror, default, Module.CastFinishAt(spell));
}

public override void OnEventEnvControl(byte index, uint state)
{
if (index is >= 1 and <= 8 && state == 0x00020001)
_position = Module.Center + 20 * (225 - index * 45).Degrees().ToDirection();
_blueMirror = (225 - index * 45).Degrees().ToDirection();
}
}

Expand All @@ -41,7 +48,7 @@ class P2MirrorMirrorHouseOfLight(BossModule module) : Components.GenericBaitAway
private WPos _mirror;
private readonly List<(Actor source, DateTime activation)> _sources = [];

private static readonly AOEShapeCone _shape = new(60, 20.Degrees()); // TODO: verify angle
private static readonly AOEShapeCone _shape = new(60, 15.Degrees());

public override void Update()
{
Expand Down
Loading

0 comments on commit f187ebe

Please sign in to comment.