Skip to content

Commit

Permalink
chaotic stuff and merge fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Dec 27, 2024
1 parent 351f09c commit 1a7ba89
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 110 deletions.
1 change: 1 addition & 0 deletions BossMod/BossModule/BossModuleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public enum Category
Ultimate,
Unreal,
Alliance,
Chaotic,
Foray,
VariantCriterion,
DeepDungeon,
Expand Down
1 change: 1 addition & 0 deletions BossMod/Config/ModuleViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public ModuleViewer(PlanDatabase? planDB, WorldState ws)
Customize(BossModuleInfo.Category.DeepDungeon, contentType.GetRow(21));
Customize(BossModuleInfo.Category.Ultimate, contentType.GetRow(28));
Customize(BossModuleInfo.Category.VariantCriterion, contentType.GetRow(30));
Customize(BossModuleInfo.Category.Chaotic, contentType.GetRow(37));

var playStyle = Service.LuminaSheet<CharaCardPlayStyle>()!;
Customize(BossModuleInfo.Category.Foray, playStyle.GetRow(6));
Expand Down
9 changes: 2 additions & 7 deletions BossMod/Modules/Dawntrail/Alliance/A11Prishe/ArenaChanges.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,12 @@ public override void OnEventEnvControl(byte index, uint state)
SetArena(ArenaENVC02000100);
break;
case 0x00080004 or 0x00800004:
SetDefaultArena();
Arena.Bounds = A11Prishe.DefaultBounds;
Arena.Center = A11Prishe.ArenaCenter;
break;
}
}

private void SetDefaultArena()
{
Arena.Bounds = A11Prishe.DefaultBounds;
Arena.Center = A11Prishe.ArenaCenter;
}

private void SetArena(ArenaBoundsComplex bounds)
{
Arena.Bounds = bounds;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace BossMod.Dawntrail.Chaotic.Ch01CloudOfDarkness;

class ArenaChanges(BossModule module) : Components.GenericAOEs(module)
{
private AOEInstance? _aoe;
private static readonly Square[] DefaultPolygon = [new(Ch01CloudOfDarkness.DefaultCenter, 40)];
private static readonly AOEShapeCustom P1Transition = new(DefaultPolygon, Ch01CloudOfDarkness.Diamond);
private static readonly AOEShapeCustom P2Transition = new(DefaultPolygon, Ch01CloudOfDarkness.Phase2ShapesWD);
private static readonly AOEShapeDonut donut = new(34, 40);

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

public override void OnEventEnvControl(byte index, uint state)
{
if (index == 0x00)
switch (state)
{
case 0x00200010:
SetAOE(P1Transition);
break;
case 0x00020001:
SetAOE(P2Transition);
break;
}
else if (index == 0x02)
switch (state)
{
case 0x00020001:
SetArena(Ch01CloudOfDarkness.Phase2BoundsND);
break;
case 0x00080004:
SetArena(Ch01CloudOfDarkness.Phase2BoundsWD);
break;
}
}

public override void OnEventDirectorUpdate(uint updateID, uint param1, uint param2, uint param3, uint param4)
{
if (updateID != 0x8000000D)
return;
switch (param1)
{
case 0x10000000: // default arena
Arena.Bounds = Ch01CloudOfDarkness.DefaultArena;
Arena.Center = Ch01CloudOfDarkness.DefaultCenter;
break;
case 0x20000000: // (phase 2)
SetArena(Ch01CloudOfDarkness.Phase2BoundsWD);
break;
case 0x40000000: // diamond arena (phase 1)
SetArena(Ch01CloudOfDarkness.Phase1Bounds);
break;
}
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.DarkDominion)
SetAOE(donut);
}

private void SetArena(ArenaBoundsComplex bounds)
{
Arena.Bounds = bounds;
Arena.Center = bounds.Center;
_aoe = null;
}

private void SetAOE(AOEShape shape)
{
_aoe = new(shape, Arena.Center, default, WorldState.FutureTime(9));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class Ch01CloudOfDarknessStates : StateMachineBuilder
{
public Ch01CloudOfDarknessStates(BossModule module) : base(module)
{
DeathPhase(0, SinglePhase);
DeathPhase(0, SinglePhase)
.ActivateOnEnter<ArenaChanges>();
}

private void SinglePhase(uint id)
Expand Down Expand Up @@ -58,65 +59,25 @@ private void SinglePhase(uint id)
}
}

// TODO: mechanic phase bounds
// TODO: flood bounds & squares
// TODO: particle concentration towers
// TODO: evil seed
// TODO: chaser beam
// TODO: tankswap hints?
[ModuleInfo(BossModuleInfo.Maturity.WIP, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1010, NameID = 13624)]
public class Ch01CloudOfDarkness(WorldState ws, Actor primary) : BossModule(ws, primary, DefaultCenter, InitialBounds)
[ModuleInfo(BossModuleInfo.Maturity.WIP, Contributors = "The Combat Reborn Team (Malediktus, LTS)", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1010, NameID = 13624)]
public class Ch01CloudOfDarkness(WorldState ws, Actor primary) : BossModule(ws, primary, DefaultCenter, DefaultArena)
{
public static readonly WPos DefaultCenter = new(100, 100);
public static readonly ArenaBoundsCircle InitialBounds = new(40);
public static readonly ArenaBoundsCustom Phase1Bounds = new(InitialBounds.Radius, new(BuildPhase1BoundsContour()));
public static readonly ArenaBoundsCustom Phase2Bounds = new(InitialBounds.Radius, BuildPhase2BoundsPoly());
public static readonly WPos Phase1Midpoint = DefaultCenter + Phase1Bounds.Poly.Parts[0].Vertices[1] + Phase1Bounds.Poly.Parts[0].Vertices[3];

public static List<WDir> BuildPhase1BoundsContour()
{
// north 'diagonal' is at [+/-15, -37] (it almost intersects the initial circle - at x=15 z is ~37.08)
// the main diagonal is 20, rotated by 45 degrees, which means that side corners are at x=+/- 40/sqrt(2), z = -37 + 40/sqrt(2) - 15
var nz = -37;
var nx = 15;
var halfDiag = 40 / MathF.Sqrt(2);
var cz = nz + halfDiag - nx;
return [new(nx, nz), new(halfDiag, cz), new(0, cz + halfDiag), new(-halfDiag, cz), new(-nx, nz)];
}

public static RelSimplifiedComplexPolygon BuildPhase2BoundsPoly()
{
// mid is union of 4 rects
var midHalfWidth = 3;
var midHalfLength = 24;
var midOffset = 15;
var op1 = new PolygonClipper.Operand();
var op2 = new PolygonClipper.Operand();
op1.AddContour(CurveApprox.Rect(new WDir(0, +midOffset), new(1, 0), midHalfWidth, midHalfLength));
op1.AddContour(CurveApprox.Rect(new WDir(0, -midOffset), new(1, 0), midHalfWidth, midHalfLength));
op2.AddContour(CurveApprox.Rect(new WDir(+midOffset, 0), new(0, 1), midHalfWidth, midHalfLength));
op2.AddContour(CurveApprox.Rect(new WDir(-midOffset, 0), new(0, 1), midHalfWidth, midHalfLength));
var mid = InitialBounds.Clipper.Union(op1, op2);

// sides is union of two platforms and the outside ring
var sideHalfWidth = 7.5f;
var sideHalfLength = 10;
var sideOffset = 19 + sideHalfLength;
var sideRingWidth = 6;
op1.Clear();
op2.Clear();
op1.AddContour(CurveApprox.Rect(new WDir(+sideOffset, 0), new(1, 0), sideHalfWidth, sideHalfLength));
op1.AddContour(CurveApprox.Rect(new WDir(-sideOffset, 0), new(1, 0), sideHalfWidth, sideHalfLength));
op2.AddContour(CurveApprox.Circle(InitialBounds.Radius, 0.1f));
op2.AddContour(CurveApprox.Circle(InitialBounds.Radius - sideRingWidth, 0.1f));
var side = InitialBounds.Clipper.Union(op1, op2);

op1.Clear();
op2.Clear();
op1.AddPolygon(mid);
op2.AddPolygon(side);
return InitialBounds.Clipper.Union(op1, op2);
}
public static readonly WPos Phase1BoundsCenter = new(100, 76.28427f);
public static readonly PolygonCustom[] Diamond = [new([new(115, 63), new(128.28427f, 76.28427f), new(100, 104.56854f), new(71.71573f, 76.28427f), new(85, 63)])];
private static readonly DonutV[] donut = [new(DefaultCenter, 34, 40, 80)];
public static readonly Shape[] Phase2ShapesND = [new Rectangle(new(100, 115), 24, 3), new Rectangle(new(100, 85), 24, 3), new Rectangle(new(115, 100), 3, 24),
new Rectangle(new(85, 100), 3, 24), new Square(new(126.5f, 100), 7.5f), new Square(new(73.5f, 100), 7.5f)];
public static readonly Shape[] Phase2ShapesWD = [.. donut, .. Phase2ShapesND];
public static readonly ArenaBoundsCircle DefaultArena = new(40);
public static readonly ArenaBoundsComplex Phase1Bounds = new(Diamond);
public static readonly ArenaBoundsComplex Phase2BoundsWD = new(Phase2ShapesWD);
public static readonly ArenaBoundsComplex Phase2BoundsND = new(Phase2ShapesND, donut);
}

// envcontrols:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ public enum AID : uint
LoomingChaosBoss = 41674, // Boss->self, 7.0s cast, single-target, visual (position swaps)
LoomingChaosAOE = 41675, // Helper->self, 7.7s cast, range 50 circle, raidwide + position swaps

//_Weaponskill_FeintParticleBeam = 40477, // Boss->self, 6.0+0.7s cast, single-target
FeintParticleBeamVisual = 40477, // Boss->self, 6.0+0,7s cast, single-target, chasing AOE
FeintParticleBeamFirst = 40478, // Helper->location, 4.0s cast, range 3 circle
FeintParticleBeamRest = 40479, // Helper->location, no cast, range 3 circle
FloodOfDarkness2 = 40455, // Boss->location, 7.0s cast, range 60 circle
Evaporation = 40454, // StygianShadow->Boss, 2.0s cast, single-target
DelugeOfDarknessEnrage = 40533, // Boss->location, 12.0s cast, range 100 circle
}

public enum SID : uint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}
}

private void Start(DateTime activation) => _source = new(Ch01CloudOfDarkness.Phase1Midpoint, 15, activation);
private void Start(DateTime activation) => _source = new(Ch01CloudOfDarkness.Phase1BoundsCenter, 15, activation);
}

class EnaeroAOE(BossModule module) : Components.GenericAOEs(module)
Expand Down Expand Up @@ -103,7 +103,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)

private void Start(DateTime activation)
{
_aoe = new(_shape, Ch01CloudOfDarkness.Phase1Midpoint, default, activation);
_aoe = new(_shape, Ch01CloudOfDarkness.Phase1BoundsCenter, default, activation);
_delayed = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class EndeathVortex(BossModule module) : Components.Knockback(module)

public override IEnumerable<Source> Sources(int slot, Actor actor) => Utils.ZeroOrOne(_source);

public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => (pos - Ch01CloudOfDarkness.Phase1Midpoint).LengthSq() <= 36;
public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => (pos - Ch01CloudOfDarkness.Phase1BoundsCenter).LengthSq() <= 36;

public override void AddHints(int slot, Actor actor, TextHints hints)
{
Expand Down Expand Up @@ -61,7 +61,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}
}

private void Start(DateTime activation) => _source = new(Ch01CloudOfDarkness.Phase1Midpoint, 15, activation, Kind: Kind.TowardsOrigin);
private void Start(DateTime activation) => _source = new(Ch01CloudOfDarkness.Phase1BoundsCenter, 15, activation, Kind: Kind.TowardsOrigin);
}

class EndeathAOE(BossModule module) : Components.GenericAOEs(module)
Expand Down Expand Up @@ -109,8 +109,8 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)

private void Start(DateTime activation)
{
_aoes.Add(new(_shapeOut, Ch01CloudOfDarkness.Phase1Midpoint, default, activation.AddSeconds(2)));
_aoes.Add(new(_shapeIn, Ch01CloudOfDarkness.Phase1Midpoint, default, activation.AddSeconds(4)));
_aoes.Add(new(_shapeOut, Ch01CloudOfDarkness.Phase1BoundsCenter, default, activation.AddSeconds(2)));
_aoes.Add(new(_shapeIn, Ch01CloudOfDarkness.Phase1BoundsCenter, default, activation.AddSeconds(4)));
_delayed = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,28 @@ public override void OnEventEnvControl(byte index, uint state)
switch (state)
{
case 0x00020001:
SetArena(D092OverseerKanilokka.DefaultArena, D092OverseerKanilokka.DefaultArena.Center);
SetArena(D092OverseerKanilokka.DefaultArena);
break;
case 0x00200010:
SetArena(D092OverseerKanilokka.TinyArena, D092OverseerKanilokka.TinyArena.Center);
SetArena(D092OverseerKanilokka.TinyArena);
break;
case 0x00800040:
SetArena(D092OverseerKanilokka.ArenaENVC00800040, D092OverseerKanilokka.ArenaENVC00800040.Center);
SetArena(D092OverseerKanilokka.ArenaENVC00800040);
break;
case 0x02000100:
SetArena(D092OverseerKanilokka.ArenaENVC02000100, D092OverseerKanilokka.ArenaENVC02000100.Center);
SetArena(D092OverseerKanilokka.ArenaENVC02000100);
break;
case 0x00080004:
SetArena(D092OverseerKanilokka.StartingBounds, D092OverseerKanilokka.StartingBounds.Center);
SetArena(D092OverseerKanilokka.StartingBounds);
break;
}
_aoe = null;
}

private void SetArena(ArenaBounds bounds, WPos center)
private void SetArena(ArenaBoundsComplex bounds)
{
Arena.Bounds = bounds;
Arena.Center = center;
Arena.Center = bounds.Center;
}
}

Expand Down
7 changes: 0 additions & 7 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa
_ => Player.Position
};

// TODO: account for leeway for casters
private WPos PathfindPosition(Actor? meleeGreedTarget)
{
var res = NavigationDecision.Build(NavigationContext, World, Hints, Player, Speed());
return meleeGreedTarget != null && res.Destination != null ? ClosestInMelee(res.Destination.Value, meleeGreedTarget) : (res.Destination ?? Player.Position);
}

// assumption: pull range is 12; hitbox is 5, so maxmelee is 8, meaning we have approx 4m to move during pull - with sprint, speed is 7.8, accel is 30 => over 0.26s accel period we move 1.014m, then need another 0.38s to reach boss (but it also moves)
private WPos PrepullPosition(FRU module, PartyRolesConfig.Assignment assignment)
{
Expand Down
21 changes: 8 additions & 13 deletions BossMod/Modules/Dawntrail/Ultimate/FRU/P2DiamondDust.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,14 @@ public override IEnumerable<Source> Sources(int slot, Actor actor)
public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
if (_safeDirs[slot] != default)
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Module.Center + 6 * _safeDirs[slot], new(1, 0), Module.Bounds.MapResolution, actor.Position, 0.25f), _activation);
hints.AddForbiddenZone(ShapeDistance.PrecisePosition(Arena.Center + 6 * _safeDirs[slot], new(1, 0), Arena.Bounds.MapResolution, actor.Position, 0.25f), _activation);
}

public override void DrawArenaForeground(int pcSlot, Actor pc)
{
base.DrawArenaForeground(pcSlot, pc);
if (_safeDirs[pcSlot] != default)
Arena.AddCircle(Module.Center + 18 * _safeDirs[pcSlot], 1, ArenaColor.Safe);
Arena.AddCircle(Arena.Center + 18 * _safeDirs[pcSlot], 1, Colors.Safe);
}

private static WDir[] BuildSafeDirs(BossModule module)
Expand Down Expand Up @@ -346,7 +346,6 @@ class P2TwinStillnessSilence(BossModule module) : Components.GenericAOEs(module)
private BitMask _thinIce;
private P2SinboundHolyVoidzone? _voidzones; // used for hints only

private const float SlideDistance = 32;
private readonly AOEShapeCone _shapeFront = new(30, 135.Degrees());
private readonly AOEShapeCone _shapeBack = new(30, 45.Degrees());

Expand All @@ -371,7 +370,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
// first, find a set of allowed angles along the border
var zoneList = new ArcList(Arena.Center, 17);
foreach (var z in _voidzones.Sources(Module))
zoneList.ForbidCircle(z.Position, _voidzones.Shape.Radius);
zoneList.ForbidCircle(z.Position, 6);

// now find closest allowed zone
var actorDir = Angle.FromDirection(actor.Position - Module.Center);
Expand All @@ -384,21 +383,17 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
{
// destination is very wide, narrow it down a bit to be in line with the boss
halfWidth = 5.Degrees();
var sourceDir = Angle.FromDirection(_source.Position - Module.Center);
var sourceDir = Angle.FromDirection(_source.Position - Arena.Center);
var sourceDist = sourceDir.DistanceToRange(closest.min + halfWidth, closest.max - halfWidth);
var oppositeDist = (sourceDir + 180.Degrees()).DistanceToRange(closest.min + halfWidth, closest.max - halfWidth);
desiredDir = oppositeDist.Abs().Rad < sourceDist.Abs().Rad ? (sourceDir + 180.Degrees() + oppositeDist) : (sourceDir + sourceDist);
}
hints.AddForbiddenZone(ShapeDistance.Circle(Module.Center, 16), WorldState.FutureTime(50));
hints.AddForbiddenZone(ShapeDistance.InvertedCone(Module.Center, 100, desiredDir, halfWidth), DateTime.MaxValue);
hints.AddForbiddenZone(ShapeDistance.Circle(Arena.Center, 16), WorldState.FutureTime(50));
hints.AddForbiddenZone(ShapeDistance.InvertedCone(Arena.Center, 100, desiredDir, halfWidth), DateTime.MaxValue);
}
return;
}

// at this point, we have thin ice, so we can either stay or move fixed distance
hints.AddForbiddenZone(ShapeDistance.Donut(actor.Position, 1, 31));
hints.AddForbiddenZone(ShapeDistance.InvertedCircle(actor.Position, 33));

if (AOEs.Count == 0)
{
// if we're behind boss, slide over
Expand All @@ -416,8 +411,8 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
{
var offset = z.Position - actor.Position;
var dist = offset.Length();
if (dist > _voidzones.Shape.Radius)
hints.AddForbiddenZone(ShapeDistance.Cone(actor.Position, 100, Angle.FromDirection(offset), Angle.Asin(dist / _voidzones.Shape.Radius)));
if (dist > 6)
hints.AddForbiddenZone(ShapeDistance.Cone(actor.Position, 100, Angle.FromDirection(offset), Angle.Asin(dist / 6)));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public override void AddGlobalHints(GlobalHints hints)
public override void DrawArenaForeground(int pcSlot, Actor pc)
{
foreach (var t in _tethers)
Arena.AddLine(t.from.Position, t.to.Position, ArenaColor.Safe); // TODO: min/max break distance
Arena.AddLine(t.from.Position, t.to.Position, Colors.Safe); // TODO: min/max break distance
}

public override void OnStatusGain(Actor actor, ActorStatus status)
Expand Down
Loading

0 comments on commit 1a7ba89

Please sign in to comment.