Skip to content

Commit 6306dd8

Browse files
authored
Merge pull request #773 from FFXIV-CombatReborn/healhotfix
Added Cannoners Phantom actions and fix logic for healers
2 parents 7ae736e + 85449c9 commit 6306dd8

File tree

6 files changed

+84
-62
lines changed

6 files changed

+84
-62
lines changed

BasicRotations/Duty/PhantomDefault.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,34 @@ public override bool GeneralGCD(out IAction? act)
269269
}
270270
}
271271

272+
if (SilverCannonPvE.CanUse(out act))
273+
{
274+
return true;
275+
}
276+
277+
//TODO: If enemy is undead should we prioritize this over SilverCannon?
278+
//TODO2: Figure out a way to identify target is undead
279+
if (HolyCannonPvE.CanUse(out act))
280+
{
281+
return true;
282+
}
283+
284+
// Only one of shock or dark can be used, prioritize Shock
285+
if (ShockCannonPvE.CanUse(out act))
286+
{
287+
return true;
288+
}
289+
290+
if (DarkCannonPvE.CanUse(out act))
291+
{
292+
return true;
293+
}
294+
295+
if (PhantomFirePvE.CanUse(out act))
296+
{
297+
return true;
298+
}
299+
272300
return base.GeneralGCD(out act);
273301
}
274302
}

RotationSolver.Basic/Actions/ActionTargetInfo.cs

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
411411
return false;
412412
}
413413

414-
int time = b.GetTTK();
415-
return time >= 0 && time >= action.Config.TimeToKill;
414+
float time = b.GetTTK();
415+
return float.IsNaN(time) || time >= action.Config.TimeToKill;
416416
}
417417

418418
#endregion
@@ -428,7 +428,7 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
428428
/// <returns>
429429
/// A <see cref="TargetResult"/> containing the target and affected characters, or <c>null</c> if no target is found.
430430
/// </returns>
431-
internal readonly TargetResult? FindTarget (bool skipAoeCheck, bool skipStatusProvideCheck, bool skipTargetStatusNeedCheck)
431+
internal readonly TargetResult? FindTarget(bool skipAoeCheck, bool skipStatusProvideCheck, bool skipTargetStatusNeedCheck)
432432
{
433433
float range = Range;
434434

@@ -502,7 +502,7 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
502502
/// <returns>
503503
/// A <see cref="TargetResult"/> containing the target area and affected characters, or <c>null</c> if no target area is found.
504504
/// </returns>
505-
private readonly TargetResult? FindTargetArea (IEnumerable<IBattleChara> canTargets, IEnumerable<IBattleChara> canAffects,
505+
private readonly TargetResult? FindTargetArea(IEnumerable<IBattleChara> canTargets, IEnumerable<IBattleChara> canAffects,
506506
float range, IPlayerCharacter player)
507507
{
508508
if (player == null)
@@ -985,9 +985,6 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
985985
Vector3 dir = target.Position - pPos;
986986
Vector3 tdir = subTarget.Position - pPos;
987987

988-
float dirLen = dir.Length();
989-
_ = tdir.Length();
990-
991988
switch (action.Action.CastType)
992989
{
993990
case 2: // Circle
@@ -998,23 +995,17 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
998995
{
999996
return false;
1000997
}
1001-
if (dirLen == 0)
1002-
return false;
1003-
tdir += dir / dirLen * target.HitboxRadius / (float)Math.Sin(_alpha);
1004-
dirLen = dir.Length();
1005-
float tdirLen = tdir.Length();
1006-
if (dirLen == 0 || tdirLen == 0)
1007-
return false;
1008-
return Vector3.Dot(dir, tdir) / (dirLen * tdirLen) >= Math.Cos(_alpha);
998+
999+
tdir += dir / dir.Length() * target.HitboxRadius / (float)Math.Sin(_alpha);
1000+
return Vector3.Dot(dir, tdir) / (dir.Length() * tdir.Length()) >= Math.Cos(_alpha);
10091001

10101002
case 4: // Line
10111003
if (subTarget.DistanceToPlayer() > EffectRange)
10121004
{
10131005
return false;
10141006
}
1015-
if (dirLen == 0)
1016-
return false;
1017-
return Vector3.Cross(dir, tdir).Length() / dirLen <= 2 + target.HitboxRadius
1007+
1008+
return Vector3.Cross(dir, tdir).Length() / dir.Length() <= 2 + target.HitboxRadius
10181009
&& Vector3.Dot(dir, tdir) >= 0;
10191010

10201011
case 10: // Donut
@@ -1796,8 +1787,8 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
17961787
{
17971788
int cmp = a.HitboxRadius.CompareTo(b.HitboxRadius);
17981789
if (cmp != 0) return cmp;
1799-
int aHp = a is IBattleChara ba ? (int)ba.CurrentHp : int.MaxValue;
1800-
int bHp = b is IBattleChara bb ? (int)bb.CurrentHp : int.MaxValue;
1790+
float aHp = a is IBattleChara ba ? ba.CurrentHp : float.MaxValue;
1791+
float bHp = b is IBattleChara bb ? bb.CurrentHp : float.MaxValue;
18011792
return aHp.CompareTo(bHp);
18021793
});
18031794
}
@@ -1809,8 +1800,8 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
18091800
{
18101801
int cmp = a.HitboxRadius.CompareTo(b.HitboxRadius);
18111802
if (cmp != 0) return cmp;
1812-
int aHp = a is IBattleChara ba ? (int)ba.CurrentHp : 0;
1813-
int bHp = b is IBattleChara bb ? (int)bb.CurrentHp : 0;
1803+
float aHp = a is IBattleChara ba ? ba.CurrentHp : 0;
1804+
float bHp = b is IBattleChara bb ? bb.CurrentHp : 0;
18141805
return bHp.CompareTo(aHp);
18151806
});
18161807
}
@@ -1837,17 +1828,17 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
18371828
filtered = [.. objects];
18381829
filtered.Sort((a, b) =>
18391830
{
1840-
int aPct = a is IBattleChara ba && ba.MaxHp != 0 ? (int)ba.CurrentHp / (int)ba.MaxHp : 0;
1841-
int bPct = b is IBattleChara bb && bb.MaxHp != 0 ? (int)bb.CurrentHp / (int)bb.MaxHp : 0;
1831+
float aPct = a is IBattleChara ba && ba.MaxHp != 0 ? (float)ba.CurrentHp / ba.MaxHp : 0;
1832+
float bPct = b is IBattleChara bb && bb.MaxHp != 0 ? (float)bb.CurrentHp / bb.MaxHp : 0;
18421833
return bPct.CompareTo(aPct);
18431834
});
18441835
break;
18451836
case TargetingType.LowHPPercent:
18461837
filtered = [.. objects];
18471838
filtered.Sort((a, b) =>
18481839
{
1849-
int aPct = a is IBattleChara ba && ba.MaxHp != 0 ? (int)ba.CurrentHp / (int)ba.MaxHp : 0;
1850-
int bPct = b is IBattleChara bb && bb.MaxHp != 0 ? (int)bb.CurrentHp / (int)bb.MaxHp : 0;
1840+
float aPct = a is IBattleChara ba && ba.MaxHp != 0 ? (float)ba.CurrentHp / ba.MaxHp : 0;
1841+
float bPct = b is IBattleChara bb && bb.MaxHp != 0 ? (float)bb.CurrentHp / bb.MaxHp : 0;
18511842
return aPct.CompareTo(bPct);
18521843
});
18531844
break;
@@ -2045,7 +2036,7 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
20452036
if (Service.Config.Priolowtank)
20462037
{
20472038
IBattleChara? lowest = null;
2048-
float minHealth = int.MaxValue;
2039+
float minHealth = float.MaxValue;
20492040
foreach (var t in attachedT)
20502041
{
20512042
float health = ObjectHelper.GetHealthRatio(t);
@@ -2060,7 +2051,7 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
20602051
else
20612052
{
20622053
IBattleChara? lowest = null;
2063-
float minHealth = int.MaxValue;
2054+
float minHealth = float.MaxValue;
20642055
foreach (var t in attachedT)
20652056
{
20662057
float health = ObjectHelper.GetHealthRatio(t);
@@ -2265,4 +2256,4 @@ public enum TargetType : byte
22652256
/// <param name="Target">the target.</param>
22662257
/// <param name="AffectedTargets">the targets that be affected by this action.</param>
22672258
/// <param name="Position">the position to use this action.</param>
2268-
public readonly record struct TargetResult(IBattleChara Target, IBattleChara[] AffectedTargets, Vector3? Position);
2259+
public readonly record struct TargetResult(IBattleChara Target, IBattleChara[] AffectedTargets, Vector3? Position);

RotationSolver.Basic/DataCenter.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ internal static SpecialCommandType SpecialType
358358
internal static float CombatTimeRaw { get; set; }
359359
private static DateTime _startRaidTime = DateTime.MinValue;
360360

361-
internal static int RaidTimeRaw
361+
internal static float RaidTimeRaw
362362
{
363363
get
364364
{
@@ -369,7 +369,7 @@ internal static int RaidTimeRaw
369369
}
370370

371371
// Calculate and return the total seconds elapsed since the raid started.
372-
return (int)(DateTime.Now - _startRaidTime).TotalSeconds;
372+
return (float)(DateTime.Now - _startRaidTime).TotalSeconds;
373373
}
374374
set
375375
{
@@ -469,7 +469,7 @@ public static int NumberOfHostilesInMaxRange
469469
}
470470
}
471471

472-
public static int NumberOfHostilesInRangeOf(int range)
472+
public static int NumberOfHostilesInRangeOf(float range)
473473
{
474474
int count = 0;
475475
var targets = AllHostileTargets;
@@ -489,7 +489,7 @@ public static bool MobsTime
489489
{
490490
get
491491
{
492-
int jobRange = JobRange;
492+
float jobRange = JobRange;
493493
int count = 0;
494494
var targets = AllHostileTargets;
495495
for (int i = 0, n = targets.Count; i < n; i++)
@@ -519,17 +519,17 @@ public static bool AreHostilesCastingKnockback
519519
}
520520
}
521521

522-
public static int JobRange
522+
public static float JobRange
523523
{
524524
get
525525
{
526-
int radius = 25;
526+
float radius = 25;
527527
if (!Player.AvailableThreadSafe)
528528
{
529529
return radius;
530530
}
531531

532-
switch (Role)
532+
switch (DataCenter.Role)
533533
{
534534
case JobRole.Tank:
535535
case JobRole.Melee:
@@ -541,16 +541,16 @@ public static int JobRange
541541
}
542542
}
543543

544-
public static int AverageTTK
544+
public static float AverageTTK
545545
{
546546
get
547547
{
548-
int total = 0;
548+
float total = 0;
549549
int count = 0;
550550
var targets = AllHostileTargets;
551551
for (int i = 0, n = targets.Count; i < n; i++)
552552
{
553-
int tTK = targets[i].GetTTK();
553+
float tTK = targets[i].GetTTK();
554554
if (!float.IsNaN(tTK))
555555
{
556556
total += tTK;
@@ -745,7 +745,7 @@ public static Dictionary<ulong, float> RefinedHP
745745
private static float GetPartyMemberHPRatio(IBattleChara member)
746746
{
747747
if (member == null)
748-
{
748+
{
749749
throw new ArgumentNullException(nameof(member));
750750
}
751751

@@ -858,7 +858,7 @@ public static float PartyMembersDifferHP
858858
internal static Queue<MacroItem> Macros { get; } = new Queue<MacroItem>();
859859

860860
#region Action Record
861-
private const int QUEUECAPACITY = 200;
861+
private const int QUEUECAPACITY = 48;
862862
private static readonly Queue<ActionRec> _actions = new(QUEUECAPACITY);
863863
private static readonly Queue<DamageRec> _damages = new(QUEUECAPACITY);
864864

@@ -1105,4 +1105,4 @@ public static bool IsHostileCastingBase(IBattleChara? h, Func<Action, bool> chec
11051105
// Invoke the check function on the action and return the result
11061106
return check?.Invoke(action) ?? false;
11071107
}
1108-
}
1108+
}

RotationSolver.Basic/Helpers/ObjectHelper.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ internal static unsafe bool IsEnemy(this IGameObject obj)
319319
internal static unsafe bool IsAllianceMember(this ICharacter obj)
320320
{
321321
return obj.GameObjectId is not 0
322-
&& !DataCenter.IsPvP && DataCenter.IsInAllianceRaid && obj is IPlayerCharacter
323-
&& (ActionManager.CanUseActionOnTarget((uint)ActionID.RaisePvE, (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Struct())
322+
&& !DataCenter.IsPvP && DataCenter.IsInAllianceRaid && obj is IPlayerCharacter
323+
&& (ActionManager.CanUseActionOnTarget((uint)ActionID.RaisePvE, (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Struct())
324324
|| ActionManager.CanUseActionOnTarget((uint)ActionID.CurePvE, (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Struct()));
325325
}
326326

@@ -1114,16 +1114,16 @@ internal static bool IsTargetMoving(this IBattleChara battleChara)
11141114
/// <returns>
11151115
/// The estimated time to kill the battle character in seconds, or <see cref="float.NaN"/> if the calculation cannot be performed.
11161116
/// </returns>
1117-
internal static int GetTTK(this IBattleChara battleChara, bool wholeTime = false)
1117+
internal static float GetTTK(this IBattleChara battleChara, bool wholeTime = false)
11181118
{
11191119
if (battleChara == null)
11201120
{
1121-
return 0;
1121+
return float.NaN;
11221122
}
11231123

11241124
if (battleChara.IsDummy())
11251125
{
1126-
return 999;
1126+
return 999.99f;
11271127
}
11281128

11291129
DateTime startTime = DateTime.MinValue;
@@ -1156,33 +1156,33 @@ internal static int GetTTK(this IBattleChara battleChara, bool wholeTime = false
11561156

11571157
if (startTime == DateTime.MinValue || (DateTime.Now - startTime) < CheckSpan)
11581158
{
1159-
return 0;
1159+
return float.NaN;
11601160
}
11611161

11621162
float currentHealthRatio = battleChara.GetHealthRatio();
1163-
if (currentHealthRatio == 0)
1163+
if (float.IsNaN(currentHealthRatio))
11641164
{
1165-
return 0;
1165+
return float.NaN;
11661166
}
11671167

11681168
// Manual average calculation to avoid LINQ
1169-
int sum = 0;
1169+
float sum = 0;
11701170
int count = 0;
1171-
foreach (int r in hpRatios.Select(v => (int)v))
1171+
foreach (float r in hpRatios)
11721172
{
11731173
sum += r;
11741174
count++;
11751175
}
1176-
int avg = count > 0 ? sum / count : 0;
1176+
float avg = count > 0 ? sum / count : 0;
11771177

11781178
float hpRatioDifference = initialHpRatio - avg;
11791179
if (hpRatioDifference <= 0)
11801180
{
1181-
return 0;
1181+
return float.NaN;
11821182
}
11831183

1184-
int elapsedTime = (int)(DateTime.Now - startTime).TotalSeconds;
1185-
return (int)(elapsedTime / hpRatioDifference * (wholeTime ? 1 : currentHealthRatio));
1184+
float elapsedTime = (float)(DateTime.Now - startTime).TotalSeconds;
1185+
return elapsedTime / hpRatioDifference * (wholeTime ? 1 : currentHealthRatio);
11861186
}
11871187

11881188
private static readonly ConcurrentDictionary<ulong, DateTime> _aliveStartTimes = [];
@@ -1446,4 +1446,4 @@ public static float DistanceToPlayer(this IBattleChara battleChara)
14461446
return distance;
14471447
}
14481448

1449-
}
1449+
}

RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public static bool CanHitPositional(EnemyPositional positional, IBattleChara ene
189189
/// <param name="range">The range to check (in yalms).</param>
190190
/// <returns>The number of hostile targets within the given range.</returns>
191191
[Description("The number of hostiles in specified range")]
192-
public static int NumberOfHostilesInRangeOf(int range)
192+
public static int NumberOfHostilesInRangeOf(float range)
193193
{
194194
return DataCenter.NumberOfHostilesInRangeOf(range);
195195
}
@@ -677,27 +677,27 @@ protected static bool StopMovingElapsedLess(float time)
677677
/// <br>WARNING: Do Not make this method the main of your rotation.</br>
678678
/// </summary>
679679
[Description("Stop moving time")]
680-
public static float StopMovingTime => DataCenter.StopMovingRaw;
680+
public static float StopMovingTime => IsMoving ? 0 : DataCenter.StopMovingRaw + DataCenter.DefaultGCDRemain;
681681

682682
/// <summary>
683683
/// How long the player has been moving.
684684
/// <br>WARNING: Do Not make this method the main of your rotation.</br>
685685
/// </summary>
686686
[Description("Moving time")]
687-
public static float MovingTime => DataCenter.MovingRaw;
687+
public static float MovingTime => IsMoving ? DataCenter.MovingRaw + DataCenter.DefaultGCDRemain : 0;
688688
/// <summary>
689689
/// How long the player has been alive.
690690
/// <br>WARNING: Do Not make this method the main of your rotation.</br>
691691
/// </summary>
692692
[Description("How long the player has been alive.")]
693-
public static float AliveTime => DataCenter.AliveTimeRaw;
693+
public static float AliveTime => Player.IsAlive() ? DataCenter.AliveTimeRaw + DataCenter.DefaultGCDRemain : 0;
694694

695695
/// <summary>
696696
/// How long the player has been dead.
697697
/// <br>WARNING: Do Not make this method the main of your rotation.</br>
698698
/// </summary>
699699
[Description("How long the player has been dead.")]
700-
public static float DeadTime => DataCenter.DeadTimeRaw;
700+
public static float DeadTime => Player.IsAlive() ? 0 : DataCenter.DeadTimeRaw + DataCenter.DefaultGCDRemain;
701701

702702
/// <summary>
703703
/// Time from GCD.

0 commit comments

Comments
 (0)