Update 0.01 C

This commit is contained in:
JJ
2025-11-23 23:37:37 -05:00
parent c724c5263b
commit ce5e7b16f4
4 changed files with 292 additions and 212 deletions
+96 -6
View File
@@ -3,11 +3,101 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wv="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
Title="Lithium" Height="570" Width="900"
Background="#1E1E1E">
Background="#1E1E1E"
WindowStyle="None"
AllowsTransparency="True">
<Grid Margin="10">
<Grid>
<!-- Custom Title Bar -->
<Grid Height="35" VerticalAlignment="Top" MouseDown="TitleBar_MouseDown">
<Grid.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#2A2A2A" Offset="0"/>
<GradientStop Color="#1E1E1E" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<!-- Left: Icon + Title -->
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,0,0">
<Image Source="/a23ae8c4c6863364165637fb70679eb3.ico" Width="20" Height="20" Margin="0,0,10,0"/>
<TextBlock Text="Lithium" Foreground="White" VerticalAlignment="Center" FontSize="14" FontWeight="SemiBold"/>
</StackPanel>
<!-- Right: Buttons -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,10,0">
<!-- Minimize -->
<Button Width="30" Height="25" Click="Minimize_Click" BorderThickness="0" Background="Transparent">
<Button.Content>
<TextBlock Text="─" Foreground="White" FontSize="16" HorizontalAlignment="Center"/>
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Cursor" Value="Hand"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#3A3A3A"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#555555"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<!-- Maximize/Restore -->
<Button Width="30" Height="25" Click="MaximizeRestore_Click" BorderThickness="0" Background="Transparent">
<Button.Content>
<TextBlock Text="☐" Foreground="White" FontSize="12" HorizontalAlignment="Center"/>
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Cursor" Value="Hand"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#3A3A3A"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#555555"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<!-- Close -->
<Button Width="30" Height="25" Click="Close_Click" BorderThickness="0" Background="Transparent">
<Button.Content>
<TextBlock Text="✕" Foreground="White" FontSize="14" HorizontalAlignment="Center"/>
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Cursor" Value="Hand"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E81123"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#A50E1A"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
<!-- Main Content -->
<Grid Margin="0,35,0,0">
<TabControl Background="#1E1E1E" Foreground="White">
<!-- Console -->
<!-- Console Tab -->
<TabItem Header="Console">
<Grid Background="#252525" Margin="10">
<ScrollViewer x:Name="ConsoleScroll" VerticalScrollBarVisibility="Auto">
@@ -20,7 +110,7 @@
</Grid>
</TabItem>
<!-- Website -->
<!-- Website Tab -->
<TabItem Header="Website">
<Grid Background="#252525">
<wv:WebView2 x:Name="Browser"
@@ -29,7 +119,7 @@
</Grid>
</TabItem>
<!-- Custom Set Builder -->
<!-- Custom Set Builder Tab -->
<TabItem Header="Custom Set Builder">
<Grid Background="#252525" Margin="10">
<Grid.RowDefinitions>
@@ -67,7 +157,7 @@
</Grid>
</TabItem>
</TabControl>
</Grid>
</Grid>
</Window>
+127 -154
View File
@@ -1,62 +1,51 @@
using System;
using Lua;
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Lua;
using System.Windows.Input;
namespace Lithium
{
public partial class MainWindow : Window
{
private bool customSetEnabled = false;
// Hotkey debounce flags
private bool nextSetHeld = false;
private bool prevSetHeld = false;
private bool refreshHeld = false;
private bool switchSideHeld = false;
// CapsLock recoil toggle
private bool nextSetHeld, prevSetHeld, refreshHeld, switchSideHeld, capsHeld;
private bool recoilEnabled = true;
private bool capsHeld = false;
// NEW: cooldown timestamps
private DateTime nextSetAllowed = DateTime.MinValue;
private DateTime prevSetAllowed = DateTime.MinValue;
private double remX = 0, remY = 0;
public MainWindow()
{
InitializeComponent();
AppendConsole("Initializing Lithium...");
AppendConsole($"Initializing Lithium...");
ConfigLoader.LoadInitConfig();
OperatorSets.LoadOperatorSets();
AppendConsole($"Loaded Operators | Current Set: {OperatorSets.CurrentSet} | Side: {(OperatorSets.onAttackers ? "Attackers" : "Defenders")}");
AppendConsole("Loaded Operators | Current Set: " + OperatorSets.CurrentSet);
string url = OperatorSets.ConfigExportUrl;
Browser.Source = !string.IsNullOrEmpty(url)
? new Uri(url)
Browser.Source = !string.IsNullOrEmpty(OperatorSets.ConfigExportUrl)
? new Uri(OperatorSets.ConfigExportUrl)
: new Uri("https://jj.giggity.gay/exindex.html");
// Start hotkey watcher
Thread hotkeyThread = new Thread(HotkeyLoop);
hotkeyThread.IsBackground = true;
hotkeyThread.Start();
StartThread(HotkeyLoop);
StartThread(RecoilLoop);
}
// Start recoil worker
Thread recoilThread = new Thread(RecoilLoop);
recoilThread.IsBackground = true;
recoilThread.Start();
private void StartThread(ThreadStart action)
{
var thread = new Thread(action) { IsBackground = true };
thread.Start();
}
// ============================================================
// RECOIL ENGINE (CapsLock toggle + both mouse buttons required)
// RECOIL ENGINE (fractional X/Y tracking for precise Ricoh-style movement)
// ============================================================
private void RecoilLoop()
{
@@ -70,22 +59,20 @@ namespace Lithium
continue;
}
bool leftPressed = Utils.IsPressed(ConfigLoader.shootKey);
bool rightPressed = Utils.IsPressed(RIGHT_MOUSE);
bool shouldFire = leftPressed && rightPressed;
if (shouldFire)
if (Utils.IsPressed(ConfigLoader.shootKey) && Utils.IsPressed(RIGHT_MOUSE))
{
var recoil = OperatorSets.GetCurrentRecoil();
if (recoil.recoilX != 0 || recoil.recoilY != 0)
{
Utils.MoveMouse(
(int)Math.Round(recoil.recoilX),
(int)Math.Round(recoil.recoilY)
);
}
double moveX = recoil.recoilX + remX;
double moveY = recoil.recoilY + remY;
int ix = (int)Math.Round(moveX);
int iy = (int)Math.Round(moveY);
remX = moveX - ix;
remY = moveY - iy;
Utils.MoveMouse(ix, iy);
}
Thread.Sleep(1);
@@ -93,7 +80,7 @@ namespace Lithium
}
// ============================================================
// HOTKEY THREAD (debounced + cooldowns + CapsLock toggle)
// HOTKEY LOOP
// ============================================================
private void HotkeyLoop()
{
@@ -101,85 +88,83 @@ namespace Lithium
while (true)
{
// -------------------------------
// CAPSLOCK → Toggle recoil
// -------------------------------
bool capsDown = Utils.IsPressed(CAPSLOCK);
if (capsDown && !capsHeld)
{
capsHeld = true;
recoilEnabled = !recoilEnabled;
AppendConsole(recoilEnabled ? "Recoil Enabled" : "Recoil Disabled");
}
if (!capsDown) capsHeld = false;
// -------------------------------
// NEXT SET (cooldown)
// -------------------------------
bool nextDown = Utils.IsPressed(ConfigLoader.nextSetKey);
if (nextDown && !nextSetHeld && DateTime.Now >= nextSetAllowed)
{
nextSetHeld = true;
nextSetAllowed = DateTime.Now.AddMilliseconds(200);
OperatorSets.NextSet();
AppendConsole("Next Set → " + OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
if (!nextDown) nextSetHeld = false;
// -------------------------------
// PREVIOUS SET (cooldown)
// -------------------------------
bool prevDown = Utils.IsPressed(ConfigLoader.prevSetKey);
if (prevDown && !prevSetHeld && DateTime.Now >= prevSetAllowed)
{
prevSetHeld = true;
prevSetAllowed = DateTime.Now.AddMilliseconds(200);
OperatorSets.PreviousSet();
AppendConsole("Previous Set → " + OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
if (!prevDown) prevSetHeld = false;
// -------------------------------
// RELOAD CONFIG
// -------------------------------
bool refreshDown = Utils.IsPressed(ConfigLoader.refreshKey);
if (refreshDown && !refreshHeld)
{
refreshHeld = true;
OperatorSets.LoadOperatorSets();
AppendConsole("Reloaded config.");
}
if (!refreshDown) refreshHeld = false;
// -------------------------------
// SWITCH SIDE
// -------------------------------
bool switchDown = Utils.IsPressed(ConfigLoader.switchSideKey);
if (switchDown && !switchSideHeld)
{
switchSideHeld = true;
OperatorSets.SwitchSide();
AppendConsole("Switched side → " + (OperatorSets.onAttackers ? "Attackers" : "Defenders"));
}
if (!switchDown) switchSideHeld = false;
HandleToggleCapsLock(CAPSLOCK);
HandleNextSet();
HandlePrevSet();
HandleRefresh();
HandleSwitchSide();
Thread.Sleep(8);
}
}
private void HandleToggleCapsLock(int capsKey)
{
bool capsDown = Utils.IsPressed(capsKey);
if (capsDown && !capsHeld)
{
capsHeld = true;
recoilEnabled = !recoilEnabled;
AppendConsole(recoilEnabled ? "Recoil Enabled" : "Recoil Disabled");
}
if (!capsDown) capsHeld = false;
}
private void HandleNextSet()
{
if (Utils.IsPressed(ConfigLoader.nextSetKey) && !nextSetHeld && DateTime.Now >= nextSetAllowed)
{
nextSetHeld = true;
nextSetAllowed = DateTime.Now.AddMilliseconds(200);
OperatorSets.NextSet();
// Only announce operator, no side
AppendConsole($"Next Set → {OperatorSets.CurrentSet}");
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
else if (!Utils.IsPressed(ConfigLoader.nextSetKey)) nextSetHeld = false;
}
private void HandlePrevSet()
{
if (Utils.IsPressed(ConfigLoader.prevSetKey) && !prevSetHeld && DateTime.Now >= prevSetAllowed)
{
prevSetHeld = true;
prevSetAllowed = DateTime.Now.AddMilliseconds(200);
OperatorSets.PreviousSet();
// Only announce operator, no side
AppendConsole($"Previous Set → {OperatorSets.CurrentSet}");
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
else if (!Utils.IsPressed(ConfigLoader.prevSetKey)) prevSetHeld = false;
}
private void HandleRefresh()
{
if (Utils.IsPressed(ConfigLoader.refreshKey) && !refreshHeld)
{
refreshHeld = true;
string current = OperatorSets.CurrentSet; // store current
OperatorSets.LoadOperatorSets();
OperatorSets.SetCurrentSet(current); // restore operator after refresh
AppendConsole($"Reloaded config | Current Set: {OperatorSets.CurrentSet} | Side: {(OperatorSets.onAttackers ? "Attackers" : "Defenders")}");
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
else if (!Utils.IsPressed(ConfigLoader.refreshKey)) refreshHeld = false;
}
private void HandleSwitchSide()
{
if (Utils.IsPressed(ConfigLoader.switchSideKey) && !switchSideHeld)
{
switchSideHeld = true;
OperatorSets.SwitchSide();
// Announce operator + side only on side switch
AppendConsole($"Switched side → {(OperatorSets.onAttackers ? "Attackers" : "Defenders")} | Current Set: {OperatorSets.CurrentSet}");
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
else if (!Utils.IsPressed(ConfigLoader.switchSideKey)) switchSideHeld = false;
}
// ============================================================
// UI CONSOLE
// ============================================================
@@ -194,10 +179,7 @@ namespace Lithium
public void UpdateCustomSetConsole(string msg)
{
Dispatcher.Invoke(() =>
{
CustomSetConsole.Text = msg;
});
Dispatcher.Invoke(() => CustomSetConsole.Text = msg);
}
// ============================================================
@@ -218,38 +200,23 @@ namespace Lithium
return;
}
if (!double.TryParse(RecoilXTextBox.Text, out var x)) x = 0;
if (!double.TryParse(RecoilYTextBox.Text, out var y)) y = 0;
double.TryParse(RecoilXTextBox.Text, out double x);
double.TryParse(RecoilYTextBox.Text, out double y);
string type = AttackerRadioButton.IsChecked == true ? "attackers" : "defenders";
var payload = new
{
type,
name,
recoilX = x,
recoilY = y
};
var payload = new { type, name, recoilX = x, recoilY = y };
try
{
HttpClient client = new HttpClient();
using HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://jj.giggity.gay/api/global/add", content);
var response = await client.PostAsync("https://jj.giggity.gay/api/global/add",
new StringContent(json, Encoding.UTF8, "application/json"));
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();
UpdateCustomSetConsole($"Failed: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}");
}
catch (Exception ex)
{
@@ -263,13 +230,9 @@ namespace Lithium
{
File.WriteAllText("custom_set.txt",
$"{OperatorNameTextBox.Text}|{RecoilXTextBox.Text}|{RecoilYTextBox.Text}|{(AttackerRadioButton.IsChecked == true ? "attacker" : "defender")}");
UpdateCustomSetConsole("Custom set saved");
}
catch
{
UpdateCustomSetConsole("Failed to save custom set");
}
catch { UpdateCustomSetConsole("Failed to save custom set"); }
}
private void LoadSet_Click(object sender, RoutedEventArgs e)
@@ -288,7 +251,6 @@ namespace Lithium
OperatorNameTextBox.Text = parts[0];
RecoilXTextBox.Text = parts[1];
RecoilYTextBox.Text = parts[2];
if (parts[3].Equals("attacker", StringComparison.OrdinalIgnoreCase))
AttackerRadioButton.IsChecked = true;
else
@@ -296,10 +258,21 @@ namespace Lithium
UpdateCustomSetConsole("Custom set loaded");
}
catch
catch { UpdateCustomSetConsole("Failed to load custom set"); }
}
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
UpdateCustomSetConsole("Failed to load custom set");
}
}
if (e.ChangedButton == MouseButton.Left) DragMove();
}
private void Minimize_Click(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized;
private void MaximizeRestore_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal;
}
private void Close_Click(object sender, RoutedEventArgs e) => Close();
}
}
+14
View File
@@ -236,6 +236,20 @@ namespace Lua
CurrentOperator = CurrentSet;
}
public static void SetCurrentSet(string name)
{
if (setNames == null || setNames.Count == 0) return;
int idx = setNames.FindIndex(s => string.Equals(s, name, StringComparison.OrdinalIgnoreCase));
if (idx >= 0)
{
currentSetIndex = idx; // set the current operator index
CurrentOperator = CurrentSet; // update CurrentOperator
}
}
// ======================================================
// FAVORITES
// ======================================================
+6 -3
View File
@@ -21,7 +21,7 @@ namespace Lua
{
while (true)
{
if (!Utils.IsCapsLockOn() && Utils.IsPressed(VK_RBUTTON))
if (Utils.IsCapsLockOn() && Utils.IsPressed(VK_RBUTTON))
{
HandleRecoilTick();
}
@@ -47,6 +47,7 @@ namespace Lua
int now = Environment.TickCount;
// Jitter
if (ConfigLoader.jitterEnabled)
{
if (!jitterActive && now - lastJitterEnd >= ConfigLoader.jitterCooldown)
@@ -55,8 +56,8 @@ namespace Lua
jitterStart = now;
double strength = 0.1 + rng.NextDouble() * 0.8;
jitterMultX = jitterMultY = 0;
switch (rng.Next(1, 5))
{
case 1: jitterMultX = -strength; break;
@@ -74,22 +75,24 @@ namespace Lua
}
}
// Calculate precise movement with remainder tracking
double jitterX = recoil.recoilX * jitterMultX;
double jitterY = recoil.recoilY * jitterMultY;
double moveX = recoil.recoilX + remX + jitterX;
double moveY = recoil.recoilY + remY + jitterY;
// Optional scaling for fine-tuning
if (ConfigLoader.debitFlag1)
{
moveX *= 1.282;
moveY *= 1.351;
}
// CAST doubles to int to fix compiler errors
int ix = (int)Math.Round(moveX);
int iy = (int)Math.Round(moveY);
// Store remainder for next tick (Ricoh-style smoothness)
remX = moveX - ix;
remY = moveY - iy;