Skip to content

Commit

Permalink
Merge pull request #542 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
some cleanup
  • Loading branch information
CarnifexOptimus authored Jan 4, 2025
2 parents 87ad87b + 25375f1 commit 608d884
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 113 deletions.
8 changes: 4 additions & 4 deletions BossMod/BossModule/StateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class Phase(State initialState, string name, float expectedDuration = -1)
public PhaseHint Hint = PhaseHint.None; // special flags for phase
}

public List<Phase> Phases { get; private init; } = phases;
public readonly List<Phase> Phases = phases;

private DateTime _curTime;
private DateTime _activation;
Expand All @@ -68,14 +68,14 @@ public class Phase(State initialState, string name, float expectedDuration = -1)
public float TimeSinceTransition => (float)(_curTime - _lastTransition).TotalSeconds;
public float TimeSinceTransitionClamped => Math.Min(TimeSinceTransition, ActiveState?.Duration ?? 0);

public int ActivePhaseIndex { get; private set; } = -1;
public int ActivePhaseIndex = -1;
public Phase? ActivePhase => Phases.ElementAtOrDefault(ActivePhaseIndex);
public State? ActiveState { get; private set; }
public State? ActiveState;

public void Start(DateTime now)
{
_activation = _curTime = now;
if (Phases.Count > 0)
if (Phases.Count != 0)
TransitionToPhase(0);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,22 @@ class IceScreamFrozenSwirl(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeRect rect = new(20, 10);
private static readonly AOEShapeCircle circle = new(15);
private readonly List<AOEInstance> _aoesCircle = [];
private readonly List<AOEInstance> _aoesRect = [];
private readonly HashSet<Actor> circleAOE = [];
private readonly HashSet<Actor> rectAOE = [];
private readonly List<AOEInstance> _aoesCircle = new(4), _aoesRect = new(4);
private readonly List<Actor> circleAOE = new(4), rectAOE = new(4);

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => _aoesCircle.Take(2).Concat(_aoesRect.Take(2));
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var countCircle = _aoesCircle.Count;
var countRect = _aoesRect.Count;
if (countCircle == 0 && countRect == 0)
return [];
var result = new List<AOEInstance>(4);
for (var i = 0; i < 2 && i < countCircle; ++i)
result.Add(_aoesCircle[i]);
for (var i = 0; i < 2 && i < countRect; ++i)
result.Add(_aoesRect[i]);
return result;
}

public override void OnActorCreated(Actor actor)
{
Expand All @@ -89,10 +99,10 @@ public override void OnTethered(Actor source, ActorTetherInfo tether)
circleAOE.Remove(source);
if (_aoesCircle.Count == 2)
{
foreach (var e in circleAOE)
_aoesCircle.Add(new(circle, e.Position, default, activation1));
for (var i = 0; i < circleAOE.Count; ++i)
_aoesCircle.Add(new(circle, circleAOE[i].Position, default, activation1));
circleAOE.Clear();
_aoesCircle.SortBy(x => x.Activation);
_aoesCircle.Sort((x, y) => x.Activation.CompareTo(y.Activation));
}
}
else if (rectAOE.Contains(source))
Expand All @@ -101,20 +111,23 @@ public override void OnTethered(Actor source, ActorTetherInfo tether)
rectAOE.Remove(source);
if (_aoesRect.Count == 2)
{
foreach (var e in rectAOE)
for (var i = 0; i < rectAOE.Count; ++i)
{
var e = rectAOE[i];
_aoesRect.Add(new(rect, e.Position, e.Rotation, activation1));
}
rectAOE.Clear();
_aoesRect.SortBy(x => x.Activation);
_aoesRect.Sort((x, y) => x.Activation.CompareTo(y.Activation));
}
}
}
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if (_aoesRect.Count > 0 && (AID)spell.Action.ID == AID.IceScream)
if (_aoesRect.Count != 0 && (AID)spell.Action.ID == AID.IceScream)
_aoesRect.RemoveAt(0);
else if (_aoesCircle.Count > 0 && (AID)spell.Action.ID == AID.FrozenSwirl)
else if (_aoesCircle.Count != 0 && (AID)spell.Action.ID == AID.FrozenSwirl)
_aoesCircle.RemoveAt(0);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,17 @@ public D050OrigenicsAerostatStates(D050OrigenicsAerostat module) : base(module)
TrivialPhase()
.ActivateOnEnter<IncendiaryCircle>()
.ActivateOnEnter<GrenadoShot>()
.Raw.Update = () => module.Enemies(OID.Aerostat2).Concat([module.PrimaryActor]).Concat(module.Enemies(OID.OrigenicsSentryS9))
.Concat(module.Enemies(OID.OrigenicsSentryS92)).Concat(module.Enemies(OID.OrigenicsSentryG10)).All(e => e.IsDeadOrDestroyed);
.Raw.Update = () =>
{
var enemies = module.Enemies(D050OrigenicsAerostat.Trash);
for (var i = 0; i < enemies.Count; ++i)
{
var e = enemies[i];
if (!e.IsDeadOrDestroyed)
return false;
}
return true;
};
}
}

Expand All @@ -40,10 +49,10 @@ public class D050OrigenicsAerostat(WorldState ws, Actor primary) : BossModule(ws
{
private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-116, -80), 14.5f, 6, 30.Degrees()), new Rectangle(new(-88, -80), 20, 5.5f),
new Polygon(new(-60, -80), 14.5f, 6, 30.Degrees()), new Rectangle(new(-144, -80), 20, 5.5f)]);
public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.Aerostat2, (uint)OID.OrigenicsSentryS9, (uint)OID.OrigenicsSentryS92, (uint)OID.OrigenicsSentryG10];

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actor(PrimaryActor);
Arena.Actors(Enemies(OID.Aerostat2).Concat(Enemies(OID.OrigenicsSentryS9)).Concat(Enemies(OID.OrigenicsSentryS92)).Concat(Enemies(OID.OrigenicsSentryG10)));
Arena.Actors(Enemies(Trash));
}
}
107 changes: 78 additions & 29 deletions BossMod/Modules/Dawntrail/Dungeon/D05Origenics/D052Deceiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public enum OID : uint

public enum AID : uint
{
AutoAttack = 870, // Boss->player, no cast, single-target
AutoAttack1 = 870, // Boss->player, no cast, single-target
AutoAttack2 = 873, // OrigenicsSentryG92->player, no cast, single-target
Teleport = 36362, // Boss->location, no cast, single-target

Expand Down Expand Up @@ -111,7 +111,7 @@ class Electray(BossModule module) : Components.SpreadFromCastTargets(module, Act

class Surge(BossModule module) : Components.Knockback(module)
{
private readonly List<Source> _sources = [];
public readonly List<Source> SourcesList = new(2);
private const float XWest = -187.5f, XEast = -156.5f;
private const int ZRow1 = -122, ZRow2 = -132, ZRow3 = -142, ZRow4 = -152, ZRow5 = -162;
private static readonly WDir offset = new(4, 0);
Expand All @@ -124,16 +124,18 @@ class Surge(BossModule module) : Components.Knockback(module)
private static readonly SafeWall[] walls2B1C = [new(new(XWest, ZRow4), new(XWest, ZRow5)), new(new(XWest, ZRow2), new(XWest, ZRow3)),
new(new(XEast, ZRow3), new(XEast, ZRow4)), new(new(XEast, ZRow1), new(XEast, ZRow2))];
private static readonly AOEShapeCone _shape = new(60, 90.Degrees());
private Func<WPos, float>? distance;

public override IEnumerable<Source> Sources(int slot, Actor actor) => _sources;
public override IEnumerable<Source> Sources(int slot, Actor actor) => SourcesList;

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.Surge)
{
var activation = Module.CastFinishAt(spell, 0.8f);
_sources.Add(new(caster.Position, 30, activation, _shape, spell.Rotation + Angle.AnglesCardinals[3], Kind.DirForward, default, GetActiveSafeWalls()));
_sources.Add(new(caster.Position, 30, activation, _shape, spell.Rotation + Angle.AnglesCardinals[0], Kind.DirForward, default, GetActiveSafeWalls()));
var activation = Module.CastFinishAt(spell);
var safewalls = GetActiveSafeWalls();
SourcesList.Add(new(caster.Position, 30, activation, _shape, spell.Rotation + Angle.AnglesCardinals[3], Kind.DirForward, default, safewalls));
SourcesList.Add(new(caster.Position, 30, activation, _shape, spell.Rotation + Angle.AnglesCardinals[0], Kind.DirForward, default, safewalls));
}
}

Expand All @@ -160,50 +162,96 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.Surge)
{
_sources.Clear();
SourcesList.Clear();
distance = null;
++NumCasts;
}
}

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
var source = Sources(slot, actor).FirstOrDefault();
if (source != default)
if (SourcesList.Count != 0)
{
var forbidden = new List<Func<WPos, float>>();
var safewalls = GetActiveSafeWalls();
for (var i = 0; i < safewalls.Length; ++i)
forbidden.Add(ShapeDistance.InvertedRect(new(Arena.Center.X, safewalls[i].Vertex1.Z - 5), safewalls[i].Vertex1.X == XWest ? -offset : offset, 10, default, 20));
hints.AddForbiddenZone(p => forbidden.Max(f => f(p)), source.Activation);
if (distance == null)
{
var safewalls = GetActiveSafeWalls();
var forbidden = new List<Func<WPos, float>>(4);

var centerX = Arena.Center.X;
for (var i = 0; i < 4; ++i)
{
var safeWall = safewalls[i];
forbidden.Add(ShapeDistance.InvertedRect(new(centerX, safeWall.Vertex1.Z - 5), safeWall.Vertex1.X == XWest ? -offset : offset, 10, default, 20));
}
distance = p =>
{
var maxDistance = float.MinValue;
for (var i = 0; i < 4; ++i)
{
var distance = forbidden[i](p);
if (distance > maxDistance)
{
maxDistance = distance;
}
}
return maxDistance;
};
}
hints.AddForbiddenZone(distance, SourcesList[0].Activation);
}
}
}

class SurgeHint(BossModule module) : Components.GenericAOEs(module)
{
private const string Risk2Hint = "Walk into safespot for knockback!";
private const string StayHint = "Wait inside safespot for knockback!";
private const string Hint = "Wait inside safespot for knockback!";
private static readonly AOEShapeRect rect = new(15.5f, 5);
private readonly List<AOEInstance> _hints = new(4);
private readonly Surge _kb = module.FindComponent<Surge>()!;

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

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
var component = Module.FindComponent<Surge>()!.Sources(slot, actor).Any();
var activeSafeWalls = Module.FindComponent<Surge>()!.GetActiveSafeWalls();
if (component)
for (var i = 0; i < activeSafeWalls.Length; ++i)
yield return new(rect, new(Arena.Center.X, activeSafeWalls[i].Vertex1.Z - 5), activeSafeWalls[i].Vertex1.X == -187.5f ? Angle.AnglesCardinals[0] : Angle.AnglesCardinals[3], default, Colors.SafeFromAOE, false);
if ((AID)spell.Action.ID == AID.Surge)
{
var activeSafeWalls = _kb.GetActiveSafeWalls();
var centerX = Arena.Center.X;
for (var i = 0; i < 4; ++i)
{
var safewall = activeSafeWalls[i].Vertex1;
_hints.Add(new(rect, new(centerX, safewall.Z - 5), safewall.X == -187.5f ? Angle.AnglesCardinals[0] : Angle.AnglesCardinals[3], default, Colors.SafeFromAOE, false));
}
}
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.Surge)
_hints.Clear();
}

public override void AddHints(int slot, Actor actor, TextHints hints)
{
base.AddHints(slot, actor, hints);
var activeSafespot = ActiveAOEs(slot, actor).Where(c => c.Shape == rect).ToList();
if (activeSafespot.Count != 0)
AOEInstance[] activeSafespot = [.. ActiveAOEs(slot, actor)];
var len = activeSafespot.Length;
if (len != 0)
{
if (!activeSafespot.Any(c => c.Check(actor.Position)))
hints.Add(Risk2Hint);
var isPositionSafe = false;
for (var i = 0; i < len; ++i)
{
if (activeSafespot[i].Check(actor.Position))
{
isPositionSafe = true;
break;
}
}
if (!isPositionSafe)
{
hints.Add(Hint);
}
else
hints.Add(StayHint, false);
hints.Add(Hint, false);
}
}
}
Expand Down Expand Up @@ -231,6 +279,7 @@ public class D052Deceiver(WorldState ws, Actor primary) : BossModule(ws, primary
protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actor(PrimaryActor);
Arena.Actors(Enemies(OID.OrigenicsSentryG92).Concat(Enemies(OID.OrigenicsSentryG91)));
Arena.Actors(Enemies(OID.OrigenicsSentryG92));
Arena.Actors(Enemies(OID.OrigenicsSentryG91));
}
}
Loading

0 comments on commit 608d884

Please sign in to comment.