summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-26 17:02:45 +0100
committersalmonik <salmonik@tuta.io>2026-10-26 17:02:45 +0100
commitab3d725cacbe8cd7153c02faf2d9fe6df7e37949 (patch)
tree2bc17507d9fb0b6f37e2a6e62f1c210d16756c66 /src
parentAimbot: fix eye height (m_vecViewOffset Z, not X); prefer head hitbox (diff)
downloadhl2h-ab3d725cacbe8cd7153c02faf2d9fe6df7e37949.tar.gz
hl2h-ab3d725cacbe8cd7153c02faf2d9fe6df7e37949.zip
Aimbot v2: bone checklist and numeric smoothness
- Aimbot -> Bones: Head, Torso (chest+stomach), Left/Right arm, Left/Right leg; the aimbot aims at the nearest selected hitbox point on the chosen target (head uses the head hitbox/bone fallback) - Aimbot -> Smoothness: value 1..45 deg/tick, Left/Right in the menu to adjust, persisted as smooth=N; default 5 (previous behaviour) - config: bone_* toggles + smooth under [aimbot] - menu gains a NODE_VALUE type (right-aligned value, Left/Right edit)
Diffstat (limited to '')
-rw-r--r--src/bones.cpp32
-rw-r--r--src/esp.cpp40
-rw-r--r--src/hl2h.h3
-rw-r--r--src/menu.cpp107
4 files changed, 164 insertions, 18 deletions
diff --git a/src/bones.cpp b/src/bones.cpp
index abcaac6..12c7406 100644
--- a/src/bones.cpp
+++ b/src/bones.cpp
@@ -460,3 +460,35 @@ bool head_position(int idx, Vector &out) {
460 } 460 }
461 return false; 461 return false;
462} 462}
463
464// Collect world-space aim points for the selected hit groups (HITGROUP_*).
465// Group 1 (head) uses head_position for its bone fallback; other groups are
466// the hitbox centers. The caller picks the point nearest to the crosshair.
467int aim_points(int idx, unsigned group_mask, Vector *out, int max) {
468 if (!out || max <= 0)
469 return 0;
470 BoneEntry *e = find_entry(idx);
471 if (!e || !e->valid || !e->hdr)
472 return 0;
473 int n = 0;
474 if ((group_mask & (1u << 1)) && n < max) {
475 Vector head;
476 if (head_position(idx, head))
477 out[n++] = head;
478 }
479 const HitboxSet *s = hitbox_set0(e->hdr);
480 if (!s)
481 return n;
482 const Hitbox *boxes = hitboxes(s);
483 for (int i = 0; i < s->numhitboxes && n < max; i++) {
484 int g = boxes[i].group;
485 if (g <= 1 || g > 7)
486 continue;
487 if (!(group_mask & (1u << g)))
488 continue;
489 Vector p;
490 if (hitbox_world(e, boxes[i], p))
491 out[n++] = p;
492 }
493 return n;
494}
diff --git a/src/esp.cpp b/src/esp.cpp
index 2987508..fbeb234 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -337,6 +337,9 @@ static QAngle angle_to(const Vector &from, const Vector &to) {
337bool aimbot_apply(CUserCmd *cmd) { 337bool aimbot_apply(CUserCmd *cmd) {
338 if (!g_iface.entitylist || g_net.origin < 0 || g_net.maxs < 0) 338 if (!g_iface.entitylist || g_net.origin < 0 || g_net.maxs < 0)
339 return false; 339 return false;
340 unsigned bone_mask = aimbot_bone_mask();
341 if (!bone_mask)
342 return false;
340 int local = engine_get_local_player(); 343 int local = engine_get_local_player();
341 if (local <= 0) 344 if (local <= 0)
342 return false; 345 return false;
@@ -388,7 +391,8 @@ bool aimbot_apply(CUserCmd *cmd) {
388 Vector origin{*(float *)(e + g_net.origin), 391 Vector origin{*(float *)(e + g_net.origin),
389 *(float *)(e + g_net.origin + 4), 392 *(float *)(e + g_net.origin + 4),
390 *(float *)(e + g_net.origin + 8)}; 393 *(float *)(e + g_net.origin + 8)};
391 Vector approx{origin.x, origin.y, origin.z + maxz * 0.9f}; 394 Vector approx{origin.x, origin.y,
395 origin.z + maxz * ((bone_mask & (1u << 1)) ? 0.9f : 0.55f)};
392 float fov = getfov(view, angle_to(g_cam_eye, approx)); 396 float fov = getfov(view, angle_to(g_cam_eye, approx));
393 if (fov >= best_fov) 397 if (fov >= best_fov)
394 continue; 398 continue;
@@ -416,24 +420,33 @@ bool aimbot_apply(CUserCmd *cmd) {
416 best_head.x, best_head.y, best_head.z); 420 best_head.x, best_head.y, best_head.z);
417 } 421 }
418 422
419 // Refine to the actual head hitbox/bone for the chosen target only. 423 // Refine to the nearest selected hitbox/bone point on the chosen target.
420 bool exact_head = false; 424 Vector pts[32];
425 int npoints = 0;
421 void *best_ent = entitylist_get(best_idx); 426 void *best_ent = entitylist_get(best_idx);
422 if (best_ent && bones_update(best_idx, best_ent)) { 427 if (best_ent && bones_update(best_idx, best_ent))
423 Vector head; 428 npoints = aim_points(best_idx, bone_mask, pts, 32);
424 if (head_position(best_idx, head) && 429 if (npoints <= 0)
425 getfov(view, angle_to(g_cam_eye, head)) <= MAX_FOV) { 430 return false;
426 best_head = head; 431 float aim_fov = 1e9f;
427 exact_head = true; 432 Vector aim_pt{};
433 for (int i = 0; i < npoints; i++) {
434 float f = getfov(view, angle_to(g_cam_eye, pts[i]));
435 if (f < aim_fov) {
436 aim_fov = f;
437 aim_pt = pts[i];
428 } 438 }
429 } 439 }
440 if (aim_fov > MAX_FOV)
441 return false;
442 best_head = aim_pt;
430 443
431 QAngle desired = angle_to(g_cam_eye, best_head); 444 QAngle desired = angle_to(g_cam_eye, best_head);
432 static int want_logs = 0; 445 static int want_logs = 0;
433 if (want_logs < 10) { 446 if (want_logs < 10) {
434 want_logs++; 447 want_logs++;
435 logf("aimbot: head=(%.1f %.1f %.1f) exact=%d want=%.2f/%.2f", 448 logf("aimbot: aim=(%.1f %.1f %.1f) points=%d fov=%.2f want=%.2f/%.2f",
436 best_head.x, best_head.y, best_head.z, (int)exact_head, desired.x, 449 best_head.x, best_head.y, best_head.z, npoints, aim_fov, desired.x,
437 desired.y); 450 desired.y);
438 } 451 }
439 float dp = desired.x - cmd->viewangles[0]; 452 float dp = desired.x - cmd->viewangles[0];
@@ -442,12 +455,13 @@ bool aimbot_apply(CUserCmd *cmd) {
442 while (dy < -180.0f) dy += 360.0f; 455 while (dy < -180.0f) dy += 360.0f;
443 456
444 constexpr float DEADZONE = 0.05f; 457 constexpr float DEADZONE = 0.05f;
445 constexpr float MAX_STEP = 5.0f; 458 float max_step = (float)aimbot_smooth_step();
459 if (max_step < 1.0f) max_step = 1.0f;
446 float maxd = fmaxf(fabsf(dp), fabsf(dy)); 460 float maxd = fmaxf(fabsf(dp), fabsf(dy));
447 if (maxd <= DEADZONE) 461 if (maxd <= DEADZONE)
448 return false; 462 return false;
449 463
450 float scale = (maxd > MAX_STEP) ? (MAX_STEP / maxd) : 1.0f; 464 float scale = (maxd > max_step) ? (max_step / maxd) : 1.0f;
451 float old_pitch = cmd->viewangles[0]; 465 float old_pitch = cmd->viewangles[0];
452 float old_yaw = cmd->viewangles[1]; 466 float old_yaw = cmd->viewangles[1];
453 float np = cmd->viewangles[0] + dp * scale; 467 float np = cmd->viewangles[0] + dp * scale;
diff --git a/src/hl2h.h b/src/hl2h.h
index f92b919..e27433f 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -165,6 +165,8 @@ void init_conmsg();
165bool feature_active(int feature); 165bool feature_active(int feature);
166bool esp_option(int opt); 166bool esp_option(int opt);
167bool bhop_autostrafe_enabled(); 167bool bhop_autostrafe_enabled();
168unsigned aimbot_bone_mask();
169int aimbot_smooth_step();
168void *entitylist_get(int idx); 170void *entitylist_get(int idx);
169int engine_get_local_player(); 171int engine_get_local_player();
170void draw_text_col(int x, int y, const char *s, int r, int g, int b); 172void draw_text_col(int x, int y, const char *s, int r, int g, int b);
@@ -182,6 +184,7 @@ int bone_nearest_core_parent(int idx, int bone);
182bool bones_is_humanoid(int idx); 184bool bones_is_humanoid(int idx);
183bool hitbox_center(int idx, const char *hitbox_name, Vector &out); 185bool hitbox_center(int idx, const char *hitbox_name, Vector &out);
184bool head_position(int idx, Vector &out); 186bool head_position(int idx, Vector &out);
187int aim_points(int idx, unsigned group_mask, Vector *out, int max);
185 188
186void outer_draw(); 189void outer_draw();
187// raw ISurface slot calls used by the PaintTraverseEx hook (hl2h.cpp) 190// raw ISurface slot calls used by the PaintTraverseEx hook (hl2h.cpp)
diff --git a/src/menu.cpp b/src/menu.cpp
index 269174d..56f8c95 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -30,7 +30,7 @@ void init_conmsg() {
30// menu tree structure 30// menu tree structure
31// --------------------------------------------------------------------------- 31// ---------------------------------------------------------------------------
32 32
33enum NodeType { NODE_ROOT, NODE_FEATURE, NODE_TOGGLE, NODE_BIND }; 33enum NodeType { NODE_ROOT, NODE_FEATURE, NODE_TOGGLE, NODE_BIND, NODE_VALUE };
34 34
35struct MenuNode { 35struct MenuNode {
36 NodeType type; 36 NodeType type;
@@ -43,6 +43,10 @@ struct MenuNode {
43 bool *active_ptr; // NODE_TOGGLE: pointer to the active flag 43 bool *active_ptr; // NODE_TOGGLE: pointer to the active flag
44 int *bind_ptr; // NODE_BIND: pointer to the key binding (SDL scancode) 44 int *bind_ptr; // NODE_BIND: pointer to the key binding (SDL scancode)
45 const char *bind_name; // NODE_BIND: current bind display name 45 const char *bind_name; // NODE_BIND: current bind display name
46 int *value_ptr = nullptr; // NODE_VALUE: pointer to the value
47 int value_min = 0;
48 int value_max = 0;
49 int value_step = 0;
46}; 50};
47 51
48// feature data 52// feature data
@@ -58,6 +62,20 @@ static FeatureState g_abh{true, 0};
58static FeatureState g_esp{true, 0}; 62static FeatureState g_esp{true, 0};
59static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu 63static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu
60 64
65// Aimbot bone checklist. Head defaults on (v1 behaviour).
66enum {
67 AIM_BONE_HEAD = 0,
68 AIM_BONE_TORSO,
69 AIM_BONE_LARM,
70 AIM_BONE_RARM,
71 AIM_BONE_LLEG,
72 AIM_BONE_RLEG,
73 AIM_BONE_COUNT
74};
75static bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false,
76 false, false, false};
77static int g_aim_smooth = 5; // degrees per tick
78
61// ESP sub-options (menu "ESP" children). Defaults match the pre-option 79// ESP sub-options (menu "ESP" children). Defaults match the pre-option
62// behaviour: everything on. 80// behaviour: everything on.
63static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true}; 81static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true};
@@ -81,6 +99,17 @@ static MenuNode g_esp_opt_nodes[ESP_OPT_COUNT] = {
81static MenuNode g_aimbot_feat{NODE_FEATURE, "Aimbot", false, 1, {}, nullptr, nullptr, nullptr}; 99static MenuNode g_aimbot_feat{NODE_FEATURE, "Aimbot", false, 1, {}, nullptr, nullptr, nullptr};
82static MenuNode g_aimbot_active{NODE_TOGGLE, "Active", false, 0, {}, &g_aimbot.active, nullptr, nullptr}; 100static MenuNode g_aimbot_active{NODE_TOGGLE, "Active", false, 0, {}, &g_aimbot.active, nullptr, nullptr};
83static MenuNode g_aimbot_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_aimbot.bind, nullptr}; 101static MenuNode g_aimbot_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_aimbot.bind, nullptr};
102static MenuNode g_aimbot_bones_feat{NODE_FEATURE, "Bones", false, 0, {}, nullptr, nullptr, nullptr};
103static MenuNode g_aimbot_bone_nodes[AIM_BONE_COUNT] = {
104 {NODE_TOGGLE, "Head", false, 0, {}, &g_aim_bones[AIM_BONE_HEAD], nullptr, nullptr},
105 {NODE_TOGGLE, "Torso", false, 0, {}, &g_aim_bones[AIM_BONE_TORSO], nullptr, nullptr},
106 {NODE_TOGGLE, "Left arm", false, 0, {}, &g_aim_bones[AIM_BONE_LARM], nullptr, nullptr},
107 {NODE_TOGGLE, "Right arm", false, 0, {}, &g_aim_bones[AIM_BONE_RARM], nullptr, nullptr},
108 {NODE_TOGGLE, "Left leg", false, 0, {}, &g_aim_bones[AIM_BONE_LLEG], nullptr, nullptr},
109 {NODE_TOGGLE, "Right leg", false, 0, {}, &g_aim_bones[AIM_BONE_RLEG], nullptr, nullptr},
110};
111static MenuNode g_aimbot_smooth_node{NODE_VALUE, "Smoothness", false, 0, {}, nullptr,
112 nullptr, nullptr, &g_aim_smooth, 1, 45, 1};
84 113
85static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation 114static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation
86static int g_visible_count = 0; 115static int g_visible_count = 0;
@@ -96,7 +125,12 @@ static void build_tree() {
96 g_esp_feat.children[0] = &g_esp_active; 125 g_esp_feat.children[0] = &g_esp_active;
97 g_aimbot_feat.children[0] = &g_aimbot_active; 126 g_aimbot_feat.children[0] = &g_aimbot_active;
98 g_aimbot_feat.children[1] = &g_aimbot_bind; 127 g_aimbot_feat.children[1] = &g_aimbot_bind;
99 g_aimbot_feat.child_count = 2; 128 g_aimbot_feat.children[2] = &g_aimbot_bones_feat;
129 g_aimbot_feat.children[3] = &g_aimbot_smooth_node;
130 g_aimbot_feat.child_count = 4;
131 for (int i = 0; i < AIM_BONE_COUNT; i++)
132 g_aimbot_bones_feat.children[i] = &g_aimbot_bone_nodes[i];
133 g_aimbot_bones_feat.child_count = AIM_BONE_COUNT;
100 for (int i = 0; i < ESP_OPT_COUNT; i++) 134 for (int i = 0; i < ESP_OPT_COUNT; i++)
101 g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i]; 135 g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i];
102 g_esp_feat.child_count = ESP_OPT_COUNT + 1; 136 g_esp_feat.child_count = ESP_OPT_COUNT + 1;
@@ -115,6 +149,7 @@ static void flatten(MenuNode *node, int depth) {
115 node->type = (depth == 0) ? NODE_ROOT 149 node->type = (depth == 0) ? NODE_ROOT
116 : (node->child_count > 0) ? NODE_FEATURE 150 : (node->child_count > 0) ? NODE_FEATURE
117 : (node->active_ptr) ? NODE_TOGGLE 151 : (node->active_ptr) ? NODE_TOGGLE
152 : (node->value_ptr) ? NODE_VALUE
118 : NODE_BIND; 153 : NODE_BIND;
119 g_depth[g_visible_count] = depth; 154 g_depth[g_visible_count] = depth;
120 g_visible[g_visible_count++] = node; 155 g_visible[g_visible_count++] = node;
@@ -167,8 +202,13 @@ static void config_save() {
167 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, 202 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active,
168 g_bhop.bind, g_bhop_autostrafe); 203 g_bhop.bind, g_bhop_autostrafe);
169 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 204 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind);
170 fprintf(f, "[aimbot]\nactive=%d\nbind=%d\n", g_aimbot.active, 205 fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\n"
171 g_aimbot.bind); 206 "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n"
207 "bone_lleg=%d\nbone_rleg=%d\n",
208 g_aimbot.active, g_aimbot.bind, g_aim_smooth,
209 g_aim_bones[AIM_BONE_HEAD], g_aim_bones[AIM_BONE_TORSO],
210 g_aim_bones[AIM_BONE_LARM], g_aim_bones[AIM_BONE_RARM],
211 g_aim_bones[AIM_BONE_LLEG], g_aim_bones[AIM_BONE_RLEG]);
172 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" 212 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n"
173 "healthnum=%d\nname=%d\nskeleton=%d\n", 213 "healthnum=%d\nname=%d\nskeleton=%d\n",
174 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], 214 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL],
@@ -184,7 +224,7 @@ static void config_load() {
184 return; 224 return;
185 char line[256]; 225 char line[256];
186 FeatureState *cur = nullptr; 226 FeatureState *cur = nullptr;
187 bool in_esp = false, in_bhop = false; 227 bool in_esp = false, in_bhop = false, in_aim = false;
188 while (fgets(line, sizeof(line), f)) { 228 while (fgets(line, sizeof(line), f)) {
189 line[strcspn(line, "\r\n")] = 0; 229 line[strcspn(line, "\r\n")] = 0;
190 if (line[0] == '[') { 230 if (line[0] == '[') {
@@ -200,6 +240,7 @@ static void config_load() {
200 cur = nullptr; 240 cur = nullptr;
201 in_esp = (cur == &g_esp); 241 in_esp = (cur == &g_esp);
202 in_bhop = (cur == &g_bhop); 242 in_bhop = (cur == &g_bhop);
243 in_aim = (cur == &g_aimbot);
203 } else if (cur) { 244 } else if (cur) {
204 char *eq = strchr(line, '='); 245 char *eq = strchr(line, '=');
205 if (!eq) 246 if (!eq)
@@ -209,6 +250,26 @@ static void config_load() {
209 if (in_bhop && strcmp(key, "autostrafe") == 0) { 250 if (in_bhop && strcmp(key, "autostrafe") == 0) {
210 g_bhop_autostrafe = atoi(val) != 0; 251 g_bhop_autostrafe = atoi(val) != 0;
211 } 252 }
253 if (in_aim) {
254 if (strcmp(key, "smooth") == 0) {
255 int v = atoi(val);
256 if (v < 1) v = 1;
257 if (v > 45) v = 45;
258 g_aim_smooth = v;
259 } else if (strcmp(key, "bone_head") == 0) {
260 g_aim_bones[AIM_BONE_HEAD] = atoi(val) != 0;
261 } else if (strcmp(key, "bone_torso") == 0) {
262 g_aim_bones[AIM_BONE_TORSO] = atoi(val) != 0;
263 } else if (strcmp(key, "bone_larm") == 0) {
264 g_aim_bones[AIM_BONE_LARM] = atoi(val) != 0;
265 } else if (strcmp(key, "bone_rarm") == 0) {
266 g_aim_bones[AIM_BONE_RARM] = atoi(val) != 0;
267 } else if (strcmp(key, "bone_lleg") == 0) {
268 g_aim_bones[AIM_BONE_LLEG] = atoi(val) != 0;
269 } else if (strcmp(key, "bone_rleg") == 0) {
270 g_aim_bones[AIM_BONE_RLEG] = atoi(val) != 0;
271 }
272 }
212 if (in_esp) { 273 if (in_esp) {
213 if (strcmp(key, "neutral") == 0) 274 if (strcmp(key, "neutral") == 0)
214 g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0; 275 g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0;
@@ -346,6 +407,25 @@ bool esp_option(int opt) {
346 407
347bool bhop_autostrafe_enabled() { return g_bhop_autostrafe; } 408bool bhop_autostrafe_enabled() { return g_bhop_autostrafe; }
348 409
410unsigned aimbot_bone_mask() {
411 unsigned m = 0;
412 if (g_aim_bones[AIM_BONE_HEAD])
413 m |= 1u << 1; // HITGROUP_HEAD
414 if (g_aim_bones[AIM_BONE_TORSO])
415 m |= (1u << 2) | (1u << 3); // chest + stomach
416 if (g_aim_bones[AIM_BONE_LARM])
417 m |= 1u << 4;
418 if (g_aim_bones[AIM_BONE_RARM])
419 m |= 1u << 5;
420 if (g_aim_bones[AIM_BONE_LLEG])
421 m |= 1u << 6;
422 if (g_aim_bones[AIM_BONE_RLEG])
423 m |= 1u << 7;
424 return m;
425}
426
427int aimbot_smooth_step() { return g_aim_smooth; }
428
349static void menu_handle_input() { 429static void menu_handle_input() {
350 poll_keyboard(); 430 poll_keyboard();
351 431
@@ -415,6 +495,19 @@ static void menu_handle_input() {
415 g_selected++; 495 g_selected++;
416 return; 496 return;
417 } 497 }
498 if (key_pressed(SCAN_LEFT) || key_pressed(SCAN_RIGHT)) {
499 MenuNode *n = g_visible[g_selected];
500 if (n->type == NODE_VALUE && n->value_ptr) {
501 int dir = key_pressed(SCAN_RIGHT) ? 1 : -1;
502 int step = n->value_step ? n->value_step : 1;
503 int v = *n->value_ptr + dir * step;
504 if (v < n->value_min) v = n->value_min;
505 if (v > n->value_max) v = n->value_max;
506 *n->value_ptr = v;
507 config_save();
508 }
509 return;
510 }
418 if (key_pressed(SCAN_ENTER)) { 511 if (key_pressed(SCAN_ENTER)) {
419 MenuNode *n = g_visible[g_selected]; 512 MenuNode *n = g_visible[g_selected];
420 if (n->child_count > 0) { 513 if (n->child_count > 0) {
@@ -599,6 +692,10 @@ void outer_draw() {
599 snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr)); 692 snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr));
600 draw_text(270, 10 + i * 20, bn[fi]); 693 draw_text(270, 10 + i * 20, bn[fi]);
601 } 694 }
695 } else if (n->type == NODE_VALUE) {
696 char vb[32];
697 snprintf(vb, sizeof(vb), "%d deg/tick", *n->value_ptr);
698 draw_text(270, 10 + i * 20, vb);
602 } 699 }
603 } 700 }
604 surf_pop_make_current(panel); 701 surf_pop_make_current(panel);