<head>
 <script type="text/javascript" src="ASCIIMathML.js"></script>
 <title>teeworlds-perl</title>
</head>

# Introduction

[Teeworlds][] is an awesome 2D multiplayer shooter. It features funny
cartoon-like graphics, sophisticated movement dynamics, and wide community one
can find interesting to participate in. Teeworlds has three standard game types
similar to those present in any first-person multiplayer shooter: deathmatch
(dm), team deathmatch (tdm) and capture the flag (ctf). There also are 
[plenty of modifications][mods] (mods), some of which change the gameplay quite
dramatically. This site is devoted to one of such mods.

[Teeworlds]: http://teeworlds.com
[mods]:      http://www.teeworlds.com/forum/viewtopic.php?id=4602

The situation with modifications in teeworlds world is rather stressed.
There is no mod support in the code, so teeworlds design does not provide
simple API to create mods. Most of mods has to significantly change the code,
and hence every single mod is a standalone full-blown fork.  This makes it
difficult to combine mods and often the same features are implemented separately
by different people in different ways for different mods. The mod described
below is not an exception. Fortunately, there was a quite successful attempt to
combine several mods into one made by [Tom][]. The result features standard
gametypes as well as instagib deathmatch (idm), team deathmatch (itdm), capture
the flag (ictf), freeze (ifreeze) and freeze capture the flag (ifrzctf). Since
this mod had most of my favourite gametypes, I decided to take it as a start and
develop it further to implement what I wanted.

[Tom]: http://www.teeworlds.com/forum/viewtopic.php?id=4358

The idea for the mod arised when I tried to make the server more configurable.
I wanted to make a random maprotation, but couldn't even make a map to appear in
rotation twice. While this particular task could easily be solved with a small
patch, I thought that it would be a nice idea to have a full-scaled programming
language for configuration files. I didn't want to reinvent the bicycle trying
to extend the available teeworlds parser or make my own language even if it
would be backward-compatible with existing server configurations. Instead, I've
chosen Perl, mainly because I wanted to study its internals and figure out how
to embed it in programs. Of course, there were a lot of other choices. I've
heard that Lua will be used for the same or similar task in the upcoming
teeworlds 0.6. Indeed, it seems to be the most suitable language despite that I
don't like some of its features: it's small, fast, and easy to embed.  Among
other choices were Python, Tcl and Scheme. Technically, it doesn't really matter
which language to use for this task as long as it is dynamic, has some form of
`eval` function and can call C functions (and if I wouldn't want to have
[REPL][], only the latter requirement would matter). In any case it is a
bad idea to often call functions from embedded language because of all the
penalties foreign function calls imply, so the speed of the embedded language
doesn't really matter. Other requirements, such as memory usage and few
dependencies, exclude several major languages, but still plenty of scripting
languages are left. The choice between them is more likely a matter of desire.
As long as you have a sane API, to implement support for another language is
quite easy. Bad thing is that Teeworlds doesn't have one, so I had to simulate
it with some hacks.

Anyway, the major points of this mod are:

* Full-blown programming language is used to configure the server. It allows
  the server administrator to use sophisticated algorithms to set server
  variables and to define actions to perform on some less frequent events.
* All code written in Perl can be changed and executed without the need to
  restart the server, right in the rcon. Writing a lot of code in rcon is not
  very comfortable, but if you have access to the machine the server is running
  on, you can use Perl `do` function. Also, remember that Perl is quite good for
  one-liners.
* Rcon extensions are designed so that the server may recognize different user
  groups and provide different sets of commands for these groups. Thus, you can
  grant rcon to ordinary users to provide more flexible vote system.
* Of course, all Tom work is still there, notably instagib and ifreeze
  gametypes, anti-spam and anti-camper protection, etc. A few additional
  features were implemented, such as multiple clients per IP protection, the
  ability to call off vote, and others.

However, there also are major drawbacks. First, the server administrator is
better to know Perl well. If you want something similar to my configuration, you
can use examples provided below, but you should understand what you are doing.
Second, the server is unlikely to compile under non-POSIX environment, notably
in Windows. I haven't tried though. Third, current approach to the definition of
command sets for user groups require writing quite a lot of code. Finally,
consider carefully security issues described in chapter [REPL][].
 
# Downloads

The mod is accessible via the following link:

[teeworlds-perl-1.1.0.tar.bz2](teeworlds-perl-1.1.0.tar.bz2)

You may get the current development version from git with the following command:

    git clone git://jini-zh.org/teeworlds-perl

Follow [these rules][compile] to compile the server. In addition to programs
listed there, you will need perl of version not older than 5.10.1 compiled with
shared libraries (libperl.so). Note that you need bam-0.2.0, not the latest
version of bam. As is with Tom's sources, the client cannot compile in this mod.
Issue `bam server_release` in the final stage of the compilation.

An example configuration is provided in [doc/example.pl][example].

[example]: example.pl
[compile]: http://teeworlds.com/?page=docs&wiki=CompilingEverything
[Changelog]: Changelog

# Concepts

## REPL

In addition to providing programming language for configuration files, I decided
to implement a REPL (read-evaluate-print loop) for rcon. It makes some form of
terminal emulation in rcon and gives the administrator complete control over the
server (well, the level of control the server API provides). Note that it is
easy to extend this control to get access to things unrelated to teeworlds, for
example to get a shell on the machine running teeworlds with the rights of the
user running teeworlds. It is easy enough to be done manually, right in the rcon
command line, so be sure to pick __strong__ root password if you choose to activate it.
Of course, there still exists the possibily of root password to be compromised.
To minimize possible damage, you may choose between two security measures.

The best way to protect your system is to run the server in [chroot jail][jail]
under unprivileged user. Make a directory, for example `/srv/teeworlds/` and put
there files you want to be available to the server. In particular, make a `maps`
directory inside `/srv/teeworlds` and put maps there. Then write a call to
[`init`][init] function in the end of your configuration file:

    init '/srv/teeworlds', 1000, 1001;

When `init` function is executed, the server [chroots][chroot] to directory
passed as the first parameter, `/srv/teeworlds` in this example, and changes its
[group identity][setgid] and [user identity][setuid] to those specified by the
second (1000) and the third (1001) parameters correspondingly. `init` also copies
system files neccessary for teeworlds to work properly. These are
`/etc/resolv.conf`, and libraries `/lib/libnss_dns.so.2`,
`/lib/libnss_files.so.2`, `/lib/libresolv.so.2`. Teeworlds uses these files to
establish connection to master servers. Since `chroot` call
can be made only by superuser, the server has to be run as root.

[init]:    #init
[chroot]:  http://linux.die.net/man/2/chroot
[jail]:    http://onlamp.com/lpt/a/3132
[setgid]:  http://linux.die.net/man/2/setgid
[setuid]:  http://linux.die.net/man/2/setuid

If you don't want to bother root every time you want to run the server, you may
consider [schroot][schroot] approach.

[schroot]: http://manpages.ubuntu.com/manpages/hardy/man1/schroot.1.html

## Groups

Often it is desirable to have several types of users administering the server.
For example, there could be administrators with full access to the server
commands, and referees who should be able to kick any user by rcon, but should
not be able to shutdown the server. With REPL this desire becomes even stronger,
because anyone who has access to the REPL, has access to the shell on the server
host system and can do a lot of nasty things. In this mod a group concept is
introduced to provide control for who can execute which functions.

Available groups are described by a global variable `%groups`. It is a hash
which keys are group names and values are references to hashes with the
following keys:

- gid: group id,
- password: group password.

Available functions are described by a global variable `%commands`. It also is a
hash which keys are command names and values are references to hashes with the
following keys:

- gid: group id,
- sub: a code to execute,

Whenever a user enters a password in order to authenticate in rcon, the server
searches for a group with the corresponding password field and assignes its group
id to the user. The user can execute only those functions whose group ids match
their group id. Two group ids match if their binary and is not zero: 

    $gid1 & $gid2 != 0

Let's consider a simple example. Suppose that there are two groups: 

    %groups = (
      admin => {
       gid => 2,
       password => 'admin password'
      },
      user  => {
       gid => 1,
       password => 'user password'
      }
     );

and three functions:

     %commands = (
      kick => {
       gid => 2,
       sub => sub { ... },
      },
      vote => {
       gid => 1 | 2,
       sub => sub { ... },
      },
      complain => {
       gid => 1,
       sub => sub { ... },
      }
     );

In this example `kick` is executable only by administrator, `complain`---only by
user and `vote` by both.

Users can belong to several groups at once either if the gid of the group they
are logged into matches gids of other groups or if they log into several groups
by means of the [`su`][su] command.

[su]: #su

There are two special group ids. Group id equal to zero designates an
unregistered player. Obviously such players cannot execute rcon commands, but
they can call predefined votes, so you may have to take them into account. Group
id equal to `$root_id` which is `~0`&mdash;the exact opposite of zero&mdash;is an id for
the root group. Root has direct access to REPL and executes commands in Perl
syntax. Note that you have to define the root group in order to turn it on.

Be careful when assigning group numbers. For the simplest case of
not-intersecting groups these should be powers of two (or, strictly speaking, a
set of orthogonal binary vectors). In general the more permissions the group
has, the bigger should be its group id.

## Votes

For a command to be votable, it has to have a `vgid` entry in the `%commands`
hash. Naturally, only users whose gid match `vgid` have permissions to run the
vote. However, `vgid` is not checked when a predefined vote is called, that is a
vote added by `addvote` to the list of votes the client can call without
authorizing in rcon.

Often it is desirable to check command parameters to prevent absurd or
undesirable votes. This can be done with entry `vcheck` which should be a
reference to a function that is passed command parameters and dies if it doesn't
like them. Here is an example:

    %commands = (
     sv_map => {
      gid => 0, # this command cannot be executed
      sub => \&sv_map,
      vgid => 1,
      vcheck => sub { 
       # $_[0] is voting client id
       # $_[1] is voting client group id
       # $_[2] is the command parameters
       die "ctf4 is not allowed\n" if $_[2] =~ /^ *ctf4 *$/
      }
     }
    )

Unfortunately, such an approach encourages duplication of the code that parses
and checks command parameters. Perhaps later it will be changed.

## More

[`more`][more] is a simple text viewer that allows the player to read a big bunch
of text in the limited space of rcon. Being fed a pack of strings, `more` splits
them so that they look nice and prints a screenful of text at once until all are
done.  To proceed to the next screen, user has to send any command except those
predefined:

* `b`: back one screen.
* `.`: redisplay the current screen.
* `/regular expression`: search for a pattern.
* `?regular expression`: search for a pattern in backwards direction.
* `n`: repeat last search.
* `N`: repeat last search in the other direction.
* `g number`: go to a given line.
* `q`: quit.
* `h`: print help message.

Unfortunately, teeworlds rcon was not supposed to be used as a terminal, so it
lacks some features. Terminals use mono-spaced font and there is a way to find
out the width and the height of the terminal at runtime. None of these is true
for teeworlds, so to control the output two variables, `$more_rows` and
 `$more_cols`, were defined. The former is the number of lines `more` prints per
screen. It seems that rcon height is fixed in the code to be 25. `$more_cols`
is a maximum number of characters to print per line. Its value is hand-picked
so that the common line of English text looks fine. Obviously it will fail for
a line like "WWWWW..." because "W" characters are rather wide, but for common
text it should do. Feel free to complain.

# API

## Configuration variables

Teeworlds uses one huge `struct` to hold a bunch of configuration variables.
Values of these variables are used throughout the code everywhere, so change
of the variable value produces immediate effect. Only two types are supported:
`int` and `char*` (string). In the configuration file variables can be accessed
via `%config` hash. Keys of the hash are variable names and values are
references to Perl objects implementing three methods:

1. `get`: returns the value of the variable.
2. `set`: sets the value of the variable.
3. `help`: returns a string describing the variable.

In addition integer variables have the following methods:

4. `min`: minimum allowed value.
5. `max`: maximum allowed value.

An example:

    # Change gametype to ctf
    $config{'sv_gametype'}->set('ctf');
    # Get the scorelimit
    $scorelimit = $config{'sv_scorelimit'}->get();

For convenience, functions with the same names as variables are defined. They
check if they are being passed a value and execute `set` or `get` method
correspondingly. The example can be written as follows:

    sv_gametype('ctf');
    $scorelimit = sv_scorelimit();

Feel free to redefine these functions in the configuration file.

Following is a list of configuration variables.

[Integer variables][]
| Variable               | Default | Minimum | Maximum | Description
|------------------------|---------|---------|---------|------------
`sv_all_respawn_after_score` |0    |    0    |    1    | Respawn unfrozen tees after one of the teams has been completely frozen [(1)][boolean]
`sv_anticamper`          |    1    |    0    |    1    | Anticamper protection [(1)][boolean]
`sv_anticamper_range`    |   100   |    0    |   500   | Camp radius
`sv_anticamper_time`     |   10    |    0    |    30   | Acceptable camp time in seconds
`sv_automelt_display`    |    1    |    0    |    1    | Display melting progress as decreasing armor [(1)][boolean]
`sv_automelt_time`       |    30   |    0    |   120   | Default tee melting time
`sv_booster_usetiles`    |    0    |    0    |    1    | Activate boost tiles [(1)][boolean]
`sv_chatloop_interval`   |    0    |    0    |10000000 | Send `sv_chatloop_message` to chat every this number of milliseconds [(2)][zero]
`sv_external_port`       |    0    |    0    | &mdash; | External port to report to master servers
`sv_fb_ball_damage_lose` |    1    |    0    |    1    | Turns on/off turnover on any damage [(1)][boolean]
`sv_fb_ball_deathtile_idle`|  3    |    0    |    60   | Number of seconds needed to reset a ball after hitting a death tile [(2)][zero]
`sv_fb_Ball_direct_pass` |    1    |    0    |    1    | Turns on/off direct-passing of ball with hook-key [(1)][boolean]
`sv_fb_ball_direct_pass_distance` | 380 | 32 |   3200  | Maximum direct-passing distance
`sv_fb_ball_offset_x`    |    0    |    0    |   1000  | X offset of the hookable center of the ball with respect to the lower left corner of the image
`sv_fb_ball_offset_y`    |    38   |    0    |   1000  | Y offset of the hookable center of the ball with respect to the lower left corner of the image
`sv_fb_ball_radius`      |    40   |    0    |   1000  | Ball hookable radius
`sv_fb_ball_reset_time`  |    30   |    1    |   500   | Number of seconds needed to reset an unused ball
`sv_fb_ball_velocity`    |   207   |    10   |   3000  | Velocity of the ball after it got shot
`sv_fb_goalcamp`         |    1    |    0    |    1    | Turns on/off goal camp protection [(1)][boolean]
`sv_fb_goalcamp_factor`  |    40   |    10   |   100   | Goal camp protection radius (`value/10.0*sv_fb_goalsize`)
`sv_fb_goalcamp_time`    |    3    |    1    |   600   | Number of seconds allowed lingering near a goal
`sv_fb_goalsize`         |    64   |    32   |   500   | Radius defining goal
`sv_fb_hook_ball`        |    1    |    0    |    1    | Turns on/off the possibily to capture the ball by hook [(1)][boolean]
`sv_fb_laser_momentum`   |   207   |  -3000  |   3000  | Momentum passed to a flag when it is hit with laser
`sv_fb_owngoal`          |    0    |    0    |    1    | Turns on/off own goals [(1)][boolean]
`sv_fb_owngoal_kick`     |    0    |    0    |    1    | Number of own goals allowed before kicking the player [(2)][zero]
`sv_fb_owngoal_penalty`  |    30   |    0    |   999   | Negative score for own goal player
`sv_fb_owngoal_warn`     |    1    |    0    |    1    | Turns on/off warning when player with ball is near own goal [(1)][boolean]
`sv_fb_score_player_ball`|    5    |    0    |   100   | Player score on ball-goal
`sv_fb_score_player_stand`|   1    |    0    |   100   | Player score for taking ball from stand
`sv_fb_score_player_tee` |    10   |    0    |   100   | Player-score on tee-goal
`sv_fb_score_team_ball`  |    50   |    1    |   100   | Team-score on ball-goal
`sv_fb_score_team_tee`   |   100   |    1    |   100   | Team-score on tee-goal
`sv_freeze_usetiles`     |    0    |    0    |    1    | Activate freeze tiles [(1)][boolean]
`sv_frozen_tags`         |    1    |    0    |    1    | Insert `[F]` in front of frozen tee's name [(1)][boolean]
`sv_grenade_reload`      |   500   |    0    |  10000  | Grenade launcher reload time in milliseconds
`sv_grenade_selfdamage`  |    1    |    0    |    1    | Grenades damage the shooter [(1)][boolean]
`sv_grenade_split`       |    0    |    0    |    10   | Number of grenades to fire per grenade launcher shot. Set to 1 to get inifinite normal grenades [(2)][zero]
`sv_high_bandwidth`      |    0    |    0    |    1    | Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only [(1)][boolean]
`sv_inactivity_kick`     |   120   |    0    |  10000  | Kick players not active for that number of seconds [(2)][zero]
`sv_inactivity_kick_spect`|   0    |    0    |    1    | Force inactive players to spectate rather than kick [(1)][boolean]
`sv_join_as_frozen`      |    0    |    0    |    1    | Freeze newcomers [(1)][boolean]
`sv_killingspree`        |    1    |    0    |    1    | Activate killing spree messages [(1)][boolean]
`sv_killingspree_award`  |    0    |    0    |    1    | Provide awards for killing sprees [(1)][boolean]
`sv_killingspree_award_lasers` | 3 |    0    |    1    | For awarded tees, use this instead of `sv_lasers`
`sv_killingspree_award_lasers_split`|1| 0    |    10   | For awarded tees, use this instead of `sv_lasers_split`
`sv_killingspree_award_reload` | 75|    1    |   100   | For awarded tees weapon reload times become this number of percents of default
`sv_killingspree_kills`  |    5    |    1    |   1000  | Number of kills per killing spree
`sv_killingspree_tag`    |    1    |    0    |    1    | Insert `[SPREE]` in front of killingspreeing tee's name [(1)][boolean]
`sv_laser_gothroughfrozens` | 0    |    0    |    1    | Let laser penetrate frozen tees [(1)][boolean]
`sv_laser_gothroughplayers`|  0    |    0    |    1    | Let laser penetrate players [(1)][boolean]
`sv_laserjumps`          |    0    |    0    |    1    | Activate laser jumps [(1)][boolean]
`sv_laser_reload`        |   800   |    0    |  10000  | Laser reload time in milliseconds
`sv_lasers`              |    1    |    1    |    10   | Number of laser beams per laser rifle shot
`sv_lasers_split`        |    1    |    0    |    10   | Angle between laser beams if `sv_lasers` is more than 1. Measured in \`pi / 100\`
`sv_map_reload`          |    0    |    0    |    1    | Reload the current map [(1)][boolean]
`sv_maxclients`          |    8    |    1    |    16   | Maximum number of clients that are allowed on a server
`sv_melt_health`         |    10   |    1    |    10   | Health of melted tee
`sv_melt_range`          |   100   |    0    |   1000  | Tee heat radius
`sv_melt_respawn`        |    1    |    0    |    1    | Respawn melted tees [(1)][boolean]
`sv_melt_tiles_degeneration`| 1    |    0    |    10   | Amount of damage per second a tee standing on ice tile receives
`sv_melt_tiles_noshoot`  |    0    |    0    |    1    | Allow shooting on hot tiles [(1)][boolean]
`sv_melt_time`           |    1    |    0    |    5    | Melting time in seconds for a tee being thawed
`sv_melt_usetiles`       |    0    |    0    |    1    | Activate melting tiles [(1)][boolean]
`sv_pause_warmup`        |    0    |    0    | &mdash; | Number of seconds to do warmup before unpausing the game
`sv_port`                |  8303   |    0    | &mdash; | Port to use for the server
`sv_powerups`            |    1    |    0    |    1    | Allow powerups like ninja [(1)][boolean]
`sv_register`            |    1    |    0    |    1    | Register server with master server for public listing [(1)][boolean]
`sv_reserved_slots`      |    0    |    0    |    16   | Keep that many slots reserved to whoever knows the password
`sv_rounds_per_map`      |    1    |    1    |   100   | Number of rounds on each map before rotating [(3)][oncyclemap-footnote]
`sv_scorelimit`          |    20   |    0    | &mdash; | Score limit [(2)][zero]
`sv_spamprotection`      |    1    |    0    |    1    | Spam protection [(1)][boolean]
`sv_spawnprotect_time`   |  1000   |    0    |  10000  | Spawnprotection time in milliseconds
`sv_spectator_slots`     |    0    |    0    |   16    | Number of slots to reserve for spectators
`sv_teambalance`         |    0    |    0    |    1    | Activate team auto-balancing
`sv_teambalance_time`    |    1    |    0    |   1000  | How many minutes to wait before autobalancing teams
`sv_teamdamage`          |    0    |    0    |    1    | Team damage [(1)][boolean]
`sv_teleport_usetiles`   |    0    |    0    |    1    | Activate teleport tiles [(1)][boolean]
`sv_timelimit`           |    0    |    0    | &mdash; | Time limit in minutes [(2)][zero]
`sv_tournament_mode`     |    0    |    0    |    1    | Tournament mode. When enabled, players joins the server as spectators [(1)][boolean]
`sv_void_frozen`         |    0    |    0    |    1    | Freeze tees respawned after being killed by death tile [(1)][boolean]
`sv_vote_kick`           |    1    |    0    |    1    | Allow voting to kick players [(1)][boolean]
`sv_vote_kick_bantime`   |    5    |    0    |   1440  | The time to ban a player if kicked by vote. 0 makes it just use kick
`sv_warmup`              |    0    |    0    | &mdash; | Number of seconds to do warmup before round starts

[String variables][]
Variable                 | Description
-------------------------|------------
`sv_binaddr`             | Address to bind the server to
`sv_chatloop_message`    | A message to send to chat every `sv_chatloop_interval` milliseconds
`sv_gametype`            | Game type [(4)][gametypes]
`sv_map`                 | Map to use on the erver
`sv_maprotation`         | Maps to rotate between [(3)][oncyclemap-footnote]
`sv_motd`                | Message of the day to display for the clients
`sv_name`                | Server name
`sv_reserved_slots_pass` | Reserved slots password

[boolean]:             #boolean
[zero]:                #zero
[oncyclemap-footnote]: #oncyclemap-footnote
[gametypes]: #gametypes

<a name="boolean">(1)</a> This is a boolean value. 0 means disabled, 
1&mdash;enabled.

<a name="zero">(2)</a> Zero value disables this option.

<a name="oncyclemap-footnote">(3)</a> [`on_cyclemap`][on_cyclemap] can be used 
to implement more complex maprotation logic

<a name="gametypes">(4)</a> Available gametypes are: 
`ctf`, `tdm`, `dm`, `ictf`, `itdm`, `idm`, `ifrzctf`, `ifreeze`.

[on_cyclemap]: #on_cyclemap

## Functions callable from Perl

Functions providing a teeworlds API for the configuration script
are described in this section. Description of function signatures uses the
following conventions:

* _cid_ is an integer value corresponding to the client number. It's maximum
  value is `$MAX_CLIENTS` which is equal to 16. -1 is often used to designate the
  server itself.
* _gid_ is client group id.
* _time_ is time in seconds.
* _ip_ is 32-bit integer representing an IP address.

[groups]: #Groups

The functions:

* `config::int::get` _=>_ ___integer___: returns value of the configuration
  variable.
* `config::int::set` ___integer___: sets the value of the
  configuration variable.
* `config::int::min` _=>_ ___integer___: returns the minimum allowed value of
  the configuration variable.
* `config::int::max` _=>_ ___integer___: returns the maximum allowed value of
  the configuration variable.
* `config::int::help` _=>_  ___string___: returns description of the
  configuration variable.
* `config::str::get` _=>_ ___string___: returns value of the configuration
  variable.
* `config::str::set` ___string___: sets the value of the
  configuration variable.
* `config::str::help` _=>_ ___string___: returns description of the configuration
  variable.
* `say_rcon`  _cid_, ___string___: sends string to rcon of client _cid_
* `client_name`  _cid_: returns player name.
* `client_active` _cid_: tests whether there is a client with a given
  id.
* `client_addr` _cid_ _=>_ ___integer___: returns client IP.
* `server_kick` _cid_ , [___string___ _reason_]: kicks player
  _cid_ with reason _reason_. Default reason is "kicked by console".
* `server_ban` _cid_, _time_: bans player _cid_ for _time_ seconds.
* `server_ban_ip` _ip_, _time_: bans _ip_ for _time_ seconds.
* `server_unban` _ip_: unbans _ip_.
* `server_ban_num` _=>_ ___integer___: returns the number of active bans.
* `server_ban_get` ___integer___ _index_ _=>_ ___integer___ _ip_, ___integer___
  _time_: returns _ip_ and its expiration time _time_ for ban _index_.
* `record` ___string___ _filename_: starts recording a demo in file _filename_.
* `stop_record`: stops demo recording.
* `server_auth` _cid_, _gid_: sets client _cid_'s
  group id to _gid_.
* `client_gid` _cid_ _=>_ ___integer___: returns client _cid_'s
  group id.
* `server_start_vote` _cid_, ___string___ _chat\_message_,
  ___string___ _description_, ___code___ _command_: starts a vote.
  Here _cid_ is id of the client started the vote (use -1 for anonymous votes),
  _chat\_message_ is the line to display in chat, _description_ is the line to
  display in vote status window, _command_ is the Perl function to execute if
  vote passes.
* `vote_active` _=>_ ___integer___: tests whether a vote is running.
* `vote_enforce` ___integer___: force vote result.
* `send_chat` _cid_, ___integer___ _target_, ___string___ _text_:
  send chat message _text_ from client _cid_ to _target_. When _cid_ is -1,
  the message is sent on behalf of the server. Set _target_ to -4 to send the
  message to all players, -3 to spectators, -2 to the red team, -1 to
  the blue team or to _cid_ of the desired client.
* `send_broadcast` _cid_, ___string___ _text_: send _text_ to
  client _cid_ as broadcast (huge letters in the center of the screen). Set
  _cid_ to -1 to send _text_ to all players.
* `addvote` ___string___ _command_: add vote _command_ to the list of votes.
  _command_ must be a predefined command.
* `delvote` ___string___ _command_: delete vote _command_ from the list of
  votes.
* `restart` [___integer___ _warmup_]: restart the game. Do warmup for _warmup_
  seconds, 0 by default.
* `server_pause` [___integer___]: pause or unpause game. If no argument
  provided, toggle.
* `endround`: force end of the round.
* `set_team` _cid_, ___integer___ _team_: move player _cid_ to
  team _team_. set _team_ to -1 for spectators, 0 for red, 1 for blue.
* `set_datadir` _path_: make engine to look in _path_ for game files.

## Functions called from C

### Internal

These functions are not supposed to be defined in the configuration script. This
documentation is provided for those who would like to extend them.

* `execute_line` _cid_, ___string___ _command_: process the string received by
  rcon of client _cid_.
* `auth` _cid_, ___string___ _password_: called when a player enters some
  password into rcon prompt.
* `client_start_vote` _cid_, ___string___ _command_: called when a player starts
  a predefined vote.
* `on_event` ___string___ _event_, _args_: dispatching function for hooks to
  server events. See [events][Events].

### Public

These are hooks to tune the server reaction to events in game. Unless
stated explicitly, these functions are not defined by default.

* <a name="on_cyclemap">`on_cyclemap`</a>: called at the end of the round.
* `server_send_chat` _cid_, ___integer___ _target_, ___string____ _message_,
  ___integer___ _bind_: called when someone produces a chat message. _cid_ equal
  to -1 means the server. _target_ is the chat target as for `send_chat`, _bind_
  is true if the message is suspected to be bind (I think it may get false
  positive in case of bad network connection, but I could not make it
  happen). Note that the function return value is discarded. The function is
  supposed to call `send_chat` by itself. The default is to allow all non-binded
  messages.
* `server_set_team` _cid_, ___integer___ _team_: executed when a player wants to
  change team. _team_ is -1 for spectators, 0 for read and 1 for blue. The
  function is supposed to check whether changing teams is allowed and do the
  change via call to `set_team`.

## Implemented Perl functions

* A function for each of the config variable. It checks if it is being passed a
  value and if so, sets the corresponding variable, otherwise returns its value.
* `sv_playerlimit` ___integer___: limit the number of non-spectating players.
  Changes `sv_spectator_slots` accordingly.
* `find` ___code___ _test_, ___array___ _=>_ _element_: returns the first
  element in array that matches _test_.
* `position` ___code___ _test_, ___array___ _=>_ _index_: returns the index of
  the first element in array that matches _test_
* `reduce` ___code___, ___array___ _=>_ _scalar_: uses a binary operation to
  combine the elements of the array. The operation should be defined in terms of
  variables `$a` and `$b`, like the `sort` builtin.
* `max` ___array___ _=>_ _number_: returns the maximum number in array.
* `min` ___array___ _=>_ _number_: returns the minimum number in array.
* <a name="init">`init`</a> ___string___ _path_, ___integer___ _system\_gid_,
  ___integer___ _system\_uid_: [chroots][chroot] to _path_ and sets the server
  group id and user id to _system\_gid_ and _system\_uid_. Do not confuse
  _system\_gid_ and _system\_uid_ with _gid_ and _cid_ used elsewhere in
  documentation! See [REPL][REPL] for details.
* `reply` ___string___ _message_: sends _message_ to the current client defined
  by `$RCON_CID` global variable. Teeworlds doesn't support tab characters
  (`"\t"`) and it doesn't like newlines (`"\n"`), so the former are replaced
  with eight spaces, and the latter are handled by several calls to `say_rcon`.
  If you need to send large amount of text, see `more`.
* `quoted_string` ___string___ _quote_: returns a regular expression that
  matches a string quoted with _quote_ with possibly escaped quotes inside.
  For example, `quoted_string('"')` will match to the whole string `"abc\"def"`.
* `player_cid` _player_ _=>_ _cid_: returns _cid_ of a player corresponding to
  _player_. The latter can be a number, a string or a regular expression.  The
  number is returned immidiately as long as it is a valid _cid_ of active
  client. The string is used to find a player whose name is equal to that
  string. The regular expression is used to find a player whose name matches the
  expression. If several names match, the function dies.
* `to_seconds` ___string___ _time_ _=>_ ___integer___ _time_: given a string
  representing some time, returns its value in seconds. The string should be
  made of sequences `number` `time_unit`, possibly divided by spaces. For
  example, "4d 3h 15" means four days, three hours and fifteen seconds. Known
  units are: `s`&mdash;second, `m`&mdash;minute, `h`&mdash;hour, `d`&mdash;day,
  `w`&mdash;week, `M`&mdash;month, `y`&mdash;year, `i`&mdash;infinity.
* `from_seconds` ___integer___ _time_ _=>_ ___string___ _time_: given a time in
  seconds, produces human-readable string describing this time. This function is
  the reverse of `to_seconds`.
* `ip` ___string___ _ip_ _=>_ ___integer___ _ip_: converts an _ip_ represented
  by a string with four decimal numbers ("127.0.0.1" for example) to 32-bit
  integer.
* `sprint_ip` ___integer___ _ip_ _=>_ ___string___ _ip_: the reverse of `ip`.
* `sprint_group` ___integer___ _gid_ _=>_ ___string___ _group\_names_:
  concatenates names of groups the given _gid_ belongs to.
* `status`: prints the list of players to the active rcon.
* `kick` _player_: kicks player _player_.
* `ban` _player_, _time_: bans player _player_ for _time_. 
* `unban` ___string___ _ip_: unbans _ip_.
* `bans`: prints current ban list in rcon.
* <a name="su">`su`</a> _password_: adds user to the group with the
  corresponding password field.
* `start_vote` [_cid_, ] ___string___ _description_, ___code___ _action_: starts
  a vote on behalf of the client _cid_. If _cid_ is not provided, `$RCON_CID` is
  used. _description_ is the vote description, _action_ is the code to execute
  if vote succeeds.
* `start_cmd_vote` [_cid_, ] ___string___ _command_: starts vote for a predefined
  command. If _cid_ is not provided, `$RCON_CID` is used. Dies if user has no
  permission to run the vote.
* `vote` _result_: force a vote. Use `yes` or 1 to force yes, `no` or 0 to force
  no.
* `call_interactive` ___code___: call an interactive function.
* `splitn` _string_, _n_ [, _fuzz_] _=>_ _substring1_, _substring2_: splits the
  string near the character number _n_. _substring1_ length is no more than _n_.
  If there is a punctuation character among the last _fuzz_ characters, the
  split will occur after that character. By default _fuzz_ is _n_ / 5.
* `split_long_string` _string_, _limit_ _=>_ ___array___: splits a long string with
  `splitn` so that the resulting strings will be of no more than _limit_
  characters in length.
* `more` ___array___ _text_: implements a simple text viewer like [more][].
* `help` [___string___ _command_]: prints help for the predefined command. With
  no parameters prints the list of available commands.
* `chat` [[_cid_, ] _target_] _text_: send _text_ to _target_'s chat on behalf
  of the client _cid_. By default _cid_ is -1 which means the server. _target_
  can be `all` for everyone, `spec` for spectators, `blue` for the blue team,
  `red` for the red team or player id. Default is `all`.
* `broadcast` [_cid_, ] _text_: broadcasts _text_ to client _cid_. Default is -1
  which means everyone.
* `team` _player_, _team_: join player _player_ to team _team_. _team_ must be
  one of `spec`, `red`, `blue` or -1, 0, 1.
* `pause` [_on_]: pause the game, if _on_ is false, unpause; if it is not
  specified, toggle.
* `free_gid` _=>_ _gid_: returns the next free gid. The function assumes that
  gid basis are powers of two and computes the next free orthogonal gid number.

[more]: http://linux.die.net/man/1/more

## Global variables

* `$MAX_CLIENTS`: the maximum number of clients the server can hold. This
  variable is not supposed to be changed. In the current version it is equal to
  16.
* `$root_gid`: root group id. It is set to `~0`, which means "every possible
  group". This variable is not supposed to be changed.
* `$RCON_CID`: id of the current client. It is set to -1 when the code is being
  executed by the server request.
* `%groups`: a hash of groups. Keys are group names, values are hashes with keys
  `gid` and `password`.
* `%commands`: a hash of predefined commands. Keys are command names, values are
  hashes with keys `gid`&mdash;binary or of ids of groups allowed to run the
  command, `sub`&mdash;the code to execute, `help`&mdash;an optional help string,
  `vgid`&mdash;an optional binary or of ids of groups allowed to vote for this
  command, `vcheck`&mdash;an optional function to run before starting the vote.
  `vcheck` should check the correctness of the parameters passed. Its arguments
  are: client id, client group id, arguments string.
* `@interactive`: when a player executes an interactive command like `more`,
  this array keeps the code interpreting player responces.
* `$more_cols`: the average number of characters fit on the screen for the
  `more` function.
* `$more_rows`: the number of rows fit on the screen for the `more` function.
* `%hooks`: a hash of hooks to server events. See [events][Events].

## Interactive functions

An interactive function is a function that may ask the user for additional input
while being executed. Since teeworlds is a single-threaded program, it is
impossible to implement it in a straightforward way, because the server will hang
while the player is talking to the function. Although the multi-threaded
approach still can be implemented, I decided to do it in a simpler way. To
create an interactive function, define the function that interpretes the user
answer and `unshift` it into the `@{$interactive[$RCON_CID]}` array. You may use
`call_interactive` for this purpose. You are free to modify
`$interactive[$RCON_CID][0]` during execution. Don't forget to `shift` the array
back when the function returns (with `call_interactive` you may call `$quit->()`
closure variable). Here is a simple example:

    sub ask_me {
     reply 'To be or not to be?';
     call_interactive {
      given ($_[0]) {
       when ('to be') {
        reply 'Ok, to be';
        $quit->();
       };
       when ('not to be') {
        reply 'Are you sure?';
        my $quit_top = $quit;
        call_interactive {
         given ($_[0]) {
          when ('yes') {
           reply 'If you say so';
           $quit->();
           $quit_top->();
          };
          when ('no') {
           reply 'So, to be or not to be?';
           $quit->();
          };
          default {
           reply 'What?';
          }
         }
        }
       };
       default {
        reply 'What??';
       }
      }
     };
     return undef;
    }

The `$quit` variable in the example contains the reference to the code that
clears the function out of the `@{interactive[$RCON_CID]}`.

The concept of interactive functions is not well-thought yet. If you really need
such function, perhaps you better read the sources to understand what kind of
magic is going on there. Currently only `more` function uses `call_interactive`,
maybe later if I need other functions, I'll make a saner interface.

## Events

Configuration script may customize server behaviour in case of different events.
For example, it may define actions that should be done when the game is over or,
in case of player leave, release the memory that is no longer needed. That is
achieved by means of hooks to server events. Hooks are subroutines stored in
`%hooks` hash. They are called when the corresponding event happen with some
parameters describing the event.

In order to ease configuration and let modules to use hooks without clashing
with other modules, the `%hooks` hash stores subroutines in the following way:
each entry in `%hooks` is a hash, elements of which are subroutines and keys are
some names assigned to these subroutines, for example

    $hooks{'leave'}{'log'} = sub {
      printf LOG '%s has left the game', client_name($_[0]) 
    };

defines a function named `log` that will print a string to the `LOG` stream when
someone leaves the game. When an event happen, all subroutines in the hash stored
under the corresponding event name are executed (in this case these are 
`values %{$hooks{'leave'}}`). Hence modules can define their functions under
module-specific names and avoid the clash with other modules.

Defined events are:

* `cyclemap`: end of the round, when it is the appropriate time to change the
  map.
* `enter` _cid_: player with client id _cid_ has entered the game.
* `leave` _cid_: player with client id _cid_ has left the game.
* `start round`: Warmup (if any) has done and the new game started.
* `end round`: The game is over, declaring the winner.

# Modules

In order to simplify configuration for several servers, most useful features are
provided in form of modules or packages in Perl terminology. To include modules
in your script, just `use` it, for example:

    use Teeworlds::Common;

The `@INC` array that holds paths used by Perl to find module files is modified
to include `~/.teeworlds` and `src/config` directories. If you want to run the
server from the place other than teeworlds repository directory, either copy
`src/config/Teeworlds` to `~/.teeworlds` or modify `@INC` appropriately.

## Common

`Teeworlds::Common` contains a set of the most common features: rcon commands
required to effectively control the server and a few useful functions. It is
expected to be included in every not-very-unusual configuration script, so it
fills the `main` namespace with its symbols. Other modules may depend on it. 

`Teeworlds::Common` provides the following functions:

<ul>
<li><code>parse_player_name</code> <i><b>string</b></i> <i>=></i> <i>id</i>,
 <i>rest</i> extracts player id from string. <i>id</i> is the value that can be
 passed to <code>player_cid</code> to get the player client id. The function
 uses the first non-whitespace character to determine the type of the result:

<ul>
 <li><code>Jini, blah</code> results in <code>(/Jini/i, 'blah')</code></li>
 <li><code>/Jini/, blah</code> results in <code>(/Jini/,  'blah')</code></li>
 <li><code>'Jini', blah</code> results in <code>('Jini',  'blah')</code></li>
 <li><code>"Jini", blah</code> results in <code>('Jini',  'blah')</code></li>
</ul>

  In the latter form you can use backslash to escape the quote, as is usual in
  Perl. For example, <code>'"a\"b", blah'</code> results in <code>('a"b',
  'blah')</code>. In every case <code>blah</code> is optional. If the function
  is evaluated in scalar context, it returns only the player id.</li>
<li> <code>inferior_player_cid</code> <i>caller_cid</i>, <i>args</i> <i>=></i>
 <i>id</i>, <i>rest</i>: same as <code>parse_player_name</code> <i>args</i>, but
 it also checks that the specified player exists and its gid is lower than
 <i>caller_cid</i>. The function dies if the check fails.</li>
<li> <code>man</code> [<i>topic</i>]: prints to rcon commands descriptions or
 other information stored in the <code>%man</code> hash. When invoked without
 arguments, prints keys of <code>%man</code>. When argument matches the key of
 <code>%man</code>, prints its data. When the argument matches command name,
 prints contents of field <code>man</code> of the corresponding
 <code>%commands</code> entry.</li>
<li> <code>mute</code> <i>target</i>: mutes the chat. <i>target</i> may be one
 of: team, public, all, or player name suitable for <code>player_cid</code>.
 </li>
<li> <code>unmute</code> <i>target</i>: unmutes the chat.</li>
<li> <code>set_map</code> <i>map</i>: changes current map to <i>map</i>. This
 function may be invoked with the <code>map</code> command and is supposed to be
 redefined if more complex logic but call to <code>sv_map</code> is desired.</li>
<li> <code>list_maps</code> <i>=></i> <i><b>array</i></b> <i>maps</i>: returns
 the list of available maps. This function is invoked with the <code>map</code>
 command and is supposed to be redefined if more complex logic but return the
 contents of <code>@maps</code> array is desired.</li>
</ul>

`Teeworlds::Common` provides the following groups: root, admin, and user, with
gids `$g_root`, `$g_admin`, `$g_user`. By default no password is defined, so
groups are inaccessible. 

`Teeworlds::Common` provides the following commands:

* `ban` _player_: bans the player.
* `bans`: prints the list of active bans.
* `broadcast` _message_: sends broadcast message to all players.
* `broadcastp` _player_ _message_: sends broadcast message to a specific player.
* `help`: provides short commands description.
* `kick` _player_: kicks the player from the server.
* `man` [_topic_]: provides additional information.
* `map` [_map_]: change the map or list available maps.
* `mute` _target_: mute _target_ (see `mute` function).
* `pause`: pause or unpause the game.
* `status`: print the list of players together with their client ids, IPs and groups.
* `restart` [_warmup_]: restart the game.
* `start_vote` _command_: start a vote for _command_.
* `su` _password_: grant the rights of the group with matching password to the
  player.
* `sv_playerlimit` ___integer___: limit the number of playing players.
* `team` _player_, _team_: move _player_ to _team_.
* `unban` _ip_: remove the ban from _ip_.
* `unmute` _target_: unmute _target_ (see `unmute` function).
* `vote` _result_: force the vote.
See the code for the details.

## Captains

`Teeworlds::Captains` provides support for the captain games. The captain game
starts with two players being elected as captains. They join opposing teams and
start choose other players in turns. The player chosen joins the team of the
corresponding captain. When both teams are built, the actual fight starts as
usual.

To start the game, two captains must be elected by means of `elect` command. By
default it can only be voted, so the majority of players have to want to play
the captain game and agree on who they want to be their captain. When both
captains are elected, everyone is forced to spectate and captains are joined
opposing teams. At this stage captains may choose their teammates by means of
the `choose` command or pass their turn to the other team via the `skip`
command. Red team chooses first. By default team balance is not set, so it is
possible to play unbalanced games. When team building is done, both captains
must invoke `ready` command and the game starts after a warmup. While playing,
the game can be paused via `stop` command and unpaused when both captains
invoke `ready` command. When someone leaves, the game pauses and it must be
unpaused in the same way. If both captains leave, the game is dropped.

To stop the captain game, vote for the `drop_game` command. The captain may be
de-elected via `drop_captain` command.

`Teeworlds::Captains` uses a lot of features from `Teeworlds::Common` and
expects it to be included first.

`Teeworlds::Captains` provides the group `captain` with gid `$g_captain`.

`Teeworlds::Captains` provides the following commands:

* `elect` _player_ [, _team_]: elect a captain for _team_. Free team is used by
  default. If there already is a captain for the given team, he will be
  superceded.
* `choose` _player_: joins the player to the team of the captain who has invoked
  the command.
* `skip`: pass the turn to choose to the other team.
* `ready`: tell the world that your team is ready to start or continue the game.
* `drop_game`: drop the captain game.
* `drop_captain`: de-elect the captain.
* `spec`: the captain may use this command to force a teammate to join the
  spectators. Teambalance is updated accordingly so he can choose someone else then.
* `stop`: pause the captain game.

## Random maps

`Teeworlds::Random_maps` sets random maprotation on the server. To define the
available maps, use `%maps` hash with keys being map names and values being
hashes with keys `probability` setting the probability for a map to appear. The
probabilities don't have to be normed to one; when all maps have been defined,
call `normalize_maps` function to compute real probabilities. They will be
stored under the `p` fields in values of `%maps` hash. Here is a short usage
example:

    %maps = (
      ctf2 => { probability => 0.5 },
      ctf4 => { probability => 0.5 },
      ctf5 => { probability => 0.3 },
    );

    normalize_maps;

After the call to `normalize_maps` `$maps{'ctf2'}{'p'}` and `$maps{'ctf4'}{'p'}`
are equal to 0.38, and `$maps{'ctf5'}{'p'}` is equal to 0.23.

`Teeworlds::Random_maps` provides the following functions:

* `normalize_maps`: recomputes the probability for maps to appear using values
  stored in `probability` fields of values in `%maps` hash. See above for
  example.
* `get_next_map` _=>_ _map_: returns the next random map.
* `next_map`: changes the current map to the next random one.

The `next_map` function is also available as a command.
