Skip to content

Commit

Permalink
some refactoring/tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Feb 12, 2025
1 parent a5f4e9b commit 143a454
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 194 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
void AddAOE(AOEShapeCone shape, float rotationOffset, float finishOffset)
=> AOEs.Add(new(shape, caster.Position, spell.Rotation + rotationOffset.Degrees(), Module.CastFinishAt(spell, finishOffset)));
=> AOEs.Add(new(shape, spell.LocXZ, spell.Rotation + rotationOffset.Degrees(), Module.CastFinishAt(spell, finishOffset)));

switch (spell.Action.ID)
{
Expand Down
60 changes: 36 additions & 24 deletions BossMod/Modules/Dawntrail/Dungeon/D01Ihuykatumu/D013Apollyon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ public enum AID : uint
BitingWind = 36761 // Helper->player, no cast, single-target
}

class Whirlwind(BossModule module) : Components.PersistentVoidzone(module, 4.5f, m => m.Enemies(OID.Whirlwind), 5);

class Whirlwind(BossModule module) : Components.PersistentVoidzone(module, 4.5f, GetWhirlwind, 5f)
{
private static List<Actor> GetWhirlwind(BossModule module) => module.Enemies((uint)OID.Whirlwind);
}
class Blade(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Blade));
class HighWind(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.HighWind));

Expand All @@ -61,15 +63,34 @@ class RazorZephyr(BossModule module) : Blades(module, AID.RazorZephyr);
class BladesOfFamine(BossModule module) : Blades(module, AID.BladesOfFamine);

class Levinsickle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Levinsickle), 4f);
class LevinsickleSpark(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 4f, ActionID.MakeSpell(AID.LevinsickleSpark), m => m.Enemies(OID.LightningVoidzone).Where(z => z.EventState != 7), 0.7f);
class LevinsickleSpark(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 4f, ActionID.MakeSpell(AID.LevinsickleSpark), GetVoidzones, 0.7f)
{
private static Actor[] GetVoidzones(BossModule module)
{
var enemies = module.Enemies((uint)OID.LightningVoidzone);
var count = enemies.Count;
if (count == 0)
return [];

var voidzones = new Actor[count];
var index = 0;
for (var i = 0; i < count; ++i)
{
var z = enemies[i];
if (z.EventState != 7)
voidzones[index++] = z;
}
return voidzones[..index];
}
}
class WingOfLightning(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WingOfLightning), new AOEShapeCone(40f, 22.5f.Degrees()), 8);

class ThunderIII2(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.ThunderIII), 6f);
class BladeTB(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.BladeTB), new AOEShapeCircle(6f), true)
{
public override void AddGlobalHints(GlobalHints hints)
{
if (CurrentBaits.Count > 0)
if (CurrentBaits.Count != 0)
hints.Add("Tankbuster cleave");
}
}
Expand All @@ -94,31 +115,22 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
return aoes;
}

private static readonly Dictionary<WPos, WPos[]> coords = new()
{
[new WPos(-121, 279)] = [new(-102.935f, 274.357f), new(-108.935f, 262.224f), new(-105.733f, 252.340f)], // SW whirlwind
[new WPos(-93, 251)] = [new(-111.688f, 253.942f), new(-102.276f, 264.313f), new(-108.922f, 276.528f)] // NW whirlwind
};

private static readonly float[] delays = [8.6f, 16.7f, 24.7f];
private static readonly double[] delays = [8.6d, 16.7d, 24.7d];
private static readonly Angle[] angles = [89.999f.Degrees(), 44.998f.Degrees(), 134.999f.Degrees(), -0.003f.Degrees()];

private void AddAOEs(WPos pos, float delay)
{
for (var i = 0; i < 4; ++i)
_aoes.Add(new(rect, pos, angles[i], WorldState.FutureTime(delay)));
}

public override void OnActorCreated(Actor actor)
{
void AddWhirlwind(ReadOnlySpan<WPos> pos)
{
for (var i = 0; i < 3; ++i)
for (var j = 0; j < 4; ++j)
_aoes.Add(new(rect, WPos.ClampToGrid(pos[i]), angles[j], WorldState.FutureTime(delays[i])));
}
if (actor.OID == (uint)OID.Whirlwind)
foreach (var pos in coords.Keys)
if (actor.Position.AlmostEqual(pos, 1f))
{
for (var i = 0; i < 3; ++i)
AddAOEs(coords[pos][i], delays[i]);
break;
}
if (actor.Position.AlmostEqual(new WPos(-121f, 279f), 1f))
AddWhirlwind([new(-102.935f, 274.357f), new(-108.935f, 262.224f), new(-105.733f, 252.340f)]); // SW whirlwind
else
AddWhirlwind([new(-111.688f, 253.942f), new(-102.276f, 264.313f), new(-108.922f, 276.528f)]); // NW whirlwind
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ public enum TetherID : uint
}

class RonkanFire(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.RonkanFire));
class RonkanAbyss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RonkanAbyss), 6);
class RonkanAbyss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RonkanAbyss), 6f);

class WrathOfTheRonka(BossModule module) : Components.GenericAOEs(module)
{
private readonly List<AOEInstance> _aoes = new(6);
private static readonly AOEShapeRect rectShort = new(12, 4), rectMedium = new(22, 4), rectLong = new(35, 4);
private static readonly AOEShapeRect rectShort = new(12f, 4f), rectMedium = new(22f, 4f), rectLong = new(35f, 4f);

private static readonly (WPos Position, AOEShapeRect Shape)[] aoeMap =
[(new(-17, 627), rectMedium), (new(17, 642), rectMedium),
Expand All @@ -51,26 +51,29 @@ public override void OnTethered(Actor source, ActorTetherInfo tether)
if (tether.ID == (uint)TetherID.StatueActivate)
{
var aoeShape = GetAOEShape(source.Position) ?? rectLong;
_aoes.Add(new(aoeShape, source.Position, source.Rotation, WorldState.FutureTime(6)));
_aoes.Add(new(aoeShape, WPos.ClampToGrid(source.Position), source.Rotation, WorldState.FutureTime(6d)));
}
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID is AID.WrathOfTheRonkaShort or AID.WrathOfTheRonkaMedium or AID.WrathOfTheRonkaLong)
if (spell.Action.ID is (uint)AID.WrathOfTheRonkaShort or (uint)AID.WrathOfTheRonkaMedium or (uint)AID.WrathOfTheRonkaLong)
_aoes.Clear();
}

private static AOEShapeRect? GetAOEShape(WPos position)
{
foreach (var (pos, shape) in aoeMap)
if (position.AlmostEqual(pos, 1))
return shape;
for (var i = 0; i < 8; ++i)
{
var aoe = aoeMap[i];
if (position.AlmostEqual(aoe.Position, 1f))
return aoe.Shape;
}
return null;
}
}

class BurningBeam(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BurningBeam), new AOEShapeRect(15, 2));
class BurningBeam(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BurningBeam), new AOEShapeRect(15f, 2f));

class D030RonkanDreamerStates : StateMachineBuilder
{
Expand All @@ -87,21 +90,20 @@ public D030RonkanDreamerStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 651, NameID = 8639)]
public class D030RonkanDreamer(WorldState ws, Actor primary) : BossModule(ws, primary, primary.Position.Z > 550 ? arena1.Center : arena2.Center, primary.Position.Z > 550 ? arena1 : arena2)
{
private static readonly WPos[] vertices1 = [new(-3.82f, 640.12f), new(-3.95f, 640.67f), new(-3.98f, 646.62f), new(-6.08f, 646.51f), new(-6.58f, 644.99f),
new(-6.28f, 643.05f), new(-6.38f, 641.22f), new(-6.60f, 639.71f), new(-6.29f, 639.34f), new(-4.27f, 639.03f)];
private static readonly WPos[] vertices2 = [new(6.61f, 625.6f), new(6.3f, 627.46f), new(6.32f, 629.1f), new(6.54f, 630.78f), new(6.28f, 631.19f),
new(4.28f, 631.45f), new(3.83f, 630.55f), new(3.82f, 629.67f), new(3.96f, 623.91f), new(6.07f, 623.83f)];
private static readonly WPos[] vertices3 = [new(-3.77f, 418.91f), new(-3.94f, 419.58f), new(-3.97f, 425.34f), new(-6.11f, 425.47f), new(-6.59f, 423.67f),
new(-6.38f, 421.66f), new(-6.38f, 420.01f), new(-6.53f, 418.49f), new(-6.27f, 418.12f), new(-4, 417.82f),
new(-3.77f, 418.91f)];
private static readonly WPos[] vertices4 = [new(6.09f, 432.98f), new(6.64f, 434.58f), new(6.37f, 436.54f), new(6.31f, 438.11f), new(6.50f, 439.59f),
new(6.48f, 440.24f), new(4.29f, 440.32f), new(3.81f, 439.47f), new(3.95f, 438.75f), new(4.00f, 432.74f),
new(6.09f, 432.98f)];
private static readonly ArenaBoundsComplex arena1 = new([new Rectangle(new(0, 640), 17.5f, 23)], [new PolygonCustom(vertices1), new PolygonCustom(vertices2)]);
private static readonly ArenaBoundsComplex arena2 = new([new Rectangle(new(0, 434.5f), 17.5f, 24)], [new PolygonCustom(vertices3), new PolygonCustom(vertices4)]);
private static readonly WPos[] vertices1 = [new(-4.299f, 646.21f), new(-4.298f, 640.685f), new(-4.118f, 640.131f), new(-4.467f, 639.508f), new(-6.074f, 639.653f),
new(-6.195f, 639.858f), new(-5.99f, 641.313f), new(-5.958f, 643.01f), new(-6.236f, 644.911f), new(-5.856f, 646.17f)];
private static readonly WPos[] vertices2 = [new(6.074f, 630.811f), new(6.195f, 630.606f), new(5.99f, 629.151f), new(5.958f, 627.454f), new(6.236f, 625.553f),
new(5.856f, 624.294f), new(4.299f, 624.254f), new(4.298f, 629.779f), new(4.118f, 630.333f), new(4.467f, 630.956f)];
private static readonly WPos[] vertices3 = [new(6.074f, 439.811f), new(6.195f, 439.606f), new(5.99f, 438.151f), new(5.958f, 436.454f), new(6.236f, 434.553f),
new(5.856f, 433.294f), new(4.299f, 433.254f), new(4.298f, 438.779f), new(4.118f, 439.333f), new(4.467f, 439.956f)];
private static readonly WPos[] vertices4 = [new(-4.299f, 424.978f), new(-4.298f, 419.453f), new(-4.118f, 418.899f), new(-4.467f, 418.277f), new(-6.074f, 418.421f),
new(-6.195f, 418.626f), new(-5.99f, 420.081f), new(-5.958f, 421.778f), new(-6.236f, 423.679f), new(-5.856f, 424.938f)];
private static readonly ArenaBoundsComplex arena1 = new([new Rectangle(new(default, 640f), 17.25f, 23f)], [new PolygonCustomO(vertices1, 0.5f), new PolygonCustomO(vertices2, 0.5f)]);
private static readonly ArenaBoundsComplex arena2 = new([new Rectangle(new(default, 434.5f), 17.25f, 23.75f)], [new PolygonCustomO(vertices3, 0.5f), new PolygonCustomO(vertices4, 0.5f)]);

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actors(Enemies(OID.RonkanVessel).Concat([PrimaryActor]).Concat(Enemies(OID.RonkanThorn)).Concat(Enemies(OID.RonkanIdol)));
Arena.Actor(PrimaryActor);
Arena.Actors(Enemies([(uint)OID.RonkanVessel, (uint)OID.RonkanThorn, (uint)OID.RonkanIdol]));
}
}
22 changes: 11 additions & 11 deletions BossMod/Modules/Shadowbringers/Dungeon/D03QitanaRavel/D031Lozatl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,36 @@ public enum AID : uint
LozatlsFury2 = 15503 // Boss->self, 4.0s cast, range 60 width 20 rect
}

abstract class LozatlsFury(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(60, 20));
abstract class LozatlsFury(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(60f, 10f));
class LozatlsFury1(BossModule module) : LozatlsFury(module, AID.LozatlsFury1);
class LozatlsFury2(BossModule module) : LozatlsFury(module, AID.LozatlsFury2);

class Stonefist(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.Stonefist));
class LozatlsScorn(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.LozatlsScorn));
class SunToss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SunToss), 5);
class SunToss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SunToss), 5f);

class RonkanLight(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeRect rect = new(60, 20); //TODO: double halfwidth is strange
private static readonly AOEShapeRect rect = new(60f, 20f);
private AOEInstance? _aoe;

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

public override void OnActorEAnim(Actor actor, uint state)
{
void AddAOE(Angle rot) => _aoe = new(rect, D031Lozatl.ArenaCenter, rot, WorldState.FutureTime(8d));
if (state == 0x00040008)
{
var activation = WorldState.FutureTime(8);
if (actor.Position.AlmostEqual(new(8, 328), 1))
_aoe = new(rect, D031Lozatl.ArenaCenter, 90.Degrees(), activation);
else if (actor.Position.AlmostEqual(new(-7, 328), 1))
_aoe = new(rect, D031Lozatl.ArenaCenter, -90.Degrees(), activation);
if (actor.Position.AlmostEqual(new(8, 328), 1f))
AddAOE(90f.Degrees());
else if (actor.Position.AlmostEqual(new(-7, 328), 1f))
AddAOE(-90f.Degrees());
}
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID is AID.RonkanLightLeft or AID.RonkanLightRight)
if (spell.Action.ID is (uint)AID.RonkanLightLeft or (uint)AID.RonkanLightRight)
_aoe = null;
}
}
Expand All @@ -72,6 +72,6 @@ public D031LozatlStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 651, NameID = 8231)]
public class D031Lozatl(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena)
{
public static readonly WPos ArenaCenter = new(0, 315);
private static readonly ArenaBoundsComplex arena = new([new Polygon(ArenaCenter, 19.5f * CosPI.Pi40th, 40)], [new Rectangle(new(0, 335.1f), 20, 2), new Rectangle(new(0, 294.5f), 20, 2)]);
public static readonly WPos ArenaCenter = new(default, 315f);
private static readonly ArenaBoundsComplex arena = new([new Polygon(ArenaCenter, 19.5f * CosPI.Pi40th, 40)], [new Rectangle(new(default, 335.1f), 20f, 2f), new Rectangle(new(default, 294.5f), 20f, 2f)]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,62 @@ public enum OID : uint

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

RipperFang = 15505, // 27B0->player, 4.0s cast, single-target
Soundwave = 15506, // 27B0->self, 3.0s cast, range 40 circle
Subsonics = 15507, // 27B0->self, 6.0s cast, single-target
Subsonics2 = 15508, // 233C->self, no cast, range 40 circle
FallingRock = 15510, // 233C->self, 2.0s cast, range 3 circle
FallingRock2 = 15509, // 233C->self, 2.0s cast, range 2 circle
FallingBoulder = 15511, // 233C->self, 2.0s cast, range 4 circle
Towerfall = 15512 // 233C->self, 3.0s cast, range 15 30.5-degree cone
RipperFang = 15505, // Boss->player, 4.0s cast, single-target
Soundwave = 15506, // Boss->self, 3.0s cast, range 40 circle
Subsonics = 15507, // Boss->self, 6.0s cast, single-target
Subsonics2 = 15508, // Helper->self, no cast, range 40 circle
FallingRock = 15510, // Helper->self, 2.0s cast, range 3 circle
FallingRock2 = 15509, // Helper->self, 2.0s cast, range 2 circle
FallingBoulder = 15511, // Helper->self, 2.0s cast, range 4 circle
Towerfall = 15512 // Helper->self, 3.0s cast, range 15 30-degree cone
}

class Towerfall(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeCone cone = new(15, 15.25f.Degrees());
public List<AOEInstance> _aoes = [];
private static readonly AOEShapeCone cone = new(15f, 15f.Degrees());
public List<AOEInstance> _aoes = new(3);

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

public override void OnActorCreated(Actor actor)
{
if ((OID)actor.OID == OID.StalactiteBig)
_aoes.Add(new(cone, actor.Position, actor.Rotation, WorldState.FutureTime(12)));
if (actor.OID == (uint)OID.StalactiteBig) // preliminary, caster position is somewhat off from stalactite position...
_aoes.Add(new(cone, actor.Position, actor.Rotation, WorldState.FutureTime(12d)));
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.Soundwave)
if (spell.Action.ID == (uint)AID.Towerfall)
{
for (var i = 0; i < _aoes.Count; ++i)
_aoes[i] = _aoes[i] with { Activation = Module.CastFinishAt(spell, 3.7f) };
var count = _aoes.Count; // remove preliminary AOE
for (var i = 0; i < count; ++i)
{
var aoe = _aoes[i];
if (aoe.Origin == caster.Position)
{
_aoes.Remove(aoe);
break;
}
}
_aoes.Add(new(cone, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell))); // add aoe with correct location and activation
}
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.Towerfall)
if (_aoes.Count != 0 && spell.Action.ID == (uint)AID.Towerfall)
_aoes.Clear();
}
}

class Soundwave(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Soundwave), "Raidwide + towers fall");
class Subsonics(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Subsonics), "Raidwide x11");
class RipperFang(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.RipperFang));
class FallingBoulder(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingBoulder), 4);
class FallingRock(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock), 3);
class FallingRock2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock2), 2);
class FallingBoulder(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingBoulder), 4f);
class FallingRock(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock), 3f);
class FallingRock2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock2), 2f);

class D032BatsquatchStates : StateMachineBuilder
{
Expand All @@ -77,5 +86,5 @@ public D032BatsquatchStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 651, NameID = 8232)]
public class D032Batsquatch(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena)
{
private static readonly ArenaBoundsComplex arena = new([new Polygon(new(62, -35), 14.5f * CosPI.Pi28th, 28)], [new Rectangle(new(61.9f, -20), 20, 2), new Rectangle(new(61.9f, -50), 20, 2)]);
private static readonly ArenaBoundsComplex arena = new([new Polygon(new(62f, -35f), 14.5f * CosPI.Pi28th, 28)], [new Rectangle(new(61.9f, -20), 20f, 2f), new Rectangle(new(61.9f, -50f), 20f, 2f)]);
}
Loading

0 comments on commit 143a454

Please sign in to comment.