/*
 * Source reconstruction for player movement physics.
 *
 * Binary SHA-256:
 * 4d2391c10e234559ace294fb69d96741cad522653c361f13f626f4dc1891acb7
 */

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "recovered_game.h"
#include "game_types.h"
#include "g_public.h"
#include "game_globals.h"
#include "g_syscalls.h"
#include "game_functions.h"
#include "coduo_x87emu.h" /* defines EMULATE_X87; x87 shim when it is 1 */
#include "coduo_native_x87.h"
#include "coduo_libm.h"

#if EMULATE_X87
/* 80-bit dot of three float pairs in x,y,z summation order — matches the
 * fmul/fmul/fmul + fadd/fadd sequence the stock movement code emits. Returns an
 * x87f register: callers either compare it at full x87 width (the slide-move
 * plane tests, which the stock binary evaluates without an intermediate float
 * store) or round it with x87f_store_f32 when the source assigns to a float. */
#define MDOT3X(a0, b0, a1, b1, a2, b2)                                      \
    x87f_add(x87f_add(x87f_mul(x87f_load_f32(a0), x87f_load_f32(b0)),          \
                      x87f_mul(x87f_load_f32(a1), x87f_load_f32(b1))),         \
             x87f_mul(x87f_load_f32(a2), x87f_load_f32(b2)))
/* (hi - lo) * frac + lo, rounded once — the BG_GetMinSpreadForWeapon stance
 * lerp; the intermediates stay in x87 width on x86. */
#define SPREADLERP(hi, lo, frac)                                            \
    x87f_store_f32(x87f_add(                                                   \
        x87f_mul(x87f_sub(x87f_load_f32(hi), x87f_load_f32(lo)),               \
                 x87f_load_f32(frac)),                                         \
        x87f_load_f32(lo)))
/* (num / den) * c — the PM_Footsteps step-interval fraction. */
#define STEPINTERVAL(num, den, c)                                           \
    x87f_store_f32(x87f_mul(                                                   \
        x87f_div(x87f_load_f32(num), x87f_load_f32(den)), x87f_load_f32(c)))
/* (int)(oldT + msec*step) & 0xff — the bob-cycle advance, computed in x87
 * width (long double is 80-bit on x86 but 64-bit on arm64). */
#define BOBCYCLE(oldT, msec, step)                                          \
    (x87f_store_i32_trunc(x87f_add(                                            \
         x87f_load_i32(oldT),                                                  \
         x87f_mul(x87f_load_i32(msec), x87f_load_f32(step)))) &                \
     0xff)
#else
#define SPREADLERP(hi, lo, frac) (((hi) - (lo)) * (frac) + (lo))
#define STEPINTERVAL(num, den, c) (((num) / (den)) * (c))
#define BOBCYCLE(oldT, msec, step)                                          \
    ((int)((long double)(oldT) +                                              \
           (long double)(msec) * (long double)(step)) &                       \
     0xff)
#endif

/* ------------------------------------------------------------------ */
/*  Utility macros                                                     */
/* ------------------------------------------------------------------ */

#define Q_ABS(x)  ((x) < 0 ? -(x) : (x))
#define FLOAT_SIGN_BIT_MASK UINT32_C(0x80000000) /* 2147483648: IEEE-754 binary32 sign bit */

enum {
    PMOVE_WBUTTON_WALK         = 0x04u, /* button MASK */
    PMOVE_WBUTTON_STANCE_LATCH = 0x02u, /* button MASK */
    PMOVE_WBUTTON_UP           = 0x10u, /* button MASK */
    PMOVE_WBUTTON_DOWN         = 0x20u, /* button MASK */
    PMOVE_WBUTTON_PRONE        = 0x40u, /* button MASK */
    PMOVE_WBUTTON_CROUCH       = 0x80u, /* button MASK */
    PMOVE_WBUTTON_STANCE_MASK  = PMOVE_WBUTTON_PRONE |
                                    PMOVE_WBUTTON_CROUCH
};

enum {
    PMOVE_BUTTON_FIRE   = 0x01u, /* button MASK */
    PMOVE_BUTTON_SPRINT = 0x08u, /* button MASK */
    PMOVE_BUTTON_WALK   = 0x10u  /* button MASK */
};

enum {
    PM_STANCE_PRONE                = 0x00000001u, /* player-state FLAG */
    PM_STANCE_CROUCH               = 0x00000002u, /* player-state FLAG */
    PM_STANCE_JUMP_HELD            = 0x00000008u, /* player-state FLAG */
    PM_STANCE_LADDER               = 0x00000010u, /* player-state FLAG */
    PM_STANCE_ADS                  = 0x00000020u, /* player-state FLAG */
    PM_STANCE_BACKPEDAL            = 0x00000040u, /* player-state FLAG */
    PM_STANCE_WALKING              = 0x00000080u, /* player-state FLAG */
    PM_STANCE_RECENT_LAND_BLOCK    = 0x00000800u, /* player-state FLAG */
    PM_STANCE_WALLJUMP             = 0x00002000u, /* player-state FLAG */
    PM_STANCE_KEEP_CURRENT_WEAPON  = 0x00004000u, /* player-state FLAG */
    PM_STANCE_PRONE_BLOCKED        = 0x00008000u  /* player-state FLAG */
};

enum {
    PM_STANCE_LANDING_STUN = 0x00000100u, /* player-state FLAG */
    PM_STANCE_PRONE_MOVEMENT_OVERRIDE = 0x00000400u, /* player-state FLAG */
    PM_LADDER_TIMER_BLOCK_MASK = 0x00000300u,
    PM_TIMER_EXPIRY_FLAGS = 0x00002300u
};

enum {
    PS_FLAG_IN_VEHICLE                 = 0x00100000u,
    PS_FLAG_ADS_HELD                   = 0x00020000u,
    PS_FLAG_FIRE_POSITION_CHECK_MASK = 0x00106000u
};

enum {
    PS_FLAG_CROUCH = 0x00000020u,
    PS_FLAG_PRONE  = 0x00000040u,
    PS_FLAG_STANCE_VALID = 0x00000010u, /* player-state FLAG */
    PS_FLAG_WALLJUMP_FRICTION = 0x00000100u,
    PS_FLAG_FIRING = 0x00000200u,
    PS_FLAG_FRICTION_TIMER = 0x00002000u
};

enum {
    PM_STANCE_FATIGUE_DRAIN = 0x00010000u, /* player-state FLAG */
    PM_STANCE_FATIGUED      = 0x00020000u  /* player-state FLAG */
};

enum {
    PM_AIM_SPREAD_SCALE_MAX = 255
};

enum {
    PM_MAX_CLIP_PLANES = 8,
    PM_MAX_TOUCH_ENTS = 32,
    PM_STEP_EVENT = 145
};

enum {
    PM_FOOTSTEP_TRACE_MASK_CLEAR = 0x02010000u,
    PM_FOOTSTEP_SURFACE_TYPE_MASK = 0x01f00000u,
    PM_FOOTSTEP_SURFACE_TYPE_SHIFT = 20,
    PM_FOOTSTEP_DEFAULT_SURFACE = 13,
    PM_FOOTSTEP_SURFACE_EVENT_BASE = 1,
    PM_FOOTSTEP_WATER_LEAN_EVENT = 44,
    PM_FOOTSTEP_WATER_WALK_EVENT = 21,
    PM_FOOTSTEP_WATER_FAST_EVENT = 90,
    PM_FOOTSTEP_WATER_PRONE_EVENT = 67
};

#define PM_SHORT_TO_ANGLE 0.005493164f /* original float32 0x3bb40000 */
#define PM_ANGLE_TO_SHORT 182.04445f /* original float32 0x43360b61 */
#define PM_LAND_FRICTION_STEP 0.00058823527f /* original float32 0x3a1a33cd */
#define PM_STEP_VELOCITY_RETAIN_BIAS 0.19999999f /* original float32 0x3e4ccccc */
#define PM_FALL_LIGHT_LANDING_HEIGHT 4.0f
#define PM_FALL_MEDIUM_LANDING_HEIGHT 8.0f
#define PM_FALL_HEAVY_LANDING_HEIGHT 12.0f
#define PM_FALL_STEP_EVENT_HEIGHT_RANGE 26.0f
#define PM_FALL_STEP_EVENT_SCALE 4.0f
#define PM_FALL_STEP_EVENT_BASE 4.0f
#define PM_FALL_LANDING_VELOCITY_SCALE 0.67f
#define PM_WATERLEVEL_FRACTION_EPSILON 0.015625f /* original float32 0x3c800000 */
enum {
    PM_LAND_FRICTION_SCALE_TIME = 1700,
    PM_FRICTION_TIMER_TIME = 1801
};

enum {
    PM_FATIGUE_SOUND_INTERVAL = 1700,
    PM_FATIGUE_RECOVERY_DELAY = 1000
};

enum {
    PM_PITCH_CLAMP = 16000,
    PM_VEHICLE_PITCH_CLAMP = 12000
};

enum {
    PM_EVENT_FOLIAGE_SOUND = 139,
    PM_EVENT_FATIGUE_SOUND = 140,
    PM_EVENT_PRONE_BLOCKED = 143,
    PM_EVENT_FATIGUE_START = 146,
    PM_EVENT_FATIGUE_STOP = 147
};

enum {
    SURFACE_NO_DAMAGE = 0x00000001u, /* surface FLAG */
    SURFACE_SLICK = 0x00000002u, /* surface FLAG */
    SURFACE_LADDER = 0x00000008u, /* surface FLAG */
    SURFACE_NO_FOOTSTEPS = 0x00002000u, /* surface FLAG */
    ADS_POINT_CONTENTS_MASK = 0x00404000u,
    ADS_POINT_CONTENTS_CROUCH = 0x00400000u /* contents MASK */
};

enum {
    PM_LEAN_CLAMP_DEGREES = 90,
    PM_JUMP_EVENT_WATER_OVERRIDE = 20,
    PM_JUMP_EVENT_RUN_BASE = 70,
    PM_JUMP_EVENT_LADDER = 83,
    PM_STEP_ENTITYNUM_MIN = 64,
    PM_STEP_EVENT_PARAM_BIAS = 128,
    PM_LANDING_EVENT_PRONE_BASE = 47,
    PM_LANDING_EVENT_SPRINT_BASE = 24,
    PM_LANDING_EVENT_HEAVY_BASE = 93,
    PM_FALL_DAMAGE_EVENT_BASE = 116,
    PM_MAX_STEP_EVENT_DELTA = 24,
    PM_FALL_STUN_MS_PER_DAMAGE = 35,
    PM_FALL_STUN_FAST_THRESHOLD = 501,
    PM_FALL_STUN_SLOW_THRESHOLD = 1500,
    PM_WALLJUMP_TIMER_LIMIT = 1801,
    PM_WALLJUMP_TIMER_NEAR_GROUND = 1800,
    PM_WALLJUMP_TIMER_AIR = 1200
};

enum {
    PM_ANIMSCRIPT_STAND_WALK_BACK = 11,
    PM_ANIMSCRIPT_CROUCH_WALK_BACK = 12,
    PM_ANIMSCRIPT_CROUCH_RUN_BACK = 13,
    PM_ANIMSCRIPT_LADDER_CLIMB_UP = 16,
    PM_ANIMSCRIPT_LADDER_CLIMB_DOWN = 17
};

/* ------------------------------------------------------------------ */
/*  Global pmove state                                                 */
/* ------------------------------------------------------------------ */

/* Global pm pointer - set by Pmove, used by sub-functions */
pmove_t *pm = NULL;

const float pm_ladderPushOff = 128.0f;
const int pm_ladderJumpTime = 300;
const float pm_ladderScale = 0.5f;
/* .rodata 0x9b4dc, dynsym pm_ladderfriction: ladder side-speed friction. */
const float pm_ladderfriction = 16.0f;
/* .rodata 0x9b4a4 / 0x9b4d4 (dynsym): noclip/UFO friction parameters. */
const float pm_stopspeed = 100.0f;
const float pm_friction = 5.5f;
/* .rodata 0x9b4e8/0x9b4ec/0x9b4f0 (dynsym): sprint fatigue parameters
 * (float32 0x3eaaaaab and 0x3e124925). */
const float pm_sprintFatigue = 0.33333334f;
const float pm_fatigueRegen = 0.14285715f;
const int pm_fatigueRegenDelay = 1000;
const float pm_accelerate = 9.0f;
const float pm_airaccelerate = 1.0f;
const float pm_flyaccelerate = 8.0f;
const float pm_waterSwimScale = 0.5f;
const float pm_waterWadeScale = 0.7f;
const float pm_prone_accelerate = 19.0f;
const float pm_ducked_accelerate = 12.0f;
const float pm_wateraccelerate = 4.0f;
const float pm_waterfriction = 1.0f;
const float pm_spectatorfriction = 5.0f;
const float pm_shellshockScale = 0.4f;

const vec4_t colorBlack = {0.0f, 0.0f, 0.0f, 1.0f};
const vec4_t colorRed = {1.0f, 0.0f, 0.0f, 1.0f};
const vec4_t colorGreen = {0.0f, 1.0f, 0.0f, 1.0f};
const vec4_t colorLtGreen = {0.0f, 0.7f, 0.0f, 1.0f};
const vec4_t colorBlue = {0.0f, 0.0f, 1.0f, 1.0f};
const vec4_t colorYellow = {1.0f, 1.0f, 0.0f, 1.0f};
const vec4_t colorLtYellow = {0.75f, 0.75f, 0.0f, 1.0f};
const vec4_t colorMdYellow = {0.5f, 0.5f, 0.0f, 1.0f};
const vec4_t colorMagenta = {1.0f, 0.0f, 1.0f, 1.0f};
const vec4_t colorCyan = {0.0f, 1.0f, 1.0f, 1.0f};
const vec4_t colorLtCyan = {0.0f, 0.75f, 0.75f, 1.0f};
const vec4_t colorMdCyan = {0.0f, 0.5f, 0.5f, 1.0f};
const vec4_t colorDkCyan = {0.0f, 0.25f, 0.25f, 1.0f};
const vec4_t colorWhite = {1.0f, 1.0f, 1.0f, 1.0f};
const vec4_t colorLtGrey = {0.75f, 0.75f, 0.75f, 1.0f};
const vec4_t colorMdGrey = {0.5f, 0.5f, 0.5f, 1.0f};
const vec4_t colorDkGrey = {0.25f, 0.25f, 0.25f, 1.0f};
const vec4_t colorOrange = {1.0f, 0.7f, 0.0f, 1.0f};
const vec4_t colorLtOrange = {0.75f, 0.525f, 0.0f, 1.0f};

/* ------------------------------------------------------------------ */
/*  pml (pmove local) structure                                        */
/* ------------------------------------------------------------------ */

pml_t pml;

#if UINTPTR_MAX == 0xffffffffu
GAME_STATIC_ASSERT(pml_right_offset, offsetof(pml_t, right) == 0x0c);
GAME_STATIC_ASSERT(pml_up_offset, offsetof(pml_t, up) == 0x18);
GAME_STATIC_ASSERT(pml_frametime_offset, offsetof(pml_t, frametime) == 0x24);
GAME_STATIC_ASSERT(pml_msec_offset, offsetof(pml_t, msec) == 0x28);
GAME_STATIC_ASSERT(pml_ground_plane_offset, offsetof(pml_t, groundPlane) == 0x2c);
GAME_STATIC_ASSERT(pml_ground_trace_offset, offsetof(pml_t, groundTrace) == 0x38);
GAME_STATIC_ASSERT(pml_ground_trace_fraction_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, fraction) == 0x38);
GAME_STATIC_ASSERT(pml_ground_trace_endpos_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, endpos) == 0x3c);
GAME_STATIC_ASSERT(pml_ground_trace_normal_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, normal) == 0x48);
GAME_STATIC_ASSERT(pml_ground_trace_normal_z_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, normal) +
                 sizeof(float) * 2 == 0x50);
GAME_STATIC_ASSERT(pml_ground_trace_surface_flags_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, surfaceFlags) == 0x54);
GAME_STATIC_ASSERT(pml_ground_trace_contents_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, contents) == 0x58);
GAME_STATIC_ASSERT(pml_ground_trace_material_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, material) == 0x5c);
GAME_STATIC_ASSERT(pml_ground_trace_entity_num_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, entityNum) == 0x60);
GAME_STATIC_ASSERT(pml_ground_trace_part_name_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, partName) == 0x62);
GAME_STATIC_ASSERT(pml_ground_trace_part_group_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, partGroup) == 0x64);
GAME_STATIC_ASSERT(pml_ground_trace_allsolid_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, allsolid) == 0x66);
GAME_STATIC_ASSERT(pml_ground_trace_startsolid_offset,
                 offsetof(pml_t, groundTrace) + offsetof(trace_t, startsolid) == 0x67);
GAME_STATIC_ASSERT(pml_max_clip_impact_offset,
                 offsetof(pml_t, maxClipImpact) == 0x68);
GAME_STATIC_ASSERT(pml_previous_origin_offset,
                 offsetof(pml_t, previousOrigin) == 0x6c);
GAME_STATIC_ASSERT(pml_previous_velocity_offset,
                 offsetof(pml_t, previousVelocity) == 0x78);
GAME_STATIC_ASSERT(pml_previous_overhead_level_offset,
                 offsetof(pml_t, previousOverheadLevel) == 0x84);
GAME_STATIC_ASSERT(pml_weapon_info_offset,
                 offsetof(pml_t, weaponInfo) == 0x88);
GAME_STATIC_ASSERT(pml_size, sizeof(pml_t) == 0x8c);

GAME_STATIC_ASSERT(pmove_trace_entity_num_offset,
                 offsetof(trace_t, entityNum) == 0x28);
GAME_STATIC_ASSERT(pmove_trace_allsolid_offset,
                 offsetof(trace_t, allsolid) == 0x2e);
GAME_STATIC_ASSERT(pmove_trace_startsolid_offset,
                 offsetof(trace_t, startsolid) == 0x2f);
GAME_STATIC_ASSERT(pmove_trace_fraction_offset, offsetof(trace_t, fraction) == 0x00);
GAME_STATIC_ASSERT(pmove_trace_endpos_offset, offsetof(trace_t, endpos) == 0x04);
GAME_STATIC_ASSERT(pmove_trace_normal_offset, offsetof(trace_t, normal) == 0x10);
GAME_STATIC_ASSERT(pmove_trace_surface_flags_offset,
                 offsetof(trace_t, surfaceFlags) == 0x1c);
GAME_STATIC_ASSERT(pmove_trace_contents_offset, offsetof(trace_t, contents) == 0x20);
GAME_STATIC_ASSERT(pmove_trace_material_offset,
                 offsetof(trace_t, material) == 0x24);
GAME_STATIC_ASSERT(pmove_trace_size, sizeof(trace_t) == 0x30);
GAME_STATIC_ASSERT(pml_embedded_trace_size,
                 offsetof(pml_t, maxClipImpact) - offsetof(pml_t, groundTrace) ==
                 sizeof(trace_t));
#endif

/* c_pmove counter */
int c_pmove = 0;

/* pmove_t command-word accessors */
#define PM_CURRENT_COMMAND(pmovePtr) (&(pmovePtr)->command)
#define PM_BUTTON_BYTE0(pmovePtr) ((pmovePtr)->command.buttons)
#define PM_BUTTON_BYTE1(pmovePtr) ((pmovePtr)->command.wbuttons)
#define PM_FORWARDMOVE(pmovePtr)  ((pmovePtr)->command.forwardmove)
#define PM_RIGHTMOVE(pmovePtr)    ((pmovePtr)->command.rightmove)
#define PM_UPMOVE(pmovePtr)       ((pmovePtr)->command.upmove)
#define PM_OLD_FORWARDMOVE(pmovePtr) ((pmovePtr)->oldCommand.forwardmove)
#define PM_OLD_RIGHTMOVE(pmovePtr)   ((pmovePtr)->oldCommand.rightmove)
#define PM_CMD_WINDOW_BUTTON_BYTE1(windowPtr) ((windowPtr)->wbuttons)
#define PM_CMD_WINDOW_FORWARDMOVE(windowPtr)  ((windowPtr)->forwardmove)
#define PM_CMD_WINDOW_RIGHTMOVE(windowPtr)    ((windowPtr)->rightmove)
#define PM_CMD_WINDOW_UPMOVE(windowPtr)       ((windowPtr)->upmove)

/* ------------------------------------------------------------------ */
/*  Extern function declarations                                       */
/* ------------------------------------------------------------------ */

void BG_AnimUpdatePlayerStateConditions(pmove_t *pmove);
void PM_Weapon(void);
effectiveStance_t PM_GetEffectiveStance(playerState_t *ps);
int  PM_WeaponAmmoAvailable(int weapon);
void PM_ContinueWeaponAnim(uint32_t anim);
int  BG_AllowPlayerWeaponAtVehiclePos(int vehicleType, int vehiclePos);
void AngleVectors(const float *angles, float *forward, float *right,
                         float *up);
void trap_SnapVector(float *vec);
const weaponInfo_t *BG_GetInfoForWeapon(int weapon);

static void PM_FootstepEvent(int oldTime, int newTime, int shouldMake);
static int  PM_ShouldMakeFootsteps(void);
/* Movement helpers defined in other translation units */
void BG_AddPredictableEventToPlayerstate(int event, int eventParm,
                                                 playerState_t *ps);
int  BG_CheckProne(int clientNum, const float *origin,
                           float radius, float height, float yaw,
                           float *groundOffset, float *pitchDown,
                           float *pitchUp, int skipInitialTrace,
                           int allowFallback, const float *groundNormal,
                           pm_trace_fn_t traceFunc,
                           pm_trace_fn_t traceDownFunc,
                           int useAltContentMask, float proneLength,
                           pm_entity_type_fn_t entityTypeFunc);
int  BG_AnimScriptAnimation(playerState_t *ps, int stateIndex,
                                    int animGroup, int a4);
void BG_UpdateConditionValue(int clientNum, int condition,
                                     int value, int a4);
float AngleNormalize180Accurate(float angle);
void ProjectPointOnPlane(float *dst, const float *point,
                                const float *normal);
void G_DebugArc(const float *center, float radius, float startAngle,
                       float endAngle, const float *color, int depthTest,
                       int duration);
const float pmGroundTraceAdjustOffsets[26 * 3] = {
    0.0f, 0.0f, 1.0f,
    -1.0f, 0.0f, 1.0f,
    0.0f, -1.0f, 1.0f,
    1.0f, 0.0f, 1.0f,
    0.0f, 1.0f, 1.0f,
    -1.0f, 0.0f, 0.0f,
    0.0f, -1.0f, 0.0f,
    1.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, -1.0f,
    -1.0f, 0.0f, -1.0f,
    0.0f, -1.0f, -1.0f,
    1.0f, 0.0f, -1.0f,
    0.0f, 1.0f, -1.0f,
    -1.0f, -1.0f, 1.0f,
    1.0f, -1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
    1.0f, 1.0f, 0.0f,
    -1.0f, 1.0f, 0.0f,
    -1.0f, -1.0f, -1.0f,
    1.0f, -1.0f, -1.0f,
    1.0f, 1.0f, -1.0f,
    -1.0f, 1.0f, -1.0f
};

const viewheight_lerp_key_t pmViewHeightLerpCrouchedRising[] = {
    {0, 60.0f, 0}, {1, 59.5f, 0}, {4, 58.5f, 0},
    {30, 56.0f, 0}, {80, 44.0f, 0}, {90, 41.5f, 0},
    {95, 40.5f, 0}, {100, 40.0f, 0}, {-1, 0.0f, 0}
};
const viewheight_lerp_key_t pmViewHeightLerpStanding[] = {
    {0, 40.0f, 0}, {5, 40.5f, 0}, {10, 41.5f, 0},
    {20, 44.0f, 0}, {70, 56.0f, 0}, {96, 58.5f, 0},
    {99, 59.5f, 0}, {100, 60.0f, 0}, {-1, 0.0f, 0}
};
const viewheight_lerp_key_t pmViewHeightLerpProne[] = {
    {0, 40.0f, 0}, {11, 38.0f, 0}, {22, 33.0f, 0},
    {34, 25.0f, 0}, {45, 16.0f, 0}, {50, 15.0f, 0},
    {55, 16.0f, 0}, {70, 18.0f, 0}, {90, 17.0f, 0},
    {100, 11.0f, 0}, {-1, 0.0f, 0}
};
const viewheight_lerp_key_t pmViewHeightLerpCrouchedFalling[] = {
    {0, 11.0f, 0}, {5, 10.0f, 0}, {30, 21.0f, 0},
    {50, 25.0f, 0}, {67, 31.0f, 0}, {83, 34.0f, 0},
    {100, 40.0f, 0}, {-1, 0.0f, 0}
};

/* Forward declarations */
static void PmoveSingle(pmove_t *pmove);
static float PM_GetViewHeightLerp(int fromHeight, int toHeight);
int PM_VerifyPronePosition(const float *origin, const float *velocity);
int PM_FloatIsNegative(float value);
void PM_AddTouchEnt(int entityNum);
int PM_SlideMove(int gravity);
void PM_StepSlideMove(int stepType);
void PM_UpdateAimDownSightFlag(void);
void PM_ClearAimDownSightFlag(void);
void PM_AdjustAimSpreadScale(void);
void PM_UpdateFatigue(void);
void PM_UpdateLean(playerState_t *ps, const usercmd_t *command,
                   pm_trace_fn_t traceFunc);
void PM_UpdatePronePitch(void);
void PM_UpdatePlayerWalkingFlag(void);
void PM_UpdatePlayerSprintingFlag(void);
void PM_LadderMove(void);
int PM_InteruptWeaponWithProneMove(void);
int PM_InteruptWeaponWithSprintMove(void);

/* ================================================================== */
/*  Helper functions                                                   */
/* ================================================================== */

/* ------------------------------------------------------------------ */
/*  0x23174  PM_trace                                                  */
/* ------------------------------------------------------------------ */
void PM_trace(trace_t *results, const float *start, const float *mins,
              const float *maxs, const float *end,
              int passEntityNum, int traceType)
{
    trace_t *trace = results;

    pm->trace(results, start, mins, maxs, end, passEntityNum, traceType);
    if (trace->startsolid != 0 && (trace->contents & CONTENTS_BODY) != 0) {
        PM_AddTouchEnt(trace->entityNum);
        pm->traceMask &= ~(int32_t)CONTENTS_BODY;
        pm->trace(results, start, mins, maxs, end, passEntityNum,
                  traceType & ~(int32_t)CONTENTS_BODY);
    }
}

/* ------------------------------------------------------------------ */
/*  0x2325a  PM_AddEvent                                               */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2325a, 3325a_PM_AddEvent.c, VERIFY-WAVE3-MOVEMENT-C01-2026-06-17): DATAFLOW_VERIFIED - predictable event call target, zero parm, and pm->ps argument from *pm checked. */
void PM_AddEvent(int event)
{
    BG_AddPredictableEventToPlayerstate(event, 0, pm->ps);
}

/* ------------------------------------------------------------------ */
/*  0x23293  PM_AddTouchEnt                                            */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x23293, 33293_PM_AddTouchEnt.c, VERIFY-WAVE3-MOVEMENT-C01-2026-06-17): DATAFLOW_VERIFIED - ENTITYNUM_NONE gate, 32-touch cap, duplicate scan, append offset, and numtouch increment checked. */
void PM_AddTouchEnt(int entityNum)
{
    int i;

    if (entityNum == ENTITYNUM_NONE ||
        pm->numtouch == PM_MAX_TOUCH_ENTS) {
        return;
    }

    for (i = 0; i < pm->numtouch; i++) {
        if (pm->impactEntityNums[i] == entityNum) {
            return;
        }
    }

    pm->impactEntityNums[pm->numtouch] = entityNum;
    pm->numtouch++;
}

/* ------------------------------------------------------------------ */
/*  0x23321  PM_ClipVelocity                                           */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x23321, 33321_PM_ClipVelocity.c, VERIFY-WAVE3-MOVEMENT-C01-2026-06-17): DATAFLOW_VERIFIED - dot product order, negative multiply, nonnegative divide, 3-axis output store, and overbounce argument checked. */
void PM_ClipVelocity(const float *in, const float *normal,
                     float *out, float overbounce)
{
    float backoff;
    int i;

    /* 0x2333a: machine sums the dot product in x,y,z order. */
#if EMULATE_X87
    backoff = x87f_store_f32(x87f_add(
        x87f_add(x87f_mul(x87f_load_f32(in[0]), x87f_load_f32(normal[0])),
                 x87f_mul(x87f_load_f32(in[1]), x87f_load_f32(normal[1]))),
        x87f_mul(x87f_load_f32(in[2]), x87f_load_f32(normal[2]))));
    if (backoff < 0.0f) {
        backoff *= overbounce;
    } else {
        /* single fdiv double-rounds (PC=64 then store) — must emulate. */
        backoff = x87f_store_f32(
            x87f_div(x87f_load_f32(backoff), x87f_load_f32(overbounce)));
    }
#else
    backoff = in[0] * normal[0] + in[1] * normal[1] + in[2] * normal[2];
    if (backoff < 0.0f) {
        backoff *= overbounce;
    } else {
        backoff /= overbounce;
    }
#endif

    for (i = 0; i < 3; i++) {
        /* 0x233ad/0x233cd: the product is rounded to float (spilled to a
         * stack slot) before the subtract. */
        float change = normal[i] * backoff;
        out[i] = in[i] - change;
    }
}

/* ------------------------------------------------------------------ */
/*  0x233e1  PM_GetEffectiveStance                                     */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x233e1, 333e1_PM_GetEffectiveStance.c, VERIFY-WAVE3-MOVEMENT-C01-2026-06-17): DATAFLOW_VERIFIED - viewHeightTarget comparisons against crouched/prone offsets and 2/1/0 returns checked. */
effectiveStance_t PM_GetEffectiveStance(playerState_t *ps)
{
    if (ps->viewHeightTarget == (int32_t)ps->crouchViewHeight) {
        return EFFECTIVE_STANCE_CROUCH;
    }
    if (ps->viewHeightTarget == (int32_t)ps->proneViewHeight) {
        return EFFECTIVE_STANCE_PRONE;
    }
    return EFFECTIVE_STANCE_STAND;
}

/* ------------------------------------------------------------------ */
/*  0x2342d  PM_GetSlowdownFriction                                   */
/*  Returns a friction multiplier based on the landing timer.          */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2342d, 3342d_FUN_0003342d.c, VERIFY-WAVE3-MOVEMENT-C01-2026-06-17): DATAFLOW_VERIFIED - pmTime < 1700 branch, float32 1.5 * 0.00058823527 + 1.0 curve, 2.5 fallback, and long double return checked. */
static long double PM_GetSlowdownFriction(void)
{
    float val;
    if (pm->ps->pmTime < PM_LAND_FRICTION_SCALE_TIME) {
#if EMULATE_X87
        val = x87f_store_f32(x87f_add(
            x87f_mul(x87f_mul(x87f_load_i32(pm->ps->pmTime),
                              x87f_load_f32(1.5f)),
                     x87f_load_f32(PM_LAND_FRICTION_STEP)),
            x87f_load_f32(1.0f)));
#else
        val = (float)pm->ps->pmTime * 1.5f * PM_LAND_FRICTION_STEP + 1.0f;
#endif
    } else {
        val = 2.5f;
    }
    return val;
}

/* ------------------------------------------------------------------ */
/*  0x2348e  PM_GetJumpFactor                                */
/*  Same logic as land friction multiplier.                            */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2348e, 3348e_FUN_0003348e.c, VERIFY-WAVE3-MOVEMENT-C01-2026-06-17): DATAFLOW_VERIFIED - pmTime < 1700 branch, float32 1.5 * 0.00058823527 + 1.0 curve, 2.5 fallback, and long double return checked. */
static long double PM_GetJumpFactor(void)
{
    float val;
    if (pm->ps->pmTime < PM_LAND_FRICTION_SCALE_TIME) {
#if EMULATE_X87
        val = x87f_store_f32(x87f_add(
            x87f_mul(x87f_mul(x87f_load_i32(pm->ps->pmTime),
                              x87f_load_f32(1.5f)),
                     x87f_load_f32(PM_LAND_FRICTION_STEP)),
            x87f_load_f32(1.0f)));
#else
        val = (float)pm->ps->pmTime * 1.5f * PM_LAND_FRICTION_STEP + 1.0f;
#endif
    } else {
        val = 2.5f;
    }
    return val;
}

/* ------------------------------------------------------------------ */
/*  0x2e2c7  BG_GetSpeed                                             */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2e2c7, 3e2c7_BG_GetSpeed.c, VERIFY-P1-MOVEMENT-C02-2026-06-17): DATAFLOW_VERIFIED - ladder flag branch, horizontal speed calculation, 500 ms ladder-jump suppression, and vertical speed return checked. */
float BG_GetSpeed(gclient_t *client, int time)
{
    if ((client->ps.playerStateFlags & PM_STANCE_LADDER) == 0) {
#if EMULATE_X87
        return (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
            x87f_mul(x87f_load_f32(client->ps.velocity[0]),
                     x87f_load_f32(client->ps.velocity[0])),
            x87f_mul(x87f_load_f32(client->ps.velocity[1]),
                     x87f_load_f32(client->ps.velocity[1])))));
#else
        return (float)CoduoLibm_Sqrt((double)(client->ps.velocity[0] *
                                    client->ps.velocity[0] +
                                    client->ps.velocity[1] *
                                    client->ps.velocity[1]));
#endif
    }

    if (coduo_int32_from_bits((uint32_t)time -
                              (uint32_t)client->ps.lastJumpCommandTime) < 500) {
        return 0.0f;
    }

    return client->ps.velocity[2];
}

/* ------------------------------------------------------------------ */
/*  0x2e342  PM_FloatAbs                                             */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2e342, 3e342_FUN_0003e342.c, VERIFY-P1-MOVEMENT-C02-2026-06-17): DATAFLOW_VERIFIED - float absolute-value return checked. */
long double PM_FloatAbs(float value)
{
    return (long double)fabsf(value);
}

/* ------------------------------------------------------------------ */
/*  0x2e35b  PM_FloatSign                                            */
/*  Returns +1 for zero/positive values and -1 for negative values.    */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2e35b, 3e35b_FUN_0003e35b.c, VERIFY-P1-MOVEMENT-C02-2026-06-17): DATAFLOW_VERIFIED - negative-predicate call and -2/+1 sign transform checked. */
int PM_FloatSign(float value)
{
    return PM_FloatIsNegative(value) * -2 + 1;
}

/* ------------------------------------------------------------------ */
/*  0x2e381  PM_FloatIsNegative                                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2e381, 3e381_FUN_0003e381.c, VERIFY-P1-MOVEMENT-C02-2026-06-17): DATAFLOW_VERIFIED - float less-than-zero predicate checked. */
int PM_FloatIsNegative(float value)
{
    return value < 0.0f;
}

/* ------------------------------------------------------------------ */
/*  0x2e3b0  PM_VerifyPronePosition                                  */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2e3b0, 3e3b0_PM_VerifyPronePosition.c, VERIFY-P1-MOVEMENT-C02-2026-06-17): DATAFLOW_VERIFIED - prone flag gate, BG_CheckProne argument offsets, trace callbacks, entity type, and failed-check origin/velocity rollback checked. */
int PM_VerifyPronePosition(const float *origin, const float *velocity)
{
    int ok;

    if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0) {
        return 1;
    }

    ok = BG_CheckProne(pm->ps->psClientNum, &pm->ps->psOrigin[0], pm->ps->playerMaxs[0],
                       30.0f, pm->ps->proneDirection, &pm->ps->torsoHeight,
                       &pm->ps->torsoPitch, &pm->ps->waistPitch,
                       1, 1, NULL, pm->trace3, pm->trace2,
                       0, 60.0f, pm->entityType);
    if (ok == 0) {
        pm->ps->psOrigin[0] = origin[0];
        pm->ps->psOrigin[1] = origin[1];
        pm->ps->psOrigin[2] = origin[2];
        pm->ps->velocity[0] = velocity[0];
        pm->ps->velocity[1] = velocity[1];
        pm->ps->velocity[2] = velocity[2];
    }

    return ok;
}

/* NOT_FROM_ORIGINAL_SOURCE: local factoring for three-axis velocity clear sites. */
static void game_compat_pm_clear_velocity(void)
{
    pm->ps->velocity[2] = 0.0f;
    pm->ps->velocity[1] = 0.0f;
    pm->ps->velocity[0] = 0.0f;
}

/* ------------------------------------------------------------------ */
/*  0x2e563  PM_SlideMove                                            */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2e563, 3e563_PM_SlideMove.c, VERIFY-MOVEMENT-PACKET-2026-06-17): DATAFLOW_VERIFIED - signature, bool return, gravity-only end velocity initialization, water/ground plane seeding, 4-bump slide loop, allsolid/max-plane velocity clears, recollision nudge, plane/crease clipping, maxClipImpact, gravity final velocity, and pmTime rollback checked. */
int PM_SlideMove(int gravity)
{
    int bumpcount;
    int numplanes;
    int i, j, k;
    float timeLeft;
    float planes[PM_MAX_CLIP_PLANES][3];
    vec3_t primalVelocity;
    vec3_t endVelocity;
    vec3_t newVelocity;
    vec3_t clippedEndVelocity;
    vec3_t dir;
    vec3_t end;
    float d;
    float into;
    trace_t trace;

    primalVelocity[0] = pm->ps->velocity[0];
    primalVelocity[1] = pm->ps->velocity[1];
    primalVelocity[2] = pm->ps->velocity[2];

    endVelocity[0] = 0.0f;
    endVelocity[1] = 0.0f;
    endVelocity[2] = 0.0f;

    if (gravity != 0) {
        endVelocity[0] = pm->ps->velocity[0];
        endVelocity[1] = pm->ps->velocity[1];
        endVelocity[2] = pm->ps->velocity[2];
#if EMULATE_X87
        endVelocity[2] = x87f_store_f32(x87f_sub(
            x87f_load_f32(endVelocity[2]),
            x87f_mul(x87f_load_i32(pm->ps->gravity),
                     x87f_load_f32(pml.frametime))));
        pm->ps->velocity[2] = x87f_store_f32(x87f_mul(
            x87f_add(x87f_load_f32(pm->ps->velocity[2]),
                     x87f_load_f32(endVelocity[2])),
            x87f_load_f32(0.5f)));
#else
        endVelocity[2] = (float)((long double)endVelocity[2] -
                                 (long double)pm->ps->gravity *
                                     (long double)pml.frametime);
        pm->ps->velocity[2] = (pm->ps->velocity[2] + endVelocity[2]) * 0.5f;
#endif
        primalVelocity[2] = endVelocity[2];

        if (pml.waterlevel != 0) {
            PM_ClipVelocity((float *)&pm->ps->velocity[0], pml.groundTrace.normal,
                            (float *)&pm->ps->velocity[0], 1.001f);
        }
    }

    timeLeft = pml.frametime;
    numplanes = 0;

    if (pml.waterlevel != 0) {
        planes[0][0] = pml.groundTrace.normal[0];
        planes[0][1] = pml.groundTrace.normal[1];
        planes[0][2] = pml.groundTrace.normal[2];
        numplanes = 1;
    }

    VectorNormalize2((const float *)&pm->ps->velocity[0], planes[numplanes]);
    numplanes++;

    for (bumpcount = 0; bumpcount < 4; bumpcount++) {
#if EMULATE_X87
        for (i = 0; i < 3; i++) {
            end[i] = x87f_store_f32(x87f_add(
                x87f_load_f32(pm->ps->psOrigin[i]),
                x87f_mul(x87f_load_f32(pm->ps->velocity[i]),
                         x87f_load_f32(timeLeft))));
        }
#else
        end[0] = pm->ps->psOrigin[0] + pm->ps->velocity[0] * timeLeft;
        end[1] = pm->ps->psOrigin[1] + pm->ps->velocity[1] * timeLeft;
        end[2] = pm->ps->psOrigin[2] + pm->ps->velocity[2] * timeLeft;
#endif

        PM_trace(&trace, &pm->ps->psOrigin[0], pm->mins, pm->maxs, end,
                 pm->ps->psClientNum, pm->traceMask);

        if (trace.allsolid != 0) {
            pm->ps->velocity[2] = 0.0f;
            return 1;
        }

        if (trace.fraction > 0.0f) {
            pm->ps->psOrigin[0] = trace.endpos[0];
            pm->ps->psOrigin[1] = trace.endpos[1];
            pm->ps->psOrigin[2] = trace.endpos[2];
        }

        if (trace.fraction == 1.0f) {
            break;
        }

        PM_AddTouchEnt(trace.entityNum);
#if EMULATE_X87
        timeLeft = x87f_store_f32(x87f_sub(
            x87f_load_f32(timeLeft),
            x87f_mul(x87f_load_f32(timeLeft), x87f_load_f32(trace.fraction))));
#else
        timeLeft -= timeLeft * trace.fraction;
#endif

        if (numplanes >= PM_MAX_CLIP_PLANES) {
            if (pm->debugMove > 1) {
                Com_Printf("%i:MAX_CLIP_PLANES\n", c_pmove);
            }
            game_compat_pm_clear_velocity();
            return 1;
        }

        for (i = 0; i < numplanes; i++) {
            /* 0x2ea8a: x,y,z summation order; the dot remains in x87 width
             * through the comparison against float32 0.999f. */
#if EMULATE_X87
            if (x87f_lt(x87f_load_f32(0.999f),
                        MDOT3X(trace.normal[0], planes[i][0],
                                  trace.normal[1], planes[i][1],
                                  trace.normal[2], planes[i][2]))) {
#else
            if (trace.normal[0] * planes[i][0] +
                trace.normal[1] * planes[i][1] +
                trace.normal[2] * planes[i][2] > 0.999f) {
#endif
                if (pm->debugMove > 1) {
                    Com_Printf("%i:recollided with plane normal (%.2f, %.2f, %.2f)\n",
                               c_pmove, (double)trace.normal[0],
                               (double)trace.normal[1],
                               (double)trace.normal[2]);
                }
                pm->ps->velocity[0] += trace.normal[0];
                pm->ps->velocity[1] += trace.normal[1];
                pm->ps->velocity[2] += trace.normal[2];
                break;
            }
        }

        if (i < numplanes) {
            continue;
        }

        planes[numplanes][0] = trace.normal[0];
        planes[numplanes][1] = trace.normal[1];
        planes[numplanes][2] = trace.normal[2];
        numplanes++;

        for (i = 0; i < numplanes; i++) {
            /* 0x2ec50: x,y,z summation order; 0x2ecb5: the epsilon is the
             * double 0.1 (fld QWORD @0x9ba48), not 0.1f. */
#if EMULATE_X87
            into = x87f_store_f32(MDOT3X(
                pm->ps->velocity[0], planes[i][0], pm->ps->velocity[1],
                planes[i][1], pm->ps->velocity[2], planes[i][2]));
#else
            into = pm->ps->velocity[0] * planes[i][0] +
                   pm->ps->velocity[1] * planes[i][1] +
                   pm->ps->velocity[2] * planes[i][2];
#endif
            if (into >= 0.1) {
                continue;
            }

            if (pml.maxClipImpact < -into) {
                uint32_t impactBits;
                memcpy(&impactBits, &into, sizeof(impactBits));
                impactBits ^= FLOAT_SIGN_BIT_MASK;
                memcpy(&pml.maxClipImpact, &impactBits,
                       sizeof(pml.maxClipImpact));
            }

            PM_ClipVelocity((float *)&pm->ps->velocity[0], planes[i],
                            newVelocity, 1.001f);
            PM_ClipVelocity(endVelocity, planes[i], clippedEndVelocity,
                            1.001f);

            for (j = 0; j < numplanes; j++) {
                if (j == i) {
                    continue;
                }
                /* 0x2edca/0x2ee18: x,y,z order; double 0.1 epsilon. */
#if EMULATE_X87
                if (x87f_le(x87f_load_f64(0.1),
                            MDOT3X(newVelocity[0], planes[j][0],
                                      newVelocity[1], planes[j][1],
                                      newVelocity[2], planes[j][2]))) {
                    continue;
                }
#else
                if (newVelocity[0] * planes[j][0] +
                    newVelocity[1] * planes[j][1] +
                    newVelocity[2] * planes[j][2] >= 0.1) {
                    continue;
                }
#endif

                PM_ClipVelocity(newVelocity, planes[j], newVelocity,
                                1.001f);
                PM_ClipVelocity(clippedEndVelocity, planes[j],
                                clippedEndVelocity, 1.001f);

                /* 0x2eebc/0x2ef77/0x2efc8: all three dot products sum in
                 * x,y,z order. */
#if EMULATE_X87
                if (x87f_lt(MDOT3X(newVelocity[0], planes[i][0],
                                      newVelocity[1], planes[i][1],
                                      newVelocity[2], planes[i][2]),
                            x87f_load_f32(0.0f))) {
#else
                if (newVelocity[0] * planes[i][0] +
                    newVelocity[1] * planes[i][1] +
                    newVelocity[2] * planes[i][2] < 0.0f) {
#endif
                    CrossProduct(planes[i], planes[j], dir);
                    VectorNormalize(dir);

#if EMULATE_X87
                    d = x87f_store_f32(MDOT3X(
                        dir[0], pm->ps->velocity[0], dir[1],
                        pm->ps->velocity[1], dir[2], pm->ps->velocity[2]));
#else
                    d = dir[0] * pm->ps->velocity[0] +
                        dir[1] * pm->ps->velocity[1] +
                        dir[2] * pm->ps->velocity[2];
#endif
                    newVelocity[0] = dir[0] * d;
                    newVelocity[1] = dir[1] * d;
                    newVelocity[2] = dir[2] * d;

#if EMULATE_X87
                    d = x87f_store_f32(MDOT3X(
                        dir[0], endVelocity[0], dir[1], endVelocity[1], dir[2],
                        endVelocity[2]));
#else
                    d = dir[0] * endVelocity[0] +
                        dir[1] * endVelocity[1] +
                        dir[2] * endVelocity[2];
#endif
                    clippedEndVelocity[0] = dir[0] * d;
                    clippedEndVelocity[1] = dir[1] * d;
                    clippedEndVelocity[2] = dir[2] * d;

                    for (k = 0; k < numplanes; k++) {
                        if (k == i || k == j) {
                            continue;
                        }
                        /* 0x2f065/0x2f0b3: x,y,z order; double 0.1. */
#if EMULATE_X87
                        if (x87f_lt(MDOT3X(newVelocity[0], planes[k][0],
                                              newVelocity[1], planes[k][1],
                                              newVelocity[2], planes[k][2]),
                                    x87f_load_f64(0.1))) {
                            game_compat_pm_clear_velocity();
                            return 1;
                        }
#else
                        if (newVelocity[0] * planes[k][0] +
                            newVelocity[1] * planes[k][1] +
                            newVelocity[2] * planes[k][2] < 0.1) {
                            game_compat_pm_clear_velocity();
                            return 1;
                        }
#endif
                    }
                }
            }

            pm->ps->velocity[0] = newVelocity[0];
            pm->ps->velocity[1] = newVelocity[1];
            pm->ps->velocity[2] = newVelocity[2];
            endVelocity[0] = clippedEndVelocity[0];
            endVelocity[1] = clippedEndVelocity[1];
            endVelocity[2] = clippedEndVelocity[2];
            break;
        }
    }

    if (gravity != 0) {
        pm->ps->velocity[0] = endVelocity[0];
        pm->ps->velocity[1] = endVelocity[1];
        pm->ps->velocity[2] = endVelocity[2];
    }

    if (pm->ps->pmTime != 0) {
        pm->ps->velocity[0] = primalVelocity[0];
        pm->ps->velocity[1] = primalVelocity[1];
        pm->ps->velocity[2] = primalVelocity[2];
    }

    return bumpcount != 0;
}

/* ------------------------------------------------------------------ */
/*  0x300a5  PM_StepDeltaRound                                         */
/*  Local helper following PM_StepSlideMove in the stock binary; the   */
/*  argument is rounded to float at the call boundary (0x2fdd4); the  */
/*  subsequent 0.5f addition remains in x87 width until truncation.   */
/* ------------------------------------------------------------------ */
static int PM_StepDeltaRound(float delta)
{
    return game_compat_int32_from_long_double_trunc(
        (long double)delta + (long double)0.5f);
}

/* ------------------------------------------------------------------ */
/*  0x2f236  PM_StepSlideMove                                        */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2f236, 3f236_PM_StepSlideMove.c, VERIFY-MOVEMENT-PACKET-2026-06-17): DATAFLOW_VERIFIED - ladder/water wall-jump clears, start/slide snapshots, slide call, prone step size, jump-step height caps, up/down traces, entityNum<64 rollback, step-result dot-product selection, jump velocity clamp, prone verification, step event clamp/bias, velocity retention, bob cycle, and footstep side effects checked. */
void PM_StepSlideMove(int stepType)
{
    int hit;
    int stepDelta;
    int stepAbs;
    int oldBobCycle;
    int downStep;
    int onGround;
    int jumpStep;
    float stepSize;
    float stepRoom;
    vec3_t down;
    vec3_t startOrigin;
    vec3_t startVelocity;
    vec3_t slideOrigin;
    vec3_t slideVelocity;
    float flatSlideDelta[2];
    float stepSlideDelta[2];
    float scale;
    float remainingJumpHeight;
    trace_t trace;

    stepRoom = 0.0f;
    jumpStep = 0;

    if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) == 0) {
        if (pml.waterlevel == 0) {
            onGround = 0;
            if ((pm->ps->playerStateFlags & PM_STANCE_WALLJUMP) != 0 &&
                pm->ps->pmTime != 0) {
                pm->ps->playerStateFlags &= ~PM_STANCE_WALLJUMP;
                pm->ps->jumpOriginZ = 0;
            }
        } else {
            onGround = 1;
        }
    } else {
        onGround = 0;
        pm->ps->playerStateFlags &= ~PM_STANCE_WALLJUMP;
        pm->ps->jumpOriginZ = 0;
    }

    startOrigin[0] = pm->ps->psOrigin[0];
    startOrigin[1] = pm->ps->psOrigin[1];
    startOrigin[2] = pm->ps->psOrigin[2];
    startVelocity[0] = pm->ps->velocity[0];
    startVelocity[1] = pm->ps->velocity[1];
    startVelocity[2] = pm->ps->velocity[2];

    hit = PM_SlideMove(stepType);

    stepSize = (pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0 ? 18.0f : 10.0f;

    if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
        if ((pm->ps->playerStateFlags & PM_STANCE_WALLJUMP) != 0 &&
            pm->ps->pmTime != 0) {
            pm->ps->playerStateFlags &= ~PM_STANCE_WALLJUMP;
            pm->ps->jumpOriginZ = 0;
        }

        /* jumpOriginZ + 39.0f is summed and compared at full x87 width
         * (no float store before the compare). */
#if EMULATE_X87
        int lgt39_le_start = x87f_le(
            x87f_add(x87f_load_f32(pm->ps->jumpOriginZ), x87f_load_f32(39.0f)),
            x87f_load_f32(startOrigin[2]));
        int lgt39_lt_start18 = x87f_lt(
            x87f_add(x87f_load_f32(pm->ps->jumpOriginZ), x87f_load_f32(39.0f)),
            x87f_add(x87f_load_f32(startOrigin[2]), x87f_load_f32(18.0f)));
#else
        int lgt39_le_start = (pm->ps->jumpOriginZ + 39.0f <= startOrigin[2]);
        int lgt39_lt_start18 =
            (pm->ps->jumpOriginZ + 39.0f < startOrigin[2] + 18.0f);
#endif
        if (hit == 0 || (pm->ps->playerStateFlags & PM_STANCE_WALLJUMP) == 0 ||
            lgt39_le_start) {
            if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) == 0 ||
                pm->ps->velocity[2] <= 0.0f) {
                return;
            }
        } else {
            stepSize = 18.0f;
            if (lgt39_lt_start18) {
#if EMULATE_X87
                stepSize = x87f_store_f32(x87f_sub(
                    x87f_add(x87f_load_f32(pm->ps->jumpOriginZ),
                             x87f_load_f32(39.0f)),
                    x87f_load_f32(startOrigin[2])));
#else
                stepSize = (pm->ps->jumpOriginZ + 39.0f) - startOrigin[2];
#endif
                if (stepSize < 1.0f) {
                    return;
                }
            }
            jumpStep = 1;
        }
    }

    slideOrigin[0] = pm->ps->psOrigin[0];
    slideOrigin[1] = pm->ps->psOrigin[1];
    slideOrigin[2] = pm->ps->psOrigin[2];
    slideVelocity[0] = pm->ps->velocity[0];
    slideVelocity[1] = pm->ps->velocity[1];
    slideVelocity[2] = pm->ps->velocity[2];
    flatSlideDelta[0] = slideOrigin[0] - startOrigin[0];
    flatSlideDelta[1] = slideOrigin[1] - startOrigin[1];

    if (hit != 0) {
        down[0] = startOrigin[0];
        down[1] = startOrigin[1];
        /* 0x2f5c3: stepSize + 1.0f is summed first, then added to the
         * copied start height. */
#if EMULATE_X87
        down[2] = x87f_store_f32(x87f_add(
            x87f_load_f32(startOrigin[2]),
            x87f_add(x87f_load_f32(stepSize), x87f_load_f32(1.0f))));
#else
        down[2] = startOrigin[2] + (stepSize + 1.0f);
#endif
        PM_trace(&trace, startOrigin, pm->mins, pm->maxs, down,
                 pm->ps->psClientNum, pm->traceMask);
#if EMULATE_X87
        stepRoom = x87f_store_f32(x87f_sub(
            x87f_mul(x87f_add(x87f_load_f32(stepSize), x87f_load_f32(1.0f)),
                     x87f_load_f32(trace.fraction)),
            x87f_load_f32(1.0f)));
#else
        stepRoom = (stepSize + 1.0f) * trace.fraction - 1.0f;
#endif
        if (stepRoom < 1.0f) {
            if (pm->debugMove != 0) {
                Com_Printf("%i:not enough step room\n", c_pmove);
            }
            stepRoom = 0.0f;
        } else {
            pm->ps->psOrigin[0] = down[0];
            pm->ps->psOrigin[1] = down[1];
            pm->ps->psOrigin[2] = startOrigin[2] + stepRoom;
            pm->ps->velocity[0] = startVelocity[0];
            pm->ps->velocity[1] = startVelocity[1];
            pm->ps->velocity[2] = startVelocity[2];
            PM_SlideMove(stepType);
        }
    }

    if (onGround != 0 || stepRoom != 0.0f || isnan(stepRoom)) {
        down[0] = pm->ps->psOrigin[0];
        down[1] = pm->ps->psOrigin[1];
        down[2] = pm->ps->psOrigin[2] - stepRoom;
        if (onGround != 0) {
            down[2] -= 9.0f;
        }

        PM_trace(&trace, &pm->ps->psOrigin[0], pm->mins, pm->maxs, down,
                 pm->ps->psClientNum, pm->traceMask);
        if (trace.entityNum < PM_STEP_ENTITYNUM_MIN) {
            pm->ps->psOrigin[0] = slideOrigin[0];
            pm->ps->psOrigin[1] = slideOrigin[1];
            pm->ps->psOrigin[2] = slideOrigin[2];
            pm->ps->velocity[0] = slideVelocity[0];
            pm->ps->velocity[1] = slideVelocity[1];
            pm->ps->velocity[2] = slideVelocity[2];
            return;
        }
        if (trace.fraction < 1.0f) {
            pm->ps->psOrigin[0] = trace.endpos[0];
            pm->ps->psOrigin[1] = trace.endpos[1];
            pm->ps->psOrigin[2] = trace.endpos[2];
            PM_ClipVelocity((float *)&pm->ps->velocity[0], trace.normal,
                            (float *)&pm->ps->velocity[0], 1.001f);
        } else if (stepRoom != 0.0f || isnan(stepRoom)) {
            pm->ps->psOrigin[2] -= stepRoom;
        }
    }

    /* 0x2f942/0x2f958: the origin deltas are rounded to float before the
     * dot products; both sums run in x,y order. */
    stepSlideDelta[0] = pm->ps->psOrigin[0] - startOrigin[0];
    stepSlideDelta[1] = pm->ps->psOrigin[1] - startOrigin[1];
    /* Both 2-term dots and the RHS +0.001f bias sum at full x87 width. */
#if EMULATE_X87
    int stepDotLe = x87f_le(
        x87f_add(x87f_mul(x87f_load_f32(stepSlideDelta[0]),
                          x87f_load_f32(pm->ps->velocity[0])),
                 x87f_mul(x87f_load_f32(stepSlideDelta[1]),
                          x87f_load_f32(pm->ps->velocity[1]))),
        x87f_add(x87f_add(x87f_mul(x87f_load_f32(flatSlideDelta[0]),
                                   x87f_load_f32(pm->ps->velocity[0])),
                          x87f_mul(x87f_load_f32(flatSlideDelta[1]),
                                   x87f_load_f32(pm->ps->velocity[1]))),
                 x87f_load_f32(0.001f)));
    int jumpTooHigh = (jumpStep != 0) &&
                      x87f_le(x87f_add(x87f_load_f32(pm->ps->jumpOriginZ),
                                       x87f_load_f32(39.0f)),
                              x87f_load_f32(pm->ps->psOrigin[2]));
#else
    int stepDotLe = (stepSlideDelta[0] * pm->ps->velocity[0] +
                     stepSlideDelta[1] * pm->ps->velocity[1] <=
                     flatSlideDelta[0] * pm->ps->velocity[0] +
                     flatSlideDelta[1] * pm->ps->velocity[1] + 0.001f);
    int jumpTooHigh = (jumpStep != 0 &&
                       pm->ps->jumpOriginZ + 39.0f <= pm->ps->psOrigin[2]);
#endif
    if (stepDotLe || jumpTooHigh) {
        pm->ps->psOrigin[0] = slideOrigin[0];
        pm->ps->psOrigin[1] = slideOrigin[1];
        pm->ps->psOrigin[2] = slideOrigin[2];
        pm->ps->velocity[0] = slideVelocity[0];
        pm->ps->velocity[1] = slideVelocity[1];
        pm->ps->velocity[2] = slideVelocity[2];

        if (pm->debugMove > 1) {
            if (jumpStep != 0) {
                Com_Printf("%i:didn't use jump step results because it went too high\n",
                           c_pmove);
            } else {
                Com_Printf("%i:didn't use step results\n", c_pmove);
            }
        }

        if (onGround != 0) {
            down[0] = pm->ps->psOrigin[0];
            down[1] = pm->ps->psOrigin[1];
            down[2] = pm->ps->psOrigin[2] - 9.0f;
            PM_trace(&trace, &pm->ps->psOrigin[0], pm->mins, pm->maxs, down,
                     pm->ps->psClientNum, pm->traceMask);
            if (trace.fraction < 1.0f) {
                pm->ps->psOrigin[0] = trace.endpos[0];
                pm->ps->psOrigin[1] = trace.endpos[1];
                pm->ps->psOrigin[2] = trace.endpos[2];
                PM_ClipVelocity((float *)&pm->ps->velocity[0], trace.normal,
                                (float *)&pm->ps->velocity[0], 1.001f);
                if (pm->debugMove > 1) {
                    Com_Printf("%i:did down step after not using step results\n",
                               c_pmove);
                }
            }
        }
    }

    if (jumpStep != 0 && pm->ps->psOrigin[2] - slideOrigin[2] > 0.0f) {
#if EMULATE_X87
        remainingJumpHeight = x87f_store_f32(x87f_sub(
            x87f_add(x87f_load_f32(pm->ps->jumpOriginZ), x87f_load_f32(39.0f)),
            x87f_load_f32(pm->ps->psOrigin[2])));
#else
        remainingJumpHeight = (pm->ps->jumpOriginZ + 39.0f) - pm->ps->psOrigin[2];
#endif
        if (remainingJumpHeight < 0.1f) {
            pm->ps->velocity[2] = 0.0f;
        } else {
#if EMULATE_X87
            remainingJumpHeight = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_mul(
                x87f_load_i32(pm->ps->gravity),
                x87f_add(x87f_load_f32(remainingJumpHeight),
                         x87f_load_f32(remainingJumpHeight)))));
#else
            remainingJumpHeight =
                (float)CoduoLibm_Sqrt((double)((long double)pm->ps->gravity *
                                     ((long double)remainingJumpHeight +
                                      (long double)remainingJumpHeight)));
#endif
            if (remainingJumpHeight < pm->ps->velocity[2]) {
                if (pm->debugMove != 0) {
                    Com_Printf("%i:adjusted jump vel: %.1f -> %.1f\n",
                               c_pmove, (double)pm->ps->velocity[2],
                               (double)remainingJumpHeight);
                }
                pm->ps->velocity[2] = remainingJumpHeight;
            }
        }
    }

    if (onGround != 0 && pm->ps->pmType < PM_TYPE_ANIM_SCRIPT_LIMIT &&
        PM_VerifyPronePosition(startOrigin, startVelocity) != 0 &&
        /* 0x2fd9e: the subtraction and fabs remain in x87 width through the
         * comparison against the double 0.5 constant. */
        (fabsl((long double)pm->ps->psOrigin[2] -
               (long double)slideOrigin[2]) > (long double)0.5) &&
        (stepDelta = PM_StepDeltaRound(pm->ps->psOrigin[2] - slideOrigin[2])) != 0) {
        if (pm->debugMove != 0) {
            if (jumpStep != 0) {
                Com_Printf("%i:jump step %2i\n", c_pmove, stepDelta);
            } else {
                Com_Printf("%i:stepped %2i\n", c_pmove, stepDelta);
            }
        }

        if (stepDelta < -16) {
            stepDelta = -16;
        } else if (stepDelta > 24) {
            stepDelta = 24;
        }
        BG_AddPredictableEventToPlayerstate(PM_STEP_EVENT,
                                            stepDelta + PM_STEP_EVENT_PARAM_BIAS,
                                            pm->ps);

#if EMULATE_X87
        scale = x87f_store_f32(x87f_add(
            x87f_mul(x87f_sub(x87f_load_f32(1.0f),
                              x87f_div(x87f_load_f32(fabsf(pm->ps->psOrigin[2] -
                                                           startOrigin[2])),
                                       x87f_load_f32(stepSize))),
                     x87f_load_f32(0.8f)),
            x87f_load_f32(PM_STEP_VELOCITY_RETAIN_BIAS)));
#else
        scale = (1.0f - fabsf(pm->ps->psOrigin[2] - startOrigin[2]) / stepSize) *
                0.8f + PM_STEP_VELOCITY_RETAIN_BIAS;
#endif
        pm->ps->velocity[0] *= scale;
        pm->ps->velocity[1] *= scale;
        pm->ps->velocity[2] *= scale;

        stepAbs = stepDelta < 0 ? -stepDelta : stepDelta;
        if (stepAbs > 3 && pm->ps->groundEntityNum != ENTITYNUM_NONE &&
            PM_ShouldMakeFootsteps() != 0) {
            downStep = stepDelta < 0 ? -stepDelta : stepDelta;
            downStep /= 2;
            if (downStep > 4) {
                downStep = 4;
            }
            oldBobCycle = pm->ps->bobCycle;
            {
#if EMULATE_X87
                /* long double is 80-bit on x86 but only 64-bit on arm64 — route
                 * the width through the shim to preserve the x87 result. */
                float bobStep = x87f_store_f32(x87f_add(
                    x87f_mul(x87f_load_i32(downStep), x87f_load_f32(1.25f)),
                    x87f_load_f32(7.0f)));
                pm->ps->bobCycle = x87f_store_i32_trunc(x87f_add(
                    x87f_load_i32(oldBobCycle), x87f_load_f32(bobStep))) & 0xff;
#else
                float bobStep = (float)((long double)downStep *
                                        (long double)1.25f +
                                        (long double)7.0f);
                pm->ps->bobCycle = (int)((long double)oldBobCycle +
                                         (long double)bobStep) & 0xff;
#endif
            }
            PM_FootstepEvent(oldBobCycle, pm->ps->bobCycle, 1);
        }
    }

}

/* ------------------------------------------------------------------ */
/*  0x234ef  PM_Friction                                         */
/*  Apply friction to the player's velocity.                           */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x234ef, 334ef_FUN_000334ef.c, VERIFY-MOVEMENT-PACKET-2026-06-17): DATAFLOW_VERIFIED - ground-plane z suppression, speed clear threshold, overhead/ground/step/fire gates, control min 100, wall-jump 0.3 friction, landing friction timer clear, overhead and spectator drops, and final velocity scale checked. */
static void PM_Friction(void)
{
    float velZ;
    float speed;
    float drop;
    float control;
    float newSpeed;
    float mult;

    velZ = pm->ps->velocity[2];
    if (pml.groundPlane != 0) {
        velZ = 0.0f;
    }

#if EMULATE_X87
    speed = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
        x87f_add(x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                          x87f_load_f32(pm->ps->velocity[0])),
                 x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                          x87f_load_f32(pm->ps->velocity[1]))),
        x87f_mul(x87f_load_f32(velZ), x87f_load_f32(velZ)))));
#else
    speed = (float)CoduoLibm_Sqrt((double)(pm->ps->velocity[0] *
                                 pm->ps->velocity[0] +
                                 pm->ps->velocity[1] *
                                 pm->ps->velocity[1] +
                                 velZ * velZ));
#endif

    if (speed < 1.0f) {
        pm->ps->velocity[2] = 0.0f;
        pm->ps->velocity[1] = 0.0f;
        pm->ps->velocity[0] = 0.0f;
        return;
    }

    drop = 0.0f;

    /* Standard ground friction */
    if (pm->overheadLevel < 2 && pml.groundPlane != 0 &&
        (pml.groundTrace.surfaceFlags & SURFACE_SLICK) == 0 &&
        (pm->ps->playerStateFlags & PS_FLAG_FIRING) == 0) {

        control = speed;
        if (control < pm_stopspeed) {
            control = pm_stopspeed;
        }
        mult = control;

        if ((pm->ps->playerStateFlags & PS_FLAG_WALLJUMP_FRICTION) != 0) {
            /* Wall-jump friction */
            mult = control * 0.3f;
        } else if ((pm->ps->playerStateFlags & PS_FLAG_FRICTION_TIMER) != 0) {
            /* Landing friction */
            if (pm->ps->pmTime < PM_FRICTION_TIMER_TIME) {
                mult = control * PM_GetSlowdownFriction();
            } else {
                pm->ps->playerStateFlags &= ~PS_FLAG_FRICTION_TIMER;
                pm->ps->jumpOriginZ = 0;
            }
        }

        /* 0x236bf: stock accumulates into the zero-initialised drop. */
#if EMULATE_X87
        drop = x87f_store_f32(x87f_add(
            x87f_load_f32(drop),
            x87f_mul(x87f_mul(x87f_load_f32(mult),
                              x87f_load_f32(pm_friction)),
                     x87f_load_f32(pml.frametime))));
#else
        drop += mult * pm_friction * pml.frametime;
#endif
    }

    /* Ladder friction */
    if (pm->overheadLevel != 0) {
#if EMULATE_X87
        drop = x87f_store_f32(x87f_add(
            x87f_load_f32(drop),
            x87f_mul(x87f_mul(x87f_mul(x87f_load_i32(pm->overheadLevel),
                                       x87f_load_f32(speed)),
                              x87f_load_f32(pm_waterfriction)),
                     x87f_load_f32(pml.frametime))));
#else
        drop += (float)pm->overheadLevel * speed * pm_waterfriction *
                pml.frametime;
#endif
    }

    /* Spectator friction */
    if (pm->ps->pmType == PM_TYPE_SPECTATOR) {
#if EMULATE_X87
        drop = x87f_store_f32(x87f_add(
            x87f_load_f32(drop),
            x87f_mul(x87f_mul(x87f_load_f32(speed),
                              x87f_load_f32(pm_spectatorfriction)),
                     x87f_load_f32(pml.frametime))));
#else
        drop += speed * pm_spectatorfriction * pml.frametime;
#endif
    }

    newSpeed = speed - drop;
    if (newSpeed < 0.0f) {
        newSpeed = 0.0f;
    }
#if EMULATE_X87
    newSpeed = x87f_store_f32(
        x87f_div(x87f_load_f32(newSpeed), x87f_load_f32(speed)));
#else
    newSpeed /= speed;
#endif

    pm->ps->velocity[0] *= newSpeed;
    pm->ps->velocity[1] *= newSpeed;
    pm->ps->velocity[2] *= newSpeed;
}

/* ------------------------------------------------------------------ */
/*  0x2379e  PM_Accelerate                                            */
/*  Accelerate velocity toward wishvel direction.                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2379e, 3379e_FUN_0003379e.c, VERIFY-MOVEMENT-PACKET-2026-06-17): DATAFLOW_VERIFIED - wishdir dot product, addSpeed gate, 100 speed floor, accel frametime multiply, addSpeed caps before and after grounded friction divisor, and three-axis velocity stores checked. */
static void PM_Accelerate(float *wishdir, float wishSpeed, float accel)
{
    float currentSpeed;
    float addSpeed;
    float accelspeed;
    int i;

#if EMULATE_X87
    currentSpeed = x87f_store_f32(x87f_add(
        x87f_add(x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                          x87f_load_f32(wishdir[0])),
                 x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                          x87f_load_f32(wishdir[1]))),
        x87f_mul(x87f_load_f32(pm->ps->velocity[2]),
                 x87f_load_f32(wishdir[2]))));
#else
    currentSpeed = pm->ps->velocity[0] * wishdir[0] +
                   pm->ps->velocity[1] * wishdir[1] +
                   pm->ps->velocity[2] * wishdir[2];
#endif
    addSpeed = wishSpeed - currentSpeed;
    if (addSpeed <= 0.0f) {
        return;
    }

    if (wishSpeed < pm_stopspeed) {
        wishSpeed = pm_stopspeed;
    }
#if EMULATE_X87
    accelspeed = x87f_store_f32(
        x87f_mul(x87f_mul(x87f_load_f32(accel), x87f_load_f32(pml.frametime)),
                 x87f_load_f32(wishSpeed)));
#else
    accelspeed = accel * pml.frametime * wishSpeed;
#endif
    if (accelspeed > addSpeed) {
        accelspeed = addSpeed;
    }

    /* Grounded movement scales acceleration by the player-state divisor. */
    if (pm->ps->groundEntityNum != ENTITYNUM_NONE) {
#if EMULATE_X87
        accelspeed = x87f_store_f32(x87f_mul(
            x87f_load_f32(accelspeed),
            x87f_div(x87f_load_f32(1.0f), x87f_load_f32(pm->ps->friction))));
#else
        accelspeed *= 1.0f / pm->ps->friction;
#endif
    }

    if (accelspeed > addSpeed) {
        accelspeed = addSpeed;
    }

    for (i = 0; i < 3; i++) {
#if EMULATE_X87
        pm->ps->velocity[i] = x87f_store_f32(x87f_add(
            x87f_load_f32(pm->ps->velocity[i]),
            x87f_mul(x87f_load_f32(accelspeed), x87f_load_f32(wishdir[i]))));
#else
        pm->ps->velocity[i] += accelspeed * wishdir[i];
#endif
    }
}

/* ------------------------------------------------------------------ */
/*  0x23905  PM_CmdScale                                          */
/*  Compute the 3D wish speed from the movement command.               */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x23905, 33905_FUN_00033905.c, VERIFY-MOVEMENT-PACKET-2026-06-17): DATAFLOW_VERIFIED - signed command byte absolutes, max axis selection, zero-command return, 3D length, speed/127 scale, walk/lean NaN path, run/sprint flag path, and noclip/ufo multipliers checked. */
static float PM_CmdScale(const usercmd_t *command)
{
    int fwd, right, up, maxVal;
    float len;
    float wishSpeed;

    fwd = (int)PM_CMD_WINDOW_FORWARDMOVE(command);
    if (fwd < 0) fwd = -fwd;
    maxVal = fwd;

    right = (int)PM_CMD_WINDOW_RIGHTMOVE(command);
    if (right < 0) right = -right;
    if (maxVal < right) {
        maxVal = right;
    }

    up = (int)PM_CMD_WINDOW_UPMOVE(command);
    if (up < 0) up = -up;
    if (maxVal < up) {
        maxVal = up;
    }

    if (maxVal == 0) {
        return 0.0f;
    }

    /* NO EMULATE_X87 shim: integer-fed sqrt — the sum is signed-byte command
     * products (exact ints), so both builds hand libm sqrt the same double, and
     * libm sqrt is IEEE-correctly-rounded/bit-portable. See
     * docs/x87-native-identical-sites.md rule 2. */
    len = (float)CoduoLibm_Sqrt((double)(float)(PM_CMD_WINDOW_FORWARDMOVE(command) *
                                      PM_CMD_WINDOW_FORWARDMOVE(command) +
                                      PM_CMD_WINDOW_RIGHTMOVE(command) *
                                      PM_CMD_WINDOW_RIGHTMOVE(command) +
                                      PM_CMD_WINDOW_UPMOVE(command) *
                                      PM_CMD_WINDOW_UPMOVE(command)));
#if EMULATE_X87
    wishSpeed = x87f_store_f32(x87f_div(
        x87f_mul(x87f_load_i32(maxVal), x87f_load_i32(pm->ps->speed)),
        x87f_mul(x87f_load_f32(len), x87f_load_f32(127.0f))));
#else
    wishSpeed = (float)(((long double)maxVal * (long double)pm->ps->speed) /
                        ((long double)len * (long double)127.0f));
#endif

    if ((pm->ps->playerStateFlags & PM_STANCE_WALKING) != 0 || pm->ps->leanFraction != 0.0f ||
        isnan(pm->ps->leanFraction)) {
        wishSpeed *= pm->ps->walkSpeedScale;
    } else if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) == 0) {
        wishSpeed *= pm->ps->runSpeedScale;
    } else {
        wishSpeed *= pm->ps->sprintSpeedScale;
    }

    if (pm->ps->pmType == PM_TYPE_NOCLIP) {
        wishSpeed *= 3.0f;
    }
    if (pm->ps->pmType == PM_TYPE_UFO) {
        wishSpeed *= 6.0f;
    }

    return wishSpeed;
}

/* ------------------------------------------------------------------ */
/*  0x23af5  PM_CmdScale_Walk                                        */
/*  Compute max ground speed from movement input, stance, and weapon.  */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x23af5, 33af5_FUN_00033af5.c, VERIFY-MOVEMENT-PACKET-2026-06-17): DATAFLOW_VERIFIED - backward/strafe scale, max input and 2D length, walk/lean/ADS-spread weapon call path, run/sprint selection, noclip/ufo branches, stance lerp order, overhead slowdown, second weapon-info movement scale call, and walk-button 0.4 multiplier checked. */
static float PM_CmdScale_Walk(const usercmd_t *command)
{
    int fwd;
    float fwdScaled, rightScaled;
    float maxInput, speed;
    float len;
    int effectiveStance;
    float lerpFrac;
    const weaponInfo_t *weaponInfo;

    fwd = (int)PM_CMD_WINDOW_FORWARDMOVE(command);
    /* 0x23b31/0x23b49/0x23b6f: fabs is applied to the product, not to the
     * operands (matters for the sign if a speed scale is negative). */
    if (fwd < 0) {
        fwdScaled = fabsf((float)PM_CMD_WINDOW_FORWARDMOVE(command) *
                          pm->ps->backSpeedScale);
    } else {
        fwdScaled = fabsf((float)PM_CMD_WINDOW_FORWARDMOVE(command));
    }

    rightScaled = fabsf((float)PM_CMD_WINDOW_RIGHTMOVE(command) *
                        pm->ps->strafeSpeedScale);
    maxInput = rightScaled;
    if (maxInput < fwdScaled) {
        maxInput = fwdScaled;
    }

    if (maxInput == 0.0f) {
        return 0.0f;
    }

    /* NO EMULATE_X87 shim: integer-fed CoduoLibm_Sqrt (rule 2, see PM_CmdScale above). */
    len = (float)CoduoLibm_Sqrt((double)(float)(PM_CMD_WINDOW_RIGHTMOVE(command) *
                                      PM_CMD_WINDOW_RIGHTMOVE(command) +
                                      PM_CMD_WINDOW_FORWARDMOVE(command) *
                                      PM_CMD_WINDOW_FORWARDMOVE(command)));
#if EMULATE_X87
    speed = x87f_store_f32(x87f_div(
        x87f_mul(x87f_load_i32(pm->ps->speed), x87f_load_f32(maxInput)),
        x87f_mul(x87f_load_f32(len), x87f_load_f32(127.0f))));
#else
    speed = (float)(((long double)pm->ps->speed * (long double)maxInput) /
                    ((long double)len * (long double)127.0f));
#endif

    /* ADS or melee or special weapon class uses the ADS speed path. */
    if ((pm->ps->playerStateFlags & PM_STANCE_WALKING) != 0 || pm->ps->leanFraction != 0.0f ||
        isnan(pm->ps->leanFraction) ||
        (pm->ps->weaponState == WEAPON_STATE_BREAKING_DOWN &&
         ((const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon))->weaponClass ==
             WEAPCLASS_LMG)) {
        speed *= pm->ps->walkSpeedScale;
    } else if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) == 0) {
        speed *= pm->ps->runSpeedScale;
    } else {
        speed *= pm->ps->sprintSpeedScale;
    }

    if (pm->ps->pmType == PM_TYPE_NOCLIP) {
        speed *= 3.0f;
    } else if (pm->ps->pmType == PM_TYPE_UFO) {
        speed *= 6.0f;
    } else {
        effectiveStance = PM_GetEffectiveStance(pm->ps);
        lerpFrac = PM_GetViewHeightLerp(pm->ps->crouchViewHeight,
                                        pm->ps->proneViewHeight);
        if (lerpFrac != 0.0f || isnan(lerpFrac)) {
#if EMULATE_X87
            speed = x87f_store_f32(x87f_mul(
                x87f_load_f32(speed),
                x87f_add(x87f_mul(x87f_sub(x87f_load_f32(1.0f),
                                           x87f_load_f32(lerpFrac)),
                                  x87f_load_f32(pm->ps->crouchSpeedScale)),
                         x87f_mul(x87f_load_f32(lerpFrac),
                                  x87f_load_f32(pm->ps->proneSpeedScale)))));
#else
            speed *= (1.0f - lerpFrac) * pm->ps->crouchSpeedScale +
                      lerpFrac * pm->ps->proneSpeedScale;
#endif
        } else {
            lerpFrac = PM_GetViewHeightLerp(pm->ps->proneViewHeight,
                                            pm->ps->crouchViewHeight);
            if (lerpFrac != 0.0f || isnan(lerpFrac)) {
#if EMULATE_X87
                speed = x87f_store_f32(x87f_mul(
                    x87f_load_f32(speed),
                    x87f_add(
                        x87f_mul(x87f_sub(x87f_load_f32(1.0f),
                                          x87f_load_f32(lerpFrac)),
                                 x87f_load_f32(pm->ps->proneSpeedScale)),
                        x87f_mul(x87f_load_f32(lerpFrac),
                                 x87f_load_f32(pm->ps->crouchSpeedScale)))));
#else
                speed *= (1.0f - lerpFrac) * pm->ps->proneSpeedScale +
                          lerpFrac * pm->ps->crouchSpeedScale;
#endif
            } else if (effectiveStance == 1) {
                speed *= pm->ps->proneSpeedScale;
            } else if (effectiveStance == 2) {
                speed *= pm->ps->crouchSpeedScale;
            }
        }

        /* Fatigue slowdown */
        if (pm->overheadLevel != 0) {
            /* 0x23ea3/0x23ebf: both intermediates are rounded to float; the
             * stock scale is 1.0 - (1.0 - pm_waterSwimScale) * frac with
             * pm_waterSwimScale a const 0.5f. */
#if EMULATE_X87
            float overheadFrac = x87f_store_f32(x87f_div(
                x87f_load_i32(pm->overheadLevel), x87f_load_f32(3.0f)));
            float overheadScale = x87f_store_f32(x87f_sub(
                x87f_load_f32(1.0f),
                x87f_mul(x87f_sub(x87f_load_f32(1.0f),
                                  x87f_load_f32(pm_waterSwimScale)),
                         x87f_load_f32(overheadFrac))));
#else
            float overheadFrac = (float)pm->overheadLevel / 3.0f;
            float overheadScale =
                1.0f - (1.0f - pm_waterSwimScale) * overheadFrac;
#endif
            speed *= overheadScale;
        }
    }

    /* Weapon-specific speed multiplier */
    weaponInfo = (const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon);
    if (pm->ps->currentWeapon != 0 && weaponInfo->moveSpeedScale > 0.0f &&
        (pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) == 0) {
        speed *= weaponInfo->moveSpeedScale;
    }

    /* Walk button reduces speed */
    if ((PM_CMD_WINDOW_BUTTON_BYTE1(command) & PMOVE_WBUTTON_WALK) != 0) {
        speed *= pm_shellshockScale;
    }

    return speed;
}

/* ------------------------------------------------------------------ */
/*  0x23f62  PM_UpdateBodyLean                                        */
/*  Post-movement direction / lean angle update.                       */
/* ------------------------------------------------------------------ */
/* VERIFIED_MACHINE_CODE(0x23f62): prone yaw payload, ladder yaw payload, movement delta length gate, vectoangles yaw use, x87 truncating angle conversions, backpedal flip, signed-byte lean clamp, and zero fallback checked. */
/* NOT_FROM_ORIGINAL_SOURCE: define i386 movsx-from-byte semantics in portable C. */
static int game_compat_pm_sign_extend_byte(uint8_t value)
{
    uint32_t extended = (uint32_t)value;

    if ((value & UINT8_C(0x80)) != 0) {
        extended |= UINT32_C(0xffffff00);
    }
    return coduo_int32_from_bits(extended);
}

static void PM_UpdateBodyLean(void)
{
    float dx, dy, dz;
    float dist;
    vec3_t dirAngles;
    float yaw;
    int lean;
    int absLean;

    if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) != 0 &&
        (pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) == 0) {
        lean = game_compat_int32_from_float_trunc(
            AngleDelta(pm->ps->proneDirection, pm->ps->viewAngles[1]));
        absLean = lean < 0
                      ? coduo_int32_from_bits(0u - (uint32_t)lean)
                      : lean;
        if (absLean > PM_LEAN_CLAMP_DEGREES) {
            lean = lean < 1 ? -PM_LEAN_CLAMP_DEGREES :
                               PM_LEAN_CLAMP_DEGREES;
        }
        pm->ps->movementDir = game_compat_pm_sign_extend_byte((uint8_t)lean);
        return;
    }

    if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0) {
        /* Knockback: use ladder yaw */
        yaw = vectoyaw(pm->ps->ladderNormal);
        yaw = 180.0f + yaw;
        lean = game_compat_int32_from_float_trunc(
            AngleDelta(yaw, pm->ps->viewAngles[1]));
        absLean = lean < 0
                      ? coduo_int32_from_bits(0u - (uint32_t)lean)
                      : lean;
        if (absLean > PM_LEAN_CLAMP_DEGREES) {
            lean = lean < 1 ? -PM_LEAN_CLAMP_DEGREES :
                               PM_LEAN_CLAMP_DEGREES;
        }
        pm->ps->movementDir = game_compat_pm_sign_extend_byte((uint8_t)lean);
        return;
    }

    /* Normal: compute lean from movement direction */
    dx = pm->ps->psOrigin[0] - pml.previousOrigin[0];
    dy = pm->ps->psOrigin[1] - pml.previousOrigin[1];
    dz = pm->ps->psOrigin[2] - pml.previousOrigin[2];

    if ((PM_FORWARDMOVE(pm) != 0 || PM_RIGHTMOVE(pm) != 0) &&
        pm->ps->groundEntityNum != ENTITYNUM_NONE) {
        /* 0x24167: machine sums the squares in x,y,z order. */
#if EMULATE_X87
        dist = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
            x87f_add(x87f_mul(x87f_load_f32(dx), x87f_load_f32(dx)),
                     x87f_mul(x87f_load_f32(dy), x87f_load_f32(dy))),
            x87f_mul(x87f_load_f32(dz), x87f_load_f32(dz)))));
#else
        dist = (float)CoduoLibm_Sqrt((double)(dx * dx + dy * dy + dz * dz));
#endif
        /* frametime * 5.0f is compared at full x87 width (0x62db2 in the stock
         * DLL: fmulp; fld dist; fcomip, no float spill), and 5.0 is not a power
         * of two, so the exact 80-bit product differs from the SSE-rounded one
         * at the boundary — emulate the compare. */
#if EMULATE_X87
        if ((dist != 0.0f || isnan(dist)) &&
            x87f_lt(x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(5.0f)),
                    x87f_load_f32(dist))) {
#else
        if ((dist != 0.0f || isnan(dist)) && pml.frametime * 5.0f < dist) {
#endif
            vec3_t dirVec;
            dirVec[0] = dx;
            dirVec[1] = dy;
            dirVec[2] = dz;
            VectorNormalize2(dirVec, dirAngles);
            vectoangles(dirAngles, dirAngles);
            lean = game_compat_int32_from_float_trunc(
                AngleDelta(dirAngles[1], pm->ps->viewAngles[1]));
            if (PM_FORWARDMOVE(pm) < 0) {
                lean = game_compat_int32_from_float_trunc(
                    AngleNormalize180((float)lean + 180.0f));
            }
            absLean = lean < 0
                          ? coduo_int32_from_bits(0u - (uint32_t)lean)
                          : lean;
            if (absLean > PM_LEAN_CLAMP_DEGREES) {
                lean = lean < 1 ? -PM_LEAN_CLAMP_DEGREES :
                                   PM_LEAN_CLAMP_DEGREES;
            }
            pm->ps->movementDir =
                game_compat_pm_sign_extend_byte((uint8_t)lean);
            return;
        }
    }
    pm->ps->movementDir = 0;
}

/* ------------------------------------------------------------------ */
/*  0x242b2  PM_GroundSurfaceType                                      */
/*  Returns the current ground surface type for movement events.       */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x242b2, 342b2_FUN_000342b2.c, VERIFY-NEXT-005-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - pml.groundTrace.surfaceFlags 0x2000 gate, surface mask 0x1f00000 >> 20, pm null/overheadLevel water override to 20, zero fallback, and return path checked. */
static int PM_GroundSurfaceType(void)
{
    int event;
    if ((pml.groundTrace.surfaceFlags & SURFACE_NO_FOOTSTEPS) == 0) {
        event = (pml.groundTrace.surfaceFlags & PM_FOOTSTEP_SURFACE_TYPE_MASK) >>
                PM_FOOTSTEP_SURFACE_TYPE_SHIFT;
        if (pm != NULL && pm->overheadLevel != 0) {
            event = PM_JUMP_EVENT_WATER_OVERRIDE;
        }
    } else {
        event = 0;
    }
    return event;
}

/* ------------------------------------------------------------------ */
/*  0x24328  PM_JumpForSurface                                       */
/*  Choose the jump event to play.                                     */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x24328, 34328_FUN_00034328.c, VERIFY-NEXT-005-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - ladder flag 0x10 branch, PM_GroundSurfaceType call, zero event preservation, +70 run-surface offset, ladder event 83, and return path checked. */
static int PM_JumpForSurface(void)
{
    int event;
    if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) == 0) {
        event = PM_GroundSurfaceType();
        if (event == 0) {
            event = 0;
        } else {
            event = event + PM_JUMP_EVENT_RUN_BASE;
        }
    } else {
        event = PM_JUMP_EVENT_LADDER;
    }
    return event;
}

/* ------------------------------------------------------------------ */
/*  0x25b9b  PM_FootstepForSurface                           */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25b9b, 35b9b_FUN_00035b9b.c, VERIFY-NEXT-005-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - surface zero return, prone +47, fatigue/sprint +70, walking/lean/NaN +24, default +1, and pm->ps->leanFraction offset 0x44 checked. */
int PM_FootstepForSurface(uint32_t playerStateFlags)
{
    int event = PM_GroundSurfaceType();

    if (event == 0) {
        return 0;
    }

    if ((playerStateFlags & PM_STANCE_PRONE) != 0) {
        return event + PM_LANDING_EVENT_PRONE_BASE;
    }
    if ((playerStateFlags & PM_STANCE_FATIGUE_DRAIN) != 0) {
        return event + PM_JUMP_EVENT_RUN_BASE;
    }
    if ((playerStateFlags & PM_STANCE_WALKING) != 0 ||
        pm->ps->leanFraction != 0.0f || isnan(pm->ps->leanFraction)) {
        return event + PM_LANDING_EVENT_SPRINT_BASE;
    }

    return event + 1;
}

/* ------------------------------------------------------------------ */
/*  0x2937c  PM_FootstepEvent                                         */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2937c, 3937c_PM_FootstepEvent.c, VERIFY-NEXT-005-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - bob edge gate, dry ground/no-ground branches, ladder bounds/end trace arguments and mask 0xfdfeffff, trace surface fallback 13, PM_FootstepForSurface call, overheadLevel 1/2 water event matrix, and all PM_AddEvent arguments checked. */
static void PM_FootstepEvent(int oldTime, int newTime, int shouldMake)
{
    uint8_t oldBob;
    uint8_t newBob;
    vec3_t mins;
    vec3_t maxs;
    vec3_t end;
    trace_t trace;
    int surfaceType;

    oldBob = (uint8_t)oldTime;
    newBob = (uint8_t)newTime;
    if ((((oldBob + 64u) ^ (newBob + 64u)) & 128u) == 0) {
        return;
    }

    if (pm->overheadLevel == 0) {
        if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
            if (shouldMake != 0 &&
                (pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0) {
                mins[0] = pm->mins[0] + 6.0f;
                mins[1] = pm->mins[1] + 6.0f;
                mins[2] = 8.0f;
                maxs[0] = pm->maxs[0] - 6.0f;
                maxs[1] = pm->maxs[1] - 6.0f;
                maxs[2] = pm->maxs[2];
                if (maxs[2] < 8.0f) {
                    maxs[2] = 8.0f;
                }

#if EMULATE_X87
                for (int i = 0; i < 3; i++) {
                    end[i] = x87f_store_f32(x87f_sub(
                        x87f_load_f32(pm->ps->psOrigin[i]),
                        x87f_mul(x87f_load_f32(pm->ps->ladderNormal[i]),
                                 x87f_load_f32(31.0f))));
                }
#else
                end[0] = pm->ps->psOrigin[0] - pm->ps->ladderNormal[0] * 31.0f;
                end[1] = pm->ps->psOrigin[1] -
                         pm->ps->ladderNormal[1] * 31.0f;
                end[2] = pm->ps->psOrigin[2] - pm->ps->ladderNormal[2] * 31.0f;
#endif

                PM_trace(&trace, &pm->ps->psOrigin[0], mins, maxs, end,
                         pm->ps->psClientNum,
                         pm->traceMask & ~(int)PM_FOOTSTEP_TRACE_MASK_CLEAR);
                surfaceType =
                    (trace.surfaceFlags & PM_FOOTSTEP_SURFACE_TYPE_MASK) >>
                    PM_FOOTSTEP_SURFACE_TYPE_SHIFT;
                if (trace.fraction == 1.0f || surfaceType == 0) {
                    surfaceType = PM_FOOTSTEP_DEFAULT_SURFACE;
                }
                PM_AddEvent(surfaceType + PM_FOOTSTEP_SURFACE_EVENT_BASE);
            }
        } else if (shouldMake != 0) {
            PM_AddEvent(PM_FootstepForSurface(pm->ps->playerStateFlags));
        }
        return;
    }

    if (pm->overheadLevel == 1 || pm->overheadLevel == 2) {
        if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0) {
            if ((pm->ps->playerStateFlags & PM_STANCE_WALKING) != 0 ||
                pm->ps->leanFraction != 0.0f || isnan(pm->ps->leanFraction)) {
                PM_AddEvent(PM_FOOTSTEP_WATER_LEAN_EVENT);
            } else if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) == 0) {
                PM_AddEvent(PM_FOOTSTEP_WATER_WALK_EVENT);
            } else {
                PM_AddEvent(PM_FOOTSTEP_WATER_FAST_EVENT);
            }
        } else {
            PM_AddEvent(PM_FOOTSTEP_WATER_PRONE_EVENT);
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x29756  PM_ShouldMakeFootsteps                                   */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x29756, 39756_PM_ShouldMakeFootsteps.c, VERIFY-PACKET-MOVEMENT-PRONE-ADJ-2026-06-17): DATAFLOW_VERIFIED - walking flag pre-read, effective-stance gate, redundant backpedal branch, and 0/1 return paths checked. */
static int PM_ShouldMakeFootsteps(void)
{
    int effectiveStance;
    int walking;

    walking = pm->ps->playerStateFlags & PM_STANCE_WALKING;
    effectiveStance = PM_GetEffectiveStance(pm->ps);
    if (effectiveStance != 1 && effectiveStance != 2) {
        if ((pm->ps->playerStateFlags & PM_STANCE_BACKPEDAL) == 0) {
            if (walking == 0) {
                return 1;
            }
        } else if (walking == 0) {
            return 1;
        }
    }
    return 0;
}

/* ------------------------------------------------------------------ */
/*  0x25c34  PM_LightLandingForSurface                               */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25c34, 35c34_FUN_00035c34.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - PM_GroundSurfaceType call, zero-preserving branch, +24 light landing event base, and return checked. */
static int PM_LightLandingForSurface(void)
{
    int event = PM_GroundSurfaceType();
    if (event != 0) {
        event += PM_LANDING_EVENT_SPRINT_BASE;
    }
    return event;
}

/* ------------------------------------------------------------------ */
/*  0x25c5f  PM_MediumLandingForSurface                              */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25c5f, 35c5f_FUN_00035c5f.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - PM_GroundSurfaceType call, zero-preserving branch, +1 medium landing event offset, and return checked. */
static int PM_MediumLandingForSurface(void)
{
    int event = PM_GroundSurfaceType();
    if (event != 0) {
        event += 1;
    }
    return event;
}

/* ------------------------------------------------------------------ */
/*  0x25c88  PM_HardLandingForSurface                               */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25c88, 35c88_FUN_00035c88.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - PM_GroundSurfaceType call, +0x5d heavy landing event base, and return checked. */
static int PM_HardLandingForSurface(void)
{
    return PM_GroundSurfaceType() + PM_LANDING_EVENT_HEAVY_BASE;
}

/* ------------------------------------------------------------------ */
/*  0x25c9e  PM_DamageLandingForSurface                                 */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25c9e, 35c9e_FUN_00035c9e.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - PM_GroundSurfaceType call, +0x74 fall-damage event base, and return checked. */
static int PM_DamageLandingForSurface(void)
{
    return PM_GroundSurfaceType() + PM_FALL_DAMAGE_EVENT_BASE;
}

/* ------------------------------------------------------------------ */
/*  0x24380  PM_Jump                                        */
/*  Set up velocity for a water jump.                                  */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x24380, 34380_FUN_00034380.c, VERIFY-NEXT-005-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - pml water/ground clears, groundEntityNum 1023 store, gravity * doubled jump height, wall-jump timer divisor, CoduoLibm_Sqrt(double) to float velocity store, 0x2008 flag set, pmTime clear, and jumpOriginZ origin-z store checked. */
static void PM_Jump(float jumpHeight)
{
    float vel;

    pml.waterlevel  = 0;
    pml.waterlevel2 = 0;
    pml.groundPlane = 0;
    pm->ps->groundEntityNum = ENTITYNUM_NONE;

    /* 0x243bd: gravity enters through fild; the doubled float jump height and
     * product remain in x87 width until the float store. */
    vel = (float)((long double)pm->ps->gravity *
                  ((long double)jumpHeight + (long double)jumpHeight));
    if ((pm->ps->playerStateFlags & PM_STANCE_WALLJUMP) != 0 &&
        pm->ps->pmTime < PM_WALLJUMP_TIMER_LIMIT) {
#if EMULATE_X87
        /* float / long double: done in x87 width on x86 (long double is only
         * 64-bit on arm64), so route the divide through the shim. */
        vel = x87f_store_f32(x87f_div(x87f_load_f32(vel),
                                      x87f_load_f32((float)PM_GetJumpFactor())));
#else
        vel = vel / PM_GetJumpFactor();
#endif
    }

    /* NO shim: single-value sqrt of the already-rounded float vel — no multi-op
     * arg to diverge, libm sqrt is bit-portable (rule 3). */
    pm->ps->velocity[2] = (float)CoduoLibm_Sqrt((double)vel);
    pm->ps->playerStateFlags |= PM_STANCE_WALLJUMP | PM_STANCE_JUMP_HELD;
    pm->ps->pmTime = 0;
    pm->ps->jumpOriginZ = pm->ps->psOrigin[2];
}

/* ------------------------------------------------------------------ */
/*  0x24483  PM_CheckJump                                             */
/*  Check if the player should jump and handle it.                     */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x24483, 34483_FUN_00034483.c, VERIFY-NEXT-005-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - last-jump/blocked/effective-stance/ADS-spread/upmove/jump-held gates, upmove clear, PM_Jump(39), ladder velocity scale and reflected-normal path, ladder flag clear, jump event, aimSpreadScale +64 clamp 255, forwardmove animation event, and 0/1 returns checked. */
static int PM_CheckJump(void)
{
    int result;

    /* Can't jump if recently landed */
    if (coduo_int32_from_bits((uint32_t)pm->command.commandTime -
                              (uint32_t)pm->ps->lastJumpCommandTime) < 500) {
        return 0;
    }

    /* Can't jump if knocked back */
    if ((pm->ps->playerStateFlags & PM_STANCE_RECENT_LAND_BLOCK) != 0) {
        return 0;
    }

    /* Can only jump from standing stance */
    if (PM_GetEffectiveStance(pm->ps) != 0) {
        return 0;
    }

    /* Class 3 weapons cannot jump while ADS is active. */
    if ((pm->ps->playerStateFlags & PM_STANCE_ADS) != 0) {
        const weaponInfo_t *wi =
            (const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon);
        if (wi->weaponClass == WEAPCLASS_LMG) {
            return 0;
        }
    }

    /* Check upmove input */
    if (PM_UPMOVE(pm) < 10) {
        return 0;
    }

    /* Jump held flag prevents repeated jumps */
    if ((pm->ps->playerStateFlags & PM_STANCE_JUMP_HELD) != 0) {
        PM_UPMOVE(pm) = 0;
        return 0;
    }

    /* Set up the jump */
    PM_Jump(39.0f);

    /* If prone, adjust jump */
    if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0) {
        pm->ps->velocity[2] *= 0.75f;
        {
            vec3_t jumpDir;
            vec3_t wallNormal;
            float dot;
            jumpDir[0] = pml.forward[0];
            jumpDir[1] = pml.forward[1];
            jumpDir[2] = 0.0f;
            VectorNormalize(jumpDir);

            wallNormal[0] = pm->ps->ladderNormal[0];
            wallNormal[1] = pm->ps->ladderNormal[1];
            wallNormal[2] = pm->ps->ladderNormal[2];
            /* 0x2460e/0x2465f: machine sums both dot products in x,y,z order. */
#if EMULATE_X87
            if (x87f_lt(MDOT3X(wallNormal[0], pml.forward[0], wallNormal[1],
                                  pml.forward[1], wallNormal[2], pml.forward[2]),
                        x87f_load_f32(0.0f))) {
#else
            if (wallNormal[0] * pml.forward[0] +
                wallNormal[1] * pml.forward[1] +
                wallNormal[2] * pml.forward[2] < 0.0f) {
#endif
                vec3_t refl;
#if EMULATE_X87
                dot = x87f_store_f32(MDOT3X(jumpDir[0], wallNormal[0],
                                              jumpDir[1], wallNormal[1],
                                              jumpDir[2], wallNormal[2]));
                for (int i = 0; i < 3; i++) {
                    refl[i] = x87f_store_f32(x87f_add(
                        x87f_load_f32(jumpDir[i]),
                        x87f_mul(x87f_mul(x87f_load_f32(dot),
                                          x87f_load_f32(-2.0f)),
                                 x87f_load_f32(wallNormal[i]))));
                }
#else
                dot = jumpDir[0] * wallNormal[0] +
                      jumpDir[1] * wallNormal[1] +
                      jumpDir[2] * wallNormal[2];
                refl[0] = jumpDir[0] + dot * -2.0f * wallNormal[0];
                refl[1] = jumpDir[1] + dot * -2.0f * wallNormal[1];
                refl[2] = jumpDir[2] + dot * -2.0f * wallNormal[2];
#endif
                VectorNormalize(refl);
                pm->ps->velocity[0] = refl[0] * pm_ladderPushOff;
                pm->ps->velocity[1] = refl[1] * pm_ladderPushOff;
            } else {
                pm->ps->velocity[0] = jumpDir[0] * pm_ladderPushOff;
                pm->ps->velocity[1] = jumpDir[1] * pm_ladderPushOff;
            }
        }
        pm->ps->playerStateFlags &= ~PM_STANCE_LADDER;
    }

    PM_AddEvent(PM_JumpForSurface());

    pm->ps->aimSpreadScale += 64.0f;
    if (pm->ps->aimSpreadScale > 255.0f) {
        pm->ps->aimSpreadScale = 255.0f;
    }

    if (PM_FORWARDMOVE(pm) < 0) {
        BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP_BACK,
                           qfalse, qtrue);
    } else {
        BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP,
                           qfalse, qtrue);
    }

    result = 1;
    return result;
}

/* ------------------------------------------------------------------ */
/*  0x2706e  PM_GetViewHeightLerp                                    */
/*  Compute the interpolation fraction for viewheight transitions.     */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2706e, 3706e_FUN_0003706e.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - lerp-active gate, -1/target/start transition predicate, PM_GetViewHeightLerpTime arguments, command-time fraction, 0..1 clamp, and zero fallbacks checked. */
static float PM_GetViewHeightLerp(int fromHeight, int toHeight)
{
    float frac;
    int lerpTime;

    if (pm->ps->viewHeightLerpTime == 0) {
        return 0.0f;
    }

    if ((fromHeight == -1 || toHeight == -1) ||
        (toHeight == pm->ps->viewHeightLerpTarget &&
         ((toHeight != pm->ps->crouchViewHeight ||
           (fromHeight == pm->ps->proneViewHeight && pm->ps->viewHeightLerpDown == 0)) ||
          (fromHeight == pm->ps->standViewHeight && pm->ps->viewHeightLerpDown != 0)))) {
        lerpTime = PM_GetViewHeightLerpTime(pm->ps, pm->ps->viewHeightLerpTarget,
                                             pm->ps->viewHeightLerpDown);
        int elapsed = coduo_int32_from_bits(
            (uint32_t)pm->command.commandTime -
            (uint32_t)pm->ps->viewHeightLerpTime);
#if EMULATE_X87
        frac = x87f_store_f32(x87f_div(
            x87f_load_i32(elapsed),
            x87f_load_i32(lerpTime)));
#else
        frac = (float)((long double)elapsed / (long double)lerpTime);
#endif
        if (frac < 0.0f) frac = 0.0f;
        else if (frac > 1.0f) frac = 1.0f;
        return frac;
    }

    return 0.0f;
}

/* ------------------------------------------------------------------ */
/*  0x26f47  PM_ViewHeightTableLerp                                   */
/*  Look up interpolated viewheight from a viewheight table.           */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x26f47, 36f47_FUN_00036f47.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - percent-zero case, 12-byte table stride, exact-hit return, interpolation math, -1 sentinel fallback, origin-adjust out-param, and long double return checked. */
static float PM_ViewHeightTableLerp(int percent,
                                    const viewheight_lerp_key_t *table,
                                    float *outOriginAdjust)
{
    float viewHeight;
    const viewheight_lerp_key_t *entry;
    int idx;

    /* VERIFIED_DECOMPILER(0x26f47, 36f47_FUN_00036f47.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED; table +8 is an integer origin-adjust value converted to float for the out-param. */
    if (percent == 0) {
        *outOriginAdjust = (float)table[0].originAdjust;
        viewHeight = table[0].height;
    } else {
        entry = &table[1];
        idx = 1;
        for (;;) {
            if (entry->percent == -1) {
                *outOriginAdjust = (float)table[0].originAdjust;
                viewHeight = table[0].height;
                break;
            }
            if (percent < entry->percent) {
                const viewheight_lerp_key_t *prev = &entry[-1];
                int percentDelta = coduo_int32_from_bits(
                    (uint32_t)percent - (uint32_t)prev->percent);
                int percentSpan = coduo_int32_from_bits(
                    (uint32_t)entry->percent - (uint32_t)prev->percent);
                int originAdjustSpan = coduo_int32_from_bits(
                    (uint32_t)entry->originAdjust -
                    (uint32_t)prev->originAdjust);
#if EMULATE_X87
                float t = x87f_store_f32(x87f_div(
                    x87f_load_i32(percentDelta),
                    x87f_load_i32(percentSpan)));
                *outOriginAdjust = x87f_store_f32(x87f_add(
                    x87f_mul(x87f_load_i32(originAdjustSpan),
                             x87f_load_f32(t)),
                    x87f_load_i32(prev->originAdjust)));
                viewHeight = x87f_store_f32(x87f_add(
                    x87f_mul(x87f_sub(x87f_load_f32(entry->height),
                                      x87f_load_f32(prev->height)),
                             x87f_load_f32(t)),
                    x87f_load_f32(prev->height)));
#else
                float t = (float)((long double)percentDelta /
                                  (long double)percentSpan);
                *outOriginAdjust =
                    (float)((long double)originAdjustSpan * (long double)t +
                            (long double)prev->originAdjust);
                viewHeight = (entry->height - prev->height) * t + prev->height;
#endif
                break;
            }
            if (percent == entry->percent) {
                *outOriginAdjust = (float)entry->originAdjust;
                viewHeight = entry->height;
                break;
            }
            idx++;
            entry = &table[idx];
        }
    }
    return viewHeight;
}

/* ------------------------------------------------------------------ */
/*  0x26ef8  PM_GetViewHeightLerpTime                                 */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x26ef8, 36ef8_PM_GetViewHeightLerpTime.c, VERIFY-PACKET-MOVEMENT-PRONE-ADJ-2026-06-17): DATAFLOW_VERIFIED - proneViewHeight/crouchViewHeight offset tests and 400/200 transition return cases checked. */
int PM_GetViewHeightLerpTime(playerState_t *client, int fromHeight,
                             int transitionMode)
{
    if (fromHeight == (int32_t)client->proneViewHeight) {
        return 400;
    }
    if (fromHeight == (int32_t)client->crouchViewHeight) {
        if (transitionMode == 0) {
            return 400;
        }
        return 200;
    }
    return 200;
}

/* ------------------------------------------------------------------ */
/*  0x271f8  PM_ViewHeightAdjust                                      */
/*  Interpolate viewheight between stances.                            */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x271f8, 371f8_FUN_000371f8.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - init/spectator branch, stance target gate, active-lerp percentage clamp, table selection, origin-adjust StepSlideMove side effects, new-lerp start fields, reversal bookkeeping, and non-stance 180 ups ramp checked. */
static void PM_ViewHeightAdjust(void)
{
    int targetHeight;
    float curHeight;
    int pct;
    int lerpTime;
    float originAdjust;
    float originAdjustDelta;

    targetHeight = pm->ps->viewHeightTarget;
    curHeight = pm->ps->viewHeightCurrent;

    /* Initialize or reset viewheight */
    if (pm->ps->viewHeightTarget == 0 || pm->ps->viewHeightCurrent == 0.0f) {
        if (pm->ps->pmType == PM_TYPE_SPECTATOR) {
            pm->ps->viewHeightCurrent = 0.0f;
        } else {
            pm->ps->viewHeightCurrent = (float)pm->ps->viewHeightTarget;
        }
        return;
    }

    /* If target changed or lerp in progress */
    if (curHeight != (float)targetHeight || isnan(curHeight) ||
        isnan((float)targetHeight) || pm->ps->viewHeightLerpTime != 0) {

        int isKnownStance = 0;

        /* Check if target is a known stance height */
        if (targetHeight == pm->ps->proneViewHeight ||
            targetHeight == pm->ps->crouchViewHeight ||
            targetHeight == pm->ps->standViewHeight) {
            isKnownStance = 1;
        }

        if (isKnownStance) {
            if (pm->ps->viewHeightLerpTime != 0) {
                /* Lerp in progress */
                lerpTime = PM_GetViewHeightLerpTime(pm->ps, pm->ps->viewHeightLerpTarget,
                                                     pm->ps->viewHeightLerpDown);
                {
                    int elapsed = coduo_int32_from_bits(
                        (uint32_t)pm->command.commandTime -
                        (uint32_t)pm->ps->viewHeightLerpTime);
                    int scaledElapsed = coduo_int32_from_bits(
                        (uint32_t)elapsed * UINT32_C(100));
                    pct = scaledElapsed / lerpTime;
                }
                if (pct < 0) pct = 0;
                else if (pct > 100) pct = 100;

                if (pct == 100) {
                    pm->ps->viewHeightCurrent = (float)pm->ps->viewHeightLerpTarget;
                    pm->ps->viewHeightLerpTime = 0;
                    pm->ps->viewHeightLerpPosAdj = 0.0f;
                } else {
                    /* VERIFIED_DECOMPILER(0x271f8, 371f8_FUN_000371f8.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED; PM_ViewHeightTableLerp returns the interpolated view height; its out-param is the origin-adjust table value. */
                    if (pm->ps->viewHeightLerpTarget == pm->ps->proneViewHeight) {
                        pm->ps->viewHeightCurrent =
                            PM_ViewHeightTableLerp(pct, pmViewHeightLerpProne,
                                                   &originAdjust);
                    } else if (pm->ps->viewHeightLerpTarget == pm->ps->crouchViewHeight) {
                        if (pm->ps->viewHeightLerpDown == 0) {
                            pm->ps->viewHeightCurrent =
                                PM_ViewHeightTableLerp(
                                    pct, pmViewHeightLerpCrouchedFalling,
                                    &originAdjust);
                        } else {
                            pm->ps->viewHeightCurrent =
                                PM_ViewHeightTableLerp(
                                    pct, pmViewHeightLerpCrouchedRising,
                                    &originAdjust);
                        }
                    } else {
                        pm->ps->viewHeightCurrent =
                            PM_ViewHeightTableLerp(pct, pmViewHeightLerpStanding,
                                                   &originAdjust);
                    }

                    /* Adjust origin if the table origin-adjust value changed. */
                    originAdjustDelta =
                        originAdjust - pm->ps->viewHeightLerpPosAdj;
                    if (fabsl((long double)pm->ps->viewHeightLerpPosAdj -
                              (long double)originAdjust) >
                        (long double)0.05) {
                        vec3_t savedVel;
                        vec3_t moveDir;

                        savedVel[0] = pm->ps->velocity[0];
                        savedVel[1] = pm->ps->velocity[1];
                        savedVel[2] = pm->ps->velocity[2];

                        if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
                            originAdjustDelta *= 0.5f;
                        }
#if EMULATE_X87
                        originAdjustDelta = x87f_store_f32(x87f_div(
                            x87f_load_f32(originAdjustDelta),
                            x87f_load_f32(pml.frametime)));
#else
                        originAdjustDelta /= pml.frametime;
#endif

                        moveDir[0] = pml.forward[0];
                        moveDir[1] = pml.forward[1];
                        moveDir[2] = 0.0f;
                        VectorNormalize(moveDir);

                        pm->ps->velocity[0] = moveDir[0] * originAdjustDelta;
                        pm->ps->velocity[1] = moveDir[1] * originAdjustDelta;
                        pm->ps->velocity[2] = moveDir[2] * originAdjustDelta;
                        PM_StepSlideMove(1);

                        pm->ps->velocity[0] = savedVel[0];
                        pm->ps->velocity[1] = savedVel[1];
                        pm->ps->velocity[2] = savedVel[2];
                        pm->ps->viewHeightLerpPosAdj = originAdjust;
                    }
                }
            }

            /* Start a new lerp if needed */
            if (pm->ps->viewHeightLerpTime == 0) {
                if (pm->ps->viewHeightCurrent != (float)targetHeight ||
                    isnan(pm->ps->viewHeightCurrent) || isnan((float)targetHeight)) {
                    pm->ps->viewHeightLerpTime = pm->command.commandTime;

                    if (targetHeight == pm->ps->proneViewHeight) {
                        pm->ps->viewHeightLerpDown = 1;
                        if ((float)pm->ps->crouchViewHeight < pm->ps->viewHeightCurrent) {
                            pm->ps->viewHeightLerpTarget = pm->ps->crouchViewHeight;
                        } else {
                            pm->ps->viewHeightLerpTarget = pm->ps->proneViewHeight;
                        }
                    } else if (targetHeight == pm->ps->crouchViewHeight) {
                        if ((float)targetHeight < pm->ps->viewHeightCurrent) {
                            pm->ps->viewHeightLerpDown = 1;
                        } else {
                            pm->ps->viewHeightLerpDown = 0;
                        }
                        pm->ps->viewHeightLerpTarget = pm->ps->crouchViewHeight;
                    } else if (targetHeight == pm->ps->standViewHeight) {
                        pm->ps->viewHeightLerpDown = 0;
                        if (pm->ps->viewHeightCurrent < (float)pm->ps->crouchViewHeight) {
                            pm->ps->viewHeightLerpTarget = pm->ps->crouchViewHeight;
                        } else {
                            pm->ps->viewHeightLerpTarget = pm->ps->standViewHeight;
                        }
                    }
                }
            } else if (pm->ps->viewHeightLerpTime != 0 &&
                       targetHeight != pm->ps->viewHeightLerpTarget &&
                       ((targetHeight < pm->ps->viewHeightLerpTarget &&
                         pm->ps->viewHeightLerpDown == 0) ||
                        (pm->ps->viewHeightLerpTarget < targetHeight &&
                         pm->ps->viewHeightLerpDown != 0))) {
                /* Direction changed mid-lerp */
                pct = 100 - pct;
                pm->ps->viewHeightLerpDown ^= 1;

                if (pm->ps->viewHeightLerpDown == 0) {
                    if (pm->ps->viewHeightLerpTarget == pm->ps->proneViewHeight) {
                        pm->ps->viewHeightLerpTarget = pm->ps->crouchViewHeight;
                    } else if (pm->ps->viewHeightLerpTarget == pm->ps->crouchViewHeight) {
                        pm->ps->viewHeightLerpTarget = pm->ps->standViewHeight;
                    }
                } else if (pm->ps->viewHeightLerpTarget == pm->ps->standViewHeight) {
                    pm->ps->viewHeightLerpTarget = pm->ps->crouchViewHeight;
                } else if (pm->ps->viewHeightLerpTarget == pm->ps->crouchViewHeight) {
                    pm->ps->viewHeightLerpTarget = pm->ps->proneViewHeight;
                }

                if (pct == 100) {
                    pm->ps->viewHeightCurrent = (float)pm->ps->viewHeightLerpTarget;
                    pm->ps->viewHeightLerpTime = 0;
                    pm->ps->viewHeightLerpPosAdj = 0.0f;
                } else {
                    int elapsed;

                    lerpTime = PM_GetViewHeightLerpTime(
                        pm->ps, pm->ps->viewHeightLerpTarget, pm->ps->viewHeightLerpDown);
#if EMULATE_X87
                    elapsed = x87f_store_i32_trunc(x87f_mul(
                        x87f_mul(x87f_load_i32(pct), x87f_load_f32(0.01f)),
                        x87f_load_i32(lerpTime)));
#else
                    elapsed = game_compat_int32_from_long_double_trunc(
                        (long double)pct * (long double)0.01f *
                        (long double)lerpTime);
#endif
                    pm->ps->viewHeightLerpTime = coduo_int32_from_bits(
                        (uint32_t)pm->command.commandTime -
                        (uint32_t)elapsed);

                    if (pm->ps->viewHeightLerpTarget == pm->ps->proneViewHeight) {
                        PM_ViewHeightTableLerp(pct, pmViewHeightLerpProne,
                                               &originAdjust);
                    } else if (pm->ps->viewHeightLerpTarget == pm->ps->crouchViewHeight) {
                        if (pm->ps->viewHeightLerpDown == 0) {
                            PM_ViewHeightTableLerp(
                                pct, pmViewHeightLerpCrouchedFalling,
                                &originAdjust);
                        } else {
                            PM_ViewHeightTableLerp(
                                pct, pmViewHeightLerpCrouchedRising,
                                &originAdjust);
                        }
                    } else {
                        PM_ViewHeightTableLerp(pct, pmViewHeightLerpStanding,
                                               &originAdjust);
                    }
                    pm->ps->viewHeightLerpPosAdj = originAdjust;
                }
            }
        } else {
            /* VERIFIED_DECOMPILER(0x271f8, 371f8_FUN_000371f8.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED; non-stance targets bypass table transitions and ramp directly at 180 units per second. */
            pm->ps->viewHeightLerpTime = 0;
            if (curHeight < (float)targetHeight) {
#if EMULATE_X87
                pm->ps->viewHeightCurrent = x87f_store_f32(x87f_add(
                    x87f_load_f32(pm->ps->viewHeightCurrent),
                    x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(180.0f))));
#else
                pm->ps->viewHeightCurrent += pml.frametime * 180.0f;
#endif
                if ((float)targetHeight <= pm->ps->viewHeightCurrent) {
                    pm->ps->viewHeightCurrent = (float)targetHeight;
                }
            } else {
#if EMULATE_X87
                pm->ps->viewHeightCurrent = x87f_store_f32(x87f_sub(
                    x87f_load_f32(pm->ps->viewHeightCurrent),
                    x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(180.0f))));
#else
                pm->ps->viewHeightCurrent -= pml.frametime * 180.0f;
#endif
                if (pm->ps->viewHeightCurrent <= (float)targetHeight) {
                    pm->ps->viewHeightCurrent = (float)targetHeight;
                }
            }
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x262b7  PM_CorrectAllSolid                                       */
/*  Linux i386 leaf 0x262b7; Mac symbols name the ground allsolid      */
/*  recovery helper as PM_CorrectAllSolid (game 0x8260, cgame 0x7980). */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x262b7, 362b7_FUN_000362b7.c, VERIFY-WAVE4-MOVEMENT-GROUND-WATER-2026-06-17): DATAFLOW_VERIFIED - 26-position startsolid probe loop, PM_trace argument order, allsolid failure ground/water/flag clears, recovered-origin writes, one-unit down trace, pml trace copy, endpos origin writes, and return values checked. */
static int PM_CorrectAllSolid(trace_t *trace)
{
    int i;
    vec3_t start;

    for (i = 0; i < 26; i++) {
        start[0] = pm->ps->psOrigin[0] + pmGroundTraceAdjustOffsets[i * 3 + 0];
        start[1] = pm->ps->psOrigin[1] + pmGroundTraceAdjustOffsets[i * 3 + 1];
        start[2] = pm->ps->psOrigin[2] + pmGroundTraceAdjustOffsets[i * 3 + 2];
        PM_trace(trace, start, pm->mins, pm->maxs, start,
                 pm->ps->psClientNum, pm->traceMask);
        if (trace->startsolid == 0) {
            break;
        }
    }

    if (i > 25) {
        pm->ps->groundEntityNum = ENTITYNUM_NONE;
        pml.waterlevel  = 0;
        pml.waterlevel2 = 0;
        pml.groundPlane = 0;
        pm->ps->playerStateFlags &= ~PM_STANCE_WALLJUMP;
        pm->ps->jumpOriginZ = 0;
        return 0;
    }

    /* Move origin to the found position */
    pm->ps->psOrigin[0] = start[0];
    pm->ps->psOrigin[1] = start[1];
    pm->ps->psOrigin[2] = start[2];

    /* Trace down 1 unit to confirm ground */
    start[2] -= 1.0f;
    PM_trace(trace, &pm->ps->psOrigin[0], pm->mins, pm->maxs, start,
             pm->ps->psClientNum, pm->traceMask);

    pml.groundTrace = *trace;

    pm->ps->psOrigin[0] = trace->endpos[0];
    pm->ps->psOrigin[1] = trace->endpos[1];
    pm->ps->psOrigin[2] = trace->endpos[2];

    return 1;
}

/* ------------------------------------------------------------------ */
/*  0x2656d  PM_GroundTraceMissed                                     */
/*  Linux i386 leaf 0x2656d; Mac symbols name the missed-ground branch */
/*  as PM_GroundTraceMissed (game 0x80a0, cgame 0x77c0).              */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2656d, 3656d_FUN_0003656d.c, VERIFY-WAVE4-MOVEMENT-GROUND-WATER-2026-06-17): DATAFLOW_VERIFIED - ground-none one-unit trace, lift debug branch, 64-unit trace, backward/forward anim events, fraction/0.015625 waterlevel2 tests, ground clear, and pml water/ground clears checked. */
static void PM_GroundTraceMissed(void)
{
    trace_t trace;
    vec3_t end;

    if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
        end[0] = pm->ps->psOrigin[0];
        end[1] = pm->ps->psOrigin[1];
        end[2] = pm->ps->psOrigin[2] - 1.0f;
        pm->trace(&trace, &pm->ps->psOrigin[0], pm->mins, pm->maxs, end,
                  pm->ps->psClientNum, pm->traceMask);
        pml.waterlevel2 = (trace.fraction != 1.0f) ? 1 : 0;
    } else {
        if (pm->debugMove != 0) {
            Com_Printf("%i:lift\n", c_pmove);
        }
        end[0] = pm->ps->psOrigin[0];
        end[1] = pm->ps->psOrigin[1];
        end[2] = pm->ps->psOrigin[2] - 64.0f;
        pm->trace(&trace, &pm->ps->psOrigin[0], pm->mins, pm->maxs, end,
                  pm->ps->psClientNum, pm->traceMask);
        if (trace.fraction == 1.0f) {
            if (PM_FORWARDMOVE(pm) < 0) {
                BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP_BACK,
                                   qfalse, qtrue);
            } else {
                BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP,
                                   qfalse, qtrue);
            }
            pml.waterlevel2 = 0;
        } else {
            pml.waterlevel2 =
                (trace.fraction < PM_WATERLEVEL_FRACTION_EPSILON) ? 1 : 0;
        }
    }
    pm->ps->groundEntityNum = ENTITYNUM_NONE;
    pml.waterlevel  = 0;
    pml.groundPlane = 0;
}

/* ------------------------------------------------------------------ */
/*  0x25cb4  PM_CrashLand                                          */
/*  Apply landing effects (damage, stun, sounds).                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25cb4, 35cb4_FUN_00035cb4.c, VERIFY-WAVE4-MOVEMENT-GROUND-WATER-2026-06-17): DATAFLOW_VERIFIED - overhead-level skip, gravity/fall discriminant, fall-damage cvar integer bounds, water damage halving, step-event clamp 24, landing event thresholds, stun timer/speed scaling, velocity multipliers, and predictable-event arguments checked. */
static void PM_CrashLand(void)
{
    float fallVel;
    float fallHeight;
    float grav;
    float minFallDamageHeight;
    float maxFallDamageHeight;
    float discriminant;
    float fallDistance;
    float impactVel;
    float halfNegGravity;
    float impactTime;
    int damagePct;
    int stepEvent;

    /* Only process if not fatigue level 3 */
    if (pm->overheadLevel == 3) {
        return;
    }

    /* 0x25cf2: the fall distance is rounded to float before it enters the
     * discriminant. */
    fallDistance = pml.previousOrigin[2] - pm->ps->psOrigin[2];
    grav = (float)pm->ps->gravity;
    fallVel = pml.previousVelocity[2];
    halfNegGravity = -grav * 0.5f;

#if EMULATE_X87
    discriminant = x87f_store_f32(x87f_sub(
        x87f_mul(x87f_load_f32(fallVel), x87f_load_f32(fallVel)),
        x87f_mul(x87f_mul(x87f_load_f32(halfNegGravity), x87f_load_f32(4.0f)),
                 x87f_load_f32(fallDistance))));
#else
    discriminant = fallVel * fallVel - halfNegGravity * 4.0f * fallDistance;
#endif
    if (discriminant < 0.0f) {
        return;
    }

    /* 0x25d7a-0x25d8b: the sqrt result is not rounded to float before the
     * subtract/divide; the only float rounding is the final store. */
#if EMULATE_X87
    impactTime = x87f_store_f32(x87f_div(
        x87f_sub(x87f_neg(x87f_load_f32(fallVel)),
                 x87f_load_f64(CoduoLibm_Sqrt((double)discriminant))),
        x87f_add(x87f_load_f32(halfNegGravity),
                 x87f_load_f32(halfNegGravity))));
    impactVel = x87f_store_f32(x87f_mul(
        x87f_add(x87f_mul(x87f_load_f32(impactTime), x87f_neg(x87f_load_f32(grav))),
                 x87f_load_f32(fallVel)),
        x87f_load_f32(-1.0f)));
    fallHeight = x87f_store_f32(x87f_div(
        x87f_mul(x87f_load_f32(impactVel), x87f_load_f32(impactVel)),
        x87f_add(x87f_load_f32(grav), x87f_load_f32(grav))));
#else
    impactTime = (float)((-fallVel - CoduoLibm_Sqrt((double)discriminant)) /
                         (halfNegGravity + halfNegGravity));
    impactVel = (impactTime * -grav + fallVel) * -1.0f;
    fallHeight = (impactVel * impactVel) / (grav + grav);
#endif

    if (pm->debugMove != 0) {
        /* 0x25dd1: machine passes the computed impact velocity, not the
         * pre-frame z velocity. */
        Com_Printf("landing vel: %.1f fall height: %.1f\n",
                   (double)impactVel, (double)fallHeight);
    }

    /* Compute damage percentage */
    minFallDamageHeight = bg_fallDamageMinHeight.value;
    maxFallDamageHeight = bg_fallDamageMaxHeight.value;

    if (maxFallDamageHeight <= minFallDamageHeight ||
        minFallDamageHeight < 0.0f) {
        Com_Printf("bg_fallDamageMaxHeight and bg_fallDamageMinHeight "
                   "have bad values\n");
        damagePct = 0;
    } else if (fallHeight <= minFallDamageHeight ||
               (pml.groundTrace.surfaceFlags & SURFACE_NO_DAMAGE) != 0 ||
               pm->ps->pmType > PM_TYPE_INTERMISSION) {
        damagePct = 0;
    } else if (maxFallDamageHeight <= fallHeight) {
        damagePct = 100;
    } else {
#if EMULATE_X87
        /* long double is 80-bit on x86 but 64-bit on arm64 — route the width
         * through the shim; the (int) truncates the 80-bit value (no float
         * spill, unlike a float-typed cast). */
        damagePct = x87f_store_i32_trunc(x87f_mul(
            x87f_div(x87f_sub(x87f_load_f32(fallHeight),
                              x87f_load_f32(minFallDamageHeight)),
                     x87f_sub(x87f_load_f32(maxFallDamageHeight),
                              x87f_load_f32(minFallDamageHeight))),
            x87f_load_f64(100.0)));
#else
        damagePct =
            (int)(((long double)fallHeight -
                   (long double)minFallDamageHeight) /
                  ((long double)maxFallDamageHeight -
                   (long double)minFallDamageHeight) *
                  (long double)100.0f);
#endif
        if (damagePct < 0) damagePct = 0;
        if (damagePct > 100) damagePct = 100;
    }

    if (pm->overheadLevel == 2) {
#if EMULATE_X87
        damagePct = x87f_store_i32_trunc(
            x87f_mul(x87f_load_i32(damagePct), x87f_load_f64(0.5)));
#else
        damagePct = (int)((long double)damagePct * (long double)0.5f);
#endif
    }

    /* Compute step event based on fall height */
    if (fallHeight <= PM_FALL_HEAVY_LANDING_HEIGHT) {
        stepEvent = 0;
    } else {
#if EMULATE_X87
        stepEvent = x87f_store_i32_trunc(x87f_add(
            x87f_mul(x87f_div(
                         x87f_sub(x87f_load_f32(fallHeight),
                                  x87f_load_f32(PM_FALL_HEAVY_LANDING_HEIGHT)),
                         x87f_load_f32(PM_FALL_STEP_EVENT_HEIGHT_RANGE)),
                     x87f_load_f32(PM_FALL_STEP_EVENT_SCALE)),
            x87f_load_f32(PM_FALL_STEP_EVENT_BASE)));
#else
        stepEvent =
            (int)(((long double)fallHeight -
                   (long double)PM_FALL_HEAVY_LANDING_HEIGHT) /
                  (long double)PM_FALL_STEP_EVENT_HEIGHT_RANGE *
                  (long double)PM_FALL_STEP_EVENT_SCALE +
                  (long double)PM_FALL_STEP_EVENT_BASE);
#endif
    }
    if (stepEvent > PM_MAX_STEP_EVENT_DELTA) {
        stepEvent = PM_MAX_STEP_EVENT_DELTA;
    }

    if (damagePct == 0) {
        if (fallHeight > PM_FALL_LIGHT_LANDING_HEIGHT) {
            if (fallHeight < PM_FALL_MEDIUM_LANDING_HEIGHT) {
                PM_AddEvent(PM_LightLandingForSurface());
            } else if (fallHeight < PM_FALL_HEAVY_LANDING_HEIGHT) {
                PM_AddEvent(PM_MediumLandingForSurface());
            } else {
                pm->ps->velocity[0] *= PM_FALL_LANDING_VELOCITY_SCALE;
                pm->ps->velocity[1] *= PM_FALL_LANDING_VELOCITY_SCALE;
                pm->ps->velocity[2] *= PM_FALL_LANDING_VELOCITY_SCALE;
                BG_AddPredictableEventToPlayerstate(PM_HardLandingForSurface(),
                                                    stepEvent, pm->ps);
            }
        }
    } else {
        /* Apply fall damage */
        if (pm->ps->legsTimer == 0) {
            BG_AnimScriptEvent(pm->ps, ANIM_EVENT_LAND,
                               qfalse, qtrue);
        }
        if (pm->debugMove != 0) {
            Com_Printf("falling damage: %i\n", damagePct);
        }
        if (damagePct < 100 &&
            (pml.groundTrace.surfaceFlags & SURFACE_SLICK) == 0) {
            int stunTime = damagePct * PM_FALL_STUN_MS_PER_DAMAGE + 500;
            float speedMult;
            if (stunTime > 2000) stunTime = 2000;
            if (stunTime < PM_FALL_STUN_FAST_THRESHOLD) {
                speedMult = 0.5f;
            } else if (stunTime < PM_FALL_STUN_SLOW_THRESHOLD) {
#if EMULATE_X87
                speedMult = x87f_store_f32(x87f_sub(
                    x87f_load_f32(0.5f),
                    x87f_mul(x87f_div(x87f_sub(x87f_load_i32(stunTime),
                                               x87f_load_f32(500.0f)),
                                      x87f_load_f32(1000.0f)),
                             x87f_load_f32(0.3f))));
#else
                speedMult = 0.5f - (((float)stunTime - 500.0f) / 1000.0f) * 0.3f;
#endif
            } else {
                speedMult = 0.2f;
            }
            if (pm->debugMove > 1) {
                Com_Printf("landing stun time: %i speed mult: %.2f\n",
                           stunTime, (double)speedMult);
            }
            pm->ps->pmTime = stunTime;
            pm->ps->playerStateFlags |= PM_STANCE_LANDING_STUN;
            pm->ps->velocity[0] *= speedMult;
            pm->ps->velocity[1] *= speedMult;
            pm->ps->velocity[2] *= speedMult;
        } else {
            pm->ps->velocity[0] *= PM_FALL_LANDING_VELOCITY_SCALE;
            pm->ps->velocity[1] *= PM_FALL_LANDING_VELOCITY_SCALE;
            pm->ps->velocity[2] *= PM_FALL_LANDING_VELOCITY_SCALE;
        }
        BG_AddPredictableEventToPlayerstate(PM_DamageLandingForSurface(),
                                            damagePct, pm->ps);
    }
}

/* ------------------------------------------------------------------ */
/*  0x26823  PM_GroundTrace                                           */
/*  Linux i386 leaf 0x26823; Mac symbols name the ground trace driver  */
/*  as PM_GroundTrace (game 0x7cc0, cgame 0x73e0).                    */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x26823, 36823_FUN_00036823.c, VERIFY-WAVE4-MOVEMENT-GROUND-WATER-2026-06-17): DATAFLOW_VERIFIED - entityStateFlags 0x106000 start/end z selection, PM_trace masks, pml trace copies, allsolid recovery call, startsolid retry, no post-retry allsolid branch, fraction/normal/upward gates, steep/land/kickoff side effects, ground entity writes, and touch add checked. */
static void PM_GroundTrace(void)
{
    vec3_t start;
    vec3_t end;
    trace_t trace;
    int entityNum;

    start[0] = pm->ps->psOrigin[0];
    start[1] = pm->ps->psOrigin[1];
    start[2] = pm->ps->psOrigin[2];
    end[0] = pm->ps->psOrigin[0];
    end[1] = pm->ps->psOrigin[1];

    if ((pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) == 0) {
        start[2] = pm->ps->psOrigin[2] + 0.25f;
        end[2] = pm->ps->psOrigin[2] - 0.25f;
    } else {
        start[2] = pm->ps->psOrigin[2];
        end[2] = pm->ps->psOrigin[2] - 1.0f;
    }

    PM_trace(&trace, start, pm->mins, pm->maxs, end,
             pm->ps->psClientNum, pm->traceMask);

    pml.groundTrace = trace;

    if (trace.allsolid == 0 || PM_CorrectAllSolid(&trace)) {
        if (trace.startsolid != 0) {
            start[2] = pm->ps->psOrigin[2] - 0.001f;
            PM_trace(&trace, start, pm->mins, pm->maxs, end,
                     pm->ps->psClientNum, pm->traceMask);
            if (trace.startsolid != 0) {
                pm->ps->groundEntityNum = ENTITYNUM_NONE;
                pml.groundPlane = 0;
                pml.waterlevel  = 0;
                pml.waterlevel2 = 0;
                return;
            }

            pml.groundTrace = trace;
        }

        entityNum = trace.entityNum;

        if (trace.fraction == 1.0f) {
            /* Didn't hit anything - not on ground */
            PM_GroundTraceMissed();
        } else if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0 ||
                   pm->ps->velocity[2] <= 0.0f ||
#if EMULATE_X87
                   x87f_le(MDOT3X(pm->ps->velocity[0], trace.normal[0],
                                     pm->ps->velocity[1], trace.normal[1],
                                     pm->ps->velocity[2], trace.normal[2]),
                           x87f_load_f32(10.0f))) {
#else
                   (pm->ps->velocity[0] * trace.normal[0] +
                    pm->ps->velocity[1] * trace.normal[1] +
                    pm->ps->velocity[2] * trace.normal[2] <= 10.0f)) {
#endif
            /* Landing or standing on ground */
            if (trace.normal[2] < 0.7f) {
                /* Steep slope */
                if (pm->debugMove != 0) {
                    Com_Printf("%i:steep\n", c_pmove);
                }
                pm->ps->groundEntityNum = ENTITYNUM_NONE;
                pml.waterlevel  = 1;
                pml.waterlevel2 = 1;
                pml.groundPlane = 0;
                pm->ps->playerStateFlags &= ~PM_STANCE_WALLJUMP;
                pm->ps->jumpOriginZ = 0;
            } else {
                /* Normal ground contact */
                pml.waterlevel  = 1;
                pml.waterlevel2 = 1;
                pml.groundPlane = 1;
                if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
                    if (pm->debugMove != 0) {
                        Com_Printf("%i:Land\n", c_pmove);
                    }
                    PM_CrashLand();
                }
                pm->ps->groundEntityNum = entityNum;
                PM_AddTouchEnt(entityNum);
            }
        } else {
            /* Moving too fast upward - kick off */
            if (pm->debugMove != 0) {
                Com_Printf("%i:kickoff\n", c_pmove);
            }
            if (PM_FORWARDMOVE(pm) < 0) {
                BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP_BACK,
                                   qfalse, qfalse);
            } else {
                BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP,
                                   qfalse, qfalse);
            }
            pml.waterlevel2 = 0;
            pm->ps->groundEntityNum = ENTITYNUM_NONE;
            pml.waterlevel  = 0;
            pml.groundPlane = 0;
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x26cf1  PM_SetWaterLevel                                         */
/*  Sample water contents at feet/mid/view height.                     */
/* ------------------------------------------------------------------ */
/* VERIFIED_MACHINE_CODE(0x26cf1): overhead level/contents clears, feet/mid/view pointContents calls with mask 0x20, viewheight-minus-mins int truncation, mid integer half-height, contents byte store, and level 1/2/3 writes checked. */
static void PM_SetWaterLevel(void)
{
    vec3_t start;
    int result;
    int heightInt;

    pm->overheadLevel = 0;
    pm->overheadContents  = 0;

    start[0] = pm->ps->psOrigin[0];
    start[1] = pm->ps->psOrigin[1];
#if EMULATE_X87
    start[2] = x87f_store_f32(x87f_add(
        x87f_add(x87f_load_f32(pm->ps->psOrigin[2]),
                 x87f_load_f32(pm->ps->playerMins[2])),
        x87f_load_f32(1.0f)));
#else
    start[2] = pm->ps->psOrigin[2] + pm->ps->playerMins[2] + 1.0f;
#endif

    result = pm->pointContents(start, pm->ps->psClientNum, CONTENTS_WATER);
    if (result != 0) {
        /* 0x26dbc: the subtraction remains in x87 width through the truncating
         * fistp; there is no intervening float store. */
        heightInt = game_compat_int32_from_long_double_trunc(
            (long double)pm->ps->viewHeightCurrent -
            (long double)pm->ps->playerMins[2]);
        pm->overheadContents = (uint8_t)result;
        pm->overheadLevel = 1;

        /* 0x26e28: machine adds origin+mins first, then the integer term. */
#if EMULATE_X87
        start[2] = x87f_store_f32(x87f_add(
            x87f_add(x87f_load_f32(pm->ps->psOrigin[2]),
                     x87f_load_f32(pm->ps->playerMins[2])),
            x87f_load_i32(heightInt / 2)));
#else
        start[2] = pm->ps->psOrigin[2] + pm->ps->playerMins[2] +
                   (float)(heightInt / 2);
#endif
        result = pm->pointContents(start, pm->ps->psClientNum, CONTENTS_WATER);
        if (result != 0) {
            pm->overheadLevel = 2;
            /* 0x26e97: machine adds origin+mins first, then the integer term. */
#if EMULATE_X87
            start[2] = x87f_store_f32(x87f_add(
                x87f_add(x87f_load_f32(pm->ps->psOrigin[2]),
                         x87f_load_f32(pm->ps->playerMins[2])),
                x87f_load_i32(heightInt)));
#else
            start[2] = pm->ps->psOrigin[2] + pm->ps->playerMins[2] +
                       (float)heightInt;
#endif
            result = pm->pointContents(start, pm->ps->psClientNum, CONTENTS_WATER);
            if (result != 0) {
                pm->overheadLevel = 3;
            }
        }
    }

}

/* ------------------------------------------------------------------ */
/*  0x2a550  PM_FoliageSounds                                    */
/*  Play foliage sounds based on movement speed.                       */
/* ------------------------------------------------------------------ */
/* VERIFIED_MACHINE_CODE(0x2a550): horizontal speed compare against cvar integer slots, reset interval clear at player-state +0x038, speed fraction clamp, truncating interval conversion, scaled mins/maxs 0.75/0.9, trace mask 2, startsolid event 139, and foliageSoundTime update checked. */
static void PM_FoliageSounds(void)
{
    float speed;
    float t;
    int interval;
    int slowInterval;
    int fastInterval;
    int speedRange;
    int intervalRange;
    vec3_t mins, maxs;
    trace_t trace;

    speed = pm->horizontalSpeed;
    slowInterval = bg_foliagesnd_slowinterval.integer;
    fastInterval = bg_foliagesnd_fastinterval.integer;
    speedRange = coduo_int32_from_bits(
        (uint32_t)bg_foliagesnd_maxspeed.integer -
        (uint32_t)bg_foliagesnd_minspeed.integer);
    intervalRange = coduo_int32_from_bits((uint32_t)fastInterval -
                                          (uint32_t)slowInterval);

    /* 0x2a573/0x2a5d4: the speed cvar integers enter the x87 chain exact
     * (fild), never rounded to float. This compare needs NO shim: speed (float)
     * and the small cvar int are both exact in double AND 80-bit, so the boolean
     * is width-independent (rule 5, docs/x87-native-identical-sites.md). The `t`
     * divide and `interval` cast below DO use the shim. */
    if (speed < (long double)bg_foliagesnd_minspeed.integer) {
        if (coduo_int32_from_bits(
                (uint32_t)pm->ps->foliageSoundTime +
                (uint32_t)bg_foliagesnd_resetinterval.integer) <
            pm->command.commandTime) {
            pm->ps->foliageSoundTime = 0;
        }
        return;
    }

    /* 0x2a5f1: the denominator is an integer subtraction fed through fild. */
#if EMULATE_X87
    t = x87f_store_f32(x87f_div(
        x87f_sub(x87f_load_f32(speed),
                 x87f_load_i32(bg_foliagesnd_minspeed.integer)),
        x87f_load_i32(speedRange)));
#else
    t = (speed - (long double)bg_foliagesnd_minspeed.integer) /
        (long double)speedRange;
#endif
    if (t > 1.0f) t = 1.0f;

#if EMULATE_X87
    interval = x87f_store_i32_trunc(x87f_add(
        x87f_mul(x87f_load_i32(intervalRange), x87f_load_f32(t)),
        x87f_load_i32(slowInterval)));
#else
    interval = game_compat_int32_from_long_double_trunc(
        (long double)intervalRange * (long double)t +
        (long double)slowInterval);
#endif

    if (coduo_int32_from_bits((uint32_t)pm->ps->foliageSoundTime +
                              (uint32_t)interval) <
        pm->command.commandTime) {
        mins[0] = pm->mins[0] * 0.75f;
        mins[1] = pm->mins[1] * 0.75f;
        mins[2] = pm->mins[2] * 0.75f;
        maxs[0] = pm->maxs[0] * 0.75f;
        maxs[1] = pm->maxs[1] * 0.75f;
        /* 0x2a705/0x2a71e: machine stores a 0.75-scaled maxs[2] first, then
         * overwrites it with the 0.9-scaled value (dead store preserved). */
        maxs[2] = pm->maxs[2] * 0.75f;
        maxs[2] = pm->maxs[2] * 0.9f;

        PM_trace(&trace, &pm->ps->psOrigin[0], mins, maxs, &pm->ps->psOrigin[0],
                 pm->ps->psClientNum, 2);

        if (trace.startsolid != 0) {
            PM_AddEvent(PM_EVENT_FOLIAGE_SOUND);
            pm->ps->foliageSoundTime = pm->command.commandTime;
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x2a7b9  PM_WaterEvents                                          */
/*  Send fatigue start/stop events.                                    */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2a7b9, 3a7b9_FUN_0003a7b9.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - previous/current overhead-level enter and exit predicates, fatigue start/stop event IDs 0x92/0x93, and no stores checked. */
static void PM_WaterEvents(void)
{
    if (pml.previousOverheadLevel == 0 && pm->overheadLevel != 0) {
        PM_AddEvent(PM_EVENT_FATIGUE_START);
    }
    if (pml.previousOverheadLevel != 0 && pm->overheadLevel == 0) {
        PM_AddEvent(PM_EVENT_FATIGUE_STOP);
    }
}

/* ------------------------------------------------------------------ */
/*  0x2c9a6  PM_CheckLadderMove                                    */
/*  Trace forward/opposite contact normal to refresh ladder contact.   */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2c9a6, 3c9a6_FUN_0003c9a6.c, VERIFY-PACKET-LADDER-2026-06-17): DATAFLOW_VERIFIED - pmTime/landing flag gate, ground-plane trace distance, ladder-without-ground reverse normal, stance flag clear, dead-state ground/water clears, prone/recent-jump gates, narrowed trace bounds, PM_trace argument order/mask, ladder surface and forward-move gates, normal stores, retry trace, and ladder-exit anim checked. */
static void PM_CheckLadderMove(void)
{
    trace_t trace;
    float checkDistance;
    vec3_t contactDir;
    vec3_t mins;
    vec3_t maxs;
    vec3_t end;
    int wasOnLadder;
    int ladderWithoutGround;
    float *contactNormal;

    if (pm->ps->pmTime != 0 &&
        (pm->ps->playerStateFlags & PM_LADDER_TIMER_BLOCK_MASK) != 0) {
        return;
    }

    checkDistance = (pml.groundPlane == 0) ? 30.0f : 8.0f;
    wasOnLadder = (pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0;
    ladderWithoutGround =
        wasOnLadder && pm->ps->groundEntityNum == ENTITYNUM_NONE;

    contactNormal = pm->ps->ladderNormal;
    if (ladderWithoutGround) {
        for (int i = 0; i < 3; i++) {
            uint32_t normalBits;
            memcpy(&normalBits, &contactNormal[i], sizeof(normalBits));
            normalBits ^= FLOAT_SIGN_BIT_MASK;
            memcpy(&contactDir[i], &normalBits, sizeof(contactDir[i]));
        }
    } else {
        contactDir[0] = pml.forward[0];
        contactDir[1] = pml.forward[1];
        contactDir[2] = 0.0f;
        VectorNormalize(contactDir);
    }

    pm->ps->playerStateFlags &= ~PM_STANCE_LADDER;

    if (pm->ps->pmType >= PM_TYPE_DEAD) {
        pm->ps->groundEntityNum = ENTITYNUM_NONE;
        pml.waterlevel = 0;
        pml.waterlevel2 = 0;
        pml.groundPlane = 0;
        return;
    }

    if (PM_GetEffectiveStance(pm->ps) == 1 ||
        coduo_int32_from_bits((uint32_t)pm->command.commandTime -
                              (uint32_t)pm->ps->lastJumpCommandTime) <
            pm_ladderJumpTime) {
        return;
    }

    mins[0] = pm->mins[0] + 6.0f;
    mins[1] = pm->mins[1] + 6.0f;
    mins[2] = 8.0f;
    maxs[0] = pm->maxs[0] - 6.0f;
    maxs[1] = pm->maxs[1] - 6.0f;
    maxs[2] = pm->maxs[2];
    if (maxs[2] < 8.0f) {
        maxs[2] = 8.0f;
    }

    /* 0x2cc3b: machine computes the scaled direction first, then adds. */
#if EMULATE_X87
    for (int i = 0; i < 3; i++) {
        end[i] = x87f_store_f32(x87f_add(
            x87f_mul(x87f_load_f32(contactDir[i]), x87f_load_f32(checkDistance)),
            x87f_load_f32(pm->ps->psOrigin[i])));
    }
#else
    end[0] = contactDir[0] * checkDistance + pm->ps->psOrigin[0];
    end[1] = contactDir[1] * checkDistance + pm->ps->psOrigin[1];
    end[2] = contactDir[2] * checkDistance + pm->ps->psOrigin[2];
#endif

    PM_trace(&trace, &pm->ps->psOrigin[0], mins, maxs, end,
             pm->ps->psClientNum, pm->traceMask);

    if (trace.fraction < 1.0f &&
        (trace.surfaceFlags & SURFACE_LADDER) != 0 &&
        (pml.groundPlane == 0 || (int8_t)PM_FORWARDMOVE(pm) > 0)) {
        contactNormal[0] = trace.normal[0];
        contactNormal[1] = trace.normal[1];
        contactNormal[2] = trace.normal[2];

        if (wasOnLadder) {
            pm->ps->playerStateFlags |= PM_STANCE_LADDER;
            return;
        }

        for (int i = 0; i < 3; i++) {
            uint32_t normalBits;
            memcpy(&normalBits, &contactNormal[i], sizeof(normalBits));
            normalBits ^= FLOAT_SIGN_BIT_MASK;
            memcpy(&contactDir[i], &normalBits, sizeof(contactDir[i]));
        }
        /* 0x2cd92: same scaled-direction-first order as above. */
#if EMULATE_X87
        for (int i = 0; i < 3; i++) {
            end[i] = x87f_store_f32(x87f_add(
                x87f_mul(x87f_load_f32(contactDir[i]),
                         x87f_load_f32(checkDistance)),
                x87f_load_f32(pm->ps->psOrigin[i])));
        }
#else
        end[0] = contactDir[0] * checkDistance + pm->ps->psOrigin[0];
        end[1] = contactDir[1] * checkDistance + pm->ps->psOrigin[1];
        end[2] = contactDir[2] * checkDistance + pm->ps->psOrigin[2];
#endif

        PM_trace(&trace, &pm->ps->psOrigin[0], mins, maxs, end,
                 pm->ps->psClientNum, pm->traceMask);
        if (trace.fraction < 1.0f &&
            (trace.surfaceFlags & SURFACE_LADDER) != 0) {
            pm->ps->playerStateFlags |= PM_STANCE_LADDER;
            return;
        }
    }

    if (ladderWithoutGround) {
        BG_AnimScriptEvent(pm->ps, ANIM_EVENT_JUMP,
                           qfalse, qtrue);
    }
}

/* ================================================================== */
/*  Target functions                                                   */
/* ================================================================== */

/* ------------------------------------------------------------------ */
/*  0x32902  BG_GetMinSpreadForWeapon                                  */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x32902, 42902_BG_GetMinSpreadForWeapon.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - BG_GetInfoForWeapon call, settled stance/ADS spread selections, lerp-time fraction clamp, prone/standing/crouch transition formulas, and return paths checked. */
float BG_GetMinSpreadForWeapon(gclient_t *client, int weapon, int time, int isADS)
{
    const weaponInfo_t *wi = (const weaponInfo_t *)BG_GetInfoForWeapon(weapon);
    float lerp;
    int elapsed;

    /* 0x32925: the lerp-start integer is compared exact (fild), not rounded
     * to float first. */
    if ((long double)client->ps.viewHeightLerpTarget == client->ps.viewHeightCurrent ||
        client->ps.viewHeightLerpTime == 0) {
        if (isADS == 0) {
            if ((client->ps.playerStateFlags & PM_STANCE_PRONE) != 0) {
                return wi->hipSpreadProne;
            }
            if ((client->ps.playerStateFlags & PM_STANCE_CROUCH) != 0) {
                return wi->hipSpreadDucked;
            }
            return wi->hipSpreadStandMin;
        }

        if ((client->ps.playerStateFlags & PM_STANCE_PRONE) != 0) {
            return wi->adsSpreadProne;
        }
        if ((client->ps.playerStateFlags & PM_STANCE_CROUCH) != 0) {
            return wi->adsSpreadDucked;
        }
        return wi->adsSpread;
    }

    /* 0x32a26: both integers enter the divide exact (fild), one rounding at
     * the lerp store. */
#if EMULATE_X87
    elapsed = coduo_int32_from_bits(
        (uint32_t)time - (uint32_t)client->ps.viewHeightLerpTime);
    lerp = x87f_store_f32(x87f_div(
        x87f_load_i32(elapsed),
        x87f_load_i32(PM_GetViewHeightLerpTime(&client->ps,
                                               client->ps.viewHeightLerpTarget,
                                               client->ps.viewHeightLerpDown))));
#else
    elapsed = coduo_int32_from_bits(
        (uint32_t)time - (uint32_t)client->ps.viewHeightLerpTime);
    lerp = (long double)elapsed /
           (long double)PM_GetViewHeightLerpTime(&client->ps, client->ps.viewHeightLerpTarget,
                                                 client->ps.viewHeightLerpDown);
#endif
    if (lerp < 0.0f) {
        lerp = 0.0f;
    } else if (lerp > 1.0f) {
        lerp = 1.0f;
    }

    if (isADS == 0) {
        if (client->ps.viewHeightLerpTarget == (int)client->ps.proneViewHeight) {
            return SPREADLERP(wi->hipSpreadProne, wi->hipSpreadDucked, lerp);
        }
        if (client->ps.viewHeightLerpTarget == (int)client->ps.standViewHeight) {
            return SPREADLERP(wi->hipSpreadStandMin, wi->hipSpreadDucked, lerp);
        }
        if (client->ps.viewHeightLerpDown == 0) {
            return SPREADLERP(wi->hipSpreadDucked, wi->hipSpreadProne, lerp);
        }
        return SPREADLERP(wi->hipSpreadDucked, wi->hipSpreadStandMin, lerp);
    }

    if (client->ps.viewHeightLerpTarget == (int)client->ps.proneViewHeight) {
        return SPREADLERP(wi->adsSpreadProne, wi->adsSpreadDucked, lerp);
    }
    if (client->ps.viewHeightLerpTarget == (int)client->ps.standViewHeight) {
        return SPREADLERP(wi->adsSpread, wi->adsSpreadDucked, lerp);
    }
    if (client->ps.viewHeightLerpDown == 0) {
        return SPREADLERP(wi->adsSpreadDucked, wi->adsSpreadProne, lerp);
    }
    return SPREADLERP(wi->adsSpreadDucked, wi->adsSpread, lerp);
}

/* ------------------------------------------------------------------ */
/*  0x2a829  PM_DropTimers                                       */
/*  Decrement movement timers by the frame delta.                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2a829, 3a829_FUN_0003a829.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - pmTime decrement/expiry flag mask 0xffffdcff, legsTimer and torsoTimer subtract-and-clamp stores, and msec source checked. */
static void PM_DropTimers(void)
{
    if (pm->ps->pmTime != 0) {
        if (pml.msec < pm->ps->pmTime) {
            pm->ps->pmTime = coduo_int32_from_bits(
                (uint32_t)pm->ps->pmTime - (uint32_t)pml.msec);
        } else {
            pm->ps->playerStateFlags &= ~PM_TIMER_EXPIRY_FLAGS;
            pm->ps->pmTime = 0;
        }
    }
    if (pm->ps->legsTimer > 0) {
        pm->ps->legsTimer = coduo_int32_from_bits(
            (uint32_t)pm->ps->legsTimer - (uint32_t)pml.msec);
        if (pm->ps->legsTimer < 0) {
            pm->ps->legsTimer = 0;
        }
    }
    if (pm->ps->torsoTimer > 0) {
        pm->ps->torsoTimer = coduo_int32_from_bits(
            (uint32_t)pm->ps->torsoTimer - (uint32_t)pml.msec);
        if (pm->ps->torsoTimer < 0) {
            pm->ps->torsoTimer = 0;
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x2a968  PM_PlayFatigueSound                                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2a968, 3a968_PM_PlayFatigueSound.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - fatigued flag gate, positive stale-time reset, 0x6a4 interval, fatigue sound event 0x8c, and sound-time store checked. */
static void PM_PlayFatigueSound(void)
{
    if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUED) == 0) {
        if (pm->ps->fatigueSoundTime > 0 &&
            coduo_int32_from_bits((uint32_t)pm->ps->fatigueSoundTime +
                                  PM_FATIGUE_SOUND_INTERVAL) <
            pm->command.commandTime) {
            pm->ps->fatigueSoundTime = 0;
        }
    } else if (coduo_int32_from_bits((uint32_t)pm->ps->fatigueSoundTime +
                                     PM_FATIGUE_SOUND_INTERVAL) <
               pm->command.commandTime) {
        PM_AddEvent(PM_EVENT_FATIGUE_SOUND);
        pm->ps->fatigueSoundTime = pm->command.commandTime;
    }
}

/* ------------------------------------------------------------------ */
/*  0x2aa22  PM_UpdateFatigue                                         */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2aa22, 3aa22_PM_UpdateFatigue.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - fatigue-drain gate, sprint-button recovery delay, recovery/drain rates 0.14285715/0.33333334, nofatigue/noclip gate, event/flag writes, and 0..1 clamps checked. */
void PM_UpdateFatigue(void)
{
    if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) == 0) {
        if ((pm->command.buttons & PMOVE_BUTTON_SPRINT) == 0) {
            /* 0x2ab7c/0x2aba8: delay and rate come from the exported
             * pm_fatigueRegenDelay / pm_fatigueRegen globals. */
            if (coduo_int32_from_bits((uint32_t)pm->ps->lastSprintTime +
                                      (uint32_t)pm_fatigueRegenDelay) <=
                pm->command.commandTime) {
#if EMULATE_X87
                pm->ps->fatigueScale = x87f_store_f32(x87f_add(
                    x87f_load_f32(pm->ps->fatigueScale),
                    x87f_mul(x87f_mul(x87f_load_i32(pml.msec),
                                      x87f_load_f32(0.001f)),
                             x87f_load_f32(pm_fatigueRegen))));
#else
                pm->ps->fatigueScale = (float)(
                    (long double)pm->ps->fatigueScale +
                    (long double)pml.msec * (long double)0.001f *
                        (long double)pm_fatigueRegen);
#endif
                if (pm->ps->fatigueScale >= 1.0f) {
                    pm->ps->fatigueScale = 1.0f;
                    if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUED) != 0) {
                        pm->ps->playerStateFlags &= ~PM_STANCE_FATIGUED;
                    }
                }
                PM_PlayFatigueSound();
            }
        } else {
            PM_PlayFatigueSound();
        }
    } else if (pm->ps->pmType != PM_TYPE_NOCLIP && bg_nofatigue.integer == 0) {
        pm->ps->lastSprintTime = pm->command.commandTime;
        /* 0x2aaa2: drain rate is the exported pm_sprintFatigue global. */
#if EMULATE_X87
        pm->ps->fatigueScale = x87f_store_f32(x87f_sub(
            x87f_load_f32(pm->ps->fatigueScale),
            x87f_mul(x87f_mul(x87f_load_i32(pml.msec), x87f_load_f32(0.001f)),
                     x87f_load_f32(pm_sprintFatigue))));
#else
        pm->ps->fatigueScale = (float)(
            (long double)pm->ps->fatigueScale -
            (long double)pml.msec * (long double)0.001f *
                (long double)pm_sprintFatigue);
#endif
        if (pm->ps->fatigueScale < 0.5f) {
            PM_AddEvent(PM_EVENT_FATIGUE_SOUND);
            pm->ps->playerStateFlags |= PM_STANCE_FATIGUED;
        }
        if (pm->ps->fatigueScale < 0.0f) {
            pm->ps->fatigueScale = 0.0f;
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x2ac45  PM_UpdateLean                                            */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2ac45, 3ac45_PM_UpdateLean.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - button/weapon/pmType/ground gates, ADS spread and entityStateFlags clears, stance max lean, 280/350 easing, lean trace start/end/mins/maxs/mask arguments, UnGetLeanFraction clamp, and sign handling checked. */
void PM_UpdateLean(playerState_t *ps, const usercmd_t *command,
                   pm_trace_fn_t traceFunc)
{
    int leanInput;
    float maxLean;
    float leanFraction;

    leanInput = 0;
    if ((command->wbuttons & (PMOVE_WBUTTON_UP |
                                   PMOVE_WBUTTON_DOWN)) != 0 &&
        (ps->playerStateFlags & PM_STANCE_KEEP_CURRENT_WEAPON) == 0 &&
        ps->pmType < PM_TYPE_ANIM_SCRIPT_LIMIT &&
        (ps->groundEntityNum != ENTITYNUM_NONE ||
         ps->pmType == PM_TYPE_LINKED)) {
        if ((command->wbuttons & PMOVE_WBUTTON_UP) != 0) {
            leanInput = -1;
        }
        if ((command->wbuttons & PMOVE_WBUTTON_DOWN) != 0) {
            leanInput += 1;
        }
    }

    if ((ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) != 0 ||
        ((ps->playerStateFlags & PM_STANCE_ADS) != 0 &&
         ((const weaponInfo_t *)BG_GetInfoForWeapon(ps->currentWeapon))->weaponClass ==
         WEAPCLASS_LMG)) {
        leanInput = 0;
    }

    maxLean = (PM_GetEffectiveStance(ps) == 1) ? 0.25f : 0.5f;
    leanFraction = ps->leanFraction;

    if (leanInput == 0) {
        if (leanFraction > 0.0f) {
#if EMULATE_X87
            leanFraction = x87f_store_f32(x87f_sub(
                x87f_load_f32(leanFraction),
                x87f_mul(x87f_div(x87f_load_i32(pml.msec), x87f_load_f32(280.0f)),
                         x87f_load_f32(maxLean))));
#else
            leanFraction -= ((float)pml.msec / 280.0f) * maxLean;
#endif
            if (leanFraction < 0.0f) {
                leanFraction = 0.0f;
            }
        } else if (leanFraction < 0.0f) {
#if EMULATE_X87
            leanFraction = x87f_store_f32(x87f_add(
                x87f_load_f32(leanFraction),
                x87f_mul(x87f_div(x87f_load_i32(pml.msec), x87f_load_f32(280.0f)),
                         x87f_load_f32(maxLean))));
#else
            leanFraction += ((float)pml.msec / 280.0f) * maxLean;
#endif
            if (leanFraction > 0.0f) {
                leanFraction = 0.0f;
            }
        }
    } else if (leanInput < 1) {
        if (leanFraction > -maxLean) {
#if EMULATE_X87
            leanFraction = x87f_store_f32(x87f_sub(
                x87f_load_f32(leanFraction),
                x87f_mul(x87f_div(x87f_load_i32(pml.msec), x87f_load_f32(350.0f)),
                         x87f_load_f32(maxLean))));
#else
            leanFraction -= ((float)pml.msec / 350.0f) * maxLean;
#endif
        }
        if (leanFraction < -maxLean) {
            leanFraction = -maxLean;
        }
    } else {
        if (leanFraction < maxLean) {
#if EMULATE_X87
            leanFraction = x87f_store_f32(x87f_add(
                x87f_load_f32(leanFraction),
                x87f_mul(x87f_div(x87f_load_i32(pml.msec), x87f_load_f32(350.0f)),
                         x87f_load_f32(maxLean))));
#else
            leanFraction += ((float)pml.msec / 350.0f) * maxLean;
#endif
        }
        if (leanFraction > maxLean) {
            leanFraction = maxLean;
        }
    }

    ps->leanFraction = leanFraction;
    if (ps->leanFraction != 0.0f || isnan(ps->leanFraction)) {
        trace_t leanTrace;
        vec3_t start;
        vec3_t end;
        vec3_t mins;
        vec3_t maxs;
        float sign;
        float blockedFraction;

        /* 0x2aeec: machine derives the sign via a PM_FloatSign call. */
        sign = (float)PM_FloatSign(ps->leanFraction);
        end[0] = ps->psOrigin[0];
        end[1] = ps->psOrigin[1];
        end[2] = ps->psOrigin[2] + ps->viewHeightCurrent;
        start[0] = end[0];
        start[1] = end[1];
        start[2] = end[2];
        AddLeanToPosition(end, ps->viewAngles[1], sign, 16.0f, 20.0f);

        mins[0] = -8.0f;
        mins[1] = -8.0f;
        mins[2] = -8.0f;
        maxs[0] = 8.0f;
        maxs[1] = 8.0f;
        maxs[2] = 8.0f;

        traceFunc(&leanTrace, start, mins, maxs, end,
                  ps->psClientNum, MASK_PLAYERSOLID);
        blockedFraction = (float)UnGetLeanFraction(leanTrace.fraction);
        if (blockedFraction < fabsf(ps->leanFraction)) {
            /* 0x2b00f: machine recomputes the sign via PM_FloatSign and
             * multiplies sign-first, the integer entering exact via fild. */
            ps->leanFraction = (float)PM_FloatSign(ps->leanFraction) *
                               blockedFraction;
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x2b031  BG_CheckProneTurned                                     */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2b031, 3b031_FUN_0003b031.c, VERIFY-PACKET-MOVEMENT-PRONE-ADJ-2026-06-17): DATAFLOW_VERIFIED - caller-used return-register wrapper, yaw fraction/check yaw, prone length interpolation, lean outputs, ground fallback flag, and BG_CheckProne argument order checked. */
int BG_CheckProneTurned(playerState_t *client, float yaw, pm_trace_fn_t traceFunc)
{
    float delta;
    float fraction;
    float checkYaw;
    float proneLength;

    delta = AngleDelta(yaw, client->viewAngles[1]);
#if EMULATE_X87
    fraction = x87f_store_f32(x87f_div(x87f_abs(x87f_load_f32(delta)),
                                       x87f_load_f32(240.0f)));
    checkYaw = AngleNormalize360Accurate(x87f_store_f32(x87f_sub(
        x87f_load_f32(yaw),
        x87f_mul(x87f_sub(x87f_load_f32(1.0f), x87f_load_f32(fraction)),
                 x87f_load_f32(delta)))));
    /* 0x2b090: machine evaluates the fraction*45 term first. */
    proneLength = x87f_store_f32(x87f_add(
        x87f_mul(x87f_load_f32(fraction), x87f_load_f32(45.0f)),
        x87f_mul(x87f_sub(x87f_load_f32(1.0f), x87f_load_f32(fraction)),
                 x87f_load_f32(60.0f))));
#else
    fraction = fabsf(delta) / 240.0f;
    checkYaw = AngleNormalize360Accurate(yaw - (1.0f - fraction) * delta);
    /* 0x2b090: machine evaluates the fraction*45 term first. */
    proneLength = fraction * 45.0f + (1.0f - fraction) * 60.0f;
#endif

    return BG_CheckProne(client->psClientNum, client->psOrigin,
                         client->playerMaxs[0], 30.0f, checkYaw,
                         &client->torsoHeight, &client->torsoPitch,
                         &client->waistPitch, 1,
                         client->groundEntityNum != ENTITYNUM_NONE,
                         NULL, traceFunc, NULL, 0, proneLength, NULL);
}

/* NOT_FROM_ORIGINAL_SOURCE: local factoring for deltaAngles short conversion. */
static void game_compat_pm_add_view_angle_delta(playerState_t *client, int axis, float delta)
{
    /* 0x2b482 and peers: the float32 operands multiply in x87 width and are
     * truncated directly by fistp; the masked low word is then added modulo
     * 2^32 to deltaAngles. */
    int32_t shortDelta = game_compat_int32_from_long_double_trunc(
        (long double)delta * (long double)PM_ANGLE_TO_SHORT);
    client->deltaAngles[axis] = coduo_int32_from_bits(
        (uint32_t)client->deltaAngles[axis] +
        ((uint32_t)shortDelta & UINT32_C(0x0000ffff)));
}

/* ------------------------------------------------------------------ */
/*  0x2b15c  PM_UpdateViewAngles                                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2b15c, 3b15c_PM_UpdateViewAngles.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - intermission/dead returns, pitch clamps, ladder/vehicle view clamps, prone yaw/pitch validation calls and delta stores, and final lean gate checked. */
void PM_UpdateViewAngles(playerState_t *client,
                         const usercmd_t *command,
                         pm_trace_fn_t traceFunc)
{
    float oldYaw;
    float commandYaw;

    if (client->pmType == PM_TYPE_INTERMISSION) {
        return;
    }

    if (client->pmType >= PM_TYPE_DEAD) {
        int16_t yawShort = (int16_t)((uint16_t)client->deltaAngles[1] +
                                     (uint16_t)command->angles[1]);
        if (client->deathYaw == 999) {
#if EMULATE_X87
            client->deathYaw = x87f_store_i32_trunc(x87f_mul(
                x87f_load_i32(yawShort),
                x87f_load_f64((double)PM_SHORT_TO_ANGLE)));
#else
            client->deathYaw =
                game_compat_int32_from_long_double_trunc(
                    (long double)yawShort *
                    (long double)PM_SHORT_TO_ANGLE);
#endif
        }
        PM_UpdateLean(client, command, traceFunc);
        return;
    }

    oldYaw = client->viewAngles[1];
    for (int axis = 0; axis < 3; axis++) {
        int16_t angleShort = (int16_t)((uint16_t)client->deltaAngles[axis] +
                                       (uint16_t)command->angles[axis]);
        if (axis == 0) {
            int pitchCap = PM_PITCH_CLAMP;
            if ((client->entityStateFlags & PS_FLAG_IN_VEHICLE) != 0) {
                pitchCap = PM_VEHICLE_PITCH_CLAMP;
            }
            if (pitchCap < angleShort) {
                client->deltaAngles[0] = coduo_int32_from_bits(
                    (uint32_t)pitchCap - (uint32_t)command->angles[0]);
                angleShort = (int16_t)pitchCap;
            } else if ((int)angleShort < -pitchCap) {
                client->deltaAngles[0] = coduo_int32_from_bits(
                    0u - (uint32_t)command->angles[0] - (uint32_t)pitchCap);
                angleShort = (int16_t)-pitchCap;
            }
        }
        client->viewAngles[axis] = (float)angleShort * PM_SHORT_TO_ANGLE;
    }
    commandYaw = client->viewAngles[1];

    if ((client->entityStateFlags & PS_FLAG_IN_VEHICLE) == 0) {
        if ((client->playerStateFlags & PM_STANCE_LADDER) != 0 &&
            client->groundEntityNum == ENTITYNUM_NONE &&
            bg_ladder_yawcap.integer != 0) {
            const float *ladderNormal = client->ladderNormal;
            float ladderYaw = vectoyaw(ladderNormal) + 180.0f;
            float delta = AngleDelta(ladderYaw, client->viewAngles[1]);

            /* 0x2b5a0-0x2b694: the yaw-cap cvar integer enters every use
             * exact (fild), never rounded to float; the negated bound is an
             * integer negation. */
            if ((long double)bg_ladder_yawcap.integer < delta ||
                delta < (long double)coduo_int32_from_bits(
                            0u - (uint32_t)bg_ladder_yawcap.integer)) {
#if EMULATE_X87
                if ((long double)bg_ladder_yawcap.integer < delta) {
                    delta = x87f_store_f32(x87f_sub(
                        x87f_load_f32(delta),
                        x87f_load_i32(bg_ladder_yawcap.integer)));
                } else {
                    delta = x87f_store_f32(x87f_add(
                        x87f_load_f32(delta),
                        x87f_load_i32(bg_ladder_yawcap.integer)));
                }
                game_compat_pm_add_view_angle_delta(client, 1, delta);
                if (delta > 0.0f) {
                    client->viewAngles[1] = AngleNormalize360Accurate(
                        x87f_store_f32(x87f_sub(
                            x87f_load_f32(ladderYaw),
                            x87f_load_i32(bg_ladder_yawcap.integer))));
                } else {
                    client->viewAngles[1] = AngleNormalize360Accurate(
                        x87f_store_f32(x87f_add(
                            x87f_load_f32(ladderYaw),
                            x87f_load_i32(bg_ladder_yawcap.integer))));
                }
#else
                if ((long double)bg_ladder_yawcap.integer < delta) {
                    delta -= (long double)bg_ladder_yawcap.integer;
                } else {
                    delta += (long double)bg_ladder_yawcap.integer;
                }
                game_compat_pm_add_view_angle_delta(client, 1, delta);
                if (delta > 0.0f) {
                    client->viewAngles[1] =
                        AngleNormalize360Accurate(
                            ladderYaw - (long double)bg_ladder_yawcap.integer);
                } else {
                    client->viewAngles[1] =
                        AngleNormalize360Accurate(
                            ladderYaw + (long double)bg_ladder_yawcap.integer);
                }
#endif
            }
        }
    } else if (pm != NULL &&
               (pm->viewClampMaxDeltas[0] != 0.0f ||
                isnan(pm->viewClampMaxDeltas[0]) ||
                pm->viewClampMaxDeltas[1] != 0.0f ||
                isnan(pm->viewClampMaxDeltas[1]) ||
                pm->viewClampMaxDeltas[2] != 0.0f ||
                isnan(pm->viewClampMaxDeltas[2]))) {
        for (int axis = 0; axis < 3; axis++) {
            float maxDelta = pm->viewClampMaxDeltas[axis];
            if (fabsf(maxDelta) >= 1.0f) {
                float delta = AngleDelta(pm->viewClampTargetAngles[axis],
                                         client->viewAngles[axis]);
                if (fabsf(maxDelta) < fabsf(delta)) {
                    if (maxDelta < delta) {
                        delta -= maxDelta;
                    } else {
                        delta += maxDelta;
                    }
                    game_compat_pm_add_view_angle_delta(client, axis, delta);
                    if (delta > 0.0f) {
                        client->viewAngles[axis] =
                            AngleNormalize360Accurate(
                                pm->viewClampTargetAngles[axis] - maxDelta);
                    } else {
                        client->viewAngles[axis] =
                            AngleNormalize360Accurate(
                                pm->viewClampTargetAngles[axis] + maxDelta);
                    }
                }
            }
        }
    }

    if ((client->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) == 0 &&
        ((client->playerStateFlags & PM_STANCE_PRONE) != 0 ||
         ((client->playerStateFlags & PM_STANCE_ADS) != 0 &&
          ((const weaponInfo_t *)BG_GetInfoForWeapon(client->currentWeapon))->weaponClass ==
          WEAPCLASS_LMG))) {
        int blocked = 0;
        float yawDelta;
        float yawCap;
        const weaponInfo_t *weaponInfo;

        if (g_debugProneCheck.integer != 0) {
            vec3_t forward;
            vec3_t start;
            vec3_t end;

            start[0] = client->psOrigin[0];
            start[1] = client->psOrigin[1];
            start[2] = client->psOrigin[2];
            /* 0x2b72b: in-place add, the viewheight integer entering exact
             * via fild. */
#if EMULATE_X87
            start[2] = x87f_store_f32(x87f_add(
                x87f_load_f32(start[2]),
                x87f_load_i32(client->proneViewHeight)));
#else
            start[2] += (long double)client->proneViewHeight;
#endif
            AngleVectors(client->viewAngles, forward, NULL, NULL);
            /* 0x2b763: machine computes the scaled forward term first. */
#if EMULATE_X87
            for (int i = 0; i < 3; i++) {
                end[i] = x87f_store_f32(x87f_add(
                    x87f_mul(x87f_load_f32(forward[i]), x87f_load_f32(18.0f)),
                    x87f_load_f32(start[i])));
            }
#else
            end[0] = forward[0] * 18.0f + start[0];
            end[1] = forward[1] * 18.0f + start[1];
            end[2] = forward[2] * 18.0f + start[2];
#endif
            G_DebugLine(start, end, colorWhite, 1, 1);
            G_DebugArc(start, 16.0f,
                       client->proneDirection - bg_prone_yawcap.value,
                       client->proneDirection + bg_prone_yawcap.value,
                       colorWhite, 1, 1);
        }

        yawDelta = AngleDelta(client->proneDirection, client->viewAngles[1]);
        yawCap = (float)bg_prone_yawcap.integer;
        weaponInfo = (const weaponInfo_t *)BG_GetInfoForWeapon(client->currentWeapon);
        if (weaponInfo->weaponClass == WEAPCLASS_LMG) {
            yawCap = (float)bg_lmg_yawcap.integer;
        }

        if ((client->playerStateFlags & PM_STANCE_PRONE) != 0 &&
            (weaponInfo->weaponClass != WEAPCLASS_LMG ||
             (client->playerStateFlags & PM_STANCE_ADS) == 0) &&
            (yawDelta > yawCap - 5.0f ||
             yawDelta < -(yawCap - 5.0f) ||
             ((command->forwardmove != 0 || command->rightmove != 0) &&
              (yawDelta != 0.0f || isnan(yawDelta))))) {
            float targetYaw;
            int keepTrying = 1;
            int proneOK;

            /* frametime * 55.0f full width (0x68018 stock: fmulp; fcomip),
             * non-power-of-two -> emulate the compare. */
#if EMULATE_X87
            if (x87f_lt(x87f_abs(x87f_load_f32(yawDelta)),
                        x87f_mul(x87f_load_f32(pml.frametime),
                                 x87f_load_f32(55.0f)))) {
#else
            if (fabsf(yawDelta) < pml.frametime * 55.0f) {
#endif
                targetYaw = client->viewAngles[1];
            } else if (yawDelta > 0.0f) {
#if EMULATE_X87
                targetYaw = x87f_store_f32(x87f_sub(
                    x87f_load_f32(client->proneDirection),
                    x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(55.0f))));
#else
                targetYaw = client->proneDirection - pml.frametime * 55.0f;
#endif
            } else {
#if EMULATE_X87
                targetYaw = x87f_store_f32(x87f_add(
                    x87f_load_f32(client->proneDirection),
                    x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(55.0f))));
#else
                targetYaw = client->proneDirection + pml.frametime * 55.0f;
#endif
            }

            while (BG_CheckProneTurned(client, targetYaw, traceFunc) == 0) {
                if (!keepTrying) {
                    goto prone_yaw_adjust_done;
                }
                yawDelta = AngleDelta(client->proneDirection, targetYaw);
                keepTrying = fabsf(yawDelta) > 1.0f;
                if (!keepTrying) {
                    blocked = 1;
                } else if (yawDelta > 0.0f) {
                    yawDelta = 1.0f;
                } else {
                    yawDelta = -1.0f;
                }
                targetYaw = AngleNormalize360Accurate(targetYaw + yawDelta);
            }

            proneOK = BG_CheckProne(client->psClientNum, client->psOrigin,
                                    client->playerMaxs[0], 30.0f,
                                    client->viewAngles[1], NULL, NULL, NULL, 1,
                                    client->groundEntityNum != ENTITYNUM_NONE,
                                    NULL, traceFunc, NULL, 0, 45.0f, NULL);
            if (proneOK != 0) {
                proneOK = BG_CheckProne(client->psClientNum, client->psOrigin,
                                        client->playerMaxs[0], 30.0f,
                                        targetYaw, NULL, NULL, NULL, 1,
                                        client->groundEntityNum !=
                                        ENTITYNUM_NONE, NULL, traceFunc,
                                        NULL, 0, 45.0f, NULL);
                if (proneOK != 0) {
                    client->proneDirection = targetYaw;
                }
            }
            if (proneOK == 0) {
                blocked = 1;
            }
        }

prone_yaw_adjust_done:
        yawDelta = AngleDelta(client->proneDirection, client->viewAngles[1]);
        if ((yawDelta != 0.0f || isnan(yawDelta)) &&
            (client->playerStateFlags & PM_STANCE_PRONE) != 0) {
            weaponInfo = (const weaponInfo_t *)BG_GetInfoForWeapon(client->currentWeapon);
            if (weaponInfo->weaponClass != WEAPCLASS_LMG) {
                float targetYaw = client->proneDirection;
                int keepTrying = 1;
                while (1) {
                    int proneOK = BG_CheckProne(
                        client->psClientNum, client->psOrigin,
                        client->playerMaxs[0], 30.0f, targetYaw,
                        NULL, NULL, NULL, 1,
                        client->groundEntityNum != ENTITYNUM_NONE,
                        NULL, traceFunc, NULL, 0, 45.0f, NULL);
                    int yawOK = 1;

                    if (proneOK != 0) {
                        yawOK = BG_CheckProneTurned(client, targetYaw,
                                                     traceFunc);
                    }
                    if (proneOK != 0 && yawOK != 0) {
                        break;
                    }
                    if (!keepTrying) {
                        goto prone_view_clamp_done;
                    }
                    keepTrying = fabsf(yawDelta) > 1.0f;
                    if (keepTrying) {
                        if (yawDelta > 0.0f) {
                            yawDelta = 1.0f;
                        } else {
                            yawDelta = -1.0f;
                        }
                    }
                    blocked = 1;
                    game_compat_pm_add_view_angle_delta(client, 1, yawDelta);
                    client->viewAngles[1] =
                        AngleNormalize360Accurate(client->viewAngles[1] +
                                                  yawDelta);
                    yawDelta = AngleDelta(client->proneDirection,
                                          client->viewAngles[1]);
                    if (proneOK == 0) {
                        targetYaw =
                            AngleNormalize360Accurate(targetYaw + yawDelta);
                    }
                }
                client->proneDirection = targetYaw;
            }
        }

prone_view_clamp_done:
        if (yawCap < yawDelta || yawDelta < -yawCap) {
            if (yawCap < yawDelta) {
                yawDelta -= yawCap;
            } else {
                yawDelta += yawCap;
            }
            game_compat_pm_add_view_angle_delta(client, 1, yawDelta);
            if (yawDelta > 0.0f) {
                client->viewAngles[1] =
                    AngleNormalize360Accurate(client->proneDirection - yawCap);
            } else {
                client->viewAngles[1] =
                    AngleNormalize360Accurate(client->proneDirection + yawCap);
            }
        }

        if (blocked != 0) {
            float oldYawDelta;

            client->playerStateFlags |= PM_STANCE_PRONE_BLOCKED;
            oldYawDelta = AngleDelta(oldYaw, client->viewAngles[1]);
            if (fabsf(oldYawDelta) <= 1.0f) {
                float commandYawDelta = AngleDelta(commandYaw,
                                                   client->viewAngles[1]);
                /* NO shim: sign test — rounding never flips the sign of the
                 * product, so `> 0.0f` is width-independent (rule 7). */
                if (oldYawDelta * commandYawDelta > 0.0f) {
                    oldYawDelta *= 0.98f;
                    client->viewAngles[1] =
                        AngleNormalize360Accurate(client->viewAngles[1] +
                                                  oldYawDelta);
                    game_compat_pm_add_view_angle_delta(client, 1, oldYawDelta);
                }
            }
        }

        yawDelta = AngleDelta(client->proneTorsoPitch, client->viewAngles[0]);
        if (yawDelta > 45.0f || yawDelta < -45.0f) {
            if (yawDelta > 45.0f) {
                yawDelta -= 45.0f;
            } else {
                yawDelta += 45.0f;
            }
            game_compat_pm_add_view_angle_delta(client, 0, yawDelta);
            if (yawDelta > 0.0f) {
                client->viewAngles[0] =
                    AngleNormalize180Accurate(client->proneTorsoPitch - 45.0f);
            } else {
                client->viewAngles[0] =
                    AngleNormalize180Accurate(client->proneTorsoPitch + 45.0f);
            }
        }
    }

    if (client->pmType != PM_TYPE_UFO &&
        client->pmType != PM_TYPE_NOCLIP &&
        client->pmType != PM_TYPE_SPECTATOR) {
        PM_UpdateLean(client, command, traceFunc);
    }
}

/* ------------------------------------------------------------------ */
/*  0x2c158  PM_UpdatePronePitch                                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2c158, 3c158_PM_UpdatePronePitch.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - prone-only gate, air/water BG_CheckProne arguments, blocked event/flag stores, ground-normal-z steep slope test at pml +0x50, and body/view pitch easing checked. */
void PM_UpdatePronePitch(void)
{
    const float *groundNormal;
    float targetPitch;
    float delta;

    if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0) {
        return;
    }

    if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
        groundNormal = (pml.waterlevel == 0) ? NULL : pml.groundTrace.normal;
        if (BG_CheckProne(pm->ps->psClientNum, pm->ps->psOrigin, pm->ps->playerMaxs[0],
                          30.0f, pm->ps->proneDirection, &pm->ps->torsoHeight,
                          &pm->ps->torsoPitch, &pm->ps->waistPitch, 1,
                          pm->ps->groundEntityNum != ENTITYNUM_NONE,
                          groundNormal, pm->trace3, pm->trace2, 0, 60.0f,
                          pm->entityType) == 0 ||
            pm->overheadLevel != 0) {
            BG_AddPredictableEventToPlayerstate(PM_EVENT_PRONE_BLOCKED, 0,
                                                pm->ps);
            pm->ps->playerStateFlags |= PM_STANCE_PRONE_BLOCKED;
        }
    } else if (pml.waterlevel != 0 && pml.groundTrace.normal[2] < 0.7f) {
        BG_AddPredictableEventToPlayerstate(PM_EVENT_PRONE_BLOCKED, 0, pm->ps);
    }

    if (pml.waterlevel == 0) {
        targetPitch = 0.0f;
    } else {
        targetPitch = PitchForYawOnNormal(pm->ps->proneDirection,
                                          pml.groundTrace.normal);
    }

    delta = AngleDelta(targetPitch, pm->ps->proneDirectionPitch);
    if (delta != 0.0f || isnan(delta)) {
        /* 0x2c3eb: machine calls PM_FloatAbs here, not inline fabs. The
         * frametime * 70.0f is compared at full x87 width (0x689df stock:
         * fmulp; fcomip); non-power-of-two -> emulate the compare too. */
#if EMULATE_X87
        if (x87f_lt(x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(70.0f)),
                    x87f_abs(x87f_load_f32(delta)))) {
#else
        if (PM_FloatAbs(delta) > pml.frametime * 70.0f) {
#endif
#if EMULATE_X87
            pm->ps->proneDirectionPitch = x87f_store_f32(x87f_add(
                x87f_load_f32(pm->ps->proneDirectionPitch),
                x87f_mul(x87f_mul(x87f_load_f32(pml.frametime),
                                  x87f_load_f32(70.0f)),
                         x87f_load_i32(PM_FloatSign(delta)))));
#else
            pm->ps->proneDirectionPitch +=
                pml.frametime * 70.0f * (float)PM_FloatSign(delta);
#endif
        } else {
            pm->ps->proneDirectionPitch += delta;
        }
        pm->ps->proneDirectionPitch =
            AngleNormalize180Accurate(pm->ps->proneDirectionPitch);
    }

    if (pml.waterlevel == 0) {
        targetPitch = 0.0f;
    } else {
        targetPitch = PitchForYawOnNormal(pm->ps->viewAngles[1],
                                          pml.groundTrace.normal);
    }

    delta = AngleDelta(targetPitch, pm->ps->proneTorsoPitch);
    if (delta != 0.0f || isnan(delta)) {
        /* 0x2c51f: machine calls PM_FloatAbs here, not inline fabs; the
         * frametime * 70.0f is compared at full x87 width (0x68b3c stock:
         * fmulp; fcomip), non-power-of-two -> emulate the compare too. */
#if EMULATE_X87
        if (x87f_lt(x87f_mul(x87f_load_f32(pml.frametime), x87f_load_f32(70.0f)),
                    x87f_abs(x87f_load_f32(delta)))) {
#else
        if (PM_FloatAbs(delta) > pml.frametime * 70.0f) {
#endif
#if EMULATE_X87
            pm->ps->proneTorsoPitch = x87f_store_f32(x87f_add(
                x87f_load_f32(pm->ps->proneTorsoPitch),
                x87f_mul(x87f_mul(x87f_load_f32(pml.frametime),
                                  x87f_load_f32(70.0f)),
                         x87f_load_i32(PM_FloatSign(delta)))));
#else
            pm->ps->proneTorsoPitch +=
                pml.frametime * 70.0f * (float)PM_FloatSign(delta);
#endif
        } else {
            pm->ps->proneTorsoPitch += delta;
        }
        pm->ps->proneTorsoPitch =
            AngleNormalize180Accurate(pm->ps->proneTorsoPitch);
    }
}

/* ------------------------------------------------------------------ */
/*  0x2c5dd  PM_SetProneMovementOverride                              */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2c5dd, 3c5dd_PM_SetProneMovementOverride.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - prone flag gate writes only the prone movement override bit. */
void PM_SetProneMovementOverride(void)
{
    if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) != 0) {
        pm->ps->playerStateFlags |= PM_STANCE_PRONE_MOVEMENT_OVERRIDE;
    }
}

/* ------------------------------------------------------------------ */
/*  0x2c622  PM_UpdatePlayerWalkingFlag                               */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2c622, 3c622_PM_UpdatePlayerWalkingFlag.c, VERIFY-WAVE4-MOVEMENT-ADS-PRONE-2026-06-17): DATAFLOW_VERIFIED - clears walking flag, then pmType/button/ADS/prone/vehicle/reload-state gates and walking flag set checked. */
void PM_UpdatePlayerWalkingFlag(void)
{
    pm->ps->playerStateFlags &= ~PM_STANCE_WALKING;

    if (pm->ps->pmType < PM_TYPE_ANIM_SCRIPT_LIMIT &&
        (PM_BUTTON_BYTE0(pm) & PMOVE_BUTTON_WALK) != 0 &&
        (pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0 &&
        (pm->ps->playerStateFlags & PM_STANCE_ADS) != 0 &&
        (pm->ps->entityStateFlags & PS_FLAG_IN_VEHICLE) == 0 &&
        pm->ps->weaponState != WEAPON_STATE_RELOADING &&
        pm->ps->weaponState != WEAPON_STATE_RELOAD_START &&
        pm->ps->weaponState != WEAPON_STATE_RELOAD_END &&
        pm->ps->weaponState != WEAPON_STATE_RELOAD_START_INTERRUPT &&
        pm->ps->weaponState != WEAPON_STATE_RELOADING_INTERRUPT) {
        pm->ps->playerStateFlags |= PM_STANCE_WALKING;
    }
}

/* ------------------------------------------------------------------ */
/*  0x2c74a  PM_UpdatePlayerSprintingFlag                             */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2c74a, 3c74a_PM_UpdatePlayerSprintingFlag.c, VERIFY-WAVE4-MOVEMENT-ADS-PRONE-2026-06-17): DATAFLOW_VERIFIED - prior sprint bit save, fatigue clear, sprint/fatigue/movement/weapon/fire/ladder gates, Com_BitCheck arguments, and flag write checked. */
void PM_UpdatePlayerSprintingFlag(void)
{
    uint32_t wasSprinting;

    wasSprinting = pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN;
    pm->ps->playerStateFlags &= ~PM_STANCE_FATIGUE_DRAIN;

    if (pm->ps->pmType < PM_TYPE_SPECTATOR &&
        (PM_BUTTON_BYTE0(pm) & PMOVE_BUTTON_SPRINT) != 0 &&
        pm->ps->fatigueScale > 0.0f &&
        (wasSprinting != 0 || pm->ps->fatigueScale > 0.25f) &&
        (pm->ps->playerStateFlags & (PM_STANCE_PRONE | PM_STANCE_CROUCH)) == 0 &&
        (pm->ps->playerStateFlags & PM_STANCE_ADS) == 0 &&
        (wasSprinting != 0 || pm->ps->groundEntityNum != ENTITYNUM_NONE) &&
        (PM_FORWARDMOVE(pm) != 0 || PM_RIGHTMOVE(pm) != 0) &&
        (pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) == 0 &&
        pm->ps->weaponState != WEAPON_STATE_BREAKING_DOWN &&
        (pml.weaponInfo->weaponType != WEAPTYPE_GRENADE ||
         pml.weaponInfo->specialTimeEnabled == 0 ||
         pml.weaponInfo->specialTimeThreshold <= pm->ps->grenadeTimeLeft ||
         pm->ps->grenadeTimeLeft == 0 ||
         Com_BitCheck(pm->ps->weaponBits, pm->ps->currentWeapon) == 0) &&
        (pml.weaponInfo->weaponType != WEAPTYPE_GRENADE ||
         ((PM_BUTTON_BYTE0(pm) & PMOVE_BUTTON_FIRE) == 0 &&
          pm->ps->weaponState != WEAPON_STATE_FIRING)) &&
        (pm->ps->playerStateFlags & PM_STANCE_LADDER) == 0) {
        pm->ps->playerStateFlags |= PM_STANCE_FATIGUE_DRAIN;
    }
}

/* ------------------------------------------------------------------ */
/*  0x32c0b  PM_UpdateAimDownSightFlag                                */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x32c0b, 42c0b_PM_UpdateAimDownSightFlag.c, VERIFY-WAVE4-MOVEMENT-ADS-PRONE-2026-06-17): DATAFLOW_VERIFIED - keep-current early return, vehicle ADS path, ADS clear gates, spread probe 15.0/1.0 offsets and 0x404000 mask, BG_CheckProneValid 30.0/60.0 arguments, flag stores, events, and condition update checked. */
void PM_UpdateAimDownSightFlag(void)
{
    const weaponInfo_t *wi;
    vec3_t angles;
    vec3_t forward;
    vec3_t probe;
    int contents;

    if ((pm->ps->playerStateFlags & PM_STANCE_KEEP_CURRENT_WEAPON) != 0) {
        return;
    }

    if (pm->ps->pmType < PM_TYPE_ANIM_SCRIPT_LIMIT &&
        (PM_BUTTON_BYTE0(pm) & PMOVE_WBUTTON_UP) != 0 &&
        (pm->ps->entityStateFlags & PS_FLAG_IN_VEHICLE) != 0) {
        pm->ps->playerStateFlags |= PM_STANCE_ADS;
        BG_UpdateConditionValue(pm->ps->psClientNum, 9, 1, 1);
        return;
    }

    if (pm->ps->pmType >= PM_TYPE_ANIM_SCRIPT_LIMIT ||
        (PM_BUTTON_BYTE0(pm) & PMOVE_WBUTTON_UP) == 0 ||
        pml.weaponInfo->adsEnabled == 0 ||
        pm->ps->weaponState == WEAPON_STATE_DROPPING ||
        pm->ps->weaponState == WEAPON_STATE_RAISING ||
        pm->ps->weaponState == WEAPON_STATE_MELEE_WINDUP ||
        pm->ps->weaponState == WEAPON_STATE_MELEE_RELAX ||
        (pm->ps->weaponState == WEAPON_STATE_BREAKING_DOWN &&
         pm->ps->currentWeapon != (int)pm->command.weapon) ||
        (pml.waterlevel2 == 0 && pm->ps->pmType != PM_TYPE_LINKED)) {
        pm->ps->playerStateFlags &= ~PM_STANCE_ADS;
        BG_UpdateConditionValue(pm->ps->psClientNum, 9, 0, 1);
        return;
    }

    wi = (const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon);
    if (wi->weaponClass == WEAPCLASS_LMG) {
        if ((pm->ps->playerStateFlags & PM_STANCE_ADS) == 0) {
            angles[0] = 0.0f;
            angles[1] = pm->ps->viewAngles[1];
            angles[2] = 0.0f;
            AngleVectors(angles, forward, NULL, NULL);

            /* 0x32e4b: machine computes the scaled forward term first, and
             * 0x32e98 rounds probe[2] to float BEFORE the +1 (two stores). */
#if EMULATE_X87
            for (int i = 0; i < 3; i++) {
                probe[i] = x87f_store_f32(x87f_add(
                    x87f_mul(x87f_load_f32(forward[i]), x87f_load_f32(15.0f)),
                    x87f_load_f32(pm->ps->psOrigin[i])));
            }
#else
            probe[0] = forward[0] * 15.0f + pm->ps->psOrigin[0];
            probe[1] = forward[1] * 15.0f + pm->ps->psOrigin[1];
            probe[2] = forward[2] * 15.0f + pm->ps->psOrigin[2];
#endif
            probe[2] += 1.0f;

            contents = pm->pointContents(probe, pm->ps->psClientNum,
                                         ADS_POINT_CONTENTS_MASK);
            if (contents != 0) {
                if ((pm->ps->playerStateFlags & PM_STANCE_ADS) == 0) {
                    pm->ps->proneDirection = pm->ps->viewAngles[1];
                }
                pm->ps->playerStateFlags |= PM_STANCE_ADS;
                if ((contents & ADS_POINT_CONTENTS_CROUCH) != 0) {
                    pm->ps->playerStateFlags |= PM_STANCE_CROUCH;
                    pm->ps->playerStateFlags &= ~PM_STANCE_PRONE;
                } else {
                    pm->ps->playerStateFlags &= ~PM_STANCE_CROUCH;
                    pm->ps->playerStateFlags &= ~PM_STANCE_PRONE;
                }
            } else if (pm->ps->serverCursorHint == CURSOR_HINT_LMG) {
                if ((pm->ps->playerStateFlags & PM_STANCE_ADS) == 0) {
                    pm->ps->proneDirection = pm->ps->viewAngles[1];
                }
                pm->ps->playerStateFlags |= PM_STANCE_ADS;
                if (pm->ps->serverCursorHintVal != 0) {
                    pm->ps->playerStateFlags |= PM_STANCE_CROUCH;
                    pm->ps->playerStateFlags &= ~PM_STANCE_PRONE;
                } else {
                    pm->ps->playerStateFlags &= ~PM_STANCE_CROUCH;
                    pm->ps->playerStateFlags &= ~PM_STANCE_PRONE;
                }
            } else if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0 &&
                       (pm->ps->groundEntityNum == ENTITYNUM_NONE ||
                        BG_CheckProneValid(
                                      pm->ps->psClientNum, &pm->ps->psOrigin[0], pm->maxs[0],
                                      30.0f, pm->ps->viewAngles[1],
                                      &pm->ps->torsoHeight, &pm->ps->torsoPitch,
                                      &pm->ps->waistPitch, 0,
                                      pm->ps->groundEntityNum != ENTITYNUM_NONE, NULL,
                                      pm->trace3, pm->trace2,
                                      0, 60.0f, 1,
                                      pm->entityType) == 0)) {
                pm->ps->playerStateFlags |= PM_STANCE_PRONE_BLOCKED;
                if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_STANCE_LATCH) == 0) {
                    if ((pm->ps->playerStateFlags & PM_STANCE_CROUCH) == 0) {
                        BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_STAND, 0, pm->ps);
                    } else {
                        BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_CROUCH, 0, pm->ps);
                    }
                }
            } else {
                if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0) {
                    pm->ps->proneDirection = pm->ps->viewAngles[1];
                }
                pm->ps->playerStateFlags |= PM_STANCE_PRONE | PM_STANCE_ADS;
            }
        }
    } else if ((pm->ps->playerStateFlags & PM_STANCE_PRONE) == 0) {
        pm->ps->playerStateFlags |= PM_STANCE_ADS;
    } else if ((pm->oldCommand.buttons & PMOVE_WBUTTON_UP) == 0 ||
               (PM_OLD_FORWARDMOVE(pm) == 0 && PM_OLD_RIGHTMOVE(pm) == 0)) {
        pm->ps->playerStateFlags |= PM_STANCE_ADS | PM_STANCE_PRONE_MOVEMENT_OVERRIDE;
    }

    BG_UpdateConditionValue(pm->ps->psClientNum, 9,
                            (pm->ps->playerStateFlags & PM_STANCE_ADS) != 0, 1);
}

/* ------------------------------------------------------------------ */
/*  0x3346f  PM_ClearAimDownSightFlag                                 */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x3346f, 4346f_PM_ClearAimDownSightFlag.c, VERIFY-WAVE4-MOVEMENT-ADS-PRONE-2026-06-17): DATAFLOW_VERIFIED - clears only ADS flag bit 0x20. */
void PM_ClearAimDownSightFlag(void)
{
    pm->ps->playerStateFlags &= ~PM_STANCE_ADS;
}

/* ------------------------------------------------------------------ */
/*  0x3349e  PM_UpdateAimDownSightLerp                                */
/*  Lerp the ADS (aim down sight) float toward 0 or 1.                */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x3349e, 4349e_PM_UpdateAimDownSightLerp.c, VERIFY-WAVE4-MOVEMENT-ADS-PRONE-2026-06-17): DATAFLOW_VERIFIED - keep-current early return, ADS-enabled/vehicle gates, reload/raise/fire-delay conditions, NAN-aware target test, vehicle-position snap, msec-scaled rates, and 0.0/1.0 clamps checked. */
void PM_UpdateAimDownSightLerp(void)
{
    int shouldADS;
    const weaponInfo_t *wi;

    if ((pm->ps->playerStateFlags & PM_STANCE_KEEP_CURRENT_WEAPON) != 0) {
        return;
    }

    wi = pml.weaponInfo;
    shouldADS = 0;
    if ((pm->ps->entityStateFlags & PS_FLAG_IN_VEHICLE) == 0) {
        if (wi->adsEnabled == 0) {
            pm->ps->adsFraction = 0.0f;
            return;
        }
    }

    if ((pm->ps->entityStateFlags & PS_FLAG_IN_VEHICLE) != 0 &&
        (pm->ps->playerStateFlags & PM_STANCE_ADS) != 0) {
        shouldADS = 1;
    } else {
        int reloadElapsed = coduo_int32_from_bits(
            (uint32_t)pm->ps->weaponTime - (uint32_t)wi->reloadLoopTime);

        if ((wi->segmentedReload == 0 &&
             pm->ps->weaponState == WEAPON_STATE_RELOADING &&
             pm->ps->weaponTime != wi->reloadLoopTime &&
             reloadElapsed > -1 &&
             wi->weaponClass != WEAPCLASS_LMG) ||
            (wi->segmentedReload != 0 &&
             wi->weaponClass != WEAPCLASS_LMG &&
             (pm->ps->weaponState == WEAPON_STATE_RELOADING ||
              pm->ps->weaponState == WEAPON_STATE_RELOADING_INTERRUPT ||
              pm->ps->weaponState == WEAPON_STATE_RELOAD_START ||
              pm->ps->weaponState == WEAPON_STATE_RELOAD_START_INTERRUPT ||
              (pm->ps->weaponState == WEAPON_STATE_RELOAD_END &&
               pm->ps->weaponTime != wi->reloadLoopTime &&
               reloadElapsed > -1))) ||
            (wi->adsRaiseEnabled == 0 &&
             pm->ps->weaponState == WEAPON_STATE_RECHAMBERING)) {
            shouldADS = 0;
        } else if ((pm->ps->playerStateFlags & PM_STANCE_ADS) != 0) {
            shouldADS = 1;
        }
    }

    if (wi->adsFireDelayEnabled != 0 &&
        pm->ps->weaponDelay != 0 &&
        pm->ps->weaponState == WEAPON_STATE_FIRING) {
        shouldADS = 1;
    }

    /* Lerp the ADS float */
    if ((shouldADS && (pm->ps->adsFraction != 1.0f || isnan(pm->ps->adsFraction))) ||
        (!shouldADS && (pm->ps->adsFraction != 0.0f || isnan(pm->ps->adsFraction)))) {

        if ((pm->ps->entityStateFlags & PS_FLAG_IN_VEHICLE) == 0 ||
            pm->ps->vehiclePosition != 1) {
            if (shouldADS) {
#if EMULATE_X87
                pm->ps->adsFraction = x87f_store_f32(x87f_add(
                    x87f_load_f32(pm->ps->adsFraction),
                    x87f_mul(x87f_load_i32(pml.msec),
                             x87f_load_f32(wi->adsFireDelayRate))));
#else
                pm->ps->adsFraction = (float)(
                    (long double)pm->ps->adsFraction +
                    (long double)pml.msec *
                        (long double)wi->adsFireDelayRate);
#endif
            } else {
#if EMULATE_X87
                pm->ps->adsFraction = x87f_store_f32(x87f_sub(
                    x87f_load_f32(pm->ps->adsFraction),
                    x87f_mul(x87f_load_i32(pml.msec),
                             x87f_load_f32(wi->adsFireDelayOutRate))));
#else
                pm->ps->adsFraction = (float)(
                    (long double)pm->ps->adsFraction -
                    (long double)pml.msec *
                        (long double)wi->adsFireDelayOutRate);
#endif
            }
        } else {
            if (shouldADS) {
                pm->ps->adsFraction = 1.0f;
            } else {
                pm->ps->adsFraction = 0.0f;
            }
        }

        if (pm->ps->adsFraction >= 1.0f) pm->ps->adsFraction = 1.0f;
        else if (pm->ps->adsFraction <= 0.0f) pm->ps->adsFraction = 0.0f;
    }
}

/* ------------------------------------------------------------------ */
/*  0x338b0  PM_InteruptWeaponWithProneMove                           */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x338b0, 438b0_PM_InteruptWeaponWithProneMove.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - ADS spread early return, weapon-state allow/reject matrix, timer/state reset, and idle animation call checked. */
int PM_InteruptWeaponWithProneMove(void)
{
    const weaponInfo_t *wi;

    if ((pm->ps->playerStateFlags & PM_STANCE_ADS) != 0) {
        wi = (const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon);
        if (wi->weaponClass == WEAPCLASS_LMG) {
            return 0;
        }
    }

    switch (pm->ps->weaponState) {
    case WEAPON_STATE_IDLE:
    case WEAPON_STATE_RAISING:
    case WEAPON_STATE_DROPPING:
    case WEAPON_STATE_RECHAMBERING:
    case WEAPON_STATE_RELOADING:
    case WEAPON_STATE_RELOADING_INTERRUPT:
    case WEAPON_STATE_RELOAD_START:
    case WEAPON_STATE_RELOAD_START_INTERRUPT:
    case WEAPON_STATE_RELOAD_END:
        return 1;

    case WEAPON_STATE_FIRING:
    case WEAPON_STATE_MELEE_RELAX:
        return 0;

    default:
        pm->ps->weaponTime = 0;
        pm->ps->weaponDelay = 0;
        pm->ps->weaponState = WEAPON_STATE_IDLE;
        PM_ContinueWeaponAnim(PM_WEAPON_ANIM_IDLE);
        return 1;
    }
}

/* ------------------------------------------------------------------ */
/*  0x33a44  PM_InteruptWeaponWithSprintMove                          */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x33a44, 43a44_PM_InteruptWeaponWithSprintMove.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - weapon-state allow/reject matrix, timer/delay/state reset stores, PM_ContinueWeaponAnim(10), and 0/1 returns checked. */
int PM_InteruptWeaponWithSprintMove(void)
{
    switch (pm->ps->weaponState) {
    case WEAPON_STATE_IDLE:
    case WEAPON_STATE_RAISING:
    case WEAPON_STATE_DROPPING:
    case WEAPON_STATE_RECHAMBERING:
    case WEAPON_STATE_RELOADING:
    case WEAPON_STATE_RELOADING_INTERRUPT:
    case WEAPON_STATE_RELOAD_START:
    case WEAPON_STATE_RELOAD_START_INTERRUPT:
    case WEAPON_STATE_RELOAD_END:
        return 1;

    case WEAPON_STATE_FIRING:
    case WEAPON_STATE_MELEE_WINDUP:
    case WEAPON_STATE_MELEE_RELAX:
        return 0;

    default:
        pm->ps->weaponTime = 0;
        pm->ps->weaponDelay = 0;
        pm->ps->weaponState = WEAPON_STATE_IDLE;
        PM_ContinueWeaponAnim(PM_WEAPON_ANIM_SWITCH_RAISE);
        return 1;
    }
}

/* ------------------------------------------------------------------ */
/*  0x25246  PM_DeadMove                                  */
/*  Clamp velocity when on ground (vehicle-related).                   */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x25246, 35246_FUN_00035246.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - ground-plane gate, three-axis speed sqrt, 20 unit bleed, zero-velocity path, VectorNormalize path, and scaled velocity stores checked. */
static void PM_DeadMove(void)
{
    float speed;

    if (pml.groundPlane != 0) {
#if EMULATE_X87
        speed = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
            x87f_add(x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                              x87f_load_f32(pm->ps->velocity[0])),
                     x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                              x87f_load_f32(pm->ps->velocity[1]))),
            x87f_mul(x87f_load_f32(pm->ps->velocity[2]),
                     x87f_load_f32(pm->ps->velocity[2])))));
#else
        speed = (float)CoduoLibm_Sqrt((double)(pm->ps->velocity[0] *
                                     pm->ps->velocity[0] +
                                     pm->ps->velocity[1] *
                                     pm->ps->velocity[1] +
                                     pm->ps->velocity[2] *
                                     pm->ps->velocity[2]));
#endif
        speed -= 20.0f;
        if (speed <= 0.0f) {
            pm->ps->velocity[2] = 0.0f;
            pm->ps->velocity[1] = 0.0f;
            pm->ps->velocity[0] = 0.0f;
        } else {
            VectorNormalize((float *)&pm->ps->velocity[0]);
            pm->ps->velocity[0] *= speed;
            pm->ps->velocity[1] *= speed;
            pm->ps->velocity[2] *= speed;
        }
    }
}

/* ------------------------------------------------------------------ */
/*  0x35dcb  PM_AdjustAimSpreadScale                                  */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x35dcb, 45dcb_PM_AdjustAimSpreadScale.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - decay-rate NaN/nonzero gate, air/prone/crouch scaling, ADS zero-growth path, two-axis turn growth, movement and air growth additions, frametime scaling, 255 update, and clamps checked. */
void PM_AdjustAimSpreadScale(void)
{
    float decayRate;
    float decay;
    float growthRate;
    float growth;
    int i;
    /* 0x35ddd/0x35de4: two 0.01 scale locals initialized up front; the
     * air-growth loop multiplies airScale by 128.0 at runtime. */
    float airScale = 0.01f;
    float turnScale = 0.01f;

    decayRate = pml.weaponInfo->aimSpreadDecayRate;
    if (decayRate != 0.0f || isnan(decayRate)) {
        if (pm->ps->groundEntityNum == ENTITYNUM_NONE &&
            pm->ps->pmType != PM_TYPE_LINKED) {
            decayRate *= 0.5f;
        } else if ((pm->ps->entityStateFlags & PS_FLAG_PRONE) != 0) {
            decayRate *= pml.weaponInfo->aimSpreadProneScale;
        } else if ((pm->ps->entityStateFlags & PS_FLAG_CROUCH) != 0) {
            decayRate *= pml.weaponInfo->aimSpreadCrouchScale;
        }

        decay = decayRate * pml.frametime;

        if (pm->ps->adsFraction == 1.0f) {
            growth = 0.0f;
        } else {
            growthRate = 0.0f;

            if (pml.weaponInfo->aimSpreadTurnRate != 0.0f ||
                isnan(pml.weaponInfo->aimSpreadTurnRate)) {
                for (i = 0; i < 2; i++) {
                    float delta;

                    /* 0x35f30: the command angle integers enter the argument
                     * chains exact (fild); 0x35f5f stores the absolute value
                     * of the AngleSubtract return. */
#if EMULATE_X87
                    delta = fabsf(AngleSubtract(
                        x87f_store_f32(x87f_mul(
                            x87f_load_i32(pm->command.angles[i]),
                            x87f_load_f32(PM_SHORT_TO_ANGLE))),
                        x87f_store_f32(x87f_mul(
                            x87f_load_i32(pm->oldCommand.angles[i]),
                            x87f_load_f32(PM_SHORT_TO_ANGLE)))));
                    growthRate = x87f_store_f32(x87f_add(
                        x87f_load_f32(growthRate),
                        x87f_div(x87f_mul(x87f_mul(x87f_load_f32(delta),
                                                   x87f_load_f32(turnScale)),
                                          x87f_load_f32(pml.weaponInfo
                                                            ->aimSpreadTurnRate)),
                                 x87f_load_f32(pml.frametime))));
#else
                    delta = fabsf(AngleSubtract(
                        (long double)pm->command.angles[i] *
                        PM_SHORT_TO_ANGLE,
                        (long double)pm->oldCommand.angles[i] *
                        PM_SHORT_TO_ANGLE));
                    growthRate += delta * turnScale *
                                  pml.weaponInfo->aimSpreadTurnRate /
                                  pml.frametime;
#endif
                }
            }

            if ((pml.weaponInfo->aimSpreadMoveAdd != 0.0f ||
                 isnan(pml.weaponInfo->aimSpreadMoveAdd)) &&
                (PM_FORWARDMOVE(pm) != 0 || PM_RIGHTMOVE(pm) != 0)) {
                growthRate += pml.weaponInfo->aimSpreadMoveAdd;
            }

            if (pm->ps->groundEntityNum == ENTITYNUM_NONE &&
                pm->ps->pmType != PM_TYPE_LINKED) {
                for (i = 0; i < 2; i++) {
                    /* 0x36021: machine computes airScale * 128.0 at runtime
                     * (bit-identical to 1.28f, but keep the machine form). */
#if EMULATE_X87
                    growthRate = x87f_store_f32(x87f_add(
                        x87f_load_f32(growthRate),
                        x87f_mul(x87f_load_f32(airScale), x87f_load_f32(128.0f))));
#else
                    growthRate += airScale * 128.0f;
#endif
                }
            }

            growth = growthRate * pml.frametime;
        }
    } else {
        growth = 0.0f;
        decay = 1.0f;
    }

#if EMULATE_X87
    pm->ps->aimSpreadScale = x87f_store_f32(x87f_add(
        x87f_load_f32(pm->ps->aimSpreadScale),
        x87f_mul(x87f_sub(x87f_load_f32(growth), x87f_load_f32(decay)),
                 x87f_load_i32(PM_AIM_SPREAD_SCALE_MAX))));
#else
    pm->ps->aimSpreadScale += (growth - decay) * (float)PM_AIM_SPREAD_SCALE_MAX;
#endif
    if (pm->ps->aimSpreadScale < 0.0f) {
        pm->ps->aimSpreadScale = 0.0f;
    } else if (pm->ps->aimSpreadScale > (float)PM_AIM_SPREAD_SCALE_MAX) {
        pm->ps->aimSpreadScale = (float)PM_AIM_SPREAD_SCALE_MAX;
    }
}

/* ------------------------------------------------------------------ */
/*  0x24838  PM_FlyMove                                               */
/*  Linux i386 dispatch calls this leaf only for pmType 4 spectator;   */
/*  Mac symbols name the analogous fly move (game 0x9be0, cgame 0x9300). */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x24838, 34838_FUN_00034838.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - friction call, command-scale zero/nonzero paths, 3-axis wish velocity, upmove add, speed-gated button z adjustment, normalize, PM_Accelerate accel 8, and StepSlideMove(0) checked. */
static void PM_FlyMove(void)
{
    vec3_t wishvel;
    vec3_t wishdir;
    float wishSpeed;
    float maxSpeed;
    int i;

    PM_Friction();

    maxSpeed = PM_CmdScale(PM_CURRENT_COMMAND(pm));
    if (maxSpeed == 0.0f) {
        wishvel[0] = 0.0f;
        wishvel[1] = 0.0f;
        wishvel[2] = 0.0f;
    } else {
        for (i = 0; i < 3; i++) {
            /* 0x248b0: machine multiplies maxSpeed by the axis vector first,
             * then by the command move (association changes the rounding). */
#if EMULATE_X87
            wishvel[i] = x87f_store_f32(x87f_add(
                x87f_mul(x87f_mul(x87f_load_f32(maxSpeed),
                                  x87f_load_f32(pml.forward[i])),
                         x87f_load_i32((int16_t)PM_FORWARDMOVE(pm))),
                x87f_mul(x87f_mul(x87f_load_f32(maxSpeed),
                                  x87f_load_f32(pml.right[i])),
                         x87f_load_i32((int16_t)PM_RIGHTMOVE(pm)))));
#else
            wishvel[i] = maxSpeed * pml.forward[i] *
                         (float)(int16_t)PM_FORWARDMOVE(pm) +
                         maxSpeed * pml.right[i] *
                         (float)(int16_t)PM_RIGHTMOVE(pm);
#endif
        }
#if EMULATE_X87
        wishvel[2] = x87f_store_f32(x87f_add(
            x87f_load_f32(wishvel[2]),
            x87f_mul(x87f_load_i32((int16_t)PM_UPMOVE(pm)),
                     x87f_load_f32(maxSpeed))));
#else
        wishvel[2] += (float)(int16_t)PM_UPMOVE(pm) * maxSpeed;
#endif
    }

    /* Adjust up/down for fly/spectator flags. */
    if (pm->ps->speed != 0) {
        /* 0x24955/0x24979: two separate stores - wishvel[2] is rounded to
         * float between the subtract and the add. */
        wishvel[2] -= (float)((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_DOWN) << 4);
        wishvel[2] += (float)((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_UP) << 4);
    }

    wishdir[0] = wishvel[0];
    wishdir[1] = wishvel[1];
    wishdir[2] = wishvel[2];
    wishSpeed = VectorNormalize(wishdir);

    PM_Accelerate(wishdir, wishSpeed, pm_flyaccelerate);
    PM_StepSlideMove(0);
}

/* ------------------------------------------------------------------ */
/*  0x249cc  PM_AirMove                                               */
/*  Movement while in the air (not on ground).                         */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x249cc, 349cc_FUN_000349cc.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - friction call, command copy for PM_CmdScale, flattened/normalized axes, 2D wish velocity, accel 1.0, water/ground clip overbounce 1.001, StepSlideMove(1), and body lean call checked. */
static void PM_AirMove(void)
{
    vec3_t wishvel;
    vec3_t wishdir;
    float wishSpeed;
    float ctrlSpeed;
    float rightSpeed;
    float maxSpeed;
    int i;

    PM_Friction();

    ctrlSpeed = (float)(int16_t)PM_FORWARDMOVE(pm);
    /* 0x24a07: machine also materializes the right move as a float local
     * before the command-scale call. */
    rightSpeed = (float)(int16_t)PM_RIGHTMOVE(pm);
    {
        usercmd_t localCommand = *PM_CURRENT_COMMAND(pm);
        float airSpeed;

        airSpeed = PM_CmdScale(&localCommand);
        maxSpeed = airSpeed;
    }

    pml.forward[2] = 0.0f;
    pml.right[2]   = 0.0f;
    VectorNormalize(pml.forward);
    VectorNormalize(pml.right);

    for (i = 0; i < 2; i++) {
#if EMULATE_X87
        wishvel[i] = x87f_store_f32(x87f_add(
            x87f_mul(x87f_load_f32(pml.forward[i]), x87f_load_f32(ctrlSpeed)),
            x87f_mul(x87f_load_f32(pml.right[i]), x87f_load_f32(rightSpeed))));
#else
        wishvel[i] = pml.forward[i] * ctrlSpeed +
                     pml.right[i] * rightSpeed;
#endif
    }
    wishvel[2] = 0.0f;

    wishdir[0] = wishvel[0];
    wishdir[1] = wishvel[1];
    wishdir[2] = 0.0f;
    wishSpeed = VectorNormalize(wishdir);
    /* 0x24af4: machine scales wishSpeed in place. */
    wishSpeed *= maxSpeed;

    PM_Accelerate(wishdir, wishSpeed, pm_airaccelerate);

    /* Clip velocity against ground plane if on ground */
    if (pml.waterlevel != 0) {
        PM_ClipVelocity((float *)&pm->ps->velocity[0], pml.groundTrace.normal, (float *)&pm->ps->velocity[0],
                        1.001f);
    }

    PM_StepSlideMove(1);
    PM_UpdateBodyLean();
}

/* ------------------------------------------------------------------ */
/*  0x24b7c  PM_WalkMove                                            */
/*  Movement while on the ground.                                      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x24b7c, 34b7c_FUN_00034b7c.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - wall-jump timer branches, jump-to-air path and lastJumpCommandTime store, friction/walk scale, ground-normal clipping, stance acceleration matrix, gravity-on-step path, speed-preserving clip, StepSlideMove gate, and body lean checked. */
static void PM_WalkMove(void)
{
    vec3_t wishvel;
    vec3_t wishdir;
    float wishSpeed;
    float maxSpeed;
    float accel;
    vec3_t origVel;
    float speed;
    int effectiveStance;
    int jumped;

    /* Handle wall-jump / landing timer */
    if ((pm->ps->playerStateFlags & 0x2000) != 0) {
        if (pm->ps->pmTime < PM_WALLJUMP_TIMER_LIMIT) {
            if (pm->ps->pmTime == 0) {
#if EMULATE_X87
                if (x87f_lt(x87f_load_f32(pm->ps->psOrigin[2]),
                            x87f_add(x87f_load_f32(pm->ps->jumpOriginZ),
                                     x87f_load_f32(18.0f)))) {
#else
                if (pm->ps->psOrigin[2] < pm->ps->jumpOriginZ + 18.0f) {
#endif
                    pm->ps->pmTime = PM_WALLJUMP_TIMER_NEAR_GROUND;
                    pm->ps->velocity[0] *= 0.65f;
                    pm->ps->velocity[1] *= 0.65f;
                    pm->ps->velocity[2] *= 0.65f;
                } else {
                    pm->ps->pmTime = PM_WALLJUMP_TIMER_AIR;
                    pm->ps->velocity[0] *= 0.5f;
                    pm->ps->velocity[1] *= 0.5f;
                    pm->ps->velocity[2] *= 0.5f;
                }
            }
        } else {
            pm->ps->playerStateFlags &= ~0x2000u;
            pm->ps->jumpOriginZ = 0;
            pm->ps->velocity[0] *= 0.65f;
            pm->ps->velocity[1] *= 0.65f;
            pm->ps->velocity[2] *= 0.65f;
        }
    }

    /* Check for jump */
    jumped = PM_CheckJump();
    if (jumped != 0) {
        PM_AirMove();
        pm->ps->lastJumpCommandTime = pm->command.commandTime;
        return;
    }

    /* Apply friction */
    PM_Friction();

    /* Build wish velocity */
    {
        float groundSpeed;

        groundSpeed = PM_CmdScale_Walk(PM_CURRENT_COMMAND(pm));
        maxSpeed = groundSpeed;
    }

    pml.forward[2] = 0.0f;
    pml.right[2]   = 0.0f;

    /* Clip forward and right against ground normal */
    PM_ClipVelocity(pml.forward, pml.groundTrace.normal, pml.forward,
                    1.001f);
    PM_ClipVelocity(pml.right, pml.groundTrace.normal, pml.right,
                    1.001f);
    VectorNormalize(pml.forward);
    VectorNormalize(pml.right);

    {
        float fwd = (float)(int16_t)PM_FORWARDMOVE(pm);
        float right = (float)(int16_t)PM_RIGHTMOVE(pm);
        int i;
        (void)fwd;
        (void)right;
        for (i = 0; i < 3; i++) {
#if EMULATE_X87
            wishvel[i] = x87f_store_f32(x87f_add(
                x87f_mul(x87f_load_f32(pml.forward[i]), x87f_load_f32(fwd)),
                x87f_mul(x87f_load_f32(pml.right[i]), x87f_load_f32(right))));
#else
            wishvel[i] = pml.forward[i] * fwd + pml.right[i] * right;
#endif
        }
    }

    wishdir[0] = wishvel[0];
    wishdir[1] = wishvel[1];
    wishdir[2] = wishvel[2];
    wishSpeed = VectorNormalize(wishdir);
    wishSpeed *= maxSpeed;

    /* Determine acceleration */
    effectiveStance = PM_GetEffectiveStance(pm->ps);
    if ((pml.groundTrace.surfaceFlags & 2) == 0 && (pm->ps->playerStateFlags & 0x200) == 0) {
        if (effectiveStance == 1) {
            accel = pm_prone_accelerate;
        } else if (effectiveStance == 2) {
            accel = pm_ducked_accelerate;
        } else {
            accel = 9.0f;
        }
    } else {
        accel = 1.0f;
    }
    if ((pm->ps->playerStateFlags & PM_STANCE_LANDING_STUN) != 0) {
        accel *= 0.25f;
    }

    PM_Accelerate(wishdir, wishSpeed, accel);

    /* Apply gravity for slopes */
    if ((pml.groundTrace.surfaceFlags & 2) != 0 || (pm->ps->playerStateFlags & 0x200) != 0) {
#if EMULATE_X87
        pm->ps->velocity[2] = x87f_store_f32(x87f_sub(
            x87f_load_f32(pm->ps->velocity[2]),
            x87f_mul(x87f_load_i32(pm->ps->gravity),
                     x87f_load_f32(pml.frametime))));
#else
        pm->ps->velocity[2] -= (float)pm->ps->gravity * pml.frametime;
#endif
    }

    /* Clip velocity against ground and preserve speed */
    origVel[0] = pm->ps->velocity[0];
    origVel[1] = pm->ps->velocity[1];
    origVel[2] = pm->ps->velocity[2];
#if EMULATE_X87
    speed = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
        x87f_add(x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                          x87f_load_f32(pm->ps->velocity[0])),
                 x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                          x87f_load_f32(pm->ps->velocity[1]))),
        x87f_mul(x87f_load_f32(pm->ps->velocity[2]),
                 x87f_load_f32(pm->ps->velocity[2])))));
#else
    speed = (float)CoduoLibm_Sqrt((double)(pm->ps->velocity[0] *
                                 pm->ps->velocity[0] +
                                 pm->ps->velocity[1] *
                                 pm->ps->velocity[1] +
                                 pm->ps->velocity[2] *
                                 pm->ps->velocity[2]));
#endif

    PM_ClipVelocity((float *)&pm->ps->velocity[0], pml.groundTrace.normal, (float *)&pm->ps->velocity[0],
                    1.001f);

    /* 0x2507b: machine sums the dot product in x,y,z order (full x87 width;
     * verified against the stock DLL via the slide harness pattern). */
#if EMULATE_X87
    if (x87f_lt(x87f_load_f32(0.0f),
                MDOT3X(pm->ps->velocity[0], origVel[0], pm->ps->velocity[1],
                          origVel[1], pm->ps->velocity[2], origVel[2]))) {
#else
    if (pm->ps->velocity[0] * origVel[0] +
        pm->ps->velocity[1] * origVel[1] +
        pm->ps->velocity[2] * origVel[2] > 0.0f) {
#endif
        VectorNormalize((float *)&pm->ps->velocity[0]);
        pm->ps->velocity[0] *= speed;
        pm->ps->velocity[1] *= speed;
        pm->ps->velocity[2] *= speed;
    }

    if (pm->ps->velocity[0] != 0.0f || isnan(pm->ps->velocity[0]) ||
        pm->ps->velocity[1] != 0.0f || isnan(pm->ps->velocity[1])) {
        PM_StepSlideMove(0);
    }

    PM_UpdateBodyLean();
}

/* ------------------------------------------------------------------ */
/*  0x2cebc  PM_LadderMove                                            */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2cebc, 3cebc_PM_LadderMove.c, VERIFY-PACKET-LADDER-2026-06-17): DATAFLOW_VERIFIED - jump-to-air path and lastJumpCommandTime store, climbScale clamp, forward/right flatten-normalize-project order, signed command bytes, wish velocity and accelerate args, vertical gravity easing, side-speed damping including NaN path and PM_FloatSign, airborne wall push, StepSlideMove, and truncating ladder yaw payload clamp checked. */
void PM_LadderMove(void)
{
    float climbScale;
    float wishSpeed;
    vec3_t wishvel;
    vec3_t wishdir;
    float wishLen;
    vec3_t side;
    float sideSpeed;
    float sideDrop;
    float wallPush;
    vec3_t wallNormal;
    float ladderYaw;
    int yawDelta;
    int yawAbs;

    if (PM_CheckJump() != 0) {
        PM_AirMove();
        pm->ps->lastJumpCommandTime = pm->command.commandTime;
        return;
    }

#if EMULATE_X87
    climbScale = x87f_store_f32(x87f_mul(
        x87f_add(x87f_load_f32(pml.forward[2]), x87f_load_f32(0.25f)),
        x87f_load_f32(2.5f)));
#else
    climbScale = (pml.forward[2] + 0.25f) * 2.5f;
#endif
    if (climbScale > 1.0f) {
        climbScale = 1.0f;
    } else if (climbScale < -1.0f) {
        climbScale = -1.0f;
    }

    pml.forward[2] = 0.0f;
    {
        vec3_t forward;

        forward[0] = pml.forward[0];
        forward[1] = pml.forward[1];
        forward[2] = pml.forward[2];
        VectorNormalize(forward);
        pml.forward[0] = forward[0];
        pml.forward[1] = forward[1];
        pml.forward[2] = forward[2];
    }

    pml.right[2] = 0.0f;
    VectorNormalize2(pml.right, side);
    wallNormal[0] = pm->ps->ladderNormal[0];
    wallNormal[1] = pm->ps->ladderNormal[1];
    wallNormal[2] = pm->ps->ladderNormal[2];
    ProjectPointOnPlane(pml.right, side, wallNormal);

    wishSpeed = PM_CmdScale(PM_CURRENT_COMMAND(pm));
    wishvel[0] = 0.0f;
    wishvel[1] = 0.0f;
    wishvel[2] = 0.0f;

    if (PM_FORWARDMOVE(pm) != 0) {
        /* 0x2cff5: machine multiplies pm_ladderScale * climbScale *
         * wishSpeed first and the command move last (association order). */
#if EMULATE_X87
        wishvel[2] = x87f_store_f32(x87f_mul(
            x87f_mul(x87f_mul(x87f_load_f32(pm_ladderScale),
                              x87f_load_f32(climbScale)),
                     x87f_load_f32(wishSpeed)),
            x87f_load_i32((int16_t)PM_FORWARDMOVE(pm))));
#else
        wishvel[2] = pm_ladderScale * climbScale * wishSpeed *
                     (float)(int16_t)PM_FORWARDMOVE(pm);
#endif
    }

    if (PM_RIGHTMOVE(pm) != 0) {
        /* 0x2d030: no rounded rightMove temporary - each component is one
         * 80-bit chain, wishSpeed * 0.2 first, the move last. */
#if EMULATE_X87
        for (int i = 0; i < 3; i++) {
            wishvel[i] = x87f_store_f32(x87f_add(
                x87f_load_f32(wishvel[i]),
                x87f_mul(x87f_mul(x87f_mul(x87f_load_f32(wishSpeed),
                                           x87f_load_f32(0.2f)),
                                  x87f_load_i32((int16_t)PM_RIGHTMOVE(pm))),
                         x87f_load_f32(pml.right[i]))));
        }
#else
        wishvel[0] += wishSpeed * 0.2f *
                      (float)(int16_t)PM_RIGHTMOVE(pm) * pml.right[0];
        wishvel[1] += wishSpeed * 0.2f *
                      (float)(int16_t)PM_RIGHTMOVE(pm) * pml.right[1];
        wishvel[2] += wishSpeed * 0.2f *
                      (float)(int16_t)PM_RIGHTMOVE(pm) * pml.right[2];
#endif
    }

    wishLen = VectorNormalize2(wishvel, wishdir);
    PM_Accelerate(wishdir, wishLen, pm_accelerate);

    if (PM_FORWARDMOVE(pm) == 0) {
        if (pm->ps->velocity[2] > 0.0f) {
#if EMULATE_X87
            pm->ps->velocity[2] = x87f_store_f32(x87f_sub(
                x87f_load_f32(pm->ps->velocity[2]),
                x87f_mul(x87f_load_i32(pm->ps->gravity),
                         x87f_load_f32(pml.frametime))));
#else
            pm->ps->velocity[2] -= (float)pm->ps->gravity * pml.frametime;
#endif
            if (pm->ps->velocity[2] < 0.0f) {
                pm->ps->velocity[2] = 0.0f;
            }
        } else {
#if EMULATE_X87
            pm->ps->velocity[2] = x87f_store_f32(x87f_add(
                x87f_load_f32(pm->ps->velocity[2]),
                x87f_mul(x87f_load_i32(pm->ps->gravity),
                         x87f_load_f32(pml.frametime))));
#else
            pm->ps->velocity[2] += (float)pm->ps->gravity * pml.frametime;
#endif
            if (pm->ps->velocity[2] > 0.0f) {
                pm->ps->velocity[2] = 0.0f;
            }
        }
    }

    if (PM_RIGHTMOVE(pm) == 0) {
        side[0] = pml.right[0];
        side[1] = pml.right[1];
        side[2] = 0.0f;
        VectorNormalize2D(side);
        /* 0x2d22c: machine sums the dot product in x,y order. */
#if EMULATE_X87
        sideSpeed = x87f_store_f32(x87f_add(
            x87f_mul(x87f_load_f32(side[0]), x87f_load_f32(pm->ps->velocity[0])),
            x87f_mul(x87f_load_f32(side[1]), x87f_load_f32(pm->ps->velocity[1]))));
#else
        sideSpeed = side[0] * pm->ps->velocity[0] + side[1] * pm->ps->velocity[1];
#endif
        if (sideSpeed != 0.0f || isnan(sideSpeed)) {
            /* 0x2d27a: machine negates sideSpeed and adds. */
#if EMULATE_X87
            for (int i = 0; i < 2; i++) {
                pm->ps->velocity[i] = x87f_store_f32(x87f_add(
                    x87f_load_f32(pm->ps->velocity[i]),
                    x87f_mul(x87f_neg(x87f_load_f32(sideSpeed)),
                             x87f_load_f32(side[i]))));
            }
#else
            pm->ps->velocity[0] += -sideSpeed * side[0];
            pm->ps->velocity[1] += -sideSpeed * side[1];
#endif

            /* 0x2d2c6: the friction factor is the pm_ladderfriction global. */
#if EMULATE_X87
            sideDrop = x87f_store_f32(x87f_mul(
                x87f_mul(x87f_load_f32(sideSpeed), x87f_load_f32(pml.frametime)),
                x87f_load_f32(pm_ladderfriction)));
#else
            sideDrop = sideSpeed * pml.frametime * pm_ladderfriction;
#endif
            if (fabsf(sideDrop) < fabsf(sideSpeed)) {
                if (fabsf(sideDrop) < 1.0f) {
                    sideDrop = (float)PM_FloatSign(sideDrop);
                }
                /* 0x2d30a: the difference is rounded to float in sideSpeed
                 * before the component adds. */
                sideSpeed -= sideDrop;
#if EMULATE_X87
                for (int i = 0; i < 2; i++) {
                    pm->ps->velocity[i] = x87f_store_f32(x87f_add(
                        x87f_load_f32(pm->ps->velocity[i]),
                        x87f_mul(x87f_load_f32(side[i]),
                                 x87f_load_f32(sideSpeed))));
                }
#else
                pm->ps->velocity[0] += side[0] * sideSpeed;
                pm->ps->velocity[1] += side[1] * sideSpeed;
#endif
            }
        }
    }

    if (pml.groundPlane == 0) {
        /* 0x2d37b: machine sums the dot product in x,y order and negates
         * sideSpeed for the adds (0x2d3c4). */
#if EMULATE_X87
        sideSpeed = x87f_store_f32(x87f_add(
            x87f_mul(x87f_load_f32(pm->ps->ladderNormal[0]),
                     x87f_load_f32(pm->ps->velocity[0])),
            x87f_mul(x87f_load_f32(pm->ps->ladderNormal[1]),
                     x87f_load_f32(pm->ps->velocity[1]))));
        for (int i = 0; i < 2; i++) {
            pm->ps->velocity[i] = x87f_store_f32(x87f_add(
                x87f_load_f32(pm->ps->velocity[i]),
                x87f_mul(x87f_neg(x87f_load_f32(sideSpeed)),
                         x87f_load_f32(pm->ps->ladderNormal[i]))));
        }
#else
        sideSpeed = pm->ps->ladderNormal[0] * pm->ps->velocity[0] +
                    pm->ps->ladderNormal[1] * pm->ps->velocity[1];
        pm->ps->velocity[0] += -sideSpeed * pm->ps->ladderNormal[0];
        pm->ps->velocity[1] += -sideSpeed * pm->ps->ladderNormal[1];
#endif

        if (wishvel[2] > 0.0f) {
            wallPush = -500.0f;
        } else {
            wallPush = -250.0f;
        }
#if EMULATE_X87
        for (int i = 0; i < 2; i++) {
            pm->ps->velocity[i] = x87f_store_f32(x87f_add(
                x87f_load_f32(pm->ps->velocity[i]),
                x87f_mul(x87f_load_f32(pm->ps->ladderNormal[i]),
                         x87f_load_f32(wallPush))));
        }
#else
        pm->ps->velocity[0] += pm->ps->ladderNormal[0] * wallPush;
        pm->ps->velocity[1] += pm->ps->ladderNormal[1] * wallPush;
#endif
    }

    PM_StepSlideMove(0);

    ladderYaw = vectoyaw(pm->ps->ladderNormal) + 180.0f;
    /* Original x87 conversion uses chop mode here, not nearest rounding. */
#if EMULATE_X87
    {
        const float ladderAngleDelta =
            AngleDelta(ladderYaw, pm->ps->viewAngles[1]);
        yawDelta = x87f_store_i32_trunc(
            x87f_load_f32(ladderAngleDelta));
    }
#elif defined(__x86_64__)
    {
        const float ladderAngleDelta =
            AngleDelta(ladderYaw, pm->ps->viewAngles[1]);
        yawDelta =
            CODUO_X87_TRUNCATE_I32((long double)ladderAngleDelta);
    }
#else
    yawDelta = (int)AngleDelta(ladderYaw, pm->ps->viewAngles[1]);
#endif
    yawAbs = yawDelta < 0 ? -yawDelta : yawDelta;
    if (yawAbs > 75) {
        yawDelta = yawDelta < 1 ? -75 : 75;
    }
    pm->ps->movementDir = (int8_t)yawDelta;
}

/* ------------------------------------------------------------------ */
/*  0x2538b  PM_NoclipMove                                            */
/*  Linux i386 dispatch case 2 is PM_TYPE_NOCLIP; Mac symbols name  */
/*  this movement mode PM_NoclipMove (game 0x9040, cgame 0x8760).      */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x2538b, 3538b_FUN_0003538b.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - standing viewheight stores, speed sqrt, friction floor 100 and 8.25 scale, zero/scale velocity paths, PM_CmdScale call, wish velocity/upmove, accel 9, and direct origin integration checked. */
static void PM_NoclipMove(void)
{
    vec3_t wishvel;
    float speed;
    float maxSpeed;
    float friction;
    float newSpeed;
    float wishSpeed;

    pm->ps->viewHeightTarget = bg_viewheight_standing.integer;
    pm->ps->standViewHeight = bg_viewheight_standing.integer;

    /* 0x253e4: machine sums the speed dot product in x,y,z order. */
#if EMULATE_X87
    speed = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
        x87f_add(x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                          x87f_load_f32(pm->ps->velocity[0])),
                 x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                          x87f_load_f32(pm->ps->velocity[1]))),
        x87f_mul(x87f_load_f32(pm->ps->velocity[2]),
                 x87f_load_f32(pm->ps->velocity[2])))));
#else
    speed = (float)CoduoLibm_Sqrt((double)(pm->ps->velocity[0] *
                                 pm->ps->velocity[0] +
                                 pm->ps->velocity[1] *
                                 pm->ps->velocity[1] +
                                 pm->ps->velocity[2] *
                                 pm->ps->velocity[2]));
#endif

    if (speed < 1.0f) {
        pm->ps->velocity[0] = 0.0f;
        pm->ps->velocity[1] = 0.0f;
        pm->ps->velocity[2] = 0.0f;
    } else {
        float drop = 0.0f; /* 0x25485 */

        /* 0x25492: the factor is pm_friction * 1.5 computed at runtime and
         * rounded to float; the floor is the pm_stopspeed global. */
        friction = pm_friction * 1.5f;
        maxSpeed = (speed < pm_stopspeed) ? pm_stopspeed : speed;
#if EMULATE_X87
        drop = x87f_store_f32(x87f_add(
            x87f_load_f32(drop),
            x87f_mul(x87f_mul(x87f_load_f32(maxSpeed), x87f_load_f32(friction)),
                     x87f_load_f32(pml.frametime))));
        newSpeed = speed - drop;
        if (newSpeed < 0.0f) newSpeed = 0.0f;
        newSpeed = x87f_store_f32(
            x87f_div(x87f_load_f32(newSpeed), x87f_load_f32(speed)));
#else
        drop += maxSpeed * friction * pml.frametime;
        newSpeed = speed - drop;
        if (newSpeed < 0.0f) newSpeed = 0.0f;
        newSpeed /= speed;
#endif
        pm->ps->velocity[0] *= newSpeed;
        pm->ps->velocity[1] *= newSpeed;
        pm->ps->velocity[2] *= newSpeed;
    }

    maxSpeed = PM_CmdScale(PM_CURRENT_COMMAND(pm));

    /* 0x255c8: machine loops the two-term wish velocity (forward term
     * first), then adds the up move to wishvel[2] as a second store. */
    {
        float fwd = (float)(int16_t)PM_FORWARDMOVE(pm);
        float right = (float)(int16_t)PM_RIGHTMOVE(pm);
        int i;

        for (i = 0; i < 3; i++) {
#if EMULATE_X87
            wishvel[i] = x87f_store_f32(x87f_add(
                x87f_mul(x87f_load_f32(pml.forward[i]), x87f_load_f32(fwd)),
                x87f_mul(x87f_load_f32(pml.right[i]), x87f_load_f32(right))));
#else
            wishvel[i] = pml.forward[i] * fwd + pml.right[i] * right;
#endif
        }
    }
    wishvel[2] += (float)(int16_t)PM_UPMOVE(pm);

    wishSpeed = VectorNormalize(wishvel);
    /* 0x25629: machine scales wishSpeed in place. */
    wishSpeed *= maxSpeed;

    PM_Accelerate(wishvel, wishSpeed, pm_accelerate);

    /* Apply velocity to origin directly (no collision) */
#if EMULATE_X87
    for (int k = 0; k < 3; k++) {
        pm->ps->psOrigin[k] = x87f_store_f32(x87f_add(
            x87f_load_f32(pm->ps->psOrigin[k]),
            x87f_mul(x87f_load_f32(pm->ps->velocity[k]),
                     x87f_load_f32(pml.frametime))));
    }
#else
    pm->ps->psOrigin[0] += pm->ps->velocity[0] * pml.frametime;
    pm->ps->psOrigin[1] += pm->ps->velocity[1] * pml.frametime;
    pm->ps->psOrigin[2] += pm->ps->velocity[2] * pml.frametime;
#endif
}

/* ------------------------------------------------------------------ */
/*  0x256ed  PM_UFOMove                                               */
/*  Linux i386 dispatch case 3 is PM_TYPE_UFO; Mac symbols name     */
/*  this movement mode PM_UFOMove (game 0x8c20, cgame 0x8340).         */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x256ed, 356ed_FUN_000356ed.c, VERIFY-MOVEMENT-BLOCKERS-2026-06-17): DATAFLOW_VERIFIED - standing viewheight stores, upmove button-byte mutations, vertical-only velocity special case, friction floor 100 and pm_friction * 1.5 scale, cross-product wish direction, doubled upmove z, accel 9, and direct origin integration checked. */
static void PM_UFOMove(void)
{
    vec3_t wishvel;
    vec3_t wishdir;
    float speed;
    float maxSpeed;
    float frictionScale;
    float friction;
    float newSpeed;
    float upMove;
    float wishSpeed;
    vec3_t sideDir;
    int i;

    (void)speed;

    pm->ps->viewHeightTarget = bg_viewheight_standing.integer;
    pm->ps->standViewHeight = bg_viewheight_standing.integer;

    /* Adjust upmove for lean buttons */
    PM_UPMOVE(pm) =
        PM_UPMOVE(pm) + (int8_t)(PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_DOWN);
    PM_UPMOVE(pm) =
        PM_UPMOVE(pm) - (int8_t)(PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_UP);

    if (PM_FORWARDMOVE(pm) == 0 && PM_RIGHTMOVE(pm) == 0) {
        if ((float)(int16_t)PM_UPMOVE(pm) == 0.0f) {
            speed = 0.0f;
        } else {
            pm->ps->velocity[1] = 0.0f;
            pm->ps->velocity[0] = 0.0f;
            speed = 127.0f;
            pm->ps->velocity[2] = (float)(int16_t)PM_UPMOVE(pm);
        }
    } else {
#if EMULATE_X87
        speed = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
            x87f_add(x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                              x87f_load_f32(pm->ps->velocity[0])),
                     x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                              x87f_load_f32(pm->ps->velocity[1]))),
            x87f_mul(x87f_load_f32(pm->ps->velocity[2]),
                     x87f_load_f32(pm->ps->velocity[2])))));
#else
        speed = (float)CoduoLibm_Sqrt((double)(pm->ps->velocity[0] *
                                     pm->ps->velocity[0] +
                                     pm->ps->velocity[1] *
                                     pm->ps->velocity[1] +
                                     pm->ps->velocity[2] *
                                     pm->ps->velocity[2]));
#endif
    }

    if (speed < 1.0f) {
        pm->ps->velocity[0] = 0.0f;
        pm->ps->velocity[1] = 0.0f;
        pm->ps->velocity[2] = 0.0f;
    } else {
        maxSpeed = speed;
        if (speed < 100.0f) {
            maxSpeed = 100.0f;
        }
#if EMULATE_X87
        /* 0x258f7..0x25907: stock reads the exported pm_friction object,
         * multiplies by 1.5f, and rounds that scale to binary32 first. */
        frictionScale = x87f_store_f32(
            x87f_mul(x87f_load_f32(pm_friction), x87f_load_f32(1.5f)));
        friction = x87f_store_f32(x87f_mul(
            x87f_mul(x87f_load_f32(maxSpeed), x87f_load_f32(frictionScale)),
            x87f_load_f32(pml.frametime)));
        newSpeed = speed - friction;
        if (newSpeed < 0.0f) newSpeed = 0.0f;
        newSpeed = x87f_store_f32(
            x87f_div(x87f_load_f32(newSpeed), x87f_load_f32(speed)));
#else
        frictionScale = pm_friction * 1.5f;
        friction = maxSpeed * frictionScale * pml.frametime;
        newSpeed = speed - friction;
        if (newSpeed < 0.0f) newSpeed = 0.0f;
        newSpeed /= speed;
#endif
        pm->ps->velocity[0] *= newSpeed;
        pm->ps->velocity[1] *= newSpeed;
        pm->ps->velocity[2] *= newSpeed;
    }

    maxSpeed = PM_CmdScale(PM_CURRENT_COMMAND(pm));

    /* Build side direction from cross product of up and right */
    sideDir[0] = 0.0f;
    sideDir[1] = 0.0f;
    sideDir[2] = 1.0f;
    {
        vec3_t cross;
        float fwd = (float)(int16_t)PM_FORWARDMOVE(pm);
        float right = (float)(int16_t)PM_RIGHTMOVE(pm);
        upMove = (float)(int16_t)PM_UPMOVE(pm);

        CrossProduct(sideDir, pml.right, cross);
        for (i = 0; i < 3; i++) {
#if EMULATE_X87
            wishvel[i] = x87f_store_f32(x87f_add(
                x87f_mul(x87f_load_f32(pml.right[i]), x87f_load_f32(right)),
                x87f_mul(x87f_load_f32(cross[i]), x87f_load_f32(fwd))));
#else
            wishvel[i] = pml.right[i] * right + cross[i] * fwd;
#endif
        }
        /* upMove+upMove is an exact doubling and the += is a single add — both
         * native-identical, so no shim needed. */
        wishvel[2] += upMove + upMove;
    }

    wishdir[0] = wishvel[0];
    wishdir[1] = wishvel[1];
    wishdir[2] = wishvel[2];
    wishSpeed = VectorNormalize(wishdir);

    PM_Accelerate(wishdir, wishSpeed * maxSpeed, pm_accelerate);

#if EMULATE_X87
    for (i = 0; i < 3; i++) {
        pm->ps->psOrigin[i] = x87f_store_f32(x87f_add(
            x87f_load_f32(pm->ps->psOrigin[i]),
            x87f_mul(x87f_load_f32(pm->ps->velocity[i]),
                     x87f_load_f32(pml.frametime))));
    }
#else
    pm->ps->psOrigin[0] += pm->ps->velocity[0] * pml.frametime;
    pm->ps->psOrigin[1] += pm->ps->velocity[1] * pml.frametime;
    pm->ps->psOrigin[2] += pm->ps->velocity[2] * pml.frametime;
#endif
}

/* ------------------------------------------------------------------ */
/*  0x297e4  PM_Footsteps                                        */
/*  Update footstep timing and animations.                             */
/* ------------------------------------------------------------------ */
/* VERIFIED_MACHINE_CODE(0x297e4): pmType guard, horizontal speed store, entityStateFlags animation branch, airborne ladder timing/events, idle animation paths, strafe/back speed conditioning, stance/viewheight speed scaling, animation IDs, truncating bob-cycle conversions, idle fallback, and PM_FootstepEvent gates checked. */
static void PM_Footsteps(void)
{
    float speed2d;
    int anim;
    int effectiveStance;
    uint32_t stanceBits;
    uint32_t sprintBit;
    float moveSpeed;
    float stepInterval;
    int oldTime;
    int shouldMake;

    anim = -1;

    if (pm->ps->pmType >= PM_TYPE_DEAD) {
        return;
    }

#if EMULATE_X87
    speed2d = (float)CoduoLibm_Sqrt(x87f_store_f64(x87f_add(
        x87f_mul(x87f_load_f32(pm->ps->velocity[0]),
                 x87f_load_f32(pm->ps->velocity[0])),
        x87f_mul(x87f_load_f32(pm->ps->velocity[1]),
                 x87f_load_f32(pm->ps->velocity[1])))));
#else
    speed2d = (float)CoduoLibm_Sqrt((double)(pm->ps->velocity[0] *
                                   pm->ps->velocity[0] +
                                   pm->ps->velocity[1] *
                                   pm->ps->velocity[1]));
#endif
    pm->horizontalSpeed = speed2d;

    if ((pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) != 0) {
        /* Vehicle / special state */
        if ((pm->ps->entityStateFlags & 0x6000) != 0) {
            if (pm->ps->viewHeightTarget == pm->ps->proneViewHeight) {
                anim = BG_AnimScriptAnimation(pm->ps, 3, 3, 1);
            } else if (pm->ps->viewHeightTarget == pm->ps->crouchViewHeight) {
                anim = BG_AnimScriptAnimation(pm->ps, 3, 2, 1);
            }
        }
        if (anim < 0) {
            BG_AnimScriptAnimation(pm->ps, 3, 1, 1);
        }
        return;
    }

    effectiveStance = PM_GetEffectiveStance(pm->ps);

    /* Prone crawling footstep */
    if (pm->ps->groundEntityNum == ENTITYNUM_NONE &&
        pm->ps->pmType != PM_TYPE_LINKED) {
        if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0) {
            if (coduo_int32_from_bits(
                    (uint32_t)pm->command.commandTime -
                    (uint32_t)pm->ps->lastJumpCommandTime) <
                pm_ladderJumpTime) {
                return;
            }
            {
#if EMULATE_X87
                float ladderDenom = x87f_store_f32(x87f_mul(
                    x87f_mul(x87f_load_f32(pm_ladderScale), x87f_load_f32(1.5f)),
                    x87f_load_f32(127.0f)));
#else
                float ladderDenom = pm_ladderScale * 1.5f * 127.0f;
#endif
                float velZ = pm->ps->velocity[2];
                if ((pm->ps->playerStateFlags & 0x80) != 0 || pm->ps->leanFraction != 0.0f ||
                    isnan(pm->ps->leanFraction)) {
#if EMULATE_X87
                    stepInterval = x87f_store_f32(x87f_mul(
                        x87f_div(x87f_load_f32(velZ),
                                 x87f_mul(x87f_load_f32(pm->ps->walkSpeedScale),
                                          x87f_load_f32(ladderDenom))),
                        x87f_load_f32(0.35f)));
#else
                    stepInterval = (velZ / (pm->ps->walkSpeedScale * ladderDenom)) * 0.35f;
#endif
                } else {
#if EMULATE_X87
                    stepInterval = x87f_store_f32(x87f_mul(
                        x87f_div(x87f_load_f32(velZ),
                                 x87f_mul(x87f_load_f32(pm->ps->runSpeedScale),
                                          x87f_load_f32(ladderDenom))),
                        x87f_load_f32(0.45f)));
#else
                    stepInterval = (velZ / (pm->ps->runSpeedScale * ladderDenom)) * 0.45f;
#endif
                }
            }
            if (pm->ps->velocity[2] >= 0.0f) {
                anim = BG_AnimScriptAnimation(pm->ps, 3,
                                              PM_ANIMSCRIPT_LADDER_CLIMB_UP, 1);
            } else {
                anim = BG_AnimScriptAnimation(
                    pm->ps, 3, PM_ANIMSCRIPT_LADDER_CLIMB_DOWN, 1);
            }
            oldTime = pm->ps->bobCycle;
            pm->ps->bobCycle = BOBCYCLE(oldTime, pml.msec, stepInterval);
            PM_FootstepEvent(oldTime, pm->ps->bobCycle, 1);
        }
        if (effectiveStance == (int)(pm->ps->playerStateFlags & 3)) {
            return;
        }
    }

    sprintBit = pm->ps->playerStateFlags & 0x80;
    stanceBits = pm->ps->playerStateFlags;

    /* Idle / very slow movement */
    if (pm->horizontalSpeed < 10.0f ||
        pm->ps->pmType == PM_TYPE_LINKED) {
        if (pm->horizontalSpeed < 1.0f) {
            pm->ps->bobCycle = 0;
        }
        if (pm->ps->viewHeightTarget == pm->ps->proneViewHeight) {
            anim = BG_AnimScriptAnimation(pm->ps, 3, 3, 1);
        } else if (pm->ps->viewHeightTarget == pm->ps->crouchViewHeight) {
            anim = BG_AnimScriptAnimation(pm->ps, 3, 2, 1);
        }
        if (anim < 0) {
            BG_AnimScriptAnimation(pm->ps, 3, 1, 1);
        }
        return;
    }

    /* Normal movement footsteps */
    moveSpeed = (float)pm->ps->speed;

    /* Adjust speed for strafe/backward */
    if (PM_FORWARDMOVE(pm) == 0) {
        if (PM_RIGHTMOVE(pm) != 0) {
#if EMULATE_X87
            moveSpeed = x87f_store_f32(x87f_mul(
                x87f_load_f32(moveSpeed),
                x87f_add(x87f_mul(x87f_sub(x87f_load_f32(pm->ps->strafeSpeedScale),
                                           x87f_load_f32(1.0f)),
                                  x87f_load_f32(0.75f)),
                         x87f_load_f32(1.0f))));
#else
            moveSpeed *= (pm->ps->strafeSpeedScale - 1.0f) * 0.75f + 1.0f;
#endif
            if (PM_RIGHTMOVE(pm) < 1) {
                BG_UpdateConditionValue(pm->ps->psClientNum, 10, 1, 1);
            } else {
                BG_UpdateConditionValue(pm->ps->psClientNum, 10, 2, 1);
            }
        }
    } else {
        if (PM_RIGHTMOVE(pm) == 0) {
            if (PM_FORWARDMOVE(pm) < 0) {
                moveSpeed *= pm->ps->backSpeedScale;
            }
        } else {
#if EMULATE_X87
            moveSpeed = x87f_store_f32(x87f_mul(
                x87f_load_f32(moveSpeed),
                x87f_mul(x87f_add(x87f_add(
                                      x87f_mul(x87f_sub(x87f_load_f32(
                                                            pm->ps->strafeSpeedScale),
                                                        x87f_load_f32(1.0f)),
                                               x87f_load_f32(0.75f)),
                                      x87f_load_f32(1.0f)),
                                  x87f_load_f32(1.0f)),
                         x87f_load_f32(0.5f))));
#else
            moveSpeed *= ((pm->ps->strafeSpeedScale - 1.0f) * 0.75f + 1.0f + 1.0f) * 0.5f;
#endif
            if (PM_FORWARDMOVE(pm) < 0) {
#if EMULATE_X87
                moveSpeed = x87f_store_f32(x87f_mul(
                    x87f_load_f32(moveSpeed),
                    x87f_mul(x87f_add(x87f_load_f32(pm->ps->backSpeedScale),
                                      x87f_load_f32(1.0f)),
                             x87f_load_f32(0.5f))));
#else
                moveSpeed *= (pm->ps->backSpeedScale + 1.0f) * 0.5f;
#endif
            }
        }
        BG_UpdateConditionValue(pm->ps->psClientNum, 10, 0, 1);
    }

    /* Apply stance speed multiplier */
    if (sprintBit == 0) {
        if ((stanceBits & PM_STANCE_FATIGUE_DRAIN) == 0) {
            moveSpeed *= pm->ps->runSpeedScale;
        } else {
            moveSpeed *= pm->ps->sprintSpeedScale;
        }
    } else {
        moveSpeed *= pm->ps->walkSpeedScale;
    }

    /* Apply viewheight lerp speed modifier */
    {
        float lerpFrac = PM_GetViewHeightLerp(pm->ps->crouchViewHeight,
                                              pm->ps->proneViewHeight);
        if (lerpFrac != 0.0f || isnan(lerpFrac)) {
#if EMULATE_X87
            moveSpeed = x87f_store_f32(x87f_mul(
                x87f_load_f32(moveSpeed),
                x87f_add(x87f_mul(x87f_sub(x87f_load_f32(1.0f),
                                           x87f_load_f32(lerpFrac)),
                                  x87f_load_f32(pm->ps->crouchSpeedScale)),
                         x87f_mul(x87f_load_f32(lerpFrac),
                                  x87f_load_f32(pm->ps->proneSpeedScale)))));
#else
            moveSpeed *= (1.0f - lerpFrac) * pm->ps->crouchSpeedScale +
                          lerpFrac * pm->ps->proneSpeedScale;
#endif
        } else {
            lerpFrac = PM_GetViewHeightLerp(pm->ps->proneViewHeight,
                                            pm->ps->crouchViewHeight);
            if (lerpFrac != 0.0f || isnan(lerpFrac)) {
#if EMULATE_X87
                moveSpeed = x87f_store_f32(x87f_mul(
                    x87f_load_f32(moveSpeed),
                    x87f_add(x87f_mul(x87f_sub(x87f_load_f32(1.0f),
                                               x87f_load_f32(lerpFrac)),
                                      x87f_load_f32(pm->ps->proneSpeedScale)),
                             x87f_mul(x87f_load_f32(lerpFrac),
                                      x87f_load_f32(pm->ps->crouchSpeedScale)))));
#else
                moveSpeed *= (1.0f - lerpFrac) * pm->ps->proneSpeedScale +
                              lerpFrac * pm->ps->crouchSpeedScale;
#endif
            } else if (effectiveStance == 1) {
                moveSpeed *= pm->ps->proneSpeedScale;
            } else if (effectiveStance == 2) {
                moveSpeed *= pm->ps->crouchSpeedScale;
            }
        }
    }

    /* Select animation and compute step interval */
    if (effectiveStance == 1) {
        if (sprintBit == 0) {
            stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.25f);
        } else {
            stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.24f);
        }
        if ((pm->ps->playerStateFlags & 0x40) == 0) {
            anim = BG_AnimScriptAnimation(pm->ps, 3, 8, 1);
        } else {
            anim = BG_AnimScriptAnimation(pm->ps, 3, 9, 1);
        }
    } else if (effectiveStance == 2) {
        if (sprintBit == 0) {
            stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.34f);
        } else {
            stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.315f);
        }
        if ((pm->ps->playerStateFlags & 0x40) == 0) {
            if (sprintBit == 0) {
                anim = BG_AnimScriptAnimation(
                    pm->ps, 3, PM_ANIMSCRIPT_CROUCH_WALK_BACK, 1);
            } else {
                anim = BG_AnimScriptAnimation(pm->ps, 3, 6, 1);
            }
        } else if (sprintBit == 0) {
            anim = BG_AnimScriptAnimation(
                pm->ps, 3, PM_ANIMSCRIPT_CROUCH_RUN_BACK, 1);
        } else {
            anim = BG_AnimScriptAnimation(pm->ps, 3, 7, 1);
        }
    } else if ((pm->ps->playerStateFlags & 0x40) == 0) {
        if (sprintBit == 0) {
            stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.335f);
            anim = BG_AnimScriptAnimation(pm->ps, 3, 10, 1);
        } else {
            stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.305f);
            anim = BG_AnimScriptAnimation(pm->ps, 3, 4, 1);
        }
    } else if (sprintBit == 0) {
        stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.36f);
        anim = BG_AnimScriptAnimation(pm->ps, 3, PM_ANIMSCRIPT_STAND_WALK_BACK, 1);
    } else {
        stepInterval = STEPINTERVAL(pm->horizontalSpeed, moveSpeed, 0.325f);
        anim = BG_AnimScriptAnimation(pm->ps, 3, 5, 1);
    }

    shouldMake = PM_ShouldMakeFootsteps();
    oldTime = pm->ps->bobCycle;
    pm->ps->bobCycle = BOBCYCLE(oldTime, pml.msec, stepInterval);

    /* Idle animation if not moving */
    if (PM_FORWARDMOVE(pm) == 0 && PM_RIGHTMOVE(pm) == 0) {
        if (pm->horizontalSpeed <= 120.0f) {
            if (pm->ps->viewHeightTarget == pm->ps->proneViewHeight) {
                anim = BG_AnimScriptAnimation(pm->ps, 3, 3, 1);
            } else if (pm->ps->viewHeightTarget == pm->ps->crouchViewHeight) {
                anim = BG_AnimScriptAnimation(pm->ps, 3, 2, 1);
            }
            if (anim < 0) {
                BG_AnimScriptAnimation(pm->ps, 3, 1, 1);
            }
        }
    } else {
        if (anim < 0) {
            BG_AnimScriptAnimation(pm->ps, 3, 1, 1);
        }
        PM_FootstepEvent(oldTime, pm->ps->bobCycle, shouldMake);
    }
}

/* ------------------------------------------------------------------ */
/*  0x27e16  PM_CheckDuck                                             */
/*  Update stance state (prone/crouch/stand transitions).              */
/* ------------------------------------------------------------------ */
/* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - stance command handling, spread-weapon gate, bounds, viewheight state, trace callbacks, allsolid/startsolid fields, prone entry traces, and pitch offsets checked against current decompiler output. */
static void PM_CheckDuck(void)
{
    int wasProne;
    int effectiveStance;
    trace_t trace;
    vec3_t start, end;

    pm->weaponAnimscriptEnabled = 0;

    if (pm->ps->pmType == PM_TYPE_SPECTATOR) {
        /* Spectator fly movement uses fixed bounds. */
        pm->mins[0] = -8.0f;
        pm->mins[1] = -8.0f;
        pm->mins[2] = -8.0f;
        pm->maxs[0] = 8.0f;
        pm->maxs[1] = 8.0f;
        pm->maxs[2] = 16.0f;
        pm->ps->playerStateFlags &= ~3u;

        /* Clear prone flag if set */
        if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_PRONE) != 0) {
            PM_BUTTON_BYTE1(pm) &= ~PMOVE_WBUTTON_PRONE;
            BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_STAND, 0, pm->ps);
        }

        /* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - spectator movement resets the primary PM_trace callback to the overhead trace slot. */
        pm->trace = pm->trace3;
        pm->ps->entityStateFlags |= PS_FLAG_STANCE_VALID;
        pm->ps->viewHeightTarget = 0;
        pm->ps->viewHeightCurrent = 0.0f;
        return;
    }

    wasProne = (int)(pm->ps->playerStateFlags & 1);

    /* Copy player bounds from gclient_t */
    pm->mins[0] = pm->ps->playerMins[0];
    pm->mins[1] = pm->ps->playerMins[1];
    pm->mins[2] = pm->ps->playerMins[2];
    pm->maxs[0] = pm->ps->playerMaxs[0];
    pm->maxs[1] = pm->ps->playerMaxs[1];
    pm->maxs[2] = pm->ps->playerMaxs[2];

    if (pm->ps->pmType >= PM_TYPE_DEAD) {
        /* Dead or special: set standing bounds */
        pm->maxs[2] = pm->ps->playerMaxs[2];
        pm->ps->viewHeightTarget = pm->ps->deadViewHeight;
        if (wasProne == 0) {
            /* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - dead/special non-prone state writes pmove+0x104 from the overhead trace slot. */
            pm->trace = pm->trace3;
            pm->ps->entityStateFlags |= PS_FLAG_STANCE_VALID;
        } else {
            /* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - dead/special prone state writes pmove+0x104 from the ADS/wall trace slot. */
            pm->trace = pm->trace2;
            pm->ps->entityStateFlags |= PS_FLAG_STANCE_VALID;
        }
        PM_ViewHeightAdjust();
        return;
    }

    if ((pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) != 0) {
        /* Vehicle / knockback: manage stance bits */
        if ((pm->ps->entityStateFlags & 0x2000) == 0 ||
            (pm->ps->entityStateFlags & 0x4000) != 0) {
            if ((pm->ps->entityStateFlags & 0x4000) == 0 ||
                (pm->ps->entityStateFlags & 0x2000) != 0) {
                pm->ps->playerStateFlags &= ~3u;
            } else {
                pm->ps->playerStateFlags = (pm->ps->playerStateFlags | 2) & ~1u;
            }
        } else {
            pm->ps->playerStateFlags = (pm->ps->playerStateFlags | 1) & ~2u;
        }
    } else if ((pm->ps->playerStateFlags & 0x4000) == 0 &&
               ((pm->ps->playerStateFlags & PM_STANCE_ADS) == 0 ||
                ((const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon))
                        ->weaponClass != WEAPCLASS_LMG)) {

        /* Clear prone-related flags if needed */
        if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) != 0 &&
            (PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_STANCE_MASK) != 0) {
            PM_BUTTON_BYTE1(pm) &= ~PMOVE_WBUTTON_STANCE_MASK;
            BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_STAND, 0, pm->ps);
        }

        if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_PRONE) == 0) {
            if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_CROUCH) == 0) {
                if ((pm->ps->playerStateFlags & 1) == 0) {
                    if ((pm->ps->playerStateFlags & 2) != 0) {
                        /* Crouching: try to stand */
                        pm->maxs[2] = pm->ps->playerMaxs[2];
                        start[0] = pm->ps->psOrigin[0];
                        start[1] = pm->ps->psOrigin[1];
                        start[2] = pm->ps->psOrigin[2];
                        pm->trace3(&trace, start, pm->mins, pm->maxs,
                                   start, pm->ps->psClientNum,
                                   pm->traceMask & ~(int32_t)CONTENTS_BODY);
                        if (!trace.allsolid) {
                            pm->ps->playerStateFlags &= ~2u;
                        } else if ((PM_BUTTON_BYTE1(pm) &
                                    PMOVE_WBUTTON_STANCE_LATCH) == 0) {
                            BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_CROUCH,
                                                                0, pm->ps);
                        }
                    }
                } else {
                    /* Prone: try to crouch */
                    pm->maxs[2] = pm->ps->playerMaxs[2];
                    start[0] = pm->ps->psOrigin[0];
                    start[1] = pm->ps->psOrigin[1];
                    start[2] = pm->ps->psOrigin[2];
                    pm->trace3(&trace, start, pm->mins, pm->maxs,
                               start, pm->ps->psClientNum,
                               pm->traceMask & ~(int32_t)CONTENTS_BODY);
                    if (!trace.allsolid) {
                        pm->ps->playerStateFlags &= ~1u;
                    } else {
                        pm->maxs[2] = 50.0f;
                        pm->trace3(&trace, start, pm->mins, pm->maxs,
                                   start, pm->ps->psClientNum,
                                   pm->traceMask & ~(int32_t)CONTENTS_BODY);
                        if (!trace.allsolid) {
                            pm->ps->playerStateFlags = (pm->ps->playerStateFlags & ~1u) | 2;
                        } else if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_STANCE_LATCH) == 0) {
                            BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_PRONE, 0, pm->ps);
                        }
                    }
                }
            } else if ((pm->ps->playerStateFlags & 1) == 0) {
                pm->ps->playerStateFlags |= 2;
            } else {
                pm->maxs[2] = 50.0f;
                start[0] = pm->ps->psOrigin[0];
                start[1] = pm->ps->psOrigin[1];
                start[2] = pm->ps->psOrigin[2];
                pm->trace3(&trace, start, pm->mins, pm->maxs,
                           start, pm->ps->psClientNum,
                           pm->traceMask & ~(int32_t)CONTENTS_BODY);
                if (!trace.allsolid) {
                    pm->ps->playerStateFlags = (pm->ps->playerStateFlags & ~1u) | 2;
                } else if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_STANCE_LATCH) == 0) {
                    BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_PRONE, 0, pm->ps);
                }
            }
        } else {
            int proneCheck = -1;
            int blockReason = 0;

            if ((pm->ps->playerStateFlags & 1) == 0) {
                if (pm->ps->groundEntityNum == ENTITYNUM_NONE) {
                    blockReason = 1;
                } else if (pm->overheadLevel != 0) {
                    blockReason = 2;
                } else {
                    proneCheck = BG_CheckProne(
                        pm->ps->psClientNum, &pm->ps->psOrigin[0], pm->maxs[0],
                        30.0f, pm->ps->viewAngles[1],
                        &pm->ps->torsoHeight, &pm->ps->torsoPitch, &pm->ps->waistPitch,
                        0, pm->ps->groundEntityNum != ENTITYNUM_NONE, 0,
                        pm->trace3, pm->trace2,
                        0, 60.0f,
                        pm->entityType);
                    if (proneCheck == 0) {
                        blockReason = 3;
                    }
                }

            }

            if ((pm->ps->playerStateFlags & 1) == 0 && blockReason != 0) {
                /* Try to go prone */
                if (pm->ps->groundEntityNum != ENTITYNUM_NONE) {
                    pm->ps->playerStateFlags |= 0x8000;
                    if ((PM_BUTTON_BYTE1(pm) & PMOVE_WBUTTON_STANCE_LATCH) == 0) {
                        if ((pm->ps->playerStateFlags & 2) == 0) {
                            BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_STAND, 0, pm->ps);
                        } else {
                            BG_AddPredictableEventToPlayerstate(EV_STANCE_FORCE_CROUCH, 0, pm->ps);
                        }
                    }
                }
            } else {
                pm->ps->playerStateFlags = (pm->ps->playerStateFlags | 1) & ~2u;
            }
        }
    }

    /* Update stance target height */
    if (pm->ps->viewHeightLerpTime == 0) {
        if ((pm->ps->playerStateFlags & 1) == 0) {
            if (pm->ps->viewHeightTarget == pm->ps->proneViewHeight) {
                pm->ps->viewHeightTarget = pm->ps->crouchViewHeight;
                pm->weaponAnimscriptEnabled = 1;
                if (pm->ps->weaponState != WEAPON_STATE_DEPLOYING &&
                    pm->ps->weaponState != WEAPON_STATE_BREAKING_DOWN) {
                    BG_PlayAnim(pm->ps, 0, 2, 0, 0, 1, 1);
                }
            } else if ((pm->ps->playerStateFlags & 2) == 0) {
                pm->ps->viewHeightTarget = pm->ps->standViewHeight;
            } else {
                pm->ps->viewHeightTarget = pm->ps->crouchViewHeight;
            }
        } else if (pm->ps->viewHeightTarget == pm->ps->standViewHeight) {
            pm->ps->viewHeightTarget = pm->ps->crouchViewHeight;
        } else {
            if (g_debugProneCheck.integer == 2) {
                BG_CheckProne(pm->ps->psClientNum, &pm->ps->psOrigin[0], pm->maxs[0],
                              30.0f, pm->ps->viewAngles[1],
                              0, 0, 0, 0, pm->ps->groundEntityNum != ENTITYNUM_NONE, 0,
                              pm->trace3, pm->trace2,
                              0, 60.0f,
                              pm->entityType);
            }
            if (pm->ps->viewHeightTarget != pm->ps->proneViewHeight) {
                pm->ps->viewHeightTarget = pm->ps->proneViewHeight;
                pm->weaponAnimscriptEnabled = 1;
                if (pm->ps->weaponState != WEAPON_STATE_DEPLOYING &&
                    pm->ps->weaponState != WEAPON_STATE_BREAKING_DOWN) {
                    BG_PlayAnim(pm->ps, 0, 2, 0, 0, 1, 1);
                }
                pm->ps->playerStateFlags |= 0x2000;
                pm->ps->pmTime = PM_WALLJUMP_TIMER_NEAR_GROUND;
            }
        }
    }

    PM_ViewHeightAdjust();

    /* Set maxs[2] and entityStateFlags based on effective stance */
    effectiveStance = PM_GetEffectiveStance(pm->ps);
    if (effectiveStance == 1) {
        if ((pm->ps->playerStateFlags & 3) == 0) {
            pm->maxs[2] = pm->ps->playerMaxs[2];
        } else if ((pm->ps->playerStateFlags & 2) == 0) {
            pm->maxs[2] = 30.0f;
        } else {
            pm->maxs[2] = 50.0f;
        }
        pm->ps->entityStateFlags |= 0x40;
        pm->ps->entityStateFlags &= ~0x20u;
    } else if (effectiveStance == 2) {
        if ((pm->ps->playerStateFlags & 3) == 0) {
            pm->maxs[2] = pm->ps->playerMaxs[2];
        } else {
            pm->maxs[2] = 50.0f;
        }
        pm->ps->entityStateFlags |= 0x20;
        pm->ps->entityStateFlags &= ~0x40u;
    } else {
        pm->maxs[2] = pm->ps->playerMaxs[2];
        pm->ps->entityStateFlags &= ~0x60u;
    }

    /* Update body model index */
    if ((pm->ps->playerStateFlags & 1) == 0) {
        /* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - actual non-prone state writes pmove+0x104 from the overhead trace slot at pmove+0x10c. */
        pm->trace = pm->trace3;
        pm->ps->entityStateFlags |= PS_FLAG_STANCE_VALID;
    } else {
        /* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - actual prone state writes pmove+0x104 from the ADS/wall trace slot at pmove+0x108. */
        pm->trace = pm->trace2;
        pm->ps->entityStateFlags |= PS_FLAG_STANCE_VALID;

        if (wasProne == 0) {
            /* Clear ADS if moving */
            if (PM_FORWARDMOVE(pm) != 0 || PM_RIGHTMOVE(pm) != 0) {
                pm->ps->playerStateFlags &= ~0x400u;
                PM_ClearAimDownSightFlag();
            }

            /* VERIFIED_DECOMPILER(0x27e16, 37e16_FUN_00037e16.c, VERIFY-P1-MOVEMENT-2026-06-17): DATAFLOW_VERIFIED - first-prone entry traces from current origin upward by 10, then back down, using pmove +0x108. */
            start[0] = pm->ps->psOrigin[0];
            start[1] = pm->ps->psOrigin[1];
            start[2] = pm->ps->psOrigin[2];
            end[0] = pm->ps->psOrigin[0];
            end[1] = pm->ps->psOrigin[1];
            end[2] = pm->ps->psOrigin[2] + 10.0f;
            pm->trace2(&trace, start, pm->mins, pm->maxs,
                       end, pm->ps->psClientNum,
                       pm->traceMask & ~(int32_t)CONTENTS_BODY);
            start[0] = trace.endpos[0];
            start[1] = trace.endpos[1];
            start[2] = trace.endpos[2];
            end[0] = pm->ps->psOrigin[0];
            end[1] = pm->ps->psOrigin[1];
            end[2] = pm->ps->psOrigin[2];
            pm->trace2(&trace, start, pm->mins, pm->maxs,
                       end, pm->ps->psClientNum,
                       pm->traceMask & ~(int32_t)CONTENTS_BODY);
            pm->ps->psOrigin[0] = trace.endpos[0];
            pm->ps->psOrigin[1] = trace.endpos[1];
            pm->ps->psOrigin[2] = trace.endpos[2];

            pm->ps->proneDirection = pm->ps->viewAngles[1];

            /* Ground trace for prone pitch */
            start[0] = pm->ps->psOrigin[0];
            start[1] = pm->ps->psOrigin[1];
            start[2] = pm->ps->psOrigin[2];
            end[0] = pm->ps->psOrigin[0];
            end[1] = pm->ps->psOrigin[1];
            end[2] = pm->ps->psOrigin[2] - 0.25f;
            pm->trace2(&trace, start, pm->mins, pm->maxs,
                       end, pm->ps->psClientNum,
                       pm->traceMask & ~(int32_t)CONTENTS_BODY);
            /* 0x29205..0x2921d: stock calls PitchForYawOnNormal only when
             * startsolid is clear and the ordered fraction is below 1.0f;
             * an unordered fraction follows the zero-pitch path. */
            if (!trace.startsolid && trace.fraction < 1.0f) {
                pm->ps->proneDirectionPitch =
                    PitchForYawOnNormal(pm->ps->proneDirection, trace.normal);
            } else {
                pm->ps->proneDirectionPitch = 0.0f;
            }

            /* Clamp body pitch into the live prone pitch offset. */
            {
                float delta = AngleDelta(pm->ps->proneDirectionPitch,
                                         pm->ps->viewAngles[0]);
                if (delta < -45.0f) {
                    pm->ps->proneTorsoPitch = pm->ps->viewAngles[0] - 45.0f;
                } else if (delta > 45.0f) {
                    pm->ps->proneTorsoPitch = pm->ps->viewAngles[0] + 45.0f;
                } else {
                    pm->ps->proneTorsoPitch = pm->ps->proneDirectionPitch;
                }
            }
        }
    }
}

/* ================================================================== */
/*  0x2d530  PmoveSingle                                              */
/* ================================================================== */

/* VERIFIED_DECOMPILER(0x2d530, 3d530_PmoveSingle.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - command sanitization, prone/ADS and sprint interrupts, stance movement clears, frame state setup, prone override clear, mode dispatch, and velocity snap checked. */
static void PmoveSingle(pmove_t *pmove)
{
    int pmType;
    int effectiveStance;
    vec3_t deltaOrigin;
    float deltaSpeedSq;
    float velocitySpeedSq;

    /* Update animation state conditions */
    BG_AnimUpdatePlayerStateConditions(pmove);

    pm = pmove;
    c_pmove++;

    pmove->overheadContents = 0;
    pmove->overheadLevel = 0;

    /* Handle PMF_FOLLOW flag */
    if ((pm->ps->playerStateFlags & 0x4000) != 0) {
        /* VERIFIED_DECOMPILER(0x2d530, 3d530_PmoveSingle.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - follow flag clears button byte0, masks button byte1 with 0xc2, then clears movement bytes. */
        PM_BUTTON_BYTE0(pmove) = 0;
        PM_BUTTON_BYTE1(pmove) &= 0xc2;
        PM_FORWARDMOVE(pmove) = 0;
        PM_RIGHTMOVE(pmove) = 0;
        PM_UPMOVE(pmove) = 0;
    }

    /* Handle jump button held */
    if ((PM_BUTTON_BYTE0(pmove) & 2) != 0) {
        /* VERIFIED_DECOMPILER(0x2d530, 3d530_PmoveSingle.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - button byte masks at pmove+0x08/+0x09 precede movement byte clears at pmove+0x18..+0x1a. */
        PM_BUTTON_BYTE0(pmove) &= 0x12;
        PM_BUTTON_BYTE1(pmove) &= 0xc2;
        PM_FORWARDMOVE(pmove) = 0;
        PM_RIGHTMOVE(pmove) = 0;
        PM_UPMOVE(pmove) = 0;
    }

    pm->ps->playerStateFlags &= ~0x8000u;

    pmType = pm->ps->pmType;
    if (pmType > PM_TYPE_INTERMISSION) {
        pm->traceMask &= ~(int32_t)CONTENTS_BODY;
    }

    pml.weaponInfo = BG_GetInfoForWeapon(pm->ps->currentWeapon);

    /* Prone / ADS interruption logic */
    if ((pm->ps->playerStateFlags & 1) == 0) {
        pm->ps->playerStateFlags &= ~0x400u;
    } else if ((PM_FORWARDMOVE(pm) != PM_OLD_FORWARDMOVE(pm) &&
                Q_ABS((int16_t)PM_OLD_FORWARDMOVE(pm)) <
                Q_ABS((int16_t)PM_FORWARDMOVE(pm))) ||
               (PM_RIGHTMOVE(pm) != PM_OLD_RIGHTMOVE(pm) &&
                Q_ABS((int16_t)PM_OLD_RIGHTMOVE(pm)) <
                Q_ABS((int16_t)PM_RIGHTMOVE(pm)))) {
        if (PM_InteruptWeaponWithProneMove() != 0) {
            pm->ps->playerStateFlags &= ~0x400u;
            PM_ClearAimDownSightFlag();
        }
    } else if (((pm->ps->playerStateFlags & PM_STANCE_ADS) == 0) &&
               (pm->ps->weaponState == WEAPON_STATE_IDLE ||
                pm->ps->weaponState == WEAPON_STATE_RAISING ||
                pm->ps->weaponState == WEAPON_STATE_DROPPING ||
                pm->ps->weaponState == WEAPON_STATE_RELOADING)) {
        pm->ps->playerStateFlags &= ~0x400u;
    }

    /* Sprint interruption */
    if ((pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) != 0) {
        PM_InteruptWeaponWithSprintMove();
    }

    effectiveStance = PM_GetEffectiveStance(pm->ps);

    if (((pm->ps->playerStateFlags & PM_STANCE_ADS) != 0) && effectiveStance == 1) {
        PM_FORWARDMOVE(pmove) = 0;
        PM_RIGHTMOVE(pm) = 0;
    }

    if ((pm->ps->playerStateFlags & PM_STANCE_ADS) != 0) {
        if (((const weaponInfo_t *)BG_GetInfoForWeapon(pm->ps->currentWeapon))->weaponClass ==
            WEAPCLASS_LMG) {
            PM_FORWARDMOVE(pmove) = 0;
            PM_RIGHTMOVE(pm) = 0;
        }
    }

    /* ADS flag management */
    if ((PM_BUTTON_BYTE0(pmove) & 2) == 0) {
        pm->ps->entityStateFlags &= ~PS_FLAG_ADS_HELD;
    } else {
        pm->ps->entityStateFlags |= PS_FLAG_ADS_HELD;
    }

    pm->ps->entityStateFlags &= ~0x200u;

    if (pm->ps->pmType != PM_TYPE_INTERMISSION &&
        (pm->ps->playerStateFlags & 0x800u) == 0 &&
        (pm->ps->weaponState == WEAPON_STATE_IDLE ||
         pm->ps->weaponState == WEAPON_STATE_FIRING) &&
        PM_WeaponAmmoAvailable(pm->ps->currentWeapon) != 0 &&
        (pm->ps->playerStateFlags & PM_STANCE_FATIGUE_DRAIN) == 0 &&
        (PM_BUTTON_BYTE0(pmove) & PMOVE_BUTTON_FIRE) != 0) {
        pm->ps->entityStateFlags |= 0x200;
    }

    if (pmType < PM_TYPE_DEAD && (PM_BUTTON_BYTE0(pmove) & 1) == 0) {
        pm->ps->playerStateFlags &= ~0x800u;
    }

    /* Initialize pml */
    memset(&pml, 0, sizeof(pml));

    pml.msec = pmove->command.commandTime - pm->ps->commandTime;
    if (pml.msec < 1) pml.msec = 1;
    else if (pml.msec > 200) pml.msec = 200;

    pm->ps->commandTime = pmove->command.commandTime;

    pml.previousOrigin[0] = pm->ps->psOrigin[0];
    pml.previousOrigin[1] = pm->ps->psOrigin[1];
    pml.previousOrigin[2] = pm->ps->psOrigin[2];
    pml.previousVelocity[0] = pm->ps->velocity[0];
    pml.previousVelocity[1] = pm->ps->velocity[1];
    pml.previousVelocity[2] = pm->ps->velocity[2];

    pml.frametime = (float)pml.msec * 0.001f;

    pml.weaponInfo = BG_GetInfoForWeapon(pm->ps->currentWeapon);

    PM_AdjustAimSpreadScale();
    PM_UpdateViewAngles(pm->ps, PM_CURRENT_COMMAND(pmove), pmove->trace3);
    AngleVectors((float *)&pm->ps->viewAngles[0], pml.forward, pml.right, pml.up);

    if (PM_UPMOVE(pm) < 10) {
        pm->ps->playerStateFlags &= ~0x8u;
    }

    if (PM_FORWARDMOVE(pm) < 0) {
        pm->ps->playerStateFlags |= 0x40;
    } else if (PM_FORWARDMOVE(pm) > 0 ||
               (PM_FORWARDMOVE(pm) == 0 && PM_RIGHTMOVE(pm) != 0)) {
        pm->ps->playerStateFlags &= ~0x40u;
    }

    if (pmType > PM_TYPE_INTERMISSION) {
        PM_FORWARDMOVE(pm) = 0;
        PM_RIGHTMOVE(pm) = 0;
        PM_UPMOVE(pm) = 0;
    }

    /* VERIFIED_DECOMPILER(0x2d530, 3d530_PmoveSingle.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - prone movement override clears forward/right move after view-angle update and pmType>5 command zeroing. */
    if (effectiveStance == 1 && (pm->ps->playerStateFlags & 0x400) != 0) {
        PM_FORWARDMOVE(pm) = 0;
        PM_RIGHTMOVE(pm) = 0;
    }

    /* Dispatch based on pmType */
    switch (pm->ps->pmType) {
    default:
    case PM_TYPE_NORMAL:
        if ((pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) == 0) {
            PM_SetWaterLevel();
            pml.previousOverheadLevel = (int)pmove->overheadLevel;
            PM_CheckDuck();
            PM_GroundTrace();
            PM_UpdateAimDownSightFlag();
            PM_UpdatePlayerWalkingFlag();
            PM_UpdatePlayerSprintingFlag();
            PM_UpdatePronePitch();

            if (pm->ps->pmType == PM_TYPE_DEAD) {
                PM_DeadMove();
            }

            PM_CheckLadderMove();
            PM_DropTimers();
            PM_UpdateFatigue();

            if ((pm->ps->playerStateFlags & PM_STANCE_LADDER) == 0) {
                if (pml.groundPlane == 0) {
                    PM_AirMove();
                } else {
                    PM_WalkMove();
                }
            } else {
                PM_LadderMove();
            }

            PM_GroundTrace();
            PM_SetWaterLevel();
            PM_Footsteps();
            PM_Weapon();
            PM_FoliageSounds();
            PM_WaterEvents();

            /* Sanitize velocity */
            deltaOrigin[0] = pm->ps->psOrigin[0] - pml.previousOrigin[0];
            deltaOrigin[1] = pm->ps->psOrigin[1] - pml.previousOrigin[1];
            deltaOrigin[2] = pm->ps->psOrigin[2] - pml.previousOrigin[2];

#if EMULATE_X87
            deltaSpeedSq = x87f_store_f32(x87f_div(
                MDOT3X(deltaOrigin[0], deltaOrigin[0], deltaOrigin[1],
                          deltaOrigin[1], deltaOrigin[2], deltaOrigin[2]),
                x87f_mul(x87f_load_f32(pml.frametime),
                         x87f_load_f32(pml.frametime))));
            velocitySpeedSq = x87f_store_f32(MDOT3X(
                pm->ps->velocity[0], pm->ps->velocity[0], pm->ps->velocity[1],
                pm->ps->velocity[1], pm->ps->velocity[2], pm->ps->velocity[2]));
#else
            deltaSpeedSq = (deltaOrigin[0] * deltaOrigin[0] +
                            deltaOrigin[1] * deltaOrigin[1] +
                            deltaOrigin[2] * deltaOrigin[2]) /
                           (pml.frametime * pml.frametime);
            velocitySpeedSq = pm->ps->velocity[0] * pm->ps->velocity[0] +
                              pm->ps->velocity[1] * pm->ps->velocity[1] +
                              pm->ps->velocity[2] * pm->ps->velocity[2];
#endif

            /* NO shim on the compare: 0.25f is a power of two so the product is
             * exact in float (exponent shift only), identical on x87/SSE; stock
             * also spills it to a float (0x6eaed) (rule 6). The velocity writes
             * below DO need the shim. */
            if (deltaSpeedSq < velocitySpeedSq * 0.25f) {
#if EMULATE_X87
                for (int i = 0; i < 3; i++) {
                    pm->ps->velocity[i] = x87f_store_f32(x87f_mul(
                        x87f_load_f32(deltaOrigin[i]),
                        x87f_div(x87f_load_f32(1.0f),
                                 x87f_load_f32(pml.frametime))));
                }
#else
                pm->ps->velocity[0] = deltaOrigin[0] * (1.0f / pml.frametime);
                pm->ps->velocity[1] = deltaOrigin[1] * (1.0f / pml.frametime);
                pm->ps->velocity[2] = deltaOrigin[2] * (1.0f / pml.frametime);
#endif
            }

            trap_SnapVector((float *)&pm->ps->velocity[0]);
        } else {
            /* Vehicle / special state */
            pm->ps->playerStateFlags &= ~0x10u;
            pm->ps->groundEntityNum = ENTITYNUM_NONE;
            pml.waterlevel  = 0;
            pml.waterlevel2 = 0;
            pml.groundPlane = 0;

            PM_UpdateAimDownSightFlag();
            PM_UpdatePlayerWalkingFlag();
            PM_UpdatePlayerSprintingFlag();
            PM_CheckDuck();
            PM_DropTimers();
            PM_UpdateFatigue();

            if (BG_AllowPlayerWeaponAtVehiclePos(pm->ps->vehicleType,
                                                  pm->ps->vehiclePosition) == 0) {
                PM_UpdateAimDownSightLerp();
            } else {
                PM_Weapon();
            }

            PM_Footsteps();
        }
        break;

    case PM_TYPE_LINKED:
    case PM_TYPE_LINKED_DEAD:
        pm->ps->playerStateFlags &= ~0x10u;
        pm->ps->groundEntityNum = ENTITYNUM_NONE;
        pml.waterlevel  = 0;
        pml.waterlevel2 = 0;
        pml.groundPlane = 0;

        PM_UpdateAimDownSightFlag();
        PM_UpdatePlayerWalkingFlag();
        PM_UpdatePlayerSprintingFlag();
        PM_CheckDuck();
        PM_DropTimers();
        PM_UpdateFatigue();

        if ((pm->ps->entityStateFlags & PS_FLAG_FIRE_POSITION_CHECK_MASK) == 0 ||
            BG_AllowPlayerWeaponAtVehiclePos(pm->ps->vehicleType,
                                              pm->ps->vehiclePosition) != 0) {
            PM_Weapon();
        } else {
            PM_UpdateAimDownSightLerp();
        }

        PM_Footsteps();
        break;

    case PM_TYPE_NOCLIP:
        pm->ps->playerStateFlags &= ~0x10u;
        PM_UpdateAimDownSightFlag();
        PM_UpdatePlayerWalkingFlag();
        PM_UpdatePlayerSprintingFlag();
        PM_NoclipMove();
        PM_Weapon();
        PM_DropTimers();
        PM_UpdateFatigue();
        break;

    case PM_TYPE_UFO:
        pm->ps->playerStateFlags &= ~0x10u;
        PM_UpdateAimDownSightFlag();
        PM_UpdatePlayerWalkingFlag();
        PM_UpdatePlayerSprintingFlag();
        PM_UFOMove();
        PM_Weapon();
        PM_DropTimers();
        PM_UpdateFatigue();
        break;

    case PM_TYPE_SPECTATOR:
        pm->ps->playerStateFlags &= ~0x10u;
        PM_UpdateAimDownSightFlag();
        PM_UpdatePlayerWalkingFlag();
        PM_UpdatePlayerSprintingFlag();
        PM_CheckDuck();
        PM_FlyMove();
        PM_DropTimers();
        PM_UpdateFatigue();
        break;

    case PM_TYPE_INTERMISSION:
        pm->ps->playerStateFlags &= ~0x10u;
        break;
    }
}

/* ================================================================== */
/*  0x2e1c7  Pmove                                                    */
/* ================================================================== */

/* VERIFIED_DECOMPILER(0x2e1c7, 3e1c7_Pmove.c, VERIFY-WAVE2-MOVEMENT-PRONE-2026-06-17): DATAFLOW_VERIFIED - command-time guard/window clamp, chunk loop bounds, PmoveSingle call, jump-held upmove, and pm clear checked. */
void Pmove(pmove_t *pmove)
{
    int startTime;
    int currentTime;
    int timeDelta;

    startTime = pmove->command.commandTime;
    currentTime = startTime;

    if (pmove->ps->commandTime > currentTime) {
        return;
    }

    if (pmove->ps->commandTime + 1000 < currentTime) {
        pmove->ps->commandTime = currentTime - 1000;
    }

    pm = pmove;
    pm->numtouch = 0;

    while (pmove->ps->commandTime != currentTime) {
        timeDelta = currentTime - pmove->ps->commandTime;

        if (pmove->pmove_msec_min == 0) {
            if (timeDelta > 66) {
                timeDelta = 66;
            }
        } else {
            if (timeDelta > pmove->pmove_msec_max) {
                timeDelta = pmove->pmove_msec_max;
            }
        }

        pmove->command.commandTime = pmove->ps->commandTime + timeDelta;
        PmoveSingle(pmove);

        if ((pmove->ps->playerStateFlags & PM_STANCE_JUMP_HELD) != 0) {
            PM_UPMOVE(pmove) = 20;
        }
    }

    pm = NULL;
}
