Skip to content

Commit

Permalink
excalibur module improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Feb 13, 2025
1 parent f9a71f6 commit b7bd753
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 74 deletions.
2 changes: 1 addition & 1 deletion BossMod/BossModule/ZoneModuleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
public sealed class ZoneModuleManager : IDisposable
{
public readonly WorldState WorldState;
public readonly ZoneModuleConfig Config = Service.Config.Get<ZoneModuleConfig>();
public static readonly ZoneModuleConfig Config = Service.Config.Get<ZoneModuleConfig>();
private readonly EventSubscriptions _subsciptions;

public ZoneModule? ActiveModule;
Expand Down
136 changes: 88 additions & 48 deletions BossMod/Modules/Endwalker/DeepDungeon/EurekaOrthos/DD99Excalibur.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public enum AID : uint
SteelFlame = 31336, // Caliburnus->location, 2.0s cast, width 4 rect charge
SteelFrost = 31337, // Caliburnus->location, 2.0s cast, width 4 rect charge

AbyssalSlash1 = 31339, // Helper->self, 7.0s cast, range 2-7 donut
AbyssalSlash2 = 31340, // Helper->self, 7.0s cast, range 7-12 donut
AbyssalSlash3 = 31341, // Helper->self, 7.0s cast, range 17-22 donut
AbyssalSlash1 = 31339, // Helper->self, 7.0s cast, range 2-7 180-degree donut segment
AbyssalSlash2 = 31340, // Helper->self, 7.0s cast, range 7-12 180-degree donut segment
AbyssalSlash3 = 31341, // Helper->self, 7.0s cast, range 17-22 180-degree donut segment

FlamesRevelation = 31331, // Helper->self, no cast, range 60 circle
FrostRevelation = 31332, // Helper->self, no cast, range 60 circle
Expand All @@ -59,10 +59,10 @@ class Steelstrike(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeRect rect = new(20f, 2f);
private static readonly AOEShapeRect rect2 = new(20f, 2f, 20f);
private readonly HashSet<AOEInstance> _aoes = [];
private readonly List<Angle> angles = [];
private readonly List<AOEInstance> swordsFire = [];
private readonly List<AOEInstance> swordsIce = [];
private readonly List<AOEInstance> _aoes = new(15);
private readonly List<Angle> angles = new(15);
private readonly List<AOEInstance> swordsFire = new(5);
private readonly List<AOEInstance> swordsIce = new(5);
private static readonly Angle[] offsets = [default, 120f.Degrees(), 240f.Degrees()];
private static readonly Angle a20 = 20f.Degrees();
private static readonly Angle a10 = 10f.Degrees();
Expand All @@ -78,19 +78,29 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
var ice = actor.FindStatus((uint)SID.SoulOfIce) != null;

return ice && (bool)nextRaidwide ? GetSafeAOEs(swordsFire)
: fire && !(bool)nextRaidwide ? GetSafeAOEs(swordsIce)
: _aoes;
: fire && !(bool)nextRaidwide ? GetSafeAOEs(swordsIce) : _aoes;
}

private IEnumerable<AOEInstance> GetSafeAOEs(List<AOEInstance> swordAOEs)
private AOEInstance[] GetSafeAOEs(List<AOEInstance> swordAOEs)
{
var result = _aoes.Except([swordAOEs.First(), swordAOEs.Last()]).ToList();
var safeAOEs = new[]
var count = _aoes.Count;
var aoes = new AOEInstance[count];

var firstSwordAOE = swordAOEs[0];
var lastSwordAOE = swordAOEs[^1];
var index = 0;
for (var i = 0; i < count; ++i)
{
swordAOEs.First() with { Color = Colors.SafeFromAOE },
swordAOEs.Last() with { Color = Colors.SafeFromAOE }
};
return result.Concat(safeAOEs);
var aoe = _aoes[i];
if (aoe == firstSwordAOE || aoe == lastSwordAOE)
continue;
aoes[index++] = _aoes[i];
}

aoes[^1] = firstSwordAOE with { Color = Colors.SafeFromAOE, Risky = false };
aoes[^2] = lastSwordAOE with { Color = Colors.SafeFromAOE, Risky = false };

return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
Expand All @@ -103,8 +113,9 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell)
break;
case (uint)AID.ThermalDivide1:
case (uint)AID.ParadoxumVisual:
foreach (var a in angles)
_aoes.Add(new(rect2, Arena.Center, a, Module.CastFinishAt(spell, 3.4f)));
var count = angles.Count;
for (var i = 0; i < count; ++i)
_aoes.Add(new(rect2, Arena.Center, angles[i], Module.CastFinishAt(spell, 3.4f)));
break;
case (uint)AID.Flameforge:
nextRaidwide = false;
Expand Down Expand Up @@ -145,14 +156,22 @@ public override void OnStatusGain(Actor actor, ActorStatus status)
swordsFire.Sort((a, b) => a.Rotation.Rad.CompareTo(b.Rotation.Rad));
swordsIce.Sort((a, b) => a.Rotation.Rad.CompareTo(b.Rotation.Rad));
}
void AddSwordAOE(Actor actor, List<AOEInstance> swordAOEs)
{
var count = _aoes.Count;
for (var i = 0; i < count; ++i)
{
var aoe = _aoes[i];
if (aoe.Rotation.AlmostEqual(actor.Rotation, Angle.DegToRad))
{
swordAOEs.Add(aoe);
break;
}
}
}
}
}

private void AddSwordAOE(Actor actor, List<AOEInstance> swordAOEs)
{
swordAOEs.Add(_aoes.FirstOrDefault(x => x.Origin.AlmostEqual(actor.Position, 1f)));
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
switch (spell.Action.ID)
Expand Down Expand Up @@ -182,22 +201,41 @@ private void AddAOEs(Angle rotation)
if (NumCasts == 0)
AddSingleAOE(rot);
else
foreach (var o in offsets)
AddSingleAOE(rot + o);
{
for (var j = 0; j < 3; ++j)
AddSingleAOE(rot + offsets[j]);
}
}
void AddSingleAOE(Angle rot)
{
_aoes.Add(new(rect, Arena.Center, rot));
angles.Add(rot);
}
}

private void AddSingleAOE(Angle rotation)
{
_aoes.Add(new(rect, WPos.ClampToGrid(Arena.Center), rotation));
angles.Add(rotation);
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if (spell.Action.ID is (uint)AID.FlamesRevelation or (uint)AID.FrostRevelation)
nextRaidwide = null;
}

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
if (_aoes.Count == 0)
return;
base.AddAIHints(slot, actor, assignment, hints);
var forbidden = new Func<WPos, float>[2];
var index = 0;
foreach (var aoe in ActiveAOEs(slot, actor))
{
if (aoe.Color == Colors.SafeFromAOE)
{
forbidden[index++] = ShapeDistance.InvertedRect(aoe.Origin, aoe.Rotation, 20f, 20f, 2f);
}
}
if (index != 0)
hints.AddForbiddenZone(ShapeDistance.Intersection(forbidden), _aoes[0].Activation);
}
}

class ThermalDivideSides(BossModule module) : Components.GenericAOEs(module)
Expand All @@ -222,30 +260,25 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
return [];
}

private IEnumerable<AOEInstance> HandleAOEs(bool condition)
private AOEInstance[] HandleAOEs(bool condition)
{
var pos1 = WPos.ClampToGrid(Arena.Center + offset);
var pos2 = WPos.ClampToGrid(Arena.Center - offset);
var pos1 = Arena.Center + offset;
var pos2 = Arena.Center - offset;

if (condition)
{
yield return new(cone, pos1, rotation + a90, activation);
yield return new(cone with { InvertForbiddenZone = true }, pos2, rotation - a90, activation, Colors.SafeFromAOE);
}
else
{
yield return new(cone, pos2, rotation - a90, activation);
yield return new(cone with { InvertForbiddenZone = true }, pos1, rotation + a90, activation, Colors.SafeFromAOE);
}
var check = condition ? 1 : -1;
var aoes = new AOEInstance[2];
aoes[0] = new(cone, condition ? pos1 : pos2, rotation + check * a90, activation);
aoes[1] = new(cone with { InvertForbiddenZone = true }, condition ? pos2 : pos1, rotation - check * a90, activation, Colors.SafeFromAOE);
return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if (spell.Action.ID is (uint)AID.ThermalDivideVisual1 or (uint)AID.ThermalDivideVisual2)
{
pattern = (AID)spell.Action.ID == AID.ThermalDivideVisual2;
pattern = spell.Action.ID == (uint)AID.ThermalDivideVisual2;
rotation = spell.Rotation;
offset = 4 * (spell.Rotation + a90).ToDirection();
offset = 4f * (spell.Rotation + a90).ToDirection();
activation = Module.CastFinishAt(spell, 1.9f);
}
}
Expand All @@ -260,8 +293,15 @@ public override void AddHints(int slot, Actor actor, TextHints hints)
{
if (pattern == null)
return;
if (ActiveAOEs(slot, actor).Any(c => c.Color == Colors.SafeFromAOE && !c.Check(actor.Position)))
hints.Add("Go to safe side!");

foreach (var aoe in ActiveAOEs(slot, actor))
{
if (aoe.Color == Colors.SafeFromAOE && !aoe.Check(actor.Position))
{
hints.Add("Go to safe side!");
break;
}
}
}
}

Expand Down
38 changes: 19 additions & 19 deletions BossMod/Modules/Endwalker/Dungeon/D05Aitiascope/D052Rhitahtyn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public override void OnEventEnvControl(byte index, uint state)
union.AddRange([squares[1], squares[3]]);

Safespots = true;
activation = WorldState.FutureTime(7.3f);
activation = WorldState.FutureTime(7.3d);
UpdateArena();
}
else if (state == 0x00080004)
Expand Down Expand Up @@ -103,22 +103,22 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
class Shrapnel(BossModule module) : Components.GenericAOEs(module)
{
private readonly List<AOEInstance> _aoes = new(36);
private static readonly AOEShapeCircle circle = new(6);
private static readonly Dictionary<string, WPos[]> shrapnelPositions = new()
private static readonly AOEShapeCircle circle = new(6f);
private static readonly Dictionary<int, WPos[]> shrapnelPositions = new()
{
["SWNE"] = [ new(-6.027f, 153.979f), new(7.98f, 160.998f), new(20.981f, 126.97f), new(7.98f, 146.99f), new(27.97f, 140.978f),
[1] = [ new(-6.027f, 153.979f), new(7.98f, 160.998f), new(20.981f, 126.97f), new(7.98f, 146.99f), new(27.97f, 140.978f), // SWNE
new(20.981f, 140.978f), new(27.97f, 133.99f), new(13.992f, 140.978f), new(20.981f, 133.99f), new(0.992f, 146.99f),
new(0.992f, 153.979f), new(-6.027f, 160.998f), new(13.992f, 126.97f), new(13.992f, 133.99f), new(0.992f, 160.998f),
new(-6.027f, 146.99f), new(7.98f, 153.979f), new(27.97f, 126.97f) ],
["NWSE"] = [ new(20.981f, 160.998f), new(13.992f, 153.979f), new(-6.027f, 140.978f), new(13.992f, 160.998f), new(-6.027f, 126.97f),
[2] = [ new(20.981f, 160.998f), new(13.992f, 153.979f), new(-6.027f, 140.978f), new(13.992f, 160.998f), new(-6.027f, 126.97f), // NWSE
new(7.98f, 126.97f), new(0.992f, 133.99f), new(7.98f, 133.99f), new(-6.027f, 133.99f), new(27.97f, 153.979f),
new(13.992f, 146.99f), new(20.981f, 146.99f), new(0.992f, 126.97f), new(0.992f, 140.978f), new(27.97f, 160.998f),
new(27.97f, 146.99f), new(20.981f, 153.979f), new(7.98f, 140.978f) ],
["W"] = [ new(-6.027f, 160.998f), new(0.992f, 153.979f), new(7.98f, 133.99f), new(-6.027f, 146.99f), new(-6.027f, 140.978f),
[3] = [ new(-6.027f, 160.998f), new(0.992f, 153.979f), new(7.98f, 133.99f), new(-6.027f, 146.99f), new(-6.027f, 140.978f), // W
new(0.992f, 133.99f), new(-6.027f, 133.99f), new(7.98f, 126.97f), new(0.992f, 140.978f), new(7.98f, 153.979f),
new(-6.027f, 153.979f), new(0.992f, 146.99f), new(0.992f, 126.97f), new(-6.027f, 126.97f), new(0.992f, 160.998f),
new(7.98f, 160.998f), new(7.98f, 146.99f), new(7.98f, 140.978f) ],
["E"] = [ new(13.992f, 160.998f), new(20.981f, 146.99f), new(20.981f, 140.978f), new(27.97f, 146.99f), new(27.97f, 140.978f),
[4] = [ new(13.992f, 160.998f), new(20.981f, 146.99f), new(20.981f, 140.978f), new(27.97f, 146.99f), new(27.97f, 140.978f), // E
new(20.981f, 133.99f), new(13.992f, 126.97f), new(27.97f, 126.97f), new(27.97f, 133.99f), new(13.992f, 146.99f),
new(27.97f, 153.979f), new(20.981f, 153.979f), new(20.981f, 126.97f), new(13.992f, 133.99f), new(13.992f, 153.979f),
new(27.97f, 160.998f), new(20.981f, 160.998f), new(13.992f, 140.978f) ]
Expand All @@ -129,31 +129,31 @@ public override void Update()
{
if (_aoes.Count == 0)
{
var target1SWNE = Module.Enemies(OID.TargetMarker1).FirstOrDefault(x => x.Position.Z < 144 && x.Rotation >= 0.1f.Degrees());
var target1NWSE = Module.Enemies(OID.TargetMarker1).FirstOrDefault(x => x.Position.Z < 144 && x.Rotation <= -0.1f.Degrees());
var target2W = Module.Enemies(OID.TargetMarker2).FirstOrDefault(x => x.Position.X < 11);
var target2E = Module.Enemies(OID.TargetMarker2).FirstOrDefault(x => x.Position.X > 11);
var target1SWNE = Module.Enemies((uint)OID.TargetMarker1).FirstOrDefault(x => x.Position.Z < 144f && x.Rotation >= 0.1f.Degrees());
var target1NWSE = Module.Enemies((uint)OID.TargetMarker1).FirstOrDefault(x => x.Position.Z < 144f && x.Rotation <= -0.1f.Degrees());
var target2W = Module.Enemies((uint)OID.TargetMarker2).FirstOrDefault(x => x.Position.X < 11f);
var target2E = Module.Enemies((uint)OID.TargetMarker2).FirstOrDefault(x => x.Position.X > 11f);
if (target1SWNE != null)
AddAOEs("SWNE");
AddAOEs(1);
else if (target1NWSE != null)
AddAOEs("NWSE");
AddAOEs(2);
else if (target2W != null)
AddAOEs("W");
AddAOEs(3);
else if (target2E != null)
AddAOEs("E");
AddAOEs(4);
}
}

private void AddAOEs(string direction)
private void AddAOEs(int direction)
{
foreach (var position in shrapnelPositions[direction])
_aoes.Add(new(circle, position, default, WorldState.FutureTime(8)));
_aoes.Add(new(circle, position, default, WorldState.FutureTime(8d)));
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if (_aoes.Count != 0 && (AID)spell.Action.ID == AID.ShrapnelShellAOE)
_aoes.RemoveAll(x => x.Origin.AlmostEqual(spell.LocXZ, 1));
if (_aoes.Count != 0 && spell.Action.ID == (uint)AID.ShrapnelShellAOE)
_aoes.RemoveAll(x => x.Origin.AlmostEqual(spell.LocXZ, 1f));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ private WPos CalculateSafeSpot(int slot)
WDir[] offsets = [new(+1, -1), new(+1, +1), new(-1, +1), new(-1, -1)]; // CW from N
var relevantTether = _states[slot].Debuff == DebuffType.Light ? EngravementOfSoulsTethers.TetherType.Dark : EngravementOfSoulsTethers.TetherType.Light;
var expectedPositions = _tethers.States.Where(s => s.Source != null).Select(s => (s.Source!.Position + 40 * s.Source.Rotation.ToDirection(), s.Tether == relevantTether)).ToList();
var offsetsOrdered = (Raid[slot]?.Class.IsSupport() ?? false) ? offsets.AsEnumerable() : offsets.Reverse();
var positionsOrdered = offsetsOrdered.Select(d => Module.Center + 7 * d);
var offsetsOrdered = (Raid[slot]?.Class.IsSupport() ?? false) ? offsets.AsEnumerable() : offsets.AsEnumerable().Reverse();
var positionsOrdered = offsetsOrdered.Select(d => Arena.Center + 7f * d);
var firstMatch = positionsOrdered.First(p => expectedPositions.MinBy(ep => (ep.Item1 - p).LengthSq()).Item2);
_states[slot].CachedSafespot = firstMatch;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ class WrathOfTheRonka(BossModule module) : Components.GenericAOEs(module)
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),
(new(-17, 436), rectMedium), (new(17, 421), rectMedium),
(new(-17, 642), rectShort), (new(17, 627), rectShort),
(new(17, 436), rectShort), (new(-17, 421), rectShort)];
[(new(-17f, 627f), rectMedium), (new(17f, 642f), rectMedium),
(new(-17f, 436f), rectMedium), (new(17f, 421f), rectMedium),
(new(-17f, 642f), rectShort), (new(17f, 627f), rectShort),
(new(17f, 436f), rectShort), (new(-17f, 421f), rectShort)];

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

Expand Down

0 comments on commit b7bd753

Please sign in to comment.