Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Paglth'an modules #516

Merged
merged 1 commit into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions BossMod/Components/BaitAway.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class GenericBaitAway(BossModule module, ActionID aid = default, bool alw
{
public record struct Bait(Actor Source, Actor Target, AOEShape Shape, DateTime Activation = default)
{
public Angle? CustomRotation { get; init; }
public Angle? CustomRotation;

public readonly Angle Rotation => CustomRotation ?? (Source != Target ? Angle.FromDirection(Target.Position - Source.Position) : Source.Rotation);

Expand All @@ -18,8 +18,8 @@ public Bait(Actor source, Actor target, AOEShape shape, DateTime activation, Ang
}
}

public bool AlwaysDrawOtherBaits = alwaysDrawOtherBaits; // if false, other baits are drawn only if they are clipping a player
public bool CenterAtTarget = centerAtTarget; // if true, aoe source is at target
public readonly bool AlwaysDrawOtherBaits = alwaysDrawOtherBaits; // if false, other baits are drawn only if they are clipping a player
public readonly bool CenterAtTarget = centerAtTarget; // if true, aoe source is at target
public bool AllowDeadTargets = true; // if false, baits with dead targets are ignored
public bool EnableHints = true;
public bool IgnoreOtherBaits; // if true, don't show hints/aoes for baits by others
Expand Down Expand Up @@ -81,7 +81,6 @@ private void AddTargetSpecificHints(Actor actor, Bait bait, AIHints hints)
case AOEShapeCone cone:
hints.AddForbiddenZone(ShapeDistance.Cone(bait.Source.Position, 100, bait.Source.AngleTo(a), cone.HalfAngle), bait.Activation);
break;

case AOEShapeRect rect:
hints.AddForbiddenZone(ShapeDistance.Cone(bait.Source.Position, 100, bait.Source.AngleTo(a), Angle.Asin(rect.HalfWidth / (a.Position - bait.Source.Position).Length())), bait.Activation);
break;
Expand Down
8 changes: 4 additions & 4 deletions BossMod/Components/CastCounter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// generic component that counts specified casts
public class CastCounter(BossModule module, ActionID aid) : BossComponent(module)
{
public ActionID WatchedAction { get; private set; } = aid;
public int NumCasts { get; protected set; }
public readonly ActionID WatchedAction = aid;
public int NumCasts;

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
Expand All @@ -15,8 +15,8 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell)

public class CastCounterMulti(BossModule module, ActionID[] aids) : BossComponent(module)
{
public ActionID[] WatchedActions = aids;
public int NumCasts { get; protected set; }
public readonly ActionID[] WatchedActions = aids;
public int NumCasts;

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
Expand Down
10 changes: 5 additions & 5 deletions BossMod/Components/CastHint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace BossMod.Components;
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
public readonly bool ShowCastTimeLeft = showCastTimeLeft; // if true, show cast time left until next instance
public readonly List<Actor> Casters = [];

public bool Active => Casters.Count > 0;
Expand All @@ -30,10 +30,10 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)

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; }
public readonly bool CanBeInterrupted;
public readonly bool CanBeStunned;
public readonly bool ShowNameInHint; // important if there are several targets
public readonly string HintExtra;

public CastInterruptHint(BossModule module, ActionID aid, bool canBeInterrupted = true, bool canBeStunned = false, string hintExtra = "", bool showNameInHint = false) : base(module, aid, "")
{
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/Chains.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ 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 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; }
public readonly uint TID = tetherID;
public bool TethersAssigned;
private readonly Actor?[] _partner = new Actor?[PartyState.MaxAllies];

public override void AddHints(int slot, Actor actor, TextHints hints)
Expand Down
16 changes: 8 additions & 8 deletions BossMod/Components/ChasingAOEs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,16 @@ 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 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;
public ActionID ActionRest = actionRest;
public float MoveDistance = moveDistance;
public float SecondsBetweenActivations = secondsBetweenActivations;
public readonly AOEShape Shape = shape;
public readonly ActionID ActionFirst = actionFirst;
public readonly ActionID ActionRest = actionRest;
public readonly float MoveDistance = moveDistance;
public readonly float SecondsBetweenActivations = secondsBetweenActivations;
public int MaxCasts = maxCasts;
public BitMask ExcludedTargets; // any targets in this mask aren't considered to be possible targets
public uint Icon = icon;
public float ActivationDelay = activationDelay;
public bool ResetExcludedTargets = resetExcludedTargets;
public readonly uint Icon = icon;
public readonly float ActivationDelay = activationDelay;
public readonly bool ResetExcludedTargets = resetExcludedTargets;
public readonly List<Actor> Actors = []; // to keep track of the icon before mechanic starts for handling custom forbidden zones
public DateTime Activation;

Expand Down
8 changes: 4 additions & 4 deletions BossMod/Components/Cleave.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
// enemy OID == 0 means 'primary actor'
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;
public bool ActiveWhileCasting { get; init; } = activeWhileCasting;
public bool OriginAtTarget { get; init; } = originAtTarget;
public readonly AOEShape Shape = shape;
public readonly bool ActiveForUntargetable = activeForUntargetable;
public readonly bool ActiveWhileCasting = activeWhileCasting;
public readonly bool OriginAtTarget = originAtTarget;
public DateTime NextExpected;
private readonly List<Actor> _enemies = module.Enemies(enemyOID != 0 ? enemyOID : module.PrimaryActor.OID);

Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/ConcentricAOEs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public struct Sequence
public int NumCastsDone;
}

public AOEShape[] Shapes = shapes;
public List<Sequence> Sequences = [];
public readonly AOEShape[] Shapes = shapes;
public readonly List<Sequence> Sequences = [];

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Sequences.Where(s => s.NumCastsDone < Shapes.Length).Select(s => new AOEInstance(Shapes[s.NumCastsDone], s.Origin, s.Rotation, s.NextActivation));

Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/Exaflare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ public class Line
public int MaxShownExplosions;
}

public AOEShape Shape { get; init; } = shape;
public readonly AOEShape Shape = shape;
public uint ImminentColor = Colors.Danger;
public uint FutureColor = Colors.AOE;
protected List<Line> Lines = [];
protected readonly List<Line> Lines = [];

public bool Active => Lines.Count > 0;

Expand Down
18 changes: 9 additions & 9 deletions BossMod/Components/ForcedMarch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ public class PlayerState
public bool Active(BossModule module) => ForcedEnd > module.WorldState.CurrentTime || PendingMoves.Count > 0;
}

public int NumActiveForcedMarches { get; private set; }
public Dictionary<ulong, PlayerState> State = []; // key = instance ID
public int NumActiveForcedMarches;
public readonly Dictionary<ulong, PlayerState> State = []; // key = instance ID
public float MovementSpeed = 6; // default movement speed, can be overridden if necessary
public float ActivationLimit = activationLimit; // do not show pending moves that activate later than this limit
public readonly float ActivationLimit = activationLimit; // do not show pending moves that activate later than this limit

// called to determine whether we need to show hint
public virtual bool DestinationUnsafe(int slot, Actor actor, WPos pos) => !Module.InBounds(pos);
Expand Down Expand Up @@ -123,12 +123,12 @@ public override void OnStatusLose(Actor actor, ActorStatus status)
// action driven forced march
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;
public Angle Rotation = rotation;
public uint StatusForced = statusForced;
public uint StatusForcedNPCs = statusForcedNPCs;
public ActionID Aid = aid;
public readonly float Duration = duration;
public readonly float Actioneffectdelay = actioneffectdelay;
public readonly Angle Rotation = rotation;
public readonly uint StatusForced = statusForced;
public readonly uint StatusForcedNPCs = statusForcedNPCs;
public readonly ActionID Aid = aid;

public override void OnStatusGain(Actor actor, ActorStatus status)
{
Expand Down
54 changes: 44 additions & 10 deletions BossMod/Components/GenericAOEs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,29 @@ public override void DrawArenaBackground(int pcSlot, Actor pc)
// self-targeted aoe that happens at the end of the cast
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 readonly AOEShape Shape = shape;
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
public uint Color = color;
public bool Risky = true; // can be customized if needed
public readonly List<Actor> Casters = [];

public IEnumerable<Actor> ActiveCasters => Casters.Take(MaxCasts);

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => ActiveCasters.Select(c => new AOEInstance(Shape, c.Position, c.CastInfo!.Rotation, Module.CastFinishAt(c.CastInfo)));
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var count = Casters.Count;
if (count == 0)
return [];
var min = count > MaxCasts ? MaxCasts : count;
var aoes = new List<AOEInstance>(min);
for (var i = 0; i < min; ++i)
{
var caster = Casters[i];
AOEInstance aoeInstance = new(Shape, caster.Position, caster.CastInfo!.Rotation, Module.CastFinishAt(caster.CastInfo));
aoes.Add(aoeInstance);
}
return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
Expand All @@ -61,7 +75,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 class SelfTargetedLegacyRotationAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
{
public AOEShape Shape { get; init; } = shape;
public readonly AOEShape Shape = shape;
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
public readonly List<Actor> Casters = [];

Expand All @@ -86,16 +100,23 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
public class LocationTargetedAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue, bool targetIsLocation = false) : GenericAOEs(module, aid)
{
public LocationTargetedAOEs(BossModule module, ActionID aid, float radius, int maxCasts = int.MaxValue, bool targetIsLocation = false) : this(module, aid, new AOEShapeCircle(radius), maxCasts, targetIsLocation) { }
public AOEShape Shape { get; init; } = shape;
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
public readonly AOEShape Shape = shape;
public readonly int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
public uint Color; // can be customized if needed
public bool Risky = true; // can be customized if needed
public bool TargetIsLocation { get; init; } = targetIsLocation; // can be customized if needed
public readonly bool TargetIsLocation = targetIsLocation; // can be customized if needed

public List<AOEInstance> Casters { get; } = [];
public readonly List<AOEInstance> Casters = [];
public IEnumerable<AOEInstance> ActiveCasters => Casters.Take(MaxCasts);

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Casters.Take(MaxCasts);
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var count = Casters.Count;
if (count == 0)
yield break;
for (var i = 0; i < (count > MaxCasts ? MaxCasts : count); ++i)
yield return Casters[i];
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
Expand All @@ -116,10 +137,23 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
// 'charge at location' aoes that happen at the end of the cast
public class ChargeAOEs(BossModule module, ActionID aid, float halfWidth) : GenericAOEs(module, aid)
{
public float HalfWidth { get; init; } = halfWidth;
public readonly float HalfWidth = halfWidth;
public readonly List<(Actor caster, AOEShape shape, Angle direction)> Casters = [];

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Casters.Select(csr => new AOEInstance(csr.shape, csr.caster.Position, csr.direction, Module.CastFinishAt(csr.caster.CastInfo)));
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var count = Casters.Count;
if (count == 0)
return [];
var aoes = new List<AOEInstance>(count);
for (var i = 0; i < count; ++i)
{
var csr = Casters[i];
AOEInstance aoeInstance = new(csr.shape, csr.caster.Position, csr.direction, Module.CastFinishAt(csr.caster.CastInfo));
aoes.Add(aoeInstance);
}
return aoes;
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
Expand Down
22 changes: 11 additions & 11 deletions BossMod/Components/Knockback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ protected struct PlayerImmuneState
public readonly bool ImmuneAt(DateTime time) => RoleBuffExpire > time || JobBuffExpire > time || DutyBuffExpire > time;
}

public List<SafeWall> SafeWalls = safeWalls ?? [];
public bool IgnoreImmunes = ignoreImmunes;
public bool StopAtWall = stopAtWall; // use if wall is solid rather than deadly
public bool StopAfterWall = stopAfterWall; // use if the wall is a polygon where you need to check for intersections
public int MaxCasts = maxCasts; // use to limit number of drawn knockbacks
public readonly List<SafeWall> SafeWalls = safeWalls ?? [];
public readonly bool IgnoreImmunes = ignoreImmunes;
public readonly bool StopAtWall = stopAtWall; // use if wall is solid rather than deadly
public readonly bool StopAfterWall = stopAfterWall; // use if the wall is a polygon where you need to check for intersections
public readonly int MaxCasts = maxCasts; // use to limit number of drawn knockbacks
private const float approxHitBoxRadius = 0.499f; // calculated because due to floating point errors this does not result in 0.001
private const float maxIntersectionError = 0.5f - approxHitBoxRadius; // calculated because due to floating point errors this does not result in 0.001

protected PlayerImmuneState[] PlayerImmunes = new PlayerImmuneState[PartyState.MaxAllies];
protected readonly PlayerImmuneState[] PlayerImmunes = new PlayerImmuneState[PartyState.MaxAllies];

public bool IsImmune(int slot, DateTime time) => !IgnoreImmunes && PlayerImmunes[slot].ImmuneAt(time);

Expand Down Expand Up @@ -225,11 +225,11 @@ public override void OnStatusLose(Actor actor, ActorStatus status)
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, List<SafeWall>? safeWalls = null)
: Knockback(module, aid, ignoreImmunes, maxCasts, stopAtWall, stopAfterWall, safeWalls)
{
public float Distance = distance;
public AOEShape? Shape = shape;
public Kind KnockbackKind = kind;
public float MinDistance = minDistance;
public bool MinDistanceBetweenHitboxes = minDistanceBetweenHitboxes;
public readonly float Distance = distance;
public readonly AOEShape? Shape = shape;
public readonly Kind KnockbackKind = kind;
public readonly float MinDistance = minDistance;
public readonly bool MinDistanceBetweenHitboxes = minDistanceBetweenHitboxes;
public readonly List<Actor> Casters = [];

public override IEnumerable<Source> Sources(int slot, Actor actor)
Expand Down
Loading