Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

most of Thalia supported, including creation of triangle AOEs and triangle arenas #13

Merged
merged 3 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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