Update 0.01 D

This commit is contained in:
JJ
2025-11-24 00:04:52 -05:00
parent ce5e7b16f4
commit ab438856ad
6 changed files with 593 additions and 137 deletions
+80
View File
@@ -0,0 +1,80 @@
using Lua;
using System;
using System.Threading;
namespace Lithium
{
internal static class HotkeyHandler
{
private const int CAPSLOCK = 0x14;
private static bool nextSetHeld, prevSetHeld, refreshHeld, switchSideHeld, capsHeld;
private static MainWindow mainWindow;
public static void Start(MainWindow window)
{
mainWindow = window;
while (true)
{
HandleToggleCapsLock();
HandleNextSet();
HandlePrevSet();
HandleRefresh();
HandleSwitchSide();
Thread.Sleep(8);
}
}
private static void HandleToggleCapsLock()
{
bool capsDown = Utils.IsPressed(CAPSLOCK);
if (capsDown && !capsHeld)
{
capsHeld = true;
mainWindow.SetRecoilEnabled(!mainWindow.IsRecoilEnabled);
}
if (!capsDown) capsHeld = false;
}
private static void HandleNextSet()
{
if (Utils.IsPressed(ConfigLoader.nextSetKey) && !nextSetHeld)
{
nextSetHeld = true;
mainWindow.HandleNextSet();
}
else if (!Utils.IsPressed(ConfigLoader.nextSetKey)) nextSetHeld = false;
}
private static void HandlePrevSet()
{
if (Utils.IsPressed(ConfigLoader.prevSetKey) && !prevSetHeld)
{
prevSetHeld = true;
mainWindow.HandlePrevSet();
}
else if (!Utils.IsPressed(ConfigLoader.prevSetKey)) prevSetHeld = false;
}
private static void HandleRefresh()
{
if (Utils.IsPressed(ConfigLoader.refreshKey) && !refreshHeld)
{
refreshHeld = true;
mainWindow.HandleRefresh();
}
else if (!Utils.IsPressed(ConfigLoader.refreshKey)) refreshHeld = false;
}
private static void HandleSwitchSide()
{
if (Utils.IsPressed(ConfigLoader.switchSideKey) && !switchSideHeld)
{
switchSideHeld = true;
mainWindow.HandleSwitchSide();
}
else if (!Utils.IsPressed(ConfigLoader.switchSideKey)) switchSideHeld = false;
}
}
}
+2 -1
View File
@@ -113,7 +113,9 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="HotkeyHandler.cs" />
<Compile Include="RecoilControl.cs" /> <Compile Include="RecoilControl.cs" />
<Compile Include="RecoilEngine.cs" />
<Compile Include="Utils.cs" /> <Compile Include="Utils.cs" />
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@@ -149,7 +151,6 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<None Include="AppDomain.AssemblyResolve" />
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
+163 -8
View File
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wv="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf" xmlns:wv="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
Title="Lithium" Height="570" Width="900" Title="Lithium" Height="650" Width="1000"
Background="#1E1E1E" Background="#1E1E1E"
WindowStyle="None" WindowStyle="None"
AllowsTransparency="True"> AllowsTransparency="True">
@@ -110,6 +110,8 @@
</Grid> </Grid>
</TabItem> </TabItem>
<!-- Website Tab --> <!-- Website Tab -->
<TabItem Header="Website"> <TabItem Header="Website">
<Grid Background="#252525"> <Grid Background="#252525">
@@ -130,33 +132,186 @@
<!-- Operator Details --> <!-- Operator Details -->
<StackPanel Grid.Row="0" Margin="20" VerticalAlignment="Top"> <StackPanel Grid.Row="0" Margin="20" VerticalAlignment="Top">
<TextBlock Text="Operator Name:" Foreground="White" FontSize="14" Margin="0,5"/> <TextBlock Text="Operator Name:" Foreground="White" FontSize="14" Margin="0,5"/>
<TextBox x:Name="OperatorNameTextBox" Margin="0,5"/> <TextBox x:Name="OperatorNameTextBox" Margin="0,5" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Text="Recoil X:" Foreground="White" FontSize="14" Margin="0,5"/> <TextBlock Text="Recoil X:" Foreground="White" FontSize="14" Margin="0,5"/>
<TextBox x:Name="RecoilXTextBox" Margin="0,5"/> <TextBox x:Name="RecoilXTextBox" Margin="0,5" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Text="Recoil Y:" Foreground="White" FontSize="14" Margin="0,5"/> <TextBlock Text="Recoil Y:" Foreground="White" FontSize="14" Margin="0,5"/>
<TextBox x:Name="RecoilYTextBox" Margin="0,5"/> <TextBox x:Name="RecoilYTextBox" Margin="0,5" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Text="Type:" Foreground="White" FontSize="14" Margin="0,5"/> <TextBlock Text="Type:" Foreground="White" FontSize="14" Margin="0,5"/>
<StackPanel Orientation="Horizontal" Margin="0,5"> <StackPanel Orientation="Horizontal" Margin="0,5">
<RadioButton x:Name="AttackerRadioButton" Content="Attacker" IsChecked="True" Margin="0,0,10,0"/> <RadioButton x:Name="AttackerRadioButton" Content="Attacker" IsChecked="True" Margin="0,0,10,0" Foreground="White"/>
<RadioButton x:Name="DefenderRadioButton" Content="Defender"/> <RadioButton x:Name="DefenderRadioButton" Content="Defender" Foreground="White"/>
</StackPanel> </StackPanel>
<Button x:Name="ToggleCustomSetButton" Content="Toggle ON/OFF" Width="120" Margin="0,15" Click="ToggleCustomSet_Click"/> <Button x:Name="ToggleCustomSetButton" Content="Toggle ON/OFF" Width="120" Margin="0,15" Click="ToggleCustomSet_Click" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
</StackPanel> </StackPanel>
<!-- Console & Publish --> <!-- Console & Publish -->
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="20"> <StackPanel Grid.Row="1" Orientation="Vertical" Margin="20">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,5"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,5">
<Button Content="Publish Set" Width="120" Margin="0,0,10,0" Click="PublishSet_Click"/> <Button Content="Publish Set" Width="120" Margin="0,0,10,0" Click="PublishSet_Click" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<Button Content="Save Set" Width="80" Margin="0,0,10,0" Click="SaveSet_Click" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<Button Content="Load Set" Width="80" Click="LoadSet_Click" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
</StackPanel> </StackPanel>
<TextBlock x:Name="CustomSetConsole" Foreground="Lime" FontFamily="Consolas" FontSize="12" Text="Set is OFF" Margin="0,5"/> <TextBlock x:Name="CustomSetConsole" Foreground="Lime" FontFamily="Consolas" FontSize="12" Text="Set is OFF" Margin="0,5"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</TabItem> </TabItem>
<!-- Settings Tab -->
<TabItem Header="Settings">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid Background="#252525" Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Basic Settings -->
<GroupBox Grid.Row="0" Grid.ColumnSpan="2" Header="Basic Settings" Foreground="White" Margin="5" BorderBrush="#444">
<StackPanel Margin="10">
<StackPanel Orientation="Horizontal" Margin="0,5">
<CheckBox x:Name="DebitFlagCheckBox" Content="Debit Flag (Fine-tuning)" Foreground="White" VerticalAlignment="Center"/>
<TextBlock Text="(1.282x X, 1.351x Y scaling)" Foreground="Gray" FontSize="11" Margin="10,0,0,0" VerticalAlignment="Center"/>
</StackPanel>
<CheckBox x:Name="BetaTestCheckBox" Content="Beta Test Mode (Merge All Operators)" Foreground="White" Margin="0,5"/>
<CheckBox x:Name="TtsEnabledCheckBox" Content="Text-to-Speech Enabled" Foreground="White" Margin="0,5"/>
<CheckBox x:Name="JitterEnabledCheckBox" Content="Jitter Enabled" Foreground="White" Margin="0,5"/>
</StackPanel>
</GroupBox>
<!-- Key Bindings -->
<GroupBox Grid.Row="1" Grid.ColumnSpan="2" Header="Key Bindings (Virtual Key Codes)" Foreground="White" Margin="5" BorderBrush="#444">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Next Set:" Foreground="White" Margin="0,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="NextSetKeyTextBox" Margin="0,5" Width="80" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Previous Set:" Foreground="White" Margin="20,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="3" x:Name="PrevSetKeyTextBox" Margin="0,5" Width="80" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Refresh:" Foreground="White" Margin="0,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="RefreshKeyTextBox" Margin="0,5" Width="80" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Grid.Row="1" Grid.Column="2" Text="Switch Side:" Foreground="White" Margin="20,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="3" x:Name="SwitchSideKeyTextBox" Margin="0,5" Width="80" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
</Grid>
</GroupBox>
<!-- Jitter Settings -->
<GroupBox Grid.Row="2" Grid.ColumnSpan="2" Header="Jitter Settings" Foreground="White" Margin="5" BorderBrush="#444">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Burst Time (ms):" Foreground="White" Margin="0,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="JitterBurstTimeTextBox" Margin="0,5" Width="80" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Cooldown (ms):" Foreground="White" Margin="20,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="3" x:Name="JitterCooldownTextBox" Margin="0,5" Width="80" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
</Grid>
</GroupBox>
<!-- User & Favorites -->
<GroupBox Grid.Row="3" Grid.ColumnSpan="2" Header="User &amp; Favorites" Foreground="White" Margin="5" BorderBrush="#444">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Username:" Foreground="White" Margin="0,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="UserNameTextBox" Margin="0,5" HorizontalAlignment="Stretch" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Favorite Attackers:" Foreground="White" Margin="20,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="3" x:Name="FavoriteAttackersTextBox" Margin="0,5" HorizontalAlignment="Stretch" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Favorite Defenders:" Foreground="White" Margin="0,5,10,5" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="FavoriteDefendersTextBox" Margin="0,5" HorizontalAlignment="Stretch" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
</Grid>
</GroupBox>
<!-- Console Settings -->
<GroupBox Grid.Row="4" Grid.Column="0" Header="Console Settings" Foreground="White" Margin="5" BorderBrush="#444">
<StackPanel Margin="10">
<TextBlock Text="Text Color:" Foreground="White" Margin="0,5"/>
<ComboBox x:Name="TextColorComboBox" Width="120" HorizontalAlignment="Left" Background="#2D2D2D" Foreground="Black" BorderBrush="#444">
<ComboBoxItem Content="White"/>
<ComboBoxItem Content="Magenta"/>
<ComboBoxItem Content="Cyan"/>
<ComboBoxItem Content="Green"/>
<ComboBoxItem Content="Yellow"/>
<ComboBoxItem Content="Red"/>
<ComboBoxItem Content="Blue"/>
<ComboBoxItem Content="Gray"/>
</ComboBox>
</StackPanel>
</GroupBox>
<!-- Action Buttons -->
<GroupBox Grid.Row="4" Grid.Column="1" Header="Actions" Foreground="White" Margin="5" BorderBrush="#444">
<StackPanel Margin="10">
<Button x:Name="SaveSettingsButton" Content="Save Settings" Click="SaveSettings_Click" Margin="0,5" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<Button x:Name="ReloadSettingsButton" Content="Reload Settings" Click="ReloadSettings_Click" Margin="0,5" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
<Button x:Name="ResetSettingsButton" Content="Reset to Defaults" Click="ResetSettings_Click" Margin="0,5" Background="#2D2D2D" Foreground="White" BorderBrush="#444"/>
</StackPanel>
</GroupBox>
<!-- Key Code Reference -->
<GroupBox Grid.Row="5" Grid.ColumnSpan="2" Header="Common Virtual Key Codes" Foreground="White" Margin="5" BorderBrush="#444">
<ScrollViewer MaxHeight="120" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="KeyCodeReferenceText" Foreground="LightGray" FontFamily="Consolas" FontSize="10" Margin="10" TextWrapping="Wrap">
0x01: Left Mouse, 0x02: Right Mouse, 0x04: Middle Mouse
0x05: XButton1, 0x06: XButton2
0x20: Space, 0x25: Left, 0x26: Up, 0x27: Right, 0x28: Down
0x30-0x39: 0-9, 0x41-0x5A: A-Z
0x70-0x87: F1-F24
Full list: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
</TextBlock>
</ScrollViewer>
</GroupBox>
<!-- Status -->
<Border Grid.Row="6" Grid.ColumnSpan="2" Background="#2D2D2D" Margin="5" BorderBrush="#444" BorderThickness="1">
<TextBlock x:Name="SettingsStatusText" Foreground="Lime" FontFamily="Consolas" FontSize="11" Margin="10,5" Text="Settings loaded successfully" TextWrapping="Wrap"/>
</Border>
</Grid>
</ScrollViewer>
</TabItem>
</TabControl> </TabControl>
</Grid> </Grid>
</Grid> </Grid>
+238 -118
View File
@@ -6,165 +6,255 @@ using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media;
namespace Lithium namespace Lithium
{ {
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
private bool customSetEnabled = false; private bool customSetEnabled = false;
private bool nextSetHeld, prevSetHeld, refreshHeld, switchSideHeld, capsHeld;
private bool recoilEnabled = true; private bool recoilEnabled = true;
private DateTime nextSetAllowed = DateTime.MinValue; private DateTime nextSetAllowed = DateTime.MinValue;
private DateTime prevSetAllowed = DateTime.MinValue; private DateTime prevSetAllowed = DateTime.MinValue;
private double remX = 0, remY = 0;
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
AppendConsole($"Initializing Lithium..."); AppendConsole("Initializing Lithium...");
ConfigLoader.LoadInitConfig(); ConfigLoader.LoadInitConfig();
OperatorSets.LoadOperatorSets(); OperatorSets.LoadOperatorSets();
AppendConsole($"Loaded Operators | Current Set: {OperatorSets.CurrentSet} | Side: {(OperatorSets.onAttackers ? "Attackers" : "Defenders")}");
AppendConsole(
$"Loaded Operators | Current Set: {OperatorSets.CurrentSet} | Side: {(OperatorSets.onAttackers ? "Attackers" : "Defenders")}"
);
Browser.Source = !string.IsNullOrEmpty(OperatorSets.ConfigExportUrl) Browser.Source = !string.IsNullOrEmpty(OperatorSets.ConfigExportUrl)
? new Uri(OperatorSets.ConfigExportUrl) ? new Uri(OperatorSets.ConfigExportUrl)
: new Uri("https://jj.giggity.gay/exindex.html"); : new Uri("https://jj.giggity.gay/exindex.html");
// Load settings into UI
LoadSettingsToUI();
StartThread(HotkeyLoop); StartThread(HotkeyLoop);
StartThread(RecoilLoop); StartThread(RecoilLoop);
} }
private void StartThread(ThreadStart action) private void StartThread(ThreadStart action)
{ {
var thread = new Thread(action) { IsBackground = true }; var t = new Thread(action)
thread.Start(); {
IsBackground = true
};
t.Start();
} }
// ============================================================ private void RecoilLoop() => RecoilEngine.Start();
// RECOIL ENGINE (fractional X/Y tracking for precise Ricoh-style movement)
// ============================================================
private void RecoilLoop()
{
const int RIGHT_MOUSE = 0x02;
while (true) private void HotkeyLoop() => HotkeyHandler.Start(this);
// ============================================================
// SETTINGS MANAGEMENT
// ============================================================
private void LoadSettingsToUI()
{
try
{ {
if (!recoilEnabled) // Basic settings
DebitFlagCheckBox.IsChecked = ConfigLoader.debitFlag1;
BetaTestCheckBox.IsChecked = ConfigLoader.betaTest;
TtsEnabledCheckBox.IsChecked = ConfigLoader.ttsEnabled;
JitterEnabledCheckBox.IsChecked = ConfigLoader.jitterEnabled;
// Key bindings
NextSetKeyTextBox.Text = $"0x{ConfigLoader.nextSetKey:X2}";
PrevSetKeyTextBox.Text = $"0x{ConfigLoader.prevSetKey:X2}";
RefreshKeyTextBox.Text = $"0x{ConfigLoader.refreshKey:X2}";
SwitchSideKeyTextBox.Text = $"0x{ConfigLoader.switchSideKey:X2}";
// Jitter settings
JitterBurstTimeTextBox.Text = ConfigLoader.jitterBurstTime.ToString();
JitterCooldownTextBox.Text = ConfigLoader.jitterCooldown.ToString();
// User & favorites
UserNameTextBox.Text = ConfigLoader.userName ?? "";
FavoriteAttackersTextBox.Text = ConfigLoader.favoriteAttackers ?? "";
FavoriteDefendersTextBox.Text = ConfigLoader.favoriteDefenders ?? "";
// Console color
foreach (ComboBoxItem item in TextColorComboBox.Items)
{ {
Thread.Sleep(1); if (item.Content.ToString() == ConfigLoader.textColor.ToString())
continue; {
TextColorComboBox.SelectedItem = item;
break;
}
} }
if (Utils.IsPressed(ConfigLoader.shootKey) && Utils.IsPressed(RIGHT_MOUSE)) SettingsStatusText.Text = "Settings loaded successfully";
{ SettingsStatusText.Foreground = new SolidColorBrush(Colors.Lime);
var recoil = OperatorSets.GetCurrentRecoil();
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);
} }
catch (Exception ex)
{
SettingsStatusText.Text = $"Error loading settings: {ex.Message}";
SettingsStatusText.Foreground = new SolidColorBrush(Colors.Red);
}
}
private void SaveSettings_Click(object sender, RoutedEventArgs e)
{
try
{
string configContent = GenerateConfigContent();
File.WriteAllText("init.config", configContent);
// Reload configuration
ConfigLoader.LoadInitConfig();
LoadSettingsToUI();
SettingsStatusText.Text = "Settings saved and reloaded successfully!";
SettingsStatusText.Foreground = new SolidColorBrush(Colors.Lime);
AppendConsole("Settings updated from UI");
}
catch (Exception ex)
{
SettingsStatusText.Text = $"Error saving settings: {ex.Message}";
SettingsStatusText.Foreground = new SolidColorBrush(Colors.Red);
}
}
private void ReloadSettings_Click(object sender, RoutedEventArgs e)
{
ConfigLoader.LoadInitConfig();
LoadSettingsToUI();
SettingsStatusText.Text = "Settings reloaded from file";
SettingsStatusText.Foreground = new SolidColorBrush(Colors.Lime);
AppendConsole("Settings reloaded from init.config");
}
private void ResetSettings_Click(object sender, RoutedEventArgs e)
{
// Reset to defaults
ConfigLoader.debitFlag1 = false;
ConfigLoader.betaTest = false;
ConfigLoader.ttsEnabled = true;
ConfigLoader.jitterEnabled = false;
ConfigLoader.nextSetKey = 0x05;
ConfigLoader.prevSetKey = 0x06;
ConfigLoader.refreshKey = 0x50;
ConfigLoader.switchSideKey = 0x4D;
ConfigLoader.jitterBurstTime = 1800;
ConfigLoader.jitterCooldown = 3000;
ConfigLoader.userName = null;
ConfigLoader.favoriteAttackers = null;
ConfigLoader.favoriteDefenders = null;
ConfigLoader.textColor = System.ConsoleColor.Magenta;
LoadSettingsToUI();
SettingsStatusText.Text = "Settings reset to defaults (save to apply)";
SettingsStatusText.Foreground = new SolidColorBrush(Colors.Yellow);
}
private string GenerateConfigContent()
{
return $@"-- Lithium Configuration File
-- Generated from UI on {DateTime.Now}
-- Basic Settings
debitFlag1 = {DebitFlagCheckBox.IsChecked.ToString().ToLower()}
betaTest = {BetaTestCheckBox.IsChecked.ToString().ToLower()}
ttsEnabled = {TtsEnabledCheckBox.IsChecked.ToString().ToLower()}
jitterEnabled = {JitterEnabledCheckBox.IsChecked.ToString().ToLower()}
-- Key Bindings (Virtual Key Codes)
nextSetKey = {ParseKeyCode(NextSetKeyTextBox.Text)}
prevSetKey = {ParseKeyCode(PrevSetKeyTextBox.Text)}
refreshKey = {ParseKeyCode(RefreshKeyTextBox.Text)}
switchSideKey = {ParseKeyCode(SwitchSideKeyTextBox.Text)}
-- Jitter Settings
jitterBurstTime = {int.Parse(JitterBurstTimeTextBox.Text)}
jitterCooldown = {int.Parse(JitterCooldownTextBox.Text)}
-- User & Favorites
userName = ""{UserNameTextBox.Text}""
favoriteAttackers = ""{FavoriteAttackersTextBox.Text}""
favoriteDefenders = ""{FavoriteDefendersTextBox.Text}""
-- Console Settings
textColor = {((ComboBoxItem)TextColorComboBox.SelectedItem)?.Content.ToString() ?? "Magenta"}";
}
private int ParseKeyCode(string text)
{
if (text.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
return Convert.ToInt32(text, 16);
}
return int.Parse(text);
} }
// ============================================================ // ============================================================
// HOTKEY LOOP // HANDLERS CALLED BY HOTKEYHANDLER
// ============================================================ // ============================================================
private void HotkeyLoop() public void SetRecoilEnabled(bool enabled)
{ {
const int CAPSLOCK = 0x14; recoilEnabled = enabled;
AppendConsole(enabled ? "Recoil Enabled" : "Recoil Disabled");
while (true)
{
HandleToggleCapsLock(CAPSLOCK);
HandleNextSet();
HandlePrevSet();
HandleRefresh();
HandleSwitchSide();
Thread.Sleep(8);
}
} }
private void HandleToggleCapsLock(int capsKey) public bool IsRecoilEnabled => recoilEnabled;
public void HandleNextSet()
{ {
bool capsDown = Utils.IsPressed(capsKey); if (DateTime.Now < nextSetAllowed) return;
if (capsDown && !capsHeld)
{ nextSetAllowed = DateTime.Now.AddMilliseconds(200);
capsHeld = true; OperatorSets.NextSet();
recoilEnabled = !recoilEnabled;
AppendConsole(recoilEnabled ? "Recoil Enabled" : "Recoil Disabled"); AppendConsole($"Next Set → {OperatorSets.CurrentSet}");
} Utils.SafeSpeak(OperatorSets.CurrentSet);
if (!capsDown) capsHeld = false;
} }
private void HandleNextSet() public void HandlePrevSet()
{ {
if (Utils.IsPressed(ConfigLoader.nextSetKey) && !nextSetHeld && DateTime.Now >= nextSetAllowed) if (DateTime.Now < prevSetAllowed) return;
{
nextSetHeld = true; prevSetAllowed = DateTime.Now.AddMilliseconds(200);
nextSetAllowed = DateTime.Now.AddMilliseconds(200); OperatorSets.PreviousSet();
OperatorSets.NextSet();
// Only announce operator, no side AppendConsole($"Previous Set → {OperatorSets.CurrentSet}");
AppendConsole($"Next Set → {OperatorSets.CurrentSet}"); Utils.SafeSpeak(OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
else if (!Utils.IsPressed(ConfigLoader.nextSetKey)) nextSetHeld = false;
} }
private void HandlePrevSet() public void HandleRefresh()
{ {
if (Utils.IsPressed(ConfigLoader.prevSetKey) && !prevSetHeld && DateTime.Now >= prevSetAllowed) string oldSet = OperatorSets.CurrentSet;
{ bool oldSide = OperatorSets.onAttackers;
prevSetHeld = true;
prevSetAllowed = DateTime.Now.AddMilliseconds(200); OperatorSets.LoadOperatorSets();
OperatorSets.PreviousSet();
// Only announce operator, no side OperatorSets.SetCurrentSet(oldSet);
AppendConsole($"Previous Set → {OperatorSets.CurrentSet}"); OperatorSets.onAttackers = oldSide;
Utils.SafeSpeak(OperatorSets.CurrentSet);
} AppendConsole(
else if (!Utils.IsPressed(ConfigLoader.prevSetKey)) prevSetHeld = false; $"Reloaded config | Current Set: {OperatorSets.CurrentSet} | Side: {(OperatorSets.onAttackers ? "Attackers" : "Defenders")}"
);
Utils.SafeSpeak(OperatorSets.CurrentSet);
} }
private void HandleRefresh() public void HandleSwitchSide()
{ {
if (Utils.IsPressed(ConfigLoader.refreshKey) && !refreshHeld) OperatorSets.SwitchSide();
{
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() AppendConsole($"Switched side → {(OperatorSets.onAttackers ? "Attackers" : "Defenders")} | Current Set: {OperatorSets.CurrentSet}");
{ Utils.SafeSpeak(OperatorSets.CurrentSet);
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 // UI CONSOLE
// ============================================================ // ============================================================
@@ -174,6 +264,7 @@ namespace Lithium
{ {
ConsoleOutput.Text += msg + Environment.NewLine; ConsoleOutput.Text += msg + Environment.NewLine;
ConsoleScroll.ScrollToBottom(); ConsoleScroll.ScrollToBottom();
Utils.AutoClearIfNearBottom();
}); });
} }
@@ -202,25 +293,40 @@ namespace Lithium
double.TryParse(RecoilXTextBox.Text, out double x); double.TryParse(RecoilXTextBox.Text, out double x);
double.TryParse(RecoilYTextBox.Text, out double y); double.TryParse(RecoilYTextBox.Text, out double y);
string type = AttackerRadioButton.IsChecked == true ? "attackers" : "defenders"; 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 try
{ {
using HttpClient client = new HttpClient(); using HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(payload); string json = JsonSerializer.Serialize(payload);
var response = await client.PostAsync("https://jj.giggity.gay/api/global/add",
new StringContent(json, Encoding.UTF8, "application/json")); var response = await client.PostAsync(
"https://jj.giggity.gay/api/global/add",
new StringContent(json, Encoding.UTF8, "application/json")
);
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
UpdateCustomSetConsole($"Successfully published: {name} ({type}) X:{x} Y:{y}"); {
UpdateCustomSetConsole($"Published: {name} ({type}) X:{x} Y:{y}");
}
else else
UpdateCustomSetConsole($"Failed: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}"); {
string body = await response.Content.ReadAsStringAsync();
UpdateCustomSetConsole($"HTTP Error {response.StatusCode}: {body}");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
UpdateCustomSetConsole("Error publishing set: " + ex.Message); UpdateCustomSetConsole("Error: " + ex.Message);
} }
} }
@@ -228,11 +334,17 @@ namespace Lithium
{ {
try try
{ {
File.WriteAllText("custom_set.txt", File.WriteAllText(
$"{OperatorNameTextBox.Text}|{RecoilXTextBox.Text}|{RecoilYTextBox.Text}|{(AttackerRadioButton.IsChecked == true ? "attacker" : "defender")}"); "custom_set.txt",
$"{OperatorNameTextBox.Text}|{RecoilXTextBox.Text}|{RecoilYTextBox.Text}|{(AttackerRadioButton.IsChecked == true ? "attacker" : "defender")}"
);
UpdateCustomSetConsole("Custom set saved"); 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) private void LoadSet_Click(object sender, RoutedEventArgs e)
@@ -246,11 +358,13 @@ namespace Lithium
} }
string[] parts = File.ReadAllText("custom_set.txt").Split('|'); string[] parts = File.ReadAllText("custom_set.txt").Split('|');
if (parts.Length != 4) throw new Exception("Invalid file"); if (parts.Length != 4)
throw new Exception("Invalid file");
OperatorNameTextBox.Text = parts[0]; OperatorNameTextBox.Text = parts[0];
RecoilXTextBox.Text = parts[1]; RecoilXTextBox.Text = parts[1];
RecoilYTextBox.Text = parts[2]; RecoilYTextBox.Text = parts[2];
if (parts[3].Equals("attacker", StringComparison.OrdinalIgnoreCase)) if (parts[3].Equals("attacker", StringComparison.OrdinalIgnoreCase))
AttackerRadioButton.IsChecked = true; AttackerRadioButton.IsChecked = true;
else else
@@ -258,20 +372,26 @@ namespace Lithium
UpdateCustomSetConsole("Custom set loaded"); UpdateCustomSetConsole("Custom set loaded");
} }
catch { UpdateCustomSetConsole("Failed to load custom set"); } catch
{
UpdateCustomSetConsole("Failed to load custom set");
}
} }
// ============================================================
// WINDOW CONTROLS
// ============================================================
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e) private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{ {
if (e.ChangedButton == MouseButton.Left) DragMove(); if (e.ChangedButton == MouseButton.Left)
DragMove();
} }
private void Minimize_Click(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized; private void Minimize_Click(object sender, RoutedEventArgs e) =>
WindowState = WindowState.Minimized;
private void MaximizeRestore_Click(object sender, RoutedEventArgs e) private void MaximizeRestore_Click(object sender, RoutedEventArgs e) =>
{
WindowState = WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; WindowState = WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal;
}
private void Close_Click(object sender, RoutedEventArgs e) => Close(); private void Close_Click(object sender, RoutedEventArgs e) => Close();
} }
+104
View File
@@ -0,0 +1,104 @@
using System;
using System.Threading;
namespace Lua
{
internal static class RecoilEngine
{
private const int VK_LBUTTON = 0x01;
private const int VK_RBUTTON = 0x02;
private static Random rng = new Random();
private static bool jitterActive = false;
private static int jitterStart = 0;
private static int lastJitterEnd = 0;
private static double remX, remY;
private static double jitterMultX, jitterMultY;
public static void Start()
{
while (true)
{
if (Utils.IsCapsLockOn() && Utils.IsPressed(VK_RBUTTON))
{
HandleRecoilTick();
}
else
{
remX = remY = 0;
jitterActive = false;
}
Thread.Sleep(2);
}
}
private static void HandleRecoilTick()
{
if (!Utils.IsPressed(VK_LBUTTON))
return;
string setName = OperatorSets.CurrentSet;
if (!OperatorSets.mergedSets.TryGetValue(setName, out var recoil))
return;
int now = Environment.TickCount;
HandleJitter(now);
ApplyRecoil(recoil, now);
}
private static void HandleJitter(int now)
{
if (ConfigLoader.jitterEnabled)
{
if (!jitterActive && now - lastJitterEnd >= ConfigLoader.jitterCooldown)
{
jitterActive = true;
jitterStart = now;
double strength = 0.1 + rng.NextDouble() * 0.8;
jitterMultX = jitterMultY = 0;
switch (rng.Next(1, 5))
{
case 1: jitterMultX = -strength; break;
case 2: jitterMultX = strength; break;
case 3: jitterMultY = -strength; break;
case 4: jitterMultY = strength; break;
}
}
if (jitterActive && now - jitterStart >= ConfigLoader.jitterBurstTime)
{
jitterActive = false;
lastJitterEnd = now;
jitterMultX = jitterMultY = 0;
}
}
}
private static void ApplyRecoil((double recoilX, double recoilY) recoil, int now)
{
double jitterX = recoil.recoilX * jitterMultX;
double jitterY = recoil.recoilY * jitterMultY;
double moveX = recoil.recoilX + remX + jitterX;
double moveY = recoil.recoilY + remY + jitterY;
if (ConfigLoader.debitFlag1)
{
moveX *= 1.282;
moveY *= 1.351;
}
int ix = (int)Math.Round(moveX);
int iy = (int)Math.Round(moveY);
remX = moveX - ix;
remY = moveY - iy;
Utils.MoveMouse(ix, iy);
}
}
}
+4 -8
View File
@@ -1,5 +1,4 @@
// Utils.cs (patched) using System;
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Speech.Synthesis; using System.Speech.Synthesis;
using System.Threading; using System.Threading;
@@ -16,8 +15,8 @@ namespace Lua
[DllImport("user32.dll")] public static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, UIntPtr dwExtraInfo); [DllImport("user32.dll")] public static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, UIntPtr dwExtraInfo);
public const uint MOUSEEVENTF_MOVE = 0x0001; public const uint MOUSEEVENTF_MOVE = 0x0001;
const int VK_CAPITAL = 0x14; private const int VK_CAPITAL = 0x14;
static bool previousCapsState; private static bool previousCapsState;
public static void InitializeCapsState() public static void InitializeCapsState()
{ {
@@ -73,15 +72,12 @@ namespace Lua
: $"🚀 Standard Mode Enabled | Current Set: {OperatorSets.CurrentSet}"; : $"🚀 Standard Mode Enabled | Current Set: {OperatorSets.CurrentSet}";
} }
// -----------------------------------------------------
// NEW: Auto console clear when near bottom
// -----------------------------------------------------
public static void AutoClearIfNearBottom() public static void AutoClearIfNearBottom()
{ {
try try
{ {
int current = Console.CursorTop; int current = Console.CursorTop;
int limit = Console.WindowHeight - 2; // keep 2-row buffer int limit = Console.WindowHeight - 2;
if (current >= limit) if (current >= limit)
{ {