Skip to content

Commit 8a1e3ad

Browse files
authored
Merge pull request #825 from FFXIV-CombatReborn/emergencyHotfix
Emergency hotfix for AOE, rolling back ATI system
2 parents d688c9b + 2270f19 commit 8a1e3ad

File tree

8 files changed

+151
-70
lines changed

8 files changed

+151
-70
lines changed

BasicRotations/Magical/SMN_Default.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
148148
return true;
149149
}
150150

151-
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.IsInCooldown && PainflarePvE.CanUse(out act))
151+
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.Cooldown.IsCoolingDown && PainflarePvE.CanUse(out act))
152152
{
153153
return true;
154154
}
155155

156-
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.IsInCooldown && FesterPvE.CanUse(out act))
156+
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.Cooldown.IsCoolingDown && FesterPvE.CanUse(out act))
157157
{
158158
return true;
159159
}
@@ -229,22 +229,22 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
229229
return true;
230230
}
231231

232-
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation && EnergyDrainPvE.Cooldown.WillHaveOneCharge(2)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.IsInCooldown && PainflarePvE.CanUse(out act))
232+
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation && EnergyDrainPvE.Cooldown.WillHaveOneCharge(2)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.Cooldown.IsCoolingDown && PainflarePvE.CanUse(out act))
233233
{
234234
return true;
235235
}
236236

237-
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation && EnergyDrainPvE.Cooldown.WillHaveOneCharge(2)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.IsInCooldown && FesterPvE.CanUse(out act))
237+
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation && EnergyDrainPvE.Cooldown.WillHaveOneCharge(2)) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.Cooldown.IsCoolingDown && FesterPvE.CanUse(out act))
238238
{
239239
return true;
240240
}
241241

242-
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.IsInCooldown && PainflarePvE.CanUse(out act))
242+
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.Cooldown.IsCoolingDown && PainflarePvE.CanUse(out act))
243243
{
244244
return true;
245245
}
246246

247-
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.IsInCooldown && FesterPvE.CanUse(out act))
247+
if (((inSolarUnique && Player.HasStatus(false, StatusID.SearingLight) && elapsed2ChargeAfterInvocation) || !SearingLightPvE.EnoughLevel || (isTargetBoss && isTargetDying)) && EnergyDrainPvE.Cooldown.IsCoolingDown && FesterPvE.CanUse(out act))
248248
{
249249
return true;
250250
}
@@ -443,7 +443,7 @@ protected override bool GeneralGCD(out IAction? act)
443443
}
444444
}
445445

446-
if (SummonTimeEndAfterGCD() && AttunmentTimeEndAfterGCD() && !InBahamut && !InPhoenix && !InSolarBahamut && SummonEmeraldPvE.IsInCooldown && SummonTopazPvE.IsInCooldown && SummonRubyPvE.IsInCooldown &&
446+
if (SummonTimeEndAfterGCD() && AttunmentTimeEndAfterGCD() && !InBahamut && !InPhoenix && !InSolarBahamut && SummonEmeraldPvE.Cooldown.IsCoolingDown && SummonTopazPvE.Cooldown.IsCoolingDown && SummonRubyPvE.Cooldown.IsCoolingDown &&
447447
RuinIvPvE.CanUse(out act, skipAoeCheck: true))
448448
{
449449
return true;

BasicRotations/Melee/DRG_Default.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
6262
&& LOTDEndAfter(1000)
6363
&& nextGCD.IsTheSameTo(true, ChaoticSpringPvE, LanceBarragePvE, WheelingThrustPvE, FangAndClawPvE))
6464
|| (nextGCD.IsTheSameTo(true, HeavensThrustPvE, DrakesbanePvE)
65-
&& (LanceChargePvE.IsInCooldown || BattleLitanyPvE.IsInCooldown));
65+
&& (LanceChargePvE.Cooldown.IsCoolingDown || BattleLitanyPvE.Cooldown.IsCoolingDown));
6666

6767
if ((!BattleLitanyPvE.Cooldown.ElapsedAfter(60) || !BattleLitanyPvE.EnoughLevel)
6868
&& LanceChargePvE.CanUse(out act))
@@ -84,7 +84,7 @@ protected override bool EmergencyAbility(IAction nextGCD, out IAction? act)
8484
&& !DrakesbanePvE.EnoughLevel
8585
&& nextGCD.IsTheSameTo(true, ChaoticSpringPvE, LanceBarragePvE, WheelingThrustPvE, FangAndClawPvE))
8686
|| (nextGCD.IsTheSameTo(true, HeavensThrustPvE, DrakesbanePvE)
87-
&& (LanceChargePvE.IsInCooldown || BattleLitanyPvE.IsInCooldown)))
87+
&& (LanceChargePvE.Cooldown.IsCoolingDown || BattleLitanyPvE.Cooldown.IsCoolingDown)))
8888
{
8989
if (LifeSurgePvE.CanUse(out act, usedUp: true))
9090
{

BasicRotations/Melee/MNK_Default.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
276276

277277
// use bh when bh and rof are ready (opener) or ask bh to wait for rof's cd to be close and then use bh
278278
if (!CombatElapsedLessGCD(2)
279-
&& ((BrotherhoodPvE.IsInCooldown && RiddleOfFirePvE.IsInCooldown) || Math.Abs(BrotherhoodPvE.Cooldown.CoolDownGroup - RiddleOfFirePvE.Cooldown.CoolDownGroup) < 3)
279+
&& ((BrotherhoodPvE.Cooldown.IsCoolingDown && RiddleOfFirePvE.Cooldown.IsCoolingDown) || Math.Abs(BrotherhoodPvE.Cooldown.CoolDownGroup - RiddleOfFirePvE.Cooldown.CoolDownGroup) < 3)
280280
&& BrotherhoodPvE.CanUse(out act))
281281
{
282282
return true;

BasicRotations/Tank/PLD_Default.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,17 +304,17 @@ protected override bool AttackAbility(IAction nextGCD, out IAction? act)
304304
return true;
305305
}
306306

307-
if (CircleOfScornPvE.CanUse(out act, skipAoeCheck: true, skipTTKCheck: true) && FightOrFlightPvE.Cooldown.IsCoolingDown && (ImperatorPvE.EnoughLevel && ImperatorPvE.IsInCooldown || !ImperatorPvE.EnoughLevel))
307+
if (CircleOfScornPvE.CanUse(out act, skipAoeCheck: true, skipTTKCheck: true) && FightOrFlightPvE.Cooldown.IsCoolingDown && (ImperatorPvE.EnoughLevel && ImperatorPvE.Cooldown.IsCoolingDown || !ImperatorPvE.EnoughLevel))
308308
{
309309
return true;
310310
}
311311

312-
if (ExpiacionPvE.CanUse(out act, skipAoeCheck: true) && FightOrFlightPvE.Cooldown.IsCoolingDown && (ImperatorPvE.EnoughLevel && ImperatorPvE.IsInCooldown || !ImperatorPvE.EnoughLevel))
312+
if (ExpiacionPvE.CanUse(out act, skipAoeCheck: true) && FightOrFlightPvE.Cooldown.IsCoolingDown && (ImperatorPvE.EnoughLevel && ImperatorPvE.Cooldown.IsCoolingDown || !ImperatorPvE.EnoughLevel))
313313
{
314314
return true;
315315
}
316316

317-
if (SpiritsWithinPvE.CanUse(out act, skipAoeCheck: true) && FightOrFlightPvE.Cooldown.IsCoolingDown && (ImperatorPvE.EnoughLevel && ImperatorPvE.IsInCooldown || !ImperatorPvE.EnoughLevel))
317+
if (SpiritsWithinPvE.CanUse(out act, skipAoeCheck: true) && FightOrFlightPvE.Cooldown.IsCoolingDown && (ImperatorPvE.EnoughLevel && ImperatorPvE.Cooldown.IsCoolingDown || !ImperatorPvE.EnoughLevel))
318318
{
319319
return true;
320320
}

RotationSolver.Basic/Actions/ActionTargetInfo.cs

Lines changed: 130 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -63,40 +63,36 @@ private readonly List<IBattleChara> GetCanTargets(bool skipStatusProvideCheck, b
6363
return [];
6464
}
6565

66-
List<IBattleChara> validTargets = [];
67-
foreach (IBattleChara target in TargetHelper.GetTargetsByRange(Range))
66+
List<IBattleChara> validTargets = new(TargetFilter.GetObjectInRadius(DataCenter.AllTargets, Range).Count());
67+
68+
foreach (IBattleChara target in TargetFilter.GetObjectInRadius(DataCenter.AllTargets, Range))
6869
{
6970
if (type == TargetType.Heal && target.GetHealthRatio() == 1)
7071
{
7172
continue;
7273
}
7374

74-
var statusCheck = CheckStatus(target, skipStatusProvideCheck, skipTargetStatusNeedCheck);
75-
var ttkCheck = CheckTimeToKill(target);
76-
var resistanceCheck = CheckResistance(target);
75+
if (!GeneralCheck(target, skipStatusProvideCheck, skipTargetStatusNeedCheck))
76+
{
77+
continue;
78+
}
79+
80+
validTargets.Add(target);
81+
}
7782

78-
if (statusCheck && ttkCheck && resistanceCheck)
83+
List<IBattleChara> result = [];
84+
foreach (IBattleChara b in validTargets)
85+
{
86+
if (!DataCenter.IsManual || IsTargetFriendly || b.GameObjectId == Svc.Targets.Target?.GameObjectId || b.GameObjectId == Player.Object?.GameObjectId)
7987
{
80-
// If auto targeting is enabled
81-
// or the skill is friendly
82-
// or the target is the currently selected hard-target
83-
// or the target is ourselves
84-
// then => Check target is in the view && ActionManager.CanUse on target && CanSee Target && action.setting predicate is true of target
85-
if (!DataCenter.IsManual || IsTargetFriendly || target.GameObjectId == Svc.Targets.Target?.GameObjectId || target.GameObjectId == Player.Object?.GameObjectId)
88+
if (InViewTarget(b) && CanUseTo(b) && action.Setting.CanTarget(b))
8689
{
87-
var view = InViewTarget(target);
88-
var canUse = CanUseTo(target);
89-
var asCanTarget = action.Setting.CanTarget(target);
90-
91-
if (view && canUse && asCanTarget)
92-
{
93-
validTargets.Add(target);
94-
}
90+
result.Add(b);
9591
}
9692
}
9793
}
9894

99-
return validTargets;
95+
return result;
10096
}
10197

10298
/// <summary>
@@ -122,21 +118,35 @@ private readonly List<IBattleChara> GetCanAffects(bool skipStatusProvideCheck, b
122118
return [];
123119
}
124120

125-
IEnumerable<IBattleChara> items = TargetHelper.GetTargetsByRange(Range + EffectRange, action.Setting.IsFriendly);
121+
IEnumerable<IBattleChara> items = TargetFilter.GetObjectInRadius(action.Setting.IsFriendly
122+
? DataCenter.PartyMembers
123+
: DataCenter.AllHostileTargets, Range + EffectRange);
126124

127-
List<IBattleChara> validTargets = new(items.Count());
128-
foreach (IBattleChara tar in items)
125+
if (type == TargetType.Heal)
129126
{
130-
if (type == TargetType.Heal && tar.GetHealthRatio() >= 1)
127+
List<IBattleChara> filteredItems = [];
128+
foreach (IBattleChara i in items)
131129
{
132-
continue;
130+
if (i.GetHealthRatio() < 1)
131+
{
132+
filteredItems.Add(i);
133+
}
133134
}
135+
items = filteredItems;
136+
}
134137

135-
if (CheckStatus(tar, skipStatusProvideCheck, skipTargetStatusNeedCheck) && CheckTimeToKill(tar) && CheckResistance(tar))
138+
List<IBattleChara> validTargets = new(items.Count());
139+
140+
foreach (IBattleChara obj in items)
141+
{
142+
if (!GeneralCheck(obj, skipStatusProvideCheck, skipTargetStatusNeedCheck))
136143
{
137-
validTargets.Add(tar);
144+
continue;
138145
}
146+
147+
validTargets.Add(obj);
139148
}
149+
140150
return validTargets;
141151
}
142152

@@ -196,26 +206,10 @@ private readonly unsafe bool CanUseTo(IBattleChara tar)
196206
return false;
197207
}
198208

199-
if (!(tar.GameObjectId != 0 && tar.Struct() != null))
200-
{
201-
return false;
202-
}
203-
204-
var specialAbilityCheck = IsSpecialAbility(action.Info.ID);
205-
var actionmanagerCheck = ActionManager.CanUseActionOnTarget(action.Info.AdjustedID, (GameObject*)tar.Struct());
206-
207-
if (!(specialAbilityCheck || actionmanagerCheck))
208-
{
209-
return false;
210-
}
211-
if (!IsTargetFriendly) // canSee check is already done as part of finding hostile targets
212-
{
213-
return DataCenter.AllHostileTargets.Contains(tar);
214-
}
215-
else // For friendly targets we still need to check CanSee
216-
{
217-
return tar.CanSee();
218-
}
209+
return tar.GameObjectId != 0 && tar.Struct() != null &&
210+
(IsSpecialAbility(action.Info.ID) ||
211+
ActionManager.CanUseActionOnTarget(action.Info.AdjustedID, (GameObject*)tar.Struct())) &&
212+
tar.CanSee();
219213
}
220214

221215
private readonly List<ActionID> _specialActions =
@@ -235,6 +229,82 @@ private readonly bool IsSpecialAbility(uint iD)
235229
return _specialActions.Contains((ActionID)iD);
236230
}
237231

232+
/// <summary>
233+
/// Performs a general check on the specified battle character to determine if it meets the criteria for targeting.
234+
/// </summary>
235+
/// <param name="battleChara">The battle character to check.</param>
236+
/// <param name="skipStatusProvideCheck">If set to <c>true</c>, skips the status provide check.</param>
237+
/// <param name="skipTargetStatusNeedCheck">If set to <c>true</c>, skips the target status need check.</param>
238+
/// <returns>
239+
/// <c>true</c> if the battle character meets the criteria for targeting; otherwise, <c>false</c>.
240+
/// </returns>
241+
public readonly bool GeneralCheck(IBattleChara battleChara, bool skipStatusProvideCheck, bool skipTargetStatusNeedCheck)
242+
{
243+
if (battleChara == null)
244+
{
245+
return false;
246+
}
247+
248+
unsafe
249+
{
250+
if (battleChara.Struct() == null)
251+
{
252+
return false;
253+
}
254+
}
255+
256+
if (!battleChara.IsTargetable)
257+
{
258+
return false;
259+
}
260+
261+
try
262+
{
263+
if (battleChara.StatusList == null)
264+
{
265+
return false;
266+
}
267+
}
268+
catch (Exception ex)
269+
{
270+
PluginLog.Error($"Exception accessing StatusList for {battleChara?.NameId}: {ex.Message}");
271+
return false;
272+
}
273+
274+
bool isBlacklisted = false;
275+
foreach (uint id in DataCenter.BlacklistedNameIds)
276+
{
277+
if (id == battleChara.NameId)
278+
{
279+
isBlacklisted = true;
280+
break;
281+
}
282+
}
283+
if (isBlacklisted)
284+
{
285+
return false;
286+
}
287+
288+
if (battleChara.IsEnemy() && !battleChara.IsAttackable())
289+
{
290+
return false;
291+
}
292+
293+
bool isStopTarget = false;
294+
long[] stopTargets = MarkingHelper.GetStopTargets();
295+
foreach (long stopId in stopTargets)
296+
{
297+
if (stopId == (long)battleChara.GameObjectId)
298+
{
299+
isStopTarget = true;
300+
break;
301+
}
302+
}
303+
return (!isStopTarget || !Service.Config.FilterStopMark) && CheckStatus(battleChara, skipStatusProvideCheck, skipTargetStatusNeedCheck)
304+
&& CheckTimeToKill(battleChara)
305+
&& CheckResistance(battleChara);
306+
}
307+
238308
/// <summary>
239309
/// Checks the status of the specified game object to determine if it meets the criteria for the action.
240310
/// </summary>
@@ -361,12 +431,14 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
361431
/// </returns>
362432
internal readonly TargetResult? FindTarget(bool skipAoeCheck, bool skipStatusProvideCheck, bool skipTargetStatusNeedCheck)
363433
{
434+
float range = Range;
435+
364436
if (action == null || action.Setting == null || action.Config == null)
365437
{
366438
return null;
367439
}
368440

369-
if (Range == 0 && EffectRange == 0)
441+
if (range == 0 && EffectRange == 0)
370442
{
371443
return new TargetResult(Player.Object, [], Player.Object.Position);
372444
}
@@ -383,7 +455,7 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
383455

384456
if (IsTargetArea)
385457
{
386-
return FindTargetArea(canTargets, canAffects, Range, Player.Object);
458+
return FindTargetArea(canTargets, canAffects, range, Player.Object);
387459
}
388460

389461
List<IBattleChara> targetsList = [.. GetMostCanTargetObjects(canTargets, canAffects, skipAoeCheck ? 0 : action.Config.AoeCount)];
@@ -406,7 +478,10 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
406478
List<IBattleChara> affectsList = [];
407479
if (affectsEnum != null)
408480
{
409-
affectsList.AddRange(affectsEnum);
481+
foreach (var a in affectsEnum)
482+
{
483+
affectsList.Add(a);
484+
}
410485
}
411486
affectedTargets = [.. affectsList];
412487
}
@@ -1085,15 +1160,15 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
10851160

10861161
IBattleChara? FindDarkCannonTarget()
10871162
{
1088-
if (battleChara != null)
1163+
if (DataCenter.AllHostileTargets != null)
10891164
{
10901165
if (PhantomRotation.CannoneerLevel < 4)
10911166
{
10921167
return FindHostile();
10931168
}
10941169
else
10951170
{
1096-
foreach (var hostile in battleChara)
1171+
foreach (var hostile in DataCenter.AllHostileTargets)
10971172
{
10981173
if (!hostile.IsOCBlindImmuneTarget() && hostile.InCombat())
10991174
{
@@ -1107,9 +1182,9 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
11071182

11081183
IBattleChara? FindShockCannonTarget()
11091184
{
1110-
if (battleChara != null)
1185+
if (DataCenter.AllHostileTargets != null)
11111186
{
1112-
foreach (var hostile in battleChara)
1187+
foreach (var hostile in DataCenter.AllHostileTargets)
11131188
{
11141189
if (!hostile.IsOCParalysisImmuneTarget() && hostile.InCombat())
11151190
{

RotationSolver.Basic/Actions/IAction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public interface IAction : ITexture, IEnoughLevel
2121
uint SortKey { get; }
2222

2323
/// <summary>
24-
/// Gets or sets a value indicating whether this action is in the cooldown window.
24+
/// Gets or sets a value indicating whether this action is in the cooldown UI window.
2525
/// </summary>
2626
bool IsInCooldown { get; set; }
2727

RotationSolver/Data/UiString.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ internal enum UiString
127127
[Description("Used to customize when RSR uses specific actions automatically. Click on an action's icon in the left list. Below, you may set the conditions for when that specific action is used. Each action can have different conditions to override the default rotation behavior.")]
128128
ConfigWindow_Actions_Description,
129129

130+
[Description("Show on CD window")]
131+
ConfigWindow_Actions_ShowOnCDWindow,
132+
130133
[Description("Time-to-kill threshold required for this action to be used")]
131134
ConfigWindow_Actions_TTK,
132135

0 commit comments

Comments
 (0)