diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-27 18:31:27 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-27 18:31:27 +0100 |
| commit | f1794edcc60f6a27e622884c82397bb77e2aa280 (patch) | |
| tree | ca1bf9aa40a612e8e7b1d1a76ff65bdddabd1add /src | |
| parent | GUI: Insert-only close, freeze mouse look at the source (diff) | |
| download | hl2h-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.cpp | 448 | ||||
| -rw-r--r-- | src/hl2h.h | 39 | ||||
| -rw-r--r-- | src/menu.cpp | 117 |
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 | ||
| 179 | enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET }; | ||
| 180 | |||
| 180 | struct Ctrl { | 181 | struct 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 | ||
| 188 | struct Card { | 191 | struct 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]; | |||
| 199 | static int g_nctrl = 0; | 201 | static int g_nctrl = 0; |
| 200 | static Card g_cards[40]; | 202 | static Card g_cards[40]; |
| 201 | static int g_ncards = 0; | 203 | static int g_ncards = 0; |
| 202 | static int g_vals[192]; | 204 | static bool g_cards_built = false; |
| 203 | static bool g_demo_built = false; | 205 | static bool g_layout_loaded = false; |
| 206 | static bool g_reset_armed = false; | ||
| 207 | static double g_reset_armed_at = 0.0; | ||
| 208 | static char g_config_label[512]; | ||
| 209 | static char g_build_label[128]; | ||
| 204 | 210 | ||
| 205 | static const char *g_cats[] = {"Movement", "Combat", "Visuals", "Weapons", | 211 | static const char *g_cats[] = {"Movement", "Combat", "Visuals", "Weapons", |
| 206 | "System"}; | 212 | "System"}; |
| 207 | static constexpr int CAT_COUNT = 5; | 213 | static constexpr int CAT_COUNT = 5; |
| 208 | 214 | ||
| 209 | static int add_card(int cat, const char *title, const char *desc, | 215 | static 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 | } |
| 222 | static void add_ctrl(int card, int kind, const char *label, const char *desc, | 227 | static 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 | } |
| 234 | static void add_toggle(int card, const char *label, const char *desc, | 241 | static 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 | } |
| 238 | static void add_slider(int card, const char *label, const char *desc, int min, | 245 | static 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 | } |
| 242 | static void add_section(int card, const char *label) { | 249 | static 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 | } |
| 245 | static void add_info(int card, const char *label) { | 252 | static 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 | } |
| 248 | static void add_button(int card, const char *label, const char *desc) { | 255 | static 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 | ||
| 252 | static void build_demo() { | 260 | static 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 | } | ||
| 267 | static 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 | |||
| 281 | static 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; | |||
| 344 | static bool g_mouse_down = false; | 390 | static bool g_mouse_down = false; |
| 345 | static bool g_mouse_rclick = false; | 391 | static bool g_mouse_rclick = false; |
| 346 | static unsigned int g_prev_mask = 0; | 392 | static unsigned int g_prev_mask = 0; |
| 393 | static int g_mouse_press = 0; // 1..5 on the frame a button goes down | ||
| 347 | static unsigned char g_prev_keys[512] = {}; | 394 | static unsigned char g_prev_keys[512] = {}; |
| 348 | static bool g_prev_cursor = true; | 395 | static bool g_prev_cursor = true; |
| 349 | static bool g_prev_relative = true; | 396 | static 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 | ||
| 483 | static 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 | |||
| 498 | static void layout() { | 530 | static 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; } | |||
| 1192 | QAngle gui_frozen_view() { return g_frozen; } | 1286 | QAngle gui_frozen_view() { return g_frozen; } |
| 1193 | 1287 | ||
| 1194 | // --------------------------------------------------------------------------- | 1288 | // --------------------------------------------------------------------------- |
| 1289 | // [gui] layout persistence | ||
| 1290 | // --------------------------------------------------------------------------- | ||
| 1291 | |||
| 1292 | static 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 | |||
| 1341 | void gui_config_init() { | ||
| 1342 | build_cards(); | ||
| 1343 | if (g_layout_loaded) | ||
| 1344 | return; | ||
| 1345 | g_layout_loaded = true; | ||
| 1346 | gui_load_layout(); | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | void 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 |
| @@ -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 | }; |
| 177 | enum 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 | |||
| 191 | struct FeatureState { | ||
| 192 | bool active; | ||
| 193 | int bind; // SDL scancode, 0 = none (always-on) | ||
| 194 | }; | ||
| 195 | |||
| 196 | extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, | ||
| 197 | g_aimbot, g_triggerbot, g_silentaim; | ||
| 198 | extern bool g_bhop_autostrafe; | ||
| 199 | extern bool g_jumpbug_assist; | ||
| 200 | extern bool g_spread_no_spread; | ||
| 201 | extern bool g_aim_bones[AIM_BONE_COUNT]; | ||
| 202 | extern int g_aim_smooth; | ||
| 203 | extern bool g_aim_vischeck; | ||
| 204 | extern int g_aim_fov; | ||
| 205 | extern bool g_aim_fov_circle; | ||
| 206 | extern int g_silent_fov; | ||
| 207 | extern bool g_esp_opt[ESP_OPT_COUNT]; | ||
| 208 | |||
| 209 | const char *scancode_name(int sc); | ||
| 210 | void config_save(); | ||
| 211 | void config_reload(); | ||
| 212 | void config_reset_defaults(); | ||
| 213 | const char *config_path_cstr(); | ||
| 177 | 214 | ||
| 178 | // --------------------------------------------------------------------------- | 215 | // --------------------------------------------------------------------------- |
| 179 | // cross-file declarations | 216 | // cross-file declarations |
| @@ -237,6 +274,8 @@ void gui_draw(); | |||
| 237 | bool gui_is_open(); | 274 | bool gui_is_open(); |
| 238 | bool gui_bind_capture_active(); | 275 | bool gui_bind_capture_active(); |
| 239 | QAngle gui_frozen_view(); | 276 | QAngle gui_frozen_view(); |
| 277 | void gui_config_init(); | ||
| 278 | void 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) |
| 241 | struct ISurface; | 280 | struct ISurface; |
| 242 | extern ISurface *g_surface; | 281 | extern 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) |
| 56 | struct FeatureState { | 56 | FeatureState g_bhop{true, 0}; |
| 57 | bool active; | 57 | bool g_bhop_autostrafe = true; |
| 58 | int bind; // SDL scancode, 0 = none | 58 | |
| 59 | }; | 59 | FeatureState g_abh{true, 0}; |
| 60 | 60 | FeatureState g_jumpbug{true, 0}; | |
| 61 | static FeatureState g_bhop{true, 0}; | 61 | bool g_jumpbug_assist = false; |
| 62 | static bool g_bhop_autostrafe = true; | 62 | FeatureState g_melee{true, 0}; |
| 63 | 63 | FeatureState g_spread{true, 0}; | |
| 64 | static FeatureState g_abh{true, 0}; | 64 | bool g_spread_no_spread = true; |
| 65 | static FeatureState g_jumpbug{true, 0}; | 65 | FeatureState g_esp{true, 0}; |
| 66 | static bool g_jumpbug_assist = false; | 66 | FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu |
| 67 | static FeatureState g_melee{true, 0}; | 67 | FeatureState g_triggerbot{true, 603}; // default Mouse4 |
| 68 | static FeatureState g_spread{true, 0}; | 68 | FeatureState g_silentaim{true, 602}; // default Mouse3 |
| 69 | static bool g_spread_no_spread = true; | ||
| 70 | static FeatureState g_esp{true, 0}; | ||
| 71 | static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu | ||
| 72 | static FeatureState g_triggerbot{true, 603}; // default Mouse4 | ||
| 73 | static 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). |
| 76 | enum { | 71 | bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, |
| 77 | AIM_BONE_HEAD = 0, | 72 | false, false, false}; |
| 78 | AIM_BONE_TORSO, | 73 | int g_aim_smooth = 5; // degrees per tick |
| 79 | AIM_BONE_LARM, | 74 | bool g_aim_vischeck = true; |
| 80 | AIM_BONE_RARM, | 75 | int g_aim_fov = 60; // angular distance from the crosshair |
| 81 | AIM_BONE_LLEG, | 76 | bool g_aim_fov_circle = true; |
| 82 | AIM_BONE_RLEG, | 77 | int g_silent_fov = 60; |
| 83 | AIM_BONE_COUNT | ||
| 84 | }; | ||
| 85 | static bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, | ||
| 86 | false, false, false}; | ||
| 87 | static int g_aim_smooth = 5; // degrees per tick | ||
| 88 | static bool g_aim_vischeck = true; | ||
| 89 | static int g_aim_fov = 60; // angular distance from the crosshair | ||
| 90 | static bool g_aim_fov_circle = true; | ||
| 91 | static 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. |
| 95 | static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true, true, true}; | 81 | bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true, true, true}; |
| 96 | 82 | ||
| 97 | // tree | 83 | // tree |
| 98 | static MenuNode g_root{NODE_ROOT, "HL2hake", false, 0, {}, nullptr, nullptr, nullptr}; | 84 | static 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 | ||
| 318 | static void config_save() { | 304 | void 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 | ||
| 452 | void config_reload() { config_load(); } | ||
| 453 | |||
| 454 | const char *config_path_cstr() { | ||
| 455 | static std::string path; | ||
| 456 | path = config_path(); | ||
| 457 | return path.c_str(); | ||
| 458 | } | ||
| 459 | |||
| 460 | void 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; | |||
| 477 | static constexpr int SCAN_ESCAPE = 41; | 498 | static constexpr int SCAN_ESCAPE = 41; |
| 478 | 499 | ||
| 479 | // simplified scancode-to-name for common keys | 500 | // simplified scancode-to-name for common keys |
| 480 | static const char *scancode_name(int sc) { | 501 | const 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(); |
