Skip to content

Commit 0f18b40

Browse files
authored
Merge pull request #821 from FFXIV-CombatReborn/mechanic
MCH Rework Queen system fully overhauled, misc fixes for base and default rotations to use faster statuscheck
2 parents 6b44ac7 + ace0ac8 commit 0f18b40

27 files changed

+284
-188
lines changed

BasicRotations/Duty/PhantomDefault.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ public override bool DefenseAreaGCD(out IAction? act)
569569
public override bool GeneralGCD(out IAction? act)
570570
{
571571
act = null;
572-
if (HasLockoutStatus || !Player.WillStatusEnd(0, true, StatusID.Reassembled))
572+
if (HasLockoutStatus || Player.HasStatus(true, StatusID.Reassembled))
573573
{
574574
return false;
575575
}

BasicRotations/Magical/PCT_Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public sealed class PCT_Default : PictomancerRotation
3333

3434
#endregion
3535

36-
private static bool InBurstStatus => !Player.WillStatusEnd(0, true, StatusID.StarryMuse);
36+
private static bool InBurstStatus => Player.HasStatus(true, StatusID.StarryMuse);
3737

3838
#region Countdown logic
3939
// Defines logic for actions to take during the countdown before combat starts.

BasicRotations/Melee/DRG_Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public sealed class DRG_Default : DragoonRotation
1414
public bool OGCDTimers { get; set; } = false;
1515
#endregion
1616

17-
private static bool InBurstStatus => !Player.WillStatusEnd(0, true, StatusID.BattleLitany);
17+
private static bool InBurstStatus => Player.HasStatus(true, StatusID.BattleLitany);
1818

1919
#region Additional oGCD Logic
2020

BasicRotations/Melee/NIN_Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
131131
}
132132

133133
// First priority is given to Kassatsu if it's available, allowing for an immediate powerful Ninjutsu.
134-
if (NoNinjutsu && KassatsuPvE.CanUse(out act))
134+
if (NoNinjutsu && !nextGCD.IsTheSameTo(false, ActionID.TenPvE, ActionID.ChiPvE, ActionID.JinPvE) && KassatsuPvE.CanUse(out act))
135135
{
136136
return true;
137137
}

BasicRotations/Melee/VPR_Default.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,8 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
133133
}
134134
}
135135

136-
if (SerpentsIrePvE.CanUse(out act))
137-
{
138-
return true;
139-
}
140-
141136
////Serpent Combo oGCDs
142-
if (LastLashPvE.CanUse(out act))
137+
if (LastLashPvE.CanUse(out act, skipAoeCheck: true))
143138
{
144139
return true;
145140
}
@@ -166,7 +161,7 @@ protected override bool MoveForwardAbility(IAction nextGCD, out IAction? act)
166161
{
167162
return true;
168163
}
169-
return base.AttackAbility(nextGCD, out act);
164+
return base.MoveForwardAbility(nextGCD, out act);
170165
}
171166

172167
[RotationDesc]
@@ -223,6 +218,11 @@ protected sealed override bool InterruptAbility(IAction nextGCD, out IAction? ac
223218

224219
protected override bool AttackAbility(IAction nextGCD, out IAction? act)
225220
{
221+
if (SerpentsIrePvE.CanUse(out act))
222+
{
223+
return true;
224+
}
225+
226226
return base.AttackAbility(nextGCD, out act);
227227
}
228228
#endregion

BasicRotations/Ranged/BRD_Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
219219
return true;
220220
}
221221

222-
if (!Player.WillStatusEnd(0, true, StatusID.BattleVoice) && RadiantFinalePvE.CanUse(out act))
222+
if (Player.HasStatus(true, StatusID.BattleVoice) && RadiantFinalePvE.CanUse(out act))
223223
{
224224
return true;
225225
}

BasicRotations/Ranged/DNC_Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public sealed class DNC_Default : DancerRotation
2222
#endregion
2323
private bool shouldUseLastDance = true;
2424

25-
private static bool InBurstStatus => !Player.WillStatusEnd(0, true, StatusID.Devilment);
25+
private static bool InBurstStatus => Player.HasStatus(true, StatusID.Devilment);
2626

2727
#region Tracking Properties
2828
public override void DisplayStatus()

BasicRotations/Ranged/MCH_Rework.cs

Lines changed: 118 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
namespace RebornRotations.Ranged;
1+
using Dalamud.Interface.Colors;
2+
3+
namespace RebornRotations.Ranged;
24

35
[Rotation("Rework", CombatType.PvE, GameVersion = "7.25")]
46
[SourceCode(Path = "main/BasicRotations/Ranged/MCH_Rework.cs")]
57
[Api(4)]
68
public sealed class MCH_Rework : MachinistRotation
79
{
810
#region Config Options
9-
[RotationConfig(CombatType.PvE, Name = "Use Automation Queen as soon as its available if you are about to overcap")]
10-
private bool DumbQueen { get; set; } = false;
11-
1211
[RotationConfig(CombatType.PvE, Name = "Use burst medicine in countdown (requires auto burst option on)")]
1312
private bool OpenerBurstMeds { get; set; } = false;
1413

@@ -36,6 +35,17 @@ public sealed class MCH_Rework : MachinistRotation
3635
}
3736
#endregion
3837

38+
protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
39+
{
40+
if (InCombat)
41+
{
42+
UpdateQueenStep();
43+
UpdateFoundStepPair();
44+
}
45+
46+
return base.EmergencyAbility(nextGCD, out act);
47+
}
48+
3949
#region oGCD Logic
4050
[RotationDesc(ActionID.TacticianPvE, ActionID.DismantlePvE)]
4151
protected override bool DefenseAreaAbility(IAction nextGCD, out IAction? act)
@@ -113,15 +123,19 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
113123
return true;
114124
}
115125

126+
if (UseQueen(out act, nextGCD))
127+
{
128+
return true;
129+
}
130+
116131
bool LowLevelHyperCheck = !AutoCrossbowPvE.EnoughLevel && SpreadShotPvE.CanUse(out _);
117132

118133
if (FullMetalFieldPvE.EnoughLevel)
119134
{
120135
if ((Heat >= 50 || HasHypercharged) && !LowLevelHyperCheck)
121136
{
122137
if (WeaponRemain < GCDTime(1) / 2
123-
&& (nextGCD.IsTheSameTo(false, FullMetalFieldPvE)
124-
|| (nextGCD.IsTheSameTo(false, DrillPvE, ChainSawPvE, AirAnchorPvE, ExcavatorPvE) && !HasFullMetalMachinist))
138+
&& nextGCD.IsTheSameTo(false, FullMetalFieldPvE)
125139
&& WildfirePvE.CanUse(out act))
126140
{
127141
return true;
@@ -169,20 +183,6 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
169183
break;
170184
}
171185

172-
// Rook Autoturret/Queen Logic
173-
if (RookAutoturretPvE.CanUse(out act, skipTTKCheck: true))
174-
{
175-
if (DumbQueen && InCombat && nextGCD.IsTheSameTo(true, HotShotPvE, AirAnchorPvE, ChainSawPvE, ExcavatorPvE) && Battery == 100)
176-
{
177-
return true;
178-
}
179-
}
180-
181-
if (UseQueen(out act, nextGCD))
182-
{
183-
return true;
184-
}
185-
186186
return base.AttackAbility(nextGCD, out act);
187187
}
188188
#endregion
@@ -191,7 +191,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
191191
protected override bool GeneralGCD(out IAction? act)
192192
{
193193
// ensure combo is not broken, okay to drop during overheat
194-
if (IsLastComboAction(true, SlugShotPvE) &&LiveComboTime >= GCDTime(1) && LiveComboTime <= GCDTime(2) && !IsOverheated)
194+
if (IsLastComboAction(true, SlugShotPvE) && LiveComboTime >= GCDTime(1) && LiveComboTime <= GCDTime(2) && !IsOverheated)
195195
{
196196
// 3
197197
if (CleanShotPvE.CanUse(out act))
@@ -232,30 +232,13 @@ protected override bool GeneralGCD(out IAction? act)
232232
if (!SpreadShotPvE.CanUse(out _))
233233
{
234234
// use AirAnchor if possible
235-
if (HotShotMasteryTrait.EnoughLevel
236-
&& AirAnchorPvE.CanUse(out act))
235+
if (AirAnchorPvE.CanUse(out act))
237236
{
238237
return true;
239238
}
240239

241240
// for opener: only use the first charge of Drill after AirAnchor when there are two
242-
if (EnhancedMultiweaponTrait.EnoughLevel
243-
&& !CombatElapsedLessGCD(6)
244-
&& !ChainSawPvE.Cooldown.WillHaveOneCharge(6)
245-
&& !CleanShotPvE.CanUse(out _) && !SlugShotPvE.CanUse(out _)
246-
&& DrillPvE.CanUse(out act, usedUp: false || (DrillPvE.Cooldown.CurrentCharges == 1 && DrillPvE.Cooldown.WillHaveXChargesGCD(2, 1, 0))))
247-
{
248-
return true;
249-
}
250-
251-
if (!EnhancedMultiweaponTrait.EnoughLevel
252-
&& DrillPvE.CanUse(out act))
253-
{
254-
return true;
255-
}
256-
257-
if (!AirAnchorPvE.EnoughLevel
258-
&& HotShotPvE.CanUse(out act))
241+
if (DrillPvE.CanUse(out act, usedUp: false))
259242
{
260243
return true;
261244
}
@@ -273,26 +256,16 @@ protected override bool GeneralGCD(out IAction? act)
273256
return true;
274257
}
275258

276-
// use FMF after ChainSaw combo in 'alternative opener'
277-
if (FullMetalFieldPvE.CanUse(out act))
259+
if (AirAnchorPvE.Cooldown.IsCoolingDown && DrillPvE.Cooldown.CurrentCharges < 2 && ChainSawPvE.Cooldown.IsCoolingDown
260+
&& !HasExcavatorReady)
278261
{
279-
//Ensure the FMF is used if FMF status will end soon
280-
if (Player.WillStatusEndGCD(1, 0, true, StatusID.FullMetalMachinist))
281-
{
282-
return true;
283-
}
284-
if (!ChainSawPvE.Cooldown.WillHaveOneChargeGCD(2))
262+
if (FullMetalFieldPvE.CanUse(out act))
285263
{
286264
return true;
287265
}
288266
}
289267

290-
// dont use the second charge of Drill if it's in opener, also save Drill for burst --- need to combine this with the logic above!!!
291-
if (EnhancedMultiweaponTrait.EnoughLevel
292-
&& !CombatElapsedLessGCD(6)
293-
&& !ChainSawPvE.Cooldown.WillHaveOneCharge(6)
294-
&& !CleanShotPvE.CanUse(out _) && !SlugShotPvE.CanUse(out _)
295-
&& DrillPvE.CanUse(out act, usedUp: true))
268+
if (DrillPvE.CanUse(out act, usedUp: true))
296269
{
297270
return true;
298271
}
@@ -323,6 +296,17 @@ protected override bool GeneralGCD(out IAction? act)
323296
}
324297
#endregion
325298

299+
#region Tracking Properties
300+
public override void DisplayStatus()
301+
{
302+
ImGui.TextColored(ImGuiColors.DalamudViolet, "Rotation Tracking:");
303+
ImGui.Text($"QueenStep: {_currentStep}");
304+
ImGui.Text($"Step Pair Found: {foundStepPair}");
305+
ImGui.TextColored(ImGuiColors.DalamudYellow, "Base Tracking:");
306+
base.DisplayStatus();
307+
}
308+
#endregion
309+
326310
// Logic for Hypercharge
327311
private bool ToolChargeSoon(out IAction? act)
328312
{
@@ -352,19 +336,93 @@ private bool ToolChargeSoon(out IAction? act)
352336
}
353337
}
354338

339+
private readonly (byte from, byte to, int step)[] _stepPairs =
340+
[
341+
(0, 60, 0),
342+
(60, 90, 1),
343+
(90, 100, 2),
344+
(100, 50, 3),
345+
(50, 60, 4),
346+
(60, 100, 5),
347+
(100, 50, 6),
348+
(50, 70, 7),
349+
(70, 100, 8),
350+
(100, 50, 9),
351+
(50, 80, 10),
352+
(70, 100, 11),
353+
(100, 50, 12),
354+
(50, 60, 13)
355+
];
356+
357+
private int _currentStep = 0; // Track the current step
358+
private bool foundStepPair = false;
359+
360+
/// <summary>
361+
/// Checks if the current battery transition matches the current step only.
362+
/// </summary>
363+
private void UpdateFoundStepPair()
364+
{
365+
// Only check the current step
366+
if (_currentStep < _stepPairs.Length)
367+
{
368+
var (from, to, _) = _stepPairs[_currentStep];
369+
foundStepPair = (LastSummonBatteryPower == from && Battery == to);
370+
}
371+
else
372+
{
373+
foundStepPair = false;
374+
}
375+
}
376+
377+
private byte _lastTrackedSummonBatteryPower = 0;
378+
379+
public void UpdateQueenStep()
380+
{
381+
// If LastSummonBatteryPower has changed since last check, advance the step
382+
if (_lastTrackedSummonBatteryPower != LastSummonBatteryPower)
383+
{
384+
_lastTrackedSummonBatteryPower = LastSummonBatteryPower;
385+
AdvanceStep();
386+
}
387+
}
388+
389+
private void AdvanceStep()
390+
{
391+
_currentStep++;
392+
}
355393
private bool UseQueen(out IAction? act, IAction nextGCD)
356394
{
357-
if (WildfirePvE.Cooldown.WillHaveOneChargeGCD(4)
358-
|| !WildfirePvE.Cooldown.ElapsedAfter(10)
359-
|| (nextGCD.IsTheSameTo(true, CleanShotPvE) && Battery == 100)
360-
|| (nextGCD.IsTheSameTo(true, HotShotPvE, AirAnchorPvE, ChainSawPvE, ExcavatorPvE) && (Battery == 90 || Battery == 100)))
395+
act = null;
396+
if (!InCombat || IsRobotActive)
397+
return false;
398+
399+
// Opener
400+
if (Battery == 60 && IsLastGCD(false, ExcavatorPvE) && CombatTime < 15)
361401
{
362-
if (InCombat && RookAutoturretPvE.CanUse(out act))
402+
if (RookAutoturretPvE.CanUse(out act))
403+
{
404+
return true;
405+
}
406+
}
407+
408+
// Only allow battery usage if the current transition matches the expected step
409+
if (foundStepPair)
410+
{
411+
if (RookAutoturretPvE.CanUse(out act))
412+
{
413+
return true;
414+
}
415+
}
416+
417+
// overcap protection
418+
if ((nextGCD.IsTheSameTo(false, CleanShotPvE, HeatedCleanShotPvE) && Battery > 90)
419+
|| (nextGCD.IsTheSameTo(false, HotShotPvE, AirAnchorPvE, ChainSawPvE, ExcavatorPvE) && Battery > 80))
420+
{
421+
if (RookAutoturretPvE.CanUse(out act))
363422
{
364423
return true;
365424
}
366425
}
367-
act = null;
368426
return false;
369427
}
370428
}

RotationSolver.Basic/Configuration/Configs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public const string
5353
Filter = AutoActionUsage, Section = 3)]
5454
public AoEType AoEType { get; set; } = AoEType.Full;
5555

56+
[ConditionBool, UI("Don't attack new mobs by AoE. (Dangerous)", Description = "Never use any AoE action when this may attack mobs that are not hostile targets.",
57+
Filter = AutoActionUsage, Section = 3)]
58+
private static readonly bool _noNewHostiles = false;
59+
5660
[ConditionBool, UI("Disable automatically during area transitions.",
5761
Description = "Automatically turn off combat state when moving between different areas.",
5862
Filter = BasicAutoSwitch)]
@@ -197,10 +201,6 @@ public const string
197201
Filter = BasicAutoSwitch, Section = 1)]
198202
private static readonly bool _startOnAttackedBySomeone = false;
199203

200-
[ConditionBool, UI("Don't attack new mobs by AoE. (Dangerous)", Description = "Never use any AoE action when this may attack mobs that are not hostile targets.",
201-
Filter = BasicAutoSwitch)]
202-
private static readonly bool _noNewHostiles = false;
203-
204204
/// <markdown file="Auto" name="Use healing abilities when playing a non-healer role" section="Healing Usage and Control">
205205
/// Allow usage of healing abilities when not playing as a healer (such as Vercure, Bloodbath, etc.)
206206
/// </markdown>

0 commit comments

Comments
 (0)