CoD4 - Double Bounce

There are 2 variables in the playerState_s struct: jumpOriginZ and pm_flags that are assigned new values upon hitting the ground or a slope. These new values prevent PM_StepSlideMove from executing specific parts of it that makes bouncing possible in the first place.

  • jumpOriginZ
    • saves the max. z-origin for your current jump (current z-origin + jump_height dvar (probably for prediction))
    • the value gets saved till one hits a slope or a groundEntity and will get reset after around 2 seconds
  • pm_flags
    • saves a flag, lets call it “Jumped-And-In-Air” ( 0x4000 ) when you perform a legit jump
    • the flag gets saved till one hits a slope or a groundEntity.

Lets assume we are on CoD4 and the current z-origin of the player is 1000.0f. The player is aiming for a bounce and at the moment he initiates the jump:
jumpOriginZ contains 1039.0f ( z-origin (1000.0f) + jump_height (39)) and pm_flags contains the Jumped-And-In-Air flag.

Now if he hits the slope correctly, PM_StepSlideMove will do its thing and initiate the bounce when jumpOriginZ is higher then the current z-origin and if he still has the Jumped-And-In-Air flag set. But with that, PM_GroundTrace gets called from within PM_StepSlideMove and resets these two variables in the playerState. These 2 values now prevent PM_StepSlideMove from executing PM_ProjectVelocity (the function responsible for bouncing).

Now to enable double bouncing, one has to disable the resets for these two variables within PM_GroundTrace by nopping them (0x90). This will alter the flow of execution to a point where PM_StepSlideMove thinks that the player just jumped, so it will always execute PM_ProjectVelocity.

​Part of PM_GroundTrace

if ( trace.walkable )
{
    pml->groundPlane = 1;
    pml->almostGroundPlane = 1;
    pml->walking = 1;

    if ( ps->groundEntityNum == 1023 )
        PM_CrashLand(pm, pml);

    ps->groundEntityNum = Trace_GetEntityHitId(&trace);
    PM_AddTouchEnt(pm, ps->groundEntityNum);
}
else
{
    ps->groundEntityNum = 1023;
    pml->groundPlane = 1;
    pml->almostGroundPlane = 1;
    pml->walking = 0;

    ps->pm_flags &= 0xFFFFBFFF; // would be the function Jump_ClearState(ps); // nop
    ps->jumpOriginZ = 0.0f;     // but its inlined in cod4                    // nop
}

There are obv. multiple ways of getting this to work. This way has some side effects like getting stuck on blockbounces or the slowdown-timer taking longer to reset. Latter happens because the slowdown-timer would normally start when one has hit the first bounce wherever now it starts counting down when the player walks on the ground.

Check out MW2 Bouncing for more info on how bounces work in general.