Skip to content

Commit

Permalink
Merge pull request #13 from FFXIV-CombatReborn/Thaliea-and-Triangles
Browse files Browse the repository at this point in the history
most of Thalia supported, including creation of triangle AOEs and triangle arenas
  • Loading branch information
LTS-FFXIV authored Mar 29, 2024
2 parents 9d7b989 + b27af88 commit 8971286
Show file tree
Hide file tree
Showing 49 changed files with 2,189 additions and 0 deletions.
57 changes: 57 additions & 0 deletions BossMod/BossModule/AOEShapes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,61 @@ private IEnumerable<WPos> ContourPoints(WPos origin, Angle rotation, float offse
yield return origin + dx1 + dy2;
}
}

public class AOEShapeTriangle : AOEShape
{
public float SideLength;
public Angle DirectionOffset;

public AOEShapeTriangle(float sideLength, Angle directionOffset = new())
{
SideLength = sideLength;
DirectionOffset = directionOffset;
}

public override bool Check(WPos position, WPos origin, Angle rotation)
{
var vertices = CalculateVertices(origin, rotation + DirectionOffset);
return position.InTri(vertices.p1, vertices.p2, vertices.p3);
}

public override void Draw(MiniArena arena, WPos origin, Angle rotation, uint color = ArenaColor.AOE)
{
var vertices = CalculateVertices(origin, rotation + DirectionOffset);
arena.AddTriangleFilled(vertices.p1, vertices.p2, vertices.p3, color);
}

public override void Outline(MiniArena arena, WPos origin, Angle rotation, uint color = ArenaColor.Danger)
{
var vertices = CalculateVertices(origin, rotation + DirectionOffset);
arena.AddTriangle(vertices.p1, vertices.p2, vertices.p3, color);
}

public override IEnumerable<IEnumerable<WPos>> Contour(WPos origin, Angle rotation, float offset = 0, float maxError = 1)
{
var vertices = CalculateVertices(origin, rotation + DirectionOffset, offset);
return new List<IEnumerable<WPos>> { new[] { vertices.p1, vertices.p2, vertices.p3 } };
}

public override Func<WPos, float> Distance(WPos origin, Angle rotation)
{
// Implementing an exact distance calculation for a triangle shape might be complex and is beyond the scope of this basic implementation.
return p => (p - origin).Length(); // Simplified placeholder
}

private (WPos p1, WPos p2, WPos p3) CalculateVertices(WPos origin, Angle rotation, float offset = 0)
{
// Calculate vertex positions for an equilateral triangle with origin as one vertex
var sideOffset = (SideLength + offset) / 2;
var height = MathF.Sqrt(3) / 2 * (SideLength + offset);
var direction = rotation.ToDirection();
var ortho = direction.OrthoR();

var p1 = origin; // The origin is one of the vertices
var p2 = origin + direction * height - ortho * sideOffset;
var p3 = origin + direction * height + ortho * sideOffset;

return (p1, p2, p3);
}
}
}
65 changes: 65 additions & 0 deletions BossMod/BossModule/ArenaBounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,69 @@ public override WDir ClampToBounds(WDir offset, float scale)
return offset;
}
}

public class ArenaBoundsTri : ArenaBounds
{
private const float sqrt3 = 1.73205080757f; // Square root of 3

public ArenaBoundsTri(WPos center, float sideLength)
: base(center, sideLength * sqrt3 / 3) { } // HalfSize is the radius of the circumscribed circle

public override IEnumerable<WPos> BuildClipPoly(float offset = 0)
{
// Calculate the vertices of the equilateral triangle
var height = HalfSize * sqrt3; // Height of the equilateral triangle
var halfSide = HalfSize;
yield return Center + new WDir(-halfSide, height / 3);
yield return Center + new WDir(halfSide, height / 3);
yield return Center + new WDir(0, -2 * height / 3);
}

public override Pathfinding.Map BuildMap(float resolution = 0.5f)
{
// BuildMap implementation for equilateral triangle
// This is a simplified example and would need to be adapted based on specific pathfinding requirements
throw new NotImplementedException();
}

public override bool Contains(WPos p)
{
var a = Center + new WDir(-HalfSize, HalfSize * sqrt3 / 3);
var b = Center + new WDir(HalfSize, HalfSize * sqrt3 / 3);
var c = Center + new WDir(0, -2 * HalfSize * sqrt3 / 3);

bool b1 = Sign(p, a, b) < 0.0f;
bool b2 = Sign(p, b, c) < 0.0f;
bool b3 = Sign(p, c, a) < 0.0f;

return ((b1 == b2) && (b2 == b3));
}

private float Sign(WPos p1, WPos p2, WPos p3)
{
return (p1.X - p3.X) * (p2.Z - p3.Z) - (p2.X - p3.X) * (p1.Z - p3.Z);
}


public override float IntersectRay(WPos origin, WDir dir)
{
// Define triangle vertices
var a = Center + new WDir(-HalfSize, HalfSize * sqrt3 / 3);
var b = Center + new WDir(HalfSize, HalfSize * sqrt3 / 3);
var c = Center + new WDir(0, -2 * HalfSize * sqrt3 / 3);

// Ray-triangle intersection algorithm goes here
// This is a complex topic and requires a bit of math
// Placeholder for the actual intersection calculation
return float.NaN; // Return NaN to indicate that this method needs proper implementation
}


public override WDir ClampToBounds(WDir offset, float scale = 1)
{
// Clamping within a triangle is highly context-dependent
// This method needs a detailed implementation based on specific requirements
return new WDir(0, 0); // Placeholder to indicate that clamping logic is needed
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace BossMod.Endwalker.Alliance.A30OpeningMobs
{
class WaterIII : Components.SelfTargetedAOEs
{
public WaterIII() : base(ActionID.MakeSpell(AID.WaterIII), new AOEShapeCircle(8)) { }
}

class PelagicCleaver1 : Components.SelfTargetedAOEs
{
public PelagicCleaver1() : base(ActionID.MakeSpell(AID.PelagicCleaver1), new AOEShapeCone(40, 30.Degrees())) { }
}

class PelagicCleaver2 : Components.SelfTargetedAOEs
{
public PelagicCleaver2() : base(ActionID.MakeSpell(AID.PelagicCleaver2), new AOEShapeCone(40, 30.Degrees())) { }
}

class WaterFlood : Components.SelfTargetedAOEs
{
public WaterFlood() : base(ActionID.MakeSpell(AID.WaterFlood), new AOEShapeCircle(6)) { }
}

class WaterBurst : Components.SelfTargetedAOEs
{
public WaterBurst() : base(ActionID.MakeSpell(AID.WaterBurst), new AOEShapeCircle(40)) { }
}

class DivineFlood : Components.SelfTargetedAOEs
{
public DivineFlood() : base(ActionID.MakeSpell(AID.DivineFlood), new AOEShapeCircle(6)) { }
}

class DivineBurst : Components.SelfTargetedAOEs
{
public DivineBurst() : base(ActionID.MakeSpell(AID.DivineBurst), new AOEShapeCircle(40)) { }
}

//[ModuleInfo(CFCID = 962, PrimaryActorOID = 0x4010)]
public class A30OpeningMobs : BossModule
{
public A30OpeningMobs(WorldState ws, Actor primary) : base(ws, primary, new ArenaBoundsCircle(new(-800, -800), 20)) { }

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actor(PrimaryActor, ArenaColor.Enemy, true);
foreach (var e in Enemies(OID.Triton))
Arena.Actor(e, ArenaColor.Enemy);
foreach (var e in Enemies(OID.DivineSprite))
Arena.Actor(e, ArenaColor.Enemy);
foreach (var e in Enemies(OID.WaterSprite))
Arena.Actor(e, ArenaColor.Enemy);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace BossMod.Endwalker.Alliance.A30OpeningMobs
{
public enum OID : uint
{
Serpent = 0x4010, // R3.450, x6
Triton = 0x4011, // R1.950, x2
DivineSprite = 0x4012, // R1.600, x3
WaterSprite = 0x4085, // R0.800, x5
UnknownEnemy = 0x400E, // R0.500, x1
UnknownActor1 = 0x1E8FB8, // R2.000, x2, EventObj type
UnknownActor2 = 0x1E8F2F, // R0.500, x1, EventObj type
};

public enum AID : uint
{
AutoAttack = 870, // Serpent/Triton->player, no cast, single-target
WaterIII = 35438, // Serpent->location, 4.0s cast, range 8 circle
PelagicCleaver1 = 35439, // Triton->self, 5.0s cast, range 40 60-degree cone
PelagicCleaver2 = 35852, // Triton->self, 5.0s cast, range 40 60-degree cone
Water = 35469, // Water Sprite/Divine Sprite->player, no cast, single-target
WaterFlood = 35442, // Water Sprite->self, 3.0s cast, range 6 circle
WaterBurst = 35443, // Water Sprite->self, no cast, range 40 circle
DivineFlood = 35440, // Divine Sprite->self, 3.0s cast, range 6 circle
DivineBurst = 35441, // Divine Sprite->self, no cast, range 40 circle
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace BossMod.Endwalker.Alliance.A30OpeningMobs
{
public class A30OpeningMobsStates : StateMachineBuilder
{
public A30OpeningMobsStates(BossModule module) : base(module)
{
TrivialPhase()
.ActivateOnEnter<WaterIII>()
.ActivateOnEnter<PelagicCleaver1>()
.ActivateOnEnter<PelagicCleaver2>()
.ActivateOnEnter<WaterFlood>()
.ActivateOnEnter<DivineFlood>();
}
}
}
16 changes: 16 additions & 0 deletions BossMod/Modules/Endwalker/Alliance/A31Thaliak/A31Thaliak.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace BossMod.Endwalker.Alliance.A31Thaliak
{
[ModuleInfo(CFCID = 962, PrimaryActorOID = 0x404C)]
public class A31Thaliak : BossModule
{
public static ArenaBoundsSquare BoundsSquare = new ArenaBoundsSquare(new(-945.006f, 944.976f), 24f);
public static ArenaBoundsTri BoundsTri = new ArenaBoundsTri(new(-945.006f, 948.500f), 41f);
public A31Thaliak(WorldState ws, Actor primary) : base(ws, primary, BoundsSquare) { }
protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actor(PrimaryActor, ArenaColor.Enemy, true);
foreach (var s in Enemies(OID.ThaliakHelper))
Arena.Actor(s, ArenaColor.Object, true);
}
}
}
91 changes: 91 additions & 0 deletions BossMod/Modules/Endwalker/Alliance/A31Thaliak/A31ThaliakEnums.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BossMod.Components;

namespace BossMod.Endwalker.Alliance.A31Thaliak

{

public enum OID : uint
{
Thaliak = 0x404C, // R9.496, x1
ThaliakClone = 0x404D, // R9.496, x1
ThaliakHelper = 0x233C, // R0.500, x44, 523 type
WindWreathedPortal = 0x1EB91D, // R0.500, x1, EventObj type
HieroglyphikaIndicator = 0x40AA, // R0.500, x1 // Rotation Indicator
UnknownActor = 0x400E, // R0.500, x1
};


public enum AID : uint
{
AutoAttack = 35036, // Thaliak->player, no cast, single-target
Ability1_1 = 35035, // Thaliak->location, no cast, single-target

Katarraktes = 35025, // Thaliak->self, 5.0s cast, single-target // Raidwide damage and bleeding damage-over-time.
KatarraktesHelper = 35034, // ThaliakHelper->self, 5.7s cast, range 70 circle

Hieroglyphika = 35023, // Thaliak->self, 5.0s cast, single-target // Covers all but two tiles of the arena with a green AoE telegraph
HieroglyphikaHelper = 35024, // ThaliakHelper->self, 3.0s cast, range 12 width 12 rect // 2 safe spots

Thlipsis = 35032, // Thaliak->self, 4.0s cast, single-target // Stack marker on random player
ThlipsisHelper = 35033, // ThaliakHelper->players, 6.0s cast, range 6 circle

Hydroptosis = 35028, // Thaliak->self, 4.0s cast, single-target // Spread markers on random players. Inflicts Water resistance down making overlap lethal.
HydroptosisHelper = 35029, // ThaliakHelper->player, 5.0s cast, range 6 circle

Rhyton = 35030, // Thaliak->self, 5.0s cast, single-target // Line AoE tankbusters targeting all 3 tanks, or whoever is top enmity if not all tanks are alive.
RhytonHelper = 35031, // ThaliakHelper->players, no cast, range 70 width 6 rect

Rheognosis = 35012, // Thaliak->self, 5.0s cast, single-target // Castbar Indicator
RheognosisPetrine = 35013, // Thaliak->self, 5.0s cast, single-target // Castbar Indicator
RheognosisPetrineHelper = 35014, // ThaliakClone->self, no cast, single-target
RheognosisKnockback = 35015, // ThaliakHelper->self, 3.0s cast, range 48 width 48 rect // Summons the same knockback clone as in Rheognosis, but two spheres of water
RheognosisCrashExaflare = 35016, // ThaliakHelper->self, no cast, range 10 width 24 rect // 5 helpers

Tetraktys = 35017, // Thaliak->self, 6.0s cast, single-target // Transforms the arena into a triangle, with a dangerous AoE surrounding it.
TetraBlueTriangles = 35018, // ThaliakHelper->self, 1.8s cast, ??? // Blue triangles?
TetraGreenTriangles = 35019, // ThaliakHelper->self, 1.8s cast, ??? // Green triangles?

TetraktuosKosmos = 35020, // Thaliak->self, 4.0s cast, single-target // Summons a triangular tower on a panel
TetraktuosKosmosHelper = 35022, // ThaliakHelper->self, 2.9s cast, ??? // telegraphed line AoEs
TetraktuosKosmosHelper2 = 35021, // ThaliakHelper->self, 2.9s cast, range 30 width 16 rect // This attack repeats, but now two towers will spawn

LeftBank = 35026, // Thaliak->self, 5.0s cast, range 60 180-degree cone // A half-room cleave
LeftBank2 = 35884, // Thaliak->self, 22.0s cast, range 60 180-degree cone // A half-room cleave
RightBank = 35027, // Thaliak->self, 5.0s cast, range 60 180-degree cone // A half-room cleave
RightBank2 = 35885, // Thaliak->self, 22.0s cast, range 60 180-degree cone // A half-room cleave
};

public enum SID : uint
{
Weakness = 43, // none->player, extra=0x0
Bleeding = 2088, // ThaliakHelper->player, extra=0x0
VulnerabilityUp = 1789, // Thaliak/ThaliakHelper->player, extra=0x1
WaterResistanceDownII = 1025, // ThaliakHelper->player, extra=0x0
Transcendent = 418, // none->player, extra=0x0
SustainedDamage = 2935, // ThaliakHelper->player, extra=0x0
DownForTheCount = 783, // ThaliakHelper->player, extra=0xEC7
Inscribed = 3732, // none->player, extra=0x0
Bind = 2518, // none->player, extra=0x0
BrinkOfDeath = 44, // none->player, extra=0x0

};


public enum IconID : uint
{
Icon_318 = 318, // player
HydroptosisSpread = 139, // player
RhytonBuster = 471, // player
ClockwiseHieroglyphika = 487, // HieroglyphikaIndicator
CounterClockwiseHieroglyphika = 490, // HieroglyphikaIndicator
};

public enum TetherID : uint
{
};


}
31 changes: 31 additions & 0 deletions BossMod/Modules/Endwalker/Alliance/A31Thaliak/A31ThaliakStates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BossMod.Components;

namespace BossMod.Endwalker.Alliance.A31Thaliak
{
class A31ThaliakStates : StateMachineBuilder
{
public A31ThaliakStates(BossModule module) : base(module)
{
SimplePhase(0, id => { SimpleState(id, 10000, "Enrage"); }, "Single phase")
.ActivateOnEnter<Hieroglyphika>()
.ActivateOnEnter<Tetraktys>()
.ActivateOnEnter<Thlipsis>()
.ActivateOnEnter<Hydroptosis>()
.ActivateOnEnter<Rhyton>()
.ActivateOnEnter<LeftBank>()
.ActivateOnEnter<LeftBank2>()
.ActivateOnEnter<RightBank>()
.ActivateOnEnter<RightBank2>()
.ActivateOnEnter<RheognosisKnockback>()
//.ActivateOnEnter<RheognosisCrashExaflare>()
.ActivateOnEnter<TetraBlueTriangles>()
.ActivateOnEnter<TetraGreenTriangles>()
.ActivateOnEnter<TetraktuosKosmosHelper>()
.ActivateOnEnter<TetraktuosKosmosHelper2>()
.Raw.Update = () => Module.PrimaryActor.IsDestroyed;
}
}
}
Loading

0 comments on commit 8971286

Please sign in to comment.