1
- namespace RebornRotations . Ranged ;
1
+ using Dalamud . Interface . Colors ;
2
+
3
+ namespace RebornRotations . Ranged ;
2
4
3
5
[ Rotation ( "Rework" , CombatType . PvE , GameVersion = "7.25" ) ]
4
6
[ SourceCode ( Path = "main/BasicRotations/Ranged/MCH_Rework.cs" ) ]
5
7
[ Api ( 4 ) ]
6
8
public sealed class MCH_Rework : MachinistRotation
7
9
{
8
10
#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
-
12
11
[ RotationConfig ( CombatType . PvE , Name = "Use burst medicine in countdown (requires auto burst option on)" ) ]
13
12
private bool OpenerBurstMeds { get ; set ; } = false ;
14
13
@@ -36,6 +35,17 @@ public sealed class MCH_Rework : MachinistRotation
36
35
}
37
36
#endregion
38
37
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
+
39
49
#region oGCD Logic
40
50
[ RotationDesc ( ActionID . TacticianPvE , ActionID . DismantlePvE ) ]
41
51
protected override bool DefenseAreaAbility ( IAction nextGCD , out IAction ? act )
@@ -113,15 +123,19 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
113
123
return true ;
114
124
}
115
125
126
+ if ( UseQueen ( out act , nextGCD ) )
127
+ {
128
+ return true ;
129
+ }
130
+
116
131
bool LowLevelHyperCheck = ! AutoCrossbowPvE . EnoughLevel && SpreadShotPvE . CanUse ( out _ ) ;
117
132
118
133
if ( FullMetalFieldPvE . EnoughLevel )
119
134
{
120
135
if ( ( Heat >= 50 || HasHypercharged ) && ! LowLevelHyperCheck )
121
136
{
122
137
if ( WeaponRemain < GCDTime ( 1 ) / 2
123
- && ( nextGCD . IsTheSameTo ( false , FullMetalFieldPvE )
124
- || ( nextGCD . IsTheSameTo ( false , DrillPvE , ChainSawPvE , AirAnchorPvE , ExcavatorPvE ) && ! HasFullMetalMachinist ) )
138
+ && nextGCD . IsTheSameTo ( false , FullMetalFieldPvE )
125
139
&& WildfirePvE . CanUse ( out act ) )
126
140
{
127
141
return true ;
@@ -169,20 +183,6 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
169
183
break ;
170
184
}
171
185
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
-
186
186
return base . AttackAbility ( nextGCD , out act ) ;
187
187
}
188
188
#endregion
@@ -191,7 +191,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
191
191
protected override bool GeneralGCD ( out IAction ? act )
192
192
{
193
193
// 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 )
195
195
{
196
196
// 3
197
197
if ( CleanShotPvE . CanUse ( out act ) )
@@ -232,30 +232,13 @@ protected override bool GeneralGCD(out IAction? act)
232
232
if ( ! SpreadShotPvE . CanUse ( out _ ) )
233
233
{
234
234
// use AirAnchor if possible
235
- if ( HotShotMasteryTrait . EnoughLevel
236
- && AirAnchorPvE . CanUse ( out act ) )
235
+ if ( AirAnchorPvE . CanUse ( out act ) )
237
236
{
238
237
return true ;
239
238
}
240
239
241
240
// 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 ) )
259
242
{
260
243
return true ;
261
244
}
@@ -273,26 +256,16 @@ protected override bool GeneralGCD(out IAction? act)
273
256
return true ;
274
257
}
275
258
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 )
278
261
{
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 ) )
285
263
{
286
264
return true ;
287
265
}
288
266
}
289
267
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 ) )
296
269
{
297
270
return true ;
298
271
}
@@ -323,6 +296,17 @@ protected override bool GeneralGCD(out IAction? act)
323
296
}
324
297
#endregion
325
298
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
+
326
310
// Logic for Hypercharge
327
311
private bool ToolChargeSoon ( out IAction ? act )
328
312
{
@@ -352,19 +336,93 @@ private bool ToolChargeSoon(out IAction? act)
352
336
}
353
337
}
354
338
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
+ }
355
393
private bool UseQueen ( out IAction ? act , IAction nextGCD )
356
394
{
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 )
361
401
{
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 ) )
363
422
{
364
423
return true ;
365
424
}
366
425
}
367
- act = null ;
368
426
return false ;
369
427
}
370
428
}
0 commit comments