Skip to content

Commit

Permalink
Merge pull request #563 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
bug fixes, added mechanic to absolute virtue
  • Loading branch information
CarnifexOptimus authored Jan 19, 2025
2 parents d424906 + 17cd0c0 commit c2fa4d3
Show file tree
Hide file tree
Showing 27 changed files with 410 additions and 137 deletions.
2 changes: 1 addition & 1 deletion BossMod/Data/Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public sealed class Actor(ulong instanceID, uint oid, int spawnIndex, string nam
public bool Omnidirectional => Utils.CharacterIsOmnidirectional(OID);
public bool IsDeadOrDestroyed => IsDead || IsDestroyed;

private static readonly HashSet<uint> ignoreNPC = [0xE19, 0xE18, 0xE1A, 0x2C11, 0x2C0F, 0x2C10, 0x2C0E, 0x2C12, 0x2EFE, 0x418F, 0x464E, 0x4697]; // friendly NPCs that should not count as party members
private static readonly HashSet<uint> ignoreNPC = [0xE19, 0xE18, 0xE1A, 0x2C11, 0x2C0F, 0x2C10, 0x2C0E, 0x2C12, 0x2EFE, 0x418F, 0x464E, 0x4697, 0x35BC, 0x3657, 0x3658]; // friendly NPCs that should not count as party members
public bool IsFriendlyNPC => Type == ActorType.Enemy && IsAlly && IsTargetable && !ignoreNPC.Contains(OID);

public ActorStatus? FindStatus(uint sid)
Expand Down
17 changes: 6 additions & 11 deletions BossMod/Modules/Dawntrail/Hunt/RankA/UrnaVariabilis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,15 @@ public enum SID : uint
public enum IconID : uint
{
PositiveChargeBoss = 291, // Boss
NegativeChargeBoss = 290, // Boss
Stackmarker = 62 // player
NegativeChargeBoss = 290 // Boss
}

class Magnetism(BossModule module) : Components.Knockback(module)
{
private enum MagneticPole { None, Plus, Minus }
private MagneticPole CurrentPole { get; set; }
private MagneticPole CurrentPole;
private enum Shape { None, Donut, Circle, Any }
private Shape CurrentShape { get; set; }
private Shape CurrentShape;
private readonly HashSet<(Actor, uint)> statusOnActor = [];
private DateTime activation;
private bool done;
Expand Down Expand Up @@ -150,24 +149,20 @@ class MagnetismCircleDonut(BossModule module) : Components.GenericAOEs(module)

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
void AddAOE(AOEShape shape) => _aoe = new(shape, spell.LocXZ, default, Module.CastFinishAt(spell, 2.5f));
switch ((AID)spell.Action.ID)
{
case AID.Magnetoplasma1:
case AID.Magnetoplasma2:
AddAOE(circle, spell);
AddAOE(circle);
break;
case AID.Magnetoring1:
case AID.Magnetoring2:
AddAOE(donut, spell);
AddAOE(donut);
break;
}
}

private void AddAOE(AOEShape shape, ActorCastInfo spell)
{
_aoe = new(shape, Module.PrimaryActor.Position, default, Module.CastFinishAt(spell, 2.5f));
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID is AID.ProximityPlasma2 or AID.RingLightning2)
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Modules/Dawntrail/Raid/M01NBIackCat/OneTwoPaw.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
if (leapingVisuals.Contains((AID)spell.Action.ID))
helper = null;

else if (_aoes.Count > 0 && allOneTwoPaws.Contains((AID)spell.Action.ID))
else if (_aoes.Count != 0 && allOneTwoPaws.Contains((AID)spell.Action.ID))
{
_currentPattern = Pattern.None;
_aoes.RemoveAt(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,25 @@ public enum AID : uint

class FlameBreath(BossModule module) : Components.GenericAOEs(module)
{
private readonly List<AOEInstance> _aoes = [];
private readonly List<AOEInstance> _aoes = new(5);
private static readonly AOEShapeCone cone = new(50, 15.Degrees());
private static readonly float intercardinalDistance = 16 * MathF.Sqrt(2);

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;
var count = _aoes.Count;
if (count == 0)
return [];

List<AOEInstance> aoes = new(5);
var firstact = _aoes[0].Activation;
for (var i = 0; i < count; ++i)
{
var a = _aoes[i];
if ((a.Activation - firstact).TotalSeconds < 1)
aoes.Add(a);
}
return aoes;
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
Expand Down Expand Up @@ -64,8 +73,8 @@ private static WPos CalculatePosition(Actor caster)

private static bool IsCasterIntercardinal(Actor caster)
{
foreach (var angle in Angle.AnglesIntercardinals)
if (caster.Rotation.AlmostEqual(angle, Angle.DegToRad))
for (var i = 0; i < 4; ++i)
if (caster.Rotation.AlmostEqual(Angle.AnglesIntercardinals[i], Angle.DegToRad))
return true;
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ public enum OID : uint

public enum AID : uint
{
HeadAttack = 31842, // 233C->player, no cast, single-target
AutoAttack = 32702, // 3D9A->player, no cast, single-target
CreatureOfDarkness = 31841, // 3D9A->self, 3.0s cast, single-target, summon Heads E<->W heading S
DarkMegaflareVisual = 31849, // 3D9A->self, 3.0s cast, single-target
DarkMegaflare = 31850, // 233C->location, 3.0s cast, range 6 circle
DarkWyrmtailVisual = 31843, // 3D9A->self, 5.0s cast, single-target
DarkWyrmtail = 31844, // 233C->self, 6.0s cast, range 40 width 16 rect, summon Heads Heading E/W from Middle Lane
DarkWyrmwingVisual = 31845, // 3D9A->self, 5.0s cast, single-target
DarkWyrmwing = 31846, // 233C->self, 6.0s cast, range 40 width 16 rect, summon Heads Heading E/W from E/W Walls
WheiMornFirst = 31847, // 3D9A->location, 5.0s cast, range 6 circle
WheiMornRest = 31848 // 3D9A->location, no cast, range 6 circle
AutoAttack = 32702, // Boss->player, no cast, single-target
HeadAttack = 31842, // Helper->player, no cast, single-target

CreatureOfDarkness = 31841, // Boss->self, 3.0s cast, single-target, summon Heads E<->W heading S
DarkMegaflareVisual = 31849, // Boss->self, 3.0s cast, single-target
DarkMegaflare = 31850, // Helper->location, 3.0s cast, range 6 circle
DarkWyrmtailVisual = 31843, // Boss->self, 5.0s cast, single-target
DarkWyrmtail = 31844, // Helper->self, 6.0s cast, range 40 width 16 rect, summon Heads Heading E/W from Middle Lane
DarkWyrmwingVisual = 31845, // Boss->self, 5.0s cast, single-target
DarkWyrmwing = 31846, // Helper->self, 6.0s cast, range 40 width 16 rect, summon Heads Heading E/W from E/W Walls
WheiMornFirst = 31847, // Boss->location, 5.0s cast, range 6 circle
WheiMornRest = 31848 // Boss->location, no cast, range 6 circle
}

public enum IconID : uint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public enum OID : uint

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

SongsOfIceAndThunder = 31851, // Boss->self, 5.0s cast, range 9 circle
SongsOfThunderAndIce = 31852, // Boss->self, 5.0s cast, range 8-40 donut
TheRamsVoice1 = 31854, // Boss->self, no cast, range 9 circle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum OID : uint
public enum AID : uint
{
AutoAttack = 6499, // Boss->player, no cast, single-target

OctupleSwipeTelegraph = 31867, // Helper->self, 1.0s cast, range 40 90-degree cone
OctupleSwipe = 31872, // Boss->self, 10.8s cast, range 40 90-degree cone
BullishSwipe1 = 31868, // Boss->self, no cast, range 40 90-degree cone
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum OID : uint
public enum AID : uint
{
AutoAttack = 6497, // Boss->player, no cast, single-target

FallingRock = 31441, // Helper->self, 2.5s cast, range 3 circle
Ferocity = 31442, // Boss->self, 5.0s cast, single-target
FerocityTetherStretchSuccess = 31443, // Boss->player, no cast, single-target
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ public override void DrawArenaForeground(int pcSlot, Actor pc)
{
public override void AddGlobalHints(GlobalHints hints)
{
if (CurrentBaits.Count > 0)
if (CurrentBaits.Count != 0)
hints.Add("Tankbuster cleave");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints)

class IceBloomCross(BossModule module) : Components.GenericAOEs(module)
{
private readonly List<AOEInstance> _aoes = [];
private readonly List<AOEInstance> _aoes = new(6);
private static readonly AOEShapeCross cross = new(40, 2.5f);

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public enum IconID : uint

class TrismegistosArenaChange(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeDonut donut = new(20, 22.5f);
private static readonly AOEShapeDonut donut = new(20, 22);
private AOEInstance? _aoe;

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,21 @@ public override void OnEventEnvControl(byte index, uint state)

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
static WPos RoundPosition(WPos position) => new(MathF.Round(position.X * 10) * 0.1f, MathF.Round(position.Z * 10) * 0.1f);
if ((AID)spell.Action.ID == AID.NecroticFluid)
{
var numExplosions = GetNumExplosions(caster);
var advance = 6 * (CurrentWind == Pattern.Southward ? new WDir(1, 0) : new(-1, 0));
var roundedPos = RoundPosition(spell.LocXZ);
var numExplosions = CurrentWind switch
{
Pattern.Southward => GetSouthwardExplosions(roundedPos, Arena.Center),
Pattern.Northward => GetNorthwardExplosions(roundedPos, Arena.Center),
_ => 0
};
var advance = 6 * (CurrentWind == Pattern.Southward ? new WDir(0, 1) : new(0, -1));
Lines.Add(new() { Next = spell.LocXZ, Advance = advance, NextExplosion = Module.CastFinishAt(spell), TimeToMove = 2, ExplosionsLeft = numExplosions, MaxShownExplosions = 5 });
}
}

private int GetNumExplosions(Actor caster)
{
return CurrentWind switch
{
Pattern.Southward => GetSouthwardExplosions(caster.Position, Arena.Center),
Pattern.Northward => GetNorthwardExplosions(caster.Position, Arena.Center),
_ => 0
};
}

private static int GetSouthwardExplosions(WPos position, WPos center)
{
return position.Z switch
Expand Down Expand Up @@ -160,7 +157,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID is AID.NecroticFluid or AID.NecroticMist)
{
Advance((AID)spell.Action.ID == AID.NecroticFluid ? caster.Position : spell.LocXZ);
Advance(spell.LocXZ);
++NumCasts;
}
}
Expand Down Expand Up @@ -196,19 +193,21 @@ class WaveOfNausea(BossModule module) : Components.GenericAOEs(module)
private readonly NecroticFluidMist _exa = module.FindComponent<NecroticFluidMist>()!;
private readonly List<AOEInstance> _aoes = new(2);
private static readonly AOEShapeDonut donut = new(6, 40);
private static readonly Shape[] differenceShapes = [new Circle(new(271.5f, -178), 6), new Circle(new(261.5f, -178), 6)];
private static readonly Shape[] differenceShapes = [new Circle(new(271.473f, -178.027f), 6), new Circle(new(261.494f, -178.027f), 6)];

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

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
void AddAOE(Angle start, Angle end)
=> _aoes.Add(new(new AOEShapeCustom([new ConeHA(spell.LocXZ, 6, start, end)], differenceShapes, InvertForbiddenZone: true), Arena.Center, default, Module.CastFinishAt(spell), Colors.SafeFromAOE));
if ((AID)spell.Action.ID == AID.WaveOfNausea)
{
_aoes.Add(new(donut, caster.Position, default, Module.CastFinishAt(spell)));
_aoes.Add(new(donut, spell.LocXZ, default, Module.CastFinishAt(spell)));
if (_exa.CurrentWind == NecroticFluidMist.Pattern.Southward)
_aoes.Add(new(new AOEShapeCustom([new ConeHA(spell.LocXZ, 6, 180.Degrees(), 90.Degrees())], differenceShapes, InvertForbiddenZone: true), Arena.Center, default, Module.CastFinishAt(spell), Colors.SafeFromAOE));
AddAOE(180.Degrees(), 90.Degrees());
else if (_exa.CurrentWind == NecroticFluidMist.Pattern.Northward)
_aoes.Add(new(new AOEShapeCustom([new ConeHA(spell.LocXZ, 6, 0.Degrees(), 90.Degrees())], differenceShapes, InvertForbiddenZone: true), Arena.Center, default, Module.CastFinishAt(spell), Colors.SafeFromAOE));
AddAOE(default, 90.Degrees());
}
}

Expand Down Expand Up @@ -251,5 +250,6 @@ public D061CausticGrebuloffStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 792, NameID = 10313)]
public class D061CausticGrebuloff(WorldState ws, Actor primary) : BossModule(ws, primary, defaultBounds.Center, defaultBounds)
{
private static readonly ArenaBoundsComplex defaultBounds = new([new Circle(new(266.5f, -178), 19.5f)], [new Rectangle(new(266.5f, -198.75f), 20, 2), new Rectangle(new(266.5f, -157), 20, 2)]);
private static readonly ArenaBoundsComplex defaultBounds = new([new Polygon(new(266.5f, -178), 19.5f * CosPI.Pi32th, 32)],
[new Rectangle(new(266.5f, -198.75f), 20, 2), new Rectangle(new(266.5f, -157), 20, 2)]);
}
35 changes: 25 additions & 10 deletions BossMod/Modules/Endwalker/Dungeon/D06DeadEnds/D062Peacekeeper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public enum AID : uint

class DecimationArenaChange(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeDonut donut = new(16, 19.5f);
private static readonly AOEShapeDonut donut = new(16, 20);
private AOEInstance? _aoe;

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe);
Expand All @@ -43,6 +43,7 @@ public override void OnEventEnvControl(byte index, uint state)
if (index == 0x17 && state == 0x00020001)
{
Arena.Bounds = D062Peacekeeper.SmallerBounds;
Arena.Center = D062Peacekeeper.ArenaCenter;
_aoe = null;
}
}
Expand Down Expand Up @@ -76,22 +77,33 @@ class EclipsingExhaust(BossModule module) : Components.RaidwideCast(module, Acti

class EclipsingExhaustKnockback(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.EclipsingExhaust), 11)
{
private static readonly Angle a36 = 36.Degrees();
public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => (Module.FindComponent<Peacefire>()?.ActiveAOEs(slot, actor).Any(z => z.Shape.Check(pos, z.Origin, z.Rotation)) ?? false) || !Module.InBounds(pos);

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
var forbidden = new List<Func<WPos, float>>();
var component = Module.FindComponent<Peacefire>()?.ActiveAOEs(slot, actor)?.ToList();
var source = Sources(slot, actor).FirstOrDefault();
if (component != null && source != default)
{
foreach (var c in component)
var forbidden = new List<Func<WPos, float>>(6);
for (var i = 0; i < component.Count; ++i)

forbidden.Add(ShapeDistance.Cone(Arena.Center, 16, Angle.FromDirection(component[i].Origin - Arena.Center), a36));
forbidden.Add(ShapeDistance.InvertedCircle(Arena.Center, 4));
hints.AddForbiddenZone(minDistanceFunc, source.Activation);

float minDistanceFunc(WPos pos)
{
forbidden.Add(ShapeDistance.InvertedCircle(Arena.Center, 5));
forbidden.Add(ShapeDistance.Cone(Arena.Center, 16, Angle.FromDirection(c.Origin - Arena.Center), 36.Degrees()));
var minDistance = float.MaxValue;
for (var i = 0; i < forbidden.Count; ++i)
{
var distance = forbidden[i](pos);
if (distance < minDistance)
minDistance = distance;
}
return minDistance;
}
if (forbidden.Count > 0)
hints.AddForbiddenZone(p => forbidden.Min(f => f(p)), source.Activation);
}
}
}
Expand All @@ -116,8 +128,11 @@ public D062PeacekeeperStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 792, NameID = 10315)]
public class D062Peacekeeper(WorldState ws, Actor primary) : BossModule(ws, primary, new(-105, -210), StartingBounds)
public class D062Peacekeeper(WorldState ws, Actor primary) : BossModule(ws, primary, StartingBounds.Center, StartingBounds)
{
public static readonly ArenaBoundsCircle StartingBounds = new(19.5f);
public static readonly ArenaBoundsCircle SmallerBounds = new(16);
public static readonly WPos ArenaCenter = new(-105, -210);
private static readonly Angle offset = 5.625f.Degrees();
public static readonly ArenaBoundsComplex StartingBounds = new([new Polygon(ArenaCenter, 19.5f * CosPI.Pi32th, 32, offset)], [new Rectangle(new(-105, -229), 20, 0.78f),
new Rectangle(new(-105, -190), 20, 1.1f)]);
public static readonly ArenaBoundsComplex SmallerBounds = new([new Polygon(ArenaCenter, 16, 32, offset)]);
}
3 changes: 1 addition & 2 deletions BossMod/Modules/Endwalker/Dungeon/D06DeadEnds/D063Rala.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public enum AID : uint

public enum SID : uint
{
HiddenStatus = 2056, // none->GoldenWings, extra=0x16C, probably just a visual?
Doom = 1769 // Helper->player, extra=0x0, heal to full doom
}

Expand Down Expand Up @@ -98,5 +97,5 @@ public D063RalaStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 792, NameID = 10316)]
public class D063Rala(WorldState ws, Actor primary) : BossModule(ws, primary, defaultBounds.Center, defaultBounds)
{
private static readonly ArenaBoundsComplex defaultBounds = new([new Circle(new(-380, -135), 19.5f)], [new Rectangle(new(-380, -114.25f), 20, 2)]);
private static readonly ArenaBoundsComplex defaultBounds = new([new Polygon(new(-380, -135), 19.5f * CosPI.Pi32th, 32)], [new Rectangle(new(-380, -114.25f), 20, 2)]);
}
2 changes: 1 addition & 1 deletion BossMod/Modules/Endwalker/FATE/Chi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
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);
hints.AddForbiddenZone(ShapeDistance.InvertedRect(Module.PrimaryActor.Position, aoe.Rotation + a90, 20, 20, 3), aoe.Activation);
}
}

Expand Down
23 changes: 23 additions & 0 deletions BossMod/Modules/Endwalker/Trial/T08Asura/ArenaChanges.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace BossMod.Endwalker.Trial.T08Asura;

class ArenaChange(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeDonut donut = new(19, 20);
private AOEInstance? _aoe;

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe);
public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.LowerRealm && Arena.Bounds == T08Asura.StartingArena)
_aoe = new(donut, Arena.Center, default, Module.CastFinishAt(spell, 0.8f));
}

public override void OnEventEnvControl(byte index, uint state)
{
if (state == 0x00020001 && index == 0x01)
{
Arena.Bounds = T08Asura.DefaultArena;
_aoe = null;
}
}
}
Loading

0 comments on commit c2fa4d3

Please sign in to comment.