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
79 A piece spec is a dictionary defining one or more pieces. When part
80 of a game spec, it appears as an entry in the top-level ``pieces``
81 array, and also defines the location(s) on the table to place the
84 There is a required entry ``type``, a string. This determines how the
85 rest of the table is interpreted. It is one of the `Piece Spec
91 These apply regardless of the value of ``type``.
93 * ``type``: Piece type or piece spec type. One of the types listed
94 in `Piece Spec Types`_. [string, enum, required]
96 * ``pos``: Position, in game coordinates, of
97 the centre of the piece. The origin is at the top left.
98 [2-element array, default ``[20,20]``]
100 * ``count``: Place multiple identical copies of this piece. [number]
102 * ``posd``: Position delta. When a spec specifies multiple pieces,
103 each successive piece will be shifted by this amount. [2-element
104 array, default ``[5,5]``]
106 * ``face``: Initial face to show (ie, "which way up" the piece
107 starts). The default face is ``0``. For most pieces that is the
108 front, and is usually a good choice. [number]
110 * ``pinned``: Whether the piece is pinned to the table. Players can
111 pin and unpin pieces during the game; this is the initial state.
114 * ``angle``: Initial orientation of the piece. Only 45-degree
115 angles are supported.
116 [number, degrees, clockwise; or string, "N", "NE" etc.]
122 Depending on the ``type``, some of these parameters will be honoured.
123 This is discussed in the descriptions for each piece spec type.
125 * ``colour``: The fill colour. For a piece type which supports only
126 one face. [string, colour]
128 * ``faces``: The main fill colour(s). [array of string(s), colours]
130 * ``edge``: The edge colour to draw. For a piece with supports only
131 one face. Default is not to draw edges. [string, colour]
133 * ``edges``: The colour of edges to draw. Default is not to draw
134 edges. Must either be a 1-element array, or as long as ``faces``
135 (specifying a different edge colour for each face). [array of
138 * ``edge_width`` [number, default 0.2 if `edge` or `edges` is
141 * ``label``. Controls display of the label with information about
142 the in-game state. Dictionary with two sub-entries:
144 - ``colour`` [string, defaults to the edge colour].
145 - ``place`` [string]: One of ``"BottomLeft"`` (default),
146 ``"TopLeft"``, ``"BottomLeftOutside"``, ``"TopLeftOutside"``.
148 * ``shape``. The shape of a piece. Dictionary with two sub-entries:
150 - ``type``. ``"Circle"`` or ``"Rect"`` [required]
151 - ``size`` [array of 1 or 2 numbers]: required if ``type="Rect"``.
152 - ``diam`` [number]: required if ``type="Circle"``.
154 * ``itemname``: Used when other parts of the game want to refer to
164 A single shape from a piece library.
166 * ``lib``: The library name. [string, required]
168 * ``item``: The item name within that library. [string, required]
183 Multiple shapes from a piece library. Cannot be used with the `count`
186 * ``lib``: The library name. [string, required]
188 * ``items``: The item names. [array of strings, required]
190 * ``prefix``, ``suffix``: Prepended and appended to each
191 entry in ``items``. Useful for abbreviating. [strings]
198 lib = "cards-oxymoron"
199 prefix = "card-oxymoron-"
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",
204 "2","3","4","5","6","7","8","9","T","J","Q","K","A",
212 A chess clock. Additional parameters:
214 * ``time``: Initial time for each player. [number, in seconds;
217 * ``per_move``: Time to add per move. [number, in seconds]
219 (These clock settings cannot be reconfigured via the game UI.)
233 A pickup or play deck. This can occult the pieces (eg, cards) you put
234 on it, shuffling them and hiding their identity.
236 Requires ``face`` and ``shape``. Only ``shape.type="Rect"`` is supported.
238 Honours ``edges``, ``edge_width``.
240 Honours ``label``, displaying the number of of pieces in (on) this deck.
242 * ``stack_pos``: When stacking neatly, stack here relative to the
243 deck centre. [two numbers, ``[0,0]``]
250 faces = ["lightblue", "grey"]
251 edges = ["black", "white"]
252 label.colour = "black"
253 label.place = "BottomLeftOutside"
261 A player hand. When active, arranges for only that player to be able
262 tos see the contents. The other players see the occulted view (eg,
265 Requires ``colour`` and ``shape``. Only ``shape.type="Rect"`` is
268 Honours ``edge``, ``edge_width``.
270 Honours ``label``, displaying the player whose hand this is, when
278 label.place = "BottomLeftOutside"
279 label.colour = "black"
291 A simple label which can display a player name.
293 Requires ``colour`` and ``shape``. Only ``shape.type="Rect"`` is supported.
295 Honours ``edge``, ``edge_width``.
303 A die (or coin), which can choose randomly
304 from a fixed set of aspects.
305 Can be "rolled" to have the server show a randomly-chosen face.
307 You must either specify an ``image`` with multiple faces,
309 so that the faces can be distinguished.
310 If the ``image`` has multiple faces *and* you specify ``labels``,
311 the number of faces implied by each must be the same.
313 The die will display a circular "cooldown timer",
314 after it has been rolled.
315 This makes rolling the die visually noticeable for all the players.
316 After the die has been rolled,
317 it cannot be flipped to a different face, or re-rolled,
318 until the timer expires.
319 Apart from that, you can see all the faces in sequence,
320 or make the die show a particular face,
321 with the standard flip operation ("f").
323 Dice can (possibly) be occulted.
324 An occultable die will, if placed in a player's active hand,
325 obscure its face (but, generally, not existence, nor cooldown time),
327 Dice aren't "shuffled" with other piece, the way (say) cards are.
328 A die is occultable if its image is occultable,
329 or if ``occult`` is explicitly specified.
334 * ``desc``: Descriptive string,
335 used in log messages reporting player actions.
336 The actual description shown to users will also report
337 the description provided by the image,
338 for the particular face showing,
339 and the number of faces.
342 * ``image``: Specifies what this die should look like.
343 [inner piece spec, as dictionary; required].
345 * ``labels``: Text strings to superimpose on the image.
347 - [list of strings] One string per face.
348 - [list of two numbers] Label faces numerically (inclusive).
349 - [single number] Label faces numerically from 1 to n (inclusive).
351 * ``label.colour`` [string, defaults to black]:
352 Colour to write the ``labels`` text strings.
354 * ``label.size`` [number, default 8]:
355 Font size for the ``labels`` text strings (in pixeels, svg ``px``).
357 * ``cooldown``: Duration of the cooldown time.
358 [duration - number(s) with units; default "4s"]
360 * ``circle_scale``: Adjusts the size of the cooldown timer circle.
361 The default is an estimate of the best size,
362 calculated from the image's bounding box.
363 [floating point number; default is 1.0, representing the estimated size]
365 * ``occult``: If supplied,
366 specifies that the die should be occultable.
367 In this case either the specified ``image``
368 must itself be occultable,
369 or it must have only one face
370 (since otherwise we wouldn't know what to display when occulted).
371 [dictionary; optional;
372 presence of even an empty dictionary is meaningful;
373 default if absent is to occult if the specified image is occultable]
375 * ``occult.label``: The text string to display when the die is occulted.
376 [string; if not specified in ``occult``,
377 defaults to ``"?"`` if any nonempty ``labels`` were specified,
378 or the empty string otherwise.]
380 The common parameter ``itemname`` is also supported.
391 image.edges = ["black","black"]
392 image.faces = ["#ccccff", "#ccffcc"]
398 Quantified resources of any kind.
399 This could be money, or "resources", or perhaps VPs.
400 In what follows we call each piece representing some currency a "banknote",
401 but it might represent some resource cubes, or whatever.
403 Each banknote has an integer quantity.
404 Currency is fungible: it can be split and merged.
405 Dropping a banknote onto another banknote of the same currency will
407 The quantity selection function in the game UI can be used to take
408 a subset of the value out of a banknote,
409 splitting the amount requested off the note,
410 and leaving the change behind.
412 So individual banknotes can be created or destroyed in play.
413 Each note can represent either resources being moved
414 from one place to another,
415 or a repository such as a bank or a player's stash.
416 (There is no enforced distinction between banknotes
417 in motion or lying about randomly on the table,
418 and a "bank", or players' money.
419 Players are expected to use location on the table to indicate
420 whose money is what, as they would with physical money.)
422 Each currency is identified by a string.
423 Different banknotes with the same currency can be merged,
424 even if they look totally different.
426 it is a good idea for all banknotes of the same
427 currency in the same game to have the same image.
429 The total amount in the game of each currency
430 remains constant during play.
431 (More can be introduced by using ``otter`` to add more banknotes.)
433 Currency is not currently occultable:
434 banknotes are always publicly visible.
438 * ``image``: Specifies what each banknote should look like.
439 The image must have only one face.
440 [inner piece spec, as dictionary; required].
442 * ``qty``: The initial amount of this banknote or stash.
443 [nonnegative integer; required]
445 * ``currency``: The currency, which defines which other
446 banknotes this one can interchange with.
448 * ``label.colour``: Text colour to use for the value.
449 [string, default "black"]
451 * ``label.size`` [number, default 6]:
452 Font size for the value (in pixels, svg ``px``).
454 * ``label.unit_rel_size`` [number, default 1]:
455 Relative font size for the unit part of the value.
456 (Proportion of the quantity.)
468 image.edges = ["#00ff00"]
469 image.faces = ["#008800"]
475 A plain rectangular piece.
477 * ``size``: Size and shape [array of 1 or 2 numbers, required]
481 Honours ``itemname``, ``edges`` and ``edge_width``.
488 faces = ["yellow","#f4f"]
497 A plain circular piece.
499 * ``diam`` [number, required].
503 Honours ``itemname``, ``edges`` and ``edge_width``.
509 An alias (generally defined in ``pcaliases`` in the game spec).
511 This allows a piece spec (which can be found in a shape library) to
512 refer to something which depends on the game spec.
514 * ``target``: Alias name.
516 Example, in ``GAME.game.toml``::
518 [pcaliases.card-back]
521 item = "card-plain-back-maroon"
523 And in ``library/LIB.toml``::
526 item_prefix = "card-oxymoron-"
529 centre = [36.5, 48.5]
533 sort = "card-playing-c_s"
534 desc_template = "the _desc of clubs"
536 occulted.method = "ByBack"
537 occulted.ilk = "card-back"