summaryrefslogtreecommitdiffstats
path: root/src/menu.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-26 15:44:45 +0100
committersalmonik <salmonik@tuta.io>2026-10-26 15:44:45 +0100
commit15e4d33220bedb62beac635580fa4d222a7f5863 (patch)
tree46cd1ee202b7d9d0597b7a91b6716ce4bef6d1a3 /src/menu.cpp
parentESP: vertical health bar right of the box, HP number beside it (diff)
downloadhl2h-15e4d33220bedb62beac635580fa4d222a7f5863.tar.gz
hl2h-15e4d33220bedb62beac635580fa4d222a7f5863.zip
ESP: menu toggles for neutral/healthbar/healthnum/name
Diffstat (limited to 'src/menu.cpp')
-rw-r--r--src/menu.cpp44
1 files changed, 39 insertions, 5 deletions
diff --git a/src/menu.cpp b/src/menu.cpp
index 302eab3..2caf0aa 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -37,7 +37,7 @@ struct MenuNode {
37 const char *label; 37 const char *label;
38 bool expanded; // for root/feature: whether children are visible 38 bool expanded; // for root/feature: whether children are visible
39 int child_count; 39 int child_count;
40 MenuNode *children[4]; // max children per node 40 MenuNode *children[8]; // max children per node
41 41
42 // leaf data 42 // leaf data
43 bool *active_ptr; // NODE_TOGGLE: pointer to the active flag 43 bool *active_ptr; // NODE_TOGGLE: pointer to the active flag
@@ -55,6 +55,11 @@ static FeatureState g_bhop{true, 0};
55 55
56static FeatureState g_abh{true, 0}; 56static FeatureState g_abh{true, 0};
57static FeatureState g_esp{true, 0}; 57static FeatureState g_esp{true, 0};
58
59// ESP sub-options (menu "ESP" children). Defaults match the pre-option
60// behaviour: everything on.
61static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true};
62
58// tree 63// tree
59static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr}; 64static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr};
60static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr}; 65static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr};
@@ -63,8 +68,14 @@ static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, n
63static MenuNode g_abh_active{NODE_TOGGLE, "Active", false, 0, {}, &g_abh.active, nullptr, nullptr}; 68static MenuNode g_abh_active{NODE_TOGGLE, "Active", false, 0, {}, &g_abh.active, nullptr, nullptr};
64static MenuNode g_esp_feat{NODE_FEATURE, "ESP", true, 1, {}, nullptr, nullptr, nullptr}; 69static MenuNode g_esp_feat{NODE_FEATURE, "ESP", true, 1, {}, nullptr, nullptr, nullptr};
65static MenuNode g_esp_active{NODE_TOGGLE, "Active", false, 0, {}, &g_esp.active, nullptr, nullptr}; 70static MenuNode g_esp_active{NODE_TOGGLE, "Active", false, 0, {}, &g_esp.active, nullptr, nullptr};
71static MenuNode g_esp_opt_nodes[ESP_OPT_COUNT] = {
72 {NODE_TOGGLE, "Show neutral", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_NEUTRAL], nullptr, nullptr},
73 {NODE_TOGGLE, "Show healthbar", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_HEALTHBAR], nullptr, nullptr},
74 {NODE_TOGGLE, "Show healthnum", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], nullptr, nullptr},
75 {NODE_TOGGLE, "Show name", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_NAME], nullptr, nullptr},
76};
66 77
67static MenuNode *g_visible[16]; // flattened visible nodes for arrow navigation 78static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation
68static int g_visible_count = 0; 79static int g_visible_count = 0;
69static int g_selected = 0; 80static int g_selected = 0;
70bool g_menu_open = false; 81bool g_menu_open = false;
@@ -74,16 +85,19 @@ static void build_tree() {
74 g_bhop_feat.children[0] = &g_bhop_active; 85 g_bhop_feat.children[0] = &g_bhop_active;
75 g_abh_feat.children[0] = &g_abh_active; 86 g_abh_feat.children[0] = &g_abh_active;
76 g_esp_feat.children[0] = &g_esp_active; 87 g_esp_feat.children[0] = &g_esp_active;
88 for (int i = 0; i < ESP_OPT_COUNT; i++)
89 g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i];
90 g_esp_feat.child_count = ESP_OPT_COUNT + 1;
77 g_root.children[0] = &g_bhop_feat; 91 g_root.children[0] = &g_bhop_feat;
78 g_root.children[1] = &g_abh_feat; 92 g_root.children[1] = &g_abh_feat;
79 g_root.children[2] = &g_esp_feat; 93 g_root.children[2] = &g_esp_feat;
80 g_root.child_count = 3; 94 g_root.child_count = 3;
81} 95}
82 96
83static int g_depth[16]; // depth of each visible row (for indentation) 97static int g_depth[32]; // depth of each visible row (for indentation)
84 98
85static void flatten(MenuNode *node, int depth) { 99static void flatten(MenuNode *node, int depth) {
86 if (g_visible_count >= 16) 100 if (g_visible_count >= 32)
87 return; 101 return;
88 node->type = (depth == 0) ? NODE_ROOT 102 node->type = (depth == 0) ? NODE_ROOT
89 : (node->child_count > 0) ? NODE_FEATURE 103 : (node->child_count > 0) ? NODE_FEATURE
@@ -139,7 +153,11 @@ static void config_save() {
139 return; 153 return;
140 fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind); 154 fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind);
141 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 155 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind);
142 fprintf(f, "[esp]\nactive=%d\nbind=%d\n", g_esp.active, g_esp.bind); 156 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n"
157 "healthnum=%d\nname=%d\n",
158 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL],
159 g_esp_opt[ESP_OPT_SHOW_HEALTHBAR],
160 g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], g_esp_opt[ESP_OPT_SHOW_NAME]);
143 fclose(f); 161 fclose(f);
144} 162}
145 163
@@ -149,6 +167,7 @@ static void config_load() {
149 return; 167 return;
150 char line[256]; 168 char line[256];
151 FeatureState *cur = nullptr; 169 FeatureState *cur = nullptr;
170 bool in_esp = false;
152 while (fgets(line, sizeof(line), f)) { 171 while (fgets(line, sizeof(line), f)) {
153 line[strcspn(line, "\r\n")] = 0; 172 line[strcspn(line, "\r\n")] = 0;
154 if (line[0] == '[') { 173 if (line[0] == '[') {
@@ -160,12 +179,23 @@ static void config_load() {
160 cur = &g_esp; 179 cur = &g_esp;
161 else 180 else
162 cur = nullptr; 181 cur = nullptr;
182 in_esp = (cur == &g_esp);
163 } else if (cur) { 183 } else if (cur) {
164 char *eq = strchr(line, '='); 184 char *eq = strchr(line, '=');
165 if (!eq) 185 if (!eq)
166 continue; 186 continue;
167 *eq = 0; 187 *eq = 0;
168 const char *key = line, *val = eq + 1; 188 const char *key = line, *val = eq + 1;
189 if (in_esp) {
190 if (strcmp(key, "neutral") == 0)
191 g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0;
192 else if (strcmp(key, "healthbar") == 0)
193 g_esp_opt[ESP_OPT_SHOW_HEALTHBAR] = atoi(val) != 0;
194 else if (strcmp(key, "healthnum") == 0)
195 g_esp_opt[ESP_OPT_SHOW_HEALTHNUM] = atoi(val) != 0;
196 else if (strcmp(key, "name") == 0)
197 g_esp_opt[ESP_OPT_SHOW_NAME] = atoi(val) != 0;
198 }
169 if (strcmp(key, "active") == 0) 199 if (strcmp(key, "active") == 0)
170 cur->active = atoi(val) != 0; 200 cur->active = atoi(val) != 0;
171 else if (strcmp(key, "bind") == 0) 201 else if (strcmp(key, "bind") == 0)
@@ -285,6 +315,10 @@ bool feature_active(int feature) {
285 return f->bind == 0 || key_held(f->bind); 315 return f->bind == 0 || key_held(f->bind);
286} 316}
287 317
318bool esp_option(int opt) {
319 return opt >= 0 && opt < ESP_OPT_COUNT && g_esp_opt[opt];
320}
321
288static void menu_handle_input() { 322static void menu_handle_input() {
289 poll_keyboard(); 323 poll_keyboard();
290 324