Skip to content
Quake/GoldSrc like movement in TF2
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

[TF2] Classic Movement


This Sourcemod plugin brings back movement as it was in Quake or Half Life 1 based games. It feels and behaves almost exactly like the original.


  • Wallstrafing
  • (Proper) Strafe jumps
  • Bunnyhopping
  • Jumping while being fully crouched
  • Double ducking
  • Small speedboosts when changing direction
  • Whatever movement results by combining any of these above

You can find the AlliedModders thread here.



Download classicmovement.smx or compile it yourself and move it into your addons/sourcemod/plugins/ folder.


The configuration file is located at cfg/sourcemod/plugin.classicmovement.cfg. It will be autogenerated when the plugin is loaded for the first time.

The following convars exist:

Variable Default Description
classicmovement_version 1.0.0 Contains the plugin version (is a constant and can't be changed).
cm_enabled 1 Enable/Disable the plugin.
cm_speedo 0 Show speedometer by default.
cm_duckjump 1 Allow jumping while being fully crouched.
cm_doubleduck 1 Allow double ducking. Might make snipers become unemployed (see here).
cm_speedcap -1 The maximum speed players can reach. -1 for unlimited.
cm_use_nice_hud 1 Whether or not to use a prettier speedometer display.
cm_hud_color "255 255 0" Speedometer HUD color. Whitespace separated red, green, blue values.
Works only if cm_use_nice_hud is enabled.
cm_allow_autohop 1 Allow users to jump automatically by holding jump. Useful for manual hopping aswell.
See also Jumping.
cm_frametime 0.009 Frametime (in seconds) to simulate a higher tickrate. 0 to disable. Negative values or values higher than 0.015 have no effect.
See also Interpolation.


Command Description
sm_speed [on|off] Show speedometer
sm_autohop [on|off] Toggle autohop (on/off)
sm_fov <number|reset> Set FOV to a custom value.
Passing "reset" rather than a number will reset the FOV (after respawn).

These settings are stored across sessions.


The default settings aim to replicate the default behaviour from Half Life 1 (and Quake).

For tweaking, only these 3 variables are useful:

  • sv_airaccelerate
    Higher values allow sharper turns without losing speed. Default is 10.
    CS bhop servers usually use a value of 100. With 100 it's nearly impossible to lose speed by turning too fast.

  • cm_frametime
    The interpolation rate (see here for an explanation). Default is 0.009.
    0.01 interpolates (one time) every second frame. 0.0075 interpolates (one time) every frame. Higher values than 0.01 are pretty much useless. Smaller values than 0.0075 will cause multiple interpolation frames per actual frame.
    The smaller the frametime the easier it is to gain speed by airstrafing and the less speed you will lose on sharp turns. If you want to achieve the latter, you should rather use sv_airaccelerate. The default value (0.009) resembles airstrafing at tickrate 100 (even though tickrate 100 actually has a frametime of 0.01) and should be fine in most cases. If you're unsure, leave it as it is.
    If you want to tweak this variable anyway, you'll have to try around a bit to find out what's best for you. Sometimes even small changes make a noticable difference, e.g. 0.008 and 0.0085.

  • tf_clamp_airducks
    Controls if players are restricted to a certain amount of ducks while in midair (2 afaik). It's enabled by default.
    Setting this to 0 disables any restrictions.
    Plays well with cm_doubleduck and allows a certain degree of duckrolling. It's also commonly used on jump maps.

Personally, I'm using sv_airaccelerate 25, cm_tickrate 0.009 and tf_clamp_airducks 0 on my server.


TF2 servers are locked at a tickrate of 66.66666. For bunnyhopping you need at least 100, though, otherwise it's nearly impossible to properly gain speed. Instead you're mostly losing speed.
This plugins comes with an interpolation algorithm, that simulates higher tickrates by simulating one (or more) movement frame(s) per actual frame. It makes airstrafing way smoother and behave almost exactly like it was in Quake/Half Life. Note that interpolation only happens during airtime. There's no need to interpolate on ground.
Here is a video that compares bunnyhopping with and without interpolation enabled.


The following table shows the game frames of a 66.66666 and 100 tickrate server.

Tickrate Frames
66.66666 1 2 3 4 5 6
100 1 2 3 4 5 6 7 8 9

As you see, during 2 frames at a 66.6666 tickrate, the engine processes 3 frames at a 100 tickrate. That means, there is 1 "skipped" frame.

What this plugin does is, it uses an internal frame counter that only increases during airtime by a value depending on the virtual frametime defined by cm_frametime.
This way the plugin can detect "skipped" frames and interpolate them by simply subdividing the movement of that frame by 2 (or more) and simulate an extra frame (or more) using that subdivision.
Note that it does not process a whole game frame. It only runs a shorter, replicated version of the engine's movement code to calculate the speed like the engine would have done it.


You can set the virtual frametime using the cm_frametime variable.
It can be calculates like this:

For optimal results, you should use a tickrate greater or equal 100.
For example, for tickrate 100 you would use:

Note that it doesn't feel 100% like a real server at this tickrate. Sometimes you have to tweak the frametime a bit to get closer to the original. For example, a frametime of 0.009 feels more like tickrate 100 than the actual frametime of 0.01.

To deactivate this functionality (why would you?) set cm_frametime to 0.
Frametimes higher than 0.015 (66.66666) don't make sense because that's the same frametime the server runs at. Doing this anyway or setting a negative frametime will disable interpolation.

Important notes

Ground speedcap

TF2 has a ground speedcap at 520 that can't be modified. No matter what speed you have, as soon as you land on ground, your speed will be capped to 520.
To avoid this, the plugin remembers your previous speed and simulates friction for each frame you're on the ground. As soon as you jump it will reset your speed to the calculated value. This effectively bypasses the 520-speedcap and allows proper mousewheel hopping above speeds of 520.

Double ducking & Duckspam

Double ducking works as expected, but could be exploited to annoy the hell out of snipers by spamming +duck while walking. This will make you twitch over the ground making it way harder to headshot you.
If you are a server owner, you should be aware of this and decide if you really want to have double ducking enabled.

Double ducking can be disabled using cm_doubleduck 0.

Tickrate issues (& solutions)

TF2 servers are locked at a tickrate of 66.66666 FPS. This is ok for normal gameplay, but awful for everything else.


Wallstrafing depends on acceleration and friction, which in turn depend on the tickrate. For example, at tickrate 100 you can gain speed up to 489 with a base speed of 320 (Spy). With tickrate 66.66666, you can only get a maximum of 467.

There is no workaround for this. It's also not that important, as it's not a game breaker.


Airstrafing with 66 FPS is awful because the frame intervals are too big to properly gain speed. You have to turn very slowly, otherwise you're mostly losing speed. This is what makes existing bunnyhop plugins feel "not right".


This plugin has an interpolation mechanism to simulate higher tickrates, which makes airstrafing way smoother. See here for an explanation of how it works and how to use it.
The default settings try to replicate a tickrate 100 server.


The engine interprets jump key input (+jump) only as jump if there was no jump input in the frame before. This prevents autohopping (jumping by holding down the jump key).

That means, when spamming +jump commands (which you usually do when using the mouse wheel to jump) they will count only as jump if there's at least 1 frame in between without a jump command. Otherwise the engine will simply ignore these commands, as it's interpreted as "holding jump".

On a tickrate >=100 server it's almost guaranteed that there are no more than 2 consecutive +jump-frames. On a tickrate 66 server though, it's very likely that you get 3-5 in a row. This makes manual hopping in TF2 annoying as hell, because your jumps get regularily "eaten up" and you loose a lot of speed.


Cells containing a + symbolize a frame with jump input, cells with a - without.

Tickrate Frames
66.66666 - + + + + -
100 - - + - + - + - +

As you see, at the 66 tickrate, all jump commands are right behind each other, and the engine will only count the first one as actual jump. If you're still in the air at that point, you'll obviously not jump.
Let's say you hit the ground in the next frame. Even though there's a jump command, it gets ignored because there was already one in the last frame and the engine interprets it as "holding jump key". That means, you are at the ground for at least 3 frames, which makes you loose a ton of speed.
In comparison, at tickrate 100 there's always a frame in between without +jump. That means your ground time is at most 1 frame.

Keep in mind that this is only an example that demonstrates the problem. The actual results depend on your mouse, how much you scroll and of course timing.


If you want to hop by holding down the jump key, that's already your solution. Simply enable autohopping.

If you want to hop using the mouse wheel, keep autohopping enabled and use the mouse wheel rather than holding down jump. This will not make you do frame perfect jumps, but still treats consecutive +jumps as actual jumps. It almost feels like hopping at tickrate 100 (or higher).

Autohopping can be activated by setting the cm_allow_autohop variable to 1. It is already enabled by default.


Duckspam/Duckroll suffers from the same problem as explained in the Jumping section. It works to a certain degree, but obviously not as good as you would expect it from a tickrate 100 server.
Unlike autohopping, there's no "duckroll key" that automatically interprets consecutive +ducks as double ducking.

There's no workaround for this. Setting tf_clamp_airducks to 0 makes it better though (see also Tweaking).
There's also no real usage for this kind of movement in TF2, so it shouldn't be that much of a problem. One use case would be to get up stairs/slopes without loosing speed, but this only works with very high framerates anyway.

Demo videos

The following videos demonstrate the features of this plugin in comparison to the original Half-Life.


  • (Maybe) Reuse +use as Duckroll/Duckspam key


  • Jump Pads might not set speed for some reason
  • FOV might get reset by other stuff (until respawn or re-entering !fov command)


You can’t perform that action at this time.