Skip to content

Commit

Permalink
Merge pull request #613 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
PotD arena bounds, obstacle map setting
  • Loading branch information
CarnifexOptimus authored Feb 16, 2025
2 parents d0143a9 + 46514d7 commit 0ff88ca
Show file tree
Hide file tree
Showing 27 changed files with 160 additions and 125 deletions.
4 changes: 2 additions & 2 deletions BossMod/AI/AIConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ sealed class AIConfig : ConfigNode
[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;

[PropertyDisplay("Allow AI to be out of pathfinding map bounds")]
public bool AllowAIToBeOutsideBounds = false;
[PropertyDisplay("Disable loading obstacle maps", tooltip: "Might be required to be enabled for some some content such as deep dungeons.")]
public bool DisableObstacleMaps = false;

[PropertyDisplay("Movement decision delay", tooltip: "Only change this at your own risk and keep this value low! Too high and it won't move in time for some mechanics. Make sure to readjust the value for different content.")]
public double MoveDelay = 0;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/AI/AIManagementWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public override void Draw()
ImGui.Spacing();
configModified |= ImGui.Checkbox("Manual targeting", ref _config.ManualTarget);
ImGui.SameLine();
configModified |= ImGui.Checkbox("Allow outside bounds", ref _config.AllowAIToBeOutsideBounds);
configModified |= ImGui.Checkbox("Disable loading obstacle maps", ref _config.DisableObstacleMaps);

ImGui.Text("Follow party slot");
ImGui.SameLine();
Expand Down
20 changes: 10 additions & 10 deletions BossMod/AI/AIManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ private void OnCommand(string cmd, string message)
ToggleFollowTarget(messageData);
configModified = cfgFollowT != _config.FollowTarget;
break;
case "OUTOFBOUNDS":
var cfgOOB = _config.AllowAIToBeOutsideBounds;
ToggleOutOfBounds(messageData);
configModified = cfgOOB != _config.AllowAIToBeOutsideBounds;
case "OBSTACLEMAPS":
var cfgOM = _config.DisableObstacleMaps;
ToggleObstacleMaps(messageData);
configModified = cfgOM != _config.DisableObstacleMaps;
break;

case "POSITIONAL":
Expand Down Expand Up @@ -229,26 +229,26 @@ private bool ToggleFocusTargetMaster()
return true;
}

private void ToggleOutOfBounds(string[] messageData)
private void ToggleObstacleMaps(string[] messageData)
{
if (messageData.Length == 1)
_config.AllowAIToBeOutsideBounds = !_config.AllowAIToBeOutsideBounds;
_config.DisableObstacleMaps = !_config.DisableObstacleMaps;
else
{
switch (messageData[1].ToUpperInvariant())
{
case "ON":
_config.AllowAIToBeOutsideBounds = true;
_config.DisableObstacleMaps = false;
break;
case "OFF":
_config.AllowAIToBeOutsideBounds = false;
_config.DisableObstacleMaps = true;
break;
default:
Service.ChatGui.Print($"[AI] Unknown follow target command: {messageData[1]}");
Service.ChatGui.Print($"[AI] Unknown obstacle map command: {messageData[1]}");
return;
}
}
Service.Log($"[AI] Following targets is now {(_config.AllowAIToBeOutsideBounds ? "enabled" : "disabled")}");
Service.Log($"[AI] Obstacle maps are now {(_config.DisableObstacleMaps ? "disabled" : "enabled")}");
}

private void ToggleIdleWhileMounted(string[] messageData)
Expand Down
3 changes: 2 additions & 1 deletion BossMod/BossModule/AIHints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public enum SpecialMode
public WPos PathfindMapCenter;
public ArenaBounds PathfindMapBounds = DefaultBounds;
public Bitmap.Region PathfindMapObstacles;
private static readonly AI.AIConfig _config = Service.Config.Get<AI.AIConfig>();

// list of potential targets
public readonly Enemy?[] Enemies = new Enemy?[100];
Expand Down Expand Up @@ -200,7 +201,7 @@ public void Normalize()
public void InitPathfindMap(Pathfinding.Map map)
{
PathfindMapBounds.PathfindMap(map, PathfindMapCenter);
if (PathfindMapObstacles.Bitmap != null)
if (PathfindMapObstacles.Bitmap != null && !_config.DisableObstacleMaps)
{
var offX = -PathfindMapObstacles.Rect.Left;
var offY = -PathfindMapObstacles.Rect.Top;
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Config/ConfigUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ public void Draw()
{ "maxdistancetarget X", "Sets max distance to target. (default = 2.6)" },
{ "maxdistanceslot X", "Sets max distance to slot. (default = 1)" },
{ "movedelay X", "Sets AI movement decision delay. (default = 0)" },
{ "outofbounds", "Toggles the allow AI to be out of arena bounds setting." },
{ "outofbounds on/off", "Sets the allow AI to be out of arena bounds setting to on or off." },
{ "obstaclemaps", "Toggles loading obstacle maps." },
{ "obstaclemaps on/off", "Sets the loading of obstacle maps to on or off." },
{ "setpresetname X", "Sets an autorotation preset for the AI, eg. setpresetname vbm default." }
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,19 @@ public DD100NybethObdilordStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 208, NameID = 5356)]
public class DD100NybethObdilord : BossModule
{
public DD100NybethObdilord(WorldState ws, Actor primary) : base(ws, primary, new(300f, 300f), new ArenaBoundsCircle(24f))
public DD100NybethObdilord(WorldState ws, Actor primary) : base(ws, primary, arena.Center, arena)
{
ActivateComponent<EncounterHints>();
}

private static readonly WPos[] vertices = [new(302.11f, 276.34f), new(307.39f, 276.36f), new(308.04f, 276.58f), new(309.51f, 278.03f), new(310.04f, 278.17f),
new(311.94f, 278.24f), new(312.52f, 278.61f), new(321.65f, 287.79f), new(321.81f, 288.44f), new(321.9f, 290.34f),
new(324.01f, 292.58f), new(324.28f, 293.17f), new(324.29f, 306.71f), new(324.08f, 307.35f), new(321.86f, 309.64f),
new(321.77f, 312.15f), new(312.3f, 321.62f), new(311.60f, 321.80f), new(309.56f, 321.92f), new(307.32f, 324.12f),
new(306.66f, 324.29f), new(300.1f, 324.22f), new(293.11f, 324.29f), new(292.52f, 323.96f), new(290.57f, 322.02f),
new(290.01f, 321.88f), new(288.08f, 321.81f), new(287.52f, 321.42f), new(278.22f, 312.13f), new(278.14f, 310.01f),
new(278f, 309.45f), new(275.71f, 307.13f), new(275.73f, 293.36f), new(275.86f, 292.68f), new(277.75f, 290.77f),
new(278.12f, 290.27f), new(278.20f, 288.37f), new(278.33f, 287.73f), new(287.51f, 278.59f), new(288.05f, 278.21f),
new(290.12f, 278.13f), new(290.61f, 277.91f), new(291.97f, 276.56f), new(302.11f, 276.34f)];
private static readonly ArenaBoundsComplex arena = new([new PolygonCustom(vertices)]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace BossMod.Heavensward.DeepDungeon.PalaceOfTheDead.DD10PalaceDeathgaze;

public enum OID : uint
{
Boss = 0x1692, // R6.000, x1
Boss = 0x1692 // R6.0
}

public enum AID : uint
Expand All @@ -13,7 +13,7 @@ public enum AID : uint
Bombination = 6418, // Boss->self, 3.0s cast, range 6+R circle
Lumisphere = 6419, // Boss->location, 3.0s cast, range 6 circle
Stormwind = 6417, // Boss->self, 3.0s cast, range 12+R 90-degree cone
Whipcrack = 6416, // Boss->player, no cast, single-target
Whipcrack = 6416 // Boss->player, no cast, single-target
}

class AeroBlast(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.AeroBlast));
Expand All @@ -34,4 +34,7 @@ public DD10PalaceDeathgazeStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 174, NameID = 4986)]
public class DD10PalaceDeathgaze(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -220f), new ArenaBoundsCircle(24f));
public class DD10PalaceDeathgaze(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena)
{
private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-300f, -220f), 24.65f, 48)], [new Rectangle(new(-300f, -245f), 20f, 1.25f)]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ public DD110AlicantoStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 209, NameID = 5371)]
public class DD110Alicanto(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -235f), new ArenaBoundsCircle(24f));
public class DD110Alicanto(WorldState ws, Actor primary) : BossModule(ws, primary, SharedBounds.ArenaBounds2090110.Center, SharedBounds.ArenaBounds2090110);
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
}
class BloodyCaress(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.BloodyCaress), new AOEShapeCone(11.6f, 60f.Degrees()), activeWhileCasting: false);
class FinalSting(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.FinalSting), "Final sting is being cast! \nKill the add or take 98% of your hp!");
class GoldDust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldDust), 8);
class GoldDust(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GoldDust), 8f);
class Leafstorm(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Leafstorm));
class RottenStench(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RottenStench), new AOEShapeRect(48.6f, 6f));

Expand All @@ -63,4 +63,4 @@ public DD120KirtimukhaStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 210, NameID = 5384)]
public class DD120Kirtimukha(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -235f), new ArenaBoundsCircle(24f));
public class DD120Kirtimukha(WorldState ws, Actor primary) : BossModule(ws, primary, SharedBounds.ArenaBounds120130.Center, SharedBounds.ArenaBounds120130);
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public enum AID : uint

class Dissever(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Dissever), new AOEShapeCone(10.8f, 45f.Degrees()), activeWhileCasting: false);

abstract class Voidzones(BossModule module, AID aid, uint oid) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(aid), m => GetVoidzones(m, oid), 2.1f)
abstract class Voidzones(BossModule module, AID aid, uint oid) : Components.PersistentVoidzoneAtCastTarget(module, 6f, ActionID.MakeSpell(aid), m => GetVoidzones(m, oid), 2.1f)
{
private static Actor[] GetVoidzones(BossModule module, uint oid)
{
Expand Down Expand Up @@ -92,4 +92,4 @@ public DD130AlfardStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 211, NameID = 5397)]
public class DD130Alfard(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -237f), new ArenaBoundsCircle(24f));
public class DD130Alfard(WorldState ws, Actor primary) : BossModule(ws, primary, SharedBounds.ArenaBounds120130.Center, SharedBounds.ArenaBounds120130);
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ public DD140AhPuchStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 212, NameID = 5410)]
public class DD140AhPuch(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -237f), new ArenaBoundsCircle(24f));
public class DD140AhPuch(WorldState ws, Actor primary) : BossModule(ws, primary, SharedBounds.ArenaBounds140150.Center, SharedBounds.ArenaBounds140150);
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
for (var i = 0; i < count; ++i)
{
var zombie = zombies[i];
hints.AddForbiddenZone(ShapeDistance.Circle(zombie.Position, 3));
hints.AddForbiddenZone(ShapeDistance.Circle(zombie.Position, 8), WorldState.FutureTime(5d));
hints.AddForbiddenZone(ShapeDistance.Circle(zombie.Position, 3f));
hints.AddForbiddenZone(ShapeDistance.Circle(zombie.Position, 8f), WorldState.FutureTime(5d));
}
}
else
Expand Down Expand Up @@ -92,7 +92,7 @@ public DD150TisiphoneStates(BossModule module) : base(module)
[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 213, NameID = 5424)]
public class DD150Tisiphone : BossModule
{
public DD150Tisiphone(WorldState ws, Actor primary) : base(ws, primary, new(-300f, -237.17f), new ArenaBoundsCircle(24f))
public DD150Tisiphone(WorldState ws, Actor primary) : base(ws, primary, SharedBounds.ArenaBounds140150.Center, SharedBounds.ArenaBounds140150)
{
ActivateComponent<EncounterHints>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public enum AID : uint
Valfodr = 7156, // Boss->player, 4.0s cast, width 6 rect charge + kb
}

class CleaveAuto(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AutoAttack), new AOEShapeCone(11.92f, 45.Degrees()), activeWhileCasting: false);
class HallOfSorrow(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 9, ActionID.MakeSpell(AID.HallOfSorrow), GetVoidzones, 1.3f)
class CleaveAuto(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AutoAttack), new AOEShapeCone(11.92f, 45f.Degrees()), activeWhileCasting: false);
class HallOfSorrow(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 9f, ActionID.MakeSpell(AID.HallOfSorrow), GetVoidzones, 1.3f)
{
private static Actor[] GetVoidzones(BossModule module)
{
Expand All @@ -39,8 +39,8 @@ private static Actor[] GetVoidzones(BossModule module)
}
}

class Infatuation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Infatuation), 7);
class Valfodr(BossModule module) : Components.BaitAwayChargeCast(module, ActionID.MakeSpell(AID.Valfodr), 3);
class Infatuation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Infatuation), 7f);
class Valfodr(BossModule module) : Components.BaitAwayChargeCast(module, ActionID.MakeSpell(AID.Valfodr), 3f);
class ValfodrKB(BossModule module) : Components.Knockback(module, ActionID.MakeSpell(AID.Valfodr), stopAtWall: true) // note actual knockback is delayed by upto 1.2s in replay
{
private int _target;
Expand Down Expand Up @@ -80,11 +80,11 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
return null;
var forbidden = new Func<WPos, float>[count];
for (var i = 0; i < count; ++i)
forbidden[i] = ShapeDistance.Circle(_aoe.Casters[i].Origin, 7);
forbidden[i] = ShapeDistance.Circle(_aoe.Casters[i].Origin, 7f);
return ShapeDistance.Union(forbidden);
}

public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => GetFireballZone() is var z && z != null && z(pos) < 0;
public override bool DestinationUnsafe(int slot, Actor actor, WPos pos) => GetFireballZone() is var z && z != null && z(pos) < 0f;

public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
Expand All @@ -100,7 +100,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
hints.AddForbiddenZone(p =>
{
var dir = (p - kbSource).Normalized();
var proj = Arena.ClampToBounds(p + dir * 25);
var proj = Arena.ClampToBounds(p + dir * 25f);
return dangerZone(proj);
}, _source.Value.Activation);
}
Expand All @@ -120,4 +120,4 @@ public DD160TodesritterStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 214, NameID = 5438)]
public class DD160Todesritter(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -300f), new ArenaBoundsCircle(25f));
public class DD160Todesritter(WorldState ws, Actor primary) : BossModule(ws, primary, SharedBounds.ArenaBounds160170180190.Center, SharedBounds.ArenaBounds160170180190);
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public enum AID : uint
FangsEnd = 7159 // Boss->player, no cast, single-target
}

class Douse(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 8, ActionID.MakeSpell(AID.Douse), GetVoidzones, 0.8f)
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 @@ -73,7 +73,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
{
var effPuddleSize = 8 + Module.PrimaryActor.HitboxRadius;
var tankDist = hints.FindEnemy(Module.PrimaryActor)?.TankDistance ?? 2;
// yaquaru tank distance seems to be around 2-2.5y, but from testing, 3y minimum is needed to move it out of the puddle, either because of rasterization shenanigans or netcode
// yulunggu tank distance seems to be around 2-2.5y, but from testing, 3y minimum is needed to move it out of the puddle, either because of rasterization shenanigans or netcode
var effTankDist = Module.PrimaryActor.HitboxRadius + tankDist + 1;

var len = puddles.Length;
Expand All @@ -87,7 +87,6 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme
}

class Drench(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Drench), new AOEShapeCone(15.75f, 45f.Degrees()), activeWhileCasting: false);

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

class DD170YulungguStates : StateMachineBuilder
Expand All @@ -103,4 +102,4 @@ public DD170YulungguStates(BossModule module) : base(module)
}

[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 215, NameID = 5449)]
public class DD170Yulunggu(WorldState ws, Actor primary) : BossModule(ws, primary, new(-300f, -300f), new ArenaBoundsCircle(25f));
public class DD170Yulunggu(WorldState ws, Actor primary) : BossModule(ws, primary, SharedBounds.ArenaBounds160170180190.Center, SharedBounds.ArenaBounds160170180190);
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public EncounterHints(BossModule module) : base(module)

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID is AID.CharybdisCast or AID.Trounce or AID.Thunderbolt)
if (spell.Action.ID is (uint)AID.CharybdisCast or (uint)AID.Trounce or (uint)AID.Thunderbolt)
++NumCast;
else if ((AID)spell.Action.ID is AID.EclipticMeteor)
else if (spell.Action.ID == (uint)AID.EclipticMeteor)
NumCast = 11;

if (NumCast == 10)
Expand Down Expand Up @@ -153,7 +153,7 @@ private Action<uint> StateCommon(string name, float duration = 10000f)
[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "LegendofIceman", GroupType = BossModuleInfo.GroupType.CFC, GroupID = 216, NameID = 5461, PlanLevel = 60)]
public class DD180Dendainsonne : BossModule
{
public DD180Dendainsonne(WorldState ws, Actor primary) : base(ws, primary, new(-300f, -300f), new ArenaBoundsCircle(25f))
public DD180Dendainsonne(WorldState ws, Actor primary) : base(ws, primary, SharedBounds.ArenaBounds160170180190.Center, SharedBounds.ArenaBounds160170180190)
{
ActivateComponent<Hints>();
}
Expand Down
Loading

0 comments on commit 0ff88ca

Please sign in to comment.