From TF2 Wiki

Jump to: navigation, search

Note that the word "scripts" as it is used on this page should not be confused with the .scr files that modify server behavior.

To share your scripts or to view scripts written by the community, please visit the Community Scripts page.

For common scripting questions, please visit the Scripting Faq page.

To learn how to install scripts, see this tutorial and/or this one, both on getting started, and this one and/or this one, both on what the key names are.


A Brief Overview of Scripts

What are binds?

Scripts in TF2 are known by several names, including "binds," "keybinds," and "bindings." Binds are a way to attach (or bind) game commands to a key.

Aren't binds cheating?

Not in many people's opinion. Think of it this way: binds allow you to do things you could have done easily, but faster. Everyone has easy access to binds, so they don't give you any advantage over other people. Also, the developers of the put this feature in deliberately and allow it to happen (and they really don't like cheating because it is a multiplayer game) so it is seen as a legitimate use of the game.

Where are binds located?


The game itself stores binds in the file:

<Steam Folder>\SteamApps\<account_name>\team fortress 2\tf\cfg\config.cfg

The commands in this file are executed every time the game starts. Even though the user can modify this file in any text editor, it's often a good idea to add custom binds elsewhere. To this end, there is another file where users can add their own binds:

<Steam Folder>\SteamApps\<account_name>\team fortress 2\tf\cfg\autoexec.cfg

This file does not exist by default, but can be created by the user. As with config.cfg, the autoexec.cfg is just a simple text file that can be edited by the user. And just like config.cfg, the autoexec.cfg file is executed whenever the game starts.

When you create your autoexec.cfg file in your favorite text editor, be sure your text editor isn't tacking on a ".txt" to the end of the filename as is default with notepad (i.e. autoexec.cfg.txt), as that will not be auto-executed. It might not even be accessible from the console!

A good way to make sure that your autoexec.cfg file is not named incorrectly is to have your operating system show all file extensions of known filetypes. Googling found this page [1] which gives good graphical instructions on exactly how to do it that.


On the Mac the files are stored in the following directory:

/Users/<Login_Name>/Library/Application Support/Steam/SteamApps/<Steam_Username>/team fortress 2/tf/cfg


On Ubuntu Linux the files are stored in the following directory:

/home/<user_name>/.local/share/Steam/SteamApps/common/Team Fortress 2/tf/cfg

Using Scripts

Putting a script in autoexec.cfg will apply that script to every class, so if there's a class you don't want to use the script, you have to counter it in the specific <class>.cfg file. Also, putting a script in <class>.cfg will also apply it to every class, so you have to counter it in the other classes too. For example, if you bind 'mouse2" to "reload" in 'engineer.cfg', but you want it to be bound to something else in the other classes, you have to re-bind "mouse2" to "something else" in all the other '(class).cfg' files.


For any key binding or alias binding script within the Source engine developer console, the following format must be followed: COMMAND <argument1> <argument2>

Quotation marks are NOT necessary for binds and aliases with singular arguments, such as bind 1 slot1. However, if you wish to create a bind whose arguments may have multiple commands or parameters, you must enclose the plural arguments with quotation marks and separate the individual components with semicolons, such as alias melee1 "slot3; +attack" (creates a new "command," the alias "melee1," to automatically switch to your melee weapon and start attacking).


COMMAND  <argument1>    <argument2>
alias    qBetween1and2  "slot2; wait 10; slot1"
bind     1              qBetween1and2

Note: I spaced the arguments out so you could see what applies to what, don't do this when you script.

How are simple binds written?

A simple bind takes the form of bind <key> <command>. For example, if we wanted to activate our primary weapon whenever we press the 1 key, then we could write a bind that looks like this:

bind 1 slot1
("slot1" is the command to activate your primary weapon)

Each bind must be written to a separate line in the autoexec.cfg file. For an example of basic keybinds, look at your config.cfg file in any text editor. For a list of useful commands, see the "Console Commands" section of this page.

How are complex binds written?

Complex binds take the same form as simple binds, except that they execute multiple commands when you press the key. Each command must be separated by a semicolon (;). For example, let's take a look at this complex bind for an Engineer (swiped from Patty on the TF2 boards):

bind "q" "build 0; wait 50; +attack; wait; -attack; slot1"
This bind attaches a series of commands to the q key. When the user presses the q key, the following series of commands is executed in order:
  • build 0 tells the game to enter the build mode for a dispenser
  • wait 50 tells the game to wait 50 frames before executing the next command
  • +attack tells the game to start and continue the primary attack (we will learn more about plus and minus commands a little later)
  • wait tells the game to wait a moment before executing the next command
  • -attack tells the game to end the primary attack
  • slot1 tells the game to activate the primary weapon (in the case of the Engineer, this is the shotgun)

How do plus(+) and minus(-) commands work?

Plus and minus commands are two-state commands. The plus state is executed (and continues to execute) while the key is pressed. The minus state executes when the key is released. For example:

bind "c" "+duck"
This bind causes the player to duck and remain crouched as long as the c key is pressed. When the c key is released, the player stands again.

It is important to note that, although the -duck command is never explicitly mentioned in the bind, it will still be executed upon release of the key.

What are aliases and how are they written?

Aliases are similar to binds except that, instead of binding a series of commands to a key, they allow the user to name a series of commands. That name can later be used in place of the series of commands. Using the Engineer example above, for example:

alias "buildDispenser" "build 0; wait 50; +attack; wait; -attack; slot1"
bind "q" "buildDispenser"
This alias followed by a keybind begins to show the power of the scripting system for TF2. We have created an alias called "buildDispenser" (although we could just as easily have called it "Fred" or "Snuffalupagus" or whatever we chose). Whenever we call the name of this alias, it executes the commands to which it's bound. Then we bind the q key to the alias name. Whenever we press the q key, that alias is executed.

Why are aliases more useful than binds? We'll get into that a little more deeply later, but imagine if you wanted to bind that same series of commands to multiple keys. Instead of typing the series again for each key, you can now just bind the alias name to each key. This way, if you want to change something in that series of commands, you only have to change it in one place.

How do plus(+) and minus(-) aliases work?

As with plus and minus commands, plus and minus aliases are two-state aliases. The plus state is executed (and continues to execute) while the key is pressed. The minus state executes when the key is released. For example, let's take a look at this plus/minus alias for an Engineer (swiped from Patty on the TF2 boards):

alias "+upgradeBuilding" "slot3; +attack"
alias "-upgradeBuilding" "-attack; wait; slot1"
bind "mouse3" "+upgradeBuilding"
  • +upgradeBuilding switches to the wrench and begins to swing it
  • -upgradeBuilding stops swinging the wrench, waits a moment, then switches back to the shotgun
  • Then we bind the middle mouse button to the plus-state of the alias we just created. As long as the button is held down, the wrench will continue to swing. As soon as the button is released, the minus-state will be executed.

Note that, even though the minus state is never explicitly mentioned in the keybind, the minus-state is executed upon release of the button. This is an automatic function of plus/minus aliases.

How are cyclical or complex aliases written?

Cyclical or complex aliases are aliases that reference or even create other aliases. Since it's difficult to explain on a general level, let's take a look at an example:

alias "duckToggle" "duck1"
alias "duck1" "+duck; alias duckToggle duck2"
alias "duck2" "-duck; alias duckToggle duck1"
  • First, we create an alias called duckToggle and assign it to another alias called duck1.
  • Second, we create the duck1 alias, which begins and continues the duck command. Then it reassigns duckToggle to a third alias called duck2.
  • Third, we create the duck2 alias, which ends the duck command (i.e. causes the player to stand up). Then it reassigns duckToggle back to duck1.

Now, the first time we execute the duckToggle alias, it will perform the duck1 alias. But the next time we execute duckToggle, it will perform the duck2 alias. Now all that's left to do is to bind a key to the duckToggle alias:

bind "c" "duckToggle"

The next time we press the c key, the player will crouch. When we press c again, the player will stand up.

Key Combinations

I've used the word key combinations by lack of another word. What it actually does is this: by pressing a key, you temporary bind one or more keys to a different command then default. This makes it look just like you are using a key combination. An exemple to change class:

// Quick Class Joiner Script. It has been tested and works.
//Press shift and a key from 1-9 to change class.
alias +joinclass "bind 1 scout; bind 2 soldier; bind 3 pyro; bind 4 demoman; bind 5 heavy; bind 6 engineer; bind 7 medic; bind 8 sniper; bind 9 spy"
alias "-joinclass" "bind 1 slot1; bind 2 slot2; bind 3 slot3; bind 4 slot4; bind 5 slot5; bind 6 slot6; bind 7 slot7; bind 8 slot8; bind 9 slot9"
alias scout "join_class scout"
alias soldier "join_class soldier"
alias pyro "join_class pyro"
alias demoman "join_class demoman"
alias heavy "join_class heavyweapons"
alias engineer "join_class engineer"
alias medic "join_class medic"
alias sniper "join_class sniper"
alias spy "join_class spy"
bind "shift" "+joinclass"

By CupOfTea

Additional Scripting Tips

Why shouldn't I bind keys within aliases?

There are several reasons why you generally shouldn't bind keys inside of aliases.

  1. It makes it difficult for the user to find and change those keybinds.
  2. If you have several keybinds within the alias and the user wants to change keys, missing one of the binds could break the alias.
  3. It makes that alias specific to only that key, and prevents the user from binding multiple keys to a single alias.

Let's look at the duckToggle alias as an example. If we were to bind keys within that alias, it might look like this:

//This is an example of how NOT to write an alias!
alias "duck1" "+duck; bind c duck2"
alias "duck2" "-duck; bind c duck1"
bind "c" "duck1"

As you can see, when the alias is written this way, the c key is bound three times! In order for users to change that key, they must find every place where the c key has been bound. If they miss even one instance, that alias will break. Now let's replace those binds with alias reassignments:

//This is a much better approach
alias "duckToggle" "duck1"
alias "duck1" "+duck; alias duckToggle duck2"
alias "duck2" "-duck; alias duckToggle duck1"

bind "c" "duckToggle"

Now why is this better? Well, first, the user only needs to look in one place for the keybind, so it's much easier to change. But it also allows the user to bind multiple keys or buttons without changing the alias at all!

bind "c" "duckToggle"
bind "v" "duckToggle"
bind "b" "duckToggle"
bind "MOUSE3" "duckToggle"
//And so on, and on, and on

If we were binding our keys inside our aliases, then we'd have to write the aliases multiple times: once for each key we want to bind. But when we move the keybinding outside the aliases, we only have to write the alias once and can bind as many keys as we want to it.

When you're writing scripts for everyone to use, try to keep this principle in mind. Not only is it easier for users to customize, but it's also easier for you to write and maintain.

How to display text onscreen

First is the example of how, followed by the explanation.

You will need a file called con_filter_text_clear.cfg that contains:

 con_filter_text ""

Then in your autoexec.cfg

// aliases to execute the 2 scripts we made
alias "cft_clear" "exec con_filter_text_clear.cfg"
alias "cft_script" "con_filter_text |}"
// aliases to toggle console filtering
alias "cf1" "con_filter_enable 1"
alias "cf0" "con_filter_enable 0"
// to echo a newline
alias "cfnl" "cf0;echo;cf1"

// if you turn this off all text disapears!  it is left always on
developer 1
// start with filtering enabled so we don't see all the console garbage on our screen

// you can play with the following settings
con_notifytime 8	// How long to display recent console text to the upper part of the game window
con_nprint_bgalpha 50	// Con_NPrint background alpha.
con_nprint_bgborder 5	// Con_NPrint border size.
contimes 8		// Number of console lines to overlay for debugging.

// our simple screen print test... which you can expand to do menus or whatever
echo "|} Isn't ofb's screen printing cool?"

Okay, that's it! Remember that when building menus you can use the clear console command to clear away your menu after it's done so it doesn't stay on the screen! Please don't clutter people's screen with "my script loaded v1.2.3 by alphaguy", we don't need spam, TF2 is pretty; leave it that way.

To understand how it works, we set up a .cfg because you can't nest quotes in an alias, alias "myalias" "echo "hi okay?"" for example doesn't work. If you've found a way to escape them properly, just edit this article and update it! We set developer to 1 which spams our users a lot, and they wouldn't know when to look for the menu, so we turn on console filtering which only prints messages that contain |}, we want something unique that won't come up often but that doesn't look like ass on the screen because we'll always need to put it there.

Then when we used cfnl to echo a newline after our filtered text. This is because filtered echo's don't add a newline, and if we didn't all our later echos would just put all the text on the same line. Give it a try to see what I mean. So we turn filtering off, echo a newline, then turn it back on so we don't spam our users.

Warning: console filtering means that you will not get any console text that isn't from your scripts! To see console output again just type cft_clear.

Console Commands

A note on syntax... if an item is surrounded in square brackets ([ or ]) it is optional; if an item is enclosed in angle brackets (< or >) then it is required for that command to work.


  • Class Restrictions
  • Description
    Alias is simply a means of reducing a long list of commands into a small package. For instance, take that example from the 'wait' command. If that were aliased, you could simply use that alias rather than try to remember the whole thing. Much easier. Plus it makes it easier to make things like communications scripts and such.
  • Syntax
    alias "<name_of_alias>" "<command; list>"
  • Arguments
    • None


  • Class Restrictions
    Engineer, Spy
  • Description
    If the Engineer who used this command has enough metal, it will put him into build mode for the item specified. If a Spy uses this command, he will arm the Electro sapper, ready to use on any hostile gadgets targeted.
  • Old syntax
    build <gadget_number>
  • Old arguments
  • New syntax
    build <group_number> <gadget_number>
  • New arguments
    • <group_number>
      0: Dispenser (only Engineer)
      1: Teleporter (only Engineer)
      2: Sentry gun (only Engineer)
      3: Electro sapper (only Spy)
    • <gadget_number>
      0: for sentry, dispenser, teleporter entry or electro sapper
      1: for teleporter exit
  • Example
    > build 2 0 (build a sentry)
    > build 1 1 (build a tele exit)

NOTE: After the 01 may 2010 update, old syntax still works the same.


  • Class Restrictions
    Engineer, Spy
  • Description
    If you have built the gadget represented by the number, congratulations, you are the prowd owner of newly minted scrap metal. Useful for Engineers who want to relocate their buildings, but largely useless for Spies (who would be very unlikely to actually want to destroy their own sappers).
  • Old syntax
    destroy <gadget_number>
  • Old arguments
    • <gadget_number>
      0: Dispenser (Engineer)
      1: Teleport Entrance (Engineer)
      2: Teleport Exit (Engineer)
      3: Sentry (Engineer)
      4: Electro Sapper (Spy)
  • New syntax
    destroy <group_number> <gadget_number>
  • New arguments
    • <group_number>
      0: Dispenser (only Engineer)
      1: Teleporter (only Engineer)
      2: Sentry gun (only Engineer)
    • <gadget_number>
      0: for sentry, dispenser or teleporter entry
      1: for teleporter exit
  • Example
    > destroy 2 0 (destroy sentry)
    > destroy 1 1 (destroy tele exit)


  • Class Restrictions
  • Description
    This, as is fairly easy to tell from the command itself, will disguise you as someone. Who, however, depends on the numbers. The first number represents the class you wish to be, while the second represents the team. When I was testing this out, team numbers above two still worked, so I imagine that it's forward-thinking support in case someone wants to remake a murderball map or something. Also, using negative numers allows you to disguise as either your team or the enemy team without setting up a team loader.
  • Syntax
    disguise <class_number> <team_number>
  • Arguments
    • <class_number>
      1: Scout
      2: Sniper
      3: Soldier
      4: Demoman
      5: Medic
      6: Heavy Weapons Guy
      7: Pyro
      8: Spy
      9: Engineer
    • <team_number>
      1: Blu
      2: Red
      -1: The Enemy Team
      -2: My Team


  • Class Restrictions
  • Description
    As one might imagine, this command changes your disguise to the last one you had. It will remember disguises after a death. This is bound to 'b' by default. Lastdisguise random will chooses a random disguise that's neither Spy nor Scout. Using the command whilst already disguised as your last disguise will switch the weapon of the disguise to the corresponding weapon armed.
  • Syntax
    lastdisguise [random]
  • Arguments
    • [random]
      Chooses a random disguise that's neither Spy nor Scout


  • Class Restrictions
  • Description
    This one's real easy. All it does is switch you back to your previously used weapon. (And I'm sure some of you probably realize that this is exactly the command that 'q' is bound to by default.)
  • Syntax
  • Arguments
    • None


  • Class Restrictions
  • Description
    Menuselect does ONLY the menu portion of slotX, so refer to that entry for the detailed explanation. Also, it ONLY works on VGUI menus, such as the voice command menus, not the visual menus like those that are used to choose class, or select which building to construct as an Engineer, etc.
  • Syntax
    menuselect <item_number>
  • Arguments
    • <item_number>
      Any valid menu choice.
  • Note: Use cancelselect to leave a menu.


  • Class Restrictions
  • Description
    Plays a selected .wav file locally (which is to say, only the user will hear it through their client). To find a .wav file to play, you will need to have a GCF explorer such as GCFScape [2]. With this you can find the path and the sound file you wish to play, and reference it via the console (or scripting).
You can also add your own .wav files to C:\Program Files\Steam\steamapps\USERNAME\team fortress 2\tf\sound\. (See Custom .wav files below.)
  • Syntax
    play <path><sound_file_name.wav>
  • Example
    play vo/demoman_specialcompleted11.wav
  • Arguments
    • None

Custom .wav files

Adding your own .wav files is as simple as dropping them in your C:\Program Files\Steam\steamapps\USERNAME\team fortress 2\tf\sound\ folder. This folder represents the root of the .wav file's path. For example, if you drop a single .wav file called soldier.wav into that folder, then you can play it by using the following command:

play soldier.wav

If you drop a .wav file into a subdirectory of that folder, then you need to preface the filename with the name of that subdirectory. For example, if you drop Soldier.wav into C:\Program Files\Steam\steamapps\USERNAME\team fortress 2\tf\sound\classes\ then you can play it using the following command:


To download a zip pack of custom .wav files that you can use in your own scripts, see the Downloads page.

The Genuine Failbot's Notes: This also works with mp3 files.


  • Class Restrictions
  • Description
    This command has a little more depth to it than first appears. While it is mainly used to choose a weapon, it can also be used as feedback to the default voice menus at 'z', 'x', and 'c'. For instance, if you have 'f' bound to 'slot1' and activate voice_menu_1 ('z'), pressing 'f' would cause you to call for a Medic. With regard to choosing a weapon, this command can act one of two ways. If you have fast weapon switching turned on, this command will immediately switch to that weapon. If you do not, this command will only highlight whatever weapon slot it represents and it remains up to you to do the final selection. Or you can use this to do it for you: "slot1; wait 50; +attack; wait; -attack".
  • Syntax
  • Arguments
    • <slot_number>
      Needs to be a number between 0 and 10. slot10 exits a menu.


  • Class Restrictions
  • Description
    The "use" command is used to literally use the specified weapon. No muss, no fuss, you just pull out that weapon if you have it.
  • Syntax
    use <weapon_name>
  • Arguments
    • <weapon_name>
      • Scout
      • Soldier
      • Pyro
      • Demoman
      • Heavy Weapons Guy
      • Engineer
      • Medic
      • Sniper
      • Spy
      see the Build section for how to equip sapper


  • Class Restrictions
  • Description
    This command is basically a direct method of using the 'z', 'x', and 'c' keys to send voice messages. Basically this allows you to bind a voice message directly to a key in the same fashion as how 'e' is by default bound to call in a Medic.
  • Syntax
    voicemenu <menu_number> <phrase_number>
  • Arguments
    • <menu_number>
      • 0 <phrase_number>
        0: Medic
        1: Thanks
        2: Go
        3: Move Up
        4: Flank Left
        5: Flank Right
        6: Yes
        7: No
      • 1 <phrase_number>
        0: Incoming
        1: Cloaked Spy
        2: Sentry Ahead
        3: Teleporter Here
        4: Dispenser Here
        5: Sentry Here
        6: Activate Ubercharge
        7: (Medic Only) Ubercharge Ready
      • 2 <phrase_number>
        0: Help
        1: Battlecry
        2: Cheers
        3: Jeers
        4: Positive
        5: Negative
        6: Nice Shot
        7: Good Job


  • Class Restrictions
  • Description
    This command is very useful when running multiple commands on the same line. Basically, what this command does is halts the execution of that line for X frames based on its parameter. If you don't use a parameter, it defaults to 1. For me, a value of 100 equals roughly a second, but I haven't had time to check whether this is server or client dependant or not, so you may have to adjust your own times accordingly. An example might be as follows for an Engineer upgrading his SG:

"use tf_weapon_wrench; wait; +duck; wait; +attack; wait 500; -attack; wait; -duck; lastinv" What that does is switch his wrench, ducks, starts swinging the wrench and continues for 5 seconds or so, stops swinging, stands up, and switches back to the last weapon used. If you were to attempt that without the waits, there's a pretty good chance it would fail rather spectacularly. It is important to note that, unlike wait commands of the past, waits will not delay further input, and can be used simply as a timer for scripting in general.

  • Syntax
    wait [wait_time]
  • Arguments
    • [wait_time]
      A value between 1 and <unknown>. Default is 1.
  • A Note About The Wait Command
Valve has fixed the functionality of the sv_allow_wait_command server variable. When disabled (set to 0) the engine simply ignores and omits any wait commands that the server is given. Consequently, many scripts on this website are broken or will only function in very specific situations. This variable is set to 1 by default, but many servers base their server.cfg files off of competitive league settings, which typically disable wait commands. Furthermore, scripts that do loops (see Autopistol Script for an example) will crash your client when triggered.

Other Common GoldSource/Source Scripting Commands

Class select changeclass

Console Toggling toggleconsole

Crouch +duck

Drop item dropitem

Echo message echo

Fire weapon +attack

FPS view cl_showfps 1

Handedness left setinfo lefthand 1

Handedness right setinfo lefthand 0

Jump +jump

Last weapon lastinv

Logo spray impulse 201

Look down +lookdown

Look up +lookup

Map info showbriefing

Map list listmaps

Move backward +back

Move forward +forward

Netgraph netgraph <num>

Next weapon invnext

Playerlist listplayers

Previous weapon invprev

Public message say

Reload weapon +reload

Score overview +showscores

Screenshot snapshot

Strafe +strafe

Strafe Left +moveleft

Strafe Right +moveright

Secondary weapon function +attack2

Taunt taunt

Suicide kill

Suicide by Explosion explode

Team message say_team

Team select changeteam

Turn left +left

Turn right +right

Voice Chat +voicerecord

( "S.A.S's Guide to Counter-Strike: Scripting" )

See also

  • To share your scripts or to view scripts written by the community, please visit the Community Scripts page.

Bindable keys - A List of the keys that are bindable and their scripting names

Error creating thumbnail: Unable to run external programs, passthru() is disabled.

English  • русский

Personal tools