summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 18:31:27 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 18:31:27 +0100
commitf1794edcc60f6a27e622884c82397bb77e2aa280 (patch)
treeca1bf9aa40a612e8e7b1d1a76ff65bdddabd1add /src
parentGUI: Insert-only close, freeze mouse look at the source (diff)
downloadhl2h-f1794edcc60f6a27e622884c82397bb77e2aa280.tar.gz
hl2h-f1794edcc60f6a27e622884c82397bb77e2aa280.zip
GUI: wire real feature state and config
Replace the dummy preview controls with the actual settings: - cards bind directly to the feature state and the existing option variables; Active/Bind now drive the same gates as the text menu; - every feature persists active+bind, including movement, melee and spread; - config path and build info are real; Reload config re-reads the INI; - Reset defaults is two-click, restores feature settings/binds and keeps the GUI layout; - window position, category and expanded cards persist under [gui] in the same config file; layout saves on drag/category/expand/close; - mouse bind capture handles all five buttons and consumes the click so it cannot re-arm immediately; - Active/Bind tooltips and full scancode names. The old text tree stays on F1 for one verification pass.
Diffstat (limited to '')
-rw-r--r--src/gui.cpp448
-rw-r--r--src/hl2h.h39
-rw-r--r--src/menu.cpp117
3 files changed, 417 insertions, 187 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
index eb9062e..7baf383 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -1,9 +1,8 @@
1// gui.cpp — custom immediate-mode GUI shell (temporary Insert preview) 1// gui.cpp — custom immediate-mode GUI
2// 2//
3// This is the first vertical slice: the visual shell, categories, cards, 3// Categories, feature cards and controls are wired to the real settings in
4// dummy controls, cursor handling and input freeze. It does not read or write 4// menu.cpp. The old text tree is still reachable on F1 until the GUI has been
5// the real feature settings yet; the next pass replaces the dummy state and 5// verified as a full replacement.
6// removes the text menu.
7 6
8#include "hl2h.h" 7#include "hl2h.h"
9 8
@@ -177,21 +176,24 @@ enum CtrlKind {
177 CK_BUTTON 176 CK_BUTTON
178}; 177};
179 178
179enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET };
180
180struct Ctrl { 181struct Ctrl {
181 int kind; 182 int kind;
182 const char *label; 183 const char *label;
183 const char *desc; 184 const char *desc;
184 int *value; 185 bool *bval; // CK_TOGGLE
186 int *ival; // CK_SLIDER
185 int min, max; 187 int min, max;
188 int action; // CK_BUTTON
186}; 189};
187 190
188struct Card { 191struct Card {
189 int cat; 192 int cat;
193 FeatureState *feat; // nullptr for non-feature cards (System)
190 const char *title; 194 const char *title;
191 const char *desc; 195 const char *desc;
192 bool expanded; 196 bool expanded;
193 bool active;
194 int bind;
195 int c0, n; 197 int c0, n;
196}; 198};
197 199
@@ -199,123 +201,167 @@ static Ctrl g_ctrls[192];
199static int g_nctrl = 0; 201static int g_nctrl = 0;
200static Card g_cards[40]; 202static Card g_cards[40];
201static int g_ncards = 0; 203static int g_ncards = 0;
202static int g_vals[192]; 204static bool g_cards_built = false;
203static bool g_demo_built = false; 205static bool g_layout_loaded = false;
206static bool g_reset_armed = false;
207static double g_reset_armed_at = 0.0;
208static char g_config_label[512];
209static char g_build_label[128];
204 210
205static const char *g_cats[] = {"Movement", "Combat", "Visuals", "Weapons", 211static const char *g_cats[] = {"Movement", "Combat", "Visuals", "Weapons",
206 "System"}; 212 "System"};
207static constexpr int CAT_COUNT = 5; 213static constexpr int CAT_COUNT = 5;
208 214
209static int add_card(int cat, const char *title, const char *desc, 215static int add_card(int cat, FeatureState *feat, const char *title,
210 bool expanded) { 216 const char *desc, bool expanded) {
211 Card &c = g_cards[g_ncards]; 217 Card &c = g_cards[g_ncards];
212 c.cat = cat; 218 c.cat = cat;
219 c.feat = feat;
213 c.title = title; 220 c.title = title;
214 c.desc = desc; 221 c.desc = desc;
215 c.expanded = expanded; 222 c.expanded = expanded;
216 c.active = true;
217 c.bind = 0;
218 c.c0 = g_nctrl; 223 c.c0 = g_nctrl;
219 c.n = 0; 224 c.n = 0;
220 return g_ncards++; 225 return g_ncards++;
221} 226}
222static void add_ctrl(int card, int kind, const char *label, const char *desc, 227static void add_ctrl(int card, int kind, const char *label, const char *desc,
223 int min, int max, int init) { 228 int min, int max, bool *bval, int *ival, int action) {
224 int i = g_nctrl++; 229 int i = g_nctrl++;
225 g_vals[i] = init; 230 Ctrl &c = g_ctrls[i];
226 g_ctrls[i].kind = kind; 231 c.kind = kind;
227 g_ctrls[i].label = label; 232 c.label = label;
228 g_ctrls[i].desc = desc; 233 c.desc = desc;
229 g_ctrls[i].value = &g_vals[i]; 234 c.bval = bval;
230 g_ctrls[i].min = min; 235 c.ival = ival;
231 g_ctrls[i].max = max; 236 c.min = min;
237 c.max = max;
238 c.action = action;
232 g_cards[card].n++; 239 g_cards[card].n++;
233} 240}
234static void add_toggle(int card, const char *label, const char *desc, 241static void add_toggle(int card, const char *label, const char *desc,
235 int init) { 242 bool *value) {
236 add_ctrl(card, CK_TOGGLE, label, desc, 0, 1, init); 243 add_ctrl(card, CK_TOGGLE, label, desc, 0, 1, value, nullptr, ACT_NONE);
237} 244}
238static void add_slider(int card, const char *label, const char *desc, int min, 245static void add_slider(int card, const char *label, const char *desc, int min,
239 int max, int init) { 246 int max, int *value) {
240 add_ctrl(card, CK_SLIDER, label, desc, min, max, init); 247 add_ctrl(card, CK_SLIDER, label, desc, min, max, nullptr, value, ACT_NONE);
241} 248}
242static void add_section(int card, const char *label) { 249static void add_section(int card, const char *label) {
243 add_ctrl(card, CK_SECTION, label, nullptr, 0, 0, 0); 250 add_ctrl(card, CK_SECTION, label, nullptr, 0, 0, nullptr, nullptr, ACT_NONE);
244} 251}
245static void add_info(int card, const char *label) { 252static void add_info(int card, const char *label) {
246 add_ctrl(card, CK_INFO, label, nullptr, 0, 0, 0); 253 add_ctrl(card, CK_INFO, label, nullptr, 0, 0, nullptr, nullptr, ACT_NONE);
247} 254}
248static void add_button(int card, const char *label, const char *desc) { 255static void add_button(int card, const char *label, const char *desc,
249 add_ctrl(card, CK_BUTTON, label, desc, 0, 0, 0); 256 int action) {
257 add_ctrl(card, CK_BUTTON, label, desc, 0, 0, nullptr, nullptr, action);
250} 258}
251 259
252static void build_demo() { 260static int ctrl_val(const Ctrl &c) {
253 if (g_demo_built) 261 if (c.kind == CK_TOGGLE && c.bval)
262 return *c.bval ? 1 : 0;
263 if (c.kind == CK_SLIDER && c.ival)
264 return *c.ival;
265 return 0;
266}
267static void ctrl_set(Ctrl &c, int v) {
268 if (c.kind == CK_TOGGLE && c.bval) {
269 *c.bval = v != 0;
270 config_save();
271 } else if (c.kind == CK_SLIDER && c.ival) {
272 if (v < c.min) v = c.min;
273 if (v > c.max) v = c.max;
274 if (*c.ival != v) {
275 *c.ival = v;
276 // Slider drags persist on mouse release; discrete changes persist now.
277 }
278 }
279}
280
281static void build_cards() {
282 if (g_cards_built)
254 return; 283 return;
255 g_demo_built = true; 284 g_cards_built = true;
256 285
257 int bhop = add_card(0, "Bunnyhop", "Automatic jump on landing.", true); 286 int bhop = add_card(0, &g_bhop, "Bunnyhop", "Automatic jump on landing.",
287 true);
258 add_toggle(bhop, "Uni-directional auto-strafe", 288 add_toggle(bhop, "Uni-directional auto-strafe",
259 "Rotate airborne movement into the velocity.", 1); 289 "Rotate airborne movement into the velocity.",
290 &g_bhop_autostrafe);
260 291
261 int abh = add_card(0, "ABH", "Accelerate on the jump tick by facing away " 292 add_card(0, &g_abh, "ABH", "Accelerate on the jump tick by facing away "
262 "from the velocity.", true); 293 "from the velocity.", true);
263 (void)abh;
264 294
265 int jb = add_card(0, "Jumpbug", "Duck+jump when landing would hurt.", true); 295 int jb = add_card(0, &g_jumpbug, "Jumpbug",
296 "Duck+jump when landing would hurt.", true);
266 add_toggle(jb, "Assist timing", 297 add_toggle(jb, "Assist timing",
267 "Nudge the final command into the unduck window.", 0); 298 "Nudge the final command into the unduck window.",
299 &g_jumpbug_assist);
268 300
269 int aim = add_card(1, "Aimbot", "Smoothly snap to a hostile target.", true); 301 int aim = add_card(1, &g_aimbot, "Aimbot",
270 g_cards[aim].bind = 604; 302 "Smoothly snap to a hostile target.", true);
271 add_toggle(aim, "Vischeck", "Require world line of sight.", 1); 303 add_toggle(aim, "Vischeck", "Require world line of sight.", &g_aim_vischeck);
272 add_slider(aim, "FOV", "Maximum angular distance from the crosshair.", 1, 180, 304 add_slider(aim, "FOV", "Maximum angular distance from the crosshair.", 1, 180,
273 60); 305 &g_aim_fov);
274 add_slider(aim, "Smoothness", "Maximum degrees per tick.", 1, 45, 5); 306 add_slider(aim, "Smoothness", "Maximum degrees per tick.", 1, 45,
275 add_toggle(aim, "Show FOV circle", "Draw the acquisition cone on screen.", 1); 307 &g_aim_smooth);
308 add_toggle(aim, "Show FOV circle", "Draw the acquisition cone on screen.",
309 &g_aim_fov_circle);
276 add_section(aim, "Bones"); 310 add_section(aim, "Bones");
277 add_toggle(aim, "Head", "Aim at the head hitbox.", 1); 311 static const char *bone_names[AIM_BONE_COUNT] = {
278 add_toggle(aim, "Torso", "Aim at the chest/stomach.", 0); 312 "Head", "Torso", "Left arm", "Right arm", "Left leg", "Right leg"};
279 add_toggle(aim, "Left arm", "Include the left arm.", 0); 313 static const char *bone_descs[AIM_BONE_COUNT] = {
280 add_toggle(aim, "Right arm", "Include the right arm.", 0); 314 "Aim at the head hitbox.", "Aim at the chest/stomach.",
281 add_toggle(aim, "Left leg", "Include the left leg.", 0); 315 "Include the left arm.", "Include the right arm.",
282 add_toggle(aim, "Right leg", "Include the right leg.", 0); 316 "Include the left leg.", "Include the right leg."};
283 317 for (int i = 0; i < AIM_BONE_COUNT; i++)
284 int sil = add_card(1, "Silent aim", "Fire at the target without turning " 318 add_toggle(aim, bone_names[i], bone_descs[i], &g_aim_bones[i]);
285 "the rendered view.", true); 319
286 g_cards[sil].bind = 602; 320 int sil = add_card(1, &g_silentaim, "Silent aim",
321 "Fire at the target without turning the rendered view.",
322 true);
287 add_slider(sil, "FOV", "Maximum angular distance from the crosshair.", 1, 180, 323 add_slider(sil, "FOV", "Maximum angular distance from the crosshair.", 1, 180,
288 60); 324 &g_silent_fov);
289 325
290 int tb = add_card(1, "Triggerbot", "Fire when the crosshair is on a hostile.", 326 add_card(1, &g_triggerbot, "Triggerbot",
291 true); 327 "Fire when the crosshair is on a hostile.", true);
292 g_cards[tb].bind = 603; 328
293 329 add_card(1, &g_melee, "Melee killbot", "360-degree crowbar silent aim.",
294 int melee = add_card(1, "Melee killbot", "360-degree crowbar silent aim.", 330 true);
295 true); 331
296 332 int esp = add_card(2, &g_esp, "ESP", "Draw hostile NPC information.", true);
297 int esp = add_card(2, "ESP", "Draw hostile NPC information.", true); 333 static const char *esp_names[ESP_OPT_COUNT] = {
298 add_toggle(esp, "Show neutral", "Include neutral wildlife.", 1); 334 "Show neutral", "Show healthbar", "Show healthnum",
299 add_toggle(esp, "Show healthbar", "Draw a health bar.", 1); 335 "Show name", "Show skeleton", "Show box",
300 add_toggle(esp, "Show healthnum", "Draw the numeric health value.", 1); 336 "Show speed graph"};
301 add_toggle(esp, "Show name", "Draw the model name.", 1); 337 static const char *esp_descs[ESP_OPT_COUNT] = {
302 add_toggle(esp, "Show skeleton", "Draw the animated bone links.", 1); 338 "Include neutral wildlife.", "Draw a health bar.",
303 add_toggle(esp, "Show box", "Draw a bounding box.", 1); 339 "Draw the numeric health value.", "Draw the model name.",
304 add_toggle(esp, "Show speed graph", "Draw the lower-center speed graph.", 1); 340 "Draw the animated bone links.", "Draw a bounding box.",
305 341 "Draw the lower-center speed graph."};
306 int spread = add_card(3, "Spread control", 342 for (int i = 0; i < ESP_OPT_COUNT; i++)
343 add_toggle(esp, esp_names[i], esp_descs[i], &g_esp_opt[i]);
344
345 int spread = add_card(3, &g_spread, "Spread control",
307 "Choose a server shot seed that tightens the cone.", 346 "Choose a server shot seed that tightens the cone.",
308 true); 347 true);
309 add_toggle(spread, "No spread", 348 add_toggle(spread, "No spread",
310 "Override the FireBullets seed with the best offset.", 1); 349 "Override the FireBullets seed with the best offset.",
311 350 &g_spread_no_spread);
312 int sys = add_card(4, "System", "Configuration and maintenance.", true); 351
313 add_info(sys, "Config: ~/.config/hl2hake/config"); 352 int sys = add_card(4, nullptr, "System", "Configuration and maintenance.",
314 add_info(sys, "Build: GUI shell preview"); 353 true);
315 add_button(sys, "Reload config", "Re-read the INI without restarting."); 354 snprintf(g_config_label, sizeof(g_config_label), "Config: %s",
316 add_button(sys, "Reset defaults", "Restore feature defaults; GUI layout kept."); 355 config_path_cstr());
317 356 snprintf(g_build_label, sizeof(g_build_label), "Build: %s %s", __DATE__,
318 (void)g_cards[melee]; 357 __TIME__);
358 add_info(sys, g_config_label);
359 add_info(sys, g_build_label);
360 add_button(sys, "Reload config", "Re-read the INI without restarting.",
361 ACT_RELOAD);
362 add_button(sys, "Reset defaults",
363 "Click twice to restore feature defaults; GUI layout kept.",
364 ACT_RESET);
319} 365}
320 366
321// --------------------------------------------------------------------------- 367// ---------------------------------------------------------------------------
@@ -344,6 +390,7 @@ static bool g_mouse_click = false;
344static bool g_mouse_down = false; 390static bool g_mouse_down = false;
345static bool g_mouse_rclick = false; 391static bool g_mouse_rclick = false;
346static unsigned int g_prev_mask = 0; 392static unsigned int g_prev_mask = 0;
393static int g_mouse_press = 0; // 1..5 on the frame a button goes down
347static unsigned char g_prev_keys[512] = {}; 394static unsigned char g_prev_keys[512] = {};
348static bool g_prev_cursor = true; 395static bool g_prev_cursor = true;
349static bool g_prev_relative = true; 396static bool g_prev_relative = true;
@@ -480,21 +527,6 @@ static void line(int x0, int y0, int x1, int y1, const Col &c) {
480 s_line(x0, y0, x1, y1); 527 s_line(x0, y0, x1, y1);
481} 528}
482 529
483static const char *bind_label(int b) {
484 switch (b) {
485 case 0: return "None";
486 case 600: return "MouseL";
487 case 601: return "MouseR";
488 case 602: return "MouseM";
489 case 603: return "Mouse4";
490 case 604: return "Mouse5";
491 case 41: return "Esc";
492 case 73: return "Insert";
493 case 59: return "F2";
494 default: return "Key";
495 }
496}
497
498static void layout() { 530static void layout() {
499 int w = g_scr_w, h = g_scr_h; 531 int w = g_scr_w, h = g_scr_h;
500 if (g_surface) { 532 if (g_surface) {
@@ -575,6 +607,7 @@ static void close_gui() {
575 g_dragging = false; 607 g_dragging = false;
576 g_scroll_drag = false; 608 g_scroll_drag = false;
577 g_slider_drag = -1; 609 g_slider_drag = -1;
610 g_reset_armed = false;
578 input_clear_mouse_states(); 611 input_clear_mouse_states();
579 if (g_sdl_ready) { 612 if (g_sdl_ready) {
580 if (sd_set_relative) 613 if (sd_set_relative)
@@ -582,6 +615,7 @@ static void close_gui() {
582 if (sd_show_cursor) 615 if (sd_show_cursor)
583 sd_show_cursor(g_prev_cursor ? 1 : 0); 616 sd_show_cursor(g_prev_cursor ? 1 : 0);
584 } 617 }
618 config_save();
585 logf("gui: closed"); 619 logf("gui: closed");
586} 620}
587 621
@@ -617,7 +651,8 @@ static void open_gui() {
617 g_capture_card = -1; 651 g_capture_card = -1;
618 g_wheel.exchange(0); 652 g_wheel.exchange(0);
619 g_scroll = 0.0f; 653 g_scroll = 0.0f;
620 g_cat = 0; 654 if (g_cat < 0 || g_cat >= CAT_COUNT)
655 g_cat = 0;
621 menu_force_close(); 656 menu_force_close();
622 logf("gui: opened"); 657 logf("gui: opened");
623} 658}
@@ -630,8 +665,16 @@ static void update_mouse() {
630 g_mouse_x = mx; 665 g_mouse_x = mx;
631 g_mouse_y = my; 666 g_mouse_y = my;
632 g_mouse_down = (mask & 1u) != 0; 667 g_mouse_down = (mask & 1u) != 0;
633 g_mouse_click = g_mouse_down && !(g_prev_mask & 1u); 668 g_mouse_press = 0;
634 g_mouse_rclick = ((mask & 2u) != 0) && !(g_prev_mask & 2u); 669 unsigned int pressed = mask & ~g_prev_mask;
670 for (int b = 0; b < 5; b++) {
671 if (pressed & (1u << b)) {
672 g_mouse_press = b + 1;
673 break;
674 }
675 }
676 g_mouse_click = g_mouse_press == 1;
677 g_mouse_rclick = g_mouse_press == 2;
635 if (g_mouse_x < 0) g_mouse_x = 0; 678 if (g_mouse_x < 0) g_mouse_x = 0;
636 if (g_mouse_y < 0) g_mouse_y = 0; 679 if (g_mouse_y < 0) g_mouse_y = 0;
637 g_prev_mask = mask; 680 g_prev_mask = mask;
@@ -648,14 +691,15 @@ static void handle_capture(const unsigned char *keys) {
648 g_capture_card = -1; 691 g_capture_card = -1;
649 return; 692 return;
650 } 693 }
651 if (g_mouse_click) { 694 Card &card = g_cards[g_capture_card];
652 g_cards[g_capture_card].bind = 600; 695 if (g_mouse_press >= 1 && g_mouse_press <= 5 && card.feat) {
653 g_capture_card = -1; 696 card.feat->bind = 600 + (g_mouse_press - 1);
654 return; 697 // Consume the click: it must not immediately re-arm capture on the same
655 } 698 // bind box.
656 if (g_mouse_rclick) { 699 g_mouse_click = false;
657 g_cards[g_capture_card].bind = 601; 700 g_mouse_rclick = false;
658 g_capture_card = -1; 701 g_capture_card = -1;
702 config_save();
659 return; 703 return;
660 } 704 }
661 for (int k = 0; k < 512; k++) { 705 for (int k = 0; k < 512; k++) {
@@ -663,8 +707,12 @@ static void handle_capture(const unsigned char *keys) {
663 continue; 707 continue;
664 if (k == 73) // Insert is reserved for opening/closing the GUI 708 if (k == 73) // Insert is reserved for opening/closing the GUI
665 continue; 709 continue;
666 g_cards[g_capture_card].bind = k; 710 if (k == 58) // F1 opens the old text tree during the verification pass
711 continue;
712 if (card.feat)
713 card.feat->bind = k;
667 g_capture_card = -1; 714 g_capture_card = -1;
715 config_save();
668 return; 716 return;
669 } 717 }
670} 718}
@@ -674,7 +722,7 @@ static void handle_mouse_click() {
674 return; 722 return;
675 int mx = g_mouse_x, my = g_mouse_y; 723 int mx = g_mouse_x, my = g_mouse_y;
676 724
677 // title bar: drag or close 725 // title bar: drag
678 Rect title{g_win_x, g_win_y, g_win_w, S(38.0f)}; 726 Rect title{g_win_x, g_win_y, g_win_w, S(38.0f)};
679 if (title.has(mx, my)) { 727 if (title.has(mx, my)) {
680 g_dragging = true; 728 g_dragging = true;
@@ -693,6 +741,7 @@ static void handle_mouse_click() {
693 if (r.has(mx, my)) { 741 if (r.has(mx, my)) {
694 g_cat = i; 742 g_cat = i;
695 g_scroll = 0.0f; 743 g_scroll = 0.0f;
744 config_save();
696 return; 745 return;
697 } 746 }
698 } 747 }
@@ -736,18 +785,20 @@ static void handle_mouse_click() {
736 if (my >= cr.y && my < cr.y + ch) { 785 if (my >= cr.y && my < cr.y + ch) {
737 // header 786 // header
738 if (my < cr.y + S(36.0f)) { 787 if (my < cr.y + S(36.0f)) {
739 if (c.cat != 4) { 788 if (c.feat) {
740 Rect active{cr.x + cr.w - S(150.0f), cr.y + S(9.0f), S(18.0f), 789 Rect active{cr.x + cr.w - S(170.0f), cr.y + S(9.0f), S(18.0f),
741 S(18.0f)}; 790 S(18.0f)};
742 Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f), 791 Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f),
743 S(22.0f)}; 792 S(22.0f)};
744 if (active.has(mx, my)) { 793 if (active.has(mx, my)) {
745 c.active = !c.active; 794 c.feat->active = !c.feat->active;
795 config_save();
746 return; 796 return;
747 } 797 }
748 if (bind.has(mx, my)) { 798 if (bind.has(mx, my)) {
749 if (mx >= bind.x + bind.w - S(18.0f)) { 799 if (mx >= bind.x + bind.w - S(18.0f)) {
750 c.bind = 0; 800 c.feat->bind = 0;
801 config_save();
751 return; 802 return;
752 } 803 }
753 g_capture_card = i; 804 g_capture_card = i;
@@ -755,6 +806,7 @@ static void handle_mouse_click() {
755 } 806 }
756 } 807 }
757 c.expanded = !c.expanded; 808 c.expanded = !c.expanded;
809 config_save();
758 return; 810 return;
759 } 811 }
760 // body 812 // body
@@ -767,7 +819,7 @@ static void handle_mouse_click() {
767 continue; 819 continue;
768 } 820 }
769 if (ct.kind == CK_TOGGLE) { 821 if (ct.kind == CK_TOGGLE) {
770 *ct.value = !*ct.value; 822 ctrl_set(ct, !ctrl_val(ct));
771 return; 823 return;
772 } 824 }
773 if (ct.kind == CK_SLIDER) { 825 if (ct.kind == CK_SLIDER) {
@@ -778,7 +830,7 @@ static void handle_mouse_click() {
778 int v = ct.min + (int)(t * (ct.max - ct.min) + 0.5f); 830 int v = ct.min + (int)(t * (ct.max - ct.min) + 0.5f);
779 if (v < ct.min) v = ct.min; 831 if (v < ct.min) v = ct.min;
780 if (v > ct.max) v = ct.max; 832 if (v > ct.max) v = ct.max;
781 *ct.value = v; 833 ctrl_set(ct, v);
782 g_slider_drag = c.c0 + j; 834 g_slider_drag = c.c0 + j;
783 } 835 }
784 return; 836 return;
@@ -787,7 +839,20 @@ static void handle_mouse_click() {
787 Rect b{cr.x + cr.w - S(176.0f), by + S(3.0f), S(160.0f), 839 Rect b{cr.x + cr.w - S(176.0f), by + S(3.0f), S(160.0f),
788 S(26.0f)}; 840 S(26.0f)};
789 if (b.has(mx, my)) { 841 if (b.has(mx, my)) {
790 logf("gui: dummy action %s", ct.label ? ct.label : "?"); 842 if (ct.action == ACT_RELOAD) {
843 config_reload();
844 logf("gui: config reloaded");
845 } else if (ct.action == ACT_RESET) {
846 double now = now_sec();
847 if (g_reset_armed && now - g_reset_armed_at < 3.0) {
848 config_reset_defaults();
849 g_reset_armed = false;
850 logf("gui: defaults restored");
851 } else {
852 g_reset_armed = true;
853 g_reset_armed_at = now;
854 }
855 }
791 return; 856 return;
792 } 857 }
793 } 858 }
@@ -815,7 +880,25 @@ static void handle_hover() {
815 int ch = card_h(c); 880 int ch = card_h(c);
816 if (my >= cr.y && my < cr.y + ch) { 881 if (my >= cr.y && my < cr.y + ch) {
817 if (my < cr.y + S(36.0f)) { 882 if (my < cr.y + S(36.0f)) {
818 g_hover_desc = c.desc; 883 if (c.feat) {
884 Rect active{cr.x + cr.w - S(170.0f), cr.y + S(9.0f), S(18.0f),
885 S(18.0f)};
886 Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f),
887 S(22.0f)};
888 if (active.has(mx, my))
889 g_hover_desc = "Enable this feature. A bind, when set, must be "
890 "held for it to run.";
891 else if (bind.has(mx, my))
892 g_hover_desc = (mx >= bind.x + bind.w - S(18.0f))
893 ? "Clear the bind. An unbound feature is "
894 "always-on."
895 : "Click, then press a key or mouse button. "
896 "Esc cancels.";
897 else
898 g_hover_desc = c.desc;
899 } else {
900 g_hover_desc = c.desc;
901 }
819 return; 902 return;
820 } 903 }
821 int by = cr.y + S(36.0f) + S(6.0f); 904 int by = cr.y + S(36.0f) + S(6.0f);
@@ -840,7 +923,7 @@ void gui_handle_input() {
840 gui_init_sdl(); 923 gui_init_sdl();
841 if (!g_surface) 924 if (!g_surface)
842 return; 925 return;
843 build_demo(); 926 build_cards();
844 layout(); 927 layout();
845 if (g_scr_w <= 0 || g_scr_h <= 0) 928 if (g_scr_w <= 0 || g_scr_h <= 0)
846 return; 929 return;
@@ -895,6 +978,7 @@ void gui_handle_input() {
895 if (g_dragging) { 978 if (g_dragging) {
896 if (!g_mouse_down) { 979 if (!g_mouse_down) {
897 g_dragging = false; 980 g_dragging = false;
981 config_save();
898 } else { 982 } else {
899 g_win_x = g_mouse_x - g_drag_dx; 983 g_win_x = g_mouse_x - g_drag_dx;
900 g_win_y = g_mouse_y - g_drag_dy; 984 g_win_y = g_mouse_y - g_drag_dy;
@@ -910,6 +994,7 @@ void gui_handle_input() {
910 if (g_slider_drag >= 0) { 994 if (g_slider_drag >= 0) {
911 if (!g_mouse_down) { 995 if (!g_mouse_down) {
912 g_slider_drag = -1; 996 g_slider_drag = -1;
997 config_save();
913 } else { 998 } else {
914 Ctrl &ct = g_ctrls[g_slider_drag]; 999 Ctrl &ct = g_ctrls[g_slider_drag];
915 Rect content{g_win_x + S(190.0f), g_win_y + S(38.0f), 1000 Rect content{g_win_x + S(190.0f), g_win_y + S(38.0f),
@@ -919,9 +1004,7 @@ void gui_handle_input() {
919 (void)content; 1004 (void)content;
920 float t = (float)(g_mouse_x - x0) / (float)(x1 - x0); 1005 float t = (float)(g_mouse_x - x0) / (float)(x1 - x0);
921 int v = ct.min + (int)(t * (ct.max - ct.min) + 0.5f); 1006 int v = ct.min + (int)(t * (ct.max - ct.min) + 0.5f);
922 if (v < ct.min) v = ct.min; 1007 ctrl_set(ct, v);
923 if (v > ct.max) v = ct.max;
924 *ct.value = v;
925 } 1008 }
926 } 1009 }
927 1010
@@ -950,9 +1033,8 @@ void gui_handle_input() {
950 if (left_edge || right_edge) { 1033 if (left_edge || right_edge) {
951 if (g_hover_slider >= 0) { 1034 if (g_hover_slider >= 0) {
952 Ctrl &ct = g_ctrls[g_hover_slider]; 1035 Ctrl &ct = g_ctrls[g_hover_slider];
953 *ct.value += right_edge ? 1 : -1; 1036 ctrl_set(ct, ctrl_val(ct) + (right_edge ? 1 : -1));
954 if (*ct.value < ct.min) *ct.value = ct.min; 1037 config_save();
955 if (*ct.value > ct.max) *ct.value = ct.max;
956 } 1038 }
957 } 1039 }
958 1040
@@ -1003,15 +1085,16 @@ static void draw_slider(const Rect &clip, const Rect &cr, int y, const Ctrl &ct)
1003 if (track_w < S(30.0f)) track_w = S(30.0f); 1085 if (track_w < S(30.0f)) track_w = S(30.0f);
1004 Rect track{track_x, y + S(9.0f), track_w, S(8.0f)}; 1086 Rect track{track_x, y + S(9.0f), track_w, S(8.0f)};
1005 fill(track, Col{38, 42, 50, 255}, &clip); 1087 fill(track, Col{38, 42, 50, 255}, &clip);
1088 int value = ctrl_val(ct);
1006 float t = (ct.max > ct.min) 1089 float t = (ct.max > ct.min)
1007 ? (float)(*ct.value - ct.min) / (float)(ct.max - ct.min) 1090 ? (float)(value - ct.min) / (float)(ct.max - ct.min)
1008 : 0.0f; 1091 : 0.0f;
1009 int fw = (int)(track_w * t + 0.5f); 1092 int fw = (int)(track_w * t + 0.5f);
1010 fill(Rect{track.x, track.y, fw, track.h}, C_ACCENT_DIM, &clip); 1093 fill(Rect{track.x, track.y, fw, track.h}, C_ACCENT_DIM, &clip);
1011 int kx = track.x + fw - S(4.0f); 1094 int kx = track.x + fw - S(4.0f);
1012 fill(Rect{kx, track.y - S(4.0f), S(8.0f), S(16.0f)}, C_ACCENT, &clip); 1095 fill(Rect{kx, track.y - S(4.0f), S(8.0f), S(16.0f)}, C_ACCENT, &clip);
1013 char val[32]; 1096 char val[32];
1014 snprintf(val, sizeof(val), "%d", *ct.value); 1097 snprintf(val, sizeof(val), "%d", value);
1015 text_in(clip, cr.x + cr.w - S(52.0f), y + S(4.0f), val, g_font_body, g_body_h, 1098 text_in(clip, cr.x + cr.w - S(52.0f), y + S(4.0f), val, g_font_body, g_body_h,
1016 S(44.0f), C_TEXT); 1099 S(44.0f), C_TEXT);
1017} 1100}
@@ -1037,15 +1120,18 @@ static void draw_card(const Rect &clip, int index, int y) {
1037 } 1120 }
1038 text_in(clip, cr.x + S(24.0f), cr.y + S(8.0f), c.title, g_font_title, 1121 text_in(clip, cr.x + S(24.0f), cr.y + S(8.0f), c.title, g_font_title,
1039 g_title_h, cr.w - S(180.0f), C_TEXT); 1122 g_title_h, cr.w - S(180.0f), C_TEXT);
1040 if (c.cat != 4) { 1123 if (c.feat) {
1041 draw_checkbox(cr.x + cr.w - S(150.0f), cr.y + S(10.0f), c.active); 1124 bool active = c.feat->active;
1042 text_in(clip, cr.x + cr.w - S(128.0f), cr.y + S(9.0f), 1125 draw_checkbox(cr.x + cr.w - S(170.0f), cr.y + S(10.0f), active);
1043 c.active ? "On" : "Off", g_font_body, g_body_h, S(30.0f), 1126 text_in(clip, cr.x + cr.w - S(148.0f), cr.y + S(9.0f),
1044 c.active ? C_GOOD : C_DIM); 1127 active ? "On" : "Off", g_font_body, g_body_h, S(32.0f),
1128 active ? C_GOOD : C_DIM);
1045 Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f), S(22.0f)}; 1129 Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f), S(22.0f)};
1046 fill(bind, Col{45, 50, 60, 255}, &clip); 1130 fill(bind, Col{45, 50, 60, 255}, &clip);
1047 outline(bind, C_BORDER, &clip); 1131 outline(bind, C_BORDER, &clip);
1048 const char *bl = (g_capture_card == index) ? "Press..." : bind_label(c.bind); 1132 const char *bl = (g_capture_card == index)
1133 ? "Press..."
1134 : scancode_name(c.feat->bind);
1049 text_in(clip, bind.x + S(7.0f), bind.y + S(3.0f), bl, g_font_body, g_body_h, 1135 text_in(clip, bind.x + S(7.0f), bind.y + S(3.0f), bl, g_font_body, g_body_h,
1050 bind.w - S(22.0f), C_TEXT); 1136 bind.w - S(22.0f), C_TEXT);
1051 text_in(clip, bind.x + bind.w - S(16.0f), bind.y + S(3.0f), "x", 1137 text_in(clip, bind.x + bind.w - S(16.0f), bind.y + S(3.0f), "x",
@@ -1068,16 +1154,24 @@ static void draw_card(const Rect &clip, int index, int y) {
1068 Rect b{cr.x + cr.w - S(176.0f), by + S(3.0f), S(160.0f), S(26.0f)}; 1154 Rect b{cr.x + cr.w - S(176.0f), by + S(3.0f), S(160.0f), S(26.0f)};
1069 fill(b, Col{45, 50, 60, 255}, &clip); 1155 fill(b, Col{45, 50, 60, 255}, &clip);
1070 outline(b, C_BORDER, &clip); 1156 outline(b, C_BORDER, &clip);
1071 text_in(clip, b.x + S(10.0f), b.y + S(4.0f), ct.label, g_font_body, 1157 const char *label = ct.label;
1158 if (ct.action == ACT_RESET && g_reset_armed) {
1159 if (now_sec() - g_reset_armed_at >= 3.0)
1160 g_reset_armed = false;
1161 else
1162 label = "Confirm reset";
1163 }
1164 text_in(clip, b.x + S(10.0f), b.y + S(4.0f), label, g_font_body,
1072 g_body_h, b.w - S(16.0f), C_TEXT); 1165 g_body_h, b.w - S(16.0f), C_TEXT);
1073 } else { 1166 } else {
1074 text_in(clip, cr.x + S(16.0f), by + S(4.0f), ct.label, g_font_body, 1167 text_in(clip, cr.x + S(16.0f), by + S(4.0f), ct.label, g_font_body,
1075 g_body_h, S(220.0f), C_TEXT); 1168 g_body_h, S(220.0f), C_TEXT);
1076 if (ct.kind == CK_TOGGLE) { 1169 if (ct.kind == CK_TOGGLE) {
1077 draw_checkbox(cr.x + cr.w - S(31.0f), by + S(5.0f), *ct.value != 0); 1170 bool on = ctrl_val(ct) != 0;
1171 draw_checkbox(cr.x + cr.w - S(31.0f), by + S(5.0f), on);
1078 text_in(clip, cr.x + cr.w - S(58.0f), by + S(3.0f), 1172 text_in(clip, cr.x + cr.w - S(58.0f), by + S(3.0f),
1079 *ct.value ? "On" : "Off", g_font_body, g_body_h, S(26.0f), 1173 on ? "On" : "Off", g_font_body, g_body_h, S(26.0f),
1080 *ct.value ? C_GOOD : C_DIM); 1174 on ? C_GOOD : C_DIM);
1081 } else if (ct.kind == CK_SLIDER) { 1175 } else if (ct.kind == CK_SLIDER) {
1082 draw_slider(clip, cr, by, ct); 1176 draw_slider(clip, cr, by, ct);
1083 } 1177 }
@@ -1126,8 +1220,8 @@ void gui_draw() {
1126 fill(Rect{win.x, win.y, S(4.0f), win.h}, C_ACCENT); 1220 fill(Rect{win.x, win.y, S(4.0f), win.h}, C_ACCENT);
1127 text_in(win, win.x + S(16.0f), win.y + S(7.0f), "HL2hake", g_font_title, 1221 text_in(win, win.x + S(16.0f), win.y + S(7.0f), "HL2hake", g_font_title,
1128 g_title_h, win.w - S(80.0f), C_TEXT); 1222 g_title_h, win.w - S(80.0f), C_TEXT);
1129 text_in(win, win.x + S(110.0f), win.y + S(10.0f), "GUI shell preview", 1223 text_in(win, win.x + S(110.0f), win.y + S(10.0f), "Settings", g_font_body,
1130 g_font_body, g_body_h, win.w - S(180.0f), C_DIM); 1224 g_body_h, win.w - S(180.0f), C_DIM);
1131 1225
1132 Rect side{win.x, win.y + S(38.0f), S(190.0f), 1226 Rect side{win.x, win.y + S(38.0f), S(190.0f),
1133 win.h - S(38.0f) - S(30.0f)}; 1227 win.h - S(38.0f) - S(30.0f)};
@@ -1181,7 +1275,7 @@ void gui_draw() {
1181 "config: ~/.config/hl2hake/config", g_font_body, g_body_h, 1275 "config: ~/.config/hl2hake/config", g_font_body, g_body_h,
1182 foot.w - S(220.0f), C_DIM); 1276 foot.w - S(220.0f), C_DIM);
1183 text_in(foot, foot.x + foot.w - S(200.0f), foot.y + S(6.0f), 1277 text_in(foot, foot.x + foot.w - S(200.0f), foot.y + S(6.0f),
1184 g_capture_card >= 0 ? "press a key / Esc" : "INS close | F1 text menu", 1278 g_capture_card >= 0 ? "press a key / Esc" : "INS close | F1 old menu",
1185 g_font_body, g_body_h, S(190.0f), C_DIM); 1279 g_font_body, g_body_h, S(190.0f), C_DIM);
1186 1280
1187 draw_tooltip(); 1281 draw_tooltip();
@@ -1192,6 +1286,78 @@ bool gui_bind_capture_active() { return g_open && g_capture_card >= 0; }
1192QAngle gui_frozen_view() { return g_frozen; } 1286QAngle gui_frozen_view() { return g_frozen; }
1193 1287
1194// --------------------------------------------------------------------------- 1288// ---------------------------------------------------------------------------
1289// [gui] layout persistence
1290// ---------------------------------------------------------------------------
1291
1292static void gui_load_layout() {
1293 FILE *f = fopen(config_path_cstr(), "r");
1294 if (!f)
1295 return;
1296 bool in_gui = false, have_x = false, have_y = false;
1297 int x = 0, y = 0, cat = 0;
1298 unsigned expanded = 0;
1299 bool have_expanded = false;
1300 char line[256];
1301 while (fgets(line, sizeof(line), f)) {
1302 line[strcspn(line, "\r\n")] = 0;
1303 if (line[0] == '[') {
1304 in_gui = strstr(line, "[gui]") != nullptr;
1305 continue;
1306 }
1307 if (!in_gui)
1308 continue;
1309 char *eq = strchr(line, '=');
1310 if (!eq)
1311 continue;
1312 *eq = 0;
1313 const char *key = line, *val = eq + 1;
1314 if (strcmp(key, "x") == 0) {
1315 x = atoi(val);
1316 have_x = true;
1317 } else if (strcmp(key, "y") == 0) {
1318 y = atoi(val);
1319 have_y = true;
1320 } else if (strcmp(key, "category") == 0) {
1321 cat = atoi(val);
1322 } else if (strcmp(key, "expanded") == 0) {
1323 expanded = (unsigned)strtoul(val, nullptr, 10);
1324 have_expanded = true;
1325 }
1326 }
1327 fclose(f);
1328 if (have_x && have_y) {
1329 g_win_x = x;
1330 g_win_y = y;
1331 g_positioned = true;
1332 }
1333 if (cat >= 0 && cat < CAT_COUNT)
1334 g_cat = cat;
1335 if (have_expanded) {
1336 for (int i = 0; i < g_ncards && i < 32; i++)
1337 g_cards[i].expanded = (expanded & (1u << i)) != 0;
1338 }
1339}
1340
1341void gui_config_init() {
1342 build_cards();
1343 if (g_layout_loaded)
1344 return;
1345 g_layout_loaded = true;
1346 gui_load_layout();
1347}
1348
1349void gui_config_write(FILE *f) {
1350 if (!f || !g_cards_built || !g_positioned)
1351 return;
1352 unsigned expanded = 0;
1353 for (int i = 0; i < g_ncards && i < 32; i++)
1354 if (g_cards[i].expanded)
1355 expanded |= 1u << i;
1356 fprintf(f, "[gui]\nx=%d\ny=%d\ncategory=%d\nexpanded=%u\n", g_win_x,
1357 g_win_y, g_cat, expanded);
1358}
1359
1360// ---------------------------------------------------------------------------
1195// SDL cursor interposition 1361// SDL cursor interposition
1196// --------------------------------------------------------------------------- 1362// ---------------------------------------------------------------------------
1197// The game re-asserts relative mouse mode / hides the cursor every frame. While 1363// The game re-asserts relative mouse mode / hides the cursor every frame. While
diff --git a/src/hl2h.h b/src/hl2h.h
index d5a9dc3..678c5af 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -174,6 +174,43 @@ enum EspOption {
174 ESP_OPT_SHOW_SPEEDGRAPH = 6, 174 ESP_OPT_SHOW_SPEEDGRAPH = 6,
175 ESP_OPT_COUNT = 7 175 ESP_OPT_COUNT = 7
176}; 176};
177enum AimBone {
178 AIM_BONE_HEAD = 0,
179 AIM_BONE_TORSO,
180 AIM_BONE_LARM,
181 AIM_BONE_RARM,
182 AIM_BONE_LLEG,
183 AIM_BONE_RLEG,
184 AIM_BONE_COUNT
185};
186
187// ---------------------------------------------------------------------------
188// feature state / settings (owned by menu.cpp until the text menu is removed)
189// ---------------------------------------------------------------------------
190
191struct FeatureState {
192 bool active;
193 int bind; // SDL scancode, 0 = none (always-on)
194};
195
196extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp,
197 g_aimbot, g_triggerbot, g_silentaim;
198extern bool g_bhop_autostrafe;
199extern bool g_jumpbug_assist;
200extern bool g_spread_no_spread;
201extern bool g_aim_bones[AIM_BONE_COUNT];
202extern int g_aim_smooth;
203extern bool g_aim_vischeck;
204extern int g_aim_fov;
205extern bool g_aim_fov_circle;
206extern int g_silent_fov;
207extern bool g_esp_opt[ESP_OPT_COUNT];
208
209const char *scancode_name(int sc);
210void config_save();
211void config_reload();
212void config_reset_defaults();
213const char *config_path_cstr();
177 214
178// --------------------------------------------------------------------------- 215// ---------------------------------------------------------------------------
179// cross-file declarations 216// cross-file declarations
@@ -237,6 +274,8 @@ void gui_draw();
237bool gui_is_open(); 274bool gui_is_open();
238bool gui_bind_capture_active(); 275bool gui_bind_capture_active();
239QAngle gui_frozen_view(); 276QAngle gui_frozen_view();
277void gui_config_init();
278void gui_config_write(FILE *f);
240// ISurface pointer (defined in menu.cpp, used for drawing tests) 279// ISurface pointer (defined in menu.cpp, used for drawing tests)
241struct ISurface; 280struct ISurface;
242extern ISurface *g_surface; 281extern ISurface *g_surface;
diff --git a/src/menu.cpp b/src/menu.cpp
index a0cf323..2a96b02 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -52,47 +52,33 @@ struct MenuNode {
52 int value_step = 0; 52 int value_step = 0;
53}; 53};
54 54
55// feature data 55// feature data (declared in hl2h.h; shared with the GUI)
56struct FeatureState { 56FeatureState g_bhop{true, 0};
57 bool active; 57bool g_bhop_autostrafe = true;
58 int bind; // SDL scancode, 0 = none 58
59}; 59FeatureState g_abh{true, 0};
60 60FeatureState g_jumpbug{true, 0};
61static FeatureState g_bhop{true, 0}; 61bool g_jumpbug_assist = false;
62static bool g_bhop_autostrafe = true; 62FeatureState g_melee{true, 0};
63 63FeatureState g_spread{true, 0};
64static FeatureState g_abh{true, 0}; 64bool g_spread_no_spread = true;
65static FeatureState g_jumpbug{true, 0}; 65FeatureState g_esp{true, 0};
66static bool g_jumpbug_assist = false; 66FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu
67static FeatureState g_melee{true, 0}; 67FeatureState g_triggerbot{true, 603}; // default Mouse4
68static FeatureState g_spread{true, 0}; 68FeatureState g_silentaim{true, 602}; // default Mouse3
69static bool g_spread_no_spread = true;
70static FeatureState g_esp{true, 0};
71static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu
72static FeatureState g_triggerbot{true, 603}; // default Mouse4
73static FeatureState g_silentaim{true, 602}; // default Mouse3
74 69
75// Aimbot bone checklist. Head defaults on (v1 behaviour). 70// Aimbot bone checklist. Head defaults on (v1 behaviour).
76enum { 71bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false,
77 AIM_BONE_HEAD = 0, 72 false, false, false};
78 AIM_BONE_TORSO, 73int g_aim_smooth = 5; // degrees per tick
79 AIM_BONE_LARM, 74bool g_aim_vischeck = true;
80 AIM_BONE_RARM, 75int g_aim_fov = 60; // angular distance from the crosshair
81 AIM_BONE_LLEG, 76bool g_aim_fov_circle = true;
82 AIM_BONE_RLEG, 77int g_silent_fov = 60;
83 AIM_BONE_COUNT
84};
85static bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false,
86 false, false, false};
87static int g_aim_smooth = 5; // degrees per tick
88static bool g_aim_vischeck = true;
89static int g_aim_fov = 60; // angular distance from the crosshair
90static bool g_aim_fov_circle = true;
91static int g_silent_fov = 60;
92 78
93// ESP sub-options (menu "ESP" children). Defaults match the pre-option 79// ESP sub-options (menu "ESP" children). Defaults match the pre-option
94// behaviour: everything on. 80// behaviour: everything on.
95static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true, true, true}; 81bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true, true, true};
96 82
97// tree 83// tree
98static MenuNode g_root{NODE_ROOT, "HL2hake", false, 0, {}, nullptr, nullptr, nullptr}; 84static MenuNode g_root{NODE_ROOT, "HL2hake", false, 0, {}, nullptr, nullptr, nullptr};
@@ -315,18 +301,18 @@ void register_bundled_font() {
315 logf("font: failed to register %s", path.c_str()); 301 logf("font: failed to register %s", path.c_str());
316} 302}
317 303
318static void config_save() { 304void config_save() {
319 FILE *f = fopen(config_path().c_str(), "w"); 305 FILE *f = fopen(config_path().c_str(), "w");
320 if (!f) 306 if (!f)
321 return; 307 return;
322 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, 308 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active,
323 g_bhop.bind, g_bhop_autostrafe); 309 g_bhop.bind, g_bhop_autostrafe);
324 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 310 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind);
325 fprintf(f, "[jumpbug]\nactive=%d\nassist=%d\n", g_jumpbug.active, 311 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n",
326 (int)g_jumpbug_assist); 312 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist);
327 fprintf(f, "[melee]\nactive=%d\n", g_melee.active); 313 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind);
328 fprintf(f, "[spread]\nactive=%d\nno_spread=%d\n", g_spread.active, 314 fprintf(f, "[spread]\nactive=%d\nbind=%d\nno_spread=%d\n",
329 (int)g_spread_no_spread); 315 g_spread.active, g_spread.bind, (int)g_spread_no_spread);
330 fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\nvischeck=%d\n" 316 fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\nvischeck=%d\n"
331 "fov=%d\nfov_circle=%d\n" 317 "fov=%d\nfov_circle=%d\n"
332 "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n" 318 "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n"
@@ -347,6 +333,7 @@ static void config_save() {
347 g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], g_esp_opt[ESP_OPT_SHOW_NAME], 333 g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], g_esp_opt[ESP_OPT_SHOW_NAME],
348 g_esp_opt[ESP_OPT_SHOW_SKELETON], g_esp_opt[ESP_OPT_SHOW_BOX], 334 g_esp_opt[ESP_OPT_SHOW_SKELETON], g_esp_opt[ESP_OPT_SHOW_BOX],
349 g_esp_opt[ESP_OPT_SHOW_SPEEDGRAPH]); 335 g_esp_opt[ESP_OPT_SHOW_SPEEDGRAPH]);
336 gui_config_write(f);
350 fclose(f); 337 fclose(f);
351} 338}
352 339
@@ -462,6 +449,40 @@ static void config_load() {
462 fclose(f); 449 fclose(f);
463} 450}
464 451
452void config_reload() { config_load(); }
453
454const char *config_path_cstr() {
455 static std::string path;
456 path = config_path();
457 return path.c_str();
458}
459
460void config_reset_defaults() {
461 g_bhop = {true, 0};
462 g_bhop_autostrafe = true;
463 g_abh = {true, 0};
464 g_jumpbug = {true, 0};
465 g_jumpbug_assist = false;
466 g_melee = {true, 0};
467 g_spread = {true, 0};
468 g_spread_no_spread = true;
469 g_esp = {true, 0};
470 for (int i = 0; i < ESP_OPT_COUNT; i++)
471 g_esp_opt[i] = true;
472 g_aimbot = {true, 604};
473 g_triggerbot = {true, 603};
474 g_silentaim = {true, 602};
475 for (int i = 0; i < AIM_BONE_COUNT; i++)
476 g_aim_bones[i] = false;
477 g_aim_bones[AIM_BONE_HEAD] = true;
478 g_aim_smooth = 5;
479 g_aim_vischeck = true;
480 g_aim_fov = 60;
481 g_aim_fov_circle = true;
482 g_silent_fov = 60;
483 config_save();
484}
485
465// --------------------------------------------------------------------------- 486// ---------------------------------------------------------------------------
466// menu input handling 487// menu input handling
467// --------------------------------------------------------------------------- 488// ---------------------------------------------------------------------------
@@ -477,7 +498,7 @@ static constexpr int SCAN_ENTER = 40;
477static constexpr int SCAN_ESCAPE = 41; 498static constexpr int SCAN_ESCAPE = 41;
478 499
479// simplified scancode-to-name for common keys 500// simplified scancode-to-name for common keys
480static const char *scancode_name(int sc) { 501const char *scancode_name(int sc) {
481 switch (sc) { 502 switch (sc) {
482 case 0: return "None"; 503 case 0: return "None";
483 case 4: return "A"; case 5: return "B"; case 6: return "C"; 504 case 4: return "A"; case 5: return "B"; case 6: return "C";
@@ -497,9 +518,12 @@ static const char *scancode_name(int sc) {
497 case 43: return "Tab"; case 44: return "Space"; 518 case 43: return "Tab"; case 44: return "Space";
498 case 79: return "Right"; case 80: return "Left"; 519 case 79: return "Right"; case 80: return "Left";
499 case 81: return "Down"; case 82: return "Up"; 520 case 81: return "Down"; case 82: return "Up";
500 case 87: return "F1"; case 88: return "F2"; case 89: return "F3"; 521 case 58: return "F1"; case 59: return "F2"; case 60: return "F3";
501 case 90: return "F4"; case 91: return "F5"; case 92: return "F6"; 522 case 61: return "F4"; case 62: return "F5"; case 63: return "F6";
502 case 93: return "F7"; case 94: return "F8"; 523 case 64: return "F7"; case 65: return "F8"; case 66: return "F9";
524 case 67: return "F10"; case 68: return "F11"; case 69: return "F12";
525 case 73: return "Insert"; case 74: return "Home"; case 75: return "PgUp";
526 case 76: return "Delete"; case 77: return "End"; case 78: return "PgDn";
503 case 600: return "MouseL"; case 601: return "MouseR"; 527 case 600: return "MouseL"; case 601: return "MouseR";
504 case 602: return "MouseM"; case 603: return "Mouse4"; 528 case 602: return "MouseM"; case 603: return "Mouse4";
505 case 604: return "Mouse5"; 529 case 604: return "Mouse5";
@@ -1009,6 +1033,7 @@ void install_menu() {
1009 register_bundled_font(); 1033 register_bundled_font();
1010 logf("config: %s", config_path().c_str()); 1034 logf("config: %s", config_path().c_str());
1011 config_load(); 1035 config_load();
1036 gui_config_init();
1012 // resolve ISurface once (used by the DrawPrintText hook in hl2h.cpp and 1037 // resolve ISurface once (used by the DrawPrintText hook in hl2h.cpp and
1013 // by outer_draw). DrawPrintText hook is installed from hkdCreateMove. 1038 // by outer_draw). DrawPrintText hook is installed from hkdCreateMove.
1014 g_surface = find_surface_interface(); 1039 g_surface = find_surface_interface();