├── .github
├── FUNDING.yml
└── README.md
├── .gitignore
├── .vscode
├── extensions.json
└── settings.json
├── Cargo.toml
├── LICENSE
├── assets
├── favicon.ico
├── header.png
└── icon.png
├── build
└── main.rs
├── rustfmt.toml
└── src
├── app.rs
├── gui.rs
└── main.rs
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: lencydev
--------------------------------------------------------------------------------
/.github/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |

5 |

6 |

7 |

8 |

9 |
10 |

11 |
12 |
13 | ## Features
14 | - **Color Detection:** Automatically fires when the configured enemy highlight color is detected in the trigger area.
15 | - **Customizable Trigger Area:** Define the size of the detection area at the center of your screen.
16 | - **Adjustable Trigger Delay:** Set a delay (in milliseconds) before firing after color detection.
17 | - **Configurable Trigger Keys:** Choose specific keyboard keys or mouse buttons to activate the triggerbot (hold mode).
18 | - **Color Tolerance:** Adjust the sensitivity of color detection to account for variations in lighting or effects.
19 | - **Resolution Setting:** Configure the application based on your in-game screen resolution.
20 | - **Simple GUI:** Easy-to-use interface for managing settings.
21 |
22 | # Usage
23 | 1. Download the latest release from the [releases](https://github.com/lencydev/valorant-triggerbot/releases) page.
24 | 2. Run the `valorant-triggerbot.exe` file.
25 | 3. Configure the settings in the application to match your preferences and in-game settings.
26 | 4. Click the `Enable` button to activate the triggerbot.
27 |
28 | ## Configuration
29 | Use the application's graphical interface to adjust the following settings:
30 |
31 | - **Resolution:** Set this to match your Valorant game resolution (e.g. 1920x1080).
32 | - **Trigger Keys:** Select the keys/buttons you want to hold to activate the triggerbot (only active if `Always Open` is off).
33 | - **Trigger Delay:** The time in milliseconds the bot waits after detecting the color before firing. Increase if it fires too early, decrease if too late.
34 | - **Trigger Area:** The size (in pixels) of the square area in the center of the screen where the bot looks for the target color.
35 | - **Target Color:** The RGB values of the enemy highlight color. Default is Purple (R 240 G 90 B 255).
36 | - **Color Tolerance:** How much variation from the Target Color is allowed. Higher values are more lenient but might cause false positives. Lower values are stricter.
37 |
38 | ### Valorant Settings
39 | These are the in-game settings required for the triggerbot to work correctly:
40 | - `General > Accessibility > Enemy Highlight Color:` Select `Purple` (or match the Target Color configured in the bot).
41 | - `Controls > Equipment > Weapons > Fire:` Set the secondary keybind to `K` (the bot simulates pressing `K`).
42 |
43 | ### Default Settings
44 | These are the default and recommended starting settings.
45 | Adjust them based on your needs.
46 | - `Resolution:` 1920x1080
47 | - `Trigger Keys:` Left Shift
48 | - `Trigger Delay:` 50ms
49 | - `Trigger Area:` 5.0
50 | - `Target Color:` Purple (R 240 G 90 B 255)
51 | - `Color Tolerance:` 50
52 |
53 | # Building from Source
54 | If you prefer to build the application yourself, follow these steps:
55 |
56 | 1. Ensure you have [Rust](https://www.rust-lang.org/tools/install) installed on your system.
57 | 2. Clone the repository:
58 |
59 | ```bash
60 | git clone https://github.com/lencydev/valorant-triggerbot.git
61 | cd valorant-triggerbot
62 | ```
63 | 3. Build the project:
64 |
65 | ```bash
66 | cargo build --release
67 | ```
68 | 4. After the compilation:
69 | - Navigate to the `target/release` directory.
70 | - Find the `valorant-triggerbot.exe` file.
71 | - Run the executable to start the application.
72 |
73 | # Disclaimer
74 | > [!WARNING]
75 | > Using third-party applications that interact with the game, like this triggerbot,
76 | > is against Riot Games' Terms of Service and can lead to account suspension or permanent ban.
77 | > Use this software entirely at your own risk.
78 |
79 | - While efforts may be made to avoid detection, anti-cheat systems like Vanguard are constantly updated, and detection is always a possibility.
80 | - The author is not responsible for any bans or other consequences resulting from the use of this software.
81 |
82 | # Support
83 | If you encounter issues or have questions, you can:
84 | - Check the [Troubleshooting](#troubleshooting) and [FAQ](#faq) sections below.
85 | - Message me on [discord](https://discord.com/users/313738210729656332).
86 |
87 | ## Troubleshooting
88 | - **Triggerbot not firing:**
89 | - Ensure Valorant's `Enemy Highlight Color` matches the bot's `Target Color`.
90 | - Verify the secondary fire keybind in Valorant is set to `K`.
91 | - Check if the `Resolution` setting in the bot matches your game resolution.
92 | - Make sure the bot is `Enabled`.
93 | - Try increasing `Color Tolerance` slightly.
94 | - Ensure the trigger area is positioned correctly over your crosshair.
95 |
96 | ## FAQ
97 | - **Q: Is this safe to use? Will I get banned?**
98 | - **A:** Using any third-party tool that gives an unfair advantage violates Valorant's ToS and carries a high risk of banning. Use at your own discretion. See the [Disclaimer](#disclaimer).
99 | - **Q: Does it work with different enemy highlight colors?**
100 | - **A:** Yes, but you need to manually configure the correct RGB values in the `Target Color` setting within the triggerbot application.
101 | - **Q: Does it work on all screen resolutions?**
102 | - **A:** It should work if you correctly set your game's resolution in the triggerbot's `Resolution` setting.
103 | - **Q: Can I change the key the bot presses to fire?**
104 | - **A:** Currently, the bot is hardcoded to press `K`. You need to set `K` as your secondary fire keybind in Valorant. Modifying this would require changing the source code.
105 |
106 | ## How it Works
107 | The triggerbot operates on a simple principle:
108 | 1. It continuously captures a small portion of your screen defined by the `Trigger Area` setting, centered around where your crosshair typically is.
109 | 2. It analyzes the pixels within this captured area.
110 | 3. If it finds pixels matching the configured `Target Color` (within the specified `Color Tolerance`), it assumes an enemy is under the crosshair.
111 | 4. After waiting for the configured `Trigger Delay`, it simulates a key press (`K` by default) to make the game fire.
112 |
113 |
114 |
115 |
116 |

117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | Cargo.lock
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "rust-lang.rust-analyzer"
4 | ]
5 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | /**
3 | * Workbench
4 | **/
5 |
6 | "workbench.colorTheme": "One Dark Pro Night Flat",
7 | "workbench.iconTheme": "material-icon-theme",
8 |
9 | /**
10 | * Editor
11 | **/
12 |
13 | "editor.bracketPairColorization.enabled": true,
14 | "editor.codeActionsOnSave": {
15 | "source.fixAll": "always"
16 | },
17 | "editor.codeLens": true,
18 | "editor.cursorSmoothCaretAnimation": "on",
19 | "editor.defaultFormatter": "rust-lang.rust-analyzer",
20 | "editor.fontFamily": "Fira Code",
21 | "editor.fontLigatures": true,
22 | "editor.formatOnPaste": true,
23 | "editor.formatOnSave": true,
24 | "editor.formatOnSaveMode": "file",
25 | "editor.guides.bracketPairs": true,
26 | "editor.linkedEditing": true,
27 | "editor.minimap.enabled": false,
28 | "editor.quickSuggestions": {
29 | "strings": "on"
30 | },
31 | "editor.renderWhitespace": "none",
32 | "editor.smoothScrolling": true,
33 | "editor.stickyScroll.enabled": false,
34 | "editor.tabSize": 2,
35 | "editor.unicodeHighlight.includeStrings": false,
36 |
37 | /**
38 | * File Management
39 | **/
40 |
41 | "files.associations": {
42 | "*.css": "tailwindcss"
43 | },
44 | "files.autoSave": "afterDelay",
45 | "files.trimTrailingWhitespace": true,
46 |
47 | /**
48 | * Explorer
49 | **/
50 |
51 | "explorer.compactFolders": false,
52 | "explorer.decorations.badges": true,
53 | "explorer.fileNesting.enabled": true,
54 | "explorer.fileNesting.expand": false,
55 | "explorer.sortOrder": "type",
56 | "explorer.sortOrderLexicographicOptions": "lower",
57 |
58 | /**
59 | * Terminal
60 | **/
61 |
62 | "terminal.integrated.allowChords": true,
63 | "terminal.integrated.fontFamily": "Fira Code",
64 | "terminal.integrated.sendKeybindingsToShell": true,
65 | "terminal.integrated.smoothScrolling": true,
66 |
67 | /**
68 | * Git
69 | **/
70 |
71 | "git.autofetch": true,
72 | "git.confirmSync": false,
73 | "git.enableSmartCommit": true,
74 |
75 | /**
76 | * Language Specific
77 | **/
78 |
79 | "[markdown]": {
80 | "editor.wordWrap": "off"
81 | },
82 | }
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "valorant-triggerbot"
3 | version = "1.4.0"
4 | edition = "2021"
5 | build = "build/main.rs"
6 |
7 | [dependencies]
8 | screenshots = "0.8.10"
9 | device_query = "1.1.3"
10 | image = "0.24.9"
11 | winit = "0.29"
12 | eframe = "0.29.1"
13 | inputbot = "0.6"
14 | winapi = { version = "0.3.9", features = ["winuser", "windef"] }
15 | enigo = "0.1"
16 |
17 | [build-dependencies]
18 | winres = "0.1"
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 lencydev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencydev/valorant-triggerbot/160babac9c5a362daf3812787591b225c4fd41e0/assets/favicon.ico
--------------------------------------------------------------------------------
/assets/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencydev/valorant-triggerbot/160babac9c5a362daf3812787591b225c4fd41e0/assets/header.png
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencydev/valorant-triggerbot/160babac9c5a362daf3812787591b225c4fd41e0/assets/icon.png
--------------------------------------------------------------------------------
/build/main.rs:
--------------------------------------------------------------------------------
1 | use winres::WindowsResource;
2 |
3 | fn main () {
4 |
5 | if cfg!(target_os = "windows") {
6 |
7 | WindowsResource::new().set_icon("assets/favicon.ico").compile().unwrap();
8 | }
9 | }
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | tab_spaces = 2
--------------------------------------------------------------------------------
/src/app.rs:
--------------------------------------------------------------------------------
1 | use crate::gui;
2 |
3 | use device_query::{DeviceQuery, DeviceState, Keycode};
4 | use eframe::{egui::Context, App, Frame};
5 | use enigo::{Enigo, Key, KeyboardControllable};
6 | use inputbot::MouseButton;
7 | use screenshots::Screen;
8 |
9 | use std::{
10 | cmp::PartialEq,
11 | fmt::{Display, Formatter, Result},
12 | thread,
13 | time::Duration,
14 | };
15 |
16 | #[derive(PartialEq, Debug)]
17 | pub enum TriggerKey {
18 | Keyboard(Keycode),
19 | Mouse(MouseButton),
20 | }
21 |
22 | #[derive(PartialEq)]
23 | pub struct Settings {
24 | pub resolution: Resolution,
25 | pub trigger_keys: Vec,
26 | pub trigger_delay: u64,
27 | pub trigger_area: f32,
28 | pub target_color: [i32; 3],
29 | pub color_tolerance: i32,
30 | pub always_open: bool,
31 | }
32 |
33 | impl Default for Settings {
34 | fn default() -> Self {
35 | Self {
36 | resolution: Resolution {
37 | width: 1920,
38 | height: 1080,
39 | },
40 | trigger_keys: vec![TriggerKey::Keyboard(Keycode::LShift)],
41 | trigger_delay: 50,
42 | trigger_area: 5.0,
43 | target_color: [240, 90, 255],
44 | color_tolerance: 50,
45 | always_open: false,
46 | }
47 | }
48 | }
49 |
50 | #[derive(PartialEq, Clone, Copy)]
51 | pub struct Resolution {
52 | pub width: u32,
53 | pub height: u32,
54 | }
55 |
56 | pub struct TriggerArea {
57 | pub x_percent: f32,
58 | pub y_percent: f32,
59 | pub width_percent: f32,
60 | pub height_percent: f32,
61 | }
62 |
63 | pub struct Triggerbot {
64 | pub enabled: bool,
65 | pub device_state: DeviceState,
66 | pub screen: Screen,
67 | pub trigger_area: TriggerArea,
68 | pub enigo: Enigo,
69 | pub settings: Settings,
70 | }
71 |
72 | impl Triggerbot {
73 | pub fn default() -> Self {
74 | let mut triggerbot = Self {
75 | enabled: false,
76 | device_state: DeviceState::new(),
77 | screen: Screen::from_point(0, 0).unwrap(),
78 | trigger_area: TriggerArea {
79 | x_percent: 0.0,
80 | y_percent: 0.0,
81 | width_percent: 0.0,
82 | height_percent: 0.0,
83 | },
84 | enigo: Enigo::new(),
85 | settings: Settings::default(),
86 | };
87 |
88 | triggerbot.update_trigger_area();
89 |
90 | triggerbot
91 | }
92 |
93 | pub fn reset_settings(&mut self) {
94 | self.settings = Settings::default();
95 | self.update_trigger_area();
96 | }
97 |
98 | pub fn is_default_settings(&self) -> bool {
99 | self.settings == Settings::default()
100 | }
101 |
102 | pub fn set_resolution(&mut self, width: u32, height: u32) {
103 | self.settings.resolution = Resolution { width, height };
104 |
105 | self.update_trigger_area();
106 | }
107 |
108 | pub fn triggerbot(&mut self) {
109 | let keys = self.device_state.get_keys();
110 |
111 | let trigger_active = !self.settings.always_open
112 | && self
113 | .settings
114 | .trigger_keys
115 | .iter()
116 | .any(|trigger| match trigger {
117 | TriggerKey::Keyboard(key) => keys.contains(key),
118 | TriggerKey::Mouse(button) => button.is_pressed(),
119 | });
120 |
121 | if self.enabled
122 | && (trigger_active || self.settings.always_open)
123 | && self.is_target_color_present()
124 | {
125 | self.enigo.key_click(Key::Layout('k'));
126 |
127 | if self.settings.trigger_delay > 0 {
128 | thread::sleep(Duration::from_millis(self.settings.trigger_delay));
129 | }
130 | }
131 | }
132 |
133 | fn is_target_color_present(&self) -> bool {
134 | let (width, height) = (
135 | self.settings.resolution.width,
136 | self.settings.resolution.height,
137 | );
138 |
139 | let x = (self.trigger_area.x_percent * width as f32) as i32;
140 | let y = (self.trigger_area.y_percent * height as f32) as i32;
141 | let w = (self.trigger_area.width_percent * width as f32) as u32;
142 | let h = (self.trigger_area.height_percent * height as f32) as u32;
143 |
144 | let capture = self.screen.capture_area(x, y, w, h).unwrap();
145 |
146 | let pixels = capture.pixels();
147 |
148 | let matching_pixels: Vec<_> = pixels
149 | .filter(|p| {
150 | p.0
151 | .iter()
152 | .zip(&self.settings.target_color)
153 | .all(|(a, b)| ((*a as i32) - b).abs() <= self.settings.color_tolerance)
154 | })
155 | .collect();
156 |
157 | !matching_pixels.is_empty()
158 | }
159 |
160 | pub fn update_trigger_area(&mut self) {
161 | let (width, height) = (
162 | self.settings.resolution.width,
163 | self.settings.resolution.height,
164 | );
165 |
166 | self.trigger_area = TriggerArea {
167 | x_percent: 0.5 - (self.settings.trigger_area / 2.0 / width as f32),
168 | y_percent: 0.5 - (self.settings.trigger_area / 2.0 / height as f32),
169 | width_percent: self.settings.trigger_area / width as f32,
170 | height_percent: self.settings.trigger_area / height as f32,
171 | };
172 | }
173 |
174 | pub fn get_keys(&self) -> Vec {
175 | let mut triggers = vec![
176 | TriggerKey::Mouse(MouseButton::LeftButton),
177 | TriggerKey::Mouse(MouseButton::MiddleButton),
178 | TriggerKey::Mouse(MouseButton::RightButton),
179 | TriggerKey::Mouse(MouseButton::X1Button),
180 | TriggerKey::Mouse(MouseButton::X2Button),
181 | ];
182 |
183 | for key in vec![
184 | Keycode::LShift,
185 | Keycode::RShift,
186 | Keycode::LControl,
187 | Keycode::RControl,
188 | Keycode::LAlt,
189 | Keycode::RAlt,
190 | Keycode::A,
191 | Keycode::F,
192 | Keycode::B,
193 | Keycode::G,
194 | Keycode::C,
195 | Keycode::H,
196 | Keycode::D,
197 | Keycode::I,
198 | Keycode::E,
199 | Keycode::J,
200 | Keycode::K,
201 | Keycode::P,
202 | Keycode::L,
203 | Keycode::Q,
204 | Keycode::M,
205 | Keycode::R,
206 | Keycode::N,
207 | Keycode::S,
208 | Keycode::O,
209 | Keycode::T,
210 | Keycode::U,
211 | Keycode::Z,
212 | Keycode::V,
213 | Keycode::Y,
214 | Keycode::W,
215 | Keycode::X,
216 | ] {
217 | triggers.push(TriggerKey::Keyboard(key));
218 | }
219 |
220 | triggers
221 | }
222 |
223 | pub fn get_keys_display_name(&self, trigger: &TriggerKey) -> String {
224 | match trigger {
225 | TriggerKey::Keyboard(key) => match key {
226 | Keycode::LShift => "Left Shift".to_string(),
227 | Keycode::RShift => "Right Shift".to_string(),
228 | Keycode::LControl => "Left Control".to_string(),
229 | Keycode::RControl => "Right Control".to_string(),
230 | Keycode::LAlt => "Left Alt".to_string(),
231 | Keycode::RAlt => "Right Alt".to_string(),
232 | _ => format!("{:?}", key),
233 | },
234 | TriggerKey::Mouse(key) => match key {
235 | MouseButton::LeftButton => "Mouse Left".to_string(),
236 | MouseButton::MiddleButton => "Mouse Middle (Wheel)".to_string(),
237 | MouseButton::RightButton => "Mouse Right".to_string(),
238 | MouseButton::X1Button => "Mouse Backward (X1)".to_string(),
239 | MouseButton::X2Button => "Mouse Forward (X2)".to_string(),
240 | _ => format!("{:?}", key),
241 | },
242 | }
243 | }
244 | }
245 |
246 | impl App for Triggerbot {
247 | fn update(&mut self, ctx: &Context, _frame: &mut Frame) {
248 | gui::build(self, ctx);
249 |
250 | self.triggerbot();
251 |
252 | ctx.request_repaint();
253 | }
254 | }
255 |
256 | impl Display for Resolution {
257 | fn fmt(&self, f: &mut Formatter<'_>) -> Result {
258 | write!(f, "{}x{}", self.width, self.height)
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/src/gui.rs:
--------------------------------------------------------------------------------
1 | use crate::app::Triggerbot;
2 |
3 | use eframe::egui::{
4 | Button, CentralPanel, Color32, ComboBox, Context, DragValue, Frame, RichText, ScrollArea, Slider,
5 | Stroke, Vec2,
6 | };
7 |
8 | pub fn build(app: &mut Triggerbot, ctx: &Context) {
9 | CentralPanel::default().show(ctx, |ui| {
10 | ui.vertical(|ui| {
11 | ui.set_width(ui.available_width());
12 |
13 | ui.group(|ui| {
14 | ui.set_width(ui.available_width());
15 |
16 | ui.horizontal(|ui| {
17 | let mut width = app.settings.resolution.width;
18 | let mut height = app.settings.resolution.height;
19 |
20 | ui.label("Resolution:");
21 | if ui
22 | .add(DragValue::new(&mut width).speed(1).range(1..=5000))
23 | .changed()
24 | {
25 | app.set_resolution(width, app.settings.resolution.height);
26 | }
27 | ui.label("x");
28 | if ui
29 | .add(DragValue::new(&mut height).speed(1).range(1..=5000))
30 | .changed()
31 | {
32 | app.set_resolution(app.settings.resolution.width, height);
33 | }
34 |
35 | ui.checkbox(&mut app.settings.always_open, "Always Open");
36 | });
37 |
38 | ui.add_space(5.0);
39 |
40 | ui.horizontal(|ui| {
41 | ui.set_width(ui.available_width());
42 |
43 | ui.label("Trigger Keys:");
44 |
45 | ComboBox::from_id_salt("combobox_trigger_keys")
46 | .selected_text(format!("{} keys selected", app.settings.trigger_keys.len()))
47 | .width(160.0)
48 | .show_ui(ui, |ui| {
49 | ui.set_min_width(160.0);
50 | ui.set_max_height(80.0);
51 |
52 | ScrollArea::vertical().max_height(200.0).show(ui, |ui| {
53 | let available_triggers = app.get_keys();
54 |
55 | for trigger in available_triggers {
56 | let mut is_selected = app.settings.trigger_keys.contains(&trigger);
57 | let display_name = app.get_keys_display_name(&trigger);
58 |
59 | if ui.checkbox(&mut is_selected, display_name).changed() {
60 | if is_selected && !app.settings.trigger_keys.contains(&trigger) {
61 | app.settings.trigger_keys.push(trigger);
62 | } else if !is_selected {
63 | if let Some(pos) =
64 | app.settings.trigger_keys.iter().position(|x| *x == trigger)
65 | {
66 | app.settings.trigger_keys.remove(pos);
67 | }
68 | }
69 | }
70 | }
71 | });
72 | });
73 | });
74 |
75 | ui.add_space(5.0);
76 |
77 | ui.horizontal(|ui| {
78 | ui.set_width(ui.available_width());
79 |
80 | ui.label("Trigger Delay (ms):");
81 | ui.add(Slider::new(&mut app.settings.trigger_delay, 0..=3000));
82 | });
83 |
84 | ui.add_space(5.0);
85 |
86 | ui.horizontal(|ui| {
87 | ui.set_width(ui.available_width());
88 |
89 | ui.label("Trigger Area:");
90 | if ui
91 | .add(Slider::new(&mut app.settings.trigger_area, 5.0..=100.0))
92 | .changed()
93 | {
94 | app.update_trigger_area();
95 | }
96 | });
97 |
98 | ui.add_space(5.0);
99 |
100 | ui.horizontal(|ui| {
101 | ui.set_width(ui.available_width());
102 |
103 | ui.label("Target Color:");
104 |
105 | let labels = ["R", "G", "B"];
106 |
107 | for i in 0..3 {
108 | ui.label(labels[i]);
109 | ui.add(
110 | DragValue::new(&mut app.settings.target_color[i])
111 | .speed(1)
112 | .range(0..=255),
113 | );
114 | }
115 |
116 | Frame::none()
117 | .fill(Color32::from_rgb(
118 | app.settings.target_color[0] as u8,
119 | app.settings.target_color[1] as u8,
120 | app.settings.target_color[2] as u8,
121 | ))
122 | .stroke(Stroke::new(1.0, Color32::WHITE))
123 | .inner_margin(Vec2::new(6.0, 6.0))
124 | .show(ui, |_| {});
125 | });
126 |
127 | ui.add_space(5.0);
128 |
129 | ui.horizontal(|ui| {
130 | ui.set_width(ui.available_width());
131 |
132 | ui.label("Color Tolerance:");
133 | ui.add(Slider::new(&mut app.settings.color_tolerance, 0..=255));
134 | });
135 | });
136 |
137 | ui.add_space(5.0);
138 |
139 | ui.horizontal(|ui| {
140 | ui.set_width(ui.available_width());
141 |
142 | let (button_text, button_color) = if app.enabled {
143 | ("Disable", Color32::from_rgb(180, 100, 100))
144 | } else {
145 | ("Enable", Color32::from_rgb(100, 180, 100))
146 | };
147 |
148 | if ui
149 | .add_sized(
150 | [ui.available_width() / 2.0, 30.0],
151 | Button::new(RichText::new(button_text).color(Color32::WHITE)).fill(button_color),
152 | )
153 | .clicked()
154 | {
155 | app.enabled = !app.enabled;
156 | };
157 |
158 | let is_default = app.is_default_settings();
159 |
160 | let reset_button_color = if is_default {
161 | Color32::DARK_GRAY
162 | } else {
163 | Color32::from_rgb(100, 100, 180)
164 | };
165 |
166 | let reset_button = Button::new(RichText::new("Reset Settings").color(Color32::WHITE))
167 | .fill(reset_button_color)
168 | .sense(if is_default {
169 | eframe::egui::Sense::hover()
170 | } else {
171 | eframe::egui::Sense::click()
172 | });
173 |
174 | if ui
175 | .add_sized([ui.available_width(), 30.0], reset_button)
176 | .clicked()
177 | && !is_default
178 | {
179 | app.reset_settings();
180 | }
181 | });
182 | });
183 | });
184 | }
185 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | #![windows_subsystem = "windows"]
2 |
3 | mod app;
4 | mod gui;
5 |
6 | use app::Triggerbot;
7 | use eframe::{
8 | egui::{IconData, ViewportBuilder},
9 | NativeOptions,
10 | };
11 |
12 | fn main() -> Result<(), eframe::Error> {
13 | let options = NativeOptions {
14 | viewport: ViewportBuilder::default()
15 | .with_resizable(false)
16 | .with_transparent(true)
17 | .with_maximize_button(false)
18 | .with_inner_size([350.0, 212.0])
19 | .with_icon(IconData {
20 | rgba: image::load_from_memory(include_bytes!("../assets/icon.png"))
21 | .unwrap()
22 | .to_rgba8()
23 | .to_vec(),
24 | width: 128,
25 | height: 128,
26 | }),
27 | ..Default::default()
28 | };
29 |
30 | eframe::run_native(
31 | "Valorant Triggerbot (v1.4.0)",
32 | options,
33 | Box::new(|_cc| Ok(Box::new(Triggerbot::default()))),
34 | )
35 | }
36 |
--------------------------------------------------------------------------------