From 8cd07c04efafcd3e927a21152d10e9fafea54517 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 14:04:39 +0100 Subject: 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. --- CONTEXT.md | 19 ++++++++++++------ src/esp.cpp | 64 +++++++++++++++++++++++++++++++++++------------------------- src/gui.cpp | 8 ++++---- src/hl2h.cpp | 31 +++++++++++++++-------------- src/menu.cpp | 17 +++++++++++----- 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. - The rendered camera FOV comes from `CViewRender::OnRenderStart` copying `C_BasePlayer::m_iDefaultFOV` into `default_fov`, so the cheat writes the - client netvar each tick when `Camera FOV > 0` (0 = stock 75). + client netvar every tick. The camera slider is 40..140 (stock 75) and the + viewmodel slider 20..120 (stock 54); 0 is not allowed (old configs with 0 + migrate to the stock value). - `viewmodel_fov` and `mat_monitorgamma` are client cvars; applied through `ClientCmd` when their slider changes. Gamma is stored as x10 - (`[view] gamma=22` = 2.2). Both live in the always-on - `Camera / display` card (`[view] fov/vmfov/gamma`). + (`[view] gamma=22` = 2.2). The gamma value is read back through + `ICvar::FindVar` and logged (`view: gamma request ..., cvar reports ...`) + to distinguish a rejected command from an OS gamma ramp the compositor + ignores. Both live in the always-on `Camera / display` card + (`[view] fov/vmfov/gamma`). ## Map transitions @@ -250,9 +255,11 @@ vocabulary / decisions. interface comes from `IServerUnknown::GetCollideable`, slot 4). - The current map name comes from the worldspawn (`entity 0`) model name (`maps/.bsp`). The map before the last change is kept as - `g_map_prev`, so the box label reads `-> next` and `prev `. -- Scanning runs at 4 Hz in the ESP draw; boxes are projected from their 8 - world corners and drawn as an orange outline with a 10 px label. + `g_map_prev`, so each trigger's own target is drawn as `-> map`, and the + trigger whose target equals `g_map_prev` is marked `<- map` (the way back). +- Scanning runs at 4 Hz in the ESP draw; the 8 world corners are projected and + the 12 edges are drawn as a 3D wireframe, with a 10 px tag above the highest + visible corner. ## Bones / ESP 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() { static void draw_transitions() { if (!g_surface || !g_ntrans) return; + // Corner bits: +x, +y, +z. Twelve edges connect corners differing by one + // bit; projecting the corners and joining them gives a proper 3D wireframe + // instead of a screen-space rectangle. + static const int edges[12][2] = { + {0, 1}, {2, 3}, {4, 5}, {6, 7}, {0, 2}, {1, 3}, + {4, 6}, {5, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; for (int i = 0; i < g_ntrans; i++) { const TransitionBox &b = g_trans[i]; - float minx = 1e9f, miny = 1e9f, maxx = -1e9f, maxy = -1e9f; + Vector corners[8]; + float xs[8], ys[8]; + bool ok[8]; int seen = 0; for (int c = 0; c < 8; c++) { - Vector p{(c & 1) ? b.maxs.x : b.mins.x, (c & 2) ? b.maxs.y : b.mins.y, - (c & 4) ? b.maxs.z : b.mins.z}; - float sx, sy; - if (!world_to_screen(p, sx, sy) || !std::isfinite(sx) || - !std::isfinite(sy)) - continue; - if (sx < minx) minx = sx; - if (sx > maxx) maxx = sx; - if (sy < miny) miny = sy; - if (sy > maxy) maxy = sy; - seen++; + corners[c] = Vector{(c & 1) ? b.maxs.x : b.mins.x, + (c & 2) ? b.maxs.y : b.mins.y, + (c & 4) ? b.maxs.z : b.mins.z}; + ok[c] = world_to_screen(corners[c], xs[c], ys[c]) && + std::isfinite(xs[c]) && std::isfinite(ys[c]); + if (ok[c]) + seen++; } if (!seen) continue; - int x0 = (int)minx, x1 = (int)maxx, y0 = (int)miny, y1 = (int)maxy; - if (x1 < -2000 || x0 > g_scr_w + 2000 || y1 < -2000 || - y0 > g_scr_h + 2000) - continue; - surf_color(255, 170, 60, 200); - surf_rect(0, x0, y0, x1, y1); + // The trigger whose target is the map we came from is the way back. + bool back = g_map_prev[0] && strcmp(b.next, g_map_prev) == 0; + int r = back ? 200 : 255, g = back ? 200 : 170, bl = back ? 200 : 60; + surf_color(r, g, bl, 210); + for (int e = 0; e < 12; e++) { + int a = edges[e][0], c = edges[e][1]; + if (ok[a] && ok[c]) + surf_line((int)xs[a], (int)ys[a], (int)xs[c], (int)ys[c]); + } + // Tag above the highest projected corner. + float topx = 0.0f, topy = 1e9f; + for (int c = 0; c < 8; c++) { + if (ok[c] && ys[c] < topy) { + topy = ys[c]; + topx = xs[c]; + } + } char line[128]; - snprintf(line, sizeof(line), "-> %.100s", b.next); - int tx = x0; + snprintf(line, sizeof(line), "%s %.100s", back ? "<-" : "->", b.next); + int tx = (int)topx; if (tx < 4) tx = 4; if (tx > g_scr_w - 120) tx = g_scr_w - 120; - int ty = y0 - 16; + int ty = (int)topy - 16; if (ty < 4) ty = 4; draw_text_small_col(tx + 1, ty + 1, line, 0, 0, 0); - draw_text_small_col(tx, ty, line, 255, 180, 70); - if (g_map_prev[0]) { - snprintf(line, sizeof(line), "prev %.48s", g_map_prev); - draw_text_small_col(tx + 1, ty + 13, line, 0, 0, 0); - draw_text_small_col(tx, ty + 12, line, 200, 200, 200); - } + draw_text_small_col(tx, ty, line, r, g, bl); } } 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() { int view = add_card(2, nullptr, "Camera / display", "Camera FOV, viewmodel FOV and monitor gamma.", true); add_slider(view, "Camera FOV", - "World camera field of view; 0 keeps the game default (75).", 0, - 140, &g_fov_camera); + "World camera field of view (40-140; stock 75).", 40, 140, + &g_fov_camera); add_slider(view, "Viewmodel FOV", - "Weapon model field of view; 0 keeps the game default (54).", 0, - 120, &g_fov_viewmodel); + "Weapon model field of view (20-120; stock 54).", 20, 120, + &g_fov_viewmodel); add_slider(view, "Gamma x10", "mat_monitorgamma x10: 16 = 1.6, 30 = 3.0, stock is 22.", 16, 30, &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() { // and monitor gamma are plain client cvars. static void view_settings_apply(void *ent) { - if (g_net.default_fov >= 0 && ent) { - static int last = -2; - int want = g_fov_camera > 0 ? g_fov_camera : 0; - if (want != last || g_fov_camera > 0) { - *(int *)((uintptr_t)ent + g_net.default_fov) = want; - last = want; - } - } - // 0 means "leave the game's value alone": only send a command once the - // slider is non-zero, then restore the stock value when it returns to 0. - static int last_vm = 0; - if (g_fov_viewmodel > 0 && g_fov_viewmodel != last_vm) { + if (g_net.default_fov >= 0 && ent) + *(int *)((uintptr_t)ent + g_net.default_fov) = g_fov_camera; + static int last_vm = 54; + if (g_fov_viewmodel != last_vm) { char cmd[48]; snprintf(cmd, sizeof(cmd), "viewmodel_fov %d", g_fov_viewmodel); console_cmd(cmd); last_vm = g_fov_viewmodel; - } else if (g_fov_viewmodel == 0 && last_vm > 0) { - console_cmd("viewmodel_fov 54"); - last_vm = 0; } static int last_gamma = 22; if (g_gamma != last_gamma) { @@ -690,6 +679,18 @@ static void view_settings_apply(void *ent) { snprintf(cmd, sizeof(cmd), "mat_monitorgamma %d.%d", g_gamma / 10, g_gamma % 10); console_cmd(cmd); + // Read back through ICvar to tell an ignored command from an OS gamma + // ramp that the compositor discards. + float got = -1.0f; + if (g_iface.cvar) { + using FindFn = void *(*)(void *, const char *); + void *v = vfunc(g_iface.cvar, 12)(g_iface.cvar, + "mat_monitorgamma"); + if (v) + got = *(float *)((uintptr_t)v + 0x2c); // ConVar m_Value.f + } + logf("view: gamma request %d.%d, cvar reports %.2f", g_gamma / 10, + g_gamma % 10, got); last_gamma = g_gamma; } } 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 bool g_spread_engine = true; // zero the pellet random draws, not just the seed bool g_auto_crouchjump = false; bool g_edge_jump = false; -int g_fov_camera = 0; // 0 = game default -int g_fov_viewmodel = 0; // 0 = game default (54) +int g_fov_camera = 75; // HL2's stock camera FOV +int g_fov_viewmodel = 54; // HL2's stock viewmodel FOV int g_gamma = 22; // mat_monitorgamma x10, stock 2.2 int g_esp_col_hostile[3] = {255, 60, 60}; int g_esp_col_neutral[3] = {220, 220, 220}; @@ -393,20 +393,27 @@ static bool config_load() { } if (in_view) { int *dst = nullptr; - int lo = 0, hi = 0; + int lo = 0, hi = 0, stock = 0; if (strcmp(key, "fov") == 0) { dst = &g_fov_camera; + lo = 40; hi = 140; + stock = 75; } else if (strcmp(key, "vmfov") == 0) { dst = &g_fov_viewmodel; + lo = 20; hi = 120; + stock = 54; } else if (strcmp(key, "gamma") == 0) { dst = &g_gamma; lo = 16; hi = 30; + stock = 22; } if (dst) { int v = atoi(val); + if (v <= 0) + v = stock; // old configs used 0 as "off" if (v < lo) v = lo; if (v > hi) v = hi; *dst = v; @@ -595,8 +602,8 @@ void config_reset_defaults() { g_spread_engine = true; g_auto_crouchjump = false; g_edge_jump = false; - g_fov_camera = 0; - g_fov_viewmodel = 0; + g_fov_camera = 75; + g_fov_viewmodel = 54; g_gamma = 22; g_esp_col_hostile[0] = 255; g_esp_col_hostile[1] = 60; -- cgit v1.2.3