Skip to content

Commit

Permalink
Chaotic improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
awgil committed Jan 1, 2025
1 parent 87326df commit ac516c6
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class Break(BossModule module) : Components.GenericGaze(module)
{
public readonly List<Eye> Eyes = [];

public override IEnumerable<Eye> ActiveEyes(int slot, Actor actor) => Eyes;//_casters.Where(c => c.CastInfo?.TargetID != actor.InstanceID).Select(c => new Eye(EyePosition(c), Module.CastFinishAt(c.CastInfo), Range: range));
public override IEnumerable<Eye> ActiveEyes(int slot, Actor actor) => Eyes;

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ class Atomos(BossModule module) : Components.Adds(module, (uint)OID.Atomos);
class LoomingChaos(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.LoomingChaosAOE));

// TODO: tankswap hints component for phase1
// TODO: phase 2 squares, break timer, teleport zones
// TODO: particle concentration towers
// TODO: evil seed
[ModuleInfo(BossModuleInfo.Maturity.WIP, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1010, NameID = 13624)]
// TODO: phase 2 squares, break timer, teleport zones, outer ring safety
// TODO: grim embrace / curse of darkness prevent turning
[ModuleInfo(BossModuleInfo.Maturity.Verified, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 1010, NameID = 13624)]
public class Ch01CloudOfDarkness(WorldState ws, Actor primary) : BossModule(ws, primary, DefaultCenter, InitialBounds)
{
public static readonly WPos DefaultCenter = new(100, 100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,17 @@ public enum AID : uint
public enum SID : uint
{
//_Gen_ArcaneDesign = 4180, // Boss->Boss, extra=0x0
//_Gen_VeilOfDarkness = 4179, // Boss->Boss, extra=0x0
//_Gen_LightningResistanceDown = 4386, // Helper/Boss->player, extra=0x1/0x2/0x3/0x4/0x5/0x6/0x7/0x8/0x9/0xA/0xB/0xC/0xD/0xE/0xF/0x10
DeadlyEmbrace = 4181, // none->player, extra=0x0
AbyssalEdge = 4182, // Boss->Boss, extra=0x0 (endeath/enaero stored)
//_Gen_VeilOfDarkness = 4179, // Boss->Boss, extra=0x0
//_Gen_CloyingCondensation = 2532, // none->player, extra=0x0
//_Gen_CloyingCondensation = 2532, // none->player, extra=0x0, prevent jumps?
//_Gen_ = 4388, // none->StygianShadow, extra=0x1052
//_Gen_ = 4387, // none->Boss, extra=0x1051
InnerDarkness = 4177, // none->player, extra=0x0, on main platform
OuterDarkness = 4178, // none->player, extra=0x0, on side platform
//_Gen_Rehabilitation = 4191, // none->Boss, extra=0x1/0x4/0x3/0x2
//_Gen_LifeDrain = 1377, // none->player, extra=0x0
//_Gen_CraftersGrace = 45, // player->player, extra=0x50
CurseOfDarkness = 2387, // none->player, extra=0x0
//_Gen_StabWound = 3061, // none->player, extra=0x0
//_Gen_StabWound = 3062, // none->player, extra=0x0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ private void Subphase2(uint id, float delay)
ThirdArtOfDarknessParticleConcentration(id + 0x20000, 4);
GhastlyGloom(id + 0x30000, 12.3f);
CurseOfDarkness(id + 0x40000, 8.3f);
EvilSeed(id + 0x50000, 9.9f);
ChaosCondensedDiffusiveForceParticleBeam(id + 0x60000, 8.1f);
EvilSeedChaosCondensedDiffusiveForceParticleBeam(id + 0x50000, 9.9f);
ActivePivotParticleBeam(id + 0x70000, 4.4f);
LoomingChaos(id + 0x80000, 6.2f);

Expand Down Expand Up @@ -246,7 +245,8 @@ private void ThirdArtOfDarknessParticleConcentration(uint id, float delay)
.DeactivateOnExit<ThirdArtOfDarknessHyperFocusedParticleBeam>()
.DeactivateOnExit<ThirdArtOfDarknessMultiProngedParticleBeam>()
.DeactivateOnExit<ThirdArtOfDarknessCleave>();
ComponentCondition<ParticleConcentration>(id + 0x50, 3.6f, comp => comp.NumCasts > 0, "Towers")
ComponentCondition<ParticleConcentration>(id + 0x50, 3.6f, comp => comp.Towers.Count == 0, "Towers")
.ExecOnEnter<ParticleConcentration>(comp => comp.ShowOuterTowers())
.DeactivateOnExit<ParticleConcentration>();
}

Expand Down Expand Up @@ -276,29 +276,29 @@ private State FloodOfDarknessAdds(uint id, float delay)
.DeactivateOnExit<FloodOfDarknessAdd>();
}

// TODO: this one needs a lot of thought
private void EvilSeed(uint id, float delay)
private void EvilSeedChaosCondensedDiffusiveForceParticleBeam(uint id, float delay)
{
ComponentCondition<EvilSeedBait>(id, delay, comp => comp.Baiters.Any())
.ActivateOnEnter<EvilSeedBait>();
ComponentCondition<EvilSeedAOE>(id + 0x10, 8.1f, comp => comp.Casters.Count > 0, "Seed plant")
.ActivateOnEnter<EvilSeedAOE>()
.ActivateOnEnter<EvilSeedVoidzone>()
.DeactivateOnExit<EvilSeedBait>();

GhastlyGloom(id + 0x1000, 2.8f)
.DeactivateOnExit<EvilSeedAOE>();

ComponentCondition<ThornyVine>(id + 0x2000, 14, comp => comp.Targets.Any())
.ActivateOnEnter<ThornyVine>();
ComponentCondition<ThornyVine>(id + 0x2010, 3, comp => comp.HaveTethers);
FloodOfDarknessAdds(id + 0x2020, 2.2f)
.DeactivateOnExit<ThornyVine>();
}
ComponentCondition<ThornyVine>(id + 0x2010, 3, comp => comp.TethersAssigned, "Tethers");
FloodOfDarknessAdds(id + 0x2020, 2.2f);

private void ChaosCondensedDiffusiveForceParticleBeam(uint id, float delay)
{
CastMulti(id, [AID.ChaosCondensedParticleBeam, AID.DiffusiveForceParticleBeam], delay, 8)
CastMulti(id + 0x3000, [AID.ChaosCondensedParticleBeam, AID.DiffusiveForceParticleBeam], 8.1f, 8)
.ActivateOnEnter<ChaosCondensedParticleBeam>()
.ActivateOnEnter<DiffusiveForceParticleBeam>();
Condition(id + 0x10, 0.7f, () => Module.FindComponent<ChaosCondensedParticleBeam>()?.NumCasts > 0 || Module.FindComponent<DiffusiveForceParticleBeam>()?.Spreads.Count == 0, "Spread/line stacks")
.ActivateOnEnter<DiffusiveForceParticleBeam>()
.DeactivateOnExit<EvilSeedVoidzone>()
.DeactivateOnExit<ThornyVine>();
Condition(id + 0x3010, 0.7f, () => Module.FindComponent<ChaosCondensedParticleBeam>()?.NumCasts > 0 || Module.FindComponent<DiffusiveForceParticleBeam>()?.Spreads.Count == 0, "Spread/line stacks")
.DeactivateOnExit<ChaosCondensedParticleBeam>()
.DeactivateOnExit<DiffusiveForceParticleBeam>(); // TODO: show second wave ...
}
Expand Down Expand Up @@ -341,7 +341,8 @@ private void ParticleConcentrationPhaser(uint id, float delay)
.ActivateOnEnter<ParticleConcentration>(); // TODO: towers appear 1s after cast end
ComponentCondition<Phaser>(id + 0x11, 1.5f, comp => comp.NumCasts >= 6, "Adds sides/front")
.DeactivateOnExit<Phaser>();
ComponentCondition<ParticleConcentration>(id + 0x20, 6.6f, comp => comp.NumCasts > 0, "Towers")
ComponentCondition<ParticleConcentration>(id + 0x20, 6.6f, comp => comp.Towers.Count == 0, "Towers")
.ExecOnEnter<ParticleConcentration>(comp => comp.ShowOuterTowers())
.DeactivateOnExit<ParticleConcentration>();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
namespace BossMod.Dawntrail.Chaotic.Ch01CloudOfDarkness;

// TODO: who gets radius 7 and who gets radius 5?
// TODO: show for second wave too...
// note: it seems that normally first wave (radius 7) hits people inside, and second wave (radius 5) hits people outside
// however, if some of the players in the mid are dead, some players on the outside will be hit by first wave (up to a total of 12 hits)
// if there are <= 12 players alive, everyone will be hit by the first wave, and the second wave will never happen
// so for safety we just show larger radius around everyone
// TODO: show second wave for players not hit by first wave
class DiffusiveForceParticleBeam(BossModule module) : Components.UniformStackSpread(module, 0, 7)
{
public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.DiffusiveForceParticleBeam)
AddSpreads(Raid.WithoutSlot(), Module.CastFinishAt(spell, 0.7f));
AddSpreads(Raid.WithoutSlot(true), Module.CastFinishAt(spell, 0.7f));
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,15 @@ public override void OnEventIcon(Actor actor, uint iconID, ulong targetID)

class EvilSeedAOE(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.EvilSeedAOE), 5);

// todo: should be chains...
class ThornyVine(BossModule module) : BossComponent(module)
class EvilSeedVoidzone(BossModule module) : Components.PersistentVoidzone(module, 5, module => module.Enemies(OID.EvilSeed).Where(z => z.EventState != 7));

class ThornyVine(BossModule module) : Components.Chains(module, (uint)TetherID.ThornyVine, default, 25)
{
public BitMask Targets;
public bool HaveTethers;

public override void OnEventIcon(Actor actor, uint iconID, ulong targetID)
{
if (iconID == (uint)IconID.ThornyVineBait)
Targets.Set(Raid.FindSlot(actor.InstanceID));
}

public override void OnTethered(Actor source, ActorTetherInfo tether)
{
if (tether.ID == (uint)TetherID.ThornyVine)
HaveTethers = true;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace BossMod.Dawntrail.Chaotic.Ch01CloudOfDarkness;
using System.Collections.Specialized;

namespace BossMod.Dawntrail.Chaotic.Ch01CloudOfDarkness;

// envcontrols:
// 1F-2E = 1-man towers
Expand Down Expand Up @@ -44,4 +46,107 @@
// 47-56 = 1-man tower falling orb
// 57-66 = 2-man tower falling orb
// 67-6E = 3-man tower falling orb
class ParticleConcentration(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.ParticleBeam1)) { }
class ParticleConcentration(BossModule module) : Components.GenericTowers(module)
{
private BitMask _innerPlayers;
private BitMask _outerPlayers;
private readonly List<WPos> _outerTowers = []; // note: initially we don't show outer towers, as players resolve different mechanics first

public void ShowOuterTowers()
{
var activation = Towers.Count > 0 ? Towers[0].Activation : default;
Towers.AddRange(_outerTowers.Select(p => new Tower(p, 3, 3, 3, _innerPlayers, activation)));
}

public override void OnStatusGain(Actor actor, ActorStatus status)
{
switch ((SID)status.ID)
{
case SID.InnerDarkness:
_innerPlayers.Set(Raid.FindSlot(actor.InstanceID));
break;
case SID.OuterDarkness:
_outerPlayers.Set(Raid.FindSlot(actor.InstanceID));
break;
}
}

public override void OnStatusLose(Actor actor, ActorStatus status)
{
switch ((SID)status.ID)
{
case SID.InnerDarkness:
_innerPlayers.Clear(Raid.FindSlot(actor.InstanceID));
break;
case SID.OuterDarkness:
_outerPlayers.Clear(Raid.FindSlot(actor.InstanceID));
break;
}
}

public override void OnEventEnvControl(byte index, uint state)
{
if (state != 0x00020001) // appear
return;

var (offset, count) = index switch
{
0x1F => (new(-9, -15), 1),
0x20 => (new(+9, -15), 1),
0x21 => (new(-21, -15), 1),
0x22 => (new(+21, -15), 1),
0x23 => (new(-15, -9), 1),
0x24 => (new(+15, -9), 1),
0x25 => (new(-15, -21), 1),
0x26 => (new(+15, -21), 1),
0x27 => (new(-9, +15), 1),
0x28 => (new(+9, +15), 1),
0x29 => (new(-21, +15), 1),
0x2A => (new(+21, +15), 1),
0x2B => (new(-15, +9), 1),
0x2C => (new(+15, +9), 1),
0x2D => (new(-15, +21), 1),
0x2E => (new(+15, +21), 1),
0x2F => (new(-12, -15), 2),
0x30 => (new(+12, -15), 2),
0x31 => (new(-18, -15), 2),
0x32 => (new(+18, -15), 2),
0x33 => (new(-15, -12), 2),
0x34 => (new(+15, -12), 2),
0x35 => (new(-15, -18), 2),
0x36 => (new(+15, -18), 2),
0x37 => (new(-12, +15), 2),
0x38 => (new(+12, +15), 2),
0x39 => (new(-18, +15), 2),
0x3A => (new(+18, +15), 2),
0x3B => (new(-15, +12), 2),
0x3C => (new(+15, +12), 2),
0x3D => (new(-15, +18), 2),
0x3E => (new(+15, +18), 2),
0x3F => (new(-26.5f, -4.5f), 3),
0x40 => (new(-22, 0), 3),
0x41 => (new(-26.5f, +4.5f), 3),
0x42 => (new(-31, 0), 3),
0x43 => (new(+26.5f, -4.5f), 3),
0x44 => (new(+22, 0), 3),
0x45 => (new(+26.5f, +4.5f), 3),
0x46 => (new(+31, 0), 3),
_ => (default(WDir), 0)
};

if (count == 3)
_outerTowers.Add(Module.Center + offset);
else if (count > 0)
Towers.Add(new(Module.Center + offset, 3, count, count, _outerPlayers, WorldState.FutureTime(10.1f)));
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID is AID.ParticleBeam1 or AID.ParticleBeam2 or AID.ParticleBeam3)
{
++NumCasts;
if (Towers.RemoveAll(t => t.Position.AlmostEqual(caster.Position, 1)) != 1)
ReportError($"Unexpected tower position @ {caster.Position}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ThirdArtOfDarknessCleave(BossModule module) : Components.GenericAOEs(modul
public enum Mechanic { None, Left, Right, Stack, Spread }

public readonly Dictionary<Actor, List<(Mechanic mechanic, DateTime activation)>> Mechanics = [];
public BitMask PlatformPlayers;

private static readonly AOEShapeCone _shape = new(15, 90.Degrees());

Expand All @@ -25,12 +26,28 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)

public override void AddHints(int slot, Actor actor, TextHints hints)
{
var (a, m) = Mechanics.FirstOrDefault(kv => kv.Key.InstanceID == actor.TargetID);
if (a != null && m.Count > 0)
hints.Add($"Order: {string.Join(" > ", m.Select(m => m.mechanic))}", false);
if (PlatformPlayers[slot])
{
var playerSide = actor.Position.X - Module.Center.X;
var (a, m) = Mechanics.FirstOrDefault(kv => (kv.Key.Position.X - Module.Center.X) * playerSide > 0);
if (a != null && m.Count > 0)
hints.Add($"Order: {string.Join(" > ", m.Select(m => m.mechanic))}", false);
}
base.AddHints(slot, actor, hints);
}

public override void OnStatusGain(Actor actor, ActorStatus status)
{
if ((SID)status.ID == SID.OuterDarkness)
PlatformPlayers.Set(Raid.FindSlot(actor.InstanceID));
}

public override void OnStatusLose(Actor actor, ActorStatus status)
{
if ((SID)status.ID == SID.OuterDarkness)
PlatformPlayers.Clear(Raid.FindSlot(actor.InstanceID));
}

public override void OnEventIcon(Actor actor, uint iconID, ulong targetID)
{
if ((OID)actor.OID == OID.StygianShadow)
Expand Down Expand Up @@ -100,7 +117,7 @@ public override void Update()
foreach (var (a, m) in _main.Mechanics)
if (m.Count > 0 && m[0].mechanic == ThirdArtOfDarknessCleave.Mechanic.Stack)
foreach (var p in Raid.WithoutSlot().SortedByRange(a.Position).Take(3))
AddStack(p, m[0].activation);
AddStack(p, m[0].activation, ~_main.PlatformPlayers);
base.Update();
}
}
Loading

0 comments on commit ac516c6

Please sign in to comment.