Game specs

A game spec defines the starting layout for a game: which pieces start on the table, and where.

It also defines some ancillary information about the game and its layout. It does not contain information about the players. Players join a game as permitted by the game access control list, which is specified in a table specification (sadly not currently properly documented, but look at the Rustdoc for TableSpec).

General

A game spec is a TOML file. It has the following entries at the top level:

  • table_size: Size of the table playing area, in Otter internal units. [array of 2 numbers, default [300,200]]
  • table_colour: Table backdrop colour. Only certain colour syntaxes are supported. [string, colour; default green]
  • pcaliases: [dictionary, values are Piece Spec dicts]. Piece alias definitions. This is used by the "Alias" piece spec.
  • pieces: Array of Piece Specs. Defines the initial pieces and their layout. Each entry is a piece spec dictionary.

Templating

Before being parsed as TOML, the spec can be processed as a one-off Tera template. This is useful because game setups can be rather repetitive.

Template expansion is done if the file starts, precisely, with the characters {# (which are the Tera comment introducer).

Tera does not natively support within-same-file macros. To allow use of macros in Otter’s single-file game specs, Otter can automatically split a game spec file into two pieces and feed them to Tera as two files.

Splitting is done if the file contains a line starting with precisely {% endmacro (the usual form of the Tera macro end sequence).

Everything up to and including the last such line is fed to Tera as if it were a file called m. Everything else is fed to Tera as if it were a second file called spec. Additionally, a line {% import "m" as m %} is added to the top of spec, so that the macros are automatically imported and can be called with {[ m::MACRO...}}. And enough blank lines are added to make the input line numbers match up with the lines in the notional spec file.

Note that line numbers reported during TOML parsing refer to lines in the template-expanded output. To help diagnose your templates, otter -vv reset ... will expand the templates itself and print out the results of the file splitting, and then of the expansion, before sending the file to the server.

For details of the template syntax, see the Tera documentation. For examples, see the built-in game specs.

Piece Specs

A piece spec is a dictionary defining one or more pieces. When part of a game spec, it appears as an entry in the top-level pieces array, and also defines the location(s) on the table to place the pieces, too.

There is a required entry type, a string. This determines how the rest of the table is interpreted. It is one of the Piece Spec Types.

Universal parameters

These apply regardless of the value of type.

  • type: Piece type or piece spec type. One of the types listed in Piece Spec Types. [string, enum, required]
  • pos: Position, in game coordinates, of the centre of the piece. The origin is at the top left. [2-element array, default [20,20]]
  • count: Place multiple identical copies of this piece. [number]
  • posd: Position delta. When a spec specifies multiple pieces, each successive piece will be shifted by this amount. [2-element array, default [5,5]]
  • face: Initial face to show (ie, “which way up” the piece starts). The default face is 0. For most pieces that is the front, and is usually a good choice. [number]
  • pinned: Whether the piece is pinned to the table. Players can pin and unpin pieces during the game; this is the initial state. [boolean]
  • angle: Initial orientation of the piece. The specified value is multiplied by 45 degrees, increasing values rotating anticlockwise. So for example 6 would mean to rotate 90 degrees clockwise. [integer 0..7]

Common parameters

Depending on the type, some of these parameters will be honoured. This is discussed in the descriptions for each piece spec type.

  • colour: The fill colour. For a piece type which supports only one face. [string, colour]

  • faces: The main fill colour(s). [array of string(s), colours]

  • edge: The edge colour to draw. For a piece with supports only one face. Default is not to draw edges. [string, colour]

  • edges: The colour of edges to draw. Default is not to draw edges. Must either be a 1-element array, or as long as faces (specifying a different edge colour for each face). [array of string(s), colours]

  • edge_width [number, default 0.2 if edge or edges is specified]

  • label. Controls display of the label with information about the in-game state. Dictionary with two sub-entries:

    • colour [string, defaults to the edge colour].
    • place [string]: One of "BottomLeft" (default), "TopLeft", "BottomLeftOutside", "TopLeftOutside".
  • shape. The shape of a piece. Dictionary with two sub-entries:
    • type. "Circle" or "Rect" [required]
    • size [array of 1 or 2 numbers]: required if type="Rect".
    • diam [number]: required if type="Circle".
  • itemname: Used when other parts of the game want to refer to this one. [string]

Piece Spec Types

"Lib"

A single shape from a piece library.

  • lib: The library name. [string, required]
  • item: The item name within that library. [string, required]

Example:

[[pieces]]
pos = [150,100]
type = "Lib"
lib = "edited"
item = "chess-board"
pinned = true

"LibList"

Multiple shapes from a piece library. Cannot be used with the count universal parameter.

  • lib: The library name. [string, required]
  • items: The item names. [array of strings, required]
  • prefix, suffix: Prepended and appended to each entry in items. Useful for abbreviating. [strings]

Example:

[[pieces]]
pos = [150, 84]
type = "LibList"
lib = "cards-oxymoron"
prefix = "card-oxymoron-"
suffix = "-s"
items = [
    "2","3","4","5","6","7","8","9","T","J","Q","K","A",
    "2","3","4","5","6","7","8","9","T","J","Q","K","A",
    "2","3","4","5","6","7","8","9","T","J","Q","K","A",
]
posd = [0, 0]

"ChessClock"

A chess clock. Additional parameters:

  • time: Initial time for each player. [number, in seconds; required]
  • per_move: Time to add per move. [number, in seconds]

(These clock settings cannot be reconfigured via the game UI.)

Example:

[[pieces]]
pos = [240, 100]
type = "ChessClock"
time = 900
per_move = 30

"PickupDeck"

A pickup or play deck. This can occult the pieces (eg, cards) you put on it, shuffling them and hiding their identity.

Requires face and shape. Only shape.type="Rect" is supported.

Honours edges, edge_width.

Honours label, displaying the number of of pieces in (on) this deck.

Example:

[[pieces]]
pos = [136,115]
type = "PickupDeck"
faces = ["lightblue", "grey"]
edges = ["black", "white"]
label.colour = "black"
label.place = "BottomLeftOutside"
shape.type = "Rect"
shape.xy = [25,30]

"Hand"

A player hand. When active, arranges for only that player to be able tos see the contents. The other players see the occulted view (eg, the backs of cards).

Requires colour and shape. Only shape.type="Rect" is supported.

Honours edge, edge_width.

Honours label, displaying the player whose hand this is, when active.

Example:

[[pieces]]
pos = [53, 25]
colour = "brown"
label.place = "BottomLeftOutside"
label.colour = "black"

type = "Hand"
edge = "white"
edge_width = 0.75
shape.type = "Rect"
shape.xy = [93,25]

"PlayerLabel"

A simple label which can display a player name.

Requires colour and shape. Only shape.type="Rect" is supported.

Honours edge, edge_width.

Honours label.

"Rect"

A plain rectangular piece.

  • size: Size and shape [array of 1 or 2 numbers, required]

Requires faces.

Honours itemname, edges and edge_width.

Exammple:

[[pieces]]
pos = [20, 85]
type = "Rect"
faces = ["yellow","#f4f"]
posd = [10, 0]
size = [7,7]
count = 8

"Disc"

A plain circular piece.

  • diam [number, required].

Requires faces.

Honours itemname, edges and edge_width.

"Alias"

An alias (generally defined in pcaliases in the game spec).

This allows a piece spec (which can be found in a shape library) to refer to something which depends on the game spec.

  • target: Alias name.

Example, in GAME.game.toml:

[pcaliases.card-back]
type = "Lib"
lib = "wikimedia"
item = "card-plain-back-maroon"

And in library/LIB.toml:

[group.clubs]
item_prefix = "card-oxymoron-"
outline = "Rect"
size = [73, 97]
centre = [36.5, 48.5]
scale = 0.25

item_suffix = "-c"
sort = "card-playing-c_s"
desc_template = "the _desc of clubs"

occulted.method = "ByBack"
occulted.ilk = "card-back"

files = """
:             sort
2     -       02      two
3     -       03      three
4     -       04      four
5     -       05      five
6     -       06      six
7     -       07      seven
8     -       08      eight
9     -       09      nine
T     -       10      ten
J     -       11      jack
Q     -       12      queen
K     -       13      king
A     -       14      ace
"""

[group.clubs.back]
type = "Alias"
target = "card-back"