summaryrefslogtreecommitdiffstats
path: root/src/vischeck.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 13:19:00 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 13:22:27 +0100
commitbb99c978c5f982e80a3007101fd61fe23635e242 (patch)
tree749acafe3d2c4fcffeb2060c7a4a92c49aa69407 /src/vischeck.cpp
parentSpeed graph: show current speed at the top-right (diff)
downloadhl2h-bb99c978c5f982e80a3007101fd61fe23635e242.tar.gz
hl2h-bb99c978c5f982e80a3007101fd61fe23635e242.zip
Jumpbug: automatic duck+jump on damaging falls
- Predict the landing speed from the current vertical velocity and a swept standing-hull ground trace; engage only when it exceeds PLAYER_MAX_SAFE_FALL_SPEED. - Press duck one command before the unduck window so FinishDuck's 36-unit origin raise places the feet ~37 units above the floor. - On the next command release duck and press jump: PlayerMove runs Duck() before CheckJumpButton, so FinishUnDuck sets ground, the jump executes, and CheckFalling never sees ground for the fall-damage check. - Measure the per-command fall from consecutive airborne origins instead of a fixed tick interval; clear IN_JUMP while waiting so the pogo latch is clear. - New Movement -> Jumpbug -> Active toggle (default on), config [jumpbug].
Diffstat (limited to '')
-rw-r--r--src/vischeck.cpp45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/vischeck.cpp b/src/vischeck.cpp
index 428f54f..6d453c5 100644
--- a/src/vischeck.cpp
+++ b/src/vischeck.cpp
@@ -95,6 +95,9 @@ constexpr unsigned MASK_VISIBLE = 0x1u | 0x4000u | 0x80u | 0x2000u;
95// MASK_SHOT = SOLID|MOVEABLE|MONSTER|WINDOW|DEBRIS|HITBOX 95// MASK_SHOT = SOLID|MOVEABLE|MONSTER|WINDOW|DEBRIS|HITBOX
96constexpr unsigned MASK_SHOT = 0x1u | 0x4000u | 0x2000000u | 0x4u | 96constexpr unsigned MASK_SHOT = 0x1u | 0x4000u | 0x2000000u | 0x4u |
97 0x4000000u | 0x40000000u; 97 0x4000000u | 0x40000000u;
98// MASK_PLAYERSOLID = SOLID|MOVEABLE|PLAYERCLIP|WINDOW|MONSTER|GRATE
99constexpr unsigned MASK_PLAYERSOLID =
100 0x1u | 0x4000u | 0x10000u | 0x4u | 0x2000000u | 0x8u;
98 101
99static void make_ray(RayCompat &ray, const Vector &start, const Vector &end) { 102static void make_ray(RayCompat &ray, const Vector &start, const Vector &end) {
100 float dx = end.x - start.x, dy = end.y - start.y, dz = end.z - start.z; 103 float dx = end.x - start.x, dy = end.y - start.y, dz = end.z - start.z;
@@ -107,6 +110,21 @@ static void make_ray(RayCompat &ray, const Vector &start, const Vector &end) {
107 ray.isSwept = (dx * dx + dy * dy + dz * dz) > 0.0f; 110 ray.isSwept = (dx * dx + dy * dy + dz * dz) > 0.0f;
108} 111}
109 112
113// Swept AABB matching the standing player hull used by CGameMovement.
114// Ray_t::Init shifts m_Start to the box center and stores the negated center
115// offset in m_StartOffset. With mins=(-16,-16,0), maxs=(16,16,72), the
116// extents are (16,16,36) and m_StartOffset is (0,0,-36).
117static void make_standing_hull_ray(RayCompat &ray, const Vector &origin,
118 float distance) {
119 ray = RayCompat{};
120 ray.start = {origin.x, origin.y, origin.z + 36.0f, 0.0f};
121 ray.delta = {0.0f, 0.0f, -distance, 0.0f};
122 ray.startOffset = {0.0f, 0.0f, -36.0f, 0.0f};
123 ray.extents = {16.0f, 16.0f, 36.0f, 0.0f};
124 ray.isRay = false;
125 ray.isSwept = true;
126}
127
110} // namespace 128} // namespace
111 129
112bool is_visible(const Vector &eye, const Vector &point) { 130bool is_visible(const Vector &eye, const Vector &point) {
@@ -147,3 +165,30 @@ void *trace_entity(const Vector &start, const Vector &end, void *ignore) {
147 return nullptr; 165 return nullptr;
148 return tr.ent; 166 return tr.ent;
149} 167}
168
169// Vertical distance from the standing player hull's feet to the first
170// standable surface below. Matches CategorizePosition's 2-unit probe and its
171// plane.normal.z >= 0.7 rule, but sweeps much farther so the caller can
172// predict the landing. Returns -1 when there is no usable ground.
173float ground_distance(const Vector &origin, void *ignore, float max_dist) {
174 if (!g_iface.enginetrace || max_dist <= 0.0f)
175 return -1.0f;
176 RayCompat ray;
177 make_standing_hull_ray(ray, origin, max_dist);
178 GameTraceCompat tr{};
179 EntityFilter filter(ignore);
180 using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *,
181 GameTraceCompat *);
182 vfunc<TraceRayFn>(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray,
183 MASK_PLAYERSOLID, &filter, &tr);
184 if (tr.startsolid || tr.fraction >= 1.0f || tr.normal.z < 0.7f) {
185 static int solid_logs = 0;
186 if (tr.startsolid && solid_logs < 4) {
187 solid_logs++;
188 logf("ground trace: startsolid at (%.1f %.1f %.1f)", origin.x,
189 origin.y, origin.z);
190 }
191 return -1.0f;
192 }
193 return tr.fraction * max_dist;
194}