Skip to content

Commit

Permalink
Merge pull request #136 from FFXIV-CombatReborn/mergeWIP2
Browse files Browse the repository at this point in the history
random improvements and additions
  • Loading branch information
CarnifexOptimus authored Jun 20, 2024
2 parents 55c0374 + d088c3c commit 93b26ab
Show file tree
Hide file tree
Showing 26 changed files with 384 additions and 291 deletions.
194 changes: 14 additions & 180 deletions BossMod/BossModule/Shapes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ public abstract record class Shape
public const float MaxApproxError = 0.01f;

public abstract List<WDir> Contour(WPos center);
public abstract RelSimplifiedComplexPolygon ToPolygon(WPos center);
public abstract string ComputeHash();

public RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new(Contour(center))]));

protected List<WDir> GetOrCreateContour(WPos center, Func<List<WDir>> createContour)
{
var key = (ComputeHash(), center);
Expand Down Expand Up @@ -46,8 +48,6 @@ public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
CurveApprox.Circle(Radius, MaxApproxError).Select(p => p + (Center - center)).ToList());

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));
public override Func<WPos, float> Distance()
=> ShapeDistance.Circle(Center, Radius);
public override string ComputeHash() => ComputeSHA512($"{nameof(Circle)}:{Center.X},{Center.Z},{Radius}");
Expand All @@ -61,9 +61,6 @@ public record class PolygonCustom(IEnumerable<WPos> Vertices) : Shape
public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () => Vertices.Select(v => v - center).ToList());

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

private bool IsConvex()
{
var hash = ComputeHash() + "IsConvex";
Expand Down Expand Up @@ -109,11 +106,7 @@ private bool IsCounterClockwise()
return isCounterClockwise;
}

public override Func<WPos, float> Distance()
{
return IsConvex() ? IsCounterClockwise() ? ShapeDistance.ConvexPolygon(Vertices, false) : ShapeDistance.ConvexPolygon(Vertices, true)
: ShapeDistance.ConcavePolygon(Vertices);
}
public override Func<WPos, float> Distance() => IsConvex() ? ShapeDistance.ConvexPolygon(Vertices, !IsCounterClockwise()) : ShapeDistance.ConcavePolygon(Vertices);

public override string ComputeHash()
{
Expand All @@ -128,9 +121,6 @@ public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
CurveApprox.Donut(InnerRadius, OuterRadius, MaxApproxError).Select(p => p + (Center - center)).ToList());

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
=> ShapeDistance.Donut(Center, InnerRadius, OuterRadius);

Expand All @@ -154,9 +144,6 @@ public override List<WDir> Contour(WPos center)
];
});

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
=> ShapeDistance.Rect(Center, Rotation, HalfHeight, HalfHeight, HalfWidth);

Expand Down Expand Up @@ -201,174 +188,31 @@ public override List<WDir> Contour(WPos center)
];
});

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
=> ShapeDistance.Cross(Center, Rotation, Length, HalfWidth);

public override string ComputeHash() => ComputeSHA512($"{nameof(Cross)}:{Center.X},{Center.Z},{Length},{HalfWidth},{Rotation.Rad}");
}

// Equilateral triangle defined by center, radius and rotation
public record class TriangleE(WPos Center, float Radius, Angle Rotation = default) : Shape
{
public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
{
var sqrt3 = MathF.Sqrt(3);
var halfSide = Radius;
var height = halfSide * sqrt3;
var centerTriangle = Center + new WDir(0, height / 3);
var vertices = new List<WDir>
{
centerTriangle + new WDir(-halfSide, height / 3) - center,
centerTriangle + new WDir(halfSide, height / 3) - center,
centerTriangle + new WDir(0, -2 * height / 3) - center
};

var cos = MathF.Cos(Rotation.Rad);
var sin = MathF.Sin(Rotation.Rad);
return vertices.Select(v => new WDir(v.X * cos - v.Z * sin, v.X * sin + v.Z * cos)).ToList();
});

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
{
var sqrt3 = MathF.Sqrt(3);
var halfSide = Radius;
var height = halfSide * sqrt3;
var a = new WDir(-halfSide, height / 3);
var b = new WDir(halfSide, height / 3);
var c = new WDir(0, -2 * height / 3);

var cos = MathF.Cos(Rotation.Rad);
var sin = MathF.Sin(Rotation.Rad);

var rotatedA = new WDir(a.X * cos - a.Z * sin, a.X * sin + a.Z * cos);
var rotatedB = new WDir(b.X * cos - b.Z * sin, b.X * sin + b.Z * cos);
var rotatedC = new WDir(c.X * cos - c.Z * sin, c.X * sin + c.Z * cos);

var relTriangle = new RelTriangle(rotatedA, rotatedB, rotatedC);

return ShapeDistance.Tri(Center, relTriangle);
}

public override string ComputeHash() => ComputeSHA512($"{nameof(TriangleE)}:{Center.X},{Center.Z},{Radius},{Rotation.Rad}");
}

// custom Triangle defined by three sides and rotation, mind the triangle inequality, side1 + side2 >= side3
public record class TriangleS(WPos Center, float SideA, float SideB, float SideC, Angle Rotation = default) : Shape
{
public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
{
var sides = new[] { SideA, SideB, SideC }.OrderByDescending(s => s).ToArray();
var a = sides[0];
var b = sides[1];
var c = sides[2];
var vertex1 = new WPos(0, 0);
var vertex2 = new WPos(a, 0);
var cosC = (b * b + a * a - c * c) / (2 * a * b);
var sinC = MathF.Sqrt(1 - cosC * cosC);
var vertex3 = new WPos(b * cosC, b * sinC);
var centroid = new WPos((vertex1.X + vertex2.X + vertex3.X) / 3, (vertex1.Z + vertex2.Z + vertex3.Z) / 3);

var vertices = new List<WDir>
{
new(vertex3.X - centroid.X, vertex3.Z - centroid.Z),
new(vertex2.X - centroid.X, vertex2.Z - centroid.Z),
new(vertex1.X - centroid.X, vertex1.Z - centroid.Z)
};

var cos = MathF.Cos(Rotation.Rad);
var sin = MathF.Sin(Rotation.Rad);
return vertices.Select(v => new WDir(v.X * cos - v.Z * sin, v.X * sin + v.Z * cos)).ToList();
});

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
{
var sides = new[] { SideA, SideB, SideC }.OrderByDescending(s => s).ToArray();
var a = sides[0];
var b = sides[1];
var c = sides[2];
var vertex1 = new WDir(0, 0);
var vertex2 = new WDir(a, 0);
var cosC = (b * b + a * a - c * c) / (2 * a * b);
var sinC = MathF.Sqrt(1 - cosC * cosC);
var vertex3 = new WDir(b * cosC, b * sinC);

var cos = MathF.Cos(Rotation.Rad);
var sin = MathF.Sin(Rotation.Rad);

var rotatedVertex1 = new WDir(vertex1.X * cos - vertex1.Z * sin, vertex1.X * sin + vertex1.Z * cos);
var rotatedVertex2 = new WDir(vertex2.X * cos - vertex2.Z * sin, vertex2.X * sin + vertex2.Z * cos);
var rotatedVertex3 = new WDir(vertex3.X * cos - vertex3.Z * sin, vertex3.X * sin + vertex3.Z * cos);

var relTriangle = new RelTriangle(rotatedVertex1, rotatedVertex2, rotatedVertex3);

return ShapeDistance.Tri(Center, relTriangle);
}

public override string ComputeHash() => ComputeSHA512($"{nameof(TriangleS)}:{Center.X},{Center.Z},{SideA},{SideB},{SideC},{Rotation.Rad}");
}
// Equilateral triangle defined by center, sidelength and rotation
public record class TriangleE(WPos Center, float SideLength, Angle Rotation = default) : Shape

// Triangle definded by base length and angle at the apex, apex points north by default
public record class TriangleA(WPos Center, float BaseLength, Angle ApexAngle, Angle Rotation = default) : Shape
{
private static readonly float heightFactor = MathF.Sqrt(3) / 2;
public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
{
var apexAngleRad = ApexAngle.Rad;
var height = BaseLength / 2 / MathF.Tan(apexAngleRad / 2);
var halfBase = BaseLength / 2;
var vertex1 = new WPos(-halfBase, 0);
var vertex2 = new WPos(halfBase, 0);
var vertex3 = new WPos(0, -height);
var centroid = new WPos((vertex1.X + vertex2.X + vertex3.X) / 3, (vertex1.Z + vertex2.Z + vertex3.Z) / 3);

var height = SideLength * heightFactor;
var vertices = new List<WDir> { new(SideLength / 2, height / 2), new(-SideLength / 2, height / 2), new(0, -height / 2) };
var cos = MathF.Cos(Rotation.Rad);
var sin = MathF.Sin(Rotation.Rad);
var vertices = new List<WDir>
{
new(vertex1.X - centroid.X, vertex1.Z - centroid.Z),
new(vertex2.X - centroid.X, vertex2.Z - centroid.Z),
new(vertex3.X - centroid.X, vertex3.Z - centroid.Z)
};

return vertices.Select(v => new WDir(v.X * cos - v.Z * sin, v.X * sin + v.Z * cos)).ToList();
vertices = vertices.Select(v => new WDir(v.X * cos - v.Z * sin, v.X * sin + v.Z * cos)).ToList();
return vertices.Select(v => v + (Center - center)).ToList();
});

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
{
var apexAngleRad = ApexAngle.Rad;
var height = BaseLength / 2 / MathF.Tan(apexAngleRad / 2);
var halfBase = BaseLength / 2;
var vertex1 = new WDir(-halfBase, 0);
var vertex2 = new WDir(halfBase, 0);
var vertex3 = new WDir(0, -height);

var cos = MathF.Cos(Rotation.Rad);
var sin = MathF.Sin(Rotation.Rad);

var rotatedVertex1 = new WDir(vertex1.X * cos - vertex1.Z * sin, vertex1.X * sin + vertex1.Z * cos);
var rotatedVertex2 = new WDir(vertex2.X * cos - vertex2.Z * sin, vertex2.X * sin + vertex2.Z * cos);
var rotatedVertex3 = new WDir(vertex3.X * cos - vertex3.Z * sin, vertex3.X * sin + vertex3.Z * cos);
public override Func<WPos, float> Distance() => ShapeDistance.ConvexPolygon(Contour(Center).Select(dir => dir + Center), cw: true);

var relTriangle = new RelTriangle(rotatedVertex1, rotatedVertex2, rotatedVertex3);

return ShapeDistance.Tri(Center, relTriangle);
}

public override string ComputeHash() => ComputeSHA512($"{nameof(TriangleA)}:{Center.X},{Center.Z},{BaseLength},{ApexAngle.Rad},{Rotation.Rad}");
public override string ComputeHash() => ComputeSHA512($"{nameof(TriangleE)}:{Center.X},{Center.Z},{SideLength},{Rotation.Rad}");
}

// for polygons defined by a radius and n amount of vertices
Expand All @@ -390,11 +234,7 @@ public override List<WDir> Contour(WPos center)
return vertices;
});

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
=> ShapeDistance.ConvexPolygon(Contour(Center).Select(dir => dir + Center), cw: true);
public override Func<WPos, float> Distance() => ShapeDistance.ConvexPolygon(Contour(Center).Select(dir => dir + Center), cw: true);

public override string ComputeHash() => ComputeSHA512($"{nameof(Polygon)}:{Center.X},{Center.Z},{Radius},{Vertices},{Rotation.Rad}");
}
Expand All @@ -406,9 +246,6 @@ public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
CurveApprox.CircleSector(Center, Radius, StartAngle, EndAngle, MaxApproxError).Select(p => p - center).ToList());

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
=> ShapeDistance.Cone(Center, Radius, (StartAngle + EndAngle) / 2, (EndAngle - StartAngle) / 2);

Expand All @@ -425,9 +262,6 @@ public override List<WDir> Contour(WPos center)
=> GetOrCreateContour(center, () =>
CurveApprox.DonutSector(InnerRadius, OuterRadius, StartAngle, EndAngle, MaxApproxError).Select(p => p + (Center - center)).ToList());

public override RelSimplifiedComplexPolygon ToPolygon(WPos center)
=> GetOrCreatePolygon(center, () => new RelSimplifiedComplexPolygon([new RelPolygonWithHoles(Contour(center))]));

public override Func<WPos, float> Distance()
=> ShapeDistance.DonutSector(Center, InnerRadius, OuterRadius, (StartAngle + EndAngle) / 2, (EndAngle - StartAngle) / 2);

Expand Down
7 changes: 2 additions & 5 deletions BossMod/Components/StackSpread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,10 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
if (isBaitNotTarget && !isBaitTarget && !forbiddenActors)
foreach (var b in ActiveBaits.Where(x => x.Target != actor))
forbiddenInverted.Add(ShapeDistance.InvertedRect(b.Source.Position, (b.Target.Position - b.Source.Position).Normalized(), Range, 0, HalfWidth));
// prevent overlapping if there are multiple line stacks
if (isBaitNotTarget && isBaitTarget)
// prevent overlapping if there are multiple line stacks, or if an actor is forbidden to enter
if (isBaitNotTarget && isBaitTarget || forbiddenActors)
foreach (var b in ActiveBaits.Where(x => x.Target != actor))
forbidden.Add(ShapeDistance.Rect(b.Source.Position, (b.Target.Position - b.Source.Position).Normalized(), Range, 0, 2 * HalfWidth));
if (forbiddenActors) // if too many people are dead, you can become a forbidden actor and get stack at the same time
foreach (var b in ActiveBaits.Where(x => x.Target != actor))
forbidden.Add(ShapeDistance.Rect(b.Source.Position, (b.Target.Position - b.Source.Position).Normalized(), Range, 0, HalfWidth));
if (forbiddenInverted.Count > 0)
hints.AddForbiddenZone(p => forbiddenInverted.Select(f => f(p)).Max(), ActiveBaits.FirstOrDefault().Activation);
if (forbidden.Count > 0)
Expand Down
8 changes: 5 additions & 3 deletions BossMod/Modules/Endwalker/Alliance/A13Azeyma/WildfireWard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
class WildfireWard(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.IlluminatingGlimpse), 15, false, 1, kind: Kind.DirLeft);
class ArenaBounds(BossModule module) : Components.GenericAOEs(module)
{
private static readonly Shape triangle = new PolygonCustom([new(-761.5f, -743.38f), new(-750, -763.27f), new(-738.51f, -743.39f)]);
private static readonly Shape circle = new Circle(A13Azeyma.NormalCenter, 29.5f);

private static readonly Circle circle = new(A13Azeyma.NormalCenter, 29.5f);
private static readonly WPos triangleCenter = new(-750, -753.325f);
private static readonly TriangleE triangle = new(triangleCenter, 24);
private static readonly AOEShapeCustom triangleCutOut = new([circle], [triangle]);
private static readonly ArenaBoundsComplex TriangleBounds = new([triangle]);

Expand All @@ -22,7 +24,7 @@ public override void OnEventEnvControl(byte index, uint state)
{
_aoe = null;
Arena.Bounds = TriangleBounds;
Arena.Center = TriangleBounds.Center;
Arena.Center = triangleCenter;
}
else if (state == 0x00080004)
Arena.Bounds = A13Azeyma.NormalBounds;
Expand Down
14 changes: 12 additions & 2 deletions BossMod/Modules/Endwalker/Alliance/A21Nophica/A21Nophica.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
namespace BossMod.Endwalker.Alliance.A21Nophica;

class ArenaBounds(BossModule module) : BossComponent(module)
class ArenaBounds(BossModule module) : Components.GenericAOEs(module)
{
private static readonly AOEShapeDonut donut = new(28, 34);
private AOEInstance? _aoe;

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

public override void OnEventEnvControl(byte index, uint state)
{
if (index == 0x39)
{
if (state == 0x02000200)
_aoe = new(donut, Module.Center, default, WorldState.FutureTime(5.8f));
if (state is 0x00200010 or 0x00020001)
{
Arena.Bounds = A21Nophica.SmallerBounds;
if (state == 0x00400004)
_aoe = null;
}
if (state is 0x00080004 or 0x00400004)
Arena.Bounds = A21Nophica.DefaultBounds;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ private void SinglePhase(uint id)
HeavensEarth(id + 0x90000, 3.1f);
Abundance(id + 0xA0000, 6.3f);
Abundance(id + 0xB0000, 4.2f);
MatronsPlentyFloralHazeReapersGaleLandwaker(id + 0xC0000, 11.2f); // TODO: verify. even on a MINE run i only saw the start of this
SimpleState(id + 0xFF0000, 100, "???");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ private void HydrostasisPetrai(uint id, float delay)
.ActivateOnEnter<Hydrostasis>()
.DeactivateOnExit<Petrai>()
.SetHint(StateMachine.StateHint.Tankbuster);
ComponentCondition<Hydrostasis>(id + 0x20, 15, comp => comp.NumCasts >= 1, "Knockback 1");
ComponentCondition<Hydrostasis>(id + 0x20, 15, comp => comp.NumCasts >= 1, "Knockback 1")
.SetHint(StateMachine.StateHint.Knockback);
ComponentCondition<Hydrostasis>(id + 0x21, 3, comp => comp.NumCasts >= 2, "Knockback 2");
ComponentCondition<Hydrostasis>(id + 0x22, 3, comp => comp.NumCasts >= 3, "Knockback 3")
.DeactivateOnExit<Hydrostasis>();
Expand All @@ -219,7 +220,8 @@ private void HydrostasisTimeAndTide(uint id, float delay)
ComponentCondition<Hydrostasis>(id + 0x10, 2.0f, comp => comp.Active)
.ActivateOnEnter<Hydrostasis>();
ActorCast(id + 0x20, _module.Althyk, AID.TimeAndTide, 0.1f, 10); // TODO: boss often dies here...
ComponentCondition<Hydrostasis>(id + 0x30, 2, comp => comp.NumCasts >= 1, "Knockback 1");
ComponentCondition<Hydrostasis>(id + 0x30, 2, comp => comp.NumCasts >= 1, "Knockback 1")
.SetHint(StateMachine.StateHint.Knockback);
ComponentCondition<Hydrostasis>(id + 0x31, 3, comp => comp.NumCasts >= 2, "Knockback 2");
ComponentCondition<Hydrostasis>(id + 0x32, 3, comp => comp.NumCasts >= 3, "Knockback 3")
.DeactivateOnExit<Hydrostasis>();
Expand Down
Loading

0 comments on commit 93b26ab

Please sign in to comment.