Last server records
Pro Nub

CountJump physics

Posted by Kpoluk 9 Jan 2019 in 17:30
First of all, let's look into how duck works. In the article about bhop physics in the beginning of the function PM_PlayerMove you could notice the call of PM_Duck. Let's see what happens in it:

The IN_DUCK bit is set and reset the same way as IN_JUMP, except that instead of the commands +jump and –jump its state is determined by +duck and –duck. In addition to it, several other variables appear in PM_Duck, describing the state of the player. For example, pmove->bInDuck equals true during the process of ducking. As soon as the player is in a sitting position, the flag FL_DUCKING is set in the variable pmove->flags, and the variable pmove->usehull becomes 1, which means changing the physical size of the model. To better understand the relationship of these parameters, we are going to consider several situations.

Ducking and Unducking

Standing on a flat surface, we press the duck button, thereby sending the command +duck. In the same frame the IN_DUCK bit is set in pmove->cmd.buttons, and the variable pmove->bInDuck becomes true. During the next 0.4 seconds (40 frames at 100 fps) the eyes level will be lowered, and the vertical coordinate the player's center pmove->origin[2] will remain unchanged. And only after this time has elapsed, the player’s origin will move down by 18 units, the model will switch to a sitting position, the FL_DUCKING flag will be set, and pmove->bInDuck will become false.

Staying in a sitting position, we begin to move forward. The article about strafe physics suggests that holding down the W key gives pmove->cmd.forwardmove = 250, so that inside the PM_Duck function we get pmove->cmd.forwardmove = 250 * 0.333 = 83.25 unit/s (about 3 times less). This is the speed we are moving in duck with.

When we release the duck button sending –duck command, PM_UnDuck function is called:

Here the engine tries with the help of the trace to move us 18 units up, firstly in a sitting position, and then in a standing one. If successful, along with the change of our origin we have the eyes level lifted abruptly, the flag FL_DUCKING and the variable pmove->usehull are reset, and pmove->bInDuck becomes false.

In the air ducking happens in one frame, during which pmove->bInDuck switches to true and back to false, the eyes level changes from 17 to 12 units above the origin, while there is no downward movement by 18 units. The transition to a standing position also takes place in one frame and without lifting by 18 units.

Decreasing the variables pmove->cmd.forwardmove and pmove->cmd.sidemove in a sitting position reduces the gain of the velocity vector (recall the functions PM_AirMove and PM_AirAccelerate, which we discussed in the article about strafe physics), so it becomes more difficult to get more speed or even simply change its direction in the air. At that in order to obtain the greatest gain, the mouse will have to be driven more smoothly than in a standing position.

Stand-Up Bhop

Now we can understand how stand-up bhop works. In flight we press the duck switching into a sitting position in one frame. As we have just found out, in this position it becomes more difficult to pick up speed. Approaching the ground we release the duck, thereby calling PM_UnDuck. With the help of the trace it checks if the model is stuck somewhere when you switch it into a standing position. While we are near the ground, the stuck is guaranteed, so after the trace PM_UnDuck does nothing. The flag FL_DUCKING is not reset, the speed is still gained with difficulty.

When we finally find ourselves on the ground, the trace comes to a point that is 18 units above the player’s origin (that is, the function checks to see if something will prevent us from standing up). If we were in the tunnel, then we would not be able to get up, and we would have done the usual bhop in a duck. However, if nothing gets in the way, and we will immediately stand up. Regardless of whether we jump into the same frame or later, PM_Jump will be called after PM_Duck, so the jump will occur from a standing position, as if there was no sitting. Actually it is acceptable to release the duck button right on the ground, the main thing is that this should happen no later than the frame with the jump command. But of cours, it is safer to do this a little in advance cause it does not affect physics anyway.

Scroll Duck

While on the ground, we try to make scroll duck. From the point of view of the engine, this will look as the command +duck;-duck, which will lead to setting the IN_DUCK bit in the pmove->cmd.buttons variable, so the process of ducking will begin in PM_Duck, the eyes level will go down a little. If we were running at a speed of v, then, according to the article about strafe physics, a call of PM_Friction would take away 4% of v, and PM_Accelerate would not give any gain (since addspeed = wishspeed - currentspeed = v * 0.333 - (v - v * 0.04) <0). For example, when running forward with W the speed would decrease from 250 to 240 units/s.

At the next frame, the IN_DUCK bit is already zeroed, so the function PM_UnDuck is called, which throws us 18 units up. It turns out that instead of ducking we did something like a small jump. And the most remarkable thing about this mini-jump is that it does not affect the variable fuser2, which was discussed in the article about the bhop physics. Thanks to this, CS gives us some interesting tricks:

1) double duck

You can climb stair of 18 units high or below without additional actions, while higher stairs will require a jump. According to the estimate of the jump height at zero fuser2 given in the article about bhop physics, we can jump onto boxes up to 45 units high (and subsequent duck increases this value to 45 + 18 = 63 units). After jumping on the box fuser2 will be greater than zero, which will slow down our futher movement.

However, if instead of a jump we make a scroll duck, and then hold down the duck key, this will allow us to climb obstacles up to 35 units high without affecting fuser2! In other words, climbing along such stairs can be accomplished almost without loss of speed (except for 4% taken away by PM_Friction). This technique is called double duck (or simply dd), although in practice scroll duck is also called dd.

2) landing with dd

If in flight we gained a high enough speed, then after landing, PM_Friction will start to cut it pretty quickly. We can weaken this process if, once on the ground, we do dd. This will "transfer" some frames to the air, where PM_Friction cannot do anything to us. Depending on the situation, under dd you can mean a scroll duck paired with a regular duck, a single scroll duck or a series of scroll ducks done in a row (note that too fast scrolling makes no sense in such a situation, since commands will “stick together” and give the effect of a regular squat).

3) CountJump and DoubleCountJump

When running on a flat surface, the scroll duck lifts us into the air by 18 units, after which we fall about 0.21 seconds (21 frames at 100 fps). In this short time we can not only compensate losses from calling PM_Friction, but also gain additional speed with the help of strafes. If you make a jump immediately after landing, then on the one hand, due to zero fuser2, it will be as long and high as LongJump, and on the other hand, the horizontal speed after it can reach 299.973 units/s, as we found out in the article about bhop physics. This combination not only gives a significant increase in the distance, but allows you to effectively deal with the edgefriction described in the article about HighJump physics. This technique received its name CountJump in honor of the Count who discovered it.

In practice, even with a good acceleration before the scroll duck, it's very hard to reach a speed of almost 300 units/s during 21 frames, so the idea was to make the scroll duck and gain the speed in the air twice. As you know, this technique was called DoubleCountJump. If strafe after each of the scroll ducks is made at the same direction, then prestrafe and air strafes are made in opposite directions, so this is called 180° DoubleCountJump.

This is how the first dcj records were done, but in practice it is quite difficult to find a map where the use of 180° dcj would make sense. It turned out to be more useful to do Straight DoubleCountJump, when you change the direction of strafe on the second scroll duck, so that the prestrafe and air strafes are made in the same direction.

It is also worth noting that a similar physics at the moment of the jump (and therefore a potential distance) can be obtained with the help of other techniques. It is enough for this that fuser2 is zero i. e. the previous jump was made earlier than 1.31 seconds ago. For example, DropBhop with a long enough drop or WeirdJump fit this description.

4) GroundStrafe

Before jumping you can do not just one or two, but any number of dds (here by dd we mean jumping with a scroll duck and subsequent staying in the air). However, maintaining speed while doing dds is not so easy. If you make a scroll duck not at the first frame on the ground, but later, then PM_Friction will inevitably take from you even more speed. Of course, as in the case of bhop, you can send several commands at once by scrolling, but then you need to be prepared for the fact that there will be less time for returning the used finger to its original position.

In addition to the late scroll duck, too early one may dangerous too. Indeed, if the scroll duck was made one frame before we land on the ground, then PM_UnDuck called at the next frame would find that the model would get stuck in the ground, which means that model should remain in a sitting position. And then we, just like during stand-up bhop, will continue to fall to the ground in a duck.

Before moving on, let's say a few words about terminology. The dd series is usually called dd run. There was also a suggestion to call it GroundStrafe (or just gs or gstrafe). If we make a jump at the end of dd run, then we get MultiCountJump. In addition to these names, you can meet the term sgs, which stands for Stand-Up GroundStrafe. Often the concepts of gs and sgs are mixed, however, generally speaking, they are different techniques. With sgs you do full double ducks, i. e. alternate scroll ducks on the ground and squats in the air. It gives the same effect with falling to the ground in a duck, which was described above, but here it happens intentionally. As in the case of stand-up bhop, ducking makes it difficult to pick up speed, but allows you not to touch the ground for longer. But actually sgs has one important feature - after landing you need at least one frame to get up, and only after it you can do a scroll duck. That is, we touch the ground less often than with gs, but spend more time on it. From this we can conclude that sgs may be more practical than gs at high horizontal speeds or in the case of a specific relief.

As an example we can take the map smk_hnseu_airstrafes. Korean guy LeblE in his demo (download) used gs, while Romanian jumper brokoly showed a run with sgs (download). Also we cannot ignore a special way of performing dd run by prize, who instead of separate scrollings did one movement of his hand over the scroll from the tip of his finger to almost the elbow (download).

In general, dd run can be used instead of normal running or fastrun, but maintaining a high enough speed (at least more than 250-260 units/s) will require a lot of training. At the same time, the top speed is not limited to 300 units/s, although it will not greatly exceed this value unless using sv_airaccelerate 100, which, although used on some servers, is illegal (as we recall from the strafe physics, by default cvar sv_airaccelerate is set to 10). Our friend rawe agreed to show the usual dd run on the standard map de_nuke (download).

Maximum prestrafe

Everyone knows that DoubleCountJump can give us prestrafe of more than 300 units/s, but what about CountJump? In the article about strafe physics we found that to maintain optimal angle u (that maximizes the speed) we need to move our mouse about 5 degrees per frame. That is for one 21-frame dd the turn is 105 degrees. Also in the article about LongJump physics we learned that speed at that is changing like Vnew = sqrt(V^2 + 875). If we take 277 units/s as maximum prestrafe before dd, plus take into account 4% taken away by PM_Friction (which leaves us 265.92 units/s), than after 21 frames we reach 298.48 units/s - this is approximate value of maximum CountJump prestrafe. For comparison FAME on his 270 block had 263.89 units/s before dd and 293.25 unit/s at the moment of jump.

But what if we use Stand-Up CountJump, i.e. CountJump with duck at the end of dd, which gives us 9 more frames in air? With pressed duck in PM_AirAccelerate we find that wishspeed = 250 * 0.333, so the optimal angle u = arccos(8.325 / V), from where reproducing calculations from the article about LongJump physics we obtain the formula for speed change: Vnew = sqrt(V^2 + 830.69). Supposing we've spent in air 20 frames without duck and 10 frames with duck, we come to more than 310 unit's at the moment of jump which is more then 300 with big reserve.

And one more interesting estimation. If we could maintain optimal u during gstrafe (recall that we also need to switch strafes to avoid spinning on one spot, which makes this example absolutely unreal), than we would reach 464 units/s - starting from this speed all gain of one dd is taken away by PM_Friction.

Duck in confined places

Since the height of the model in the standing position is 72 units, the minimum height of the tunnel in which we can walk is 73 units. The sitting height is two times less, so in this case the minimum height of the tunnel will be 37 units. If we sit down and try to jump in a tunnel with a height of 73 units, then we will definitely hit the ceiling with our head, since the jump height at zero fuser2 is 45 units (36 + 45 = 81 > 73). Interestingly, in the same tunnel we can jump from a standing position if we hold the duck in advance. Indeed, as we found out earlier, after setting the IN_DUCK bit, we have 0.4 seconds, during which the center of the model will remain at the same height. If at this time we make the jump, then after calling PM_Jump we will be in the air, and right at the next frame without hitting our head we will switch to a sitting position in PM_Duck. Sadly, we will not fly long, because up to the ceiling there will be only 73 - 36 - 18 = 19 units left. Nevertheless, this reserve gives us the ability to jump out from under the overhang, which turns out to be very useful on kz maps.

And now let us ask ourselves a question - what will happen if we make a scroll duck standing in a tunnel? The tunnel with a height of 91 units and above will not create problems for us, but at a height of 73 to 90 units we will get into a tough situation: first, PM_Duck will start ducking, setting the variable pmove->bInDuck to true, and at the next frame PM_UnDuck will find that it is not possible to raise the model by 18 units upwards, so pmove->bInDuck will stay true. In subsequent calls, PM_Duck will think that we are in the process of ducking, and therefore slow us down. At that the slowdown will not disappear until we press the duck button and completely sit down. You can also simply “crawl out” of the tunnel, then PM_UnDuck will finally throw us 18 units up, setting pmove->bInDuck to false.

Duck will be also important to us in the next article dedicated to EdgeBug and JumpBug.