Skip to content

Commit

Permalink
some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Feb 10, 2025
1 parent eb6209a commit 1be826b
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 125 deletions.
9 changes: 5 additions & 4 deletions BossMod/Components/ChasingAOEs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public WPos PredictedPosition()
{
var offset = Target.Position - PrevPos;
var distance = offset.Length();
return distance > MoveDist ? PrevPos + MoveDist * offset / distance : Target.Position;
var pos = distance > MoveDist ? PrevPos + MoveDist * offset / distance : Target.Position;
return WPos.ClampToGrid(pos);
}
}

Expand Down Expand Up @@ -111,7 +112,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if (spell.Action == ActionFirst)
{
var pos = spell.TargetID == caster.InstanceID ? caster.Position : WorldState.Actors.Find(spell.TargetID)?.Position ?? spell.LocXZ;
var pos = spell.LocXZ;
var (slot, target) = Raid.WithSlot().ExcludedFromMask(ExcludedTargets).MinBy(ip => (ip.Item2.Position - pos).LengthSq());
if (target != null)
{
Expand All @@ -127,7 +128,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell)
if (spell.Action == ActionFirst || spell.Action == ActionRest)
{
var pos = spell.MainTargetID == caster.InstanceID ? caster.Position : WorldState.Actors.Find(spell.MainTargetID)?.Position ?? spell.TargetXZ;
Advance(pos, MoveDistance, WorldState.CurrentTime);
Advance(WPos.ClampToGrid(pos), MoveDistance, WorldState.CurrentTime);
if (Chasers.Count == 0 && ResetExcludedTargets)
{
ExcludedTargets.Reset();
Expand Down Expand Up @@ -185,7 +186,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell)
if (spell.Action == ActionFirst || spell.Action == ActionRest)
{
var pos = spell.MainTargetID == caster.InstanceID ? caster.Position : WorldState.Actors.Find(spell.MainTargetID)?.Position ?? spell.TargetXZ;
Advance(pos, MoveDistance, WorldState.CurrentTime);
Advance(WPos.ClampToGrid(pos), MoveDistance, WorldState.CurrentTime);
if (Chasers.Count == 0 && ResetExcludedTargets)
{
ExcludedTargets.Clear();
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/Exaflare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
var l = Lines[i];
if (l.ExplosionsLeft != 0)
exas[i] = (l.Next, l.NextExplosion, l.Rotation);
exas[i] = (WPos.ClampToGrid(l.Next), l.NextExplosion, l.Rotation);
}
return exas;
}
Expand All @@ -73,7 +73,7 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
pos += l.Advance;
time = time.AddSeconds(l.TimeToMove);
exas.Add((pos, time, l.Rotation));
exas.Add((WPos.ClampToGrid(pos), time, l.Rotation));
}
}
return exas;
Expand Down
30 changes: 20 additions & 10 deletions BossMod/Components/Gaze.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public record struct Eye(
WPos Position,
DateTime Activation = new(),
Angle Forward = new(), // if non-zero, treat specified side as 'forward' for hit calculations
float Range = 10000);
float Range = 10000,
ulong? ActorID = null);

public bool Inverted = inverted; // if inverted, player should face eyes instead of averting

Expand All @@ -35,12 +36,12 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
if (Inverted)
{
foreach (var eye in ActiveEyes(slot, actor).Where(eye => actor.Position.InCircle(eye.Position, eye.Range)))
hints.ForbiddenDirections.Add((Angle.FromDirection(actor.Position - eye.Position) - eye.Forward, 135.Degrees(), eye.Activation));
hints.ForbiddenDirections.Add((Angle.FromDirection(actor.Position - eye.Position) - eye.Forward, 135f.Degrees(), eye.Activation));
}
else
{
foreach (var eye in ActiveEyes(slot, actor).Where(eye => actor.Position.InCircle(eye.Position, eye.Range)))
hints.ForbiddenDirections.Add((Angle.FromDirection(eye.Position - actor.Position) - eye.Forward, 45.Degrees(), eye.Activation));
hints.ForbiddenDirections.Add((Angle.FromDirection(eye.Position - actor.Position) - eye.Forward, 45f.Degrees(), eye.Activation));
}
}

Expand All @@ -54,7 +55,7 @@ public override void DrawArenaForeground(int pcSlot, Actor pc)

if (pc.Position.InCircle(eye.Position, eye.Range))
{
var (min, max) = Inverted ? (45, 315) : (-45, 45);
var (min, max) = Inverted ? (45f, 315f) : (-45f, 45f);
Arena.PathArcTo(pc.Position, 1, (pc.Rotation + eye.Forward + min.Degrees()).Rad, (pc.Rotation + eye.Forward + max.Degrees()).Rad);
MiniArena.PathStroke(false, Colors.Enemy);
}
Expand Down Expand Up @@ -89,23 +90,32 @@ private Vector2 IndicatorScreenPos(WPos eye)
// gaze that happens on cast end
public class CastGaze(BossModule module, ActionID aid, bool inverted = false, float range = 10000) : GenericGaze(module, aid, inverted)
{
public readonly List<Actor> _casters = [];
public readonly List<Eye> Eyes = [];

public override IEnumerable<Eye> ActiveEyes(int slot, Actor actor) => _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)
{
if (spell.Action == WatchedAction)
_casters.Add(caster);
Eyes.Add(new(spell.LocXZ, Module.CastFinishAt(spell), default, range, caster.InstanceID));
}

public override void OnCastFinished(Actor caster, ActorCastInfo spell)
{
if (spell.Action == WatchedAction)
_casters.Remove(caster);
{
var count = Eyes.Count;
for (var i = 0; i < count; ++i)
{
var eye = Eyes[i];
if (eye.ActorID == caster.InstanceID)
{
Eyes.Remove(eye);
break;
}
}
}
}

protected WPos EyePosition(Actor caster) => caster.CastInfo == null || caster.CastInfo.TargetID == caster.InstanceID ? caster.Position : WorldState.Actors.Find(caster.CastInfo.TargetID)?.Position ?? caster.CastInfo.LocXZ;
}

// 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
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/Knockback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,11 @@ public override IEnumerable<Source> Sources(int slot, Actor actor)
var minDist = MinDistance + (MinDistanceBetweenHitboxes ? actor.HitboxRadius + c.HitboxRadius : 0);
if (c.CastInfo!.TargetID == c.InstanceID)
{
yield return new(c.Position, Distance, Module.CastFinishAt(c.CastInfo), Shape, c.CastInfo.Rotation, KnockbackKind, minDist);
yield return new(c.CastInfo.LocXZ, Distance, Module.CastFinishAt(c.CastInfo), Shape, c.CastInfo.Rotation, KnockbackKind, minDist);
}
else
{
var origin = WorldState.Actors.Find(c.CastInfo.TargetID)?.Position ?? c.CastInfo.LocXZ;
var origin = c.CastInfo.LocXZ;
yield return new(origin, Distance, Module.CastFinishAt(c.CastInfo), Shape, Angle.FromDirection(origin - c.Position), KnockbackKind, minDist);
}
}
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Components/LineOfSightAOE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
public void Refresh()
{
var caster = ActiveCaster;
WPos? position = caster != null ? (WorldState.Actors.Find(caster.CastInfo!.TargetID)?.Position ?? caster.CastInfo!.LocXZ) : null;
WPos? position = caster != null ? caster.CastInfo!.LocXZ : null;
Modify(position, BlockerActors().Select(b => (b.Position, b.HitboxRadius)), Module.CastFinishAt(caster?.CastInfo));
}
}
14 changes: 7 additions & 7 deletions BossMod/Components/PersistentVoidzone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
var aoes = new List<AOEInstance>();
foreach (var source in Sources(Module))
{
aoes.Add(new(Shape, source.Position, source.Rotation));
aoes.Add(new(Shape, WPos.ClampToGrid(source.Position), source.Rotation));
}
return aoes;
}
Expand All @@ -25,7 +25,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
return;
var forbidden = new List<Func<WPos, float>>();
foreach (var s in Sources(Module))
forbidden.Add(Shape.Distance(s.Position, s.Rotation));
forbidden.Add(Shape.Distance(WPos.ClampToGrid(s.Position), s.Rotation));
hints.AddForbiddenZone(ShapeDistance.Union(forbidden));
}
}
Expand All @@ -47,11 +47,11 @@ public class PersistentVoidzoneAtCastTarget(BossModule module, float radius, Act
public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
foreach (var p in _predictedByEvent)
yield return new(Shape, p.pos, default, p.time);
yield return new(Shape, WPos.ClampToGrid(p.pos), default, p.time);
foreach (var p in _predictedByCast)
yield return new(Shape, WorldState.Actors.Find(p.caster.CastInfo!.TargetID)?.Position ?? p.caster.CastInfo.LocXZ, default, p.time);
yield return new(Shape, p.caster.CastInfo!.LocXZ, default, p.time);
foreach (var z in Sources(Module))
yield return new(Shape, z.Position);
yield return new(Shape, WPos.ClampToGrid(z.Position));
}

public override void Update()
Expand All @@ -77,7 +77,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
base.OnEventCast(caster, spell);
if (spell.Action == WatchedAction)
_predictedByEvent.Add((WorldState.Actors.Find(spell.MainTargetID)?.Position ?? spell.TargetXZ, WorldState.FutureTime(CastEventToSpawn)));
_predictedByEvent.Add((spell.TargetXZ, WorldState.FutureTime(CastEventToSpawn)));
}
}

Expand Down Expand Up @@ -107,7 +107,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme

foreach (var source in Sources(Module))
{
var shape = Shape.Distance(source.Position, source.Rotation);
var shape = Shape.Distance(WPos.ClampToGrid(source.Position), source.Rotation);
shapes.Add(shape);
}
if (shapes.Count == 0)
Expand Down
30 changes: 15 additions & 15 deletions BossMod/Components/StackSpread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public readonly int NumInside(BossModule module)
for (var i = 0; i < party.Length; ++i)
{
var indexActor = party[i];
if (!ForbiddenPlayers[indexActor.Item1] && indexActor.Item2.Position.InCircle(Target.Position, Radius))
if (!ForbiddenPlayers[indexActor.Item1] && indexActor.Item2.Position.InCircle(WPos.ClampToGrid(Target.Position), Radius))
++count;
}
return count;
}
public readonly bool CorrectAmountInside(BossModule module) => NumInside(module) is var count && count >= MinSize && count <= MaxSize;
public readonly bool InsufficientAmountInside(BossModule module) => NumInside(module) is var count && count < MaxSize;
public readonly bool TooManyInside(BossModule module) => NumInside(module) is var count && count > MaxSize;
public readonly bool IsInside(WPos pos) => pos.InCircle(Target.Position, Radius);
public readonly bool IsInside(WPos pos) => pos.InCircle(WPos.ClampToGrid(Target.Position), Radius);
public readonly bool IsInside(Actor actor) => IsInside(actor.Position);
}

Expand Down Expand Up @@ -133,7 +133,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints)
var numUnsatisfiedStacks = 0;
foreach (var s in ActiveStacks.Where(s => !s.ForbiddenPlayers[slot]))
{
if (actor.Position.InCircle(s.Target.Position, s.Radius))
if (actor.Position.InCircle(WPos.ClampToGrid(s.Target.Position), s.Radius))
++numParticipatingStacks;
else if (Raid.WithoutSlot().InRadiusExcluding(s.Target, s.Radius).Count() + 1 < s.MinSize)
++numUnsatisfiedStacks;
Expand All @@ -149,11 +149,11 @@ public override void AddHints(int slot, Actor actor, TextHints hints)
//hints.Add("Stack!", ActiveStacks.Count(s => !s.ForbiddenPlayers[slot] && actor.Position.InCircle(s.Target.Position, s.Radius)) != 1);
}

if (ActiveSpreads.Any(s => s.Target != actor && actor.Position.InCircle(s.Target.Position, s.Radius)))
if (ActiveSpreads.Any(s => s.Target != actor && actor.Position.InCircle(WPos.ClampToGrid(s.Target.Position), s.Radius)))
{
hints.Add("GTFO from spreads!");
}
else if (ActiveStacks.Any(s => s.Target != actor && s.ForbiddenPlayers[slot] && actor.Position.InCircle(s.Target.Position, s.Radius)))
else if (ActiveStacks.Any(s => s.Target != actor && s.ForbiddenPlayers[slot] && actor.Position.InCircle(WPos.ClampToGrid(s.Target.Position), s.Radius)))
{
hints.Add("GTFO from forbidden stacks!");
}
Expand All @@ -165,25 +165,25 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
// TODO: think how to improve this, current implementation works, but isn't particularly good - e.g. nearby players tend to move to same spot, turn around, etc.
// ideally we should provide per-mechanic spread spots, but for simple cases we should try to let melee spread close and healers/rdd spread far from main target...
foreach (var spreadFrom in ActiveSpreads.Where(s => s.Target != actor))
hints.AddForbiddenZone(ShapeDistance.Circle(spreadFrom.Target.Position, spreadFrom.Radius + ExtraAISpreadThreshold), spreadFrom.Activation);
hints.AddForbiddenZone(ShapeDistance.Circle(WPos.ClampToGrid(spreadFrom.Target.Position), spreadFrom.Radius + ExtraAISpreadThreshold), spreadFrom.Activation);
foreach (var spreadFrom in ActiveSpreads.Where(s => s.Target == actor))
foreach (var x in Raid.WithoutSlot())
if (!ActiveSpreads.Any(s => s.Target == x))
hints.AddForbiddenZone(ShapeDistance.Circle(x.Position, spreadFrom.Radius + ExtraAISpreadThreshold), spreadFrom.Activation);
hints.AddForbiddenZone(ShapeDistance.Circle(WPos.ClampToGrid(x.Position), spreadFrom.Radius + ExtraAISpreadThreshold), spreadFrom.Activation);
foreach (var avoid in ActiveStacks.Where(s => s.Target != actor && (s.ForbiddenPlayers[slot] || !s.IsInside(actor) && (s.CorrectAmountInside(Module) || s.TooManyInside(Module)) || s.IsInside(actor) && s.TooManyInside(Module))))
hints.AddForbiddenZone(ShapeDistance.Circle(avoid.Target.Position, avoid.Radius), avoid.Activation);
hints.AddForbiddenZone(ShapeDistance.Circle(WPos.ClampToGrid(avoid.Target.Position), avoid.Radius), avoid.Activation);

if (Stacks.FirstOrDefault(s => s.Target == actor) is var actorStack && actorStack.Target != null)
{
// forbid standing next to other stack markers or overlapping them
foreach (var stackWith in ActiveStacks.Where(s => s.Target != actor))
hints.AddForbiddenZone(ShapeDistance.Circle(stackWith.Target.Position, stackWith.Radius * 2), stackWith.Activation);
hints.AddForbiddenZone(ShapeDistance.Circle(WPos.ClampToGrid(stackWith.Target.Position), stackWith.Radius * 2), stackWith.Activation);
// if player got stackmarker and is playing with NPCs, go to a NPC to stack with them since they will likely not come to you
if (Raid.WithoutSlot().Any(x => x.Type == ActorType.Buddy))
{
var forbidden = new List<Func<WPos, float>>();
foreach (var stackWith in ActiveStacks.Where(s => s.Target == actor))
forbidden.Add(ShapeDistance.InvertedCircle(Raid.WithoutSlot().FirstOrDefault(x => !x.IsDead && !IsSpreadTarget(x) && !IsStackTarget(x))!.Position, actorStack.Radius / 3));
forbidden.Add(ShapeDistance.InvertedCircle(WPos.ClampToGrid(Raid.WithoutSlot().FirstOrDefault(x => !x.IsDead && !IsSpreadTarget(x) && !IsStackTarget(x))!.Position), actorStack.Radius * 0.33f));
if (forbidden.Count > 0)
hints.AddForbiddenZone(ShapeDistance.Intersection(forbidden), actorStack.Activation);
}
Expand All @@ -193,7 +193,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
var forbidden = new List<Func<WPos, float>>();
foreach (var s in ActiveStacks.Where(x => !x.ForbiddenPlayers[slot] && (x.IsInside(actor) && !x.TooManyInside(Module)
|| !x.IsInside(actor) && x.InsufficientAmountInside(Module))))
forbidden.Add(ShapeDistance.InvertedCircle(s.Target.Position, s.Radius - 0.25f));
forbidden.Add(ShapeDistance.InvertedCircle(WPos.ClampToGrid(s.Target.Position), s.Radius - 0.25f));
if (forbidden.Count > 0)
hints.AddForbiddenZone(ShapeDistance.Intersection(forbidden), ActiveStacks.FirstOrDefault().Activation);
}
Expand Down Expand Up @@ -236,25 +236,25 @@ public override void DrawArenaForeground(int pcSlot, Actor pc)
if (!AlwaysShowSpreads && Spreads.FindIndex(s => s.Target == pc) is var iSpread && iSpread >= 0)
{
// Draw only own circle if spreading; no one should be inside.
DrawCircle(pc.Position, Spreads[iSpread].Radius);
DrawCircle(WPos.ClampToGrid(pc.Position), Spreads[iSpread].Radius);
}
else
{
// Handle safe stack circles
foreach (var s in ActiveStacks.Where(x => x.Target == pc || !x.ForbiddenPlayers[pcSlot]
&& !IsSpreadTarget(pc) && !IsStackTarget(pc) && (x.IsInside(pc)
&& !x.TooManyInside(Module) || !x.IsInside(pc) && x.InsufficientAmountInside(Module))))
DrawCircle(s.Target.Position, s.Radius, Colors.Safe);
DrawCircle(WPos.ClampToGrid(s.Target.Position), s.Radius, Colors.Safe);

// Handle dangerous stack circles
foreach (var s in ActiveStacks.Where(x => x.Target != pc && (IsStackTarget(pc) || x.ForbiddenPlayers[pcSlot] || IsSpreadTarget(pc) ||
!x.IsInside(pc) && (x.CorrectAmountInside(Module) || x.TooManyInside(Module)) ||
x.IsInside(pc) && x.TooManyInside(Module))))
DrawCircle(s.Target.Position, s.Radius);
DrawCircle(WPos.ClampToGrid(s.Target.Position), s.Radius);

// Handle spread circles
foreach (var s in ActiveSpreads)
DrawCircle(s.Target.Position, s.Radius);
DrawCircle(WPos.ClampToGrid(s.Target.Position), s.Radius);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,13 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell)
}
void AddAOEs(AOEShape shape2, Angle initialAngle)
{
var pos = WPos.ClampToGrid(Arena.Center);
for (var i = 0; i < 3; ++i)
{
var activation = Module.CastFinishAt(spell, 1.8f + i * 0.3f);
var angle = initialAngle - i * a120;
_aoes.Add(new(donutSectorSmall, Arena.Center, angle, activation));
_aoes.Add(new(shape2, Arena.Center, angle, activation));
_aoes.Add(new(donutSectorSmall, pos, angle, activation));
_aoes.Add(new(shape2, pos, angle, activation));
}
}
}
Expand Down
Loading

0 comments on commit 1be826b

Please sign in to comment.