Update 0.01 D
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,9 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="HotkeyHandler.cs" />
|
||||
<Compile Include="RecoilControl.cs" />
|
||||
<Compile Include="RecoilEngine.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -149,7 +151,6 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="AppDomain.AssemblyResolve" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
|
||||
+164
-9
@@ -2,7 +2,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
Title="Lithium" Height="650" Width="1000"
|
||||
Background="#1E1E1E"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True">
|
||||
@@ -110,6 +110,8 @@
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
|
||||
|
||||
<!-- Website Tab -->
|
||||
<TabItem Header="Website">
|
||||
<Grid Background="#252525">
|
||||
@@ -130,34 +132,187 @@
|
||||
<!-- Operator Details -->
|
||||
<StackPanel Grid.Row="0" Margin="20" VerticalAlignment="Top">
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5">
|
||||
<RadioButton x:Name="AttackerRadioButton" Content="Attacker" IsChecked="True" Margin="0,0,10,0"/>
|
||||
<RadioButton x:Name="DefenderRadioButton" Content="Defender"/>
|
||||
<RadioButton x:Name="AttackerRadioButton" Content="Attacker" IsChecked="True" Margin="0,0,10,0" Foreground="White"/>
|
||||
<RadioButton x:Name="DefenderRadioButton" Content="Defender" Foreground="White"/>
|
||||
</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>
|
||||
|
||||
<!-- Console & Publish -->
|
||||
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="20">
|
||||
<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>
|
||||
<TextBlock x:Name="CustomSetConsole" Foreground="Lime" FontFamily="Consolas" FontSize="12" Text="Set is OFF" Margin="0,5"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</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 & 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>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</Window>
|
||||
+239
-119
@@ -6,165 +6,255 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Lithium
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private bool customSetEnabled = false;
|
||||
private bool nextSetHeld, prevSetHeld, refreshHeld, switchSideHeld, capsHeld;
|
||||
private bool recoilEnabled = true;
|
||||
|
||||
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} | Side: {(OperatorSets.onAttackers ? "Attackers" : "Defenders")}"
|
||||
);
|
||||
|
||||
Browser.Source = !string.IsNullOrEmpty(OperatorSets.ConfigExportUrl)
|
||||
? new Uri(OperatorSets.ConfigExportUrl)
|
||||
: new Uri("https://jj.giggity.gay/exindex.html");
|
||||
|
||||
// Load settings into UI
|
||||
LoadSettingsToUI();
|
||||
|
||||
StartThread(HotkeyLoop);
|
||||
StartThread(RecoilLoop);
|
||||
}
|
||||
|
||||
private void StartThread(ThreadStart action)
|
||||
{
|
||||
var thread = new Thread(action) { IsBackground = true };
|
||||
thread.Start();
|
||||
var t = new Thread(action)
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
t.Start();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// RECOIL ENGINE (fractional X/Y tracking for precise Ricoh-style movement)
|
||||
// ============================================================
|
||||
private void RecoilLoop()
|
||||
{
|
||||
const int RIGHT_MOUSE = 0x02;
|
||||
private void RecoilLoop() => RecoilEngine.Start();
|
||||
|
||||
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);
|
||||
continue;
|
||||
if (item.Content.ToString() == ConfigLoader.textColor.ToString())
|
||||
{
|
||||
TextColorComboBox.SelectedItem = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Utils.IsPressed(ConfigLoader.shootKey) && Utils.IsPressed(RIGHT_MOUSE))
|
||||
{
|
||||
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);
|
||||
SettingsStatusText.Text = "Settings loaded successfully";
|
||||
SettingsStatusText.Foreground = new SolidColorBrush(Colors.Lime);
|
||||
}
|
||||
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;
|
||||
|
||||
while (true)
|
||||
{
|
||||
HandleToggleCapsLock(CAPSLOCK);
|
||||
HandleNextSet();
|
||||
HandlePrevSet();
|
||||
HandleRefresh();
|
||||
HandleSwitchSide();
|
||||
Thread.Sleep(8);
|
||||
}
|
||||
recoilEnabled = enabled;
|
||||
AppendConsole(enabled ? "Recoil Enabled" : "Recoil Disabled");
|
||||
}
|
||||
|
||||
private void HandleToggleCapsLock(int capsKey)
|
||||
public bool IsRecoilEnabled => recoilEnabled;
|
||||
|
||||
public void HandleNextSet()
|
||||
{
|
||||
bool capsDown = Utils.IsPressed(capsKey);
|
||||
if (capsDown && !capsHeld)
|
||||
{
|
||||
capsHeld = true;
|
||||
recoilEnabled = !recoilEnabled;
|
||||
AppendConsole(recoilEnabled ? "Recoil Enabled" : "Recoil Disabled");
|
||||
}
|
||||
if (!capsDown) capsHeld = false;
|
||||
if (DateTime.Now < nextSetAllowed) return;
|
||||
|
||||
nextSetAllowed = DateTime.Now.AddMilliseconds(200);
|
||||
OperatorSets.NextSet();
|
||||
|
||||
AppendConsole($"Next Set → {OperatorSets.CurrentSet}");
|
||||
Utils.SafeSpeak(OperatorSets.CurrentSet);
|
||||
}
|
||||
|
||||
private void HandleNextSet()
|
||||
public void HandlePrevSet()
|
||||
{
|
||||
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;
|
||||
if (DateTime.Now < prevSetAllowed) return;
|
||||
|
||||
prevSetAllowed = DateTime.Now.AddMilliseconds(200);
|
||||
OperatorSets.PreviousSet();
|
||||
|
||||
AppendConsole($"Previous Set → {OperatorSets.CurrentSet}");
|
||||
Utils.SafeSpeak(OperatorSets.CurrentSet);
|
||||
}
|
||||
|
||||
private void HandlePrevSet()
|
||||
public void HandleRefresh()
|
||||
{
|
||||
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;
|
||||
string oldSet = OperatorSets.CurrentSet;
|
||||
bool oldSide = OperatorSets.onAttackers;
|
||||
|
||||
OperatorSets.LoadOperatorSets();
|
||||
|
||||
OperatorSets.SetCurrentSet(oldSet);
|
||||
OperatorSets.onAttackers = oldSide;
|
||||
|
||||
AppendConsole(
|
||||
$"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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
OperatorSets.SwitchSide();
|
||||
|
||||
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;
|
||||
AppendConsole($"Switched side → {(OperatorSets.onAttackers ? "Attackers" : "Defenders")} | Current Set: {OperatorSets.CurrentSet}");
|
||||
Utils.SafeSpeak(OperatorSets.CurrentSet);
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// UI CONSOLE
|
||||
// ============================================================
|
||||
@@ -174,6 +264,7 @@ namespace Lithium
|
||||
{
|
||||
ConsoleOutput.Text += msg + Environment.NewLine;
|
||||
ConsoleScroll.ScrollToBottom();
|
||||
Utils.AutoClearIfNearBottom();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -202,25 +293,40 @@ namespace Lithium
|
||||
|
||||
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
|
||||
{
|
||||
using HttpClient client = new HttpClient();
|
||||
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)
|
||||
UpdateCustomSetConsole($"Successfully published: {name} ({type}) X:{x} Y:{y}");
|
||||
{
|
||||
UpdateCustomSetConsole($"Published: {name} ({type}) X:{x} Y:{y}");
|
||||
}
|
||||
else
|
||||
UpdateCustomSetConsole($"Failed: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}");
|
||||
{
|
||||
string body = await response.Content.ReadAsStringAsync();
|
||||
UpdateCustomSetConsole($"HTTP Error {response.StatusCode}: {body}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateCustomSetConsole("Error publishing set: " + ex.Message);
|
||||
UpdateCustomSetConsole("Error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,11 +334,17 @@ namespace Lithium
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText("custom_set.txt",
|
||||
$"{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 { UpdateCustomSetConsole("Failed to save custom set"); }
|
||||
catch
|
||||
{
|
||||
UpdateCustomSetConsole("Failed to save custom set");
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadSet_Click(object sender, RoutedEventArgs e)
|
||||
@@ -246,11 +358,13 @@ namespace Lithium
|
||||
}
|
||||
|
||||
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];
|
||||
RecoilXTextBox.Text = parts[1];
|
||||
RecoilYTextBox.Text = parts[2];
|
||||
|
||||
if (parts[3].Equals("attacker", StringComparison.OrdinalIgnoreCase))
|
||||
AttackerRadioButton.IsChecked = true;
|
||||
else
|
||||
@@ -258,21 +372,27 @@ namespace Lithium
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
private void Close_Click(object sender, RoutedEventArgs e) => Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -1,5 +1,4 @@
|
||||
// Utils.cs (patched)
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Speech.Synthesis;
|
||||
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);
|
||||
public const uint MOUSEEVENTF_MOVE = 0x0001;
|
||||
|
||||
const int VK_CAPITAL = 0x14;
|
||||
static bool previousCapsState;
|
||||
private const int VK_CAPITAL = 0x14;
|
||||
private static bool previousCapsState;
|
||||
|
||||
public static void InitializeCapsState()
|
||||
{
|
||||
@@ -73,15 +72,12 @@ namespace Lua
|
||||
: $"🚀 Standard Mode Enabled | Current Set: {OperatorSets.CurrentSet}";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// NEW: Auto console clear when near bottom
|
||||
// -----------------------------------------------------
|
||||
public static void AutoClearIfNearBottom()
|
||||
{
|
||||
try
|
||||
{
|
||||
int current = Console.CursorTop;
|
||||
int limit = Console.WindowHeight - 2; // keep 2-row buffer
|
||||
int limit = Console.WindowHeight - 2;
|
||||
|
||||
if (current >= limit)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user