-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #379 from xanunderscore/dtdungeon12
Dawntrail dungeons 1&2
- Loading branch information
Showing
9 changed files
with
756 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
189 changes: 189 additions & 0 deletions
189
BossMod/Modules/Dawntrail/Dungeon/D01Ihuykatumu/D011PrimePunutiy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
namespace BossMod.Dawntrail.Dungeon.D01Ihuykatumu.D011PrimePunutiy; | ||
|
||
public enum OID : uint | ||
{ | ||
Helper = 0x233C, // R0.500, x16 (spawn during fight), 523 type | ||
Boss = 0x4190, // R7.990, x1 | ||
ProdigiousPunutiy = 0x4191, // R4.230, x0 (spawn during fight) | ||
Punutiy = 0x4192, // R2.820, x0 (spawn during fight) | ||
PetitPunutiy = 0x4193, // R2.115, x0 (spawn during fight) | ||
IhuykatumuFlytrap = 0x4194, // R1.600, x0 (spawn during fight) | ||
} | ||
|
||
public enum AID : uint | ||
{ | ||
PunutiyPress = 36492, // Boss->self, 5.0s cast, range 60 circle | ||
Hydrowave = 36493, // Boss->self, 4.0s cast, range 60 30-degree cone | ||
AddsHydrowave = 36509, | ||
Resurface = 36494, // Boss->self, 5.0s cast, range 100 60-degree cone | ||
Resurface2 = 36495, // Boss->self, 7.0s cast, single-target | ||
Bury1 = 36497, // 233C->self, 4.0s cast, range 12 circle | ||
Bury2 = 36498, // 233C->self, 4.0s cast, range 8 circle | ||
Bury3 = 36499, // 233C->self, 4.0s cast, range 25 width 6 rect | ||
Bury4 = 36500, // 233C->self, 4.0s cast, range 35 width 10 rect | ||
Bury5 = 36501, // 233C->self, 4.0s cast, range 4 circle | ||
Bury6 = 36502, // 233C->self, 4.0s cast, range 6 circle | ||
Bury7 = 36503, // 233C->self, 4.0s cast, range 25 width 6 rect | ||
Bury8 = 36504, // 233C->self, 4.0s cast, range 35 width 10 rect | ||
Decay = 36505, // 4194->self, 7.0s cast, range ?-40 donut | ||
ShoreShaker = 36514, // Boss->self, 4.0+1.0s cast, single-target | ||
ShoreShaker1 = 36515, // 233C->self, 5.0s cast, range 10 circle | ||
ShoreShaker2 = 36516, // 233C->self, 7.0s cast, range ?-20 donut | ||
ShoreShaker3 = 36517, // 233C->self, 9.0s cast, range ?-30 donut | ||
} | ||
|
||
class PunutiyFlop(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.PunutiyPress)); | ||
class Hydrowave(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Hydrowave), new AOEShapeCone(60, 15.Degrees())); | ||
|
||
class Bury(BossModule module) : Components.GenericAOEs(module) | ||
{ | ||
private readonly List<(Actor Caster, AOEInstance AOE)> _activeAOEs = []; | ||
|
||
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => _activeAOEs.Select(x => x.AOE); | ||
|
||
public override void OnCastStarted(Actor caster, ActorCastInfo spell) | ||
{ | ||
AOEShape? toAdd = (AID)spell.Action.ID switch | ||
{ | ||
AID.Bury1 => new AOEShapeCircle(12), | ||
AID.Bury2 => new AOEShapeCircle(8), | ||
AID.Bury3 or AID.Bury7 => new AOEShapeRect(25, 3), | ||
AID.Bury4 or AID.Bury8 => new AOEShapeRect(35, 5), | ||
AID.Bury5 => new AOEShapeCircle(4), | ||
AID.Bury6 => new AOEShapeCircle(6), | ||
_ => null | ||
}; | ||
if (toAdd != null) | ||
_activeAOEs.Add((caster, new AOEInstance(toAdd, caster.Position, spell.Rotation, spell.NPCFinishAt))); | ||
} | ||
|
||
public override void OnCastFinished(Actor caster, ActorCastInfo spell) | ||
{ | ||
_activeAOEs.RemoveAll(x => x.Caster == caster); | ||
} | ||
} | ||
|
||
class Resurface(BossModule module) : Components.GenericAOEs(module) | ||
{ | ||
private AOEInstance? _aoe; | ||
|
||
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); | ||
|
||
public override void OnCastStarted(Actor caster, ActorCastInfo spell) | ||
{ | ||
if (spell.Action.ID == (uint)AID.Resurface) | ||
_aoe = new AOEInstance(new AOEShapeCone(100, 32.Degrees()), caster.Position, spell.Rotation, spell.NPCFinishAt); | ||
} | ||
|
||
public override void OnCastFinished(Actor caster, ActorCastInfo spell) | ||
{ | ||
if (spell.Action.ID == (uint)AID.Resurface2) | ||
_aoe = null; | ||
} | ||
} | ||
|
||
class Decay(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Decay), new AOEShapeDonut(5, 40)) | ||
{ | ||
public override void DrawArenaForeground(int pcSlot, Actor pc) | ||
=> Arena.Actors(Module.Enemies(OID.IhuykatumuFlytrap).Where(x => !x.IsDead), ArenaColor.Object, allowDeadAndUntargetable: true); | ||
} | ||
|
||
abstract class TetherBait(BossModule module, bool centerAtTarget = false) : Components.GenericBaitAway(module, default, true, centerAtTarget) | ||
{ | ||
public override void DrawArenaForeground(int pcSlot, Actor pc) | ||
{ | ||
base.DrawArenaForeground(pcSlot, pc); | ||
foreach (var b in ActiveBaits) | ||
{ | ||
if (Arena.Config.ShowOutlinesAndShadows) | ||
Arena.AddLine(b.Source.Position, b.Target.Position, 0xFF000000, 2); | ||
Arena.AddLine(b.Source.Position, b.Target.Position, ArenaColor.Danger); | ||
} | ||
} | ||
|
||
public override void OnTethered(Actor source, ActorTetherInfo tether) | ||
{ | ||
if (tether.ID != 17) | ||
return; | ||
|
||
var tar = WorldState.Actors.Find(tether.Target); | ||
if (tar == null) | ||
return; | ||
|
||
OnTetherCreated(source, tar); | ||
} | ||
|
||
public override void OnUntethered(Actor source, ActorTetherInfo tether) | ||
{ | ||
if (tether.ID == 17) | ||
CurrentBaits.Clear(); | ||
} | ||
|
||
protected abstract void OnTetherCreated(Actor source, Actor target); | ||
} | ||
|
||
class FlopBait(BossModule module) : TetherBait(module, true) | ||
{ | ||
protected override void OnTetherCreated(Actor source, Actor target) | ||
{ | ||
switch ((OID)source.OID) | ||
{ | ||
case OID.ProdigiousPunutiy: | ||
CurrentBaits.Add(new(source, target, new AOEShapeCircle(14))); | ||
break; | ||
case OID.PetitPunutiy: | ||
CurrentBaits.Add(new(source, target, new AOEShapeCircle(6))); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
class HydroBait(BossModule module) : TetherBait(module, false) | ||
{ | ||
protected override void OnTetherCreated(Actor source, Actor target) | ||
{ | ||
if ((OID)source.OID == OID.Punutiy) | ||
CurrentBaits.Add(new(source, target, new AOEShapeCone(60, 15.Degrees()))); | ||
} | ||
} | ||
|
||
class ShoreShaker(BossModule module) : Components.ConcentricAOEs(module, [new AOEShapeCircle(10), new AOEShapeDonut(10, 20), new AOEShapeDonut(20, 30)]) | ||
{ | ||
public override void OnCastStarted(Actor caster, ActorCastInfo spell) | ||
{ | ||
if ((AID)spell.Action.ID == AID.ShoreShaker) | ||
AddSequence(Module.Center, spell.NPCFinishAt); | ||
} | ||
|
||
public override void OnEventCast(Actor caster, ActorCastEvent spell) | ||
{ | ||
var order = (AID)spell.Action.ID switch | ||
{ | ||
AID.ShoreShaker1 => 0, | ||
AID.ShoreShaker2 => 1, | ||
AID.ShoreShaker3 => 2, | ||
_ => -1 | ||
}; | ||
if (!AdvanceSequence(order, caster.Position, WorldState.FutureTime(2f))) | ||
ReportError($"unexpected order {order}"); | ||
} | ||
} | ||
|
||
class D011PrimePunutiyStates : StateMachineBuilder | ||
{ | ||
public D011PrimePunutiyStates(BossModule module) : base(module) | ||
{ | ||
TrivialPhase() | ||
.ActivateOnEnter<PunutiyFlop>() | ||
.ActivateOnEnter<Hydrowave>() | ||
.ActivateOnEnter<Resurface>() | ||
.ActivateOnEnter<Bury>() | ||
.ActivateOnEnter<Decay>() | ||
.ActivateOnEnter<FlopBait>() | ||
.ActivateOnEnter<HydroBait>() | ||
.ActivateOnEnter<ShoreShaker>(); | ||
} | ||
} | ||
|
||
[ModuleInfo(BossModuleInfo.Maturity.WIP, Contributors = "xan", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 826, NameID = 12723)] | ||
public class D011PrimePunutiy(WorldState ws, Actor primary) : BossModule(ws, primary, new(35, -95), new ArenaBoundsSquare(20)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
// there is nothing here. boss 2 can trivially be solved by AI |
130 changes: 130 additions & 0 deletions
130
BossMod/Modules/Dawntrail/Dungeon/D01Ihuykatumu/D013Apollyon.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
namespace BossMod.Dawntrail.Dungeon.D01Ihuykatumu.D013Apollyon; | ||
|
||
public enum OID : uint | ||
{ | ||
Helper = 0x233C, // R0.500, x?, 523 type | ||
Boss = 0x4165, // R7.000, x? | ||
LightningAOE = 0x1EBA21, // R0.500, x?, EventObj type | ||
Whirlwind = 0x416C, // R1.000, x? | ||
} | ||
|
||
public enum AID : uint | ||
{ | ||
RazorZephyr = 36340, // 4165->self, 4.0s cast, range 50 width 12 rect | ||
BladeST = 36347, // 4165->none, 4.5s cast, single-target | ||
HighWind = 36341, // 4165->self, 5.0s cast, range 60 circle | ||
BladesOfFamine = 36346, // 233C->self, 3.0s cast, range 50 width 12 rect | ||
LevinsickleSpark = 36349, // 233C->location, 5.0s cast, range 4 circle | ||
Levinsickle = 36350, // 233C->location, 5.0s cast, range 4 circle | ||
WingOfLightning = 36351, // 233C->self, 8.0s cast, range 40 ?-degree cone | ||
ThunderIII = 36353, // 233C->player, 5.0s cast, range 6 circle | ||
BladeAOE = 36357, // 233C->none, 5.0s cast, range 6 circle | ||
WindSickle = 36358, // 233C->self, 4.0s cast, range ?-60 donut | ||
RazorStorm = 36355, // 4165->self, 5.0s cast, range 40 width 40 rect | ||
Windwhistle = 36359, // 4165->self, 4.0s cast, single-target | ||
Cuttingwind = 36360, // 233C->self, no cast, range 72 width 8 rect | ||
} | ||
|
||
class RazorZephyr(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RazorZephyr), new AOEShapeRect(50, 6)); | ||
class Blade(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.BladeST)); | ||
class HighWind(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.HighWind)); | ||
class BladesOfFamine(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BladesOfFamine), new AOEShapeRect(50, 6)); | ||
class WingOfLightning(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.WingOfLightning), new AOEShapeCone(40, 22.5f.Degrees()), maxCasts: 8); | ||
class LightningHelper(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(OID.LightningAOE)); | ||
class ThunderIII(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.ThunderIII), 6); | ||
class BladeAOE(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.BladeAOE), new AOEShapeCircle(6), centerAtTarget: true); | ||
class WindSickle(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.WindSickle), new AOEShapeDonut(6, 60)); | ||
class RazorStorm(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RazorStorm), new AOEShapeRect(40, 20)); | ||
class Levinsickle(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Levinsickle), 4); | ||
class LevinsickleSpark(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.LevinsickleSpark), 4); | ||
|
||
// first aoe is 10 seconds after windwhistle | ||
// rest are 8 seconds after previous | ||
class Whirlwind(BossModule module) : Components.GenericAOEs(module) | ||
{ | ||
private int _activations; | ||
private DateTime _nextActivation; | ||
|
||
private static readonly List<Angle> Rotations = [0.Degrees(), 45.Degrees(), 90.Degrees(), 135.Degrees()]; | ||
|
||
public override void OnCastFinished(Actor caster, ActorCastInfo spell) | ||
{ | ||
if ((AID)spell.Action.ID == AID.Windwhistle) | ||
_nextActivation = WorldState.FutureTime(10); | ||
} | ||
|
||
public override void DrawArenaBackground(int pcSlot, Actor pc) | ||
{ | ||
foreach (var c in ActiveAOEs(pcSlot, pc)) | ||
{ | ||
c.Shape.Draw(Arena, c.Origin, c.Rotation, c.Color); | ||
c.Shape.Outline(Arena, c.Origin, c.Rotation, ArenaColor.AOE); | ||
} | ||
} | ||
|
||
public override void OnEventCast(Actor caster, ActorCastEvent spell) | ||
{ | ||
if ((AID)spell.Action.ID == AID.Cuttingwind) | ||
{ | ||
_activations += 1; | ||
_nextActivation = WorldState.FutureTime(8); | ||
} | ||
} | ||
|
||
public override void OnActorDestroyed(Actor actor) | ||
{ | ||
_activations = 0; | ||
_nextActivation = default; | ||
} | ||
|
||
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) | ||
{ | ||
if (_activations >= 12) | ||
yield break; | ||
|
||
var whirlwind = Module.Enemies(OID.Whirlwind).FirstOrDefault(); | ||
if (whirlwind == null) | ||
yield break; | ||
|
||
var whirlyHelper = Module.Enemies(OID.Helper).FirstOrDefault(x => x.NameID == 12715); | ||
if (whirlyHelper == null) | ||
yield break; | ||
|
||
foreach (var angle in Rotations) | ||
{ | ||
yield return new AOEInstance(new AOEShapeRect(72, 4, 72), whirlwind.Position, angle, _nextActivation, Shade(_nextActivation), _nextActivation < WorldState.FutureTime(4)); | ||
} | ||
} | ||
|
||
private uint Shade(DateTime activation) | ||
{ | ||
var clampedETA = Math.Clamp((activation - WorldState.CurrentTime).TotalSeconds, 0, 4); | ||
var opacity = 1 - clampedETA / 4; | ||
var alpha = (uint)(opacity * 96) + 32; | ||
return 0x008080 + alpha * 0x1000000; | ||
} | ||
} | ||
|
||
class D013ApollyonStates : StateMachineBuilder | ||
{ | ||
public D013ApollyonStates(BossModule module) : base(module) | ||
{ | ||
TrivialPhase() | ||
.ActivateOnEnter<RazorZephyr>() | ||
.ActivateOnEnter<Blade>() | ||
.ActivateOnEnter<HighWind>() | ||
.ActivateOnEnter<BladesOfFamine>() | ||
.ActivateOnEnter<WingOfLightning>() | ||
.ActivateOnEnter<LightningHelper>() | ||
.ActivateOnEnter<ThunderIII>() | ||
.ActivateOnEnter<BladeAOE>() | ||
.ActivateOnEnter<WindSickle>() | ||
.ActivateOnEnter<RazorStorm>() | ||
.ActivateOnEnter<Levinsickle>() | ||
.ActivateOnEnter<LevinsickleSpark>() | ||
.ActivateOnEnter<Whirlwind>(); | ||
} | ||
} | ||
|
||
[ModuleInfo(BossModuleInfo.Maturity.WIP, Contributors = "xan", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 826, NameID = 12711)] | ||
public class D013Apollyon(WorldState ws, Actor primary) : BossModule(ws, primary, new(-107, 265), new ArenaBoundsCircle(20)); |
Oops, something went wrong.