From a9746039700eceaddc1a6ac3c4b6373ead6fbfb7 Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Sat, 2 Nov 2024 00:29:19 +0100 Subject: [PATCH] reverted some stuff until bug is identified --- BossMod/BossModule/AOEShapes.cs | 25 ++++++++++++++++++- BossMod/Components/BaitAway.cs | 16 ++++++------ BossMod/Components/CastCounter.cs | 2 +- BossMod/Components/CastHint.cs | 6 ++--- BossMod/Components/Chains.cs | 2 +- BossMod/Components/ChasingAOEs.cs | 4 +-- BossMod/Components/Cleave.cs | 2 +- BossMod/Components/ConcentricAOEs.cs | 2 +- BossMod/Components/DirectionalParry.cs | 2 +- BossMod/Components/Exaflare.cs | 4 +-- BossMod/Components/ForcedMarch.cs | 6 ++--- BossMod/Components/Gaze.cs | 4 +-- BossMod/Components/GenericAOEs.cs | 10 ++++---- BossMod/Components/Knockback.cs | 2 +- BossMod/Components/PersistentVoidzone.cs | 8 +++--- BossMod/Components/Protean.cs | 2 +- BossMod/Components/RotatingAOE.cs | 2 +- BossMod/Components/SharedTankbuster.cs | 12 ++++----- BossMod/Components/StackSpread.cs | 16 ++++++------ BossMod/Components/StayInBounds.cs | 2 +- BossMod/Components/StayMove.cs | 2 +- BossMod/Components/TankSwap.cs | 2 +- BossMod/Components/Tethers.cs | 8 +++--- BossMod/Components/Towers.cs | 4 +-- BossMod/Components/Twister.cs | 8 +++--- BossMod/Components/UnavoidableDamage.cs | 18 ++++++------- BossMod/Components/WildCharge.cs | 2 +- .../Dungeon/D02WorqorZormor/D022Kahderyor.cs | 2 +- 28 files changed, 99 insertions(+), 76 deletions(-) diff --git a/BossMod/BossModule/AOEShapes.cs b/BossMod/BossModule/AOEShapes.cs index 0c9784f97f..3787b72de9 100644 --- a/BossMod/BossModule/AOEShapes.cs +++ b/BossMod/BossModule/AOEShapes.cs @@ -184,11 +184,33 @@ public sealed record class AOEShapeCustom(IEnumerable Shapes1, IEnumerabl { private RelSimplifiedComplexPolygon? polygon; private readonly int hashkey = CreateCacheKey(Shapes1, Shapes2 ?? [], DifferenceShapes ?? [], Operand); - + public static readonly Dictionary Cache = []; + public static readonly LinkedList CacheOrder = new(); + public void AddToCache(RelSimplifiedComplexPolygon value) + { + if (Cache.Count >= 50) + { + var lruKey = CacheOrder.Last?.Value; + if (lruKey != null) + { + Cache.Remove(lruKey.Value); + CacheOrder.RemoveLast(); + } + } + Cache[hashkey] = value; + CacheOrder.Remove(hashkey); + CacheOrder.AddFirst(hashkey); + } public override string ToString() => $"Custom AOE shape: hashkey={hashkey}, ifz={InvertForbiddenZone}"; private RelSimplifiedComplexPolygon GetCombinedPolygon(WPos origin) { + if (Cache.TryGetValue(hashkey, out var cachedResult)) // for moving custom AOEs we don't want to recalculate the polygon every frame since they move at server ticks and not frame + { + CacheOrder.Remove(hashkey); + CacheOrder.AddFirst(hashkey); + return polygon = cachedResult; + } var shapes1 = CreateOperandFromShapes(Shapes1, origin); var shapes2 = CreateOperandFromShapes(Shapes2, origin); var differenceOperands = CreateOperandFromShapes(DifferenceShapes, origin); @@ -204,6 +226,7 @@ private RelSimplifiedComplexPolygon GetCombinedPolygon(WPos origin) polygon = combinedShapes != null ? clipper.Difference(new PolygonClipper.Operand(combinedShapes), differenceOperands) : clipper.Difference(shapes1, differenceOperands); + AddToCache(polygon); return polygon; } diff --git a/BossMod/Components/BaitAway.cs b/BossMod/Components/BaitAway.cs index ca62ceb9a5..d65508ac07 100644 --- a/BossMod/Components/BaitAway.cs +++ b/BossMod/Components/BaitAway.cs @@ -3,7 +3,7 @@ // generic component for mechanics that require baiting some aoe (by proximity, by tether, etc) away from raid // some players can be marked as 'forbidden' - if any of them is baiting, they are warned // otherwise we show own bait as as outline (and warn if player is clipping someone) and other baits as filled (and warn if player is being clipped) -public abstract class GenericBaitAway(BossModule module, ActionID aid = default, bool alwaysDrawOtherBaits = true, bool centerAtTarget = false) : CastCounter(module, aid) +public class GenericBaitAway(BossModule module, ActionID aid = default, bool alwaysDrawOtherBaits = true, bool centerAtTarget = false) : CastCounter(module, aid) { public record struct Bait(Actor Source, Actor Target, AOEShape Shape, DateTime Activation = default) { @@ -111,9 +111,9 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) } // bait on all players, requiring everyone to spread out -public abstract class BaitAwayEveryone : GenericBaitAway +public class BaitAwayEveryone : GenericBaitAway { - protected BaitAwayEveryone(BossModule module, Actor? source, AOEShape shape, ActionID aid = default) : base(module, aid) + public BaitAwayEveryone(BossModule module, Actor? source, AOEShape shape, ActionID aid = default) : base(module, aid) { AllowDeadTargets = false; if (source != null) @@ -122,7 +122,7 @@ protected BaitAwayEveryone(BossModule module, Actor? source, AOEShape shape, Act } // component for mechanics requiring tether targets to bait their aoe away from raid -public abstract class BaitAwayTethers(BossModule module, AOEShape shape, uint tetherID, ActionID aid = default, uint enemyOID = default, float activationDelay = default) : GenericBaitAway(module, aid) +public class BaitAwayTethers(BossModule module, AOEShape shape, uint tetherID, ActionID aid = default, uint enemyOID = default, float activationDelay = default) : GenericBaitAway(module, aid) { public AOEShape Shape = shape; public uint TID = tetherID; @@ -178,7 +178,7 @@ public override void OnUntethered(Actor source, ActorTetherInfo tether) } // component for mechanics requiring icon targets to bait their aoe away from raid -public abstract class BaitAwayIcon(BossModule module, AOEShape shape, uint iconID, ActionID aid = default, float activationDelay = 5.1f, bool centerAtTarget = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget) +public class BaitAwayIcon(BossModule module, AOEShape shape, uint iconID, ActionID aid = default, float activationDelay = 5.1f, bool centerAtTarget = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget) { public AOEShape Shape = shape; public uint IID = iconID; @@ -201,7 +201,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } // component for mechanics requiring cast targets to gtfo from raid (aoe tankbusters etc) -public abstract class BaitAwayCast(BossModule module, ActionID aid, AOEShape shape, bool centerAtTarget = false, bool endsOnCastEvent = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget) +public class BaitAwayCast(BossModule module, ActionID aid, AOEShape shape, bool centerAtTarget = false, bool endsOnCastEvent = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget) { public AOEShape Shape = shape; public bool EndsOnCastEvent = endsOnCastEvent; @@ -227,7 +227,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } // a variation of BaitAwayCast for charges that end at target -public abstract class BaitAwayChargeCast(BossModule module, ActionID aid, float halfWidth) : GenericBaitAway(module, aid) +public class BaitAwayChargeCast(BossModule module, ActionID aid, float halfWidth) : GenericBaitAway(module, aid) { public float HalfWidth = halfWidth; @@ -260,7 +260,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // a variation of baits with tethers for charges that end at target -public abstract class BaitAwayChargeTether(BossModule module, float halfWidth, float activationDelay, ActionID aidGood, ActionID aidBad = default, uint tetherIDBad = 57, uint tetherIDGood = 1, uint enemyOID = default, float minimumDistance = default) +public class BaitAwayChargeTether(BossModule module, float halfWidth, float activationDelay, ActionID aidGood, ActionID aidBad = default, uint tetherIDBad = 57, uint tetherIDGood = 1, uint enemyOID = default, float minimumDistance = default) : StretchTetherDuo(module, minimumDistance, activationDelay, tetherIDBad, tetherIDGood, new AOEShapeRect(default, halfWidth), default, enemyOID) { public ActionID AidGood = aidGood; diff --git a/BossMod/Components/CastCounter.cs b/BossMod/Components/CastCounter.cs index 827fedd5f6..1cc308303b 100644 --- a/BossMod/Components/CastCounter.cs +++ b/BossMod/Components/CastCounter.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic component that counts specified casts -public abstract class CastCounter(BossModule module, ActionID aid) : BossComponent(module) +public class CastCounter(BossModule module, ActionID aid) : BossComponent(module) { public ActionID WatchedAction { get; private set; } = aid; public int NumCasts { get; protected set; } diff --git a/BossMod/Components/CastHint.cs b/BossMod/Components/CastHint.cs index 7efda6dac7..ac5ef1de78 100644 --- a/BossMod/Components/CastHint.cs +++ b/BossMod/Components/CastHint.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic component that is 'active' when any actor casts specific spell -public abstract class CastHint(BossModule module, ActionID aid, string hint, bool showCastTimeLeft = false) : CastCounter(module, aid) +public class CastHint(BossModule module, ActionID aid, string hint, bool showCastTimeLeft = false) : CastCounter(module, aid) { public string Hint = hint; public bool ShowCastTimeLeft = showCastTimeLeft; // if true, show cast time left until next instance @@ -28,14 +28,14 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } } -public abstract class CastInterruptHint : CastHint +public class CastInterruptHint : CastHint { public bool CanBeInterrupted { get; init; } public bool CanBeStunned { get; init; } public bool ShowNameInHint { get; init; } // important if there are several targets public string HintExtra { get; init; } - protected CastInterruptHint(BossModule module, ActionID aid, bool canBeInterrupted = true, bool canBeStunned = false, string hintExtra = "", bool showNameInHint = false) : base(module, aid, "") + public CastInterruptHint(BossModule module, ActionID aid, bool canBeInterrupted = true, bool canBeStunned = false, string hintExtra = "", bool showNameInHint = false) : base(module, aid, "") { CanBeInterrupted = canBeInterrupted; CanBeStunned = canBeStunned; diff --git a/BossMod/Components/Chains.cs b/BossMod/Components/Chains.cs index 2420215b0e..7164428544 100644 --- a/BossMod/Components/Chains.cs +++ b/BossMod/Components/Chains.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // component for breakable chains - Note that chainLength for AI considers the minimum distance needed for a chain-pair to be broken (assuming perfectly stacked at cast) -public abstract class Chains(BossModule module, uint tetherID, ActionID aid = default, float chainLength = 0, bool spreadChains = true) : CastCounter(module, aid) +public class Chains(BossModule module, uint tetherID, ActionID aid = default, float chainLength = 0, bool spreadChains = true) : CastCounter(module, aid) { public uint TID { get; init; } = tetherID; public bool TethersAssigned { get; private set; } diff --git a/BossMod/Components/ChasingAOEs.cs b/BossMod/Components/ChasingAOEs.cs index 6d6794adfd..1402f5e9ed 100644 --- a/BossMod/Components/ChasingAOEs.cs +++ b/BossMod/Components/ChasingAOEs.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic 'chasing AOE' component - these are AOEs that follow the target for a set amount of casts -public abstract class GenericChasingAOEs(BossModule module, float moveDistance, ActionID aid = default, string warningText = "GTFO from chasing aoe!") : GenericAOEs(module, aid, warningText) +public class GenericChasingAOEs(BossModule module, float moveDistance, ActionID aid = default, string warningText = "GTFO from chasing aoe!") : GenericAOEs(module, aid, warningText) { private readonly float MoveDistance = moveDistance; @@ -81,7 +81,7 @@ private void AddForbiddenZones(Actor actor, AIHints hints, bool isTarget) } // standard chasing aoe; first cast is long - assume it is baited on the nearest allowed target; successive casts are instant -public abstract class StandardChasingAOEs(BossModule module, AOEShape shape, ActionID actionFirst, ActionID actionRest, float moveDistance, float secondsBetweenActivations, int maxCasts, bool resetExcludedTargets = false, uint icon = default, float activationDelay = 5.1f) : GenericChasingAOEs(module, moveDistance) +public class StandardChasingAOEs(BossModule module, AOEShape shape, ActionID actionFirst, ActionID actionRest, float moveDistance, float secondsBetweenActivations, int maxCasts, bool resetExcludedTargets = false, uint icon = default, float activationDelay = 5.1f) : GenericChasingAOEs(module, moveDistance) { public AOEShape Shape = shape; public ActionID ActionFirst = actionFirst; diff --git a/BossMod/Components/Cleave.cs b/BossMod/Components/Cleave.cs index 99ad5b29c9..ce4ad3caaa 100644 --- a/BossMod/Components/Cleave.cs +++ b/BossMod/Components/Cleave.cs @@ -2,7 +2,7 @@ // generic component for cleaving autoattacks; shows shape outline and warns when anyone other than main target is inside // enemy OID == 0 means 'primary actor' -public abstract class Cleave(BossModule module, ActionID aid, AOEShape shape, uint enemyOID = 0, bool activeForUntargetable = false, bool originAtTarget = false, bool activeWhileCasting = true) : CastCounter(module, aid) +public class Cleave(BossModule module, ActionID aid, AOEShape shape, uint enemyOID = 0, bool activeForUntargetable = false, bool originAtTarget = false, bool activeWhileCasting = true) : CastCounter(module, aid) { public AOEShape Shape { get; init; } = shape; public bool ActiveForUntargetable { get; init; } = activeForUntargetable; diff --git a/BossMod/Components/ConcentricAOEs.cs b/BossMod/Components/ConcentricAOEs.cs index 49cafe4d9e..b0253fda17 100644 --- a/BossMod/Components/ConcentricAOEs.cs +++ b/BossMod/Components/ConcentricAOEs.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic 'concentric aoes' component - a sequence of aoes (typically cone then donuts) with same origin and increasing size -public abstract class ConcentricAOEs(BossModule module, AOEShape[] shapes) : GenericAOEs(module) +public class ConcentricAOEs(BossModule module, AOEShape[] shapes) : GenericAOEs(module) { public struct Sequence { diff --git a/BossMod/Components/DirectionalParry.cs b/BossMod/Components/DirectionalParry.cs index 03d31bb144..44ac75e002 100644 --- a/BossMod/Components/DirectionalParry.cs +++ b/BossMod/Components/DirectionalParry.cs @@ -2,7 +2,7 @@ // generic 'directional parry' component that shows actors and sides it's forbidden to attack them from // uses common status + custom prediction -public abstract class DirectionalParry(BossModule module, uint[] actorOID) : AddsMulti(module, actorOID) +public class DirectionalParry(BossModule module, uint[] actorOID) : AddsMulti(module, actorOID) { [Flags] public enum Side diff --git a/BossMod/Components/Exaflare.cs b/BossMod/Components/Exaflare.cs index 5cda215d0c..f63f4290d6 100644 --- a/BossMod/Components/Exaflare.cs +++ b/BossMod/Components/Exaflare.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic 'exaflare' component - these mechanics are a bunch of moving aoes, with different lines either staggered or moving with different speed -public abstract class Exaflare(BossModule module, AOEShape shape, ActionID aid = default) : GenericAOEs(module, aid, "GTFO from exaflare!") +public class Exaflare(BossModule module, AOEShape shape, ActionID aid = default) : GenericAOEs(module, aid, "GTFO from exaflare!") { public class Line { @@ -21,7 +21,7 @@ public class Line public bool Active => Lines.Count > 0; - protected Exaflare(BossModule module, float radius, ActionID aid = new()) : this(module, new AOEShapeCircle(radius), aid) { } + public Exaflare(BossModule module, float radius, ActionID aid = new()) : this(module, new AOEShapeCircle(radius), aid) { } public override IEnumerable ActiveAOEs(int slot, Actor actor) { diff --git a/BossMod/Components/ForcedMarch.cs b/BossMod/Components/ForcedMarch.cs index 8be25035cf..eb70ca239b 100644 --- a/BossMod/Components/ForcedMarch.cs +++ b/BossMod/Components/ForcedMarch.cs @@ -3,7 +3,7 @@ // generic component dealing with 'forced march' mechanics // these mechanics typically feature 'march left/right/forward/backward' debuffs, which rotate player and apply 'forced march' on expiration // if there are several active march debuffs, we assume they are chained together -public abstract class GenericForcedMarch(BossModule module, float activationLimit = float.MaxValue) : BossComponent(module) +public class GenericForcedMarch(BossModule module, float activationLimit = float.MaxValue) : BossComponent(module) { public class PlayerState { @@ -87,7 +87,7 @@ public void DeactivateForcedMovement(Actor player) } // typical forced march is driven by statuses -public abstract class StatusDrivenForcedMarch(BossModule module, float duration, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit) +public class StatusDrivenForcedMarch(BossModule module, float duration, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit) { public float Duration = duration; public readonly uint[] Statuses = [statusForward, statusLeft, statusBackward, statusRight, statusForced, statusForcedNPCs]; // 5 elements: fwd, left, back, right, forced, forcedNPCs @@ -121,7 +121,7 @@ public override void OnStatusLose(Actor actor, ActorStatus status) } // action driven forced march -public abstract class ActionDrivenForcedMarch(BossModule module, ActionID aid, float duration, Angle rotation, float actioneffectdelay, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit) +public class ActionDrivenForcedMarch(BossModule module, ActionID aid, float duration, Angle rotation, float actioneffectdelay, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit) { public float Duration = duration; public float Actioneffectdelay = actioneffectdelay; diff --git a/BossMod/Components/Gaze.cs b/BossMod/Components/Gaze.cs index 786228fc28..f402daa6e4 100644 --- a/BossMod/Components/Gaze.cs +++ b/BossMod/Components/Gaze.cs @@ -82,7 +82,7 @@ private Vector2 IndicatorScreenPos(WPos eye) } // gaze that happens on cast end -public abstract class CastGaze(BossModule module, ActionID aid, bool inverted = false, float range = 10000) : GenericGaze(module, aid, inverted) +public class CastGaze(BossModule module, ActionID aid, bool inverted = false, float range = 10000) : GenericGaze(module, aid, inverted) { public readonly List _casters = []; @@ -104,7 +104,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // cast weakpoint component: a number of casts (with supposedly non-intersecting shapes), player should face specific side determined by active status to the caster for aoe he's in -public abstract class CastWeakpoint(BossModule module, ActionID aid, AOEShape shape, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight) : GenericGaze(module, aid, true) +public class CastWeakpoint(BossModule module, ActionID aid, AOEShape shape, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight) : GenericGaze(module, aid, true) { public AOEShape Shape = shape; public readonly uint[] Statuses = [statusForward, statusLeft, statusBackward, statusRight]; // 4 elements: fwd, left, back, right diff --git a/BossMod/Components/GenericAOEs.cs b/BossMod/Components/GenericAOEs.cs index 6b816fb369..9b195024d8 100644 --- a/BossMod/Components/GenericAOEs.cs +++ b/BossMod/Components/GenericAOEs.cs @@ -33,7 +33,7 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) } // self-targeted aoe that happens at the end of the cast -public abstract class SelfTargetedAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue, uint color = 0) : GenericAOEs(module, aid) +public class SelfTargetedAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue, uint color = 0) : GenericAOEs(module, aid) { public AOEShape Shape { get; init; } = shape; public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless @@ -59,7 +59,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // self-targeted aoe that uses current caster's rotation instead of rotation from cast-info - used by legacy modules written before i've reversed real cast rotation -public abstract class SelfTargetedLegacyRotationAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid) +public class SelfTargetedLegacyRotationAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid) { public AOEShape Shape { get; init; } = shape; public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless @@ -83,7 +83,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // location-targeted circle aoe that happens at the end of the cast -public abstract class LocationTargetedAOEs(BossModule module, ActionID aid, float radius, int maxCasts = int.MaxValue) : GenericAOEs(module, aid) +public class LocationTargetedAOEs(BossModule module, ActionID aid, float radius, int maxCasts = int.MaxValue) : GenericAOEs(module, aid) { public AOEShapeCircle Shape { get; init; } = new(radius); public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless @@ -109,7 +109,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // location-targeted aoe component which supports shapes that aren't circles -public abstract class LocationTargetedAOEsOther(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid) +public class LocationTargetedAOEsOther(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid) { public AOEShape Shape { get; init; } = shape; public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless @@ -135,7 +135,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // 'charge at location' aoes that happen at the end of the cast -public abstract class ChargeAOEs(BossModule module, ActionID aid, float halfWidth) : GenericAOEs(module, aid) +public class ChargeAOEs(BossModule module, ActionID aid, float halfWidth) : GenericAOEs(module, aid) { public float HalfWidth { get; init; } = halfWidth; public readonly List<(Actor caster, AOEShape shape, Angle direction)> Casters = []; diff --git a/BossMod/Components/Knockback.cs b/BossMod/Components/Knockback.cs index cc60d84e39..38413a00a2 100644 --- a/BossMod/Components/Knockback.cs +++ b/BossMod/Components/Knockback.cs @@ -222,7 +222,7 @@ public override void OnStatusLose(Actor actor, ActorStatus status) // generic 'knockback from/attract to cast target' component // TODO: knockback is really applied when effectresult arrives rather than when actioneffect arrives, this is important for ai hints (they can reposition too early otherwise) -public abstract class KnockbackFromCastTarget(BossModule module, ActionID aid, float distance, bool ignoreImmunes = false, int maxCasts = int.MaxValue, AOEShape? shape = null, Kind kind = Kind.AwayFromOrigin, float minDistance = 0, bool minDistanceBetweenHitboxes = false, bool stopAtWall = false, bool stopAfterWall = false, IEnumerable? safeWalls = null) +public class KnockbackFromCastTarget(BossModule module, ActionID aid, float distance, bool ignoreImmunes = false, int maxCasts = int.MaxValue, AOEShape? shape = null, Kind kind = Kind.AwayFromOrigin, float minDistance = 0, bool minDistanceBetweenHitboxes = false, bool stopAtWall = false, bool stopAfterWall = false, IEnumerable? safeWalls = null) : Knockback(module, aid, ignoreImmunes, maxCasts, stopAtWall, stopAfterWall, safeWalls) { public float Distance = distance; diff --git a/BossMod/Components/PersistentVoidzone.cs b/BossMod/Components/PersistentVoidzone.cs index edd7ffcba0..7faf03040a 100644 --- a/BossMod/Components/PersistentVoidzone.cs +++ b/BossMod/Components/PersistentVoidzone.cs @@ -4,7 +4,7 @@ namespace BossMod.Components; // voidzone (circle aoe that stays active for some time) centered at each existing object with specified OID, assumed to be persistent voidzone center // for moving 'voidzones', the hints can mark the area in front of each source as dangerous // TODO: typically sources are either eventobj's with eventstate != 7 or normal actors that are non dead; other conditions are much rarer -public abstract class PersistentVoidzone(BossModule module, float radius, Func> sources, float moveHintLength = 0) : GenericAOEs(module, default, "GTFO from voidzone!") +public class PersistentVoidzone(BossModule module, float radius, Func> sources, float moveHintLength = 0) : GenericAOEs(module, default, "GTFO from voidzone!") { public AOEShape Shape { get; init; } = moveHintLength == 0 ? new AOEShapeCircle(radius) : new AOEShapeCapsule(radius, moveHintLength); public Func> Sources { get; init; } = sources; @@ -29,7 +29,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme // note that if voidzone is predicted by cast start rather than cast event, we have to account for possibility of cast finishing without event (e.g. if actor dies before cast finish) // TODO: this has problems when target moves - castevent and spawn position could be quite different // TODO: this has problems if voidzone never actually spawns after castevent, eg because of phase changes -public abstract class PersistentVoidzoneAtCastTarget(BossModule module, float radius, ActionID aid, Func> sources, float castEventToSpawn) : GenericAOEs(module, aid, "GTFO from voidzone!") +public class PersistentVoidzoneAtCastTarget(BossModule module, float radius, ActionID aid, Func> sources, float castEventToSpawn) : GenericAOEs(module, aid, "GTFO from voidzone!") { public AOEShapeCircle Shape { get; init; } = new(radius); public Func> Sources { get; init; } = sources; @@ -79,7 +79,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) // these are normal voidzones that could be 'inverted' (e.g. when you need to enter a voidzone at specific time to avoid some mechanic) // TODO: i'm not sure whether these should be considered actual voidzones (if so, should i merge them with base component? what about cast prediction?) or some completely other type of mechanic (maybe drawing differently) // TODO: might want to have per-player invertability -public abstract class PersistentInvertibleVoidzone(BossModule module, float radius, Func> sources, ActionID aid = default) : CastCounter(module, aid) +public class PersistentInvertibleVoidzone(BossModule module, float radius, Func> sources, ActionID aid = default) : CastCounter(module, aid) { public AOEShapeCircle Shape { get; init; } = new(radius); public Func> Sources { get; init; } = sources; @@ -120,7 +120,7 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) } // invertible voidzone that is inverted when specific spell is being cast; resolved when cast ends -public abstract class PersistentInvertibleVoidzoneByCast(BossModule module, float radius, Func> sources, ActionID aid) : PersistentInvertibleVoidzone(module, radius, sources, aid) +public class PersistentInvertibleVoidzoneByCast(BossModule module, float radius, Func> sources, ActionID aid) : PersistentInvertibleVoidzone(module, radius, sources, aid) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) { diff --git a/BossMod/Components/Protean.cs b/BossMod/Components/Protean.cs index 998120113e..60094a8460 100644 --- a/BossMod/Components/Protean.cs +++ b/BossMod/Components/Protean.cs @@ -32,7 +32,7 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) } // typical protean will originate from primary actor and hit all alive players -public abstract class SimpleProtean(BossModule module, ActionID aid, AOEShape shape) : GenericProtean(module, aid, shape) +public class SimpleProtean(BossModule module, ActionID aid, AOEShape shape) : GenericProtean(module, aid, shape) { public override IEnumerable<(Actor source, Actor target)> ActiveAOEs() => Raid.WithoutSlot().Select(p => (Module.PrimaryActor, p)); } diff --git a/BossMod/Components/RotatingAOE.cs b/BossMod/Components/RotatingAOE.cs index 56c4f45d1a..606bcb966a 100644 --- a/BossMod/Components/RotatingAOE.cs +++ b/BossMod/Components/RotatingAOE.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic 'rotating aoes' component - a sequence of aoes (typically cones) with same origin and increasing rotation -public abstract class GenericRotatingAOE(BossModule module) : GenericAOEs(module) +public class GenericRotatingAOE(BossModule module) : GenericAOEs(module) { public record struct Sequence ( diff --git a/BossMod/Components/SharedTankbuster.cs b/BossMod/Components/SharedTankbuster.cs index 599eca4af2..10140b289b 100644 --- a/BossMod/Components/SharedTankbuster.cs +++ b/BossMod/Components/SharedTankbuster.cs @@ -2,7 +2,7 @@ // generic 'shared tankbuster' component; assumes only 1 concurrent cast is active // TODO: revise and improve (track invuln, ai hints, num stacked tanks?) -public abstract class GenericSharedTankbuster(BossModule module, ActionID aid, AOEShape shape, bool originAtTarget = false) : CastCounter(module, aid) +public class GenericSharedTankbuster(BossModule module, ActionID aid, AOEShape shape, bool originAtTarget = false) : CastCounter(module, aid) { public AOEShape Shape { get; init; } = shape; public bool OriginAtTarget { get; init; } = originAtTarget; @@ -13,7 +13,7 @@ public abstract class GenericSharedTankbuster(BossModule module, ActionID aid, A public bool Active => Source != null; // circle shapes typically have origin at target - protected GenericSharedTankbuster(BossModule module, ActionID aid, float radius) : this(module, aid, new AOEShapeCircle(radius), true) { } + public GenericSharedTankbuster(BossModule module, ActionID aid, float radius) : this(module, aid, new AOEShapeCircle(radius), true) { } public override void AddHints(int slot, Actor actor, TextHints hints) { @@ -81,9 +81,9 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) } // shared tankbuster at cast target -public abstract class CastSharedTankbuster(BossModule module, ActionID aid, AOEShape shape, bool originAtTarget = false) : GenericSharedTankbuster(module, aid, shape, originAtTarget) +public class CastSharedTankbuster(BossModule module, ActionID aid, AOEShape shape, bool originAtTarget = false) : GenericSharedTankbuster(module, aid, shape, originAtTarget) { - protected CastSharedTankbuster(BossModule module, ActionID aid, float radius) : this(module, aid, new AOEShapeCircle(radius), true) { } + public CastSharedTankbuster(BossModule module, ActionID aid, float radius) : this(module, aid, new AOEShapeCircle(radius), true) { } public override void OnCastStarted(Actor caster, ActorCastInfo spell) { @@ -103,9 +103,9 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // shared tankbuster at icon -public abstract class IconSharedTankbuster(BossModule module, uint iconId, ActionID aid, AOEShape shape, float activationDelay = 5.1f, bool originAtTarget = false) : GenericSharedTankbuster(module, aid, shape, originAtTarget) +public class IconSharedTankbuster(BossModule module, uint iconId, ActionID aid, AOEShape shape, float activationDelay = 5.1f, bool originAtTarget = false) : GenericSharedTankbuster(module, aid, shape, originAtTarget) { - protected IconSharedTankbuster(BossModule module, uint iconId, ActionID aid, float radius, float activationDelay = 5.1f) : this(module, iconId, aid, new AOEShapeCircle(radius), activationDelay, true) { } + public IconSharedTankbuster(BossModule module, uint iconId, ActionID aid, float radius, float activationDelay = 5.1f) : this(module, iconId, aid, new AOEShapeCircle(radius), activationDelay, true) { } public virtual Actor? BaitSource(Actor target) => Module.PrimaryActor; diff --git a/BossMod/Components/StackSpread.cs b/BossMod/Components/StackSpread.cs index 6cd894a460..f501d6b204 100644 --- a/BossMod/Components/StackSpread.cs +++ b/BossMod/Components/StackSpread.cs @@ -210,7 +210,7 @@ public abstract class UniformStackSpread(BossModule module, float stackRadius, f } // spread/stack mechanic that selects targets by casts -public abstract class CastStackSpread(BossModule module, ActionID stackAID, ActionID spreadAID, float stackRadius, float spreadRadius, int minStackSize = 2, int maxStackSize = int.MaxValue, bool alwaysShowSpreads = false) +public class CastStackSpread(BossModule module, ActionID stackAID, ActionID spreadAID, float stackRadius, float spreadRadius, int minStackSize = 2, int maxStackSize = int.MaxValue, bool alwaysShowSpreads = false) : UniformStackSpread(module, stackRadius, spreadRadius, minStackSize, maxStackSize, alwaysShowSpreads) { public ActionID StackAction { get; init; } = stackAID; @@ -246,13 +246,13 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } // generic 'spread from targets of specific cast' mechanic -public abstract class SpreadFromCastTargets(BossModule module, ActionID aid, float radius, bool drawAllSpreads = true) : CastStackSpread(module, default, aid, 0, radius, alwaysShowSpreads: drawAllSpreads); +public class SpreadFromCastTargets(BossModule module, ActionID aid, float radius, bool drawAllSpreads = true) : CastStackSpread(module, default, aid, 0, radius, alwaysShowSpreads: drawAllSpreads); // generic 'stack with targets of specific cast' mechanic -public abstract class StackWithCastTargets(BossModule module, ActionID aid, float radius, int minStackSize = 2, int maxStackSize = int.MaxValue) : CastStackSpread(module, aid, default, radius, 0, minStackSize, maxStackSize); +public class StackWithCastTargets(BossModule module, ActionID aid, float radius, int minStackSize = 2, int maxStackSize = int.MaxValue) : CastStackSpread(module, aid, default, radius, 0, minStackSize, maxStackSize); // spread/stack mechanic that selects targets by icon and finishes by cast event -public abstract class IconStackSpread(BossModule module, uint stackIcon, uint spreadIcon, ActionID stackAID, ActionID spreadAID, float stackRadius, float spreadRadius, float activationDelay, int minStackSize = 2, int maxStackSize = int.MaxValue, bool alwaysShowSpreads = false, int maxCasts = 1) +public class IconStackSpread(BossModule module, uint stackIcon, uint spreadIcon, ActionID stackAID, ActionID spreadAID, float stackRadius, float spreadRadius, float activationDelay, int minStackSize = 2, int maxStackSize = int.MaxValue, bool alwaysShowSpreads = false, int maxCasts = 1) : UniformStackSpread(module, stackRadius, spreadRadius, minStackSize, maxStackSize, alwaysShowSpreads) { public uint StackIcon { get; init; } = stackIcon; @@ -299,14 +299,14 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } // generic 'spread from actors with specific icon' mechanic -public abstract class SpreadFromIcon(BossModule module, uint icon, ActionID aid, float radius, float activationDelay, bool drawAllSpreads = true) : IconStackSpread(module, 0, icon, default, aid, 0, radius, activationDelay, alwaysShowSpreads: drawAllSpreads); +public class SpreadFromIcon(BossModule module, uint icon, ActionID aid, float radius, float activationDelay, bool drawAllSpreads = true) : IconStackSpread(module, 0, icon, default, aid, 0, radius, activationDelay, alwaysShowSpreads: drawAllSpreads); // generic 'stack with actors with specific icon' mechanic -public abstract class StackWithIcon(BossModule module, uint icon, ActionID aid, float radius, float activationDelay, int minStackSize = 2, int maxStackSize = int.MaxValue, int maxCasts = 1) : IconStackSpread(module, icon, 0, aid, default, radius, 0, activationDelay, minStackSize, maxStackSize, false, maxCasts); +public class StackWithIcon(BossModule module, uint icon, ActionID aid, float radius, float activationDelay, int minStackSize = 2, int maxStackSize = int.MaxValue, int maxCasts = 1) : IconStackSpread(module, icon, 0, aid, default, radius, 0, activationDelay, minStackSize, maxStackSize, false, maxCasts); // generic single hit "line stack" component, usually do not have an iconID, instead players get marked by cast event // usually these have 50 range and 4 halfWidth, but it can be modified -public abstract class LineStack(BossModule module, ActionID aidMarker, ActionID aidResolve, float activationDelay, float range = 50, float halfWidth = 4, int minStackSize = 4, int maxStackSize = int.MaxValue, int maxCasts = 1, bool markerIsFinalTarget = true) : GenericBaitAway(module) +public class LineStack(BossModule module, ActionID aidMarker, ActionID aidResolve, float activationDelay, float range = 50, float halfWidth = 4, int minStackSize = 4, int maxStackSize = int.MaxValue, int maxCasts = 1, bool markerIsFinalTarget = true) : GenericBaitAway(module) { // TODO: add forbidden slots logic? // TODO: add logic for min and max stack size @@ -426,7 +426,7 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) { } } // generic 'donut stack' mechanic -public abstract class DonutStack(BossModule module, ActionID aid, uint icon, float innerRadius, float outerRadius, float activationDelay, int minStackSize = 2, int maxStackSize = int.MaxValue) : UniformStackSpread(module, innerRadius / 3, default, minStackSize, maxStackSize) +public class DonutStack(BossModule module, ActionID aid, uint icon, float innerRadius, float outerRadius, float activationDelay, int minStackSize = 2, int maxStackSize = int.MaxValue) : UniformStackSpread(module, innerRadius / 3, default, minStackSize, maxStackSize) { // this is a donut targeted on each player, it is best solved by stacking // regular stack component won't work because this is self targeted diff --git a/BossMod/Components/StayInBounds.cs b/BossMod/Components/StayInBounds.cs index 87c9811abd..5cfa410358 100644 --- a/BossMod/Components/StayInBounds.cs +++ b/BossMod/Components/StayInBounds.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // component that forces the AI to stay in bounds or return inside (for example after a failed knockback) -public abstract class StayInBounds(BossModule module) : BossComponent(module) +public class StayInBounds(BossModule module) : BossComponent(module) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { diff --git a/BossMod/Components/StayMove.cs b/BossMod/Components/StayMove.cs index 9353af4197..a0c45db604 100644 --- a/BossMod/Components/StayMove.cs +++ b/BossMod/Components/StayMove.cs @@ -2,7 +2,7 @@ // component for mechanics that either require players to move or stay still // priorities can be used to simplify implementation when e.g. status changes at different stages of the mechanic (eg if prep status is replaced with pyretic, we want to allow them to happen in any sequence) -public abstract class StayMove(BossModule module, float maxTimeToShowHint = float.PositiveInfinity) : BossComponent(module) +public class StayMove(BossModule module, float maxTimeToShowHint = float.PositiveInfinity) : BossComponent(module) { public enum Requirement { None, Stay, Move } public record struct PlayerState(Requirement Requirement, DateTime Activation, int Priority = 0); diff --git a/BossMod/Components/TankSwap.cs b/BossMod/Components/TankSwap.cs index 88bfef3b44..e011060146 100644 --- a/BossMod/Components/TankSwap.cs +++ b/BossMod/Components/TankSwap.cs @@ -3,7 +3,7 @@ // generic tank-swap component for multi-hit tankbusters, with optional aoe // assume that target of the first hit is locked when mechanic starts, then subsequent targets are selected based on who the boss targets // TODO: this version assumes that boss cast and first-hit are potentially from different actors; the target lock could also be things like icons, etc - generalize more... -public abstract class TankSwap(BossModule module, ActionID bossCast, ActionID firstCast, ActionID subsequentHit, float timeBetweenHits, AOEShape? shape, bool centerAtTarget) : GenericBaitAway(module, centerAtTarget: centerAtTarget) +public class TankSwap(BossModule module, ActionID bossCast, ActionID firstCast, ActionID subsequentHit, float timeBetweenHits, AOEShape? shape, bool centerAtTarget) : GenericBaitAway(module, centerAtTarget: centerAtTarget) { private Actor? _source; private ulong _prevTarget; // before first cast, this is the target of the first hit diff --git a/BossMod/Components/Tethers.cs b/BossMod/Components/Tethers.cs index 29a14889e7..a9afb378a9 100644 --- a/BossMod/Components/Tethers.cs +++ b/BossMod/Components/Tethers.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic component for tankbuster at tethered targets; tanks are supposed to intercept tethers and gtfo from the raid -public abstract class TankbusterTether(BossModule module, ActionID aid, uint tetherID, float radius) : CastCounter(module, aid) +public class TankbusterTether(BossModule module, ActionID aid, uint tetherID, float radius) : CastCounter(module, aid) { public uint TID { get; init; } = tetherID; public float Radius { get; init; } = radius; @@ -123,7 +123,7 @@ public override void OnUntethered(Actor source, ActorTetherInfo tether) } // generic component for tethers that need to be intercepted eg. to prevent a boss from gaining buffs -public abstract class InterceptTether(BossModule module, ActionID aid, uint tetherID) : CastCounter(module, aid) +public class InterceptTether(BossModule module, ActionID aid, uint tetherID) : CastCounter(module, aid) { public uint TID { get; init; } = tetherID; private readonly List<(Actor Player, Actor Enemy)> _tethers = []; @@ -185,7 +185,7 @@ public override void OnUntethered(Actor source, ActorTetherInfo tether) // generic component for tethers that need to be stretched and switch between a "good" and "bad" tether // at the end of the mechanic various things are possible, eg. single target dmg, knockback/pull, AOE etc. -public abstract class StretchTetherDuo(BossModule module, float minimumDistance, float activationDelay, uint tetherIDBad = 57, uint tetherIDGood = 1, AOEShape? shape = null, ActionID aid = default, uint enemyOID = default, bool knockbackImmunity = false) : GenericBaitAway(module, aid) +public class StretchTetherDuo(BossModule module, float minimumDistance, float activationDelay, uint tetherIDBad = 57, uint tetherIDGood = 1, AOEShape? shape = null, ActionID aid = default, uint enemyOID = default, bool knockbackImmunity = false) : GenericBaitAway(module, aid) { public AOEShape? Shape = shape; public uint TIDGood = tetherIDGood; @@ -370,7 +370,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme } // generic component for tethers that need to be stretched -public abstract class StretchTetherSingle(BossModule module, uint tetherID, float minimumDistance, AOEShape? shape = null, ActionID aid = default, uint enemyOID = default, float activationDelay = default, bool knockbackImmunity = false, bool needToKite = false) : +public class StretchTetherSingle(BossModule module, uint tetherID, float minimumDistance, AOEShape? shape = null, ActionID aid = default, uint enemyOID = default, float activationDelay = default, bool knockbackImmunity = false, bool needToKite = false) : StretchTetherDuo(module, minimumDistance, activationDelay, tetherID, tetherID, shape, aid, enemyOID, knockbackImmunity) { public override void AddHints(int slot, Actor actor, TextHints hints) diff --git a/BossMod/Components/Towers.cs b/BossMod/Components/Towers.cs index 89ff1da111..9108626055 100644 --- a/BossMod/Components/Towers.cs +++ b/BossMod/Components/Towers.cs @@ -1,6 +1,6 @@ namespace BossMod.Components; -public abstract class GenericTowers(BossModule module, ActionID aid = default) : CastCounter(module, aid) +public class GenericTowers(BossModule module, ActionID aid = default) : CastCounter(module, aid) { public struct Tower(WPos position, float radius, int minSoakers = 1, int maxSoakers = 1, BitMask forbiddenSoakers = default, DateTime activation = default) { @@ -91,7 +91,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme } } -public abstract class CastTowers(BossModule module, ActionID aid, float radius, int minSoakers = 1, int maxSoakers = 1) : GenericTowers(module, aid) +public class CastTowers(BossModule module, ActionID aid, float radius, int minSoakers = 1, int maxSoakers = 1) : GenericTowers(module, aid) { public float Radius = radius; public int MinSoakers = minSoakers; diff --git a/BossMod/Components/Twister.cs b/BossMod/Components/Twister.cs index 6c12dbb589..586742ad1b 100644 --- a/BossMod/Components/Twister.cs +++ b/BossMod/Components/Twister.cs @@ -2,7 +2,7 @@ // generic 'twister' component: a set of aoes that appear under players, but can't be accurately predicted until it's too late // normally you'd predict them at the end (or slightly before the end) of some cast, or on component creation -public abstract class GenericTwister(BossModule module, float radius, uint oid, ActionID aid = default) : GenericAOEs(module, aid, "GTFO from twister!") +public class GenericTwister(BossModule module, float radius, uint oid, ActionID aid = default) : GenericAOEs(module, aid, "GTFO from twister!") { private readonly AOEShapeCircle _shape = new(radius); private readonly uint _twisterOID = oid; @@ -36,16 +36,16 @@ public override void OnActorCreated(Actor actor) } // twister that activates immediately on init -public abstract class ImmediateTwister : GenericTwister +public class ImmediateTwister : GenericTwister { - protected ImmediateTwister(BossModule module, float radius, uint oid, float activationDelay) : base(module, radius, oid) + public ImmediateTwister(BossModule module, float radius, uint oid, float activationDelay) : base(module, radius, oid) { AddPredicted(activationDelay); } } // twister that activates on cast end, or slightly before -public abstract class CastTwister(BossModule module, float radius, uint oid, ActionID aid, float activationDelay, float predictBeforeCastEnd = 0) : GenericTwister(module, radius, oid, aid) +public class CastTwister(BossModule module, float radius, uint oid, ActionID aid, float activationDelay, float predictBeforeCastEnd = 0) : GenericTwister(module, radius, oid, aid) { private readonly float _activationDelay = activationDelay; // from cast-end to twister spawn private readonly float _predictBeforeCastEnd = predictBeforeCastEnd; diff --git a/BossMod/Components/UnavoidableDamage.cs b/BossMod/Components/UnavoidableDamage.cs index 017592ab6c..f3f7efe5ab 100644 --- a/BossMod/Components/UnavoidableDamage.cs +++ b/BossMod/Components/UnavoidableDamage.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic unavoidable raidwide, started and finished by a single cast -public abstract class RaidwideCast(BossModule module, ActionID aid, string hint = "Raidwide") : CastHint(module, aid, hint) +public class RaidwideCast(BossModule module, ActionID aid, string hint = "Raidwide") : CastHint(module, aid, hint) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { @@ -11,7 +11,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme } // generic unavoidable raidwide, initiated by a custom condition and applied by an instant cast after a delay -public abstract class RaidwideInstant(BossModule module, ActionID aid, float delay, string hint = "Raidwide") : CastCounter(module, aid) +public class RaidwideInstant(BossModule module, ActionID aid, float delay, string hint = "Raidwide") : CastCounter(module, aid) { public float Delay = delay; public string Hint = hint; @@ -40,7 +40,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } // generic unavoidable instant raidwide initiated by a cast (usually visual-only) -public abstract class RaidwideCastDelay(BossModule module, ActionID actionVisual, ActionID actionAOE, float delay, string hint = "Raidwide") : RaidwideInstant(module, actionAOE, delay, hint) +public class RaidwideCastDelay(BossModule module, ActionID actionVisual, ActionID actionAOE, float delay, string hint = "Raidwide") : RaidwideInstant(module, actionAOE, delay, hint) { public ActionID ActionVisual = actionVisual; @@ -52,7 +52,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) } // generic unavoidable instant raidwide cast initiated by NPC yell -public abstract class RaidwideAfterNPCYell(BossModule module, ActionID aid, uint npcYellID, float delay, string hint = "Raidwide") : RaidwideInstant(module, aid, delay, hint) +public class RaidwideAfterNPCYell(BossModule module, ActionID aid, uint npcYellID, float delay, string hint = "Raidwide") : RaidwideInstant(module, aid, delay, hint) { public uint NPCYellID = npcYellID; @@ -64,7 +64,7 @@ public override void OnActorNpcYell(Actor actor, ushort id) } // generic unavoidable single-target damage, started and finished by a single cast (typically tankbuster, but not necessary) -public abstract class SingleTargetCast(BossModule module, ActionID aid, string hint = "Tankbuster") : CastHint(module, aid, hint) +public class SingleTargetCast(BossModule module, ActionID aid, string hint = "Tankbuster") : CastHint(module, aid, hint) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { @@ -80,7 +80,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme } // generic unavoidable single-target damage, initiated by a custom condition and applied by an instant cast after a delay -public abstract class SingleTargetInstant(BossModule module, ActionID aid, float delay, string hint = "Tankbuster") : CastCounter(module, aid) +public class SingleTargetInstant(BossModule module, ActionID aid, float delay, string hint = "Tankbuster") : CastCounter(module, aid) { public float Delay = delay; // delay from visual cast end to cast event public string Hint = hint; @@ -109,7 +109,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } // generic unavoidable instant single-target damage initiated by a cast (usually visual-only) -public abstract class SingleTargetCastDelay(BossModule module, ActionID actionVisual, ActionID actionAOE, float delay, string hint = "Tankbuster") : SingleTargetInstant(module, actionAOE, delay, hint) +public class SingleTargetCastDelay(BossModule module, ActionID actionVisual, ActionID actionAOE, float delay, string hint = "Tankbuster") : SingleTargetInstant(module, actionAOE, delay, hint) { public ActionID ActionVisual = actionVisual; @@ -124,7 +124,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) } // generic unavoidable instant single-target damage initiated by a cast (usually visual-only) -public abstract class SingleTargetEventDelay(BossModule module, ActionID actionVisual, ActionID actionAOE, float delay, string hint = "Tankbuster") : SingleTargetInstant(module, actionAOE, delay, hint) +public class SingleTargetEventDelay(BossModule module, ActionID actionVisual, ActionID actionAOE, float delay, string hint = "Tankbuster") : SingleTargetInstant(module, actionAOE, delay, hint) { public ActionID ActionVisual = actionVisual; @@ -140,4 +140,4 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } // generic unavoidable single-target damage, started and finished by a single cast, that can be delayed by moving out of range (typically tankbuster, but not necessary) -public abstract class SingleTargetDelayableCast(BossModule module, ActionID aid, string hint = "Tankbuster") : SingleTargetCastDelay(module, aid, aid, 0, hint); +public class SingleTargetDelayableCast(BossModule module, ActionID aid, string hint = "Tankbuster") : SingleTargetCastDelay(module, aid, aid, 0, hint); diff --git a/BossMod/Components/WildCharge.cs b/BossMod/Components/WildCharge.cs index 39c2de20ef..7518d32d23 100644 --- a/BossMod/Components/WildCharge.cs +++ b/BossMod/Components/WildCharge.cs @@ -1,7 +1,7 @@ namespace BossMod.Components; // generic 'wild charge': various mechanics that consist of charge aoe on some target that other players have to stay in; optionally some players can be marked as 'having to be closest to source' (usually tanks) -public abstract class GenericWildCharge(BossModule module, float halfWidth, ActionID aid = default, float fixedLength = 0) : CastCounter(module, aid) +public class GenericWildCharge(BossModule module, float halfWidth, ActionID aid = default, float fixedLength = 0) : CastCounter(module, aid) { public enum PlayerRole { diff --git a/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D022Kahderyor.cs b/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D022Kahderyor.cs index 1c1df0dfaa..35bbe25db9 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D022Kahderyor.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D022Kahderyor.cs @@ -176,7 +176,7 @@ public D022KahderyorStates(BossModule module) : base(module) public class D022Kahderyor(WorldState ws, Actor primary) : BossModule(ws, primary, DefaultBounds.Center, DefaultBounds) { private static readonly WPos arenaCenter = new(-53, -57); - public static readonly ArenaBoundsComplex DefaultBounds = new([new Circle(arenaCenter, 19.5f)], [new Rectangle(new(-72.5f, -57), 20, 0.75f, 90.Degrees()), new Rectangle(arenaCenter, 20, 1.5f)]); + public static readonly ArenaBoundsComplex DefaultBounds = new([new Circle(arenaCenter, 19.5f)], [new Rectangle(new(-72.5f, -57), 20, 0.75f, 90.Degrees()), new Rectangle(new(-53, -37), 20, 1.5f)]); protected override void DrawEnemies(int pcSlot, Actor pc) {