Skip to content

Commit 0f69ddd

Browse files
committed
Enhance Phantom Cannoneer logic and hotfix for statestring
1 parent c07a871 commit 0f69ddd

File tree

7 files changed

+167
-42
lines changed

7 files changed

+167
-42
lines changed

BasicRotations/Duty/PhantomDefault.cs

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using RotationSolver.Basic.Rotations.Duties;
2+
using System.ComponentModel;
23

34
namespace RebornRotations.Duty;
45

@@ -29,8 +30,29 @@ public sealed class PhantomDefault : PhantomRotation
2930
[RotationConfig(CombatType.PvE, Name = "Your HP percentage needed to use Occult Chakra", PhantomJob = PhantomJob.Monk)]
3031
public float OccultChakraHPThreshold { get; set; } = 0.3f;
3132

32-
[RotationConfig(CombatType.PvE, Name = "Use Dark Cannon instead of Shock Cannon", PhantomJob = PhantomJob.Cannoneer)]
33-
public bool PreferDarkCannon { get; set; }
33+
[RotationConfig(CombatType.PvE, Name = "Use Dark Cannon or Shock Cannon in cases where the mob is immune to both blind and paralysis", PhantomJob = PhantomJob.Cannoneer)]
34+
public DarkShockCannonImmuneStrategy DarkShockCannonImmuneUsage { get; set; } = DarkShockCannonImmuneStrategy.DarkCannon;
35+
36+
public enum DarkShockCannonImmuneStrategy : byte
37+
{
38+
[Description("Dark Cannon")]
39+
DarkCannon,
40+
41+
[Description("Shock Cannon")]
42+
ShockCannon,
43+
}
44+
45+
[RotationConfig(CombatType.PvE, Name = "Use Dark Cannon or Shock Cannon in cases where the mob is susceptible to both blind and paralysis", PhantomJob = PhantomJob.Cannoneer)]
46+
public DarkShockCannonStrategy DarkShockCannonUsage { get; set; } = DarkShockCannonStrategy.DarkCannon;
47+
48+
public enum DarkShockCannonStrategy : byte
49+
{
50+
[Description("Dark Cannon")]
51+
DarkCannon,
52+
53+
[Description("Shock Cannon")]
54+
ShockCannon,
55+
}
3456

3557
[Range(0, 1, ConfigUnitType.Percent)]
3658
[RotationConfig(CombatType.PvE, Name = "Average party HP percent to predict to heal with judgement instead of damage things", PhantomJob = PhantomJob.Oracle)]
@@ -582,27 +604,57 @@ public override bool GeneralGCD(out IAction? act)
582604
return true;
583605
}
584606

585-
if (SilverCannonPvE.CanUse(out act))
586-
{
587-
return true;
588-
}
589-
590-
//TODO: If enemy is undead should we prioritize this over SilverCannon?
591-
//TODO2: Figure out a way to identify target is undead
592607
if (HolyCannonPvE.CanUse(out act))
593608
{
594609
return true;
595610
}
596611

597-
// Only one of shock or dark can be used, prioritize Shock unless PreferDarkCannon is set
598-
if (!PreferDarkCannon && ShockCannonPvE.CanUse(out act))
612+
if (SilverCannonPvE.CanUse(out act))
599613
{
600614
return true;
601615
}
602616

603-
if (DarkCannonPvE.CanUse(out act))
617+
if (InCombat)
604618
{
605-
return true;
619+
// logic if both cannons effects can be used on target
620+
if (ShockCannonPvE.CanUse(out _) && DarkCannonPvE.CanUse(out _))
621+
{
622+
if (DarkShockCannonUsage == DarkShockCannonStrategy.DarkCannon && DarkCannonPvE.CanUse(out act))
623+
{
624+
return true;
625+
}
626+
if (DarkShockCannonUsage == DarkShockCannonStrategy.ShockCannon && ShockCannonPvE.CanUse(out act))
627+
{
628+
return true;
629+
}
630+
}
631+
632+
// logic for each cannon effect seperately
633+
if (DarkCannonPvE.CanUse(out act))
634+
{
635+
return true;
636+
}
637+
638+
if (ShockCannonPvE.CanUse(out act))
639+
{
640+
return true;
641+
}
642+
643+
// logic if neither cannons effects can be used on target
644+
if (CannoneerLevel < 4 || DarkShockCannonImmuneUsage == DarkShockCannonImmuneStrategy.DarkCannon)
645+
{
646+
if (DarkCannonPvE.Setting.TargetType == TargetType.HighHP && DarkCannonPvE.CanUse(out act))
647+
{
648+
return true;
649+
}
650+
}
651+
if (DarkShockCannonImmuneUsage == DarkShockCannonImmuneStrategy.ShockCannon)
652+
{
653+
if (ShockCannonPvE.Setting.TargetType == TargetType.HighHP && ShockCannonPvE.CanUse(out act))
654+
{
655+
return true;
656+
}
657+
}
606658
}
607659

608660
if (PhantomFirePvE.CanUse(out act))

RotationSolver.Basic/Actions/ActionTargetInfo.cs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using FFXIVClientStructs.FFXIV.Client.Game.Object;
1010
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
1111
using RotationSolver.Basic.Configuration;
12+
using RotationSolver.Basic.Rotations.Duties;
1213
using static RotationSolver.Basic.Configuration.ConfigTypes;
1314
using AttackType = RotationSolver.Basic.Data.AttackType;
1415
using CombatRole = RotationSolver.Basic.Data.CombatRole;
@@ -440,7 +441,7 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
440441

441442
if (range == 0 && EffectRange == 0)
442443
{
443-
return new TargetResult(Player.Object, Array.Empty<IBattleChara>(), Player.Object.Position);
444+
return new TargetResult(Player.Object, [], Player.Object.Position);
444445
}
445446

446447
TargetType type = action.Setting.TargetType;
@@ -1145,6 +1146,9 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
11451146
TargetType.Range => battleChara != null ? RandomRangeTarget(battleChara) : null,
11461147
TargetType.Magical => battleChara != null ? RandomMagicalTarget(battleChara) : null,
11471148
TargetType.Physical => battleChara != null ? RandomPhysicalTarget(battleChara) : null,
1149+
TargetType.DarkCannon => FindDarkCannonTarget(),
1150+
TargetType.ShockCannon => FindShockCannonTarget(),
1151+
TargetType.HolyCannon => FindHolyCannon(),
11481152
TargetType.PhantomMob => FindPhantomMob(),
11491153
TargetType.PhantomBell => FindPhantomBell(),
11501154
TargetType.PhantomRespite => FindPhantomRespite(),
@@ -1158,6 +1162,65 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
11581162
_ => FindHostile(),
11591163
};
11601164

1165+
IBattleChara? FindDarkCannonTarget()
1166+
{
1167+
if (DataCenter.AllHostileTargets != null)
1168+
{
1169+
if (PhantomRotation.CannoneerLevel < 4)
1170+
{
1171+
return FindHostile();
1172+
}
1173+
else
1174+
{
1175+
foreach (var hostile in DataCenter.AllHostileTargets)
1176+
{
1177+
if (!hostile.IsOCBlindImmuneTarget() && hostile.InCombat())
1178+
{
1179+
return hostile;
1180+
}
1181+
}
1182+
}
1183+
}
1184+
return null;
1185+
}
1186+
1187+
IBattleChara? FindShockCannonTarget()
1188+
{
1189+
if (DataCenter.AllHostileTargets != null)
1190+
{
1191+
foreach (var hostile in DataCenter.AllHostileTargets)
1192+
{
1193+
if (!hostile.IsOCParalysisImmuneTarget() && hostile.InCombat())
1194+
{
1195+
return hostile;
1196+
}
1197+
}
1198+
}
1199+
return null;
1200+
}
1201+
1202+
IBattleChara? FindHolyCannon()
1203+
{
1204+
if (DataCenter.AllHostileTargets != null)
1205+
{
1206+
if (PhantomRotation.CannoneerLevel < 6)
1207+
{
1208+
return FindHostile();
1209+
}
1210+
else
1211+
{
1212+
foreach (var hostile in DataCenter.AllHostileTargets)
1213+
{
1214+
if (hostile != null && hostile.IsOCUndeadTarget() && hostile.InCombat())
1215+
{
1216+
return hostile;
1217+
}
1218+
}
1219+
}
1220+
}
1221+
return null;
1222+
}
1223+
11611224
IBattleChara? FindPhantomDispel()
11621225
{
11631226
if (DataCenter.AllHostileTargets != null)
@@ -2331,7 +2394,7 @@ private static bool IsNeededRole(IBattleChara character)
23312394

23322395
private static IBattleChara? RandomPickByJobs(IEnumerable<IBattleChara> tars, params Job[] jobs)
23332396
{
2334-
List<IBattleChara> targets = new();
2397+
List<IBattleChara> targets = [];
23352398
foreach (var t in tars)
23362399
{
23372400
if (t.IsJobs(jobs))
@@ -2385,7 +2448,10 @@ public enum TargetType : byte
23852448
PhantomMob,
23862449
PhantomBell,
23872450
PhantomRespite,
2388-
PhantomDispel
2451+
PhantomDispel,
2452+
HolyCannon,
2453+
DarkCannon,
2454+
ShockCannon
23892455
}
23902456
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
23912457

RotationSolver.Basic/Helpers/ObjectHelper.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,15 +625,14 @@ internal static bool IsSpecialInclusionPriority(this IBattleChara battleChara)
625625
13925, //Troubadour
626626
13923, //Geshunpest
627627
13927, //Dullahan
628-
629628
};
630629

631630
/// <summary>
632631
/// Check to see if Occult Crecent target is Undead.
633632
/// </summary>
634633
public static bool IsOCUndeadTarget(this IBattleChara battleChara)
635634
{
636-
return IsOCSlowgaImmuneList.Contains(battleChara.NameId);
635+
return IsOCUndeadList.Contains(battleChara.NameId);
637636
}
638637

639638
/// <summary>

RotationSolver.Basic/Rotations/Duties/PhantomRotation.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ static partial void ModifyPhantomFirePvE(ref ActionSetting setting)
389389
static partial void ModifyHolyCannonPvE(ref ActionSetting setting)
390390
{
391391
setting.ActionCheck = () => CannoneerLevel >= 2;
392+
setting.TargetType = TargetType.HolyCannon;
392393
setting.CreateConfig = () => new ActionConfig()
393394
{
394395
AoeCount = 1,
@@ -402,7 +403,7 @@ static partial void ModifyHolyCannonPvE(ref ActionSetting setting)
402403
static partial void ModifyDarkCannonPvE(ref ActionSetting setting)
403404
{
404405
setting.ActionCheck = () => CannoneerLevel >= 3;
405-
setting.TargetStatusProvide = [StatusID.Blind];
406+
setting.TargetType = TargetType.DarkCannon;
406407
setting.CreateConfig = () => new ActionConfig()
407408
{
408409
AoeCount = 1,
@@ -416,7 +417,7 @@ static partial void ModifyDarkCannonPvE(ref ActionSetting setting)
416417
static partial void ModifyShockCannonPvE(ref ActionSetting setting)
417418
{
418419
setting.ActionCheck = () => CannoneerLevel >= 4;
419-
setting.TargetStatusProvide = [StatusID.Paralysis];
420+
setting.TargetType = TargetType.ShockCannon;
420421
setting.CreateConfig = () => new ActionConfig()
421422
{
422423
AoeCount = 1,

RotationSolver/Commands/RSCommands_StateSpecialCommand.cs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ namespace RotationSolver.Commands
66
{
77
public static partial class RSCommands
88
{
9-
public static string StateString { get; private set; } = "Off";
10-
public static string SpecialString { get; private set; } = string.Empty;
9+
public static string _stateString = "Off", _specialString = string.Empty;
1110

12-
internal static string EntryString => $"{StateString}{(DataCenter.SpecialTimeLeft < 0 ? string.Empty : $" - {SpecialString}: {DataCenter.SpecialTimeLeft:F2}s")}";
11+
internal static string EntryString => $"{_stateString}{(DataCenter.SpecialTimeLeft < 0 ? string.Empty : $" - {_specialString}: {DataCenter.SpecialTimeLeft:F2}s")}";
1312

1413
private static string _lastToastMessage = string.Empty;
1514

@@ -37,14 +36,14 @@ private static void UpdateToast()
3736
public static unsafe void DoStateCommandType(StateCommandType stateType, int index = -1)
3837
{
3938
DoOneCommandType((type, role) => type.ToStateString(role), role =>
40-
{
41-
if (DataCenter.State)
4239
{
43-
stateType = AdjustStateType(stateType, ref index);
44-
}
45-
UpdateState(stateType, role);
46-
return stateType;
47-
});
40+
if (DataCenter.State)
41+
{
42+
stateType = AdjustStateType(stateType, ref index);
43+
}
44+
UpdateState(stateType, role);
45+
return stateType;
46+
});
4847
}
4948

5049
private static StateCommandType AdjustStateType(StateCommandType stateType, ref int index)
@@ -106,23 +105,23 @@ public static void UpdateState(StateCommandType stateType, JobRole role)
106105
break;
107106
}
108107

109-
StateString = stateType.ToStateString(role);
108+
_stateString = stateType.ToStateString(role);
110109
UpdateToast();
111110
}
112111

113112
private static void DoSpecialCommandType(SpecialCommandType specialType, bool sayout = true)
114113
{
115114
DoOneCommandType((type, role) => type.ToSpecialString(role), role =>
116-
{
117-
SpecialString = specialType.ToSpecialString(role);
118-
DataCenter.SpecialType = specialType;
119-
if (sayout)
120115
{
121-
UpdateToast();
122-
}
116+
_specialString = specialType.ToSpecialString(role);
117+
DataCenter.SpecialType = specialType;
118+
if (sayout)
119+
{
120+
UpdateToast();
121+
}
123122

124-
return specialType;
125-
});
123+
return specialType;
124+
});
126125
}
127126

128127
private static void DoOneCommandType<T>(Func<T, JobRole, string> sayout, Func<JobRole, T> doingSomething)
@@ -138,4 +137,4 @@ private static void DoOneCommandType<T>(Func<T, JobRole, string> sayout, Func<Jo
138137
_ = doingSomething(role);
139138
}
140139
}
141-
}
140+
}

RotationSolver/UI/RotationConfigWindow.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3839,9 +3839,17 @@ private static unsafe void DrawTargetData()
38393839
ImGui.Spacing();
38403840
ImGui.Text($"FateID: {battleChara.FateId().ToString() ?? string.Empty}");
38413841
ImGui.Text($"EventType: {battleChara.GetEventType().ToString() ?? string.Empty}");
3842+
ImGui.Text($"IsBozjanCEFateMob: {battleChara.IsBozjanCEFateMob()}");
3843+
ImGui.Spacing();
38423844
ImGui.Text($"IsOccultCEMob: {battleChara.IsOccultCEMob()}");
38433845
ImGui.Text($"IsOccultFateMob: {battleChara.IsOccultFateMob()}");
3844-
ImGui.Text($"IsBozjanCEFateMob: {battleChara.IsBozjanCEFateMob()}");
3846+
ImGui.Text($"IsOCUndeadTarget: {battleChara.IsOCUndeadTarget()}");
3847+
ImGui.Text($"IsOCSlowgaImmuneTarget: {battleChara.IsOCSlowgaImmuneTarget()}");
3848+
ImGui.Text($"IsOCDoomImmuneTarget: {battleChara.IsOCDoomImmuneTarget()}");
3849+
ImGui.Text($"IsOCStunImmuneTarget: {battleChara.IsOCStunImmuneTarget()}");
3850+
ImGui.Text($"IsOCFreezeImmuneTarget: {battleChara.IsOCFreezeImmuneTarget()}");
3851+
ImGui.Text($"IsOCBlindImmuneTarget: {battleChara.IsOCBlindImmuneTarget()}");
3852+
ImGui.Text($"IsOCParalysisImmuneTarget: {battleChara.IsOCParalysisImmuneTarget()}");
38453853
ImGui.Spacing();
38463854
ImGui.Text($"Is Current Focus Target: {battleChara.IsFocusTarget()}");
38473855
ImGui.Text($"TTK: {battleChara.GetTTK()}");

RotationSolver/Updaters/TargetUpdater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private static List<IBattleChara> GetAllHostileTargets()
101101

102102
foreach (IBattleChara target in allTargets)
103103
{
104-
if (!target.IsEnemy() || !target.IsTargetable)
104+
if (!target.IsEnemy() || !target.IsTargetable || !target.CanSee())
105105
continue;
106106

107107
bool hasInvincible = false;

0 commit comments

Comments
 (0)