4 A game spec defines the starting layout for a game: **which pieces start
5 on the table, and where**.
7 It also defines some ancillary information about the game and its
8 layout. It does not contain information about the players.
9 Players join a game as permitted by the game access control list,
10 which is specified in a *table specification* (sadly not currently
11 properly documented, but look at the Rustdoc for ``TableSpec``).
16 A game spec is a TOML file. It has the following entries at the top
19 * ``table_size``: Size of the table playing area, in Otter internal
20 units. [array of 2 numbers, default ``[300,200]``]
22 * ``table_colour``: Table backdrop colour. Only certain colour
23 syntaxes are supported. [string, colour; default ``green``]
25 * ``pcaliases``: [dictionary, values are Piece Spec dicts]. Piece
26 alias definitions. This is used by the ``"Alias"`` piece spec.
28 * ``pieces``: Array of `Piece Specs`_. Defines the initial pieces
29 and their layout. Each entry is a piece spec dictionary.
31 * ``format`` [integer]: Specifies which version of the Otter data
32 formats the spec file was written to.
33 This document describes ``format=1``.
34 See :ref:`bundle-compatibility`.
40 Before being parsed as TOML, the spec can be processed as a one-off
41 Tera template. This is useful because game setups can be rather
44 Template expansion is done if the file starts, precisely, with the
45 characters ``{#`` (which are the Tera comment introducer).
47 Tera does not natively support within-same-file macros. To allow use
48 of macros in Otter's single-file game specs, Otter can automatically
49 split a game spec file into two pieces and feed them to Tera as two
52 Splitting is done if the file contains a line starting with precisely
53 ``{% endmacro`` (the usual form of the Tera macro end sequence).
55 Everything up to and including the `last` such line is fed to Tera as
56 if it were a file called ``m``. Everything else is fed to Tera as if
57 it were a second file called ``spec``. Additionally, a line ``{%
58 import "m" as m %}`` is added to the top of ``spec``, so that the
59 macros are automatically imported and can be called with ``{[
60 m::MACRO...}}``. And enough blank lines are added to make the input
61 line numbers match up with the lines in the notional ``spec`` file.
63 Note that line numbers reported during TOML parsing
64 refer to lines in the template-expanded output.
65 To help diagnose your templates, ``otter -vv reset ...`` will expand
66 the templates itself and print out the results of the file splitting,
67 and then of the expansion, before sending the file to the server.
69 For details of the template syntax, see `the Tera documentation`_.
70 For examples, see the built-in game specs.
72 .. _the Tera documentation: https://tera.netlify.app/docs/#templates
77 A piece spec is a dictionary defining one or more pieces. When part
78 of a game spec, it appears as an entry in the top-level ``pieces``
79 array, and also defines the location(s) on the table to place the
82 There is a required entry ``type``, a string. This determines how the
83 rest of the table is interpreted. It is one of the `Piece Spec
89 These apply regardless of the value of ``type``.
91 * ``type``: Piece type or piece spec type. One of the types listed
92 in `Piece Spec Types`_. [string, enum, required]
94 * ``pos``: Position, in game coordinates, of
95 the centre of the piece. The origin is at the top left.
96 [2-element array, default ``[20,20]``]
98 * ``count``: Place multiple identical copies of this piece. [number]
100 * ``posd``: Position delta. When a spec specifies multiple pieces,
101 each successive piece will be shifted by this amount. [2-element
102 array, default ``[5,5]``]
104 * ``face``: Initial face to show (ie, "which way up" the piece
105 starts). The default face is ``0``. For most pieces that is the
106 front, and is usually a good choice. [number]
108 * ``pinned``: Whether the piece is pinned to the table. Players can
109 pin and unpin pieces during the game; this is the initial state.
112 * ``angle``: Initial orientation of the piece. The
113 specified value is multiplied by 45 degrees, increasing values
114 rotating anticlockwise. So for example ``6`` would mean to rotate
115 90 degrees clockwise. [integer 0..7]
121 Depending on the ``type``, some of these parameters will be honoured.
122 This is discussed in the descriptions for each piece spec type.
124 * ``colour``: The fill colour. For a piece type which supports only
125 one face. [string, colour]
127 * ``faces``: The main fill colour(s). [array of string(s), colours]
129 * ``edge``: The edge colour to draw. For a piece with supports only
130 one face. Default is not to draw edges. [string, colour]
132 * ``edges``: The colour of edges to draw. Default is not to draw
133 edges. Must either be a 1-element array, or as long as ``faces``
134 (specifying a different edge colour for each face). [array of
137 * ``edge_width`` [number, default 0.2 if `edge` or `edges` is
140 * ``label``. Controls display of the label with information about
141 the in-game state. Dictionary with two sub-entries:
143 - ``colour`` [string, defaults to the edge colour].
144 - ``place`` [string]: One of ``"BottomLeft"`` (default),
145 ``"TopLeft"``, ``"BottomLeftOutside"``, ``"TopLeftOutside"``.
147 * ``shape``. The shape of a piece. Dictionary with two sub-entries:
149 - ``type``. ``"Circle"`` or ``"Rect"`` [required]
150 - ``size`` [array of 1 or 2 numbers]: required if ``type="Rect"``.
151 - ``diam`` [number]: required if ``type="Circle"``.
153 * ``itemname``: Used when other parts of the game want to refer to
163 A single shape from a piece library.
165 * ``lib``: The library name. [string, required]
167 * ``item``: The item name within that library. [string, required]
182 Multiple shapes from a piece library. Cannot be used with the `count`
185 * ``lib``: The library name. [string, required]
187 * ``items``: The item names. [array of strings, required]
189 * ``prefix``, ``suffix``: Prepended and appended to each
190 entry in ``items``. Useful for abbreviating. [strings]
197 lib = "cards-oxymoron"
198 prefix = "card-oxymoron-"
201 "2","3","4","5","6","7","8","9","T","J","Q","K","A",
202 "2","3","4","5","6","7","8","9","T","J","Q","K","A",
203 "2","3","4","5","6","7","8","9","T","J","Q","K","A",
211 A chess clock. Additional parameters:
213 * ``time``: Initial time for each player. [number, in seconds;
216 * ``per_move``: Time to add per move. [number, in seconds]
218 (These clock settings cannot be reconfigured via the game UI.)
232 A pickup or play deck. This can occult the pieces (eg, cards) you put
233 on it, shuffling them and hiding their identity.
235 Requires ``face`` and ``shape``. Only ``shape.type="Rect"`` is supported.
237 Honours ``edges``, ``edge_width``.
239 Honours ``label``, displaying the number of of pieces in (on) this deck.
246 faces = ["lightblue", "grey"]
247 edges = ["black", "white"]
248 label.colour = "black"
249 label.place = "BottomLeftOutside"
257 A player hand. When active, arranges for only that player to be able
258 tos see the contents. The other players see the occulted view (eg,
261 Requires ``colour`` and ``shape``. Only ``shape.type="Rect"`` is
264 Honours ``edge``, ``edge_width``.
266 Honours ``label``, displaying the player whose hand this is, when
274 label.place = "BottomLeftOutside"
275 label.colour = "black"
287 A simple label which can display a player name.
289 Requires ``colour`` and ``shape``. Only ``shape.type="Rect"`` is supported.
291 Honours ``edge``, ``edge_width``.
299 A die (or coin), which can choose randomly
300 from a fixed set of aspects.
301 Can be "rolled" to have the server show a randomly-chosen face.
303 You must either specify an ``image`` with multiple faces,
305 so that the faces can be distinguished.
306 If the ``image`` has multiple faces *and* you specify ``labels``,
307 the number of faces implied by each must be the same.
309 The die will display a circular "cooldown timer",
310 after it has been rolled.
311 This makes rolling the die visually noticeable for all the players.
312 After the die has been rolled,
313 it cannot be flipped to a different face, or re-rolled,
314 until the timer expires.
315 Apart from that, you can see all the faces in sequence,
316 or make the die show a particular face,
317 with the standard flip operation ("f").
319 Dice can (possibly) be occulted.
320 An occultable die will, if placed in a player's active hand,
321 obscure its face (but, generally, not existence, nor cooldown time),
323 Dice aren't "shuffled" with other piece, the way (say) cards are.
324 A die is occultable if its image is occultable,
325 or if ``occult`` is explicitly specified.
330 * ``desc``: Descriptive string,
331 used in log messages reporting player actions.
332 The actual description shown to users will also report
333 the description provided by the image,
334 for the particular face showing,
335 and the number of faces.
338 * ``image``: Specifies what this die should look like.
339 [inner piece spec, as dictionary; required].
341 * ``labels``: Text strings to superimpose on the image.
343 - [list of strings] One string per face.
344 - [list of two numbers] Label faces numerically (inclusive).
345 - [single number] Label faces numerically from 1 to n (inclusive).
347 * ``label.colour`` [string, defaults to black]:
348 Colour to write the ``labels`` text strings.
350 * ``label.size`` [number, default 8]:
351 Font size for the ``labels`` text strings (in pixeels, svg ``px``).
353 * ``cooldown``: Duration of the cooldown time.
354 [duration - number(s) with units; default "4s"]
356 * ``circle_scale``: Adjusts the size of the cooldown timer circle.
357 The default is an estimate of the best size,
358 calculated from the image's bounding box.
359 [floating point number; default is 1.0, representing the estimated size]
361 * ``occult``: If supplied,
362 specifies that the die should be occultable.
363 In this case either the specified ``image``
364 must itself be occultable,
365 or it must have only one face
366 (since otherwise we wouldn't know what to display when occulted).
367 [dictionary; optional;
368 presence of even an empty dictionary is meaningful;
369 default if absent is to occult if the specified image is occultable]
371 * ``occult.label``: The text string to display when the die is occulted.
372 [string; if not specified in ``occult``,
373 defaults to ``"?"`` if any nonempty ``labels`` were specified,
374 or the empty string otherwise.]
376 The common parameter ``itemname`` is also supported.
387 image.edges = ["black","black"]
388 image.faces = ["#ccccff", "#ccffcc"]
394 Quantified resources of any kind.
395 This could be money, or "resources", or perhaps VPs.
396 In what follows we call each piece representing some currency a "banknote",
397 but it might represent some resource cubes, or whatever.
399 Each banknote has an integer quantity.
400 Currency is fungible: it can be split and merged.
401 Dropping a banknote onto another banknote of the same currency will
403 The quantity selection function in the game UI can be used to take
404 a subset of the value out of a banknote,
405 splitting the amount requested off the note,
406 and leaving the change behind.
408 So individual banknotes can be created or destroyed in play.
409 Each note can represent either resources being moved
410 from one place to another,
411 or a repository such as a bank or a player's stash.
412 (There is no enforced distinction between banknotes
413 in motion or lying about randomly on the table,
414 and a "bank", or players' money.
415 Players are expected to use location on the table to indicate
416 whose money is what, as they would with physical money.)
418 Each currency is identified by a string.
419 Different banknotes with the same currency can be merged,
420 even if they look totally different.
422 it is a good idea for all banknotes of the same
423 currency in the same game to have the same image.
425 The total amount in the game of each currency
426 remains constant during play.
427 (More can be introduced by using ``otter`` to add more banknotes.)
429 Currency is not currently occultable:
430 banknotes are always publicly visible.
434 * ``image``: Specifies what each banknote should look like.
435 The image must have only one face.
436 [inner piece spec, as dictionary; required].
438 * ``qty``: The initial amount of this banknote or stash.
439 [nonnegative integer; required]
441 * ``currency``: The currency, which defines which other
442 banknotes this one can interchange with.
444 * ``label.colour``: Text colour to use for the value.
445 [string, default "black"]
447 * ``label.size`` [number, default 6]:
448 Font size for the value (in pixeels, svg ``px``).
450 * ``label.unit_rel_size`` [number, default 1]:
451 Relative font size for the unit part of the value.
452 (Proportion of the quantity.)
464 image.edges = ["#00ff00"]
465 image.faces = ["#008800"]
471 A plain rectangular piece.
473 * ``size``: Size and shape [array of 1 or 2 numbers, required]
477 Honours ``itemname``, ``edges`` and ``edge_width``.
484 faces = ["yellow","#f4f"]
493 A plain circular piece.
495 * ``diam`` [number, required].
499 Honours ``itemname``, ``edges`` and ``edge_width``.
505 An alias (generally defined in ``pcaliases`` in the game spec).
507 This allows a piece spec (which can be found in a shape library) to
508 refer to something which depends on the game spec.
510 * ``target``: Alias name.
512 Example, in ``GAME.game.toml``::
514 [pcaliases.card-back]
517 item = "card-plain-back-maroon"
519 And in ``library/LIB.toml``::
522 item_prefix = "card-oxymoron-"
525 centre = [36.5, 48.5]
529 sort = "card-playing-c_s"
530 desc_template = "the _desc of clubs"
532 occulted.method = "ByBack"
533 occulted.ilk = "card-back"