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

- 1. Introduction
- 2. Basic things
  - 2.1 Types of programs
    - 2.1.1 Processes
    - 2.1.2 System programs
    - 2.1.3 Observer programs
    - 2.1.4 Client programs
    - 2.1.5 Client (operator)
    - 2.1.6 Client (delegate)
  - 2.2 Templates
  - 2.3 Code editor
  - 2.4 Menu interface
- 3. Playing the game
  - 3.1 Missions
  - 3.2 Starting from a system file
  - 3.3 Multiplayer
  - 3.4 Programs you can use
- 4. Compiler
  - 4.1 Some C keywords that work differently
  - 4.2 Processes and sub-processes
  - 4.3 Preprocessor
  - 4.4 Memory and registers
  - 4.5 Built-in functions
    - 4.5.1 Basic built-in functions
    - 4.5.2 Method-based built-in functions
- 5. Interfaces
  - 5.1 Process interface
  - 5.2 Client/observer program interface
  - 5.3 System program interface
  - 5.4 More on process interfaces: shapes and sizes
  - 5.5 The process data box
- 6. Methods
  - 6.1 Process methods (PR)
  - 6.2 Client methods (CL)
  - 6.3 Client/Observer methods (CLOB)
  - 6.4 Observer methods (OB)
  - 6.5 System methods (SY)
- 7. Bcode and the assembler
  - 7.1 Assembly instructions and operands
    - 7.1.1 Operand types
  - 7.2 Instructions
  - 7.3 Other asm instructions and directives
    - 7.3.1 Address spaces
    - 7.3.2 Name spaces
    - 7.3.3 Scoped operands
    - 7.3.4 Miscellaneous
- Appendix A: Key codes

# 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:

- Processes, which are the things you see moving around on the screen and doing stuff.
- An observer program, which provides a user interface.
- One client program for each player. These supervise the players' processes.
- Possibly, an operator program that lets the player give commands directly to their processes.
- A system program, which is responsible for setting the rules and administering the game.

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:

- They are made out of data, which can be gathered with an allocation method (a process with an allocation method is immobile). Different shapes and sizes of process cost different amounts of data to create.

- To perform actions using their methods they need interrupts (irpt), which can be generated by an interrupt generation method.

- Instructions are consumed when a process performs basic computations and are replenished each time the process runs (which is usually once each 16 ticks, or about twice a second).

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:

- Source files can't be longer than 2000 lines;

- Each line of a source file can't be longer than 160 characters.

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:

- The sy_multi.c program (in the src directory) is an example of a system program designed for multiplayer games.

- Operator programs can't be used. If clients are permitted, use delegate programs instead.

- Observer programs can be used, and can accept input. Each player or spectator can choose their own observer program, unless for some reason the system program is designed not to allow this.

- Players can save and load the game at any time. In particular, they can save after step 8 then load the game again when it's time to go back to step 4 for the next turn. Saved games include templates, so you don't need to reload the gamefile or turnfiles after loading from a saved game.

- While the game is running players shouldn't clear or load any templates, as this may cause desynchronisation. Only do this at step 4, or during a test run that will be discarded.

- The game verifies each turnfile for player number and turn number when loading.

- There is no standard naming convention for turnfiles, other than that they should end in .tf, so players can agree on how to name them.

- Multiplayer relies on each player's copy of the game being the same version and running in exactly the same way, except for observer programs. The same version of the game should run the same way even across different operating systems and build environments, as long as they perform integer calculations in a consistent way (or at least I think it should).

- The system program shouldn't be designed to accept user input or communicate with observer programs (unless you're sure you know what you're doing), as this can cause desynchronisation.

- If the players don't trust anyone in particular to set up the gamefile without altering the system program in a cheaty way, they can each compile the system program on their own computer then make their own gamefile. As long as the system program and all of the settings (world size etc) are the same, the gamefiles should be identical.

# 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:

- It has only one basic variable type: int, which is a 16-bit signed integer. No floats, chars, structs or unsigned variables. It does allow arrays of ints, with up to three dimensions.

- Pointers as a separate type are not supported. But memory addresses are just ints so you can, if you want, use the & address-of operator and the * dereference operator on ints to experience some of the excitement of using pointers. Also, *0 is valid (although not very useful).

- Referring to an array but leaving out a dimension does not give a pointer to the first element of that dimension. You have to use the & operator to get the address of the 0 element of the dimension. Sorry :(

- It doesn't recognise statements used as expressions. That means no return a++;. You'll have to keep them separate, sorry :(

- Variable scope is either global (to a process) or local (to a function). There is no block scope.

- Operator precedence is non-standard. You can assume that logical operators bind more loosely than comparison operators, which bind more loosely than arithmetic/bitwise operators, but other than that everything is basically left-to-right. In particular, multiplication doesn't bind more tightly than addition or subtraction. Use brackets!

- It doesn't give many warnings. Also, some of its error messages could probably be a little more useful.

- It doesn't do much optimisation. Actually, the only optimisation it does is basic constant folding (so it knows how to turn a = b + 5 + (2 * 2) into a = b + 9, although it's not smart enough to know how to fold a = 5 + b + 4 because the constants aren't all in a row). On the bright side the lack of optimisation leaves plenty of scope for fun with the inline assembler.

- Octal numbers aren't supported. I hope this will not cause any great inconvenience. Hexadecimal numbers are supported although I haven't got around to updating the syntax highlighter to recognise them yet.

- Binary numbers with the 0b prefix are supported (e.g. 0b11 is 3), although the syntax highlighter doesn't know this either.

- Programs need to be designed to be executed repeatedly. This has consequences for variable initialisation: static variables retain their values between executions, so you may need special initialisation code that you wouldn't usually need in a C program.

- Currently, each source file must be no longer than 2,000 lines. If you need a longer program you can use #include to combine multiple .c files together. Also, each line must be no longer than 160 characters.

- There are strict limits on compiled code size, although this is really a game constraint rather than a limitation of the compiler. System programs must fit in 16384 words (each word is 16 bits), processes must fit in 4096 and all other program types have 8192. This includes static data and the stack, as well as any sub-processes.

- There is no dynamic memory allocation (although I guess you could implement it yourself if you really wanted to).

- There is no linker. Everything that a program needs should be in the same .c file, or in other .c files that are #included directly.

- There are also no header files, and the .h extension isn't supported.

- None of the standard C libraries are available. Some things that would normally be done with libraries, like I/O routines and complicated maths operations, are done using methods or special built-in functions.

- Programs can contain other programs with their own special address space and naming scope. See processes and sub-processes.

- Programs have a special "interface" definition at the start, which defines various characteristics of the program.

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:

- a "factory" process can build other processes using the code inside a process definition,

- a core process can spawn new processes that connect to it and maybe also spawn their own nested sub-processes, ending up with a complex multisegmented super-process,

- a system program can copy programs from sub-processes into templates - the compiler uses the term "process", but sub-processes can be other types of program (client and observer) as well.

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:
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:
Here's what the various fields mean:

- header ("Process 1"): the number in the header is the process' index. Process indices are invisible to processes themselves, but clients, observers and system programs can refer to processes by their indices.
- hp: how much damage the process can take (the number in brackets is the maximum).
- ex: the number of ticks until the process' next execution cycle.
- at (x,y) speed s (x,y): this is the location of the process (in pixels, from the top left of the world), and its speed (in pixels per tick, multiplied by 16 to avoid underflow), and the x and y components of its speed.
- angle is the direction the process' vertex 0 is pointing in, in integer degrees (from 0 to 8192, where 0 is right).
- spin is the process' rate of rotation (positive is clockwise, negative is anticlockwise).
- block is the 128x128 pixel block the process is in (this isn't really useful, other than for debugging the game itself)
- irpt is the process' interrupt buffer (the number in brackets is the maximum size of the buffer). If the process is connected with other processes, this is the shared buffer.
- base is the base upkeep cost of the process. It must pay this many irpt each time it executes, or it will take damage and eventually deallocate.
- data is the process' data buffer (followed by its maximum). If the process is connected with other processes, this is shared.
- instr is the number of instructions the process had left after its last execution, with the number available in brackets.
- used is the number of instructions it used.
- size is the process' size
- mass is the total mass of the process, equal to the base mass of its shape plus the total mass of all of its methods (the number in brackets is the maximum mass for its shape and size).
- moment is the process' moment of inertia (currently for a single process this is the same as its mass). This determines how much force is needed to make the process rotate.
- base mass is the basic mass of the process without any methods.
- method mass is the total mass of the process' methods, with the maximum in brackets. The process' total mass is the sum of this and its base mass.

If the process is a member of a group of linked processes, there will be another line here:

- group mass is the total mass of the group.
- moment is the moment of inertia of the group as a whole. I wouldn't say that the game simulates angular momentum very well, but it tries.
- spin is the spin of the group as a whole.

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:

- vx indicates which vertex an external method is on.
- ang indicates the angle an external directional method is pointing (as an offset from angle 0 of the vertex the method is on).
- extensions, for methods that have extensions (e.g. a scan method might have range+1).
- some methods give other information here as well (e.g. MT_PR_IRPT gives the method's maximum generation capacity per tick).

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

- A process can use MT_PR method types, like MT_PR_MOVE (which lets a process move) or MR_PR_IRPT (which generates interrupts for the process to use).

- A delegate program can use MT_CL method types, like MT_CL_COMMAND (which lets the delegate program issue commands to processes). Delegate programs can also use MT_CLOB method types, which are also available to observer programs.

- An observer program can use MT_OB method types, like MT_OB_INPUT (which lets the observer program read user input from the mouse and keyboard). Observer programs can use MT_CLOB method types too.

- An operator program can use all MT_CL, MT_OB and MT_CLOB method types. It is the ability to use user input methods as well as the command method that lets operator programs translate user input into control over processes.

- A system program can use all MT_CL, MT_OB and MT_CLOB methods, as well as MT_SY methods like MT_SY_MANAGE (which gives the system program overall control over the game).

- There are also MT_ERROR methods, which indicate various kinds of error in a program's interface definition.

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

- Movement (MT_PR_MOVE): Allows a process to accelerate.
- New process (MT_PR_NEW): Allows a process to create other processes.
- New process (sub) (MT_PR_NEW_SUB): Allows a process to create other processes, with some limitations that make this method more suited to creating parts of a multi-process group than to creating whole new processes.
- Malicious packet (MT_PR_PACKET): Allows a process to attack other processes.
- Directional packet (MT_PR_DPACKET): Like MT_PR_PACKET, but can be aimed.
- Stream (MT_PR_STREAM): More effective, but more expensive, than packet methods.
- Directional Stream (MT_PR_DSTREAM): Like MT_PR_DPACKET for streams.
- Scan (MT_PR_SCAN): Allows a process to scan its surroundings for other processes.
- Interrupt generator (MT_PR_IRPT): Allows a process to generate energy.
- Data allocator (MT_PR_ALLOCATE): Allows a process to allocate data from its surroundings, and also makes process immobile.
- Standard (MT_PR_STD): Provides various standard functions.
- Mathematics (MT_PR_MATHS): Performs various calculations, including trigonometry.
- Designate (MT_PR_DESIGNATE): Allows a process to designate another process as a target, then find it again.
- Link (MT_PR_LINK): Allows a process to connect to another process (which must also have a link method)
- Restore (MT_PR_RESTORE): Allows a process to repair itself.
- Redundancy (MT_PR_REDUNDANCY): Makes a process more robust.
- Broadcast (MT_PR_BROADCAST): Sends brief messages to nearby processes.
- Listen (MT_PR_LISTEN): Lets a process hear broadcast messages.
- Yield (MT_PR_YIELD): Sends irpt and data to nearby processes.
- Storage (MT_PR_STORAGE): Increases a process' data storage buffer.
- Static (MT_PR_STATIC): Makes a process immobile.
- Command (process) (MT_PR_COMMAND): Allows a process to communicate with a client program using the process' command registers.
- Virtual interface (MT_PR_VIRTUAL): Protects a process from damage, but costs a lot of IRPT.

Client methods

- Command-give (client) (MT_CL_COMMAND_GIVE): Allows a client program to communicate with processes via their command registers.
- Template (client) (MT_CL_TEMPLATE): Allows a client program to copy code from itself into a template.

Client/observer methods

- Point check (MT_CLOB_POINT): Allows a client/observer to check whether a process exists at a specified point, and a few other similar things.
- Query process (MT_CLOB_QUERY): Allows a client/observer to get information about a process (similar to the MT_PR_INFO method).
- Scan (clob) (MT_CLOB_SCAN): Allows a client/observer to scan areas of the world for processes (has additional modes that MT_PR_SCAN doesn't have).
- Mathematics (MT_CLOB_MATHS): The same as MT_PR_MATHS.
- Standard (MT_CLOB_STD): Provides various standard functions (although not quite the same ones as MT_PR_STD).
- Command-receive (MT_CLOB_COMMAND_REC): Allows the program to read process' command registers.

Observer methods

- Input (MT_OB_INPUT): Allows the observer to receive input from the user.
- View (MT_OB_VIEW): Sets up the screen display in various ways.
- Console (MT_OB_CONSOLE): Controls the placement and function of text consoles.
- Select (MT_OB_SELECT): Allows the observer to place minor graphical elements on the display, to indicate things like selected processes.
- Control (MT_OB_CONTROL): Gives various pieces of information about the game settings, and lets the observer communicate with the system program.

System methods

- Place process (MT_SY_PLACE_PROC): Allows the system program to place processes in the world.
- Template (MT_SY_TEMPLATE): Allows the system program to manipulate templates.
- Modify process (MT_SY_MODIFY_PROC): Allows the system program to change various things about processes.
- Manage (MT_SY_MANAGE): Allows the system program to manage various things about the game, like declaring a winner.

Special methods

- End (MT_END): Indicates the end of a program's methods (you don't need to worry about this one; it's added automatically).
- Invalid type error (MT_ERROR_INVALID): Indicates an invalid method type in a program's interface definition.
- Duplicate method error (MT_ERROR_DUPLICATE): Some methods cannot be duplicated.
- Invalid vertex error (MT_ERROR_VERTEX): Indicates an external method with an invalid vertex (e.g. a method put on vertex 7 of a hexagon).
- Invalid mass error (MT_ERROR_MASS): Indicates that the method would have caused its process to be overweight.
- New sub method error (MT_ERROR_SUB): Indicates that the process was created with the MT_PR_NEW_SUB method, but a method that a NEW_SUB method cannot create was in the process' interface.

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:

- A base data cost, which is added to the data cost (and therefore also the irpt cost) of any process that includes the method.

- A maintenance interrupt cost which must be paid each time the process executes.

- Data and interrupt costs, and maintenance irpt costs, for each extension added to the method.

These depend on the method's cost category:

- Minimal: base data and maintenance cost 2, extension data and maintenance cost 1

- Low: base data and maintenance cost 4, extension data and maintenance cost 2

- Medium: base data and maintenance cost 8, extension data and maintenance cost 4

- High: base data and maintenance cost 16, extension data and maintenance cost 8

- Ultra: base data and maintenance cost 32, extension data and maintenance cost 16

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:

- Ready: the method is ready to fire. It starts in this phase and automatically returns to it after the end of the recycle phase.
- Warm-up: the stream is being generated and the method is using up irpt, but no damage is being caused yet.
- Firing: the stream is causing damage. The central part of the stream gets brighter.
- Cool-down: the stream is neither causing damage nor using irpt.
- Recycle: the method can't be used.

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:

- 0 if it is ready to fire;
- -1 if it is currently in warm-up, firing or cool-down phase;
- the number of ticks until it is ready to fire again if it is in recycle phase.

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