18xx map and tile generator

Will build 18xx assets in a deterministic way. Currently focussed on tile manifests, printable tile sheets and maps. The program takes a bunch of JSON files which dictate what it should do. It outputs to SVG files, scaled to fit A4 paper.

Hexagon space

Items within a hex are usually given in hexagon-space. This is a 3 dimensional space where the axis are at 60° to each other. An example of the axis is given below. Note that the orientation of the axis when the hexagons are oriented with horizontal edges differs from when the hexagons are oriented with vertical edges.

Instead of using coordinates in hexagon-space there are these position codes that can be used as a shortcut. North is the upper edge on a hexagon that has horizontal edges, it is the top left edge on hexagons that are oriented vertically.

Coordinate system

When specifying coordinates a position code can be used by inserting {"Named": "<code>"} in the appropriate location. <code> is one of the above position codes. When specifying a coordinate in hexagon-space it done done by setting the coordinate to {"HexSpace": [<x>, <y>, <z>]} where <x>, <y> and <z> are floating point numbers. It is important to always include at least one decimal even when not required (so 10.0 instead of 10). Otherwise map18xx will not be able to understand it.

Modes

The program can operate in several different modes, they are described here.

Definitions

By default the program runs in 'definitions' mode, meaning that it will output all currently known tile definitions to a single file definitions.svg. The output contains a list of tiles without a colour that can be used to define other tiles in a game.

Game mode

Generates a tile manifest (lists each tile in the game and how many there are in total) and sheets with tiles to print and play and play a specific game of 18xx. It will also generate a map on which the tiles can be placed.

Command line arguments

A list of command line options is given below:

Tile definitions

To build a game you first need to know what tiles are available. To simplify the specification of tiles there are tile definitions which cover possible configurations of tiles. These definitions include the tracks and stations on a tile, but they also dictate where revenue circles and other text on the tile goes. The tile definitions live in tiledefs/, there is one tile definiton per file. The filename (the part before the .json) determines how the tile can be refered to from other files. The contents of the file can include:

The is_lawson parameter is a boolean that is false by default. It will draw the centre of a tile neatly when multiple lines meet there. The tile number is always drawn at the bottom right corner and has text_id = 0.

text_id keys

Before discussing what can be defined on a tile it is necessary to know how to specify text. To reduce the number of definitions required a consumer like a tile manifest can determine what text goes on the tile. The tile definition can specify where the text should go on the tile. To link these the consumer has to supply an array of strings, the definition can then pick the string to use from that array using the text_id (or similar) key. These IDs represent a 0-based index in the array of strings. The 0th element of the string array is reserved for the tile number. It is recommended to keep the id of the text_id field as small as possible, otherwise the consumer will have to specify a lot of empty strings. Multiple elements on a tile can use the same text_id, these will all use the same string.

paths array

To define the lines that run across a tile you can use the paths array. Each entry defines a single path. They usually look like JSON { "start": { "Named": "N" }, "end": { "HexSpace": [0.1, 0.2, 0.3] }, "is_bridge": true }

There are several things here. First are the start and end keys, these define the start and end positions of a path respectively. These can take the position codes and hexagon-space coordinates that were defined in the 'Hexagon space' section.

Usually paths are drawn with level crossings. If paths cross but it is not allowed to switch there the is_bridge key can be used. Its default value is false. When set to true it will cause white lines to be drawn along the path it is specified on whenever it intersects with another path. It is only necessary to specify it on one of the crossing paths.

cities array

Cities which have a space for tokens can be defined using the cities array. Each city defines a new set of up to 4 token circles with its own revenue circle. It is currently not possible to rotate a city. A city can be defined as JSON { "circles": 2, "position": { "Named": "C" }, "text_id": 1, "revenue_position": { "HexSpace": [0.0, 0.6, 0.0] }

The first key is the circles key, this determines how many token spots are available. This can be any number between 1 and 4 inclusive, if another amount is specified then a red circle will be drawn to indicate that it is an invalid amount. The position key specifies where to put the city. Usually it doesn't make sense to use a position code other than { "Named": "C" } because the city would be drawn half off the tile.

To define where the revenue should be located the revenue_position key can be used. It is recommended to use a hexagon-space coordinate. Along with revenue_position there is a text_id which specifies which string ends up as the revenue number. It is suggested to set this to 1 for consistency. If different cities earn different revenue they should have a different text_id.

stops array

Small cities are always rendered as small black circles. In the future it may become possible to render them as dashes as well. A stop is defined as JSON { "position": { "HexSpace": [0.0, 0.0, 0.0] }, "text_id": 1, "revenue_angle": 30 }

A stop must have these three fields, other fields are ignored. The position key defines where a stop is positioned. The text_id field specifies which string is used as the revenue. The revenue circle is always at the same distance from a stop. You can specify where it goes with the revenue_angle key. This is the angle in degrees at which the revenue circle should be drawn relative to the stop.

Tile code

Some tiles have a letter or code on them to restrict the upgrade path. Think of B and OO tiles in 1830 for example. The string that is used for this can be defined with code_text_id and its position is defined with the code_position key. The code_position can be a position code or a coordinate in hexagon-space.

Game definition

By using game for the mode option mode you can put the program into game mode that will generate all files to PnP a game. The game mode requires an additional NAME parameter; this is the name of the game to generate files for. The available games are the sub directories in the games directory. Thisoutputs a tile manifest in manifest.svg and a list of files called NAME-sheet-x.svg where NAME is the name of the game and x is a sequence number. Each of these sheet files can be directly printed on A4 paper. The manifest file contains an example of each tile in the game together with a number that indicates how many of those tiles are available during play.

Tile manifest

A tile manifest consists of a list of tiles and a list of how often this tile can be used in the game. The definition of a usable tiles is given by the tiles array. A single entry looks like JSON { "color": "green", "base_tile": "52", "text": [ "59", "40", "OO" ] }

There are several elements here. The first is the color key, this defines which color the tile is. Usual picks are yellow, green, russet and grey. The next key is base_tile which specifies which tile definition is used. This can be any JSON file in the tiledefs/ directory. Finally is the text array, it specifies the string that the text_ids in the tile definition refer to. The first entry is always the displayed tile number, this does not have to be the same as the base_tile key. The meaning of other entries depends on what the tile definition used as text_id.

To specify the amounts available of each tile there is an amounts array, it looks like JSON "amounts": { "1": 1, "2": 1, "3": 2, "4": 2, "7": 4 }

It has a number of string keys, these are the tile number that were defined in the first element of a tile's text array. After the colon is the amount of tiles that are available for placement during the game.