Skip to content

Commit

Permalink
Merge branch 'mergeWIP'
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Dec 5, 2024
2 parents 1db5ec5 + f93a2fd commit b5f1199
Show file tree
Hide file tree
Showing 100 changed files with 877 additions and 457 deletions.
2 changes: 1 addition & 1 deletion BossMod/AI/AIConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ sealed class AIConfig : ConfigNode
[PropertyDisplay("Enable auto AFK", tooltip: "Enables auto AFK if out of combat. While AFK AI will not use autorotation or target anything")]
public bool AutoAFK = false;

[PropertyDisplay("Enable out of combat AFK mode", tooltip: "Time in seconds out of combat until AFK mode enables. Any movement will reset timer or disable AFK mode if already active.")]
[PropertyDisplay("Auto AFK timer", tooltip: "Time in seconds out of combat until AFK mode enables. Any movement will reset timer or disable AFK mode if already active.")]
public float AFKModeTimer = 10;

public string? AIAutorotPresetName;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/AI/AIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void Update(Actor? player, AIHints hints, DateTime now)
var moveRequested = _movement.IsMoveRequested();
var castInProgress = player.CastInfo != null && !player.CastInfo.EventHappened;
var forbidMovement = moveRequested || !AllowInterruptingCastByMovement && _amex.MoveMightInterruptCast;
if (NaviTargetPos != null && !forbidMovement && (NaviTargetPos.Value - player.Position).LengthSq() > 0.01f)
if (NaviTargetPos != null && !forbidMovement && (NaviTargetPos.Value - player.Position).LengthSq() > 0.001f)
{
var y = NaviTargetVertical != null && IsVerticalAllowed ? NaviTargetVertical.Value : player.PosRot.Y;
desiredPosition = new(NaviTargetPos.Value.X, y, NaviTargetPos.Value.Z);
Expand Down
7 changes: 4 additions & 3 deletions BossMod/BossModule/AIHints.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace BossMod;
using BossMod.AST;

namespace BossMod;

// information relevant for AI decision making process for a specific player
public sealed class AIHints
Expand Down Expand Up @@ -37,7 +39,6 @@ public enum SpecialMode
// information needed to build base pathfinding map (onto which forbidden/goal zones are later rasterized), if needed (lazy, since it's somewhat expensive and not always needed)
public WPos PathfindMapCenter;
public ArenaBounds PathfindMapBounds = DefaultBounds;
public WaypointManager WaypointManager { get; private set; } = new WaypointManager();
public Bitmap.Region PathfindMapObstacles;

// list of potential targets
Expand Down Expand Up @@ -134,7 +135,7 @@ public void FillPotentialTargets(WorldState ws, bool playerIsDefaultTank)
{
// fate mob in fate we are NOT a part of, skip entirely. it's okay to "attack" these (i.e., they won't be added as forbidden targets) because we can't even hit them
// (though aggro'd mobs will continue attacking us after we unsync, but who really cares)
if (actor.FateID > 0 && actor.FateID != allowedFateID)
if (actor.FateID != 0 && actor.FateID != allowedFateID)
continue;

// target is dying; skip it so that AI retargets, but ensure that it's not marked as a forbidden target
Expand Down
15 changes: 14 additions & 1 deletion BossMod/BossModule/BossModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,22 @@ public abstract class BossModule : IDisposable
public IReadOnlyList<Actor> Enemies(uint oid)
{
IReadOnlyList<Actor>? entry = _relevantEnemies.GetValueOrDefault(oid);
entry ??= _relevantEnemies[oid] = WorldState.Actors.Where(actor => actor.OID == oid).ToList();
entry ??= _relevantEnemies[oid] = [.. WorldState.Actors.Where(actor => actor.OID == oid)];
return entry;
}

public IReadOnlyList<Actor> Enemies(ReadOnlySpan<uint> enemies)
{
List<Actor> relevantenemies = [];
for (var i = 0; i < enemies.Length; ++i)
{
var enemy = enemies[i];
IReadOnlyList<Actor>? entry = _relevantEnemies.GetValueOrDefault(enemy);
entry ??= _relevantEnemies[enemy] = [.. WorldState.Actors.Where(actor => actor.OID == enemy)];
relevantenemies.AddRange(entry);
}
return relevantenemies;
}
public IReadOnlyList<Actor> Enemies<OID>(OID oid) where OID : Enum => Enemies((uint)(object)oid);

// component management: at most one component of any given type can be active at any time
Expand Down
8 changes: 8 additions & 0 deletions BossMod/BossModule/MiniArena.cs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,14 @@ public void Actors(IEnumerable<Actor> actors, uint color = 0, bool allowDeadAndU
Actor(a, color == 0 ? Colors.Enemy : color, allowDeadAndUntargetable);
}

public void Actors(IReadOnlyList<Actor> actors, uint color = 0, bool allowDeadAndUntargetable = false)
{
for (var i = 0; i < actors.Count; ++i)
{
Actor(actors[i], color == 0 ? Colors.Enemy : color, allowDeadAndUntargetable);
}
}

public static void End()
{
ImGui.GetWindowDrawList().PopClipRect();
Expand Down
7 changes: 7 additions & 0 deletions BossMod/BossModule/TreasureHuntTemplate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace BossMod;

// for treasure hunt roulettes
public abstract class THTemplate(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena)
{
private static readonly ArenaBoundsComplex arena = new([new Polygon(new(100, 100), 19, 48)]);
}
4 changes: 2 additions & 2 deletions BossMod/Components/StackSpread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,14 @@ public override PlayerPriority CalcPriority(int pcSlot, Actor pc, int playerSlot

public override void DrawArenaForeground(int pcSlot, Actor pc)
{
void DrawCircle(WPos position, float radius, uint color = 0) => Arena.AddCircle(position, radius, color);
if (!AlwaysShowSpreads && Spreads.FindIndex(s => s.Target == pc) is var iSpread && iSpread >= 0)
{
// Draw only own circle if spreading; no one should be inside.
Arena.AddCircle(pc.Position, Spreads[iSpread].Radius);
DrawCircle(pc.Position, Spreads[iSpread].Radius);
}
else
{
void DrawCircle(WPos position, float radius, uint color = 0) => Arena.AddCircle(position, radius, color);
// Handle safe stack circles
foreach (var s in ActiveStacks.Where(x => x.Target == pc || !x.ForbiddenPlayers[pcSlot]
&& !IsSpreadTarget(pc) && !IsStackTarget(pc) && (x.IsInside(pc)
Expand Down
9 changes: 8 additions & 1 deletion BossMod/Components/Tethers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ public override void DrawArenaForeground(int pcSlot, Actor pc)
}
}

private bool IsTether(Actor actor, uint tetherID) => TetherOnActor.Contains((actor, tetherID));
protected bool IsTether(Actor actor, uint tetherID) => TetherOnActor.Contains((actor, tetherID));

private void DrawTetherLines(Actor target, uint color = 0)
{
Expand Down Expand Up @@ -390,4 +390,11 @@ public override void AddHints(int slot, Actor actor, TextHints hints)
else
base.AddHints(slot, actor, hints);
}

public override void DrawArenaForeground(int pcSlot, Actor pc)
{
base.DrawArenaForeground(pcSlot, pc);
if (needToKite && IsTether(pc, TIDBad))
Arena.Actor(ActiveBaits.FirstOrDefault(x => x.Target == pc).Source, Colors.Object, true);
}
}
18 changes: 13 additions & 5 deletions BossMod/Components/Towers.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace BossMod.Components;

public class GenericTowers(BossModule module, ActionID aid = default) : CastCounter(module, aid)
public class GenericTowers(BossModule module, ActionID aid = default, bool prioritizeInsufficient = false) : CastCounter(module, aid)
{
public struct Tower(WPos position, float radius, int minSoakers = 1, int maxSoakers = 1, BitMask forbiddenSoakers = default, DateTime activation = default)
{
Expand All @@ -20,6 +20,7 @@ public struct Tower(WPos position, float radius, int minSoakers = 1, int maxSoak
}

public List<Tower> Towers = [];
public bool PrioritizeInsufficient = prioritizeInsufficient; // give priority to towers with more than 0 but less than min soakers

// default tower styling
public static void DrawTower(MiniArena arena, WPos pos, float radius, bool safe)
Expand Down Expand Up @@ -57,15 +58,22 @@ public override void DrawArenaForeground(int pcSlot, Actor pc)

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
if (Towers.Count == 0)
var count = Towers.Count;
if (count == 0)
return;
var forbiddenInverted = new List<Func<WPos, float>>();
var forbidden = new List<Func<WPos, float>>();
if (!Towers.Any(x => x.ForbiddenSoakers[slot]))
{
if (Raid.WithoutSlot(true).Count() <= 8) // don't do this in unorganized content where people do whatever
foreach (var t in Towers.Where(x => !x.IsInside(actor) && x.InsufficientAmountInside(Module) && x.NumInside(Module) > 0))
forbiddenInverted.Add(ShapeDistance.InvertedCircle(t.Position, t.Radius));
if (PrioritizeInsufficient)
{
List<Tower> insufficientTowers = [];
foreach (var t in Towers.Where(x => x.InsufficientAmountInside(Module) && x.NumInside(Module) > 0))
insufficientTowers.Add(t);
var mostRelevantTower = insufficientTowers.OrderByDescending(x => x.NumInside(Module)).ThenBy(x => (x.Position - actor.Position).LengthSq()).FirstOrDefault();
if (insufficientTowers.Count > 0)
forbiddenInverted.Add(ShapeDistance.InvertedCircle(mostRelevantTower.Position, mostRelevantTower.Radius));
}
var inTower = Towers.Any(x => x.IsInside(actor) && x.CorrectAmountInside(Module));
var missingSoakers = !inTower && Towers.Any(x => x.InsufficientAmountInside(Module));
if (forbiddenInverted.Count == 0)
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Data/WorldState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public sealed record class OpRSVData(string Key, string Value) : Operation
{
protected override void Exec(WorldState ws)
{
Service.LuminaRSV[Key] = System.Text.Encoding.UTF8.GetBytes(Value); // TODO: reconsider...
Service.LuminaRSV[Key] = Encoding.UTF8.GetBytes(Value); // TODO: reconsider...
ws.RSVEntries[Key] = Value;
ws.RSVDataReceived.Fire(this);
}
Expand Down
1 change: 1 addition & 0 deletions BossMod/Framework/IPCProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public IPCProvider(RotationModuleManager autorotation, ActionManagerEx amex, Mov
Register("AI.GetPreset", () => ai.GetAIPreset);
Register("AI.GetPotentialTargets", () => autorotation.Hints.PotentialTargets);
Register("AI.GetSpecialMode", () => autorotation.Hints.ImminentSpecialMode);
Register("AI.ForbiddenDirections", () => autorotation.Hints.ForbiddenDirections);
Register("AI.ForcedTarget", () => autorotation.Hints.ForcedTarget);
Register("AI.SetPositional", (Positional positional) => autorotation.Hints.SetPositional(positional));
}
Expand Down
6 changes: 4 additions & 2 deletions BossMod/Modules/Dawntrail/Alliance/A10Trash/A10Aquarius.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public A10AquariusStates(BossModule module) : base(module)
.ActivateOnEnter<SpiderWeb>()
.ActivateOnEnter<HundredFists>()
.ActivateOnEnter<Agaricus>()
.Raw.Update = () => Module.WorldState.Actors.Where(x => x.IsTargetable && !x.IsAlly).All(x => x.IsDeadOrDestroyed);
.Raw.Update = () => Module.Enemies(A10Aquarius.Trash).All(x => x.IsDeadOrDestroyed);
}
}

Expand Down Expand Up @@ -97,9 +97,11 @@ public class A10Aquarius(WorldState ws, Actor primary) : BossModule(ws, primary,
new(-503.55f, 696.32f), new(-504.41f, 695.37f), new(-504.92f, 695.35f), new(-506.16f, 695.72f), new(-506.72f, 695.68f),
new(-505.95f, 688.81f), new(-505.83f, 688.18f), new(-505.76f, 687.58f), new(-505.52f, 686.9f), new(-500.62f, 686.9f)];
private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]);
public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.ElderGobbue, (uint)OID.RobberCrab1, (uint)OID.RobberCrab2, (uint)OID.DeathCap,
(uint)OID.BarkSpider1, (uint)OID.BarkSpider2, (uint)OID.Skimmer1, (uint)OID.Skimmer2];

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly));
Arena.Actors(Enemies(Trash));
}
}
9 changes: 5 additions & 4 deletions BossMod/Modules/Dawntrail/Alliance/A10Trash/A10Despot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public enum AID : uint
IsleDrop = 41699, // Boss->location, 3.0s cast, range 6 circle
Peck = 41695, // Flamingo2->player, no cast, single-target
Panzerfaust = 41698, // Boss->player, 5.0s cast, single-target, interruptible tankbuster
PanzerfaustRepeats = 41353, // Boss->player, no cast, single-target, knockback 10, apply concussion
PanzerfaustRepeats = 41353 // Boss->player, no cast, single-target, knockback 10, apply concussion
}

class IsleDrop(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.IsleDrop), 6);
Expand Down Expand Up @@ -77,7 +77,7 @@ public A10DespotStates(BossModule module) : base(module)
.ActivateOnEnter<Panzerfaust>()
.ActivateOnEnter<PanzerfaustHint>()
.ActivateOnEnter<ScraplineStorm>()
.Raw.Update = () => Module.WorldState.Actors.Where(x => x.IsTargetable && !x.IsAlly).All(x => x.IsDeadOrDestroyed);
.Raw.Update = () => Module.Enemies(A10Despot.Trash).All(x => x.IsDeadOrDestroyed);
}
}

Expand Down Expand Up @@ -120,10 +120,11 @@ public class A10Despot(WorldState ws, Actor primary) : BossModule(ws, primary, a
new(-586.45f, -635.02f), new(-587.01f, -635.5f), new(-587.48f, -636.06f), new(-587.43f, -636.72f), new(-586.1f, -639.84f),
new(-585.55f, -640.25f)];
private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]);
public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.Flamingo1, (uint)OID.Flamingo2];

protected override bool CheckPull() => WorldState.Actors.Any(x => x.PosRot.Y > -960 & x.InCombat);
protected override bool CheckPull() => Enemies(Trash).Any(x => x.InCombat);
protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly));
Arena.Actors(Enemies(Trash));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public A10GroundskeeperStates(BossModule module) : base(module)
TrivialPhase()
.ActivateOnEnter<IsleDrop>()
.ActivateOnEnter<MysteriousLight>()
.Raw.Update = () => Module.WorldState.Actors.Where(x => !x.IsAlly && x.IsTargetable && x.InCombat).All(x => x.IsDeadOrDestroyed);
.Raw.Update = () => Module.Enemies(A10Groundskeeper.Trash).All(x => x.IsDeadOrDestroyed);
}
}

Expand All @@ -52,9 +52,10 @@ public class A10Groundskeeper(WorldState ws, Actor primary) : BossModule(ws, pri
new(-557.2f, -616.93f), new(-556.69f, -616.59f), new(-556.17f, -616.37f), new(-555.61f, -616.44f), new(-555.32f, -616.94f),
new(-544.54f, -642.34f)];
private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]);
public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.Groundskeeper, (uint)OID.Sprinkler];

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly));
Arena.Actors(Enemies(Trash));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public A10VanguardPathfinderStates(BossModule module) : base(module)
TrivialPhase()
.ActivateOnEnter<Seismostomp>()
.ActivateOnEnter<BombToss>()
.Raw.Update = () => Module.WorldState.Actors.Where(x => x.IsTargetable && !x.IsAlly).All(x => x.IsDeadOrDestroyed);
.Raw.Update = () => Module.Enemies(A10VanguardPathfinder.Trash).All(x => x.IsDeadOrDestroyed);
}
}

Expand All @@ -54,9 +54,10 @@ public class A10VanguardPathfinder(WorldState ws, Actor primary) : BossModule(ws
new(790.4f, 624.3f), new(790.66f, 623.66f), new(790.86f, 623), new(790.61f, 622.49f), new(791.1f, 622.42f),
new(791.62f, 622.18f), new(791.71f, 621.53f), new(802.28f, 621.41f)];
private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]);
public static readonly uint[] Trash = [(uint)OID.Boss, (uint)OID.VanguardsSlime1, (uint)OID.VanguardsSlime2, (uint)OID.GoblinReplica];

protected override void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly));
Arena.Actors(Enemies(Trash));
}
}
1 change: 0 additions & 1 deletion BossMod/Modules/Dawntrail/Alliance/A11Prishe/A11Prishe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

class NullifyingDropkick(BossModule module) : Components.CastSharedTankbuster(module, ActionID.MakeSpell(AID.NullifyingDropkick), 6);
class Holy(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Holy), 6);
class Explosion(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCircle(8));
class BanishgaIV(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.BanishgaIV));
class Banishga(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Banishga));

Expand Down
10 changes: 5 additions & 5 deletions BossMod/Modules/Dawntrail/Alliance/A11Prishe/AuroralUppercut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@ public override void OnStatusLose(Actor actor, ActorStatus status)

class AuroralUppercutHint(BossModule module) : Components.GenericAOEs(module)
{
private static readonly Angle a45 = 45.Degrees(), a135 = 135.Degrees(), a44 = 44.Degrees(), a10 = 10.Degrees(), a60 = 60.Degrees();
private static readonly Angle a45 = 45.Degrees(), a135 = 135.Degrees(), a44 = 44.Degrees(), a10 = 10.Degrees(), a59 = 59.Degrees();
private static readonly WPos center = A11Prishe.ArenaCenter;
private AOEInstance? _aoe;
private static readonly AOEShapeCustom hintENVC00020001KB25 = new([new ConeHA(center, 10, -144.Degrees(), a44), new ConeHA(center, 10, 36.Degrees(), a44)],
private static readonly AOEShapeCustom hintENVC00020001KB25 = new([new DonutSegmentHA(center, 4, 10, -144.Degrees(), a44), new DonutSegmentHA(center, 4, 10, 36.Degrees(), a44)],
[new ConeHA(center, 10, -a135, a10), new ConeHA(center, 10, a45, a10)], InvertForbiddenZone: true);
private static readonly AOEShapeCustom hintENVC02000100KB25 = new([new ConeHA(center, 10, 126.Degrees(), a44), new ConeHA(center, 10, -54.Degrees(), a44)],
private static readonly AOEShapeCustom hintENVC02000100KB25 = new([new DonutSegmentHA(center, 4, 10, 126.Degrees(), a44), new DonutSegmentHA(center, 4, 10, -54.Degrees(), a44)],
[new ConeHA(center, 10, a135, a10), new ConeHA(center, 10, -a45, a10)], InvertForbiddenZone: true);
private static readonly AOEShapeCustom hintENVC00020001KB38 = new([new ConeHA(center, 5, -a135, a10), new ConeHA(center, 5, a45, a10)], InvertForbiddenZone: true);
private static readonly AOEShapeCustom hintENVC02000100KB38 = new([new ConeHA(center, 5, a135, a10), new ConeHA(center, 5, -a45, a10)], InvertForbiddenZone: true);
private static readonly AOEShapeCustom hintENVC00020001KB12 = new([new ConeHA(center, 5, a135, a60), new ConeHA(center, 5, -a45, a60),
private static readonly AOEShapeCustom hintENVC00020001KB12 = new([new ConeHA(center, 5, a135, a59), new ConeHA(center, 5, -a45, a59),
new ConeV(ArenaChanges.MiddleENVC00020001[0].Center + new WDir(-9, -9), 3, -a135, a45, 3),
new ConeV(ArenaChanges.MiddleENVC00020001[1].Center + new WDir(9, 9), 3, a45, a45, 3),
new Rectangle(center + new WDir(-3, -15), 5, 1), new Rectangle(center + new WDir(3, 15), 5, 1)], InvertForbiddenZone: true);
private static readonly AOEShapeCustom hintENVC02000100KB12 = new([new ConeHA(center, 5, -a135, a60), new ConeHA(center, 5, a45, a60),
private static readonly AOEShapeCustom hintENVC02000100KB12 = new([new ConeHA(center, 5, -a135, a59), new ConeHA(center, 5, a45, a59),
new ConeV(ArenaChanges.MiddleENVC02000100[0].Center + new WDir(9, -9), 3, -a45, a45, 3),
new ConeV(ArenaChanges.MiddleENVC02000100[1].Center + new WDir(-9, 9), 3, a135, a45, 3),
new Rectangle(center + new WDir(-15, 3), 1, 5), new Rectangle(center + new WDir(15, -3), 1, 5)], InvertForbiddenZone: true);
Expand Down
Loading

0 comments on commit b5f1199

Please sign in to comment.