Skip to content

Commit

Permalink
Merge pull request #576 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
some cleanups
  • Loading branch information
CarnifexOptimus authored Jan 24, 2025
2 parents 619ff8c + 7b56453 commit 01a13ef
Show file tree
Hide file tree
Showing 41 changed files with 327 additions and 208 deletions.
2 changes: 1 addition & 1 deletion BossMod/AI/AIBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ sealed class AIBehaviour(AIController ctrl, RotationModuleManager autorot, Prese
public WorldState WorldState => autorot.Bossmods.WorldState;
public Preset? AIPreset = aiPreset;
public float ForceMovementIn = float.MaxValue; // TODO: reconsider
private readonly AIConfig _config = Service.Config.Get<AIConfig>();
private static readonly AIConfig _config = Service.Config.Get<AIConfig>();
private readonly NavigationDecision.Context _naviCtx = new();
private NavigationDecision _naviDecision;
private bool _afkMode;
Expand Down
3 changes: 1 addition & 2 deletions BossMod/AI/AIManagementWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace BossMod.AI;

sealed class AIManagementWindow : UIWindow
{
private readonly AIConfig _config;
private static readonly AIConfig _config = Service.Config.Get<AIConfig>();
private readonly AIManager _manager;
private readonly EventSubscriptions _subscriptions;
private const string _title = $"AI: off{_windowID}";
Expand All @@ -15,7 +15,6 @@ sealed class AIManagementWindow : UIWindow
public AIManagementWindow(AIManager manager) : base(_windowID, false, new(100, 100))
{
WindowName = _title;
_config = Service.Config.Get<AIConfig>();
_manager = manager;
_subscriptions = new
(
Expand Down
3 changes: 1 addition & 2 deletions BossMod/AI/AIManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sealed class AIManager : IDisposable
public static AIManager? Instance;
public readonly RotationModuleManager Autorot;
public readonly AIController Controller;
private readonly AIConfig _config;
private static readonly AIConfig _config = Service.Config.Get<AIConfig>();
private readonly AIManagementWindow _wndAI;
public int MasterSlot = PartyState.PlayerSlot; // non-zero means corresponding player is master
public AIBehaviour? Beh;
Expand All @@ -26,7 +26,6 @@ public AIManager(RotationModuleManager autorot, ActionManagerEx amex, MovementOv
_wndAI = new AIManagementWindow(this);
Autorot = autorot;
Controller = new(autorot.WorldState, amex, movement);
_config = Service.Config.Get<AIConfig>();
Service.CommandManager.AddHandler("/bmrai", new Dalamud.Game.Command.CommandInfo(OnCommand) { HelpMessage = "Toggle AI mode" });
Service.CommandManager.AddHandler("/vbmai", new Dalamud.Game.Command.CommandInfo(OnCommand) { ShowInHelp = false });
}
Expand Down
15 changes: 7 additions & 8 deletions BossMod/BossModule/ArenaBounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public override WDir ClampToBounds(WDir offset)
private Pathfinding.Map BuildMap()
{
var map = new Pathfinding.Map(MapResolution, default, Radius, Radius);
map.BlockPixelsInsideConvex(ShapeDistance.InvertedCircle(default, Radius), -1, 0);
map.BlockPixelsInside2(ShapeDistance.InvertedCircle(default, Radius), -1);
return map;
}
}
Expand All @@ -178,7 +178,7 @@ private static float CalculateScaleFactor(Angle Rotation)
private Pathfinding.Map BuildMap()
{
var map = new Pathfinding.Map(MapResolution, default, HalfWidth, HalfHeight, Rotation);
map.BlockPixelsInsideConvex(ShapeDistance.InvertedRect(default, Rotation, HalfHeight, HalfHeight, HalfWidth), -1, 0);
map.BlockPixelsInside2(ShapeDistance.InvertedRect(default, Rotation, HalfHeight, HalfHeight, HalfWidth), -1);
return map;
}

Expand Down Expand Up @@ -256,10 +256,10 @@ public override WDir ClampToBounds(WDir offset)
for (var i = 0; i < edges.Length; ++i)
{
ref var edge = ref edges[i];
var segmentVector = edge.Item2 - edge.Item1;
var segmentLengthSq = segmentVector.LengthSq();
var t = Math.Max(0, Math.Min(1, (offset - edge.Item1).Dot(segmentVector) / segmentLengthSq));
var nearest = edge.Item1 + t * segmentVector;
var edge1 = edge.Item1;
var segmentVector = edge.Item2 - edge1;
var t = Math.Max(0, Math.Min(1, (offset - edge1).Dot(segmentVector) / segmentVector.LengthSq()));
var nearest = edge1 + t * segmentVector;
var distance = (nearest - offset).LengthSq();

if (distance < minDistance)
Expand Down Expand Up @@ -304,7 +304,6 @@ private Pathfinding.Map BuildMap()
var width = map.Width;
var height = map.Height;
var resolution = map.Resolution;
ref var center = ref map.Center;

var halfSample = resolution * Half - Epsilon; // tiny offset to account for floating point inaccuracies

Expand All @@ -323,7 +322,7 @@ private Pathfinding.Map BuildMap()

var dx = new WDir(resolution, 0);
var dy = new WDir(0, resolution);
var startPos = center - (width * Half - Half) * dx - (height * Half - Half) * dy;
var startPos = map.Center - (width * Half - Half) * dx - (height * Half - Half) * dy;

Parallel.For(0, height, y =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,25 @@ public override void AddGlobalHints(GlobalHints hints)

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
var orbs = new List<Func<WPos, float>>();
Actor[] sph = [.. _orbs];
var len = sph.Length;
Actor[] orbz = [.. _orbs];
var len = orbz.Length;
if (len != 0)
{
var orbs = new Func<WPos, float>[len];
hints.ActionsToExecute.Push(ActionID.MakeSpell(ClassShared.AID.Sprint), actor, ActionQueue.Priority.High);
for (var i = 0; i < len; ++i)
{
var o = sph[i];
orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.5f * o.Rotation.ToDirection(), 0.56f));
var o = orbz[i];
orbs[i] = ShapeDistance.InvertedRect(o.Position + 0.5f * o.Rotation.ToDirection(), new WDir(0, 1), 0.75f, 0.75f, 0.75f);
}
}
if (orbs.Count != 0)
hints.AddForbiddenZone(ShapeDistance.Intersection(orbs));
}
}

public override void DrawArenaForeground(int pcSlot, Actor pc)
{
foreach (var orb in _orbs)
Arena.AddCircle(orb.Position, 1.4f, Colors.Safe);
Arena.AddCircle(orb.Position, 1, Colors.Safe);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var count = AOEs.Count;
if (count == 0)
yield break;
return [];
var aoes = new AOEInstance[count];
for (var i = 0; i < count; ++i)
{
var aoe = AOEs[i];
yield return (aoe.Activation - AOEs[0].Activation).TotalSeconds <= delay ? aoe with { Color = Colors.Danger } : aoe with { Risky = false };
aoes[i] = (aoe.Activation - AOEs[0].Activation).TotalSeconds <= delay ? aoe with { Color = Colors.Danger } : aoe with { Risky = false };
}
return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public enum AID : uint
FreeSpiritsVisual = 40639, // Boss->self, 4.0+1,0s cast, single-target
FreeSpirits = 40640, // Helper->self, 5.0s cast, range 20 circle

Soulweave1 = 40642, // PreservedSoul->self, 2.5s cast, range ?-32 donut
Soulweave2 = 40641, // PreservedSoul->self, 2.5s cast, range ?-32 donut
Soulweave1 = 40642, // PreservedSoul->self, 2.5s cast, range 28-32 donut
Soulweave2 = 40641, // PreservedSoul->self, 2.5s cast, range 28-32 donut

PhantomFloodVisual = 40643, // Boss->self, 3.7+1,3s cast, single-target
PhantomFlood = 40644, // Helper->self, 5.0s cast, range 5-20 donut
Expand Down Expand Up @@ -90,12 +90,14 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var count = _aoes.Count;
if (count == 0)
yield break;
return [];
var aoes = new AOEInstance[count];
for (var i = 0; i < count; ++i)
{
var aoe = _aoes[i];
yield return (aoe.Activation - _aoes[0].Activation).TotalSeconds <= 1.2 ? aoe with { Color = Colors.Danger } : aoe with { Risky = false };
aoes[i] = (aoe.Activation - _aoes[0].Activation).TotalSeconds <= 1.3f ? aoe with { Color = Colors.Danger } : aoe with { Risky = false };
}
return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
Expand Down Expand Up @@ -130,9 +132,9 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
if (count == 0)
return [];
var max = count > 6 ? 6 : count;
List<AOEInstance> aoes = new(max);
var aoes = new AOEInstance[max];
for (var i = 0; i < max; ++i)
aoes.Add(_aoes[i]);
aoes[i] = _aoes[i];
return aoes;
}

Expand Down
6 changes: 3 additions & 3 deletions BossMod/Modules/Dawntrail/Hunt/RankA/Nechuciho.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
if (count == 0)
return [];
var max = count > 2 ? 2 : count;
List<AOEInstance> aoes = new(max);
var aoes = new AOEInstance[max];
for (var i = 0; i < max; ++i)
{
var aoe = _aoes[i];
if (i == 0)
aoes.Add(count > 1 ? aoe with { Color = Colors.Danger } : aoe);
aoes[i] = count > 1 ? aoe with { Color = Colors.Danger } : aoe;
else if (i == 1)
aoes.Add(_aoes[0].Rotation.AlmostEqual(_aoes[1].Rotation + a180, Angle.DegToRad) ? aoe with { Risky = false } : aoe);
aoes[i] = _aoes[0].Rotation.AlmostEqual(_aoes[1].Rotation + a180, Angle.DegToRad) ? aoe with { Risky = false } : aoe;
}
return aoes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,25 @@ public override void AddGlobalHints(GlobalHints hints)

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
var orbs = new List<Func<WPos, float>>();
if (ActiveOrbs.Any())
foreach (var o in ActiveOrbs)
orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.56f * o.Rotation.ToDirection(), 0.75f));
if (orbs.Count > 0)
Actor[] orbz = [.. ActiveOrbs];
var len = orbz.Length;
if (len != 0)
{
var orbs = new Func<WPos, float>[len];
hints.ActionsToExecute.Push(ActionID.MakeSpell(ClassShared.AID.Sprint), actor, ActionQueue.Priority.High);
for (var i = 0; i < len; ++i)
{
var o = orbz[i];
orbs[i] = ShapeDistance.InvertedRect(o.Position + 0.5f * o.Rotation.ToDirection(), new WDir(0, 1), 0.75f, 0.75f, 0.75f);
}
hints.AddForbiddenZone(ShapeDistance.Intersection(orbs));
}
}

public override void DrawArenaForeground(int pcSlot, Actor pc)
{
foreach (var orb in ActiveOrbs)
Arena.AddCircle(orb.Position, 1.4f, Colors.Safe);
Arena.AddCircle(orb.Position, 1, Colors.Safe);
}
}

Expand Down
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 @@ -13,6 +13,7 @@ class P5ParadiseLost(BossModule module) : Components.CastCounter(module, ActionI
public class FRU(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena with { IsCircle = true })
{
private static readonly ArenaBoundsComplex arena = new([new Polygon(new(100, 100), 20, 64)]);
public static readonly ArenaBoundsSquare PathfindHugBorderBounds = new(20); // this is a hack to allow precise positioning near border by some mechanics, TODO reconsider

private Actor? _bossP2;
private Actor? _iceVeil;
Expand Down
1 change: 1 addition & 0 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/P1UtopianSky.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
_ => default
};
var range = spreadSpot == 0 ? 13 : 19;
hints.PathfindMapBounds = FRU.PathfindHugBorderBounds;
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Arena.Center + range * direction.ToDirection(), new(0, 1), Arena.Bounds.MapResolution, actor.Position, 0.1f), _aoes.Activation);
}
}
Expand Down
5 changes: 4 additions & 1 deletion BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ class P2DiamondDustSafespots(BossModule module) : BossComponent(module)
public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
if (_safeOffs[slot] != default)
{
hints.PathfindMapBounds = FRU.PathfindHugBorderBounds;
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Arena.Center + _safeOffs[slot], new WDir(0, 1), Arena.Bounds.MapResolution, actor.Position, 0.1f));
}
}

public override void DrawArenaForeground(int pcSlot, Actor pc)
Expand Down Expand Up @@ -299,7 +302,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
// non-healers should just stack with whatever closest healer is
// before first cast, ignore master's movements
var moveDir = NumCasts > 0 ? master.LastFrameMovement.Normalized() : default;
var capsule = ShapeDistance.Capsule(master.Position + 2 * moveDir, moveDir, 4, 1);
var capsule = ShapeDistance.Capsule(master.Position + 2 * moveDir, moveDir, 4, 1.5f);
hints.AddForbiddenZone(p => -capsule(p), DateTime.MaxValue);
}

Expand Down
12 changes: 6 additions & 6 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/P2MirrorMirror.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,21 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
{
0 => -135.Degrees(),
1 => 135.Degrees(),
2 => -90.Degrees(),
3 => 90.Degrees(),
2 => -95.Degrees(),
3 => 95.Degrees(),
_ => default
};
}
else
{
dir = Angle.FromDirection(origin.Actor.Position - Arena.Center) + group switch
{
0 => (RedRangedLeftOfMelee ? -90 : 90).Degrees(),
1 => (RedRangedLeftOfMelee ? 90 : -90).Degrees(),
0 => (RedRangedLeftOfMelee ? -95 : 95).Degrees(),
1 => (RedRangedLeftOfMelee ? 95 : -95).Degrees(),
2 => 180.Degrees(),
3 => (RedRangedLeftOfMelee ? -135 : 135).Degrees(),
4 => -90.Degrees(),
5 => 90.Degrees(),
4 => -95.Degrees(),
5 => 95.Degrees(),
6 => (RedRangedLeftOfMelee ? 180 : -135).Degrees(),
7 => (RedRangedLeftOfMelee ? 135 : 180).Degrees(),
_ => default
Expand Down
7 changes: 4 additions & 3 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/P3Apocalypse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.ComponentModel;

namespace BossMod.Dawntrail.Ultimate.FRU;
namespace BossMod.Dawntrail.Ultimate.FRU;

class P3Apocalypse(BossModule module) : Components.GenericAOEs(module)
{
Expand Down Expand Up @@ -268,7 +266,10 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
{
var safeSpot = SafeOffset(slot, out _);
if (safeSpot != default)
{
hints.PathfindMapBounds = FRU.PathfindHugBorderBounds;
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Arena.Center + safeSpot, new(0, 1), Arena.Bounds.MapResolution, actor.Position, 0.1f), Spreads.Count != 0 ? Spreads[0].Activation : DateTime.MaxValue);
}
}

public override void DrawArenaForeground(int pcSlot, Actor pc)
Expand Down
7 changes: 4 additions & 3 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/P4CrystallizeTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,10 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
if (hint.offset != default)
{
// we want to stay really close to border
if (hint.offset.LengthSq() > 18 * 18)
hint.offset *= 19.5f / 19;
if (hint.offset.LengthSq() > 324)
hint.offset *= 1.02632f;

if (hint.hint.HasFlag(Hint.KnockbackFrom) && Raid.WithoutSlot().Any(p => p.PendingKnockbacks.Count > 0))
if (hint.hint.HasFlag(Hint.KnockbackFrom) && Raid.WithoutSlot(false, true, true).Any(p => p.PendingKnockbacks.Count > 0))
{
return; // don't even try moving until all knockbacks are resolved, that can fuck up others...
}
Expand All @@ -412,6 +412,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
}
if (hint.hint.HasFlag(Hint.SafespotPrecise))
{
hints.PathfindMapBounds = FRU.PathfindHugBorderBounds;
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Arena.Center + hint.offset, new(0, 1), Arena.Bounds.MapResolution, actor.Position, 0.1f));
}
if (hint.hint.HasFlag(Hint.Maelstrom) && _hourglass != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme

// do not clip either tower (it's visible at half-angle = asin(4/8) = 30) or each other
var dir = (_darklit.AssignE[slot] ? +1 : -1) * (_darklit.AssignS[slot] ? 60 : 120).Degrees();
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Module.Center + 4 * dir.ToDirection(), new(0, 1), Arena.Bounds.MapResolution, actor.Position, 0.1f), _activation);
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Arena.Center + 4 * dir.ToDirection(), new(0, 1), Arena.Bounds.MapResolution, actor.Position, 0.1f), _activation);
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,23 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
var count = _aoes.Count;
if (count == 0)
return [];
List<AOEInstance> aoes = new(count);
var aoes = new AOEInstance[count];
for (var i = 0; i < count; ++i)
{
var aoe = _aoes[i];
if (i == 0)
aoes.Add(count > 1 ? aoe with { Color = Colors.Danger } : aoe);
aoes[i] = count > 1 ? aoe with { Color = Colors.Danger } : aoe;
else
aoes.Add(aoe with { Risky = false });
aoes[i] = aoe with { Risky = false };
}
return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.DireStraitsVisualFirst)
if ((AID)spell.Action.ID is AID.DireStraitsVisualFirst or AID.DireStraitsVisualSecond)
{
_aoes.Add(new(_shape, Arena.Center, spell.Rotation, Module.CastFinishAt(spell, 5)));
_aoes.Add(new(_shape, Arena.Center, spell.Rotation + 180.Degrees(), Module.CastFinishAt(spell, 6.7f)));
_aoes.Add(new(_shape, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell, 4.8f)));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class SerpentsTide(BossModule module) : Components.GenericAOEs(module)
public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.SerpentsTide)
AOEs.Add(new(_shape, caster.Position, spell.Rotation, Module.CastFinishAt(spell)));
AOEs.Add(new(_shape, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell)));
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
Expand Down
Loading

0 comments on commit 01a13ef

Please sign in to comment.