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 course, it is safer to do this a little in advance so as not to accidentally be late.
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. Moreover active scrolling can lead to a full squat. Let's discuss this point in a little more detail.
Если в 21-ый фрейм сделать scroll duck, то моделька окажется в приседе, и телепорт в конце этого фрейма не сработает, зато сработает после вставания модельки в начале следующего фрейма (при этом
PM_Friction в 22-ой фрейм всё равно будет вызвана, так что количество фреймов в воздухе можно считать неизменным). Однако если мы при активной прокрутке скролла сделали scroll duck ещё и в 22-ой фрейм, то вызванная в следующем 23-ем фрейме функция
If you look at the change in vertical speed during a double duck, then the suspicion creeps in that we must spend more than 21 frames in the air. The point here is that when we find ourselves at a distance of less than 2 units from the ground, a special function is called that teleports us to the ground (we will talk more about it in the article about the physics of EdgeBug and JumpBug). If you do a scroll duck in the 21st frame, then the model will be in a duck state, and the teleport at the end of the frame won't work, but it will work after the model stands up at the start of the next frame (at that
PM_Friction still will be called in the 22nd frame, so we can consider the number of air frames to be the same). However, if, while actively scrolling, we use scroll duck into the 22nd frame as well, then the
PM_UnDuck function called in the next 23rd frame will detect that standing model would stuck in the ground, which means the model should remain in a sitting position, and we will continue to fall to the ground in duck just like in a stand-up bhop.
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 (in terms of jump statistics plugin the minimal number of FOG, i.e. frames on the ground, is 2 for gs and 3 for sgs). 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.