18SH – an 18xx shell
18SH is designed as a replacement for the spreadsheets used to calculate end of game scores in 18xx games. Spreadsheets are fine, especially if they're well designed with formulas to avoid entering the same data twice, but I wanted to try how an interactive shell would work.
The design philosophy behind 18SH is to not support game rules, but just offer a simple and effective way of recording the financial transactions of the game. 18SH aims to support different ways money and shares are handled, it has tools that make life easier for both full cap and incremental cap games, for example, but it cannot track company value automatically or enforce certificate limit.
18SH follows semantic versioning; the biggest catch is that save file compatibility is only guaranteed within major versions. If the first number changes in the version number, your saved games won't work anymore.
Installing & requirements
Clone from GitHub or download the files. The GitHub
master is the current
state of development and not always stable. For stable releases, get the
tagged release packages. Then
install the Node modules with
and you're ready to go. 18SH requires Node.js.
If you use a stable release package, just download the new package and use that.
If you clone from GitHub, you can upgrade to the latest version with
Note that the latest
master may be unstable. However, major version
development generally happens in a separate branch, so
master will have the
latest version of the current major version.
Run 18SH with Node:
If there isn't an active game in the Configstore storage, a new game will be created and assigned a name. If you quit and then restart 18SH, it will continue with the same game. You can also switch between two games.
Shares can be bought by issuing the right commands (see below for a list), company values can be set and with the command
you'll finally see the end results.
<player|company> buys <count> <company> [@<price> [from <source>]]
There's no need to introduce player or company names: just use any abbreviations you like, as long as you always refer to the same player or company with the same abbreviation. The names are case insensitive (and always converted to upper case anyway).
If you specify a price, that amount of money will be reducted from the buyer. Price is the price for single share, so it will be multiplied by the number of shares bought. If you specify a source, the money will be paid to the source, and the share will be removed from the source. When buying from pool, do not specify the source; this is mostly useful in partical cap games like 1846, where companies own their own shares and are paid for share purchases.
You can't specify source without a price.
Companies can also buy shares, either their own or from other companies.
You can abbreviate the command to
buy. Count can be omitted,
in which case it's assumed to be 1. You can drop the
@ from the price, if you
prefer, and adding the
from is optional.
All of these commands have Mikko buy two LNWR shares:
Mikko buys 2 LNWR Mikko buy 2 LNWR Mikko b 2 LNWR
In a game of 1846, you will see something like this. These commands have the same effect:
Mikko buys 1 GT @100 from GT Mikko b GT 100 GT
<player|company> sells <count> <company> [@<price>]
The opposite of buying shares. The same principles apply to
sell: you can
abbreviate the command. If you specify the price, the seller will be given that
much money from the bank.
If you try to sell more than you have, 18SH will sell to zero. You can't sell
to someone; for transactions like that, you always have to
<player|company> cash <amount>
Adjusts the player or company cash. If
<amount> is positive, the money is
added and if it's negative, the money is removed. All transactions happen
between the player or the company and the bank.
Company must be floated before its cash can be handled (see
<player|company> give <amount> to <player|company>
Has the player or company move the specific amount of money to the target.
A company must be floated before its cash can be handled (see
Doing one of these:
GT give 60 to Mikko GT g 60 Mikko
is the same as doing
GT cash -60 Mikko cash 60
<company> dividends <number>
This command has the company distribute
<number> as a dividend. Use the
per-share value, not the total dividend: if there are ten shares as usual and
the total sum is £200, the command is
GER dividends 20
as the per-share dividend is £20. This command can be abbreviated up to
and it also has an alias,
pays. These are all identical to the command above:
GER d 20 GER pays 20 GER pay 20 GER pa 20 GER p 20
<company> halfdividends <number>
Distributes half dividends where half the sum is paid to the company and the
rest is distributed to shares, rounded up for the benefit of the shareholders.
<number> is not the per-share dividend, but the total sum to distribute.
Thus if you do
NYC halfdividends 290
NYC will retain 140 and each NYC share is paid 15.
If you want to change the default setting for half dividend rounding, 18SH supports two other methods. To round in favour of company, use the command
and in order to round like it's done in 1837 (calculate exact sum per share, then round share payments down – paying 50 would net 25 in company treasury and a 30% owner would get 7.5 that rounds down to 7), use
<company> float <number>
Starts up a company and sets its cash to
<number>. This needs to be done
first if you want to track company cash, because otherwise
<company> cash <amount> will not work correctly but will instead assume
<company> is a
NYC float 630
In partial-cap games like 1846, you generally want to float companies like this:
GT float 0 GT buys 10 GT @0
Now 18SH knows GT exists and GT has 10 shares. Then the president can determine the price of one share and then buy the initial shares:
Mikko buys 2 GT @100 from GT
Now GT would have $200 and Mikko has 2 GT shares.
Closes the company, removing it from play completely (all shares and cash in company treasury gone).
Moves the game to next SR or OR. The current round is shown in the status bar.
<player|company> income <amount>
Sets the player or company income to the specified amount. This income is
automatically paid in the beginning of each OR and happens whenever the command
next OR is used.
Mikko income 25
<company> value <number>
This sets the company share price value to
<number>. This is required so that
18SH can report the final values for players. Again, all of these are
SECR value 67 SECR val 67 SECR v 67
banksize <currency symbol><number>
Sets the game bank size to the specified value. Once this is set, the status bar will show the money remaining in the bank (calculated as bank size minus the cash players have).
The default currency is dollars, but you can specify any one-letter currency symbol when setting the bank size in order to change currency, like this:
banksize £2500 banksize €2500 banksize ₹2500
If you wish to use 1825 style company credits where company money is not included in the bank, you can set that up with
Shows the remaining cash in bank.
This command prints out a list of share and cash holdings for all players.
This command prints out a list of player net worth values. All share holdings
are multiplied by the share values and the cash holdings are added to that. In
order for this command to work, the values need to be set using
This command prints out a list of companies with their share values and the share ownership.
Undoes the previous game state altering command (commands that just show the
game state like
values are not considered for
undo). 18SH has
a history of commands entered, and
undo simply removes the last command from
the list and then resets the game state to that.
Opens the specified game and closes the current game (game state is saved to the file after each command, so nothing is lost).
Lists all the games that are saved at the moment.
Deletes the saved game with a given name. This is permanent and cannot be undone.
A list of these commands.
exit. Exits the 18SH shell. The game state is automatically saved after
every command in the local configstore (
# <comment> <command> # <comment>
Anything after a # is considered a comment and is ignored by parser, but is stored in the command history. You can use comments to keep a log of game events, for example, or to explain why cash is moved from place to place for future reference.
The biggest problem with 18SH is that the cash situation is not visible to other players. This can be rectified with 18SH Cash Display. If you have a cash display server running up, you can connect 18SH to it and display the cash status on another screen.
For further instructions on setting up the Cash Display, refer to the Cash Display GitHub page. 18SH will send the status information automatically to the server whenever things change, all you need to to is to tell where the server is. This is done by setting an environmental variable that points to the server. The exact method depends on your system (see this helpful guide). On my Mac running zsh, I do it like this:
In any case, the name of the environmental variable is
DISPLAY18SH. Make sure
you add the
18sh/ to the end of the URL of the server.
See Cash Display GitHub page for version compatibility information: 18SH and the server must have compatible version numbers.
For discussion about 18SH, see the BoardGameGeek 18SH thread.
18SH doesn't have many dependencies:
- terminal-kit is used to handle the user interface.
- cli-table is used to print out pretty tables.
- configstore stores the game data.
- axios is used to send the data to the cash display server.
See changelog.md in the repo for change history, todo list and the unreleased features already available from the repo, but not in releases.
See license information.