Scripting for Dummies

I see script-related questions all the time. "Where do I find a dual weapon bind?" Where can I find a railgun-zoom script?" "Can someone give me a rocketjump script?" There are plenty of sites that offer ready-made scripts just waiting for you to copy and paste into your autoexec. What I'll try to do here is a little different. I want to help you understand how to write scripts so that you can make your own. Once you learn the basics, it's easy.

First, why write scripts and what do they do for you?

I've added scripts to my basic configuration for three main reasons:

  1. Improve control flexibility (e.g., multiple weapon binds)
  2. Execute multiple functions with one keystroke (e.g., demo recording)
  3. Facilitate config customization for multiple mods (e.g., Urban Terror)

After reading through this basic explanation of script writing you should be comfortable with writing your own basic scripts. Visit The Bind:Arena to see some examples of some really cool scripts and Commander Keen's Quake 3 Arena Console Page for all of the different console commands and variables you might need while writing your scripts.

Script Organization

Scripts have to be saved in a separate .cfg file from your q3config.cfg. The reason is that Quake overwrites the q3config file every time you start a game or change settings and therefore will delete your scripts and comments. I put all of my scripts into an autoexec.cfg. If you don't know how to put one together, visit the Tweaking Your Controls:Making an Autoexec section for a quick lesson.

As you write scripts, use //comments to help annotate what your script does. It will help better organize scripts in your configuration and if you want to give your scripts to other people, it makes it pretty clear what it does. Quake will not execute anything that follows a pair of double-backslashes (//).

Example of //

You can also use the Echo command (more on this later) to give yourself in-game messages when a script has been activated. We'll discuss this later, but you can go to some of the examples section and look at the zoom toggle and the demo recording script to see what in-game messages I give myself when the script is activated.

Back to Top

Basic Binds

Binding a key to perform a single action is the easiest place to start. We'll start by binding the x-key to select the railgun (weapon 7).

The syntax is:

    bind [key] "[command]"
Since we want to bind x to the railgun, we will substitute x for [key] and weapon 7 for [command]. This should give us:
    bind x "weapon 7"
That was simple enough, let's move on.

Back to Top

Multiple Binds

We can also bind a key to execute multiple commands. Remember that Quake executes commands in the order you've specified so we have to be a little careful. For example, we are going to bind a key to select the best choice between the rocket launcher (weapon 5) and the shotgun (weapon 3).

The syntax is:

    bind [key] "[command 1]; [command 2]"
You have to separate the commands with a semicolon (;) so that Quake recognizes where each command starts and stops. We're going to use the x-key again for [key], weapon 3 for [command 1], and weapon 5 for [command 2]. This should give us:
    bind x "weapon 3; weapon 5"
When you hit x, the bind selects the first weapon (e.g., weapon 3) then immediately selects the second weapon (e.g., weapon 5). In effect, if you have both weapons in your inventory, it selects the last one in the sequence. If you only have one of the weapons, it will only find and therefore activate that weapon. This is why we want to make sure we write weapon 3 first since given the choice between the two, we always want to end up with the rocket launcher.

You can string a whole bunch of commands together to be executed all at once. This bind for example, will take a remove all the clutter from your screen (e.g., icons, guns, etc) , take a screenshot, and then return your HUD to the way it was.

    bind F11 "cg_draw2d 0;cg_drawgun 0; wait; wait; wait; screenshot; toggle cg_draw2d; toggle cg_drawgun"

Back to Top

Recursive Scripts

Everything is clear so far, right? Now, instead of only selecting the best weapon, what if we want to toggle back and forth between two weapons like the railgun and the rocket launcher or make it possible to zoom to 3x or 6x magnification? This requires a script, which I will call the recursive script. By recursive, I mean that you can cycle through the script an infinite number of times. The intent is to execute one string of commands when you hit the bound key, then re-bind the key to execute new string of commands the next time you use the key.

The process is:

Step 1 - Name your script and add a short description of what it does
Add your name and description after a comment (// - double-backslash) so that Quake doesn't try to recognize it as a command. Assigning a good descriptive name will help you find your script later, and if you decide to share it with others, helps them understand what they're getting.
    // 3x - 6x zoom toggle
Step 2 - Write commands for each 'step' in the script
    set [scriptline(n)] "[command]; set [nextscriptline] vstr [scriptline(n+1)]; echo [comment]"

  1. The set command tells Quake that you are defining a line of commands that will be grouped and executed under the name [scriptline].
  2. [scriptline(n)] - is the name of one iteration or step in your script. If you have a large number of steps, start numbering with 1. If you have 4 steps, then the highest number should be 4. For scripts with a small number of steps, you can use simple names, just make sure that you don't use the same name twice.
  3. [command] - is the command or set of commands you want to execute with the script. Multiple commands should be separated by a semicolon (;) like we learned in the Multiple Binds section.
  4. set [nextscriptline] - this tells the script to assign [nextscriptline] to execute the string of commands defined in [scriptline(n+1)]
  5. vstr [scriptline(n+1)] - is the name of the next alias in the sequence to be activated. Look at the weapon scripts. In the first iteration, I want to choose the Rocket Launcher over the Plasma Gun, but in the second, I want to reverse the sequence. In your last iteration, make n=1 to start all over from the beginning. This will let your key cycle through all of the combinations you've written, then start all over from the beginning. You don't have to use a numerical sequence, but it might make it easier to keep track of. In any case, pick whatever you're comfortable with.
  6. echo [comment] - Any text that follows the echo command will be shown to you as an in-game message. I find this useful for reminding me what my script just did.
Here's an example for a 3x - 6x zoom toggle:
    set zoomtoggle1 "cg_zoomfov 15; sensitivity 25; set nextzoomtoggle vstr zoomtoggle2; echo 6x magnification"
    set zoomtoggle2 "cg_zoomfov 30; sensitivity 17; set nextzoomtoggle vstr zoomtoggle1; echo 3x magnification"
Step 3 - Assign dynamic variable to first 'step' in sequence
After you have finished writing the basic set of commands, use
    set [nextscriptline] vstr [scriptline(n+1)]
This tells the computer that [nextscriptline] should start by executing [scriptline(n+1)]. Notice however, that every time you execute your script, the value attached to [nextscriptline] changes. Here's an example for a 3x - 6x zoom toggle:
    set nextzoomtoggle "vstr zoomtoggle1"

Step 4 - Bind key to execute dynamic variable
The last step is to bind a key to execute your new script. We learned the syntax in the first step, Simple Binds. The final line in the zoom toggle looks like: Here's an example for a 3x - 6x zoom toggle:
    bind b "vstr nextzoomtoggle"
All this does is bind the key to execute the string of commands associated with [nextscriptline].

Here's what it looks like when it's all put together:

Try this out and play around a little. You'll be writing your own scripts in no time. Go to the Examples section to see a couple I've written.

Back to Top

Toggles

Any command that can be set to either on or off, can be set up on a toggle. For example, you can set Always Run to either on (1) or off (0), therefore I can create a toggle that lets me switch between always on or always off. This has a couple of advantages:
  1. In the case of the +speed (run) command, I don't have to hold down my SHIFT key to run or walk. If I want to sneak up on someone, I can hit the toggle to walk, and then hit it again when I want to resume running.
  2. This set up conserves keys. Instead of one button set to enable always run and another to disable it, I can consolidate everything to one key.

The syntax is:

    bind [key] "toggle [command]"
Here are a couple of examples that I use in my autoexec.cfg
    bind SHIFT "toggle cl_run"
    bind F2 "toggle r_fastsky" //Speed toggle
    bind F3 "toggle cg_drawFPS" //Displays Frames per Second
    bind F4 "toggle cg_drawTimer" //Displays timer
    bind F5 "toggle cg_thirdperson" //Shows model in thirdperson view
    bind F6 "toggle cg_drawgun" //Shows gun

Look through your configuration for variables that take either a 0 or 1 value. Those are the commands that can be set up on a toggle.

Back to Top

Other Executables

I use these to clean up my autoexec.cfg. Basically, I have a file containing all of my favorite servers, one with all of my communications binds and scripts, and a third with my demo recording/handling binds. Having them in a separate file lets me share them with teammates, team comm binds for example, or pass along my favorite servers without having to send the entire autoexec. The other reason for this is config organization. If your configuration to too large, Quake 3 will have problems executing the whole thing. Seperate configs set up as executables enable you to reduce the overall size of your primary autoexec.

The syntax is:

    exec [filename.cfg]
Here are a couple of examples that I use in my autoexec.cfg
    exec comm.cfg
    exec serverlist.cfg
    exec demo.cfg
You can also combine this with a bind command, for example to exec a new set of key bindings for a mod. I use this technique with any mod that requires an extensive set of new key binds such as Urban Terror, Titanium, or Pwrweapons. This way, when I enter a game, I simple hit the bound key, and I'm ready to play. Here's an example.
    bind 7 "exec terror.cfg"

Download a copy of my Q3:A autoexec.cfg if you want to see how my bindings and scripts are set up.

Back to Top

Examples

I’ve included examples of several scripts I use to illustrate what we just covered. Use them as you like.

    // Changes skins for use on pure servers
    set gameskin1 "model mynx/blue; set nextskin vstr gameskin2; echo Mynx..."
    set gameskin2 "model spitfire/red; set nextskin vstr gameskin1; echo Spitfire..."
    set nextskin "vstr gameskin1"
    bind x "vstr nextskin"

    // Multiple-Weaponbind Script RL-PG
    set rl "weapon 8; weapon 5; set weapongroup1 vstr pg"
    set pg "weapon 5; weapon 8; set weapongroup1 vstr rl"
    set weapongroup1 "vstr rl"
    bind x "vstr weapongroup1"

    // Multiple-Weaponbind Script RL-BFG
    set bfg "weapon 5; weapon 9; set weapongroup2 vstr rkt"
    set rkt "weapon 9; weapon 5; set weapongroup2 vstr bfg"
    set weapongroup2 "vstr bfg"
    bind x "vstr weapongroup2"

    // Zoom toggle change to railgun, zoom in, and change sensitivity
    set zoomin "weapon 7; cg_fov 15; sensitivity 25; set nextzoom vstr zoomout"
    set zoomout "weapprev; cg_fov 90; sensitivity 17; set nextzoom vstr zoomin"
    set nextzoom "vstr zoomin"
    bind r "vstr nextzoom"

    // Zoom Toggle
    set zoomtoggle1 "cg_zoomfov 15; sensitivity 25; set nextzoomtoggle vstr zoomtoggle2; echo 6x magnification"
    set zoomtoggle2 "cg_zoomfov 30; sensitivity 17; set nextzoomtoggle vstr zoomtoggle1; echo 3x magnification"
    set nextzoomtoggle "vstr zoomtoggle1"
    bind b "vstr nextzoomtoggle"

    You can also use recursive scripts to help set up server configurations

    // Maplist
    seta m1 "fraglimit 20; map q3dm3 ; set nextmap vstr m2"
    seta m2 "fraglimit 20; map keep ; set nextmap vstr m3"
    seta m3 "fraglimit 20; map 69pickup1 ; set nextmap vstr m1"
    vstr "m1"

Here's an example of a recursive script that executes another recursive script to record demos. The nested script ensures that each demo recorded has its own name to prevent overwriting a demo that has been already created.

    // Demo Recording Script - Starts and stops a recording for a group of demos
    set toggle1 "g_synchronousClients 1; vstr nextdemo; g_synchronousClients 0; set nexttoggle vstr toggle2"
    set toggle2 "stoprecord; set nexttoggle vstr toggle1; echo Stop Recording ..."
    set nexttoggle "vstr toggle1"
    bind j "vstr nexttoggle"

    set demo1 "record gamedemo1; set nextdemo vstr demo2; echo Recording Demo #1"
    set demo2 "record gamedemo2; set nextdemo vstr demo3; echo Recording Demo #2"
    set demo3 "record gamedemo3; set nextdemo vstr demo4; echo Recording Demo #3"
    set demo4 "record gamedemo4; set nextdemo vstr demo5; echo Recording Demo #4"
    set demo5 "record gamedemo5; set nextdemo vstr demo6; echo Recording Demo #5 - last demo"
    set demo6 "echo no more demos"
    set nextdemo "vstr demo1"

Go back to Quake 4 Dummies