I’ve fleshed out the design a bit more:
Basic actions
These actions are state changes to objects:
- create: Create an object
- destroy: Destroy an object
- clone: Make a copy of an object from another object
- move: Move an object from one location to another
- flip: Set which face of an object is up
- rotate: Rotate an object about its center
- set property: Set a named property with a given value on an object
- unset property: Remove a named property from an object
- set permissions: Set permissions for an object
These actions involve a source of randomness:
- roll: Roll a die
- choose: Randomly select objects from a set
- shuffle: Shuffle the locations of a set of objects
These actions reveal information:
vis:piece: Reveal the positional properties of the piece (parent, location, angle, anchor, children)
vis:type: Reveal the piece type
vis:name: Reveal the piece name
vis:face_up: Reveal the face which is up
vis:faces: Reveal the complete face list
vis:prop:propname: Reveal the property with the name propnanme.
vis is short for “visibility”.
Permissions
A permission is a named set of actions.
{
"id": "",
"description": "",
"actions": {
"allow": [],
"deny": []
},
"order": ["deny", "allow"]
}
id: The id of this permission.
description: The description of this permission.
actions.allow: A list of permitted actions.
actions.deny: A list of prohibited actions.
order: The order in which actions.deny and actions.allow are applied.
actions.allow and actions.deny may have * in their lists, which matches all action, and may also have x:*, which matches all actions in action group x.
Player sets
Player ids are singleton player sets.
Composite player sets are:
{
"id": 0,
"description": "",
"members": []
}
id: The id of the player set.
description: A description of this player set.
members: A list of members of this player set.
Player sets can be members of other player sets. Player sets must be well-founded. * is the set of all players.
Piece types
{
"id": 0,
"description": "",
"name": "",
"faces": [],
"occluded_face": ""
"props": {}
}
id: The id of this piece type.
description: A description of this piece type.
name: The name this piece type. Inherited by pieces of this type if not overridden.
faces: The faces of this piece type. Inherited by pieces of this type if not overridden.
occluded_face: The face of this piece type to show when a piece of this type is occluded by other pieces. Inherited by pieces of this type if not overridden.
props: Named properties of this piece type. Inherited by pieces of this type if not overridden.
Pieces
Pieces are game objects.
{
"id": 2,
"parent": 1,
"location": { "x": 1.0, "y": 2.0, "z": 3.0 },
"angle": 0.0,
"anchor": "Center"
"children": [],
"face_up": 1,
"type": 1,
"props": {},
"permissions": {}
}
id: The id of this piece.
parent: The id of the parent of this piece. A piece sits atop its parent.
location: The coordinates of the piece within the coordinate system of its parent.
angle: The rotation of the piece about its anchor point.
anchor: The origin of the piece’s coordinate system with respect to the piece’s faces. Possible values are BottomLeft, BottomCenter, Bottom Right, CenterLeft, Center, CenterRight, TopLeft, TopCenter, TopRight, a pair of percentages, a pair of absolute measurements.
children: A list of ids of children of this piece. A piece’s children sit atop it.
face_up: The index of the showing face of this piece.
type: The id of this piece’s type.
permissions: A map of player sets to lists of permissions granted to the players in those sets.
name, faces, occluded_face, props may also be specified, overriding those inherited from the piece type.
Example
This example shows how a card from Twilight Struggle could be represented:
Players:
{
"id": 0,
"name": "US"
"description": "US player",
}
{
"id": 1,
"name": "USSR"
"description": "USSR player",
}
Images:
{
"fyp": "images/fyp.png",
"back": "images/back.png"
}
Piece type:
{
"id": 0,
"description": "Five-Year Plan card",
"name": "Five-Year Plan",
"faces": [ "fyp", "back" ],
"occluded_face": "back",
"props": {
"event": [ 0 ],
"ops": 3,
"time": "early",
"removed_on_event": false
}
}
Permissions for the card when it is in the draw pile, in hand, and in the discard pile:
{
"id": "in_draw_pile",
"description": "Permissions for cards in draw pile",
"commands": {
"allow": [
"vis:piece",
"vis:face_up",
"move",
"set_permissions"
],
"deny": [
"vis:type",
"vis:name",
"vis:faces",
"vis:prop:*"
]
},
"order": ["deny", "allow"]
}
{
"id": "in_hand_own",
"description": "Permissions for cards in own hand",
"commands": {
"allow": [
"vis:piece",
"vis:face_up"
"vis:type",
"vis:name",
"vis:faces",
"vis:prop:*"
"move",
"flip",
"set_permissions"
],
"deny": [
]
},
"order": ["deny", "allow"]
}
{
"id": "in_hand_opponent",
"description": "Permissions for cards in opponent's hand",
"commands": {
"allow": [
"vis:piece",
"vis:face_up"
],
"deny": [
"vis:type",
"vis:name",
"vis:faces",
"vis:prop:*"
]
},
"order": ["deny", "allow"]
}
{
"id": "in_discard",
"description": "Permissions for cards in discard pile",
"commands": {
"allow": [
"vis:piece",
"vis:face_up"
"vis:type",
"vis:name",
"vis:faces",
"vis:prop:*",
"move",
"flip",
"set_permissions"
],
"deny": [
]
},
"order": ["deny", "allow"]
}
Piece in draw pile:
{
"id": 0,
"type": 0,
"parent": 1,
"location": { "x": 1.0, "y": 2.0, "z": 3.0 },
"angle": 0.0,
"anchor": "center"
"children": [],
"face_up": 1,
"permissions": {
"*": [ "in_draw_pile" ]
}
}
Piece in US player hand:
{
"id": 0,
"type": 0,
"parent": 1,
"location": { "x": 1.0, "y": 2.0, "z": 3.0 },
"angle": 0.0,
"anchor": "center"
"children": [],
"face_up": 0,
"permissions": {
"0": [ "in_hand_own" ],
"1": [ "in_hand_opponent" ],
}
}
Piece in discard pile:
{
"id": 0,
"type": 0,
"parent": 1,
"location": { "x": 1.0, "y": 2.0, "z": 3.0 },
"angle": 0.0,
"anchor": "center"
"children": [],
"face_up": 1,
"permissions": {
"*": [ "in_discard" ]
}
}
Notes
I’m not certain that specifying permissions as allow/deny lists is useful or desirable; it might be simpler and more ergonomic to specify them as purely additive, e.g.,
{
"id": "in_draw_pile",
"description": "Permissions for cards in draw pile",
"commands": {
"vis:piece",
"vis:face_up"
"move",
"set_permissions"
}
}