12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208 |
- Minetest Lua Client Modding API Reference 0.5.0
- ================================================
- * More information at <http://www.minetest.net/>
- * Developer Wiki: <http://dev.minetest.net/>
- Introduction
- ------------
- ** WARNING: The client API is currently unstable, and may break/change without warning. **
- Content and functionality can be added to Minetest 0.4.15-dev+ by using Lua
- scripting in run-time loaded mods.
- A mod is a self-contained bunch of scripts, textures and other related
- things that is loaded by and interfaces with Minetest.
- Transferring client-sided mods from the server to the client is planned, but not implemented yet.
- If you see a deficiency in the API, feel free to attempt to add the
- functionality in the engine and API. You can send such improvements as
- source code patches on GitHub (https://github.com/minetest/minetest).
- Programming in Lua
- ------------------
- If you have any difficulty in understanding this, please read
- [Programming in Lua](http://www.lua.org/pil/).
- Startup
- -------
- Mods are loaded during client startup from the mod load paths by running
- the `init.lua` scripts in a shared environment.
- Paths
- -----
- * `RUN_IN_PLACE=1` (Windows release, local build)
- * `$path_user`:
- * Linux: `<build directory>`
- * Windows: `<build directory>`
- * `$path_share`
- * Linux: `<build directory>`
- * Windows: `<build directory>`
- * `RUN_IN_PLACE=0`: (Linux release)
- * `$path_share`
- * Linux: `/usr/share/minetest`
- * Windows: `<install directory>/minetest-0.4.x`
- * `$path_user`:
- * Linux: `$HOME/.minetest`
- * Windows: `C:/users/<user>/AppData/minetest` (maybe)
- Mod load path
- -------------
- Generic:
- * `$path_share/clientmods/`
- * `$path_user/clientmods/` (User-installed mods)
- In a run-in-place version (e.g. the distributed windows version):
- * `minetest-0.4.x/clientmods/` (User-installed mods)
- On an installed version on Linux:
- * `/usr/share/minetest/clientmods/`
- * `$HOME/.minetest/clientmods/` (User-installed mods)
- Modpack support
- ----------------
- **NOTE: Not implemented yet.**
- Mods can be put in a subdirectory, if the parent directory, which otherwise
- should be a mod, contains a file named `modpack.txt`. This file shall be
- empty, except for lines starting with `#`, which are comments.
- Mod directory structure
- ------------------------
- clientmods
- ├── modname
- | ├── depends.txt
- | ├── init.lua
- └── another
- ### modname
- The location of this directory.
- ### depends.txt
- List of mods that have to be loaded before loading this mod.
- A single line contains a single modname.
- Optional dependencies can be defined by appending a question mark
- to a single modname. Their meaning is that if the specified mod
- is missing, that does not prevent this mod from being loaded.
- ### init.lua
- The main Lua script. Running this script should register everything it
- wants to register. Subsequent execution depends on minetest calling the
- registered callbacks.
- `minetest.setting_get(name)` and `minetest.setting_getbool(name)` can be used
- to read custom or existing settings at load time, if necessary.
- ### `sounds`
- Media files (sounds) that will be transferred to the
- client and will be available for use by the mod.
- Naming convention for registered textual names
- ----------------------------------------------
- Registered names should generally be in this format:
- "modname:<whatever>" (<whatever> can have characters a-zA-Z0-9_)
- This is to prevent conflicting names from corrupting maps and is
- enforced by the mod loader.
- ### Example
- In the mod `experimental`, there is the ideal item/node/entity name `tnt`.
- So the name should be `experimental:tnt`.
- Enforcement can be overridden by prefixing the name with `:`. This can
- be used for overriding the registrations of some other mod.
- Example: Any mod can redefine `experimental:tnt` by using the name
- :experimental:tnt
- when registering it.
- (also that mod is required to have `experimental` as a dependency)
- The `:` prefix can also be used for maintaining backwards compatibility.
- Sounds
- ------
- **NOTE: max_hear_distance and connecting to objects is not implemented.**
- Only Ogg Vorbis files are supported.
- For positional playing of sounds, only single-channel (mono) files are
- supported. Otherwise OpenAL will play them non-positionally.
- Mods should generally prefix their sounds with `modname_`, e.g. given
- the mod name "`foomod`", a sound could be called:
- foomod_foosound.ogg
- Sounds are referred to by their name with a dot, a single digit and the
- file extension stripped out. When a sound is played, the actual sound file
- is chosen randomly from the matching sounds.
- When playing the sound `foomod_foosound`, the sound is chosen randomly
- from the available ones of the following files:
- * `foomod_foosound.ogg`
- * `foomod_foosound.0.ogg`
- * `foomod_foosound.1.ogg`
- * (...)
- * `foomod_foosound.9.ogg`
- Examples of sound parameter tables:
- -- Play locationless
- {
- gain = 1.0, -- default
- }
- -- Play locationless, looped
- {
- gain = 1.0, -- default
- loop = true,
- }
- -- Play in a location
- {
- pos = {x = 1, y = 2, z = 3},
- gain = 1.0, -- default
- max_hear_distance = 32, -- default, uses an euclidean metric
- }
- -- Play connected to an object, looped
- {
- object = <an ObjectRef>,
- gain = 1.0, -- default
- max_hear_distance = 32, -- default, uses an euclidean metric
- loop = true,
- }
- Looped sounds must either be connected to an object or played locationless.
- ### SimpleSoundSpec
- * e.g. `""`
- * e.g. `"default_place_node"`
- * e.g. `{}`
- * e.g. `{name = "default_place_node"}`
- * e.g. `{name = "default_place_node", gain = 1.0}`
- Representations of simple things
- --------------------------------
- ### Position/vector
- {x=num, y=num, z=num}
- For helper functions see "Vector helpers".
- ### pointed_thing
- * `{type="nothing"}`
- * `{type="node", under=pos, above=pos}`
- * `{type="object", id=ObjectID}`
- Flag Specifier Format
- ---------------------
- Flags using the standardized flag specifier format can be specified in either of
- two ways, by string or table.
- The string format is a comma-delimited set of flag names; whitespace and
- unrecognized flag fields are ignored. Specifying a flag in the string sets the
- flag, and specifying a flag prefixed by the string `"no"` explicitly
- clears the flag from whatever the default may be.
- In addition to the standard string flag format, the schematic flags field can
- also be a table of flag names to boolean values representing whether or not the
- flag is set. Additionally, if a field with the flag name prefixed with `"no"`
- is present, mapped to a boolean of any value, the specified flag is unset.
- E.g. A flag field of value
- {place_center_x = true, place_center_y=false, place_center_z=true}
- is equivalent to
- {place_center_x = true, noplace_center_y=true, place_center_z=true}
- which is equivalent to
- "place_center_x, noplace_center_y, place_center_z"
- or even
- "place_center_x, place_center_z"
- since, by default, no schematic attributes are set.
- Formspec
- --------
- Formspec defines a menu. It is a string, with a somewhat strange format.
- Spaces and newlines can be inserted between the blocks, as is used in the
- examples.
- ### Examples
- #### Chest
- size[8,9]
- list[context;main;0,0;8,4;]
- list[current_player;main;0,5;8,4;]
- #### Furnace
- size[8,9]
- list[context;fuel;2,3;1,1;]
- list[context;src;2,1;1,1;]
- list[context;dst;5,1;2,2;]
- list[current_player;main;0,5;8,4;]
- #### Minecraft-like player inventory
- size[8,7.5]
- image[1,0.6;1,2;player.png]
- list[current_player;main;0,3.5;8,4;]
- list[current_player;craft;3,0;3,3;]
- list[current_player;craftpreview;7,1;1,1;]
- ### Elements
- #### `size[<W>,<H>,<fixed_size>]`
- * Define the size of the menu in inventory slots
- * `fixed_size`: `true`/`false` (optional)
- * deprecated: `invsize[<W>,<H>;]`
- #### `container[<X>,<Y>]`
- * Start of a container block, moves all physical elements in the container by (X, Y)
- * Must have matching container_end
- * Containers can be nested, in which case the offsets are added
- (child containers are relative to parent containers)
- #### `container_end[]`
- * End of a container, following elements are no longer relative to this container
- #### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]`
- * Show an inventory list
- #### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
- * Show an inventory list
- #### `listring[<inventory location>;<list name>]`
- * Allows to create a ring of inventory lists
- * Shift-clicking on items in one element of the ring
- will send them to the next inventory list inside the ring
- * The first occurrence of an element inside the ring will
- determine the inventory where items will be sent to
- #### `listring[]`
- * Shorthand for doing `listring[<inventory location>;<list name>]`
- for the last two inventory lists added by list[...]
- #### `listcolors[<slot_bg_normal>;<slot_bg_hover>]`
- * Sets background color of slots as `ColorString`
- * Sets background color of slots on mouse hovering
- #### `listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>]`
- * Sets background color of slots as `ColorString`
- * Sets background color of slots on mouse hovering
- * Sets color of slots border
- #### `listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>;<tooltip_bgcolor>;<tooltip_fontcolor>]`
- * Sets background color of slots as `ColorString`
- * Sets background color of slots on mouse hovering
- * Sets color of slots border
- * Sets default background color of tooltips
- * Sets default font color of tooltips
- #### `tooltip[<gui_element_name>;<tooltip_text>;<bgcolor>,<fontcolor>]`
- * Adds tooltip for an element
- * `<bgcolor>` tooltip background color as `ColorString` (optional)
- * `<fontcolor>` tooltip font color as `ColorString` (optional)
- #### `image[<X>,<Y>;<W>,<H>;<texture name>]`
- * Show an image
- * Position and size units are inventory slots
- #### `item_image[<X>,<Y>;<W>,<H>;<item name>]`
- * Show an inventory image of registered item/node
- * Position and size units are inventory slots
- #### `bgcolor[<color>;<fullscreen>]`
- * Sets background color of formspec as `ColorString`
- * If `true`, the background color is drawn fullscreen (does not effect the size of the formspec)
- #### `background[<X>,<Y>;<W>,<H>;<texture name>]`
- * Use a background. Inventory rectangles are not drawn then.
- * Position and size units are inventory slots
- * Example for formspec 8x4 in 16x resolution: image shall be sized
- 8 times 16px times 4 times 16px.
- #### `background[<X>,<Y>;<W>,<H>;<texture name>;<auto_clip>]`
- * Use a background. Inventory rectangles are not drawn then.
- * Position and size units are inventory slots
- * Example for formspec 8x4 in 16x resolution:
- image shall be sized 8 times 16px times 4 times 16px
- * If `true` the background is clipped to formspec size
- (`x` and `y` are used as offset values, `w` and `h` are ignored)
- #### `pwdfield[<X>,<Y>;<W>,<H>;<name>;<label>]`
- * Textual password style field; will be sent to server when a button is clicked
- * When enter is pressed in field, fields.key_enter_field will be sent with the name
- of this field.
- * `x` and `y` position the field relative to the top left of the menu
- * `w` and `h` are the size of the field
- * Fields are a set height, but will be vertically centred on `h`
- * Position and size units are inventory slots
- * `name` is the name of the field as returned in fields to `on_receive_fields`
- * `label`, if not blank, will be text printed on the top left above the field
- * See field_close_on_enter to stop enter closing the formspec
- #### `field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
- * Textual field; will be sent to server when a button is clicked
- * When enter is pressed in field, fields.key_enter_field will be sent with the name
- of this field.
- * `x` and `y` position the field relative to the top left of the menu
- * `w` and `h` are the size of the field
- * Fields are a set height, but will be vertically centred on `h`
- * Position and size units are inventory slots
- * `name` is the name of the field as returned in fields to `on_receive_fields`
- * `label`, if not blank, will be text printed on the top left above the field
- * `default` is the default value of the field
- * `default` may contain variable references such as `${text}'` which
- will fill the value from the metadata value `text`
- * **Note**: no extra text or more than a single variable is supported ATM.
- * See field_close_on_enter to stop enter closing the formspec
- #### `field[<name>;<label>;<default>]`
- * As above, but without position/size units
- * When enter is pressed in field, fields.key_enter_field will be sent with the name
- of this field.
- * Special field for creating simple forms, such as sign text input
- * Must be used without a `size[]` element
- * A "Proceed" button will be added automatically
- * See field_close_on_enter to stop enter closing the formspec
- #### `field_close_on_enter[<name>;<close_on_enter>]`
- * <name> is the name of the field
- * if <close_on_enter> is false, pressing enter in the field will submit the form but not close it
- * defaults to true when not specified (ie: no tag for a field)
- #### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
- * Same as fields above, but with multi-line input
- #### `label[<X>,<Y>;<label>]`
- * `x` and `y` work as per field
- * `label` is the text on the label
- * Position and size units are inventory slots
- #### `vertlabel[<X>,<Y>;<label>]`
- * Textual label drawn vertically
- * `x` and `y` work as per field
- * `label` is the text on the label
- * Position and size units are inventory slots
- #### `button[<X>,<Y>;<W>,<H>;<name>;<label>]`
- * Clickable button. When clicked, fields will be sent.
- * `x`, `y` and `name` work as per field
- * `w` and `h` are the size of the button
- * Fixed button height. It will be vertically centred on `h`
- * `label` is the text on the button
- * Position and size units are inventory slots
- #### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
- * `x`, `y`, `w`, `h`, and `name` work as per button
- * `texture name` is the filename of an image
- * Position and size units are inventory slots
- #### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>;<noclip>;<drawborder>;<pressed texture name>]`
- * `x`, `y`, `w`, `h`, and `name` work as per button
- * `texture name` is the filename of an image
- * Position and size units are inventory slots
- * `noclip=true` means the image button doesn't need to be within specified formsize
- * `drawborder`: draw button border or not
- * `pressed texture name` is the filename of an image on pressed state
- #### `item_image_button[<X>,<Y>;<W>,<H>;<item name>;<name>;<label>]`
- * `x`, `y`, `w`, `h`, `name` and `label` work as per button
- * `item name` is the registered name of an item/node,
- tooltip will be made out of its description
- to override it use tooltip element
- * Position and size units are inventory slots
- #### `button_exit[<X>,<Y>;<W>,<H>;<name>;<label>]`
- * When clicked, fields will be sent and the form will quit.
- #### `image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
- * When clicked, fields will be sent and the form will quit.
- #### `textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>]`
- * Scrollable item list showing arbitrary text elements
- * `x` and `y` position the itemlist relative to the top left of the menu
- * `w` and `h` are the size of the itemlist
- * `name` fieldname sent to server on doubleclick value is current selected element
- * `listelements` can be prepended by #color in hexadecimal format RRGGBB (only),
- * if you want a listelement to start with "#" write "##".
- #### `textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<selected idx>;<transparent>]`
- * Scrollable itemlist showing arbitrary text elements
- * `x` and `y` position the item list relative to the top left of the menu
- * `w` and `h` are the size of the item list
- * `name` fieldname sent to server on doubleclick value is current selected element
- * `listelements` can be prepended by #RRGGBB (only) in hexadecimal format
- * if you want a listelement to start with "#" write "##"
- * Index to be selected within textlist
- * `true`/`false`: draw transparent background
- * See also `minetest.explode_textlist_event` (main menu: `engine.explode_textlist_event`)
- #### `tabheader[<X>,<Y>;<name>;<caption 1>,<caption 2>,...,<caption n>;<current_tab>;<transparent>;<draw_border>]`
- * Show a tab**header** at specific position (ignores formsize)
- * `x` and `y` position the itemlist relative to the top left of the menu
- * `name` fieldname data is transferred to Lua
- * `caption 1`...: name shown on top of tab
- * `current_tab`: index of selected tab 1...
- * `transparent` (optional): show transparent
- * `draw_border` (optional): draw border
- #### `box[<X>,<Y>;<W>,<H>;<color>]`
- * Simple colored semitransparent box
- * `x` and `y` position the box relative to the top left of the menu
- * `w` and `h` are the size of box
- * `color` is color specified as a `ColorString`
- #### `dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]`
- * Show a dropdown field
- * **Important note**: There are two different operation modes:
- 1. handle directly on change (only changed dropdown is submitted)
- 2. read the value on pressing a button (all dropdown values are available)
- * `x` and `y` position of dropdown
- * Width of dropdown
- * Fieldname data is transferred to Lua
- * Items to be shown in dropdown
- * Index of currently selected dropdown item
- #### `checkbox[<X>,<Y>;<name>;<label>;<selected>]`
- * Show a checkbox
- * `x` and `y`: position of checkbox
- * `name` fieldname data is transferred to Lua
- * `label` to be shown left of checkbox
- * `selected` (optional): `true`/`false`
- #### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
- * Show a scrollbar
- * There are two ways to use it:
- 1. handle the changed event (only changed scrollbar is available)
- 2. read the value on pressing a button (all scrollbars are available)
- * `x` and `y`: position of trackbar
- * `w` and `h`: width and height
- * `orientation`: `vertical`/`horizontal`
- * Fieldname data is transferred to Lua
- * Value this trackbar is set to (`0`-`1000`)
- * See also `minetest.explode_scrollbar_event` (main menu: `engine.explode_scrollbar_event`)
- #### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
- * Show scrollable table using options defined by the previous `tableoptions[]`
- * Displays cells as defined by the previous `tablecolumns[]`
- * `x` and `y`: position the itemlist relative to the top left of the menu
- * `w` and `h` are the size of the itemlist
- * `name`: fieldname sent to server on row select or doubleclick
- * `cell 1`...`cell n`: cell contents given in row-major order
- * `selected idx`: index of row to be selected within table (first row = `1`)
- * See also `minetest.explode_table_event` (main menu: `engine.explode_table_event`)
- #### `tableoptions[<opt 1>;<opt 2>;...]`
- * Sets options for `table[]`
- * `color=#RRGGBB`
- * default text color (`ColorString`), defaults to `#FFFFFF`
- * `background=#RRGGBB`
- * table background color (`ColorString`), defaults to `#000000`
- * `border=<true/false>`
- * should the table be drawn with a border? (default: `true`)
- * `highlight=#RRGGBB`
- * highlight background color (`ColorString`), defaults to `#466432`
- * `highlight_text=#RRGGBB`
- * highlight text color (`ColorString`), defaults to `#FFFFFF`
- * `opendepth=<value>`
- * all subtrees up to `depth < value` are open (default value = `0`)
- * only useful when there is a column of type "tree"
- #### `tablecolumns[<type 1>,<opt 1a>,<opt 1b>,...;<type 2>,<opt 2a>,<opt 2b>;...]`
- * Sets columns for `table[]`
- * Types: `text`, `image`, `color`, `indent`, `tree`
- * `text`: show cell contents as text
- * `image`: cell contents are an image index, use column options to define images
- * `color`: cell contents are a ColorString and define color of following cell
- * `indent`: cell contents are a number and define indentation of following cell
- * `tree`: same as indent, but user can open and close subtrees (treeview-like)
- * Column options:
- * `align=<value>`
- * for `text` and `image`: content alignment within cells.
- Available values: `left` (default), `center`, `right`, `inline`
- * `width=<value>`
- * for `text` and `image`: minimum width in em (default: `0`)
- * for `indent` and `tree`: indent width in em (default: `1.5`)
- * `padding=<value>`: padding left of the column, in em (default `0.5`).
- Exception: defaults to 0 for indent columns
- * `tooltip=<value>`: tooltip text (default: empty)
- * `image` column options:
- * `0=<value>` sets image for image index 0
- * `1=<value>` sets image for image index 1
- * `2=<value>` sets image for image index 2
- * and so on; defined indices need not be contiguous empty or
- non-numeric cells are treated as `0`.
- * `color` column options:
- * `span=<value>`: number of following columns to affect (default: infinite)
- **Note**: do _not_ use a element name starting with `key_`; those names are reserved to
- pass key press events to formspec!
- Spatial Vectors
- ---------------
- * `vector.new(a[, b, c])`: returns a vector:
- * A copy of `a` if `a` is a vector.
- * `{x = a, y = b, z = c}`, if all `a, b, c` are defined
- * `vector.direction(p1, p2)`: returns a vector
- * `vector.distance(p1, p2)`: returns a number
- * `vector.length(v)`: returns a number
- * `vector.normalize(v)`: returns a vector
- * `vector.floor(v)`: returns a vector, each dimension rounded down
- * `vector.round(v)`: returns a vector, each dimension rounded to nearest int
- * `vector.apply(v, func)`: returns a vector
- * `vector.equals(v1, v2)`: returns a boolean
- For the following functions `x` can be either a vector or a number:
- * `vector.add(v, x)`: returns a vector
- * `vector.subtract(v, x)`: returns a vector
- * `vector.multiply(v, x)`: returns a scaled vector or Schur product
- * `vector.divide(v, x)`: returns a scaled vector or Schur quotient
- Helper functions
- ----------------
- * `dump2(obj, name="_", dumped={})`
- * Return object serialized as a string, handles reference loops
- * `dump(obj, dumped={})`
- * Return object serialized as a string
- * `math.hypot(x, y)`
- * Get the hypotenuse of a triangle with legs x and y.
- Useful for distance calculation.
- * `math.sign(x, tolerance)`
- * Get the sign of a number.
- Optional: Also returns `0` when the absolute value is within the tolerance (default: `0`)
- * `string.split(str, separator=",", include_empty=false, max_splits=-1, sep_is_pattern=false)`
- * If `max_splits` is negative, do not limit splits.
- * `sep_is_pattern` specifies if separator is a plain string or a pattern (regex).
- * e.g. `string:split("a,b", ",") == {"a","b"}`
- * `string:trim()`
- * e.g. `string.trim("\n \t\tfoo bar\t ") == "foo bar"`
- * `minetest.wrap_text(str, limit)`: returns a string
- * Adds new lines to the string to keep it within the specified character limit
- * limit: Maximal amount of characters in one line
- * `minetest.pos_to_string({x=X,y=Y,z=Z}, decimal_places))`: returns string `"(X,Y,Z)"`
- * Convert position to a printable string
- Optional: 'decimal_places' will round the x, y and z of the pos to the given decimal place.
- * `minetest.string_to_pos(string)`: returns a position
- * Same but in reverse. Returns `nil` if the string can't be parsed to a position.
- * `minetest.string_to_area("(X1, Y1, Z1) (X2, Y2, Z2)")`: returns two positions
- * Converts a string representing an area box into two positions
- * `minetest.is_yes(arg)`
- * returns whether `arg` can be interpreted as yes
- * `table.copy(table)`: returns a table
- * returns a deep copy of `table`
- Minetest namespace reference
- ------------------------------
- ### Utilities
- * `minetest.get_current_modname()`: returns the currently loading mod's name, when we are loading a mod
- * `minetest.get_language()`: returns the currently set gettext language.
- * `minetest.get_version()`: returns a table containing components of the
- engine version. Components:
- * `project`: Name of the project, eg, "Minetest"
- * `string`: Simple version, eg, "1.2.3-dev"
- * `hash`: Full git version (only set if available), eg, "1.2.3-dev-01234567-dirty"
- Use this for informational purposes only. The information in the returned
- table does not represent the capabilities of the engine, nor is it
- reliable or verifiable. Compatible forks will have a different name and
- version entirely. To check for the presence of engine features, test
- whether the functions exported by the wanted features exist. For example:
- `if minetest.check_for_falling then ... end`.
- * `minetest.sha1(data, [raw])`: returns the sha1 hash of data
- * `data`: string of data to hash
- * `raw`: return raw bytes instead of hex digits, default: false
- ### Logging
- * `minetest.debug(...)`
- * Equivalent to `minetest.log(table.concat({...}, "\t"))`
- * `minetest.log([level,] text)`
- * `level` is one of `"none"`, `"error"`, `"warning"`, `"action"`,
- `"info"`, or `"verbose"`. Default is `"none"`.
- ### Global callback registration functions
- Call these functions only at load time!
- * `minetest.register_globalstep(func(dtime))`
- * Called every client environment step, usually interval of 0.1s
- * `minetest.register_on_shutdown(func())`
- * Called before client shutdown
- * **Warning**: If the client terminates abnormally (i.e. crashes), the registered
- callbacks **will likely not be run**. Data should be saved at
- semi-frequent intervals as well as on server shutdown.
- * `minetest.register_on_connect(func())`
- * Called at the end of client connection (when player is loaded onto map)
- * `minetest.register_on_receiving_chat_message(func(message))`
- * Called always when a client receive a message
- * Return `true` to mark the message as handled, which means that it will not be shown to chat
- * `minetest.register_on_sending_chat_message(func(message))`
- * Called always when a client send a message from chat
- * Return `true` to mark the message as handled, which means that it will not be sent to server
- * `minetest.register_chatcommand(cmd, chatcommand definition)`
- * Adds definition to minetest.registered_chatcommands
- * `minetest.unregister_chatcommand(name)`
- * Unregisters a chatcommands registered with register_chatcommand.
- * `minetest.register_on_death(func())`
- * Called when the local player dies
- * `minetest.register_on_hp_modification(func(hp))`
- * Called when server modified player's HP
- * `minetest.register_on_damage_taken(func(hp))`
- * Called when the local player take damages
- * `minetest.register_on_formspec_input(func(formname, fields))`
- * Called when a button is pressed in the local player's inventory form
- * Newest functions are called first
- * If function returns `true`, remaining functions are not called
- * `minetest.register_on_dignode(func(pos, node))`
- * Called when the local player digs a node
- * Newest functions are called first
- * If any function returns true, the node isn't dug
- * `minetest.register_on_punchnode(func(pos, node))`
- * Called when the local player punches a node
- * Newest functions are called first
- * If any function returns true, the punch is ignored
- * `minetest.register_on_placenode(function(pointed_thing, node))`
- * Called when a node has been placed
- * `minetest.register_on_item_use(func(item, pointed_thing))`
- * Called when the local player uses an item.
- * Newest functions are called first.
- * If any function returns true, the item use is not sent to server.
- * `minetest.register_on_modchannel_message(func(channel_name, sender, message))`
- * Called when an incoming mod channel message is received
- * You must have joined some channels before, and server must acknowledge the
- join request.
- * If message comes from a server mod, `sender` field is an empty string.
- * `minetest.register_on_modchannel_signal(func(channel_name, signal))`
- * Called when a valid incoming mod channel signal is received
- * Signal id permit to react to server mod channel events
- * Possible values are:
- 0: join_ok
- 1: join_failed
- 2: leave_ok
- 3: leave_failed
- 4: event_on_not_joined_channel
- 5: state_changed
- * `minetest.register_on_inventory_open(func(inventory))`
- * Called when the local player open inventory
- * Newest functions are called first
- * If any function returns true, inventory doesn't open
- ### Sounds
- * `minetest.sound_play(spec, parameters)`: returns a handle
- * `spec` is a `SimpleSoundSpec`
- * `parameters` is a sound parameter table
- * `minetest.sound_stop(handle)`
- ### Timing
- * `minetest.after(time, func, ...)`
- * Call the function `func` after `time` seconds, may be fractional
- * Optional: Variable number of arguments that are passed to `func`
- * `minetest.get_us_time()`
- * Returns time with microsecond precision. May not return wall time.
- * `minetest.get_day_count()`
- * Returns number days elapsed since world was created, accounting for time changes.
- * `minetest.get_timeofday()`
- * Returns the time of day: `0` for midnight, `0.5` for midday
- ### Map
- * `minetest.get_node_or_nil(pos)`
- * Returns the node at the given position as table in the format
- `{name="node_name", param1=0, param2=0}`, returns `nil`
- for unloaded areas or flavor limited areas.
- * `minetest.find_node_near(pos, radius, nodenames, [search_center])`: returns pos or `nil`
- * `radius`: using a maximum metric
- * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
- * `search_center` is an optional boolean (default: `false`)
- If true `pos` is also checked for the nodes
- * `minetest.get_meta(pos)`
- * Get a `NodeMetaRef` at that position
- * `minetest.get_node_level(pos)`
- * get level of leveled node (water, snow)
- * `minetest.get_node_max_level(pos)`
- * get max available level for leveled node
- ### Player
- * `minetest.get_wielded_item()`
- * Returns the itemstack the local player is holding
- * `minetest.send_chat_message(message)`
- * Act as if `message` was typed by the player into the terminal.
- * `minetest.run_server_chatcommand(cmd, param)`
- * Alias for `minetest.send_chat_message("/" .. cmd .. " " .. param)`
- * `minetest.clear_out_chat_queue()`
- * Clears the out chat queue
- * `minetest.localplayer`
- * Reference to the LocalPlayer object. See [`LocalPlayer`](#localplayer) class reference for methods.
- ### Privileges
- * `minetest.get_privilege_list()`
- * Returns a list of privileges the current player has in the format `{priv1=true,...}`
- * `minetest.string_to_privs(str)`: returns `{priv1=true,...}`
- * `minetest.privs_to_string(privs)`: returns `"priv1,priv2,..."`
- * Convert between two privilege representations
- ### Client Environment
- * `minetest.get_player_names()`
- * Returns list of player names on server
- * `minetest.disconnect()`
- * Disconnect from the server and exit to main menu.
- * Returns `false` if the client is already disconnecting otherwise returns `true`.
- * `minetest.take_screenshot()`
- * Take a screenshot.
- * `minetest.get_server_info()`
- * Returns [server info](#server-info).
- * `minetest.send_respawn()`
- * Sends a respawn request to the server.
- ### Storage API
- * `minetest.get_mod_storage()`:
- * returns reference to mod private `StorageRef`
- * must be called during mod load time
- ### Mod channels
- ![Mod channels communication scheme](docs/mod channels.png)
- * `minetest.mod_channel_join(channel_name)`
- * Client joins channel `channel_name`, and creates it, if necessary. You
- should listen from incoming messages with `minetest.register_on_modchannel_message`
- call to receive incoming messages. Warning, this function is asynchronous.
- * You should use a minetest.register_on_connect(function() ... end) to perform
- a successful channel join on client startup.
- ### Misc.
- * `minetest.parse_json(string[, nullvalue])`: returns something
- * Convert a string containing JSON data into the Lua equivalent
- * `nullvalue`: returned in place of the JSON null; defaults to `nil`
- * On success returns a table, a string, a number, a boolean or `nullvalue`
- * On failure outputs an error message and returns `nil`
- * Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}`
- * `minetest.write_json(data[, styled])`: returns a string or `nil` and an error message
- * Convert a Lua table into a JSON string
- * styled: Outputs in a human-readable format if this is set, defaults to false
- * Unserializable things like functions and userdata are saved as null.
- * **Warning**: JSON is more strict than the Lua table format.
- 1. You can only use strings and positive integers of at least one as keys.
- 2. You can not mix string and integer keys.
- This is due to the fact that JSON has two distinct array and object values.
- * Example: `write_json({10, {a = false}})`, returns `"[10, {\"a\": false}]"`
- * `minetest.serialize(table)`: returns a string
- * Convert a table containing tables, strings, numbers, booleans and `nil`s
- into string form readable by `minetest.deserialize`
- * Example: `serialize({foo='bar'})`, returns `'return { ["foo"] = "bar" }'`
- * `minetest.deserialize(string)`: returns a table
- * Convert a string returned by `minetest.deserialize` into a table
- * `string` is loaded in an empty sandbox environment.
- * Will load functions, but they cannot access the global environment.
- * Example: `deserialize('return { ["foo"] = "bar" }')`, returns `{foo='bar'}`
- * Example: `deserialize('print("foo")')`, returns `nil` (function call fails)
- * `error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)`
- * `minetest.compress(data, method, ...)`: returns `compressed_data`
- * Compress a string of data.
- * `method` is a string identifying the compression method to be used.
- * Supported compression methods:
- * Deflate (zlib): `"deflate"`
- * `...` indicates method-specific arguments. Currently defined arguments are:
- * Deflate: `level` - Compression level, `0`-`9` or `nil`.
- * `minetest.decompress(compressed_data, method, ...)`: returns data
- * Decompress a string of data (using ZLib).
- * See documentation on `minetest.compress()` for supported compression methods.
- * currently supported.
- * `...` indicates method-specific arguments. Currently, no methods use this.
- * `minetest.rgba(red, green, blue[, alpha])`: returns a string
- * Each argument is a 8 Bit unsigned integer
- * Returns the ColorString from rgb or rgba values
- * Example: `minetest.rgba(10, 20, 30, 40)`, returns `"#0A141E28"`
- * `minetest.encode_base64(string)`: returns string encoded in base64
- * Encodes a string in base64.
- * `minetest.decode_base64(string)`: returns string
- * Decodes a string encoded in base64.
- * `minetest.gettext(string)` : returns string
- * look up the translation of a string in the gettext message catalog
- * `fgettext_ne(string, ...)`
- * call minetest.gettext(string), replace "$1"..."$9" with the given
- extra arguments and return the result
- * `fgettext(string, ...)` : returns string
- * same as fgettext_ne(), but calls minetest.formspec_escape before returning result
- * `minetest.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a position
- * returns the exact position on the surface of a pointed node
- * `minetest.global_exists(name)`
- * Checks if a global variable has been set, without triggering a warning.
- ### UI
- * `minetest.ui.minimap`
- * Reference to the minimap object. See [`Minimap`](#minimap) class reference for methods.
- * If client disabled minimap (using enable_minimap setting) this reference will be nil.
- * `minetest.camera`
- * Reference to the camera object. See [`Camera`](#camera) class reference for methods.
- * `minetest.show_formspec(formname, formspec)` : returns true on success
- * Shows a formspec to the player
- * `minetest.display_chat_message(message)` returns true on success
- * Shows a chat message to the current player.
- Class reference
- ---------------
- ### ModChannel
- An interface to use mod channels on client and server
- #### Methods
- * `leave()`: leave the mod channel.
- * Client leaves channel `channel_name`.
- * No more incoming or outgoing messages can be sent to this channel from client mods.
- * This invalidate all future object usage
- * Ensure your set mod_channel to nil after that to free Lua resources
- * `is_writeable()`: returns true if channel is writable and mod can send over it.
- * `send_all(message)`: Send `message` though the mod channel.
- * If mod channel is not writable or invalid, message will be dropped.
- * Message size is limited to 65535 characters by protocol.
- ### Minimap
- An interface to manipulate minimap on client UI
- #### Methods
- * `show()`: shows the minimap (if not disabled by server)
- * `hide()`: hides the minimap
- * `set_pos(pos)`: sets the minimap position on screen
- * `get_pos()`: returns the minimap current position
- * `set_angle(deg)`: sets the minimap angle in degrees
- * `get_angle()`: returns the current minimap angle in degrees
- * `set_mode(mode)`: sets the minimap mode (0 to 6)
- * `get_mode()`: returns the current minimap mode
- * `set_shape(shape)`: Sets the minimap shape. (0 = square, 1 = round)
- * `get_shape()`: Gets the minimap shape. (0 = square, 1 = round)
- ### Camera
- An interface to get or set information about the camera and camera-node.
- Please do not try to access the reference until the camera is initialized, otherwise the reference will be nil.
- #### Methods
- * `set_camera_mode(mode)`
- * Pass `0` for first-person, `1` for third person, and `2` for third person front
- * `get_camera_mode()`
- * Returns 0, 1, or 2 as described above
- * `get_fov()`
- * Returns:
- ```lua
- {
- x = number,
- y = number,
- max = number,
- actual = number
- }
- ```
- * `get_pos()`
- * Returns position of camera with view bobbing
- * `get_offset()`
- * Returns eye offset vector
- * `get_look_dir()`
- * Returns eye direction unit vector
- * `get_look_vertical()`
- * Returns pitch in radians
- * `get_look_horizontal()`
- * Returns yaw in radians
- * `get_aspect_ratio()`
- * Returns aspect ratio of screen
- ### LocalPlayer
- An interface to retrieve information about the player. The player is
- not accessible until the client is fully done loading and therefore
- not at module init time.
- To get the localplayer handle correctly, use `on_connect()` as follows:
- ```lua
- local localplayer
- minetest.register_on_connect(function()
- localplayer = minetest.localplayer
- end)
- ```
- Methods:
- * `get_pos()`
- * returns current player current position
- * `get_velocity()`
- * returns player speed vector
- * `get_hp()`
- * returns player HP
- * `get_name()`
- * returns player name
- * `is_attached()`
- * returns true if player is attached
- * `is_touching_ground()`
- * returns true if player touching ground
- * `is_in_liquid()`
- * returns true if player is in a liquid (This oscillates so that the player jumps a bit above the surface)
- * `is_in_liquid_stable()`
- * returns true if player is in a stable liquid (This is more stable and defines the maximum speed of the player)
- * `get_liquid_viscosity()`
- * returns liquid viscosity (Gets the viscosity of liquid to calculate friction)
- * `is_climbing()`
- * returns true if player is climbing
- * `swimming_vertical()`
- * returns true if player is swimming in vertical
- * `get_physics_override()`
- * returns:
- ```lua
- {
- speed = float,
- jump = float,
- gravity = float,
- sneak = boolean,
- sneak_glitch = boolean
- }
- ```
- * `get_override_pos()`
- * returns override position
- * `get_last_pos()`
- * returns last player position before the current client step
- * `get_last_velocity()`
- * returns last player speed
- * `get_breath()`
- * returns the player's breath
- * `get_movement_acceleration()`
- * returns acceleration of the player in different environments:
- ```lua
- {
- fast = float,
- air = float,
- default = float,
- }
- ```
- * `get_movement_speed()`
- * returns player's speed in different environments:
- ```lua
- {
- walk = float,
- jump = float,
- crouch = float,
- fast = float,
- climb = float,
- }
- ```
- * `get_movement()`
- * returns player's movement in different environments:
- ```lua
- {
- liquid_fluidity = float,
- liquid_sink = float,
- liquid_fluidity_smooth = float,
- gravity = float,
- }
- ```
- * `get_last_look_horizontal()`:
- * returns last look horizontal angle
- * `get_last_look_vertical()`:
- * returns last look vertical angle
- * `get_key_pressed()`:
- * returns last key typed by the player
- ### Settings
- An interface to read config files in the format of `minetest.conf`.
- It can be created via `Settings(filename)`.
- #### Methods
- * `get(key)`: returns a value
- * `get_bool(key)`: returns a boolean
- * `set(key, value)`
- * `remove(key)`: returns a boolean (`true` for success)
- * `get_names()`: returns `{key1,...}`
- * `write()`: returns a boolean (`true` for success)
- * write changes to file
- * `to_table()`: returns `{[key1]=value1,...}`
- ### NodeMetaRef
- Node metadata: reference extra data and functionality stored in a node.
- Can be obtained via `minetest.get_meta(pos)`.
- #### Methods
- * `get_string(name)`
- * `get_int(name)`
- * `get_float(name)`
- * `to_table()`: returns `nil` or a table with keys:
- * `fields`: key-value storage
- * `inventory`: `{list1 = {}, ...}}`
- -----------------
- ### Definitions
- * `minetest.get_node_def(nodename)`
- * Returns [node definition](#node-definition) table of `nodename`
- * `minetest.get_item_def(itemstring)`
- * Returns item definition table of `itemstring`
- #### Node Definition
- ```lua
- {
- has_on_construct = bool, -- Whether the node has the on_construct callback defined
- has_on_destruct = bool, -- Whether the node has the on_destruct callback defined
- has_after_destruct = bool, -- Whether the node has the after_destruct callback defined
- name = string, -- The name of the node e.g. "air", "default:dirt"
- groups = table, -- The groups of the node
- paramtype = string, -- Paramtype of the node
- paramtype2 = string, -- ParamType2 of the node
- drawtype = string, -- Drawtype of the node
- mesh = <string>, -- Mesh name if existant
- minimap_color = <Color>, -- Color of node on minimap *May not exist*
- visual_scale = number, -- Visual scale of node
- alpha = number, -- Alpha of the node. Only used for liquids
- color = <Color>, -- Color of node *May not exist*
- palette_name = <string>, -- Filename of palette *May not exist*
- palette = <{ -- List of colors
- Color,
- Color
- }>,
- waving = number, -- 0 of not waving, 1 if waving
- connect_sides = number, -- Used for connected nodes
- connects_to = { -- List of nodes to connect to
- "node1",
- "node2"
- },
- post_effect_color = Color, -- Color overlayed on the screen when the player is in the node
- leveled = number, -- Max level for node
- sunlight_propogates = bool, -- Whether light passes through the block
- light_source = number, -- Light emitted by the block
- is_ground_content = bool, -- Whether caves should cut through the node
- walkable = bool, -- Whether the player collides with the node
- pointable = bool, -- Whether the player can select the node
- diggable = bool, -- Whether the player can dig the node
- climbable = bool, -- Whether the player can climb up the node
- buildable_to = bool, -- Whether the player can replace the node by placing a node on it
- rightclickable = bool, -- Whether the player can place nodes pointing at this node
- damage_per_second = number, -- HP of damage per second when the player is in the node
- liquid_type = <string>, -- A string containing "none", "flowing", or "source" *May not exist*
- liquid_alternative_flowing = <string>, -- Alternative node for liquid *May not exist*
- liquid_alternative_source = <string>, -- Alternative node for liquid *May not exist*
- liquid_viscosity = <number>, -- How fast the liquid flows *May not exist*
- liquid_renewable = <boolean>, -- Whether the liquid makes an infinite source *May not exist*
- liquid_range = <number>, -- How far the liquid flows *May not exist*
- drowning = bool, -- Whether the player will drown in the node
- floodable = bool, -- Whether nodes will be replaced by liquids (flooded)
- node_box = table, -- Nodebox to draw the node with
- collision_box = table, -- Nodebox to set the collision area
- selection_box = table, -- Nodebox to set the area selected by the player
- sounds = { -- Table of sounds that the block makes
- sound_footstep = SimpleSoundSpec,
- sound_dig = SimpleSoundSpec,
- sound_dug = SimpleSoundSpec
- },
- legacy_facedir_simple = bool, -- Whether to use old facedir
- legacy_wallmounted = bool -- Whether to use old wallmounted
- }
- ```
- #### Item Definition
- ```lua
- {
- name = string, -- Name of the item e.g. "default:stone"
- description = string, -- Description of the item e.g. "Stone"
- type = string, -- Item type: "none", "node", "craftitem", "tool"
- inventory_image = string, -- Image in the inventory
- wield_image = string, -- Image in wieldmesh
- palette_image = string, -- Image for palette
- color = Color, -- Color for item
- wield_scale = Vector, -- Wieldmesh scale
- stack_max = number, -- Number of items stackable together
- usable = bool, -- Has on_use callback defined
- liquids_pointable = bool, -- Whether you can point at liquids with the item
- tool_capabilities = <table>, -- If the item is a tool, tool capabilities of the item
- groups = table, -- Groups of the item
- sound_place = SimpleSoundSpec, -- Sound played when placed
- sound_place_failed = SimpleSoundSpec, -- Sound played when placement failed
- node_placement_prediction = string -- Node placed in client until server catches up
- }
- ```
- -----------------
- ### Chat command definition (`register_chatcommand`)
- {
- params = "<name> <privilege>", -- Short parameter description
- description = "Remove privilege from player", -- Full description
- func = function(param), -- Called when command is run.
- -- Returns boolean success and text output.
- }
- ### Server info
- ```lua
- {
- address = "minetest.example.org", -- The domain name/IP address of a remote server or "" for a local server.
- ip = "203.0.113.156", -- The IP address of the server.
- port = 30000, -- The port the client is connected to.
- protocol_version = 30 -- Will not be accurate at start up as the client might not be connected to the server yet, in that case it will be 0.
- }
- ```
- Escape sequences
- ----------------
- Most text can contain escape sequences, that can for example color the text.
- There are a few exceptions: tab headers, dropdowns and vertical labels can't.
- The following functions provide escape sequences:
- * `minetest.get_color_escape_sequence(color)`:
- * `color` is a [ColorString](#colorstring)
- * The escape sequence sets the text color to `color`
- * `minetest.colorize(color, message)`:
- * Equivalent to:
- `minetest.get_color_escape_sequence(color) ..
- message ..
- minetest.get_color_escape_sequence("#ffffff")`
- * `minetest.get_background_escape_sequence(color)`
- * `color` is a [ColorString](#colorstring)
- * The escape sequence sets the background of the whole text element to
- `color`. Only defined for item descriptions and tooltips.
- * `minetest.strip_foreground_colors(str)`
- * Removes foreground colors added by `get_color_escape_sequence`.
- * `minetest.strip_background_colors(str)`
- * Removes background colors added by `get_background_escape_sequence`.
- * `minetest.strip_colors(str)`
- * Removes all color escape sequences.
- `ColorString`
- -------------
- `#RGB` defines a color in hexadecimal format.
- `#RGBA` defines a color in hexadecimal format and alpha channel.
- `#RRGGBB` defines a color in hexadecimal format.
- `#RRGGBBAA` defines a color in hexadecimal format and alpha channel.
- Named colors are also supported and are equivalent to
- [CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors).
- To specify the value of the alpha channel, append `#AA` to the end of the color name
- (e.g. `colorname#08`). For named colors the hexadecimal string representing the alpha
- value must (always) be two hexadecimal digits.
- `Color`
- -------------
- `{a = alpha, r = red, g = green, b = blue}` defines an ARGB8 color.
|