summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 14:04:39 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 14:04:39 +0100
commit8cd07c04efafcd3e927a21152d10e9fafea54517 (patch)
treec89fdf577c90e82080ff5c15982d016cc3f5f7fa
parentAdd ESP, aim, view and movement batch (diff)
downloadhl2h-8cd07c04efafcd3e927a21152d10e9fafea54517.tar.gz
hl2h-8cd07c04efafcd3e927a21152d10e9fafea54517.zip
Transitions: per-trigger targets and 3D wireframe; FOV range fixes
- Each changelevel trigger now shows its own target map. The trigger whose target is the map we came from is marked "<- map"; the forward one is "-> map". No more appending one global previous-map line to every box. - Draw the volume as a projected 8-corner / 12-edge wireframe with the tag above its highest visible corner instead of a screen-space rectangle. - Camera FOV is 40..140 (stock 75) and viewmodel FOV 20..120 (stock 54); 0 is no longer allowed and old configs using 0 migrate to the stock value. - Log the mat_monitorgamma readback via ICvar so we can tell whether the command is rejected or the OS/compositor ignores the gamma ramp.
-rw-r--r--CONTEXT.md19
-rw-r--r--src/esp.cpp64
-rw-r--r--src/gui.cpp8
-rw-r--r--src/hl2h.cpp31
-rw-r--r--src/menu.cpp17
5 files changed, 82 insertions, 57 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index 2e1ce52..4df44bd 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -234,11 +234,16 @@ vocabulary / decisions.
234 234
235- The rendered camera FOV comes from `CViewRender::OnRenderStart` copying 235- The rendered camera FOV comes from `CViewRender::OnRenderStart` copying
236 `C_BasePlayer::m_iDefaultFOV` into `default_fov`, so the cheat writes the 236 `C_BasePlayer::m_iDefaultFOV` into `default_fov`, so the cheat writes the
237 client netvar each tick when `Camera FOV > 0` (0 = stock 75). 237 client netvar every tick. The camera slider is 40..140 (stock 75) and the
238 viewmodel slider 20..120 (stock 54); 0 is not allowed (old configs with 0
239 migrate to the stock value).
238- `viewmodel_fov` and `mat_monitorgamma` are client cvars; applied through 240- `viewmodel_fov` and `mat_monitorgamma` are client cvars; applied through
239 `ClientCmd` when their slider changes. Gamma is stored as x10 241 `ClientCmd` when their slider changes. Gamma is stored as x10
240 (`[view] gamma=22` = 2.2). Both live in the always-on 242 (`[view] gamma=22` = 2.2). The gamma value is read back through
241 `Camera / display` card (`[view] fov/vmfov/gamma`). 243 `ICvar::FindVar` and logged (`view: gamma request ..., cvar reports ...`)
244 to distinguish a rejected command from an OS gamma ramp the compositor
245 ignores. Both live in the always-on `Camera / display` card
246 (`[view] fov/vmfov/gamma`).
242 247
243## Map transitions 248## Map transitions
244 249
@@ -250,9 +255,11 @@ vocabulary / decisions.
250 interface comes from `IServerUnknown::GetCollideable`, slot 4). 255 interface comes from `IServerUnknown::GetCollideable`, slot 4).
251- The current map name comes from the worldspawn (`entity 0`) model name 256- The current map name comes from the worldspawn (`entity 0`) model name
252 (`maps/<name>.bsp`). The map before the last change is kept as 257 (`maps/<name>.bsp`). The map before the last change is kept as
253 `g_map_prev`, so the box label reads `-> next` and `prev <map>`. 258 `g_map_prev`, so each trigger's own target is drawn as `-> map`, and the
254- Scanning runs at 4 Hz in the ESP draw; boxes are projected from their 8 259 trigger whose target equals `g_map_prev` is marked `<- map` (the way back).
255 world corners and drawn as an orange outline with a 10 px label. 260- Scanning runs at 4 Hz in the ESP draw; the 8 world corners are projected and
261 the 12 edges are drawn as a 3D wireframe, with a 10 px tag above the highest
262 visible corner.
256 263
257## Bones / ESP 264## Bones / ESP
258 265
diff --git a/src/esp.cpp b/src/esp.cpp
index 1e67a8a..7baf2c8 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -1769,45 +1769,55 @@ static void transitions_scan() {
1769static void draw_transitions() { 1769static void draw_transitions() {
1770 if (!g_surface || !g_ntrans) 1770 if (!g_surface || !g_ntrans)
1771 return; 1771 return;
1772 // Corner bits: +x, +y, +z. Twelve edges connect corners differing by one
1773 // bit; projecting the corners and joining them gives a proper 3D wireframe
1774 // instead of a screen-space rectangle.
1775 static const int edges[12][2] = {
1776 {0, 1}, {2, 3}, {4, 5}, {6, 7}, {0, 2}, {1, 3},
1777 {4, 6}, {5, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};
1772 for (int i = 0; i < g_ntrans; i++) { 1778 for (int i = 0; i < g_ntrans; i++) {
1773 const TransitionBox &b = g_trans[i]; 1779 const TransitionBox &b = g_trans[i];
1774 float minx = 1e9f, miny = 1e9f, maxx = -1e9f, maxy = -1e9f; 1780 Vector corners[8];
1781 float xs[8], ys[8];
1782 bool ok[8];
1775 int seen = 0; 1783 int seen = 0;
1776 for (int c = 0; c < 8; c++) { 1784 for (int c = 0; c < 8; c++) {
1777 Vector p{(c & 1) ? b.maxs.x : b.mins.x, (c & 2) ? b.maxs.y : b.mins.y, 1785 corners[c] = Vector{(c & 1) ? b.maxs.x : b.mins.x,
1778 (c & 4) ? b.maxs.z : b.mins.z}; 1786 (c & 2) ? b.maxs.y : b.mins.y,
1779 float sx, sy; 1787 (c & 4) ? b.maxs.z : b.mins.z};
1780 if (!world_to_screen(p, sx, sy) || !std::isfinite(sx) || 1788 ok[c] = world_to_screen(corners[c], xs[c], ys[c]) &&
1781 !std::isfinite(sy)) 1789 std::isfinite(xs[c]) && std::isfinite(ys[c]);
1782 continue; 1790 if (ok[c])
1783 if (sx < minx) minx = sx; 1791 seen++;
1784 if (sx > maxx) maxx = sx;
1785 if (sy < miny) miny = sy;
1786 if (sy > maxy) maxy = sy;
1787 seen++;
1788 } 1792 }
1789 if (!seen) 1793 if (!seen)
1790 continue; 1794 continue;
1791 int x0 = (int)minx, x1 = (int)maxx, y0 = (int)miny, y1 = (int)maxy; 1795 // The trigger whose target is the map we came from is the way back.
1792 if (x1 < -2000 || x0 > g_scr_w + 2000 || y1 < -2000 || 1796 bool back = g_map_prev[0] && strcmp(b.next, g_map_prev) == 0;
1793 y0 > g_scr_h + 2000) 1797 int r = back ? 200 : 255, g = back ? 200 : 170, bl = back ? 200 : 60;
1794 continue; 1798 surf_color(r, g, bl, 210);
1795 surf_color(255, 170, 60, 200); 1799 for (int e = 0; e < 12; e++) {
1796 surf_rect(0, x0, y0, x1, y1); 1800 int a = edges[e][0], c = edges[e][1];
1801 if (ok[a] && ok[c])
1802 surf_line((int)xs[a], (int)ys[a], (int)xs[c], (int)ys[c]);
1803 }
1804 // Tag above the highest projected corner.
1805 float topx = 0.0f, topy = 1e9f;
1806 for (int c = 0; c < 8; c++) {
1807 if (ok[c] && ys[c] < topy) {
1808 topy = ys[c];
1809 topx = xs[c];
1810 }
1811 }
1797 char line[128]; 1812 char line[128];
1798 snprintf(line, sizeof(line), "-> %.100s", b.next); 1813 snprintf(line, sizeof(line), "%s %.100s", back ? "<-" : "->", b.next);
1799 int tx = x0; 1814 int tx = (int)topx;
1800 if (tx < 4) tx = 4; 1815 if (tx < 4) tx = 4;
1801 if (tx > g_scr_w - 120) tx = g_scr_w - 120; 1816 if (tx > g_scr_w - 120) tx = g_scr_w - 120;
1802 int ty = y0 - 16; 1817 int ty = (int)topy - 16;
1803 if (ty < 4) ty = 4; 1818 if (ty < 4) ty = 4;
1804 draw_text_small_col(tx + 1, ty + 1, line, 0, 0, 0); 1819 draw_text_small_col(tx + 1, ty + 1, line, 0, 0, 0);
1805 draw_text_small_col(tx, ty, line, 255, 180, 70); 1820 draw_text_small_col(tx, ty, line, r, g, bl);
1806 if (g_map_prev[0]) {
1807 snprintf(line, sizeof(line), "prev %.48s", g_map_prev);
1808 draw_text_small_col(tx + 1, ty + 13, line, 0, 0, 0);
1809 draw_text_small_col(tx, ty + 12, line, 200, 200, 200);
1810 }
1811 } 1821 }
1812} 1822}
1813 1823
diff --git a/src/gui.cpp b/src/gui.cpp
index 974347a..88e5521 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -413,11 +413,11 @@ static void build_cards() {
413 int view = add_card(2, nullptr, "Camera / display", 413 int view = add_card(2, nullptr, "Camera / display",
414 "Camera FOV, viewmodel FOV and monitor gamma.", true); 414 "Camera FOV, viewmodel FOV and monitor gamma.", true);
415 add_slider(view, "Camera FOV", 415 add_slider(view, "Camera FOV",
416 "World camera field of view; 0 keeps the game default (75).", 0, 416 "World camera field of view (40-140; stock 75).", 40, 140,
417 140, &g_fov_camera); 417 &g_fov_camera);
418 add_slider(view, "Viewmodel FOV", 418 add_slider(view, "Viewmodel FOV",
419 "Weapon model field of view; 0 keeps the game default (54).", 0, 419 "Weapon model field of view (20-120; stock 54).", 20, 120,
420 120, &g_fov_viewmodel); 420 &g_fov_viewmodel);
421 add_slider(view, "Gamma x10", 421 add_slider(view, "Gamma x10",
422 "mat_monitorgamma x10: 16 = 1.6, 30 = 3.0, stock is 22.", 16, 30, 422 "mat_monitorgamma x10: 16 = 1.6, 30 = 3.0, stock is 22.", 16, 30,
423 &g_gamma); 423 &g_gamma);
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index 74a8c6c..f7106cd 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -664,25 +664,14 @@ static void install_uniform_random_hook() {
664// and monitor gamma are plain client cvars. 664// and monitor gamma are plain client cvars.
665 665
666static void view_settings_apply(void *ent) { 666static void view_settings_apply(void *ent) {
667 if (g_net.default_fov >= 0 && ent) { 667 if (g_net.default_fov >= 0 && ent)
668 static int last = -2; 668 *(int *)((uintptr_t)ent + g_net.default_fov) = g_fov_camera;
669 int want = g_fov_camera > 0 ? g_fov_camera : 0; 669 static int last_vm = 54;
670 if (want != last || g_fov_camera > 0) { 670 if (g_fov_viewmodel != last_vm) {
671 *(int *)((uintptr_t)ent + g_net.default_fov) = want;
672 last = want;
673 }
674 }
675 // 0 means "leave the game's value alone": only send a command once the
676 // slider is non-zero, then restore the stock value when it returns to 0.
677 static int last_vm = 0;
678 if (g_fov_viewmodel > 0 && g_fov_viewmodel != last_vm) {
679 char cmd[48]; 671 char cmd[48];
680 snprintf(cmd, sizeof(cmd), "viewmodel_fov %d", g_fov_viewmodel); 672 snprintf(cmd, sizeof(cmd), "viewmodel_fov %d", g_fov_viewmodel);
681 console_cmd(cmd); 673 console_cmd(cmd);
682 last_vm = g_fov_viewmodel; 674 last_vm = g_fov_viewmodel;
683 } else if (g_fov_viewmodel == 0 && last_vm > 0) {
684 console_cmd("viewmodel_fov 54");
685 last_vm = 0;
686 } 675 }
687 static int last_gamma = 22; 676 static int last_gamma = 22;
688 if (g_gamma != last_gamma) { 677 if (g_gamma != last_gamma) {
@@ -690,6 +679,18 @@ static void view_settings_apply(void *ent) {
690 snprintf(cmd, sizeof(cmd), "mat_monitorgamma %d.%d", g_gamma / 10, 679 snprintf(cmd, sizeof(cmd), "mat_monitorgamma %d.%d", g_gamma / 10,
691 g_gamma % 10); 680 g_gamma % 10);
692 console_cmd(cmd); 681 console_cmd(cmd);
682 // Read back through ICvar to tell an ignored command from an OS gamma
683 // ramp that the compositor discards.
684 float got = -1.0f;
685 if (g_iface.cvar) {
686 using FindFn = void *(*)(void *, const char *);
687 void *v = vfunc<FindFn>(g_iface.cvar, 12)(g_iface.cvar,
688 "mat_monitorgamma");
689 if (v)
690 got = *(float *)((uintptr_t)v + 0x2c); // ConVar m_Value.f
691 }
692 logf("view: gamma request %d.%d, cvar reports %.2f", g_gamma / 10,
693 g_gamma % 10, got);
693 last_gamma = g_gamma; 694 last_gamma = g_gamma;
694 } 695 }
695} 696}
diff --git a/src/menu.cpp b/src/menu.cpp
index 4e521f7..ead5f2d 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -79,8 +79,8 @@ bool g_aim_punch = true; // compensate server aim punch
79bool g_spread_engine = true; // zero the pellet random draws, not just the seed 79bool g_spread_engine = true; // zero the pellet random draws, not just the seed
80bool g_auto_crouchjump = false; 80bool g_auto_crouchjump = false;
81bool g_edge_jump = false; 81bool g_edge_jump = false;
82int g_fov_camera = 0; // 0 = game default 82int g_fov_camera = 75; // HL2's stock camera FOV
83int g_fov_viewmodel = 0; // 0 = game default (54) 83int g_fov_viewmodel = 54; // HL2's stock viewmodel FOV
84int g_gamma = 22; // mat_monitorgamma x10, stock 2.2 84int g_gamma = 22; // mat_monitorgamma x10, stock 2.2
85int g_esp_col_hostile[3] = {255, 60, 60}; 85int g_esp_col_hostile[3] = {255, 60, 60};
86int g_esp_col_neutral[3] = {220, 220, 220}; 86int g_esp_col_neutral[3] = {220, 220, 220};
@@ -393,20 +393,27 @@ static bool config_load() {
393 } 393 }
394 if (in_view) { 394 if (in_view) {
395 int *dst = nullptr; 395 int *dst = nullptr;
396 int lo = 0, hi = 0; 396 int lo = 0, hi = 0, stock = 0;
397 if (strcmp(key, "fov") == 0) { 397 if (strcmp(key, "fov") == 0) {
398 dst = &g_fov_camera; 398 dst = &g_fov_camera;
399 lo = 40;
399 hi = 140; 400 hi = 140;
401 stock = 75;
400 } else if (strcmp(key, "vmfov") == 0) { 402 } else if (strcmp(key, "vmfov") == 0) {
401 dst = &g_fov_viewmodel; 403 dst = &g_fov_viewmodel;
404 lo = 20;
402 hi = 120; 405 hi = 120;
406 stock = 54;
403 } else if (strcmp(key, "gamma") == 0) { 407 } else if (strcmp(key, "gamma") == 0) {
404 dst = &g_gamma; 408 dst = &g_gamma;
405 lo = 16; 409 lo = 16;
406 hi = 30; 410 hi = 30;
411 stock = 22;
407 } 412 }
408 if (dst) { 413 if (dst) {
409 int v = atoi(val); 414 int v = atoi(val);
415 if (v <= 0)
416 v = stock; // old configs used 0 as "off"
410 if (v < lo) v = lo; 417 if (v < lo) v = lo;
411 if (v > hi) v = hi; 418 if (v > hi) v = hi;
412 *dst = v; 419 *dst = v;
@@ -595,8 +602,8 @@ void config_reset_defaults() {
595 g_spread_engine = true; 602 g_spread_engine = true;
596 g_auto_crouchjump = false; 603 g_auto_crouchjump = false;
597 g_edge_jump = false; 604 g_edge_jump = false;
598 g_fov_camera = 0; 605 g_fov_camera = 75;
599 g_fov_viewmodel = 0; 606 g_fov_viewmodel = 54;
600 g_gamma = 22; 607 g_gamma = 22;
601 g_esp_col_hostile[0] = 255; 608 g_esp_col_hostile[0] = 255;
602 g_esp_col_hostile[1] = 60; 609 g_esp_col_hostile[1] = 60;