From f77879784efc678f21b21a2e408158e95f30b7b3 Mon Sep 17 00:00:00 2001 From: Andrew Gilewsky Date: Thu, 12 Dec 2024 22:51:41 +0000 Subject: [PATCH 1/5] Some neyoozotel fixes. --- BossMod/Data/Actor.cs | 1 + BossMod/Data/ActorState.cs | 2 +- .../Dawntrail/Hunt/RankS/Neyoozoteel.cs | 22 +++++++++++-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/BossMod/Data/Actor.cs b/BossMod/Data/Actor.cs index 8028394141..d3a31f83d0 100644 --- a/BossMod/Data/Actor.cs +++ b/BossMod/Data/Actor.cs @@ -42,6 +42,7 @@ public sealed record class ActorCastInfo public float RemainingTime => TotalTime - ElapsedTime; public float NPCTotalTime => TotalTime + NPCFinishDelay; public float NPCRemainingTime => NPCTotalTime - ElapsedTime; + public float AdjustedTotalTime => TotalTime + Action.CastTimeExtra(); public bool IsSpell() => Action.Type == ActionType.Spell; public bool IsSpell(AID aid) where AID : Enum => Action == ActionID.MakeSpell(aid); diff --git a/BossMod/Data/ActorState.cs b/BossMod/Data/ActorState.cs index fac820499d..f54a50dee6 100644 --- a/BossMod/Data/ActorState.cs +++ b/BossMod/Data/ActorState.cs @@ -52,7 +52,7 @@ public void Tick(float dt) { act.PrevPosRot = act.PosRot; if (act.CastInfo != null) - act.CastInfo.ElapsedTime += dt; + act.CastInfo.ElapsedTime = Math.Min(act.CastInfo.ElapsedTime + dt, act.CastInfo.AdjustedTotalTime); } } diff --git a/BossMod/Modules/Dawntrail/Hunt/RankS/Neyoozoteel.cs b/BossMod/Modules/Dawntrail/Hunt/RankS/Neyoozoteel.cs index 5ca3e8dfed..29fb753f1f 100644 --- a/BossMod/Modules/Dawntrail/Hunt/RankS/Neyoozoteel.cs +++ b/BossMod/Modules/Dawntrail/Hunt/RankS/Neyoozoteel.cs @@ -5,6 +5,10 @@ public enum OID : uint Boss = 0x4233, // R6.500, x1 } +// 7.11+ +// RLB -> 37370 > 37371 > 42173 +// LBR -> 37396 > 37394 > 37395 +// LBL -> 37396 > 37394 > 42174 public enum AID : uint { AutoAttack = 872, // Boss->player, no cast, single-target @@ -14,14 +18,14 @@ public enum AID : uint WhirlingOmenRLB = 37378, // Boss->self, 3.0s cast, single-target, visual (apply omens: right-left-back) WhirlingOmenLBL = 37379, // Boss->self, 3.0s cast, single-target, visual (apply omens: left-back-left) SapSpiller = 37397, // Boss->self, 12.0s cast, single-target, visual (consume omens, cast instant saps) - NoxiousSapRear = 37394, // Boss->self, no cast, range 30 120-degree cone (consume rear?) - NoxiousSapRight1 = 37395, // Boss->self, no cast, range 30 120-degree cone (consume first right?) - NoxiousSapLeft1 = 37396, // Boss->self, no cast, range 30 120-degree cone (consume first left?) - NoxiousSapRight2 = 37370, // Boss->self, no cast, range 30 120-degree cone (consume second right?) - NoxiousSapLeft2 = 37371, // Boss->self, no cast, range 30 120-degree cone (consume second left?) - NoxiousSapNew1 = 42172, // Boss->self, no cast, range 30 120-degree cone (???) - NoxiousSapNew2 = 42173, // Boss->self, no cast, range 30 120-degree cone (consume back in RLB?) - NoxiousSapNew3 = 42174, // Boss->self, no cast, range 30 120-degree cone (???) + NoxiousSapR1 = 37370, // Boss->self, no cast, range 30 120-degree cone (consume first right?) + NoxiousSapL2 = 37371, // Boss->self, no cast, range 30 120-degree cone (consume second left?) + NoxiousSapB2 = 37394, // Boss->self, no cast, range 30 120-degree cone (consume second rear?) + NoxiousSapR3 = 37395, // Boss->self, no cast, range 30 120-degree cone (consume third right?) + NoxiousSapL1 = 37396, // Boss->self, no cast, range 30 120-degree cone (consume first left?) + NoxiousSapR2 = 42172, // Boss->self, no cast, range 30 120-degree cone (???) + NoxiousSapB3 = 42173, // Boss->self, no cast, range 30 120-degree cone (consume third back?) + NoxiousSapL3 = 42174, // Boss->self, no cast, range 30 120-degree cone (consume third left?) Neurotoxify = 38331, // Boss->self, 5.0s cast, range 40 circle, raidwide + apply delayed stun Cocopult = 37307, // Boss->players, 5.0s cast, range 5 circle stack RavagingRootsCW = 37373, // Boss->self, 5.0s cast, range 30 width 6 cross @@ -100,7 +104,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID is AID.NoxiousSapRear or AID.NoxiousSapRight1 or AID.NoxiousSapLeft1 or AID.NoxiousSapRight2 or AID.NoxiousSapLeft2 or AID.NoxiousSapNew1 or AID.NoxiousSapNew2 or AID.NoxiousSapNew3 && _nextAOE != null) + if ((AID)spell.Action.ID is AID.NoxiousSapR1 or AID.NoxiousSapR2 or AID.NoxiousSapR3 or AID.NoxiousSapL1 or AID.NoxiousSapL2 or AID.NoxiousSapL3 or AID.NoxiousSapB2 or AID.NoxiousSapB3 && _nextAOE != null) { if (!_nextAOE.Value.Rotation.AlmostEqual(spell.Rotation, 0.1f)) ReportError($"Unexpected rotation: got {spell.Rotation}, expected {_nextAOE.Value.Rotation}"); From ff75a1243b933e776376bebe2e4359754dd55ecd Mon Sep 17 00:00:00 2001 From: Andrew Gilewsky Date: Thu, 12 Dec 2024 22:51:57 +0000 Subject: [PATCH 2/5] Minor fru things. --- BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs | 13 +++++++++---- .../Modules/Dawntrail/Ultimate/FRU/P3Apocalypse.cs | 11 +++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs b/BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs index 3c449ff128..9046935303 100644 --- a/BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs +++ b/BossMod/Modules/Dawntrail/Ultimate/FRU/FRUAI.cs @@ -33,7 +33,7 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa { MovementStrategy.Prepull => PrepullPosition(module, assignment), MovementStrategy.DragToCenter => DragToCenterPosition(module), - MovementStrategy.MaxMeleeNearest => primaryTarget != null ? ClosestInMelee(Player.Position, primaryTarget) : Player.Position, + MovementStrategy.MaxMeleeNearest => primaryTarget != null ? primaryTarget.Position + 7.5f * (Player.Position - primaryTarget.Position).Normalized() : Player.Position, MovementStrategy.ClockSpot => ClockSpotPosition(module, assignment, 6), _ => Player.Position }; @@ -45,13 +45,18 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa _ => module.PrimaryActor.Position + new WDir(0, 12.5f) }; + // notes on boss movement: boss top speed is ~8.5m, it moves up to distance 7.5m (both hitboxes + 2m) + // empyrically, if i stand still, i can start moving when boss is ~11m away and it will still be dragged to intended spot private WPos DragToCenterPosition(FRU module) { if (module.PrimaryActor.Position.Z >= module.Center.Z - 1) return module.Center - new WDir(0, 6); // boss is positioned, go to N clockspot - var dragSpot = module.Center + new WDir(0, 7.75f); // we need to stay approx here, it's fine to overshoot a little bit - then when boss teleports, it won't turn - var meleeSpot = ClosestInMelee(dragSpot, module.PrimaryActor); - return UptimeDowntimePos(dragSpot, meleeSpot, 0, GCD); + var dragDistance = module.PrimaryActor.HitboxRadius + Player.HitboxRadius + 2.25f; // we need to stay approx here, it's fine to overshoot a little bit - then when boss teleports, it won't turn + var meleeDistance = module.PrimaryActor.HitboxRadius + Player.HitboxRadius + 2.75f; // -0.25 is a small extra leeway + var dragDir = (module.Center - module.PrimaryActor.Position).Normalized(); + var dragSpot = module.Center + dragDistance * dragDir; + var timeToMelee = ((dragSpot - module.PrimaryActor.Position).Length() - meleeDistance) / (Speed() + 8.5f); // assume 8.5 boss speed... + return GCD > timeToMelee + 0.1f ? dragSpot : module.PrimaryActor.Position + meleeDistance * dragDir; } private WPos ClockSpotPosition(FRU module, PartyRolesConfig.Assignment assignment, float range) => assignment switch diff --git a/BossMod/Modules/Dawntrail/Ultimate/FRU/P3Apocalypse.cs b/BossMod/Modules/Dawntrail/Ultimate/FRU/P3Apocalypse.cs index 63948fe00d..dae4ddaf10 100644 --- a/BossMod/Modules/Dawntrail/Ultimate/FRU/P3Apocalypse.cs +++ b/BossMod/Modules/Dawntrail/Ultimate/FRU/P3Apocalypse.cs @@ -36,6 +36,17 @@ void addAt(int position, DateTime activation) public override IEnumerable ActiveAOEs(int slot, Actor actor) => _aoes.Take(6); + public override void DrawArenaForeground(int pcSlot, Actor pc) + { + // draw safespots (TODO: improve - account for concrete assignments, show different spots at different mechanic stages) + if (_aoes.Count > 0 && NumCasts < 16 && _starting != null) + { + var safeOff = 10 * (_starting.Value - _rotation).ToDirection(); + Arena.AddCircle(Module.Center + safeOff, 1, ArenaColor.Safe); + Arena.AddCircle(Module.Center - safeOff, 1, ArenaColor.Safe); + } + } + public override void OnActorCreated(Actor actor) { if ((OID)actor.OID == OID.ApocalypseLight) From 5d585c417c0273e18bac5ede6fd85a54f7a405ae Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Fri, 13 Dec 2024 07:00:28 +0100 Subject: [PATCH 3/5] refactored Slice is Right module --- .../TheSliceIsRight/TheSliceIsRight.cs | 131 ++++++++---------- 1 file changed, 54 insertions(+), 77 deletions(-) diff --git a/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs b/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs index 8e22c5fd1f..1edcae6643 100644 --- a/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs +++ b/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs @@ -2,11 +2,11 @@ namespace BossMod.Global.GoldSaucer.SliceIsRight; public enum OID : uint { - Boss = 0x25AB, //R=1.80 Yojimbo - Daigoro = 0x25AC, //R=2.50 - Bamboo = 0x25AD, //R=0.50 + Boss = 0x25AB, //R=1.8 + Daigoro = 0x25AC, //R=2.5 + Bamboo = 0x25AD, //R=0.5 Helper = 0x1EAEDF, - Somethingoutsidethearena = 0x2BC8, //not sure what this does, spawns multiple times before the minigame starts, but casts something during the minigame, probably just for visuals + VisualOutsideArena = 0x2BC8, HelperCupPhase1 = 0x1EAEB7, HelperCupPhase2 = 0x1EAEB6, HelperCupPhase3 = 0x1EAE9D, @@ -18,106 +18,82 @@ public enum OID : uint public enum AID : uint { - Yoyimbodoesstuff1 = 19070, // 25AB->self, no cast, single-target - Yoyimbodoesstuff2 = 18331, // 25AB->self, no cast, single-tat - Yoyimbodoesstuff3 = 18329, // 25AB->self, no cast, single-target - Yoyimbodoesstuff4 = 18332, // 25AB->self, no cast, single-target - Yoyimbodoesstuff5 = 18328, // 25AB->location, no cast, single-target - Yoyimbodoesstuff6 = 18326, // 25AB->self, 3.0s cast, single-target - Yoyimbodoesstuff7 = 18339, // 25AB->self, 3.0s cast, single-target - Yoyimbodoesstuff8 = 18340, // 25AB->self, no cast, single-target - Yoyimbodoesstuff9 = 19026, // 25AB->self, no cast, single-target - Somethingoutsidethearena = 18338, // 2BC8->self, no cast, single-target - BambooSplit = 18333, // 25AD->self, 0.7s cast, range 28 width 5 rect - BambooCircleFall = 18334, // 25AD->self, 0.7s cast, range 11 circle - BambooSpawn = 18327, // 25AD->self, no cast, range 3 circle - FirstGilJump = 18335, // 25AC->location, 2.5s cast, width 7 rect charge - NextGilJump = 18336, // 25AC->location, 1.5s cast, width 7 rect charge - BadCup = 18337, // 25AC->self, 1.0s cast, range 15+R 120-degree cone + YojimboVisual1 = 19070, // Boss->self, no cast, single-target + YojimboVisual2 = 18331, // Boss->self, no cast, single-tat + YojimboVisual3 = 18329, // Boss->self, no cast, single-target + YojimboVisual4 = 18332, // Boss->self, no cast, single-target + YojimboVisual5 = 18328, // Boss->location, no cast, single-target + YojimboVisual6 = 18326, // Boss->self, 3.0s cast, single-target + YojimboVisual7 = 18339, // Boss->self, 3.0s cast, single-target + YojimboVisual8 = 18340, // Boss->self, no cast, single-target + YojimboVisual9 = 19026, // Boss->self, no cast, single-target + VisualOutsideArena = 18338, // VisualOutsideArena->self, no cast, single-target + + BambooSplit = 18333, // Bamboo->self, 0.7s cast, range 28 width 5 rect + BambooCircleFall = 18334, // Bamboo->self, 0.7s cast, range 11 circle + BambooSpawn = 18327, // Bamboo->self, no cast, range 3 circle + FirstGilJump = 18335, // Daigoro->location, 2.5s cast, width 7 rect charge + NextGilJump = 18336, // Daigoro->location, 1.5s cast, width 7 rect charge + BadCup = 18337, // Daigoro->self, 1.0s cast, range 15+R 120-degree cone } class BambooSplits(BossModule module) : Components.GenericAOEs(module) { - private readonly List _doublesidedsplit = []; - private readonly List _singlesplit = []; - private readonly List _circle = []; - private readonly List _doublesidedsplitToberemoved = []; - private readonly List _singlesplitToberemoved = []; - private readonly List _circleToberemoved = []; - private readonly List _bamboospawn = []; - private static readonly AOEShapeRect rectdouble = new(28, 2.5f, 28); - private static readonly AOEShapeRect rectsingle = new(28, 2.5f); + private readonly List _aoes = []; + private static readonly AOEShapeRect rect = new(28, 2.5f); private static readonly AOEShapeCircle circle = new(11); private static readonly AOEShapeCircle bamboospawn = new(3); - private DateTime _activation; - private DateTime _time; + private static readonly Angle a90 = 90.Degrees(); - public override IEnumerable ActiveAOEs(int slot, Actor actor) - { - foreach (var b in _doublesidedsplit) - yield return new(rectdouble, b.Position, b.Rotation + 90.Degrees(), _activation.AddSeconds(7)); - foreach (var b in _singlesplit) - yield return new(rectsingle, b.Position, b.Rotation + 90.Degrees(), _activation.AddSeconds(7)); - foreach (var b in _circle) - yield return new(circle, b.Position, b.Rotation, _activation.AddSeconds(7)); - foreach (var b in _bamboospawn) - yield return new(bamboospawn, b.Position); //activation time varies a lot (depending on the set?), just avoid entirely - } + public override IEnumerable ActiveAOEs(int slot, Actor actor) => _aoes; public override void OnActorCreated(Actor actor) { if ((OID)actor.OID is OID.HelperCircle or OID.HelperDoubleRect or OID.HelperSingleRect) - _bamboospawn.Add(actor); - } - - public override void Update() - { - if (_time != default && WorldState.CurrentTime > _time) - { - _time = default; - _circle.RemoveAll(_circleToberemoved.Contains); - _circleToberemoved.Clear(); - _singlesplit.RemoveAll(_singlesplitToberemoved.Contains); - _singlesplitToberemoved.Clear(); - _doublesidedsplit.RemoveAll(_doublesidedsplitToberemoved.Contains); - _doublesidedsplitToberemoved.Clear(); - } + _aoes.Add(new(bamboospawn, actor.Position, default, WorldState.FutureTime(2.7f))); } public override void OnActorEAnim(Actor actor, uint state) { - if (state == 0x00010002) //bamboo gets activated, technically we could draw the AOEs before, but then we could see different sets overlap - { - if ((OID)actor.OID == OID.HelperCircle && !_circle.Contains(actor)) - _circle.Add(actor); - else if ((OID)actor.OID == OID.HelperSingleRect && !_singlesplit.Contains(actor)) - _singlesplit.Add(actor); - else if ((OID)actor.OID == OID.HelperDoubleRect && !_doublesidedsplit.Contains(actor)) - _doublesidedsplit.Add(actor); - _activation = WorldState.FutureTime(7); - } - else if (state == 0x00040008) //bamboo deactivation animation, spell casts end about 0.75s later + if (state == 0x00010002) { + var activation = WorldState.FutureTime(7); // activation varies per set, taking the lowest we can find if ((OID)actor.OID == OID.HelperCircle) - _circleToberemoved.Add(actor); + _aoes.Add(new(circle, actor.Position, actor.Rotation, activation)); else if ((OID)actor.OID == OID.HelperSingleRect) - _singlesplitToberemoved.Add(actor); + _aoes.Add(new(rect, actor.Position, actor.Rotation + a90, activation)); else if ((OID)actor.OID == OID.HelperDoubleRect) - _doublesidedsplitToberemoved.Add(actor); - _time = WorldState.FutureTime(0.75f); + { + _aoes.Add(new(rect, actor.Position, actor.Rotation + a90, activation)); + _aoes.Add(new(rect, actor.Position, actor.Rotation - a90, activation)); + } } } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if (_bamboospawn.Count > 0 && (AID)spell.Action.ID == AID.BambooSpawn) - _bamboospawn.RemoveAt(0); + if (_aoes.Count != 0) + { + switch ((AID)spell.Action.ID) + { + case AID.BambooSpawn: + _aoes.RemoveAll(x => x.Origin == caster.Position && x.Shape == bamboospawn); + break; + case AID.BambooSplit: + case AID.BambooCircleFall: + AOEInstance[] aoesToRemove = [.. _aoes.Where((aoe, index) => aoe.Origin == caster.Position).Take(2)]; + if (aoesToRemove.Length >= 1) + _aoes.Remove(aoesToRemove[0]); + if (aoesToRemove.Length == 2 && aoesToRemove[0].Activation == aoesToRemove[1].Activation) + _aoes.Remove(aoesToRemove[1]); + break; + } + } } } class DaigoroFirstGilJump(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.FirstGilJump), 3.5f); class DaigoroNextGilJump(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.NextGilJump), 3.5f); -class DaigoroBadCup(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BadCup), new AOEShapeCone(17.5f, 60.Degrees())); class TheSliceIsRightStates : StateMachineBuilder { @@ -131,7 +107,8 @@ public TheSliceIsRightStates(BossModule module) : base(module) } [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.GoldSaucer, GroupID = 181, NameID = 9066)] -public class TheSliceIsRight(WorldState ws, Actor primary) : BossModule(ws, primary, new(70.5f, -36), new ArenaBoundsCircle(15)) +public class TheSliceIsRight(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - protected override bool CheckPull() { return PrimaryActor != null; } + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(70.5f, -36), 15, 28)]); + protected override bool CheckPull() => PrimaryActor != null; } From 9cc53c2989e8aea37f6ce770d90035914ba36a92 Mon Sep 17 00:00:00 2001 From: Andrew Gilewsky Date: Fri, 13 Dec 2024 19:02:52 +0000 Subject: [PATCH 4/5] FRU small improvement. --- .../Dawntrail/Ultimate/FRU/P1FallOfFaith.cs | 140 +++++++++++------- 1 file changed, 87 insertions(+), 53 deletions(-) diff --git a/BossMod/Modules/Dawntrail/Ultimate/FRU/P1FallOfFaith.cs b/BossMod/Modules/Dawntrail/Ultimate/FRU/P1FallOfFaith.cs index 0bc5eebaa2..cf19894d2a 100644 --- a/BossMod/Modules/Dawntrail/Ultimate/FRU/P1FallOfFaith.cs +++ b/BossMod/Modules/Dawntrail/Ultimate/FRU/P1FallOfFaith.cs @@ -3,19 +3,12 @@ // TODO: more positioning options?.. class P1FallOfFaith(BossModule module) : Components.CastCounter(module, default) { - private struct PlayerState - { - public int TetherOrder; // 0 if no tether, otherwise 1-4 - public bool? OddGroup; - public WPos Spot1; - public WPos Spot2; - } - private readonly FRUConfig _config = Service.Config.Get(); - private readonly PlayerState[] _states = new PlayerState[PartyState.MaxPartySize]; + private readonly int[] _playerOrder = new int[PartyState.MaxPartySize]; // 0 if not assigned, 1-4 if tethered, 5-8 for conga help order (5/6 help group 1, 7/8 help group 2) private readonly List _tetherTargets = []; private readonly List _currentBaiters = []; private BitMask _fireTethers; // bit i is set if i'th tether is fire + private int _numFetters; private static readonly AOEShapeCone _shapeFire = new(60, 45.Degrees()); private static readonly AOEShapeCone _shapeLightning = new(60, 60.Degrees()); @@ -32,11 +25,11 @@ public override void Update() public override void AddHints(int slot, Actor actor, TextHints hints) { - ref var state = ref _states[slot]; - if (state.TetherOrder != 0) - hints.Add($"Order: {state.TetherOrder}", false); - else if (state.OddGroup != null) - hints.Add($"Help group {(state.OddGroup.Value ? 1 : 2)}", false); + var order = _playerOrder[slot]; + if (order > 4) + hints.Add($"Help group {(order < 7 ? 1 : 2)}", false); + else if (order > 0) + hints.Add($"Order: {order}", false); if (ActiveBaits(slot, actor, true).Any(bait => bait.shape.Check(actor.Position, bait.origin, bait.dir))) hints.Add("GTFO from baited aoe!"); @@ -50,7 +43,12 @@ public override void AddGlobalHints(GlobalHints hints) hints.Add(string.Join(" -> ", Enumerable.Range(NumCasts, _tetherTargets.Count - NumCasts).Select(i => _fireTethers[i] ? "Fire" : "Lightning"))); } - public override PlayerPriority CalcPriority(int pcSlot, Actor pc, int playerSlot, Actor player, ref uint customColor) => PlayerPriority.Normal; + public override PlayerPriority CalcPriority(int pcSlot, Actor pc, int playerSlot, Actor player, ref uint customColor) + { + // if player should bait, highlight source and other assistants + var source = AssignedBaitSource(pcSlot); + return source == player ? PlayerPriority.Danger : source != null && source == AssignedBaitSource(playerSlot) ? PlayerPriority.Interesting : PlayerPriority.Normal; + } public override void DrawArenaBackground(int pcSlot, Actor pc) { @@ -63,11 +61,19 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) foreach (var bait in ActiveBaits(pcSlot, pc, false)) bait.shape.Outline(Arena, bait.origin, bait.dir, _fireTethers[NumCasts] ? ArenaColor.Safe : ArenaColor.Danger); - ref var state = ref _states[pcSlot]; - var firstBait = state.OddGroup == true ? 0 : 1; - var safespot = NumCasts <= firstBait ? state.Spot1 : NumCasts <= firstBait + 2 ? state.Spot2 : default; - if (safespot != default) - Arena.AddCircle(safespot, 1, ArenaColor.Safe); + var baitOrder = NextAssignedBaitOrder(pcSlot); + if (baitOrder > 0) + { + var tetherSpot = TetherSpot(baitOrder); + var isBaiter = _playerOrder[pcSlot] == baitOrder; + Arena.AddCircle(tetherSpot, 1, isBaiter ? ArenaColor.Safe : ArenaColor.Danger); + if (!isBaiter) + { + var offset = BaitOffset(_playerOrder[pcSlot], _fireTethers[baitOrder - 1]); + if (offset != default) + Arena.AddCircle(tetherSpot + offset, 1, ArenaColor.Safe); + } + } } public override void OnTethered(Actor source, ActorTetherInfo tether) @@ -83,12 +89,12 @@ public override void OnTethered(Actor source, ActorTetherInfo tether) var slot = Raid.FindSlot(tether.Target); if (slot >= 0) { - var order = _states[slot].TetherOrder = _tetherTargets.Count; - var odd = (order & 1) != 0; - var firstBait = order <= 2; - _states[slot].OddGroup = odd; - _states[slot].Spot1 = TetherSpot(odd, !firstBait); - _states[slot].Spot2 = TetherSpot(odd, firstBait); + _playerOrder[slot] = _tetherTargets.Count; + //var odd = (order & 1) != 0; + //var firstBait = order <= 2; + //_states[slot].OddGroup = odd; + //_states[slot].Spot1 = TetherSpot(odd, !firstBait); + //_states[slot].Spot2 = TetherSpot(odd, firstBait); } if (_tetherTargets.Count == 4) @@ -98,9 +104,15 @@ public override void OnTethered(Actor source, ActorTetherInfo tether) public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if ((AID)spell.Action.ID is AID.FallOfFaithSinsmite or AID.FallOfFaithSinblaze) + switch ((AID)spell.Action.ID) { - ++NumCasts; + case AID.FloatingFetters: + ++_numFetters; + break; + case AID.FallOfFaithSinsmite: + case AID.FallOfFaithSinblaze: + ++NumCasts; + break; } } @@ -108,49 +120,71 @@ private void InitAssignments() { List<(int slot, int prio)> conga = []; foreach (var (slot, group) in _config.P1FallOfFaithAssignment.Resolve(Raid)) - if (_states[slot].TetherOrder == 0) + if (_playerOrder[slot] == 0) conga.Add((slot, group)); if (conga.Count != 4) return; // no assignments - conga.SortBy(c => c.prio); - InitNormalSpots(conga[0].slot, true, true); - InitNormalSpots(conga[1].slot, true, false); - InitNormalSpots(conga[2].slot, false, false); - InitNormalSpots(conga[3].slot, false, true); + for (int i = 0; i < conga.Count; ++i) + _playerOrder[conga[i].slot] = i + 5; + + //InitNormalSpots(conga[0].slot, true, true); + //InitNormalSpots(conga[1].slot, true, false); + //InitNormalSpots(conga[2].slot, false, false); + //InitNormalSpots(conga[3].slot, false, true); } - private WPos TetherSpot(bool odd, bool far) + private bool IsGroupEven(int order) => order is 2 or 4 or 7 or 8; + + private int NextAssignedBaitOrder(int slot) { - var dir = _config.P1FallOfFaithEW ? 90.Degrees() : 0.Degrees(); - if (odd) - dir -= 180.Degrees(); - return Module.Center + (far ? 7 : 4) * dir.ToDirection(); + var order = _playerOrder[slot]; + if (order == 0) + return 0; + var nextCast = IsGroupEven(order) ? 1 : 0; + if (NumCasts > nextCast) + nextCast += 2; // first bait is done + return NumCasts <= nextCast && nextCast < _tetherTargets.Count ? nextCast + 1 : 0; } - private WPos ProteanSpot(bool odd, bool close) + private Actor? AssignedBaitSource(int slot) { - var baiter = TetherSpot(odd, false); - var offset = close ? 3 : -3; - WDir dir = _config.P1FallOfFaithEW ? new(0, -1) : new(1, 0); - return baiter + offset * dir; + var order = NextAssignedBaitOrder(slot); + return order > 0 ? _tetherTargets[order - 1] : null; } - private WPos NormalSpot(bool odd, bool close, int order) => _fireTethers[order] ? TetherSpot(odd, true) : ProteanSpot(odd, close); + private WDir GroupDirection(int order) + { + if (order == 0) + return default; + var dir = _config.P1FallOfFaithEW ? 90.Degrees() : 0.Degrees(); + if (!IsGroupEven(order)) + dir -= 180.Degrees(); + return dir.ToDirection(); + } + + // note: if target is fettered, it can no longer move + private WPos TetherSpot(int order) => order <= _numFetters ? _tetherTargets[order - 1].Position : Module.Center + 5.5f * GroupDirection(order); + + private WDir CenterBaitOffset(int order) => GroupDirection(order) * 2; - private void InitNormalSpots(int slot, bool odd, bool close) + private WDir ProteanBaitOffset(int order) { - ref var state = ref _states[slot]; - state.OddGroup = odd; - state.Spot1 = NormalSpot(odd, close, odd ? 0 : 1); - state.Spot2 = NormalSpot(odd, close, odd ? 2 : 3); + if (order < 5) + return default; + WDir dir = _config.P1FallOfFaithEW ? new(0, -1) : new(1, 0); + return (order is 5 or 8 ? 2 : -2) * dir; } + private WDir BaitOffset(int order, bool fire) => order == 0 ? default : order < 5 || fire ? CenterBaitOffset(order) : ProteanBaitOffset(order); + private bool ShouldBeBaiting(int slot) { - var nextBaitsOdd = (NumCasts & 1) == 0; - ref var state = ref _states[slot]; - return state.OddGroup == null || state.OddGroup == nextBaitsOdd; // if there are no assignments, we don't actually know whether player should be baiting... + var order = _playerOrder[slot]; + if (order == 0) + return true; // if there are no assignments, we don't actually know whether player should be baiting... + var nextBaitsEven = (NumCasts & 1) != 0; + return IsGroupEven(order) == nextBaitsEven; } private IEnumerable<(AOEShapeCone shape, WPos origin, Angle dir)> ActiveBaits(int slot, Actor actor, bool wantDangerous) From c5da1a1bc6033ca4b51fc29632fdea3ffd4384fa Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:16:19 +0100 Subject: [PATCH 5/5] knockback AI for Jeuno boss 4 --- BossMod/Autorotation/akechi/AkechiGNB.cs | 2 - .../Alliance/A11Prishe/AuroralUppercut.cs | 12 +-- .../Alliance/A14ShadowLord/A14ShadowLord.cs | 8 +- .../Alliance/A14ShadowLord/CthonicFury.cs | 30 ------- .../Alliance/A14ShadowLord/DarkNebula.cs | 81 +++++++++++++++++++ .../Alliance/A14ShadowLord/GigaSlash.cs | 15 ++-- .../Dungeon/D02WorqorZormor/D023Gurfurlur.cs | 2 +- .../MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs | 2 +- .../TheSliceIsRight/TheSliceIsRight.cs | 2 +- .../T04PortaDecumana/T04PortaDecumana2.cs | 2 +- BossMod/Pathfinding/NavigationDecision.cs | 2 +- 11 files changed, 105 insertions(+), 53 deletions(-) create mode 100644 BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/DarkNebula.cs diff --git a/BossMod/Autorotation/akechi/AkechiGNB.cs b/BossMod/Autorotation/akechi/AkechiGNB.cs index 70ffff2953..135a17ad17 100644 --- a/BossMod/Autorotation/akechi/AkechiGNB.cs +++ b/BossMod/Autorotation/akechi/AkechiGNB.cs @@ -518,7 +518,6 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa if (ShouldUseDoubleDown(ddStrat, primaryTarget)) QueueGCD(AID.DoubleDown, primaryTarget, ddStrat == OffensiveStrategy.Force || Ammo == 1 ? GCDPriority.ForcedGCD : GCDPriority.DoubleDown); - //Gnashing Fang Combo execution if (GunComboStep == 1) QueueGCD(AID.SavageClaw, primaryTarget, gfStrat == GnashingStrategy.ForceClaw ? GCDPriority.ForcedGCD : GCDPriority.GF23); @@ -543,7 +542,6 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget, floa if (Unlocked(AID.BurstStrike) && Unlocked(AID.Bloodfest) && ShouldUseBurstStrike(strikeStrat, primaryTarget)) QueueGCD(AID.BurstStrike, primaryTarget, strikeStrat == OffensiveStrategy.Force ? GCDPriority.ForcedGCD : nmCD < 1 ? GCDPriority.ForcedGCD : GCDPriority.BurstStrike); - //Fated Circle execution var fcStrat = strategy.Option(Track.FatedCircle).As(); if (ShouldUseFatedCircle(fcStrat, primaryTarget)) diff --git a/BossMod/Modules/Dawntrail/Alliance/A11Prishe/AuroralUppercut.cs b/BossMod/Modules/Dawntrail/Alliance/A11Prishe/AuroralUppercut.cs index 391a4279c9..fe91e0df31 100644 --- a/BossMod/Modules/Dawntrail/Alliance/A11Prishe/AuroralUppercut.cs +++ b/BossMod/Modules/Dawntrail/Alliance/A11Prishe/AuroralUppercut.cs @@ -3,7 +3,7 @@ namespace BossMod.Dawntrail.Alliance.A11Prishe; class AuroralUppercut(BossModule module) : Components.Knockback(module, ignoreImmunes: true) { private Source? _source; - public override IEnumerable Sources(int slot, Actor actor) => Utils.ZeroOrOne(_source); + public override IEnumerable Sources(int slot, Actor actor) => _source != null && actor.FindStatus(SID.Knockback) == null ? Utils.ZeroOrOne(_source) : []; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { @@ -30,15 +30,15 @@ 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(), a59 = 59.Degrees(); + private static readonly Angle a45 = 45.Degrees(), a135 = 135.Degrees(), a44 = 44.Degrees(), a13 = 12.5f.Degrees(), a59 = 59.Degrees(); private static readonly WPos center = A11Prishe.ArenaCenter; private AOEInstance? _aoe; 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); + [new ConeHA(center, 10, -a135, a13), new ConeHA(center, 10, a45, a13)], InvertForbiddenZone: true); 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); + [new ConeHA(center, 10, a135, a13), new ConeHA(center, 10, -a45, a13)], InvertForbiddenZone: true); + private static readonly AOEShapeCustom hintENVC00020001KB38 = new([new ConeHA(center, 5, -a135, a13), new ConeHA(center, 5, a45, a13)], InvertForbiddenZone: true); + private static readonly AOEShapeCustom hintENVC02000100KB38 = new([new ConeHA(center, 5, a135, a13), new ConeHA(center, 5, -a45, a13)], InvertForbiddenZone: true); 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), diff --git a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/A14ShadowLord.cs b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/A14ShadowLord.cs index 5f63cc3acb..672b0a3e5c 100644 --- a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/A14ShadowLord.cs +++ b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/A14ShadowLord.cs @@ -13,10 +13,10 @@ public class A14ShadowLord(WorldState ws, Actor primary) : BossModule(ws, primar private const float HalfWidth = 1.9f; public static readonly WPos ArenaCenter = new(150, 800); public static readonly ArenaBoundsCircle DefaultBounds = new(30); - private static readonly Circle[] circles = [new(new(166, 800), RadiusSmall), new(new(134, 800), RadiusSmall), + public static readonly Circle[] Circles = [new(new(166, 800), RadiusSmall), new(new(134, 800), RadiusSmall), new(new(150, 816), RadiusSmall), new(new(150, 784), RadiusSmall)]; - private static readonly RectangleSE[] rects = [new(circles[1].Center, circles[2].Center, HalfWidth), new(circles[1].Center, circles[3].Center, HalfWidth), - new(circles[3].Center, circles[0].Center, HalfWidth), new(circles[0].Center, circles[2].Center, HalfWidth)]; - public static readonly Shape[] Combined = [.. circles, .. rects]; + private static readonly RectangleSE[] rects = [new(Circles[1].Center, Circles[2].Center, HalfWidth), new(Circles[1].Center, Circles[3].Center, HalfWidth), + new(Circles[3].Center, Circles[0].Center, HalfWidth), new(Circles[0].Center, Circles[2].Center, HalfWidth)]; + public static readonly Shape[] Combined = [.. Circles, .. rects]; public static readonly ArenaBoundsComplex ComplexBounds = new(Combined); } diff --git a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/CthonicFury.cs b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/CthonicFury.cs index a5a204f788..c0146a24a9 100644 --- a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/CthonicFury.cs +++ b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/CthonicFury.cs @@ -64,36 +64,6 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) }; } -class DarkNebula(BossModule module) : Components.Knockback(module) -{ - public readonly List Casters = []; - - public override IEnumerable Sources(int slot, Actor actor) - { - foreach (var caster in Casters.Take(2)) - { - var dir = caster.CastInfo?.Rotation ?? caster.Rotation; - var kind = dir.ToDirection().OrthoL().Dot(actor.Position - caster.Position) > 0 ? Kind.DirLeft : Kind.DirRight; - yield return new(caster.Position, 20, Module.CastFinishAt(caster.CastInfo), null, dir, kind); - } - } - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.DarkNebulaShort or AID.DarkNebulaLong) - Casters.Add(caster); - } - - public override void OnCastFinished(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.DarkNebulaShort or AID.DarkNebulaLong) - { - ++NumCasts; - Casters.Remove(caster); - } - } -} - class EchoesOfAgony(BossModule module) : Components.StackWithIcon(module, (uint)IconID.EchoesOfAgony, ActionID.MakeSpell(AID.EchoesOfAgonyAOE), 5, 9.2f, PartyState.MaxAllianceSize, PartyState.MaxAllianceSize) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) diff --git a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/DarkNebula.cs b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/DarkNebula.cs new file mode 100644 index 0000000000..8f15fcac41 --- /dev/null +++ b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/DarkNebula.cs @@ -0,0 +1,81 @@ +namespace BossMod.Dawntrail.Alliance.A14ShadowLord; + +class DarkNebula(BossModule module) : Components.Knockback(module) +{ + private const int Length = 4; + private const float HalfWidth = 1.75f; + + public readonly List Casters = []; + + private static readonly Angle a90 = 90.Degrees(); + private static readonly List<(Predicate Matcher, int[] CircleIndices, WDir Directions)> PositionMatchers = + [ + (pos => pos == new WPos(142, 792), [3, 1], 45.Degrees().ToDirection()), // 135° + (pos => pos == new WPos(158, 792), [0, 3], -135.Degrees().ToDirection()), // 45° + (pos => pos == new WPos(158, 808), [2, 0], -45.Degrees().ToDirection()), // -45° + (pos => pos.AlmostEqual(new WPos(142, 808), 1), [1, 2], 135.Degrees().ToDirection()) // -135° + ]; + + public override IEnumerable Sources(int slot, Actor actor) + { + var count = Casters.Count; + if (count != 0) + { + for (var i = 0; i < count; ++i) + { + if (i < 2) + { + var caster = Casters[i]; + var dir = caster.CastInfo?.Rotation ?? caster.Rotation; + var kind = dir.ToDirection().OrthoL().Dot(actor.Position - caster.Position) > 0 ? Kind.DirLeft : Kind.DirRight; + yield return new(caster.Position, 20, Module.CastFinishAt(caster.CastInfo), null, dir, kind); + } + } + } + } + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID is AID.DarkNebulaShort or AID.DarkNebulaLong) + Casters.Add(caster); + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID is AID.DarkNebulaShort or AID.DarkNebulaLong) + { + ++NumCasts; + Casters.Remove(caster); + } + } + + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + if (Casters.Count == 0) + return; + + var forbidden = new List>(); + var caster0 = Casters[0]; + static Func CreateForbiddenZone(int circleIndex, WDir dir) + => ShapeDistance.InvertedRect(A14ShadowLord.Circles[circleIndex].Center, dir, Length, 0, HalfWidth); + + var mapping = PositionMatchers.FirstOrDefault(m => m.Matcher(caster0.Position)); + + if (Casters.Count == 1) + { + foreach (var circleIndex in mapping.CircleIndices) + { + forbidden.Add(CreateForbiddenZone(circleIndex, mapping.Directions)); + } + } + else + { + var caster1 = Casters[1]; + var rotationMatch = caster0.Rotation.AlmostEqual(caster1.Rotation + a90, Angle.DegToRad); + var circleIndex = rotationMatch ? mapping.CircleIndices.First() : mapping.CircleIndices.Last(); + forbidden.Add(CreateForbiddenZone(circleIndex, mapping.Directions)); + } + + hints.AddForbiddenZone(p => forbidden.Max(f => f(p)), Sources(slot, actor).FirstOrDefault().Activation); + } +} diff --git a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/GigaSlash.cs b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/GigaSlash.cs index a9a6448e58..314b2c4b52 100644 --- a/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/GigaSlash.cs +++ b/BossMod/Modules/Dawntrail/Alliance/A14ShadowLord/GigaSlash.cs @@ -7,23 +7,26 @@ class GigaSlash(BossModule module) : Components.GenericAOEs(module) AID.GigaSlashNightfallBAOE3, AID.GigaSlashNightfallLAOE1, AID.GigaSlashNightfallRAOE2, AID.GigaSlashNightfallRAOE1, AID.GigaSlashNightfallLAOE2]; private static readonly AOEShapeCone[] _shapes = [new(60, 112.5f.Degrees()), new(60, 135.Degrees()), new(60, 105.Degrees())]; - public override IEnumerable ActiveAOEs(int slot, Actor actor) => AOEs.Take(1); + public override IEnumerable ActiveAOEs(int slot, Actor actor) + { + if (AOEs.Count > 0) + yield return AOEs[0] with { Risky = Module.FindComponent()?.Casters.Count == 0 }; + } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { + if (AOEs.Count == 0) + return; base.AddAIHints(slot, actor, assignment, hints); // stay close to the middle if there is next imminent aoe from same origin - if (AOEs.Count > 1 && AOEs[0].Origin == AOEs[1].Origin) + if (Module.FindComponent()?.Casters.Count == 0 && AOEs.Count > 1 && AOEs[0].Origin == AOEs[1].Origin) hints.AddForbiddenZone(ShapeDistance.InvertedCircle(AOEs[0].Origin, 3), AOEs[0].Activation); } public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - var rotation = spell.Rotation; - var position = caster.Position; - void AddAOE(AOEShapeCone shape, float rotationOffset, float finishOffset) - => AOEs.Add(new(shape, position, rotation + rotationOffset.Degrees(), Module.CastFinishAt(spell, finishOffset))); + => AOEs.Add(new(shape, caster.Position, spell.Rotation + rotationOffset.Degrees(), Module.CastFinishAt(spell, finishOffset))); switch ((AID)spell.Action.ID) { diff --git a/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D023Gurfurlur.cs b/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D023Gurfurlur.cs index d101036e29..505e08d077 100644 --- a/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D023Gurfurlur.cs +++ b/BossMod/Modules/Dawntrail/Dungeon/D02WorqorZormor/D023Gurfurlur.cs @@ -86,7 +86,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme for (var i = 0; i < len; ++i) { var o = sph[i]; - orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.5f * o.Rotation.ToDirection(), 0.5f)); + orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.5f * o.Rotation.ToDirection(), 0.55f)); } } if (orbs.Count != 0) diff --git a/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs b/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs index 0afb73125a..d99a71bef6 100644 --- a/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs +++ b/BossMod/Modules/Dawntrail/Quest/MSQ/TheWarmthOfTheFamily/Tturuhhetso.cs @@ -111,7 +111,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme var orbs = new List>(); if (ActiveOrbs.Any()) foreach (var o in ActiveOrbs) - orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.5f * o.Rotation.ToDirection(), 0.75f)); + orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.55f * o.Rotation.ToDirection(), 0.75f)); if (orbs.Count > 0) hints.AddForbiddenZone(p => orbs.Max(f => f(p))); } diff --git a/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs b/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs index 1edcae6643..733a6086b5 100644 --- a/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs +++ b/BossMod/Modules/Global/GoldSaucer/TheSliceIsRight/TheSliceIsRight.cs @@ -109,6 +109,6 @@ public TheSliceIsRightStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Verified, Contributors = "Malediktus", GroupType = BossModuleInfo.GroupType.GoldSaucer, GroupID = 181, NameID = 9066)] public class TheSliceIsRight(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - private static readonly ArenaBoundsComplex arena = new([new Polygon(new(70.5f, -36), 15, 28)]); + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(70.5f, -36), 15 * CosPI.Pi28th, 28)]); protected override bool CheckPull() => PrimaryActor != null; } diff --git a/BossMod/Modules/RealmReborn/Trial/T04PortaDecumana/T04PortaDecumana2.cs b/BossMod/Modules/RealmReborn/Trial/T04PortaDecumana/T04PortaDecumana2.cs index 20ebaf6eb5..db6cac4e90 100644 --- a/BossMod/Modules/RealmReborn/Trial/T04PortaDecumana/T04PortaDecumana2.cs +++ b/BossMod/Modules/RealmReborn/Trial/T04PortaDecumana/T04PortaDecumana2.cs @@ -89,7 +89,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme { hints.ActionsToExecute.Push(ActionID.MakeSpell(ClassShared.AID.Sprint), actor, ActionQueue.Priority.High); foreach (var o in ActiveOrbs) - orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.5f * o.Rotation.ToDirection(), 0.5f)); + orbs.Add(ShapeDistance.InvertedCircle(o.Position + 0.55f * o.Rotation.ToDirection(), 0.5f)); } if (orbs.Count > 0) hints.AddForbiddenZone(p => orbs.Max(f => f(p))); diff --git a/BossMod/Pathfinding/NavigationDecision.cs b/BossMod/Pathfinding/NavigationDecision.cs index 90ec904957..27d0727bf8 100644 --- a/BossMod/Pathfinding/NavigationDecision.cs +++ b/BossMod/Pathfinding/NavigationDecision.cs @@ -41,7 +41,7 @@ public enum Decision public int MapGoal; public Decision DecisionType; - public const float DefaultForbiddenZoneCushion = 0.15f; + public const float DefaultForbiddenZoneCushion = 0.18f; public static NavigationDecision Build(Context ctx, WorldState ws, AIHints hints, Actor player, WPos? targetPos, float targetRadius, Angle targetRot, Positional positional, float playerSpeed = 6, float forbiddenZoneCushion = DefaultForbiddenZoneCushion) {