Language Help

This page provides help with the language the parser uses. For general help on using this application, head for General Help. Before we begin going over what you can do with this, let's familiarize ourselves with what makes this app: Macros. On this page you can find a macro reference you can use anytime.

Macros

Macros are the basic elements besides text itself. What they essentially do is replace themselves with text. For example, the macro

red

replaces itself with:

^1

Some macros, unlike this one, require arguments. They are specified within parens:

wrap_msg(screenshotJPEG)

You can even define your own:

define(yourname, cooller)
yourname
cooller

Some macros are more complex than that:

bind toggle((c,v), s_volume, +.1, .7, 0, 1)
bind v "vstr _cycle_s_volume_f"
bind c "vstr _cycle_s_volume_b"
set _cycle_s_volume_-0 "s_volume -0;set lastfeedback print ^8[ ^4s_volume: ^1-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.1;set _cycle_s_volume_b vstr _cycle_s_volume_-0"
set _cycle_s_volume_0.1 "s_volume 0.1;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^10.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.2;set _cycle_s_volume_b vstr _cycle_s_volume_-0"
set _cycle_s_volume_0.2 "s_volume 0.2;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^10.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.3;set _cycle_s_volume_b vstr _cycle_s_volume_0.1"
set _cycle_s_volume_0.3 "s_volume 0.3;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^10.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.4;set _cycle_s_volume_b vstr _cycle_s_volume_0.2"
set _cycle_s_volume_0.4 "s_volume 0.4;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^10.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.5;set _cycle_s_volume_b vstr _cycle_s_volume_0.3"
set _cycle_s_volume_0.5 "s_volume 0.5;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^10.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.6;set _cycle_s_volume_b vstr _cycle_s_volume_0.4"
set _cycle_s_volume_0.6 "s_volume 0.6;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^10.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.7;set _cycle_s_volume_b vstr _cycle_s_volume_0.5"
set _cycle_s_volume_0.7 "s_volume 0.7;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^10.7^8 | ^70.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.8;set _cycle_s_volume_b vstr _cycle_s_volume_0.6"
vstr _cycle_s_volume_0.7
set _cycle_s_volume_0.8 "s_volume 0.8;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^10.8^8 | ^70.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_0.9;set _cycle_s_volume_b vstr _cycle_s_volume_0.7"
set _cycle_s_volume_0.9 "s_volume 0.9;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^10.9^8 | ^71^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_1;set _cycle_s_volume_b vstr _cycle_s_volume_0.8"
set _cycle_s_volume_1 "s_volume 1;set lastfeedback print ^8[ ^4s_volume: ^7-0^8 | ^70.1^8 | ^70.2^8 | ^70.3^8 | ^70.4^8 | ^70.5^8 | ^70.6^8 | ^70.7^8 | ^70.8^8 | ^70.9^8 | ^11^8 ];vstr lastfeedback;set _cycle_s_volume_f vstr _cycle_s_volume_1;set _cycle_s_volume_b vstr _cycle_s_volume_

..and that's the whole point of this.

Recipes

Here are some interesting macros almost ready to use. They are ranked in order of complexity, so the first ones will be the simpliest (so don't be disappointed :D). They are independent of eachother so you could pick ones you want to use and leave the other ones alone. (Hence it is called recipes and not tutorial).

Most of the recipes are organized so that you build up to a working code, explaining every step of the creation involved, so that one day you can work out your own solutions to your own problems. If you don't care about that, you can jump straight to the last example, which is usually the most complete one.

Yellow blocks are usable code examples. Gray ones are either code excerpts which aren't complete enough or examples/schemas that are not code at all. Blue ones show the generated result of the last code example. Click "Try it" once in a while! :)

Echoing a message to yourself

Quake Live recently made it easier with the print command:

print Hello world!

would show "Hello world!" in the chat area. This application also provides a print macro. Used the same way as above this paragraph the behaviour remains unchanged.

But if you put the message as argument(inside parens) like this new functionality is added:

print(Hello world!)

You can now use the repeatfeedback vstr, which will repeat the last message passed to print():

bind F4 vstr repeatfeedback

A simple application of this is the wrap_message macro which will run the command given as argument and display a message so as to make certain the command was run:

bind key wrap_msg(command)
bind F11 wrap_msg(screenshotJPEG)

Pretty much all important macros described here and in the reference give feedback in the way that allows use of the repeatfeedback vstr. If for a reason you don't want that feedback to appear, see the next section.

Turning feedback off

Turning feedback off is as easy as it should be, thanks to this macro:

silence_feedback(config that would produce feedback)
silence_feedback({
    
    bind toggle(a, r_fastsky)

})

It will not affect deliberate uses of print:

silence_feedback({

    bind b print(hi)

})
bind b set lastfeedback print hi;vstr lastfeedback

cl_demoRecordMessage toggle

QL already provides a basic toggle command of it's own:

bind b toggle cl_demoRecordMessage

This however poses a problem: you don't know if it's on or off, if it did anything so you can't be sure it is recording or not.

The simpliest version of the toggle macro palliates this problem:

bind toggle(b, cl_demoRecordMessage)

It will turn cl_demoRecordMessage off when the resulted config is executed and, every time you press b, will toggle cl_demoRecordMessage and tell you the current value with a pretty message.

Volume script/s_volume toggle

Probably the most shared config snipplet ever. Another face of toggle makes a customizable one which is only one line to share:

bind toggle((bkey, fkey), cvar, increment, default, min, max, range)
bind toggle((pgdn, pgup), s_volume, +0.1, 0.7, 0, 1, 2)

Short explanation of the parameters: Page down/up will decrease/increase s_volume by increments of 0.1. s_volume will be set to 0.7 when the config is executed and will be limited to values from 0 to 1. The message shown when you press either keys will show up to 2 values on the left/right of the active value.

Demo speed control

Same as above, but with a mathematical expression, and when it reaches 0, sets cl_freezedemo to 1:

bind toggle((leftarrow, rightarrow), timescale, {{2^%s}}, 1, 0, 128, 2,
    2, {{%s %s;set cl_freezedemo 0}},
    ( (0, {{%1 0.0001;set cl_freezedemo 1}}) )
    )

Changing message colors

If you don't like the default colors or just want to change them, you can simply redefine a few macros to achieve it:

define(color_available, ^6)
define(color_key, ^1)

You can also use the color macros if you don't remember their numbers:

define(color_available, {magenta})
define(color_key, {red})

Here are the used macros for the colors or each part of this typical output from the menu macro:

                [ My fancy menu: 0: <= | 1: ragequit | 2: My fancy submenu | 3: => ]
color_active    
color_available                             ragequit
color_key                        0:      1:            2:                    3:
color_message     My fancy menu:
color_more                          <=                    My fancy submenu      =>
color_wrapper   [                      |             |                     |       ]

For toggle:

                [ s_volume: <= | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | => ]
color_active                                 0.7
color_available                  0.5   0.6         0.8   0.9
color_key      
color_message     s_volume:
color_more                  <=                                 =>
color_wrapper   [              |     |     |     |     |     |    ]

Weapon-specific settings and last weapon bind

apply_defaults is a macro that takes two parameters, which can be both written like a normal config:

apply_defaults(defaults, setters)

setters would be a config defining binds, cvars or aliases each one setting other cvars or aliases. I'm sure an example would help so here's how this could apply to weapons:

Let's set a default sensitivity, fov and crosshair, then set weapon binds with weapon-specific settings. You'd probably want to have all your weapons in there, but to keep the example short, we're only gonna use 4:

apply_defaults({{
    
set sensitivity 2
set cg_fov 120
set cg_drawcrosshair 2

}}, {{

bind 5 "weapon 5; set sensitivity 1.5; set cg_drawcrosshair 3"
bind 6 "weapon 6; set cg_fov 105"
bind 7 "weapon 7; set cg_drawcrosshair 5"
bind 8 weapon 8

}})

So here the defaults will be applied to every weapon bind, while the default values in the unparsed code remains readable and easy to edit:

set sensitivity 2
set cg_fov 120
set cg_drawcrosshair 2

bind 5 "weapon 5;set sensitivity 1.5;set cg_drawcrosshair 3;set cg_fov 120"
bind 6 "weapon 6;set cg_fov 105;set sensitivity 2;set cg_drawcrosshair 2"
bind 7 "weapon 7;set cg_drawcrosshair 5;set sensitivity 2;set cg_fov 120"
bind 8 "weapon 8;set sensitivity 2;set cg_fov 120;set cg_drawcrosshair 2"

Now, to obtain a "last weapon" bind, you can simply wrap the whole bit with the last_weapon macro and put bind key in front:

bind q last_weapon({apply_defaults({{
    
set sensitivity 2
set cg_fov 120
set cg_drawcrosshair 2

}}, {{

bind 5 "weapon 5; set sensitivity 1.5; set cg_drawcrosshair 3"
bind 6 "weapon 6; set cg_fov 105"
bind 7 "weapon 7; set cg_drawcrosshair 5"
bind 8 weapon 8

}})
})

Using numpad keys to follow players

You probably want to familiarize yourself with Quoting before proceeding.

Let's start by creating a list of keys. Since they all start with kp_, we will not put it on each of them. Let's use a for loop for that:

for(key in (0,1,2,3), {{{kp_}key
}})

for re-interprets it's body for each run, so we double-quote the whole body so it doesnt get interpreted. Inside it we make key "stand out" so it gets replaced by a key at each run:

kp_0
kp_1
kp_2
kp_3

However, these aren't keys that QL recognizes. Fortunately, there are predefined macros which translate kp_# into the respective real keys. However, it is only interpreted once, so it only translates from {kp_}key to kp_#.

The eval macro can help interpreting code twice(or more). The macro interprets anything given to it as first argument, so we can have things interpreted twice by having the argument quoted:

define(key, 1)
{kp_}key
eval({{kp_}key})
kp_1
KP_END

Applied to our code:

for(key in (0,1,2,3), {{eval({{kp_}key})
}})
KP_INS
KP_END
KP_DOWNARROW
KP_PGDN

Let's now expand to all keys we want to use:

concat({range(10)}, (enter, minus, plus, slash, star, del))

range(10) will generate a list of numbers(from 0 to 9 -- 10 numbers). enter, minus, etc are other numpad keys. concat(.., ..) merges two sequences together:

(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, enter, minus, plus, slash, star, del)

Let's patch that in:

for(key in {concat({range(10)}, (enter, minus, plus, slash, star, del))},
    {{eval({{kp_}key})
}})
KP_INS
KP_END
KP_DOWNARROW
KP_PGDN
KP_LEFTARROW
KP_5
KP_RIGHTARROW
KP_HOME
KP_UPARROW
KP_PGUP
kp_enter
kp_minus
kp_plus
kp_slash
*
kp_del

So, all is good. Let's make the lines complete:

for(key in {concat({range(10)}, (enter, minus, plus, slash, star, del))},
    {{bind eval({{kp_}key}) follow ??
}})

Ah, little problem here, where will we get a number from? We'd want a number to be associated with each key, despite all keys not being numbers.

enumerate takes a sequence as parameter and returns a new one with each entry paired up with a number:

enumerate((enter, minus, plus))
((0, enter), (1, minus), (2, plus))

Let's apply it to our final and working example:

for((i, key) in {enumerate({concat({range(10)}, (enter, minus, plus, slash, star, del))})}, {{bind eval({{kp_}key}) follow i
}})

for allows you to give a list before in so that when items from the source (after in) are lists, they get unpacked to i and key, respectively.

waiting for/taken/take MH/RA/YA team binds

Once again, the for loop will help us do repetitive jobs: We will use two of them: One for the type of message(taken, take, waiting for), and inside this one, a second one for the item.

In this recipe we will suppose you are going to set them on 9 different keys. The next recipe will turn it into a toggle.

Let's do the loop on the messages with RA being the item:

for(msg in (RA taken, waiting for RA, take RA),
    msg
)

for works by just defining a macro(msg) to the current value of the sequence being looped on(RA taken, etc).

When you mention an user macro, it is not only replaced with the value of that macro, but the value is also re-interpreted. That behaviour can be used by defining 2 macros, the second one mentionning the first one, then mentionning the second one:

define(ham, eggs)
define(spam, {{snake ham}})
spam
snake eggs

We can use it here by replacing RA with X and defining X to RA:

for(msg in (X taken, waiting for X, take X),
{{define(X, RA)dnl
msg
}})
RA taken
waiting for RA
take RA

So there we have it for the RA, so let's turn the define into a loop for the other ones:

for(msg in (X taken, waiting for X, take X),
{{for(X in (RA, MH, YA),
msg
)}})

We have to put the keys in the first loop, so that each iteration gets a new set of keys:

for((keys,                  msg) in (
    ((kp_1, kp_2, kp_3),    X taken),
    ((kp_4, kp_5, kp_6),    waiting for X),
    ((kp_7, kp_8, kp_9),    take X)
    ),
{{for(X in (RA, MH, YA),
msg
)}})

We find ourselves with two lists((kp_1, kp_2, kp_3) and (RA, MH, YA)) from which we want to associate items. zip does that:

zip((kp_1, kp_2, kp_3), (RA, MH, YA))
((kp_1, RA), (kp_2, MH), (kp_3, YA))

We can use that with the inner for loop:

for((keys,                  msg) in (
    ((kp_1, kp_2, kp_3),    X taken),
    ((kp_4, kp_5, kp_6),    waiting for X),
    ((kp_7, kp_8, kp_9),    take X)
    ),
{{for((key, X) in 
    {zip({keys}, (RA, MH, YA))},
bind key say_team msg
)}})

And that gives you these binds on 9 different keys.

Macro reference

apply_defaults
Echoes back the first argument and feed each embedded command with cvars/binds/aliases from the first argument ::

apply_defaults({{ set sensitivity 1; }}, {{ bind s weapon 0 bind y weapon 1 bind f "weapon 2;set sensitivity 3" // + more weapon binds .. }})

set sensitivity 1;

bind s "weapon 0;set sensitivity 1" bind y "weapon 1;set sensitivity 1" bind f "weapon 2;set sensitivity 3" // + more weapon binds ..

black
Alias for ^8
black

produces:

^8
blue
Alias for ^4
blue

produces:

^4
color_active
Color used for an item that is active, or has been activated
define(color_active, {red})
color_available
Color used for an item that is available, but not active
define(color_available, {white})
color_key
Color used for a key
define(color_key, {cyan})
color_message
Color used for messages or questions
define(color_message, {blue})
color_more
Color used for an item that will reveal more items
define(color_more, {green})
color_wrapper
Color used for decoration
define(color_wrapper, {black})
concat
Glues two or more strings together
concat(hello, sun)
concat(hello, { }, sun)
hellosun
hello sun
confirm
Wraps command so that the user must confirm it
bind key confirm(command)

bind pause confirm(timeout)

key will have to be pressed twice for the command to be run. See also reset_confirms.

cvar_sanitize
Turns a string into a cvarname-compatible name
cvar_sanitize(INCOMING HIGH!)
incoming_high_
cyan
Alias for ^5
cyan

produces:

^5
define
Defines a new macro
define(spam, ham)dnl
I like spam.

This will produce:

I like ham.
defn
Returns a defined macro's content, without interpretation
define(spam, ham)
define(ham, eggs)
spam
defn(spam)
eggs
ham
dnl
Clears everything until a newline is found

For instance:

dnl This is a comment that won't appear in the final config.
// However, this one will.
// However, this one will.
echo
Deprecated - Use print instead
embed_config
Puts a config within quotes

embed_config takes care of putting cvars or binds that have multiple instructions (and need to be quoted properly) separately.

This is safe:

set packedconfig embed_config(
    bind x "weapon 5; cg_zoomSens 5"
    bind y "weapon 6; cg_zoomSens 2"
    set spam "ham;eggs"
)
set packedconfig "bind x vstr _config_0_hr_0;bind y vstr _config_0_hr_1;set spam vstr _config_0_hr_2"
set _config_0_hr_0 "weapon 5;cg_zoomSens 5"
set _config_0_hr_1 "weapon 6;cg_zoomSens 2"
set _config_0_hr_2 "ham;eggs"
enumerate
Enumerates a sequence
enumerate((a, b, c))
((0, a), (1, b), (2, c))

Particularily useful in conjuction with for:

for((k, v) in {enumerate((a, b, c))},
{{k: v
}})
0: a
1: b
2: c
eq
"Equals" operator
eq(hello, bear) // hello, bear
eq(hello, hello) // hello, hello
eq(3, 3) // 3, 3
 // hello, bear
1 // hello, hello
1 // 3, 3
error
Throws a parse error
error(This is an error.)
eval
Interprets given code
define(spam, ham)
eval(spam)
dnl "ham"
for
Iterates over a list

We can distunguish 2 syntaxes:

for(element in list, do)

For each element present in list, element will be defined and what's in do will be run:

for(player in (cooller, fatal1ty, my cat), {{player
}})
cooller
fatal1ty
my cat

second syntax allows for setting multiple macros simultaneously:.

for((element_1, element_2, ...) in ((value_a1, value_a2, ...), ...)
for((player, nationality) in (
   (cooller, russian),
   (fatal1ty, american),
   (my cat, french)
),
{{player is nationality
}})
cooller is russian
fatal1ty is american
my cat is french
ge
"Greater or equal" operator
lt(1,2) // 1, 2
lt(2,2) // 2, 2
lt(3,2) // 3, 2
 // 1, 2
1 // 2, 2
1 // 3, 2
green
Alias for ^2
green

produces:

^2
gt
"Greater than" operator
lt(1,2) // 1, 2
lt(2,2) // 2, 2
lt(3,2) // 3, 2
 // 1, 2
 // 2, 2
1 // 3, 2
hide_output
Returns an empty string

Useful for running code with quotes but not making it appear in the final config:

hide_output({

This won't be shown.

define(yourname, ^1A^2n^3a^4r^5k^6i)
^ this will be defined

})
if
Runs code depending on a condition
if(condition, then)
if(condition, then, else)
is_defined
Returns if a macro is defined or not
is_defined(red) // {red}
is_defined(eval) // {eval}
is_defined(doesntexist) // {doesntexist}

returns:

1// red
1// eval
// doesntexist
kp_0
Alias for KP_INS
kp_0

produces:

KP_INS
kp_1
Alias for KP_END
kp_1

produces:

KP_END
kp_2
Alias for KP_DOWNARROW
kp_2

produces:

KP_DOWNARROW
kp_3
Alias for KP_PGDN
kp_3

produces:

KP_PGDN
kp_4
Alias for KP_LEFTARROW
kp_4

produces:

KP_LEFTARROW
kp_5
Alias for KP_5
kp_5

produces:

KP_5
kp_6
Alias for KP_RIGHTARROW
kp_6

produces:

KP_RIGHTARROW
kp_7
Alias for KP_HOME
kp_7

produces:

KP_HOME
kp_8
Alias for KP_UPARROW
kp_8

produces:

KP_UPARROW
kp_9
Alias for KP_PGUP
kp_9

produces:

KP_PGUP
kp_point
Alias for KP_DEL
kp_point

produces:

KP_DEL
kp_star
Alias for *
kp_star

produces:

*
last_weapon
If given all your weapon binds as argument, generates a bind that will bring you your last selected weapon
bind q last_weapon({{

bind x weapon 0
bind c weapon 1
bind v weapon 2
// etc

}})
le
"Less or equal" operator
lt(1,2) // 1, 2
lt(2,2) // 2, 2
lt(3,2) // 3, 2
1 // 1, 2
1 // 2, 2
 // 3, 2
len
Returns a sequence's length ::

len((a, b, c)) len({range(5)}) len(Hello world!)

3
5
12
lt
"Less than" operator
lt(1,2) // 1, 2
lt(2,2) // 2, 2
lt(3,2) // 3, 2
1 // 1, 2
 // 2, 2
 // 3, 2
magenta
Alias for ^6
magenta

produces:

^6
matheval
Evaluates a mathematical expression

It supports +(add), -(substract), *(multiply), /(divide), ^(power), and parens:

matheval(1 + 1)
matheval(2 - 1)
matheval(2 * 3)
matheval(60 / 15)
matheval(2 ^ 4)
matheval((2 + 2) * 3)
2
1
6
4
16
12
menu
Builds a menu

This macro allows you to create menus of any size, with submenus and paging support.

Let's start with the basic syntax:

bind key menu(menu title, (menu option, ...), template, keys)

menu title is the title of the menu as it will appear at the beginning of it. keys is a list of the keys you want the menu to use. The default is to use these keys:

(1, 2, 3, 4, 5, 6)

The first and the last keys become navigation keys when the menu is too long to be set on the provided set of keys.

menu options are the core of it: It is a list of menu entries to be put in the menu. Menu entries can be of multiple forms:

Simple command:

ragequit

Named command:

(Shuffle, callvote shuffle)

Submenu:

(My fancy submenu,
    (
        timeout,
        pause,
        allready
    )
)

That makes 3 different syntaxes for menu items:

command
(name, command, template)
(name, submenu, template)

You probably now wonder what template is. It is optional and it allows you to save some typing for similar commands:

(My favorite maps,
    (qzdm20,qzca2,qzdm5,qzdm6),
callvote map %s)

This would make a submenu with commands callvote map qzdm20, etc. It defaults to %s so the command you give is the command produced. a template in a submenu or subentry overrides the current one, for example you can do this:

(My favorite maps,
    (
        (NEXTMAP, callvote nextmap, %s),
        qzdm20,
        qzca2,
        qzdm5,
        qzdm6
    ),
callvote map %s)

Also, you can give multiple commands:

(Forced Models,
    (
        (Playing, {
        reset cg_forceBlueTeamModel
        reset cg_forceRedTeamModel
        }),
        (Spec'ing, {
        cg_forceBlueTeamModel keel/bright
        cg_forceRedTeamModel crash/bright
        })
    )
)

Here's a full example:

bind F9 menu(My fancy menu,
    (
        ragequit
        (Call a shuffle, callvote shuffle),
        (My fancy submenu,
            (
                timeout,
                pause,
                allready
            )
        ),
        (My favorite maps,
            (
                (NEXTMAP, callvote nextmap, %s),
                qzdm20,
                qzca2,
                qzdm5,
                qzdm6
            ),
        callvote map %s),
        (Forced Models,
            (
                (Playing, {
                reset cg_forceBlueTeamModel
                reset cg_forceRedTeamModel
                }),
                (Spec'ing, {
                cg_forceBlueTeamModel keel/bright
                cg_forceRedTeamModel crash/bright
                })
            )
        )
    )
)
name_stripped
The user's color-stripped nickname
// thiscfg - Generated for name_stripped
not
"not" operator
not() // Empty argument
not(0) // 0
not(false) // false
not(no) // no

not(1) // 1
not(yes) // yes
not(true) // true

not(asdfa) // asdfa

not(()) // ()
not((a, b, c)) // (a, b, c)
not() // Empty argument
not(0) // 0
not(false) // false
not(no) // no

not(1) // 1
not(yes) // yes
not(true) // true

not(asdfa) // asdfa

not(()) // ()
not((a, b, c)) // (a, b, c)
numlock
Alias for KP_NUMLOCK
numlock

produces:

KP_NUMLOCK
pack_config
Puts a config into one long line
pack_config({
    bind MOUSE1 "+attack"
    bind MOUSE2 "+zoom"
    set sensitivity "0.25"
    set cl_mouseAccel "0"
})
"bind MOUSE1 "+attack";bind MOUSE2 "+zoom";set sensitivity "0.25";set cl_mouseAccel "0""

Please note that if you want put a config into quotes(for a bind, a vstr..), you should use embed_config instead.

print
Echoes a message to the user

It acts the same as the print command:

bind p print Hello world!

However, if used in the following form, it will allow you to use the repeatfeedback vstr to repeat the last message passed through print():

bind p print(Hello world!)
bind o vstr repeatfeedback
range
Returns a list of numbers

With one parameter, range gives a list of numbers leading from 0 to it:

range(5)
(0, 1, 2, 3, 4)

With two parameters, it gives a list of integers going from the first parameter to the second:

range(2, 5)
(2, 3, 4)

With three parameters, it is the same as with two, the third parameter being the step between numbers:

range(0, 10, 2)
(0, 2, 4, 6, 8)
read
Interprets a config and return its contents as an array for manipulation

Each entry in the returned array corresponds to one "line" of the config and is an array itself. The first entry of each of these arrays represents the type of the entry. Depending on this number, the entry may have more or less arguments, or none.

Here is a list of each kind of entry and their syntax.

read_empty (0)

(0)

An empty line. Takes no argument.

read_slashcomment (1)

(1, Example comment)

A comment that takes all the end of a line. The only argument is the contents of the comment.

read_starcomment (2)

(2, Example comment)

A comment that stops at */.

read_command (3)

(3, command)
(3, command, arguments passed to the command)

A command or a cvar used as one.

read_set (4), read_bind (5), read_alias(6)

(4, cvar name, cvar value)
(5, key, command)
(6, alias name, alias value)

A set, bind or alias statement. Note that the values assigned to those are not interpreted automatically.

Example output

Here's an example config being parsed with read, for you to have a global view of the thing.

read({{

// comment
/* comment */command
/* comment
bind a weapon 0
set sensitivity 1.5
set myvstr "r_vertexlight 0; vid_restart"
alias +myalias "+moveup;+zoom"
sensitivity 2
vid_restart

}})
((0), (0), (0), (1, {{ comment}}), (3, command), (2, {{ comment}}), (0), (1, {{ comment}}), (5, a, weapon 0), (4, sensitivity, 1.5), (4, myvstr, r_vertexlight 0; vid_restart), (6, +myalias, +moveup;+zoom), (3, sensitivity, 2), (3, vid_restart), (0))

For readability, here's the same output with one entry per line:

(
(0),
(0),
(0),
(1, {{ comment}}),
(3, command),
(2, {{ comment}}),
(0),
(1, {{ comment}}),
(5, a, weapon 0),
(4, sensitivity, 1.5),
(4, myvstr, r_vertexlight 0; vid_restart),
(6, +myalias, +moveup;+zoom),
(3, sensitivity, 2),
(3, vid_restart),
(0)
)
read_alias
Alias for 6
read_alias

produces:

6
read_bind
Alias for 5
read_bind

produces:

5
read_command
Alias for 3
read_command

produces:

3
read_empty
Alias for 0
read_empty

produces:

0
read_set
Alias for 4
read_set

produces:

4
read_slashcomment
Alias for 1
read_slashcomment

produces:

1
read_starcomment
Alias for 2
read_starcomment

produces:

2
red
Alias for ^1
red

produces:

^1
reset_confirms
Resets preceeding confirm prompts

This will reset confirm prompts to the state where they still need two presses to do anything.

bind key confirm(command)
bind key confirm(command)
...
bind key reset_confirms

Note that this only takes effect on preceeding confirm calls since the last reset_confirms call(or since the beginning).

silence_feedback
Silences feedback from one or more macros.
silence_feedback({

bind toggle(b, r_fastsky)

})

This will however leave alone deliberate uses of print like:

print Hello
bind a print Hello
strip_colors
Strips Quake color codes from a string
strip_colors(^1A^2n^3a^4r^5k^6i)
Anarki
toggle
Toggles a cvar between multiple values

This command has many syntaxes. The simpliest is as follows:

bind toggle(key, cvar)
bind toggle(b, r_fastsky)

This will make key toggle cvar between 1 and 0, the default value being 0. Obviously, this doesn't allow for much customization, so the next syntax provides a bit more:

bind toggle(key, cvar, (value, value, ..), default)
bind toggle(b, r_fastsky, (1, 0)) // default will be 1

Here, within parens you can put all values you want, and specify the default value which will be used when the config is run. If not specified, the default value will be the first value from the list.

The last syntax is for numeric values only:

bind toggle(key, cvar, increment, default min, max)
bind toggle(pgdown, s_volume, 0.1, 0.7, 0, 1)

This will generate a toggle that will cycle through all values between min and max, with spacings of increment. A negative value for increment will reverse the order.

Of course, cycling one-way through a long list is tiresome especially if you miss the item you want every time you pass it :) So here comes the bi-directional toggle synxtax:

bind toggle((backwardkey, forwardkey), cvar, ...)
bind toggle((pgdn, pgup), s_volume, 0.1, 0.7, 0, 1)

It works on all syntaxes, even on the basic ones. The backward key goes left in the list while the forward one goes right.

Finally, the last argument in all syntaxes specifying the default value can be used to limit the number of choices shown at once in the list:

bind toggle(key, cvar, (value, value, ..), default, range)
bind toggle(key, cvar, increment, default, min, max, range)
bind toggle((c,v), s_volume, +.05, .7, 0, 1, 2)

This will only show 2 values on the left/right of the current value, with the ommitted values replaced by a single ellipsis on each side, like this:

[ <= | 0.6 | 0.65 | >0.7< | 0.75 | 0.8 | => ]

Ok I lied, this wasn't the last part and there are more optional arguments. They only apply to the increment syntax.

First off, the precision argument tells how much to round the value. It defaults to 2 digits after the decimal point:

bind toggle(key, cvar, increment, default, min, max, range, precision)
bind toggle((c,v), s_volume, +.05, .7, 0, 1, 2, 2)

Last two arguments set templates for individual values. The first is a default template, the second is a list of (value, template) pairs. By template I mean format string, like those in printf. Please refer to the php manual on sprintf for further info on these. Anyways, here's how it looks:

bind toggle(key, cvar, increment, default, min, max, range,
    precision, default_template, ((value, template), ...))
bind toggle((leftarrow, rightarrow), timescale, 0.25, 1, 0, 8, 2,
    2, {{%s %s;set cl_freezedemo 0}},
    ( (0, {{%1$s 0.0001;set cl_freezedemo 1}}) )
    )

The template is filled with two values: the command/cvar to be set, and the value.

If enough customization isn't enough, incr can be a mathematical expression in the style of v = f(k). For instance this uses powers of 2 for timescales:

bind toggle((leftarrow, rightarrow), timescale, {{2^%s}}, 1, 0, 128, 2,
    2, {{%s %s;set cl_freezedemo 0}},
    ( (0, {{%1$s 0.0001;set cl_freezedemo 1}}) )
    )

That is all.

toggle_configs
Toggles between multiple configs

The syntax is similar to toggle's:

bind toggle_configs(key, ((name, config), (name, config), ...), default, range)
bind toggle_configs((backward,forward), ((name, config), (name, config), ...), default, range)

The main difference is that the list is made of (name, config) pairs.

For example:

bind toggle_configs(F9, (
(Visibility, {

r_picmip 15
...

}),
(Quality, {

r_picmip 0
...

})
), Quality)

The default and range arguments are optional. They are described in toggle's help.

unread
Restores content created with read to their original form
unread(((0), (0), (0), (1, {{ comment}}), (3, command), (2, {{ comment}}), (0), (1, {{ comment}}), (5, a, weapon 0), (4, sensitivity, 1.5), (4, myvstr, r_vertexlight 0; vid_restart), (6, +myalias, +moveup;+zoom), (3, sensitivity, 2), (3, vid_restart), (0)))
// comment
command /* comment */  // comment
bind a weapon 0
set sensitivity 1.5
set myvstr "r_vertexlight 0; vid_restart"
alias +myalias "+moveup;+zoom"
sensitivity 2
vid_restart
url
Alias for http://epsy46.free.fr/ql/gen
url

produces:

http://epsy46.free.fr/ql/gen
version
Alias for 1.0b1-epsy
version

produces:

1.0b1-epsy
white
Alias for ^7
white

produces:

^7
wrap_msg
Wraps a command within a message
bind o wrap_msg(screenshotJPEG)
write
Returns the first passed argument without change
yellow
Alias for ^3
yellow

produces:

^3
zip
Swaps colums and rows in a bidimensional array zip returns a list with 1st member being a list with the 1st member of every list passed to it, the 2nd being a list with the 2nds and so on. In ASCII-art:.

Item 1 Item 2 Item 3 List 1 List 2 List 3 List 1 A B C =============> Item 1 A B C List 2 D E F ==== zip ====> Item 2 D E F List 3 G H I =============> Item 3 G H I

Translated to code it looks like this:

zip((A, B, C), (D, E, F), (G, H, I))
((A, D, G), (B, E, H), (C, F, I))

It uses the shortest list's length, like python's implementation:

zip((A, B, C), (D, E), (G, H, I))
((A, D, G), (B, E, H))

Quoting

It is important that you grasp how quoting works. It assumes two different roles depending on context. But first of all, let's take a peek at how this works on the big scheme of things.

The whole the document is is some sort of interpreted text. Within this text you can find macro calls along the regular text itself. As seen before, a macro call can have arguments. The whole macro call, including the arguments, isn't searched for other possible macro calls.

However, as the macro processor reads the arguments, it will pick up opening quotes { and match them against closing ones }. Text that is found between these will be interpreted, just like the text directly within the document(it is in fact internally the same object, QuotedText).

Grouped quotes inside this kind of text are unlike the other treated as escapes. Anything found inside will just be copied verbatim.

Here are some examples. Let's start with the global context:

define(spam, ham)dnl
1. spam
2. {spam}
3. {{spam}}

This would result as follows:

1. ham
2. spam
3. {spam}

See in 3. how nesting quotes doesn't act just like a toggle between verbatim copy and interpreted.

Now within a macro call:

define(spam, ham)dnl
1. write(spam)
2. write({spam})
3. write({{spam}})
4. write({{{spam}}})

Which result in:

1. spam
2. ham
3. spam
4. {spam}

In test 1., we effectively see it isn't interpreted. In test cases 2., 3. and 4., we see that they are behaving the same as if what's inside the quotes was in the global context.

To summarize: The global context of the document is interpreted. Quotes inside a macro call makes text interpreted. Within interpreted text, quotes act as escapes and make text uninterpreted.