diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 966984ad6..99f9eca5e 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -2,7 +2,7 @@
AnyCPU
net471
- 7.2
+ 7.3
AnyCPU;x64
diff --git a/Dalamud/Game/ClientState/JobGauge.cs b/Dalamud/Game/ClientState/JobGauge.cs
new file mode 100644
index 000000000..e91b342fe
--- /dev/null
+++ b/Dalamud/Game/ClientState/JobGauge.cs
@@ -0,0 +1,25 @@
+using Dalamud.Game.ClientState.Structs.JobGauge;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState {
+ public static class JobGauge {
+
+ private static IntPtr gaugeStart;
+
+ public static void Init(ProcessModule module) {
+ gaugeStart = module.BaseAddress + 0x1b2d4b4;
+ }
+
+ // Should only be called with the gauge types in
+ // ClientState.Structs.JobGauge
+ public static T Gauge() {
+ return Marshal.PtrToStructure(gaugeStart);
+ }
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/ASTGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/ASTGauge.cs
new file mode 100644
index 000000000..3372da7d2
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/ASTGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class ASTGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/BLMGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/BLMGauge.cs
new file mode 100644
index 000000000..89f2df857
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/BLMGauge.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct BLMGauge {
+ [FieldOffset(0xc)] public short TimeUntilNextPolyglot; //eno timer (ms)
+ [FieldOffset(0xe)] public short ElementTimeRemaining; //ui/af timer
+ [FieldOffset(0x10)] private byte ElementStance; //ui/af
+ [FieldOffset(0x11)] public byte NumUmbralHearts; //number of umbral hearts
+ [FieldOffset(0x12)] public byte NumPolyglotStacks; //number of polyglot stacks
+ [FieldOffset(0x13)] public bool IsEnoActive; //eno active?
+
+ public bool InUmbralIce() {
+ return ElementStance > 4;
+ }
+
+ public bool InAstralFire() {
+ return ElementStance > 0 && ElementStance < 4;
+ }
+
+ }
+
+
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/BRDGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/BRDGauge.cs
new file mode 100644
index 000000000..b5d408a70
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/BRDGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class BRDGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/DNCGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/DNCGauge.cs
new file mode 100644
index 000000000..0302015f2
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/DNCGauge.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ public unsafe struct DNCGauge {
+ [FieldOffset(0xc)] public byte NumFeathers;
+ [FieldOffset(0xd)] public byte Esprit;
+ [FieldOffset(0xe)] public fixed byte StepOrder[4];
+ [FieldOffset(0x12)] public byte NumCompleteSteps;
+
+ public bool IsDancing() {
+ return StepOrder[0] != 0;
+ }
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/DRGGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/DRGGauge.cs
new file mode 100644
index 000000000..1e6293be7
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/DRGGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class DRGGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/DRKGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/DRKGauge.cs
new file mode 100644
index 000000000..bb4cdf455
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/DRKGauge.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+ [StructLayout(LayoutKind.Explicit)]
+ public struct DRKGauge {
+ [FieldOffset(0xc)] public short Blood;
+ [FieldOffset(0xe)] public short DarksideTimeRemaining;
+ [FieldOffset(0x10)] public bool HasDarkArts;
+ [FieldOffset(0x12)] public short ShadowTimeRemaining;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/GNBGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/GNBGauge.cs
new file mode 100644
index 000000000..772ffb18a
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/GNBGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class GNBGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/MCHGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/MCHGauge.cs
new file mode 100644
index 000000000..73f43f3dd
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/MCHGauge.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct MCHGauge{
+
+ [FieldOffset(0xc)] public short OverheatTimeRemaining;
+ [FieldOffset(0xe)] public short RobotTimeRemaining;
+ [FieldOffset(0x10)] public byte Heat;
+ [FieldOffset(0x11)] public byte Battery;
+ [FieldOffset(0x12)] public byte LastRobotBatteryPower;
+ [FieldOffset(0x13)] private byte TimerActive;
+
+ public bool IsOverheated() {
+ return (TimerActive & 1) != 0;
+ }
+ public bool IsRobotActive() {
+ return (TimerActive & 2) != 0;
+ }
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/MNKGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/MNKGauge.cs
new file mode 100644
index 000000000..0ba90975e
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/MNKGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class MNKGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/NINGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/NINGauge.cs
new file mode 100644
index 000000000..a70d77d18
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/NINGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class NINGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/PLDGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/PLDGauge.cs
new file mode 100644
index 000000000..7042ffc08
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/PLDGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class PLDGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/RDMGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/RDMGauge.cs
new file mode 100644
index 000000000..c2919a924
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/RDMGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct RDMGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/SAMGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/SAMGauge.cs
new file mode 100644
index 000000000..2b0a6d532
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/SAMGauge.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct SAMGauge {
+
+ [FieldOffset(0xf)] public byte Kenki;
+ [FieldOffset(0x10)] public byte Sen;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/SCHGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/SCHGauge.cs
new file mode 100644
index 000000000..ed241b46a
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/SCHGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class SCHGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/SMNGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/SMNGauge.cs
new file mode 100644
index 000000000..0c76138f5
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/SMNGauge.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct SMNGauge {
+
+ //Unfinished
+ [FieldOffset(0xc)] public short TimerRemaining;
+ [FieldOffset(0xf)] public bool IsDemiActive;
+ [FieldOffset(0x10)] public byte NumStacks;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/WARGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/WARGauge.cs
new file mode 100644
index 000000000..78387efb5
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/WARGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class WARGauge {
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/JobGauge/WHMGauge.cs b/Dalamud/Game/ClientState/Structs/JobGauge/WHMGauge.cs
new file mode 100644
index 000000000..4ae079e00
--- /dev/null
+++ b/Dalamud/Game/ClientState/Structs/JobGauge/WHMGauge.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Game.ClientState.Structs.JobGauge {
+
+ [StructLayout(LayoutKind.Explicit)]
+ class WHMGauge {
+ }
+}
diff --git a/Dalamud/Game/Internal/Gui/IconReplacer.cs b/Dalamud/Game/Internal/Gui/IconReplacer.cs
index bd40830b1..869ac04f6 100644
--- a/Dalamud/Game/Internal/Gui/IconReplacer.cs
+++ b/Dalamud/Game/Internal/Gui/IconReplacer.cs
@@ -1,4 +1,6 @@
+using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Actors.Types;
+using Dalamud.Game.ClientState.Structs.JobGauge;
using Dalamud.Hooking;
using Serilog;
using System;
@@ -22,6 +24,8 @@ namespace Dalamud.Game.Internal.Gui {
this.address = new IconReplacerAddressResolver();
this.address.Setup(scanner);
+ JobGauge.Init(module);
+
this.byteBase = scanner.Module.BaseAddress;
this.jobInfo = byteBase + 0x1b2d4b4;
this.comboTimer = byteBase + 0x1AE1B10;
@@ -227,6 +231,9 @@ namespace Dalamud.Game.Internal.Gui {
// Replace Mangetsu with Mangetsu combo
if (actionID == 7484) {
+ if (activeBuffArray != null) {
+ if (SearchBuffArray(1233)) return 7484;
+ }
if (comboTime > 0) {
if (lastMove == 7483) return 7484;
}
@@ -235,6 +242,9 @@ namespace Dalamud.Game.Internal.Gui {
// Replace Yukikaze with Yukikaze combo
if (actionID == 7485) {
+ if (activeBuffArray != null) {
+ if (SearchBuffArray(1233)) return 7485;
+ }
if (comboTime > 0) {
if (lastMove == 7483) return 7485;
}
@@ -311,7 +321,7 @@ namespace Dalamud.Game.Internal.Gui {
// Or with Heat Blast when overheated.
// For some reason the shots use their unheated IDs as combo moves
if (actionID == 7413) {
- if (Marshal.ReadInt16(jobInfo, 0xc) > 0) return 7410;
+ if (JobGauge.Gauge().IsOverheated() && level >= 35) return 7410;
if (comboTime > 0) {
if (lastMove == 2866) return 7412;
if (lastMove == 2868) return 7413;
@@ -321,7 +331,7 @@ namespace Dalamud.Game.Internal.Gui {
// Replace Spread Shot with Auto Crossbow when overheated.
if (actionID == 2870) {
- if (Marshal.ReadInt16(jobInfo, 0xc) > 0) return 16497;
+ if (JobGauge.Gauge().IsOverheated() && level >= 52) return 16497;
return 2870;
}
@@ -329,16 +339,17 @@ namespace Dalamud.Game.Internal.Gui {
// Enochian changes to B4 or F4 depending on stance.
if (actionID == 3575) {
- if (Marshal.ReadByte(jobInfo, 0x13) == 1) {
- if (Marshal.ReadByte(jobInfo, 0x10) > 3) return 3576;
- if (Marshal.ReadByte(jobInfo, 0x10) > 0) return 3577;
+ BLMGauge jobInfo = JobGauge.Gauge();
+ if (jobInfo.IsEnoActive) {
+ if (jobInfo.InUmbralIce()) return 3576;
+ return 3577;
}
return 3575;
}
// Umbral Soul and Transpose
- if (actionID == 16506) {
- if (Marshal.ReadByte(jobInfo, 0x10) > 3) return 16506;
+ if (actionID == 149) {
+ if (JobGauge.Gauge().InUmbralIce() && level >= 76) return 16506;
return 149;
}
@@ -400,17 +411,63 @@ namespace Dalamud.Game.Internal.Gui {
}
// DANCER
- // TODO: Single-target. This needs to be done alongside 1-button dances.
+
+ // Standard Step is one button.
+ if (actionID == 15997) {
+ DNCGauge gauge = JobGauge.Gauge();
+ if (gauge.IsDancing()) {
+ if (gauge.NumCompleteSteps == 2) {
+ return 16192;
+ }
+ else {
+ // C# can't implicitly cast from int to ulong.
+ return (ulong)(15999 + gauge.StepOrder[gauge.NumCompleteSteps] - 1);
+ }
+ }
+ return 15997;
+ }
- // Handle AoE GCDs on one button. Procs take priority over combo.
+ // Technical Step is one button.
+ if (actionID == 15998) {
+ DNCGauge gauge = JobGauge.Gauge();
+ if (gauge.IsDancing()) {
+ if (gauge.NumCompleteSteps == 4) {
+ return 16196;
+ }
+ else {
+ // C# can't implicitly cast from int to ulong.
+ return (ulong)(15999 + gauge.StepOrder[gauge.NumCompleteSteps] - 1);
+ }
+ }
+ return 15998;
+ }
- if (actionID == 15994) {
+ // Fountain changes into Fountain combo, prioritizing procs over combo,
+ // and Fountainfall over Reverse Cascade.
+ if (actionID == 15990) {
if (activeBuffArray != null) {
- if (SearchBuffArray(1816)) return 15995;
- if (SearchBuffArray(1817)) return 15996;
+ if (SearchBuffArray(1815)) return 15992;
+ if (SearchBuffArray(1814)) return 15991;
}
if (comboTime > 0) {
- if (lastMove == 15993) return 15994;
+ if (lastMove == 15989) return 15990;
+ }
+ return 15989;
+ }
+
+ // AoE GCDs are split into two buttons, because priority matters
+ // differently in different single-target moments. Thanks yoship.
+ // Replaces each GCD with its procced version.
+ if (actionID == 15994) {
+ if (activeBuffArray != null) {
+ if (SearchBuffArray(1817)) return 15996;
+ }
+ return 15994;
+ }
+
+ if (actionID == 15993) {
+ if (activeBuffArray != null) {
+ if (SearchBuffArray(1816)) return 15995;
}
return 15993;
}