diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-27 13:19:00 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-27 13:22:27 +0100 |
| commit | bb99c978c5f982e80a3007101fd61fe23635e242 (patch) | |
| tree | 749acafe3d2c4fcffeb2060c7a4a92c49aa69407 /src/vischeck.cpp | |
| parent | Speed graph: show current speed at the top-right (diff) | |
| download | hl2h-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.cpp | 45 |
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 |
| 96 | constexpr unsigned MASK_SHOT = 0x1u | 0x4000u | 0x2000000u | 0x4u | | 96 | constexpr unsigned MASK_SHOT = 0x1u | 0x4000u | 0x2000000u | 0x4u | |
| 97 | 0x4000000u | 0x40000000u; | 97 | 0x4000000u | 0x40000000u; |
| 98 | // MASK_PLAYERSOLID = SOLID|MOVEABLE|PLAYERCLIP|WINDOW|MONSTER|GRATE | ||
| 99 | constexpr unsigned MASK_PLAYERSOLID = | ||
| 100 | 0x1u | 0x4000u | 0x10000u | 0x4u | 0x2000000u | 0x8u; | ||
| 98 | 101 | ||
| 99 | static void make_ray(RayCompat &ray, const Vector &start, const Vector &end) { | 102 | static 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). | ||
| 117 | static 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 | ||
| 112 | bool is_visible(const Vector &eye, const Vector &point) { | 130 | bool 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. | ||
| 173 | float 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 | } | ||
