Skip to content

Commit

Permalink
merge fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Feb 22, 2025
1 parent 2eee8d2 commit 8d4346b
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 63 deletions.
6 changes: 2 additions & 4 deletions BossMod/BossModule/AIHints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,6 @@ public Func<WPos, float> GoalProximity(WPos destination, float maxDistance, floa
};
}

public WPos ClampToBounds(WPos position) => PathfindMapCenter + PathfindMapBounds.ClampToBounds(position - PathfindMapCenter);

public Func<WPos, float> PullTargetToLocation(Actor target, WPos destination, float destRadius = 2)
{
var enemy = FindEnemy(target);
Expand All @@ -430,8 +428,8 @@ public Func<WPos, float> PullTargetToLocation(Actor target, WPos destination, fl
if (desiredToTarget.LengthSq() > leewaySq)
{
var dest = destination - adjRange * desiredToTarget.Normalized();
return GoalSingleTarget(dest, PathfindMapBounds.MapResolution, 10);
return GoalSingleTarget(dest, PathfindMapBounds.MapResolution, 10f);
}
return _ => 0;
return _ => 0f;
}
}
20 changes: 10 additions & 10 deletions BossMod/BossModule/ArenaBounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// radius is the largest horizontal/vertical dimension: radius for circle, max of width/height for rect
// note: this class to represent *relative* arena bounds (relative to arena center) - the reason being that in some cases effective center moves every frame, and bounds caches a lot (clip poly & base map for pathfinding)
// note: if arena bounds are changed, new instance is recreated; max approx error can change without recreating the instance
public abstract record class ArenaBounds(float Radius, float MapResolution, float ScaleFactor = 1)
public abstract record class ArenaBounds(float Radius, float MapResolution, float ScaleFactor = 1, bool AllowObstacleMap = false)
{
// fields below are used for clipping & drawing borders
public readonly PolygonClipper Clipper = new();
Expand Down Expand Up @@ -145,7 +145,7 @@ public void AddToInstanceCache(object key, object value)
}
}

public sealed record class ArenaBoundsCircle(float Radius, float MapResolution = 0.5f) : ArenaBounds(Radius, MapResolution)
public sealed record class ArenaBoundsCircle(float Radius, float MapResolution = 0.5f, bool AllowObstacleMap = false) : ArenaBounds(Radius, MapResolution, AllowObstacleMap: AllowObstacleMap)
{
private Pathfinding.Map? _cachedMap;

Expand Down Expand Up @@ -175,7 +175,7 @@ private Pathfinding.Map BuildMap()
}

// if rotation is 0, half-width is along X and half-height is along Z
public record class ArenaBoundsRect(float HalfWidth, float HalfHeight, Angle Rotation = default, float MapResolution = 0.5f) : ArenaBounds(Math.Max(HalfWidth, HalfHeight), MapResolution, Rotation != default ? CalculateScaleFactor(Rotation) : 1)
public record class ArenaBoundsRect(float HalfWidth, float HalfHeight, Angle Rotation = default, float MapResolution = 0.5f, bool AllowObstacleMap = false) : ArenaBounds(Math.Max(HalfWidth, HalfHeight), MapResolution, Rotation != default ? CalculateScaleFactor(Rotation) : 1, AllowObstacleMap)
{
private Pathfinding.Map? _cachedMap;
public readonly WDir Orientation = Rotation.ToDirection();
Expand Down Expand Up @@ -215,7 +215,7 @@ public override WDir ClampToBounds(WDir offset)
}
}

public sealed record class ArenaBoundsSquare(float Radius, Angle Rotation = default, float MapResolution = 0.5f) : ArenaBoundsRect(Radius, Radius, Rotation, MapResolution) { }
public sealed record class ArenaBoundsSquare(float Radius, Angle Rotation = default, float MapResolution = 0.5f, bool AllowObstacleMap = false) : ArenaBoundsRect(Radius, Radius, Rotation, MapResolution, AllowObstacleMap) { }

// custom complex polygon bounds
public record class ArenaBoundsCustom : ArenaBounds
Expand All @@ -225,8 +225,8 @@ public record class ArenaBoundsCustom : ArenaBounds
private readonly (WDir, WDir)[] edges;
public float HalfWidth, HalfHeight;

public ArenaBoundsCustom(float Radius, RelSimplifiedComplexPolygon Poly, float MapResolution = 0.5f, float ScaleFactor = 1)
: base(Radius, MapResolution, ScaleFactor)
public ArenaBoundsCustom(float Radius, RelSimplifiedComplexPolygon Poly, float MapResolution = 0.5f, float ScaleFactor = 1, bool AllowObstacleMap = false)
: base(Radius, MapResolution, ScaleFactor, AllowObstacleMap)
{
poly = Poly;

Expand Down Expand Up @@ -383,21 +383,21 @@ public sealed record class ArenaBoundsComplex : ArenaBoundsCustom
public readonly WPos Center;
public bool IsCircle; // can be used by gaze component for gazes outside of the arena

public ArenaBoundsComplex(Shape[] UnionShapes, Shape[]? DifferenceShapes = null, Shape[]? AdditionalShapes = null, float MapResolution = 0.5f, float ScaleFactor = 1)
: base(BuildBounds(UnionShapes, DifferenceShapes, AdditionalShapes, MapResolution, ScaleFactor, out var center, out var halfWidth, out var halfHeight))
public ArenaBoundsComplex(Shape[] UnionShapes, Shape[]? DifferenceShapes = null, Shape[]? AdditionalShapes = null, float MapResolution = 0.5f, float ScaleFactor = 1, bool AllowObstacleMap = false)
: base(BuildBounds(UnionShapes, DifferenceShapes, AdditionalShapes, MapResolution, ScaleFactor, AllowObstacleMap, out var center, out var halfWidth, out var halfHeight))
{
Center = center;
HalfWidth = halfWidth;
HalfHeight = halfHeight;
}

private static ArenaBoundsCustom BuildBounds(Shape[] unionShapes, Shape[]? differenceShapes, Shape[]? additionalShapes, float mapResolution, float scalefactor, out WPos center, out float halfWidth, out float halfHeight)
private static ArenaBoundsCustom BuildBounds(Shape[] unionShapes, Shape[]? differenceShapes, Shape[]? additionalShapes, float mapResolution, float scalefactor, bool allowObstacleMap, out WPos center, out float halfWidth, out float halfHeight)
{
var properties = CalculatePolygonProperties(unionShapes, differenceShapes ?? [], additionalShapes ?? []);
center = properties.Center;
halfWidth = properties.HalfWidth;
halfHeight = properties.HalfHeight;
return new(scalefactor == 1 ? properties.Radius : properties.Radius / scalefactor, properties.Poly, mapResolution, scalefactor);
return new(scalefactor == 1 ? properties.Radius : properties.Radius / scalefactor, properties.Poly, mapResolution, scalefactor, allowObstacleMap);
}

private static (WPos Center, float HalfWidth, float HalfHeight, float Radius, RelSimplifiedComplexPolygon Poly) CalculatePolygonProperties(Shape[] unionShapes, Shape[] differenceShapes, Shape[] additionalShapes)
Expand Down
29 changes: 19 additions & 10 deletions BossMod/BossModule/BossModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,18 @@ public void CalculateAIHints(int slot, ref Actor actor, ref PartyRolesConfig.Ass
hints.PathfindMapCenter = Center;
hints.PathfindMapBounds = Bounds;

var (entry, bitmap) = Obstacles.Find(new Vector3(Center.X, actor.PosRot.Y, Center.Z));
if (entry != null && bitmap != null)
if (Arena.Bounds.AllowObstacleMap)
{
var originCell = (Center - entry.Origin) / bitmap.PixelSize;
var originX = (int)originCell.X;
var originZ = (int)originCell.Z;
var halfSize = (int)(Bounds.Radius / bitmap.PixelSize);
hints.PathfindMapObstacles = new(bitmap, new(originX - halfSize, originZ - halfSize, originX + halfSize, originZ + halfSize));
var (entry, bitmap) = Obstacles.Find(new Vector3(Center.X, actor.PosRot.Y, Center.Z));
if (entry != null && bitmap != null)
{
var originCell = (Center - entry.Origin) / bitmap.PixelSize;
var originX = (int)originCell.X;
var originZ = (int)originCell.Z;
var halfSize = (int)(Bounds.Radius / bitmap.PixelSize);
hints.PathfindMapObstacles = new(bitmap, new(originX - halfSize, originZ - halfSize, originX + halfSize, originZ + halfSize));
}
}

var count = Components.Count;
for (var i = 0; i < count; ++i)
Components[i].AddAIHints(slot, actor, assignment, hints);
Expand Down Expand Up @@ -390,9 +392,15 @@ private void DrawWaymark(Vector3? pos, string text, uint color)

private void DrawPartyMembers(int pcSlot, ref Actor pc)
{
foreach (var (slot, player) in Raid.WithSlot().Exclude(pcSlot))
var raid = Raid.WithSlot();
var count = raid.Length;
for (var i = 0; i < count; ++i)
{
var (prio, color) = CalculateHighestPriority(pcSlot, ref pc, slot, player);
if (i == pcSlot)
continue;

var player = raid[i].Item2;
var (prio, color) = CalculateHighestPriority(pcSlot, ref pc, i, player);

var isFocus = WorldState.Client.FocusTargetId == player.InstanceID;
if (prio == BossComponent.PlayerPriority.Irrelevant && !WindowConfig.ShowIrrelevantPlayers && !(isFocus && WindowConfig.ShowFocusTargetPlayer))
Expand Down Expand Up @@ -429,6 +437,7 @@ private void DrawPartyMembers(int pcSlot, ref Actor pc)
}
}
}

Arena.Actor(player, color);
}
}
Expand Down
2 changes: 1 addition & 1 deletion BossMod/BossModule/SimpleBossModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// base class for simple boss modules (hunts, fates, dungeons, etc.)
// these always center map around PC
public abstract class SimpleBossModule(WorldState ws, Actor primary) : BossModule(ws, primary, primary.Position, new ArenaBoundsCircle(30f))
public abstract class SimpleBossModule(WorldState ws, Actor primary) : BossModule(ws, primary, primary.Position, new ArenaBoundsCircle(30, AllowObstacleMap: true))
{
private WPos _prevFramePathfindCenter;

Expand Down
23 changes: 20 additions & 3 deletions BossMod/Components/Adds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,23 @@
public class Adds(BossModule module, uint oid, int priority = 0) : BossComponent(module)
{
public readonly List<Actor> Actors = module.Enemies(oid);
public IEnumerable<Actor> ActiveActors => Actors.Where(a => a.IsTargetable && !a.IsDead);
public IEnumerable<Actor> ActiveActors
{
get
{
var count = Actors.Count;
var activeActors = new List<Actor>(count);
for (var i = 0; i < count; ++i)
{
var actor = Actors[i];
if (actor.IsTargetable && !actor.IsDead)
{
activeActors.Add(actor);
}
}
return activeActors;
}
}

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
Expand All @@ -23,8 +39,9 @@ public class AddsPointless(BossModule module, uint oid) : Adds(module, oid)
{
public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
foreach (var act in ActiveActors)
hints.SetPriority(act, AIHints.Enemy.PriorityPointless);
var count = Actors.Count;
for (var i = 0; i < count; ++i)
hints.SetPriority(Actors[i], AIHints.Enemy.PriorityPointless);
}
}

Expand Down
4 changes: 2 additions & 2 deletions BossMod/Data/ActorState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public List<Operation> CompareToInitial()
if (act.MountId != 0)
ops.Add(new OpMount(instanceID, act.MountId));
if (act.ForayInfo != default)
yield return new OpForayInfo(act.InstanceID, act.ForayInfo);
ops.Add(new OpForayInfo(act.InstanceID, act.ForayInfo));
if (act.Tether.ID != 0)
ops.Add(new OpTether(instanceID, act.Tether));
if (act.CastInfo != null)
Expand Down Expand Up @@ -371,7 +371,7 @@ protected override void ExecActor(ref WorldState ws, ref Actor actor)
public Event<Actor> ForayInfoChanged = new();
public sealed record class OpForayInfo(ulong InstanceID, ActorForayInfo Value) : Operation(InstanceID)
{
protected override void ExecActor(WorldState ws, Actor actor)
protected override void ExecActor(ref WorldState ws, ref Actor actor)
{
actor.ForayInfo = Value;
ws.Actors.ForayInfoChanged.Fire(actor);
Expand Down
7 changes: 4 additions & 3 deletions BossMod/Data/ClientState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -451,15 +451,16 @@ protected override void Exec(ref WorldState ws)
public override void Write(ReplayRecorder.Output output)
{
output.EmitFourCC("CLKV"u8);
foreach (var val in Value)
output.Emit(val);
var len = Value.Length;
for (var i = 0; i < len; ++i)
output.Emit(Value[i]);
}
}

public Event<OpFateInfo> FateInfo = new();
public sealed record class OpFateInfo(uint FateId, DateTime StartTime) : WorldState.Operation
{
protected override void Exec(WorldState ws) => ws.Client.FateInfo.Fire(this);
protected override void Exec(ref WorldState ws) => ws.Client.FateInfo.Fire(this);
public override void Write(ReplayRecorder.Output output) => output.EmitFourCC("FATE"u8).Emit(FateId).Emit(StartTime.Ticks);
}
}
4 changes: 2 additions & 2 deletions BossMod/Modules/Global/DeepDungeon/AutoClear.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,14 +389,14 @@ public override void CalculateAIHints(int playerSlot, Actor player, AIHints hint
if (!Config.Enable || Palace.IsBossFloor || BetweenFloors)
return;

var canNavigate = _config.MaxPull == 0 ? !player.InCombat : hints.PotentialTargets.Count(t => t.Actor.AggroPlayer && !t.Actor.IsDeadOrDestroyed) < _config.MaxPull;
var canNavigate = Config.MaxPull == 0 ? !player.InCombat : hints.PotentialTargets.Count(t => t.Actor.AggroPlayer && !t.Actor.IsDeadOrDestroyed) < Config.MaxPull;

var countWalls = Walls.Count;
for (var i = 0; i < countWalls; ++i)
{
var wall = Walls[i];
var w = wall.Wall;
hints.AddForbiddenZone(ShapeDistance.Rect(w.Position, (wall.Rotated ? 90f : 0f).Degrees(), w.Depth, w.Depth, 20f));
hints.AddForbiddenZone(ShapeDistance.Rect(w.Position, (wall.Rotated ? 90f : default).Degrees(), w.Depth, w.Depth, 20f));
}

if (canNavigate)
Expand Down
37 changes: 36 additions & 1 deletion BossMod/Modules/Heavensward/DeepDungeon/DD70Yaquaru.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ public enum AID : uint
FangsEnd = 7092 // Boss->player, no cast, single-target
}

public enum SID : uint
{
Heavy = 14
}

class Douse(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 8f, ActionID.MakeSpell(AID.Douse), GetVoidzones, 0.8f)
{
public static Actor[] GetVoidzones(BossModule module)
Expand Down Expand Up @@ -89,14 +94,44 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme

class Electrogenesis(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Electrogenesis), 8f);

class FangsEnd(BossModule module) : BossComponent(module)
{
private BitMask _heavy;

public override void Update()
{
for (var i = 0; i < 4; ++i)
{
var player = Raid[i];
if (player == null)
continue;

if (player.FindStatus((uint)SID.Heavy) is ActorStatus st && (st.ExpireAt - WorldState.CurrentTime).TotalSeconds > 8d)
_heavy.Set(i);
}
}

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

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
hints.ShouldCleanse |= _heavy;
}
}

class DD70YaquaruStates : StateMachineBuilder
{
public DD70YaquaruStates(BossModule module) : base(module)
{
TrivialPhase()
.ActivateOnEnter<Douse>()
.ActivateOnEnter<DousePuddle>()
.ActivateOnEnter<Electrogenesis>();
.ActivateOnEnter<Electrogenesis>()
.ActivateOnEnter<FangsEnd>();
}
}

Expand Down
19 changes: 9 additions & 10 deletions BossMod/Modules/Heavensward/DeepDungeon/DD90TheGodmother.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,17 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
hints.SetPriority(g, AIHints.Enemy.PriorityForbidden);
}
}

class GiddyBomb(BossModule module) : BossComponent(module)
{
public static readonly WPos[] BombSpawns = [
new(-305, -240),
new(-295, -240),
new(-295, -240),
new(-300, -235)
];
public static readonly WPos[] BombSpawns = [new(-305f, -240f), new(-295f, -240f), new(-295f, -240f), new(-300f, -235f)];

private int _index;

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID == AID.HypothermalCombustion)
_index++;
if (spell.Action.ID == (uint)AID.HypothermalCombustion)
++_index;
}

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
Expand All @@ -57,8 +53,11 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
return;

// giddy bomb is alive, don't pull anywhere
if (Module.Enemies(OID.GiddyBomb).Any(x => !x.IsDeadOrDestroyed))
return;
var giddybombs = Module.Enemies((uint)OID.GiddyBomb);
var count = giddybombs.Count;
for (var i = 0; i < count; ++i)
if (!giddybombs[i].IsDeadOrDestroyed)
return;

var nextBombSpot = BombSpawns[_index % BombSpawns.Length];
hints.GoalZones.Add(hints.PullTargetToLocation(Module.PrimaryActor, nextBombSpot));
Expand Down
10 changes: 7 additions & 3 deletions BossMod/Modules/Stormblood/Foray/Hydatos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ public class EurekaConfig : ConfigNode
[PropertyDisplay("Max number of mobs to pull at once (0 for no limit)")]
[PropertySlider(0, 30, Speed = 0.1f)]
public int MaxPullCount = 10;

[PropertyDisplay("Show auto farm window")]
public bool ShowAutoFarmWindow = false;

}

[ConfigDisplay(Name = "Hydatos", Parent = typeof(EurekaConfig))]
Expand Down Expand Up @@ -85,8 +89,8 @@ static class NMExtensions
[ZoneModuleInfo(BossModuleInfo.Maturity.WIP, 639)]
public class Hydatos : ZoneModule
{
private readonly EurekaConfig _eurekaConfig = Service.Config.Get<EurekaConfig>();
private readonly HydatosConfig _hydatosConfig = Service.Config.Get<HydatosConfig>();
private static readonly EurekaConfig _eurekaConfig = Service.Config.Get<EurekaConfig>();
private static readonly HydatosConfig _hydatosConfig = Service.Config.Get<HydatosConfig>();

private readonly EventSubscriptions _subscriptions;

Expand Down Expand Up @@ -148,7 +152,7 @@ private bool ShouldIgnore(Actor caster, Actor player)
};
}

public override bool WantDrawExtra() => true;
public override bool WantDrawExtra() => _eurekaConfig.ShowAutoFarmWindow;

public override string WindowName() => "Hydatos###Eureka module";

Expand Down
2 changes: 1 addition & 1 deletion BossMod/Modules/Stormblood/Foray/Hydatos/Ceto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ public CetoStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.EurekaNM, GroupID = 639, NameID = 1421, Contributors = "xan", SortOrder = 9)]
public class Ceto(WorldState ws, Actor primary) : BossModule(ws, primary, new(747.8959f, -878.8765f), new ArenaBoundsCircle(80f, MapResolution: 1));
public class Ceto(WorldState ws, Actor primary) : BossModule(ws, primary, new(747.8959f, -878.8765f), new ArenaBoundsCircle(80f, 1f, true));

2 changes: 1 addition & 1 deletion BossMod/Modules/Stormblood/Foray/Hydatos/Daphne.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ public DaphneStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.EurekaNM, GroupID = 639, NameID = 1417, Contributors = "xan", SortOrder = 5)]
public class Daphne(WorldState ws, Actor primary) : BossModule(ws, primary, new(207.8475f, -736.8179f), new ArenaBoundsCircle(80f, MapResolution: 1));
public class Daphne(WorldState ws, Actor primary) : BossModule(ws, primary, new(207.8475f, -736.8179f), new ArenaBoundsCircle(80f, 1f, true));

Loading

0 comments on commit 8d4346b

Please sign in to comment.