# MEG-4 User's Manual

Welcome to the manual for the MEG-4, the Free and Open Source virtual fantasy console.

Hint

This manual can be used off-line. From the right-click pop-up menu, choose "Save As". But it is also embedded in the MEG-4 emulator, just press `F1` any time.

Next

# Getting Started

## In Your Browser

If you don't want to install anything, just visit the website, it has an emulator running in your browser.

## Installing

Go to the repository and download the archive for your operating system.

### Windows

1. download meg4-i686-win-sdl.zip
2. extract it to `C:\Program Files` directory and enjoy!

This is a portable executable, no actual installation required.

### Linux

1. download meg4-x86_64-linux-sdl.tgz
2. extract it to the `/usr` directory and enjoy!

Alternatively you can download the deb version for Ubuntu or RaspiOS and install that with

    sudo dpkg -i meg4_*.deb

## Running

When you run the MEG-4 emulator, your machine's localization will be autodetected, and if possible, the emulator will greet you in your own language. The first screen it will show you is the "MEG-4 Floppy Drive" screen.

MEG-4 Floppy Drive

Just drag'n'drop a floppy file onto the drive, or left click on the drive to open the file selector. These floppies are PNG images with additional data, and an empty one looks like this:

MEG-4 Floppy

Other formats are supported too, see file formats for more details on what else can be imported. Once your floppy is loaded, the screen will automatically change to the game screen.

Alternatively you can also press `Esc` here to get to the editor screens and start creating contents from ground up.

### Command Line Options

On Windows, replace `-` with `/` for the flags (because that's the Windows' way of specifying flags, for example `/n`, `/vv`), otherwise all options are identical.

Use right-click on `meg4.exe`, and from the popup menu select Create shortcut. Then right-click on the newly created shortcut file, and from the popup menu choose Properties.

Setting command line options under Windows A window will appear, where you can specify the command line options in the Target field. Press OK to save it. After this, don't click on the program, rather click on this shortcut, and the program will start with those command line options. If you wish, you can have multiple shortcuts with different options.

    meg4 [-L <xx>] [-z] [-n] [-w] [-v|-vv] [-s] [-d <dir>] [floppy]

Option | Description
--- | ---
`-L <xx>` | The argument of this flag can be "en", "es", "de", "fr" etc. Using this flag forces a specific language dictionary for the emulator and avoids automatic detection. If there's no such dictionary, then English is used.
`-z` | On Linux by default, the GTK libraries are run-time linked to get the open file modal. Using this flag will make it call `zenity` instead (requires zenity to be installed on your computer).
`-n` | Force using the "nearest" interpolation method. By default, it is only used if the screen size is multiple of 320 x 200. Also forces this latter in windowed mode.
`-w` | Start in windowed mode (by default it is fullscreen)
`-v, -vv` | Enable verbose mode. `meg4` will print out detailed information to the standard output (as well as your script's trace calls), so run this from a terminal.
`-s` | Enable strace, tracing of system calls (only if compiled with DEBUG).
`-d <dir>` | Optional, if given, then floppies will be stored in this directory and no open file modal is used.
`floppy` | If this parameter is given, then the floppy (or any other supported format) is automatically loaded on start.

PreviousNext

# File Formats

Although the built-in editors are pretty awesome, MEG-4 is capable of handling various file formats both on export and import side to ease creation of content, and make the use of MEG-4 actual fun.

## Floppies

MEG-4 stores programs in "floppies". These are image files that look like a real floppy disk. You can save in this format by pressing `Ctrl`+`S`, or by selecting > `Save` from the menu (see interface). You'll be prompted to give a label to the floppy, which will be your program's title as well. To load such floppies, press `Ctrl`+`L`, or just simply drag'n'drop these image files onto the MEG-4 Floppy Drive.

The low level specification for this format can be found here.

## Project Format

For convenience, there's also a project format, which is a zip archive containing the console's data in only common and well-known formats so that you can use your favourite editor or tool to modify them. You can save in this format by selecting the > `Export ZIP` menu option. To load, you can simply drag'n'drop such zip files into the MEG-4 Floppy Drive.

Hint

One of the test tools, the converter can be used to convert floppies into zip archives. And the advcomp compiler can convert adventure game JSON files into playable zip project files.

Files in the project archive:

### metainfo.txt

A plain text file with the MEG-4 firmware version and the program's title.

### program.X

Your program's source code, created in the code editor, as a plain text file. You can use any text editor to modify. On export, newlines are replaced with CRLF for Windows compatibility, on import it doesn't matter if lines are ended with NL or with CRLF, both supported.

The source code must start with a special first line, a `#!` shebang followed by the programming language used. For example `#!c` or `#!lua`. This language code must also match the extension in the file name, eg: program.c or program.lua.

### sprites.png

A 256 x 256 pixels indexed PNG file, containing the 256 colors palette and all of the 1024 sprites, each 8 x 8 pixels, created in the sprite editor. This image file is editable by GrafX2, GIMP, Paint etc. On import, true color images will be converted to the default MEG-4 palette using the smallest weighted sRGB distance method. This works, but not looking particularly good, therefore it is recommended to save and import paletted PNG images instead. Sprites can also be imported from Truevision TARGA (.tga) images, if they are indexed and have the correct dimensions of 256 x 256 pixels.

### map.tmx

The map, created in the map editor, in a format that can be used with the Tiled MapEditor. Only CSV encoded .tmx is generated, but on import base64 encoded and compressed .tmx files can be loaded too (everything except zstd). Furthermore PNG or TARGA images are supported on import too, provided they are indexed and their dimensions match the required 320 x 200 pixels. The palette in these images aren't used, except the spritebank selector is stored in the first entry (index 0) alpha channel.

### font.bdf

The font, created with the font editor, in a format that can be edited by many tools, like xmbdfed or gbdfed. Obviously I'd recommend my SFNEdit instead, and FontForge works perfectly too. On import, besides of X11 Bitmap Distribution Format (.bdf), PC Screen Font 2 (.psfu, .psf2), Scalable Screen Font (.sfn) and FontForge's native SplineFontDB (.sfd, bitmap variant only) supported too.

### sounds.mod

The sound effects you created in the editor in Amiga MOD format. See music below. The song must be named `MEG-4 SFX`.

All 31 waveforms are stored in this file, as for the note patterns only the first pattern used, and only one channel (64 notes in total, one for each sound effect).

### musicXX.mod

The music tracks you created in the editor in Amiga MOD format. The XX number in the file name is a two digit hexadecimal number, which represents the track number (from `00` to `07`). The song must be named `MEG-4 TRACKXX`, where XX must be the same hexadecimal number as in the filename. There are dozens of third party programs to edit these files, just google "music tracker", for example MilkyTracker or OpenMPT, but for a true retro feeling, I'd recommend the moderized clone of FastTracker II, available for both Linux and Windows.

From music files, only those waveforms are loaded that are referenced from the notes.

You can find a huge database of downloadable Amiga MOD files at modarchive.org. But not all files are actually in .mod format on that site (some are .xm, .it or .s3m etc.); you'll have to load those in a tracker and save them as a .mod first.

Warning

The Amiga MOD format is a lot more featureful than what the MEG-4 DSP chip can handle. Keep this in mind when you edit .mod files in third party trackers! Waveforms can't be longer than 16376 samples and songs longer than 16 patterns (1024 rows) will be truncated on import. Pattern order will be linearized, and although pattern break 0xD handled, other pattern commands are simply skipped. Also if you import multiple tracks, then they will share the same 31 samples.

Music can also be imported from MIDI files, but these files only store the musical note sheet, and not the waveforms like Amiga MOD files do. General MIDI Patch has standardized the instrument codes though, and MEG-4 has some built-in wavepatterns for these, but due to size constraints those are not the best quality, so importing your own wavepatterns with MIDI files is strongly recommended.

### memXX.txt

Hexdump of the memory overlays data (which are binary blobs by nature). Here XX is a hexadecimal number from `00` to `FF`. The format is the same as hexdump -C's, you can edit these with a text editor. On import, binary files by the name memXX.bin also supported. For example, if you want to embed a file into your MEG-4 program, then name it mem00.bin, drap'n'drop it into the emulator, and afterwards you'll be able to load it in your program with the memload function.

## Other Formats

Normally waveforms are automatically loaded from Amiga MOD files, but you can also individually import and export wave patterns in .wav (RIFF Wave 44100 Hz, 8-bit, mono) format. These are editable with Audacity for example. If the imported file is named as dspXX.wav, where XX is a hexadecimal number between `01` and `1F`, then the waveform is loaded at that position, otherwise at the first empty slot.

You can import MEG-4 Color Themes from "GIMP Palette" files. These are simple text files with a little header, and in each line red, green and blue numeric values. Each color entry line defines the color of a specific UI element, see the default theme src/misc/theme.gpl for an example. Theme files can also be edited visually using GIMP or Gpick programs too.

By default, MEG-4 supports the Raspberry Pi 3B+ GPIO pin layout, but you can load any arbitrary configuration from a plain text file. Here the first line must be "GPIO Layout", the second line is the name of the board, the third line is the device file, and the rest is a list of physical pin - GPIO register offset mappings (where -1 means the pin is not assigned to the GPIO chip, eg. voltage or ground pins). For an example, see src/misc/gpio.txt.

It is also possible to import AdvGame 2.0 Adventure Game archives, although point'n'click games will be reduced to textual games.

Furthermore, you can import PICO-8 cartridges (both in .p8 and .p8.png formats) and TIC-80 cartridges (both in .tic and .tic.png formats), however you'll have to adjust the imported source code, because their memory layouts and API calls are different to MEG-4's. But at least you'll get their assets properly. The TIC-80 project format isn't supported because those files are unidentifiable. If you really want to import such a file, then first you'll have to convert it using the `prj2tic` tool, which can be found in the TIC-80 source repo.

Exporting into these cartridges is not possible, because the MEG-4 is lot more featureful than the competition. There's simply no place for all the MEG-4 features in those files.

PreviousNext

# User Input

## Gamepad

The first gamepad's buttons and joysticks are mapped to the keyboard, they are working simultaniously. For example it doesn't matter if you press Ⓧ on the controller, or `X` on the keyboard, in both case both gamepad button flag and keyboard state flag will be set. The mapping can be changed by writing the keyboard scancodes to MEG-4's memory, see memory map for details. The default mapping goes like cursor arrows are the directions ◁, △, ▽, ▷; the `Space` is the primary button Ⓐ, `C` is the secondary button Ⓑ and `X` is Ⓧ, `Z` is Ⓨ. The Konami Code is working too (see `KEY_CHEAT` scancode).

## Pointer

Coordinates and button pressed states can be easily accessed from the MEG-4's memory. Scrolling (both vertical and if supported, horizontal) handled as if your mouse had up / down or left / right buttons.

## Keyboard

For convenience, it has several shortcuts and multiple input methods. All characters required for programming can be accessed with an `Alt` combination, regardless what keyboard layout the platform is using:

Left `Alt` combinations

Key Combination | Description
--- | ---
`GUI` | Or Super, sometimes has a logo on it. UNICODE codepoint input mode.
`AltGr` | The right Alt key, activates Compose mode when pressed alone.
`Alt`+`U` | In case your keyboard lacks the `GUI` key, UNICODE input mode too.
`Alt`+`Space` | Fallback Compose, for keyboards without the `AltGr` key.
`Alt`+`I` | Enter icon (emoticons) input mode.
`Alt`+`G` | Enter Greek input mode.
`Alt`+`J` | Enter Hiragana input mode.
`Alt`+`K` | Enter Katakana input mode.
`Alt`+`C` | Enter Cyrillic input mode.
`Ctrl`+`S` | Save floppy.
`Ctrl`+`L` | Load floppy.
`Ctrl`+`R` | Run your program.
`Ctrl`+`⏎Enter` | Toggle fullscreen mode.
`Ctrl`+`A` | Select all.
`Ctrl`+`I` | Invert selection.
`Ctrl`+`X` | Cut, copy to clipboard and delete.
`Ctrl`+`C` | Copy to clipboard.
`Ctrl`+`V` | Paste from clipboard.
`Ctrl`+`Z` | Undo.
`Ctrl`+`Y` | Redo.
`F1` | Built-in help pages (the API Reference in this manual, see interface).
`F2` | Code Editor
`F3` | Sprite Editor
`F4` | Map Editor
`F5` | Font Editor
`F6` | Sound Effects
`F7` | Music Tracks
`F8` | Memory Overlays Editor
`F9` | Visual Editor
`F10` | Debugger
`F11` | Toggle fullscreen mode.
`F12` | Save screen as `meg4_scr_(unix timestamp).png`.

### UNICODE Codepoint Mode

In this mode you can enter hex numbers (`0` to `9` and `A` to `F`). Instead of these separately pressed keys, the codepoint they describe will be added as if your keyboard had that key. For example the sequence `GUI`, `2`, `e`, `⏎Enter` will add a `.` dot, because codepoint `U+0002E` is the `.` dot character.

Note

Only the Basic Multilingual Plane (`U+00000` to `U+0FFFF`) supported, with some exceptions for the emoticons range starting at `U+1F600`. Other codepoints will be simply skipped.

This mode automatically quits after the character is entered.

### Compose Mode

In compose mode you can add acute, umlaut, tilde etc. to the characters. For example the sequence `AltGr`, `a`, `'` will add `á`, or `AltGr`, `s`, `s` will add `ß`, and another example, `AltGr`, `c`, `,` will add `ç`, etc. You can use `Shift` in combination with the letter to get the uppercase variants.

This mode automatically quits after the character is entered.

### Icon Mode

In icon mode you can add special icon characters, representing the emulator's input (like the sequence `Alt`+`I`, `m` will add the `🖱` mouse icon, and `Alt`+`I`, `a` will add the icon of the gamepad's `Ⓐ` button) as well as emoji icons (like `Alt`+`I`, `;`, `)` will add the character `😉`, or `Alt`+`I`, `<`, `3` will produce `❤`).

This mode automatically quits after the character is entered.

### Katakana and Hiragana Modes

Similar to icon mode, but here you can type the Romaji letters of pronounced sound to get the character. For example the sequence `Alt`+`K`, `n`, `a`, `n`, `i`, `k`, `a` is interpreted as three sounds, and therefore will add the three characters `ナニヵ`. Also, punctation works as expected, for example `Alt`+`K`, `.` will produce Japanese full stop character `。`.

You can use `Shift` in combination with the first letter to get the uppercase variants, for example `Alt`+`K`, `Shift`+`s`, `u` will produce `ス` and not `ㇲ`.

This mode remains active after the character is entered, press `Esc` to return to normal input mode.

### Cyrillic Mode

It is based on KOI8-RU, but some letters are mapped to number and symbol keys. For example `Alt`+`C`, `Shift`+`l`, `e`, `n`, `i`, `n` will produce the characters `Ленин`.

This mode remains active after the character is entered, press `Esc` to return to normal input mode.

### Greek Mode

Tries to be phonetically correct, but there's no one-to-one mapping with the Latin alphabet. For example `Alt`+`G`, `Shift`+`p`, `l`, `a`, `t`, `o` `n`, will produce the characters `Πλατων`.

This mode remains active after the character is entered, press `Esc` to return to normal input mode.

Note

This feature is implemented using data tables, new combinations can be added to `src/inp.c` any time without coding skills.

PreviousNext

# Interface

By default the screen will be blurry to mimic old CRT monitors. You can turn this off with the `-n` (or `/n` on Windows) command line flag, however then pixels won't be equally sized. You can counteract this by switching to windowed mode, where the screen size will be always exact multiple of 320 x 200 pixels.

## Game Screen

By default, you'll see the game screen, with your game running (or the MEG-4 Floppy Drive if there's no game loaded). When you press `Esc` on this screen, then you'll switch to editor mode.

## Editor Screens

If you press `Esc` (no re-compilation) or `Ctrl`+`R` (re-compiles your program) in any of the editor modes then you'll return to the game screen.

All editors are themable, to recolor the entire interface, just drag'n'drop a GIMP Palette file into the screen. See other formats for details.

Help and the Menu

All editors have a menu on the top. By clicking on the icon, a pop up menu will appear, from where you can access various functions, most of which also accessible through keyboard shortcuts (see keyboard). You can also access the built-in help pages from here, however that's always accessible in all editors by pressing `F1` too.

## Help Pages

On the help pages screen, you can click on the links, and you can also press `Backspace` to return to the previous help page in history. If the history is empty, then this will return to the Table of Contents page. The help screen is the exception to the rule, because pressing `Esc` here does not always return to the game screen, instead it returns to the screen where it was invoked from.

To start a search, you can click on the search input box on the top right, or just start typing what you're looking for.

The built-in help pages reader is actually a very minimal MarkDown viewer, and it shows exactly the same info that were used to generate this manual (but this manual you're reading now has more sections, the built-in one is limited to the API Reference).

PreviousNext

# Code Editor

Click on the pencil icon (or press `F2`) to write your program's source code.

Code has three sub-pages, one where you can write the source code (this one), the Visual Editor, where you can do the same using structograms, and your program's machine code can be seen in the debugger.

Code Editor

Here the entire area (1) is one big input field for the source code. At the bottom (2), you can see the status bar, with the current row and coloumn, the UNICODE codepoint of the character under the cursor, and if you're standing in an API's argument list, a quick help on that API function's parameters (suitable for all programming languages).

## Programming Language

The program must start with a special line, with the characters `#!` followed by the language you want to use. By default, it uses MEG-4 C (a subset of ANSI C), but you can choose others as well. See the list under "Programming" in the table of contents on the left.

## User Provided Functions

Regardless to the scripting language you choose, there are two functions that you should implement. They have no arguments and they return no value.

- `setup` function is optional and runs only once when your program gets loaded.
- `loop` function is mandatory, and runs every time a frame is generated. At 60 FPS this means a 16.6 msecs timeframe, but the MEG-4 "hardware" itself takes about 2-3 msecs, which leaves you a 12-13 msecs for your function to fill. You can query this value from the performance counter MMIO register, see memory map. If it takes longer to run the `loop` function, then the screen might became laggy, and the emulator will be less responsive than usual.

## Additional Shortcuts

In addition to standard keyboard shortcuts and input methods, the code editor has lot more text editing related shortcuts.

From the menu, you can also access Find, Replace, Go to, Undo, Redo as well as the list of bookmarks and the defined functions.

PreviousNext

# Sprite Editor

Click on the stamp icon (or press `F3`) to modify the sprites.

The sprites you create here can be displayed using spr, and also used by dlg to generate a dialog window and by stext when it displays text on screen.

Sprite Editor

The editor has three main boxes, two on the top, and one below.

## Sprite Editor Box

The one on the left is the sprite editor box (1). This is where you can draw the sprite. places the selected pixel on the sprite, clears it to empty.

When the `Shift` is hold down, then a line can be drawn from last modified point.

## Sprite Selector

On the right you can see the sprite selector (2). The sprite you select here will be editable on the left. You can select multiple adjacent sprites and edit them together.

## Palette

Below you can see the palette (3). The first item cannot be set, because that's for erase. If you select any other color, then the palette button will become active. Clicking on it will bring up the HSV color picker (5), and with that you can modify the color for that palette entry.

The default MEG-4 palette uses 32 colors of the DawnBringer32 palette, 8 grayscale gradients, and 6 x 6 x 6 RGB combinations.

## Toolbar

Sprite Toolbar

Under the sprite editor, you see the tool buttons (4). With these you can easily modify the sprite. Shifting in different directions, rotating clock-wise, flipping etc. If there's an active selection, then they operate on the selection only, otherwise on the entire sprite. For the rotation, you must select an area which has the same width as height, otherwise rotation would be impossible.

The flood fill tool only fills adjacent same pixels, unless there's a selection. With a selection the entire selected area is filled, no matter what pixels the selection contains.

## Selections

There are two kinds of selections: rectangle selection and fuzzy select. The former selects a rectangular area, the other selects continous regions with the same pixel. You can press and hold `Shift` to expand the selection, and `Ctrl` to intersect and make it smaller.

Pressing `Ctrl`+`A` will select all, and `Ctrl`+`I` will invert the current selection.

When a selection is active, you can press `Ctrl`+`C` to copy the area to the clipboard. Later, you can press `Ctrl`+`V` to paste it. Pasting works exactly like the pencil tool, except now you can paint with the whole copied area like a brush. It worth noting that empty pixels are copied to. If you don't want your brush to clear the area, then only select non-empty pixels (you can use `Ctrl`+ to deselect the empty areas) before copy, that way the empty pixels won't be copied to the clipboard, and in return won't be used as part of the brush.

PreviousNext

# Map Editor

Clicking on the jigsaw icon (or pressing `F4`) will bring up the map editor. Here you can place sprites as tiles on the map.

The map you've created here (or any parts of it) can be put on screen using the map or with the maze commands (see below).

Map Editor

The map is special in a way that it can only display 256 different tiles at once out of the 1024 sprites. For each sprite bank, the first sprite is always reserved for the empty tile, so sprites 0, 256, 512, and 768 cannot be used on maps.

## Map Editor Box

On top the big area is where you can see and edit the maps (1). It is shown as one big map, 320 columns wide and 200 rows high. You can use the zoom in and zoom out buttons on the toolbar, or the mouse wheel to zoom. By pressing right click and holding it down, you can drag the map, but you can also use the scrollbars on the right and on the bottom.

Clicking with left button will set the selected sprite on the map. Select the first sprite to clear the map ( right click does not clear here, instead it moves the map).

When the `Shift` is hold down, then a line can be drawn from last modified point.

## Toolbar

Below the map editor area is the toolbar (2), same as on the sprite editor page, with exactly the same functionality and same keyboard shortcuts (but has a Wang tile tool and it can use sprite patterns too, see below). Next to the tool buttons you can find the zoom buttons and the map selector. This latter selects which sprite bank is used on the map (just for the editor. When your game runs, you'll have to set the byte at offset 0007F to change the map's sprite bank, see Graphics Processing Unit).

## Sprite Palette

On the right to the buttons is the sprite selector (3), where you can select the sprite you want to draw with. As said earlier, the first sprite in every 256 sprites bank is unusable, reserved to the empty map tile.

The difference to the sprite editor is (where you can choose just one color from the palette), here on the map you can select multiple adjacent sprites at once. With paint, all of them will be painted at once (exactly the same way as if they were pasted from the clipboard), and what's more, flood fill will use them as a brush too, filling the selected area with that multi-sprite pattern.

Even more, clicking `Shift`+ with the fill tool, it will choose one sprite from the pattern randomly. For example, let's assume you have 4 sprites with different looking trees. If you select all of them and fill an area on the map, then those sprites will be placed always in the same order, repeating one after another, which isn't looking good for a forest. But if you press and hold down `Shift` during clicking with the fill tool, then each tile will be choosen randomly from those selected 4 tree sprites, which looks much more a real forest.

## Wang Tiles

When the Wang tile tool is selected, the Wang tilesets area (4) becomes active. You can easily draw roads, rivers, castlewalls, etc. with this tool.

Wang tile tool

But before you could use it, you have to configure it. It can hold 64 different tilesets (eg. one for a river, one for a road, etc.), and each tileset has 16 sprites, one for each combination.

To set it up, first select a sprite on the sprite palette, then click on the corresponding Wang tile button depending which combination that sprite represents. If you select more sprites on the palette, then you can set up more tiles at once (starting from the button you've clicked).

Note

Wang tileset configurations are reserved and saved on your floppy.

Now that you have a Wang tileset configured, you can use the tool just like paint, except it will automatically place the approprite sprite to draw continuous shapes on the map.

## 3D Maze

You can also display the map as a 3D maze with the maze function. For this, the turtle position and direction is used as the player's view point to the maze, but to accomodate sub-tile positions, here the turtle's coordinate is multiplied by 128 (originally I've used 8 to match pixels on the map, but movement was too blocky that way). So for example (64,64) is the centre of the top left field on the map, and (320,192) is the centre of the third coloumn and second row.

Here `scale` parameter acts differently too: when set to 0, then the maze will use 32 x 8 tiles as seen on the sprite palette, one for each tile, each 8 x 8 pixels in size. When set to 1, then there will be 16 x 16 tiles, each tile will use 2 x 2 sprites, so 16 x 16 pixels in size. With 3, you'll have 4 x 4 kinds of tiles, so 16 different tiles in total, each 64 x 64 pixels. In this case the map will select these larger tiles, so tile id only equals with the sprite id if the scale is 0. For example if map has the id of 1 with scale set to 1, then instead of sprite id 1, this will select sprites 2, 3, 34, 35.

    Tile id 1 with scale 0          Tile id 1 with scale 1
    +---+===+---+---+-              +---+---+===+===+-
    |  0|::1|  2|  3| ...           |  0|  1|::2|::3| ...
    +---+===+---+---+-              +---+---+===+===+-
    | 32| 33| 34| 35| ...           | 32| 33|:34|:35| ...
    +---+---+---+---+-              +---+---+===+===+-

Regardless you'll have to place sprite id 1 on the map from the palette to get these sprites. Tile id 0 as usual means empty.

If `sky` is set, then that tile will be displayed as a ceiling to the maze. On the other hand, `grd` is only displayed as floor where the map is empty. When you call the maze, you separate the tile ids into ranges, and this specifies how a tile is displayed (floor, wall or sprite). Everything greater than or equal to `wall` will be non-walkable and displayed as a cube, with the selected tile sprites on the cube's sides without transparency. Tiles greater than or equal to `obj` will be non-walkable too, but displayed as a properly scaled 2D sprite always facing towards the player (the turtle's position) and with alpha channel applied, so unlike the walls the objects can be transparent.

Tile id | Description
--- | ---
0 | Always walkable, `grd` displayed as floor instead
1 <= x < `door` | Walkable, displayed as floor
`door` <= x < `wall` | Displayed as a wall, but walkable
`wall` <= x < `obj` | Non-walkable, displayed as a wall
`obj` <= x | Non-walkable, displayed as an object sprite

You can also add non-player characters (or other objects) to the maze independently to the map (in an int array with x, y, tile id triplets, where the coordinates are multiplied by 128). These will be walkable and will be displayed the same as object sprites; collision detection, movement and all the other aspects have to be implemented in your game by you. The `maze` command just diplays these. It does a favour for you though, if the given NPC can directly see the player, then the tile id's most significant 4 bits in the array will be set. Which bits depends on their distance to each other: the most significant bit (0x80000000) is set if their distance is smaller than 8 map fields, next bit (0x40000000) if less than 4 fields, next bit (0x20000000) if less than 2 map fields, and finally last bit (0x10000000) if they are on the same field or neightbouring map fields.

Furthermore this command also takes care of navigation in the maze, `▴` / △ moves the turtle forward, `▾` / ▽ backward; `◂` / ◁ turns left, and `▸` / ▷ turns right (keyboard mappings for the gamepad can be changed, see memory map for details). Handling all the other gamepad buttons and interactions are up to you to code in your game, the `maze` only helps you with moving the player and handling collisions with the walls.

Note

Don't forget that you always have to divide the turtle's position by 128 to get the player's position on the map.

PreviousNext

# Font Editor

Click on the letter icon (or press `F5`) to modify the fonts.

This font will be used by width when you measure a string, and also by text when you display text from your program.

Font Editor

This page has a similar arrangement as the sprite editor, it's just the palette is missing. On the left you can find the glyph editor area (1), and on the right the glyph selector (2). (Glyph is the displayed typeface of a UNICODE character.)

## Glyph Editor

It is as simple as left clicking sets typeface (foreground), and clears to empty (background).

When the `Shift` is hold down, then a line can be drawn from last modified point.

## Glyph Selector

You can search for a UNICODE codepoint, but if you press a key, the glyph selector will jump to its glyph. If your keyboard layout lacks some keys, you can use one of the special input modes, see keyboard.

## Toolbar

The toolbar here is limited, only shifting, rotating and flipping allowed, there are no selection tools. However copy (`Ctrl`+`C`) and paste (`Ctrl`+`V`) works as usual on the glyph selector table.

PreviousNext

# Sound Effects

Click on the speaker icon (or press `F6`) to bring up the sound effects editor.

You can play these sound effects from your program using the sfx command.

Sound Effects

On the left, you'll see the waveform editor and its toolbar (1), on the right the effect selector (2), and below the effect editor (3).

## Effect Selector

On the right you see the list of effects (2), each represented by a music note (technically all sound effects are music notes, with selectable waveforms and special effects option). Clicking on this list (or pressing `▴` / `▾`) will edit that effect.

Important

When you select a sound effect, it's current configuration is saved to history. You can revert to this by pressing undo until you select another sound effect. If you have pressed undo, then you will be able to do a redo until you don't modify. (The modifications won't be saved in history one-by-one, only the state when you've selected that sound effect.)

## Effect Editor

The piano at the bottom (3), looks like and works like the note editor on the music tracks, except it has less options selectable. You can find further info there, including the keyboard layout.

## Waveform Toolbar

Normally the waveform (1) is read-only, and you'll only see what wave the sound effect uses. You'll have to click on the button with the lock icon to make it editable (but first, make sure your sound effect actually has a waveform choosen).

Waveform Toolbar

When the toolbar is unlocked, then clicking on the wave will change it.

Warning

If you change a waveform, then effective immediately all sound effects and music tracks will change too that use that waveform.

Important

When you unlock a waveform, it's current state is saved in history. You can revert to this by pressing undo. (The modifications won't be saved in history one-by-one, only the wave at the moment when you've pressed unlock.)

Using the toolbar you can change the finetuning value (-8 to 7), the volume (0 to 64) and the repeat interval. If you click on the repeat button, then it will remain pressed, and you can select a loop range on the waveform. The wave will be played first through, then it will jump to the beginning of the selected range, and it will repeat that range infinitely.

For convenience, you have 4 default wave generator buttons, one to load the default pattern (the one that General MIDI uses) from the soundfont for this wave and various tools to set the length, rotate, enlarge, shrink, negate, flip etc. the wave. The button before the last will continously play it using its current configuration (even if no loop range defined).

Finally the last button, the Export will export the sample in RIFF Wave format. You can edit this with a third party tool, and to load it back, just drag'n'drop the modified file to the MEG-4 screen.

PreviousNext

# Music Tracks

Click on the music note icon (or press `F7`) to edit the music tracks.

The music you create here can be played in your program using the music command.

You'll see five coloumns and below a piano.

Music Tracks

## Tracks

On the left the first coloumn selects which music track to edit (1).

Key Combination | Description
--- | ---
`Page Up` | Switch to previous track.
`Page Down` | Switch to next track.
`Space` | Start / stop playing the track.

Below the track selector you can see the DSP status registers (2), but this block only comes alive when music playback is on.

## Channels

Next to it, you'll see four similar coloumns, each with notes (3). These are the 4 channels that the music can simultaniously play. This is similar to standard music sheets, for more info read the General MIDI section below.

Key Combination | Description
--- | ---
`◂` | Switch to previous channel.
`▸` | Switch to next channel.
`▴` | Switch to previous row.
`▾` | Switch to next row.
`Home` | Switch to first row.
`End` | Switch to last row.
`Ins` | Insert a row. Move everything below down one row.
`Del` | Delete a row. Move everything below up one row.
`Backspace` | Clear note.

## Note Editor

Under the channels you can see the note editor (4), with some buttons on the left and a big piano on the right.

Important

When you select a note, it's current configuration is saved to history. You can revert to this by pressing undo until you select another note. If you have pressed undo, then you will be able to do a redo until you don't modify. (The modifications won't be saved in history one-by-one, only the state when you've selected that note.)

Notes have three parts, the first one (on the top in the editor), the pitch consist of further three sub-parts: the note itself, like `C` or `D`. Then the `-` character if it's a flat note, or `#` for sharp notes. The third part is simply the octave, from `0` (lowest pitch) to `7` (highest pitch). The 440 Hz pitch for the standard musical note A for example is therefore written as `A-4`. Using the piano you can easily select the pitch.

After the pitch comes the aforementioned instrument (the middle part of the note) that chooses the waveform to be used, from `01` to `1F`. The value 0 is printed as `..` and means keep using the same waveform as before.

Finally, you can also add special effects to the notes (the last part of the note), like arpeggio (make it sound like a chord), portamento, vibrato, tremolo etc. See the note effects for a full list. This has a numeric parameter, usually interpreted as "how much". It is printed as three hex numbers, where the first represents the effect type and the last two are the parameter, or `...` if it's not set. For example `C00` means set the volume to zero, so silence the channel.

### Keyboard

Piano Keyboard arrangement

1. wave selectors
2. effect selectors
3. octave selectors
4. piano keyboard

Key Combination | Description
--- | ---
`1` - `0` | Select wave 1 to 10 (or if pressed with `Shift` 11 to 20).
`Q` | Clear all effects on note (but leave pitch and sample untouched).
`W` | Arpeggio dur (major chord).
`E` | Arpeggio moll (minor chord).
`R` | Slide up a full note.
`T` | Slide up a half note.
`Y` | Slide down a half note.
`U` | Slide down a full note.
`I` | Vibrato small.
`O` | Vibrato large.
`P` | Tremolo small.
`[` | Tremolo large.
`]` | Silence the channel "effect".
`Z` | Switch one octave down.
`.` | Switch one octave up.
`X` | C note on the current octave.
`D` | C# note on the current octave.
`C` | D note on the current octave.
`F` | D# note on the current octave.
`V` | E note on the current octave.
`B` | F note on the current octave.
`H` | F# note on the current octave.
`N` | G note on the current octave.
`J` | G# note on the current octave.
`M` | A note on the current octave.
`K` | A# note on the current octave.
`,` | B note on the current octave.

Note

Keys on the English keyboard have been used in this table. But it doesn't actually matter what keyboard layout you use, the only thing that matters is the location of these keys on the English keyboard. For example, if you have AZERTY layout, then clearing effects will be `A` for you, and on a QWERTZ keyboard `Z` will add slide down effect, and `Y` will change the octave.

It is important to mention that not all features have a keyboard shortcut. For example you might have 31 wavepatterns, but only the first 20 have shortcuts. Similarily, there are several magnitudes more effects than what's accessible through shortcuts.

## General MIDI

You can import music (at least the note sheets) from MIDI files. Very simply put, if a classic music note sheet is stored on a computer in a digitalized form, then it is using the MIDI format to do so. Now these are suitable from a single instrument to a huge orchestra, so they can store a lot more than what the MEG-4 is capable of, therefore

Warning

Not all MIDI files can be imported properly.

Before we could continue, we must talk about the terms, because unfortunately both the MIDI specification and the MEG-4 uses the same nomenclature - but for totally different things.

- MIDI song: a single .mid file (SMF2 format not supported).
- MIDI track: one row on a classic music notes sheet.
- MIDI channel: only exists because MIDI was created by morons, who thought it is fun to squash everything into a single track when storing in files, otherwise exactly the same as a track. You have 16 of these.
- MIDI instrument: a code (standardized by the General MIDI Patch), which describes the instrument a particular channel is using (except when that's channel 10, don't even ask), you have 128 of these instrument codes.
- MIDI note: one note in the range C on octave -1 to G on octave 9, 128 different notes in total.
- MIDI concurrent notes: the number of notes that can be played at once at any given time. There are 16 channels and 128 notes in MIDI, so this is 2048.
- MEG-4 track: a song, you can have 8 of these.
- MEG-4 sample: a wavepattern stored as a series of PCM samples, analogous to instrument, you have 31 of these.
- MEG-4 channel: the number of concurrent notes that can be played at once at any given time, this is 4.
- MEG-4 note: one note in the range C on octave 0 to B on octave 7, 96 different notes in total.

To avoid confusion, hereafter we'll talk about one MEG-4 track only, and "track" will refer to MIDI channels, and "channel" will refer to MEG-4 channels.

### Instruments

Concerning instruments, in total there are 16 families with 8 instruments in each. MEG-4 doesn't have 128 wave banks, so best it can do is, assigning two wavepatterns per family (families 15 and 16 are for sound effects):

Family | SF | Patch | How should sound like | SF | Patch | How should sound like
--- | --- | --- | --- | --- | --- | ---
Piano | 01 | 1-4 | Acoustic Grand Piano | 02 | 5-8 | Electric Piano
Chromatic | 03 | 9-12 | Celesta | 04 | 13-16 | Tubular Bells
Organ | 05 | 17-20 | Church Organ | 06 | 21-24 | Accordion
Guitar | 07 | 25-28 | Acoustic Guitar | 08 | 29-32 | Electric Guitar
Bass | 09 | 33-36 | Acoustic Bass | 0A | 37-40 | Slap Bass
Strings | 0B | 41-44 | Violin | 0C | 45-48 | Orchestral Harp
Ensemble | 0D | 49-52 | String Ensemble | 0E | 53-56 | Choir Aahs
Brass | 0F | 57-60 | Trumpet | 10 | 61-64 | French Horn
Reed | 11 | 65-68 | Saxophone | 12 | 69-72 | Oboe
Pipe | 13 | 73-76 | Piccolo | 14 | 77-80 | Blown Bottle
Synth Lead | 15 | 81-84 | Synth 1 | 16 | 85-88 | Synth 2
Synth Pad | 17 | 89-92 | Synth 3 | 18 | 93-96 | Synth 3

In short, the General MIDI instrument will become the `(patch - 1) / 4 + 1`th wave in the soundfont.

Note that MEG-4 assigns waves dynamically, so these number mean the soundfont's wave number. For example if your MIDI file uses two instruments only, let's say Grand Piano and Electric Guitar, then piano would be assigned wave 1, and guitar wave 2. You can load all waves apriori from the soundfont in the sound effects editor, and then your imported MIDI file will use exactly these wave numbers.

### Patterns

The MEG-4 patterns are analogous to classic music note sheets, but while on a classic sheet time goes from left to right and each MIDI track is tied to an instrument, in MEG-4 the time goes from top to bottom, and you can dynamically assign which waveform to use on a particular channel. Consider the following example (taken from the General MIDI specification):

Classic musical note sheet on the left, its MEG-4 pattern equivalent on the right

On the left we have three tracks, Electric Piano 2, Harp and Bassoon. The first notes to be played are on the bassoon, right two notes at the same time. Note the bass key on the 3rd track, so these are notes C on octave 3 and C on octave 4, and they both last 4 quoter-notes, so whole notes.

On the right you can see the MEG-4 pattern equivalent. The first row describes these two notes played on a bassoon: `C-3` on the first channel, and `C-4` on the second. The sample `12` (hex, provided that you have manually loaded the soundfont apriori, otherwise the number would be different) selects the oboe waveform, which isn't exactly a bassoon, but that's the closest we have in the soundfont. The `C30` part means the velocity at which these notes are played, which is analogous to the volume (the harder you hit a key on the piano, the louder its sound will be). MEG-4 note volumes go from 0 (silence) to 64 (40 in hex, full volume). So 30 in hex means 75% of the full volume.

The next note to be played is on the harp, starts a quoter-note later than the bassoon, it is a G on octave 4 and lasts 3 quoter-notes long. On the MEG-4 pattern you can see this as `G-4` in the fourth row (because it starts at that time), and since channels 1 and 2 are still playing the bassoon, it is played on channel 3. If we were to put this on channel 1 or 2, then the previously played note on that channel would be silenced and replaced by this new one. The sample here is `0C` (hex), which is Orchestral Harp.

The last note is on the first MIDI track, which starts half a note later from the start, is an E on octave 5, and lasts 2 quoter-notes, or with other words a half-note long. Because it starts half a note from the start, you can see `E-5` in the 8th row, and since we already have 3 notes to be played, so it is assigned to channel 4. The sample `02` selects the waveform for Electric Piano, which isn't the same as MIDI Electric Piano 2, but pretty close.

Now we have two whole long notes, one half and a quoter long and another half note long; started at the beginning, quoter and half note later in this order. This means they all must end at the same time. You can see this in the 16th (or 10 in hex) row, all channels have a `C00`, "set volume to 0" command.

### Tempo

MIDI silently assumes 120 BPM and defines a divisor to quoter-notes. Then it might also define the length of a quoter-note in milliseconds, or not. The point is, it is very complex, and not all combinations can be translated to MEG-4 properly. I've written the importer in a way to discard accumulating rounding errors, and only care about the same relative delta times between two consecutive notes. This way the MEG-4 song's tempo never will be exactly the same as the MIDI song's, but it should sound similar and should never deviate too much either.

The tempo on the MEG-4 is much simpler. You have a fixed 3000 ticks per minute, and the default tempo is 6 ticks per row. This means to achive 125 BPM using the default tempo, you should put notes in every 4th rows (because 3000 / 6 / 4 = 125). If you set the tempo (see effect `Fxx`) to half of that, 3 ticks per row, then each row will last half the time, therefore you'll get 250 BPM if you were using every 4th row. To get 125 BPM with tempo 3, you would have to use every 8th rows. If you set the tempo to 12, then each row will last twice the time, therefore every 4th row will get you 62.5 BPM, and you'd have to use every 2nd rows for 125 BPM. Hope this makes sense to you.

This only sets when a note should be started to play, and totally independent of how long that sound lasts. For the latter you should use a new note on the same channel, or you should use a `C00` "set volume to 0" effect in the row when you want the note to be cut off. If you change the tempo in between, that won't influence the sound played, just how long it's played (because the row to turn it off would now reached at a different time).

Now notes will stop playing too if their wavepattern ends. When that happens, depends on the pitch and the number of samples in the wavepattern (playing at C-4 requires 882 samples of the wave to be sent to the speaker on every ticks). There's a trick here: you can set a so called "loop" on the wavepattern, which means after all the samples are played once, the selected region of the wave will be repeated indefinitely (so you'll have to explicitly cut it off, otherwise the sound would really never stop).

PreviousNext

# Memory Overlays

Click on the RAM icon (or press `F8`) to modify the memory overlays.

Overlays are very useful, because they allow switching portions of the RAM, so that you can handle more data than what actually fits in the memory. You can use these to dynamically load sprites, maps, fonts or any arbitrary program data in run-time with the memload function.

They have another very useful feature: if you use memsave in your program, then the contents of the overlay will be saved on the user's computer. Next time you call `memload`, it won't load the overlay's data from your floppy, rather from the user's computer. With this, you can create permanent storage to store high-scores for example.

Memory Overlays

## Overlay Selector

On the top you can see the memory overlays' overview with each overlay's length (1). The darker entries mean that particular overlay isn't set. You have 256 overlay slots, from 00 to FF.

## Overlay Contents

Below the table you can see the hexdump of the overlay's contents (only if a non-empty overlay is selected, 2).

Hexdump is a pretty simple and straightforward format: in the first coloumn you can see the address, which is always dividable by 16. This is followed by the hex representation of 16 bytes at that address, followed by the character representation of the same 16 bytes. That's all to it.

## Overlay Menu

On the menu bar (3), you can specify a memory address and a size, and press on the Save button to store data in the selected overlay. Pressing the Load button will load the contents of the overlay into the specified memory address, but this time the size only specifies the upper limit how much bytes to load.

The Export button will bring up the save file modal, and will allow you to save and modify the binary data with a third party editor. To import a memory overlay back, all you need to do is naming the file `memXX.bin`, where `XX` is the number of the overlay you want use, from 00 to FF, and just drag'n'drop that file into the MEG-4's screen.

PreviousNext

# Visual Editor

Click on the flowchart icon (or press `F9`) to edit the source code visually using structograms.

Code has three sub-pages, one allows you to edit the source code visually (this one), textual edit can be done in the Code Editor, and your program's machine code can be seen in the debugger.

TODO

PreviousNext

# Debugger

Click on the ladybug icon (or press `F10`) to examine your program's machine code.

Code has three sub-pages, one where you can see your program's machine code (this one), the Code Editor where you can write the source code as text, and the Visual Editor, where you can do the same using structograms.

Warning

The debugger only works with the built-in languages. It is not available with third party languages like Lua for example, those are not, and cannot be supported.

Here you can see how the CPU sees your program. By pressing `Space` you can do a step by step execution and see the registers and the memory change. Clicking on the Code / Data button in the menu (1, or pressing the `Tab` key) will switch between code and data views.

Debugger

## Code View

On the left you can see the callstack (2). This is used to backtrace function calls. It also displays the corresponding source line where the function was called. This is a link, clicking on it will bring up the Code Editor, positioned at the line in question. The top of the list is always the line which is currently being executed.

On the right is the list of bytecode instructions in Assembly that the CPU actually executes (3).

## Data View

On the left is the list of your global variables with their actual values (2).

On the right you can see the stack (3), which is splitted into separate parts. Everything above the BP register is the argument list to the currently running function, and everything below that but above the SP register is the area for the local variables.

## Registers

Independently to which view is active, you can always see the CPU registers at the bottom (4). With third party languages, only the FLG, TMR and PC registers are available. See mnemonics for more details on each register.

PreviousNext

# C

If you want to use this language, then start your program with a `#!c` line.

## Example Program

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

`#!c /* global variables */ int acounter = 123; float anumber = 3.1415; addr_t anaddress = 0x0048C; str_t astring = "something"; uint32_t anarray[10]; /* Things to do on startup */ void setup() { /* local variables */ int iamlocal = 123; } /* Things to run for every frame, at 60 FPS */ void loop() { /* Get MEG-4 style outputs */ printf("a counter %d, left shift %d\n", acounter, getkey(KEY_LSHIFT)); }`

## Description

The default language of the console is MEG-4 C. Despite being a very simple language, it is for somewhat intermediate programmers. If you're a total beginner, then I'd recommend using BASIC instead.

It was created as a deliberately simplified ANSI C to help learning programming. Hence it is limited, not everything is supported that ANSI C expects, but replacing

    #!c

with

    1
    2
    3

`#include <stdint.h> typedef char* str_t; typedef void* addr_t;`

will make the MEG-4 C source to compile with any standard ANSI C compiler (gcc, clang, tcc etc.).

It has one non-standard keyword, the `debug;`, which you can place anywhere in your code and will invoke the built-in debugger. After this, you can execute your code step by step, watching what it is doing.

Here comes a gentle introduction to the C language, focusing on what's special in MEG-4 C.

## Pre-compiler

Because there's only one source, and system function prototypes are supported out-of-the-box, there's no need for header files. The pre-compiler therefore is limited to simple (non-macro) defines and conditional source code blocks only.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

`/* replace all occurance of (defvar) with (expression) */ #define (defvar) (expression) /* include code block if (defvar) is defined */ #ifdef (defvar) /* include code block if (defvar) is not defined */ #ifndef (defvar) /* include code block if (expression) is true */ #if (expression) /* else block */ #else /* end of conditional code block inclusion */ #endif`

You can use enumerations with the `enum` keyword, separated by commas and enclosed in curly brackets. Each element will be one bigger than the previous one. These act as if you had multiple rows of defines. For example the following two are identical:

    1
    2
    3

`#define A 0 #define B 1 #define C 2`

    1

`enum { A, B, C };`

It is also possible to assign direct values using the equal sign, for example:

    1

`enum { ONE = 1, TWO, THREE, FIVE = 5, SIX };`

## Literals

MEG-4 C understands decimal based numbers (either integer or floating point with or without scientific notation). Hexadecimal numbers must be prefixed by `0x`, binary by `0b`, octal by `0`; characters must be surrounded by apostrophes and strings must be enclosed in double quotes:

    1
    2
    3
    4
    5
    6
    7
    8

`42 3.1415 .123e-10 0777 0b00100110 0x0048C 'á' "Goodbye and thanks for all the fish!\n"`

## Variables

Unlike in BASIC, variables must be declared. You can place these declaration in two places: at the top level, or at the beginning of a function body. The former become global variable (accessible by all functions), while the latter will be a local variable, accessible only to the function where it was declared. Another difference, that global variables can be initialized (a value assigned to them using `=`), while local variables cannot be, you must explicitly write code to set their values.

A declaration consist of two things: a type and a name. MEG-4 C supports all ANSI C types: `char` (signed byte), `short` (signed word), `int` (signed integer), `float` (floating point). You might also put `unsigned` in front of these to make them, well, unsigned. In ANSI C `int` can be omitted with `short`, but in MEG-4 you must not use it. So `short int` isn't a valid type, `short` in itself is. Furthermore MEG-4 C supports and prefers standard types instead (defined in stdint.h under ANSI C). These have some simple rules: if they are unsigned, then they start with the letter `u`; then `int` means integer type, followed by the number of bits they occupy, and finally suffixed by a `_t` which stands for type. For example, `int` is the same as `int32_t` and `unsigned short` is the same as `uint16_t`. Examples:

    1
    2
    3
    4
    5

`int a = 42; uint8_t b = 0xFF; short c = 0xFFFF; str_t d = "Something"; float e = 3.1415;`

Unlike in ANSI C, which allows only English letters in variable names, MEG-4 C allows anything that does not start with a number and isn't a keyword. For example, `int déjà_vu;` is perfectly valid (note how the name contains non-English letters).

## Arrays and Pointers

Multiple elements of the same type can be assigned to a single variable, which is called an array. Pointers are special variables that contain a memory address which points to a list of variables of the same type. The similarity between these two isn't a coincidence, but there are subtle differences.

There's no special command for arrays like in BASIC, instead you just specify the number of elements between `[` and `]` after the name.

    1

`int anarray[10];`

Referencing an array's value happens similarily, with an index between `[` and `]`. The index starts at 0, and array bounds are checked. MEG-4 supports up to 4 dimensions.

To declare a pointer, one has to prefix the variable name with a `*`. Because C does not recognize string type, and strings are actually just bytes one after another in memory, therefore we use `char*` pointer. This might be strange at first, so MEG-4 C defines the `str_t` type, but this is actually the same as `char*`.

Because pointers hold an address, you must give an address as their value (using `&` returns the address of the variables), and pointers always return an address. In order to get the value at that address, you must de-reference the pointer. You have two options to do this: either prefix it with `*`, or suffix it with an index between `[` and `]`, just like with arrays. For example the two reference in the second printf are the same:

    1
    2
    3
    4
    5

`int variable = 1; int *pointer = &variable; printf("pointer's value (address): %x\n", pointer); printf("pointed value: %x %x\n", *pointer, pointer[0]);`

You cannot mix pointers with arrays, because that would be ambiguous. For example

    1

`int *a[10];`
Could mean a single pointer that points to a list of 10 contiguous integers (`*(int[10])`), but it could also mean 10 independent pointers each pointing to a single, not neccessarily contiguous integers (`(*int)[10]`). Not obvious which one, so pointers and arrays cannot be mixed within the same declaration.

Warning

Unlike arrays, there's no bound check with pointers!

## Operators

In descending order of precedence:

Arithmetic

    * / %
    + -

The first one is multiplication, division and `%` is modulus (aka. remainder after division, eg. `10 % 3` is 1), addition and subtraction.

Relational

    != ==
    <= >= < >

Not equal, equal, less or equal, greater or equal, less than, greater than.

Logical

    !
    &&
    ||

Logical negation (0 becomes 1, everything non-zero becomes 0), and (returns 1 if both arguments are non-zero), or (returns 1 if at least one of the arguments are non-zero).

Bitwise

    ~
    &
    |
    << >>

Bitwise negation, bitwise and, bitwise or, bitwise shift to the left and right. Note that these are the same operators like logical ones, but instead of the whole value, they operate on each binary digits individually. For example logical not `!0x0100 == 0`, but the bitwise not `~0x0100 == 0x1011`. Bitwise shifting is the same as multiplying or dividing by power of two. For example shifting a value to the left by 1 is the same as multipying it by 2.

Incremental

    ++ --

Increment and decrement. You can use these as a prefix and as a suffix as well. When used as prefix, like `++a`, then the variable is increased and the increased value is returned; as a suffix `a++` it will increase the value too, but returns the value before the increment.

    1
    2

`a = 0; b = ++a * 3; /* a == 1, b == 3 */ a = 0; b = a++ * 3; /* a == 1, b == 0 */`

Conditional

    ?:

This is a trinary operator, with three operands, separated by `?` and `:`. If the first operand is true, then the whole expression is replaced by the second operand, otherwise with the third. For this the type of the second and third operands must be the same. For example `a >= 0 ? "positive" : "negative"`.

Assignment

    = *= /= %= += -= ~= &= |= <<= >>=

The first places the value of an expression in a variable. The others execute the operation on that variable, and then store the result in the very same variable. For example these are identical: `a *= 3;` and `a = a * 3;`.

Unlike other languages, in C the assignment is an operator too. This means they can appear anywhere in an expression, for example `a > 0 && (b = 2)`. That's why assignment is `=` and logical equal is `==`, so that you can use both in the same expression.

There's also the address-of operator, the `&` which returns the address of a variable. This is usable when the MEG-4 API expects an `addr_t` address parameter.

Operators are executed in precedence order, for example in `1+2*3` we have two operators, `+` and `*`, but `*` has the higher precedence, therefore first `2*3` is calculated, and then `1+6`. That's why the result is 7 and not 9.

## Control Flow

Unlike BASIC where the primary way of altering the control flow is defining labels, in C (as being a structured language) you specify blocks of instructions instead. If you want to handle multiple instructions together, then you place them between `{` and `}` (but it is possible to put only one instruction in a block).

Like everythig else, the conditionals use such blocks too:

    1
    2
    3
    4
    5

`if(a != b) { printf("a not equal to b\n"); } else { printf("a equals b\n"); }`

You can add an `else` branch, which executes when then the expression is false, but using `else` is optional.

With multiple possible values, you can use a `switch` statement. Here each `case` acts as a label, being choosen depending on the expression's value.

    1
    2
    3
    4
    5
    6

`switch(a) { case 1: printf("a is 1.\n"); case 2: printf("a is either 1 or 2.\n"); break; case 3: printf("a is 3.\n"); break; default: printf("a is something else.\n"); break; }`

There's a special block, defined by the label `default`, which matches any value that doesn't have its own `case`. These blocks are concatenated, so if the control jumps to a `case`, then that block, and every other blocks after that is executed. In the example above, if `a` is 1, then two printfs will be called. To stop this from happening, you must use `break` to exit the `switch`.

C supports three iteration types: pre-testing loop, post-testing loop and counting loop.

The pre-testing loop checks the conditional expression first, and does not run the iteration body at all if its false.

    1
    2
    3

`while(a != 1) { ... }`

The post-testing loop runs the iteration body at least once, it checks the condition afterwards, and repeats only if its true.

    1
    2
    3

`do { ... } while(a != 1);`

The counting loop in C is pretty universal. It expects three expressions, in order: initialization, conditional, stepping. Because you can freely define these, it is possible to use multiple variables or whatever expressions you like (not necessarily counting). Example:

    1
    2
    3

`for(a = 0; a < 10; a++) { ... }`

This is the same as:

    1
    2
    3
    4
    5

`a = 0; while(a < 10) { ... a++; }`

You can exit the iteration by using the `break` statement in its body, but with loops you can also use `continue`, which breaks the execution of the block too, but instead of exiting it continues from the next iteration.

    1
    2
    3
    4
    5

`for(a = 0; a < 100; a++) { if(a < 10) continue; if(a > 50) break; printf("a value between 10 and 50: %d\n", a); }`

## Functions

Important

No statements allowed outside of function bodies.

You must divide your programs into smaller programs which might be called multiple times, these are called functions. These are declared as return value's type, name, argument list in `(` and `)` parenthesis, and function body in a `{` and `}` block. Two of these, `setup` and `loop` has special meaning, see code editor. The C language does not differentiate between subroutines and functions; everything is a function. The only difference is, functions that do not return a value has the return value's type as `void`.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

`void are_we_there_yet(int A) { if(A > 0) { printf("Not yet\n") return; } printf("YES! Do things we wanted to do on arrival\n"); return; } void setup() { /* do it once */ are_we_there_yet(1); /* then do it again */ are_we_there_yet(0); }`

Functions are simply called from programs by their names, followed by their argument list in parenthesis (the parenthesis is mandatory, even if the argument list is empty). There's no special command and there's no difference in the call if the function returns a value or not.

Returning from a function is done by the `return;` instruction. If the function has a return value, then you must specify an expression after the `return`, and that expression's type must be the same as the function's return type. Specifying `return` (independly if the function has a return value or not) is mandatory.

    1
    2
    3
    4
    5
    6
    7
    8
    9

`str_t mystringfunc() { return "a string"; } void setup() { a = mystringfunc(); }`

## Provided Functions

The C language has no special commands for input or output; you simply just do MEG-4 API calls for those. The getc returns a character, gets returns a string and you can print out strings with printf.

Under MEG-4 C you use the MEG-4 API exactly as it is specified in this documentation, there are no tricks, no renaming, no suffixes, nor substitutions either.

PreviousNext

# BASIC

If you want to use this language, then start your program with a `#!bas` line.

## Example Program

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

`#!bas REM global variables LET acounter% = 123 LET anumber = 3.1415 LET anaddress% = $0048C LET astring$ = "something" DIM anarray(10) REM Things to do on startup SUB setup REM local variables LET iamlocal = 123 END SUB REM Things to run for every frame, at 60 FPS SUB loop REM BASIC style print PRINT "I"; " am"; " running" REM Get MEG-4 style outputs printf("a counter %d, left shift %d\n", acounter%, getkey%(KEY_LSHIFT)) END SUB`

## Dialect

BASIC stands for Beginners' All-purpose Symbolic Instruction Code. It was created by John Kemeny in 1963 with the explicit goal to teach students programming with it. The MEG-4 BASIC is a bit more modern than that, it supports all of ANSI X3.60-1978 (ECMA-55) and many featues from ANSI X3.113-1987 (ECMA-116) too, with minor deviations. It allows longer than 2 characters identifiers, and its floating point as well as integer arithmetics are 32 bit. Most important differences: no interactive mode, therefore you don't have to number each instruction any more (you can use labels instead), and all BASIC keywords are case-insensitive as in the specification, but variable and function names are case-sensitive. The MEG-4 API function calls must be in lower-case; as for the rest it is up to you, but those are case-sensitive too (for example `APPLE`, `Apple` and `apple` are three distinct variables).

It has one non-standard keyword, the `DEBUG`, which you can place anywhere in your code and will invoke the built-in debugger. After this, you can execute your code step by step, watching what it is doing.

Here goes a detailed description with examples, and all differences noted.

## Literals

MEG-4 BASIC understands decimal based numbers (either integer or floating point with or without scientific notation). Hexadecimal numbers must be prefixed by `$` (not in the specification, but this was usual in Commodore BASIC and pretty much in every other dialects of the '80s) and strings must be enclosed in double quotes:

    1
    2
    3
    4
    5

`42 3.1415 .123e-10 $0048C "Goodbye and thanks for all the fish!\n"`

Warning

The specification expects 7-bit ASCII, but MEG-4 BASIC uses zero terminated UTF-8 encoding. It also accepts C-like escape sequences (eg. `\"` is double quotes, `\t` is tab, `\n` is the newline character), and the string's maximum size is limited to 255 bytes (the specification requires 18 bytes).

## Variables

Variables aren't declared, instead the last letter in their name identifies their type. This can be `%` for integers, `$` for strings, and not in the specification, but MEG-4 BASIC accepts `!` for bytes and `#` for double bytes (word). Anything else is interpreted as a floating point variable.

    1
    2
    3
    4
    5

`LET A% = 42 LET B! = $FF LET C# = $FFFF LET D$ = "string" LET E = 3.1415`

The conversion between byte, integer and floating point is automatic and fully transparent. However trying to use a string literal in a number variable or storing a number literal in a string variable would reasult in an error (you must explicitly use `STR$` and `VAL`).

When you assign values to variables, the `LET` command can be omited.

Literals can also be added to your program using the `DATA` statement, and then can be assigned to variables with the `READ` command. `READ` reads in as many data literals as many variables its argument has, and can be called repeatedly. To reset to the first `DATA` statement where `READ` reads from, use `RESTORE`.

    1
    2
    3
    4

`RESTORE READ name$, income DATA "Joe", 1234 DATA "John", 2345`

There are a few special variables, provided by the system. `RND` returns a floating point random number between 0 and 1, `INKEY$` returns the key the user has pressed or an empty string, `TIME` returns the number of ticks (1/1000th seconds) since power on, and finally `NOW%` returns the number of elapsed seconds since Jan 1, 1970 midnight in Greenwich Mean Time.

## Arrays

Multiple elements of the same type can be assigned to a single variable, which is called an array.

    1
    2
    3

`DIM A(10) DIM B(10, 10) DIM C(1 TO 6)`

The BASIC specification expects two-dimensional arrays to be handled, but MEG-4 BASIC supports up to 4 dimensions. Array elements can be bytes, integers, numbers or strings. Dynamically resizing arrays with `REDIM` is not possible, all are statically allocated using `DIM`. When the size isn't given, one dimension and 10 elements are assumed.

Warning

Index starts at 1 (as in ANSI and not at 0 as in ECMA-55). The `OPTION BASE` statement isn't supported, but you can set the first index of each array with the `TO` keyword.

## Operators

In descending order of precedence:

Arithmetic

    ^
    * / MOD
    + -

The first one is for exponentiation (eg. b squared is `b^2`), multiplication, division and `MOD` is modulus (aka. remainder after division, eg. `10 MOD 3` is 1), addition and subtraction.

Relational

    <> =
    <= >= < >

Not equal, equal, less or equal, greater or equal, less than, greater than.

Logical

    NOT
    AND
    OR

Logical negation (0 becomes 1, everything non-zero becomes 0), and (returns 1 if both arguments are non-zero), or (returns 1 if at least one of the arguments are non-zero).

There's one non-standard operator, the `@` returns the address of a variable. This is usable when the MEG-4 API expects an `addr_t` address parameter.

Operators are executed in precedence order, for example in `1+2*3` we have two operators, `+` and `*`, but `*` has the higher precedence, therefore first `2*3` is calculated, and then `1+6`. That's why the result is 7 and not 9.

## Control Flow

The statement `END` stops control flow (exists your program).

MEG-4 BASIC does not use line numbers any more, instead it supports `GOTO` with labels, for example:

    1
    2
    3

`this_is_a_label: GOTO this_is_a_label`

Warning

Some BASIC dialects allow you to use multiple commands separated by `:` in one line. In MEG-4 BASIC `:` identifies a label, so you must use one command per line (as expected by ECMA-55).

Conditional jumps use labels too:

    1
    2

`IF a$ <> b$ THEN this_is_a_label ON a GOTO label1, label2, label3 ELSE labelother`

The `ON` .. `GOTO` always needs a numerical expression, and chooses the label accordingly, starting from 1 (if the expression is zero or negative, that always jumps to the `ELSE` label). There's no `ON` .. `GOSUB`, because GOSUB does not accept labels in MEG-4 BASIC.

Warning

The `GOSUB` statement does not accept labels at all, and its semantics are a bit changed in MEG-4 BASIC, see below.

For `IF`, both numerical and relational expressions are accepted (every non-zero expression considered true), and what's more, multi line `IF` .. `THEN` .. `ELSE` .. `END IF` blocks are supported too (but no `SELECT CASE`).

    1
    2
    3
    4
    5

`IF var >= 0 THEN PRINT "var is positive" ELSE PRINT "var is negative" END IF`

As an exception, one command is allowed in a single line `IF`, provided that's a `GOTO` or an `END`:

    1
    2

`IF a < 0 THEN GOTO label IF b > 42 THEN END`

For iterations, the counting loop checks its condition before the iteration (does not execute the block if the initial value is greater (or less) than the limit), and looks like this:

    1
    2
    3

`FOR i = 1 TO 100 STEP 2 ... NEXT i`

This `FOR` .. `NEXT` is essentially the same as:

    1
    2
    3
    4
    5
    6
    7
    8
    9

`LET i = 1 LET lim = 100 LET inc = 2 line1: IF (i - lim) * SGN(inc) > 0 THEN line2 ... LET i = i + inc GOTO line1 line2:`

The loop variable must be of float type. The `STEP` is optional (defaults to 1.0), and the expression after that can be a float literal or another float variable. The from and limit both can be more complex expressions, but they too must return a floating point value.

    1
    2
    3

`FOR i = (1+2+a)*3 TO 4*(5+6)/b+c STEP j ... NEXT i`

Warning

Unlike the specification, which allows multiple variables after `NEXT`, MEG-4 BASIC accepts exactly one. So for nested loops you'll have to use multiple `NEXT` commands, exactly as many as `FOR` statements there are.

    1
    2
    3
    4
    5

`FOR y = 1 TO 10 FOR x = 1 TO 100 ... NEXT x NEXT y`

MEG-4 BASIC has no other kind of loops like C, but if you want a non-counting pre-testing loop, you can do this:

    1
    2
    3
    4
    5

`again: IF a > 0 THEN ... GOTO again END IF`

And instead of a post-testing loop:

    1
    2
    3

`again: ... IF a > 0 THEN again`

## Subroutines and Functions

Important

Statements not inside of any subroutine are simply threated as if they were inside the `setup` subroutine.

You can divide your programs into smaller programs which might be called multiple times, these are called subroutines. They are defined between `SUB` and `END SUB` blocks. Two of these, `setup` and `loop` has special meaning, see code editor. As mentioned earlier, in MEG-4 BASIC `GOSUB` does not accept labels, and that's because here it accepts subroutine names only.

    1
    2
    3
    4
    5
    6
    7
    8

`SUB mysubroutine PRINT "do something that you want to do multiple times" END SUB REM do it once GOSUB mysubroutine REM then do it again GOSUB mysubroutine`

Control is transferred on `GOSUB`, and it is returned to the line after `GOSUB` when `END SUB` (or the optional `RETURN`) reached. Subroutines can access global variables and they might have parameters.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

`SUB are_we_there_yet(A) IF A > 0 THEN PRINT "Not yet" RETURN END IF PRINT "YES! Do things we wanted to do on arrival" END SUB REM do it once GOSUB are_we_there_yet(1) REM then do it again GOSUB are_we_there_yet(0)`

Functions are very similar, but they must have a `RETURN` and their `RETURN` statement must contain a returned value, same type as identified by the function's name. Functions are simply called from programs by their names, followed by their argument list in parenthesis (the parenthesis is mandatory, even if the argument list is empty). For example:

    1
    2
    3
    4
    5

`FUNCTION mystringfunc$() RETURN "a string" END FUNCTION LET a$ = mystringfunc$()`

## Print Statement

    PRINT expression [;|,] [expression [;|,] [expression [;|,]]] ...

Prints one or more exporession on screen. If the expressions are separated by `;` semi-colon, then tightly one after another. If by `,` colon, then the output will be splitted into coloumns. Numbers are always prefixed by a space, and if the command ends in an expression (not in `;` nor in `,`), then a newline character will be printed at the end as well.

## Input Statement

    INPUT "prompt" [;|,] variable

Prints out prompt, then reads in a value from user and stores it in the given variable. If the prompt and the variable is spearated by a `,` colon, then it also prints a `?` question-mark after the prompt.

Warning

The ECMA-55 specification allows multiple variables to be specified, but the MEG-4 BASIC allows only one.

## Peek and Poke

You can directly access the MEG-4 memory with these commands, even the MMIO area.

Read

    variable = PEEK(address)

Reads in the byte at the given address, converts it into a floating point and stores it in the given variable.

For example, to check if the keyboard queue is not empty:

    1

`IF PEEK($1A) <> PEEK($1B) THEN`
Store

    POKE address, expression

Calculates the expression, converts it into a byte and stores that byte value at the given address.

For example, to set the palette for color index 1:

    1
    2
    3
    4
    5
    6
    7
    8

`REM red component POKE $84, 10 REM green component POKE $85, 10 REM blue component POKE $86, 10 REM alpha (transparency) POKE $87, 255`

## Provided Functions

Some MEG-4 API are provided as system variables, `RND` (rnd), `TIME` (time), `NOW%` (now), and `INKEY$` (getc).

Others are provided as commands, `INPUT` (gets + val), `PRINT` (printf), `PEEK` (inb), `POKE` (outb).

As to comply with ECMA-55, two functions are renamed: `SQR` (sqrt) and `ATN%` (atan). All the rest is used as they appear in this documentation, except they are properly suffixed according their return types (for example, str returns a string, so it is called `STR$`).

Note that ECMA-55 expects that trigonometrical functions use radians by default (with an `OPTION` command to switch to degrees), however the MEG-4 API always uses degrees, 0 to 359, where 0 is up, and 90 is to the right. That's why the `ATN%` gets an integer type suffix for example, as it returns degrees in an integer.

Normally all functions without a return value must be called with the `GOSUB` keyword, however the MEG-4 API is a special case, because with those the keyword can be ommited, and the API function can be used as-is.

PreviousNext

# Assembly

If you want to use this language, then start your program with a `#!asm` line.

## Example Program

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

`#!asm .data /* global variables */ acounter: di 123 anumber: df 3.1415 anaddress: di 0x0048C astring: db "something" anarray: di 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 fmt: db "a counter %d, left shift %d\n" .code /* Things to do on startup */ setup: /* local variables (not really, just reserve space on the stack) */ sp -4 ret /* Things to run for every frame, at 60 FPS */ loop: /* Get MEG-4 style outputs */ pshci KEY_LSHIFT scall getkey sp 4 pushi ci acounter ldi pushi pshci fmt scall printf sp 12 ret`

## Description

This isn't an actual programming language. When you compile one of the built-in languages, the compiler generates bytecode that the CPU executes. Assembly is a one-to-one transcription of that bytecode with human-readable textual mnemonics. It has two sections, data and code, both containing a series of labels and instructions. Instructions are mnemonics with an optional parameter.

You can play around and experiment with this if you feel brave.

## Literals

Same as MEG-4 C literals.

## Variables

There's no such thing as a variable in Assembly. Instead you specify the data section with `.data`, and just place the data after one of the `db` (byte), `dw` (word), `di` (integer), `df` (float) instructions. In this stream of data, before the instruction, you can place labels which will hold the address of that data. To load a value in your code section, first you put that label in the accumulator register using `ci`, and then issue one of the `ldb` (load byte), `ldw` (load word), `ldi` (load integer) or `ldf` (load float) instructions. If the `ldb` or `ldw` instructions has a non-zero argument, then they sign-extend the value to 32 bit.

## Control Flow

Everything that you place after the `.code` keyword will be code. There's no implicit control flow, each instruction is executed one after another; you have to alter the PC (program counter) using one of the `jmp` (jump), `jz` (jump if zero), `jnz` (jump if not zero) or `sw` (switch, case selection) instructions to change the control flow manually.

## Functions

There's no function declaration. You just use a label to mark a spot in the code. You push all arguments on the stack in reverse order using `pushi` and `pushf`, then you use a `call` mnemonic with that label. Within the function, you can get the address of these parameters with the `adr` (address) instruction, with its parameter being the function parameter's number multiplied by four. For example `adr 0` loads the first function parameter's address in the accumulator register, and `adr 4` loads the second's. You can return from the function with the `ret` instruction. Return values are returned in the accumulator register, which you can set directly with the `ci` (constant integer) and `cf` (constant float) instructions, and indirectly with the `popi`, `popf`, `ldb`, `ldw`, `ldi` and `ldf` instructions. After the call it is the caller's responsibility to remove the parameters from the stack by using an `sp` + number of parameters times four instruction.

## Provided Functions

You have all the MEG-4 API functions at your disposal; using the exact names as they are listed in this documentation.

You have to push all arguments on the stack in reverse order, then use an `scall` (system call) mnemonic with a MEG-4 API function name as parameter. After the call it is the caller's responsibility to remove the parameters from the stack.

## Mnemonics

Before we go into the details, we must talk about the MEG-4 CPU specification.

The MEG-4 CPU is a 32-bit, little endian CPU. All values are stored in a way that smallest digits are placed on the smaller addresses. It is capable of performing operations on 8 bit, 16 bit and 32 bit integers (signed and unsigned) and on 32 bit floating point numbers.

The memory model is flat, meaning all data can be accessed through a single offset. Has no paging and no virtual address translation, no segmentation, except all data and code segment references are implicit (aka. no segment prefixes, referencing segments are automatic).

For security reasons code segment and data segment are separated, as well as the call stack and the data stack. Stack overflow and any other code injection through buffer overflow attacks are simply impossible on this CPU, which makes it very secure and bullet-proof (also supporting 3rd party bytecode like Lua would be impossible without code separation). In this reagard it is more like a Harvard architecture, but in every other aspect it's more like a von Neumann architecture.

The CPU has the following registers:

- AC: accumulator register, with an integer value
- AF: accumulator register, with a floating point value
- FLG: processor flags (setup is done, blocked for I/O, blocked for timer, execution stopped)
- TMR: the timer register's current value
- DP: data pointer, this points to the top of the used global variable memory
- BP: base pointer, marks the top of the function stack frame
- SP: stack pointer, the bottom of the stack
- CP: callstack pointer, the top of the callstack
- PC: program counter, the address of the instruction currently being executed

The data segment is byte based, meaning DP, BP and SP registers point to 8 bit units. You can place data to the data segment using the `db` (8 bit), `dw` (16 bit), `di` (32 bit) and `df` (32 bit float) mnemonics. These might have one or more comma separated arguments, and for `db` strings literals and character literals can also be used.

The code segment has a 32 bit granularity, meaning that's the smallest address unit you can use. For this reason the PC points to these 32 bit units and not bytes. The following mnemonics can be used to place instructions to the code segment:

Mnemonic | Parameter | Description
--- | --- | ---
`debug` |  | Invoke the built-in debugger (nop for MEG-4 PRO)
`ret` |  | Return from `call`, pops from the call stack
`scall` | MEG-4 API function | System call
`call` | address/code label | Pushes the position to the call stack and then calls a function
`jmp` | address/code label | Jump to address
`jz` | address/code label | Jump to address if accumulator is zero
`jnz` | address/code label | Jump to address if accumulator isn't zero
`js` | address/code label | Pop value, adjust its sign and jump to address if negative or zero
`jns` | address/code label | Pop value, adjust its sign and jump to address if positive
`sw` | num,addr,addr0,addr1... | Switch (see below)
`ci` | number/data label | Place an integer value into the accumulator
`cf` | number | Place a floating point number into the accumulator
`bnd` | number | Checks if the accumulator's value is between 0 and number
`lea` | number | Loads the address DP + number into the accumulator
`adr` | number | Loads the address BP + number into the accumulator
`sp` | number | Adjust SP register by number
`pshci` | number/data label | Push an integer constant to the data stack
`pshcf` | number | Push a float constant to the data stack
`pushi` |  | Push the accumulator as integer to the data stack
`pushf` |  | Push the accumulator as float to the data stack
`popi` |  | Pop an integer value from the data stack into the accumulator
`popf` |  | Pop a float value from the data stack into the accumulator
`cnvi` |  | Convert the value on the top of the stack into an integer
`cnvf` |  | Convert the value on the top of the stack into a float
`ldb` | 0/1 | Loads a byte from the address in the accumulator (sign extend if arg is non-zero)
`ldw` | 0/1 | Loads a word from the address in the accumulator (sign extend if arg is non-zero)
`ldi` |  | Loads an integer from the address in the accumulator
`ldf` |  | Loads a float from the address in the accumulator
`stb` |  | Pops the address from stack and stores a byte from accumulator
`stw` |  | Pops the address from stack and stores a word from accumulator
`sti` |  | Pops the address from stack and stores an int from accumulator
`stf` |  | Pops the address from stack and stores a float from accumulator
`incb` | number | Pops the address from stack and increase the byte at address by number
`incw` | number | Pops the address from stack and increase the word at address by number
`inci` | number | Pops the address from stack and increase the integer at address by number
`decb` | number | Pops the address from stack and decrease the byte at address by number
`decw` | number | Pops the address from stack and decrease the word at address by number
`deci` | number | Pops the address from stack and decrease the integer at address by number
`not` |  | Perform logical NOT on the accumulator
`neg` |  | Perform bitwise NOT on the accumulator
`or` |  | Pop a value from stack and perform bitwise OR on the accumulator
`xor` |  | Pop a value from stack and perform EXCLUSIVE OR on the accumulator
`and` |  | Pop a value from stack and perform bitwise AND on the accumulator
`shl` |  | Pop a value and shift accumulator bits to the left, place result in accumulator
`shr` |  | Pop a value and shift accumulator bits to the right, place result in accumulator
`eq` |  | Pop a value and set accumulator if accumulator is the same as the popped
`ne` |  | Pop a value and set accumulator if accumulator isn't the same
`lts` |  | Pop a value and set accumulator if it's less than as signed
`gts` |  | Pop a value and set accumulator if it's greater than as signed
`les` |  | Pop a value and set accumulator if it's less or equal as signed
`ges` |  | Pop a value and set accumulator if it's greater or equal as signed
`ltu` |  | Pop a value and set accumulator if it's less than as unsigned
`gtu` |  | Pop a value and set accumulator if it's greater than as unsigned
`leu` |  | Pop a value and set accumulator if it's less or equal as unsigned
`geu` |  | Pop a value and set accumulator if it's greater or equal as unsigned
`ltf` |  | Pop a value and set accumulator if it's less than as float
`gtf` |  | Pop a value and set accumulator if it's greater than as float
`lef` |  | Pop a value and set accumulator if it's less or equal as float
`gef` |  | Pop a value and set accumulator if it's greater or equal as float
`addi` |  | Pop a value and add it to the accumulator as integer
`subi` |  | Pop a value and subtract the accumulator from it as integer
`muli` |  | Pop a value and multiply the accumulator with it as integer
`divi` |  | Pop a value and divide by the accumulator as integer
`modi` |  | Pop a value, divide and put the remainder in accumulator as integer
`powi` |  | Pop a value and raise to the power of accumulator as interger
`addf` |  | Pop a value and add it to the accumulator as float
`subf` |  | Pop a value and subtract the accumulator from it as float
`mulf` |  | Pop a value and multiply the accumulator with it as float
`divf` |  | Pop a value and divide by the accumulator as float
`modf` |  | Pop a value, divide and put the fractional in accumulator as float
`powf` |  | Pop a value and raise to the power of accumulator as float

The `sw` mnemonic has variable number (but at least three) arguments. The first one is a number, the second is a code label, as well as all the rest are code labels. It subtracts the number from the accumulator and checks if the result is positive and less than the number of the labels given. If not, then it jumps to the first label in the second argument. If it is, then it picks the accumulatorth label starting from the third parameter (second label), and jumps there.

So in a nutshell it is

    sw (value), (label to jump to otherwise),
      (label to jump to if accumulator equals value),
      (label to jump to if accumulator equals value + 1),
      (label to jump to if accumulator equals value + 2),
      (label to jump to if accumulator equals value + 3),
      ...
      (label to jump to if accumulator equals value + N)

Every `sw` mnemonic might have up to 256 value labels.

PreviousNext

# Lua

If you want to use this language, then start your program with a `#!lua` line.

## Example Program

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

`#!lua -- global variables acounter = 123 anumber = 3.1415 anaddress = 0x0048C astring = "something" anarray = {} -- Things to do on startup function setup() -- local variables iamlocal = 234 end -- Things to run for every frame, at 60 FPS function loop() -- Lua style print print("I", "am", "running") -- Get MEG-4 style outputs printf("a counter %d, left shift %d\n", acounter, getkey(KEY_LSHIFT)) end`

## Further Info

Unlike the other languages, this isn't integral part of MEG-4, rather provided by a thrid party library. Due to that it does not (and cannot) have perfect integration (no debugger and no translated error messages for example). Its runner is bloated and much slower compared to the other languages, but it works, and you can use it.

The embedded version is Lua 5.4.7, with modifications. For security reasons it lacks concurrency, as well as module loading, file access, pipes, command execution. The `coroutine`, `io` and `os` modules and their functions aren't available (but the language features and all the other parts of the baselib are still there). Instead of these missing tables, it has the MEG-4 API, which can be used as in any other language (with some slight, minor differences for better integration).

If you're interested in this language then you can find more information in the Programming in Lua documentation.

## API Differences

- memsave can accept either a MEG-4 memory address (integer) or a Lua table with integers (supposed to be a byte array).
- memload on call, a valid MEG-4 memory address must be passed, but then it returns a Lua table anyway. If you don't want to load to a specific MMIO area, then specify `MEM_USER` (0x30000) and just simply use the data in the returned Lua table.
- memcpy parameters can be two MEG-4 memory addresses as usual, or one of them can be a Lua table (just one, not both). You can use this function to copy data between MEG-4 memory and Lua (but inb and outb also works).
- remap only accepts a Lua table (with 256 integer values).
- maze instead of the last two parameters (`numnpc` and `npc`) one single Lua table (with each element being another table) can be used.
- printf, sprintf and trace does not use MEG-4's format string rules, but Lua's (however these two are almost entirely identical).

PreviousNext

# Memory Map

## Misc

All values are little endian, so the smaller digit is stored on the smaller address.

Offset | Size | Description
--- | --- | ---
00000 | 1 | MEG-4 firmware version major
00001 | 1 | MEG-4 firmware version minor
00002 | 1 | MEG-4 firmware version bugfix
00003 | 1 | performance counter, last frame's unspent time in 1/1000th secs
00004 | 4 | number of 1/1000th second ticks since power on
00008 | 8 | UTC unix timestamp
00010 | 2 | current locale

The performance counter shows the time unspent when the last frame was generated. If this is zero or negative, then it means how much your loop() function has overstepped its available timeframe.

## Pointer

Offset | Size | Description
--- | --- | ---
00012 | 2 | pointer buttons state (see getbtn and getclk)
00014 | 2 | pointer sprite index
00016 | 2 | pointer X coordinate
00018 | 2 | pointer Y coordinate

The pointer buttons are as follows:

Define | Bitmask | Description
--- | --- | ---
`BTN_L` | 1 | Left mouse button
`BTN_M` | 2 | Middle mouse button
`BTN_R` | 4 | Right mouse button
`SCR_U` | 8 | Scroll up
`SCR_D` | 16 | Scroll down
`SCR_L` | 32 | Scroll left
`SCR_R` | 64 | Scroll right

The upper bits of the pointer sprite index are used for hotspots: bit 13-15 hotspot Y, bit 10-12 hotspot X, bit 0-9 sprite. There are some predefined built-in cursors:

Define | Value | Description
--- | --- | ---
`PTR_NORM` | 03fb | Normal (arrow) pointer
`PTR_TEXT` | 03fc | Text pointer
`PTR_HAND` | 0bfd | Link pointer
`PTR_ERR` | 93fe | Error pointer
`PTR_NONE` | ffff | The pointer is hidden

## Keyboard

Offset | Size | Description
--- | --- | ---
0001A | 1 | keyboard queue tail
0001B | 1 | keyboard queue head
0001C | 64 | keyboard queue, 16 elements, each 4 bytes (see popkey)
0005C | 18 | keyboard keys pressed state by scancodes (see getkey)

The keys popped from the queue are represented in UTF-8. Some invalid UTF-8 sequences represent special (non-printable) keys, for example:

Keycode | Description
--- | ---
`\x8` | The character 8, `←Backspace` key
`\x9` | The character 9, `Tab` key
`\n` | The character 10, `⏎Enter` key
`\x1b` | The character 27, `Esc` key
`Del` | The `Del` key
`Up` | The cursor arrow `▴` key
`Down` | The cursor arrow `▾` key
`Left` | The cursor arrow `◂` key
`Rght` | The cursor arrow `▸` key
`Cut` | The Cut key (or `Ctrl`+`X`)
`Cpy` | The Copy key (or `Ctrl`+`C`)
`Pst` | The Paste key (or `Ctrl`+`V`)

The scancodes are as follows:

ScanCode | Address | Bitmask | Define
--- | --- | --- | ---
0 | 0005C | 1 | `KEY_CHEAT`
1 | 0005C | 2 | `KEY_F1`
2 | 0005C | 4 | `KEY_F2`
3 | 0005C | 8 | `KEY_F3`
4 | 0005C | 16 | `KEY_F4`
5 | 0005C | 32 | `KEY_F5`
6 | 0005C | 64 | `KEY_F6`
7 | 0005C | 128 | `KEY_F7`
8 | 0005D | 1 | `KEY_F8`
9 | 0005D | 2 | `KEY_F9`
10 | 0005D | 4 | `KEY_F10`
11 | 0005D | 8 | `KEY_F11`
12 | 0005D | 16 | `KEY_F12`
13 | 0005D | 32 | `KEY_PRSCR`
14 | 0005D | 64 | `KEY_SCRLOCK`
15 | 0005D | 128 | `KEY_PAUSE`
16 | 0005E | 1 | `KEY_BACKQUOTE`
17 | 0005E | 2 | `KEY_1`
18 | 0005E | 4 | `KEY_2`
19 | 0005E | 8 | `KEY_3`
20 | 0005E | 16 | `KEY_4`
21 | 0005E | 32 | `KEY_5`
22 | 0005E | 64 | `KEY_6`
23 | 0005E | 128 | `KEY_7`
24 | 0005F | 1 | `KEY_8`
25 | 0005F | 2 | `KEY_9`
26 | 0005F | 4 | `KEY_0`
27 | 0005F | 8 | `KEY_MINUS`
28 | 0005F | 16 | `KEY_EQUAL`
29 | 0005F | 32 | `KEY_BACKSPACE`
30 | 0005F | 64 | `KEY_TAB`
31 | 0005F | 128 | `KEY_Q`
32 | 00060 | 1 | `KEY_W`
33 | 00060 | 2 | `KEY_E`
34 | 00060 | 4 | `KEY_R`
35 | 00060 | 8 | `KEY_T`
36 | 00060 | 16 | `KEY_Y`
37 | 00060 | 32 | `KEY_U`
38 | 00060 | 64 | `KEY_I`
39 | 00060 | 128 | `KEY_O`
40 | 00061 | 1 | `KEY_P`
41 | 00061 | 2 | `KEY_LBRACKET`
42 | 00061 | 4 | `KEY_RBRACKET`
43 | 00061 | 8 | `KEY_ENTER`
44 | 00061 | 16 | `KEY_CAPSLOCK`
45 | 00061 | 32 | `KEY_A`
46 | 00061 | 64 | `KEY_S`
47 | 00061 | 128 | `KEY_D`
48 | 00062 | 1 | `KEY_F`
49 | 00062 | 2 | `KEY_G`
50 | 00062 | 4 | `KEY_H`
51 | 00062 | 8 | `KEY_J`
52 | 00062 | 16 | `KEY_K`
53 | 00062 | 32 | `KEY_L`
54 | 00062 | 64 | `KEY_SEMICOLON`
55 | 00062 | 128 | `KEY_APOSTROPHE`
56 | 00063 | 1 | `KEY_BACKSLASH`
57 | 00063 | 2 | `KEY_LSHIFT`
58 | 00063 | 4 | `KEY_LESS`
59 | 00063 | 8 | `KEY_Z`
60 | 00063 | 16 | `KEY_X`
61 | 00063 | 32 | `KEY_C`
62 | 00063 | 64 | `KEY_V`
63 | 00063 | 128 | `KEY_B`
64 | 00064 | 1 | `KEY_N`
65 | 00064 | 2 | `KEY_M`
66 | 00064 | 4 | `KEY_COMMA`
67 | 00064 | 8 | `KEY_PERIOD`
68 | 00064 | 16 | `KEY_SLASH`
69 | 00064 | 32 | `KEY_RSHIFT`
70 | 00064 | 64 | `KEY_LCTRL`
71 | 00064 | 128 | `KEY_LSUPER`
72 | 00065 | 1 | `KEY_LALT`
73 | 00065 | 2 | `KEY_SPACE`
74 | 00065 | 4 | `KEY_RALT`
75 | 00065 | 8 | `KEY_RSUPER`
76 | 00065 | 16 | `KEY_MENU`
77 | 00065 | 32 | `KEY_RCTRL`
78 | 00065 | 64 | `KEY_INS`
79 | 00065 | 128 | `KEY_HOME`
80 | 00066 | 1 | `KEY_PGUP`
81 | 00066 | 2 | `KEY_DEL`
82 | 00066 | 4 | `KEY_END`
83 | 00066 | 8 | `KEY_PGDN`
84 | 00066 | 16 | `KEY_UP`
85 | 00066 | 32 | `KEY_LEFT`
86 | 00066 | 64 | `KEY_DOWN`
87 | 00066 | 128 | `KEY_RIGHT`
88 | 00067 | 1 | `KEY_NUMLOCK`
89 | 00067 | 2 | `KEY_KP_DIV`
90 | 00067 | 4 | `KEY_KP_MUL`
91 | 00067 | 8 | `KEY_KP_SUB`
92 | 00067 | 16 | `KEY_KP_7`
93 | 00067 | 32 | `KEY_KP_8`
94 | 00067 | 64 | `KEY_KP_9`
95 | 00067 | 128 | `KEY_KP_ADD`
96 | 00068 | 1 | `KEY_KP_4`
97 | 00068 | 2 | `KEY_KP_5`
98 | 00068 | 4 | `KEY_KP_6`
99 | 00068 | 8 | `KEY_KP_1`
100 | 00068 | 16 | `KEY_KP_2`
101 | 00068 | 32 | `KEY_KP_3`
102 | 00068 | 64 | `KEY_KP_ENTER`
103 | 00068 | 128 | `KEY_KP_0`
104 | 00069 | 1 | `KEY_KP_DEC`
105 | 00069 | 2 | `KEY_INT1`
106 | 00069 | 4 | `KEY_INT2`
107 | 00069 | 8 | `KEY_INT3`
108 | 00069 | 16 | `KEY_INT4`
109 | 00069 | 32 | `KEY_INT5`
110 | 00069 | 64 | `KEY_INT6`
111 | 00069 | 128 | `KEY_INT7`
112 | 0006A | 1 | `KEY_INT8`
113 | 0006A | 2 | `KEY_LNG1`
114 | 0006A | 4 | `KEY_LNG2`
115 | 0006A | 8 | `KEY_LNG3`
116 | 0006A | 16 | `KEY_LNG4`
117 | 0006A | 32 | `KEY_LNG5`
118 | 0006A | 64 | `KEY_LNG6`
119 | 0006A | 128 | `KEY_LNG7`
120 | 0006B | 1 | `KEY_LNG8`
121 | 0006B | 2 | `KEY_APP`
122 | 0006B | 4 | `KEY_POWER`
123 | 0006B | 8 | `KEY_KP_EQUAL`
124 | 0006B | 16 | `KEY_EXEC`
125 | 0006B | 32 | `KEY_HELP`
126 | 0006B | 64 | `KEY_SELECT`
127 | 0006B | 128 | `KEY_STOP`
128 | 0006C | 1 | `KEY_AGAIN`
129 | 0006C | 2 | `KEY_UNDO`
130 | 0006C | 4 | `KEY_CUT`
131 | 0006C | 8 | `KEY_COPY`
132 | 0006C | 16 | `KEY_PASTE`
133 | 0006C | 32 | `KEY_FIND`
134 | 0006C | 64 | `KEY_MUTE`
135 | 0006C | 128 | `KEY_VOLUP`
136 | 0006D | 1 | `KEY_VOLDN`

## Gamepad

Offset | Size | Description
--- | --- | ---
0006E | 2 | gamepad joystick threshold (defaults to 8000)
00070 | 8 | primary gamepad - keyboard scancode mappings (see keyboard)
00078 | 4 | 4 gamepads button pressed state (see getpad)

The gamepad buttons are as follows:

Define | Bitmask | Description
--- | --- | ---
`BTN_L` | 1 | The `◁` button or joystick left
`BTN_U` | 2 | The `△` button or joystick up
`BTN_R` | 4 | The `▷` button or joystick right
`BTN_D` | 8 | The `▽` button or joystick down
`BTN_A` | 16 | The `Ⓐ` button
`BTN_B` | 32 | The `Ⓑ` button
`BTN_X` | 64 | The `Ⓧ` button
`BTN_Y` | 128 | The `Ⓨ` button

The `△△▽▽◁▷◁▷ⒷⒶ` sequence makes the `KEY_CHEAT` "key" pressed.

## Graphics Processing Unit

Offset | Size | Description
--- | --- | ---
0007E | 1 | UNICODE code point upper bits for font glyph mapping
0007F | 1 | sprite bank selector for the map
00080 | 1024 | palette, 256 colors, each entry 4 bytes, RGBA
00480 | 2 | x0, crop area X start in pixels (for all drawing functions)
00482 | 2 | x1, crop area X end in pixels
00484 | 2 | y0, crop area Y start in pixels
00486 | 2 | y1, crop area Y end in pixels
00488 | 2 | displayed vram X offset in pixels or 0xffff
0048A | 2 | displayed vram Y offset in pixels or 0xffff
0048C | 1 | turtle pen down flag (see up, down)
0048D | 1 | turtle pen color, palette index 0 to 255 (see color)
0048E | 2 | turtle direction in degrees, 0 to 359 (see left, right)
00490 | 2 | turtle X offset in pixels (see move)
00492 | 2 | turtle Y offset in pixels
00494 | 2 | maze walking speed in 1/128 tiles (see maze)
00496 | 2 | maze rotating speed in degrees (1 to 90)
00498 | 1 | console foreground color, palette index 0 to 255 (see printf)
00499 | 1 | console background color, palette index 0 to 255
0049A | 2 | console X offset in pixels
0049C | 2 | console Y offset in pixels
0049E | 2 | camera X offset in 3D space (see tri3d, tritx, mesh)
004A0 | 2 | camera Y offset
004A2 | 2 | camera Z offset
004A4 | 2 | camera direction, pitch (0 up, 90 forward)
004A6 | 2 | camera direction, yaw (0 left, 90 forward)
004A8 | 1 | camera field of view in angles (45, negative gives orthographic)
004AA | 2 | light source position X offset (see tri3d, tritx, mesh)
004AC | 2 | light source position Y offset
004AE | 2 | light source position Z offset
00600 | 64000 | map, 320 x 200 sprite indices (see map and maze)
10000 | 65536 | sprites, 256 x 256 palette indices, 1024 8 x 8 pixels (see spr)
28000 | 32768 | window for 4096 font glyphs (see 0007E, width and text)

## Digital Signal Processor

Offset | Size | Description
--- | --- | ---
0007C | 1 | waveform bank selector (1 to 31)
0007D | 1 | music track bank selector (0 to 7)
004BA | 1 | current tempo (in ticks per row, read-only)
004BB | 1 | current track being played (read-only)
004BC | 2 | current row being played (read-only)
004BE | 2 | number of total rows in current track (read-only)
004C0 | 64 | 16 channel status registers, each 4 bytes (read-only)
00500 | 256 | 64 sound effects, each 4 bytes
20000 | 16384 | window for waveform samples (see 0007C)
24000 | 16384 | window for music patterns (see 0007D)

The DSP status registers are all read-only, and for each channel they look like:

Offset | Size | Description
--- | --- | ---
0 | 2 | current position in the waveform being played
2 | 1 | current waveform (1 to 31, 0 if the channel is silent)
3 | 1 | current volume (0 means channel is turned off)

The first 4 channels are for the music, the rest for the sound effects.

Note that the waveform index 0 means "use the previous waveform", so index 0 cannot be used in the selector. The format of every other waveform:

Offset | Size | Description
--- | --- | ---
0 | 2 | number of samples
2 | 2 | loop start
4 | 2 | loop length
6 | 1 | finetune value, -8 to 7
7 | 1 | volume, 0 to 64
8 | 16376 | signed 8-bit mono samples

The format of the sound effects and the music tracks are the same, the only difference is, music tracks have 4 notes per row, one for each channel, and there are 1024 rows; while for sound effects there's only one note and 64 rows.

Offset | Size | Description
--- | --- | ---
0 | 1 | note number, see `NOTE_x` defines, 0 to 96
1 | 1 | waveform index, 0 to 31
2 | 1 | effect type, 0 to 255 (see note effects)
3 | 1 | effect parameter

The counting of notes goes as follows: 0 means no note set. Followed by 8 octaves, each with 12 notes, so 1 equals to C-0, 12 is B-0 (on the lowest octave), 13 is C-1 (one octave higher) and 14 is C#1 (C sharp, semitone higher). For example the D note on the 4th octave would be 1 + 4*12 + 2 = 51. The B-7 is 96, the highest note on the highest octave. You also have built-in defines, for example C-1 is `NOTE_C_1` and C#1 is `NOTE_Cs1`, if you don't want to count then you can use these as well in your program.

## Note Effects

For simplicity, MEG-4 uses the same codes as the Amiga MOD file (this way you'll see the same in the built-in editor as well as in a third party music tracker), but it does not support all of them. As said earlier, these codes are represented by three hex numbers, the first being the type `t`, and the last two the parameter, `xy` (or `xx`). The types `E1` to `ED` are all stored in the type byte, although it looks like one of their nibble might belong to the parameter, but it's not.

Effect | Code | Description
--- | --- | ---
... | 000 | No effect
Arp | 0xy | Arpeggio, play note, note+x semitone and note+y semitone
Po/ | 1xx | Portamento up, slide period by x up
Po\ | 2xx | Portamento down, slide period by x down
Ptn | 3xx | Tone portamento, slide period to period x
Vib | 4xy | Vibrato, oscillate the pitch by y semitones at x freq
Ctv | 5xy | Continue Tone portamento + volume slide by x up or y down
Cvv | 6xy | Continue Vibrato + volume slide by x up or by y down
Trm | 7xy | Tremolo, oscillate the volume by y amplitude at x freq
Ofs | 9xx | Set sample offset to x * 256
Vls | Axy | Slide volume by x up or by y down
Jmp | Bxx | Position jump, set row to x * 64
Vol | Cxx | Set volume to x
Fp/ | E1x | Fine portamento up, increase period by x
Fp\ | E2x | Fine portamento down, decrease period by x
Svw | E4x | Set vibrato waveform, 0 sine, 1 saw, 2 square, 3 noise
Ftn | E5x | Set finetune, change tuning by x (-8 to 7)
Stw | E7x | Set tremolo waveform, 0 sine, 1 saw, 2 square, 3 noise
Rtg | E9x | Retrigger note, trigger current sample every x ticks
Fv/ | EAx | Fine volume slide up, increase by x
Fv\ | EBx | Fine volume slide down, decrease by x
Cut | ECx | Cut note in x ticks
Dly | EDx | Delay note in x ticks
Tpr | Fxx | Set number of ticks per row to x (tick defalts to 6)

## User Memory

Memory addresses from 00000 to 2FFFF belong to the MMIO, everything above (starting from 30000 or `MEM_USER`) is freely usable user memory.

Offset | Size | Description
--- | --- | ---
30000 | 4 | (BASIC only) offset of DATA
30004 | 4 | (BASIC only) current READ counter
30008 | 4 | (BASIC only) maximum READ, number of DATA

This is followed by the global variables that you have declared in your program, followed by the constants, like string literals. In case of BASIC, then this is followed by the actual DATA records.

Memory addresses above the initialized data can be dynamically allocated and freed in your program via the malloc and free calls.

Lastly the stack, which is at the top (starting from C0000 or `MEM_LIMIT`) and growing downwards. Your program's local variables (that you declared inside a function) go here. The size of the stack always changes depending on which function calls which other function in your program.

If by any chance the top of the dynamically allocated data and the bottom of the stack would overlap, then MEG-4 throws an "Out of memory" error.

## Format String

Some functions, printf, sprintf and trace use a format string that may contain special characters to reference arguments and to describe how to display them. These are:

Code | Description
--- | ---
`%%` | The `%` character
`%d` | Next parameter as a decimal number
`%u` | Next parameter as an unsigned decimal number
`%x` | Next parameter as a hexadecimal number
`%o` | Next parameter as an octal number
`%b` | Next parameter as a binary number
`%f` | Next parameter as a floating point number
`%s` | Next parameter as a string
`%c` | Next parameter as an UTF-8 character
`%p` | Next parameter as an address (pointer)
`\t` | Tab, fix vertical position before continue
`\n` | Start a new line

You can add padding by specifying the length between `%` and the code. If that starts with `0`, then value will be padded with zeros, otherwise with spaces. For example `%4d` will pad the value to the right with spaces, and `%04x` with zeros. The `f` accepts a number after a dot, which tells the number of digits in the fractional part (up to 8), eg. `%.6f`.

## 3D Space

In MEG-4, the 3 dimensional space is handled according to the right-hand rule: +X is on the right, +Y is up, and +Z is towards the viewer.

      +Y
       |
       |__ +X
      /
    +Z

Each point must be placed in the range -32767 to +32767. How this 3D world is projected to your 2D screen depends on how you configure the camera (see Graphics Processing Unit address 0049E). Of course, you have to place the camera in the world, with X, Y, Z coordinates. Then you have to tell where the camera is looking at, using pitch and yaw. Finally you also have to tell what kind of lens the camera has, by specifying the field of view angle. That latter normally should be between 30 (very narrow) and 180 degrees (like fish and birds). MEG-4 supports up to 127 degrees, but there's a trick. Positive FOV values will be projected as perspective (the farther the object is, the smaller it is), but negative values also handled, just with orthographic projection (no matter the distance, the object's size will be the same). Perspective is used in FPS games, while the orthographic projection is mostly preferred by strategy games.

You can display a set of triangles (a complete 3D model) using the mesh function efficiently. Because models probably have local coordinates, that would draw all models one on top of another around the origo. So if you want to dispay multiple models in the world, first you should translate them (place them) into world coordinates using trns, and then use the translated vertex cloud with mesh (moving and rotating the model around won't change the triangles, just their vertex coordinates).

## Code Editor Shortcuts

Additional keyboard shortcuts you can use when editing the source:

Key | Description
--- | ---
`Ctrl`+`F` | Find string
`Ctrl`+`G` | Find again
`Ctrl`+`H` | Search and replace (in the selected text, or in lack of that, in the entire source)
`Ctrl`+`J` | Go to line
`Ctrl`+`D` | Go to function definition
`Ctrl`+`N` | List bookmarks
`Ctrl`+`B` | Toggle bookmark on current line
`Ctrl`+`▴` | Go to previous bookmark
`Ctrl`+`▾` | Go to next bookmark
`Ctrl`+`◂` | Go to the beginning of the previous word
`Ctrl`+`▸` | Go to the end of the next word
`Ctrl`+`,` | Decrease indentation of selection
`Ctrl`+`.` | Increase indentation of selection
`Home` | Move cursor to the beginning of the line
`End` | Move cursor to the end of the line
`PgUp` | Move cursor 42 lines (one page) up
`PgDown` | Move cursor 42 lines (one page) down
`F1` | If the cursor is in an API's argument list, then go to function's built-in help page

Regardless to platform's keyboard layout, all characters required for programing (and some more) can always be accessed:

Left `Alt` +
`` `(` `)` `{` `}` `〈` `〉` `!` `^` `_` `-` `=`
`⇥` `` `` `€` `₹` `~` `¥` `` `` `°` `"` `[` `]`
`↨` `&` `$` `@` `¦` `` `#` `` `` `£` `;` `'` `\`
`⇮` `:` `?` `` `元` `%` `+` `✶` `,` `.` `/`

See also the menu for alternative input methods and their keyboard shortcuts.

PreviousNext

# Console

## putc

    1

`void putc(uint32_t chr)`

Description
  Prints a character to console.
Parameters

  Argument | Description
  --- | ---
  chr | UTF-8 character

## printf

    1

`void printf(str_t fmt, ...)`

Description
  Prints text to console.
Parameters

  Argument | Description
  --- | ---
  fmt | string to display, a format string
  ... | optional arguments

## getc

    1

`uint32_t getc(void)`

Description
  Reads a character from console, blocks program when there's no input.
Return Value
  An UTF-8 character the user entered.
See Also
  popkey

## gets

    1

`str_t gets(void)`

Description
  Reads in a newline terminated string from user (does not return the newline).
Return Value
  The bytes read in a string.

## trace

    1

`void trace(str_t fmt, ...)`

Description
  Trace execution by printing to stdout. Only works if `meg4` was started with the `-v` verbose flag.
Parameters

  Argument | Description
  --- | ---
  fmt | format string
  ... | optional arguments

## delay

    1

`void delay(uint16_t msec)`

Description
  Delays program execution.
Parameters

  Argument | Description
  --- | ---
  msec | delay in milliseconds

## exit

    1

`void exit(void)`

Description
  Exits program.

PreviousNext

# Audio

## sfx

    1

`void sfx(uint8_t sfx, uint8_t channel, uint8_t volume)`

Description
  Plays a sound effect.
Parameters

  Argument | Description
  --- | ---
  sfx | the index of the sound effect, 0 to 63
  channel | channel to be used, 0 to 11
  volume | volume to be used, 0 to 255, 0 turns off channel

## music

    1

`void music(uint8_t track, uint16_t row, uint8_t volume)`

Description
  Plays a music track.
Parameters

  Argument | Description
  --- | ---
  track | the index of the music track, 0 to 7
  row | row to start playing from, 0 to 1023 (max song length)
  volume | volume to be used, 0 to 255, 0 turns off music

PreviousNext

# GPIO

## gpio_rev

    1

`uint32_t gpio_rev(void)`

Description
  Query the GPIO board's revision number. Returns 0 if the platform isn't GPIO capable.
Return Value
  Board's revision number or 0 if not supported.

## gpio_get

    1

`int gpio_get(uint8_t pin)`

Description
  Read the value of a GPIO pin.
Parameters

  Argument | Description
  --- | ---
  pin | physical pin number, 1 to 40

Return Value
  Returns 1 if the pin is high, 0 if it's low, -1 on error (GPIO pin not supported).
See Also
  gpio_set

## gpio_set

    1

`int gpio_set(uint8_t pin, int value)`

Description
  Write the value to a GPIO pin.
Parameters

  Argument | Description
  --- | ---
  pin | physical pin number, 1 to 40
  value | 1 to set the pin high, 0 for low

Return Value
  Returns 0 on success, -1 on error (GPIO pin not supported).
See Also
  gpio_get

PreviousNext

# Graphics

## cls

    1

`void cls(uint8_t palidx)`

Description
  Clears the entire screen and resets display offsets, also sets the console's background color.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255

See Also
  pget, pset

## cget

    1

`uint32_t cget(uint16_t x, uint16_t y)`

Description
  Get pixel at a coordinate and return color RGBA.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels
  y | Y coordinate in pixels

Return Value
  A packed color, with RGBA channels (red is in the least significant byte).
See Also
  cls, pget, pset

## pget

    1

`uint8_t pget(uint16_t x, uint16_t y)`

Description
  Get pixel at a coordinate and return its palette index.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels
  y | Y coordinate in pixels

Return Value
  Color in palette index, 0 to 255.
See Also
  cls, pset, cget

## pset

    1

`void pset(uint8_t palidx, uint16_t x, uint16_t y)`

Description
  Plots a pixel at a coordinate.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x | X coordinate in pixels
  y | Y coordinate in pixels

See Also
  cls, pget

## width

    1

`uint16_t width(int8_t type, str_t str)`

Description
  Returns displayed text's width in pixels.
Parameters

  Argument | Description
  --- | ---
  type | font type, -4 to 4
  str | string to measure

Return Value
  Number of pixels required to display text.
See Also
  text

## text

    1

`void text(uint8_t palidx, int16_t x, int16_t y, int8_t type, uint8_t shidx, uint8_t sha, str_t str)`

Description
  Prints text on screen.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x | X coordinate in pixels
  y | Y coordinate in pixels
  type | font type, -4 to -1 monospace, 1 to 4 proportional
  shidx | shadow's color, palette index 0 to 255
  sha | shadow's alpha, 0 (fully transparent) to 255 (fully opaque)
  str | string to display

See Also
  width

## line

    1

`void line(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1)`

Description
  Draws an anti-aliased line.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | starting X coordinate in pixels
  y0 | starting Y coordinate in pixels
  x1 | ending X coordinate in pixels
  y1 | ending Y coordinate in pixels

See Also
  qbez, cbez

## qbez

    1
    2

`void qbez(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t cx, int16_t cy)`

Description
  Draws a quadratic Bezier curve.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | starting X coordinate in pixels
  y0 | starting Y coordinate in pixels
  x1 | ending X coordinate in pixels
  y1 | ending Y coordinate in pixels
  cx | control point X coordinate in pixels
  cy | control point Y coordinate in pixels

See Also
  line, cbez

## cbez

    1
    2

`void cbez(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t cx0, int16_t cy0, int16_t cx1, int16_t cy1)`

Description
  Draws a cubic Bezier curve.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | starting X coordinate in pixels
  y0 | starting Y coordinate in pixels
  x1 | ending X coordinate in pixels
  y1 | ending Y coordinate in pixels
  cx0 | first control point X coordinate in pixels
  cy0 | first control point Y coordinate in pixels
  cx1 | second control point X coordinate in pixels
  cy1 | second control point Y coordinate in pixels

See Also
  line, qbez

## tri

    1

`void tri(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)`

Description
  Draws a triangle.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | first edge X coordinate in pixels
  y0 | first edge Y coordinate in pixels
  x1 | second edge X coordinate in pixels
  y1 | second edge Y coordinate in pixels
  x2 | third edge X coordinate in pixels
  y2 | third edge Y coordinate in pixels

See Also
  ftri, tri2d, tri3d, tritx, mesh, trns

## ftri

    1

`void ftri(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)`

Description
  Draws a filled triangle.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | first edge X coordinate in pixels
  y0 | first edge Y coordinate in pixels
  x1 | second edge X coordinate in pixels
  y1 | second edge Y coordinate in pixels
  x2 | third edge X coordinate in pixels
  y2 | third edge Y coordinate in pixels

See Also
  tri, tri2d, tri3d, tritx, mesh, trns

## tri2d

    1
    2
    3

`void tri2d(uint8_t pi0, int16_t x0, int16_t y0, uint8_t pi1, int16_t x1, int16_t y1, uint8_t pi2, int16_t x2, int16_t y2)`

Description
  Draws a filled triangle with color gradients.
Parameters

  Argument | Description
  --- | ---
  pi0 | first edge color, palette index 0 to 255
  x0 | first edge X coordinate in pixels
  y0 | first edge Y coordinate in pixels
  pi1 | second edge color, palette index 0 to 255
  x1 | second edge X coordinate in pixels
  y1 | second edge Y coordinate in pixels
  pi2 | third edge color, palette index 0 to 255
  x2 | third edge X coordinate in pixels
  y2 | third edge Y coordinate in pixels

See Also
  tri, ftri, tri3d, tritx, mesh, trns

## tri3d

    1
    2
    3

`void tri3d(uint8_t pi0, int16_t x0, int16_t y0, int16_t z0, uint8_t pi1, int16_t x1, int16_t y1, int16_t z1, uint8_t pi2, int16_t x2, int16_t y2, int16_t z2)`

Description
  Draws a filled triangle with color gradients in 3D space.
Parameters

  Argument | Description
  --- | ---
  pi0 | first edge color, palette index 0 to 255
  x0 | first edge X coordinate in space
  y0 | first edge Y coordinate in space
  z0 | first edge Z coordinate in space
  pi1 | second edge color, palette index 0 to 255
  x1 | second edge X coordinate in space
  y1 | second edge Y coordinate in space
  z1 | second edge Z coordinate in space
  pi2 | third edge color, palette index 0 to 255
  x2 | third edge X coordinate in space
  y2 | third edge Y coordinate in space
  z2 | third edge Z coordinate in space

See Also
  tri, ftri, tri2d, tritx, mesh, trns

## tritx

    1
    2
    3

`void tritx(uint8_t u0, uint8_t v0, int16_t x0, int16_t y0, int16_t z0, uint8_t u1, uint8_t v1, int16_t x1, int16_t y1, int16_t z1, uint8_t u2, uint8_t v2, int16_t x2, int16_t y2, int16_t z2)`

Description
  Draws a textured triangle in 3D space.
Parameters

  Argument | Description
  --- | ---
  u0 | first edge texture X coordinate 0 to 255
  v0 | first edge texture Y coordinate 0 to 255
  x0 | first edge X coordinate in space
  y0 | first edge Y coordinate in space
  z0 | first edge Z coordinate in space
  u1 | second edge texture X coordinate 0 to 255
  v1 | second edge texture Y coordinate 0 to 255
  x1 | second edge X coordinate in space
  y1 | second edge Y coordinate in space
  z1 | second edge Z coordinate in space
  u2 | third edge texture X coordinate 0 to 255
  v2 | third edge texture Y coordinate 0 to 255
  x2 | third edge X coordinate in space
  y2 | third edge Y coordinate in space
  z2 | third edge Z coordinate in space

See Also
  tri, ftri, tri2d, tri3d, mesh, trns

## mesh

    1

`void mesh(addr_t verts, addr_t uvs, uint16_t numtri, addr_t tris)`

Description
  Draws a mesh made of triangles in 3D space, using indices to vertices and texture coordinates (or palette).
Parameters

  Argument | Description
  --- | ---
  verts | address of vertices array, 3 x 2 bytes each, X, Y, Z
  uvs | address of UVs array (if 0, then palette is used), 2 x 1 bytes each, texture X, Y
  numtri | number of triangles
  tris | address of triangles array with indices, 6 x 1 bytes each, vi1, ui1/pi1, vi2, ui2/pi2, vi3, ui3/pi3

See Also
  tri, ftri, tri2d, tri3d, tritx, trns

## rect

    1

`void rect(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1)`

Description
  Draws a rectangle.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | top left corner X coordinate in pixels
  y0 | top left corner Y coordinate in pixels
  x1 | bottom right X coordinate in pixels
  y1 | bottom right Y coordinate in pixels

See Also
  frect

## frect

    1

`void frect(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1)`

Description
  Draws a filled rectangle.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | top left corner X coordinate in pixels
  y0 | top left corner Y coordinate in pixels
  x1 | bottom right X coordinate in pixels
  y1 | bottom right Y coordinate in pixels

See Also
  rect

## circ

    1

`void circ(uint8_t palidx, int16_t x, int16_t y, uint16_t r)`

Description
  Draws a circle.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x | center X coordinate in pixels
  y | center Y coordinate in pixels
  r | radius in pixels

See Also
  fcirc, ellip, fellip

## fcirc

    1

`void fcirc(uint8_t palidx, int16_t x, int16_t y, uint16_t r)`

Description
  Draws a filled circle.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x | center X coordinate in pixels
  y | center Y coordinate in pixels
  r | radius in pixels

See Also
  circ, ellip, fellip

## ellip

    1

`void ellip(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1)`

Description
  Draws an ellipse.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | top left corner X coordinate in pixels
  y0 | top left corner Y coordinate in pixels
  x1 | bottom right X coordinate in pixels
  y1 | bottom right Y coordinate in pixels

See Also
  circ, fcirc, fellip

## fellip

    1

`void fellip(uint8_t palidx, int16_t x0, int16_t y0, int16_t x1, int16_t y1)`

Description
  Draws a filled ellipse.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255
  x0 | top left corner X coordinate in pixels
  y0 | top left corner Y coordinate in pixels
  x1 | bottom right X coordinate in pixels
  y1 | bottom right Y coordinate in pixels

See Also
  circ, fcirc, ellip

## move

    1

`void move(int16_t x, int16_t y, uint16_t deg)`

Description
  Moves turtle to the given position on screen or in the maze.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels (or 1/128 tiles with maze)
  y | Y coordinate in pixels
  deg | direction in degrees, 0 to 359, 0 is upwards on screen, 90 is to the right

See Also
  left, right, up, down, color, forw, back

## left

    1

`void left(uint16_t deg)`

Description
  Turns turtle left.
Parameters

  Argument | Description
  --- | ---
  deg | change in degrees, 0 to 359

See Also
  move, right, up, down, color, forw, back

## right

    1

`void right(uint16_t deg)`

Description
  Turns turtle right.
Parameters

  Argument | Description
  --- | ---
  deg | change in degrees, 0 to 359

See Also
  move, left, up, down, color, forw, back

## up

    1

`void up(void)`

Description
  Lifts turtle's tail up. The turtle will move without drawing a line.
See Also
  move, left, right, down, color, forw, back

## down

    1

`void down(void)`

Description
  Puts turtle's tail down. The turtle will move drawing a line (see color).
See Also
  move, left, right, up, color, forw, back

## color

    1

`void color(uint8_t palidx)`

Description
  Sets turtle paint color.
Parameters

  Argument | Description
  --- | ---
  palidx | color, palette index 0 to 255

See Also
  move, left, right, up, down, forw, back

## forw

    1

`void forw(uint16_t cnt)`

Description
  Moves turtle forward.
Parameters

  Argument | Description
  --- | ---
  cnt | amount in pixels (or 1/128 tiles with maze)

See Also
  move, left, right, up, down, color, back

## back

    1

`void back(uint16_t cnt)`

Description
  Moves turtle backward.
Parameters

  Argument | Description
  --- | ---
  cnt | amount in pixels (or 1/128 tiles with maze)

See Also
  move, left, right, up, down, color, forw

## spr

    1

`void spr(int16_t x, int16_t y, uint16_t sprite, uint8_t sw, uint8_t sh, int8_t scale, uint8_t type)`

Description
  Displays a sprite, or multiple adjacent sprites.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels
  y | Y coordinate in pixels
  sprite | sprite id, 0 to 1023
  sw | number of horizontal sprites
  sh | number of vertical sprites
  scale | scale, -3 to 4
  type | transform, 0=normal, 1=rotate 90, 2=rotate 180, 3=rotate 270, 4=flip vertically, 5=flip+90, 6=flip horizontally, 7=flip+270

See Also
  dlg, stext

## dlg

    1
    2
    3
    4

`void dlg(int16_t x, int16_t y, uint16_t w, uint16_t h, int8_t scale, uint16_t tl, uint16_t tm, uint16_t tr, uint16_t ml, uint16_t bg, uint16_t mr, uint16_t bl, uint16_t bm, uint16_t br)`

Description
  Displays a dialog window using sprites.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels
  y | Y coordinate in pixels
  w | dialog width in pixels
  h | dialog height in pixels
  scale | scale, -3 to 4
  tl | top left corner sprite id
  tm | top middle sprite id
  tr | top right corner sprite id
  ml | middle left side sprite id
  bg | background sprite id
  mr | middle right side sprite id
  bl | bottom left corner sprite id
  bm | bottom middle sprite id
  br | bottom right corner sprite id

See Also
  spr, stext

## stext

    1

`void stext(int16_t x, int16_t y, uint16_t fs, uint16_t fu, uint8_t sw, uint8_t sh, int8_t scale, str_t str)`

Description
  Displays text on screen using sprites.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels
  y | Y coordinate in pixels
  fs | first sprite id to be used for displaying
  fu | first UNICODE (smallest character) in string
  sw | number of horizontal sprites
  sh | number of vertical sprites
  scale | scale, -3 to 4
  str | zero terminated UTF-8 string

See Also
  spr, dlg

## remap

    1

`void remap(addr_t replace)`

Description
  Replaces tiles on map. Can be used to animate tiles on the map.
Parameters

  Argument | Description
  --- | ---
  replace | an array of 256 sprite ids

See Also
  mget, mset, map, maze

## mget

    1

`uint16_t mget(uint16_t mx, uint16_t my)`

Description
  Returns one tile on map.
Parameters

  Argument | Description
  --- | ---
  mx | X coordinate on map in tiles
  my | Y coordinate on map in tiles

Return Value
  The sprite id of the tile at the given coordinate.
See Also
  remap, mset, map, maze

## mset

    1

`void mset(uint16_t mx, uint16_t my, uint16_t sprite)`

Description
  Sets one tile on map.
Parameters

  Argument | Description
  --- | ---
  mx | X coordinate on map in tiles
  my | Y coordinate on map in tiles
  sprite | sprite id, 0 to 1023

See Also
  remap, mget, map, maze

## map

    1

`void map(int16_t x, int16_t y, uint16_t mx, uint16_t my, uint16_t mw, uint16_t mh, int8_t scale)`

Description
  Draws (part of) the map.
Parameters

  Argument | Description
  --- | ---
  x | X coordinate in pixels
  y | Y coordinate in pixels
  mx | X coordinate on map in tiles
  my | Y coordinate on map in tiles
  mw | number of horizontal tiles
  mh | number of vertical tiles
  scale | scale, -3 to 4

See Also
  remap, mget, mset, maze

## maze

    1
    2

`void maze(uint16_t mx, uint16_t my, uint16_t mw, uint16_t mh, uint8_t scale, uint16_t sky, uint16_t grd, uint16_t door, uint16_t wall, uint16_t obj, uint8_t numnpc, addr_t npc)`

Description
  Displays map as a 3D maze, using turtle's position.
Parameters

  Argument | Description
  --- | ---
  mx | X coordinate on map in tiles
  my | Y coordinate on map in tiles
  mw | number of horizontal tiles
  mh | number of vertical tiles
  scale | number of sprites per tiles in power of two, 0 to 3
  sky | sky tile index
  grd | ground tile index
  door | first door tile index
  wall | first wall tile index
  obj | first object tile index
  numnpc | number of NPC records
  npc | an uint32_t array of numnpc times x,y,tile index triplets

See Also
  remap, mget, mset, map

PreviousNext

# Input

## getpad

    1

`int getpad(int pad, int btn)`

Description
  Gets the current state of a gamepad button.
Parameters

  Argument | Description
  --- | ---
  pad | gamepad index, 0 to 3
  btn | one of the gamepad buttons, `BTN_`

Return Value
  Zero if not pressed, non-zero if pressed.
See Also
  prspad, relpad, getbtn, getclk, getkey

## prspad

    1

`int prspad(int pad, int btn)`

Description
  Returns true if gamepad button was pressed since last call.
Parameters

  Argument | Description
  --- | ---
  pad | gamepad index, 0 to 3
  btn | one of the gamepad buttons, `BTN_`

Return Value
  Zero if not pressed, non-zero if pressed.
See Also
  relpad, getpad, getbtn, getclk, getkey

## relpad

    1

`int relpad(int pad, int btn)`

Description
  Returns true if gamepad button was released since last call.
Parameters

  Argument | Description
  --- | ---
  pad | gamepad index, 0 to 3
  btn | one of the gamepad buttons, `BTN_`

Return Value
  Zero if wasn't released, non-zero if released.
See Also
  prspad, getpad, getbtn, getclk, getkey

## getbtn

    1

`int getbtn(int btn)`

Description
  Gets the mouse buttons state.
Parameters

  Argument | Description
  --- | ---
  btn | one of the pointer buttons, `BTN_` or `SCR_`

Return Value
  Zero if not pressed, non-zero if pressed.
See Also
  prspad, relpad, getpad, getclk, getkey

## getclk

    1

`int getclk(int btn)`

Description
  Gets mouse button clicking.
Parameters

  Argument | Description
  --- | ---
  btn | one of the pointer buttons, `BTN_`

Return Value
  Zero if not clicked, non-zero if clicked.
See Also
  prspad, relpad, getpad, getbtn, getkey

## getkey

    1

`int getkey(int sc)`

Description
  Gets the current state of a key.
Parameters

  Argument | Description
  --- | ---
  sc | scancode, 1 to 144, see keyboard

Return Value
  Zero if not pressed, non-zero if pressed.
See Also
  prspad, relpad, getpad, getbtn, getclk

## popkey

    1

`uint32_t popkey(void)`

Description
  Pop an UTF-8 key from the keyboard queue. See keyboard, and for the blocking version getc.
Return Value
  The UTF-8 representation of the key, or 0 if the queue was empty (no blocking).
See Also
  pendkey, lenkey, speckey, getc

## pendkey

    1

`int pendkey(void)`

Description
  Returns true if there's a key pending in the queue (but leaves the key in the queue, does not pop it).
Return Value
  Returns 1 if there are keys in the queue pending.
See Also
  popkey, lenkey, speckey

## lenkey

    1

`int lenkey(uint32_t key)`

Description
  Returns the length of a UTF-8 key in bytes.
Parameters

  Argument | Description
  --- | ---
  key | the key, popped from the queue

Return Value
  UTF-8 representation's length in bytes.
See Also
  popkey, pendkey, speckey

## speckey

    1

`int speckey(uint32_t key)`

Description
  Returns true if key is a special key.
Parameters

  Argument | Description
  --- | ---
  key | the key, popped from the queue

Return Value
  Returns 1 if it's a special key, and 0 if it's a printable one.
See Also
  popkey, pendkey, lenkey

PreviousNext

# Mathematics

## rand

    1

`uint32_t rand(void)`

Description
  Get random. Use `%` modulo to make it smaller, for example `1 + rand() % 6` returns random between 1 and 6, like a dice.
Return Value
  A random number between 0 and 232-1 (4294967295).
See Also
  rnd

## rnd

    1

`float rnd(void)`

Description
  Get random. Same as rand, but returns a floating point number.
Return Value
  A random number between 0.0 and 1.0.
See Also
  rand

## float

    1

`float float(int val)`

Description
  Returns the floating point equivalent of an integer number.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  The floating point of value.
See Also
  int

## int

    1

`int int(float val)`

Description
  Returns the integer equivalent of a floating point number.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  The integer of value.
See Also
  float

## floor

    1

`float floor(float val)`

Description
  Returns the largest integral number that's not greater than value.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  The floor of value.
See Also
  ceil

## ceil

    1

`float ceil(float val)`

Description
  Returns the smallest integral number that's not less than value.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  The ceiling of value.
See Also
  floor

## sgn

    1

`float sgn(float val)`

Description
  Returns the sign of the value.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  Either 1.0 or -1.0.
See Also
  abs

## abs

    1

`float abs(float val)`

Description
  Returns the absolute of the value.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  Either value or -value, always positive.
See Also
  sgn

## exp

    1

`float exp(float val)`

Description
  Returns the exponential of the value, i.e. base of natural logarithms raised to power of the value.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  Returns eval.
See Also
  log, pow

## log

    1

`float log(float val)`

Description
  Returns the natural logarithm of the value.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  Returns natural logarithm of value.
See Also
  exp

## pow

    1

`float pow(float val, float exp)`

Description
  Returns the value raised to the power of exponent. This is a slow operation, try to avoid.
Parameters

  Argument | Description
  --- | ---
  val | value
  exp | exponent

Return Value
  Returns valexp.
See Also
  exp, sqrt, rsqrt

## sqrt

    1

`float sqrt(float val)`

Description
  Returns the square root of the value. This is a slow operation, try to avoid.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  Square root of the value.
See Also
  pow, rsqrt

## rsqrt

    1

`float rsqrt(float val)`

Description
  Returns the reciprocal of the square root of the value (`1 / sqrt(val)`). Uses John Carmack's fast method.
Parameters

  Argument | Description
  --- | ---
  val | value

Return Value
  Reciprocal of the square root of the value.
See Also
  pow, sqrt

## clamp

    1

`float clamp(float val, float minv, float maxv)`

Description
  Clamps a value between the limits.
Parameters

  Argument | Description
  --- | ---
  val | value
  minv | minimum value
  maxv | maximum value

Return Value
  Clamped value.
See Also
  clampv2, clampv3, clampv4

## lerp

    1

`float lerp(float a, float b, float t)`

Description
  Linear interpolates two numbers.
Parameters

  Argument | Description
  --- | ---
  a | first float number
  b | second float number
  t | interpolation value between 0.0 and 1.0

See Also
  lerpv2, lerpv3, lerpv4, lerpq, slerpq

## pi

    1

`float pi(void)`

Description
  Returns π as a floating point number.
Return Value
  The value 3.14159265358979323846.

## cos

    1

`float cos(uint16_t deg)`

Description
  Returns cosine.
Parameters

  Argument | Description
  --- | ---
  deg | degree, 0 to 359, 0 is up, 90 on the right

Return Value
  Cosine of the degree, between -1.0 to 1.0.
See Also
  sin, tan, acos, asin, atan, atan2

## sin

    1

`float sin(uint16_t deg)`

Description
  Returns sine.
Parameters

  Argument | Description
  --- | ---
  deg | degree, 0 to 359, 0 is up, 90 to the right

Return Value
  Sine of the degree, between -1.0 to 1.0.
See Also
  cos, tan, acos, asin, atan, atan2

## tan

    1

`float tan(uint16_t deg)`

Description
  Returns tangent.
Parameters

  Argument | Description
  --- | ---
  deg | degree, 0 to 359, 0 is up, 90 to the right

Return Value
  Tangent of the degree, between -1.0 to 1.0.
See Also
  cos, sin, acos, asin, atan, atan2

## acos

    1

`uint16_t acos(float val)`

Description
  Returns arcus cosine.
Parameters

  Argument | Description
  --- | ---
  val | value, -1.0 to 1.0

Return Value
  Arcus cosine in degree, 0 to 359, 0 is up, 90 to the right.
See Also
  cos, sin, tan, asin, atan, atan2

## asin

    1

`uint16_t asin(float val)`

Description
  Returns arcus sine.
Parameters

  Argument | Description
  --- | ---
  val | value, -1.0 to 1.0

Return Value
  Arcus sine in degree, 0 to 359, 0 is up, 90 to the right.
See Also
  cos, sin, tan, acos, atan, atan2

## atan

    1

`uint16_t atan(float val)`

Description
  Returns arcus tangent.
Parameters

  Argument | Description
  --- | ---
  val | value, -1.0 to 1.0

Return Value
  Arcus tangent in degree, 0 to 359, 0 is up, 90 to the right.
See Also
  cos, sin, tan, acos, asin, atan2

## atan2

    1

`uint16_t atan2(float y, float x)`

Description
  Returns arcus tangent for y/x, using the signs of y and x to determine the quadrant.
Parameters

  Argument | Description
  --- | ---
  y | Y coordinate
  x | X coordinate

Return Value
  Arcus tangent in degree, 0 to 359, 0 is up, 90 to the right.
See Also
  cos, sin, tan, acos, asin

## dotv2

    1

`float dotv2(addr_t a, addr_t b)`

Description
  Calculates dot product of two vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  a | address of two floats
  b | address of two floats

Return Value
  Dot product of the vectors.
See Also
  lenv2, scalev2, negv2, addv2, subv2, mulv2, divv2, clampv2, lerpv2, normv2

## lenv2

    1

`float lenv2(addr_t a)`

Description
  Calculates the length of a vector with two elements. This is slow, try to avoid (see normv2).
Parameters

  Argument | Description
  --- | ---
  a | address of two floats

Return Value
  Length of the vector.
See Also
  dotv2, scalev2, negv2, addv2, subv2, mulv2, divv2, clampv2, lerpv2, normv2

## scalev2

    1

`void scalev2(addr_t a, float s)`

Description
  Scales a vector with two elements.
Parameters

  Argument | Description
  --- | ---
  a | address of two floats
  s | scaler value

See Also
  dotv2, lenv2, negv2, addv2, subv2, mulv2, divv2, clampv2, lerpv2, normv2

## negv2

    1

`void negv2(addr_t a)`

Description
  Negates a vector with two elements.
Parameters

  Argument | Description
  --- | ---
  a | address of two floats

See Also
  dotv2, lenv2, scalev2, addv2, subv2, mulv2, divv2, clampv2, lerpv2, normv2

## addv2

    1

`void addv2(addr_t dst, addr_t a, addr_t b)`

Description
  Adds together vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of two floats
  a | address of two floats
  b | address of two floats

See Also
  dotv2, lenv2, scalev2, negv2, subv2, mulv2, divv2, clampv2, lerpv2, normv2

## subv2

    1

`void subv2(addr_t dst, addr_t a, addr_t b)`

Description
  Subtracts vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of two floats
  a | address of two floats
  b | address of two floats

See Also
  dotv2, lenv2, scalev2, negv2, addv2, mulv2, divv2, clampv2, lerpv2, normv2

## mulv2

    1

`void mulv2(addr_t dst, addr_t a, addr_t b)`

Description
  Multiplies vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of two floats
  a | address of two floats
  b | address of two floats

See Also
  dotv2, lenv2, scalev2, negv2, addv2, subv2, divv2, clampv2, lerpv2, normv2

## divv2

    1

`void divv2(addr_t dst, addr_t a, addr_t b)`

Description
  Divides vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of two floats
  a | address of two floats
  b | address of two floats

See Also
  dotv2, lenv2, scalev2, negv2, addv2, subv2, mulv2, clampv2, lerpv2, normv2

## clampv2

    1

`void clampv2(addr_t dst, addr_t v, addr_t minv, addr_t maxv)`

Description
  Clamps vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of two floats
  v | address of two floats, input
  minv | address of two floats, minimum
  maxv | address of two floats, maximum

See Also
  dotv2, lenv2, scalev2, negv2, addv2, subv2, mulv2, divv2, lerpv2, normv2

## lerpv2

    1

`void lerpv2(addr_t dst, addr_t a, addr_t b, float t)`

Description
  Linear interpolates vectors with two elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of two floats
  a | address of two floats
  b | address of two floats
  t | interpolation value between 0.0 and 1.0

See Also
  dotv2, lenv2, scalev2, negv2, addv2, subv2, mulv2, divv2, clampv2, normv2

## normv2

    1

`void normv2(addr_t a)`

Description
  Normalizes a vector with two elements.
Parameters

  Argument | Description
  --- | ---
  a | address of two floats

See Also
  dotv2, lenv2, scalev2, negv2, addv2, subv2, mulv2, divv2, clampv2, lerpv2

## dotv3

    1

`float dotv3(addr_t a, addr_t b)`

Description
  Calculates dot product of two vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  a | address of three floats
  b | address of three floats

Return Value
  Dot product of the vectors.
See Also
  lenv3, scalev3, negv3, addv3, subv3, mulv3, divv3, crossv3, clampv3, lerpv3, normv3

## lenv3

    1

`float lenv3(addr_t a)`

Description
  Calculates the length of a vector with three elements. This is slow, try to avoid (see normv3).
Parameters

  Argument | Description
  --- | ---
  a | address of three floats

Return Value
  Length of the vector.
See Also
  dotv3, scalev3, negv3, addv3, subv3, mulv3, divv3, crossv3, clampv3, lerpv3, normv3

## scalev3

    1

`void scalev3(addr_t a, float s)`

Description
  Scales a vector with three elements.
Parameters

  Argument | Description
  --- | ---
  a | address of three floats
  s | scaler value

See Also
  dotv3, lenv3, negv3, addv3, subv3, mulv3, divv3, crossv3, clampv3, lerpv3, normv3

## negv3

    1

`void negv3(addr_t a)`

Description
  Negates a vector with three elements.
Parameters

  Argument | Description
  --- | ---
  a | address of three floats

See Also
  dotv3, lenv3, scalev3, addv3, subv3, mulv3, divv3, crossv3, clampv3, lerpv3, normv3

## addv3

    1

`void addv3(addr_t dst, addr_t a, addr_t b)`

Description
  Adds together vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  a | address of three floats
  b | address of three floats

See Also
  dotv3, lenv3, scalev3, negv3, subv3, mulv3, divv3, crossv3, clampv3, lerpv3, normv3

## subv3

    1

`void subv3(addr_t dst, addr_t a, addr_t b)`

Description
  Subtracts vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  a | address of three floats
  b | address of three floats

See Also
  dotv3, lenv3, scalev3, negv3, addv3, mulv3, divv3, crossv3, clampv3, lerpv3, normv3

## mulv3

    1

`void mulv3(addr_t dst, addr_t a, addr_t b)`

Description
  Multiplies vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  a | address of three floats
  b | address of three floats

See Also
  dotv3, lenv3, scalev3, negv3, addv3, subv3, divv3, crossv3, clampv3, lerpv3, normv3

## divv3

    1

`void divv3(addr_t dst, addr_t a, addr_t b)`

Description
  Divides vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  a | address of three floats
  b | address of three floats

See Also
  dotv3, lenv3, scalev3, negv3, addv3, subv3, mulv3, crossv3, clampv3, lerpv3, normv3

## crossv3

    1

`void crossv3(addr_t dst, addr_t a, addr_t b)`

Description
  Calculates cross product of vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  a | address of three floats
  b | address of three floats

See Also
  dotv3, lenv3, scalev3, negv3, addv3, subv3, mulv3, divv3, clampv3, lerpv3, normv3

## clampv3

    1

`void clampv3(addr_t dst, addr_t v, addr_t minv, addr_t maxv)`

Description
  Clamps vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  v | address of three floats, input
  minv | address of three floats, minimum
  maxv | address of three floats, maximum

See Also
  dotv3, lenv3, scalev3, negv3, addv3, subv3, mulv3, divv3, crossv3, lerpv3, normv3

## lerpv3

    1

`void lerpv3(addr_t dst, addr_t a, addr_t b, float t)`

Description
  Linear interpolates vectors with three elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  a | address of three floats
  b | address of three floats
  t | interpolation value between 0.0 and 1.0

See Also
  dotv3, lenv3, scalev3, negv3, addv3, subv3, mulv3, divv3, crossv3, clampv3, normv3

## normv3

    1

`void normv3(addr_t a)`

Description
  Normalizes a vector with three elements.
Parameters

  Argument | Description
  --- | ---
  a | address of three floats

See Also
  dotv3, lenv3, scalev3, negv3, addv3, subv3, mulv3, divv3, crossv3, clampv3, lerpv3

## dotv4

    1

`float dotv4(addr_t a, addr_t b)`

Description
  Calculates dot product of two vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats
  b | address of four floats

Return Value
  Dot product of the vectors.
See Also
  lenv4, scalev4, negv4, addv4, subv4, mulv4, divv4, clampv4, lerpv4, normv4

## lenv4

    1

`float lenv4(addr_t a)`

Description
  Calculates the length of a vector with four elements. This is slow, try to avoid (see normv4).
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

Return Value
  Length of the vector.
See Also
  dotv4, scalev4, negv4, addv4, subv4, mulv4, divv4, clampv4, lerpv4, normv4

## scalev4

    1

`void scalev4(addr_t a, float s)`

Description
  Scales a vector with four elements.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats
  s | scaler value

See Also
  dotv4, lenv4, negv4, addv4, subv4, mulv4, divv4, clampv4, lerpv4, normv4

## negv4

    1

`void negv4(addr_t a)`

Description
  Negates a vector with four elements.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

See Also
  dotv4, lenv4, scalev4, addv4, subv4, mulv4, divv4, clampv4, lerpv4, normv4

## addv4

    1

`void addv4(addr_t dst, addr_t a, addr_t b)`

Description
  Adds together vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  dotv4, lenv4, negv4, scalev4, subv4, mulv4, divv4, clampv4, lerpv4, normv4

## subv4

    1

`void subv4(addr_t dst, addr_t a, addr_t b)`

Description
  Subtracts vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  dotv4, lenv4, scalev4, negv4, addv4, mulv4, divv4, clampv4, lerpv4, normv4

## mulv4

    1

`void mulv4(addr_t dst, addr_t a, addr_t b)`

Description
  Multiplies vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  dotv4, lenv4, scalev4, negv4, addv4, subv4, divv4, clampv4, lerpv4, normv4

## divv4

    1

`void divv4(addr_t dst, addr_t a, addr_t b)`

Description
  Divides vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  dotv4, lenv4, scalev4, negv4, addv4, subv4, mulv4, clampv4, lerpv4, normv4

## clampv4

    1

`void clampv4(addr_t dst, addr_t v, addr_t minv, addr_t maxv)`

Description
  Clamps vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  v | address of four floats, input
  minv | address of four floats, minimum
  maxv | address of four floats, maximum

See Also
  dotv4, lenv4, scalev4, negv4, addv4, subv4, mulv4, divv4, lerpv4, normv4

## lerpv4

    1

`void lerpv4(addr_t dst, addr_t a, addr_t b, float t)`

Description
  Linear interpolates vectors with four elements.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats
  t | interpolation value between 0.0 and 1.0

See Also
  dotv4, lenv4, scalev4, negv4, addv4, subv4, mulv4, divv4, clampv4, normv4

## normv4

    1

`void normv4(addr_t a)`

Description
  Normalizes a vector with four elements.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

See Also
  dotv4, lenv4, scalev4, negv4, addv4, subv4, mulv4, divv4, clampv4, lerpv4

## idq

    1

`void idq(addr_t a)`

Description
  Loads the identity quaternion.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

See Also
  eulerq, dotq, lenq, scaleq, negq, addq, subq, mulq, rotq, lerpq, slerpq, normq

## eulerq

    1

`void eulerq(addr_t dst, uint16_t pitch, uint16_t yaw, uint16_t roll)`

Description
  Loads a quaternion using Euler angles.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  pitch | rotation around X axis in degrees, 0 to 359
  yaw | rotation around Y axis in degrees, 0 to 359
  roll | rotation around Z axis in degrees, 0 to 359

See Also
  idq, dotq, lenq, scaleq, negq, addq, subq, mulq, rotq, lerpq, slerpq, normq

## dotq

    1

`float dotq(addr_t a, addr_t b)`

Description
  Calculates dot product of a quaternion.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats
  b | address of four floats

Return Value
  Dot product of the quaternion.
See Also
  idq, eulerq, lenq, scaleq, negq, addq, subq, mulq, rotq, lerpq, slerpq, normq

## lenq

    1

`float lenq(addr_t a)`

Description
  Calculates the length of a quaternion.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

Return Value
  Length of the quaternion.
See Also
  idq, eulerq, dotq, scaleq, negq, addq, subq, mulq, rotq, lerpq, slerpq, normq

## scaleq

    1

`void scaleq(addr_t a, float s)`

Description
  Scales a quaternion.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats
  s | scaler value

See Also
  idq, eulerq, dotq, lenq, negq, addq, subq, mulq, rotq, lerpq, slerpq, normq

## negq

    1

`void negq(addr_t a)`

Description
  Negates a quaternion.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

See Also
  idq, eulerq, dotq, lenq, scaleq, addq, subq, mulq, rotq, lerpq, slerpq, normq

## addq

    1

`void addq(addr_t dst, addr_t a, addr_t b)`

Description
  Adds together quaternions.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, subq, mulq, rotq, lerpq, slerpq, normq

## subq

    1

`void subq(addr_t dst, addr_t a, addr_t b)`

Description
  Subtracts quaternions.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, addq, mulq, rotq, lerpq, slerpq, normq

## mulq

    1

`void mulq(addr_t dst, addr_t a, addr_t b)`

Description
  Multiplies quaternions.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, addq, subq, rotq, lerpq, slerpq, normq

## rotq

    1

`void rotq(addr_t dst, addr_t q, addr_t v)`

Description
  Rotates a vector with three elements by a quaternion.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  q | address of four floats
  v | address of three floats

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, addq, subq, mulq, lerpq, slerpq, normq

## lerpq

    1

`void lerpq(addr_t dst, addr_t a, addr_t b, float t)`

Description
  Linear interpolates two quaternions.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats
  t | interpolation value between 0.0 and 1.0

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, addq, subq, mulq, rotq, slerpq, normq

## slerpq

    1

`void slerpq(addr_t dst, addr_t a, addr_t b, float t)`

Description
  Spherical interpolates a quaternion.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  a | address of four floats
  b | address of four floats
  t | interpolation value between 0.0 and 1.0

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, addq, subq, mulq, rotq, lerpq, normq

## normq

    1

`void normq(addr_t a)`

Description
  Normalizes a quaternion.
Parameters

  Argument | Description
  --- | ---
  a | address of four floats

See Also
  idq, eulerq, dotq, lenq, scaleq, negq, addq, subq, mulq, rotq, lerpq, slerpq

## idm4

    1

`void idm4(addr_t a)`

Description
  Loads a 4 x 4 identity matrix.
Parameters

  Argument | Description
  --- | ---
  a | address of 16 floats

See Also
  trsm4, detm4, addm4, subm4, mulm4, mulm4v3, mulm4v4, invm4, trpm4

## trsm4

    1

`void trsm4(addr_t dst, addr_t t, addr_t r, addr_t s)`

Description
  Creates a 4 x 4 matrix with translation, rotation and scaling.
Parameters

  Argument | Description
  --- | ---
  dst | address of 16 floats, destination matrix
  t | address of three floats, translation vector
  r | address of four floats, rotation quaternion
  s | address of three floats, scaling vector

See Also
  idm4, detm4, addm4, subm4, mulm4, mulm4v3, mulm4v4, invm4, trpm4

## detm4

    1

`float detm4(addr_t a)`

Description
  Returns the matrix's determinant.
Parameters

  Argument | Description
  --- | ---
  a | address of 16 floats

Return Value
  The matrix's determinant.
See Also
  idm4, trsm4, addm4, subm4, mulm4, mulm4v3, mulm4v4, invm4, trpm4

## addm4

    1

`void addm4(addr_t dst, addr_t a, addr_t b)`

Description
  Adds matrices together.
Parameters

  Argument | Description
  --- | ---
  dst | address of 16 floats
  a | address of 16 floats
  b | address of 16 floats

See Also
  idm4, trsm4, detm4, subm4, mulm4, mulm4v3, mulm4v4, invm4, trpm4

## subm4

    1

`void subm4(addr_t dst, addr_t a, addr_t b)`

Description
  Subtracts matrices.
Parameters

  Argument | Description
  --- | ---
  dst | address of 16 floats
  a | address of 16 floats
  b | address of 16 floats

See Also
  idm4, trsm4, detm4, addm4, mulm4, mulm4v3, mulm4v4, invm4, trpm4

## mulm4

    1

`void mulm4(addr_t dst, addr_t a, addr_t b)`

Description
  Multiplies matrices.
Parameters

  Argument | Description
  --- | ---
  dst | address of 16 floats
  a | address of 16 floats
  b | address of 16 floats

See Also
  idm4, trsm4, detm4, addm4, subm4, mulm4v3, mulm4v4, invm4, trpm4

## mulm4v3

    1

`void mulm4v3(addr_t dst, addr_t m, addr_t v)`

Description
  Multiplies a vector with three elements by a matrix.
Parameters

  Argument | Description
  --- | ---
  dst | address of three floats
  m | address of 16 floats
  v | address of three floats

See Also
  idm4, trsm4, detm4, addm4, subm4, mulm4, mulm4v4, invm4, trpm4

## mulm4v4

    1

`void mulm4v4(addr_t dst, addr_t m, addr_t v)`

Description
  Multiplies a vector with four elements by a matrix.
Parameters

  Argument | Description
  --- | ---
  dst | address of four floats
  m | address of 16 floats
  v | address of four floats

See Also
  idm4, trsm4, detm4, addm4, subm4, mulm4, mulm4v3, invm4, trpm4

## invm4

    1

`void invm4(addr_t dst, addr_t a)`

Description
  Calculates inverse matrix.
Parameters

  Argument | Description
  --- | ---
  dst | address of 16 floats
  a | address of 16 floats

See Also
  idm4, trsm4, detm4, addm4, subm4, mulm4, mulm4v3, mulm4v4, trpm4

## trpm4

    1

`void trpm4(addr_t dst, addr_t a)`

Description
  Transpose matrix.
Parameters

  Argument | Description
  --- | ---
  dst | address of 16 floats
  a | address of 16 floats

See Also
  idm4, trsm4, detm4, addm4, subm4, mulm4, mulm4v3, mulm4v4, invm4

## trns

    1
    2
    3
    4

`void trns(addr_t dst, addr_t src, uint8_t num, int16_t x, int16_t y, int16_t z, uint16_t pitch, uint16_t yaw, uint16_t roll, float scale)`

Description
  Translate a vertex cloud, aka. place a 3D model in 3D space.
Parameters

  Argument | Description
  --- | ---
  dst | destination vertices array, 3 x 2 bytes each, X, Y, Z
  src | source vertices array, 3 x 2 bytes each, X, Y, Z
  num | number of vertex coordinate triplets in the array
  x | world X coordinate, -32767 to 32767
  y | world Y coordinate, -32767 to 32767
  z | world Z coordinate, -32767 to 32767
  pitch | rotation around X axis in degrees, 0 to 359
  yaw | rotation around Y axis in degrees, 0 to 359
  roll | rotation around Z axis in degrees, 0 to 359
  scale | scale, use 1.0 to keep original size

See Also
  mesh

PreviousNext

# Memory

## inb

    1

`uint8_t inb(addr_t src)`

Description
  Read in one byte from memory.
Parameters

  Argument | Description
  --- | ---
  src | address, 0x00000 to 0xBFFFF

Return Value
  Returns the value at that address.

## inw

    1

`uint16_t inw(addr_t src)`

Description
  Read in a word (two bytes) from memory.
Parameters

  Argument | Description
  --- | ---
  src | address, 0x00000 to 0xBFFFE

Return Value
  Returns the value at that address.

## ini

    1

`uint32_t ini(addr_t src)`

Description
  Read in an integer (four bytes) from memory.
Parameters

  Argument | Description
  --- | ---
  src | address, 0x00000 to 0xBFFFC

Return Value
  Returns the value at that address.

## outb

    1

`void outb(addr_t dst, uint8_t value)`

Description
  Write out one byte to memory.
Parameters

  Argument | Description
  --- | ---
  dst | address, 0x00000 to 0xBFFFF
  value | value to set, 0 to 255

## outw

    1

`void outw(addr_t dst, uint16_t value)`

Description
  Write out a word (two bytes) to memory.
Parameters

  Argument | Description
  --- | ---
  dst | address, 0x00000 to 0xBFFFE
  value | value to set, 0 to 65535

## outi

    1

`void outi(addr_t dst, uint32_t value)`

Description
  Write out an integer (four bytes) to memory.
Parameters

  Argument | Description
  --- | ---
  dst | address, 0x00000 to 0xBFFFC
  value | value to set, 0 to 4294967295

## memsave

    1

`int memsave(uint8_t overlay, addr_t src, uint32_t size)`

Description
  Saves memory area to overlay.
Parameters

  Argument | Description
  --- | ---
  overlay | index of overlay to write to, 0 to 255
  src | memory offset to save from, 0x00000 to 0xBFFFF
  size | number of bytes to save

Return Value
  Returns 1 on success, 0 on error.
See Also
  memload

## memload

    1

`int memload(addr_t dst, uint8_t overlay, uint32_t maxsize)`

Description
  Loads an overlay into the specified memory area.
Parameters

  Argument | Description
  --- | ---
  dst | memory offset to load to, 0x00000 to 0xBFFFF
  overlay | index of overlay to read from, 0 to 255
  maxsize | maximum number of bytes to load

Return Value
  Returns the number of bytes actually loaded.
See Also
  memsave

## memcpy

    1

`void memcpy(addr_t dst, addr_t src, uint32_t len)`

Description
  Copy memory regions.
Parameters

  Argument | Description
  --- | ---
  dst | destination address, 0x00000 to 0xBFFFF
  src | source address, 0x00000 to 0xBFFFF
  len | number of bytes to copy

## memset

    1

`void memset(addr_t dst, uint8_t value, uint32_t len)`

Description
  Set memory region to a given value.
Parameters

  Argument | Description
  --- | ---
  dst | destination address, 0x00000 to 0xBFFFF
  value | value to set, 0 to 255
  len | number of bytes to set

## memcmp

    1

`int memcmp(addr_t addr0, addr_t addr1, uint32_t len)`

Description
  Compare memory regions.
Parameters

  Argument | Description
  --- | ---
  addr0 | first address, 0x00000 to 0xBFFFF
  addr1 | second address, 0x00000 to 0xBFFFF
  len | number of bytes to compare

Return Value
  Returns difference, 0 if the two memory region matches.

## deflate

    1

`int deflate(addr_t dst, addr_t src, uint32_t len)`

Description
  Compress a buffer using RFC1950 deflate (zlib).
Parameters

  Argument | Description
  --- | ---
  dst | destination address, 0x30000 to 0xBFFFF
  src | source address, 0x30000 to 0xBFFFF
  len | number of bytes to compress

Return Value
  0 or negative on error, otherwise the length of the compressed buffer and compressed data in dst.
See Also
  inflate

## inflate

    1

`int inflate(addr_t dst, addr_t src, uint32_t len)`

Description
  Uncompress a buffer with RFC1950 deflate (zlib) compressed data.
Parameters

  Argument | Description
  --- | ---
  dst | destination address, 0x30000 to 0xBFFFF
  src | source address, 0x30000 to 0xBFFFF
  len | number of compressed bytes

Return Value
  0 or negative on error, otherwise the length of the uncompressed buffer and uncompressed data in dst.
See Also
  deflate

## time

    1

`float time(void)`

Description
  Returns the number of ticks since power on.
Return Value
  The elapsed time in milliseconds since power on.
See Also
  now

## now

    1

`uint32_t now(void)`

Description
  Returns the UNIX timestamp. Check the byte at offset 0000C to see if it overflows.
Return Value
  The elapsed time in seconds since 1 Jan 1970 midnight, Greenwich Mean Time.
See Also
  time

## atoi

    1

`int atoi(str_t src)`

Description
  Converts an ASCII decimal string into an integer number.
Parameters

  Argument | Description
  --- | ---
  src | string address, 0x00000 to 0xBFFFF

Return Value
  The number value of the string.
See Also
  itoa, str, val

## itoa

    1

`str_t itoa(int value)`

Description
  Converts an integer number into an ASCII decimal string.
Parameters

  Argument | Description
  --- | ---
  value | the value, -2147483648 to 2147483647

Return Value
  The converted string.
See Also
  atoi, str, val

## val

    1

`float val(str_t src)`

Description
  Converts an ASCII decimal string into a floating point number.
Parameters

  Argument | Description
  --- | ---
  src | string address, 0x00000 to 0xBFFFF

Return Value
  The number value of the string.
See Also
  itoa, atoi, str

## str

    1

`str_t str(float value)`

Description
  Converts a floating point number into an ASCII decimal string.
Parameters

  Argument | Description
  --- | ---
  value | the value

Return Value
  The converted string.
See Also
  atoi, itoa, val

## sprintf

    1

`str_t sprintf(str_t fmt, ...)`

Description
  Returns a zero terminated UTF-8 string created using format and arguments.
Parameters

  Argument | Description
  --- | ---
  fmt | format string
  ... | optional arguments

Return Value
  Constructed string.

## strlen

    1

`int strlen(str_t src)`

Description
  Return the number of bytes in a string (without the terminating zero).
Parameters

  Argument | Description
  --- | ---
  src | string address, 0x00000 to 0xBFFFF

Return Value
  The number of bytes in the string.
See Also
  mblen

## mblen

    1

`int mblen(str_t src)`

Description
  Return the number of UTF-8 multi-byte characters in a string (without the terminating zero).
Parameters

  Argument | Description
  --- | ---
  src | string address, 0x00000 to 0xBFFFF

Return Value
  The number of characters in the string.
See Also
  strlen

## malloc

    1

`addr_t malloc(uint32_t size)`

Description
  Allocates user memory dynamically.
Parameters

  Argument | Description
  --- | ---
  size | number of bytes to allocate

Return Value
  Address of the new allocated buffer or NULL on error.
See Also
  realloc, free

## realloc

    1

`addr_t realloc(addr_t addr, uint32_t size)`

Description
  Resize a previously allocated buffer.
Parameters

  Argument | Description
  --- | ---
  addr | address of the allocated buffer
  size | number of bytes to resize to

Return Value
  Address of the new allocated buffer or NULL on error.
See Also
  malloc, free

## free

    1

`int free(addr_t addr)`

Description
  Frees dynamically allocated user memory.
Parameters

  Argument | Description
  --- | ---
  addr | address of the allocated buffer

Return Value
  1 on success, 0 on error.
See Also
  malloc, realloc

PreviousNext

# Bouncing Ball

In this tutorial we'll create a program that bounces a ball on the screen.

## Displaying the Ball

First things first, start `meg4` and select the Sprite Editor (press `F3`). Select the first sprite on the right, and edit it on the left.

Drawing the ball

Now go to the Code Editor (press `F2`). At first, our program will be an empty skeleton.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

`#!c void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ }`

Let's place this newly drawn sprite on screen! You can do this by calling the spr function. Go to the body of the `setup()` function, start typing, and at the bottom in the statusbar you'll see the required parameters.

We can see that the first two arguments are `x, y`, the screen coordinate where we want to place the sprite (if it's not obvious from the name what a parameter does, just press `F1` and a detailed help will show up. Pressing `Esc` there will bring you back to the code editor). The screen is 320 pixels wide and 200 pixels tall, so in order to place at the centre, let's use `160, 100`. Next argument is the `sprite`. We've drawn our ball at the 0th sprite, so use `0`. After comes `sw` (sprite width) and `sh` (sprite height), which tells how many sprites we want to display. Our ball only occupies 1 sprite, so simply write `1, 1`. Then comes `scale`, but we don't want to magnify our ball, so just use `1` here too. Finally, the last parameter is `type`, which can be used to display the sprite transformed. We don't want any transformation, so just use `0`.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

`#!c void setup() { /* Things to do on startup */ spr(160, 100, 0, 1, 1, 1, 0); } void loop() { /* Things to run for every frame, at 60 FPS */ }`

Now try running this code by pressing `Ctrl`+`R`, and let's see what happens. If you have made some mistake by typing the code, an error message will show up in the status bar, and the cursor will be positioned to the faulting part.

If everything went well, then the editor screen will disappear, and black screen with the ball in the middle will appear instead. Our ball isn't exactly at the centre, because we forgot to subtract the half of the sprite's size from the coordinates (we are displaying only one sprite here (sw = 1 and sh = 1), so 8 x 8 pixels in total, half of that is 4). Press `F2` to go back to the editor, and let's fix this.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

`#!c void setup() { /* Things to do on startup */ spr(156, 96, 0, 1, 1, 1, 0); } void loop() { /* Things to run for every frame, at 60 FPS */ }`

Let's run this again! We have the ball at proper position, but we can still see it at the wrong position! That's because we haven't cleared the screen. We can do that by calling cls, so let's add that before drawing the sprite.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

`#!c void setup() { /* Things to do on startup */ cls(0); spr(156, 96, 0, 1, 1, 1, 0); } void loop() { /* Things to run for every frame, at 60 FPS */ }`

Now everything is fine, our ball shown at exactly the centre of the screen.

## Moving the Ball

There's a problem in our code. We display the ball in `setup()` which only runs once when our program starts. To move the ball, we have to display it over and over again, at different positions. To achieve this, let's move the code that displays our ball into the `loop()` function. This runs every time when the screen is redrawn.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

`#!c void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(156, 96, 0, 1, 1, 1, 0);}`

If we press `Ctrl`+`R` now, then the ball will be displayed exactly as before. What we can't see is that the ball is now drawn not only once, but over and over again.

Let's move that ball! It is displayed at the same position, because we have used constant coordinates. Let's fix this by introducing two variables, which will store the ball's current position on screen.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

`#!c int x, y; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(156, 96, 0, 1, 1, 1, 0); }`

Replace the coordinates in drawing call to these variables, and let's assign them values on program start.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

`#!c int x, y; void setup() { /* Things to do on startup */ x = 156; y = 96;} void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); }`

If we run our program now, there'll be still no change. However using variables we can now change the ball's position in run-time, let's do that.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

`#!c int x, y; void setup() { /* Things to do on startup */ x = 156; y = 96; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); x = x + 1; y = y + 1;}`

Run this program, and you'll see the ball moving!

## Bouncing the Ball

We are not ready yet, because our ball disappears pretty quickly from the screen. This is because we constantly increasing its coordinates, and we don't change its direction when it reaches the edge of the screen.

Just like as we did with the coordinates at first, we are using a constant and now we want to change the direction in our program dynamically. The solution is the same, we replace the constants with two new variables.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

`#!c int x, y, dx, dy; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); x = x + dx; y = y + dy; }`

Great! As mentioned before, the screen is 320 pixels wide and 200 pixels tall. This means that the valid values for the `x` coordinate are between 0 and 319, and for `y` between 0 and 199. But we don't want our ball to disappear from the screen, so we have to subtract the sprite's size (8 x 8 pixels) from these. This gives 0 to 311 for `x`, and 0 to 191 for `y`. If our ball's coordinate reaches one of these values, then we must change it's direction so that it won't leave the screen.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

`#!c int x, y, dx, dy; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); x = x + dx; y = y + dy; if(x == 0 || x == 311) dx = -dx; if(y == 0 || y == 191) dy = -dy;}`

Run this program by pressing `Ctrl`+`R`. Congratulations, you have a moving ball that bounces off the screen edges!

## Adding a Bat

A game that we can't play with isn't very interesing. So we'll add a bat that the player can control.

Go to the Sprite Editor (press `F3`) and let's draw the bat. This time we'll make it three sprites wide. You can draw these one by one, or you can select multiple sprites on the right and edit them together on the left.

Drawing the bat

Just like with the ball, we'll use spr to display it on screen. But we also know that we'll need a variable to store its position, so let's add that too at once.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

`#!c int x, y, dx, dy, px; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); spr(px, 191, 1, 3, 1, 1, 0); x = x + dx; y = y + dy; if(x == 0 || x == 311) dx = -dx; if(y == 0 || y == 191) dy = -dy; }`

So the `x` argument becomes `px`, and we don't want to move the bat vertically, just horizontally, so the `y` argument is a constant `191`. Because we draw the bat at the 1st sprite, the `sprite` parameter is `1`. And because it is three sprites wide, `sw` is `3`, but it is still just one sprite tall, so `sh` is `1`.

So far so good, but how will the player move this bat with the mouse? We'll set the mouse coordinate to the `px` variable for that. If you go the memory map, then under pointer you can see that the mouse's X coordinate is stored on 2 bytes at address `00016`. To get this value, we use the inw function (word, because we need 2 bytes). But we also must not allow moving the bat off screen, so we clamp if the coordinate is bigger than the screen size minus the bat's size (which is three sprites, so 24 pixels). One more thing, the offsets in the memory map are given in hexadecimal, so we need the `0x` prefix to tell the compiler that this is a hexadecimal number.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

`#!c int x, y, dx, dy, px; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); px = inw(0x16); if(px > 296) px = 296; spr(px, 191, 1, 3, 1, 1, 0); x = x + dx; y = y + dy; if(x == 0 || x == 311) dx = -dx; if(y == 0 || y == 191) dy = -dy; }`

Let's run this program! We can see the bat and we can also move it around with the mouse. But there's a problem. The ball doesn't care where the bat is. Let's fix this by modifying the screen bottom check to a bat position check so that it would bounce on the bat only. Don't forget that the ball is 8 pixels tall, so we must check at a smaller coordinate.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

`#!c int x, y, dx, dy, px; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); px = inw(0x16); if(px > 296) px = 296; spr(px, 191, 1, 3, 1, 1, 0); x = x + dx; y = y + dy; if(x == 0 || x == 311) dx = -dx; if(y == 0 || (y == 183 && x >= px && x <= px + 24)) dy = -dy; }`

This means the `y` coordinate is zero, or it is `183` and at the same time the `x` coordinate is between `px` and `px + 24` (where `px` is the bat's position).

## Game Over

Now that we have changed the bottom check, we have to add a new check to see if the ball has left the screen. Of course this would mean game over.

First, remember that `loop()` runs constantly, so to stop moving the ball any further, we set the `dx` and `dy` variables to zero. Second, we want to display a game over message.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

`#!c int x, y, dx, dy, px; str_t msg = "GAME OVER!"; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); px = inw(0x16); if(px > 296) px = 296; spr(px, 191, 1, 3, 1, 1, 0); x = x + dx; y = y + dy; if(x == 0 || x == 311) dx = -dx; if(y == 0 || (y == 183 && x >= px && x <= px + 24)) dy = -dy; if(y > 199) { dx = dy = 0; text(184, (320 - width(2, msg)) / 2, 90, 2, 112, 128, msg); }}`

We can display text on screen using the text function. At the bottom, the quick help shows what arguments it has. The first one is `palidx`, which is a palette index, the color of the text. Press `F3` and click on the desired color. At the bottom, we'll see the index in hexadecimal and in parenthesis in decimal as well.

I have choosen a red color, by the index `B8` or `184` in decimal. Let's go back to the code editor by pressing `F2`, and enter this number. The next two arguments are `x` and `y`, the position on screen. We could have count the number of pixels in the text, but we are lazy, so we use the width function for that. Subtracting this from the width of the screen and dividing by two will place the text exactly at the middle. Because we are too lazy to type the text twice, we've also used a string variable `msg` to store the message. Therefore we use `msg` once when we calculate its size, and also when we pass it to the display function to say what to print. After the coordinates comes the `type`, which is the font's type, or more specifically its size. We want big letters, so we've used `2`, double size. After this comes the shadow, `shidx`, which is also a color index. I've choosen a darker red here. For a shadow, it is important how transparent it is, we can specify this in the `sha` argument. That is an alpha channel value from 0 (fully transparent) to 255 (fully opaque). By using `128`, which is half way between these values, I've told to use half transparent. And finally the `str` argument specifies the text to be displayed, which we store in the `msg` variable.

## Restart

And last, if the player clicks, we want to restart the game.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

`#!c int x, y, dx, dy, px; str_t msg = "GAME OVER!"; void setup() { /* Things to do on startup */ x = 156; y = 96; dx = dy = 1; } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(x, y, 0, 1, 1, 1, 0); px = inw(0x16); if(px > 296) px = 296; spr(px, 191, 1, 3, 1, 1, 0); x = x + dx; y = y + dy; if(x == 0 || x == 311) dx = -dx; if(y == 0 || (y == 183 && x >= px && x <= px + 24)) dy = -dy; if(y > 199) { dx = dy = 0; text(184, (320 - width(2, msg)) / 2, 90, 2, 112, 128, msg); if(getclk(BTN_L)) setup(); } }`

To query if the user has clicked, we use the getclk function, with a `BTN_L` argument, meaning is the left button clicked. We've used the `setup()` function to set the default values for our little bouncing ball game. This is very convenient, because calling `setup()` now will therefore simply reset our game.

PreviousNext

# Walking

In this tutorial we'll create a walking character using sprites. This is the basis of many adventure and rouge-like games.

## Get the Spritesheet

We could draw the sprites ourselves, but for simplicity I've downloaded a public domain sheet from the internet. This contains three animation phases in every line, and has one line per all 4 directions. There are lots of spritesheets on the net like this, because this is the popular RPG Maker's sprite layout.

Warning

Always check the licensing terms when you use assets downloaded from the internet. Do not use the asset if you're unsure about its terms of use.

Start `meg4` and drag'n'drop this downloaded PNG image on the window to import.

The imported sprite sheet

As you can see, one character sprite is made up of 4 x 4 sprites. Let's display that! Press `F2` to go to the Code Editor.

## Display Character

We start with the usual skeleton. We know from the previous tutorial that we'll have to clear the screen and display the sprites using spr in the `loop()` function, because animation requires constant redrawing.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

`#!c void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ cls(0); spr(144, 84, 0, 4, 4, 0, 0);}`

The centre of the screen is at 160, 100 but our character is 4 x 4 sprites in size (32 x 32 pixels), so we have to subtract the half of that. Then comes 0 for `sprite`, meaning the first sprite, followed by 4, 4 because we want to display that many sprites. The last two parameters are 0, 0 because we don't want to scale nor transform, we want the sprites to be displayed exactly as they appear in the Sprite Editor.

## Changing Directions

Next, let's allow changing the direction in which the character is pointing to. For that, we'll use getpad, which returns the gamepad's state. The primary gamepad controller is mapped to the keyboard, so pressing the cursor arrow keys will work too. To handle the direction, we'll need a variable to store the current direction, and this should select the sprite we draw.

Get the sprite id

You can press `F3` and click on the top left sprite of the character frame to get the sprite id for that direction. We set these ids in the `dir` variable, and then we'll use this variable in place of the `sprite` parameter.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

`#!c int dir; void setup() { /* Things to do on startup */ } void loop() { /* Get user input */ if(getpad(0, BTN_D)) { dir = 0; } else if(getpad(0, BTN_L)) { dir = 128; } else if(getpad(0, BTN_R)) { dir = 256; } else if(getpad(0, BTN_U)) { dir = 384; } /* Display the character */ cls(0); spr(144, 84, dir, 4, 4, 0, 0); }`

Try it out! You'll see that by pressing the arrows our character will change directions.

## Adding Animation

Our character doesn't walk yet. Let's fix it! We want our character to walk when a button (or arrow key) is pressed, and stop when that's released. For that, we'll need a variable to keep track if the button is currently pressed.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

`#!c int dir, pressed; void setup() { /* Things to do on startup */ } void loop() { /* Get user input */ pressed = 0; if(getpad(0, BTN_D)) { dir = 0; pressed = 1; } else if(getpad(0, BTN_L)) { dir = 128; pressed = 1; } else if(getpad(0, BTN_R)) { dir = 256; pressed = 1; } else if(getpad(0, BTN_U)) { dir = 384; pressed = 1; } /* Display the character */ cls(0); spr(144, 84, dir, 4, 4, 0, 0); }`

First, we clear the `pressed` variable. Then in the if blocks we set it to 1. This way when we press a button, the variable becomes 1, but as soon as we release the button, it will be cleared to 0.

We'll also need a variable to tell which animation frame to display. We could have used some funky expression to get the sprite id, but it is a lot easier to use an array instead storing which sprite to pick in the row. So row tells the direction, and columns tells the animation frame. Adding this two together gives us the final frame.

One more thing, we have three animation sprites, but we'll have to display four frames, the sprite in the middle needs to be displayed twice to get a proper back and forth animation for moving the legs. So in a given row we take the frame from the middle, the last, the middle again and then the first.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

`#!c int dir, pressed, frame; int anim[4] = { 4, 8, 4, 0 }; void setup() { /* Things to do on startup */ } void loop() { /* Get user input */ pressed = 0; if(getpad(0, BTN_D)) { dir = 0; pressed = 1; } else if(getpad(0, BTN_L)) { dir = 128; pressed = 1; } else if(getpad(0, BTN_R)) { dir = 256; pressed = 1; } else if(getpad(0, BTN_U)) { dir = 384; pressed = 1; } /* Display the character */ frame = pressed ? (frame + 1) & 3 : 0; cls(0); spr(144, 84, dir + anim[frame], 4, 4, 0, 0); }`

Next, we calculate which animation frame to display, but only if a button is pressed. If not, then we use a constant 0, meaning the first frame. Otherwise we increase `frame` to get the next frame, and we use bitwise AND to avoid overflow. When `frame` becomes 4 (which is 0b100 in binary) and we AND that with 3 (0b011), then the result will be 0, so the frame counter wraps around. We could have used "modulo number of frames" as well, but this is faster. Finally, we get the sprite id offset for this animation frame (stored in the `anim` array) and we add that to the `dir` variable to get which sprite to display.

Try it out, press `Ctrl`+`R`! It works fine, except our character is animated way too fast. That's because we increase the `frame` counter on every refresh, so 60 times per second. To fix this, we should get the ticks from the MMIO and calculate the frame independently to the refresh rate. However ticks counter is in millisec, so we should divide it. If we would divide that by 100, then we'd get 10 frames per second. We'll use shifting to the right 7 bits instead, which is equivalent of diving by 128. So first, press `F1`, and click on Misc. We can see that the ticks counter is at address 0x4, and it is 4 bytes long (so we'll have to use ini). Go back to the code and replace the frame calculation with this.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

`#!c int dir, pressed, frame; int anim[4] = { 4, 8, 4, 0 }; void setup() { /* Things to do on startup */ } void loop() { /* Get user input */ pressed = 0; if(getpad(0, BTN_D)) { dir = 0; pressed = 1; } else if(getpad(0, BTN_L)) { dir = 128; pressed = 1; } else if(getpad(0, BTN_R)) { dir = 256; pressed = 1; } else if(getpad(0, BTN_U)) { dir = 384; pressed = 1; } /* Display the character */ frame = pressed ? (ini(0x4) >> 7) & 3 : 0; cls(0); spr(144, 84, dir + anim[frame], 4, 4, 0, 0); }`

And we're done! We have a nicely walking character animation that we can control in our game. You could also move the character on screen by using variables for the x, y arguments, but it is very common in such games to move the map under the character in the opposite direction instead.

PreviousNext

# Cannon

In this tutorial we'll create a cannon. This contains all the basics for an Asteroids game.

## Display the Turret

We start with the usual skeleton. We know from the previous tutorial that we'll have to clear the screen and we'll use line to draw a very simple turret.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

`#!c void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* Display */ cls(0); line(23, 160, 100, 160, 100 - 10);}`

The centre of the screen is at 160, 100 and we draw a 10 pixels long turret pointing upwards by subtracting 10 pixels from the end Y coordinate. We also gave it a grayish color (23).

## Rotating the Turret

In order to make the player able to rotate this, we'll need a variable to keep track of the current degree where the turret should point to.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

`#!c int deg; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Display */ cls(0); line(23, 160, 100, 160, 100 - 10); }`

We query if the player has pressed left or right arrow keys, and we change the degree accordingly. We are not ready yet, because we must also clip the degree and make it so that when we reach the lower limit we set the highest value, and when we reach the higher limit we set the lowest value. This will result in a nicely rotating around the clock turret.

Now to display the turret rotated at this degree, we'll need to know how much that degree means in pixels on the X and Y axis. One might remember from school math class that this is exactly what sinus and cosinus functions do. Of course they return a unit value, so if we want our turret to be 10 pixels long, we have to multiply that by 10. It is important that sin and cos returns a floating point number (so not `1` but `1.0`).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

`#!c int deg; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Display */ cls(0); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

Press `Ctrl`+`R`, and you'll see that the turret is nicely rotating!

## Adding a Bullet

As we know from bouncing the ball, to display a moving object we'll need two variables to store its coordinate and another two storing how much it should move. Unlike that ball, which only moved in diagonal, here we want to handle any arbitrary degree, so for a smooth movement we need to store sub-pixels, therefore we'll use floating point numbers for these variables (not `int` but `float`).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

`#!c float x, y, dx, dy;int deg; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Move the bullet */ x += dx; y += dy; if(x < 0 || x >= 320 || y < 0 || y >= 200) dx = dy = 0.0; /* Display */ cls(0); pset(8, x, y); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

Just like we did in the first tutorial, in the main `loop()` we add the delta values to the current coordinates. We also check if the bullet has reached the edge of the screen, and if so then we reset to stop the bullet's further movement. To display the bullet, we just simply set a yellow (8) pixel with pset.

## Firing the Cannon

One last thing left is to make the player able to fire this cannon.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35

`#!c float x, y, dx, dy; int deg; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Fire the cannon */ if(getkey(KEY_SPACE)) { dx = cos(deg); dy = sin(deg); x = 160 + dx * 9; y = 100 + dy * 9; } /* Move the bullet */ x += dx; y += dy; if(x < 0 || x >= 320 || y < 0 || y >= 200) dx = dy = 0.0; /* Display */ cls(0); pset(8, x, y); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

When the player presses the `Space`, we set the dx and dy values depending how much pixels the current degree means on the X and Y axis. We also set the x and y variables to point at the end of the turret. We multiply the delta values by 9 for this, because the very next thing we are about to do is adding the delta values to the current coordinates, thus resulting in multiplying by 10.

Try it out! It works, but has a drawback though. If the player holds down the `Space`, then nothing happens. This is because getkey will return constantly true, so we keep setting the x, y, dx, dy variables to the same values, and movement can't happen. Let's fix this! We need a variable to keep track if we have already fired the cannon.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

`#!c float x, y, dx, dy; int deg, fired; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Fire the cannon */ if(getkey(KEY_SPACE)) { if(!fired) { fired = 1; dx = cos(deg); dy = sin(deg); x = 160 + dx * 9; y = 100 + dy * 9; } } else fired = 0; /* Move the bullet */ x += dx; y += dy; if(x < 0 || x >= 320 || y < 0 || y >= 200) dx = dy = 0.0; /* Display */ cls(0); pset(8, x, y); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

So when `Space` is pressed, we also check if `fired` variable is not set, and if it isn't, then we set it along with the other variables. This way we'll only set the other variables once. But we don't want to keep `fired` that way, therefore when `Space` is not pressed, we clear that flag so that we could fire the cannon again. And that's all about it.

Hint

We have added a block around the lines which set those variables. No need to type so many spaces to indent all those lines, you can select the lines and press `Ctrl`+`.` to make the editor increase indentation at once.

## Multiple Bullets

Our code still has an issue. If we fire the cannon when a bullet is already fired, then the first bullet disappears. This is because we can only handle one bullet at a time, we have only one x, y, dx, dy quadlet. To support more bullets, we need to convert these to arrays which can hold multiple values, one quadlet for each bullet.

At first, just create arrays with one element. When we declare them, we need to tell the compiler the number of elements, but when we reference them, we use an index starting from zero, therefore the indeces of an array with N elements goes 0 to N - 1.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41

`#!c #define N 1 float x[N], y[N], dx[N], dy[N]; int deg, fired; void setup() { /* Things to do on startup */ } void loop() { /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Fire the cannon */ if(getkey(KEY_SPACE)) { if(!fired) { fired = 1; dx[0] = cos(deg); dy[0] = sin(deg); x[0] = 160 + dx[0] * 9; y[0] = 100 + dy[0] * 9; } } else fired = 0; /* Move the bullet */ x[0] += dx[0]; y[0] += dy[0]; if(x[0] < 0 || x[0] >= 320 || y[0] < 0 || y[0] >= 200) dx[0] = dy[0] = 0.0; /* Display */ cls(0); pset(8, x[0], y[0]); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

Try this out! It should work exactly as before.

Now moving on, we introduce loops, which iterates on all elements. First, let's do this with the movement and the display.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46

`#!c #define N 1 float x[N], y[N], dx[N], dy[N]; int deg, fired; void setup() { /* Things to do on startup */ } void loop() { int i; /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Fire the cannon */ if(getkey(KEY_SPACE)) { if(!fired) { fired = 1; dx[0] = cos(deg); dy[0] = sin(deg); x[0] = 160 + dx[0] * 9; y[0] = 100 + dy[0] * 9; } } else fired = 0; /* Move the bullets */ for(i = 0; i < N; i++) { x[i] += dx[i]; y[i] += dy[i]; if(x[i] < 0 || x[i] >= 320 || y[i] < 0 || y[i] >= 200) dx[i] = dy[i] = 0.0; } /* Display */ cls(0); for(i = 0; i < N; i++) pset(8, x[i], y[i]); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

As you can see, we didn't change much, we just put a loop around the expressions, and we have replaced the constant `0` index with the loop variable `i`. This way on each iteration the loop body moves one bullet. Same way, we use another loop to display one bullet in each iteration.

We also have to make the cannon fire a bullet. This is a bit trickier, as we'll have to find a quadlet of variables which is not being used. And once we find one, we need to stop, because we only want to set one bullet's variables.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50

`#!c #define N 1 float x[N], y[N], dx[N], dy[N]; int deg, fired; void setup() { /* Things to do on startup */ } void loop() { int i; /* Things to run for every frame, at 60 FPS */ /* User input */ if(getkey(KEY_LEFT)) deg--; if(getkey(KEY_RIGHT)) deg++; if(deg < 0) deg = 359; if(deg > 359) deg = 0; /* Fire the cannon */ if(getkey(KEY_SPACE)) { if(!fired) { fired = 1; for(i = 0; i < N; i++) if(dx[i] == 0.0 && dy[i] == 0.0) { dx[i] = cos(deg); dy[i] = sin(deg); x[i] = 160 + dx[i] * 9; y[i] = 100 + dy[i] * 9; break; } } } else fired = 0; /* Move the bullets */ for(i = 0; i < N; i++) { x[i] += dx[i]; y[i] += dy[i]; if(x[i] < 0 || x[i] >= 320 || y[i] < 0 || y[i] >= 200) dx[i] = dy[i] = 0.0; } /* Display */ cls(0); for(i = 0; i < N; i++) pset(8, x[i], y[i]); line(23, 160, 100, 160 + cos(deg)*10, 100 + sin(deg)*10); }`

So this loop contains a conditional, which checks if a certain bullet's movement is zero. If so, then we have found an empty bullet slot at `i` that we can use. We do the same setup as before on the `i`th quadlet, and then the `break` keyword quits the loop.

Let's run this! Still no change, works exactly as before. To put into perspective why we have worked so hard with these arrays, change only one thing:

    1

`#define N 100`

And presto!

By replacing the fixed 160 and 100 coordinates of the cannon with another x, y and dx, dy variables, you'll be able to move it, and you'll get an Asteroids spaceship!

PreviousNext

# Sound Effect

In this tutorial we'll prepare and import a sound effect. We'll use Audacity, but other wave editors should work too.

## Load Wave

First, let's open the desired wave file in Audacity.

Open the sound wave in Audacity

We can see right away that there are two waves, meaning our sound sample is stereo. MEG-4 can only handle mono, so go to `Tracks` > `Mix` > `Mix Stereo Down to Mono` to convert it. If you see only one waveform, you can skip this step.

## Tuning and Volume

Now MEG-4 does tune the samples on its own, and for that to work, all imported waves must be tuned to a specific pitch. For some reason pitch detection is broken in Audacity, so you'll have to do it manually. Press `Ctrl`+`A` to select the wave, and then go to `Analyze` > `Plot Spectrum...`.

Analyzing the spectrum

Move your cursor above the biggest peak, and the current pitch will show up below (which is `C3` in this example). If the shown note isn't `C4`, then select `Effect` > `Pitch and Tempo` > `Change Pitch...`.

Changing the pitch

In the "from" field, enter the value that you saw in the spectrum window, and in the "to" field enter C-4, then press "Apply".

Changing the volume

Next thing is to normalize the volume. Go to `Effect` > `Volume and Compression` > `Amplify...`. In the popup window just press "Apply" (everything is autodetected correctly, no need to change anything).

## Number of Samples

MEG-4 supports no more than 16376 samples per waves. If you have fewer samples than this in the first place, then you can skip this step.

Under the waveform you'll see the selection in milliseconds, click on that small "s" and change it to "samples".

Changing the unit

In our example that's more than the allowed maximum. The number of samples is calculated as the value under "Project Sample Rate" multiplied by the length. So to lower the number of samples, either we lower the rate or we cut off the end of the wave. In this tutorial we'll do both.

Select everything let's say after 1.0, and press `Del` to delete. This does the trick, but makes the ending sound harsh. To fix that, select a reasonable portion at the end and go to `Effect` > `Fading` > `Fade Out`. This will make the wave end nicely.

Chopping off and fading out the end

Our wave is still too long (44380 samples), but we can't cut off more without ruining the sample. This is where the sample rate comes in. In previous versions of Audacity, this was comfortably displayed at the bottom on the toolbar as "Project Rate (Hz)". But not any more, on newer Audacity it is a lot more complicated. First, click `Audio Setup` on the toolbar and select `Audio Settings...`. In the popup window, look for "Quality" / "Project Sample Rate", and from the drop-down select "Other..." to make the actual input field editable.

Warning

Make sure you calculate the number correctly. Audacity is incapable of undoing this step, so you can't give it another try!

Enter a number here, which is 16376 divided by the length of your wave (1.01 secs in our example) and press "OK".

Lowering the number of samples

Select the entire wave (press `Ctrl`+`A`) then you should see that the end of the selection is below 16376.

## Save and Import

Finally, save the new modified wave by selecting `File` > `Export` > `Export as WAV`. Make sure encoding is "Unsigned 8-bit PCM". As filename, enter `dspXX.wav`, where `XX` is a hex number between `01` and `1F`, the MEG-4 wave slot where you want to load this sample (using a different filename works too, but then the wave will be loaded at the first free slot).

Imported wave form

Once you have the file, just drag'n'drop it into the MEG-4 window and you're done.

PreviousNext

# Adventure Game

The advcomp compiler can parse AdvGame JSON source files and can convert those into MEG-4 Adventure Games. These are classic textual games (also known as Interactive Fiction) where the player enters sentences in order to progress in the game. Each sentence is then parsed into a verb and noun(s), and looked up. If a script is found for that verb and noun(s) combination, then it is executed.

Note

The `advcomp` tool can also generate point'n'click adventure games from the very same JSON files. Although MEG-4 can import these too, but converts them into textual games, the point'n'click gameplay mode is only available with the `advgame` interpreter.

Limitations:

- verbs: 32 different actions, each 15 bytes, up to 8 synonyms (max. 1536 bytes in total)
- nouns: 255 different objects, each 15 bytes (max. 1536 bytes in total)
- messages: 32 different strings per room, each 255 bytes (max. 2048 bytes per language)
- scripts: 1 global, 63 shared by all rooms, and 63 different per on room
- instructions: 21 mnemonics with 8 conditions, branch-free design, 61 instructions per scripts
- images: 1 per room by default, but you can add custom implementation
- rooms: 254 in total, connectable in 6 different directions

## Game State

The Adventure Game state is an array of 256 bytes. The first byte stores the current room number, the last 32 bytes are reserved for the inventory, all the others are up to you. You can use these as flags, you can store counters in them, whatever. Scripts operate on this 256 bytes of memory, and this state can be saved and loaded in a game save file.

## Top Level

The source file must have an `"AdvGame"` JSON structure at the top which is also a magic. Its fields are:

- `sprites`: string, path to a 256 x 256 pixels sprite sheet PNG, the first 32 rows must be empty
- `music`: array of strings, path to Amiga MOD (.mod) or MIDI (.mid) files (up to 8 files)
- `sounds`: array of strings, path to RIFF WAVE (.wav) files (up to 31 elements)
- `setup`: array of numbers, initial game state values (up to 256 elements, each between 0 and 255, first number is starting room)
- `status`: array of numbers, game states to be shown on status (up to 2, see `custom` for more)
- `vars`: array of strings, aliases to game state indeces, aka "variables" (only used in the JSON)
- `rooms`: array of strings, aliases to room numbers (only used in the JSON)
- `verbs`: array of strings, aliases to `verb1`, `verb2`, `verb3` etc. (only used in the JSON)
- `nouns`: array of strings, aliases to nouns (only used in the JSON)
- `colors`: array of 5 numbers, intro and room background and text, and prompt color
- `pos`: number, text position from top in pixels
- `custom`: array of strings, additional C code to display user interface (first intro code, second room code)
- `logic`: array of strings, common game logic script executed before each and every command
- `config0`: structure, main game configuration
- `config1`: structure, alternative game configuration (to support multi-language)
- numbers/"rooms" alias: structure, room definitions.

Normally sprites are assumed to be splitted: top 128 rows are swapped between rooms, bottom 128 rows are constant (for ui elements, icons, etc. this latter is loaded from `sprites`). If textpos is set, then both on the intro page and in rooms textpos rows (up to 96 pixels) starting from the sprite sheet's row 32 will be shown on screen. With the custom user interface C code you can display whatever and howmany sprites you'd like.

## Configuration

There's a main and an alternative configuration to support more languages. Their fields are:

- `lang`: string, two letter language code
- `text`: string, intro text (up to 429 bytes)
- `answers`: array of 4 strings, messages (up to 63 bytes each): unknown verb, can't go there, can't use, game saved
- `save`: array of strings, verbs to save game (up to 15 bytes, 8 synonyms)
- `load`: array of strings, verbs to load game
- `list`: array of strings, verbs to list inventory
- `north`: array of strings, verbs to navigate to North
- `west`: array of strings, verbs to navigate to West
- `east`: array of strings, verbs to navigate to East
- `south`: array of strings, verbs to navigate to South
- `up`: array of strings, verbs to go upstrairs
- `down`: array of strings, verbs to go downstairs
- `verb1`: array of strings, verbs for action 1 (key can be one of the "verbs" aliases)
- `verb2`: array of strings, verbs for action 2
- `verb3`: array of strings, verbs for action 3
- `verb32`: array of strings, verbs for action 32
- `nouns`: array of strings, nouns for objects (up to 255 strings)

During parsing, words shorter than three UNICODE characters must match exactly, otherwise it is enough if the words starts with that. This is needed for inflecting languages, not for English (an example could be maybe `nouns` being `[ "brit" ]` that would match both if player typed either `briton` or `british`).

## Rooms

Room number goes from 1 to 254 (room 0 is the intro or reset or no direction for navigation verbs, 255 is the saved game slot). Each room structure's fields are:

- `image`: string, path to a PNG image, up to 256 x 96 pixels
- `text0`: array of strings, texts for `config0` (up to 32 strings, each 255 bytes)
- `text1`: array of strings, texts for `config1`
- `north`: number / string / array of strings, go to North script
- `west`: number / string / array of strings, go to West script
- `east`: number / string / array of strings, go to East script
- `south`: number / string / array of strings, go to South script
- `up`: number / string / array of strings, go upstairs script
- `down`: number / string / array of strings, go downstairs script
- `logic`: number / string / array of strings, script to run when player enters this specific room
- `verbX`: number / string / array of strings, scripts with a single verb (X goes 1 to 32 or a "verbs" alias)
- `verbX Y`: number / string / array of strings, scripts with a verb and a single noun (Y goes 1 to 255, or a "nouns" alias)
- `verbX Y Z`: number / string / array of strings, scripts with a verb and two nouns (Y, Z goes 1 to 255, or a "nouns" alias)

Texts can be 255 bytes long, and each room might have 32 texts, can be displayed with the `say` / `sayv` / `sayc` instructions.

The scripts in room 1 are special in a way that they can be accessed from every other room too. Therefore it is recommended to put a "Game over" room here, which has only a `jmp 0` reset in its logic, so that there's no further command parsing in this room.

## Scripts

Every JSON value after a navigation or a verb command can be a non-zero number, which is a room number:

    "north": 12,

Or it can be a string, which is a "rooms" alias:

    "north": "attic",

But if it is an array of strings, then it is a script with instructions:

    "north": [ "jmp 12" ],

These alter the game's state, display messages, etc., Instruction arguments are numbers, but in the appropriate places "rooms", "vars", etc. aliases can be used.

Available instructions:

- `end`: end script
- `and`: it's suffix is added to next instruction's condition with a logical AND
- `or`: it's suffix is added to next instruction's condition with a logical OR
- `bgm X`: play background music (X goes 0 to 7)
- `sfx X`: play sound effect (X goes 0 to 63)
- `jmp X`: goes to room X (X goes from 0 to 254)
- `jmpv (X)`: like `jmp`, but reads the room number from variable X
- `call X`: call script X in room 1 (X goes 1 to 64)
- `callv (X)`: like `call`, but reads the script number from variable X
- `give X`: add noun X to inventory (X goes 1 to 255)
- `take X`: remove noun X from inventory
- `say X`: says text X (X is from 1 to 32)
- `sayv (X) Y`: say text value of variable X + Y
- `sayc X Y`: either say text X (false) or Y (true) depending on condition
- `add (X) Y`: increase game state variable X by Y (X and Y goes from 1 to 255)
- `addv (X) (Y)`: increase game state variable X by value of variable Y
- `sub (X) Y`: decrease game state variable X by Y (X and Y goes from 1 to 255)
- `subv (X) (Y)`: decrease game state variable X by value of variable Y
- `set (X) Y`: set variable X to Y (Y can be 0 to 255)
- `rnd (X) Y`: like `set`, but puts a random number between 0 and Y into X
- `mov (X) (Y)`: move value of variable Y into variable X

All of these instructions can be expanded with exactly one of these suffixes:

- no suffix: unconditionally execute
- `if (V) = N`: only do if variable V equals N
- `if (V) != N`: only do if variable V isn't N
- `if (V) <= N`: only do if variable V less than or equal to N
- `if (V) < N`: only do if variable V less than N
- `if (V) > N`: only do if variable V greater than N
- `has N`: only do if noun N is in the inventory
- `not N`: only do if noun N is not in the inventory

A special case when `(V)` is 250 or above, these use the navigation drirections: 250 (or `north`), 251 (or `west`), 252 (or `east`), 253 (or `south`), 254 (or `up`), 255 (or `down`). For example to check if the room is passable to the North, that's `if north != 0`. These state indeces are storing the inventory's bitmask, which must be accessed using the `has` and `not` conditions, so there's no conflict.

Jumping to room 0 will wait for a keypress, then resets the game and instead of 0, jumps to the given starting room (this needs an explicit `jmp` command as number 0 cannot be used as destination room number).

Normally to connect rooms one would specify a room number (or "rooms" alias), but this allows passing from one room to another unconditionally. For example if you store a "has the key" flag in game state 7, and in room 11 you have a door and you only want to allow to go North to room 12 if the player has that key, then you'll need a scripted navigation.

    "11": {
      "text0": [ "The door is closed." ],
      "north": [ "jmp 12 if (7) = 1", "say 1" ]
    }

Instead of a number now we have an array of strings, with a `jmp 12 if (7) = 1` instruction in the `north` property. This would only jump to room 12 if state 7 is 1, otherwise it remains in room 11. In this case we can also say "The door is closed" with a `say 1` instruction (if we jumped to room 12 then this won't be executed). You can use a "rooms" alias in place of a room number, and a "vars" alias instead of a game state index (variable), for example `jmp attic if key = 1`. You can also use more complex conditions with the `and` / `or` instructions, if you add them before the instruction they should affect. For example to only allow passing when it's night and the player has a lamp too, then `[ "and if night = 1", "and has lamp", "jmp attic if key = 1" ]`.

Another example, which randomly picks a room between 100 and 109:

    [ "rnd (1) 10",   /* random between 0 and 9 into game state 1 */
      "add (1) 100",  /* add 100 so state 1 is now between 100 and 109 */
      "jmpv (1)" ]    /* jump to the room stored in a game state */

Texts can be choosen depending on variables too, for example if you store the cause of death 0 to 2 in variable 9, then:

    "text0": [
      "You're dead, because:",  /* 1st text */
      "you drown",              /* 2nd text */
      "you starved",            /* 3rd text */
      "monster eat you"         /* 4th text */
    ],
    "logic": [ "say 1", "sayv (9) 2" ]

This will first display the 1st text with `say`, then `sayv` takes the value from game state 9, adds 2 to it and displays one of the texts from 2nd to 4th.

The conditional text is also useful, which can display either a false or a true text depending on its suffix. For example:

    "text0": [
      "You don't have a key.",  /* 1st text */
      "The chest is now open."  /* 2nd text */
    ],
    "open chest": [ "sayc 1 2 has key", "set (10) 1 has key" ]

If the player does not have the key, then `sayc` will display the first, otherwise the second text. Then we set a "chest open" flag with `set`, but only if the player has the key. (To specify the command like this, you'll need a "verbs" alias `open` and a "nouns" alias `chest` as well. Again, aliases are only used in the JSON and they are independent to the translated words players can type in the game.)

## Example Games

Example MEG-4 Adventure Games can be found in the meg4_advgame repository.

PreviousNext

# MEG-4 License

The MEG-4 Fantasy Console is Free and Open Source software available under GPLv3+ or any later version of that license.

     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The MEG-4 PRO Fantasy Console's license is commercial and proprietary. It offers plus functionality over the GPL'd version, it can export your program into a standalone Web, Windows or Linux application.

PreviousNext

# Links

Materials used creating MEG-4

- pocketmod
- stb_image
- Bresenham
- raycasting
- TinyGL
- Lua
- DawnBringer32
- ZIP format
- PNG format
- TGA format
- TMX format
- BDF format
- MOD format
- MIDI format
- PICO-8 format
- TIC-80 format

Previous