Scripting

From Team Fortress Wiki
Revision as of 07:38, 3 October 2010 by Magnum357 (talk | contribs) (Aren't binds cheating?: Added missing word.)
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.

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

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 game 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 that.

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.

Syntax

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).

Examples:

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 example 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
cf1

// 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?"
cfnl

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 wont' 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.

ALIAS

  • Class Restrictions
    None
  • 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


BUILD

  • 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 Gun, Dispenser, teleporter entry or Electro Sapper
      1: for teleporter exit
  • Example
    > build 2 0 (build a Sentry Gun)
    > build 1 1 (build a tele exit)

NOTE: Currently you cannot call build a second time with an Engineer when you are already in build mode, you need to swap to any of your weapon before being able to call build again (bug or feature?)

NOTE: This issue is fixed, the build command can now be called repeately without problems.

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

DESTROY

  • 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 Gun, Dispenser or teleporter entry
      1: for teleporter exit
  • Example
    > destroy 2 0 (destroy Sentry Gun)
    > destroy 1 1 (destroy tele exit)

DISGUISE

  • Class Restrictions
    Spy
  • 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

LASTDISGUISE

  • Class Restrictions
    Spy
  • 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

LASTINV

  • Class Restrictions
    None
  • 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
    lastinv
  • Arguments
    • None


MENUSELECT

  • Class Restrictions
    None
  • 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.



PLAY

  • Class Restrictions
    None
  • 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:

classes/soldier.wav

SLOT<X>

  • Class Restrictions
    None
  • 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
    slot<slot_number>
  • Arguments
    • <slot_number>
      Needs to be a number between 0 and 10. slot10 exits a menu.


USE

  • Class Restrictions
    None
  • 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
      tf_weapon_scattergun
      tf_weapon_pistol_scout
      tf_weapon_lunchbox_drink
      tf_weapon_bat
      tf_weapon_bat_wood
      • Soldier
      tf_weapon_rocketlauncher
      tf_weapon_rocketlauncher_directhit
      tf_weapon_shotgun_soldier
      tf_weapon_buff_item
      tf_weapon_shovel
      tf_weapon_sword
      • Pyro
      tf_weapon_flamethrower
      tf_weapon_shotgun_pyro
      tf_weapon_flaregun
      tf_weapon_fireaxe
      • Demoman
      tf_weapon_grenadelauncher
      tf_weapon_grenade_demoman
      tf_weapon_pipebomblauncher
      tf_weapon_pumpkin_bomb
      tf_weapon_bottle
      tf_weapon_base
      tf_weapon_sword
      • Heavy Weapons Guy
      tf_weapon_minigun
      tf_weapon_shotgun_hwg
      tf_weapon_lunchbox
      tf_weapon_fists
      • Engineer
      tf_weapon_shotgun_primary
      tf_weapon_sentry_revenge
      tf_weapon_pistol
      tf_weapon_laser_pointer
      tf_weapon_wrench
      tf_weapon_robot_arm
      tf_weapon_pda_engineer_destroy
      tf_weapon_pda_engineer_build
      • Medic
      tf_weapon_syringegun_medic
      tf_weapon_medigun
      tf_weapon_bonesaw
      • Sniper
      tf_weapon_sniperrifle
      tf_weapon_compound_bow
      tf_weapon_smg
      tf_weapon_jar
      tf_weapon_club
      • Spy
      tf_weapon_revolver
      tf_weapon_knife
      tf_weapon_pda_spy
      see the Build section for how to equip sapper

VOICEMENU

  • Class Restrictions
    None
  • 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 ÜberCharge
        7: (Medic Only) ÜberCharge Ready
      • 2 <phrase_number>
        0: Help
        1: Battlecry
        2: Cheers
        3: Jeers
        4: Positive
        5: Negative
        6: Nice Shot
        7: Good Job


WAIT

  • Class Restrictions
    None
  • 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

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