Icon dev (#4)

Icon dev
This commit is contained in:
goaaats 2019-11-01 23:12:38 +09:00 committed by GitHub
commit f889ef7650
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 1104 additions and 437 deletions

View file

@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XIVLauncher.Dalamud
{
//CURRENT HIGHEST FLAG IS 44
[Flags]
public enum CustomComboPreset : long
{
None = 0,
// DRAGOON
[CustomComboInfo("Coerthan Torment Combo", "Replace Coerthan Torment with its combo chain", 22)]
DragoonCoerthanTormentCombo = 1L << 0,
[CustomComboInfo("Chaos Thrust Combo", "Replace Chaos Thrust with its combo chain", 22)]
DragoonChaosThrustCombo = 1L << 1,
[CustomComboInfo("Full Thrust Combo", "Replace Full Thrust with its combo chain", 22)]
DragoonFullThrustCombo = 1L << 2,
// DARK KNIGHT
[CustomComboInfo("Souleater Combo", "Replace Souleater with its combo chain", 32)]
DarkSouleaterCombo = 1L << 3,
[CustomComboInfo("Stalwart Soul Combo", "Replace Stalwart Soul with its combo chain", 32)]
DarkStalwartSoulCombo = 1L << 4,
// PALADIN
[CustomComboInfo("Goring Blade Combo", "Replace Goring Blade with its combo chain", 19)]
PaladinGoringBladeCombo = 1L << 5,
[CustomComboInfo("Royal Authority Combo", "Replace Royal Authority with its combo chain", 19)]
PaladinRoyalAuthorityCombo = 1L << 6,
[CustomComboInfo("Prominence Combo", "Replace Prominence with its combo chain", 19)]
PaladinProminenceCombo = 1L << 7,
// WARRIOR
[CustomComboInfo("Storms Path Combo", "Replace Storms Path with its combo chain", 21)]
WarriorStormsPathCombo = 1L << 8,
[CustomComboInfo("Storms Eye Combo", "Replace Storms Eye with its combo chain", 21)]
WarriorStormsEyeCombo = 1L << 9,
[CustomComboInfo("Mythril Tempest Combo", "Replace Mythril Tempest with its combo chain", 21)]
WarriorMythrilTempestCombo = 1L << 10,
// SAMURAI
[CustomComboInfo("Yukikaze Combo", "Replace Yukikaze with its combo chain", 34)]
SamuraiYukikazeCombo = 1L << 11,
[CustomComboInfo("Gekko Combo", "Replace Gekko with its combo chain", 34)]
SamuraiGekkoCombo = 1L << 12,
[CustomComboInfo("Kasha Combo", "Replace Kasha with its combo chain", 34)]
SamuraiKashaCombo = 1L << 13,
[CustomComboInfo("Mangetsu Combo", "Replace Mangetsu with its combo chain", 34)]
SamuraiMangetsuCombo = 1L << 14,
[CustomComboInfo("Oka Combo", "Replace Oka with its combo chain", 34)]
SamuraiOkaCombo = 1L << 15,
// NINJA
[CustomComboInfo("Armor Crush Combo", "Replace Armor Crush with its combo chain", 30)]
NinjaArmorCrushCombo = 1L << 17,
[CustomComboInfo("Aeolian Edge Combo", "Replace Aeolian Edge with its combo chain", 30)]
NinjaAeolianEdgeCombo = 1L << 18,
[CustomComboInfo("Hakke Mujinsatsu Combo", "Replace Hakke Mujinsatsu with its combo chain", 30)]
NinjaHakkeMujinsatsuCombo = 1L << 19,
// GUNBREAKER
[CustomComboInfo("Solid Barrel Combo", "Replace Solid Barrel with its combo chain", 37)]
GunbreakerSolidBarrelCombo = 1L << 20,
[CustomComboInfo("Gnashing Fang Combo", "Replace Gnashing Fang with its combo chain", 37)]
GunbreakerGnashingFangCombo = 1L << 21,
[CustomComboInfo("Demon Slaughter Combo", "Replace Demon Slaughter with its combo chain", 37)]
GunbreakerDemonSlaughterCombo = 1L << 22,
// MACHINIST
[CustomComboInfo("Heated Clan Shot Combo/Heat", "Replace Heated Clan Shot with its combo chain or with Heat Blast when overheated.", 31)]
MachinistHeatedClanShotFeature = 1L << 23,
[CustomComboInfo("Spread Shot Heat", "Replace Spread Shot with Auto Crossbow when overheated.", 31)]
MachinistSpreadShotFeature = 1L << 24,
// BLACK MAGE
[CustomComboInfo("Enochian Stance Switcher", "Change Enochian to Fire 4 or Blizzard 4 depending on stance.", 25)]
BlackEnochianFeature = 1L << 25,
[CustomComboInfo("Umbral Soul/Transpose Switcher", "Change between Umbral Soul and Transpose automatically.", 25)]
BlackManaFeature = 1L << 26,
// ASTROLOGIAN
[CustomComboInfo("Draw on Play", "Play turns into Draw when no card is drawn, as well as the usual Play behavior.", 33)]
AstrologianCardsOnDrawFeature = 1L << 27,
// SUMMONER
[CustomComboInfo("Demi-summon combiners", "Dreadwyrm Trance, Summon Bahamut, and Firebird Trance are now one button. Deathflare, Enkindle Bahamut, and Enkindle Phoenix are now one button.", 27)]
SummonerDemiCombo = 1L << 28,
[CustomComboInfo("Brand of Purgatory Combo", "Replaces Fountain of Fire with Brand of Purgatory when under the affect of Hellish Conduit.", 27)]
SummonerBoPCombo = 1L << 38,
[CustomComboInfo("ED Fester", "Change Energy Drain into Fester while you have Aetherflow stacks.", 27)]
SummonerEDFesterCombo = 1L << 39,
[CustomComboInfo("ES Painflare", "Change Energy Siphon into Painflare while you have Aetherflow stacks.", 27)]
SummonerESPainflareCombo = 1L << 40,
// SCHOLAR
[CustomComboInfo("Seraph Fey Blessing/Consolation", "Change Fey Blessing into Consolation when Seraph is out.", 28)]
ScholarSeraphConsolationFeature = 1L << 29,
[CustomComboInfo("ED Aetherflow", "Change Energy Drain into Aetherflow when you have no more Aetherflow stacks.", 28)]
ScholarEnergyDrainFeature = 1L << 37,
// DANCER
[CustomComboInfo("AoE GCD procs", "Replaces all AoE GCDs with their procced version when available.", 38)]
DancerAoeGcdFeature = 1L << 32,
[CustomComboInfo("Fan Dance Combos", "Change Fan Dance and Fan Dance 2 into Fan Dance 3 while flourishing.", 38)]
DancerFanDanceCombo = 1L << 33,
// WHITE MAGE
[CustomComboInfo("Solace into Misery", "Replaces Afflatus Solace with Afflatus Misery when Misery is ready to be used.", 24)]
WhiteMageSolaceMiseryFeature = 1L << 35,
[CustomComboInfo("Rapture into Misery", "Replaces Afflatus Rapture with Afflatus Misery when Misery is ready to be used.", 24)]
WhiteMageRaptureMiseryFeature = 1L << 36,
// BARD
[CustomComboInfo("Wanderer's into Pitch Perfect", "Replaces Wanderer's Minuet with Pitch Perfect while in WM.", 23)]
BardWandererPPFeature = 1L << 41,
[CustomComboInfo("Heavy Shot into Straight Shot", "Replaces Heavy Shot/Burst Shot with Straight Shot/Refulgent Arrow when procced.", 23)]
BardStraightShotUpgradeFeature = 1L << 42,
// MONK
// RED MAGE
[CustomComboInfo("Red Mage AoE Combo", "Replaces Veraero/thunder 2 with Impact when Dualcast or Swiftcast are active.", 35)]
RedMageAoECombo = 1L << 48,
[CustomComboInfo("Redoublement combo", "Replaces Redoublement with its combo chain, following enchantment rules.", 35)]
RedMageMeleeCombo = 1L << 49
}
public class CustomComboInfoAttribute : Attribute
{
internal CustomComboInfoAttribute(string fancyName, string description, byte classJob)
{
FancyName = fancyName;
Description = description;
ClassJob = classJob;
}
public string FancyName { get; }
public string Description { get; }
public byte ClassJob { get; }
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.IO;
using Dalamud.DiscordBot;
using Newtonsoft.Json;
using XIVLauncher.Dalamud;
namespace Dalamud
{
[Serializable]
public class DalamudConfiguration
{
public DiscordFeatureConfiguration DiscordFeatureConfig { get; set; }
public bool OptOutMbCollection { get; set; } = false;
public CustomComboPreset ComboPresets { get; set; }
public List<string> BadWords { get; set; }
public class FateInfo {
public string Name { get; set; }
public int Id { get; set; }
}
public List<FateInfo> Fates;
public static DalamudConfiguration Load(string path) {
return JsonConvert.DeserializeObject<DalamudConfiguration>(File.ReadAllText(path));
}
public void Save(string path) {
File.WriteAllText(path, JsonConvert.SerializeObject(this));
}
}
}

View file

@ -14,8 +14,8 @@ using Dalamud.Game.Internal;
using Dalamud.Game.Internal.Gui; using Dalamud.Game.Internal.Gui;
using Dalamud.Game.Network; using Dalamud.Game.Network;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Settings;
using Serilog; using Serilog;
using XIVLauncher.Dalamud;
namespace Dalamud { namespace Dalamud {
public sealed class Dalamud : IDisposable { public sealed class Dalamud : IDisposable {
@ -42,10 +42,11 @@ namespace Dalamud {
public readonly IconReplacer IconReplacer; public readonly IconReplacer IconReplacer;
public readonly IconReplaceChecker IconReplaceChecker; public readonly DalamudConfiguration Configuration;
public Dalamud(DalamudStartInfo info) { public Dalamud(DalamudStartInfo info) {
this.StartInfo = info; this.StartInfo = info;
this.Configuration = DalamudConfiguration.Load(info.ConfigurationPath);
this.baseDirectory = info.WorkingDirectory; this.baseDirectory = info.WorkingDirectory;
@ -63,17 +64,15 @@ namespace Dalamud {
SetupCommands(); SetupCommands();
ChatHandlers = new ChatHandlers(this); ChatHandlers = new ChatHandlers(this);
NetworkHandlers = new NetworkHandlers(this, info.OptOutMbCollection); NetworkHandlers = new NetworkHandlers(this, this.Configuration.OptOutMbCollection);
this.ClientState = new ClientState(this, info, this.sigScanner, this.targetModule); this.ClientState = new ClientState(this, info, this.sigScanner, this.targetModule);
this.BotManager = new DiscordBotManager(this, info.DiscordFeatureConfig); this.BotManager = new DiscordBotManager(this, this.Configuration.DiscordFeatureConfig);
this.PluginManager = new PluginManager(this, info.PluginDirectory, info.DefaultPluginDirectory); this.PluginManager = new PluginManager(this, info.PluginDirectory, info.DefaultPluginDirectory);
this.IconReplaceChecker = new IconReplaceChecker(this.targetModule, this.sigScanner); this.IconReplacer = new IconReplacer(this, this.sigScanner);
this.IconReplacer = new IconReplacer(this, this.targetModule, this.sigScanner);
try { try {
this.PluginManager.LoadPlugins(); this.PluginManager.LoadPlugins();
@ -89,8 +88,6 @@ namespace Dalamud {
this.BotManager.Start(); this.BotManager.Start();
this.IconReplaceChecker.Enable();
this.IconReplacer.Enable(); this.IconReplacer.Enable();
} }
@ -109,8 +106,6 @@ namespace Dalamud {
this.unloadSignal.Dispose(); this.unloadSignal.Dispose();
this.IconReplaceChecker.Dispose();
this.IconReplacer.Dispose(); this.IconReplacer.Dispose();
} }
@ -130,6 +125,11 @@ namespace Dalamud {
ShowInHelp = false ShowInHelp = false
}); });
CommandManager.AddHandler("/xldcombo", new CommandInfo(OnCommandDebugCombo) {
HelpMessage = "COMBO debug",
ShowInHelp = false
});
CommandManager.AddHandler("/xlhelp", new CommandInfo(OnCommandHelp) { CommandManager.AddHandler("/xlhelp", new CommandInfo(OnCommandHelp) {
HelpMessage = "Shows list of commands available." HelpMessage = "Shows list of commands available."
}); });
@ -217,8 +217,8 @@ namespace Dalamud {
} }
private void OnFateWatchAdd(string command, string arguments) { private void OnFateWatchAdd(string command, string arguments) {
if (PersistentSettings.Instance.Fates == null) if (this.Configuration.Fates == null)
PersistentSettings.Instance.Fates = new List<PersistentSettings.FateInfo>(); this.Configuration.Fates = new List<DalamudConfiguration.FateInfo>();
dynamic candidates = XivApi.Search(arguments, "Fate").GetAwaiter().GetResult(); dynamic candidates = XivApi.Search(arguments, "Fate").GetAwaiter().GetResult();
@ -227,32 +227,36 @@ namespace Dalamud {
return; return;
} }
var fateInfo = new PersistentSettings.FateInfo { var fateInfo = new DalamudConfiguration.FateInfo {
Id = candidates.Results[0].ID, Id = candidates.Results[0].ID,
Name = candidates.Results[0].Name Name = candidates.Results[0].Name
}; };
PersistentSettings.Instance.Fates.Add(fateInfo); this.Configuration.Fates.Add(fateInfo);
this.Configuration.Save(this.StartInfo.ConfigurationPath);
Framework.Gui.Chat.Print($"Added fate \"{fateInfo.Name}\"."); Framework.Gui.Chat.Print($"Added fate \"{fateInfo.Name}\".");
} }
private void OnFateWatchList(string command, string arguments) { private void OnFateWatchList(string command, string arguments) {
if (PersistentSettings.Instance.Fates == null) if (this.Configuration.Fates == null)
PersistentSettings.Instance.Fates = new List<PersistentSettings.FateInfo>(); this.Configuration.Fates = new List<DalamudConfiguration.FateInfo>();
if (PersistentSettings.Instance.Fates.Count == 0) { if (this.Configuration.Fates.Count == 0) {
Framework.Gui.Chat.Print("No fates on your watchlist."); Framework.Gui.Chat.Print("No fates on your watchlist.");
return; return;
} }
foreach (var fate in PersistentSettings.Instance.Fates) this.Configuration.Save(this.StartInfo.ConfigurationPath);
foreach (var fate in this.Configuration.Fates)
Framework.Gui.Chat.Print($"Fate {fate.Id}: {fate.Name}"); Framework.Gui.Chat.Print($"Fate {fate.Id}: {fate.Name}");
} }
private void OnFateWatchRemove(string command, string arguments) { private void OnFateWatchRemove(string command, string arguments) {
if (PersistentSettings.Instance.Fates == null) if (this.Configuration.Fates == null)
PersistentSettings.Instance.Fates = new List<PersistentSettings.FateInfo>(); this.Configuration.Fates = new List<DalamudConfiguration.FateInfo>();
dynamic candidates = XivApi.Search(arguments, "Fate").GetAwaiter().GetResult(); dynamic candidates = XivApi.Search(arguments, "Fate").GetAwaiter().GetResult();
@ -261,37 +265,45 @@ namespace Dalamud {
return; return;
} }
PersistentSettings.Instance.Fates.RemoveAll(x => x.Id == candidates.Results[0].ID); this.Configuration.Fates.RemoveAll(x => x.Id == candidates.Results[0].ID);
this.Configuration.Save(this.StartInfo.ConfigurationPath);
Framework.Gui.Chat.Print($"Removed fate \"{candidates.Results[0].Name}\"."); Framework.Gui.Chat.Print($"Removed fate \"{candidates.Results[0].Name}\".");
} }
private void OnBadWordsAdd(string command, string arguments) { private void OnBadWordsAdd(string command, string arguments) {
if (PersistentSettings.Instance.BadWords == null) if (this.Configuration.BadWords == null)
PersistentSettings.Instance.BadWords = new List<string>(); this.Configuration.BadWords = new List<string>();
PersistentSettings.Instance.BadWords.Add(arguments); this.Configuration.BadWords.Add(arguments);
this.Configuration.Save(this.StartInfo.ConfigurationPath);
Framework.Gui.Chat.Print($"Muted \"{arguments}\"."); Framework.Gui.Chat.Print($"Muted \"{arguments}\".");
} }
private void OnBadWordsList(string command, string arguments) { private void OnBadWordsList(string command, string arguments) {
if (PersistentSettings.Instance.BadWords == null) if (this.Configuration.BadWords == null)
PersistentSettings.Instance.BadWords = new List<string>(); this.Configuration.BadWords = new List<string>();
if (PersistentSettings.Instance.BadWords.Count == 0) { if (this.Configuration.BadWords.Count == 0) {
Framework.Gui.Chat.Print("No muted words or sentences."); Framework.Gui.Chat.Print("No muted words or sentences.");
return; return;
} }
foreach (var word in PersistentSettings.Instance.BadWords) Framework.Gui.Chat.Print($"\"{word}\""); this.Configuration.Save(this.StartInfo.ConfigurationPath);
foreach (var word in this.Configuration.BadWords) Framework.Gui.Chat.Print($"\"{word}\"");
} }
private void OnBadWordsRemove(string command, string arguments) { private void OnBadWordsRemove(string command, string arguments) {
if (PersistentSettings.Instance.BadWords == null) if (this.Configuration.BadWords == null)
PersistentSettings.Instance.BadWords = new List<string>(); this.Configuration.BadWords = new List<string>();
PersistentSettings.Instance.BadWords.RemoveAll(x => x == arguments); this.Configuration.BadWords.RemoveAll(x => x == arguments);
this.Configuration.Save(this.StartInfo.ConfigurationPath);
Framework.Gui.Chat.Print($"Unmuted \"{arguments}\"."); Framework.Gui.Chat.Print($"Unmuted \"{arguments}\".");
} }
@ -328,6 +340,75 @@ namespace Dalamud {
} }
} }
private void OnCommandDebugCombo(string command, string arguments) {
var argumentsParts = arguments.Split();
switch (argumentsParts[0]) {
case "setall": {
foreach (var value in Enum.GetValues(typeof(CustomComboPreset)).Cast<CustomComboPreset>()) {
if (value == CustomComboPreset.None)
continue;
this.Configuration.ComboPresets |= value;
}
Framework.Gui.Chat.Print("all SET");
}
break;
case "unsetall": {
foreach (var value in Enum.GetValues(typeof(CustomComboPreset)).Cast<CustomComboPreset>()) {
this.Configuration.ComboPresets &= value;
}
Framework.Gui.Chat.Print("all UNSET");
}
break;
case "set": {
foreach (var value in Enum.GetValues(typeof(CustomComboPreset)).Cast<CustomComboPreset>()) {
if (value.ToString().ToLower() != argumentsParts[1].ToLower())
continue;
this.Configuration.ComboPresets |= value;
Framework.Gui.Chat.Print(argumentsParts[1] + " SET");
}
}
break;
case "toggle": {
foreach (var value in Enum.GetValues(typeof(CustomComboPreset)).Cast<CustomComboPreset>()) {
if (value.ToString().ToLower() != argumentsParts[1].ToLower())
continue;
this.Configuration.ComboPresets ^= value;
Framework.Gui.Chat.Print(argumentsParts[1] + " TOGGLE");
}
}
break;
case "unset": {
foreach (var value in Enum.GetValues(typeof(CustomComboPreset)).Cast<CustomComboPreset>()) {
if (value.ToString().ToLower() != argumentsParts[1].ToLower())
continue;
this.Configuration.ComboPresets &= ~value;
Framework.Gui.Chat.Print(argumentsParts[1] + " UNSET");
}
}
break;
case "list": {
foreach (var value in Enum.GetValues(typeof(CustomComboPreset)).Cast<CustomComboPreset>()) {
if (this.Configuration.ComboPresets.HasFlag(value))
Framework.Gui.Chat.Print(value.ToString());
}
}
break;
default: Framework.Gui.Chat.Print("Unknown");
break;
}
this.Configuration.Save(this.StartInfo.ConfigurationPath);
}
private void OnBotJoinCommand(string command, string arguments) { private void OnBotJoinCommand(string command, string arguments) {
if (this.BotManager != null && this.BotManager.IsConnected) if (this.BotManager != null && this.BotManager.IsConnected)
Process.Start( Process.Start(

View file

@ -64,4 +64,7 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Configuration\" />
</ItemGroup>
</Project> </Project>

View file

@ -3,15 +3,14 @@ using Dalamud.DiscordBot;
namespace Dalamud { namespace Dalamud {
[Serializable] [Serializable]
public sealed class DalamudStartInfo { public sealed class DalamudStartInfo
{
public string WorkingDirectory; public string WorkingDirectory;
public string ConfigurationPath;
public string PluginDirectory; public string PluginDirectory;
public string DefaultPluginDirectory; public string DefaultPluginDirectory;
public ClientLanguage Language; public ClientLanguage Language;
public DiscordFeatureConfiguration DiscordFeatureConfig { get; set; }
public bool OptOutMbCollection { get; set; } = false;
} }
public enum ClientLanguage public enum ClientLanguage

View file

@ -5,7 +5,6 @@ using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game.Chat; using Dalamud.Game.Chat;
using Dalamud.Settings;
using Serilog; using Serilog;
namespace Dalamud.Game { namespace Dalamud.Game {
@ -81,8 +80,8 @@ namespace Dalamud.Game {
var originalMessage = string.Copy(message); var originalMessage = string.Copy(message);
if (PersistentSettings.Instance.BadWords != null && if (this.dalamud.Configuration.BadWords != null &&
PersistentSettings.Instance.BadWords.Any(x => originalMessage.Contains(x))) { this.dalamud.Configuration.BadWords.Any(x => originalMessage.Contains(x))) {
// This seems to be in the user block list - let's not show it // This seems to be in the user block list - let's not show it
Log.Debug("Blocklist triggered"); Log.Debug("Blocklist triggered");
isHandled = true; isHandled = true;

View file

@ -37,8 +37,8 @@ namespace Dalamud.Game.ClientState.Actors {
var actorStruct = Marshal.PtrToStructure<Structs.Actor>(offset); var actorStruct = Marshal.PtrToStructure<Structs.Actor>(offset);
Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"), //Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
actorStruct.ObjectKind.ToString()); // actorStruct.ObjectKind.ToString());
switch (actorStruct.ObjectKind) { switch (actorStruct.ObjectKind) {
case ObjectKind.Player: return new PlayerCharacter(actorStruct); case ObjectKind.Player: return new PlayerCharacter(actorStruct);

View file

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using Dalamud.Game.ClientState.Actors; using Dalamud.Game.ClientState.Actors;
using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Game.Internal; using Dalamud.Game.Internal;
using Serilog;
namespace Dalamud.Game.ClientState namespace Dalamud.Game.ClientState
{ {
@ -54,6 +55,8 @@ namespace Dalamud.Game.ClientState
Address = new ClientStateAddressResolver(); Address = new ClientStateAddressResolver();
Address.Setup(scanner); Address.Setup(scanner);
Log.Verbose("===== C L I E N T S T A T E =====");
this.ClientLanguage = startInfo.Language; this.ClientLanguage = startInfo.Language;
this.Actors = new ActorTable(Address); this.Actors = new ActorTable(Address);

View file

@ -15,7 +15,7 @@ namespace Dalamud.Game.ClientState
protected override void Setup64Bit(SigScanner sig) { protected override void Setup64Bit(SigScanner sig) {
ActorTable = sig.Module.BaseAddress + 0x1B29B40; ActorTable = sig.Module.BaseAddress + 0x1B29B40;
LocalContentId = sig.Module.BaseAddress + 0x1B58B60; LocalContentId = sig.Module.BaseAddress + 0x1B58B60;
JobGaugeData = sig.Module.BaseAddress + 0x1B2D4B4; JobGaugeData = sig.Module.BaseAddress + 0x1BFD110;
} }
} }
} }

View file

@ -1,11 +1,5 @@
using Dalamud.Game.ClientState.Structs.JobGauge;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using Serilog;
using System.Threading.Tasks;
namespace Dalamud.Game.ClientState { namespace Dalamud.Game.ClientState {
public class JobGauges { public class JobGauges {
@ -13,12 +7,14 @@ namespace Dalamud.Game.ClientState {
public JobGauges(ClientStateAddressResolver addressResolver) { public JobGauges(ClientStateAddressResolver addressResolver) {
Address = addressResolver; Address = addressResolver;
Log.Verbose("JobGaugeData address {JobGaugeData}", Address.ActorTable);
} }
// Should only be called with the gauge types in // Should only be called with the gauge types in
// ClientState.Structs.JobGauge // ClientState.Structs.JobGauge
public T Get<T>() { public T Get<T>() {
return Marshal.PtrToStructure<T>(Address.ActorTable); return Marshal.PtrToStructure<T>(Address.JobGaugeData);
} }
} }
} }

View file

@ -9,5 +9,18 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct ASTGauge { public struct ASTGauge {
[FieldOffset(4)] private CardType Card;
[FieldOffset(5)] private unsafe fixed byte Seals[3];
public CardType DrawnCard() {
return Card;
}
public unsafe bool ContainsSeal(SealType seal) {
if (Seals[0] == (byte)seal) return true;
if (Seals[1] == (byte)seal) return true;
if (Seals[2] == (byte)seal) return true;
return false;
}
} }
} }

View file

@ -9,12 +9,12 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct BLMGauge { public struct BLMGauge {
[FieldOffset(0xc)] public short TimeUntilNextPolyglot; //eno timer (ms) [FieldOffset(0)] public short TimeUntilNextPolyglot; //eno timer (ms)
[FieldOffset(0xe)] public short ElementTimeRemaining; //ui/af timer [FieldOffset(2)] public short ElementTimeRemaining; //ui/af timer
[FieldOffset(0x10)] private byte ElementStance; //ui/af [FieldOffset(4)] private byte ElementStance; //ui/af
[FieldOffset(0x11)] public byte NumUmbralHearts; //number of umbral hearts [FieldOffset(5)] public byte NumUmbralHearts; //number of umbral hearts
[FieldOffset(0x12)] public byte NumPolyglotStacks; //number of polyglot stacks [FieldOffset(6)] public byte NumPolyglotStacks; //number of polyglot stacks
[FieldOffset(0x13)] public bool IsEnoActive; //eno active? [FieldOffset(7)] private byte EnoState; //eno active?
public bool InUmbralIce() { public bool InUmbralIce() {
return ElementStance > 4; return ElementStance > 4;
@ -24,6 +24,10 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
return ElementStance > 0 && ElementStance < 4; return ElementStance > 0 && ElementStance < 4;
} }
public bool IsEnoActive() {
return EnoState > 0;
}
} }

View file

@ -9,5 +9,8 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct BRDGauge { public struct BRDGauge {
[FieldOffset(0)] public short SongTimer;
[FieldOffset(2)] public byte NumSongStacks;
[FieldOffset(4)] public CurrentSong ActiveSong;
} }
} }

View file

@ -9,13 +9,17 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public unsafe struct DNCGauge { public unsafe struct DNCGauge {
[FieldOffset(0xc)] public byte NumFeathers; [FieldOffset(0)] public byte NumFeathers;
[FieldOffset(0xd)] public byte Esprit; [FieldOffset(1)] public byte Esprit;
[FieldOffset(0xe)] public fixed byte StepOrder[4]; [FieldOffset(2)] private fixed byte StepOrder[4];
[FieldOffset(0x12)] public byte NumCompleteSteps; [FieldOffset(6)] public byte NumCompleteSteps;
public bool IsDancing() { public bool IsDancing() {
return StepOrder[0] != 0; return StepOrder[0] != 0;
} }
public ulong NextStep() {
return (ulong)(15999 + StepOrder[NumCompleteSteps] - 1);
}
} }
} }

View file

@ -9,5 +9,8 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct DRGGauge { public struct DRGGauge {
[FieldOffset(0)] public short BOTDTimer;
[FieldOffset(2)] public BOTDState BOTDState;
[FieldOffset(3)] public byte EyeCount;
} }
} }

View file

@ -8,9 +8,13 @@ using System.Threading.Tasks;
namespace Dalamud.Game.ClientState.Structs.JobGauge { namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct DRKGauge { public struct DRKGauge {
[FieldOffset(0xc)] public short Blood; [FieldOffset(0)] public byte Blood;
[FieldOffset(0xe)] public short DarksideTimeRemaining; [FieldOffset(2)] public short DarksideTimeRemaining;
[FieldOffset(0x10)] public bool HasDarkArts; [FieldOffset(4)] private byte DarkArtsState;
[FieldOffset(0x12)] public short ShadowTimeRemaining; [FieldOffset(6)] public short ShadowTimeRemaining;
public bool HasDarkArts() {
return DarkArtsState > 0;
}
} }
} }

View file

@ -9,5 +9,8 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct GNBGauge { public struct GNBGauge {
[FieldOffset(0)] public byte NumAmmo;
[FieldOffset(2)] public short MaxTimerDuration;
[FieldOffset(4)] public byte AmmoComboStepNumber;
} }
} }

View file

@ -0,0 +1,67 @@
using System;
namespace Dalamud.Game.ClientState.Structs.JobGauge {
public enum SealType : byte {
NONE = 0,
SUN,
MOON,
CELESTIAL
}
public enum CardType : byte {
NONE = 0,
BALANCE,
BOLE,
ARROW,
SPEAR,
EWER,
SPIRE,
LORD = 0x70,
LADY = 0x80
}
public enum SummonPet : byte {
NONE = 0,
IFRIT = 3,
TITAN,
GARUDA
}
public enum PetGlam : byte {
NONE = 0,
EMERALD,
TOPAZ,
RUBY
}
[Flags]
public enum Sen : byte {
NONE = 0,
SETSU = 1 << 0,
GETSU = 1 << 1,
KA = 1 << 2
}
public enum BOTDState : byte {
NONE = 0,
BOTD,
LOTD
}
public enum CurrentSong : byte {
MAGE = 5,
ARMY = 0xA,
WANDERER = 0xF
}
public enum DismissedFairy : byte {
EOS = 6,
SELENE
}
public enum Mudras : byte {
TEN = 1,
CHI = 2,
JIN = 3
}
}

View file

@ -10,12 +10,12 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct MCHGauge{ public struct MCHGauge{
[FieldOffset(0xc)] public short OverheatTimeRemaining; [FieldOffset(0)] public short OverheatTimeRemaining;
[FieldOffset(0xe)] public short RobotTimeRemaining; [FieldOffset(2)] public short RobotTimeRemaining;
[FieldOffset(0x10)] public byte Heat; [FieldOffset(4)] public byte Heat;
[FieldOffset(0x11)] public byte Battery; [FieldOffset(5)] public byte Battery;
[FieldOffset(0x12)] public byte LastRobotBatteryPower; [FieldOffset(6)] public byte LastRobotBatteryPower;
[FieldOffset(0x13)] private byte TimerActive; [FieldOffset(7)] private byte TimerActive;
public bool IsOverheated() { public bool IsOverheated() {
return (TimerActive & 1) != 0; return (TimerActive & 1) != 0;

View file

@ -9,5 +9,13 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct MNKGauge { public struct MNKGauge {
[FieldOffset(0)] public byte GLTimer;
[FieldOffset(2)] public byte NumGLStacks;
[FieldOffset(3)] public byte NumChakra;
[FieldOffset(4)] private byte GLTimerFreezeState;
public bool IsGLTimerFroze() {
return GLTimerFreezeState > 0;
}
} }
} }

View file

@ -9,5 +9,9 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct NINGauge { public struct NINGauge {
[FieldOffset(0)] public int HutonTimeLeft;
[FieldOffset(4)] public byte TCJMudrasUsed; //some sort of mask
[FieldOffset(5)] public byte Ninki;
[FieldOffset(6)] public byte NumHutonManualCasts; //wtf
} }
} }

View file

@ -9,5 +9,6 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct PLDGauge { public struct PLDGauge {
[FieldOffset(0)] public byte GaugeAmount;
} }
} }

View file

@ -9,5 +9,7 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct RDMGauge { public struct RDMGauge {
[FieldOffset(0)] public byte WhiteGauge;
[FieldOffset(1)] public byte BlackGauge;
} }
} }

View file

@ -10,7 +10,7 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct SAMGauge { public struct SAMGauge {
[FieldOffset(0xf)] public byte Kenki; [FieldOffset(3)] public byte Kenki;
[FieldOffset(0x10)] public byte Sen; [FieldOffset(4)] public Sen Sen;
} }
} }

View file

@ -9,5 +9,9 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct SCHGauge { public struct SCHGauge {
[FieldOffset(2)] public byte NumAetherflowStacks;
[FieldOffset(3)] public byte FairyGaugeAmount;
[FieldOffset(4)] public short SeraphTimer;
[FieldOffset(6)] public DismissedFairy DismissedFairy;
} }
} }

View file

@ -11,8 +11,21 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
public struct SMNGauge { public struct SMNGauge {
//Unfinished //Unfinished
[FieldOffset(0xc)] public short TimerRemaining; [FieldOffset(0)] public short TimerRemaining;
[FieldOffset(0xf)] public bool IsDemiActive; [FieldOffset(2)] public SummonPet ReturnSummon;
[FieldOffset(0x10)] public byte NumStacks; [FieldOffset(3)] public PetGlam ReturnSummonGlam;
[FieldOffset(4)] public byte NumStacks;
public bool IsPhoenixReady() {
return (NumStacks & 0x10) > 0;
}
public bool IsBahamutReady() {
return (NumStacks & 8) > 0;
}
public bool HasAetherflowStacks() {
return (NumStacks & 3) > 0;
}
} }
} }

View file

@ -9,5 +9,6 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct WARGauge { public struct WARGauge {
[FieldOffset(0)] public byte BeastGaugeAmount;
} }
} }

View file

@ -9,5 +9,8 @@ namespace Dalamud.Game.ClientState.Structs.JobGauge {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct WHMGauge { public struct WHMGauge {
[FieldOffset(2)] public short LilyTimer; //Counts to 30k = 30s
[FieldOffset(4)] public byte NumLilies;
[FieldOffset(5)] public byte NumBloodLily;
} }
} }

View file

@ -1,6 +1,5 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Settings;
using Dalamud.Game.Internal.Gui; using Dalamud.Game.Internal.Gui;
using Dalamud.Game.Internal.Libc; using Dalamud.Game.Internal.Libc;
using Dalamud.Game.Internal.Network; using Dalamud.Game.Internal.Network;
@ -56,7 +55,7 @@ namespace Dalamud.Game.Internal {
Network = new GameNetwork(dalamud, scanner); Network = new GameNetwork(dalamud, scanner);
Resource = new ResourceManager(dalamud, scanner); //Resource = new ResourceManager(dalamud, scanner);
} }
private void HookVTable() { private void HookVTable() {

View file

@ -1,38 +0,0 @@
using System;
using System.Diagnostics;
using Dalamud.Hooking;
namespace Dalamud.Game.Internal.Gui {
public class IconReplaceChecker {
private IconReplaceCheckerAddressResolver address;
private Hook<OnCheckDetour> checkerHook;
public IconReplaceChecker(ProcessModule module, SigScanner scanner) {
this.address = new IconReplaceCheckerAddressResolver();
this.address.Setup(scanner);
hookChecker();
}
private void hookChecker() {
this.checkerHook = new Hook<OnCheckDetour>(this.address.BaseAddress, (Delegate)new OnCheckDetour(this.HandleChecker), (object)this);
}
public void Enable() {
this.checkerHook.Enable();
}
public void Dispose() {
this.checkerHook.Dispose();
}
// I hate this function. This is the dumbest function to exist in the game. Just return 1.
// Determines which abilities are allowed to have their icons updated.
private ulong HandleChecker(int actionID) {
return 1;
}
private delegate ulong OnCheckDetour(int actionID);
public delegate ulong OnCheckDelegate(int actionID);
}
}

View file

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dalamud.Game.Internal.Gui {
class IconReplaceCheckerAddressResolver : BaseAddressResolver {
public IntPtr BaseAddress { get; private set; }
protected bool IsResolved { get; set; }
protected override void Setup64Bit(SigScanner sig)
{
this.BaseAddress = sig.ScanText("81 f9 d4 08 00 00 7f 33 0f 84 fa 01 00 00 83 c1 eb 81 f9 a3 00 00 00");
}
}
}

View file

@ -6,11 +6,18 @@ using Serilog;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using XIVLauncher.Dalamud;
namespace Dalamud.Game.Internal.Gui { namespace Dalamud.Game.Internal.Gui {
public class IconReplacer { public class IconReplacer {
private IconReplacerAddressResolver address; public delegate ulong OnGetIconDelegate(byte param1, uint param2);
private Hook<OnIconDetour> iconHook; public delegate ulong OnCheckIsIconReplaceableDelegate(int actionID);
private Hook<OnGetIconDelegate> iconHook;
private Hook<OnCheckIsIconReplaceableDelegate> checkerHook;
private IconReplacerAddressResolver Address;
private IntPtr comboTimer; private IntPtr comboTimer;
private IntPtr lastComboMove; private IntPtr lastComboMove;
private IntPtr activeBuffArray = IntPtr.Zero; private IntPtr activeBuffArray = IntPtr.Zero;
@ -19,28 +26,38 @@ namespace Dalamud.Game.Internal.Gui {
private Dalamud dalamud; private Dalamud dalamud;
private PlayerCharacter localCharacter = null; private PlayerCharacter localCharacter = null;
public unsafe IconReplacer(Dalamud dalamud, ProcessModule module, SigScanner scanner) { public unsafe IconReplacer(Dalamud dalamud, SigScanner scanner) {
this.dalamud = dalamud; this.dalamud = dalamud;
this.address = new IconReplacerAddressResolver(); this.Address = new IconReplacerAddressResolver();
this.address.Setup(scanner); this.Address.Setup(scanner);
this.byteBase = scanner.Module.BaseAddress; this.byteBase = scanner.Module.BaseAddress;
this.jobInfo = byteBase + 0x1b2d4b4; this.comboTimer = byteBase + 0x1BB5B50;
this.comboTimer = byteBase + 0x1AE1B10; this.lastComboMove = byteBase + 0x1BB5B54;
this.lastComboMove = byteBase + 0x1AE1B14;
this.iconHook = new Hook<OnIconDetour>(this.address.BaseAddress, (Delegate)new OnIconDetour(this.HandleIconUpdate), (object)this); Log.Verbose("===== H O T B A R S =====");
Log.Verbose("IsIconReplaceable address {IsIconReplaceable}", Address.IsIconReplaceable);
Log.Verbose("GetIcon address {GetIcon}", Address.GetIcon);
this.iconHook = new Hook<OnGetIconDelegate>(this.Address.GetIcon, new OnGetIconDelegate(GetIconDetour), this);
this.checkerHook = new Hook<OnCheckIsIconReplaceableDelegate>(this.Address.IsIconReplaceable, new OnCheckIsIconReplaceableDelegate(CheckIsIconReplaceableDetour), this);
} }
public void Enable() { public void Enable() {
this.iconHook.Enable(); this.iconHook.Enable();
this.checkerHook.Enable();
} }
public void Dispose() { public void Dispose() {
this.iconHook.Dispose(); this.iconHook.Dispose();
this.checkerHook.Dispose();
} }
// I hate this function. This is the dumbest function to exist in the game. Just return 1.
// Determines which abilities are allowed to have their icons updated.
private ulong CheckIsIconReplaceableDetour(int actionID) {
return 1;
}
/// <summary> /// <summary>
/// Replace an ability with another ability /// Replace an ability with another ability
@ -51,16 +68,16 @@ namespace Dalamud.Game.Internal.Gui {
/// For example, Souleater combo on DRK happens by dragging Souleater /// For example, Souleater combo on DRK happens by dragging Souleater
/// onto your bar and mashing it. /// onto your bar and mashing it.
/// </summary> /// </summary>
private unsafe ulong HandleIconUpdate(byte self, uint actionID) { private unsafe ulong GetIconDetour(byte self, uint actionID) {
// TODO: BRD, RDM, level checking for everything. // TODO: More jobs, level checking for everything.
// Check if player is loaded in by trying to get their buffs. // Check if player is loaded in by trying to get their buffs.
// If not, skip everything until we are (game will crash cause I'm lazy). // If not, skip everything until we are (game will crash cause I'm lazy).
if (activeBuffArray == IntPtr.Zero) { if (activeBuffArray == IntPtr.Zero) {
try { try {
activeBuffArray = FindBuffAddress(); activeBuffArray = FindBuffAddress();
localCharacter = dalamud.ClientState.LocalPlayer; Log.Verbose("ActiveBuffArray address: {ActiveBuffArray}", activeBuffArray);
} }
catch (Exception e) { catch (Exception e) {
activeBuffArray = IntPtr.Zero; activeBuffArray = IntPtr.Zero;
@ -68,349 +85,489 @@ namespace Dalamud.Game.Internal.Gui {
} }
} }
// TODO: this is currently broken
// As it stands, don't rely on localCharacter.level for anything.
/*
if (localCharacter == null) {
try {
localCharacter = dalamud.ClientState.LocalPlayer;
}
catch(Exception e) {
localCharacter = null;
return this.iconHook.Original(self, actionID);
}
}
*/
// Don't clutter the spaghetti any worse than it already is. // Don't clutter the spaghetti any worse than it already is.
int lastMove = Marshal.ReadInt32(lastComboMove); int lastMove = Marshal.ReadInt32(lastComboMove);
float comboTime = (float)Marshal.ReadInt32(comboTimer); float comboTime = (float)Marshal.ReadInt32(comboTimer);
byte level = localCharacter.Level; //localCharacter = dalamud.ClientState.LocalPlayer;
//byte level = localCharacter.Level;
byte level = 80;
// DRAGOON // DRAGOON
// TODO: Jump/High Jump into Mirage Dive // TODO: Jump/High Jump into Mirage Dive
// Replace Coerthan Torment with Coerthan Torment combo chain // Replace Coerthan Torment with Coerthan Torment combo chain
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DragoonCoerthanTormentCombo)) {
if (actionID == 16477) { if (actionID == 16477) {
if (comboTime > 0) { if (comboTime > 0) {
if (Marshal.ReadInt32(lastComboMove) == 86) return 7397; if (lastMove == 86 && level >= 62) return 7397;
if (Marshal.ReadInt32(lastComboMove) == 7397) return 16477; if (lastMove == 7397 && level >= 72) return 16477;
} }
return 86; return 86;
} }
}
// Replace Chaos Thrust with the Chaos Thrust combo chain // Replace Chaos Thrust with the Chaos Thrust combo chain
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DragoonChaosThrustCombo)) {
if (actionID == 88) { if (actionID == 88) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 75 || lastMove == 16479) return 87; if ((lastMove == 75 || lastMove == 16479) && level >= 18) return 87;
if (lastMove == 87) return 88; if (lastMove == 87 && level >= 50) return 88;
}
if (SearchBuffArray(802) && level >= 56) return 3554;
if (SearchBuffArray(803) && level >= 58) return 3556;
if (SearchBuffArray(1863) && level >= 76) return 16479;
}
if (activeBuffArray != IntPtr.Zero) {
if (SearchBuffArray(802)) return 3554;
if (SearchBuffArray(803)) return 3556;
if (SearchBuffArray(1863)) return 16479;
}
return 75; return 75;
} }
}
// Replace Full Thrust with the Full Thrust combo chain // Replace Full Thrust with the Full Thrust combo chain
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DragoonFullThrustCombo)) {
if (actionID == 84) { if (actionID == 84) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 75 || lastMove == 16479) return 78; if ((lastMove == 75 || lastMove == 16479) && level >= 4) return 78;
if (lastMove == 78) return 84; if (lastMove == 78 && level >= 26) return 84;
}
if (SearchBuffArray(802) && level >= 56) return 3554;
if (SearchBuffArray(803) && level >= 58) return 3556;
if (SearchBuffArray(1863) && level >= 76) return 16479;
}
if (activeBuffArray != IntPtr.Zero) {
if (SearchBuffArray(802)) return 3554;
if (SearchBuffArray(803)) return 3556;
if (SearchBuffArray(1863)) return 16479;
}
return 75; return 75;
} }
}
// DARK KNIGHT // DARK KNIGHT
// Replace Souleater with Souleater combo chain // Replace Souleater with Souleater combo chain
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DarkSouleaterCombo)) {
if (actionID == 3632) { if (actionID == 3632) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 3617) return 3623; if (lastMove == 3617 && level >= 2) return 3623;
if (lastMove == 3623) return 3632; if (lastMove == 3623 && level >= 26) return 3632;
} }
return 3617; return 3617;
} }
}
// Replace Stalwart Soul with Stalwart Soul combo chain // Replace Stalwart Soul with Stalwart Soul combo chain
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DarkStalwartSoulCombo)) {
if (actionID == 16468) { if (actionID == 16468) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 3621) return 16468; if (lastMove == 3621 && level >= 72) return 16468;
} }
return 3621; return 3621;
} }
}
// PALADIN // PALADIN
// Replace Goring Blade with Goring Blade combo // Replace Goring Blade with Goring Blade combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.PaladinGoringBladeCombo)) {
if (actionID == 3538) { if (actionID == 3538) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 9) return 15; if (lastMove == 9 && level >= 4) return 15;
if (lastMove == 15) return 3538; if (lastMove == 15 && level >= 54) return 3538;
} }
return 9; return 9;
} }
}
// Replace Royal Authority with Royal Authority combo // Replace Royal Authority with Royal Authority combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.PaladinRoyalAuthorityCombo)) {
if (actionID == 3539) { if (actionID == 3539) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 9) return 15; if (lastMove == 9 && level >= 4) return 15;
if (lastMove == 15) return 3539; if (lastMove == 15) {
if (level >= 60) return 3539;
if (level >= 26) return 21;
} }
}
return 9; return 9;
} }
}
// Replace Prominence with Prominence combo // Replace Prominence with Prominence combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.PaladinProminenceCombo)) {
if (actionID == 16457) { if (actionID == 16457) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 7381) return 16457; if (lastMove == 7381 && level >= 40) return 16457;
} }
return 7381; return 7381;
} }
}
// WARRIOR // WARRIOR
// Replace Storm's Path with Storm's Path combo // Replace Storm's Path with Storm's Path combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.WarriorStormsPathCombo)) {
if (actionID == 42) { if (actionID == 42) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 31) return 37; if (lastMove == 31 && level >= 4) return 37;
if (lastMove == 37) return 42; if (lastMove == 37 && level >= 26) return 42;
} }
return 31; return 31;
} }
}
// Replace Storm's Eye with Storm's Eye combo // Replace Storm's Eye with Storm's Eye combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.WarriorStormsEyeCombo)) {
if (actionID == 45) { if (actionID == 45) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 31) return 37; if (lastMove == 31 && level >= 4) return 37;
if (lastMove == 37) return 45; if (lastMove == 37 && level >= 50) return 45;
} }
return 31; return 31;
} }
}
// Replace Mythril Tempest with Mythril Tempest combo // Replace Mythril Tempest with Mythril Tempest combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.WarriorMythrilTempestCombo)) {
if (actionID == 16462) { if (actionID == 16462) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 41) return 16462; if (lastMove == 41 && level >= 40) return 16462;
} }
return 41; return 41;
} }
}
// SAMURAI // SAMURAI
// Replace Yukikaze with Yukikaze combo // Replace Yukikaze with Yukikaze combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SamuraiYukikazeCombo)) {
if (actionID == 7480) { if (actionID == 7480) {
if (activeBuffArray != IntPtr.Zero) {
if (SearchBuffArray(1233)) return 7480; if (SearchBuffArray(1233)) return 7480;
}
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 7477) return 7480; if (lastMove == 7477 && level >= 50) return 7480;
} }
return 7477; return 7477;
} }
}
// Replace Gekko with Gekko combo // Replace Gekko with Gekko combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SamuraiGekkoCombo)) {
if (actionID == 7481) { if (actionID == 7481) {
if (activeBuffArray != IntPtr.Zero) {
if (SearchBuffArray(1233)) return 7481; if (SearchBuffArray(1233)) return 7481;
}
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 7477) return 7478; if (lastMove == 7477 && level >= 4) return 7478;
if (lastMove == 7478) return 7481; if (lastMove == 7478 && level >= 30) return 7481;
} }
return 7477; return 7477;
} }
}
// Replace Kasha with Kasha combo // Replace Kasha with Kasha combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SamuraiKashaCombo)) {
if (actionID == 7482) { if (actionID == 7482) {
if (activeBuffArray != null) {
if (SearchBuffArray(1233)) return 7482; if (SearchBuffArray(1233)) return 7482;
}
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 7477) return 7479; if (lastMove == 7477 && level >= 18) return 7479;
if (lastMove == 7479) return 7482; if (lastMove == 7479 && level >= 40) return 7482;
} }
return 7477; return 7477;
} }
}
// Replace Mangetsu with Mangetsu combo // Replace Mangetsu with Mangetsu combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SamuraiMangetsuCombo)) {
if (actionID == 7484) { if (actionID == 7484) {
if (activeBuffArray != null) {
if (SearchBuffArray(1233)) return 7484; if (SearchBuffArray(1233)) return 7484;
}
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 7483) return 7484; if (lastMove == 7483 && level >= 35) return 7484;
} }
return 7483; return 7483;
} }
}
// Replace Yukikaze with Yukikaze combo // Replace Oka with Oka combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SamuraiOkaCombo)) {
if (actionID == 7485) { if (actionID == 7485) {
if (activeBuffArray != null) {
if (SearchBuffArray(1233)) return 7485; if (SearchBuffArray(1233)) return 7485;
}
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 7483) return 7485; if (lastMove == 7483 && level >= 45) return 7485;
} }
return 7483; return 7483;
} }
}
// NINJA // NINJA
// Replace Shadow Fang with Shadow Fang combo
if (actionID == 2257) {
if (comboTime > 0) {
if (lastMove == 2240) return 2257;
}
return 2240;
}
// Replace Armor Crush with Armor Crush combo // Replace Armor Crush with Armor Crush combo
if (actionID == 2257) { if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.NinjaArmorCrushCombo)) {
if (actionID == 3563) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 2240) return 2242; if (lastMove == 2240 && level >= 4) return 2242;
if (lastMove == 2242) return 3563; if (lastMove == 2242 && level >= 54) return 3563;
} }
return 2240; return 2240;
} }
}
// Replace Aeolian Edge with Aeolian Edge combo // Replace Aeolian Edge with Aeolian Edge combo
if (actionID == 2257) { if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.NinjaAeolianEdgeCombo)) {
if (actionID == 2255) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 2240) return 2242; if (lastMove == 2240 && level >= 4) return 2242;
if (lastMove == 2242) return 2255; if (lastMove == 2242 && level >= 26) return 2255;
} }
return 2240; return 2240;
} }
}
// Replace Hakke Mujinsatsu with Hakke Mujinsatsu combo // Replace Hakke Mujinsatsu with Hakke Mujinsatsu combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.NinjaHakkeMujinsatsuCombo)) {
if (actionID == 16488) { if (actionID == 16488) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 2254) return 16488; if (lastMove == 2254 && level >= 52) return 16488;
} }
return 2254; return 2254;
} }
}
// GUNBREAKER // GUNBREAKER
// Replace Solid Barrel with Solid Barrel combo // Replace Solid Barrel with Solid Barrel combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.GunbreakerSolidBarrelCombo)) {
if (actionID == 16145) { if (actionID == 16145) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 16137) return 16139; if (lastMove == 16137 && level >= 4) return 16139;
if (lastMove == 16139) return 16145; if (lastMove == 16139 && level >= 26) return 16145;
} }
return 16137; return 16137;
} }
}
// Replace Gnashing Fang with Gnashing Fang combo // Replace Gnashing Fang with Gnashing Fang combo
// TODO: Potentially add Contuation moves as well? // TODO: Potentially add Contuation moves as well?
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.GunbreakerGnashingFangCombo)) {
if (actionID == 16146) { if (actionID == 16146) {
byte ammoComboState = Marshal.ReadByte(jobInfo, 0x10); byte ammoComboState = this.dalamud.ClientState.JobGauges.Get<GNBGauge>().AmmoComboStepNumber;
if (ammoComboState == 1) return 16147; if (ammoComboState == 1) return 16147;
if (ammoComboState == 2) return 16150; if (ammoComboState == 2) return 16150;
return 16146; return 16146;
} }
}
// Replace Demon Slaughter with Demon Slaughter combo // Replace Demon Slaughter with Demon Slaughter combo
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.GunbreakerDemonSlaughterCombo)) {
if (actionID == 16149) { if (actionID == 16149) {
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 16141) return 16149; if (lastMove == 16141 && level >= 40) return 16149;
} }
return 16141; return 16141;
} }
}
// MACHINIST // MACHINIST
// Replace Heated Clean Shot with Heated Clean Shot combo // Replace Heated Clean Shot with Heated Clean Shot combo
// Or with Heat Blast when overheated. // Or with Heat Blast when overheated.
// For some reason the shots use their unheated IDs as combo moves // For some reason the shots use their unheated IDs as combo moves
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MachinistHeatedClanShotFeature)) {
if (actionID == 7413) { if (actionID == 7413) {
if (this.dalamud.ClientState.JobGauges.Get<MCHGauge>().IsOverheated() && level >= 35) return 7410; MCHGauge gauge = this.dalamud.ClientState.JobGauges.Get<MCHGauge>();
// End overheat slightly early to prevent eager button mashing clipping your gcd with a fake 6th HB.
if (gauge.IsOverheated() && level >= 35 && gauge.OverheatTimeRemaining > 30) return 7410;
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 2866) return 7412; if (lastMove == 2866) {
if (lastMove == 2868) return 7413; if (level >= 60) return 7412;
if (level >= 2) return 2868;
}
if (lastMove == 2868) {
if (level >= 64) return 7413;
if (level >= 26) return 2873;
}
} }
return 7411; return 7411;
} }
}
// Replace Spread Shot with Auto Crossbow when overheated. // Replace Spread Shot with Auto Crossbow when overheated.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MachinistSpreadShotFeature)) {
if (actionID == 2870) { if (actionID == 2870) {
if (this.dalamud.ClientState.JobGauges.Get<MCHGauge>().IsOverheated() && level >= 52) return 16497; if (this.dalamud.ClientState.JobGauges.Get<MCHGauge>().IsOverheated() && level >= 52) return 16497;
return 2870; return 2870;
} }
}
// BLACK MAGE // BLACK MAGE
// Enochian changes to B4 or F4 depending on stance. // Enochian changes to B4 or F4 depending on stance.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.BlackEnochianFeature)) {
if (actionID == 3575) { if (actionID == 3575) {
BLMGauge jobInfo = this.dalamud.ClientState.JobGauges.Get<BLMGauge>(); BLMGauge jobInfo = this.dalamud.ClientState.JobGauges.Get<BLMGauge>();
if (jobInfo.IsEnoActive) { if (jobInfo.IsEnoActive()) {
if (jobInfo.InUmbralIce()) return 3576; if (jobInfo.InUmbralIce() && level >= 58) return 3576;
return 3577; if (level >= 60) return 3577;
} }
return 3575; return 3575;
} }
}
// Umbral Soul and Transpose // Umbral Soul and Transpose
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.BlackManaFeature)) {
if (actionID == 149) { if (actionID == 149) {
if (this.dalamud.ClientState.JobGauges.Get<BLMGauge>().InUmbralIce() && level >= 76) return 16506; BLMGauge gauge = this.dalamud.ClientState.JobGauges.Get<BLMGauge>();
if (gauge.InUmbralIce() && gauge.IsEnoActive() && level >= 76) return 16506;
return 149; return 149;
} }
}
// ASTROLOGIAN // ASTROLOGIAN
// Make cards on the same button as draw // Make cards on the same button as play
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.AstrologianCardsOnDrawFeature)) {
if (actionID == 17055) { if (actionID == 17055) {
byte x = Marshal.ReadByte(jobInfo, 0x10); ASTGauge gauge = this.dalamud.ClientState.JobGauges.Get<ASTGauge>();
switch (x) { switch (gauge.DrawnCard()) {
case 1: case CardType.BALANCE:
return 4401; return 4401;
case 2: case CardType.BOLE:
return 4404; return 4404;
case 3: case CardType.ARROW:
return 4402; return 4402;
case 4: case CardType.SPEAR:
return 4403; return 4403;
case 5: case CardType.EWER:
return 4405; return 4405;
case 6: case CardType.SPIRE:
return 4406; return 4406;
case 0x70: /*
case CardType.LORD:
return 7444; return 7444;
case 0x80: case CardType.LADY:
return 7445; return 7445;
*/
default: default:
return 3590; return 3590;
} }
} }
}
// SUMMONER // SUMMONER
// DWT changes. // DWT changes.
// Now contains DWT, Deathflare, Summon Bahamut, Enkindle Bahamut, FBT, and Enkindle Phoenix. // Now contains DWT, Deathflare, Summon Bahamut, Enkindle Bahamut, FBT, and Enkindle Phoenix.
// What a monster of a button. // What a monster of a button.
/*
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerDwtCombo)) {
if (actionID == 3581) { if (actionID == 3581) {
byte stackState = Marshal.ReadByte(jobInfo, 0x10); SMNGauge gauge = this.dalamud.ClientState.JobGauges.Get<SMNGauge>();
if (Marshal.ReadInt16(jobInfo, 0xc) > 0) { if (gauge.TimerRemaining > 0) {
if (Marshal.ReadInt16(jobInfo, 0xe) > 0) { if (gauge.ReturnSummon > 0) {
if (stackState > 0) return 16516; if (gauge.IsPhoenixReady()) return 16516;
return 7429; return 7429;
} }
return 3582; if (level >= 60) return 3582;
} }
else { else {
if (stackState == 0) return 3581; if (gauge.IsBahamutReady()) return 7427;
if (stackState == 8) return 7427; if (gauge.IsPhoenixReady()) return 16513;
if (stackState == 0x10) return 16513;
return 3581; return 3581;
} }
} }
}
*/
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerDemiCombo)) {
// Replace Deathflare with demi enkindles
if (actionID == 3582) {
SMNGauge gauge = this.dalamud.ClientState.JobGauges.Get<SMNGauge>();
if (gauge.IsPhoenixReady()) return 16516;
if (gauge.TimerRemaining > 0 && gauge.ReturnSummon != SummonPet.NONE) return 7429;
return 3582;
}
//Replace DWT with demi summons
if (actionID == 3581) {
SMNGauge gauge = this.dalamud.ClientState.JobGauges.Get<SMNGauge>();
if (gauge.IsBahamutReady()) return 7427;
if (gauge.IsPhoenixReady() ||
(gauge.TimerRemaining > 0 && gauge.ReturnSummon != SummonPet.NONE)) return 16513;
return 3581;
}
}
// Ruin 1 now upgrades to Brand of Purgatory in addition to Ruin 3 and Fountain of Fire
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerBoPCombo)) {
if (actionID == 163) {
SMNGauge gauge = this.dalamud.ClientState.JobGauges.Get<SMNGauge>();
if (gauge.TimerRemaining > 0) {
if (gauge.IsPhoenixReady()) {
if (SearchBuffArray(1867)) {
return 16515;
}
return 16514;
}
}
if (level >= 54) return 3579;
return 163;
}
}
// Change Energy Drain into Fester
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerEDFesterCombo)) {
if (actionID == 16508) {
if (this.dalamud.ClientState.JobGauges.Get<SMNGauge>().HasAetherflowStacks())
return 181;
return 16508;
}
}
//Change Energy Siphon into Painflare
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.SummonerESPainflareCombo)) {
if (actionID == 16510) {
if (this.dalamud.ClientState.JobGauges.Get<SMNGauge>().HasAetherflowStacks())
if (level >= 52) return 3578;
return 16510;
}
}
// SCHOLAR // SCHOLAR
// Change Fey Blessing into Consolation when Seraph is out. // Change Fey Blessing into Consolation when Seraph is out.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.ScholarSeraphConsolationFeature)) {
if (actionID == 16543) { if (actionID == 16543) {
if (Marshal.ReadInt16(jobInfo, 0x10) > 0) return 16546; if (this.dalamud.ClientState.JobGauges.Get<SCHGauge>().SeraphTimer > 0) return 16546;
return 16543; return 16543;
} }
}
// Change Energy Drain into Aetherflow when you have no more Aetherflow stacks.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.ScholarEnergyDrainFeature)) {
if (actionID == 167) {
if (this.dalamud.ClientState.JobGauges.Get<SCHGauge>().NumAetherflowStacks == 0) return 166;
return 167;
}
}
// DANCER // DANCER
/*
// Standard Step is one button. // Standard Step is one button.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DancerStandardStepCombo)) {
if (actionID == 15997) { if (actionID == 15997) {
DNCGauge gauge = this.dalamud.ClientState.JobGauges.Get<DNCGauge>(); DNCGauge gauge = this.dalamud.ClientState.JobGauges.Get<DNCGauge>();
if (gauge.IsDancing()) { if (gauge.IsDancing()) {
@ -419,13 +576,15 @@ namespace Dalamud.Game.Internal.Gui {
} }
else { else {
// C# can't implicitly cast from int to ulong. // C# can't implicitly cast from int to ulong.
return (ulong)(15999 + gauge.StepOrder[gauge.NumCompleteSteps] - 1); return gauge.NextStep();
} }
} }
return 15997; return 15997;
} }
}
// Technical Step is one button. // Technical Step is one button.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DancerTechnicalStepCombo)) {
if (actionID == 15998) { if (actionID == 15998) {
DNCGauge gauge = this.dalamud.ClientState.JobGauges.Get<DNCGauge>(); DNCGauge gauge = this.dalamud.ClientState.JobGauges.Get<DNCGauge>();
if (gauge.IsDancing()) { if (gauge.IsDancing()) {
@ -434,78 +593,265 @@ namespace Dalamud.Game.Internal.Gui {
} }
else { else {
// C# can't implicitly cast from int to ulong. // C# can't implicitly cast from int to ulong.
return (ulong)(15999 + gauge.StepOrder[gauge.NumCompleteSteps] - 1); return gauge.NextStep();
} }
} }
return 15998; return 15998;
} }
}
// Fountain changes into Fountain combo, prioritizing procs over combo, // Fountain changes into Fountain combo, prioritizing procs over combo,
// and Fountainfall over Reverse Cascade. // and Fountainfall over Reverse Cascade.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DancerFountainCombo)) {
if (actionID == 15990) { if (actionID == 15990) {
if (activeBuffArray != null) { if (this.dalamud.ClientState.JobGauges.Get<DNCGauge>().IsDancing()) return 15999;
if (SearchBuffArray(1815)) return 15992; if (SearchBuffArray(1815)) return 15992;
if (SearchBuffArray(1814)) return 15991; if (SearchBuffArray(1814)) return 15991;
}
if (comboTime > 0) { if (comboTime > 0) {
if (lastMove == 15989) return 15990; if (lastMove == 15989 && level >= 2) return 15990;
} }
return 15989; return 15989;
} }
}
*/
// AoE GCDs are split into two buttons, because priority matters // AoE GCDs are split into two buttons, because priority matters
// differently in different single-target moments. Thanks yoship. // differently in different single-target moments. Thanks yoship.
// Replaces each GCD with its procced version. // Replaces each GCD with its procced version.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DancerAoeGcdFeature)) {
if (actionID == 15994) { if (actionID == 15994) {
if (activeBuffArray != null) {
if (SearchBuffArray(1817)) return 15996; if (SearchBuffArray(1817)) return 15996;
}
return 15994; return 15994;
} }
if (actionID == 15993) { if (actionID == 15993) {
if (activeBuffArray != null) {
if (SearchBuffArray(1816)) return 15995; if (SearchBuffArray(1816)) return 15995;
}
return 15993; return 15993;
} }
}
// Fan Dance changes into Fan Dance 3 while flourishing. // Fan Dance changes into Fan Dance 3 while flourishing.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.DancerFanDanceCombo)) {
if (actionID == 16007) { if (actionID == 16007) {
if (activeBuffArray != null) {
if (SearchBuffArray(1820)) return 16009; if (SearchBuffArray(1820)) return 16009;
}
return 16007; return 16007;
} }
// Fan Dance 2 changes into Fan Dance 3 while flourishing. // Fan Dance 2 changes into Fan Dance 3 while flourishing.
if (actionID == 16008) { if (actionID == 16008) {
if (activeBuffArray != null) {
if (SearchBuffArray(1820)) return 16009; if (SearchBuffArray(1820)) return 16009;
}
return 16008; return 16008;
} }
}
// WHM
// Replace Solace with Misery when full blood lily
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.WhiteMageSolaceMiseryFeature)) {
if (actionID == 16531) {
if (this.dalamud.ClientState.JobGauges.Get<WHMGauge>().NumBloodLily == 3)
return 16535;
return 16531;
}
}
// Replace Solace with Misery when full blood lily
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.WhiteMageRaptureMiseryFeature)) {
if (actionID == 16534) {
if (this.dalamud.ClientState.JobGauges.Get<WHMGauge>().NumBloodLily == 3)
return 16535;
return 16534;
}
}
// BARD
// Replace Wanderer's Minuet with PP when in WM.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.BardWandererPPFeature)) {
if (actionID == 3559) {
if (this.dalamud.ClientState.JobGauges.Get<BRDGauge>().ActiveSong == CurrentSong.WANDERER) {
return 7404;
}
return 3559;
}
}
// Replace HS/BS with SS/RA when procced.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.BardStraightShotUpgradeFeature)) {
if (actionID == 97) {
if (SearchBuffArray(122)) {
if (level >= 70) return 7409;
return 98;
}
if (level >= 76) return 16495;
return 97;
}
}
// MONK
/*
// Replace Snap Punch with flank positional combo.
// During PB, Snap (with sub-max stacks) > Twin (with no active Twin) > DK
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MonkFlankCombo)) {
if (actionID == 56) {
if (SearchBuffArray(110)) {
MNKGauge gauge = this.dalamud.ClientState.JobGauges.Get<MNKGauge>();
if ((gauge.NumGLStacks < 3 && level < 76) || SearchBuffArray(103)) {
return 56;
}
else if (gauge.NumGLStacks < 4 && level >= 76 && SearchBuffArray(105)) {
return 56;
}
else if (!SearchBuffArray(101)) return 61;
else return 74;
}
else {
if (SearchBuffArray(107) && level >= 50) return 74;
if (SearchBuffArray(108) && level >= 18) return 61;
if (SearchBuffArray(109) && level >= 6) return 56;
return 74;
}
}
}
// Replace Demolish with rear positional combo.
// During PB, Demo (with sub-max stacks) > Bootshine.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MonkRearCombo)) {
if (actionID == 66) {
if (SearchBuffArray(110)) {
MNKGauge gauge = this.dalamud.ClientState.JobGauges.Get<MNKGauge>();
if ((gauge.NumGLStacks < 3 && level < 76) || SearchBuffArray(103)) {
return 66;
}
else if (gauge.NumGLStacks < 4 && level >= 76 && SearchBuffArray(105)) {
return 66;
}
else return 53;
}
else {
if (SearchBuffArray(107)) return 53;
if (SearchBuffArray(108) && level >= 4) return 54;
if (SearchBuffArray(109) && level >= 30) return 66;
return 53;
}
}
}
// Replace Rockbreaker with AoE combo.
// During PB, RB (with sub-max stacks) > Twin Snakes (if not applied) > RB.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.MonkAoECombo)) {
if (actionID == 70) {
if (SearchBuffArray(110)) {
MNKGauge gauge = this.dalamud.ClientState.JobGauges.Get<MNKGauge>();
if ((gauge.NumGLStacks < 3 && level < 76) || SearchBuffArray(103)) {
return 70;
}
else if (gauge.NumGLStacks < 4 && level >= 76 && SearchBuffArray(105)) {
return 70;
}
else if (!SearchBuffArray(101)) return 61;
else return 70;
}
else {
if (SearchBuffArray(107)) return 62;
if (SearchBuffArray(108)) {
if (!SearchBuffArray(101)) return 61;
if (level >= 45) return 16473;
}
if (SearchBuffArray(109) && level >= 30) return 70;
return 62;
}
}
}
*/
// RED MAGE
/*
// Replace Verstone with White Magic spells. Priority order:
// Scorch > Verholy > Verstone = Veraero (with Dualcast active) > opener Veraero > Jolt
// Impact is not the first available spell to allow for precast openers.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.RedMageWhiteMagicFeature)) {
if (actionID == 7511) {
if ((lastMove == 7526 || lastMove == 7525) && level >= 80) return 16530;
if (lastMove == 7529 && level >= 70) return 7526;
if ((SearchBuffArray(1249) || SearchBuffArray(167)) && level >= 10) return 7507;
if (SearchBuffArray(1235) && level >= 30) return 7511;
RDMGauge gauge = this.dalamud.ClientState.JobGauges.Get<RDMGauge>();
if ((gauge.BlackGauge == 0 && gauge.WhiteGauge == 0) && level >= 10) return 7507;
if (level >= 62) return 7524;
return 7503;
}
}
// Replace Verfire with Black Magic spells. Priority order:
// Scorch > Verflare> Verfire = Verthunder (with Dualcast active) > opener Verthunder > Jolt
// Impact is not the first available spell to allow for precast openers.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.RedMageBlackMagicFeature)) {
if (actionID == 7510) {
if ((lastMove == 7526 || lastMove == 7525) && level >= 80) return 16530;
if (lastMove == 7529 && level >= 68) return 7525;
if ((SearchBuffArray(1249) || SearchBuffArray(167)) && level >= 4) return 7505;
if (SearchBuffArray(1234) && level >= 26) return 7510;
RDMGauge gauge = this.dalamud.ClientState.JobGauges.Get<RDMGauge>();
if ((gauge.BlackGauge == 0 && gauge.WhiteGauge == 0) && level >= 4) return 7505;
if (level >= 62) return 7524;
return 7503;
}
}
*/
// Replace Veraero/thunder 2 with Impact when Dualcast is active
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.RedMageAoECombo)) {
if (actionID == 16525) {
if (level >= 66 && (SearchBuffArray(1249) || SearchBuffArray(167))) return 16526;
return 16525;
}
if (actionID == 16524) {
if (level >= 66 && (SearchBuffArray(1249) || SearchBuffArray(167))) return 16526;
return 16524;
}
}
// Replace Redoublement with Redoublement combo, Enchanted if possible.
if (this.dalamud.Configuration.ComboPresets.HasFlag(CustomComboPreset.RedMageMeleeCombo)) {
if (actionID == 7516) {
RDMGauge gauge = this.dalamud.ClientState.JobGauges.Get<RDMGauge>();
if ((lastMove == 7504 || lastMove == 7527) && level >= 35) {
if (gauge.BlackGauge >= 25 && gauge.WhiteGauge >= 25) return 7528;
return 7512;
}
if (lastMove == 7512 && level >= 50) {
if (gauge.BlackGauge >= 25 && gauge.WhiteGauge >= 25) return 7529;
return 7516;
}
if (gauge.BlackGauge >= 30 && gauge.WhiteGauge >= 30) return 7527;
return 7516;
}
}
return this.iconHook.Original(self, actionID); return this.iconHook.Original(self, actionID);
} }
private unsafe bool SearchBuffArray(short needle) { private bool SearchBuffArray(short needle) {
for (int i = 0; i < 60; i++) { for (int i = 0; i < 60; i++) {
if (Marshal.ReadInt16(activeBuffArray + 4 * i) == needle) return true; if (Marshal.ReadInt16(activeBuffArray + 4 * i) == needle) return true;
} }
return false; return false;
} }
private delegate ulong OnIconDetour(byte param1, uint param2);
public delegate ulong OnIconDelegate(byte param1, uint param2);
private unsafe delegate int* getArray(long* address); private unsafe delegate int* getArray(long* address);
private unsafe IntPtr FindBuffAddress() { private unsafe IntPtr FindBuffAddress() {
IntPtr randomAddress = byteBase + 0x1b2c970; IntPtr randomAddress = byteBase + 0x1c04be0;
IntPtr num = Marshal.ReadIntPtr(randomAddress); IntPtr num = Marshal.ReadIntPtr(randomAddress);
IntPtr step2 = (IntPtr)(Marshal.ReadInt64(num) + 0x248); IntPtr step2 = (IntPtr)(Marshal.ReadInt64(num) + 0x248);
IntPtr step3 = Marshal.ReadIntPtr(step2); IntPtr step3 = Marshal.ReadIntPtr(step2);

View file

@ -6,11 +6,12 @@ using System.Threading.Tasks;
namespace Dalamud.Game.Internal.Gui { namespace Dalamud.Game.Internal.Gui {
class IconReplacerAddressResolver : BaseAddressResolver { class IconReplacerAddressResolver : BaseAddressResolver {
public IntPtr BaseAddress { get; private set; } public IntPtr GetIcon { get; private set; }
protected bool IsResolved { get; set; } public IntPtr IsIconReplaceable { get; private set; }
protected override void Setup64Bit(SigScanner sig) { protected override void Setup64Bit(SigScanner sig) {
this.BaseAddress = sig.ScanText("81 fa d4 08 00 00 7f 4b 74 44 8d 42 eb 3d a3 00 00 00"); this.GetIcon = sig.ScanText("48 89 5c 24 08 48 89 6c 24 10 48 89 74 24 18 57 48 83 ec 30 8b da be dd 1c 00 00 bd d3 0d 00 00");
this.IsIconReplaceable = sig.ScanText("81 f9 2e 01 00 00 7f 39 81 f9 2d 01 00 00 0f 8d 11 02 00 00 83 c1 eb");
} }
} }
} }

View file

@ -6,7 +6,6 @@ using System.Threading.Tasks;
using Dalamud.Game.Network.MarketBoardUploaders; using Dalamud.Game.Network.MarketBoardUploaders;
using Dalamud.Game.Network.Structures; using Dalamud.Game.Network.Structures;
using Dalamud.Game.Network.Universalis.MarketBoardUploaders; using Dalamud.Game.Network.Universalis.MarketBoardUploaders;
using Dalamud.Settings;
using Serilog; using Serilog;
namespace Dalamud.Game.Network { namespace Dalamud.Game.Network {
@ -46,14 +45,14 @@ namespace Dalamud.Game.Network {
} }
if (opCode == ZoneOpCode.FateSpawn) { if (opCode == ZoneOpCode.FateSpawn) {
if (PersistentSettings.Instance.Fates == null) if (this.dalamud.Configuration.Fates == null)
return; return;
var data = new byte[64]; var data = new byte[64];
Marshal.Copy(dataPtr, data, 0, 64); Marshal.Copy(dataPtr, data, 0, 64);
var fateId = data[16]; var fateId = data[16];
if (PersistentSettings.Instance.Fates.Any(x => x.Id == fateId) && if (this.dalamud.Configuration.Fates.Any(x => x.Id == fateId) &&
this.dalamud.BotManager.IsConnected) this.dalamud.BotManager.IsConnected)
Task.Run(() => this.dalamud.BotManager.ProcessFate(fateId)); Task.Run(() => this.dalamud.BotManager.ProcessFate(fateId));

View file

@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Dalamud.Settings
{
public class PersistentSettings {
private static PersistentSettings _instance = null;
private static readonly string ConfigPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "settings.json");
public static PersistentSettings Instance {
get {
if (_instance == null) {
if (!File.Exists(ConfigPath)) {
_instance = new PersistentSettings();
return _instance;
}
_instance = JsonConvert.DeserializeObject<PersistentSettings>(File.ReadAllText(ConfigPath));
}
return _instance;
}
}
public class FateInfo {
public string Name { get; set; }
public int Id { get; set; }
}
public List<FateInfo> Fates;
public List<string> BadWords;
public void Save() {
File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(this));
}
public static void Reset() {
_instance = new PersistentSettings();
Instance.Save();
}
}
}