diff --git a/Lithium/ConfigLoader.cs b/Lithium/ConfigLoader.cs
index ec349da..657d0ed 100644
--- a/Lithium/ConfigLoader.cs
+++ b/Lithium/ConfigLoader.cs
@@ -18,6 +18,10 @@ namespace Lua
public static int prevSetKey = 0x06; // XBUTTON2
public static int refreshKey = 0x50; // P
public static int switchSideKey = 0x4D; // M
+ public static int shootKey = 0x01; // Left mouse button
+ public static int altShootKey = 0x02;
+
+
// Favorites and user
public static string favoriteAttackers = null;
diff --git a/Lithium/Lithium.csproj b/Lithium/Lithium.csproj
index 2cf98ac..16400eb 100644
--- a/Lithium/Lithium.csproj
+++ b/Lithium/Lithium.csproj
@@ -51,6 +51,9 @@
prompt
4
+
+ a23ae8c4c6863364165637fb70679eb3.ico
+
..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll
@@ -172,19 +175,22 @@
+ latest
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Lithium/MainWindow.xaml.cs b/Lithium/MainWindow.xaml.cs
index eb0faf8..db00b3c 100644
--- a/Lithium/MainWindow.xaml.cs
+++ b/Lithium/MainWindow.xaml.cs
@@ -14,79 +14,136 @@ namespace Lithium
{
private bool customSetEnabled = false;
+ // Hotkey debounce flags
+ private bool nextSetHeld = false;
+ private bool prevSetHeld = false;
+ private bool refreshHeld = false;
+ private bool switchSideHeld = false;
+
public MainWindow()
{
InitializeComponent();
- // Load configs
AppendConsole("Initializing Lithium...");
+
ConfigLoader.LoadInitConfig();
OperatorSets.LoadOperatorSets();
AppendConsole("Loaded Operators | Current Set: " + OperatorSets.CurrentSet);
- // Load website inside browse
string url = OperatorSets.ConfigExportUrl;
- Browser.Source = !string.IsNullOrEmpty(url) ? new Uri(url) : new Uri("https://jj.giggity.gay/exindex.html");
+ Browser.Source = !string.IsNullOrEmpty(url)
+ ? new Uri(url)
+ : new Uri("https://jj.giggity.gay/exindex.html");
-
- Thread hotkeyThread = new Thread(HotkeyLoop)
- {
- IsBackground = true
- };
+ // Start hotkey watcher
+ Thread hotkeyThread = new Thread(HotkeyLoop);
+ hotkeyThread.IsBackground = true;
hotkeyThread.Start();
+
+ // Start recoil worker
+ Thread recoilThread = new Thread(RecoilLoop);
+ recoilThread.IsBackground = true;
+ recoilThread.Start();
}
- #region Keybinds
+ // ============================================================
+ // RECOIL SYSTEM (THIS IS WHAT WAS MISSING)
+ // ============================================================
+ private void RecoilLoop()
+ {
+ const int RIGHT_MOUSE = 0x02; // Right mouse button
+
+ while (true)
+ {
+ bool leftPressed = Utils.IsPressed(ConfigLoader.shootKey); // 0x01
+ bool rightPressed = Utils.IsPressed(RIGHT_MOUSE); // 0x02
+
+ // Only trigger recoil when BOTH are held
+ bool shouldFire = leftPressed && rightPressed;
+
+ if (shouldFire)
+ {
+ var recoil = OperatorSets.GetCurrentRecoil();
+
+ if (recoil.recoilX != 0 || recoil.recoilY != 0)
+ {
+ Utils.MoveMouse(
+ (int)Math.Round(recoil.recoilX),
+ (int)Math.Round(recoil.recoilY)
+ );
+ }
+ }
+
+ Thread.Sleep(1);
+ }
+ }
+
+
+
+
+ // ============================================================
+ // HOTKEY THREAD (debounced)
+ // ============================================================
private void HotkeyLoop()
{
while (true)
{
// Next Set
- if (Utils.IsPressed(ConfigLoader.nextSetKey))
+ bool nextDown = Utils.IsPressed(ConfigLoader.nextSetKey);
+ if (nextDown && !nextSetHeld)
{
+ nextSetHeld = true;
OperatorSets.NextSet();
AppendConsole("Next Set → " + OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
- Thread.Sleep(200);
}
+ if (!nextDown) nextSetHeld = false;
// Previous Set
- if (Utils.IsPressed(ConfigLoader.prevSetKey))
+ bool prevDown = Utils.IsPressed(ConfigLoader.prevSetKey);
+ if (prevDown && !prevSetHeld)
{
+ prevSetHeld = true;
OperatorSets.PreviousSet();
AppendConsole("Previous Set → " + OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
- Thread.Sleep(200);
}
+ if (!prevDown) prevSetHeld = false;
- // Reload Config
- if (Utils.IsPressed(ConfigLoader.refreshKey))
+ // Reload config
+ bool refreshDown = Utils.IsPressed(ConfigLoader.refreshKey);
+ if (refreshDown && !refreshHeld)
{
+ refreshHeld = true;
OperatorSets.LoadOperatorSets();
AppendConsole("Reloaded config.");
- Thread.Sleep(300);
}
+ if (!refreshDown) refreshHeld = false;
// Switch Side
- if (Utils.IsPressed(ConfigLoader.switchSideKey))
+ bool switchDown = Utils.IsPressed(ConfigLoader.switchSideKey);
+ if (switchDown && !switchSideHeld)
{
+ switchSideHeld = true;
OperatorSets.SwitchSide();
AppendConsole("Switched side → " + (OperatorSets.onAttackers ? "Attackers" : "Defenders"));
- Thread.Sleep(250);
}
+ if (!switchDown) switchSideHeld = false;
- Thread.Sleep(10);
+ Thread.Sleep(8);
}
}
- #endregion
- #region Console Append
+ // ============================================================
+ // SAFE UI CONSOLE APPEND
+ // ============================================================
public void AppendConsole(string msg)
{
Dispatcher.Invoke(() =>
{
- ConsoleOutput.Text += msg + "\n";
+ ConsoleOutput.Text += msg + Environment.NewLine;
+ ConsoleScroll.ScrollToBottom();
});
}
@@ -97,10 +154,10 @@ namespace Lithium
CustomSetConsole.Text = msg;
});
}
- #endregion
-
- #region Custom Set Builder Handlers
+ // ============================================================
+ // CUSTOM SET BUILDER
+ // ============================================================
private void ToggleCustomSet_Click(object sender, RoutedEventArgs e)
{
customSetEnabled = !customSetEnabled;
@@ -131,23 +188,23 @@ namespace Lithium
try
{
+ HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(payload);
- using (HttpClient client = new HttpClient())
- {
- var content = new StringContent(json, Encoding.UTF8, "application/json");
- HttpResponseMessage response = await client.PostAsync("https://jj.giggity.gay/api/global/add", content);
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+ var response = await client.PostAsync("https://jj.giggity.gay/api/global/add", content);
- if (response.IsSuccessStatusCode)
- {
- UpdateCustomSetConsole($"Successfully published: {name} ({type}) X:{x} Y:{y}");
- }
- else
- {
- string errorText = await response.Content.ReadAsStringAsync();
- UpdateCustomSetConsole($"Failed to publish: {response.StatusCode} - {errorText}");
- }
+ if (response.IsSuccessStatusCode)
+ {
+ UpdateCustomSetConsole($"Successfully published: {name} ({type}) X:{x} Y:{y}");
}
+ else
+ {
+ string errorText = await response.Content.ReadAsStringAsync();
+ UpdateCustomSetConsole($"Failed: {response.StatusCode} - {errorText}");
+ }
+
+ client.Dispose();
}
catch (Exception ex)
{
@@ -159,8 +216,9 @@ namespace Lithium
{
try
{
- string path = "custom_set.txt";
- File.WriteAllText(path, $"{OperatorNameTextBox.Text}|{RecoilXTextBox.Text}|{RecoilYTextBox.Text}|{(AttackerRadioButton.IsChecked == true ? "attacker" : "defender")}");
+ File.WriteAllText("custom_set.txt",
+ $"{OperatorNameTextBox.Text}|{RecoilXTextBox.Text}|{RecoilYTextBox.Text}|{(AttackerRadioButton.IsChecked == true ? "attacker" : "defender")}");
+
UpdateCustomSetConsole("Custom set saved");
}
catch
@@ -173,21 +231,23 @@ namespace Lithium
{
try
{
- string path = "custom_set.txt";
- if (!File.Exists(path))
+ if (!File.Exists("custom_set.txt"))
{
UpdateCustomSetConsole("No saved set found");
return;
}
- string[] parts = File.ReadAllText(path).Split('|');
- if (parts.Length != 4) throw new Exception("Invalid file format");
+ string[] parts = File.ReadAllText("custom_set.txt").Split('|');
+ if (parts.Length != 4) throw new Exception("Invalid file");
OperatorNameTextBox.Text = parts[0];
RecoilXTextBox.Text = parts[1];
RecoilYTextBox.Text = parts[2];
- if (parts[3].ToLower() == "attacker") AttackerRadioButton.IsChecked = true;
- else DefenderRadioButton.IsChecked = true;
+
+ if (parts[3].Equals("attacker", StringComparison.OrdinalIgnoreCase))
+ AttackerRadioButton.IsChecked = true;
+ else
+ DefenderRadioButton.IsChecked = true;
UpdateCustomSetConsole("Custom set loaded");
}
@@ -196,7 +256,5 @@ namespace Lithium
UpdateCustomSetConsole("Failed to load custom set");
}
}
-
- #endregion
}
}
diff --git a/Lithium/OperatorSets.cs b/Lithium/OperatorSets.cs
index b213b65..d9bac22 100644
--- a/Lithium/OperatorSets.cs
+++ b/Lithium/OperatorSets.cs
@@ -22,18 +22,23 @@ namespace Lua
public static List attackerNames = new List();
public static List defenderNames = new List();
-
public static List setNames = new List();
public static int currentSetIndex = 0;
public static bool onAttackers = true;
+ // ======================================================
+ // ONLINE CONFIG URL
+ // ======================================================
+ private static string OnlineConfigUrl =>
+ string.IsNullOrEmpty(ConfigLoader.userName)
+ ? null
+ : $"https://jj.giggity.gay/api/config/export?name={Uri.EscapeDataString(ConfigLoader.userName)}";
+
public static string ConfigExportUrl =>
- string.IsNullOrEmpty(ConfigLoader.userName)
- ? null
- : $"https://jj.giggity.gay/exindex.html?name={Uri.EscapeDataString(ConfigLoader.userName)}";
-
-
+ string.IsNullOrEmpty(ConfigLoader.userName)
+ ? null
+ : $"https://jj.giggity.gay/exindex.html?name={Uri.EscapeDataString(ConfigLoader.userName)}";
// ======================================================
// CURRENT SET + CURRENT OPERATOR
@@ -67,13 +72,21 @@ namespace Lua
}
}
+ // ======================================================
+ // GET CURRENT RECOIL
+ // ======================================================
+ public static (double recoilX, double recoilY) GetCurrentRecoil()
+ {
+ string op = CurrentOperator;
- // Build online URL
- private static string OnlineConfigUrl =>
- string.IsNullOrEmpty(ConfigLoader.userName)
- ? null
- : $"https://jj.giggity.gay/api/config/export?name={Uri.EscapeDataString(ConfigLoader.userName)}";
+ if (onAttackers && attackers.ContainsKey(op))
+ return attackers[op];
+ if (!onAttackers && defenders.ContainsKey(op))
+ return defenders[op];
+
+ return (0, 0);
+ }
// ======================================================
// LOAD CONFIG
@@ -99,10 +112,7 @@ namespace Lua
allLines.AddRange(txt.Split('\n'));
}
}
- catch
- {
- // ignored
- }
+ catch { }
}
// ---------- LOCAL ----------
@@ -122,19 +132,14 @@ namespace Lua
if (line.StartsWith("--") || line.StartsWith("#")) continue;
if (line.StartsWith("attackers", StringComparison.OrdinalIgnoreCase))
- {
- inAtk = true; inDef = false; continue;
- }
- if (line.StartsWith("defenders", StringComparison.OrdinalIgnoreCase))
- {
- inAtk = false; inDef = true; continue;
- }
- if (line == "}" || line == "]," || line == "],")
- {
- inAtk = false; inDef = false; continue;
- }
+ { inAtk = true; inDef = false; continue; }
+
+ if (line.StartsWith("defenders", StringComparison.OrdinalIgnoreCase))
+ { inAtk = false; inDef = true; continue; }
+
+ if (line == "}" || line == "]," || line == "],")
+ { inAtk = false; inDef = false; continue; }
- // parse recoil line
if (Helper.TryParseRecoilLine(line, out var name, out var x, out var y))
{
if (inAtk)
@@ -153,12 +158,10 @@ namespace Lua
MergeSets();
RestoreFavorites();
- // correct operator selection
if (setNames.Count > 0)
CurrentOperator = CurrentSet;
}
-
// ======================================================
// MERGE
// ======================================================
@@ -167,11 +170,8 @@ namespace Lua
if (ConfigLoader.betaTest)
{
mergedSets.Clear();
-
- foreach (var kv in attackers)
- mergedSets[kv.Key] = kv.Value;
- foreach (var kv in defenders)
- mergedSets[kv.Key] = kv.Value;
+ foreach (var kv in attackers) mergedSets[kv.Key] = kv.Value;
+ foreach (var kv in defenders) mergedSets[kv.Key] = kv.Value;
setNames = attackerNames.Concat(defenderNames)
.Distinct(StringComparer.OrdinalIgnoreCase)
@@ -192,27 +192,19 @@ namespace Lua
currentSetIndex = Helper.SafeClampIndex(currentSetIndex, setNames.Count);
}
-
// ======================================================
// RESTORE
// ======================================================
public static void RestoreSet(string oldSet)
{
- if (setNames.Count == 0)
- {
- currentSetIndex = 0;
- return;
- }
-
- int idx = setNames.FindIndex(s =>
- string.Equals(s, oldSet, StringComparison.OrdinalIgnoreCase));
+ if (setNames.Count == 0) { currentSetIndex = 0; return; }
+ int idx = setNames.FindIndex(s => string.Equals(s, oldSet, StringComparison.OrdinalIgnoreCase));
currentSetIndex = idx >= 0 ? idx : 0;
CurrentOperator = CurrentSet;
}
-
// ======================================================
// SWITCH SIDE
// ======================================================
@@ -225,7 +217,6 @@ namespace Lua
RestoreFavorites();
}
-
// ======================================================
// CYCLING
// ======================================================
@@ -245,17 +236,12 @@ namespace Lua
CurrentOperator = CurrentSet;
}
-
// ======================================================
// FAVORITES
// ======================================================
private static void RestoreFavorites()
{
- if (setNames.Count == 0)
- {
- currentSetIndex = 0;
- return;
- }
+ if (setNames.Count == 0) { currentSetIndex = 0; return; }
if (ConfigLoader.betaTest)
{
@@ -264,7 +250,6 @@ namespace Lua
{
currentSetIndex = setNames.FindIndex(s =>
string.Equals(s, ConfigLoader.favoriteAttackers, StringComparison.OrdinalIgnoreCase));
-
CurrentOperator = CurrentSet;
return;
}
@@ -274,7 +259,6 @@ namespace Lua
{
currentSetIndex = setNames.FindIndex(s =>
string.Equals(s, ConfigLoader.favoriteDefenders, StringComparison.OrdinalIgnoreCase));
-
CurrentOperator = CurrentSet;
return;
}
@@ -284,34 +268,26 @@ namespace Lua
return;
}
- // non-beta side-based
- if (onAttackers)
+ if (onAttackers && !string.IsNullOrEmpty(ConfigLoader.favoriteAttackers) &&
+ setNames.Contains(ConfigLoader.favoriteAttackers, StringComparer.OrdinalIgnoreCase))
{
- if (!string.IsNullOrEmpty(ConfigLoader.favoriteAttackers) &&
- setNames.Contains(ConfigLoader.favoriteAttackers, StringComparer.OrdinalIgnoreCase))
- {
- currentSetIndex = setNames.FindIndex(s =>
- string.Equals(s, ConfigLoader.favoriteAttackers, StringComparison.OrdinalIgnoreCase));
-
- CurrentOperator = CurrentSet;
- return;
- }
+ currentSetIndex = setNames.FindIndex(s =>
+ string.Equals(s, ConfigLoader.favoriteAttackers, StringComparison.OrdinalIgnoreCase));
+ CurrentOperator = CurrentSet;
+ return;
}
- else
- {
- if (!string.IsNullOrEmpty(ConfigLoader.favoriteDefenders) &&
- setNames.Contains(ConfigLoader.favoriteDefenders, StringComparer.OrdinalIgnoreCase))
- {
- currentSetIndex = setNames.FindIndex(s =>
- string.Equals(s, ConfigLoader.favoriteDefenders, StringComparison.OrdinalIgnoreCase));
- CurrentOperator = CurrentSet;
- return;
- }
+ if (!onAttackers && !string.IsNullOrEmpty(ConfigLoader.favoriteDefenders) &&
+ setNames.Contains(ConfigLoader.favoriteDefenders, StringComparer.OrdinalIgnoreCase))
+ {
+ currentSetIndex = setNames.FindIndex(s =>
+ string.Equals(s, ConfigLoader.favoriteDefenders, StringComparison.OrdinalIgnoreCase));
+ CurrentOperator = CurrentSet;
+ return;
}
currentSetIndex = 0;
CurrentOperator = CurrentSet;
}
}
-}
\ No newline at end of file
+}
diff --git a/Lithium/RecoilControl.cs b/Lithium/RecoilControl.cs
index 0ab5da5..e93419e 100644
--- a/Lithium/RecoilControl.cs
+++ b/Lithium/RecoilControl.cs
@@ -1,5 +1,4 @@
-// RecoilControl.cs (patched)
-using System;
+using System;
using System.Threading;
namespace Lua
@@ -41,7 +40,7 @@ namespace Lua
if (!Utils.IsPressed(VK_LBUTTON))
return;
- var setName = OperatorSets.CurrentSet;
+ string setName = OperatorSets.CurrentSet;
if (!OperatorSets.mergedSets.TryGetValue(setName, out var recoil))
return;
@@ -87,6 +86,7 @@ namespace Lua
moveY *= 1.351;
}
+ // CAST doubles to int to fix compiler errors
int ix = (int)Math.Round(moveX);
int iy = (int)Math.Round(moveY);
@@ -96,4 +96,4 @@ namespace Lua
Utils.MoveMouse(ix, iy);
}
}
-}
\ No newline at end of file
+}
diff --git a/Lithium/a23ae8c4c6863364165637fb70679eb3.ico b/Lithium/a23ae8c4c6863364165637fb70679eb3.ico
new file mode 100644
index 0000000..1d592a3
Binary files /dev/null and b/Lithium/a23ae8c4c6863364165637fb70679eb3.ico differ
diff --git a/Lithium/bin/Lithium.7z b/Lithium/bin/Lithium.7z
index 90d7b8c..6a3f7c5 100644
Binary files a/Lithium/bin/Lithium.7z and b/Lithium/bin/Lithium.7z differ