chiark / gitweb /
docs: Provide xref for piece specs
[otter.git] / docs / gamespec.rst
1 Game specs
2 ==========
3
4 A game spec defines the starting layout for a game: **which pieces start
5 on the table, and where**.
6
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``).
12
13 General
14 -------
15
16 A game spec is a TOML file.  It has the following entries at the top
17 level:
18
19  * ``table_size``: Size of the table playing area, in Otter internal
20    units.  [array of 2 numbers, default ``[300,200]``]
21
22  * ``table_colour``: Table backdrop colour.  Only certain colour
23    syntaxes are supported.   [string, colour; default ``green``]
24
25  * ``pcaliases``: [dictionary, values are Piece Spec dicts].  Piece
26    alias definitions.  This is used by the ``"Alias"`` piece spec.
27
28  * ``pieces``: Array of `Piece Specs`_.  Defines the initial pieces
29    and their layout.  Each entry is a piece spec dictionary.
30
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`.
35
36
37 Templating
38 ``````````
39
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
42 repetitive.
43
44 Template expansion is done if the file starts, precisely, with the
45 characters ``{#`` (which are the Tera comment introducer).
46
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
50 files.
51
52 Splitting is done if the file contains a line starting with precisely
53 ``{% endmacro`` (the usual form of the Tera macro end sequence).
54
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.
62
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.
68
69 For details of the template syntax, see `the Tera documentation`_.
70 For examples, see the built-in game specs.
71
72 .. _the Tera documentation: https://tera.netlify.app/docs/#templates
73
74 .. _piece-specs:
75
76 Piece Specs
77 -----------
78
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
82 pieces, too.
83
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
86 Types`_.
87
88 Universal parameters
89 ````````````````````
90
91 These apply regardless of the value of ``type``.
92
93  * ``type``: Piece type or piece spec type.  One of the types listed
94    in `Piece Spec Types`_.  [string, enum, required]
95
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]``]
99
100  * ``count``: Place multiple identical copies of this piece.  [number]
101
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]``]
105
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]
109
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.
112    [boolean]
113
114  * ``angle``: Initial orientation of the piece.  Only 45-degree
115    angles are supported.
116    [number, degrees, clockwise; or string, "N", "NE" etc.]
117
118
119 Common parameters
120 `````````````````
121
122 Depending on the ``type``, some of these parameters will be honoured.
123 This is discussed in the descriptions for each piece spec type.
124
125  * ``colour``: The fill colour.  For a piece type which supports only
126    one face.  [string, colour]
127
128  * ``faces``: The main fill colour(s).  [array of string(s), colours]
129
130  * ``edge``: The edge colour to draw.  For a piece with supports only
131    one face.  Default is not to draw edges.  [string, colour]
132
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
136    string(s), colours]
137
138  * ``edge_width`` [number, default 0.2 if `edge` or `edges` is
139    specified]
140
141  * ``label``.  Controls display of the label with information about
142    the in-game state.  Dictionary with two sub-entries:
143
144     - ``colour`` [string, defaults to the edge colour].
145     - ``place`` [string]: One of ``"BottomLeft"`` (default),
146       ``"TopLeft"``, ``"BottomLeftOutside"``, ``"TopLeftOutside"``.
147
148  * ``shape``.  The shape of a piece.  Dictionary with two sub-entries:
149
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"``.
153
154  * ``itemname``: Used when other parts of the game want to refer to
155    this one.  [string]
156
157
158 Piece Spec Types
159 ----------------
160
161 ``"Lib"``
162 `````````
163
164 A single shape from a piece library.
165
166  * ``lib``: The library name.  [string, required]
167  
168  * ``item``: The item name within that library.  [string, required]
169
170 Example::
171
172   [[pieces]]
173   pos = [150,100]
174   type = "Lib"
175   lib = "edited"
176   item = "chess-board"
177   pinned = true
178
179
180 ``"LibList"``
181 `````````````
182
183 Multiple shapes from a piece library.  Cannot be used with the `count`
184 universal parameter.
185
186  * ``lib``: The library name. [string, required]
187
188  * ``items``: The item names. [array of strings, required]
189
190  * ``prefix``, ``suffix``: Prepended and appended to each
191    entry in ``items``.  Useful for abbreviating.  [strings]
192
193 Example::
194
195   [[pieces]]
196   pos = [150, 84]
197   type = "LibList"
198   lib = "cards-oxymoron"
199   prefix = "card-oxymoron-"
200   suffix = "-s"
201   items = [
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",
205   ]
206   posd = [0, 0]
207
208
209 ``"ChessClock"``
210 ````````````````
211
212 A chess clock.  Additional parameters:
213
214  * ``time``: Initial time for each player. [number, in seconds;
215    required]
216
217  * ``per_move``: Time to add per move.  [number, in seconds]
218
219 (These clock settings cannot be reconfigured via the game UI.)
220
221 Example::
222
223   [[pieces]]
224   pos = [240, 100]
225   type = "ChessClock"
226   time = 900
227   per_move = 30
228
229
230 ``"PickupDeck"``
231 ````````````````
232
233 A pickup or play deck.  This can occult the pieces (eg, cards) you put
234 on it, shuffling them and hiding their identity.
235
236 Requires ``face`` and ``shape``.  Only ``shape.type="Rect"`` is supported.
237
238 Honours ``edges``, ``edge_width``.
239
240 Honours ``label``, displaying the number of of pieces in (on) this deck.
241
242  * ``stack_pos``: When stacking neatly, stack here relative to the
243    deck centre.  [two numbers, ``[0,0]``]
244
245 Example::
246   
247   [[pieces]]
248   pos = [136,115]
249   type = "PickupDeck"
250   faces = ["lightblue", "grey"]
251   edges = ["black", "white"]
252   label.colour = "black"
253   label.place = "BottomLeftOutside"
254   shape.type = "Rect"
255   shape.xy = [25,30]
256
257
258 ``"Hand"``
259 ``````````
260
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,
263 the backs of cards).
264
265 Requires ``colour`` and ``shape``.  Only ``shape.type="Rect"`` is
266 supported.
267
268 Honours ``edge``, ``edge_width``.
269
270 Honours ``label``, displaying the player whose hand this is, when
271 active.
272
273 Example::
274
275   [[pieces]]
276   pos = [53, 25]
277   colour = "brown"
278   label.place = "BottomLeftOutside"
279   label.colour = "black"
280
281   type = "Hand"
282   edge = "white"
283   edge_width = 0.75
284   shape.type = "Rect"
285   shape.xy = [93,25]
286
287
288 ``"PlayerLabel"``
289 `````````````````
290
291 A simple label which can display a player name.
292
293 Requires ``colour`` and ``shape``.  Only ``shape.type="Rect"`` is supported.
294
295 Honours ``edge``, ``edge_width``.
296
297 Honours ``label``.
298
299
300 ``"Die"``
301 `````````
302
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.
306
307 You must either specify an ``image`` with multiple faces,
308 and/or ``labels``,
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.
312
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").
322
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),
326 from other players.
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.
330
331
332 Parameters:
333
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.
340    [string; optional]
341
342  * ``image``: Specifies what this die should look like.
343    [inner piece spec, as dictionary; required].
344
345  * ``labels``: Text strings to superimpose on the image.
346
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).
350
351  * ``label.colour`` [string, defaults to black]:
352    Colour to write the ``labels`` text strings.
353
354  * ``label.size`` [number, default 8]:
355    Font size for the ``labels`` text strings (in pixeels, svg ``px``).
356
357  * ``cooldown``: Duration of the cooldown time.
358    [duration - number(s) with units; default "4s"]
359
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]
364
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]
374
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.]
379    
380 The common parameter ``itemname`` is also supported.
381
382 Example::
383   
384   [[pieces]]
385   pos = [155, 15]
386   type = "Die"
387   labels = ["A", "B"]
388   image.type = "Disc"
389   image.diam = 12
390   circle_scale = 0.833
391   image.edges = ["black","black"]
392   image.faces = ["#ccccff", "#ccffcc"]
393
394
395 ``"Currency"``
396 ```````````````
397
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.
402
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
406 merge the two.
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.
411
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.)
421
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.
425 To avoid confusion,
426 it is a good idea for all banknotes of the same
427 currency in the same game to have the same image.
428
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.)
432
433 Currency is not currently occultable:
434 banknotes are always publicly visible.
435
436 Parameters:
437
438  * ``image``: Specifies what each banknote should look like.
439    The image must have only one face.
440    [inner piece spec, as dictionary; required].
441
442  * ``qty``: The initial amount of this banknote or stash.
443    [nonnegative integer; required]
444
445  * ``currency``: The currency, which defines which other
446    banknotes this one can interchange with.
447
448  * ``label.colour``: Text colour to use for the value.
449    [string, default "black"]
450
451  * ``label.size`` [number, default 6]:
452    Font size for the value (in pixels, svg ``px``).
453
454  * ``label.unit_rel_size`` [number, default 1]:
455    Relative font size for the unit part of the value.
456    (Proportion of the quantity.)
457
458 Exammple::
459
460   [[pieces]]
461   pos = [125, 45]
462   type = "Currency"
463   qty = 400
464   min_unit = 5
465   currency = "ƒ"
466   image.type = "Rect"
467   image.size = [20,7]
468   image.edges = ["#00ff00"]
469   image.faces = ["#008800"]
470
471
472 ``"Rect"``
473 ``````````
474
475 A plain rectangular piece.
476
477  * ``size``: Size and shape  [array of 1 or 2 numbers, required]
478
479 Requires ``faces``.
480
481 Honours ``itemname``, ``edges`` and ``edge_width``.
482
483 Exammple::
484
485   [[pieces]]
486   pos = [20, 85]
487   type = "Rect"
488   faces = ["yellow","#f4f"]
489   posd = [10, 0]
490   size = [7,7]
491   count = 8
492
493
494 ``"Disc"``
495 ``````````
496
497 A plain circular piece.
498
499  * ``diam`` [number, required].
500
501 Requires ``faces``.
502
503 Honours ``itemname``, ``edges`` and ``edge_width``.
504
505
506 ``"Alias"``
507 ```````````
508
509 An alias (generally defined in ``pcaliases`` in the game spec).
510
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.
513
514  * ``target``: Alias name.
515
516 Example, in ``GAME.game.toml``::
517
518   [pcaliases.card-back]
519   type = "Lib"
520   lib = "wikimedia"
521   item = "card-plain-back-maroon"
522
523 And in ``library/LIB.toml``::
524
525   [group.clubs]
526   item_prefix = "card-oxymoron-"
527   outline = "Rect"
528   size = [73, 97]
529   centre = [36.5, 48.5]
530   scale = 0.25
531
532   item_suffix = "-c"
533   sort = "card-playing-c_s"
534   desc_template = "the _desc of clubs"
535
536   occulted.method = "ByBack"
537   occulted.ilk = "card-back"
538
539   files = """
540   :             sort
541   2     -       02      two
542   3     -       03      three
543   4     -       04      four
544   5     -       05      five
545   6     -       06      six
546   7     -       07      seven
547   8     -       08      eight
548   9     -       09      nine
549   T     -       10      ten
550   J     -       11      jack
551   Q     -       12      queen
552   K     -       13      king
553   A     -       14      ace
554   """
555
556   [group.clubs.back]
557   type = "Alias"
558   target = "card-back"