Skip to content

Commit

Permalink
Merge pull request #442 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
merge Byakko unreal
  • Loading branch information
CarnifexOptimus authored Nov 16, 2024
2 parents 61f5ab7 + 6f2eb18 commit 0886036
Show file tree
Hide file tree
Showing 13 changed files with 588 additions and 35 deletions.
2 changes: 1 addition & 1 deletion BossMod/Framework/ActionManagerEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ private void UpdateDetour(ActionManager* self)
var desiredRotation = CalculateDesiredOrientation(actionImminent);

// execute rotation, if needed
var autoRotateConfig = fwk->SystemConfig.GetConfigOption(/*(uint)ConfigOption.AutoFaceTargetOnAction*/225); // TODO: 7.1: update config option
var autoRotateConfig = fwk->SystemConfig.GetConfigOption((uint)ConfigOption.AutoFaceTargetOnAction);
var autoRotateOriginal = autoRotateConfig->Value.UInt;
if (desiredRotation != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ProsecutionOfWar(BossModule module) : Components.TankSwap(module, ActionID
class DyingMemory(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.DyingMemory));
class DyingMemoryLast(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.DyingMemoryLast));

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "veyn, Malediktus", PlanLevel = 100, PrimaryActorOID = (uint)OID.BossP1, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1017, NameID = 13029)]
[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "veyn, Malediktus", PrimaryActorOID = (uint)OID.BossP1, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1017, NameID = 13029, PlanLevel = 100)]
public class Ex3QueenEternal(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaCenter, NormalBounds)
{
public static readonly WPos ArenaCenter = Trial.T03QueenEternal.T03QueenEternal.ArenaCenter;
Expand Down
19 changes: 19 additions & 0 deletions BossMod/Modules/Dawntrail/Unreal/Un1Byakko/AratamaPuddle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace BossMod.Dawntrail.Unreal.Un1Byakko;

class AratamaPuddleBait(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.AratamaPuddle, ActionID.MakeSpell(AID.AratamaPuddle), 4, 5.1f)
{
private DateTime _nextSpread;

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if (spell.Action == SpreadAction && WorldState.CurrentTime > _nextSpread)
{
if (++NumFinishedSpreads >= 3)
Spreads.Clear();
else
_nextSpread = WorldState.FutureTime(0.5f); // protection in case one target dies
}
}
}

class AratamaPuddleVoidzone(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(OID.AratamaPuddle).Where(z => z.EventState != 7));
30 changes: 30 additions & 0 deletions BossMod/Modules/Dawntrail/Unreal/Un1Byakko/HundredfoldHavoc.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace BossMod.Dawntrail.Unreal.Un1Byakko;

class HundredfoldHavoc(BossModule module) : Components.Exaflare(module, 5)
{
public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID is AID.HundredfoldHavocFirst)
{
Lines.Add(new() { Next = caster.Position, Advance = 5 * spell.Rotation.ToDirection(), NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1.1f, ExplosionsLeft = 4, MaxShownExplosions = 2 });
}
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID is AID.HundredfoldHavocFirst or AID.HundredfoldHavocRest)
{
++NumCasts;
int index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1));
if (index == -1)
{
ReportError($"Failed to find entry for {caster.InstanceID:X}");
return;
}

AdvanceLine(Lines[index], caster.Position);
if (Lines[index].ExplosionsLeft == 0)
Lines.RemoveAt(index);
}
}
}
42 changes: 42 additions & 0 deletions BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Intermission.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace BossMod.Dawntrail.Unreal.Un1Byakko;

class VoiceOfThunder : Components.PersistentInvertibleVoidzone
{
public VoiceOfThunder(BossModule module) : base(module, 2, m => m.Enemies(OID.AramitamaSoul).Where(x => !x.IsDead))
{
InvertResolveAt = WorldState.CurrentTime;
}

public override void AddHints(int slot, Actor actor, TextHints hints)
{
if (Sources(Module).Any(x => !Shape.Check(actor.Position, x)))
hints.Add("Touch the orbs!");
}
}

class IntermissionOrbAratama(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.IntermissionOrbAratama), "GTFO from puddle!")
{
public readonly List<AOEInstance> AOEs = [];

private static readonly AOEShapeCircle _shape = new(2);

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => AOEs;

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
switch ((AID)spell.Action.ID)
{
case AID.IntermissionOrbSpawn:
AOEs.Add(new(_shape, spell.TargetXZ, default, WorldState.FutureTime(5.1f)));
break;
case AID.IntermissionOrbAratama:
++NumCasts;
AOEs.RemoveAll(aoe => aoe.Origin.AlmostEqual(spell.TargetXZ, 1));
break;
}
}
}

class IntermissionSweepTheLeg(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.IntermissionSweepTheLeg), new AOEShapeDonut(5, 25));
class ImperialGuard(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ImperialGuard), new AOEShapeRect(44.75f, 2.5f));
class FellSwoop(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.FellSwoop));
42 changes: 42 additions & 0 deletions BossMod/Modules/Dawntrail/Unreal/Un1Byakko/StateOfShock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace BossMod.Dawntrail.Unreal.Un1Byakko;

class StateOfShock(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.StateOfShockSecond))
{
public int NumStuns;

public override void OnStatusGain(Actor actor, ActorStatus status)
{
if ((SID)status.ID == SID.Stun)
++NumStuns;
}

public override void OnStatusLose(Actor actor, ActorStatus status)
{
if ((SID)status.ID == SID.Stun)
--NumStuns;
}
}

class HighestStakes(BossModule module) : Components.GenericTowers(module, ActionID.MakeSpell(AID.HighestStakesAOE))
{
private BitMask _forbidden;

public override void OnEventIcon(Actor actor, uint iconID, ulong targetID)
{
if (iconID == (uint)IconID.HighestStakes)
{
Towers.Add(new(actor.Position, 6, 3, 3, _forbidden, WorldState.FutureTime(6.1f)));
}
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if (spell.Action == WatchedAction)
{
++NumCasts;
Towers.Clear();
foreach (var t in spell.Targets)
_forbidden.Set(Raid.FindSlot(t.ID));
}
}
}
31 changes: 31 additions & 0 deletions BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Un1Byakko.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace BossMod.Dawntrail.Unreal.Un1Byakko;

class StormPulseRepeat(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.StormPulseRepeat));
class HeavenlyStrike(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.HeavenlyStrike), new AOEShapeCircle(3), true);
class FireAndLightningBoss(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FireAndLightningBoss), new AOEShapeRect(54.3f, 10));
class FireAndLightningAdd(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FireAndLightningAdd), new AOEShapeRect(54.75f, 10));
class SteelClaw(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.SteelClaw), new AOEShapeCone(17.75f, 30.Degrees()), (uint)OID.Hakutei); // TODO: verify angle
class WhiteHerald(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.WhiteHerald, ActionID.MakeSpell(AID.WhiteHerald), 15, 5.1f); // TODO: verify falloff
class DistantClap(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DistantClap), new AOEShapeDonut(4, 25));
class SweepTheLegBoss(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SweepTheLegBoss), new AOEShapeCone(28.3f, 135.Degrees()));

[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "veyn", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1007, NameID = 7092, PlanLevel = 100)]
public class Un1Byakko(WorldState ws, Actor primary) : BossModule(ws, primary, default, new ArenaBoundsCircle(20))
{
private Actor? _hakutei;
public Actor? Boss() => PrimaryActor;
public Actor? Hakutei() => _hakutei;

protected override void UpdateModule()
{
// TODO: this is an ugly hack, think how multi-actor fights can be implemented without it...
// the problem is that on wipe, any actor can be deleted and recreated in the same frame
_hakutei ??= StateMachine.ActivePhaseIndex >= 0 ? Enemies(OID.Hakutei).FirstOrDefault() : null;
}

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actor(PrimaryActor);
Arena.Actor(_hakutei);
}
}
84 changes: 84 additions & 0 deletions BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Un1ByakkoEnums.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
namespace BossMod.Dawntrail.Unreal.Un1Byakko;

public enum OID : uint
{
Boss = 0x4579, // R4.300, x1
Hakutei = 0x4581, // R4.750, x1 - tiger
Helper = 0x464D, // R0.500, x29, mixed types
AratamaForce = 0x4589, // R0.700, x0 (spawn during fight) - orbs from center
IntermissionHakutei = 0x458B, // R4.750, x0 (spawn during fight)
AramitamaSoul = 0x458A, // R1.000, x0 (spawn during fight) - orbs from edge
AratamaPuddle = 0x1E8EA9, // R0.500, x0 (spawn during fight), EventObj type
IntermissionHelper = 0x1EA87E, // R0.500, x0 (spawn during fight), EventObj type
VacuumClaw = 0x1EA957, // R0.500, x0 (spawn during fight), EventObj type
}

public enum AID : uint
{
AutoAttackBoss = 39987, // Boss->player, no cast, single-target
AutoAttackAdd = 39988, // Hakutei->player, no cast, single-target
TeleportBoss = 39929, // Boss->location, no cast, single-target
TeleportAdd = 39927, // Hakutei->location, no cast, single-target
StormPulse = 39933, // Boss->self, 4.0s cast, range 100 circle, raidwide
StormPulseRepeat = 39964, // Boss->self, no cast, range 100 circle, raidwide
HeavenlyStrike = 39931, // Boss->players, 4.0s cast, range 3 circle tankbuster

StateOfShock = 39937, // Boss->player, 4.0s cast, single-target, stun target to grab & throw it
StateOfShockSecond = 39928, // Boss->player, no cast, single-target, stun second target to grab & throw it
Clutch = 39938, // Boss->player, no cast, single-target, grab target
HighestStakes = 39939, // Boss->location, 5.0s cast, single-target, jump
HighestStakesAOE = 39940, // Helper->location, no cast, range 6 circle tower

UnrelentingAnguish = 39950, // Boss->self, 3.0s cast, single-target, visual (orbs)
UnrelentingAnguishAratama = 39958, // AratamaForce->self, no cast, range 2 circle, orb explosion
OminousWind = 39948, // Boss->self, no cast, single-target, apply bubbles
OminousWindAOE = 39949, // Helper->self, no cast, range 6 circle
FireAndLightningBoss = 39930, // Boss->self, 4.0s cast, range 50+R width 20 rect

DanceOfTheIncomplete = 39924, // Boss->self, no cast, single-target, visual (split off tiger)
AddAppear = 39923, // Hakutei->self, no cast, single-target, visual (start appear animation)
AratamaPuddle = 39926, // Helper->location, no cast, range 4 circle, puddle drop
SteelClaw = 39936, // Hakutei->self, no cast, range 13+R ?-degree cone, cleave
WhiteHerald = 39962, // Hakutei->self, no cast, range 50 circle with ? falloff
DistantClap = 39934, // Boss->self, 5.0s cast, range 4-25 donut
FireAndLightningAdd = 39935, // Hakutei->self, 4.0s cast, range 50+R width 20 rect

VoiceOfThunder = 39959, // Hakutei->self, no cast, single-target, visual (physical damage down orbs)
VoiceOfThunderAratama = 39965, // AramitamaSoul->self, no cast, range 2 circle, orb explosion if soaked
VoiceOfThunderAratamaFail = 39960, // AramitamaSoul->Hakutei, no cast, single-target, orb explosion if it reaches the tiger, heals
RoarOfThunder = 39961, // Hakutei->self, 20.0s cast, range 100 circle, raidwide scaled by remaining hp
RoarOfThunderEnd1 = 39968, // Hakutei->Boss, no cast, single-target, visual (???)
RoarOfThunderEnd2 = 39967, // Boss->self, no cast, single-target, visual (???)
IntermissionOrbVisual = 39951, // Boss->self, no cast, single-target, visual (start next set of orbs)
IntermissionOrbSpawn = 39952, // Helper->location, no cast, single-target, visual (location of next orb)
IntermissionOrbAratama = 39953, // Helper->location, no cast, range 2 circle
ImperialGuard = 39954, // IntermissionHakutei->self, 3.0s cast, range 40+R width 5 rect
IntermissionSweepTheLegVisual = 39956, // Boss->self, no cast, single-target, visual (start donut)
IntermissionSweepTheLeg = 39957, // Helper->self, 5.1s cast, range 5-25 donut
IntermissionEnd = 39970, // Boss->self, no cast, single-target, visual (intermission end)
FellSwoop = 39963, // Helper->self, no cast, range 100 circle, raidwide

AnswerOnHigh = 39941, // Boss->self, no cast, single-target, visual (exaflare start)
HundredfoldHavocFirst = 39942, // Helper->self, 5.0s cast, range 5 circle exaflare
HundredfoldHavocRest = 39943, // Helper->self, no cast, range 5 circle exaflare
SweepTheLegBoss = 39932, // Boss->self, 4.0s cast, range 24+R 270-degree cone

Bombogenesis = 39944, // Boss->self, no cast, single-target, visual (3 baited puddle icons)
GaleForce = 39945, // Helper->self, no cast, range 6 circle, baited puddle
VacuumClaw = 39946, // Helper->self, no cast, range ? circle, growing voidzone aoe
VacuumBlade = 39947, // Helper->self, no cast, range 100 circle, raidwide
}

public enum SID : uint
{
Stun = 201, // Boss->player, extra=0x0
OminousWind = 1481, // none->player, extra=0x0
}

public enum IconID : uint
{
HighestStakes = 62, // Helper->self
AratamaPuddle = 4, // player->self
WhiteHerald = 87, // player->self
Bombogenesis = 101, // player->self
}
Loading

0 comments on commit 0886036

Please sign in to comment.