Invincible Countermeasure

Copyright 2015 Linley Henzell

Version: beta 2

1. Introduction


Invincible Countermeasure is a game of defending/infiltrating computer systems (although it won't teach you anything about how to do this in the real world). It has singleplayer modes and also supports play-by-email multiplayer; networked multiplayer may be implemented sometime in the future.

This is the manual. Fortunately, you don't need to read it to play the game - it's mostly a detailed reference for advanced players, so if you just want to play then start up the game and play the tutorials and missions. You can get basic help about what most of the buttons and other objects in the menu interface (although not currently the game interface) by right-clicking on them with your mouse.

You can also change some of the game's settings (like the size of the game window, fullscreen, sound volume etc) by editing init.txt.

Invincible Countermeasure is licensed under the GPL v3 (or later), and source code is available online. To build it you will need a C compiler (I use gcc) with the Allegro 5 library (I have 5.0.10;  5.1 may work as well). See the comments in m_main.c for more information about building the game.


A note on security


This game executes user-supplied bytecode inside a simple virtual machine. I've done my best to make sure everything the bytecode interpreter does is bounds-checked, heavily supervised and as far away from system calls as practicable. But I'm not a professional programmer and I can't guarantee that the virtual machine is bulletproof when running unknown code by other people, especially in its current state as an untested beta. Exercise discretion when running other people's processes etc, particularly in bcode form!

See also the Disclaimer and Limitation clauses of the GPL (in licence.txt in the main game directory).


Contents


2. Basic things


Your task is to defend (or, perhaps, attack) a computer system, represented on your display by a large rectangular arena. In this world your will is executed by processes running on the system; processes can move, sense their surroundings, attack, reproduce and many other things. In some environments you can control them directly, while in others they are free to make their own decisions.

2.1 Types of programs


The game recognises a few different kinds of programs:
There are examples of each kind of program in the src subdirectory, with prefixes indicating what kind they are (pr = process, op = operator, ob = observer, sy = system, m = mission system). Files with the prsc prefix use the standard command macros in the stand_coms.c file, which means that they are designed to work with an operator. Files with just the pr prefix are autonomous processes.

The missions subdirectory contains the same source files as the src subdirectory, but they are used for missions. It's probably best to leave them alone and work in the src subdirectory.

2.1.1 Processes


Each process is a small (<=8KB) bytecode program running in a 16-bit virtual machine. The game comes with a number of pre-written processes you can use, and you can write your own using the game's built-in C compiler and assembler.

Processes use three resources:
Each process has an interface which allows it to interact with other processes and the world around it. A process' interface gives it shape and size and also sets out a range of methods that the process can use. Methods affect a process' characteristics or give it access to some kind of special function. Some methods are external and can be seen on the outside of the process' interface, like the Move method that allows a process to move around, while others are internal, like the Maths method that performs various calculations.

One way that processes can interact with each other is by generating destructive data packets, and if a process absorbs too many of these it will be explosively deallocated. Achieving your goals will probably involve deallocating your opponents in this way, but exactly what your objective is will depend on the nature of the computer system you are trying to control.

2.1.2 System programs


The system is controlled by a system program, which is a bytecode program running in the same kind of virtual machine as a process but with a range of special privileges. A system program's interface defines the arena in which the conflict takes place, and a system program has access to a special set of methods that give it control over basically everything. System programs don't require data, but are subject to (generous) limits on interrupts (3000 per tick) and instructions (30000 per tick).

Among other things, a system program can spawn processes - and it is this capability that an attacker must exploit.

2.1.3 Observer programs


You will need some way to watch what's going on, and this is what an observer program is for. It has access to methods that can read user input from the mouse and keyboard, move the viewing screen's "camera" around and present various forms of information to you. However, it can't interact with processes directly.

The system program may prevent the use of an observer program, as all of an observer's functions can be performed by an operator program (see below) or by the system itself.

Like system programs, observers execute once per tick and have 3000 interrupts and 30000 instructions to play with.

2.1.4 Client programs


Each player (including computer-controlled players) can have its own client program, if the system allows it. A client program serves as a kind of supervisor, keeping track of what your processes are doing and issuing commands through a special command method. Client programs execute each tick and have the same interrupt and instruction limits as system programs and observers.

There are two kinds of client programs: operators and delegates. Which kind you can use depends on the system program's settings.

2.1.5 Client (operator)


An operator is a client program that also has access to the observer methods that allow user input and exercise control over the user interface. Basically, an operator lets you play the game directly, by turning mouse clicks and keystrokes into commands issued to your processes.

2.1.6 Client (delegate)


A delegate is just like an operator that can't use observer methods. It can supervise your processes and coordinate their activities but it can't read user input, so it has to be able to work autonomously.

If the system allows you to use an operator, you can use a delegate instead and waive the right to issue commands directly. If you do this, you'll probably also want to load an observer (or you won't have much of a user interface).

2.2 Templates


You can open the template menu by clicking on the little "Te" button near the top right of the screen.

To load any kind of program into the game, you need to put it into a template. When the game first starts the only open template is for a system program, but when you start playing you may be able to use process, observer, delegate and operator templates as well (exactly which types are available depends on the rules set by the system program). Process templates can be used by the system program to introduce processes into the world, and when one process creates another process it can copy the new process' code from a process template. The system program can also load observer, delegate and operator programs from the respective templates.

You can load a file directly from disk into a template using the "load file" button on the template display. Two types of file are accepted: compiled bcode (bytecode) files (with a .bc extension) and source files (with a .c extension). When you load a source file the code is compiled automatically; if there is an error, the error message appears in the message log at the bottom of the template window.

You can also import a file from an open tab in the code editor using the "import from editor" button.

If you don't need a file in a template any more, you can clear the template with the "clear" button.

2.3 Code editor


To open the code editor, click on the little "Ed" button near the top right of the screen.

The code editor is a basic integrated development environment for the game's built-in compiler and assembler. You don't have to use it - you can use another program entirely to edit your source files (I use Code::Blocks), then use them by loading directly into templates - but it has some features that can be useful, like test compilation and code completion for various keywords.

The File, Edit and Find menus contain basic editor functions that do obvious things. Note that editing or saving a file that is loaded into a template will not change the version in the template, so you will need to clear and reload the template to update it.

The Build menu gives you various tools for testing and analysing code (although since loading a source file into a template automatically invokes the compiler, you don't strictly need to use any of them). The Build menu has the following functions:
Test build
This attempts to compile the currently open tab. If successful, the results are discarded.
Build bcode
This attempts to compile the currently open tab, and if successful it puts the result in a new bcode tab (although this may not be very useful, as the editor can't do much with pure bcode).
Build asm
This attempts to compile the currently open tab into assembly language, and puts the result in a new tab.
Crunched asm
This does the same as Build asm, but tries to shorten the generated asm code by fitting multiple instructions on each line (because with one instruction per line, generated asm is often too long for the editor).
Convert bcode
If the currently open tab is a bcode tab, this converts it into editable asm format. It will just be numbers, though (I may get around to writing a disassembler at some point).
Import bcode
Use this during a game to import bcode from the currently selected process (this is the process whose information is being displayed in the process information box in the game display). The process' current bcode state will be copied directly into a new bcode tab.

Some limitations of the editor:
These are also limitations of the compiler, which can't load files that have too many lines (you can get around this with #include) and will have problems with files with lines that are too long (you'll get a warning).

2.4 Menu interface


When you first start the game, you are in the start-up screen.

The left side of the screen has a game menu with the following options:

Missions
Start playing a single-player mission.
  • Advanced missions
  • Start playing an advanced single-player mission.
    Tutorial
    Start playing the tutorial. Try this first!
    Use System File
    Start a game from a system file loaded into the system file template (which is in the templates panel on the right-hand side of the screen).
    Load Saved Game
    Load a saved game (*.sav) from disk.
    Load Gamefile
    Load a gamefile (*.gam) from disk. Used for multiplayer games.
    Exit
    Exit.


    Panel buttons

    A row of icons in the top right of the screen lets you switch what the panel on the right-hand side of the screen is used for:
    Te (Templates)
    Opens the template menu.
    Ed (Editor)
    Opens the code editor and compiler.

    When you are playing the game, three more buttons appear:
    Pr (Programs)
    Gives you information about the performance of the system file and other programs.
    Sy (System menu)
    Opens a menu allowing you to start/stop the game, save to disk etc.
    X (Close)
    Closes the panel so you can see more of the game.

    3. Playing the game


    There are two basic ways to begin playing the game: starting a mission, and loading a system file.

    3.1 Missions


    Missions are pre-set single-player games. Some of them are tutorials, which you should probably play through before you try anything else.

    When you open the Missions menu, a number of default mission templates open in the template panel. Programs loaded into these will be available at the start of each mission you play until you exit the game. They start preloaded with a basic operator, a factory and a defender process, but you can change these if you want to.

    There are also advanced missions: these are the same as the normal missions but do not allow operator programs, so you will have to use a delegate (or autonomous processes).

    3.2 Starting from a system file


    To use a system file, load it into the System File template (which is in the Template panel to the right of the main menu), then click on the Use System File button in the main menu. This will open a setup menu which lets you set the game's basic parameters (unless the system program has made them unmodifiable).

    The setup menu works like this:
    Start
    Starts the game.
    Players
    This is the number of players, including any that are computer-controlled. The game supports 2, 3 and 4 player games.
    Turns
    A game can be set to last for 1 to 16 turns. If the system program allows it, setting the number of turns to zero makes them unlimited (although the system program can end the game and declare a winner at any time it wants).
    Turns may not be particularly important for a single-player game, but in a multiplayer game the end of a turn is the time when players can update their templates before sharing turnfiles.
    Minutes per turn
    A turn can be anything from 1 to 60 minutes long. If the system program lets you set the turn length to zero, turns will be indefinitely long (the system program can end them, though).
    Processes
    This is the maximum number of processes each player can have at once (1 to 200).
    World size (x/y)
    This is the size of the world, in 128-pixel blocks (the maximum width or height is 80 blocks, or about 10,000 pixels).
    Player names
    You can change the player names, if you like.
    Save gamefile
    Gamefiles are used for multiplayer games (see below).
    Exit
    Returns to the main menu.

    3.3 Multiplayer


    Currently, play-by-email multiplayer with up to four players is supported (simultaneous networked multiplayer may happen one day, but not yet).

    A multiplayer game starts off with a system program designed for multiplayer, which one player or a neutral party uses to create a gamefile. Players take turns by setting up their templates with code that gets turned into processes in the game, and other code that supervises and directs those processes (their delegate program). Each player makes a turnfile containing the code in their templates, which they share with all the other players. It's up to the players to work out how to best make use of their templates! But the obvious ways to do so are to write new strategies into delegate programs and update the structure and tactical code of newly created processes (existing processes can't be reprogrammed directly).

    Detailed instructions on how to set up and play a multiplayer game:

    1. One player (or a neutral party) loads an appropriate system file into the system file template and clicks "Use System File" to enter the game setup menu.

    2. They use the setup menu to set up the game parameters (number of players, player names, size of world etc.) then use the "Save Gamefile" option in the setup menu to save a gamefile, which they then send to all players by attaching it to an email or something like that.

    3. Each player opens a copy of the gamefile using the "Load Gamefile" button in the main menu.

    4. Each player takes their turn by loading program/process files into their templates. At this stage players can test their processes/programs as much as they want.

    5. Each player uses the "save turnfile" option at the top of their section of the template menu (this saves the contents of their templates to a .tf file).

    6. Each player sends their turnfile to all other players.

    7. When everyone has everyone else's turnfiles, each player opens the gamefile again and loads all of the players' turnfiles using the "load turnfile" option in the players' sections of the template menu.

    8. Each player runs the game until the turn is over or someone wins.

    9. If a winner is declared, it's game over!

    10. Otherwise, go to step 4.


    Notes on multiplayer:

    4. Compiler


    Invincible Countermeasure is in essence a programming game. One way to program it is to write directly in bytecode, but you probably don't want to do that. Instead, you can use its special dialect of C!

    The game's built-in compiler is available from the code editor, and is also automatically called when you load a source file into a template. It is not a very good compiler. It has a range of limitations and odd features, some dictated by the environment but most resulting from the fact that I don't really know how to write a compiler.

    (What I do know about how compilers work I learned from Serge Zaitsev's CUCU project (quote: "Never, please, never do it this way!"), which is the only explanation of basic compiler design that has made any sense at all to me. See http://zserge.com/blog/cucu-part1.html.)

    The compiler also has an inline assembler. See the Assembler chapter below for details.

    Some of the compiler's "special" characteristics are:

    The programs in the src directory are full of comments, so you could look at those if you're trying to work out how to code in this environment.

    4.1 Some C keywords that work differently


    static


    Declaring a variable as static should work as expected, except that it will retain its value through repeated executions.

    Declaring a function as static means something different: it makes all of the function's local variables, including function parameters, static by default. The overhead involved in using automatic variables makes it a good idea to always do this unless you are using recursion or something like that.


    auto

    Currently, automatic arrays cannot be initialised with the syntax:

    auto int hello [4] = {0, 1, 2, 3}; // this does work for static arrays, though
    You will have to initialise each value separately:

    auto int hello [4]; // although since auto is the default in an automatic function and can't be used in a static function, the auto keyword is unnecessary
    hello [0] = 0;
    hello [1] = 1; // etc

    Sorry. 


    main

    The main function's type is static void main(void).


    switch

    Switch should work as expected, but the compiler always turns a switch statement into a jump table. This is good where there are lots of cases with not too much space between them, but not so good if there are just a few cases or the cases have large gaps.


    for

    Because statements and expressions aren't interchangeable, for statements must always be in the form for (<statement>; <expression>; <statement>).

    This shouldn't be a problem for basic uses like for (i = 0; i < 10; i++) but may make some tricks difficult.


    exit

    Since there's no stdlib, there's no exit function. I should really write one. Until I do, you can exit by returning from main or by using the asm exit instruction like this:

    asm {exit}

    Some other things that are not supported:

    variable types that are not int

    the ternary ? operator

    const

    typedef

    sizeof

    restrict

    extern

    register

    volatile


    4.2 Processes and sub-processes


    Processes that create other processes don't always have to copy their code from templates - they can copy parts of themselves into other new processes as well. This is what process definitions are for.

    A process definition looks like this:


    process i_am_a_process; // this declares/prototypes i_am_a_process as a process.
                            // Put it at the start along with function prototypes.
    process i_am_a_process // this is the definition of i_am_a_process
    {
    // Process code goes here.
    // The process should have an interface definition, a main function and anything
    // else it will need to be able to function independently.
    // You can use #include here to include another whole file as a sub-process.
    }
     
    In this example, i_am_a_process is a sub-process of the process in which its definition appears, which we'll call the main process. This means that the main process can use the code inside the process definition to build new processes - see the details of the MT_PR_NEW method for how to do this. Some uses of sub-processes are:
    The code inside a process definition is not directly visible to the main process, and cannot be executed directly by the main process (as each process definition has its own address space which assumes that the start of the process is address 0). However, a sub-process' bcode can be modified at runtime. Compiled code can't do this without horrible pointer arithmetic, but the assembler has a scope command that can be used to modify sub-processes. Modifications will apply to any processes newly created from the modified sub-process definition.

    The assembler has a corresponding type called an aspace (address space). Each process definition also implicitly defines an aspace with the same name for asm code to refer to.

    4.3 Preprocessor


    The preprocessor deals with both compiled and assembled code. It works mostly like a standard C preprocessor, but with some differences.

    The following standard directives are supported:

    #include

    #define

    #undef

    #ifdef

    #ifndef

    #endif

    #error

    The #define directive does not currently allow function-like macros. A macro must be a single text string, and can't have parameters.

    The #error directive does not currently allow an error message to be defined (so the directive is just #error). You will get a file name and line number report, though.

    The name of the file to be included by an #include directive should be surrounded by quotes ("), and not angle brackets (<>). The path specified in the directive should be relative to the location of the file in which the #include appears.

    One potential problem with using the #define directive is that a #defined macro stays around for the rest of the preprocessing stage, or until #undef'd. This will cause problems if you are using #include to bring together multiple files and some of those files use the same macros. To help deal with this, the special #subdefine directive produces a macro that is only visible within the file it appears in and any file #included by that file.

    Also, these are not supported yet:

    #if

    #else

    #elif

    #line

    #pragma


    4.4 Memory and registers


    Each program consists of a certain number of 16-bit words of memory: 4096 (processes), 8192 (observers/clients) or 16384 (system). This contains all of the program's code and data.

    The first two addresses are taken up by a jump to the main function (or wherever the programs starts), followed by the program's interface definition, which is a few dozen words long (the exact length depends on the program type). In compiled code (but not necessarily assembled code) the interface definition is followed by code, including any sub-processes, then static data, then the stack. The stack grows upwards from the end of the program.

    Programs have access to a few different sets of registers:
    Processor registers
    These are the registers used for basic computation There are eight of them, A to H, and you don't need to worry about them unless you're writing in assembly language. Unlike the other kinds of registers, these are reset to zero each execution cycle.
    Method registers
    Each program has a "bank" of 64 method registers, 4 for each method slot. Method slot 1 can use method registers 0 to 3, method slot 2 can use 4 to 7 etc. Some methods take up more than one slot and can use 8, 12 or 16 method registers. Compiled code can address method registers using the get, put and call built-in functions.
    Method registers have a few different purposes: they can determine what happens when a method is called, they can contain useful information about what the method is doing, and they can determine how a method behaves between execution cycles. Exactly what each register does depends on the type of method it is associated with. The method descriptions below have a full description of how each method uses its registers.
    Command registers
    Each process has 16 command registers than can be read or written to by both the process and the client program belonging to the same player (allowing them to communicate with each other). The MT_PR_COMMAND, MR_PR_STD, MT_CL_COMMAND and MT_CLOB_STD methods can address these registers.
    System/observer shared registers
    These registers are shared by the system and observer (or operator). They allow communication between these programs, similarly to the way the command registers allow a client to communicate with its processes. The MT_OB_CONTROL and MT_SY_MANAGE methods can address these registers.

    4.5 Built-in functions


    The compiler has a number of built-in functions. Some of them give access to basic features of the environment, while others facilitate the use of methods so that you don't always have to use the clunky put/get/call functions.

    4.5.1 Basic built-in functions


    These are always available, and can be used by all program types.


    put()

    int put(<constant> int method, <constant> int method_register, int value ...)


    This sets a method register to a specified value. method, which must be a constant, is the index of the method and should be a number from 0 to 15. method_register, which should also be a constant, is the index of the register as an offset from the first register associated with the method. value is the value that the register will be set to. If multiple values are passed, they are put in successive registers.

    It returns 1 on success, 0 on failure.

    The MB_* number tokens are built-in macros that identify each method register for each method type. See Methods for lists of the MB tokens for each method.

    Example:

    put(METH_MOVE, MB_PR_MOVE_RATE, 5, 16);
    This sets the first register (the RATE register) of the process' move method to 5 (this affects the rate of movement), and the second register (which affects how long the method will be activated for) to 16. It assumes that METH_MOVE is an enum or macro that the user has defined to specify the index of the move method.

    If either the method index or the method register index need to be variables, you can't use put(). Use put_index() instead.


    get()

    int get(<constant> int method, <constant> int method_register);

    This is the opposite of put. It returns the value in a method register.

    Example:

    a = get(METH_MOVE, MB_PR_MOVE_RATE);

    put_index()

    int put_index(int method_register, int value ...)

    This is like put(), but method_register is the target register's index in the whole bank of method registers. Each process has 64 registers in its method bank, and each method has 4 registers assigned to it (or 8, 12 or 16 if the method takes up multiple slots). Unlike in put(), method_register can be a variable.

    Example:

    put((METH_MOVE * 4) + MB_PR_MOVE_RATE, 5, 16);
    This does the same thing as the example given for put() above.


    get_index()

    int get_index(int method_register)

    This is the get version of put_index().

    Example:

    a = get((METH_MOVE * 4) + MB_PR_MOVE_RATE);

    call()

    int call(int method, <int value ...>)

    This calls a method and returns the method's return value. method should be the index of the method (0-15). What actually happens when a method is called depends entirely on what kind of method it is; some need to be called to do anything, while others don't need to be called at all.

    If one or more values are also passed, they are put into the method's registers (starting at register 0) before the call is executed. This saves the need to write out a put statement before the call. Currently, you can only do this if method is a constant.

    Example:

    a = call(METH_DESIGNATE, MS_PR_DESIGNATE_LOCATE);
    This puts MS_PR_DESIGNATE_LOCATE into the first register of the process' designate method (MB_PR_DESIGNATE_STATUS), then calls the method and leaves the method's return value in a. It assumes that METH_DESIGNATE is an enum or macro that the user has defined to specify the index of the designate method. MS_PR_DESIGNATE_LOCATE is a built-in method status macro which tells the DESIGNATE method to find its currently designated target.


    process_start()

    int process_start(process process_name)

    This returns the start address of a process (called process_name) that is a sub-process of the current process. The sub-process must have been declared previously.

    It doesn't work with sub-sub-processes (you can use asm for that if you really want to).


    process_end()

    int process_end(process process_name)

    Just like process_start, but for the other end.


    print()

    void print(...)

    print sends a message to a console. By default, everything you print is coloured light grey and goes to console 0. You can change this using the MT_OB_CONSOLE method.

    print accepts three kinds of parameters:

    1. String literals:

    print("Hello!"); // no C-style formatted string input, sorry
    2. Expressions:

    print(a + 5);
    3. Addresses of null-terminated strings:

    print($&string [0]); // the $ sign tells print to treat what follows as the address of the first element of a string

    A single print statement can contain multiple kinds of things separated by commas:

    print("\nThe value is ", value); // \n is newline
    or:

    int name [10] = {"Horatio"}; // note that a string being declared must be surrounded by braces
    print("\nHello! My name is ", $&name [0]);


    Fixing the horrible $& syntax is on my to-do list.


    data(<constant> int mode, <various other constant parameters>)

    data is used to get various game constants that are known at compile time, like the angle of each vertex in a particular shape. Unlike other built-in functions it is resolved to a constant during compilation and so can be used anywhere a literal number could be used (e.g. in an interface definition). Its parameters must be constants.

    The modes currently available are:
    DATA_SHAPE_VERTICES
    This gets the number of vertices a shape has. Parameters: shape
    DATA_SHAPE_VERTEX_ANGLE
    The angle of a vertex from the process' centre. Parameters: shape, vertex
    DATA_SHAPE_VERTEX_DIST
    The distance of a vertex from the process' centre (in pixels). Parameters: shape, size, vertex
    DATA_SHAPE_VERTEX_ANGLE_PREV
    The angle from one vertex to the previous one. Parameters: shape, vertex
    DATA_SHAPE_VERTEX_ANGLE_NEXT
    The angle from one vertex to the next one. Parameters: shape, vertex
    DATA_SHAPE_VERTEX_ANGLE_MIN
    This is the lowest angle offset that a directional method at this vertex can have while still pointing outwards. For example, if a method at a particular vertex can be pointed from between -2500 and 3000, this will return -2500. These angle offsets can be used in the angle field of the interface definition for the method, and are also relevant to methods that can change their angle (like MT_PR_DPACKET).
    DATA_SHAPE_VERTEX_ANGLE_MAX
    The same as DATA_SHAPE_VERTEX_ANGLE_MIN, but gets the maximum angle offset.

    Examples:

    a = data(DATA_SHAPE_VERTICES, SHAPE_4SQUARE); // sets a to the number of corners a square has. May not be so useful
    vertex_angle = data(DATA_SHAPE_VERTEX_ANGLE, SHAPE_6HEXAGON, 2); // sets vertex_angle to the angle of a hexagon's third vertex
    vertex_dist = data(DATA_SHAPE_VERTEX_DIST, SHAPE_3TRIANGLE, 1, 2); // sets vertex_dist to the distance from the centre of a triangular process of size 1 to its vertex 2 (its third vertex)


    4.5.2 Method-based built-in functions


    These are built-in functions that facilitate the use of a particular method. They only work in programs that include the appropriate method in their interface.


    MT_PR_STD method built-in functions

    The MT_PR_STD method provides various standard functions, especially functions that give a process basic information about itself and the rest of the world. These functions can only be used by processes, and require there to be a MT_PR_STD method in the process' interface. Most take no arguments and all return int.

    int get_x(void)
    Returns the process' x coordinate (in pixels, from the left).
    int get_y(void)
    Returns the process' y coordinate (in pixels, from the top).
    int get_angle(void)
    Returns the angle in which the process' vertex 0 is pointing, in integer degrees. Rightwards is angle 0, full circle is 8192.
    int get_speed_x(void)
    Returns the x component of the process' velocity, in pixels per tick multiplied by 16 (because without multiplication it would often be too small). Can be positive (rightwards) or negative (leftwards).
    int get_speed_y(void)
    Returns y speed. Positive is down, negative is up.
    int get_team(void)
    Returns the team (player index) that the process belongs to. Player 1 is 0, player 2 is 1 etc.
    int get_hp(void)
    Returns how many hit points the process has.
    int get_hp_max(void)
    Returns the maximum hp the process can have.
    int get_instr(void)
    Returns how many instructions the process has left to execute this tick. Imprecise, as the function itself costs instructions.
    int get_instr_max(void)
    Returns how many instructions it started with.
    int get_irpt(void)
    Returns how many interrupts the process has left. If the process is connected to other processes, this is the shared total.
    int get_irpt_max(void)
    Returns the process' maximum number of interrupts. If the process is connected to other processes, this returns the shared total maximum.
    int get_own_irpt_max(void)
    Returns the process' maximum number of interrupts. Is not affected by connected processes.
    int get_data(void)
    Returns how much data the process has left. If the process is connected to other processes, this is the shared total.
    int get_data_max(void)
    Returns how much data it can store. If the process is connected to other processes, this returns the shared total maximum.
    int get_own_data_max(void)
    Returns how much data it can store. Is not affected by connected processes.
    int get_spin(void)
    Returns an approximation of the process' rotation speed, in integer angle units per tick (8192 is a full circle). Can be positive (clockwise) or negative (anticlockwise).
    int get_group_x(void)
    If the process is a member of a group of processes joined together by MT_PR_LINK methods, this returns the x coordinate of the centre of the group (which is roughly the group's centre of mass). If the process is not a member of a group, this just returns the process' x coordinate.
    int get_group_y(void)
    Similar.
    int get_group_x_speed(void)
    If the process is a member of a group, returns the x component of the group's velocity (measured at the group's centre of mass).
    int get_group_y_speed(void)
    The same, for y.
    int get_group_members(void)
    Returns the number of processes in the process' group, including the process itself. Returns 1 if the process is not a member of a group.
    int get_world_x(void)
    Returns the width of the game arena, in pixels.
    int get_world_y(void)
    Same, for height.
    int get_ex_time(void)
    Returns the number of ticks until the process executes again (this isn't very useful for a process, but a client may have a use for the query version of this).
    int get_efficiency(void)
    Returns the efficiency that an allocator process would have at the process' location. This is a more expensive operation, and costs 32 irpt.
    int get_vertices(void)
    Returns the number of vertices the process has. Like data(DATA_SHAPE_VERTICES, <shape>), but since this is a method call it is not fixed at compile time. May be useful if the process' shape can be changed by the process that creates it.
    int get_vertex_angle(int vertex)
    Returns the angle of one of the process' vertices.
    int get_vertex_dist(int vertex)
    Returns the distance (in pixels) from the centre of the process to one of its vertices.
    int get_vertex_angle_next(int vertex)
    The angle from one vertex to the next one.
    int get_vertex_angle_prev(int vertex)
    The angle from one vertex to the previous one.
    int get_vertex_angle_min(int vertex)
    The minimum offset from zero that a method at a particular vertex can have.
    int get_vertex_angle_max(int vertex)
    The maximum offset from zero that a method at a particular vertex can have.
    get_method(int method_index)
    Returns the type (MT_PR_?) of method method_index.
    get_method_find(int method_type, int number)
    Returns the index of the first method of method_type in the process' interface, if number is 0. If number is 1, returns the second instance of that method type. If 2, the third (etc).
    set_command(int command_register, int value)
    Sets one of the process' command registers to value. Note that reading command registers requires the separate MT_PR_COMMAND method.
    set_command_bit_1(int command_register, int bit)
    Sets a bit of the value in command_register to 1. For example:
    set_command_bit_1(3, 5); // sets bit 5 of register 3 to 1

    set_command_bit_0(int command_register, int bit)
    Sets a bit of the value in command_register to 0.


    MT_PR_COMMAND (process command) built-in functions

    A process can use the MT_PR_COMMAND method to read from its 16 command registers, which let it communicate with a client or operator program (writing to its command registers just requires the MT_PR_STD method). The built-in functions are:

    int get_command(int command_register)
    This returns the contents of a command register (0-15).
    int get_command_bit(int command_register, int bit)
    This gets a single bit from a command register. For example:
    a = get_command_bit(3, 5); // returns 1 if bit 5 of register 3 is 1, and 0 otherwise

    MT_CL_COMMAND_GIVE (client command-give) built-in functions
    A client can use the MT_CL_COMMAND_GIVE method to write to the command registers of its processes.
    int command(int process_index, int command_register, int value)
    This sets a specified command register belonging to a specified process to a specified value. It takes only one value at a time.
    int command_bit_1(int process_index, int command_register, int bit)
    This sets a specified bit of a specified command register belonging to a specified process to 1.
    int command_bit_0(int process_index, int command_register, int bit)
    This sets a specified bit of a specified command register belonging to a specified process to 0.

    MT_CLOB_COMMAND_REC (client/observer command-receive) built-in functions

    A client or observer can use the MT_CLOB_COMMAND_REC method to read the command registers of processes.
    int check_command(int process_index, int command_register)
    This returns the contents of a specified command register belonging to a specified process. The process must belong to the same player as the client program (or any player if the method is being used by a system or observer program).
    int check_command_bit(int process_index, int command_register, int bit)
    This returns the contents of a specified bit of a specified command register belonging to a specified process. The process must belong to the same player as the client program (or any player if the method is being used by a system or observer program).

    MT_CLOB_QUERY (query) built-in functions

    The MT_CLOB_QUERY method is like the INFO method, but it is used by client or observer methods to get information about processes. Most of the get_*() built-in INFO functions have corresponding query functions which are used in the same way, except that the query function takes a process index as an argument. The process does not have to be controlled by the same player as the client/observer program.

    Example:

    a = query_x(process_index);
    This sets a to the x coordinate of the process with the index process_index.

    Unlike get_* functions, query functions can be called against non-existent processes. If the specified process does not exist, a query function will usually return -1. However, if a process is destroyed its index will be reserved for several ticks afterwards, during which time it is being de-allocated and its index will not be re-used, and a query will return -2 instead. Calling a query function that should not otherwise return a negative number (e.g. query_hp(...)) allows a client/observer process to check whether a process exists.

    Some of the get functions do things that client processes can do better with other methods, so there are no built-in query functions for these (although call can be used instead if for some reason you want to). These are get_world_x(), get_world_y() and get_efficiency().

    One query function that doesn't have a get equivalent is query_mbank(int process_index, int method_register), which returns the value of a method register of a process (and is equivalent to the process calling get_index()).


    MTYPE_CLOB_WORLD (world information) built-in functions

    The MTYPE_CLOB_WORLD method gives a client/observer/system program information about the parameters of the game.
    int world_x(void)
    Returns the width of the game area (in pixels).
    int world_y(void)
    Same, for height.
    int world_processes(void)
    Returns the maximum number of processes that can exist in the world.
    int world_processes_each(void)
    Returns the maximum number of processes that each player can have at once.
    int world_team(void)
    For a client program, returns the program's player index. Returns -1 for observer and system programs.
    int world_teams(void)
    Returns the number of players.
    int world_first_process(void)
    For a client program, returns the lowest index that a process controlled by this player can have (so player 1 might control indices 0-99 while player 2 controls 100-199 and player 3 controls 200-299). Produces undefined results for other program types (they can call the method directly with a parameter to find out this value for particular players).
    int world_last_process(void)
    Like world_first_process(), but returns the highest process index.
    int world_time(void)
    Returns the number of ticks elapsed so far. This overflows easily, so after the program's WORLD method is called in this way, register 1 of the method holds the number of ticks divided by 32,767.

    MT_PR_MATHS/MT_CLOB_MATHS (mathematics) built-in functions

    These all require either the MT_PR_MATHS or the MT_CLOB_MATHS method.

    Because only integers are available, the trigonometric functions use an integer angle system in which 0 is directly right and 8192 is a full circle clockwise (so 2048 is down, 4096 is left and 6144 is up). Angles less than 0 or greater than 8191 just wrap around, so you don't need to bounds-check angle values. There are a number of built-in macros for angles: ANGLE_1 is a full circle (8192), ANGLE_2 is a half circle (4096) etc all the way to ANGLE_32.

    A limitation of the maths functions is that they cannot be used as parameters of each other or themselves (this is because they are simple wrappers around the call function, and trying to call the maths method like this causes its registers to be overwritten with each call). So, for example, you can't do this:

    a = angle_difference(1000, atan2(y, x)); // the call to atan2 overwrites values needed for the angle_difference call before it can be executed
    Use variables to store the intermediate steps instead (this is actually a limitation of all method-based built-in functions, but it's most significant for the maths ones).
    int hypot(int y, int x)
    Returns the hypotenuse of y and x. Useful for distance calculations.
    int sqrt(int value)
    Returns the square root of value. Returns 0 if value <= 0.
    int pow(int value1, int value2)
    Returns value1 to the power of value2.
    int abs(int value)
    Returns the magnitude of value.
    int angle_difference(int angle1, int angle2)
    Returns the magnitude of the shortest distance (in integer degrees) between angle1 and angle2. Takes account of wrapping, so if you call, for example, angle_difference(8000, 100) it will correctly return 292 instead of 7900.
    int signed_angle_difference(int angle1, int angle2)
    Like angle_difference(), but returns a signed value (calculated from angle1) instead of a magnitude (so, for example, signed_angle_difference(300, 100) returns -200).
    int turn_direction(int angle1, int angle2)
    Returns the direction of the closest way from angle1 to angle2: returns 1 for clockwise, -1 for anticlockwise and 0 if the angles are same (for example, turn_direction(5000, 3000) returns -1).
    int sin(int angle, int value)
    Returns the sine of angle (which should be in integer degrees) multiplied by value. Its most obvious use is to determine the y component of a line that has angle (angle) and is (value) pixels long.
    int cos(int angle, int value)
    Returns a cosine multiplied by value. Use this to determine the x component of a line.
    int atan2(int y, int x)
    Returns an arctangent, in integer degrees (equivalent to C's atan2 function). This function is useful for getting the angle of a line joining two points, but it is relatively expensive.

    5. Interfaces


    Each program must have an interface definition, which sets out what methods it has available to it. For processes, the interface definition also determines the shape and size of the process. For system programs, the interface definition sets the basic parameters of the game.

    5.1 Process interface


    Process interface definitions are in the following format:


    interface
    {
     (program type),
     (process shape),
     (process size),
     (base vertex),
     {
       {
        (method type),
        (method vertex),
        (method angle),
        (method extension 0),
        (method extension 1),
        (method extension 2)
       },
       {
        (method type),
        (method vertex),
        (method angle),
        (method extension 0),
        (method extension 1),
        (method extension 2)
       },
       {
        etc... (up to 16 methods)
       }
     }
    }



    Program type
    For a process, the program type must be PROGRAM_TYPE_PROCESS. Other types are:
    PROGRAM_TYPE_DELEGATE
    PROGRAM_TYPE_OPERATOR
    PROGRAM_TYPE_OBSERVER
    PROGRAM_TYPE_SYSTEM
    Process shape
    This is the shape (octagon, pointy hexagon, diamond etc) that embodies the process. See process shapes/sizes.
    Process size
    From 0 to 3. The size of a process determines how durable it is, how much it costs to build, how much irpt and data it can fit in its buffers and how much method mass it can have. See process shapes/sizes.
    Base vertex
    The is the default vertex that will be directly next to the parent process, if the parent process' NEW method specifies the child vertex as -1.
    Methods
    A process can have up to 16 of these, as long it has enough capacity for their mass.
    Method type
    One of the MT_PR_* values. MT_PR_NONE (0) means no method.
    Method vertex
    If the method is an external method, this is the vertex it will be installed into. Only one method can be at each vertex. This value doesn't matter for internal methods.
    Method angle
    If the method is a directional external method, this is an offset to the angle it points in. 0 means the method will point directly away from the centre of the process, -ANGLE_4 will point 90 degrees anticlockwise from that, etc. 
    Methods can't point inwards. If you try to set a method pointing inwards, its angle will be corrected to the nearest valid angle. 
    If you want to set an angle with reference to the whole process' angle (for example, you want to point a MOVE method directly backwards) you can set the angle value to the angle you want the method to point in relative to the process' angle, minus the angle of the vertex. See the MOVE methods in the example just below.
    Extensions
    Some methods can be optimised in various ways by giving them extensions. See Extensions.
    A method can have at most 4 total levels of extensions.
    Error methods
    If there's something wrong with a method in an interface definition, it might be replaced by an error method that indicates what went wrong (for example, you tried to put two methods on a single vertex). See special methods.
    Method enums
    If you put a label in front of a method definition, it will be turned into an enum with a value equal to the index of that method (even if there are gaps). Thanks to Peter Hull for coding this!
    Example of a process interface:

    interface
    {
     PROGRAM_TYPE_PROCESS, SHAPE_4POINTY, 3, 3, // program type, shape, size (from 0-3), base_vertex
     {
      METH_MOVE1: {MT_PR_MOVE, 1, ANGLE_2 - data(DATA_SHAPE_VERTEX_ANGLE, SHAPE_4POINTY, 1)}, // acceleration method on vertex 1, pointing 180deg (ANGLE_2) relative to vertex 0
      METH_MOVE2: {MT_PR_MOVE, 3, ANGLE_2 - data(DATA_SHAPE_VERTEX_ANGLE, SHAPE_4POINTY, 3)}, // acceleration method on vertex 3, pointing 180deg (ANGLE_2) relative to vertex 0
      METH_COM: {MT_PR_COMMAND}, // command method. allows process to communicate with operator/delegate
      METH_MATHS: {MT_PR_MATHS}, // maths method. allows trigonometry etc.
      METH_STD: {MT_PR_STD}, // standard process method. does several basic things like giving  access to process's current properties (location etc)
      {MT_PR_IRPT}, // generates irpt. functions automatically (although can be configured not to)
      METH_PACKET: {MT_PR_PACKET, 0, 0, 1, 1, 1}, // packet method. allows process to attack.
      METH_SCAN: {MT_PR_SCAN}, // scan method. allows process to sense its surroundings. takes up 3 method slots
      {MT_NONE}, // space for scan method
      {MT_NONE}, // space for scan method
      METH_DESIGNATE: {MT_PR_DESIGNATE}, // designator. allows process to keep track of a target acquired through scan
     }
    }


    5.2 Client/observer program interface


    These are like process interfaces, except that they do not specify a shape, size or base vertex. Since no client/observer methods are external or have extensions, these kinds of interfaces can be a bit simpler.

    For example, this is an interface for an operator program:

    interface
    {
     PROGRAM_TYPE_OPERATOR, // program's type
     {
      {MT_OB_INPUT}, // input method - allows reading of user input
      {MT_CL_COMMAND}, // command method - allows operator to communicate with processes
      {MT_CLOB_POINT}, // point check - allows operator to find what is at a particular point
      {MT_OB_VIEW}, // view - allows interaction with display
      {MT_NONE}, // makes space for view method
      {MT_OB_SELECT}, // select - allows operator to set display elements indicating selected process
      {MT_OB_CONSOLE}, // console - allows operator to control console windows
      {MT_CLOB_WORLD}, // world - gives information about the game world
      {MT_CLOB_QUERY}, // query - allows operator to get information about processes (similar to MT_PR_INFO)
      {MT_CLOB_MATHS}, // maths method (works the same way as MT_PR_MATHS)
      {MT_CLOB_SCAN}, // scanner - similar to MT_PR_SCAN but with some additional features
      {MT_NONE}, // makes space for scan method
      {MT_NONE}, // makes space for scan method
      {MT_OB_CONTROL}, // control - allows operator to query various things about the user interface
     }
    }


    5.3 System program interface


    System program interfaces are a bit more complicated, because they need to set out some of the game rules right at the start.

    interface
    {
     (program type),
     {Options: number of players},
     {Options: number of turns},
     {Options: length of each turn, in minutes},
     {Options: number of processes each player can have},
     {Options: number of packets each player can have},
     {Options: width of game area, in 128-pixel blocks},
     {Options: height of game area},
     (allow player clients),
     (player number of operator),
     (allow user observer),
     {(whether player 0 may change its client template), (whether player 1 may do so), etc.},
     {(whether player 0 may change its process templates), (whether player 2 may do so), etc.},
     {
       {
        (method type), // this is the only field that is actually used
        (method vertex), // vertex, angle and extension are only relevant to processes
        (method angle),
        (method extension 0),
        (method extension 1),
        (method extension 2)
       },
       {
        (method type),
        (method vertex),
        (method angle),
        (method extension 0),
        (method extension 1),
        (method extension 2)
       },
       {
        etc... (up to 16 methods)
       }
     }
    }

    Options
    Options determine the range of options that are available to the user in the game setup menu when starting a game using this system program. 
    They are in the format:
    {(whether user can change this setting (0 or 1)), (default value), (minimum value), (maximum value)}
    If the first field is 0, the user won't be able to change this value. The (default value) will be used.
  • If (minimum value) or (maximum value) is 0, the minimum or maximum possible value will be used.
    An example of the Options: number of turns field:
    {1, 5, 1, 10}, // 1 means the user can change this value. They will be able to set the turns from 1 to 10, with a default of 5.
    An example of the Options: width of game area field:
    {0, 30}, // the user can't change this value. The area must be 30 blocks wide.
    Allow player clients
    If 1, players have access to client program templates and can load client programs into them.
    Player number of operator
    This is the player who gets to be the operator (i.e. they can load an operator program into their client program template, while other players can just load delegate programs). Set to -1 if there is no operator.
    Allow user observer
    If 1, there will be an observer template. If 0, there won't be. If there is no operator, this should be 1 (unless the system program is handling user input).
    May change client template
    The system program can lock templates so that users can't change them. This doesn't prevent the system program making changes. An example:
    {0, 1, 1, 1}, // player 1 can't change its client template. Players 2, 3 and 4 can.
    May change process templates
    The same, but for process templates.

    This is an example of a system program interface (from the sy_multi.c multiplayer system program):

    interface
    {
     PROGRAM_TYPE_SYSTEM,
     // The following are: option, default, min, max
     // If min or max is left as 0, the game's actual min/max values will be used
     {1, 2, 2}, // players
     {1, 3, 1}, // turns
     {1, 5, 1}, // minutes per turn
     {1, 100}, // processes per team
     {1, 400}, // packets per team
     {1, 60}, // width of world
     {1, 60}, // height of world
     1, // allow_player_clients
     -1, // index of player who is operator (is -1 if no operator)
     1, // allow_user_observer
     {1, 1, 1, 1}, // may_change_client_template
     {1, 1, 1, 1}, // may_change_proc_templates
     {
      {MT_SY_PLACE_PROC},
      {MT_NONE}, // space for PLACE_PROC
      {MT_SY_TEMPLATE},
      {MT_SY_MODIFY},
      {MT_SY_MANAGE},
      {MT_NONE}, // space for MANAGE
      {MT_OB_VIEW},
      {MT_NONE}, // space for VIEW
      {MT_OB_CONSOLE},
      {MT_CLOB_CHANNEL},
      {MT_CLOB_QUERY},
      {MT_CLOB_WORLD},
      {MT_CLOB_MATHS},
     }
    }


    5.4 More on process interfaces: shapes and sizes


    Each process' interface must set a shape and size for the process. A process' shape affects how many vertices it has available for external methods, how robust it is, how large its irpt and data buffers are and its maximum method mass capacity. A process' size affects these things as well (except for number of vertices).

    The following shapes are available:

    SHAPE_3TRIANGLE
    SHAPE_4SQUARE
    SHAPE_4DIAMOND
    SHAPE_4POINTY
    SHAPE_4TRAP
    SHAPE_4IRREG_L
    SHAPE_4IRREG_R
    SHAPE_4ARROW
    SHAPE_5PENTAGON
    SHAPE_5POINTY
    SHAPE_5LONG
    SHAPE_5WIDE
    SHAPE_6HEXAGON
    SHAPE_6POINTY
    SHAPE_6LONG
    SHAPE_6IRREG_L
    SHAPE_6IRREG_R
    SHAPE_6ARROW
    SHAPE_6STAR
    SHAPE_8OCTAGON
    SHAPE_8POINTY
    SHAPE_8LONG
    SHAPE_8STAR

    Size can be 0, 1, 2 or 3.

    Here's what the shapes look like, and the attributes for each size of each shape:

    Picture of various process shapes

    The attributes are:
    base mass
    The "mass" of a process represents how much data it consists of. The heavier a process is, the more slowly it accelerates and the more momentum it carries. The data cost of creating a process is equal to its mass. Base mass is the mass a process has with no methods at all.
    max method mass
    Each method has a build cost which determines how much data it costs to add to a process, with method extensions increasing this cost. A shape's maximum method mass is the upper limit on the amount of method mass a process can have. If a process' interface gives it too much method mass, any method that would cause it to go overweight is replaced by an error.
    max hp
    This is how much damage the process can take before deallocating. It can be increased by the MT_PR_REDUNDANCY method.
    irpt buffer
    This is how many irpt the process can hold at once. The size of a process' irpt buffer can't be increased.
    data buffer
    This is how much data the process can hold at once. It can be increased by the MT_PR_STORAGE method.

    5.5 The process data box


    The process data box shows up when a process is selected (at least when you are using the observer and operator programs that come with the game). It looks like this:

    picture of process data box

    Here's what the various fields mean:
    If the process is a member of a group of linked processes, there will be another line here:
    commands show the state of each of the process' 16 command registers.

    Methods lists the process' methods in order.
    First is the name of the method, followed by its four method registers.
    A method that takes up multiple slots will be followed by sub-method slots .These also have method registers.

    On the next line is the method's mass (m), followed by some other things that depend on what kind of method it is:

    6. Methods


    A method is a special capability, function or characteristic of a program. Methods are part of a program's interface; each program's interface has 16 slots for methods, although some methods take up multiple slots.

    Each type of program has a different set of methods available to it.

    All methods are fail-safe; if they receive invalid instructions, or if they encounter an error of some kind when activated, they will return without otherwise affecting their process or program. In some cases they will return a value indicating why they failed.

    Process methods
    Client methods
    Client/observer methods
    Observer methods
    System methods
    Special methods

    Attributes of process methods
    External
    An external method occupies one of the process' external vertices (which vertex it occupies is set by the process' interface). If two external methods are given the same vertex, the second one will fail and be replaced with an MT_ERROR_VERTEX error. A process can't have more external methods than it has vertices.
    Internal
    An internal method doesn't occupy a vertex.
    Automatic
    An automatic method operates between process executions, usually based on the settings in its method bank registers. For example, the MOVE method can be set to accelerate the process constantly until the next program execution 16 ticks later.
    Called
    A called method does something when called using the compiler's call() built-in function or the assembler's call instructions, and may also return a value. For example, when the MATHS method is called it performs a calculation on values in its method bank registers and returns the result.
    Not called
    Does nothing when called, and returns 0.
    Directional
    An external method may point in a particular direction, which is determined by the angle field in its interface definition. For example, the PACKET method fires a packet in its specified direction. An external method's direction generally cannot point inwards.
    Single
    A process can only have one method of this type. Any others will be replaced by an MT_ERROR_DUPLICATE error.

    Method costs

    Each process method has the following costs:
    These depend on the method's cost category:
    Some methods also have additional costs which must be paid when the method is used. This is mentioned in the method descriptions below.

    6.1 Process methods (PR)


    These start with MT_PR. Some process methods have extensions, which make them more effective in various ways but increase their cost. A process methods' extensions are set in the process' interface.

    Movement: MT_PR_MOVE
    This method allows processes to move and rotate. It works like a jet, accelerating the process away from the direction it is pointing, and also generating torque.

    External, directional, automatic, not called
    Cost: High
    Size 1 (method registers: 4)

    Extensions:
    0: power


    Registers
    MB_PR_MOVE_RATE
    Acceleration rate (basically, power level).
    MB_PR_MOVE_COUNTER
    Number of ticks to operate for (set to zero to turn method off)
    MB_PR_MOVE_DELAY
    Delay before starting to operate
    To use:
    1. Set the rate register to the acceleration rate you want. Usually this is the maximum, which is 5+(3*power extension), but if you set the rate register above this it will just work at the maximum.
    2. Set the counter register to the number of ticks that the method should operate for. If you set this to 16 or more, the method will provide thrust until the process' next execution.
    3. Set the delay register to the number of ticks to wait before the method starts operating. Set to 0 if you don't want a delay. The counter register doesn't count down during this delay.
    Using it costs 2 interrupts per rate per tick. So if you set it to run for 16 ticks at rate 5, it will cost 160 interrupts.


    New: MT_PR_NEW
    This method allows a process to create another process. The new process' bcode can be copied from the parent process' own bcode, or from a template.

    Internal, called
    Cost: Ultra
    Size 2 (method registers: 8)

    Extensions: none

    Registers
    MB_PR_NEW_STATUS
    Sets the mode of operation (see MS_PR_NEW_* values below).
    MB_PR_NEW_VERTEX1
    The vertex of the parent process that the new process will be created at.
    MB_PR_NEW_VERTEX2
    The vertex of the new process that will start in contact with VERTEX1 of the parent process. Set to -1 to use the new process' base_vertex interface value (specified in the new process' interface definition).
    MB_PR_NEW_ANGLE
    The angle the new process will have when created (relative to the angle of the parent process' vertex). At angle 0, the new process' vertex set by the vertex2 register will be pointing directly towards the parent process.
    MB_PR_NEW_START
    The start address of the new process' bcode, in the source bcode.
    MB_PR_NEW_END
    The end address.
    MB_PR_NEW_LINK
    If both processes have MT_PR_LINK methods at their mutual vertices, this can be set to 1 and the processes will be connected.
    MB_PR_NEW_TEMPLATE
    If the new process is being created from a template, this is the index of the template (0 to 3).

    Statuses
    MS_PR_NEW_NOTHING
    The method will do nothing.
    MS_PR_NEW_BC_BUILD
    The method will attempt to create a new process. The new process' bcode will be copied from the parent process' own bcode. The method will return an MR_PR_NEW_* result value.
    MS_PR_NEW_BC_TEST
    The method will test whether a new process can be created. It will make sure that the values in the method's registers are correct, that the new process' interface allows it to be created (e.g. it must have valid shape and size values), that the parent process has sufficient data and irpt, and that the new process will not collide with an existing process.
    MS_PR_NEW_BC_COST_DATA
    The method will work out the data cost of building a new process with from the specified bcode.
    MS_PR_NEW_BC_COST_IRPT
    The same, but for irpt cost.
    MS_PR_NEW_T_BUILD
    Like MS_PR_NEW_BC_BUILD, but the method will try to build from one of its player's process templates. The MB_PR_NEW_TEMPLATE register indicates which template to use.
    MS_PR_NEW_T_TEST
    Like MS_PR_NEW_BC_TEST, but for templates.
    MS_PR_NEW_T_COST_DATA
    Data cost of building from a template.
    MS_PR_NEW_T_COST_IRPT
    irpt cost of building from a template (currently this is the same as the data cost).

    Return values

    Calling the method will return one of the following:
    MR_NEW_NONE
    No result.
    MR_NEW_SUCCESS
    The new process was successfully built.
    MR_NEW_TEST_SUCCESS
    The test was successful.
    MR_NEW_FAIL_STATUS
    Unrecognised MB_PR_NEW_STATUS value.
    MR_NEW_FAIL_TYPE
    The interface definition in the source bcode indicates that it is not a process (this can happen if e.g. you try to build a process from a system program).
    MR_NEW_FAIL_OBSTACLE
    The process would collide with another process, or the edge of the map, if created (the specified location of the new process is indicated on screen for a short time).
    MR_NEW_FAIL_IRPT
    The parent process does not have enough irpt.
    MR_NEW_FAIL_DATA
    Not enough data.
    MR_NEW_FAIL_START_BOUNDS
    The start address specified in the start address register is out of bounds.
    MR_NEW_FAIL_END_BOUNDS
    The end address is out of bounds.
    MR_NEW_FAIL_INTERFACE
    There is a problem with the new process' interface definition.
    MR_NEW_FAIL_TOO_MANY_PROCS
    The player already has too many processes.
    MR_NEW_FAIL_SHAPE
    The shape specified in the process' interface is invalid.
    MR_NEW_FAIL_SIZE
    The size specified in the process' interface is invalid.
    MR_NEW_FAIL_PARENT_VERTEX
    The parent vertex register value is invalid.
    MR_NEW_FAIL_CHILD_VERTEX
    The new process vertex register value is invalid.
    MR_NEW_FAIL_TEMPLATE
    The template index in the template register is invalid.
    MR_NEW_FAIL_TEMPLATE_EMPTY
    The template indicated by the template register is empty.
    MR_NEW_FAIL_LOCATION
    Invalid location (only returned by the MT_SY_PLACE method)
    MR_NEW_FAIL_PLAYER
    Invalid player index (only returned by the MT_SY_PLACE method)

    The amount of data required to create a new process is equal to the mass of the process. A process' mass is the sum of its base mass, determined by its shape and size (see process shapes), and the total mass of all of its methods.

    The irpt cost of building a new process is the same as the data cost.

    There is also some overhead for calling this method: 64 irpt for a build call, and 32 irpt for any other call (such as a test, or a cost query). If the parent process has insufficient irpt, the method will return MR_NEW_FAIL_IRPT.

    An example of a simple use of this method to create a new process based on a sub-process of the parent process:

    build_result = call(METH_NEW,
     MS_PR_NEW_BC_BUILD, // status: try to build a new process using bcode copied from the parent process
     3, // vertex1: the new process will be built at the parent process' vertex 3
     0, // vertex2: the new process' vertex 0 will be next to the parent process' vertex 3
     0, // angle: the new process' vertex 0 will be pointing directly towards the parent process
     process_start(name_of_new_process),
     process_end(name_of_new_process), // these address values indicate that the new process' bcode is to be copied from a subprocess of the parent called name_of_new_process
     0, // link: the new process will not be connected to the parent process
     0); // template: not relevant

    // After this call, build_result will hold one of the MR_NEW_? values.


    An example of using this method to create a new process from a template:

    build_result = call(METH_NEW,
     MS_PR_NEW_T_BUILD, // status: try to build a new process using bcode copied from a template
     3, // vertex1: the new process will be built at the parent process' vertex 3
     -1, // vertex2: the new process' base vertex will be next to the parent process' vertex 3
     0, // angle: the new process' vertex 0 will be pointing directly towards the parent process
     0, // start address
     BCODE_SIZE_PROCESS - 1, // end address: this is the end of the template, so the entire template will be copied
     0, // link: the new process will not be connected to the parent process
     1); // template: this is the second of the player's 4 process templates

    An example of the previous call, but as a test:

    test_result = call(METH_NEW,
     MS_PR_NEW_T_TEST, // status: try to build a new process using bcode copied from a template, but  stop before actually building it
     3, // vertex1: the new process will be built at the parent process' vertex 3
     0, // vertex2: the new process' vertex 0 will be next to the parent process' vertex 3
     0, // angle: the new process' vertex 0 will be pointing directly towards the parent process
     0, // start address
     BCODE_SIZE_PROCESS - 1, // end address: this is the end of the template, so the entire template will be copied
     0, // link: the new process will not be connected to the parent process
     1); // template: this is the second of the player's 4 process templates

    // This is exactly the same, except for the status.


    New (sub): MT_PR_NEW_SUB
    This method is the same as the MT_PR_NEW method, except that it cannot create new processes which have either the MT_PR_NEW method or the MT_PR_IRPT method, and it is cheaper (medium cost instead of ultra - creating new processes costs the same, though). These limitations make it suitable for doing things like creating new sub-processes linked to a main process.

    Internal, called
    Cost: Medium
    Size 2 (method registers: 8)


    Packet: MT_PR_PACKET
    This method shoots out a malicious packet at your enemies.

    External, directional, automatic, not called
    Cost: High
    Size 1 (method registers: 4)

    Extensions:
    0: power (increases damage)
    1: speed (increases the packet's speed, although not its range)
    2: range (increases the packet's flight time)

    Registers
    MB_PR_PACKET_COUNTER
    Number of ticks after the process executes at which the method should fire. If this is <= 0, the method won't fire. Set to 1 to fire immediately. However, the method has an 8-tick recycle period after firing during which it can't fire again. If the counter reaches 1 during this period, it will fire at the end of it.
    MB_PR_PACKET_FRIENDLY
    If 1, the packet will hit friendly processes as well as processes belonging to other players. If zero or any other value, will only hit other players' processes. Since method registers default to zero at program creation, you probably don't want to do anything to this.
    All you need to do to tell a packet method to fire is to set its counter register to 1. The irpt cost of firing a packet is (2 + total number of extensions) * 32, or 64 (0 extensions), 96 (1), 128 (2), 160 (3) or 192 (4).


    Directional packet: MT_PR_DPACKET
    Like MT_PR_PACKET, but can rotate. In return for this it does a bit less damage, has a slightly reduced speed and flight time, and costs slightly more to use.

    External, directional, automatic, called
    Cost: High
    Size 1 (method registers: 4)

    Extensions:
    0: power (increases damage)
    1: speed (increases the packet's speed, although not its range)
    2: range (increases the packet's flight time)

    Registers
    MB_PR_DPACKET_COUNTER
    Number of ticks after the process executes at which the method should fire. If this is <= 0, the method won't fire. Set to 1 to fire immediately.
    MB_PR_DPACKET_ANGLE
    The method will turn towards this angle, at 32 integer degrees per tick. The angle should be an offset from the vertex angle of the vertex the method is on. The method will not turn to an inwards angle (it will stop at the edge). You can use the data built-in function with the DATA_SHAPE_VERTEX_ANGLE_MIN and DATA_SHAPE_VERTEX_ANGLE_MAX modes to work out the minimum and maximum offsets from angle 0 that this method can point in.
    MB_PR_DPACKET_FRIENDLY
    If 1, the packet will hit friendly processes as well as processes belonging to other players. If any other value, will only hit other players' processes.

    The irpt cost of firing a packet is (2 + total number of extensions) * 36, or 72 (0 extensions), 108 (1), 144 (2), 180 (3) or 216 (4).

    Calling this method returns its current angle.


    Stream: MT_PR_STREAM
    This method shoots out a stream of malicious data at your enemies. It is more expensive than the packet methods, and costs a huge amount of irpt to use, but is also very powerful.

    External, directional, automatic, called
    Cost: Ultra
    Size 1 (method registers: 4)

    Extensions:
    0: time (increases the amount of time the method can stay in its firing phase)
    1: range (increases the range of the stream)
    2: recycle (reduces the time that it takes the method to be ready again after being used)

    Registers
    MB_PR_STREAM_FIRE
    Set this to 1 to tell the method to fire as soon as it's ready.
    This method has five phases:
    The warm-up phase lasts for 8 ticks.

    The firing phase lasts for 6 + (3 * time extension) ticks. During the firing phase, the stream causes 36hp damage per tick.

    Initiating firing consumes 2048 + (512 * number of extensions) irpt (which is a lot). Since no single process has an irpt buffer that large, this method can only be used on multi-part processes.

    The cool-down phase lasts for 16 ticks, then the method enters the recycle phase.

    The recycle phase lasts for 96 - (16 * recycle extension) ticks, then the method returns to the ready phase.

    To use the method, set the MB_PR_STREAM_FIRE register to 1. The next time the method is in the ready phase (which may be immediately after it finishes executing), it will enter the warm-up phase then begin firing.

    When called, the method returns:


    Stream: MT_PR_DSTREAM
    This is the directional version of the Stream method. It is less powerful than Stream, causing 24hp damage per tick rather than 36.

    External, directional, automatic, called
    Cost: Ultra
    Size 1 (method registers: 4)

    It has an additional MB_PR_DSTREAM_ANGLE register that works just like the MB_PR_DPACKET_ANGLE register. The method stops rotating while firing.


    Scan: MT_PR_SCAN
    This method scans a square area around a process to find other processes that meet certain criteria. When it finds them, it copies their location into memory, in order of distance (nearest to furthest). It also has a secondary "examine" mode that gives more information about a particular nearby process.

    The centre of the scan can be set off from the process' actual location, as long as the whole of the scanned area is within range. If part of the scanned area would be out of range, the scanned area is reduced so as to be a square that is entirely within range.

    Internal, called
    Cost: Medium
    Size 3 (method registers: 12)

    Extensions:
    0: range


    Registers
    MB_PR_SCAN_STATUS
    This determines what the method does when called. Should be an MS_PR_SCAN_* value.
    MB_PR_SCAN_START_ADDRESS
    The results of the scan will be copied into the process' memory. This should be the address of the first element of an array large enough to hold the results.
    MB_PR_SCAN_NUMBER
    The number of processes to find. When this number has been reached, the scan will stop.
    MB_PR_SCAN_X1
    The x offset (in pixels) of the centre of the scan from the process' location.
    MB_PR_SCAN_Y1
    y offset.
    MB_PR_SCAN_SIZE
    The scanned area is an orthogonal square around its centre, with the edges being this number of pixels away from the centre.
    MB_PR_SCAN_SIZE2
    Not used for the MT_PR_SCAN method (but see MT_CLOB_SCAN)
    MB_PR_SCAN_BITFIELD_WANT
    MB_PR_SCAN_BITFIELD_NEED
    MB_PR_SCAN_BITFIELD_REJECT
    See below for a discussion of the bitfields

    Statuses
    MS_PR_SCAN_SCAN
    Performs a scan when called.
    MS_PR_SCAN_EXAMINE
    Performs examine when called.

    Return value

    In either mode, a successful scan returns the number of processes found (which may be zero). An unsuccessful scan returns one of the following result values:
    MR_SCAN_FAIL_SIZE (-1)
    Size is negative (a size that is positive but too large is just reduced to a valid size).
    MR_SCAN_FAIL_RANGE (-2)
    Centre of scan is out of range.
    MR_SCAN_FAIL_STATUS (-3)
    Invalid status register.
    MR_SCAN_FAIL_ADDRESS (-4)
    Invalid address for results (0 counts as invalid).
    MR_SCAN_FAIL_NUMBER (-5)
    Invalid number of results requested.
    MR_SCAN_FAIL_IRPT (-6)
    Not enough irpt to perform scan.

    Bitfields

    The bitfield method registers allow the scanning process to filter out certain processes. Each process has a binary signature determined by its team: a process on team 0 has the signature 0b0001, a process on team 1 has 0b0010, etc.

    In order for a process to be detected during a scan:
    1. At least one 1 bit in the process' signature must also be 1 in the WANT bitfield;
    2. All bits that are 1 in the NEED bitfield must also be 1 in the signature;
    3. No bits that are 1 in the REJECT bitfield can be 1 in the signature.
    Currently the team of a process is the only value that can be filtered in this way; this means that the NEED and REJECT bitfields are not really useful yet. Future versions will have more values for filtering.

    The most obvious use of the WANT bitfield is to find any processes that belong to another player. To do this, set up a bitmask like this:

    scan_bitmask = 0b1111 ^ (1 << get_team());
    This will give player 0 a 0b1110 bitmask, player 1 a 0b1101 bitmask, etc.
    To find friendly processes only, use:

    scan_bitmask = 1 << get_team();
    Example:

    int scan_result [8] [2]; // can hold up to 8 results of a scan
    int number_found;
    int scan_bitmask;
    scan_bitmask = 0b1111 ^ (1 << get_team());

    number_found = call(METH_SCAN,
     MS_PR_SCAN_SCAN, // scan mode
     &scan_result [0] [0], // address of first element of result array
     8, // number of targets to find
     0, // x offset of scan centre from process
     0, // y offset
     10000, // size of scan (in pixels). Maximum range is 400-900 ??; using a very high value just results in the maximum being used
     0, // not used for scans by processes (see MT_CLOB_SCAN)
     scan_bitmask, // BITFIELD_WANT
     0, // need bitfield
     0); // reject bitfield


    After this, the scan_result array will be filled with the x/y coordinates (as offsets from the scanning process) of up to 8 nearby enemy processes, sorted in increasing order of distance. The variable number_found will hold the number of processes found.


    Examine mode


    When called with the status MS_PR_SCAN_EXAMINE, this method gets information about a single process at a particular location. It has the same range as a scan. It will return 1 on success, 0 on failure.

    Only some of the method's registers are relevant to an EXAMINE operation. These are:
    MB_PR_SCAN_STATUS
    Should be MS_PR_SCAN_EXAMINE.
    MB_PR_SCAN_START_ADDRESS
    The address of the first element of an array large enough to hold the results.
    MB_PR_SCAN_X1
    The x offset (in pixels) of the examination from the process' location.
    MB_PR_SCAN_Y1
    y offset.
    Currently the only information revealed by an examination is the process' location (as an offset from the examining process) and its speed. Future versions will provide more.

    Example:

    int examine_result [4];
    int examine_success;
    int target_x, target_y, target_speed_x, target_speed_y;

    examine_success = call(METH_SCAN,
     MS_PR_SCAN_EXAMINE,
     &examine_result [0],
     0, // this is number of targets to find - not relevant for examine (is ignored)
     200, // x offset from examining process
     0); // y offset
    // other registers are unused in this mode

    if (examine_success)
    {
     target_x = examine_result [0];
     target_y = examine_result [1];
     target_speed_x = examine_result [2];
     target_speed_y = examine_result [3];
    }



    Cost


    Calling this method in scan mode costs 64 + (the maximum number of results accepted * 2) + (scan_size / 8) irpt. So for a scan with a range of 1000 that accepts 4 results (no matter how many are actually found), the cost would be 64 + (4 * 2) + (1000 / 8), or 197.

    Calling this method in examine mode costs a flat rate of 48 irpt.


    Interrupt generator: MT_PR_IRPT
    This method generates interrupts (irpts) that the process can use to sustain itself and activate its other methods. It automatically generates a certain number of irpt each tick.

    Internal, automatic, single
    Cost: High
    Size 1 (method registers: 4)

    Extensions:
    0: capacity


    Registers
    MB_PR_IRPT_STATUS
    Holds the method's status.

    Statuses

    MS_PR_IRPT_SET
    Calling the method with this status sets it to generate the number of irpt in register 1. If this number is too high, it will be set to maximum. It is set to maximum at process creation, so you probably don't want to do anything to it (it's only real purpose is to allow a process with an irpt method to self-destruct by turning the method off, as a process with insufficient irpt takes damage).
    MS_PR_IRPT_MAX
    Returns the number of irpt the method generates each tick.
    The number of irpt that the method can generate each tick is 8 + (4 * extension [0]).


    Data allocator: MT_PR_ALLOCATE
    This method allocates data when called. A process with this method is immobile, and can neither move nor rotate.

    External, called, single
    Cost: Ultra
    Size 1 (method registers: 4)

    Extensions: none

    To use this method, call it (it can be called once per cycle, unless another process with the same method is interfering with it). It does not make any use of its registers.

    Processes with this method should be at least 800 pixels away from each other, or their efficiency will be reduced. A process can use the MT_PR_INFO method to check efficiency at its current location (whether or not it has an allocate method itself), and a client/observer can use the MT_CLOB_POINT method to check efficiency at any location. Low efficiency prevents it from being called each cycle.

    It allocates 8 data when called, and costs 32 irpt per data allocated.


    Standard: MT_PR_STD
    This method provides various standard functions, most of the giving the process information about itself and a few of the global parameters of the game. The compiler has a set of built-in functions that simplify the use of this method and can do anything that can be done by calling it directly (see MT_PR_STD built-in functions).

    Internal, called
    Cost: Minimal
    Size 1 (method registers: 4)

    Extensions: none

    Registers
    MB_PR_STD_STATUS
    When called, the method will return a value determined by its status.

    Statuses
    MS_PR_STD_GET_X
    The method returns the process' current x location (in pixels).
    MS_PR_STD_GET_Y
    y location.
    MS_PR_STD_GET_ANGLE
    Angle (in integer units, 0-8191).
    MS_PR_STD_GET_SPEED_X
    x component of velocity (multiplied by 16, to avoid underflow).
    MS_PR_STD_GET_SPEED_Y
    y component.
    MS_PR_STD_GET_TEAM
    Which player controls this process (0 = player 1, 1 = player 2 etc.).
    MS_PR_STD_GET_HP
    Process' current hp.
    MS_PR_STD_GET_HP_MAX
    Process' maximum hp.
    MS_PR_STD_GET_INSTR
    Instructions left (imprecise as the call itself uses instructions).
    MS_PR_STD_GET_INSTR_MAX
    Maximum number of instructions the process can have.
    MS_PR_STD_GET_IRPT
    Irpt left.
    MS_PR_STD_GET_IRPT_MAX
    Max irpt. If the process is connected with other processes, returns the shared total maximum.
    MS_PR_STD_GET_OWN_IRPT_MAX
    Max irpt. Ignores other connected processes.
    MS_PR_STD_GET_DATA
    Data left.
    MS_PR_STD_GET_DATA_MAX
    Max data. If the process is connected with other processes, returns the shared total maximum.
    MS_PR_STD_GET_OWN_DATA_MAX
    Max data. Ignores other connected processes.
    MS_PR_STD_GET_SPIN
    Process' current spin, in integer units. If the process is a group member, returns the group's spin.
    MS_PR_STD_GET_GR_X
    Centre of mass of the process' group.
    MS_PR_STD_GET_GR_Y
    Group y.
    MS_PR_STD_GET_GR_SPEED_X
    x component of velocity of group's centre (multiplied by 16).
    MS_PR_STD_GET_GR_SPEED_Y
    y component.
    MS_PR_STD_GET_GR_MEMBERS
    Number of members of the group (returns 1 if not a group member).
    MS_PR_STD_GET_EX_COUNT
    Ticks until process executes again (not so useful, although its query counterpart may be useful).
    MS_PR_STD_GET_WORLD_W
    Width of game arena, in pixels.
    MS_PR_STD_GET_WORLD_H
    Height.
    MS_PR_STD_GET_EFFICIENCY
    Efficiency that a data allocator would have at the process' current location.
    MS_PR_STD_GET_TIME
    Returns the elapsed time of the world (not just the process) in ticks. Sets register 1 to the returned value and register 2 to that value divided by 32,767 (to avoid overflow).
    MS_PR_STD_GET_VERTICES
    Returns the number of vertices the process has.
    MS_PR_STD_GET_VX_ANGLE
    Returns the angle of the vertex in register 1.
    MS_PR_STD_GET_VX_DIST
    Returns the distance to the vertex in register 1.
    MS_PR_STD_GET_VX_ANGLE_PREV
    Returns the previous angle of the vertex in register 1.
    MS_PR_STD_GET_VX_ANGLE_NEXT
    Returns the next angle of the vertex in register 1.
    MS_PR_STD_GET_VX_ANGLE_MIN
    Returns the minimum angle of the vertex in register 1.
    MS_PR_STD_GET_VX_ANGLE_MAX
    Returns the maximum angle of the vertex in register 1.
    MS_PR_STD_ACTION
    Assigns the action in register 1 to the next console line printed by this process, and all further lines printed by the process until the end of its current execution cycle. If the user clicks on this line, the action will be available to the operator/observer/system program, which can use it to send commands back to the process (this is how the prsc_cfactory.c process accepts build commands).
    See the end of this list of statuses for an example of how to use actions.
    MS_PR_STD_WAIT
    The process' next execution cycle will be delayed by the number of ticks in register 1 (to a maximum of 16 additional ticks).
    MS_PR_STD_COLOUR
    Changes the colour of lines printed to a console. Register 1 is the colour (uses a COL_* macro: colours are COL_DGREY, COL_LGREY, COL_WHITE, COL_LBLUE, COL_DBLUE, COL_LRED, COL_DRED, COL_LGREEN, COL_DGREEN, COL_LPURPLE, COL_DPURPLE).
    MS_PR_STD_SET_COMMAND
    Sets the command register indicated by register 1 to the value in register 2. Processes need the MT_PR_COMMAND method to be able to read commands back.
    MS_PR_STD_COMMAND_BIT_0
    Sets a particular bit of the contents of a command register to 0. Register 1 is the command register, register 2 is the bit.
    MS_PR_STD_COMMAND_BIT_1
    Sets a particular bit of the contents of a command register to 1. Register 1 is the command register, register 2 is the bit.
    MS_PR_STD_PRINT_OUT
    Sets the process' print output to its standard output console (exactly which console this is can be set by the operator/observer/system program).
    MS_PR_STD_PRINT_OUT2
    Sets the process' print output to its alternative output console (exactly which console this is can be set by the operator/observer/system program).
    MS_PR_STD_PRINT_ERR
    Sets the process' print output to its error output console (exactly which console this is can be set by the operator/observer/system program).
    MS_PR_STD_TEMPLATE_NAME
    Prints the name of the template (0 - 3) in register 1, as if the process had used the print command.

    Each call costs 1 irpt, except for GET_EFFICIENCY, which costs 32 irpt.


    How to use actions


    This method can be used to attach an action to the next line of text that the process prints using the print command, and all other lines that it prints until this method is called again or execution is completed. If the user clicks on a line with an action, an operator or observer program is informed through its MT_OB_CONSOLE method and can do something about it (such as focus on the process, or give it a command).

    Processes themselves have no direct access to information about what actions the user has clicked on.

    All lines printed by processes have an action with value 0 attached by default (the example observer/operator programs use this to focus on a process if the user clicks on a line printed by the process).

    Example:

    call(METH_ACTION, 1);
    print("\n Click here to do A.");

    call(METH_ACTION, 2);
    print("\n Or here to do B.");

    // If the user clicks on either line, an action will be sent to the user's operator or observer program

    call(METH_ACTION, 0); // resets the action for any further messages



    Mathematics: MT_PR_MATHS
    This method provides maths functions more complicated than the simple ones (add, subtract etc) that are available as basic bcode operations. The compiler has a set of built-in functions that simplify the use of this method and can do almost anything (save some possible optimisations involving register re-use) that can be done by calling it directly. For more information about this, and about the maths functions generally, see MT_PR_MATHS built-in functions.

    Internal, called
    Cost: Minimal
    Size 1 (method registers: 4)
    Extensions: none


    Registers
    MB_PR_MATHS_STATUS
    Determines what function the method will perform when called
    MB_PR_MATHS_TERM1
    MB_PR_MATHS_TERM2
    MB_PR_MATHS_TERM3
    These are the values the function will be performed on.

    Statuses
    MS_PR_MATHS_NONE
    Does nothing, returns 0. Is probably unnecessary.
    MS_PR_MATHS_ATAN2
    Returns atan2(term1, term2). Cost: 12 irpt.
    MS_PR_MATHS_SIN
    Returns sin(term1) * term2. Cost: 4 irpt.
    MS_PR_MATHS_COS
    Returns cos(term1) * term2. Cost: 4 irpt.
    MS_PR_MATHS_HYPOT
    Returns hypot(term1, term2). Cost: 8 irpt.
    MS_PR_MATHS_TURN_DIR
    Returns the direction (-1, 0 or 1) of the shortest path from the angle term1 to the angle term2. Cost: 2 irpt.
    MS_PR_MATHS_ANGLE_DIFF
    Returns the magnitude of the difference between angles term1 and term2. Cost: 2 irpt.
    MS_PR_MATHS_ANGLE_DIFF_S
    Same, but signed. Cost: 2 irpt.
    MS_PR_MATHS_ABS
    Returns abs(term1). Cost: 1 irpt.
    MS_PR_MATHS_SQRT
    Returns sqrt(term1). Cost: 8 irpt.
    MS_PR_MATHS_POW
    Returns pow(term1, term2). Cost: 4 irpt.
    When using this method, be careful not to use the return value of one call to it as a parameter of another call (as the parameter call will overwrite part of the other call). See built-in maths functions for more on this.


    Designate: MT_PR_DESIGNATE
    This method allows a process to track another process that is within range, without having to use the scan method to find it each cycle. A single process can have multiple designate methods if it needs to keep track of multiple targets.

    Internal, called
    Cost: Minimal
    Size 1 (method registers: 4)

    Extensions:
    0: range


    Registers
    MB_PR_DESIGNATE_STATUS
    Determines whether the method is acquiring a target, or locating its previously acquired target.
    MB_PR_DESIGNATE_X
    x location of target (as an offset from calling process).
    MB_PR_DESIGNATE_Y
    y location.

    Statuses
    MS_PR_DESIGNATE_LOCATE
    Sets MB_PR_DESIGNATE_X/Y to the location of the current acquired target, if it's in range. Returns 1 if the target is found, 0 otherwise (which could mean that the target is out of range, or no longer exists).
    MS_PR_DESIGNATE_SPEED
    Sets MB_PR_DESIGNATE_X/Y to the x and y speed of the current acquired target, if it's in range. Returns 1 if the target is found, 0 otherwise.
    MS_PR_DESIGNATE_ACQUIRE
    Acquires target at MB_PR_DESIGNATE_X/Y offset from process.

    To use this method, call it with status MS_PR_DESIGNATE_ACQUIRE and with MB_PR_DESIGNATE_X/Y set to the offset of another process from the calling process. It will return 1 if successful, 0 otherwise. Then in future cycles the process can call the method with status MS_PR_DESIGNATE_LOCATE to get the location of the target, and MS_PR_DESIGNATE_SPEED to get its speed.

    Calling with status MS_PR_DESIGNATE_LOCATE or _SPEED returns 1 if successful, and 0 if unsuccessful. A return value of 0 could mean the target is out of range, or it could mean that the target no longer exists.

    The method's range is a square extending 900 pixels in each direction from the process (plus an additional 300 pixels for each range extension).

    Example of combining the scan and designate methods:

    int scan_return, designated, scan_bitmask;
    int target_x, target_y;
    int scan_result [2];

    scan_bitmask = 0b1111 ^ (1 << get_team());

    scan_return = call(METH_SCAN, // method's index
                       MS_PR_SCAN_SCAN, // status register (MB_PR_SCAN_STATUS) - tells the method to run scan
                       &scan_result [0], // memory address to put results of scan (MB_PR_SCAN_START_ADDRESS)
                       1, // number of targets to find (MB_PR_SCAN_NUMBER) - scanner will stop after finding 1
                       0, // x offset of scan centre (MB_PR_SCAN_X1) - scan is centred on process
                       0, // y offset of scan centre (MB_PR_SCAN_Y1) - scan is centred on process
                       10000, // size of scan (in pixels) (MB_PR_SCAN_SIZE) - very high value means maximum range
                       0, // (MB_PR_SCAN_Y2) - not relevant to this type of scan
                       scan_bitmask, // this bitmask indicates which targets will be found (MB_PR_SCAN_BITFIELD_WANT)
                       0, // bitmask for accepting only certain targets (MB_PR_SCAN_BITFIELD_NEED) - not used here
                       0); // bitmask for rejecting certain targets (MB_PR_SCAN_BITFIELD_REJECT) - not used here

    if (scan_return > 0)
    {
      designated = call(METH_DESIGNATE,
                        MS_PR_DESIGNATE_ACQUIRE, // This mode saves a target
                        scan_result [0], // This is the location of the target as an x offset from the process
                        scan_result [1]); // Same for y

    // The DESIGNATE method returns 1 if it is successful (which should always be the case here, but let's check anyway):
      if (designated == 1)
      {
       target_x = x + scan_result [0];
       target_y = y + scan_result [1];
      }
    }

    // Later, if you want to retrieve the location of the target:

    designated = call(METH_DESIGNATE,
                      MS_PR_DESIGNATE_LOCATE); // This mode saves a target

    target_x = get(METH_DESIGNATE,
                   MB_PR_DESIGNATE_X);
    target_y = get(METH_DESIGNATE,
                   MB_PR_DESIGNATE_Y);




    Link: MT_PR_LINK
    This method allows processes to connect to each other directly. If a process creates another process using the MT_PR_NEW or MT_PR_NEW_SUB method, and if each process has an MT_PR_LINK method at the vertex that meets the other process, and if the MB_PR_NEW_LINK register is set to 1, the processes will be connected. A group of processes connected in this way can have as many as 16 members.

    There is not (currently) any way to have two existing separate processes join together.

    External, called
    Cost: Minimal
    Size 1 (method registers: 4)

    Extensions: none


    Registers
    MB_PR_LINK_STATUS
    Determines what the method does when called.
    MB_PR_LINK_VALUE1
    The purpose of this register depends on its status when called.
    MB_PR_LINK_VALUE2
    Same.
    MB_PR_LINK_MESSAGE_ADDRESS
    This register holds a memory address to which messages received through the connection will be stored.

    Statuses
    MS_PR_LINK_EXISTS
    Returns 1 if there is something connected to this method, 0 if nothing connected.
    MS_PR_LINK_MESSAGE
    Sends the two value registers as a message to the process on the other side of the connection.
    MS_PR_LINK_RECEIVED
    Returns the number of messages received from the other process since the last cycle.
    MS_PR_LINK_SEND_IRPT
    Dends an amount of irpt (determined by value1) through the connection. If there is limited space in the other process' irpt buffer, the amount sent will be reduced accordingly. There is overhead of 24 irpt for calling this, but no limit on the amount sent.
    MS_PR_LINK_SEND_DATA
    Sends data. There is overhead of 24 irpt for calling this, but no limit on the amount sent.
    MS_PR_LINK_NEXT_EXECUTION
    Returns the number of ticks before the connected process will execute.
    MS_PR_LINK_DISCONNECT
    Lets go.

    The method can receive up to LINK_MESSAGES_MAX messages (currently 8), each LINK_MESSAGE_SIZE long (currently 2).

    An example of sending and receiving messages:

    // the sending process does this:
    call(METH_LINK, MS_PR_LINK_MESSAGE, 100, 200);

    // the receiving process does this:
    int link_message [LINK_MESSAGES_MAX] [LINK_MESSAGE_SIZE];
    int number_of_messages;

    put(METH_LINK, MB_PR_LINK_MESSAGE_ADDRESS, &link_message [0] [0]); // only need to do this once, at process initialisation

    number_of_messages = call(METH_LINK, MS_PR_LINK_RECEIVED); // this call will return 1 because the other process sent 1 message

    if (number_of_messages > 0)
    {

     // the sending process' call above will have set link_message [0] [0] to 100 and link_message [0] [1] to 200

     // so here we can do something with the messages...

    }



    Restore: MT_PR_RESTORE
    This method allows processes to repair themselves.

    Internal, called
    Cost: High
    Size 1 (method registers: 4)

    Extensions:
    0: rate


    Registers
    MB_PR_RESTORE_NUMBER
    The number of hp the method will try to restore when called.
    Example:

    call(METH_RESTORE, 4); // tries to restore 4 hp.
    The method can restore 1 hp per call, plus 1 for each rate extension. It can be called once per cycle. Restoring costs 128 irpt per hp restored, so it is not cheap.


    Redundancy: MT_PR_REDUNDANCY
    This method increases the number of hp a process has.

    Internal, not called, single
    Cost: Minimal + special
    Size 1 (method registers: 4)

    Extensions:
    0: extra

    Registers: None

    If a process has this method, its hp is increased by 40% (plus an additional 20% for each extension). The process' mass (and therefore also its data cost) is increased by the same proportion.


    Broadcast: MT_PR_BROADCAST
    This method allows a process to communicate with other processes that have the MT_PR_LISTEN method.

    External, called
    Cost: Minimal
    Size 1 (method registers: 4)

    Extensions:
    0: range

    Registers
    MB_PR_BROADCAST_POWER
    This is the range of the broadcast, in pixels (the range is a square extending this number of pixels in each direction). If this register is set too high, the maximum range will be used.
    MB_PR_BROADCAST_ID
    This holds a bitfield message ID that listening processes can use to screen incoming messages.
    MB_PR_BROADCAST_VALUE1
    This is the first value of the message.
    MB_PR_BROADCAST_VALUE2
    Second value (each message is 2 ints long).
    Example:


    call(METH_BROADCAST, 1000, 0b101, 5, 10); // sends the message (5, 10) to other processes within 1000 pixels (orthogonally), with a bitfield message ID of 0b101.
    The maximum range of a broadcast is 600 pixels, plus 300 for each range extension. The cost of sending a broadcast is 32 irpt plus the broadcast's power / 32.


    Listen: MT_PR_LISTEN
    This method receives and stores messages sent by other processes using the broadcast method. It can only hear messages sent by processes controlled by the same player.

    Internal, called, automatic
    Cost: Minimal
    Size 1 (method registers: 4)

    Extensions: none


    Registers
    MB_PR_LISTEN_ID_WANT
    A bitfield. At least one bit of the value in this register must be 1 in a broadcast's message ID for the message to be received. Set this to 0 to receive no messages.
    MB_PR_LISTEN_ID_NEED
    All bits that are 1 in this value must be 1 in a broadcast's message ID for the message to be received.
    MB_PR_LISTEN_ID_REJECT
    No bits that are 1 in this value can be 1 in a broadcast's message ID for the message to be received.
    MB_PR_LISTEN_ADDRESS
    The address that received messages will be recorded to. If 0, no messages will be recorded.
    A listen method can receive up to LISTEN_MESSAGES messages (currently 8) between cycles, and each message is LISTEN_MESSAGE_SIZE (currently 5) ints long. When called, it returns the number of messages received since the previous cycle.

    The structure of a message is:
    LISTEN_RECORD_ID
    The message ID bitfield.
    LISTEN_RECORD_VALUE1
    The first value of the message.
    LISTEN_RECORD_VALUE2
    Second value.
    LISTEN_RECORD_SOURCE_X
    The location of the message's source when the message was sent, as an x offset from the listening process.
    LISTEN_RECORD_SOURCE_Y
    y offset.
    Example:


    int messages [LISTEN_MESSAGES] [LISTEN_MESSAGE_SIZE];

    int messages_received, message_source_x_offset, message_source_y_offset;

    put(METH_LISTEN, MB_PR_LISTEN_ADDRESS, &messages [0] [0]); // only needs to be done once, at process initialisation

    put(METH_LISTEN, MB_PR_LISTEN_WANT, 0xFFFF); // receive all messages - this also only needs to be done once, at initialisation

    // Now check for messages received:
    messages_received = call(METH_LISTEN);

    if (messages_received > 0)
    {
     // find the location of the process that sent the first message received:
     message_source_x_offset = messages [0] [LISTEN_RECORD_SOURCE_X];
     message_source_y_offset = messages [0] [LISTEN_RECORD_SOURCE_Y];
    }


    Yield: MT_PR_YIELD
    This method allows a process to transmit irpt and data to another nearby process. It transfers much more slowly than the MT_PR_LINK method, but does not require a direct connection.

    External, called
    Cost: Medium
    Size 1 (method registers: 4)

    Extensions:
    0: range
    1: rate


    Registers

    MB_PR_YIELD_IRPT
    When called, the method tries to transfer this much irpt to the target process.
    MB_PR_YIELD_DATA
    Same, for data.
    MB_PR_YIELD_X
    This is the location of the target process, as an x offset from the yielding process.
    MB_PR_YIELD_Y
    y offset.

    Return values

    The method returns one of the following values:
    MR_YIELD_SUCCESS
    Success.
    MR_YIELD_FAIL_ALREADY
    The method has already been called this cycle.
    MR_YIELD_FAIL_SETTINGS
    One of the method's registers contains an invalid number.
    MR_YIELD_FAIL_IRPT
    The process doesn't have enough irpt.
    MR_YIELD_FAIL_DATA
    The process doesn't have enough data.
    MR_YIELD_FAIL_TARGET
    Nothing was found at the target location.
    MR_YIELD_FAIL_FULL
    The target process had no space in its irpt or data buffer to receive anything.
    MR_YIELD_FAIL_RANGE
    The specified x/y offsets are out of range.
    Trying to send more irpt or data than the target can receive just results in a lesser amount being transferred (unless nothing can be transferred at all, in which the call fails).

    The method has a range of 500 pixels (orthogonal square) plus 300 per range extension, and can transfer at a rate of 255 irpt plus 127 per rate extension, and 4 data plus 4 per rate extension. Calling it has an overhead of 32 irpt.


    Storage: MT_PR_STORAGE
    This method increases the amount of data a process can store.

    Internal, not called
    Cost: Medium
    Size 1 (method registers: 4)

    Extensions:
    0: capacity

    Registers: none

    Increases the maximum data storage by 40% plus 20% for each capacity extension.


    Static: MT_PR_STATIC
    This method makes a process immobile, like an allocate method. It isn't particularly useful, but it's there if you need it.

    Internal, not called
    Cost: Minimal
    Size 1 (method registers: 4)

    Registers: none


    Command (process): MT_PR_COMMAND
    This method allows a process to receive commands from its player's client program. You can use the get_command() and get_command_bit() built-in functions to call this method easily.

    Each process has 16 command registers, each of which can be read and written to by both the process and the client. Command registers are initialised to zero on process creation, but retain their values between executions.

    This method is not needed to write to command registers; the MT_PR_STD method can do this.

    Internal, called
    Cost: Minimal
    Size 1 (method registers: 4)

    Extensions: none


    Registers

    MB_PR_COMMAND_STATUS
    Read or write.
    MB_PR_COMMAND_INDEX
    Which command register is being read from.
    MB_PR_COMMAND_BIT
    If reading a single bit, this is the bit.

    Statuses

    MS_PR_COMMAND_READ
    Calling with this status returns the value of the command register in MB_PR_COMMAND_INDEX.
    MS_PR_COMMAND_BIT
    Calling with this status returns the value (1 or 0) of a single bit (indicated by MB_PR_COMMAND_BIT) in command register MB_PR_COMMAND_INDEX.


    Virtual interface: MT_PR_VIRTUAL
    This method provides a buffer that absorbs damage that would otherwise be inflicted on a process. It can greatly increase the process' durability, but it is expensive and having it active costs a lot of irpt.

    Internal, called, single
    Cost: Ultra
    Size 1 (method registers: 4)

    Extensions:
    0: capacity
    1: charge rate

    Maximum capacity is 96 (plus 32 for each capacity extension).

    Costs an additional 64 irpt (plus 32 for each extension) each cycle while active.

    Registers
    MB_PR_VIRTUAL_STATUS
    Status register. Affects what the method does when called.
    MB_PR_VIRTUAL_VALUE
    When calling the method with the MS_PR_VIRTUAL_CHARGE status, this register determines how much charge is attempted.
    MB_PR_VIRTUAL_CURRENT
    This register holds the current strength of the method. Changing it doesn't do anything.
    MB_PR_VIRTUAL_MAX
    This register holds the maximum strength of the method. Changing it doesn't do anything.
    Statuses

    MS_PR_VIRTUAL_CHARGE
    When called, tries to charge up the method by the amount in register 1. The maximum amount it can be charged by is 4 (plus 3 for each charge rate extension), and it can be charged only once each execution cycle. There is no need to check whether the method is fully charged, as any overcharge is ignored.
    After a virtual interface is broken by damage, it cannot be charged for a short period (96 ticks).
    MS_PR_VIRTUAL_GET_STATE
    Returns -1 if the method is active, 0 if it is inactive but can be charged, or, if it has been broken and cannot be charged yet, the number of ticks before it can be charged.
    MS_PR_VIRTUAL_GET_MAX
    Returns the maximum capacity of the method.
    MS_PR_VIRTUAL_DISABLE
    Turns the method off, losing all charge (but not preventing recharging for any period of time).

    6.2 Client methods (CL)

    These methods can be used by operator, delegate and system programs.

    Command (client): MT_CL_COMMAND_GIVE
    This method is the other side of the MT_PR_COMMAND method. It allows a client program to communicate with all processes it controls by writing to their command registers (the MT_CLOB_COMMAND_REC method allows clients and observers to read command registers).

    Size 1 (method registers: 4)


    Registers

    MB_PR_COMMAND_STATUS
    Read or write.
    MB_PR_COMMAND_PR_INDEX
    Which process is being commanded.
    MB_PR_COMMAND_CMD_INDEX
    Which command register is being used.
    MB_PR_COMMAND_VALUE
    If writing to a register, this is the value written.

    Statuses

    MS_CL_COMMAND_VALUE
    Sets the command register in MB_PR_COMMAND_CMD_INDEX of the process in MB_PR_COMMAND_PR_INDEX to MB_PR_COMMAND_VALUE.
    MS_CL_COMMAND_BIT_0
    Like MS_CL_COMMAND_VALUE, but MB_PR_COMMAND_VALUE indicates a bit of the register that is to be set to 0.
    MS_CL_COMMAND_BIT_1
    Like MS_CL_COMMAND_BIT_0, but sets the bit to 1.
    You can use the command(), command_bit_0(1) and command_bit_1() built-in functions to call this method easily.


    Template: MT_CL_TEMPLATE
    This method copies code from the client program to a process template (if the system program allows process templates to be modified). It works a lot like the MT_SY_TEMPLATE method, except that it can only copy to the player's process templates (so the template index is just a number from 0 to 3).

    Size 1 (method registers: 4)


    Registers

    MB_CL_TEMPLATE_INDEX
    This is the number of the process template (0 to 3).
    MB_CL_TEMPLATE_START
    This is the start address, in the client's bcode, of the code to copy.
    MB_CL_TEMPLATE_END
    This is the end address.
    MB_CL_TEMPLATE_NAME
    This is the address of a null-terminated string to be used as the name of the template. If 0, the template is not given a name.

    6.3 Client/Observer methods (CLOB)

    These methods can be used by clients (operators and delegates), observers and system programs.


    Check point: MT_CLOB_POINT
    Allows a client/observer to find what's at a particular location.

    Size 1 (method registers: 4)


    Statuses

    MS_CLOB_POINT_EXACT
    This status followed by x,y coordinates returns the index of the process at that location (with more or less pixel accuracy), or -1 if no process found.
    MS_CLOB_POINT_FUZZY
    Similar to EXACT, but checks a small area around the target coordinates as well and returns the index of the closest process. May be useful for things like checking whether the user has clicked on a process.
    MS_CLOB_POINT_ALLOC_EFFIC
    Returns the allocator efficiency (0-100) that a process with an allocator method would have at a particular location.
    Example:

    a = call(METH_POINT, MS_CLOB_POINT_EXACT, 1000, 3000); // returns index of process at 1000,3000

    Query: MT_CLOB_QUERY
    Allows a client/observer to run the equivalent of an MT_PR_INFO method call for a specified process. Uses the same MS_PR_INFO_* statuses as the INFO method. Can be called on processes controlled by other players. Returns -1 if a process doesn't exist, unless it was destroyed in the last few ticks in which case it returns -2.

    Size 1 (method registers: 4)

    Example:

    x = call(METH_QUERY, MS_PR_INFO_GET_X, 20); // returns x coordinate of process 20
    The query_*() built-in functions make it easy to use this method.


    Scan (clob): MT_CLOB_SCAN
    Allows a client/observer to scan an area of the world, a bit like a process' scan using the MT_PR_SCAN method.

    Size 2 (method registers: 8)


    Statuses

    MS_CLOB_SCAN_SCAN
    This status works much like the MT_PR_SCAN scan, and uses the same MB_* macros. The differences are:
    1. The MB_PR_SCAN_X1 and Y1 values are absolute values rather than offsets. The centre of the scan can be anywhere in the game area.
    2. The scan's maximum size is 1200 (as CLOB methods don't have extensions).
    MS_CLOB_SCAN_RECTANGLE
    This status performs a scan over a rectangle with specified corners, rather than a square. Its results are ordered roughly from left to right then top to bottom, rather than from the centre of the scan. Also:
    1. The MB_PR_SCAN_X1 and Y1 values are the coordinates of the top left of the rectangle.
    2. The MB_PR_SCAN_SIZE value is the x coordinate of the bottom right, and the MB_PR_SIZE2 value is the y coordinate of the bottom right.
    3. The maximum size of the scan is 4096x4096 pixels. If it is larger, it will be shrunk from the right and bottom.
    MS_CLOB_SCAN_EXAMINE
    Like the MS_PR_SCAN_EXAMINE call, but the MB_PR_SCAN_X1 and Y1 values are absolute values rather than offsets.
    MS_CLOB_SCAN_SCAN_INDEX
    This works in the same way as MS_CLOB_SCAN_SCAN, but the results array is a list of process indices rather than a list of coordinates.
    MS_CLOB_SCAN_RECTANGLE_INDEX
    The rectangular version of MS_CLOB_SCAN_SCAN_INDEX.
    All calls return the number of processes found if successful, and an MR_SCAN_FAIL_* value if unsuccessful.


    Maths (clob): MT_CLOB_MATHS
    This works just like MT_PR_MATHS, and uses the MS_PR_MATHS_* status values and built-in functions.

    Size 1 (method registers: 4)

    Standard client/observer method: MT_CLOB_STD
    Gives a client/observer various basic functions, such as functions returning pieces of information about the game parameters or about the client/observer itself. The world_*() built-in functions can be used instead of some of these method calls.

    Size 1 (method registers: 4)


    Statuses

    MS_CLOB_STD_WORLD_SIZE_X
    Returns the width of the game area, in pixels.
    MS_CLOB_STD_WORLD_SIZE_Y
    Same, for height.
    MS_CLOB_STD_WORLD_PROCS
    The maximum number of processes that can exist.
    MS_CLOB_STD_WORLD_TEAM
    The player index number of the client (-1 for observers).
    MS_CLOB_STD_WORLD_TEAMS
    How many players there are.
    MS_CLOB_STD_WORLD_TEAM_SIZE
    Actual number of processes for team indicated by register 1.
    MS_CLOB_STD_WORLD_PROCS_EACH
    Maximum number of processes for each team.
    MS_CLOB_STD_WORLD_FIRST_PROC
    First process index for team indicated by register 1 (e.g. if each team can have 100 processes, calling this for team 2 will return 200).
    MS_CLOB_STD_WORLD_LAST_PROC
    Last process index (e.g. if each team can have 100 processes, calling this for team 2 will return 299).
    MS_CLOB_STD_WORLD_INSTR_LEFT
    How many instructions the client/observer has left.
    MS_CLOB_STD_WORLD_TIME
    Returns how many ticks have elapsed in the game. This is likely to overflow fairly quickly, so after the method is called with this status, register 1 holds the time divided by 32767 (also, register holds the time % 32767).
    MS_CLOB_STD_TEMPLATE_NAME
    Prints the name of a process template to a console (as if it was being printed with the print() function).
    If used by a client or operator program, register 1 holds the index (0 to 3) of the process template.
    If used by an observer or system program, register 1 holds the index of the player who the template belongs to, and register 2 holds the template's index.

    Command receive: MT_CLOB_COMMAND_REC
    This method allows client and observer programs to read process' command registers. If used by a client, only processes controlled by the client can be read.

    Size 1 (method registers: 4)


    Statuses
    MS_CLOB_COMMAND_VALUE
    Register 1 holds the process index, and register 2 holds the index of the command register.
    MS_CLOB_COMMAND_BIT
    Register 1 holds the process index, register 2 holds the index of the command register and register 3 indicates which bit is being read. The method returns 0 or 1.
    You can use the check_command() and check_command_bit(1) built-in functions to call this method easily.

    6.4 Observer methods (OB)

    These methods can be used by observers, operators and system programs (but not by delegate programs).

    Input: MT_OB_INPUT
    Receives input from the user.

    Size 1 (method registers: 4)

    What this method does when called depends entirely on the value of the first method register.


    Status

    MS_OB_INPUT_MOUSE_BUTTON
    Sets register 1 to the left mouse button's status (a BUTTON_* value), sets register 2 to the right mouse button's status, and returns the mouse's status (a MOUSE_STATUS_* value).
    Example:
    int lmb, rmb, mouse_status;

    mouse_status = call(METH_INPUT, MS_OB_INPUT_MOUSE_BUTTON);

    if (mouse_status != MOUSE_STATUS_OUTSIDE)
    {
     lmb = get(METH_INPUT, 1);
     if (lmb <= BUTTON_NOT_PRESSED) // means that button not pressed (and also not just released)
      rmb = get(METH_INPUT, 2);
    }

    MS_OB_INPUT_MODE_MOUSE_XY
    Sets registers 1 and 2 to the x and y coordinates of the mouse, and returns the mouse's status. The coordinates indicate the mouse's position in the game world (in pixels), not on screen, so you do not need to adjust for camera position.
    MS_OB_INPUT_MOUSE_SCREEN_XY
    Like MS_OB_INPUT_MODE_MOUSE_XY, but the coordinates give the mouse's position on the game display, with 0,0 being the top left corner.
    MS_OB_INPUT_MOUSE_MAP_XY
    Like MS_OB_INPUT_MODE_MOUSE_XY, but only works if the mouse is over the map. The coordinates indicate the position in the game world that corresponds to the mouse's position on the map.
    MS_OB_INPUT_KEY
    Returns the status of a key (using one of the BUTTON_* values also used for mouse button status). The key should be specified in register 1 as one of the KEY_* values (see Appendix A: Key codes).
    Example:
    int is_a_pressed;

    is_a_pressed = call(METH_INPUT, MS_OB_INPUT_KEYBOARD, KEY_A);

    MS_OB_INPUT_ANY_KEY
    Checks for any key being pressed, and returns its KEY_* value (or -1 if no key being pressed). Also sets register 0 to the key's BUTTON_* status.
    If multiple keys are being pressed, it just returns one of them.

    Mouse status values (returned by all mouse method calls)
    MOUSE_STATUS_OUTSIDE
    The mouse is outside the game area (e.g. on the editor panel, or outside the game's window). In this case, no other values (mouse button status etc.) are set.
    MOUSE_STATUS_AVAILABLE
    The mouse is in the game area, and none of the following statuses apply.
    MOUSE_STATUS_MAP
    The mouse is over the map.
    MOUSE_STATUS_CONSOLE
    The mouse is over a console.
    MOUSE_STATUS_PROCESS
    The mouse is over the process data display.

    Mouse button and key status values
    BUTTON_JUST_RELEASED (-1)
    The button is not being pressed, but was being pressed until a tick ago.
    BUTTON_NOT_PRESSED (0)
    The button is not being pressed and was not just released.
    BUTTON_JUST_PRESSED (1)
    The button was just pressed.
    BUTTON_HELD (2)
    The button is being held.

    View: MT_OB_VIEW
    Controls the screen and various aspects of the user interface.

    Size 2 (method registers: 8)

    What this method does when called depends on the value of the first method register.


    Statuses
    MS_OB_VIEW_FOCUS_XY
    Sets the camera position (which determines what part of the game area the user sees). Registers 1 and 2 are x/y coordinates, in pixels.
    Example:
    call(METH_VIEW, MS_OB_VIEW_FOCUS_XY, 1000, 2000); // sets the camera so the location 1000,2000 will be in the centre of the screen.
    MS_OB_VIEW_FOCUS_PROC
    Sets the camera position so a particular process (with the index specified in register 1) is at the centre of the screen. Does nothing if the process doesn't exist.
    Example:
    call(METH_VIEW, MS_OB_VIEW_FOCUS_PROC, 50); // screen will be centred on process 50.
    MS_OB_VIEW_PROC_DATA
    Opens the process data box, and sets it to display information about a process specified by register 1. You should probably set the data box's location (using the next status) before calling this.
    MS_OB_VIEW_PROC_DATA_XY
    Sets the location of the top left of the data box to the screen location indicated by registers 1 and 2.
    MS_OB_VIEW_SCROLL_XY
    Moves the screen left/right (register 1) and up/down (register 2). Won't move it past the edges of the game area.
    MS_OB_VIEW_MAP_VISIBLE
    Sets the map on (1) or off (0) (register 1) .
    MS_OB_VIEW_MAP_XY
    Sets the x/y location of the map.
    MS_OB_VIEW_MAP_SIZE
    Sets the size of the map. Register 1 is width and register 2 is height (both in pixels).
    MS_OB_VIEW_DISPLAY_SIZE
    Gets the size of the display. When called, the method sets register 1 to the current width of the game area of the screen, and register 2 to the height. This doesn't include the editor panel, if it's open. Returns 1 if the display has been resized since the last cycle (for example, if the editor panel was just opened or closed), and 0 otherwise.
    Example:
    int screen_just_resized;

    screen_just_resized = call(METH_VIEW, MS_OB_VIEW_DISPLAY_SIZE);

    if (screen_just_resized)
    {
     print("\nScreen resized to ", get(METH_VIEW, 1), " by ", get(METH_VIEW, 2), " pixels.");
    }


    MS_OB_VIEW_COLOUR_PROC
    Changes the colours used for a player's processes. Register 1 is the player index, register 2 is the red value at minimum intensity, register 3 is the red value at maximum intensity, register 4 is the green value at minimum intensity, etc. Colour values are 0 to 255.
    Maximum intensity is the colour used for things like undamaged processes. Minimum intensity is used for things like badly damaged processes and the faint underlay thing that appears underneath a process. The maximum intensity value for a colour can be less than the minimum, in which case that colour component increases as the intensity decreases.
    Example:

    call(METH_VIEW,
     MS_OB_VIEW_COLOUR_PROC, // status
     0, // player index (i.e. player 1)
     180, // red at minimum intensity
     10, // red at maximum intensity
     0, // green min
     50, // green max
     0, // blue min
     210); // blue max

    // these settings make processes look blue (with a red underlay) when undamaged, then redder the more damaged they get.

    This is a relatively expensive operation.
    MS_OB_VIEW_COLOUR_PACKET
    Just like MS_OB_VIEW_COLOUR_PROC, but changes packet colours for a specified player.
    MS_OB_VIEW_COLOUR_DRIVE
    Changes colours produced by the MOVE method.
    MS_OB_VIEW_COLOUR_BACK
    Changes the colour of the background. Just uses registers 1 (red), 2 (green) and 3 (blue).
    MS_OB_VIEW_COLOUR_BACK2
    Changes the base colour of the hexagonal pattern in the background. Just uses registers 1 (red), 2 (green) and 3 (blue).
    MSTATUS_OB_VIEW_SOUND
    Plays an interface sound (e.g. the blip you get when you click on a process). Not yet fully implemented. Register 1 indicates which sample to play (currently does nothing), register 2 indicates the tone (currently a chromatic scale from 0 to about 40, I think), and register 3 is volume (1 to 100).


    Console: MT_OB_CONSOLE
    Controls the consoles that display text printed by processes and other programs.

    Size 1 (method registers: 4)

    Up to 4 consoles are available (consoles 0 to 3). For most console method calls, register 0 is the status and register 1 is the index of the console being affected.


    Statuses
    MS_OB_CONSOLE_OPEN
    Opens a console.
    MS_OB_CONSOLE_CLOSE
    Closes a console.
  • MS_OB_CONSOLE_MIN
  • Minimises a console.
    MS_OB_CONSOLE_STATE
    Returns the state of a console. States are 0 (closed), 1 (open but minimised), 2 (open).
    MS_OB_CONSOLE_GET_XY
    Gets the on-screen location of the console. After the call, registers 2 and 3 hold the x/y coordinates of the top left corner of the console (if the console's header is at the top) or the bottom left corner (if the header is at the bottom).
    MS_OB_CONSOLE_MOVE
    Sets the location of the console. Works like MS_OB_CONSOLE_GET_XY, but the other way around.
    MS_OB_CONSOLE_LINES
    Sets the number of lines in the console (when maximised) to register 2. The maximum size is 40.
    MS_OB_CONSOLE_ACTION_SET
    Sets an action (see below).
    MS_OB_CONSOLE_ACTION_CHECK
    Checks for actions (see below).
    MS_OB_CONSOLE_CLEAR
    Clears a console's contents.
    MS_OB_CONSOLE_STYLE
    Changes the style of a console to a CONSOLE_STYLE value (see below). The style value goes in register 2.
    MS_OB_CONSOLE_OUT
    Sets which console the calling program's standard output is sent to.
    MS_OB_CONSOLE_ERR
    Sets which console the calling program's error output (including errors generated by the game itself) is sent to.
    MS_OB_CONSOLE_COLOUR
    Sets the colour of a console's text to one of the following values (in register 2): COL_DGREY, COL_LGREY, COL_WHITE, COL_LBLUE, COL_DBLUE, COL_LRED, COL_DRED, COL_LGREEN, COL_DGREEN, COL_LPURPLE, COL_DPURPLE.
    MS_OB_CONSOLE_FONT
    Sets the font of a console to one of the following (in register 2): FONT_CODE (this is the font used in the code editor), FONT_CODE_BOLD, FONT_BASIC (this is the default), FONT_BASIC_BOLD, FONT_BASIC_LARGE. Also clears the console.
    MS_OB_CONSOLE_BACKGROUND
    Sets the colour of the console's background (and header) to the value in register 2. Colours are BCOL_GREY, BCOL_RED, BCOL_GREEN, BCOL_BLUE, BCOL_YELLOW, BCOL_ORANGE, BCOL_PURPLE, BCOL_TURQUOISE, BCOL_AQUA, BCOL_CYAN.
    MS_OB_CONSOLE_TITLE
    Sets the title of the console. Register 2 should hold the address of a null-terminated string. For example:
    int console_name [10] = {"Commands"};
    call(METH_CONSOLE, MS_OB_CONSOLE_TITLE, 0, &console_name [0]); // sets the name of console 0
    MS_OB_CONSOLE_LINES_USED
    Returns the number of lines that have been printed to the console (up to the maximum number it can hold) since it was last cleared.
    MS_OB_CONSOLE_OUT_SYSTEM
    Sets the console to which the system program's standard output is sent.
    MS_OB_CONSOLE_OUT_OBSERVER
    Sets the console to which the observer's standard output is sent.
    MS_OB_CONSOLE_OUT_PLAYER
    Sets the console to which standard output from a player's programs (including client and processes) is sent. Register 1 holds the console index and register 2 holds the player index.
    MS_OB_CONSOLE_OUT2_PLAYER
    Sets the console to which a player's alternative output is sent.
    MS_OB_CONSOLE_ERR_SYSTEM
    Sets the console to which the system's error output is sent.
    MS_OB_CONSOLE_ERR_OBSERVER
    Sets the console to which the observer's error output is sent.
    MS_OB_CONSOLE_ERR_PLAYER
    Sets the console to which error output from a player is sent. Works like MS_OB_CONSOLE_OUT_PLAYER.

    Example of using a console:

    call(METH_CONSOLE, MS_OB_CONSOLE_OPEN, 0); // opens console 0
    call(METH_CONSOLE, MS_OB_CONSOLE_XY, 0, 50, 50); // puts console 0 at 50,50 on screen



    Actions


    You can assign an action to a line printed to a console using the MS_OB_CONSOLE_ACTION_SET status. If the user clicks on the line, a call to MS_OB_CONSOLE_ACTION_CHECK will inform the observer/operator of the action.

    An MS_OB_CONSOLE_ACTION_SET call applies to the most recently printed line in the specified console (this is different to the way the MT_PR_ACTION process method sets actions; they apply to all later lines printed by the process). The values in registers 2 and 3 will be set as the action values.

    An MS_OB_CONSOLE_ACTION_CHECK call checks whether the user has clicked on a console line with an action attached to it. It returns one of the following values:
    CONSOLE_ACTION_NONE
    No action occurred.
    CONSOLE_ACTION_SYSTEM
    An action was found. The action was generated by the system program.
    CONSOLE_ACTION_OBSERVER
    An action generated by the observer program was found.
    CONSOLE_ACTION_OPERATOR
    An action generated by the operator program was found.
    CONSOLE_ACTION_PROCESS
    An action generated by a process was found.
    Note that there is no way for a delegate program to generate an action.

    If an action generated by a system, observer or operator was found, the registers will be set as follows:
    Register 0: the console that the line was in.
    Register 1: the first value of the action.
    Register 2: the second value of the action.

    If an action generated by a process was found, the registers will be set as follows:
    Register 0: the console that the line was in.
    Register 1: the index of the player who controls the process (0-3).
    Register 2: the index of the process.
    Register 3: the value the process set for the action.

    Every line printed by a process automatically attaches an action with a value of 0 (the observer and operator programs that come with the game use this to focus on a process when the user clicks on a line printed by the process). The process can set a different value using the MT_PR_STD method.

    Example:

    // setting the action:
    print("\n >> click here to send an action! <<");
    call(METH_CONSOLE, MS_OB_CONSOLE_ACTION_SET, 0, 100, 200);
    // This adds an action to the line just printed to console 0.

    // checking for an action:
    int action_detected, source_console, action_value1, action_value2;

    action_detected = call(METH_CONSOLE, MS_OB_CONSOLE_ACTION_CHECK); 

    if (action_detected == CONSOLE_ACTION_OPERATOR)
    {
     source_console = get(METH_CONSOLE, 0);
     action_value1 = get(METH_CONSOLE, 1);
     action_value2 = get(METH_CONSOLE, 2);
    }
    // if the user clicked on the line set above in this example, source_console would be 0, action_value1 would be 100 and action_value2 would be 200


    Console styles

    The following styles are available:
    CONSOLE_STYLE_BASIC
    A basic top-down scrollable console.
    CONSOLE_STYLE_BASIC_UP
    Like BASIC, but the header is at the bottom of the console and the rest of the console extends upwards from it.
    CONSOLE_STYLE_CLEAR_CENTRED
    The console is just lines of centred text, with no background.
    CONSOLE_STYLE_BOX
    A non-scrollable box.
    CONSOLE_STYLE_BOX_UP
    Like BOX but the console extends upwards.

    Select: MT_OB_SELECT
    Adds some minor graphic elements to the user interface. There can be up to 64 markers active at once.

    Size 1 (method registers: 4)


    Statuses
    MS_OB_SELECT_SET_MARKER
    Creates a marker, and returns the index of the newly created marker (or -1 if there are no markers left). 
    Register 1 sets the marker type, register 2 is how many ticks the marker lasts for, and register 3 is the colour. After you set a marker, you need to place it as well, using one of the following calls.
    The colour should be one of BCOL_GREY, BCOL_RED, BCOL_GREEN, BCOL_BLUE, BCOL_YELLOW, BCOL_ORANGE, BCOL_PURPLE, BCOL_TURQUOISE, BCOL_AQUA or BCOL_CYAN.
    MS_OB_SELECT_PLACE_MARKER
    Places a marker at a specified location. Register 1 is the marker's index, register 2 is x (world coordinates, not screen coordinates) and register 3 is y.
    MS_OB_SELECT_PLACE_MARKER2
    Used for markers with two sets of coordinates (boxes and lines). Sets the second set of coordinates (register 1 is index, register 2 is x, register 3 is y). If the marker is a box, this corner can be in any direction from the first corner (it doesn't have to be the bottom right of the box).
    MS_OB_SELECT_BIND_MARKER
    Binds a marker to a process (marker index in register 1; process index in register 2). If the marker has two sets of coordinates, this binds the first set to the process.
    MS_OB_SELECT_BIND_MARKER2
    Binds the second set of coordinates of a line marker to a process (marker index in register 1; process index in register 2).
    MS_OB_SELECT_UNBIND_PROCESS
    Removes all markers from a process (index in register 1).
    MS_OB_SELECT_CLEAR_ALL
    Clears all markers, with no transition animations (i.e. markers disappear instantaneously instead of fading out).
    MS_OB_SELECT_EXPIRE_ALL
    Causes all markers to expire, showing transition animations.
    MS_OB_SELECT_CLEAR
    Clears a single marker (index in register 1).
    MS_OB_SELECT_EXPIRE
    Causes a single marker to expire (index in register 1).
    MS_OB_SELECT_MARKER_SPIN
    Sets the speed and direction a marker spins in (only relevant for the markers that do actually spin). Register 1 is the marker index, register 2 is the new spin (-128 to 128).
    MS_OB_SELECT_MARKER_ANGLE
    Sets the angle of a marker. Only relevant for markers that can spin. Register 1 is the marker index, register 2 is the new angle (0 to 8192).
    MS_OB_SELECT_MARKER_SIZE
    Sets the size of a marker. Register 1 is marker index, register 2 is size (0 to 15).
    Marker types

    There are currently the following kinds of markers:
    MARKER_BASIC
    Spinning marker with 4 inward-pointing things.
    MARKER_BASIC_6
    Like BASIC, but with 6 things.
    MARKER_BASIC_8
    Like BASIC, but with 8 things.
    MARKER_PROC_BOX
    Draws a box around a process. Base size depends on the process' size.
    MARKER_CORNERS
    Little outward-pointing arrow things.
    MARKER_SHARP
    Like BASIC, but with pointier things.
    MARKER_SHARP_5
    Like BASIC, but with 5 pointier things.
    MARKER_SHARP
    Like BASIC, but with 7 pointier things.
    MARKER_BOX
    A box that appears on the game display (e.g. used for selecting groups of processes). Uses both sets of coordinates.
    MARKER_MAP_POINT
    A point that appears on the map only.
  • MARKER_MAP_AROUND_1
  • Another kind of map marker.
    MARKER_MAP_AROUND_2
    Another kind of map marker.
    MARKER_MAP_CROSS
    Another kind of map marker.
    MARKER_MAP_LINE
    A line that appears on the map. Uses both sets of coordinates.
    MARKER_MAP_BOX
    A box that appears on the map. Uses both sets of coordinates.

    Example:

    int marker, map_marker;

    marker = call(METH_SELECT, MS_OB_SELECT_SET_MARKER, MARKER_BASIC, 32, BCOL_YELLOW);
    call(METH_SELECT, MS_OB_SELECT_PLACE_MARKER, marker, 1000, 3000);
    map_marker = call(METH_SELECT, MS_OB_SELECT_SET_MARKER, MARKER_MAP, 32);
    call(METH_SELECT, MS_OB_SELECT_PLACE_MARKER, map_marker, 1000, 3000);

    // This puts two markers at the location 1000,3000. One will be displayed on the screen, and the other will be displayed on the map. Both will last for about a second (32 ticks).
    // If a new marker can't be set (because there are already 64 markers), the _SET_MARKER call will return -1 and the PLACE_MARKER calls will just do nothing.

    Example:

    int marker;

    marker = call(METH_SELECT, MS_OB_SELECT_SET_MARKER, MARKER_BOX, 1, BCOL_GREY);
    call(METH_SELECT, MS_OB_SELECT_PLACE_MARKER, marker, 500, 800);
    call(METH_SELECT, MS_OB_SELECT_PLACE_MARKER2, marker, 700, 1000);

    // This puts a box with corners at 500,800 and 700,1000. It will last for a single tick.


    Control: MT_OB_CONTROL
    Gives the observer some information about the game and allows it to communicate with the system program.

    Size 1 (method registers: 4)


    Statuses

    MS_OB_CONTROL_PAUSED
    Returns 1 if the game is paused, 0 otherwise. Can't be used to tell if the game is halted rather than paused (as the observer won't be running if it's halted).
    MS_OB_CONTROL_PAUSE_SET
    Turns pause on (if register 1 is 1) or off (if register 1 is 0)
    MS_OB_CONTROL_FF
    Returns 1 if the game is fast-forwarding, 0 otherwise.
    MS_OB_CONTROL_FF_SET
    Turns fast forward on (if register 1 is 1) or off (if register 1 is 0).
    Register 2 determines the fast forward mode: 0 means smooth fast forward mode (the game unlocks the frame rate and runs as fast as it can), 1 means skippy mode (the game displays 1 frame per second and between those frames runs as fast as possible), 2 means 4x speed (only 1 in 4 frames is displayed), 3 means 8x speed.
    MS_OB_CONTROL_PHASE
    Returns the game phase (see game phases)
    MS_OB_CONTROL_SYSTEM_SET
    Allows the observer to communicate with the system program. There are 64 shared registers that both can use (the system program can use them with the MT_SY_MANAGE method). Register 1 is the register index, register 2 is the value to set it to.
    MS_OB_CONTROL_SYSTEM_READ
    Returns the value of a system/observer shared register. Register 1 (of the method) is the register index.
    MS_OB_CONTROL_TURN
    Returns the current turn. Returns -1 if the game doesn't have turns.
    MS_OB_CONTROL_TURNS
    Returns the number of turns in the game. Returns -1 if there is no specific limit, or if the game doesn't have turns.
    MS_OB_CONTROL_SECONDS_LEFT
    Returns the number of seconds left in the current turn.
    MS_OB_CONTROL_TICKS_LEFT
    Returns the number of ticks left in the current turn, capped at 32767.
    MS_OB_CONTROL_TURN_SECONDS
    Returns the total number of seconds in a turn.


    6.5 System methods (SY)

    These methods can only be used by the system program.

    Place: MT_SY_PLACE
    Places processes in the world. Similar to the MT_PR_NEW method, but the system program can put processes anywhere and doesn't have to worry about data costs.

    Size 2 (method registers: 8)


    Registers

    MB_SY_PLACE_STATUS
    Type of call. After a new process is successfully created, holds the index of the new process. Also holds the data or irpt cost of creating a new process after a cost query.
    MB_SY_PLACE_X
    x location of new process.
    MB_SY_PLACE_Y
    y location.
    MB_SY_PLACE_ANGLE
    Angle of new process.
    MB_SY_PLACE_ADDRESS1
    Start address of new process' bcode (in the system program itself, or in a template).
    MB_SY_PLACE_ADDRESS2
    End address.
    MB_SY_PLACE_INDEX
    Which player will control the process.
    MB_SY_PLACE_TEMPLATE
    If reading bcode from a template, this is the template (uses different indices from the MT_PR_NEW method, because the system program can use all templates - see below).

    Statuses
    MS_SY_PLACE_NOTHING
    Does nothing.
    MS_SY_PLACE_BC_CALL
    Places a new process, with the new process' bcode being copied from the system program.
    MS_SY_PLACE_BC_CALL_TEST
    Tests whether it's possible to create a new process.
    MS_SY_PLACE_BC_COST_DATA
    Gets the data cost (the cost will be in the status register).
    MS_SY_PLACE_BC_COST_IRPT
    Irpt cost.
    MS_SY_PLACE_T_CALL
    Like MS_SY_PLACE_BC_CALL, but uses a template instead.
    MS_SY_PLACE_T_CALL_TEST
    Test template.
    MS_SY_PLACE_T_COST_DATA
    Data cost of placing from template.
    MS_SY_PLACE_T_COST_IRPT
    Irpt cost of placing from template.

    Template indices

    When placing from a template, the following values can be used in the MB_SY_PLACE_TEMPLATE register:

    TEMPLATE_OBSERVER
    TEMPLATE_P0_CLIENT
    TEMPLATE_P1_CLIENT
    TEMPLATE_P2_CLIENT
    TEMPLATE_P3_CLIENT
    TEMPLATE_P0_PROCESS_0
    TEMPLATE_P0_PROCESS_1
    TEMPLATE_P0_PROCESS_2
    TEMPLATE_P0_PROCESS_3
    TEMPLATE_P1_PROCESS_0
    TEMPLATE_P1_PROCESS_1
    TEMPLATE_P1_PROCESS_2
    TEMPLATE_P1_PROCESS_3
    TEMPLATE_P2_PROCESS_0
    TEMPLATE_P2_PROCESS_1
    TEMPLATE_P2_PROCESS_2
    TEMPLATE_P2_PROCESS_3
    TEMPLATE_P3_PROCESS_0
    TEMPLATE_P3_PROCESS_1
    TEMPLATE_P3_PROCESS_2
    TEMPLATE_P3_PROCESS_3

    When called, the method will return one of the MR_NEW_* values (which are also used by the MT_PR_NEW method).

    Example:

    int place_result, new_process_index;

    place_result = call(METH_PLACE,
     MS_SY_PLACE_BC_CALL, // status: copies new process from the system program
     2000, // x coordinate (absolute)
     2000, // y coordinate
     ANGLE_2, // angle of new process (ANGLE_2 means 4096, or 1/2 of a full circle, so the process' vertex 0 will be pointing left)
     process_start(some_process), // some_process is a subprocess of the system program
     process_end(some_process),
     0, // new process will belong to player 1
     0); // template index - not used

    if (place_result == MR_NEW_SUCCESS)
    {
     new_process_index = get(METH_PLACE, MB_SY_PLACE_STATUS); // on success, the status register holds the new process' index
     call(METH_MODIFY, MS_SY_MODIFY_INSTANT, new_process_index); // makes new process appear instantly, without fading in
    }

    Another example:

    int place_result;

    place_result = call(METH_PLACE,
     MS_SY_PLACE_T_CALL, // status: copies new process from a template
     3000, // x
     3000, // y
     0, // angle (0 is right)
     0, // start address
     BCODE_SIZE_PROCESS - 1, // end address - this is the final address in a process template
     1, // player 2
     TEMPLATE_P2_PROCESS_0); // uses player 2's process template 0

    // copying from address 0 to address (BCODE_SIZE_PROCESS - 1) uses the entire template. It's possible to only use part of a template by specifying different addresses, if you know what you're doing


    Template: MT_SY_TEMPLATE
    Allows the system program to copy code from itself to templates.

    Size 1 (method registers: 4)


    Registers

    MB_SY_TEMPLATE_TYPE
    Target template. Should be one of the TEMPLATE_* macros. Note that loading code into an observer or client template doesn't change the currently loaded observer or client; the MANAGE method must load it. 
    MB_SY_TEMPLATE_START
    Start address of the bcode to be copied from the system program.
    MB_SY_TEMPLATE_END
    End address.
    MB_SY_TEMPLATE_NAME
    Address of the start of a null-terminated string, which will show up in the template menu as the template's name. If this is 0, the name will just be "Unnamed".
    Example:

    process a_process; // assume this is defined elsewhere in the system program

    int process_name [20] = {"a process"}; // template name can be up to 20 characters

    call(METH_TEMPLATE,
     TEMPLATE_P1_PROCESS_0, // copies to player 1's first process template
     process_start(a_process),
     process_end(a_process),
     &process_name [0]);


    Modify process: MT_SY_MODIFY
    Allows the system program to modify processes in various ways.

    Size 1 (method registers: 4)


    Registers

    MB_SY_MODIFY_PROC_STATUS
    Status.
    MB_SY_MODIFY_PROC_INDEX
    Index of process to modify.
    MB_SY_MODIFY_PROC_VALUE
    New value.
    MB_SY_MODIFY_PROC_VALUE2
    New value2.

    Statuses

    MS_SY_MODIFY_HP
    Changes a process' hp to new value (bounds-checked from 1 to max hp - this can't be used to destroy a process).
    MS_SY_MODIFY_IRPT
    Changes a process' irpt to new value (bounds-checked from 0 to max irpt).
    MS_SY_MODIFY_DATA
    Changes a process' data to new value (bounds-checked from 0 to max data).
    MS_SY_MODIFY_MB
    Changes a method register (specified by MB_SY_MODIFY_PROC_VALUE) of a process to new value2.
    MS_SY_MODIFY_BCODE
    Changes bcode address (specified by MB_SY_MODIFY_PROC_VALUE) of a process to new value2.
    MS_SY_MODIFY_INSTANT
    If called just after a process is newly placed, this prevents the fade-in effect and makes the process just appear. The value registers are not used.
    Examples:

    call(METH_MODIFY,
     MS_SY_MODIFY_HP,
     100, // affects process 100
     1); // process will have 1 hp

    call(METH_MODIFY,
     MS_SY_MODIFY_BCODE,
     100, // affects process 100
     1200, // affects bcode address 1200
     0); // new bcode value is 0

    call(METH_MODIFY,
     MS_SY_MODIFY_INSTANT,
     100); // affects process 100



    Manage: MT_SY_MANAGE
    An essential method for system programs that allows them to run the game.

    Size 1 (method registers: 4)


    Statuses

    MS_SY_MANAGE_PAUSED
    Returns 1 if the game is paused or 0 if not (while paused, system, observer and operator programs continue to run). Can't be used to tell if the game is halted rather than paused (as the system program won't be running if it's halted).
    MS_SY_MANAGE_PAUSE_SET
    Turns pause on (if register 1 is 1) or off (if register 1 is 0). Note that the MT_OB_CONTROL method can set pause as well.
    MS_SY_MANAGE_FF
    Returns 1 if the game is running in fast forward, 0 if not
    MS_SY_MANAGE_FF_SET
    Turns fast forward on (if register 1 is 1) or off (if register 1 is 0).
    Register 2 determines the fast forward mode: 0 means smooth fast forward mode (the game unlocks the frame rate and runs as fast as it can), and 1 means skippy mode (the game displays 1 frame per second and between those frames runs as fast as possible).
    Note that the MT_OB_CONTROL method can set fast forward as well.
    MS_SY_MANAGE_PHASE
    Returns the current game phase.
    MS_SY_MANAGE_OB_SET
    Allows the system program to communicate with the observer/operator. There are 64 shared registers that both can use (the observer/operator  can use them with the MT_OB_CONTROL method). Register 1 is the register index, register 2 is the value to set it to.
    MS_SY_MANAGE_OB_READ
    Returns the value of a system/observer shared register. Register 1 (of the method) is the register index.
    MS_SY_MANAGE_TURN
    Returns which turn it is.
    MS_SY_MANAGE_TURNS
    Returns how many turns the game has.
    MS_SY_MANAGE_SECONDS_LEFT
    Returns how many seconds there are left in the current turn.
    MS_SY_MANAGE_TICKS_LEFT
    Returns how many ticks are left in the current turn. Returns 32767 if more than 32767 ticks are left.
    MS_SY_MANAGE_TURN_SECONDS
    Returns how many seconds there are in a turn.
    MS_SY_MANAGE_GAMEOVER
    Finishes the game. Register 1 is the game end state. Register 2 is also relevant to some states.
    MS_SY_MANAGE_END_PREGAME
    If the game is in the PHASE_PREGAME, this ends it.
    MS_SY_MANAGE_END_TURN
    If the game is in the PHASE_WORLD phase, this ends the current turn. If this is the last turn, the game will be ended with status GAME_END_TIME.
    MS_SY_MANAGE_START_TURN
    If the game is in the PHASE_TURN phase, this starts the next turn and enters PHASE_WORLD phase.
    MS_SY_MANAGE_LOAD_OBSERVER
    Loads the observer template into the actual observer program.
    MS_SY_MANAGE_LOAD_CLIENT
    Loads a player's client template. Register 1 is the player index.
    MS_SY_MANAGE_ALLOCATE_EFFECT
    Sets what a player's allocate methods do to the background hexagons. Register 1 is the player index, register 2 is the effect (0 = disrupt, which disrupts the hexagons randomly, and 1 = align, which aligns the hexagons).

    Game phases

    PHASE_WORLD
    The game is running, processes are executing etc. 
    This phase ends when time runs out, or when the system program calls the MANAGE method with status MS_SY_MANAGE_END_TURN.
    PHASE_PREGAME
    Before the game starts, the system program has 16 ticks to set everything up. During this time, only the system program runs. Processes can be placed in the world, but they don't do anything. 
    This phase ends after 16 ticks, or when the system program calls the MANAGE method with status  MS_SY_MANAGE_END_PREGAME. At the end of the pregame phase the game automatically enters the turn phase.
    PHASE_TURN
    Waiting for a turn to start. During this phase, system, observer and operator programs run but delegate programs and processes do not. 
    This phase ends when the system program calls the MANAGE method with status MS_SY_MANAGE_START_TURN.
    PHASE_OVER
    Game has finished.

    Game end states

    These affect the text that is shown along with the GAME OVER sign.

    GAME_END_BASIC
    Just shows GAME OVER.
    GAME_END_YOU_WON
    Tells the user that they won.
    GAME_END_YOU_LOST
    Tells the user that they lost.
    GAME_END_PLAYER_WON
    Indicates that the player specified by register 2 won.
    GAME_END_PLAYER_LOST
    Indicates that the player specified by register 2 lost.
    GAME_END_DRAW
    The game ended with a draw.
    GAME_END_TIME
    Ran out of time.

    7. Bcode and the assembler


    The assembler lets you control what a program does at a lower, more detailed level than the compiler. You can write whole programs in assembly language, or use bits of in-line assembler alongside compiled code.

    "asm" tells the compiler to call the assembler to deal with whatever is within the following braces. Generally, the assembler has access to everything defined in compiled code (such as variable and function names), but not vice-versa.

    You can use the "build to asm" function in the Build menu to tell the compiler to generate assembly language instead of bcode. The asm code will be written to a new editor tab.

    7.1 Assembly instructions and operands


    The assembler accepts a range of instructions that are translated directly into bcode. The first 6 bits of a bcode value determine which instruction it is; the remaining 10 bits are used to indicate register operands (if any). Other kinds of operand are kept in the following bcode values.

    Reading a value from bcode costs one instruction. Most operations have additional costs as well. Reading a register operand from the lower bits of an instruction has no extra cost. The cost values given for each instruction below include the cost of reading the instruction and, if the following bcode value contains an operand, that operand.

    7.1.1 Operand types


    The assembler recognises the following kinds of operands:

    r <register>

    This is one of the eight processor registers, A to H. Operations involving the registers are fast. Each of the registers is identical; they all hold a signed 16-bit value and can be used to perform the same range of simple calculations and other operations.

    Example:

    setrr A B
    This copies the value in register B into register A. Generally, the first operand is the target of the instruction; it's like saying A = B.

    If you are writing inline asm code, the current version of the compiler allows you to safely use registers A, B, C and D for any purpose (the compiler is not clever enough to use them itself). The compiler uses registers E and F to perform calculations, register G as the stack pointer and register H as the stack frame base pointer.

    A register operand has no additional cost, as it is part of the instruction itself.

    Operations that result in arithmetical overflows just happen.


    a <address>

    This uses the value in a memory address. The address can be expressed as a literal number (like "100", although this is probably not that useful), an identifier (like the name of a variable) or an identifier plus a constant offset.

    The assembler has access to any identifier defined by the compiler that can be resolved to a particular memory address, and because it treats almost all kinds of identifiers in the same way (as simple references to memory addresses) it can use identifiers before they are declared or defined. The "scope" command allows it to refer to identifiers in different address spaces and name spaces as well.

    Example:

    int hello = 5;

    asm
    {
    setra A hello
    }
    // This copies the value 5 to register A.


    asm
    {
    setrn C 200
    setar hello_array+1 C
    }
    // This copies the value 200 to hello_array [1].

    int hello_array [3];
    This copies the value in register C to hello_array [1].

    One thing that you can't use as an address operand is an automatic local variable. You need to calculate the variable's position on the stack first (see number operands below).

    Trying to use an address that is out of bounds causes the program to exit and writes an error message to the error channel.

    An address operand has an additional cost of 2 (reading the address then following it to the value in the address).


    n <number>

    This uses a constant value. Like an address operand, the value can be a literal number, an identifier or an identifier plus a constant offset. If it's an identifier which can be resolved to a particular memory address, the number will be that address. If it's an automatic variable, the number will be the variable's stack frame offset (add this to the stack frame base pointer to get the variable's actual address).

    Examples:

    setrn A 10

    This sets register A to 10.

    int hello;

    asm
    {
    setrn A hello
    }


    This sets register A to the memory address of the variable hello (equivalent to &hello).

    auto int hello_auto;

    hello_auto = 5;

    static int thing;

    asm
    {
    setrn A hello_auto // sets A to the stack frame offset of hello_auto
    add A A H // adds A to the stack frame base register, leaving the result in A
    setdr A A // sets A to the value in the address pointed to by itself
    setar thing A // copies the value in A to the address of thing
    }


    Assuming that register H is the stack frame base pointer, the asm here is equivalent to:

    thing = hello_auto;
    and demonstrates why automatic variables are much less efficient than static variables!

    label_name:
     a = 5;

    // other stuff happens here

    asm
    {
    jumpn label_name
    }

    The jump instruction is equivalent to:

    goto label_name;
    A number operand has an additional cost of 1 (reading the number).


    d <deregister>

    This operand type dereferences a register; it's like an address operand, but the address is in a register rather than in the following instruction.

    Example:


    static int hello;

    asm
    {
    setrn A hello
    setrn B 5
    setdr A B
    }


    This is a (pointlessly) longer way of doing the same thing as:

    setrn A 5
    setar hello A


    and is equivalent to:

    hello = 5;
    A deregister operand has an additional cost of 1 (following the address in the register).


    b <method bank>

    The method bank is a "bank" of 64 special registers used by a program's methods. The <method bank> operand is used only by some of the put and get instructions (and only if the method register being used is known at assembly time). It should be a number.

    Example:

    setrn A 5
    putbr 2 A

    This sets method bank register 2 (which is the third register of the first method) to the value 5. It is equivalent to the compiled code:

    put(0, 2, 5);
    A method bank operand has no additional cost (as it is stored in six bits of the instruction).


    m <method>

    This is method 0 to 15. It is used only for the callmr instruction, which calls a specified method and leaves its return value in a register.

    Example:

    int hello;

    asm
    {
    callmr 3 A
    setar hello A
    }

    This calls method 3 and leaves its return value in the variable hello. It is equivalent to:

    int hello;
    hello = call(3);

    A method operand has no additional cost (as it is stored in four bits of the instruction).


    s <string>

    This is used only by the special print instruction "prints". The instruction should be followed by a memory initialiser containing a null-terminated string (the null character is added automatically).

    Example:

    prints {"hello!"}
    Is equivalent to the compiled code:

    print("hello!");
    The string is printed to the program's current console.

    7.2 Instructions


    The instructions recognised by the assembler are:

    No operation

    0. nop
    size 1 cost 1
    This does nothing.


    Set instructions

    1. setrr <register 1> <register 2>
    size 1 cost 1
    Copies the value in <register 2> to <register 1>.

    2. setra <register> <address>
    size 2 cost 3
    Copies the value in the memory address pointed to by <address> to <register>.

    3. setar <address> <register>
    size 2 cost 3
    Copies the value in <register> to the memory address pointed to by <address>.

    4. setrn <register> <number>
    size 2 cost 2
    Copies <number> to <register>.

    5. setrd <register 1> <register 2>
    size 1 cost 2
    Copies the value in the memory address pointed to by <register 2> to <register 1>.

    6. setdr <register 1> <register 2>
    size 1 cost 2
    Copies the value in <register 2> to the memory address pointed to by <register 1>.


    Arithmetic instructions

    7. add <register 1> <register 2> <register 3>
    size 1 cost 2
    Adds <register 2> and <register 3> and puts the result in <register 1>.

    Example:

    add A B C    // is equivalent to A = B + C
    add A A B    // is equivalent to A += B

    8. sub <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for subtraction (<register 1> = <register 2> - <register 3>).

    9. mul <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for multiplication (<register 1> = <register 2> * <register 3>).

    10. div <register 1> <register 2> <register 3>
    size 1 cost 3
    Like add, but for division (<register 1> = <register 2> / <register 3>). Trying to divide by zero just returns zero.

    11. mod <register 1> <register 2> <register 3>
    size 1 cost 3
    Like add, but gets the remainder of <register 2> / <register 3>. Trying to divide by zero just returns zero.

    11. incr <register>
    size 1 cost 1
    Value in <register> is increased by 1.

    12. decr <register>
    size 1 cost 1
    Value in <register> is decreased by 1.


    Bitwise operation instructions

    13. and <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for bitwise and (<register 1> = <register 2> & <register 3>).

    14. or <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for bitwise or (<register 1> = <register 2> | <register 3>).

    15. xor <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for bitwise xor (<register 1> = <register 2> ^ <register 3>).

    16. bnot <register 1> <register 2>
    size 1 cost 2
    Bitwise not. Equivalent to <register 1> = ~<register 2>.

    17. bshiftl <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for left bitshift (<register 1> = <register 2> << <register 3>).

    18. bshiftr <register 1> <register 2> <register 3>
    size 1 cost 2
    Like add, but for right bitshift (<register 1> = <register 2> >> <register 3>).


    Logical not

    19. not <register1> <register2>
    size 1 cost 1
    Logical not. If <register2> is zero, <register1> is set to 1. Otherwise, <register1> is set to zero. Equivalent to <register1> = !<register2>.


    Branching instructions

    20. jumpr <register>
    size 1 cost 2
    Jump to address stored in <register>. If target is out of bounds, program exits.

    21. jumpn <number>
    size 2 cost 3
    Jump to address <number>. If target is out of bounds, program exits.

    22. iftrue <register> <address>
    size 2 cost 3
    If <register> is anything other than zero, jump to <address>. If target is out of bounds, program exits.

    23. iffalse <register> <address>
    size 2 cost 3
    If <register> is zero, jump to <address>. If target is out of bounds, program exits.


    Comparison instructions

    24. cmpeq <register1> <register2>
    size 1 cost 2
    If <register1> and <register2> contain the same value, sets <register1> to 1. Otherwise, sets <register1> to 0.

    25. cmpneq <register1> <register2>
    size 1 cost 2
    If <register1> and <register2> contain the same value, sets <register1> to 0. Otherwise, sets <register1> to 1.

    26. cmpgr <register1> <register2>
    size 1 cost 2
    If <register1> is greater than <register2>, sets <register1> to 1. Otherwise, sets <register1> to 0.

    27. cmpgre <register1> <register2>
    size 1 cost 2
    If <register1> is greater than or equal to <register2>, sets <register1> to 1. Otherwise, sets <register1> to 0.

    28. cmpls <register1> <register2>
    size 1 cost 2
    If <register1> is less than <register2>, sets <register1> to 1. Otherwise, sets <register1> to 0.

    29. cmplse <register1> <register2>
    size 1 cost 2
    If <register1> is less than or equal to <register2>, sets <register1> to 1. Otherwise, sets <register1> to 0.


    Exit instruction

    30. exit
    size 1 cost 1
    Program exits.


    Stack instructions

    31. push <register1> <register2>
    size 1 cost 2
    This is a special compound instruction that facilitates the use of a stack. It increments <register2> (which should be the stack pointer), then copies the value in <register1> to the address now pointed to by <register2>.

    push E G
    // is equivalent to, but slightly cheaper and smaller than:
    incr G
    setdr G E

    It occurs to me that the increment should probably come after the set. Oh well.

    32. pop <register1> <register2>
    size 1 cost 2
    This is another special compound stack instruction. It copies the value in the address pointed to by <register2> to <register1>, then decrements <register2>. 

    pop E G
    // is equivalent to, but slightly cheaper and smaller than:
    setrd E G
    decr G


    Method bank instructions

    33. putbr <method bank> <register>
    size 1 cost 2
    Copies the value in <register> to <method bank>.

    34. putbn <method bank> <number>
    size 2 cost 3
    Copies <number> to <method bank>.

    35. putba <method bank> <address>
    size 2 cost 4
    Copies the value in <address> to <method bank>.

    36. putrr <register1> <register2>
    size 1 cost 2
    Copies the value in <register2> to the method bank register pointed to by <register1>.

    37. putrn <register> <number>
    size 2 cost 3
    Copies <number> to the method bank register pointed to by <register>.

    38. putra <register> <address>
    size 2 cost 4
    Copies the value in <address> to the method bank register pointed to by <register>.

    39. getrb <register> <method bank>
    size 1 cost 2
    Copies the value in <method bank> to <register>.

    40. getrr <register1> <register2>
    size 1 cost 2
    Copies the value in the method bank register pointed to by <register2> to <register1>.


    Method call instructions

    41. callmr <method> <register>
    size 1 cost 2 (this is the minimum; the actual cost depends on the cost of calling the particular method)
    Calls <method> and leaves the result of the method call in <register>.

    42. callrr <register1> <register2>
    size 1 cost 2 (actual cost depends on cost of calling the particular method)
    Calls the method indicated by <register1> and leaves the result of the method call in <register2>.


    Print instructions

    43. prints <string>
    size (1 + length of string) cost (2)
    Prints <string> to the current console. <string> can be up to 80 characters long, and must be null-terminated.
    This instruction has a cost of only 2 regardless of how long the string is (this is because of its value as a debugging aid; the cost may be increased in future).

    44. printr <register>
    size 1 cost 2
    Prints the value of <register> to the current console as a number.

    45. printsa <address>
    size 2 cost 3
    Prints a null-terminated string starting from <address> to the current console.

    46. printsr <register>
    size 1 cost 2
    Prints a null-terminated string starting from the address pointed to by <register> to the current console.


    7.3 Other asm instructions and directives

    7.3.1 Address spaces


    An address space (aspace) corresponds to a compiler process. If you're writing inline assembler you can just ignore the difference and refer to processes as if they were aspaces, because the compiler automatically creates an aspace for each process. If you're writing a whole program in assembler, you can use aspaces to define subprocesses.

    All identifiers defined within an aspace have a scope limited to that aspace (and possibly further limited to an nspace within the aspace). Also, all memory references generated by the assembler from identifiers defined and used within an aspace will assume that the start of the aspace is address zero. This means that code within an aspace within a program will not run properly while it is in that program, but it will run if the aspace is copied to a separate program so that the start of the aspace is the start of the separate program.

    Aspaces can be nested within other aspaces (although not within nspaces).

    It's not necessary to define an aspace for the program as a whole. Each program has an implicit "self" aspace.

    The assembler recognises the following aspace commands:
    def aspace <aspace name>
    This starts an aspace.
    aspace_end
    This ends the current aspace (you don't specify an aspace to end; it's always the current one).
    aspace_end_address <aspace name>
    Using this as a number operand gives you the last memory address within the aspace (if you need the address of the start of an aspace, just use the aspace name as a number operand).
    Example:

    def aspace main_process

    // (process definition goes here)

    def aspace subprocess

    // (sub-process definition goes here)

    aspace_end // this ends subprocess
    aspace_end // this ends main_process

    7.3.2 Name spaces


    A name space (nspace) corresponds to a function. All identifiers defined within an nspace have scope limited to that nspace. An nspace doesn't have any effect on memory addresses, and if you are writing assembler code you might not need to use nspaces at all. They are really only necessary to reflect function scope in asm code generated by the compiler.

    Unlike aspaces, nspaces cannot be nested.

    The assembler recognises the following nspace commands:
    def nspace <nspace name>
    This starts an nspace.
    nspace_end
    This ends the current nspace (you can't specify an nspace to end; it's always the current one).
    nspace_rejoin <nspace name>
    This re-enters a previously defined nspace in the same aspace (the compiler uses this to keep function code separate from static local variable storage).
    There isn't an equivalent of aspace_end_address for nspaces, as nspace_rejoin means that an nspace can have multiple ends. If for some reason you need to know the end of a block of nspace code, you can put a label there.

    Example:

    def aspace main_process

    def nspace a_function
    // (stuff)
    nspace_end // this ends a_function

    def aspace subprocess
    // (stuff)
    aspace_end // this ends subprocess

    nspace_rejoin a_function
    def int local_variable {0} // this variable is within the main_process aspace and the a_function nspace.
    nspace_end // this ends a_function again

    aspace_end // this ends main_process


    7.3.3 Scoped operands


    The assembler can access identifiers from outside the present process, function, aspace or nspace using the scope command. A scoped operand can be used before it is declared or defined, as long as it is defined eventually.

    Processes and aspaces are preceded by ".", functions and nspaces are preceded by ":" and the final identifier to be addressed is preceded by "::".

    Example:

    setar scope.hello_process:hello_function::hello_variable A
    This copies a value from register A to a static local variable (hello_variable) in a function (hello_function) in a process that is a subprocess of the current process (hello_process). The address of hello_variable that this generates is relative to the current aspace, not the aspace of hello_process.

    A process or aspace used in a scope command must be a sub-process/aspace of the current process/aspace (or a sub-sub-process/aspace etc). If multiple layers of nested processes/aspaces are involved, each layer must be referred to.

    Example:

    setar scope.hello_subprocess.hello_subsubprocess::hello_variable A
    This copies a value from register A to a global variable in a sub-sub-process of the current process.

    Two possible uses of the scope command are:

    1. Accessing static local variables in other functions.

    2. Modifying subprocesses (as any new process created from a modified subprocess definition will contain the modification).

    7.3.4 Miscellaneous

    asm_only
    If you put this on the first line of a process, it tells the compiler to expect the entire process to be a single block of assembly code. The compiler will not generate things like an interface or a jump to the main function; it assumes that this will all be handled by the assembler.
    def int <int name>
    This defines an identifier for the immediately following address. To use it as a variable, it should be followed by one or more memory initialisers (even if the value is to be zero).
    Example:
    def int hello {5}       
              This defines a variable (or, more accurately for asm code, a label for a memory address) called "hello" and initialises it to 5.
    Variables defined in asm code aren't recognised by the compiler (this may be changed later).
    def label <label name>
    This defines a label for the immediately following address. There isn't currently a difference between this and def int, but defining a label in this way at least indicates that you intend to use it as a jump target.
    Example:
    def label jump_target

    /// ... (other code here)

    jumpn jump_target

              The jumpn jumps to the instruction just after the label definition.
    When the compiler is generating asm code it will generate a def label command for any label it finds in the compiled code, even ones that aren't used. You can use this to help read the generated asm.
    memory initialisation
    To initialise memory, just put the values inside braces like this:
    {0, 1, 2, 3}
    This puts the numbers 0 to 3 in successive bcode instructions. The values are fixed at compile-time and can be modified at run-time. Note that the program will try to execute these as code if it reaches them (although all of these would be treated as nop instructions, as their high 6 bits are all zero).

    Appendix A: Key codes


    These are used by the MT_OB_INPUT method when a key is pressed.
    They may assume a certain keyboard arrangement (I've only tested them on my keyboard).

    KEY_0
    KEY_1
    KEY_2
    KEY_3
    KEY_4
    KEY_5
    KEY_6
    KEY_7
    KEY_8
    KEY_9
    KEY_A
    KEY_B
    KEY_C
    KEY_D
    KEY_E
    KEY_F
    KEY_G
    KEY_H
    KEY_I
    KEY_J
    KEY_K
    KEY_L
    KEY_M
    KEY_N
    KEY_O
    KEY_P
    KEY_Q
    KEY_R
    KEY_S
    KEY_T
    KEY_U
    KEY_V
    KEY_W
    KEY_X
    KEY_Y
    KEY_Z

    KEY_MINUS
    KEY_EQUALS
    KEY_SBRACKET_OPEN
    KEY_SBRACKET_CLOSE
    KEY_BACKSLASH
    KEY_SEMICOLON
    KEY_APOSTROPHE
    KEY_COMMA
    KEY_PERIOD
    KEY_SLASH

    KEY_LSHIFT
    KEY_RSHIFT
    KEY_LCTRL
    KEY_RCTRL

    KEY_UP
    KEY_DOWN
    KEY_LEFT
    KEY_RIGHT

    KEY_ENTER
    KEY_BACKSPACE
    KEY_INSERT
    KEY_HOME
    KEY_PGUP
    KEY_PGDN
    KEY_DELETE
    KEY_END
    KEY_TAB
    // KEY_ESCAPE (this key is unavailable - the game uses it directly)

    KEY_PAD_0
    KEY_PAD_1
    KEY_PAD_2
    KEY_PAD_3
    KEY_PAD_4
    KEY_PAD_5
    KEY_PAD_6
    KEY_PAD_7
    KEY_PAD_8
    KEY_PAD_9
    KEY_PAD_MINUS
    KEY_PAD_PLUS
    KEY_PAD_ENTER
    KEY_PAD_DELETE
    KEYS // total number of KEY macros