summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2021-05-01 00:48:35 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-16 19:47:32 +0100
commit38ffd7b596c5888b36588e4490c4d4bc35e7be62 (patch)
tree756e3ce290178b279026e744da0bcf7d793a42b8
downloadhammer-of-the-scots-38ffd7b596c5888b36588e4490c4d4bc35e7be62.tar.gz
hammer: Import Hammer of the Scots.
-rw-r--r--Scottish_Thistle_(Heraldry).svg1
-rw-r--r--about.html8
-rw-r--r--cards/card_1.jpgbin0 -> 55793 bytes
-rw-r--r--cards/card_1.pngbin0 -> 493108 bytes
-rw-r--r--cards/card_2.jpgbin0 -> 58652 bytes
-rw-r--r--cards/card_2.pngbin0 -> 511264 bytes
-rw-r--r--cards/card_3.jpgbin0 -> 59809 bytes
-rw-r--r--cards/card_3.pngbin0 -> 518804 bytes
-rw-r--r--cards/card_back.svg90
-rw-r--r--cards/card_herald.jpgbin0 -> 69451 bytes
-rw-r--r--cards/card_herald.pngbin0 -> 551725 bytes
-rw-r--r--cards/card_pillage.jpgbin0 -> 69529 bytes
-rw-r--r--cards/card_pillage.pngbin0 -> 551547 bytes
-rw-r--r--cards/card_sea_move.jpgbin0 -> 66550 bytes
-rw-r--r--cards/card_sea_move.pngbin0 -> 543169 bytes
-rw-r--r--cards/card_truce.jpgbin0 -> 67505 bytes
-rw-r--r--cards/card_truce.pngbin0 -> 546330 bytes
-rw-r--r--cards/card_victuals.jpgbin0 -> 63486 bytes
-rw-r--r--cards/card_victuals.pngbin0 -> 531693 bytes
-rw-r--r--cover.1x.jpgbin0 -> 32485 bytes
-rw-r--r--cover.2x.jpgbin0 -> 118138 bytes
-rw-r--r--cover.jpgbin0 -> 388706 bytes
-rw-r--r--data.js314
-rw-r--r--info/blocks.html181
-rw-r--r--info/cards.html42
-rw-r--r--info/notes.html25
-rw-r--r--info/rules.html18
-rw-r--r--info/rules1.jpgbin0 -> 255499 bytes
-rw-r--r--info/rules2.jpgbin0 -> 224607 bytes
-rw-r--r--info/rules3.jpgbin0 -> 250771 bytes
-rw-r--r--info/rules4.jpgbin0 -> 268494 bytes
-rw-r--r--info/rules5.jpgbin0 -> 250278 bytes
-rw-r--r--info/rules6.jpgbin0 -> 247756 bytes
-rw-r--r--info/rules7.jpgbin0 -> 231085 bytes
-rw-r--r--info/rules8.jpgbin0 -> 196200 bytes
-rw-r--r--map150.pngbin0 -> 15049229 bytes
-rw-r--r--map75.pngbin0 -> 4429961 bytes
-rw-r--r--new_blocks_england.pngbin0 -> 216858 bytes
-rw-r--r--new_blocks_scotland.pngbin0 -> 237072 bytes
-rw-r--r--old_blocks_england.pngbin0 -> 100252 bytes
-rw-r--r--old_blocks_scotland.pngbin0 -> 129085 bytes
-rw-r--r--play.html888
-rw-r--r--rules.js2825
-rw-r--r--thumbnail.jpgbin0 -> 18115 bytes
-rw-r--r--turn_marker.jpgbin0 -> 14589 bytes
-rw-r--r--ui.js740
46 files changed, 5132 insertions, 0 deletions
diff --git a/Scottish_Thistle_(Heraldry).svg b/Scottish_Thistle_(Heraldry).svg
new file mode 100644
index 0000000..f97cdfc
--- /dev/null
+++ b/Scottish_Thistle_(Heraldry).svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250"><g stroke-width="1.5"><path d="M129.6 227.4S116 222 102 224.2c-9.7 1.6-17 10.6-26.6 12.4-3.6.7-11-.7-11-.7 7.1-4.2 5.8-8.5 7.8-12.7-2.7-.9-3.3 1-8-1.7-5.3-3-3.5-9.5-13.2-9.6-9 0-15.9 4.2-24.1 8.8-1.8-6.6 1.5-9.8 3.2-13.5-3.6-1.4-3.1-9-12.4-13.8 12.4-4 15 8.7 25.5 5-4.5-15.9-35.8-15.6-41.5-47.8 11.5 10.4 20 7.6 21.7 6.7-2.3-4.3-5.2-9.8-7.6-15-3.3-6.7-1.3-14-7-20.8 6.7 2.3 7.3 4.5 9.6 6.8-.5-5.3-1.4-10.7 1.4-16 1.4 2.8 2 6.8 5.3 6.4 2.4-8 5.9-13.6 11-15.6-2.1 8.7 4.6 15.1-1 23.8 5.2 1.8 8-5.4 14.8-3.2-2.7 6.2-5.7 10.8-7.2 24.9-.9 8.8 9.5 11.5 11.6 3.4.5-2 .6-1.7-.1-7.4 13.5 11.7 3.4 24.2 6.7 36 1.9 7 9.8 4.4 9.2 0l-1.4-9.8 4.6 3.2-2.9-9.6s6.4 2.2 8.5 4.6c9 10 6.4 27.1 15 37.5 2.2 2.7 5.6 4.3 8.8 5.7 3.9 1.7 8.5 1.3 12.4 3.2a32.8 32.8 0 0114.5 12z" fill="#218b4d" stroke="#16502d"/><path d="M32.7 110l1 5.6c.7 3.5 1 6-1.4 9.5A3.2 3.2 0 0034 130c2 .7 4 .5 5.7 0 1.5-.6 2.7-1.4 3.8-2l1.4-.7a61.2 61.2 0 00-5.4 21c-.6 5.7 2.7 10.3 7 11.5 4 1.1 8.8-1.4 10.5-6.1 1.2 2.8 1.4 5.6 1.2 8.7-.4 5.7-2.4 12.2-.4 19.2 1.3 4.7 5.6 7 9.1 6.5 1.8-.2 3.4-1 4.6-2.4 1.3-1.3 2-3.3 1.7-5.4l-.4-3a3.2 3.2 0 003.5-4.2l-.7-2.5 1 .6a38.3 38.3 0 016.8 17.3c1.5 6.8 3 14.2 8 20.2 2.8 3.5 6.8 5.1 10 6.5 5 2.2 9.5 1.8 12.3 3.2 2.1 1 3.8 2 5.3 3.2-5-1-11.1-1.5-17.6-.4-5.6 1-10.2 3.9-14.4 6.5-4.3 2.7-8.2 5.1-12.2 5.9h-3.2c.6-1 1.3-2 1.6-2.8 1-2.6 1.2-4.6 2-6.2a3.2 3.2 0 00-2-4.4c-2-.6-3.6-.3-4.3-.3-.6 0-1 0-3-1-1.8-1-2.3-2.6-4-5a13 13 0 00-10.9-5c-8.1-.2-14.6 3-21.2 6.6.5-2.3 2-4 3.2-6.9a3.2 3.2 0 00-1.7-4.2s-.2-.1-.6-.8l-1.9-3.5c-.5-1-1.4-2.1-2.3-3.2 1 .4 1.9 1 3 1.7 1.7 1 3.6 2.4 6 3.1 2.5.8 5.5 1 8.7-.2a3.2 3.2 0 002-3.9c-1.3-4.9-4.7-8.4-8.7-11.3-3.9-3-8.4-5.4-12.8-8.3a41 41 0 01-17.4-19.5c3.1 1.7 6 2.6 8.5 3 4.5.5 7.5-.5 9-1.3a3.2 3.2 0 001.4-4.3c-2.2-4.2-5.1-9.7-7.5-14.8-1.4-2.8-1.7-6-2.4-9.6l-.2-.9a3.2 3.2 0 005.5-2.5c-.3-2.7-.5-5-.5-7.3l.2.2c1.2.8 2.7 1.2 4.2 1a3.2 3.2 0 002.7-2.3c1.2-4.2 2.8-7.3 4.5-9.6z" fill="#219d56"/><path d="M26.7 126.9a8.3 8.3 0 005.5 7.8c1.5.5 3 .7 4.5.7-1 3.4-1.7 7.3-2.3 12.3-.8 7.7 4 15 10.8 17 2.4.6 5 .4 7.6-.5-.7 4.8-2 11 0 18.7 1.9 6.6 9.1 11 14.9 10.2a12 12 0 009.7-7.4l1 3.8c1.5 6.7 3 15 9 22.3 2.3 2.9 5 4.6 7.4 5.8-4.1 1.6-7.6 3.9-10.6 5.7l-4 2.4a8.3 8.3 0 00-5.5-10.5c-3.1-1-6-.5-5.8-.5 0 0 1 .4-.6-.5-.1 0 0-.2-2.3-3.4a20 20 0 00-15-7.2l-1.5.2a8.3 8.3 0 001.7-7.7 26.9 26.9 0 00-10.6-14c-4.4-3.2-9-5.7-13.1-8.5a54 54 0 01-8.8-7c3.7 0 6.5-.9 8.5-2a8.3 8.3 0 003.5-11.1l-7.4-14.8c-.4-.8-.7-1.8-1-3a8.3 8.3 0 004.4-8.2v-.6z" fill="#21ad5e"/><path d="M31 117.8s-1.7 3.3-2.5 7.2c-1 3.8-1 8.3-.7 11.2.5 7.3 2.3 14.5 5 21.5-.3-6-.6-18.6 8.9-26.5a39 39 0 00-7.3 30.3A67.3 67.3 0 0051 184.7c-1.5-6.3-1-10 0-13.2 1.3-3.7 3.1-6.8 3.8-13.7 1.4 4.6-2.3 11-3.2 18.7-.3 3 .5 7 1.3 10.1a146 146 0 015.6 5.7c6.1 6.7 10.2 12.2 16.4 18.2 1.4 1.4 3.4 2.6 5.4 3.8a25.4 25.4 0 01-3.3-16.5c.5-6 1.4-11.7-1.3-17.3 4.6 4.4 3 15.4 2.8 17.5-.4 5.9-.2 11.6 4.7 17.7a35 35 0 004.8 1.7c5.6 1.5 10.7 1.4 16.2 2.4H98c-3.4 0-7.5-.1-10.3-.8a35.3 35.3 0 01-16-8.9 51.6 51.6 0 00-17-5.1 25 25 0 00-18.4 5.4c2.3-4.4 11.7-6.8 13.7-7h5c4.8.5 9.3 1.6 13.7 3.7-4.2-4.4-7.8-9.2-11.7-13.5l-8.1-8c-5.8-4-11.7-6.1-17.3-9-3.5-1.9-15-6.3-18-13 5.6 5.6 12 8.7 18.6 11.6 4 1.8 8.2 3.6 12.3 6a51.6 51.6 0 01-11.2-17.8l-11.4-17c2.1.8 6.3 6.8 9 10.9-5-14.1-8.2-31.9.2-39.5z" style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Sans" font-weight="400" color="#000" fill="#1b6d3c" overflow="visible" font-family="Sans"/><path d="M120.4 227.4s13.6-5.5 27.6-3.2c9.7 1.6 17 10.6 26.6 12.4 3.6.7 11-.7 11-.7-7.1-4.2-5.8-8.5-7.8-12.7 2.7-.9 3.3 1 8-1.7 5.3-3 3.5-9.5 13.2-9.6 9 0 15.9 4.2 24.1 8.8 1.8-6.6-1.5-9.8-3.2-13.5 3.6-1.4 3.1-9 12.4-13.8-12.4-4-15 8.7-25.5 5 4.5-15.9 35.8-15.6 41.5-47.8-11.5 10.4-20 7.6-21.7 6.7 2.3-4.3 5.2-9.8 7.6-15 3.3-6.7 1.3-14 7-20.8-6.7 2.3-7.3 4.5-9.6 6.8.5-5.3 1.4-10.7-1.4-16-1.4 2.8-2 6.8-5.3 6.4-2.4-8-5.9-13.6-11-15.6 2.1 8.7-4.6 15.1 1 23.8-5.2 1.8-8-5.4-14.8-3.2 2.7 6.2 5.7 10.8 7.2 24.9.9 8.8-9.5 11.5-11.6 3.4-.5-2-.6-1.7.1-7.4-13.5 11.7-3.4 24.2-6.7 36-1.9 7-9.8 4.4-9.2 0l1.4-9.8-4.6 3.2 2.9-9.6s-6.4 2.2-8.5 4.6c-9 10-6.4 27.1-15 37.5a22.9 22.9 0 01-8.8 5.7c-3.9 1.7-8.5 1.3-12.4 3.2a32.8 32.8 0 00-14.5 12z" fill="#218b4d" stroke="#16502d"/><path d="M217.3 110l-1 5.6c-.7 3.5-1 6 1.4 9.5a3.2 3.2 0 01-1.7 4.8c-2 .7-4 .5-5.7 0-1.5-.6-2.7-1.4-3.8-2l-1.4-.7a61.2 61.2 0 015.4 21c.6 5.7-2.7 10.3-7 11.5-4 1.1-8.8-1.4-10.5-6.1a18.5 18.5 0 00-1.2 8.7c.4 5.7 2.4 12.2.4 19.2-1.3 4.7-5.6 7-9.1 6.5-1.8-.2-3.4-1-4.6-2.4a6.7 6.7 0 01-1.7-5.4l.4-3a3.2 3.2 0 01-3.5-4.2l.7-2.5-1 .6a38.3 38.3 0 00-6.8 17.3c-1.5 6.8-3 14.2-8 20.2-2.8 3.5-6.8 5.1-10 6.5-5 2.2-9.5 1.8-12.3 3.2-2.1 1-3.8 2-5.3 3.2 5-1 11.1-1.5 17.6-.4 5.6 1 10.2 3.9 14.4 6.5 4.3 2.7 8.2 5.1 12.2 5.9h3.2c-.6-1-1.3-2-1.6-2.8-1-2.6-1.2-4.6-2-6.2a3.2 3.2 0 012-4.4c2-.6 3.6-.3 4.3-.3.6 0 1 0 3-1 1.8-1 2.3-2.6 4-5a13 13 0 0110.9-5c8.1-.2 14.6 3 21.2 6.6-.5-2.3-2-4-3.2-6.9a3.2 3.2 0 011.7-4.2s.2-.1.6-.8l1.9-3.5c.5-1 1.4-2.1 2.3-3.2-1 .4-1.9 1-3 1.7-1.7 1-3.6 2.4-6 3.1-2.5.8-5.5 1-8.7-.2a3.2 3.2 0 01-2-3.9c1.3-4.9 4.7-8.4 8.7-11.3 3.9-3 8.4-5.4 12.8-8.3a41 41 0 0017.4-19.5c-3.1 1.7-6 2.6-8.5 3-4.5.5-7.5-.5-9-1.3a3.2 3.2 0 01-1.4-4.3c2.2-4.2 5.1-9.7 7.5-14.8 1.4-2.8 1.7-6 2.4-9.6l.2-.9a3.2 3.2 0 01-5.5-2.5c.3-2.7.5-5 .5-7.3l-.2.2a6.4 6.4 0 01-4.2 1 3.2 3.2 0 01-2.7-2.3 30.7 30.7 0 00-4.5-9.6z" fill="#219d56"/><path d="M223.3 126.9a8.3 8.3 0 01-5.5 7.8c-1.5.5-3 .7-4.5.7 1 3.4 1.7 7.3 2.3 12.3.8 7.7-4 15-10.8 17-2.4.6-5 .4-7.6-.5.7 4.8 2 11 0 18.7-1.9 6.6-9.1 11-14.9 10.2a12 12 0 01-9.7-7.4l-1 3.8c-1.5 6.7-3 15-9 22.3-2.3 2.9-5 4.6-7.4 5.8 4.1 1.6 7.6 3.9 10.6 5.7l4 2.4a8.3 8.3 0 015.5-10.5c3.1-1 6-.5 5.8-.5 0 0-1 .4.6-.5.1 0 0-.2 2.3-3.4a20 20 0 0115-7.2l1.5.2a8.3 8.3 0 01-1.7-7.7 26.9 26.9 0 0110.6-14c4.4-3.2 9-5.7 13.1-8.5a54 54 0 008.8-7c-3.7 0-6.5-.9-8.5-2a8.3 8.3 0 01-3.5-11.1l7.4-14.8c.4-.8.7-1.8 1-3a8.3 8.3 0 01-4.4-8.2v-.6z" fill="#21ad5e"/><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Sans" d="M219 117.8a34 34 0 003.2 18.4 74.1 74.1 0 01-5 21.5c.3-6 .6-18.6-8.9-26.5a39 39 0 017.3 30.3 67.3 67.3 0 01-16.6 23.2c1.5-6.3 1-10 0-13.2-1.3-3.7-3.1-6.8-3.8-13.7-1.4 4.6 2.3 11 3.2 18.7.3 3-.5 7-1.3 10.1a146 146 0 00-5.6 5.7c-6.1 6.7-10.2 12.2-16.4 18.2a25.6 25.6 0 01-5.4 3.8 25.4 25.4 0 003.3-16.5c-.5-6-1.4-11.7 1.3-17.3-4.6 4.4-3 15.4-2.8 17.5.4 5.9.2 11.6-4.7 17.7a35 35 0 01-4.8 1.7c-5.6 1.5-10.7 1.4-16.2 2.4h6.2c3.4 0 7.5-.1 10.3-.8a35.3 35.3 0 0016-8.9 51.6 51.6 0 0117-5.1 25 25 0 0118.4 5.4c-2.3-4.4-11.7-6.8-13.7-7h-5c-4.8.5-9.3 1.6-13.7 3.7 4.2-4.4 7.8-9.2 11.7-13.5l8.1-8c5.8-4 11.7-6.1 17.3-9 3.5-1.9 15-6.3 18-13-5.6 5.6-12 8.7-18.6 11.6-4 1.8-8.2 3.6-12.3 6a51.6 51.6 0 0011.2-17.8l11.4-17c-2.1.8-6.3 6.8-9 10.9 5-14.1 8.2-31.9-.2-39.5z" font-weight="400" color="#000" fill="#1b6d3c" overflow="visible" font-family="Sans"/><g stroke-width="1.2" font-weight="400" color="#000" fill="#1a5d34" font-family="Bitstream Vera Sans"><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Bitstream Vera Sans" d="M109.6 155.7c7.8 2.5 10 3.5 14.3 4.2 1.1 1.5-.2 1.5-.6 2a214 214 0 01-13.7-6.2zM111 162c7 3.6 8.9 5 12.9 6.2.7 1.7-.5 1.4-1.1 1.8-5-3.2-5.6-3.6-11.7-8zM109.5 171.2c7.8 2.6 10 3.5 14.3 4.2 1.1 1.5-.1 1.5-.6 2a214 214 0 01-13.7-6.2zM111.7 178.3c7.2 3.3 9.2 4.5 13.3 5.6.9 1.6-.4 1.5-1 2-5.2-3-5.8-3.5-12.3-7.6zM110.3 188c6.8 3.7 8.7 5 12.7 6.4.6 1.7-.6 1.4-1.2 1.8-5-3.3-5.5-3.7-11.5-8.2zM107.4 199.3c7.8 2.5 10 3.5 14.3 4.1 1.1 1.6-.2 1.5-.6 2a214 214 0 01-13.7-6.1zM106.5 211c7.7 2.6 10 3.6 14.2 4.2 1.1 1.5-.1 1.5-.6 2a214 214 0 01-13.6-6.1zM105.8 222.9c7.8 2.5 10 3.5 14.3 4.1 1.1 1.6-.1 1.5-.6 2a214 214 0 01-13.7-6.1zM137.8 208.8c-7.2 3.3-9.2 4.5-13.3 5.6-.8 1.6.4 1.5 1 1.9 5.2-3 5.9-3.4 12.3-7.5zM138.3 198.8c-7.2 3.3-9.3 4.5-13.4 5.5-.8 1.7.4 1.5 1 2 5.3-3 6-3.4 12.4-7.5zM136.9 190.6c-7.2 3.4-9.3 4.5-13.3 5.6-.9 1.7.4 1.5 1 2 5.2-3 5.8-3.4 12.3-7.6zM138.6 180.9c-6.3 4.2-8 5.7-11.8 7.3-.5 1.7.7 1.4 1.4 1.7 4.5-3.6 5-4.1 10.4-9zM140.5 170.2c-6.8 3.8-8.7 5-12.7 6.4-.7 1.7.6 1.5 1.2 1.9 4.9-3.3 5.5-3.8 11.5-8.3zM140.7 163.3c-7.7 2.6-10 3.6-14.2 4.3-1.1 1.6.2 1.5.7 2 5.7-2.5 6.4-2.8 13.5-6.3zM139.9 155c-8 2.2-10.3 3-14.6 3.5-1.3 1.4 0 1.5.4 2 6-2.1 6.7-2.4 14.2-5.4z" overflow="visible"/></g><g stroke-width="1.4"><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Sans" d="M181.6-718.4s-7 23.8-6.2 40.4c.5 8 2.1 20.5 2.2 27.7 0 7.3-2.8 17-3.6 25.7-.5 6 .6 12.9.7 20.2 0 5-1 11.9-1 11.9l11.5-16s-3.5-8.3-2.9-16.1c.7-7.5 2.3-16.7 2.3-25.7-.1-8.2-1.8-20.7-2.2-28-.8-14.2 6-38.1 6-38.1z" font-weight="400" color="#000" fill="#218b4d" stroke="#185731" overflow="visible" font-family="Sans" transform="matrix(1.1792 0 0 1.03779 -87.5 861.5)"/><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Sans" d="M129 116.5s-8.3 24.7-7.3 41.3c.5 8 2.5 21 2.5 28.8.1 8-3 18.2-4 26.9-.9 9.7 1 16.4 1 16.4.8-2.4 3.1-3.1 5.6-4.1 0 0-2.8-3.5-2-12.3.9-8.1 3-18.1 3-27-.1-8.1-2-21-2.5-28.9-1-15.4 7-40.2 7-40.2z" font-weight="400" color="#000" fill="#21ad5e" overflow="visible" font-family="Sans"/><g stroke-width="1.9"><path d="M100-225.6s3.3-2 6-4.5c4.9-4.6 11.3-17.7 19.4-14.2 1.2.6 2.2 2 2.3 3.3 1 7.4-10.6 12.8-16 14.3-4.8 1.4-11.6 1-11.6 1z" fill="#1e7b44" stroke="#144929" transform="matrix(.78496 -.30842 .35044 .69083 116 435.4)"/><path d="M127 230.3c-1.3.3-2.7 3.4-3.6 6.5-.7 2-2 5.6-2.5 7.7 3.4-1.4 8.8-7.8 9.2-11.5.1-1.6-.7-3-3.2-2.7z" fill="#1b6d3c"/></g></g><g stroke-width=".5"><path d="M105.8 97C99 68.4 61.7 28.4 61.7 28.4s.4-2.8 2-4c1.7-1.4 4.5-1.1 5.8-2 1.4-1 1.1-3.5 2.5-4.4 1.3-.8 4.2 0 5.6-.9 1.3-.8 1.7-3.6 3-4.4 1.4-.7 3.8.7 5.2 0 1.4-.6 1.9-3.7 3.3-4.3 1.4-.6 3.7 1.3 5 .8 1.5-.5 1.8-3 3.2-3.5 1.4-.5 3.9 1.2 5.3.8 1.4-.4 2-2.8 3.3-3.1 1.5-.4 3.7 1.5 5.2 1.2 1.4-.2 2.6-2.2 4-2.4 1.4-.2 3 1.5 4.4 1.3 1.4 0 2.8-2.3 4.2-2.3 1.5 0 2.8 2 4.2 2 1.4 0 2.8-1.8 4.2-1.7 1.4 0 2.8 2.1 4.2 2.3 1.3.1 2.7-1.8 4-1.6 1.5.2 2.8 2.6 4.2 2.9 1.3.2 3.4-1.6 4.7-1.2 1.3.3 2 2.8 3.3 3.2 1.3.4 3.1-1 4.4-.6 1.3.5 2 2.9 3.4 3.4 1.2.6 3.6-1.1 4.8-.6 1.3.6 1.5 3.5 2.7 4.2 1.2.7 3.5-.6 4.7.1 1.2.8 1.3 3.4 2.5 4.2 1.2.8 3.7-.1 4.9.7 1.1.8.8 3.5 2 4.4 1 .9 3.6.2 4.9 1.4 1.3 1.2 1.5 4.3 1.5 4.3S150.9 68.6 143.9 97h-38z" fill="#a44476"/><path d="M135 4.3c1.3.2 4-2.2 5.4-2 1.4.2 2.7 2.6 4 2.9 1.4.2 3.5-1.6 4.8-1.2 1.3.3 2 2.8 3.3 3.2 1.3.4 3.1-1 4.4-.6 1.3.5 2 2.9 3.4 3.4 1.2.6 3.6-1.1 4.8-.6 1.3.6 1.5 3.5 2.7 4.2 1.2.7 3.5-.6 4.7.1 1.2.8 7.7 8 9 8.7-22.3 21-35.4 34.5-44.3 74.7h-6.4c-2.8-28.9-7-64.8 4.1-92.8z" fill="#b15183"/><path d="M140.4 2.3c1.4.2 2.7 2.6 4 2.9 1.4.2 3.5-1.6 4.8-1.2 1.3.3 2 2.8 3.3 3.2 1.3.4 3.1-1 4.4-.6 1.3.5 2 2.9 3.4 3.4 1.2.6 3.6-1.1 4.8-.6 1.3.6 1.5 3.5 2.7 4.2 1.2.7 3.5-.6 4.7.1C157 28.1 140 65.2 133 97.1h-6.3c.2-24 5.6-72 13.6-94.8z" fill="#b9618e"/><path d="M123.4 101.8l-14-4.3C100 70.5 83.5 47.6 67.8 24l5-6.4h5.4l3.2-5 5.5 1 3.6-5 4.1.9 3.6-3.7 4.6 1.4 3.2-3.6 5.4 2.3c9.4 29.6 8.5 65.1 12 96z" fill="#923e66"/><path d="M112.2 97C100.6 71.9 91.7 46.6 71 21.2l1.8-3.6h4c21.8 26.6 29.1 53 40.8 79.6l1.2.5c-4.5-19.7-5.6-44-32.8-84.2l3.6-5 4.1.5c13.6 14.9 29 80 30.1 88.7l-11.6-.5z" fill="#782e51"/><path d="M167.3 12.7l-1.8-4.1-3.6 1.3C151.5 26 152 30.7 149.5 38c4-4 4.6-14.6 17.8-25.2zM180.5 22.2l-1.8-4-3.6 1.3c-18.6 19.3-19.6 28-21.2 34.5 3.4-6.3 13.3-21.8 26.6-31.8zM135.2 4.5l-3.3-3.1-2.8 2.7c-5 21.9-2.1 42-1.2 48.5 1-7.6.7-36.6 7.3-48.1z" fill="#c2779e"/><path d="M132.2 97.1c-1.3-31.7 3.6-62 12-91.3l5.4-2.3 2.3 4.1c-11.9 30-17.3 60-17 90l-2.7-.5z" fill="#9b3b6d"/><path d="M105.8 97C99 68.4 61.7 28.4 61.7 28.4s.4-2.8 2-4c1.7-1.4 4.5-1.1 5.8-2 1.4-1 1.1-3.5 2.5-4.4 1.3-.8 4.2 0 5.6-.9 1.3-.8 1.7-3.6 3-4.4 1.4-.7 3.8.7 5.2 0 1.4-.6 1.9-3.7 3.3-4.3 1.4-.6 3.7 1.3 5 .8 1.5-.5 1.8-3 3.2-3.5 1.4-.5 3.9 1.2 5.3.8 1.4-.4 2-2.8 3.3-3.1 1.5-.4 3.7 1.5 5.2 1.2 1.4-.2 2.6-2.2 4-2.4 1.4-.2 3 1.5 4.4 1.3 1.4 0 2.8-2.3 4.2-2.3 1.5 0 2.8 2 4.2 2 1.4 0 2.8-1.8 4.2-1.7 1.4 0 2.8 2.1 4.2 2.3 1.3.1 2.7-1.8 4-1.6 1.5.2 2.8 2.6 4.2 2.9 1.3.2 3.4-1.6 4.7-1.2 1.3.3 2 2.8 3.3 3.2 1.3.4 3.1-1 4.4-.6 1.3.5 2 2.9 3.4 3.4 1.2.6 3.6-1.1 4.8-.6 1.3.6 1.5 3.5 2.7 4.2 1.2.7 3.5-.6 4.7.1 1.2.8 1.3 3.4 2.5 4.2 1.2.8 3.7-.1 4.9.7 1.1.8.8 3.5 2 4.4 1 .9 3.6.2 4.9 1.4 1.3 1.2 1.5 4.3 1.5 4.3S150.9 68.6 143.9 97h-38 0z" fill="none" stroke="#620040" stroke-width="1.385785"/></g><g stroke-width=".6" font-weight="400" color="#000" fill="#782e51" font-family="Bitstream Vera Sans"><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Bitstream Vera Sans" d="M46.8 68.5C56 75.8 76.4 94.3 89 100.7c.9 3.1-.9 2.6-1.8 3.3-11.8-7.9-28-19.8-40.5-35.5zM63.7 56.5c9.8 8.3 26.7 26 36.6 34.4.4 3.2-1.3 2.5-2.3 3-10.6-11.2-24.3-23-34.3-37.4zM40 89c10.3 5.8 33.2 21.1 46.7 25.5 1.3 3-.5 2.8-1.3 3.6-12.9-6-30.7-15.5-45.4-29.1zM42.5 113.3c11.2 4 36.5 14.8 50.5 16.7 1.8 2.7 0 2.8-.6 3.8-13.7-3.7-33-9.7-49.9-20.5zM47.2 137.5c12 .1 39.3 2.4 53.2-.3 2.6 2 1 2.6.7 3.7-14.2 1-34.4 1.4-53.9-3.4zM62.8 156.8c11.9-.8 39.4-.6 53-4.4 2.8 1.8 1.2 2.6 1 3.7-14.1 2-34.2 4-54 .7zM83.7 172c11.6-2.7 38.8-6.8 51.7-12.7 3 1.4 1.5 2.4 1.5 3.5a178.3 178.3 0 01-53.2 9.2zM203.3 68.8c-9.4 7.3-29.8 25.7-42.5 32-.8 3.2 1 2.7 1.8 3.4a178.3 178.3 0 0040.7-35.4zM186.4 56.7c-9.8 8.3-26.8 25.8-36.7 34.2-.4 3.3 1.3 2.6 2.2 3.1 10.7-11.1 24.4-22.9 34.5-37.3zM210 89.3c-10.4 5.8-33.3 21-46.8 25.3-1.3 3 .5 2.8 1.3 3.6 12.9-6 30.7-15.3 45.5-29zM207.4 113.6c-11.2 3.9-36.5 14.7-50.6 16.5-1.8 2.8 0 2.8.6 3.8 13.8-3.6 33-9.6 50-20.3zM202.6 137.8c-11.9 0-39.3 2.2-53.2-.5-2.6 2-1 2.6-.7 3.7 14.2 1 34.4 1.5 53.9-3.2zM185 157c-12-.8-39.4-.8-53-4.6-2.8 1.8-1.2 2.6-1 3.7 14 2.1 34.1 4.2 54 1z" overflow="visible"/><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Bitstream Vera Sans" d="M166 172.1c-11.6-2.6-38.7-6.9-51.6-12.8-3 1.4-1.6 2.4-1.5 3.5 13.5 4.3 33 9.5 53.1 9.3z" overflow="visible"/></g><g stroke-width=".5"><path d="M87 154.2c21 19.7 55 19.6 76 0a48.2 48.2 0 00-.1-71.3 56.2 56.2 0 00-76 0 48.2 48.2 0 00.2 71.3z" fill="#218b4d"/><path d="M93.2 81.3a47 47 0 0163.6-.2 40.2 40.2 0 010 59.6 46.9 46.9 0 01-63.6.2 40.3 40.3 0 010-59.6z" fill="#219d56"/><path d="M99.2 80.2a37.2 37.2 0 0150.6-.2c14 13.1 14.1 34 0 47.5a37.1 37.1 0 01-50.6.2 32 32 0 010-47.5z" fill="#21ad5e"/><path d="M103.8 82.8a26.4 26.4 0 0136.2-.3 22.6 22.6 0 01-.2 34 26.3 26.3 0 01-36 .2 22.7 22.7 0 010-34z" fill="#21c168"/><g fill="#1a5d34" font-weight="400" color="#000" font-family="Bitstream Vera Sans"><path d="M85.6 84l2.3-1.2c21.2 39.7 47.8 56.3 69.9 75.8l-4.6 2.5c-21.8-19.2-46-36.7-67.6-77zm12.8-10l1.8-.6c19 28.5 42.6 52.7 69.7 73.6l-3.4 3.6a313.4 313.4 0 01-68-76.5zM76 98l2-1.6c19.4 38 42.3 53 63.2 70l-6 1.2C114.3 150.7 95.6 136.3 76 98zm39.6-29l1.8-.7a315.2 315.2 0 0060 65.1l-3 4.5a326.8 326.8 0 01-58.8-69zm-44.7 49l1.8-1.7c12.5 25 31 40.3 47.7 52.8l-7.9-1.6A124.8 124.8 0 0170.9 118zm64-49l1.8-.7c16.5 25.5 29.3 34.3 42.6 44.5l-.8 5c-13.3-10.1-27-23-43.7-48.8z" style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Bitstream Vera Sans" overflow="visible"/><path d="M166 86.6l-2.1-1.3c-24 38.2-51.9 53-75.4 71l4.4 2.8c23.2-17.7 48.7-33.6 73.2-72.5zM154 76l-1.8-.8a308.3 308.3 0 01-73.8 68.7l3 3.8c28.9-19.3 51.3-44.2 72.6-71.7zm20.7 25.2l-2-1.6c-22.2 36.6-46 50.1-68.2 65.8l6 1.5c22-15.5 41.6-28.6 64.2-65.7zm-37.4-31.4l-1.8-.8a310.2 310.2 0 01-63.4 60.6L75 134c24.9-18.3 43.1-40 62.4-64.4zm40.9 51.7l-1.6-1.7c-14.4 24-34 38.2-51.6 49.5l8-1a126.5 126.5 0 0045.2-46.8zm-60.1-53l-1.9-.8C98 92 85.8 99.7 71.8 109l.4 5c14-9.2 27.3-21 45.9-45.6z" style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Bitstream Vera Sans" fill="#1b6d3c" overflow="visible"/></g><path d="M-281.4 1320.4c0 8.8-7.2 16-16.2 16-8.9 0-16.1-7.2-16.1-16 0-8.9 7.2-16 16.1-16 9 0 16.2 7.1 16.2 16z" transform="matrix(-2.34303 2.20672 2.37465 2.22024 -3707.6 -2156.3)" fill="none" stroke="#16502d"/></g></g></svg> \ No newline at end of file
diff --git a/about.html b/about.html
new file mode 100644
index 0000000..fa6f3ed
--- /dev/null
+++ b/about.html
@@ -0,0 +1,8 @@
+<p>
+Hammer of the Scots brings the rebellion of the Braveheart, William Wallace, to life. As the English player, you seek to pacify Scotland by controlling all the important noble lords. The Scottish player also seeks the allegiance of nobles to support a difficult struggle for freedom.
+
+<p>
+Designer: Tom Dalgliesh and Jerry Taylor.
+
+<p>
+Copyright &copy; 2002-2019 <a href="https://columbiagames.com/cgi-bin/query/cfg/zoom.cfg?product_id=3161">Columbia Games</a> and Jerry Taylor.
diff --git a/cards/card_1.jpg b/cards/card_1.jpg
new file mode 100644
index 0000000..b832375
--- /dev/null
+++ b/cards/card_1.jpg
Binary files differ
diff --git a/cards/card_1.png b/cards/card_1.png
new file mode 100644
index 0000000..6dc15f9
--- /dev/null
+++ b/cards/card_1.png
Binary files differ
diff --git a/cards/card_2.jpg b/cards/card_2.jpg
new file mode 100644
index 0000000..7875059
--- /dev/null
+++ b/cards/card_2.jpg
Binary files differ
diff --git a/cards/card_2.png b/cards/card_2.png
new file mode 100644
index 0000000..dd48d31
--- /dev/null
+++ b/cards/card_2.png
Binary files differ
diff --git a/cards/card_3.jpg b/cards/card_3.jpg
new file mode 100644
index 0000000..517843d
--- /dev/null
+++ b/cards/card_3.jpg
Binary files differ
diff --git a/cards/card_3.png b/cards/card_3.png
new file mode 100644
index 0000000..f57b45a
--- /dev/null
+++ b/cards/card_3.png
Binary files differ
diff --git a/cards/card_back.svg b/cards/card_back.svg
new file mode 100644
index 0000000..ac35b71
--- /dev/null
+++ b/cards/card_back.svg
@@ -0,0 +1,90 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
+ width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
+ preserveAspectRatio="xMidYMid meet">
+<metadata>
+Created by potrace 1.15, written by Peter Selinger 2001-2017
+</metadata>
+<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
+fill="#000000" stroke="none">
+<path d="M2087 4566 c-94 -34 -165 -107 -192 -199 -19 -63 -19 -117 -1 -187 8
+-30 12 -58 10 -61 -2 -4 -28 -13 -56 -19 -29 -7 -105 -31 -168 -53 -531 -185
+-847 -507 -979 -998 -30 -113 -60 -332 -68 -495 l-6 -144 431 0 c238 0 432 -3
+432 -6 0 -3 -7 -13 -16 -21 -29 -29 -464 -614 -464 -624 0 -5 122 -9 313 -8
+l312 0 65 85 c36 47 71 93 78 102 29 39 246 319 268 347 47 60 181 235 279
+364 55 73 128 169 163 214 l63 82 -499 3 -500 2 -6 31 c-9 48 -7 552 3 567 4
+8 19 12 32 10 l24 -3 3 -272 2 -273 235 0 235 0 2 473 3 472 100 5 c82 5 109
+11 150 32 112 59 168 153 168 283 0 67 -4 89 -26 131 -33 64 -113 137 -174
+158 -56 19 -164 20 -216 2z"/>
+<path d="M2831 4569 c-79 -24 -157 -95 -192 -174 -30 -67 -30 -180 -1 -245 30
+-66 87 -127 146 -158 42 -21 69 -27 151 -32 l100 -5 3 -472 2 -473 235 0 235
+0 0 270 0 270 26 6 c14 4 30 2 35 -3 5 -5 8 -129 7 -304 l-3 -294 -501 -5
+-502 -5 137 -181 c75 -99 154 -203 176 -232 22 -28 94 -121 160 -207 66 -86
+157 -204 203 -263 45 -59 89 -116 97 -127 9 -11 45 -57 81 -102 l65 -83 309 0
+c189 0 310 4 310 9 0 12 -446 611 -466 627 -8 6 -11 14 -7 17 3 4 198 7 431 7
+l425 0 -6 153 c-24 606 -225 1013 -636 1288 -137 92 -410 209 -579 249 -28 6
+-54 15 -57 19 -2 4 2 29 10 56 45 147 -16 299 -146 370 -45 24 -68 29 -134 32
+-44 1 -95 -2 -114 -8z"/>
+<path d="M2283 3181 c-37 -23 -47 -50 -39 -96 7 -35 50 -75 81 -75 25 0 73 28
+85 49 21 40 12 87 -21 115 -36 31 -63 33 -106 7z"/>
+<path d="M2525 3191 c-41 -17 -58 -48 -52 -93 16 -117 161 -114 174 3 5 42 3
+48 -27 72 -32 27 -59 32 -95 18z"/>
+<path d="M2748 3184 c-68 -36 -63 -126 9 -163 35 -18 59 -13 92 18 44 41 44
+98 0 135 -34 29 -61 32 -101 10z"/>
+<path d="M835 1503 c-42 -5 -115 -33 -144 -55 -96 -74 -105 -212 -19 -297 42
+-42 135 -81 195 -81 39 0 160 37 169 52 3 5 -4 20 -15 32 -22 23 -22 23 -59 5
+-69 -36 -145 -21 -177 34 -26 44 -26 150 0 194 33 56 88 68 173 36 39 -15 44
+-15 62 2 11 10 20 21 20 25 0 12 -92 47 -135 52 -22 2 -53 2 -70 1z"/>
+<path d="M1283 1499 c-87 -16 -165 -75 -183 -140 -35 -121 18 -224 139 -268
+73 -27 119 -27 192 0 112 41 176 146 149 243 -32 117 -164 191 -297 165z m107
+-67 c33 -34 45 -93 37 -183 -17 -188 -186 -159 -187 32 0 82 9 116 40 149 36
+39 72 39 110 2z"/>
+<path d="M1680 1290 l0 -200 138 0 139 0 11 25 c7 14 12 28 12 30 0 3 -36 5
+-80 5 l-80 0 0 170 0 170 -70 0 -70 0 0 -200z"/>
+<path d="M2060 1345 c0 -106 4 -153 14 -173 74 -142 340 -134 395 11 6 16 11
+91 11 168 l0 139 -70 0 -70 0 0 -150 c0 -137 -2 -152 -20 -170 -24 -24 -67
+-26 -98 -4 -21 15 -22 21 -22 170 l0 154 -70 0 -70 0 0 -145z"/>
+<path d="M2620 1290 l0 -200 40 0 40 0 0 126 c0 88 3 123 11 118 6 -3 36 -59
+67 -123 l57 -116 49 0 50 0 38 90 c21 50 44 102 49 118 21 52 29 26 29 -93 l0
+-120 70 0 70 0 0 200 0 200 -81 0 -80 0 -15 -37 c-8 -21 -21 -51 -29 -68 -7
+-16 -23 -54 -35 -82 -12 -29 -26 -53 -29 -53 -4 0 -33 54 -65 120 l-57 120
+-90 0 -89 0 0 -200z"/>
+<path d="M3320 1290 l0 -200 154 0 c85 0 167 5 183 11 50 19 73 48 73 94 0 46
+-23 75 -75 95 -22 9 -26 14 -15 19 60 25 87 76 65 128 -18 42 -70 53 -244 53
+l-141 0 0 -200z m237 129 c18 -16 16 -69 -4 -91 -10 -11 -30 -18 -55 -18 l-38
+0 0 59 c0 38 5 61 13 65 17 7 67 -2 84 -15z m12 -187 c23 -56 -15 -100 -80
+-90 -22 3 -24 9 -27 61 l-3 57 49 0 c45 0 51 -3 61 -28z"/>
+<path d="M3830 1290 l0 -200 70 0 70 0 0 200 0 200 -70 0 -70 0 0 -200z"/>
+<path d="M4216 1482 c-3 -5 -21 -46 -40 -93 -19 -46 -54 -132 -79 -191 l-45
+-108 47 0 c45 0 48 2 60 35 l12 35 85 0 85 0 15 -35 14 -35 75 0 c41 0 75 1
+75 3 0 6 -41 118 -93 252 l-55 140 -75 3 c-41 2 -78 -1 -81 -6z m72 -164 c31
+-88 31 -88 -32 -88 l-54 0 10 38 c15 53 39 112 47 112 3 0 16 -28 29 -62z"/>
+<path d="M1450 991 c-43 -14 -104 -48 -122 -68 -25 -27 -58 -104 -58 -135 0
+-35 32 -107 63 -139 47 -49 113 -73 202 -73 64 0 89 5 126 23 l47 23 4 92 c3
+50 3 94 1 99 -2 4 -44 7 -94 7 l-89 0 0 -29 c0 -24 5 -30 30 -34 29 -6 30 -8
+30 -67 l0 -60 -46 0 c-38 0 -51 5 -74 30 -57 61 -53 212 7 260 35 27 104 27
+150 -1 l35 -22 25 26 26 25 -44 23 c-47 24 -172 36 -219 20z"/>
+<path d="M3560 991 c-46 -11 -89 -41 -105 -71 -17 -34 -20 -83 -5 -110 13 -25
+85 -66 130 -75 19 -4 41 -11 50 -15 8 -4 28 -13 43 -19 33 -13 44 -36 26 -57
+-21 -26 -126 -15 -176 18 -35 23 -40 24 -61 10 -31 -20 -28 -37 13 -61 54 -32
+149 -46 223 -33 74 13 116 42 137 94 32 80 -22 136 -176 182 -88 26 -111 45
+-88 72 18 22 117 18 161 -6 36 -19 37 -19 60 0 l23 20 -25 19 c-45 35 -156 51
+-230 32z"/>
+<path d="M1931 968 c-5 -13 -25 -61 -45 -108 -57 -132 -104 -243 -110 -263 -5
+-16 0 -18 41 -15 43 3 47 5 58 38 l12 35 85 3 85 3 18 -41 18 -40 74 0 c40 0
+73 2 73 4 0 7 -59 167 -74 201 -7 17 -28 69 -46 118 l-34 87 -73 0 c-67 0 -74
+-2 -82 -22z m57 -110 c5 -7 15 -33 22 -58 6 -25 13 -53 16 -62 5 -16 -2 -18
+-50 -18 -62 0 -69 10 -42 62 8 15 17 40 21 57 7 33 16 38 33 19z"/>
+<path d="M2320 785 l0 -205 40 0 40 0 0 126 c0 96 3 125 13 122 12 -4 51 -76
+102 -190 26 -58 26 -58 70 -58 44 0 45 1 68 53 13 28 34 79 47 112 49 122 60
+115 60 -40 l0 -125 70 0 70 0 0 205 0 205 -82 0 -83 0 -24 -58 c-13 -31 -35
+-81 -48 -110 -12 -29 -23 -57 -23 -63 0 -33 -32 11 -83 114 l-58 117 -89 0
+-90 0 0 -205z"/>
+<path d="M3030 785 l0 -205 153 0 154 0 11 25 c7 14 12 30 12 35 0 6 -41 10
+-94 10 l-93 0 -7 38 c-10 64 -14 62 84 62 l90 0 0 35 0 35 -84 0 -84 0 -7 40
+c-4 21 -4 44 0 50 3 5 43 10 91 10 46 0 84 4 84 10 0 5 -5 21 -12 35 l-11 25
+-144 0 -143 0 0 -205z"/>
+</g>
+</svg>
diff --git a/cards/card_herald.jpg b/cards/card_herald.jpg
new file mode 100644
index 0000000..24d9105
--- /dev/null
+++ b/cards/card_herald.jpg
Binary files differ
diff --git a/cards/card_herald.png b/cards/card_herald.png
new file mode 100644
index 0000000..6f9723c
--- /dev/null
+++ b/cards/card_herald.png
Binary files differ
diff --git a/cards/card_pillage.jpg b/cards/card_pillage.jpg
new file mode 100644
index 0000000..7f0c2c7
--- /dev/null
+++ b/cards/card_pillage.jpg
Binary files differ
diff --git a/cards/card_pillage.png b/cards/card_pillage.png
new file mode 100644
index 0000000..ada8d92
--- /dev/null
+++ b/cards/card_pillage.png
Binary files differ
diff --git a/cards/card_sea_move.jpg b/cards/card_sea_move.jpg
new file mode 100644
index 0000000..d618d97
--- /dev/null
+++ b/cards/card_sea_move.jpg
Binary files differ
diff --git a/cards/card_sea_move.png b/cards/card_sea_move.png
new file mode 100644
index 0000000..9547697
--- /dev/null
+++ b/cards/card_sea_move.png
Binary files differ
diff --git a/cards/card_truce.jpg b/cards/card_truce.jpg
new file mode 100644
index 0000000..b1f062a
--- /dev/null
+++ b/cards/card_truce.jpg
Binary files differ
diff --git a/cards/card_truce.png b/cards/card_truce.png
new file mode 100644
index 0000000..b411bf1
--- /dev/null
+++ b/cards/card_truce.png
Binary files differ
diff --git a/cards/card_victuals.jpg b/cards/card_victuals.jpg
new file mode 100644
index 0000000..1114a8d
--- /dev/null
+++ b/cards/card_victuals.jpg
Binary files differ
diff --git a/cards/card_victuals.png b/cards/card_victuals.png
new file mode 100644
index 0000000..3ac24e8
--- /dev/null
+++ b/cards/card_victuals.png
Binary files differ
diff --git a/cover.1x.jpg b/cover.1x.jpg
new file mode 100644
index 0000000..595cbf1
--- /dev/null
+++ b/cover.1x.jpg
Binary files differ
diff --git a/cover.2x.jpg b/cover.2x.jpg
new file mode 100644
index 0000000..9f0cbf4
--- /dev/null
+++ b/cover.2x.jpg
Binary files differ
diff --git a/cover.jpg b/cover.jpg
new file mode 100644
index 0000000..db2d852
--- /dev/null
+++ b/cover.jpg
Binary files differ
diff --git a/data.js b/data.js
new file mode 100644
index 0000000..8a710a6
--- /dev/null
+++ b/data.js
@@ -0,0 +1,314 @@
+"use strict";
+
+const CARDS = {
+ 1: {
+ name: "Herald",
+ event: "herald",
+ image: "card_herald",
+ text: "Name an enemy noble (not Moray). Roll a die to convert him to your side at current strength.\n1-4 Success\n5-6 Failure\nIf a battle results, resolve it now with the defecting noble as the attacker."
+ },
+ 2: {
+ name: "Pillage",
+ event: "pillage",
+ image: "card_pillage",
+ text: "Pillage one enemy group adjacent to a friendly group. The enemy blocks take two (2) hits (applied as per combat losses).\nPillaged step(s) may be added to friendly blocks in the pillaging group."
+ },
+ 3: {
+ name: "Sea Move",
+ event: "sea_move",
+ image: "card_sea_move",
+ text: "Move one (1) or two (2) blocks from one coastal area to one other friendly (not vacant) coastal area (including England).\nThe Norse cannot use this card."
+ },
+ 4: {
+ name: "Truce",
+ event: "truce",
+ image: "card_truce",
+ text: "Opponent can move, but not attack. Scots cannot enter England."
+ },
+ 5: {
+ name: "Victuals",
+ event: "victuals",
+ image: "card_victuals",
+ text: "Distribute three (3) steps among friendly blocks in one group."
+ },
+ 6: { name: "a 3", moves: 3, image: "card_3" },
+ 7: { name: "a 3", moves: 3, image: "card_3" },
+ 8: { name: "a 3", moves: 3, image: "card_3" },
+ 9: { name: "a 2", moves: 2, image: "card_2" },
+ 10: { name: "a 2", moves: 2, image: "card_2" },
+ 11: { name: "a 2", moves: 2, image: "card_2" },
+ 12: { name: "a 2", moves: 2, image: "card_2" },
+ 13: { name: "a 2", moves: 2, image: "card_2" },
+ 14: { name: "a 2", moves: 2, image: "card_2" },
+ 15: { name: "a 2", moves: 2, image: "card_2" },
+ 16: { name: "a 2", moves: 2, image: "card_2" },
+ 17: { name: "a 2", moves: 2, image: "card_2" },
+ 18: { name: "a 2", moves: 2, image: "card_2" },
+ 19: { name: "a 1", moves: 1, image: "card_1" },
+ 20: { name: "a 1", moves: 1, image: "card_1" },
+ 21: { name: "a 1", moves: 1, image: "card_1" },
+ 22: { name: "a 1", moves: 1, image: "card_1" },
+ 23: { name: "a 1", moves: 1, image: "card_1" },
+ 24: { name: "a 1", moves: 1, image: "card_1" },
+ 25: { name: "a 1", moves: 1, image: "card_1" },
+};
+
+let BLOCKS = {}
+
+let AREAS = {
+ "England": { x: 1360, y: 1750 },
+ "Ross": { x: 583, y: 376 },
+ "Garmoran": { x: 466, y: 573 },
+ "Moray": { x: 644, y: 599 },
+ "Strathspey": { x: 973, y: 436 },
+ "Buchan": { x: 1218, y: 518 },
+ "Lochaber": { x: 435, y: 766 },
+ "Badenoch": { x: 834, y: 635 },
+ "Mar": { x: 974, y: 709 },
+ "Angus": { x: 1099, y: 820 },
+ "Argyll": { x: 433, y: 1099 },
+ "Atholl": { x: 714, y: 904 },
+ "Lennox": { x: 626, y: 1244 },
+ "Mentieth": { x: 748, y: 1067 },
+ "Fife": { x: 966, y: 1089 },
+ "Carrick": { x: 675, y: 1446 },
+ "Lanark": { x: 830, y: 1375 },
+ "Lothian": { x: 973, y: 1236 },
+ "Selkirk": { x: 1015, y: 1379 },
+ "Dunbar": { x: 1187, y: 1287 },
+ "Galloway": { x: 685, y: 1667 },
+ "Annan": { x: 946, y: 1566 },
+ "Teviot": { x: 1151, y: 1424 },
+
+ "E. Bag": { x: 150, y: 1900 },
+ "S. Bag": { x: 150, y: 50 },
+}
+
+let BORDERS = {};
+
+(function () {
+ function border(A,B,T) {
+ if (A > B)
+ [A, B] = [B, A];
+ let id = A + "/" + B;
+ AREAS[A].exits.push(B);
+ AREAS[B].exits.push(A);
+ BORDERS[id] = T;
+ }
+
+ for (let a in AREAS) {
+ AREAS[a].cathedral = false;
+ AREAS[a].home = null;
+ AREAS[a].coastal = false;
+ AREAS[a].exits = [];
+ }
+
+ AREAS["Strathspey"].cathedral = true;
+ AREAS["Lennox"].cathedral = true;
+ AREAS["Fife"].cathedral = true;
+
+ AREAS["Ross"].home = "Ross";
+ AREAS["Moray"].home = "Moray";
+ AREAS["Buchan"].home = "Buchan";
+ AREAS["Lochaber"].home = "Comyn";
+ AREAS["Badenoch"].home = "Comyn";
+ AREAS["Mar"].home = "Mar";
+ AREAS["Angus"].home = "Angus";
+ AREAS["Argyll"].home = "Argyll";
+ AREAS["Atholl"].home = "Atholl";
+ AREAS["Lennox"].home = "Lennox";
+ AREAS["Mentieth"].home = "Mentieth";
+ AREAS["Carrick"].home = "Bruce";
+ AREAS["Lanark"].home = "Steward";
+ AREAS["Dunbar"].home = "Dunbar";
+ AREAS["Galloway"].home = "Galloway";
+ AREAS["Annan"].home = "Bruce";
+
+ AREAS["England"].limit = 0;
+ AREAS["Ross"].limit = 1;
+ AREAS["Garmoran"].limit = 0;
+ AREAS["Moray"].limit = 2;
+ AREAS["Strathspey"].limit = 1;
+ AREAS["Buchan"].limit = 2;
+ AREAS["Lochaber"].limit = 1;
+ AREAS["Badenoch"].limit = 2;
+ AREAS["Mar"].limit = 1;
+ AREAS["Angus"].limit = 2;
+ AREAS["Argyll"].limit = 2;
+ AREAS["Atholl"].limit = 1;
+ AREAS["Lennox"].limit = 1;
+ AREAS["Mentieth"].limit = 3;
+ AREAS["Fife"].limit = 2;
+ AREAS["Carrick"].limit = 1;
+ AREAS["Lanark"].limit = 2;
+ AREAS["Lothian"].limit = 2;
+ AREAS["Selkirk"].limit = 0;
+ AREAS["Dunbar"].limit = 2;
+ AREAS["Galloway"].limit = 1;
+ AREAS["Annan"].limit = 2;
+ AREAS["Teviot"].limit = 1;
+
+ function red(A,B) { border(A,B,"minor"); }
+ function black(A,B) { border(A,B,"major"); }
+ function northsea(A) { AREAS[A].coastal = true; }
+ function irishsea(A) { AREAS[A].coastal = true; }
+
+ black("Buchan", "Angus")
+ black("Buchan", "Mar")
+ black("Carrick", "Annan")
+ black("Carrick", "Lanark")
+ black("England", "Annan")
+ black("England", "Dunbar")
+ black("Fife", "Angus")
+ black("Fife", "Mentieth")
+ black("Lanark", "Mentieth")
+ black("Lennox", "Carrick")
+ black("Lennox", "Lanark")
+ black("Lennox", "Mentieth")
+ black("Lothian", "Dunbar")
+ black("Lothian", "Lanark")
+ black("Lothian", "Mentieth")
+ black("Moray", "Lochaber")
+ black("Moray", "Strathspey")
+ black("Selkirk", "Teviot")
+ black("Strathspey", "Badenoch")
+ black("Strathspey", "Buchan")
+ black("Teviot", "Dunbar")
+ red("Angus", "Mar")
+ red("Argyll", "Lennox")
+ red("Atholl", "Angus")
+ red("Atholl", "Argyll")
+ red("Atholl", "Badenoch")
+ red("Atholl", "Fife")
+ red("Atholl", "Lennox")
+ red("Atholl", "Mar")
+ red("Atholl", "Mentieth")
+ red("Badenoch", "Lochaber")
+ red("Badenoch", "Mar")
+ red("Buchan", "Badenoch")
+ red("England", "Teviot")
+ red("Galloway", "Annan")
+ red("Lanark", "Annan")
+ red("Galloway", "Carrick")
+ red("Garmoran", "Lochaber")
+ red("Garmoran", "Moray")
+ red("Lochaber", "Argyll")
+ red("Lochaber", "Atholl")
+ red("Moray", "Badenoch")
+ red("Ross", "Garmoran")
+ red("Ross", "Moray")
+ red("Selkirk", "Annan")
+ red("Selkirk", "Dunbar")
+ red("Selkirk", "Lanark")
+ red("Selkirk", "Lothian")
+ red("Teviot", "Annan")
+
+ northsea("England")
+ northsea("Ross")
+ northsea("Moray")
+ northsea("Strathspey")
+ northsea("Buchan")
+ northsea("Angus")
+ northsea("Mentieth")
+ northsea("Fife")
+ northsea("Lothian")
+ northsea("Dunbar")
+
+ irishsea("England")
+ irishsea("Ross")
+ irishsea("Garmoran")
+ irishsea("Lochaber")
+ irishsea("Argyll")
+ irishsea("Lennox")
+ irishsea("Carrick")
+ irishsea("Galloway")
+ irishsea("Annan")
+
+ function block(owner, type, name, move, combat, steps, mortal, image) {
+ let id = name;
+ if (type == 'nobles')
+ id = name + "/" + owner[0];
+ let item = {
+ owner: owner,
+ type: type,
+ name: name,
+ move: move,
+ combat: combat,
+ steps: steps,
+ mortal: mortal,
+ image: image,
+ }
+ BLOCKS[id] = item;
+ }
+
+ const A4 = "A4"; const A3 = "A3"; const A2 = "A2"; const A1 = "A1";
+ const B4 = "B4"; const B3 = "B3"; const B2 = "B2"; const B1 = "B1";
+ const C4 = "C4"; const C3 = "C3"; const C2 = "C2"; const C1 = "C1";
+
+ block("Scotland", "wallace", "Wallace", 3, A3, 4, true, 11);
+ block("Scotland", "king", "King", 3, A3, 4, true, 12);
+ block("Scotland", "infantry", "Douglas", 2, C3, 4, false, 13);
+ block("Scotland", "infantry", "Campbell", 2, C2, 4, false, 14);
+ block("Scotland", "infantry", "Graham", 2, C2, 4, false, 15);
+ block("Scotland", "infantry", "MacDonald", 2, C3, 3, false, 16);
+ block("Scotland", "infantry", "Lindsay", 2, C2, 3, false, 17);
+
+ block("Scotland", "infantry", "Fraser", 2, C3, 3, false, 21);
+ block("Scotland", "infantry", "Barclay", 2, C2, 4, false, 22);
+ block("Scotland", "infantry", "Grant", 2, C2, 3, false, 23);
+ block("Scotland", "cavalry", "Keith", 3, B1, 3, false, 24);
+ block("Scotland", "archers", "Etterick", 3, B2, 2, false, 25);
+ block("Scotland", "norse", "Norse", 0, A2, 3, true, 26);
+ block("Scotland", "knights", "French Knights", 2, B3, 4, true, 27);
+
+ block("Scotland", "nobles", "Comyn", 2, B2, 4, false, 31);
+ block("Scotland", "moray", "Moray", 2, B2, 3, true, 32);
+ block("Scotland", "nobles", "Angus", 2, B2, 3, false, 33);
+ block("Scotland", "nobles", "Argyll", 2, B2, 3, false, 34);
+ block("Scotland", "nobles", "Bruce", 2, B2, 4, false, 35);
+ block("Scotland", "nobles", "Mar", 2, B2, 3, false, 36);
+ block("Scotland", "nobles", "Lennox", 2, B2, 3, false, 37);
+
+ block("Scotland", "nobles", "Buchan", 2, B2, 3, false, 41);
+ block("Scotland", "nobles", "Galloway", 2, B2, 3, false, 42);
+ block("Scotland", "nobles", "Ross", 2, B2, 3, false, 43);
+ block("Scotland", "nobles", "Atholl", 2, B2, 3, false, 44);
+ block("Scotland", "nobles", "Dunbar", 2, B2, 3, false, 45);
+ block("Scotland", "nobles", "Mentieth", 2, B2, 3, false, 46);
+ block("Scotland", "nobles", "Steward", 2, B2, 3, false, 47);
+
+ block("England", "king", "Edward", 3, B4, 4, true, 61);
+ block("England", "archers", "Lancaster Archers", 2, B3, 3, false, 62);
+ block("England", "archers", "Wales Archers", 2, B3, 3, false, 63);
+ block("England", "knights", "Lancaster Knights", 2, B3, 4, false, 64);
+ block("England", "knights", "York Knights", 2, B3, 4, false, 65);
+ block("England", "knights", "Durham Knights", 2, B3, 3, false, 66);
+ block("England", "hobelars", "Hobelars", 3, A2, 3, true, 67);
+
+ block("England", "infantry", "York Infantry", 2, C2, 4, false, 71);
+ block("England", "infantry", "Lancaster Infantry", 2, C2, 4, false, 72);
+ block("England", "infantry", "Northumber Infantry", 2, C2, 4, false, 73);
+ block("England", "infantry", "Durham Infantry", 2, C2, 3, false, 74);
+ block("England", "infantry", "Cumbria Infantry", 2, C2, 3, false, 75);
+ block("England", "infantry", "Westmor Infantry", 2, C2, 3, false, 82);
+ block("England", "infantry", "Wales Infantry", 2, C3, 3, false, 76);
+ block("England", "infantry", "Ulster Infantry", 2, C3, 3, false, 77);
+
+ block("England", "nobles", "Comyn", 2, B2, 4, false, 81);
+ block("England", "nobles", "Angus", 2, B2, 3, false, 83);
+ block("England", "nobles", "Argyll", 2, B2, 3, false, 84);
+ block("England", "nobles", "Bruce", 2, B2, 4, false, 85);
+ block("England", "nobles", "Mar", 2, B2, 3, false, 86);
+ block("England", "nobles", "Lennox", 2, B2, 3, false, 87);
+
+ block("England", "nobles", "Buchan", 2, B2, 3, false, 91);
+ block("England", "nobles", "Galloway", 2, B2, 3, false, 92);
+ block("England", "nobles", "Ross", 2, B2, 3, false, 93);
+ block("England", "nobles", "Atholl", 2, B2, 3, false, 94);
+ block("England", "nobles", "Dunbar", 2, B2, 3, false, 95);
+ block("England", "nobles", "Mentieth", 2, B2, 3, false, 96);
+ block("England", "nobles", "Steward", 2, B2, 3, false, 97);
+})();
+
+if (typeof module != 'undefined')
+ module.exports = { CARDS, BLOCKS, AREAS, BORDERS }
diff --git a/info/blocks.html b/info/blocks.html
new file mode 100644
index 0000000..531a535
--- /dev/null
+++ b/info/blocks.html
@@ -0,0 +1,181 @@
+<html>
+<title>Hammer of the Scots - Blocks</title>
+<link rel="stylesheet" href="../blocks.css">
+<style>
+body {
+ margin: 40px;
+ background-color: slategray;
+ color: white;
+ text-align: center;
+}
+div.list {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+div.block {
+ width: 60px;
+ height: 60px;
+ margin: 5px;
+ background-size: 700% 400%;
+ box-shadow: 1px 1px 4px rgba(0,0,0,0.5);
+}
+div.block:hover {
+ transform: scale(2);
+}
+.oldblocks div.block {
+ border-radius: 6px;
+}
+.oldblocks div.block.england { border: 3px solid brown; background-color: brown; }
+.oldblocks div.block.scotland { border: 3px solid #06a; background-color: #06a; }
+.newblocks div.block.england { border: 3px solid #a12; background-color: #a12; }
+.newblocks div.block.scotland { border: 3px solid #059; background-color: #059; }
+
+.oldblocks .known.scotland{background-image:url(../old_blocks_scotland.png)}
+.oldblocks .known.england{background-image:url(../old_blocks_england.png)}
+.newblocks .known.scotland{background-image:url(../new_blocks_scotland.png)}
+.newblocks .known.england{background-image:url(../new_blocks_england.png)}
+
+.known.block_11{background-position:0px 0px}
+.known.block_12{background-position:-60px 0px}
+.known.block_13{background-position:-120px 0px}
+.known.block_14{background-position:-180px 0px}
+.known.block_15{background-position:-240px 0px}
+.known.block_16{background-position:-300px 0px}
+.known.block_17{background-position:-360px 0px}
+.known.block_21{background-position:0px -60px}
+.known.block_22{background-position:-60px -60px}
+.known.block_23{background-position:-120px -60px}
+.known.block_24{background-position:-180px -60px}
+.known.block_25{background-position:-240px -60px}
+.known.block_26{background-position:-300px -60px}
+.known.block_27{background-position:-360px -60px}
+.known.block_31{background-position:0px -120px}
+.known.block_32{background-position:-60px -120px}
+.known.block_33{background-position:-120px -120px}
+.known.block_34{background-position:-180px -120px}
+.known.block_35{background-position:-240px -120px}
+.known.block_36{background-position:-300px -120px}
+.known.block_37{background-position:-360px -120px}
+.known.block_41{background-position:0px -180px}
+.known.block_42{background-position:-60px -180px}
+.known.block_43{background-position:-120px -180px}
+.known.block_44{background-position:-180px -180px}
+.known.block_45{background-position:-240px -180px}
+.known.block_46{background-position:-300px -180px}
+.known.block_47{background-position:-360px -180px}
+.known.block_61{background-position:0px 0px}
+.known.block_62{background-position:-60px 0px}
+.known.block_63{background-position:-120px 0px}
+.known.block_64{background-position:-180px 0px}
+.known.block_65{background-position:-240px 0px}
+.known.block_66{background-position:-300px 0px}
+.known.block_67{background-position:-360px 0px}
+.known.block_71{background-position:0px -60px}
+.known.block_72{background-position:-60px -60px}
+.known.block_73{background-position:-120px -60px}
+.known.block_74{background-position:-180px -60px}
+.known.block_75{background-position:-240px -60px}
+.known.block_76{background-position:-300px -60px}
+.known.block_77{background-position:-360px -60px}
+.known.block_81{background-position:0px -120px}
+.known.block_82{background-position:-60px -120px}
+.known.block_83{background-position:-120px -120px}
+.known.block_84{background-position:-180px -120px}
+.known.block_85{background-position:-240px -120px}
+.known.block_86{background-position:-300px -120px}
+.known.block_87{background-position:-360px -120px}
+.known.block_91{background-position:0px -180px}
+.known.block_92{background-position:-60px -180px}
+.known.block_93{background-position:-120px -180px}
+.known.block_94{background-position:-180px -180px}
+.known.block_95{background-position:-240px -180px}
+.known.block_96{background-position:-300px -180px}
+.known.block_97{background-position:-360px -180px}
+
+
+</style>
+<body id="body" class="oldblocks">
+<h1>
+Hammer of the Scots - Blocks
+</h1>
+
+<button onclick="window.body.className='oldblocks'">1st edition</button>
+<button onclick="window.body.className='newblocks'">3rd edition</button>
+
+<h2>Scottish</h2>
+<div class="list">
+<div class="scotland known block block_11"></div>
+<div class="scotland known block block_12"></div>
+<div class="scotland known block block_13"></div>
+<div class="scotland known block block_14"></div>
+<div class="scotland known block block_15"></div>
+<div class="scotland known block block_16"></div>
+<div class="scotland known block block_17"></div>
+</div>
+<div class="list">
+<div class="scotland known block block_21"></div>
+<div class="scotland known block block_22"></div>
+<div class="scotland known block block_23"></div>
+<div class="scotland known block block_24"></div>
+<div class="scotland known block block_25"></div>
+<div class="scotland known block block_26"></div>
+<div class="scotland known block block_27"></div>
+</div>
+<div class="list">
+<div class="scotland known block block_31"></div>
+<div class="scotland known block block_32"></div>
+<div class="scotland known block block_33"></div>
+<div class="scotland known block block_34"></div>
+<div class="scotland known block block_35"></div>
+<div class="scotland known block block_36"></div>
+<div class="scotland known block block_37"></div>
+</div>
+<div class="list">
+<div class="scotland known block block_41"></div>
+<div class="scotland known block block_42"></div>
+<div class="scotland known block block_43"></div>
+<div class="scotland known block block_44"></div>
+<div class="scotland known block block_45"></div>
+<div class="scotland known block block_46"></div>
+<div class="scotland known block block_47"></div>
+</div>
+
+<h2>English</h2>
+<div class="list">
+<div class="england known block block_61"></div>
+<div class="england known block block_62"></div>
+<div class="england known block block_63"></div>
+<div class="england known block block_64"></div>
+<div class="england known block block_65"></div>
+<div class="england known block block_66"></div>
+<div class="england known block block_67"></div>
+</div>
+<div class="list">
+<div class="england known block block_71"></div>
+<div class="england known block block_72"></div>
+<div class="england known block block_73"></div>
+<div class="england known block block_74"></div>
+<div class="england known block block_75"></div>
+<div class="england known block block_76"></div>
+<div class="england known block block_77"></div>
+</div>
+<div class="list">
+<div class="england known block block_81"></div>
+<div class="england known block block_82"></div>
+<div class="england known block block_83"></div>
+<div class="england known block block_84"></div>
+<div class="england known block block_85"></div>
+<div class="england known block block_86"></div>
+<div class="england known block block_87"></div>
+</div>
+<div class="list">
+<div class="england known block block_91"></div>
+<div class="england known block block_92"></div>
+<div class="england known block block_93"></div>
+<div class="england known block block_94"></div>
+<div class="england known block block_95"></div>
+<div class="england known block block_96"></div>
+<div class="england known block block_97"></div>
+</div>
+
diff --git a/info/cards.html b/info/cards.html
new file mode 100644
index 0000000..92d2e2f
--- /dev/null
+++ b/info/cards.html
@@ -0,0 +1,42 @@
+<html>
+<title>Hammer of the Scots - Cards</title>
+<style>
+body { background-color: slategray; margin: 40px; text-align: center; color: white; }
+img {
+ margin: 20px;
+ box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
+ width: 224px;
+ height: 344px;
+ border-radius: 12px;
+}
+</style>
+<body>
+<h1>Hammer of the Scots - Cards</h1>
+<img src="../cards/card_herald.jpg">
+<img src="../cards/card_pillage.jpg">
+<img src="../cards/card_sea_move.jpg">
+<img src="../cards/card_truce.jpg">
+<img src="../cards/card_victuals.jpg">
+
+<img src="../cards/card_3.jpg">
+<img src="../cards/card_3.jpg">
+<img src="../cards/card_3.jpg">
+
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+<img src="../cards/card_2.jpg">
+
+<img src="../cards/card_1.jpg">
+<img src="../cards/card_1.jpg">
+<img src="../cards/card_1.jpg">
+<img src="../cards/card_1.jpg">
+<img src="../cards/card_1.jpg">
+<img src="../cards/card_1.jpg">
+<img src="../cards/card_1.jpg">
diff --git a/info/notes.html b/info/notes.html
new file mode 100644
index 0000000..8d7d9df
--- /dev/null
+++ b/info/notes.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<head>
+<title>Hammer of the Scots - Notes</title>
+<link rel="stylesheet" href="/fonts/fonts.css">
+<link rel="stylesheet" href="/style.css">
+<style>h1{text-align:center}body{max-width:50rem;margin:0 auto;}</style>
+</head>
+<body>
+<div class="main">
+
+<h1>
+Hammer of the Scots: Implementation Notes</h1>
+
+<hr>
+
+<p>
+How do I designate the attacking main force?
+<p>
+The first block that moves into a contested area defines the main force.
+Any other blocks who start from the same location and enter the battle across the same border also count as being part of the main force.
+The attacking main force move is marked with an asterisk in the game log.
+
+<hr>
+
+<p style="font-style:normal;font-size:36px;text-align:center;margin:0">&#x2766;</p>
diff --git a/info/rules.html b/info/rules.html
new file mode 100644
index 0000000..1cddc4b
--- /dev/null
+++ b/info/rules.html
@@ -0,0 +1,18 @@
+<html>
+<title>Hammer of the Scots - Rules</title>
+<style>
+body { background-color: slategray; }
+img { display: block; margin: 40px auto; box-shadow: 2px 2px 20px rgba(0,0,0,0.5); }
+</style>
+<body>
+<img src="rules1.jpg">
+<img src="rules2.jpg">
+<img src="rules3.jpg">
+<img src="rules4.jpg">
+<img src="rules5.jpg">
+<img src="rules6.jpg">
+<a name="braveheart"></a>
+<a name="the_bruce"></a>
+<img src="rules7.jpg">
+<a name="campaign"></a>
+<img src="rules8.jpg">
diff --git a/info/rules1.jpg b/info/rules1.jpg
new file mode 100644
index 0000000..3a0a762
--- /dev/null
+++ b/info/rules1.jpg
Binary files differ
diff --git a/info/rules2.jpg b/info/rules2.jpg
new file mode 100644
index 0000000..2b7769e
--- /dev/null
+++ b/info/rules2.jpg
Binary files differ
diff --git a/info/rules3.jpg b/info/rules3.jpg
new file mode 100644
index 0000000..029a0e1
--- /dev/null
+++ b/info/rules3.jpg
Binary files differ
diff --git a/info/rules4.jpg b/info/rules4.jpg
new file mode 100644
index 0000000..9de1b64
--- /dev/null
+++ b/info/rules4.jpg
Binary files differ
diff --git a/info/rules5.jpg b/info/rules5.jpg
new file mode 100644
index 0000000..0dd2717
--- /dev/null
+++ b/info/rules5.jpg
Binary files differ
diff --git a/info/rules6.jpg b/info/rules6.jpg
new file mode 100644
index 0000000..28b0453
--- /dev/null
+++ b/info/rules6.jpg
Binary files differ
diff --git a/info/rules7.jpg b/info/rules7.jpg
new file mode 100644
index 0000000..fe1b21c
--- /dev/null
+++ b/info/rules7.jpg
Binary files differ
diff --git a/info/rules8.jpg b/info/rules8.jpg
new file mode 100644
index 0000000..59c66ff
--- /dev/null
+++ b/info/rules8.jpg
Binary files differ
diff --git a/map150.png b/map150.png
new file mode 100644
index 0000000..4779910
--- /dev/null
+++ b/map150.png
Binary files differ
diff --git a/map75.png b/map75.png
new file mode 100644
index 0000000..359e5b7
--- /dev/null
+++ b/map75.png
Binary files differ
diff --git a/new_blocks_england.png b/new_blocks_england.png
new file mode 100644
index 0000000..44455d5
--- /dev/null
+++ b/new_blocks_england.png
Binary files differ
diff --git a/new_blocks_scotland.png b/new_blocks_scotland.png
new file mode 100644
index 0000000..492080c
--- /dev/null
+++ b/new_blocks_scotland.png
Binary files differ
diff --git a/old_blocks_england.png b/old_blocks_england.png
new file mode 100644
index 0000000..1f13483
--- /dev/null
+++ b/old_blocks_england.png
Binary files differ
diff --git a/old_blocks_scotland.png b/old_blocks_scotland.png
new file mode 100644
index 0000000..da77448
--- /dev/null
+++ b/old_blocks_scotland.png
Binary files differ
diff --git a/play.html b/play.html
new file mode 100644
index 0000000..d397148
--- /dev/null
+++ b/play.html
@@ -0,0 +1,888 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
+<meta charset="UTF-8">
+<title>HAMMER OF THE SCOTS</title>
+<link rel="icon" href="Scottish_Thistle_(Heraldry).svg">
+<link rel="stylesheet" href="/fonts/fonts.css">
+<link rel="stylesheet" href="/common/grid.css">
+<link rel="stylesheet" href="/common/battle_abc.css">
+<link rel="stylesheet" href="blocks.css">
+<script defer src="/socket.io/socket.io.min.js"></script>
+<script defer src="/common/client.js"></script>
+<script defer src="data.js"></script>
+<script defer src="ui.js"></script>
+<style>
+
+.grid_center { background-color: slategray; }
+.grid_role { background-color: silver; }
+.grid_top { background-color: silver; }
+.grid_top.your_turn { background-color: orange; }
+.one .role_name { background-color: salmon; }
+.two .role_name { background-color: skyblue; }
+
+.card {
+ width: 225px;
+ height: 350px;
+ border-radius: 10px;
+ background-color: #883737;
+}
+
+.small_card {
+ width: 90px;
+ height: 140px;
+ border-radius: 4px;
+}
+
+.role_info {
+ display: flex;
+ justify-content: center;
+}
+
+/* MAP */
+
+.map {
+ position: relative;
+ display: block;
+ background-color: darkslategray;
+ width: 1688px;
+ height: 1950px;
+}
+
+.map svg {
+ position: absolute;
+}
+
+.map svg image {
+ pointer-events: none;
+}
+
+.map svg path.area {
+ opacity: 0;
+ fill-opacity: 0.4;
+ fill: white;
+}
+.map svg path.area.where {
+ opacity: 1;
+ fill: darkslategray;
+}
+.map svg path.area.highlight {
+ cursor: pointer;
+ opacity: 1;
+ fill: white;
+}
+
+.map.hide_blocks div.blocks {
+ visibility: hidden;
+}
+
+/* TURN MARKER */
+
+div.turn {
+ pointer-events: none;
+ position: absolute;
+ width: 66px;
+ height: 66px;
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-image: url(turn_marker.jpg);
+ box-shadow: 1px 1px 3px rgba(0,0,0,0.5);
+ border-radius: 4px;
+ transition: 700ms ease;
+}
+
+
+div.turn.year_1297 { left: 1511px; top: 221px; }
+div.turn.year_1298 { left: 1511px; top: 306px; }
+div.turn.year_1299 { left: 1511px; top: 392px; }
+div.turn.year_1300 { left: 1511px; top: 478px; }
+div.turn.year_1301 { left: 1511px; top: 563px; }
+div.turn.year_1302 { left: 1511px; top: 649px; }
+div.turn.year_1303 { left: 1511px; top: 734px; }
+div.turn.year_1304 { left: 1511px; top: 820px; }
+div.turn.year_1305 { left: 1511px; top: 906px; }
+div.turn.year_1306 { left: 1511px; top: 992px; }
+div.turn.year_1307 { left: 1511px; top: 1077px; }
+div.turn.year_1308 { left: 1511px; top: 1163px; }
+div.turn.year_1309 { left: 1511px; top: 1249px; }
+div.turn.year_1310 { left: 1511px; top: 1334px; }
+div.turn.year_1311 { left: 1511px; top: 1420px; }
+div.turn.year_1312 { left: 1511px; top: 1506px; }
+div.turn.year_1313 { left: 1511px; top: 1591px; }
+div.turn.year_1314 { left: 1511px; top: 1677px; }
+
+/* BLOCKS */
+
+.oldblocks div.block { border-radius: 8px; }
+.newblocks div.block { border-radius: 4px; }
+
+.map div.block {
+ position: absolute;
+}
+
+div.block {
+ background-size: cover;
+ background-repeat: no-repeat;
+ width: 60px;
+ height: 60px;
+ box-shadow: 0px 0px 3px black;
+}
+
+.oldblocks div.block.England { border: 3px solid brown; background-color: brown; }
+.oldblocks div.block.Scotland { border: 3px solid #06a; background-color: #06a; }
+.oldblocks div.block.highlight { border-color: white; }
+.oldblocks div.block.selected { border-color: yellow; }
+.oldblocks div.block.highlight { box-shadow: 0px 0px 4px 1px white; }
+.oldblocks div.block.selected { box-shadow: 0 0 4px 1px yellow; }
+
+.newblocks div.block.England { border: 2px solid #a12; background-color: #a12; }
+.newblocks div.block.Scotland { border: 2px solid #059; background-color: #059; }
+.newblocks div.block.highlight { box-shadow: 0px 0px 2px 3px white; }
+.newblocks div.block.selected { box-shadow: 0px 0px 2px 3px yellow; }
+
+div.block.highlight { cursor: pointer; }
+div.block.moved { filter: grayscale(50%) brightness(80%); }
+div.block.highlight.moved { filter: grayscale(60%) brightness(95%); }
+
+div.block.r1 { transform: rotate(-90deg); }
+div.block.r2 { transform: rotate(-180deg); }
+div.block.r3 { transform: rotate(-270deg); }
+
+div.block:hover { z-index: 1; }
+
+div.block {
+ transition-property: top, left, transform;
+ transition-duration: 700ms, 700ms, 200ms;
+ transition-timing-function: ease;
+}
+
+/* HERALD DIALOG */
+
+.herald {
+ background-color: white;
+ border: 1px solid black;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.5);
+ z-index: 50;
+ user-select: none;
+ visibility: hidden;
+}
+.herald.show {
+ visibility: visible;
+}
+.herald_header {
+ font-weight: bold;
+ cursor: move;
+ border-bottom: 1px solid black;
+ background-color: lightsteelblue;
+ padding: 3px 1em;
+}
+.herald_noble {
+ padding: 3px 1em;
+ display: none;
+}
+.herald_noble:hover {
+ color: white;
+ background-color: black;
+}
+.herald_noble.show {
+ display: block;
+}
+
+/* BATTLE BOARD */
+
+.battle { background-color: silver; }
+.battle .battle_message { background-color: lightsteelblue; }
+.battle .battle_header { background-color: steelblue; color: white; font-weight: bold; }
+.battle .battle_separator { background-color: steelblue; }
+
+.battle_line.enemy .battle_menu_list { min-height: 0; }
+.battle_reserves > td > div { height: 66px; }
+.battle_a_cell > div { min-width: 240px; }
+.battle_b_cell > div { min-width: 240px; }
+.battle_c_cell > div { min-width: 240px; }
+
+/* CARD AND MARKER IMAGES */
+
+div.card_back {
+ background-image: url('cards/card_back.svg');
+ background-color: gainsboro;
+ background-size: contain;
+ background-position: 0% 40%;
+ background-repeat: no-repeat;
+}
+
+div.card_truce{background-image:url('cards/card_truce.jpg')}
+div.card_herald{background-image:url('cards/card_herald.jpg')}
+div.card_sea_move{background-image:url('cards/card_sea_move.jpg')}
+div.card_pillage{background-image:url('cards/card_pillage.jpg')}
+div.card_victuals{background-image:url('cards/card_victuals.jpg')}
+div.card_1{background-image:url('cards/card_1.jpg')}
+div.card_2{background-image:url('cards/card_2.jpg')}
+div.card_3{background-image:url('cards/card_3.jpg')}
+
+</style>
+</head>
+<body class="oldlabels">
+
+<div class="status" id="status"></div>
+
+<div class="chat_window">
+<div class="chat_header">Chat</div>
+<div class="chat_text"></div>
+<form class="chat_form" action=""><input id="chat_input" autocomplete="off"></form>
+</div>
+
+<table class="battle">
+<tr>
+<th class="battle_header" colspan=4></th>
+<tr class="battle_reserves enemy">
+<td colspan=4><div id="ER"></div></td>
+<tr class="battle_line enemy">
+<td class="battle_a_cell"><div id="EA"></div></td>
+<td class="battle_b_cell"><div id="EB"></div></td>
+<td class="battle_c_cell"><div id="EC"></div></td>
+<tr class="battle_separator">
+<td colspan=4>
+<tr class="battle_line friendly">
+<td class="battle_a_cell"><div id="FA"></div></td>
+<td class="battle_b_cell"><div id="FB"></div></td>
+<td class="battle_c_cell"><div id="FC"></div></td>
+<tr class="battle_reserves friendly">
+<td colspan=4><div id="FR"></div></td>
+<tr>
+<th class="battle_message" colspan=4></th>
+</table>
+
+<div class="herald">
+<div class="herald_header">Name an enemy noble:</div>
+<div id="herald+Angus" class="herald_noble" onclick="on_herald('Angus')">Angus</div>
+<div id="herald+Argyll" class="herald_noble" onclick="on_herald('Argyll')">Argyll</div>
+<div id="herald+Atholl" class="herald_noble" onclick="on_herald('Atholl')">Atholl</div>
+<div id="herald+Bruce" class="herald_noble" onclick="on_herald('Bruce')">Bruce</div>
+<div id="herald+Buchan" class="herald_noble" onclick="on_herald('Buchan')">Buchan</div>
+<div id="herald+Comyn" class="herald_noble" onclick="on_herald('Comyn')">Comyn</div>
+<div id="herald+Dunbar" class="herald_noble" onclick="on_herald('Dunbar')">Dunbar</div>
+<div id="herald+Galloway" class="herald_noble" onclick="on_herald('Galloway')">Galloway</div>
+<div id="herald+Lennox" class="herald_noble" onclick="on_herald('Lennox')">Lennox</div>
+<div id="herald+Mar" class="herald_noble" onclick="on_herald('Mar')">Mar</div>
+<div id="herald+Mentieth" class="herald_noble" onclick="on_herald('Mentieth')">Mentieth</div>
+<div id="herald+Ross" class="herald_noble" onclick="on_herald('Ross')">Ross</div>
+<div id="herald+Steward" class="herald_noble" onclick="on_herald('Steward')">Steward</div>
+</div>
+
+<div class="grid_window">
+
+ <div class="grid_top">
+ <div class="menu">
+ <div class="menu_title"><img src="/images/cog.svg"></div>
+ <div class="menu_popup">
+ <div class="menu_item" onclick="toggle_fullscreen()">Fullscreen</div>
+ <div class="menu_separator"></div>
+ <div class="menu_item" onclick="old_block_style()">Old labels</div>
+ <div class="menu_item" onclick="new_block_style()">New labels</div>
+ <div class="menu_separator"></div>
+ <div class="menu_item" onclick="window.open('info/notes.html', '_blank')">Notes</div>
+ <div class="menu_item" onclick="window.open('info/rules.html', '_blank')">Rules</div>
+ <div class="menu_item" onclick="window.open('info/cards.html', '_blank')">Cards</div>
+ <div class="menu_item" onclick="window.open('info/blocks.html', '_blank')">Blocks</div>
+ <div class="menu_separator"></div>
+ <div class="menu_item" onclick="confirm_resign()">Resign</div>
+ <div class="menu_separator"></div>
+ <div class="menu_item" onclick="send_save()">&#x1F41E; Save</div>
+ <div class="menu_item" onclick="send_restore()">&#x1F41E; Restore</div>
+ <div class="menu_separator"></div>
+ <div class="menu_item" onclick="send_restart('Braveheart')">Braveheart</div>
+ <div class="menu_item" onclick="send_restart('The Bruce')">The Bruce</div>
+ <div class="menu_item" onclick="send_restart('Campaign')">Campaign</div>
+ </div>
+ </div>
+
+ <div class="image_button" onclick="toggle_blocks()"><img src="/images/earth-africa-europe.svg"></div>
+ <div class="image_button" onclick="toggle_log()"><img src="/images/scroll-quill.svg"></div>
+ <div class="image_button chat_button" onclick="toggle_chat()"><img src="/images/chat-bubble.svg"></div>
+
+ <div id="prompt" class="prompt">Connecting...</div>
+
+ <button id="end_pillage_button" onclick="on_button_end_pillage()" class="hide">
+ End pillage
+ </button>
+ <button id="end_builds_button" onclick="on_button_end_builds()" class="hide">
+ End builds
+ </button>
+ <button id="end_disbanding_button" onclick="on_button_end_disbanding()" class="hide">
+ End disbanding
+ </button>
+ <button id="disband_button" onclick="on_button_disband()" class="hide">
+ Disband
+ </button>
+ <button id="eliminate_button" onclick="on_button_eliminate()" class="hide">
+ Eliminate
+ </button>
+ <button id="end_retreat_button" onclick="on_button_end_retreat()" class="hide">
+ End retreat
+ </button>
+ <button id="end_regroup_button" onclick="on_button_end_regroup()" class="hide">
+ End regroup
+ </button>
+ <button id="end_move_phase_button" onclick="on_button_end_move_phase()" class="hide">
+ End move phase
+ </button>
+ <button id="crown_bruce_button" onclick="on_crown_bruce()" class="hide">
+ Coronation: Bruce
+ </button>
+ <button id="crown_comyn_button" onclick="on_crown_comyn()" class="hide">
+ Coronation: Comyn
+ </button>
+ <button id="return_of_the_king_button" onclick="on_return_of_the_king()" class="hide">
+ Return of the King
+ </button>
+ <button id="play_event_button" onclick="on_button_play_event()" class="hide">
+ Play event
+ </button>
+ <button id="pass_button" onclick="on_button_pass()" class="hide">
+ Pass
+ </button>
+ <button id="undo_button" onclick="on_button_undo()" class="hide">
+ Undo
+ </button>
+ </div>
+
+ <div class="grid_role">
+
+ <div class="role one">
+ <div class="role_vp" id="england_vp"></div>
+ <div class="role_name">England (<span class="role_user">$USER</span>)</div>
+ <div class="role_info">
+ <div class="small_card card_back" id="england_card"></div>
+ </div>
+ </div>
+
+ <div class="role two">
+ <div class="role_vp" id="scotland_vp"></div>
+ <div class="role_name">Scotland (<span class="role_user">$USER</span>)</div>
+ <div class="role_info">
+ <div class="small_card card_back" id="scotland_card"></div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="grid_log">
+ <div class="log" id="log"></div>
+ </div>
+
+ <div class="grid_center">
+
+<div id="map" class="map">
+
+<svg id="svgmap" width="1688px" height="1950px" viewBox="0 0 1688 1950">
+<g id="areas" transform="translate(0,1950) scale(0.1,-0.1)">
+<path id="area+Ross" class="area" d="M4865 17971 c-23 -5 -37 -19 -64 -68 -43 -77 -74 -94 -130 -69 -26
+12 -49 15 -73 11 -33 -6 -38 -4 -64 31 -47 61 -85 94 -109 94 -55 0 -65 -74
+-17 -123 24 -25 32 -42 32 -70 0 -41 23 -62 81 -73 54 -11 67 -21 94 -75 23
+-45 55 -92 114 -170 11 -14 39 -31 63 -38 24 -7 60 -28 80 -47 20 -18 55 -38
+77 -44 80 -21 104 -93 50 -154 -37 -43 -35 -47 60 -139 38 -38 73 -77 76 -87
+3 -10 22 -29 43 -42 39 -27 90 -116 112 -196 9 -37 9 -48 -5 -68 -33 -51 -61
+-24 -119 117 -41 99 -44 103 -82 116 -26 9 -74 44 -131 98 -50 47 -102 89
+-116 94 -25 10 -139 -7 -165 -23 -7 -4 -4 -22 6 -47 13 -34 25 -46 67 -65 27
+-13 55 -24 61 -24 18 0 51 -43 69 -88 14 -34 15 -45 5 -57 -17 -21 -44 -19
+-119 10 -116 45 -151 66 -176 110 -27 46 -62 80 -120 119 -53 35 -83 34 -91
+-1 -4 -16 -23 -65 -42 -111 -26 -61 -41 -84 -58 -88 -21 -5 -154 43 -202 74
+-31 20 -51 61 -63 130 -15 85 -17 89 -53 112 -54 33 -81 27 -111 -23 -54 -94
+-43 -183 30 -235 24 -17 56 -49 71 -72 26 -40 27 -43 16 -104 -7 -35 -12 -80
+-12 -100 0 -26 -7 -44 -25 -62 -15 -15 -25 -36 -25 -53 0 -33 -27 -61 -60 -61
+-29 0 -86 61 -125 131 -23 43 -27 59 -22 99 5 37 1 58 -20 101 -14 30 -28 77
+-32 104 l-6 50 -75 -1 c-45 0 -94 -8 -122 -18 -42 -16 -48 -23 -54 -54 -4 -19
+-3 -74 1 -121 10 -104 10 -143 1 -241 l-7 -75 48 -34 c44 -32 122 -61 164 -61
+32 0 68 -40 84 -95 18 -64 12 -100 -21 -122 -22 -14 -28 -13 -94 18 -71 32
+-72 32 -104 15 -25 -13 -41 -37 -75 -111 -24 -52 -41 -101 -38 -109 3 -8 24
+-26 45 -40 72 -45 142 -148 142 -207 0 -26 10 -41 50 -78 37 -34 50 -53 50
+-74 0 -15 9 -36 19 -46 17 -17 29 -18 106 -13 127 7 252 -14 288 -49 62 -62 6
+-139 -85 -116 -42 10 -164 1 -173 -14 -4 -5 -16 -9 -27 -9 -12 0 -32 -10 -44
+-21 -34 -32 -63 -19 -143 61 -38 39 -77 70 -86 70 -10 0 -47 32 -84 71 -65 70
+-113 105 -131 94 -17 -11 -59 -115 -73 -187 -9 -40 -20 -85 -26 -101 -20 -52
+-32 -158 -22 -191 5 -17 12 -48 16 -68 5 -31 11 -39 33 -44 77 -16 94 -43 67
+-106 -12 -31 -13 -45 -3 -82 10 -39 10 -51 -5 -81 -23 -49 -22 -62 14 -104 16
+-20 39 -46 49 -58 36 -44 101 -27 195 51 52 43 132 95 198 129 35 18 39 18 63
+3 40 -27 51 -61 31 -96 -9 -15 -17 -35 -17 -42 0 -27 35 -48 79 -48 37 0 49 6
+94 49 29 27 72 78 97 112 66 92 104 129 132 129 14 0 35 12 49 26 34 36 72 54
+116 54 59 0 101 16 142 53 49 45 137 78 231 87 119 13 185 27 229 49 22 12 50
+21 61 21 44 0 164 -61 215 -109 28 -26 59 -52 70 -58 26 -13 145 -31 280 -42
+69 -6 142 -19 195 -36 118 -37 212 -45 345 -29 141 17 302 72 439 152 55 33
+122 68 147 79 25 11 70 37 100 58 30 20 77 47 104 60 28 12 64 34 81 48 17 14
+56 35 86 47 31 11 75 35 99 53 83 61 323 178 448 219 85 27 100 35 142 82 26
+28 82 87 123 132 53 56 78 90 82 115 10 50 20 65 59 89 39 24 135 162 156 225
+8 24 43 71 85 115 95 101 185 232 170 247 -2 3 -20 0 -38 -5 -62 -20 -116 -24
+-140 -11 -13 7 -43 29 -67 51 -61 53 -85 51 -181 -17 -93 -65 -119 -69 -181
+-22 -24 17 -64 43 -88 57 -99 56 -104 113 -16 162 77 43 92 48 146 48 66 0 85
+12 94 57 4 20 14 51 22 67 12 22 14 46 9 97 -6 57 -3 81 19 152 33 111 57 132
+200 178 47 15 91 38 133 72 56 44 64 55 79 109 22 80 115 181 183 198 25 7 71
+31 104 54 79 55 223 193 212 203 -9 9 -4027 14 -4071 4z"/>
+<path id="area+Strathspey" class="area" d="M9580 15955 c-201 -58 -206 -61 -225 -111 -23 -61 -61 -103 -114
+-127 -39 -17 -57 -18 -166 -12 -67 4 -148 4 -181 0 -49 -7 -63 -13 -89 -42
+-16 -20 -54 -50 -82 -69 -29 -19 -53 -40 -53 -48 0 -29 22 -72 55 -106 34 -36
+53 -82 75 -182 12 -55 12 -59 -16 -115 -17 -35 -29 -77 -30 -105 -1 -25 -8
+-57 -15 -70 -15 -28 -80 -106 -132 -160 -44 -44 -117 -199 -117 -247 0 -35
+-20 -80 -45 -101 -9 -7 -44 -23 -78 -34 -66 -23 -107 -66 -107 -111 0 -30 76
+-124 106 -131 13 -3 46 -1 73 6 37 9 72 9 135 1 85 -10 86 -10 153 21 38 17
+93 51 123 74 63 48 146 92 181 95 13 1 52 1 86 1 57 -2 66 -5 108 -42 25 -22
+51 -40 57 -40 6 0 35 -25 64 -56 l54 -56 83 8 c45 5 118 8 162 6 371 -13 416
+-6 527 77 35 26 91 62 124 80 34 18 85 56 113 84 174 175 222 227 246 267 16
+25 49 70 75 101 25 30 52 71 60 90 8 19 23 50 35 69 12 19 37 73 55 119 19 46
+44 96 56 111 13 15 56 41 97 58 63 26 82 30 128 25 48 -5 59 -2 83 19 19 16
+31 39 37 72 5 26 25 74 44 106 36 59 72 169 82 247 5 40 3 44 -24 54 -15 6
+-53 11 -83 11 -30 0 -82 9 -115 20 -34 12 -83 20 -113 20 -36 -1 -67 5 -93 18
+-63 33 -125 22 -210 -37 -85 -58 -219 -113 -275 -113 -71 0 -185 32 -326 90
+-132 54 -160 69 -265 142 -61 42 -75 47 -138 51 -59 5 -87 1 -185 -28z"/>
+<path id="area+Buchan" class="area" d="M12891 15833 c-13 -3 -52 -27 -86 -53 -85 -68 -98 -71 -170 -49 -33
+10 -74 19 -91 19 -17 0 -52 11 -78 25 -26 14 -52 25 -58 25 -6 0 -32 -20 -58
+-44 -55 -52 -30 -48 -370 -49 -217 0 -238 1 -275 20 -35 18 -119 30 -177 25
+-16 -2 -54 -107 -73 -202 -4 -19 -24 -69 -45 -110 -21 -41 -43 -94 -50 -117
+-24 -93 -103 -145 -205 -137 -50 5 -68 2 -105 -18 -42 -21 -48 -30 -91 -128
+-90 -205 -173 -329 -330 -495 -47 -49 -93 -102 -102 -117 -19 -30 -109 -101
+-182 -143 -27 -15 -75 -47 -105 -71 -111 -85 -164 -100 -387 -110 -143 -6
+-153 -8 -153 -26 0 -13 14 -25 48 -40 26 -11 61 -32 77 -45 48 -38 179 -123
+191 -123 6 0 20 -11 33 -24 17 -18 24 -44 33 -115 12 -99 20 -107 67 -75 24
+17 192 74 218 74 15 0 92 -30 243 -95 47 -20 101 -41 120 -47 19 -6 64 -25
+100 -44 36 -18 88 -39 115 -45 28 -6 79 -22 115 -34 122 -43 212 -59 287 -50
+37 4 118 8 180 10 62 2 116 6 121 9 5 3 34 -1 63 -8 88 -22 166 -30 316 -30
+126 -1 144 -3 166 -21 14 -11 52 -42 85 -69 64 -50 114 -116 176 -228 54 -99
+102 -117 217 -81 50 15 93 17 248 10 37 -2 47 2 63 24 11 14 22 44 25 66 5 35
+1 47 -23 78 -81 106 -11 396 197 818 27 55 119 169 256 316 34 37 64 79 68 96
+13 58 26 80 61 103 22 15 43 41 56 70 12 26 39 75 61 110 32 51 38 68 31 90
+-4 15 -8 61 -8 102 -1 52 -6 83 -18 101 -23 36 -36 89 -31 126 4 21 -4 51 -22
+90 -22 46 -29 77 -33 151 l-4 94 -52 33 c-62 40 -87 67 -116 125 -13 25 -36
+64 -52 88 -27 40 -32 42 -77 42 -67 0 -105 16 -136 56 -25 32 -30 35 -65 29
+-24 -4 -50 -1 -75 9 -36 15 -83 18 -134 9z"/>
+<path id="area+Moray" class="area" d="M8505 15441 c-102 -65 -142 -75 -295 -75 -116 1 -141 3 -175 21 -38
+20 -43 20 -105 6 -36 -8 -84 -23 -108 -34 -62 -28 -80 -24 -123 22 -35 38 -42
+41 -74 36 -20 -3 -69 -22 -108 -41 -40 -20 -76 -36 -81 -36 -5 0 -24 -11 -42
+-25 -18 -14 -54 -34 -79 -45 -25 -11 -63 -33 -84 -50 -21 -17 -62 -40 -92 -51
+-30 -11 -70 -33 -89 -48 -19 -15 -57 -38 -84 -49 -27 -12 -72 -39 -100 -59
+-28 -20 -82 -52 -120 -70 -38 -19 -108 -57 -155 -86 -168 -101 -410 -165 -627
+-167 -45 0 -75 -5 -82 -12 -5 -7 -12 -54 -14 -105 -4 -87 -6 -95 -42 -147 -52
+-76 -100 -200 -93 -243 4 -20 23 -53 48 -81 52 -59 89 -139 89 -195 0 -48 -40
+-122 -82 -151 -85 -60 -165 -105 -206 -116 -97 -24 -137 -44 -182 -89 -53 -53
+-65 -88 -79 -229 -7 -67 -19 -111 -51 -187 -24 -55 -43 -111 -44 -125 -1 -31
+23 -37 157 -39 104 -1 143 -12 201 -56 22 -17 56 -30 93 -35 212 -32 269 -51
+337 -110 60 -54 104 -34 182 81 54 78 184 193 286 251 32 18 93 58 134 89 44
+33 99 64 132 74 32 10 83 26 115 37 31 10 73 18 92 18 20 0 50 6 68 14 51 21
+168 146 228 241 30 48 75 111 100 139 25 28 54 67 64 86 10 19 48 64 84 100
+36 36 81 85 100 109 22 28 55 53 95 73 34 16 85 43 115 59 30 16 68 29 85 29
+38 0 237 48 252 61 6 5 14 35 17 67 9 105 66 183 153 208 62 18 79 36 88 91
+10 69 83 224 126 268 114 117 125 133 125 194 1 57 12 87 39 111 37 30 13 152
+-43 214 -20 22 -45 53 -54 69 -10 15 -21 27 -25 27 -4 0 -34 -18 -67 -39z"/>
+<path id="area+Garmoran" class="area" d="M4970 14940 c-19 -11 -49 -19 -66 -20 -18 0 -47 -6 -65 -14 -21 -9
+-53 -12 -90 -9 -77 7 -150 -19 -201 -72 -37 -38 -42 -40 -119 -46 -79 -5 -80
+-6 -128 -55 -26 -27 -62 -59 -79 -72 -18 -13 -32 -29 -32 -36 0 -19 -144 -177
+-177 -194 -15 -8 -59 -18 -98 -22 -53 -5 -81 -14 -114 -35 -37 -25 -51 -28
+-111 -27 -59 1 -72 -2 -84 -19 -7 -11 -34 -33 -60 -49 -52 -33 -72 -71 -59
+-110 8 -24 13 -25 103 -31 54 -3 114 -14 140 -24 32 -13 69 -17 132 -16 89 1
+118 -10 118 -44 0 -34 -94 -89 -180 -105 -59 -11 -120 -39 -133 -61 -8 -12 -4
+-25 13 -49 13 -18 23 -46 23 -61 0 -35 -35 -87 -88 -129 -77 -61 -93 -112 -50
+-155 20 -21 34 -25 82 -25 99 -1 202 -65 224 -141 8 -24 29 -54 56 -78 27 -26
+43 -48 43 -64 0 -30 -34 -67 -62 -67 -34 0 -112 56 -148 106 -24 34 -48 53
+-88 71 -52 23 -60 24 -121 13 -104 -18 -113 -22 -136 -65 -13 -23 -45 -55 -74
+-75 -28 -19 -60 -48 -71 -65 -21 -32 -27 -75 -10 -75 5 0 25 -16 44 -35 35
+-34 36 -35 79 -23 53 14 91 5 124 -28 22 -22 24 -30 18 -79 -6 -45 -4 -60 14
+-88 12 -19 35 -40 52 -47 42 -18 170 -7 242 20 52 20 64 21 103 10 55 -16 196
+-5 277 21 33 10 70 19 84 19 13 0 52 12 86 26 54 23 72 26 142 21 59 -3 95
+-11 135 -31 67 -32 87 -32 153 -4 66 27 119 69 238 188 88 88 98 103 128 180
+22 56 38 122 47 195 8 61 22 130 31 154 33 90 143 175 260 201 26 6 87 34 134
+63 146 86 153 130 43 265 -61 75 -72 116 -51 201 15 63 62 174 106 249 21 36
+38 165 26 201 -10 32 -60 52 -154 62 -356 36 -332 32 -398 72 -33 20 -68 49
+-78 63 -16 25 -92 64 -123 64 -9 -1 -33 -9 -52 -20z"/>
+<path id="area+Badenoch" class="area" d="M8983 14261 c-29 -16 -71 -43 -93 -61 -41 -32 -144 -86 -191 -100
+-14 -4 -68 -4 -119 2 -62 6 -110 5 -142 -1 -55 -12 -132 0 -182 30 -30 17 -33
+17 -151 -7 -66 -14 -143 -29 -171 -34 -58 -9 -67 -13 -143 -64 -29 -20 -58
+-36 -65 -36 -16 0 -209 -207 -229 -245 -8 -17 -25 -39 -38 -50 -12 -11 -61
+-78 -108 -150 -60 -91 -111 -153 -167 -206 -84 -80 -106 -91 -239 -117 -151
+-30 -246 -72 -300 -132 -11 -12 -49 -37 -85 -55 -100 -50 -225 -155 -281 -235
+-27 -38 -49 -78 -49 -89 0 -11 20 -36 46 -58 111 -92 127 -110 156 -170 17
+-34 41 -69 52 -77 21 -13 109 -40 186 -55 44 -10 110 -43 132 -68 28 -30 48
+-89 48 -139 0 -104 -46 -183 -133 -230 -94 -50 -90 -40 -91 -236 -1 -170 -1
+-174 -30 -227 -49 -95 -36 -144 51 -183 38 -17 45 -17 71 -4 15 8 44 32 64 53
+169 178 261 259 329 287 24 10 93 17 215 22 205 8 227 14 351 109 38 29 84 60
+101 69 40 20 52 44 52 98 0 28 9 59 26 88 14 25 37 72 50 105 28 68 58 103
+127 147 40 25 63 32 128 38 70 6 86 12 135 45 45 31 62 51 91 109 47 95 74
+129 139 177 83 61 152 89 236 96 58 5 91 14 164 49 96 47 172 105 318 247 105
+102 253 224 311 258 22 13 61 41 86 63 25 23 74 57 108 76 105 59 124 74 158
+120 19 25 47 62 64 83 34 42 45 87 32 134 -9 37 -90 94 -308 218 -62 36 -73
+46 -98 98 l-29 59 -92 -7 c-112 -9 -152 5 -191 63 -15 22 -40 46 -56 52 -16 7
+-46 26 -66 41 -49 40 -109 39 -180 0z"/>
+<path id="area+Mar" class="area" d="M10264 13606 c-33 -12 -81 -37 -106 -55 -31 -22 -62 -35 -94 -39 -44
+-5 -55 -12 -119 -76 -41 -42 -103 -90 -151 -119 -45 -26 -89 -58 -98 -72 -9
+-14 -35 -34 -59 -46 -55 -28 -198 -145 -319 -261 -250 -239 -368 -311 -539
+-328 -140 -13 -225 -74 -303 -219 -39 -72 -61 -99 -106 -136 -70 -55 -94 -64
+-188 -75 -110 -12 -143 -38 -198 -155 -23 -51 -46 -104 -49 -118 -9 -34 10
+-67 38 -67 13 0 50 -16 83 -36 58 -36 111 -55 264 -95 41 -11 117 -41 169 -67
+80 -40 103 -58 153 -115 32 -37 58 -73 58 -80 0 -6 11 -36 25 -64 33 -72 54
+-71 97 4 38 64 84 93 174 112 29 5 75 24 101 41 140 91 204 130 258 158 62 31
+167 105 239 168 52 45 194 130 240 143 22 6 63 6 108 0 53 -7 104 -5 188 6 63
+8 132 15 153 15 22 0 85 13 141 29 55 16 113 32 127 35 15 3 49 25 75 49 27
+25 69 54 94 67 25 12 68 40 96 61 57 43 175 88 317 119 127 28 167 49 246 130
+63 65 191 238 191 259 0 13 121 243 142 270 10 13 28 56 39 95 12 39 30 86 41
+104 11 18 18 38 15 46 -3 7 -34 20 -69 29 -64 17 -186 18 -394 1 -60 -5 -95
+-2 -136 10 -31 9 -71 16 -88 16 -18 0 -58 11 -89 25 -31 13 -85 31 -120 40
+-36 9 -90 29 -120 44 -31 16 -67 32 -81 36 -14 4 -93 36 -177 71 -83 35 -164
+64 -180 63 -15 0 -55 -10 -89 -23z"/>
+<path id="area+Angus" class="area" d="M11965 13303 c-16 -3 -36 -10 -43 -16 -22 -18 -78 -138 -91 -194 -7
+-28 -23 -66 -36 -83 -13 -18 -54 -94 -91 -169 -37 -75 -80 -151 -96 -169 -15
+-18 -36 -49 -47 -70 -10 -20 -57 -78 -104 -128 -96 -101 -167 -142 -287 -165
+-163 -31 -306 -101 -478 -237 -37 -28 -83 -56 -102 -61 -19 -5 -71 -19 -115
+-31 -44 -13 -98 -26 -120 -31 -78 -16 -282 -33 -390 -34 l-111 0 -84 -49 c-47
+-27 -103 -64 -125 -82 -69 -59 -222 -164 -262 -180 -21 -9 -94 -54 -163 -100
+-98 -66 -137 -86 -180 -94 -81 -15 -107 -28 -132 -68 -12 -20 -41 -58 -65 -84
+-24 -27 -43 -59 -43 -71 0 -12 12 -69 26 -127 14 -58 29 -148 34 -200 11 -116
+15 -129 49 -136 78 -15 116 -32 215 -95 127 -80 130 -80 299 -48 142 27 202
+23 233 -17 59 -75 57 -74 143 -74 59 0 100 7 155 25 88 30 127 31 182 6 102
+-46 128 -160 74 -317 -19 -52 -20 -66 -10 -119 6 -33 22 -93 37 -133 l26 -73
+72 6 c46 5 92 3 128 -5 55 -13 57 -12 104 18 82 53 114 62 218 62 86 0 101 3
+155 30 74 37 124 39 191 4 70 -35 90 -30 105 27 15 62 18 65 78 104 29 18 92
+72 141 119 62 61 114 101 173 133 57 31 92 58 108 82 99 146 124 188 124 205
+0 10 -11 31 -25 48 -19 22 -25 41 -25 76 0 59 26 103 81 139 23 16 54 40 70
+54 27 25 27 29 22 100 -10 140 64 306 155 350 43 21 90 53 166 110 24 19 210
+288 245 356 39 76 54 150 57 296 4 137 6 151 29 185 13 20 33 62 44 94 25 73
+35 91 91 163 78 99 142 211 138 242 -7 59 -99 73 -226 33 -85 -26 -147 -23
+-211 9 -33 17 -51 40 -103 127 -50 85 -80 122 -147 183 l-84 76 -71 1 c-39 1
+-84 0 -101 -3z"/>
+<path id="area+Lochaber" class="area" d="M5057 12858 c-81 -81 -131 -115 -212 -144 -84 -31 -140 -30 -215 1
+-76 32 -163 34 -221 4 -22 -11 -64 -23 -92 -25 -29 -3 -72 -12 -97 -19 -63
+-18 -273 -38 -321 -30 -40 7 -87 -4 -244 -55 -60 -20 -61 -20 -117 -1 -110 38
+-150 70 -174 143 -22 66 -41 74 -140 60 -97 -13 -117 -31 -140 -127 -9 -38
+-34 -115 -55 -170 -22 -55 -39 -105 -39 -112 0 -7 12 -24 26 -38 22 -22 25
+-31 19 -67 l-7 -41 43 7 c179 26 210 28 234 12 50 -33 40 -74 -27 -114 -37
+-21 -35 -46 3 -62 29 -13 32 -12 82 39 54 52 85 63 106 37 17 -20 0 -49 -44
+-75 -19 -11 -35 -27 -35 -36 0 -9 -11 -27 -25 -40 -18 -19 -35 -25 -68 -25
+-24 0 -70 -9 -103 -19 -32 -11 -87 -27 -121 -37 -44 -12 -63 -23 -63 -34 0
+-25 48 -66 111 -94 70 -33 97 -59 79 -80 -9 -11 -23 -14 -55 -9 -33 4 -54 1
+-82 -14 -21 -11 -55 -23 -75 -27 l-37 -7 19 -32 c36 -58 21 -117 -30 -117 -21
+0 -35 9 -50 30 -19 27 -26 30 -56 24 -36 -7 -58 9 -115 86 -25 33 -27 34 -55
+21 -30 -14 -68 -23 -189 -42 -52 -8 -89 -8 -145 0 -68 11 -81 10 -143 -9 -59
+-18 -70 -26 -79 -51 -6 -17 -27 -41 -50 -55 -53 -34 -66 -65 -45 -109 9 -19
+28 -42 42 -51 34 -22 106 -30 136 -13 16 8 57 12 119 10 85 -2 99 -5 135 -29
+58 -39 159 -63 211 -50 34 8 48 7 75 -8 42 -22 232 -38 263 -22 12 6 49 38 83
+71 60 58 65 61 122 65 79 6 123 -11 170 -64 55 -63 88 -74 199 -67 63 4 100 2
+122 -7 41 -17 33 -34 -21 -41 -24 -3 -62 -14 -83 -23 -31 -14 -54 -16 -100
+-11 -78 8 -168 41 -197 71 -35 38 -77 32 -141 -19 -125 -102 -236 -142 -413
+-150 -153 -7 -175 -15 -175 -62 0 -64 122 -278 196 -346 33 -29 198 -93 294
+-113 42 -9 94 -31 147 -62 110 -66 135 -81 155 -96 15 -10 32 -5 110 32 75 37
+108 61 179 130 47 47 97 103 111 125 90 146 126 196 153 211 16 9 57 43 91 75
+40 38 74 61 101 68 30 8 56 28 97 72 31 33 56 64 56 69 0 5 34 38 75 74 58 51
+83 66 107 66 17 0 46 9 64 21 21 12 46 19 66 17 28 -2 35 -9 44 -38 10 -29 18
+-37 51 -45 53 -13 73 -31 73 -67 0 -26 -6 -32 -56 -54 -31 -14 -71 -36 -89
+-49 -17 -14 -47 -28 -66 -31 -47 -9 -89 -32 -89 -48 0 -20 19 -24 59 -13 23 6
+54 5 90 -2 69 -14 253 -17 344 -6 43 5 93 4 140 -4 58 -10 87 -9 152 2 102 18
+132 10 184 -50 23 -25 41 -49 41 -54 0 -12 121 -94 173 -117 34 -15 73 -22
+135 -24 81 -3 90 -1 127 25 31 21 51 27 92 27 73 0 96 12 141 73 53 71 90 88
+189 86 55 -1 90 3 117 15 38 17 198 160 204 183 2 7 -14 21 -36 32 -50 25 -98
+80 -111 126 -11 42 3 110 42 193 24 51 25 60 20 191 -8 194 9 237 118 291 70
+36 99 82 99 159 0 42 -4 53 -30 74 -16 14 -53 30 -82 37 -29 6 -90 22 -135 36
+-92 28 -106 40 -152 139 -19 39 -44 74 -67 92 -20 15 -59 47 -88 71 -46 39
+-55 43 -89 38 -47 -8 -94 11 -156 62 -62 53 -76 59 -156 71 -208 31 -189 25
+-290 86 -36 22 -52 25 -150 25 -82 1 -124 6 -165 20 -30 11 -58 19 -63 20 -4
+0 -35 -28 -70 -62z"/>
+<path id="area+Atholl" class="area" d="M7858 11726 c-31 -13 -86 -46 -123 -73 -37 -28 -101 -68 -142 -88
+l-74 -37 -169 -3 c-92 -2 -179 -6 -192 -10 -41 -13 -141 -91 -201 -156 -137
+-150 -224 -243 -261 -277 -121 -116 -192 -173 -243 -199 -52 -25 -67 -28 -142
+-26 l-85 3 -65 -69 c-59 -62 -72 -71 -123 -82 -36 -7 -59 -18 -62 -28 -22 -73
+-29 -140 -31 -291 l-2 -175 -41 -97 c-35 -80 -42 -107 -42 -161 0 -61 -1 -65
+-39 -98 -33 -30 -39 -43 -45 -91 -4 -30 -4 -67 -1 -81 9 -32 -26 -111 -55
+-127 -29 -16 -41 -51 -29 -92 9 -34 11 -35 90 -52 45 -10 123 -19 175 -22 104
+-4 132 -14 243 -91 67 -45 158 -78 194 -70 84 19 267 87 294 109 19 15 106
+300 118 388 6 52 33 100 67 124 54 39 143 87 180 96 95 26 182 76 230 131 25
+30 66 68 90 84 23 16 64 48 89 71 33 30 66 49 115 64 62 19 83 21 209 15 121
+-6 153 -4 233 14 51 11 106 30 123 41 38 28 130 60 168 60 44 0 289 85 357
+123 91 51 98 66 102 215 3 121 1 134 -36 277 -63 239 -115 372 -166 429 -42
+47 -195 125 -280 142 -38 8 -77 19 -86 24 -10 5 -39 14 -65 20 -26 6 -77 28
+-113 50 -36 22 -75 40 -86 40 -12 0 -46 -11 -78 -24z"/>
+<path id="area+Argyll" class="area" d="M4475 10895 c-22 -7 -52 -16 -67 -19 -14 -3 -54 -29 -87 -57 -50 -41
+-68 -65 -97 -127 -19 -43 -45 -88 -58 -102 -13 -14 -35 -61 -51 -105 -19 -55
+-40 -93 -67 -123 -41 -45 -42 -62 -4 -62 50 0 94 -97 83 -181 -8 -58 -28 -76
+-93 -81 -76 -7 -112 -42 -123 -122 -7 -51 -13 -63 -59 -109 -60 -61 -94 -134
+-93 -197 0 -47 -19 -80 -49 -80 -35 0 -78 -53 -85 -106 -4 -27 -13 -71 -20
+-99 -7 -27 -16 -76 -19 -109 l-6 -58 72 6 c40 3 88 7 107 8 69 6 69 -63 -1
+-101 -71 -39 -88 -59 -88 -105 0 -29 -15 -69 -51 -142 -29 -56 -50 -107 -47
+-114 2 -8 24 5 58 34 65 56 105 62 115 18 10 -47 -10 -109 -54 -165 -42 -56
+-71 -114 -71 -145 0 -10 14 -29 31 -41 29 -22 31 -27 27 -72 -3 -27 -11 -55
+-18 -64 -16 -19 -54 -19 -84 0 -13 9 -31 13 -39 9 -21 -8 -124 -153 -144 -203
+-8 -20 -33 -64 -55 -99 -23 -34 -38 -66 -34 -69 13 -13 41 14 70 66 32 59 75
+91 124 91 25 0 32 -4 32 -19 0 -43 -57 -145 -169 -303 -55 -78 -120 -210 -123
+-250 -5 -53 23 -47 96 21 56 53 71 61 104 61 76 0 81 -36 15 -117 -44 -54 -74
+-104 -144 -243 -38 -76 -64 -221 -47 -257 14 -27 23 -34 75 -53 26 -10 35 -21
+43 -51 6 -22 17 -39 24 -39 8 0 43 16 78 37 34 20 79 44 99 54 21 10 56 45 85
+85 75 103 117 144 149 144 37 0 85 30 91 57 4 13 11 23 16 23 11 0 4 71 -17
+170 -8 36 -18 101 -24 145 -5 44 -19 102 -31 128 -20 45 -21 56 -12 167 12
+171 42 207 112 135 19 -19 42 -35 53 -35 10 0 42 23 72 51 46 43 56 59 65 105
+17 79 33 94 106 97 66 2 94 -11 94 -45 0 -20 -45 -158 -62 -191 -5 -9 -29 -40
+-53 -67 -26 -30 -47 -64 -51 -85 -6 -32 -4 -50 12 -125 3 -14 -4 -53 -15 -87
+-11 -33 -23 -96 -27 -140 l-7 -79 36 -47 c19 -25 40 -62 47 -82 12 -36 39 -56
+92 -69 16 -3 48 -21 73 -38 55 -39 74 -30 52 23 -25 62 -50 180 -44 215 7 40
+87 153 124 172 39 21 74 6 174 -73 51 -41 102 -75 112 -75 18 0 19 6 15 71 -5
+59 -13 86 -49 156 -38 73 -44 94 -44 147 0 54 2 61 20 61 19 0 33 -20 56 -85
+7 -19 30 -52 51 -73 47 -49 75 -134 89 -272 15 -158 35 -195 105 -195 29 0 36
+7 74 70 23 39 55 111 71 161 16 51 42 116 59 145 16 30 30 67 30 84 0 24 -7
+33 -40 50 -52 27 -75 61 -60 89 12 24 35 26 70 6 14 -8 36 -14 49 -15 26 0 26
+-3 1 189 -11 82 -7 93 54 181 39 54 37 87 -5 140 -30 37 -34 49 -32 94 0 28 4
+70 8 93 6 34 2 49 -19 85 -45 78 -28 170 37 201 19 9 39 17 44 17 20 0 46 41
+54 87 14 73 45 128 91 158 l41 27 -7 63 c-7 71 4 106 41 130 27 18 30 51 6 78
+-14 14 -19 41 -22 109 -3 101 12 159 54 198 17 16 25 34 25 57 0 19 4 53 9 76
+6 23 13 59 16 80 3 21 19 53 36 72 25 28 29 40 24 65 -5 23 5 55 46 147 l52
+118 -6 90 c-4 50 -2 133 4 185 7 74 6 97 -4 107 -8 8 -48 14 -112 16 -112 4
+-157 20 -291 103 -55 34 -77 55 -98 93 -14 27 -33 52 -42 55 -9 3 -54 1 -99
+-6 -65 -9 -98 -9 -148 0 -85 16 -122 15 -182 -4 -40 -12 -63 -13 -110 -5 -106
+18 -246 21 -290 6z"/>
+<path id="area+Fife" class="area" d="M8858 10613 c-8 -10 -24 -34 -36 -54 -17 -29 -42 -47 -115 -82 -50
+-25 -128 -57 -172 -70 -44 -14 -104 -35 -133 -46 -29 -12 -67 -21 -84 -21 -17
+0 -63 -17 -102 -39 -39 -21 -85 -42 -102 -45 -55 -12 -65 -33 -75 -158 -12
+-137 -41 -301 -76 -424 -16 -59 -22 -97 -17 -106 16 -28 105 -89 148 -102 31
+-10 67 -37 137 -105 164 -161 232 -201 384 -226 32 -5 55 -22 117 -83 68 -67
+83 -89 117 -168 22 -50 43 -108 47 -129 4 -22 19 -64 33 -95 23 -48 26 -69 27
+-165 1 -60 5 -135 9 -165 3 -31 3 -78 -2 -105 -6 -34 -5 -70 3 -109 7 -33 10
+-65 8 -71 -14 -35 45 -115 84 -115 30 0 176 -56 213 -82 15 -10 50 -23 77 -29
+48 -12 52 -11 82 14 17 15 44 27 59 27 15 0 42 11 61 25 19 14 39 25 45 25 6
+0 27 12 46 26 65 48 111 67 164 66 62 -2 186 26 202 45 6 8 14 38 18 66 13
+114 23 135 94 191 36 30 76 58 88 65 12 6 36 31 54 55 17 25 55 61 84 80 29
+19 93 73 143 119 82 77 97 87 148 97 94 20 194 -9 224 -65 8 -15 22 -31 32
+-36 26 -14 92 4 184 50 43 22 104 49 134 60 31 12 76 34 100 50 53 34 244 208
+248 226 2 7 -10 20 -25 29 -15 10 -62 53 -103 96 -70 73 -79 79 -125 85 -119
+14 -225 56 -273 108 -28 29 -82 141 -82 168 0 10 9 40 19 67 11 27 23 88 27
+136 l7 86 -60 0 c-48 0 -68 5 -97 25 -56 38 -103 34 -157 -14 -54 -47 -136
+-93 -206 -116 -28 -9 -63 -25 -77 -36 -14 -11 -89 -49 -167 -84 -78 -36 -170
+-83 -205 -106 -67 -43 -193 -89 -247 -89 -40 0 -77 24 -77 51 0 23 43 51 125
+81 49 18 75 37 145 107 47 48 111 117 142 154 62 74 64 85 31 167 -24 59 -54
+209 -47 238 3 15 15 56 25 91 25 82 24 132 -1 164 -30 38 -68 42 -136 14 -86
+-36 -109 -39 -221 -28 -111 10 -140 23 -174 77 -24 40 -44 42 -152 17 -40 -9
+-113 -17 -162 -17 l-91 -1 -104 66 c-58 37 -115 72 -127 78 -33 17 -88 14
+-105 -6z"/>
+<path id="area+Mentieth" class="area" d="M7607 10210 c-35 -11 -74 -33 -100 -57 -23 -21 -63 -54 -88 -73 -25
+-19 -58 -52 -74 -73 -37 -51 -79 -78 -210 -130 -61 -25 -136 -60 -166 -80 -59
+-38 -74 -62 -82 -133 -3 -22 -27 -112 -55 -200 -45 -140 -57 -166 -97 -212
+-40 -48 -45 -59 -45 -102 0 -63 32 -149 75 -201 65 -77 77 -198 27 -267 -54
+-76 -53 -75 -49 -142 3 -44 15 -86 35 -130 16 -36 38 -89 47 -118 22 -67 50
+-87 109 -79 117 16 163 -32 235 -248 29 -85 56 -179 61 -209 10 -65 85 -201
+144 -264 48 -51 104 -86 164 -102 24 -6 78 -29 120 -50 43 -21 139 -54 217
+-75 76 -20 172 -50 211 -66 40 -16 79 -29 88 -29 9 0 39 -9 68 -21 33 -13 101
+-26 178 -33 117 -12 129 -11 185 7 47 16 76 35 135 92 42 40 86 75 97 79 12 4
+35 29 52 55 34 56 94 91 157 91 21 0 45 4 52 9 17 11 31 72 32 139 0 64 -24
+92 -103 118 -29 9 -72 27 -95 41 -34 19 -52 24 -80 19 -150 -25 -184 -20 -214
+30 -17 29 -25 34 -45 30 -28 -8 -80 17 -87 41 -3 10 -8 44 -12 75 -5 45 -3 63
+10 83 22 33 36 32 86 -10 51 -43 78 -50 125 -35 20 6 61 10 93 8 52 -3 57 -1
+70 22 8 16 10 39 6 65 -7 38 -10 121 -16 400 -3 102 -6 126 -25 162 -13 23
+-27 63 -33 89 -15 65 -75 193 -108 227 -58 62 -101 87 -188 113 -129 37 -174
+66 -310 197 -81 77 -135 122 -160 131 -39 14 -95 46 -146 86 -33 26 -52 88
+-45 150 3 25 19 88 36 140 30 94 39 144 62 329 9 76 9 96 -3 106 -8 8 -60 14
+-148 18 -114 5 -144 3 -193 -13z"/>
+<path id="area+Lennox" class="area" d="M5747 9313 c-2 -4 -8 -23 -12 -41 -3 -17 -22 -50 -40 -72 -31 -37
+-33 -44 -28 -93 7 -66 -12 -107 -66 -143 -40 -26 -54 -51 -67 -114 -13 -71
+-32 -99 -88 -135 -31 -20 -56 -41 -56 -47 0 -6 9 -42 21 -81 17 -56 19 -84 14
+-138 -7 -68 -7 -69 26 -101 49 -49 58 -72 47 -120 -5 -22 -20 -60 -34 -85 -21
+-34 -25 -51 -20 -81 4 -20 11 -71 15 -112 8 -74 31 -151 52 -177 13 -15 87
+-17 109 -3 12 8 11 13 -8 40 -57 76 -74 108 -97 182 -31 99 -33 158 -5 183 20
+18 21 18 40 -1 11 -11 31 -51 45 -88 29 -81 77 -162 114 -194 14 -12 56 -38
+92 -57 76 -39 109 -75 109 -118 0 -21 9 -37 31 -56 17 -14 47 -41 66 -59 33
+-30 34 -34 21 -54 -17 -25 -109 -67 -150 -68 -32 0 -146 50 -192 85 -42 32
+-120 34 -186 4 -71 -32 -90 -55 -90 -109 0 -26 -10 -73 -22 -106 -18 -50 -22
+-85 -25 -226 l-4 -168 37 -97 c67 -176 58 -262 -40 -371 -58 -66 -59 -90 -7
+-140 51 -49 136 -162 167 -223 32 -64 62 -79 112 -55 35 17 102 67 199 149 24
+20 59 45 76 53 17 9 53 34 80 55 27 22 61 41 75 44 191 36 239 58 337 155 95
+94 135 114 210 105 67 -9 113 14 173 84 24 28 61 60 82 71 22 11 54 33 72 49
+45 39 91 61 128 61 59 0 194 42 245 76 83 55 183 158 206 210 32 77 26 92 -61
+135 -93 47 -170 124 -239 238 -53 87 -81 162 -81 213 0 16 -9 50 -19 76 -10
+26 -31 87 -47 136 -38 125 -51 136 -144 139 -98 3 -142 28 -165 95 -9 26 -26
+70 -37 97 -60 148 -70 187 -66 260 3 63 8 78 41 126 51 74 51 119 0 185 -47
+62 -83 152 -91 228 l-7 61 -42 -2 c-22 -1 -71 -11 -107 -22 l-67 -21 -93 30
+c-68 22 -112 44 -161 80 -71 53 -82 56 -215 65 -47 3 -101 8 -121 11 -20 3
+-39 2 -42 -3z"/>
+<path id="area+Dunbar" class="area" d="M11034 7945 c-16 -7 -53 -40 -82 -74 -62 -71 -62 -84 -1 -133 56 -45
+77 -85 94 -172 16 -82 30 -116 76 -179 56 -77 29 -177 -65 -245 -27 -19 -59
+-56 -76 -85 -27 -47 -30 -59 -28 -132 3 -76 1 -83 -35 -147 -20 -36 -37 -78
+-37 -92 0 -28 52 -137 74 -156 10 -7 30 -9 59 -5 45 7 117 -15 117 -36 0 -5
+31 -39 69 -77 53 -52 79 -89 119 -167 28 -55 60 -127 73 -160 32 -87 35 -90
+110 -76 55 9 69 17 112 58 27 27 60 69 73 95 27 53 41 63 99 73 22 3 68 13
+102 22 51 13 73 14 119 4 32 -6 78 -11 104 -11 40 0 60 -9 146 -63 76 -49 104
+-73 122 -105 13 -23 27 -42 31 -42 4 0 46 25 94 55 48 30 112 66 142 80 45 20
+59 31 71 62 26 61 91 150 127 172 41 25 228 232 241 266 8 21 1 44 -47 138
+-31 61 -59 130 -63 152 -8 50 -16 59 -75 92 -56 30 -75 54 -85 109 -9 51 -20
+64 -54 64 -16 0 -59 16 -96 36 -55 29 -74 35 -103 29 -89 -15 -111 -15 -192 3
+-106 24 -210 82 -264 148 -51 62 -139 125 -242 174 -76 36 -90 40 -135 34
+l-50 -7 -65 69 c-36 38 -79 91 -95 117 -45 72 -85 88 -248 99 -74 5 -151 13
+-171 17 -24 6 -46 4 -65 -4z"/>
+<path id="area+Lothian" class="area" d="M10808 7634 c-12 -25 -37 -59 -55 -75 -33 -28 -43 -32 -114 -44 -20
+-3 -58 -21 -85 -40 -70 -50 -134 -69 -234 -70 -93 0 -122 11 -175 64 -16 17
+-53 51 -82 75 l-51 43 -74 -3 c-40 -2 -114 -6 -164 -10 -105 -8 -148 3 -200
+49 -35 30 -35 30 -89 17 -43 -10 -71 -10 -150 0 -80 11 -99 10 -105 0 -5 -7
+-11 -54 -15 -104 -4 -50 -13 -106 -21 -124 -16 -38 -63 -62 -123 -62 -60 0
+-88 -15 -111 -60 -12 -23 -35 -49 -53 -58 -44 -24 -97 -77 -97 -98 0 -9 19
+-64 42 -122 53 -133 99 -186 171 -195 78 -11 105 -31 136 -101 16 -34 36 -87
+45 -118 12 -43 27 -65 65 -101 28 -26 58 -47 67 -47 9 0 33 10 52 22 55 34
+116 28 246 -21 60 -22 117 -41 127 -41 10 0 39 18 64 40 61 52 66 55 160 74
+60 12 89 14 115 6 19 -5 101 -10 182 -10 l146 0 33 41 c39 49 81 69 146 69
+107 1 162 31 184 99 6 20 25 59 42 86 27 45 30 58 28 122 -1 65 2 80 33 140
+23 47 54 87 100 129 44 40 66 69 66 83 0 13 -16 49 -35 80 -40 64 -55 109 -55
+162 0 21 -10 50 -23 70 -23 35 -81 79 -103 79 -7 0 -23 -21 -36 -46z"/>
+<path id="area+Lanark" class="area" d="M7596 7148 c-29 -61 -49 -86 -123 -154 -48 -44 -106 -92 -128 -107
+-41 -27 -210 -77 -262 -77 -35 -1 -57 -13 -119 -68 -47 -42 -48 -44 -35 -75 7
+-18 18 -50 23 -72 34 -130 72 -168 288 -276 30 -15 69 -42 86 -61 74 -78 134
+-211 134 -296 0 -52 2 -57 49 -102 33 -32 54 -63 62 -92 21 -70 16 -173 -13
+-268 -40 -129 -43 -155 -18 -180 11 -11 29 -20 41 -20 11 0 54 -14 94 -31 82
+-34 110 -61 210 -199 35 -49 101 -120 160 -172 55 -49 126 -114 158 -144 32
+-30 79 -64 105 -75 25 -11 66 -39 91 -62 58 -54 117 -91 135 -84 8 3 17 23 20
+44 4 21 24 65 46 98 40 62 74 85 240 158 30 14 81 47 113 74 40 35 76 56 117
+68 33 10 74 27 91 37 29 17 31 23 26 58 -3 21 -26 85 -52 141 -68 148 -68 157
+-6 283 45 93 51 114 51 168 0 35 7 92 16 128 11 50 13 80 5 135 -5 38 -8 108
+-7 155 1 78 5 93 44 174 23 48 42 92 42 97 0 5 -32 39 -70 75 -60 57 -73 75
+-86 123 -22 75 -59 157 -75 167 -7 4 -37 11 -67 15 -29 4 -64 15 -77 23 -36
+24 -102 126 -129 202 -14 37 -33 76 -44 86 -19 19 -20 19 -78 -3 -51 -20 -75
+-22 -178 -20 -77 2 -143 9 -185 21 -168 47 -240 69 -286 88 -60 25 -315 92
+-350 92 -22 0 -30 -11 -59 -72z"/>
+<path id="area+Carrick" class="area" d="M6760 6562 c-40 -24 -55 -27 -136 -28 -103 0 -110 -3 -175 -83 -57
+-70 -125 -107 -260 -142 -94 -24 -124 -38 -192 -84 -137 -93 -257 -191 -257
+-209 0 -8 30 -39 68 -69 40 -34 81 -78 102 -113 34 -56 35 -62 36 -159 l1
+-101 46 -67 c62 -90 66 -119 32 -210 -14 -40 -35 -100 -44 -134 -10 -35 -24
+-70 -31 -78 -7 -8 -63 -31 -125 -50 -98 -31 -118 -41 -148 -74 -50 -55 -56
+-70 -63 -153 -8 -83 -22 -118 -58 -141 -14 -9 -52 -44 -85 -78 l-61 -61 0 -96
+c0 -76 -5 -108 -21 -148 -12 -29 -19 -58 -16 -66 5 -14 127 -54 232 -78 28 -6
+66 -21 86 -33 20 -12 72 -42 115 -67 43 -25 101 -68 129 -97 74 -77 101 -85
+232 -73 105 10 141 16 233 38 25 7 106 17 180 23 74 6 173 15 220 20 47 5 124
+6 171 3 72 -5 97 -3 150 14 35 12 100 26 144 31 44 6 121 16 170 22 78 10 99
+9 145 -4 72 -22 149 -81 180 -139 32 -60 65 -95 110 -118 19 -10 59 -30 88
+-45 l52 -28 119 12 c66 6 153 11 194 11 86 0 100 10 116 80 17 74 13 151 -9
+193 -36 67 -21 107 58 149 l31 17 -22 60 -22 61 22 62 c28 77 23 87 -80 157
+-40 27 -79 56 -87 66 -8 9 -38 28 -68 41 -36 16 -86 55 -151 116 -53 51 -131
+123 -172 159 -40 36 -101 104 -133 150 -33 46 -73 99 -90 117 -31 33 -118 72
+-162 72 -47 0 -94 27 -109 64 -21 49 -19 88 10 197 41 155 46 185 34 240 -9
+42 -17 54 -45 71 -47 28 -65 66 -73 163 -7 68 -15 95 -45 151 -53 96 -71 113
+-203 180 -150 76 -213 135 -238 220 -9 32 -21 66 -25 74 -12 25 -52 21 -100
+-8z"/>
+<path id="area+England" class="area" d="M13092 6528 c-33 -35 -80 -88 -105 -119 -25 -31 -68 -72 -95 -91 -36
+-27 -57 -52 -82 -102 -34 -69 -69 -103 -130 -128 -43 -18 -170 -99 -187 -119
+-7 -8 -18 -36 -24 -62 -13 -45 -12 -47 19 -91 58 -80 79 -153 117 -398 3 -20
+30 -85 61 -144 30 -59 60 -129 65 -156 9 -42 8 -53 -16 -106 -22 -49 -55 -88
+-183 -214 -143 -142 -164 -159 -242 -196 -82 -38 -245 -95 -420 -146 -47 -14
+-112 -36 -145 -49 -33 -13 -96 -37 -139 -53 -113 -41 -185 -109 -222 -207 -40
+-107 -98 -215 -149 -277 -25 -30 -45 -60 -45 -66 0 -21 -71 -117 -136 -186
+-35 -36 -64 -71 -64 -76 0 -5 -26 -39 -57 -75 -121 -136 -151 -174 -201 -255
+-57 -91 -99 -147 -177 -233 -27 -30 -86 -97 -130 -148 -44 -51 -97 -101 -118
+-112 -50 -26 -65 -58 -42 -93 28 -43 13 -71 -55 -106 -91 -46 -138 -42 -224
+18 -121 84 -109 79 -163 59 -27 -11 -70 -25 -98 -33 -50 -14 -105 -60 -105
+-88 0 -21 22 -35 65 -39 44 -5 68 -31 59 -61 -3 -12 -24 -37 -45 -57 -21 -20
+-39 -41 -39 -47 0 -20 -29 -20 -61 -1 -84 48 -121 60 -151 48 -37 -15 -83 -89
+-123 -201 -18 -51 -45 -120 -59 -153 -22 -53 -24 -69 -19 -137 9 -115 -25
+-181 -140 -275 -42 -35 -35 -51 26 -58 28 -3 1185 -5 2569 -3 2049 2 2519 5
+2530 16 11 11 13 369 13 1920 l0 1907 -26 40 c-20 29 -28 58 -33 108 -9 113
+-22 141 -100 215 -83 78 -132 100 -177 77 -66 -34 -114 -3 -103 66 8 45 -4 53
+-67 50 -42 -2 -52 2 -88 34 -51 46 -95 113 -121 184 -17 44 -37 70 -101 130
+-71 65 -162 175 -211 252 -9 14 -18 41 -20 59 -2 19 -8 35 -14 37 -6 2 -38
+-25 -72 -59z"/>
+<path id="area+Selkirk" class="area" d="M10758 6560 c-9 -6 -29 -10 -45 -11 -15 0 -55 -3 -88 -6 -56 -5 -62
+-8 -112 -61 l-53 -55 -225 5 c-124 4 -241 2 -260 -2 -34 -8 -53 -19 -144 -85
+-45 -33 -74 -32 -189 11 -181 68 -182 68 -252 -26 -100 -134 -125 -242 -99
+-430 8 -62 7 -83 -5 -119 -10 -26 -16 -76 -16 -123 0 -65 -5 -89 -24 -127 -37
+-71 -76 -162 -76 -177 0 -8 20 -54 44 -102 24 -48 54 -115 66 -149 21 -59 25
+-63 75 -83 29 -12 63 -33 76 -47 52 -56 100 -83 148 -83 25 0 66 -5 91 -11 24
+-5 108 -12 185 -14 77 -2 214 -9 304 -14 108 -7 170 -7 182 -1 10 6 30 32 45
+58 15 26 46 76 70 112 24 36 55 96 69 133 14 38 34 86 45 107 20 40 93 110
+163 157 305 204 291 191 316 298 24 98 104 193 199 236 34 16 65 35 68 44 9
+22 -40 148 -89 230 -23 39 -72 100 -108 136 l-68 67 -74 4 c-86 4 -109 18
+-128 77 -6 20 -16 42 -22 49 -11 14 -45 15 -69 2z"/>
+<path id="area+Teviot" class="area" d="M11867 6155 c-49 -13 -90 -25 -91 -27 -64 -101 -141 -182 -187 -196
+-19 -5 -68 -15 -109 -21 -134 -20 -204 -41 -240 -70 -48 -38 -98 -114 -105
+-159 -14 -95 -26 -114 -112 -177 -44 -33 -127 -91 -184 -130 -153 -104 -187
+-142 -233 -259 -22 -54 -58 -126 -80 -161 -23 -35 -50 -78 -61 -96 -11 -18
+-27 -43 -35 -55 -13 -20 -12 -25 13 -61 14 -21 32 -54 38 -73 7 -19 20 -46 29
+-60 21 -31 105 -207 115 -240 18 -61 57 -112 102 -132 89 -39 157 -103 233
+-218 40 -60 80 -116 91 -126 19 -17 21 -16 50 12 50 47 102 131 158 254 65
+145 134 223 227 257 81 30 181 71 228 93 21 10 82 29 135 41 126 29 339 101
+415 141 38 20 94 65 147 118 47 47 108 105 135 130 28 25 60 67 73 93 29 60
+25 79 -54 235 -30 59 -55 118 -55 131 0 33 -30 184 -51 261 -13 44 -32 81 -59
+114 -33 40 -40 56 -40 91 0 27 -12 69 -34 116 -33 70 -39 77 -113 125 -72 46
+-86 51 -154 57 -41 3 -81 8 -89 11 -8 2 -55 -6 -103 -19z"/>
+<path id="area+Annan" class="area" d="M9175 4916 c-27 -13 -64 -26 -81 -30 -17 -4 -63 -33 -103 -66 -39
+-32 -93 -67 -118 -77 -199 -78 -219 -104 -252 -328 -5 -33 -18 -80 -29 -104
+-21 -46 -20 -57 13 -121 8 -16 15 -42 15 -59 0 -29 -5 -35 -79 -89 -21 -16
+-22 -21 -12 -57 16 -59 14 -185 -5 -236 -14 -40 -37 -221 -37 -293 0 -31 5
+-36 165 -178 101 -90 159 -194 202 -363 29 -113 89 -175 168 -175 42 0 126 39
+157 74 30 32 55 33 92 2 39 -33 115 -48 208 -40 67 6 83 4 126 -16 44 -20 55
+-21 98 -11 102 23 178 24 241 2 75 -26 79 -26 124 4 23 16 51 25 75 25 56 0
+83 18 168 111 163 179 277 322 335 417 44 72 115 162 180 226 17 17 47 56 67
+86 20 30 52 71 71 89 20 19 36 42 36 50 0 9 -13 37 -28 64 -121 211 -184 285
+-280 329 -70 32 -109 76 -141 162 -19 50 -70 156 -147 305 -36 69 -44 78 -104
+110 -59 33 -72 36 -150 37 -209 2 -461 17 -523 30 -38 8 -82 14 -98 14 -39 0
+-64 13 -121 67 -26 24 -59 48 -73 53 -43 16 -107 11 -160 -14z"/>
+<path id="area+Galloway" class="area" d="M5272 4010 c-53 -56 -113 -129 -132 -163 -26 -45 -55 -76 -105 -115
+-55 -42 -73 -62 -84 -95 -53 -161 -77 -219 -111 -272 -50 -77 -79 -142 -86
+-197 -7 -51 34 -195 83 -293 32 -63 73 -195 73 -234 0 -53 -62 -111 -119 -111
+-29 0 -118 84 -130 123 -15 52 -22 163 -11 192 16 41 -26 179 -61 201 -13 8
+-118 -14 -137 -29 -40 -31 -59 -111 -68 -293 -6 -99 -5 -103 26 -164 17 -34
+40 -96 51 -138 10 -42 27 -87 36 -101 9 -14 67 -76 130 -137 62 -61 113 -116
+113 -123 0 -6 25 -38 55 -71 40 -44 55 -68 55 -89 0 -58 32 -135 72 -172 32
+-31 38 -43 38 -77 0 -22 4 -52 10 -66 7 -20 5 -35 -7 -61 -9 -19 -14 -38 -10
+-41 9 -9 110 -10 124 -1 10 6 9 16 -2 45 -7 20 -21 75 -30 121 -9 46 -27 111
+-40 145 -13 33 -29 86 -35 116 -6 30 -20 78 -31 105 -24 59 -20 77 38 150 31
+39 65 64 144 108 57 32 116 67 130 78 23 19 30 19 70 9 57 -15 64 -22 116
+-102 28 -43 52 -69 66 -72 147 -28 139 -24 202 -90 73 -76 149 -136 209 -165
+50 -25 67 -47 97 -127 17 -45 40 -74 117 -151 79 -78 110 -101 181 -135 47
+-22 105 -54 127 -70 39 -28 43 -29 70 -15 64 33 88 83 72 148 -9 32 -8 64 0
+125 8 52 9 91 3 106 -12 31 4 115 25 139 28 31 13 52 -64 92 -83 44 -101 66
+-120 151 -25 111 -25 157 -3 194 23 36 76 72 107 72 21 0 57 -32 67 -61 3 -8
+21 -40 40 -71 29 -45 48 -61 104 -90 81 -43 131 -58 158 -48 11 4 41 26 67 49
+72 64 120 48 93 -30 -22 -61 0 -133 61 -202 19 -20 34 -43 34 -50 0 -7 14 -26
+31 -43 26 -25 38 -29 90 -30 l59 -1 9 36 c5 20 12 53 16 74 6 40 64 107 91
+107 22 0 74 -55 74 -79 0 -11 -9 -44 -21 -73 -22 -56 -19 -92 9 -106 9 -5 50
+-12 91 -15 79 -7 92 -3 151 44 19 16 74 46 122 69 48 22 90 45 93 51 4 5 24
+21 46 35 l40 25 -26 44 -26 44 22 42 c23 46 100 129 119 129 7 0 32 -18 57
+-40 25 -22 52 -40 60 -40 23 0 55 20 98 60 59 56 92 62 237 39 l123 -19 37 39
+c50 53 55 80 28 143 -18 42 -21 62 -16 107 17 147 18 179 6 245 -15 91 -56
+209 -91 264 -15 24 -81 93 -147 153 -76 70 -125 122 -132 142 -7 20 -8 62 -4
+113 l7 82 -38 12 c-26 9 -57 10 -99 4 -34 -4 -117 -8 -186 -8 l-125 -1 -100
+55 c-91 50 -104 61 -145 122 -59 87 -77 106 -125 130 -34 18 -51 20 -135 15
+-137 -8 -236 -24 -305 -48 -51 -18 -74 -20 -155 -15 -52 4 -142 2 -200 -3
+-249 -24 -389 -39 -398 -45 -23 -14 -190 -37 -281 -38 -117 -2 -171 19 -227
+88 -20 24 -62 58 -93 76 -31 17 -81 49 -111 70 -43 29 -79 43 -165 63 -60 14
+-118 28 -128 31 -12 4 -44 -23 -115 -96z"/>
+</g>
+</svg>
+
+<div id="turn" class="turn year_1297"></div>
+<div id="blocks" class="blocks"></div>
+<div id="offmap" class="offmap" style="visibility:hidden"></div>
+
+</div>
+
+<div class="hand">
+<div id="card+1" class="card card_herald"></div>
+<div id="card+2" class="card card_pillage"></div>
+<div id="card+3" class="card card_sea_move"></div>
+<div id="card+4" class="card card_truce"></div>
+<div id="card+5" class="card card_victuals"></div>
+<div id="card+6" class="card card_3"></div>
+<div id="card+7" class="card card_3"></div>
+<div id="card+8" class="card card_3"></div>
+<div id="card+9" class="card card_2"></div>
+<div id="card+10" class="card card_2"></div>
+<div id="card+11" class="card card_2"></div>
+<div id="card+12" class="card card_2"></div>
+<div id="card+13" class="card card_2"></div>
+<div id="card+14" class="card card_2"></div>
+<div id="card+15" class="card card_2"></div>
+<div id="card+16" class="card card_2"></div>
+<div id="card+17" class="card card_2"></div>
+<div id="card+18" class="card card_2"></div>
+<div id="card+19" class="card card_1"></div>
+<div id="card+20" class="card card_1"></div>
+<div id="card+21" class="card card_1"></div>
+<div id="card+22" class="card card_1"></div>
+<div id="card+23" class="card card_1"></div>
+<div id="card+24" class="card card_1"></div>
+<div id="card+25" class="card card_1"></div>
+</div>
+
+ </div>
+
+</div>
+</body>
diff --git a/rules.js b/rules.js
new file mode 100644
index 0000000..3514f95
--- /dev/null
+++ b/rules.js
@@ -0,0 +1,2825 @@
+"use strict";
+
+exports.scenarios = [
+ "Braveheart",
+ "The Bruce",
+ "Campaign",
+];
+
+// TODO: delay retreats to end of battle initiative step so they are hidden
+// TODO: prohibit moving back to last location?
+// TODO: undo builds
+
+const { CARDS, BLOCKS, AREAS, BORDERS } = require('./data');
+
+const ENEMY = { Scotland: "England", England: "Scotland" }
+const OBSERVER = "Observer";
+const BOTH = "Both";
+const ENGLAND = "England";
+const SCOTLAND = "Scotland";
+const E_BAG = "E. Bag";
+const S_BAG = "S. Bag";
+const EDWARD = "Edward";
+const KING = "King";
+const MORAY = "Moray";
+const E_BRUCE = "Bruce/E";
+const S_BRUCE = "Bruce/S";
+const E_COMYN = "Comyn/E";
+const S_COMYN = "Comyn/S";
+const WALLACE = "Wallace";
+const NORSE = "Norse";
+const FRENCH_KNIGHTS = "French Knights";
+
+// serif cirled numbers
+const DIE_HIT = [ 0, '\u2776', '\u2777', '\u2778', '\u2779', '\u277A', '\u277B' ];
+const DIE_MISS = [ 0, '\u2460', '\u2461', '\u2462', '\u2463', '\u2464', '\u2465' ];
+
+const ATTACK_MARK = " *";
+const RESERVE_MARK = "";
+
+let states = {};
+
+let game = null;
+
+function log(...args) {
+ let s = Array.from(args).join(" ");
+ game.log.push(s);
+}
+
+function print_turn_log_no_count(text) {
+ function print_move(last) {
+ return "\n" + last.join(" \u2192 ");
+ }
+ if (game.turn_log.length > 0) {
+ game.turn_log.sort();
+ for (let entry of game.turn_log)
+ text += print_move(entry);
+ } else {
+ text += "\nnothing.";
+ }
+ log(text);
+ delete game.turn_log;
+}
+
+function print_turn_log(verb) {
+ function print_move(last) {
+ return "\n" + n + " " + last.join(" \u2192 ");
+ }
+ let text = game.active + " " + verb + ":";
+ game.turn_log.sort();
+ let last = game.turn_log[0];
+ let n = 0;
+ for (let entry of game.turn_log) {
+ if (entry.toString() != last.toString()) {
+ text += print_move(last);
+ n = 0;
+ }
+ ++n;
+ last = entry;
+ }
+ if (n > 0)
+ text += print_move(last);
+ else
+ text += "\nnothing.";
+ log(text);
+ delete game.turn_log;
+}
+
+function is_active_player(current) {
+ return (current == game.active) || (game.active == BOTH && current != OBSERVER);
+}
+
+function is_inactive_player(current) {
+ return current == OBSERVER || (game.active != current && game.active != BOTH);
+}
+
+function remove_from_array(array, item) {
+ let i = array.indexOf(item);
+ if (i >= 0)
+ array.splice(i, 1);
+}
+
+function clear_undo() {
+ game.undo = [];
+}
+
+function push_undo() {
+ game.undo.push(JSON.stringify(game, (k,v) => {
+ if (k === 'undo') return undefined;
+ if (k === 'log') return v.length;
+ return v;
+ }));
+}
+
+function pop_undo() {
+ let undo = game.undo;
+ let log = game.log;
+ Object.assign(game, JSON.parse(undo.pop()));
+ game.undo = undo;
+ log.length = game.log;
+ game.log = log;
+}
+
+function gen_action_undo(view) {
+ if (!view.actions)
+ view.actions = {}
+ if (game.undo && game.undo.length > 0)
+ view.actions.undo = 1;
+ else
+ view.actions.undo = 0;
+}
+
+function gen_action(view, action, argument) {
+ if (!view.actions)
+ view.actions = {}
+ if (argument != undefined) {
+ if (!(action in view.actions))
+ view.actions[action] = [ argument ];
+ else
+ view.actions[action].push(argument);
+ } else {
+ view.actions[action] = 1;
+ }
+}
+
+function roll_d6() {
+ return Math.floor(Math.random() * 6) + 1;
+}
+
+function shuffle_deck() {
+ let deck = [];
+ for (let c = 1; c <= 25; ++c)
+ deck.push(c);
+ return deck;
+}
+
+function deal_cards(deck, n) {
+ let hand = [];
+ for (let i = 0; i < n; ++i) {
+ let k = Math.floor(Math.random() * deck.length);
+ hand.push(deck[k]);
+ deck.splice(k, 1);
+ }
+ return hand;
+}
+
+function block_name(who) {
+ if (who == EDWARD)
+ return game.edward == 1 ? "Edward I" : "Edward II";
+ if (who == KING)
+ return "Scottish King";
+ return BLOCKS[who].name;
+}
+
+function block_owner(who) {
+ return BLOCKS[who].owner;
+}
+
+function block_type(who) {
+ return BLOCKS[who].type;
+}
+
+function block_move(who) {
+ return BLOCKS[who].move;
+}
+
+function block_max_steps(who) {
+ return BLOCKS[who].steps;
+}
+
+function block_is_mortal(who) {
+ return BLOCKS[who].mortal;
+}
+
+function block_initiative(who) {
+ return BLOCKS[who].combat[0];
+}
+
+function block_printed_fire_power(who) {
+ return BLOCKS[who].combat[1] | 0;
+}
+
+function block_fire_power(who, where) {
+ let area = AREAS[where];
+ let combat = block_printed_fire_power(who);
+ if (is_defender(who)) {
+ if (block_type(who) == 'nobles' && area.home == block_name(who))
+ ++combat;
+ else if (who == MORAY && where == "Moray")
+ ++combat;
+ }
+ return combat;
+}
+
+function is_coastal_area(where) {
+ return AREAS[where].coastal;
+}
+
+function is_cathedral_area(where) {
+ return AREAS[where].cathedral;
+}
+
+function is_friendly_coastal_area(where) {
+ return is_coastal_area(where) && is_friendly_area(where);
+}
+
+function is_in_friendly_coastal_area(who) {
+ let where = game.location[who];
+ if (where && where != E_BAG && where != S_BAG)
+ return is_friendly_coastal_area(where);
+ return false;
+}
+
+function is_on_map(who) {
+ let where = game.location[who];
+ if (where && where != E_BAG && where != S_BAG)
+ return true;
+ return false;
+}
+
+function count_blocks_in_area(where) {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (game.location[b] == where)
+ ++count;
+ return count;
+}
+
+function castle_limit(where) {
+ if (game.active == SCOTLAND && is_cathedral_area(where))
+ return AREAS[where].limit + 1;
+ return AREAS[where].limit;
+}
+
+function is_within_castle_limit(where) {
+ return count_blocks_in_area(where) <= castle_limit(where);
+}
+
+function is_under_castle_limit(where) {
+ return count_blocks_in_area(where) < castle_limit(where);
+}
+
+function count_english_nobles() {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (block_owner(b) == ENGLAND && block_type(b) == 'nobles')
+ if (is_on_map(b))
+ ++count;
+ return count;
+}
+
+function count_scottish_nobles() {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (block_owner(b) == SCOTLAND && block_type(b) == 'nobles')
+ if (is_on_map(b))
+ ++count;
+ if (is_on_map(MORAY))
+ ++count;
+ return count;
+}
+
+function find_noble(owner, name) {
+ if (name in BLOCKS)
+ return name;
+ return name + "/" + owner[0];
+}
+
+function border_id(a, b) {
+ return (a < b) ? a + "/" + b : b + "/" + a;
+}
+
+function border_was_last_used_by_enemy(from, to) {
+ return game.last_used[border_id(from, to)] == ENEMY[game.active];
+}
+
+function border_type(a, b) {
+ return BORDERS[border_id(a,b)];
+}
+
+function border_limit(a, b) {
+ return game.border_limit[border_id(a,b)] || 0;
+}
+
+function reset_border_limits() {
+ game.border_limit = {};
+}
+
+function count_friendly(where) {
+ let p = game.active;
+ let count = 0;
+ for (let b in BLOCKS)
+ if (game.location[b] == where && block_owner(b) == p)
+ ++count;
+ return count;
+}
+
+function count_enemy(where) {
+ let p = ENEMY[game.active];
+ let count = 0;
+ for (let b in BLOCKS)
+ if (game.location[b] == where && block_owner(b) == p)
+ ++count;
+ return count;
+}
+
+function is_friendly_area(where) { return count_friendly(where) > 0 && count_enemy(where) == 0; }
+function is_enemy_area(where) { return count_friendly(where) == 0 && count_enemy(where) > 0; }
+function is_neutral_area(where) { return count_friendly(where) == 0 && count_enemy(where) == 0; }
+function is_contested_area(where) { return count_friendly(where) > 0 && count_enemy(where) > 0; }
+function is_friendly_or_neutral_area(where) { return is_friendly_area(where) || is_neutral_area(where); }
+
+function have_contested_areas() {
+ for (let where in AREAS)
+ if (is_contested_area(where))
+ return true;
+ return false;
+}
+
+function count_pinning(where) {
+ return count_enemy(where);
+}
+
+function count_pinned(where) {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (game.location[b] == where && block_owner(b) == game.active)
+ if (!game.reserves.includes(b))
+ ++count;
+ return count;
+}
+
+function is_pinned(from) {
+ if (game.active == game.p2) {
+ if (count_pinned(from) <= count_pinning(from))
+ return true;
+ }
+ return false;
+}
+
+function can_block_use_border(who, from, to) {
+ if (border_type(from, to) == 'major')
+ return border_limit(from, to) < 6;
+ return border_limit(from, to) < 2;
+}
+
+function can_block_move_to(who, from, to) {
+ // No group moves across Anglo-Scottish border
+ if (from == ENGLAND || to == ENGLAND)
+ if (game.moves == 0)
+ return false;
+ if (game.active == SCOTLAND && game.truce == SCOTLAND && to == ENGLAND)
+ return false;
+ if (can_block_use_border(who, from, to)) {
+ if (count_pinning(from) > 0) {
+ if (border_was_last_used_by_enemy(from, to))
+ return false;
+ }
+ if (game.truce == game.active && is_enemy_area(to))
+ return false;
+ return true;
+ }
+ return false;
+}
+
+function can_block_move(who) {
+ if (who == NORSE)
+ return false;
+ if (block_owner(who) == game.active && !game.moved[who]) {
+ let from = game.location[who];
+ if (from) {
+ if (is_pinned(from))
+ return false;
+ for (let to of AREAS[from].exits)
+ if (can_block_move_to(who, from, to))
+ return true;
+ }
+ }
+ return false;
+}
+
+function can_block_continue(who, from, here) {
+ if (here == ENGLAND)
+ return false;
+ if (is_contested_area(here))
+ return false;
+ if (border_type(from, here) == 'minor')
+ return false;
+ if (game.distance >= block_move(who))
+ return false;
+ for (let to of AREAS[here].exits)
+ if (to != game.last_from && can_block_move_to(who, here, to))
+ return true;
+ return false;
+}
+
+function can_block_retreat_to(who, to) {
+ if (is_friendly_area(to) || is_neutral_area(to)) {
+ let from = game.location[who];
+ if (block_owner(who) == ENGLAND && from == ENGLAND)
+ return false;
+ if (block_owner(who) == SCOTLAND && to == ENGLAND)
+ return false;
+ if (can_block_use_border(who, from, to)) {
+ if (border_was_last_used_by_enemy(from, to))
+ return false;
+ return true;
+ }
+ }
+ return false;
+}
+
+function can_block_retreat(who) {
+ if (who == NORSE)
+ return true;
+ if (block_owner(who) == game.active) {
+ let from = game.location[who];
+ for (let to of AREAS[from].exits)
+ if (can_block_retreat_to(who, to))
+ return true;
+ }
+ return false;
+}
+
+function can_block_regroup_to(who, to) {
+ if (is_friendly_area(to) || is_neutral_area(to)) {
+ let from = game.location[who];
+ if (block_owner(who) == ENGLAND && from == ENGLAND)
+ return false;
+ if (block_owner(who) == SCOTLAND && to == ENGLAND)
+ return false;
+ if (can_block_use_border(who, from, to))
+ return true;
+ }
+ return false;
+}
+
+function can_block_regroup(who) {
+ if (block_owner(who) == game.active) {
+ let from = game.location[who];
+ for (let to of AREAS[from].exits)
+ if (can_block_regroup_to(who, to))
+ return true;
+ }
+ return false;
+}
+
+function is_battle_reserve(b) {
+ return game.reserves.includes(b);
+}
+
+function is_attacker(b) {
+ if (game.location[b] == game.where && block_owner(b) == game.attacker[game.where])
+ return !game.reserves.includes(b);
+ return false;
+}
+
+function is_defender(b) {
+ if (game.location[b] == game.where && block_owner(b) != game.attacker[game.where])
+ return !game.reserves.includes(b);
+ return false;
+}
+
+function swap_blocks(old) {
+ let bo = ENEMY[block_owner(old)];
+ let b = find_noble(bo, block_name(old));
+ game.location[b] = game.location[old];
+ game.steps[b] = game.steps[old];
+ game.location[old] = null;
+ game.steps[old] = block_max_steps(old);
+ return b;
+}
+
+function disband(who) {
+ game.location[who] = block_owner(who) == ENGLAND ? E_BAG : S_BAG;
+ game.steps[who] = block_max_steps(who);
+}
+
+function eliminate_block(who, reason) {
+ if (block_type(who) == 'nobles') {
+ if (reason == 'retreat') {
+ game.turn_log.push([game.location[who], "Captured"]);
+ } else if (reason == 'combat') {
+ game.flash = block_name(who) + " is captured.";
+ log(block_name(who) + " is captured.");
+ } else {
+ log(block_name(who) + " is captured.");
+ }
+ } else {
+ if (reason == 'retreat') {
+ game.turn_log.push([game.location[who], "Eliminated"]);
+ } else if (reason == 'combat') {
+ game.flash = block_name(who) + " is eliminated.";
+ log(block_name(who) + " is eliminated.");
+ } else {
+ if (block_owner(who) == ENGLAND)
+ log("English block is eliminated.");
+ else
+ log("Scottish block is eliminated.");
+ }
+ }
+
+ // TODO: clean up and check all combinations
+ if (who == EDWARD) {
+ if (reason == 'combat' || reason == 'retreat') {
+ if (game.edward == 1) {
+ game.edward = 2;
+ disband(who);
+ } else {
+ game.location[who] = null;
+ if (reason == 'combat') {
+ game.victory = "Scotland wins because king Edward II has died in battle!";
+ game.result = SCOTLAND;
+ }
+ }
+ } else {
+ disband(who);
+ }
+ } else if (who == KING) {
+ game.location[who] = null;
+ if (reason == 'combat') {
+ game.victory = "England wins because the Scottish king has died in battle!";
+ game.result = ENGLAND
+ }
+ } else if (block_is_mortal(who) && (reason == 'combat' || reason == 'retreat')) {
+ game.location[who] = null;
+ } else if (block_type(who) == 'nobles') {
+ who = swap_blocks(who);
+ game.steps[who] = 1; // flip at strength 1 if eliminated
+ if (reason == 'combat' || reason == 'retreat')
+ game.reserves.push(who);
+ } else {
+ disband(who);
+ }
+}
+
+function reduce_block(who, reason) {
+ if (game.steps[who] == 1) {
+ eliminate_block(who, reason);
+ } else {
+ --game.steps[who];
+ }
+}
+
+function count_attackers() {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (is_attacker(b))
+ ++count;
+ return count;
+}
+
+function count_defenders() {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (is_defender(b))
+ ++count;
+ return count;
+}
+
+const CELTIC_BLOCKS = [
+ "Ulster Infantry",
+ "Wales Archers",
+ "Wales Infantry",
+];
+
+function celtic_unity_roll(who) {
+ let die = roll_d6();
+ if (die >= 5) {
+ log(who + " roll " + DIE_MISS[die] + " for Celtic unity and return to the draw pool.");
+ disband(who);
+ } else {
+ log(who + " roll " + DIE_HIT[die] + " for Celtic unity \u2013 no effect.");
+ }
+}
+
+// SETUP
+
+function reset_blocks() {
+ for (let b in BLOCKS) {
+ game.steps[b] = block_max_steps(b);
+ if (block_type(b) == 'nobles')
+ game.location[b] = null;
+ else if (block_owner(b) == ENGLAND)
+ game.location[b] = E_BAG;
+ else
+ game.location[b] = S_BAG;
+ }
+}
+
+function deploy_noble(owner, area, name) {
+ if (name in BLOCKS) {
+ game.location[name] = area;
+ } else {
+ let friend = find_noble(owner, name);
+ let enemy = find_noble(ENEMY[owner], name);
+ game.location[friend] = area;
+ game.location[enemy] = null;
+ }
+}
+
+function deploy_block(area, block) {
+ game.location[block] = area;
+}
+
+function draw_from_bag(bag, exclude_list) {
+ let list = [];
+ for (let b in BLOCKS) {
+ if (exclude_list && exclude_list.includes(b))
+ continue;
+ if (game.location[b] == bag)
+ list.push(b);
+ }
+ return list[Math.floor(Math.random() * list.length)];
+}
+
+function deploy_english(count) {
+ let list = [];
+ for (let b in BLOCKS)
+ if (game.location[b] == E_BAG)
+ list.push(b);
+ for (let i = 0; i < count; ++i) {
+ let x = Math.floor(Math.random() * list.length);
+ let b = list[x];
+ list.splice(x,1);
+ game.location[b] = ENGLAND;
+ game.steps[b] = block_max_steps(b);
+ }
+}
+
+function deploy_off_map(block) {
+ game.location[block] = null;
+}
+
+function setup_braveheart() {
+ reset_blocks();
+
+ deploy_noble("England", "Badenoch", "Comyn");
+ deploy_noble("England", "Angus", "Angus");
+ deploy_noble("England", "Argyll", "Argyll");
+ deploy_noble("England", "Mar", "Mar");
+ deploy_noble("England", "Lennox", "Lennox");
+ deploy_noble("England", "Buchan", "Buchan");
+ deploy_noble("England", "Ross", "Ross");
+ deploy_noble("England", "Atholl", "Atholl");
+ deploy_noble("England", "Dunbar", "Dunbar");
+ deploy_noble("England", "Mentieth", "Mentieth");
+ deploy_noble("England", "Lanark", "Steward");
+
+ deploy_block("Lothian", "Cumbria Infantry");
+ deploy_block("Mentieth", "Northumber Infantry");
+
+ deploy_english(4);
+
+ deploy_noble("Scotland", "Annan", "Bruce");
+ deploy_noble("Scotland", "Galloway", "Galloway");
+
+ deploy_block("Fife", "Wallace");
+ deploy_block("Fife", "Douglas");
+ deploy_block("Fife", "Barclay");
+ deploy_block("Moray", "Moray");
+ deploy_block("Moray", "Fraser");
+ deploy_block("Strathspey", "Grant");
+
+ deploy_off_map("King");
+ deploy_off_map("French Knights");
+
+ game.scottish_king = false;
+ game.edward = 1;
+ game.year = 1297;
+ game.end_year = 1305;
+}
+
+function setup_the_bruce() {
+ reset_blocks();
+
+ deploy_noble("England", "Badenoch", "Comyn");
+ deploy_noble("England", "Angus", "Angus");
+ deploy_noble("England", "Argyll", "Argyll");
+ deploy_noble("England", "Buchan", "Buchan");
+ deploy_noble("England", "Galloway", "Galloway");
+ deploy_noble("England", "Ross", "Ross");
+ deploy_noble("England", "Mentieth", "Mentieth");
+ deploy_noble("England", "Lanark", "Steward");
+
+ deploy_block("Moray", "Cumbria Infantry");
+ deploy_block("Mentieth", "Northumber Infantry");
+ deploy_block("Lothian", "Durham Infantry");
+ deploy_block("Lanark", "Westmor Infantry");
+
+ deploy_english(6);
+
+ deploy_noble("Scotland", "Dunbar", "Dunbar");
+ deploy_noble("Scotland", "Lennox", "Lennox");
+ deploy_noble("Scotland", "Atholl", "Atholl");
+ deploy_noble("Scotland", "Mar", "Mar");
+ deploy_noble("Scotland", "Carrick", "Bruce");
+
+ deploy_block("Fife", "King");
+ deploy_block("Fife", "Douglas");
+ deploy_block("Fife", "Barclay");
+ deploy_block("Lennox", "Campbell");
+ deploy_block("Carrick", "Lindsay");
+
+ deploy_off_map("Moray");
+ deploy_off_map("Wallace");
+ deploy_off_map("French Knights");
+
+ game.scottish_king = true;
+ game.edward = 1;
+ game.year = 1306;
+ game.end_year = 1314;
+}
+
+function setup_campaign() {
+ setup_braveheart();
+ game.end_year = 1400; /* no limit */
+}
+
+// GAME TURN
+
+function start_year() {
+ log("");
+ log("Start Year " + game.year + ".");
+
+ // Deal new cards
+ let deck = shuffle_deck();
+ game.e_hand = deal_cards(deck, 5);
+ game.s_hand = deal_cards(deck, 5);
+
+ start_game_turn();
+}
+
+function start_game_turn() {
+ let turn = 6 - game.e_hand.length;
+ log("");
+ log("Start Turn " + turn + " of Year " + game.year + ".");
+
+ // Reset movement and attack tracking state
+ game.truce = false;
+ reset_border_limits();
+ game.last_used = {};
+ game.attacker = {};
+ game.reserves = [];
+ game.moved = {};
+
+ goto_card_phase();
+}
+
+function end_game_turn() {
+ if (count_english_nobles() == 0) {
+ game.victory = "Scotland wins by controlling all the nobles!";
+ game.result = SCOTLAND;
+ }
+ if (count_scottish_nobles() == 0) {
+ game.victory = "England wins by controlling all the nobles!";
+ game.result = ENGLAND;
+ }
+ if (game.victory)
+ return goto_game_over();
+
+ if (game.e_hand.length > 0)
+ start_game_turn()
+ else
+ goto_winter_turn();
+}
+
+// CARD PHASE
+
+function goto_card_phase() {
+ game.e_card = 0;
+ game.s_card = 0;
+ game.show_cards = false;
+ game.state = 'play_card';
+ game.active = BOTH;
+}
+
+function resume_play_card() {
+ if (game.s_card > 0 && game.e_card > 0)
+ reveal_cards();
+ else if (game.s_card > 0)
+ game.active = ENGLAND;
+ else if (game.e_card > 0)
+ game.active = SCOTLAND;
+ else
+ game.active = BOTH;
+}
+
+states.play_card = {
+ prompt: function (view, current) {
+ if (current == OBSERVER)
+ return view.prompt = "Waiting for players to play a card.";
+ if (current == ENGLAND) {
+ if (game.e_card) {
+ view.prompt = "Waiting for Scotland to play a card.";
+ gen_action(view, 'undo');
+ } else {
+ view.prompt = "Play a card.";
+ for (let c of game.e_hand)
+ gen_action(view, 'play', c);
+ }
+ }
+ if (current == SCOTLAND) {
+ if (game.s_card) {
+ view.prompt = "Waiting for England to play a card.";
+ gen_action(view, 'undo');
+ } else {
+ view.prompt = "Play a card.";
+ for (let c of game.s_hand)
+ gen_action(view, 'play', c);
+ }
+ }
+ },
+ play: function (card, current) {
+ if (current == ENGLAND) {
+ remove_from_array(game.e_hand, card);
+ game.e_card = card;
+ }
+ if (current == SCOTLAND) {
+ remove_from_array(game.s_hand, card);
+ game.s_card = card;
+ }
+ resume_play_card();
+ },
+ undo: function (_, current) {
+ if (current == ENGLAND) {
+ game.e_hand.push(game.e_card);
+ game.e_card = 0;
+ }
+ if (current == SCOTLAND) {
+ game.s_hand.push(game.s_card);
+ game.s_card = 0;
+ }
+ resume_play_card();
+ }
+}
+
+function reveal_cards() {
+ log("England plays " + CARDS[game.e_card].name + ".");
+ log("Scotland plays " + CARDS[game.s_card].name + ".");
+ game.show_cards = true;
+
+ let ec = CARDS[game.e_card];
+ let sc = CARDS[game.s_card];
+
+ if (ec.event && sc.event) {
+ log("Two events played at the same time. The year will end after this turn.");
+ game.e_hand.length = 0;
+ game.s_hand.length = 0;
+ }
+
+ if (ec.event) {
+ game.p1 = ENGLAND;
+ game.p2 = SCOTLAND;
+ } else if (sc.event) {
+ game.p1 = SCOTLAND;
+ game.p2 = ENGLAND;
+ } else if (sc.moves > ec.moves) {
+ game.p1 = SCOTLAND;
+ game.p2 = ENGLAND;
+ } else {
+ game.p1 = ENGLAND;
+ game.p2 = SCOTLAND;
+ }
+
+ game.active = game.p1;
+ start_player_turn();
+}
+
+function start_player_turn() {
+ log("");
+ log("Start " + game.active + " turn.");
+ reset_border_limits();
+ let ec = CARDS[game.e_card];
+ let sc = CARDS[game.s_card];
+ if (game.active == ENGLAND && ec.event)
+ goto_event(ec.event);
+ else if (game.active == SCOTLAND && sc.event)
+ goto_event(sc.event);
+ else if (game.active == ENGLAND)
+ goto_move_phase(ec.moves);
+ else if (game.active == SCOTLAND)
+ goto_move_phase(sc.moves);
+}
+
+function end_player_turn() {
+ game.moves = 0;
+ game.activated = null;
+ game.main_origin = null;
+ game.main_border = null;
+
+ if (game.active == game.p2) {
+ goto_battle_phase();
+ } else {
+ game.active = game.p2;
+ start_player_turn();
+ }
+}
+
+// CORONATION
+
+function can_crown_bruce() {
+ return game.location[WALLACE] == null && game.location[S_BRUCE] == "Fife";
+}
+
+function can_crown_comyn() {
+ return game.location[WALLACE] == null && game.location[S_COMYN] == "Fife";
+}
+
+function can_crown_balliol() {
+ return game.year >= 1301 && is_on_map(FRENCH_KNIGHTS);
+}
+
+function goto_event(event) {
+ if (game.active == SCOTLAND && !game.scottish_king &&
+ (can_crown_bruce() || can_crown_comyn() || can_crown_balliol())) {
+ game.state = 'coronation_event';
+ game.event = event;
+ } else {
+ goto_event_card(event);
+ }
+}
+
+states.coronation_event = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to crown a king.";
+ view.prompt = "Play event or crown a king?";
+ gen_action(view, 'play_event');
+ if (can_crown_bruce())
+ gen_action(view, 'crown_bruce');
+ if (can_crown_comyn())
+ gen_action(view, 'crown_comyn');
+ if (can_crown_balliol())
+ gen_action(view, 'return_of_the_king');
+ },
+ crown_bruce: function () {
+ log("Bruce is crowned King!");
+ game.scottish_king = true;
+ game.location[KING] = "Fife";
+ game.steps[KING] = block_max_steps(KING);
+ defect_comyn_nobles();
+ },
+ crown_comyn: function () {
+ log("Comyn is crowned King!");
+ game.scottish_king = true;
+ game.location[KING] = "Fife";
+ game.steps[KING] = block_max_steps(KING);
+ defect_bruce_nobles();
+ },
+ return_of_the_king: function () {
+ log("Return of the King!");
+ game.scottish_king = true;
+ game.location[KING] = game.location[FRENCH_KNIGHTS];
+ game.steps[KING] = block_max_steps(KING);
+ defect_bruce_nobles();
+ },
+ play_event: function () {
+ let event = game.event;
+ delete game.event;
+ goto_event_card(event);
+ },
+}
+
+function defect_bruce_nobles() {
+ defect_nobles([ "Bruce", "Mar", "Lennox", "Atholl", "Dunbar", "Mentieth", "Steward" ]);
+}
+
+function defect_comyn_nobles() {
+ defect_nobles([ "Comyn", "Angus", "Argyll", "Buchan", "Galloway", "Ross" ]);
+}
+
+function defect_nobles(list) {
+ for (let name of list) {
+ let who = find_noble(game.active, name);
+ if (is_on_map(who)) {
+ let where = game.location[who];
+ log(name + " defects.");
+ who = swap_blocks(who);
+ if (is_contested_area(where))
+ game.attacker[where] = block_owner(who);
+ }
+ }
+ resume_coronation();
+}
+
+function resume_coronation() {
+ if (have_contested_areas()) {
+ game.active = game.p1;
+ game.state = 'coronation_battles';
+ } else {
+ game.active = SCOTLAND;
+ end_player_turn();
+ }
+}
+
+states.coronation_battles = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to choose a battle.";
+ view.prompt = "Coronation: Choose the next battle to fight!";
+ for (let where in AREAS)
+ if (is_contested_area(where))
+ gen_action(view, 'area', where);
+ },
+ area: function (where) {
+ start_battle(where, 'coronation');
+ },
+}
+
+// EVENTS
+
+function goto_event_card(event) {
+ switch (event) {
+ case 'herald': goto_herald(); break;
+ case 'pillage': goto_pillage(); break;
+ case 'sea_move': goto_sea_move(); break;
+ case 'truce': goto_truce(); break;
+ case 'victuals': goto_victuals(); break;
+ }
+}
+
+function goto_truce() {
+ log("Truce is in effect!");
+ game.truce = ENEMY[game.active];
+ end_player_turn();
+}
+
+function goto_herald() {
+ game.state = 'herald';
+}
+
+function is_enemy_noble(who) {
+ return is_on_map(who) && block_type(who) == 'nobles' && block_owner(who) == ENEMY[game.active];
+}
+
+states.herald = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to choose a noble.";
+ view.prompt = "Herald: Name an enemy noble to try to convert to your side.";
+ gen_action(view, 'pass');
+ for (let b in BLOCKS)
+ if (is_enemy_noble(b))
+ gen_action(view, 'noble', block_name(b));
+ },
+ noble: function (name) {
+ let who = find_noble(ENEMY[game.active], name);
+ let die = roll_d6();
+ if (die <= 4) {
+ log("Herald roll " + DIE_HIT[die] + " converts " + name + ".");
+ let where = game.location[who];
+ who = swap_blocks(who);
+ if (is_contested_area(where)) {
+ game.attacker[where] = game.active;
+ start_battle(where, 'herald');
+ return;
+ }
+ } else {
+ log("Herald roll " + DIE_MISS[die] + " fails to convert " + name + ".");
+ }
+ end_player_turn();
+ },
+ pass: function () {
+ end_player_turn();
+ },
+}
+
+function goto_victuals() {
+ game.victuals = 3;
+ game.where = null;
+ game.state = 'victuals';
+ game.turn_log = [];
+ clear_undo();
+}
+
+states.victuals = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to build.";
+ view.prompt = "Victuals: Distribute three steps among friendly blocks in one group.";
+ gen_action_undo(view);
+ gen_action(view, 'end_builds');
+ if (game.victuals > 0) {
+ for (let b in BLOCKS) {
+ if (is_on_map(b) && block_owner(b) == game.active)
+ if (game.steps[b] < block_max_steps(b))
+ if (!game.where || game.location[b] == game.where)
+ gen_action(view, 'block', b);
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ game.where = game.location[who];
+ game.turn_log.push([game.where]);
+ ++game.steps[who];
+ --game.victuals;
+ },
+ end_builds: function () {
+ print_turn_log("victuals");
+ clear_undo();
+ delete game.victuals;
+ game.where = null;
+ end_player_turn();
+ },
+ undo: pop_undo
+}
+
+function goto_pillage() {
+ game.state = 'pillage';
+ game.turn_log = [];
+}
+
+states.pillage = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to pillage.";
+ view.prompt = "Pillage: Pillage one enemy group adjacent to a friendly group.";
+ gen_action(view, 'pass');
+ for (let from in AREAS) {
+ if (is_friendly_area(from)) {
+ for (let to of AREAS[from].exits)
+ if (is_contested_area(to) || is_enemy_area(to))
+ gen_action(view, 'area', to);
+ }
+ }
+ },
+ area: function (where) {
+ game.where = where;
+ game.pillage = 2;
+ game.active = ENEMY[game.active];
+ game.state = 'pillage_hits';
+ },
+ pass: function () {
+ end_player_turn();
+ },
+}
+
+function pillage_victims() {
+ function is_candidate(b) {
+ return block_owner(b) == game.active && game.location[b] == game.where;
+ }
+ let max = 0;
+ for (let b in BLOCKS)
+ if (is_candidate(b) && game.steps[b] > max)
+ max = game.steps[b];
+ let list = [];
+ for (let b in BLOCKS)
+ if (is_candidate(b) && game.steps[b] == max)
+ list.push(b);
+ return list;
+}
+
+states.pillage_hits = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to apply pillage hits.";
+ view.prompt = "Pillage: Apply two hits in " + game.where + ".";
+ for (let b of pillage_victims())
+ gen_action(view, 'block', b);
+ },
+ block: function (who) {
+ --game.pillage;
+ reduce_block(who, 'pillage');
+ if (game.pillage == 0 || pillage_victims().length == 0) {
+ game.active = ENEMY[game.active];
+ game.state = 'pillage_builds';
+ game.pillage = 2 - game.pillage;
+ game.from = game.where;
+ game.where = null;
+ }
+ },
+}
+
+states.pillage_builds = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to apply pillage builds.";
+ view.prompt = "Pillage: Add pillaged steps to friendly blocks in the pillaging group.";
+ gen_action_undo(view);
+ gen_action(view, 'end_pillage');
+ if (game.pillage > 0) {
+ if (game.where) {
+ for (let b in BLOCKS)
+ if (block_owner(b) == game.active && game.location[b] == game.where)
+ if (game.steps[b] < block_max_steps(b))
+ gen_action(view, 'block', b);
+ } else {
+ for (let to of AREAS[game.from].exits)
+ for (let b in BLOCKS)
+ if (block_owner(b) == game.active && game.location[b] == to)
+ if (game.steps[b] < block_max_steps(b))
+ gen_action(view, 'block', b);
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ game.where = game.location[who];
+ game.turn_log.push([game.from, game.where]);
+ ++game.steps[who];
+ --game.pillage;
+ // TODO: auto-end pillage builds?
+ // if (game.pillage == 0) end_pillage(game.from);
+ },
+ end_pillage: function () {
+ while (game.pillage > 0) {
+ --game.pillage;
+ game.turn_log.push([game.from]);
+ }
+ end_pillage(game.from);
+ },
+ undo: pop_undo
+}
+
+function end_pillage(where) {
+ print_turn_log("pillages");
+ game.from = null;
+ game.where = null;
+ delete game.pillage;
+ if (is_contested_area(where)) {
+ game.attacker[where] = ENEMY[game.active];
+ start_battle(where, 'pillage');
+ } else {
+ end_player_turn();
+ }
+}
+
+function goto_sea_move() {
+ game.moves = 2;
+ game.from = null;
+ game.where = null;
+ game.state = 'sea_move';
+ game.turn_log = [];
+ clear_undo();
+}
+
+states.sea_move = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to sea move.";
+ view.prompt = "Sea Move: Move one or two blocks from one coastal area to one other friendly coastal area.";
+ gen_action_undo(view);
+ gen_action(view, 'end_move_phase');
+ if (game.moves > 0) {
+ for (let b in BLOCKS) {
+ if (b == NORSE)
+ continue;
+ if (is_in_friendly_coastal_area(b) && block_owner(b) == game.active)
+ if (!game.from || game.location[b] == game.from)
+ gen_action(view, 'block', b);
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ game.who = who;
+ game.state = 'sea_move_to';
+ },
+ end_move_phase: function () {
+ print_turn_log("sea moves");
+ clear_undo();
+ game.moves = 0;
+ game.from = null;
+ game.where = null;
+ end_player_turn();
+ },
+ undo: pop_undo
+}
+
+states.sea_move_to = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to sea move.";
+ view.prompt = "Sea Move: Move one or two blocks from one coastal area to one other friendly coastal area.";
+ gen_action_undo(view);
+ gen_action(view, 'block', game.who);
+ if (game.where) {
+ gen_action(view, 'area', game.where);
+ } else {
+ let from = game.location[game.who];
+ for (let to in AREAS)
+ if (to != from && is_friendly_coastal_area(to))
+ gen_action(view, 'area', to);
+ }
+ },
+ area: function (to) {
+ if (!game.from)
+ game.from = game.location[game.who];
+ game.turn_log.push([game.from, to]);
+ game.location[game.who] = to
+ game.moved[game.who] = true;
+ game.where = to;
+ game.who = null;
+ --game.moves;
+ game.state = 'sea_move';
+ },
+ block: pop_undo,
+ undo: pop_undo
+}
+
+// MOVE PHASE
+
+function goto_move_phase(moves) {
+ game.state = 'move_who';
+ game.moves = moves;
+ game.activated = [];
+ game.main_origin = {};
+ game.main_border = {};
+ game.turn_log = [];
+ clear_undo();
+}
+
+states.move_who = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to move.";
+ view.prompt = "Choose an army to move. " + game.moves + "MP left.";
+ gen_action_undo(view);
+ gen_action(view, 'end_move_phase');
+ for (let b in BLOCKS) {
+ if (b == NORSE && game.active == SCOTLAND && is_on_map(NORSE)) {
+ if (!game.moved[b] && game.moves > 0 && !is_pinned(game.location[NORSE]))
+ gen_action(view, 'block', NORSE);
+ }
+ if (can_block_move(b)) {
+ if (game.moves == 0) {
+ let from = game.location[b];
+ if (game.activated.includes(from))
+ gen_action(view, 'block', b);
+ } else {
+ gen_action(view, 'block', b);
+ }
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ game.who = who;
+ game.state = 'move_where';
+ game.origin = game.location[who];
+ game.last_from = null;
+ game.distance = 0;
+ },
+ end_move_phase: function () {
+ clear_undo();
+ game.moves = 0;
+ print_turn_log("moves");
+ end_player_turn();
+ },
+ undo: pop_undo
+}
+
+function move_block(who, from, to) {
+ game.location[who] = to;
+ game.border_limit[border_id(from, to)] = border_limit(from, to) + 1;
+ game.distance ++;
+ if (is_contested_area(to)) {
+ game.last_used[border_id(from, to)] = game.active;
+ if (!game.attacker[to]) {
+ game.attacker[to] = game.active;
+ game.main_border[to] = from;
+ game.main_origin[to] = game.origin;
+ return ATTACK_MARK;
+ } else {
+ if (game.attacker[to] != game.active || game.main_border[to] != from || game.main_origin[to] != game.origin) {
+ game.reserves.push(who);
+ return RESERVE_MARK;
+ } else {
+ return ATTACK_MARK;
+ }
+ }
+ }
+ return false;
+}
+
+states.move_where = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to move.";
+ view.prompt = "Move " + block_name(game.who) + "."
+ gen_action_undo(view);
+ gen_action(view, 'block', game.who);
+ let from = game.location[game.who];
+ if (game.who == NORSE) {
+ for (let to in AREAS)
+ if (to != from && to != ENGLAND && is_coastal_area(to))
+ if (game.truce != game.active || !is_enemy_area(to))
+ gen_action(view, 'area', to);
+ } else {
+ if (game.distance > 0)
+ gen_action(view, 'area', from);
+ for (let to of AREAS[from].exits) {
+ if (to != game.last_from && can_block_move_to(game.who, from, to))
+ gen_action(view, 'area', to);
+ }
+ }
+ },
+ block: function (who) {
+ if (game.distance == 0)
+ pop_undo();
+ else
+ end_move();
+ },
+ area: function (to) {
+ let from = game.location[game.who];
+ if (to == from) {
+ end_move();
+ return;
+ }
+ if (game.who == NORSE) {
+ log("The Norse move by sea.");
+ game.location[game.who] = to;
+ game.moved[game.who] = true;
+ if (is_contested_area(to)) {
+ if (!game.attacker[to]) {
+ game.turn_log.push([from, to + ATTACK_MARK + " (Norse)"]);
+ game.attacker[to] = game.active;
+ } else {
+ game.turn_log.push([from, to + RESERVE_MARK + " (Norse)"]);
+ game.reserves.push(game.who);
+ }
+ } else {
+ game.turn_log.push([from, to + " (Norse)"]);
+ }
+ --game.moves;
+ game.who = null;
+ game.state = 'move_who';
+ } else {
+ if (game.distance == 0)
+ game.move_buf = [ from ];
+ let mark = move_block(game.who, from, to);
+ if (mark)
+ game.move_buf.push(to + mark);
+ else
+ game.move_buf.push(to);
+ game.last_from = from;
+ if (!can_block_continue(game.who, from, to))
+ end_move();
+ }
+ },
+ undo: pop_undo
+}
+
+function end_move() {
+ if (game.distance > 0) {
+ let to = game.location[game.who];
+ if (game.origin == ENGLAND || to == ENGLAND) {
+ log(game.active + " crosses the Anglo-Scottish border.");
+ game.moves --;
+ } else if (!game.activated.includes(game.origin)) {
+ log(game.active + " activates " + game.origin + ".");
+ game.activated.push(game.origin);
+ game.moves --;
+ }
+ game.moved[game.who] = true;
+ game.turn_log.push(game.move_buf);
+ }
+ delete game.move_buf;
+ game.who = null;
+ game.distance = 0;
+ game.origin = null;
+ game.last_from = null;
+ game.state = 'move_who';
+}
+
+// BATTLE PHASE
+
+function goto_battle_phase() {
+ if (have_contested_areas()) {
+ game.active = game.p1;
+ game.state = 'battle_phase';
+ } else {
+ goto_border_raids();
+ }
+}
+
+states.battle_phase = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to choose a battle.";
+ view.prompt = "Choose the next battle to fight!";
+ for (let where in AREAS)
+ if (is_contested_area(where))
+ gen_action(view, 'area', where);
+ },
+ area: function (where) {
+ start_battle(where, 'battle');
+ },
+}
+
+function start_battle(where, reason) {
+ game.battle_active = game.active;
+ game.battle_reason = reason;
+ game.flash = "";
+ log("");
+ if (reason != 'battle')
+ log("Defection battle in " + where + ".");
+ else
+ log("Battle in " + where + ".");
+ game.where = where;
+ game.battle_round = 0;
+ game.state = 'battle_round';
+ start_battle_round();
+}
+
+function resume_battle() {
+ if (game.victory)
+ return goto_game_over();
+ game.state = 'battle_round';
+ pump_battle_round();
+}
+
+function end_battle() {
+ game.flash = "";
+ game.battle_round = 0;
+ reset_border_limits();
+ game.moved = {};
+
+ game.active = game.attacker[game.where];
+ if (is_contested_area(game.where))
+ log("~ " + ENEMY[game.active] + " wins the battle ~");
+ else if (is_enemy_area(game.where))
+ log("~ " + ENEMY[game.active] + " wins the battle ~");
+ else
+ log("~ " + game.active + " wins the battle ~");
+
+ goto_retreat();
+}
+
+function bring_on_reserves() {
+ for (let b in BLOCKS)
+ if (game.location[b] == game.where)
+ remove_from_array(game.reserves, b);
+}
+
+function start_battle_round() {
+ if (++game.battle_round <= 3) {
+ log("~ Battle round " + game.battle_round + " ~");
+
+ reset_border_limits();
+ game.moved = {};
+
+ if (game.battle_round == 1) {
+ for (let b of CELTIC_BLOCKS)
+ if (game.location[b] == game.where && !is_battle_reserve(b))
+ celtic_unity_roll(b);
+ }
+ if (game.battle_round == 2) {
+ if (count_defenders() == 0) {
+ log("Defending main force was eliminated. The attacker is now the defender.");
+ game.attacker[game.where] = ENEMY[game.attacker[game.where]];
+ } else if (count_attackers() == 0) {
+ log("Attacking main force was eliminated.");
+ }
+ for (let b of CELTIC_BLOCKS)
+ if (game.location[b] == game.where && is_battle_reserve(b))
+ celtic_unity_roll(b);
+ bring_on_reserves();
+ }
+ if (game.battle_round == 3) {
+ bring_on_reserves();
+ }
+
+ pump_battle_round();
+ } else {
+ end_battle();
+ }
+}
+
+function pump_battle_round() {
+ function filter_battle_blocks(ci, is_candidate) {
+ let output = null;
+ for (let b in BLOCKS) {
+ if (is_candidate(b) && !game.moved[b]) {
+ if (block_initiative(b) == ci) {
+ if (!output)
+ output = [];
+ output.push(b);
+ }
+ }
+ }
+ return output;
+ }
+
+ function battle_step(active, initiative, candidate) {
+ game.battle_list = filter_battle_blocks(initiative, candidate);
+ if (game.battle_list) {
+ game.active = active;
+ return true;
+ }
+ return false;
+ }
+
+ if (is_friendly_area(game.where) || is_enemy_area(game.where)) {
+ end_battle();
+ } else if (count_attackers() == 0 || count_defenders() == 0) {
+ start_battle_round();
+ } else {
+ let attacker = game.attacker[game.where];
+ let defender = ENEMY[attacker];
+
+ if (battle_step(defender, 'A', is_defender)) return;
+ if (battle_step(attacker, 'A', is_attacker)) return;
+ if (battle_step(defender, 'B', is_defender)) return;
+ if (battle_step(attacker, 'B', is_attacker)) return;
+ if (battle_step(defender, 'C', is_defender)) return;
+ if (battle_step(attacker, 'C', is_attacker)) return;
+
+ start_battle_round();
+ }
+}
+
+function pass_with_block(b) {
+ game.flash = block_name(b) + " passes.";
+ log(block_name(b) + " passes.");
+ game.moved[b] = true;
+ resume_battle();
+}
+
+function retreat_with_block(b) {
+ game.who = b;
+ game.state = 'retreat_in_battle';
+}
+
+function fire_with_block(b) {
+ game.moved[b] = true;
+ game.hits = 0;
+ let steps = game.steps[b];
+ let fire = block_fire_power(b, game.where);
+ let printed_fire = block_printed_fire_power(b);
+ let rolls = [];
+ for (let i = 0; i < steps; ++i) {
+ let die = roll_d6();
+ if (die <= fire) {
+ rolls.push(DIE_HIT[die]);
+ ++game.hits;
+ } else {
+ rolls.push(DIE_MISS[die]);
+ }
+ }
+ game.flash = block_name(b) + " " + BLOCKS[b].combat;
+ if (fire > printed_fire)
+ game.flash += "+" + (fire - printed_fire);
+ game.flash += "\nfires " + rolls.join(" ") + "\n";
+ if (game.hits == 0)
+ game.flash += "and misses.";
+ else if (game.hits == 1)
+ game.flash += "and scores 1 hit.";
+ else
+ game.flash += "and scores " + game.hits + " hits.";
+ log(game.flash);
+ if (game.hits > 0) {
+ game.active = ENEMY[game.active];
+ goto_battle_hits();
+ } else {
+ resume_battle();
+ }
+}
+
+states.battle_round = {
+ show_battle: true,
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to choose a combat action.";
+ view.prompt = "Fire, retreat, or pass with an army.";
+ for (let b of game.battle_list) {
+ gen_action(view, 'block', b);
+ gen_action(view, 'battle_fire', b);
+ gen_action(view, 'battle_pass', b);
+ if (can_block_retreat(b))
+ gen_action(view, 'battle_retreat', b);
+ }
+ },
+ block: function (who) {
+ fire_with_block(who);
+ },
+ battle_fire: function (who) {
+ fire_with_block(who);
+ },
+ battle_retreat: function (who) {
+ retreat_with_block(who);
+ },
+ battle_pass: function (who) {
+ pass_with_block(who);
+ }
+}
+
+function goto_battle_hits() {
+ game.battle_list = list_victims(game.active);
+ if (game.battle_list.length == 0)
+ resume_battle();
+ else
+ game.state = 'battle_hits';
+}
+
+function apply_hit(who) {
+ game.flash = block_name(who) + " takes a hit.";
+ reduce_block(who, 'combat');
+ game.hits--;
+ if (game.victory)
+ goto_game_over();
+ else if (game.hits == 0)
+ resume_battle();
+ else {
+ game.battle_list = list_victims(game.active);
+ if (game.battle_list.length == 0)
+ resume_battle();
+ else
+ game.flash += " " + game.hits + (game.hits == 1 ? " hit left." : " hits left.");
+ }
+}
+
+function list_victims(p) {
+ let is_candidate = (p == game.attacker[game.where]) ? is_attacker : is_defender;
+ let max = 0;
+ for (let b in BLOCKS)
+ if (is_candidate(b) && game.steps[b] > max)
+ max = game.steps[b];
+ let list = [];
+ for (let b in BLOCKS)
+ if (is_candidate(b) && game.steps[b] == max)
+ list.push(b);
+ return list;
+}
+
+states.battle_hits = {
+ show_battle: true,
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to assign hits.";
+ view.prompt = "Assign " + game.hits + (game.hits != 1 ? " hits" : " hit") + " to your armies.";
+ for (let b of game.battle_list) {
+ gen_action(view, 'block', b);
+ gen_action(view, 'battle_hit', b);
+ }
+ },
+ block: function (who) {
+ apply_hit(who);
+ },
+ battle_hit: function (who) {
+ apply_hit(who);
+ },
+}
+
+function goto_retreat() {
+ game.active = game.attacker[game.where];
+ if (is_contested_area(game.where)) {
+ game.state = 'retreat';
+ game.turn_log = [];
+ clear_undo();
+ } else {
+ goto_regroup();
+ }
+}
+
+states.retreat = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to retreat.";
+ view.prompt = "Retreat: Choose an army to move.";
+ gen_action_undo(view);
+ if (!is_contested_area(game.where))
+ gen_action(view, 'end_retreat');
+ for (let b in BLOCKS)
+ if (game.location[b] == game.where && can_block_retreat(b))
+ gen_action(view, 'block', b);
+ },
+ end_retreat: function () {
+ for (let b in BLOCKS)
+ if (game.location[b] == game.where && block_owner(b) == game.active)
+ eliminate_block(b, 'retreat');
+ print_turn_log("retreats");
+ clear_undo();
+ goto_regroup();
+ },
+ block: function (who) {
+ push_undo();
+ game.who = who;
+ game.state = 'retreat_to';
+ },
+ undo: pop_undo
+}
+
+states.retreat_to = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to retreat.";
+ gen_action_undo(view);
+ gen_action(view, 'block', game.who);
+ let can_retreat = false;
+ if (game.who == NORSE) {
+ view.prompt = "Retreat: Move the army to a friendly coastal area.";
+ for (let to in AREAS) {
+ if (to != game.where && to != ENGLAND && is_friendly_coastal_area(to)) {
+ gen_action(view, 'area', to);
+ can_retreat = true;
+ }
+ }
+ } else {
+ view.prompt = "Retreat: Move the army to a friendly or neutral area.";
+ for (let to of AREAS[game.where].exits) {
+ if (can_block_retreat_to(game.who, to)) {
+ gen_action(view, 'area', to);
+ can_retreat = true;
+ }
+ }
+ }
+ if (!can_retreat)
+ gen_action(view, 'eliminate');
+ },
+ area: function (to) {
+ let from = game.where;
+ if (game.who == NORSE) {
+ game.turn_log.push([from, to + " (Norse)"]);
+ game.location[game.who] = to;
+ } else {
+ game.turn_log.push([from, to]);
+ move_block(game.who, game.where, to);
+ }
+ game.who = null;
+ game.state = 'retreat';
+ },
+ eliminate: function () {
+ eliminate_block(game.who, 'retreat');
+ game.state = 'retreat';
+ },
+ block: pop_undo,
+ undo: pop_undo
+}
+
+states.retreat_in_battle = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to retreat.";
+ gen_action(view, 'undo');
+ if (game.who == NORSE) {
+ view.prompt = "Retreat: Move the army to a friendly coastal area.";
+ for (let to in AREAS)
+ if (to != game.where && to != ENGLAND && is_friendly_coastal_area(to))
+ gen_action(view, 'area', to);
+ } else {
+ view.prompt = "Retreat: Move the army to a friendly or neutral area.";
+ for (let to of AREAS[game.where].exits)
+ if (can_block_retreat_to(game.who, to))
+ gen_action(view, 'area', to);
+ }
+ },
+ area: function (to) {
+ if (game.who == NORSE) {
+ game.flash = "Norse retreat to " + to + ".";
+ log("The Norse retreat to " + to + ".");
+ game.location[game.who] = to;
+ } else {
+ game.flash = block_name(game.who) + " retreats.";
+ log(game.active + " retreats to " + to + ".");
+ move_block(game.who, game.where, to);
+ }
+ game.who = null;
+ resume_battle();
+ },
+ undo: function () {
+ game.who = null;
+ resume_battle();
+ }
+}
+
+function goto_regroup() {
+ game.active = game.attacker[game.where];
+ if (is_enemy_area(game.where))
+ game.active = ENEMY[game.active];
+ game.state = 'regroup';
+ game.turn_log = [];
+ clear_undo();
+}
+
+states.regroup = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to regroup.";
+ view.prompt = "Regroup: Choose an army to move.";
+ gen_action_undo(view);
+ gen_action(view, 'end_regroup');
+ for (let b in BLOCKS)
+ if (game.location[b] == game.where && can_block_regroup(b))
+ gen_action(view, 'block', b);
+ },
+ block: function (who) {
+ push_undo();
+ game.who = who;
+ game.state = 'regroup_to';
+ },
+ end_regroup: function () {
+ print_turn_log("regroups");
+ game.where = null;
+ clear_undo();
+ game.active = game.battle_active;
+ delete game.battle_active;
+ if (game.battle_reason == 'herald') {
+ delete game.battle_reason;
+ end_player_turn();
+ } else if (game.battle_reason == 'pillage') {
+ delete game.battle_reason;
+ end_player_turn();
+ } else if (game.battle_reason == 'coronation') {
+ delete game.battle_reason;
+ resume_coronation();
+ } else {
+ delete game.battle_reason;
+ goto_battle_phase();
+ }
+ },
+ undo: pop_undo
+}
+
+states.regroup_to = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to regroup.";
+ view.prompt = "Regroup: Move the army to a friendly or neutral area.";
+ gen_action_undo(view);
+ gen_action(view, 'block', game.who);
+ if (game.who == NORSE) {
+ for (let to in AREAS)
+ if (to != game.where && to != ENGLAND && is_friendly_coastal_area(to))
+ gen_action(view, 'area', to);
+ } else {
+ for (let to of AREAS[game.where].exits)
+ if (can_block_regroup_to(game.who, to))
+ gen_action(view, 'area', to);
+ }
+ },
+ area: function (to) {
+ let from = game.where;
+ if (game.who == NORSE) {
+ game.turn_log.push([from, to + " (Norse)"]);
+ game.location[game.who] = to;
+ } else {
+ game.turn_log.push([from, to]);
+ move_block(game.who, game.where, to);
+ }
+ game.who = null;
+ game.state = 'regroup';
+ },
+ block: pop_undo,
+ undo: pop_undo
+}
+
+// BORDER RAIDS
+
+function count_non_noble_english_blocks() {
+ let count = 0;
+ for (let b in BLOCKS)
+ if (block_owner(b) == ENGLAND && block_type(b) != 'nobles')
+ if (game.location[b])
+ ++count;
+ return count;
+}
+
+function goto_border_raids() {
+ game.active = ENGLAND;
+ if (is_enemy_area(ENGLAND)) {
+ log("Scotland border raids.");
+ if (count_non_noble_english_blocks() > 0) {
+ game.state = 'border_raids';
+ } else {
+ log("England has no non-noble blocks in play.");
+ }
+ } else {
+ end_game_turn();
+ }
+}
+
+states.border_raids = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for England to choose a border raid victim.";
+ view.prompt = "Border Raids: Eliminate a non-Noble block.";
+ for (let b in BLOCKS)
+ if (block_owner(b) == ENGLAND && block_type(b) != 'nobles')
+ if (game.location[b])
+ gen_action(view, 'block', b);
+ },
+ block: function (who) {
+ eliminate_block(who, 'border_raids')
+ end_game_turn();
+ },
+}
+
+// WINTERING
+
+function goto_winter_turn() {
+ game.moved = {};
+ log("");
+ log("Start Wintering.");
+ english_nobles_go_home();
+}
+
+function is_bruce(who) {
+ return who == E_BRUCE || who == S_BRUCE;
+}
+
+function is_comyn(who) {
+ return who == E_COMYN || who == S_COMYN;
+}
+
+function find_noble_home(who) {
+ for (let where in AREAS)
+ if (AREAS[where].home == block_name(who))
+ return where;
+ return null;
+}
+
+function go_home_to(who, home) {
+ let name = block_name(who);
+ let from = game.location[who];
+ if (from != home) {
+ game.location[who] = home;
+ if (is_contested_area(home)) {
+ game.turn_log.push([name, home + " \u2727"]);
+ who = swap_blocks(who);
+ } else {
+ game.turn_log.push([name, home]);
+ }
+ }
+}
+
+function go_home(who) {
+ go_home_to(who, find_noble_home(who));
+}
+
+function english_nobles_go_home() {
+ game.turn_log = [];
+ game.active = ENGLAND;
+ for (let b in BLOCKS) {
+ if (block_owner(b) == ENGLAND && block_type(b) == 'nobles' && game.location[b])
+ if (!is_bruce(b) && !is_comyn(b))
+ go_home(b);
+ }
+
+ game.going_home = ENGLAND;
+ game.bruce_home = false;
+ game.comyn_home = false;
+ goto_e_bruce();
+}
+
+function scottish_nobles_go_home() {
+ game.turn_log = [];
+ game.active = SCOTLAND;
+ for (let b in BLOCKS) {
+ if (block_owner(b) == SCOTLAND && block_type(b) == 'nobles' && game.location[b])
+ if (!is_bruce(b) && !is_comyn(b))
+ go_home(b);
+ }
+ game.going_home = SCOTLAND;
+ goto_s_bruce();
+}
+
+function goto_e_bruce() {
+ game.who = E_BRUCE;
+ if (game.location[E_BRUCE] && !game.bruce_home)
+ send_bruce_home();
+ else
+ end_bruce();
+}
+
+function goto_s_bruce() {
+ game.who = S_BRUCE;
+ if (game.location[S_BRUCE] && !game.bruce_home)
+ send_bruce_home();
+ else
+ end_bruce();
+}
+
+function send_bruce_home() {
+ game.bruce_home = true;
+ let annan = is_friendly_or_neutral_area("Annan");
+ let carrick = is_friendly_or_neutral_area("Carrick");
+ if (annan && !carrick) {
+ go_home_to(game.who, "Annan");
+ game.who = null;
+ return end_bruce();
+ }
+ if (carrick && !annan) {
+ go_home_to(game.who, "Carrick");
+ game.who = null;
+ return end_bruce();
+ }
+ if (!annan && !carrick) {
+ game.active = ENEMY[game.active];
+ game.who = swap_blocks(game.who);
+ }
+ game.state = 'bruce';
+}
+
+states.bruce = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to move Bruce to one of his home areas.";
+ view.prompt = "Nobles go Home: Move Bruce to one of his home areas.";
+ gen_action(view, 'area', "Annan");
+ gen_action(view, 'area', "Carrick");
+ },
+ area: function (to) {
+ go_home_to(game.who, to);
+ game.who = null;
+ end_bruce();
+ },
+}
+
+function end_bruce() {
+ game.who = null;
+ game.active = game.going_home;
+ if (game.going_home == ENGLAND)
+ goto_e_comyn();
+ else
+ goto_s_comyn();
+}
+
+function goto_e_comyn() {
+ game.who = E_COMYN;
+ if (game.location[E_COMYN] && !game.comyn_home)
+ send_comyn_home();
+ else
+ end_comyn();
+}
+
+function goto_s_comyn() {
+ game.who = S_COMYN;
+ if (game.location[S_COMYN] && !game.comyn_home)
+ send_comyn_home();
+ else
+ end_comyn();
+}
+
+function send_comyn_home() {
+ game.comyn_home = true;
+ let badenoch = is_friendly_or_neutral_area("Badenoch");
+ let lochaber = is_friendly_or_neutral_area("Lochaber");
+ if (badenoch && !lochaber) {
+ go_home_to(game.who, "Badenoch");
+ game.who = null;
+ return end_comyn();
+ }
+ if (lochaber && !badenoch) {
+ go_home_to(game.who, "Lochaber");
+ game.who = null;
+ return end_comyn();
+ }
+ if (!lochaber && !badenoch) {
+ game.active = ENEMY[game.active];
+ game.who = swap_blocks(game.who);
+ }
+ game.state = 'comyn';
+}
+
+states.comyn = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to move Comyn to one of his home areas.";
+ view.prompt = "Nobles go Home: Move Comyn to one of his home areas.";
+ gen_action(view, 'area', "Badenoch");
+ gen_action(view, 'area', "Lochaber");
+ },
+ area: function (to) {
+ go_home_to(game.who, to);
+ game.who = null;
+ end_comyn();
+ },
+}
+
+function end_comyn() {
+ game.who = null;
+ game.active = game.going_home;
+ if (game.active == ENGLAND) {
+ print_turn_log_no_count("English nobles go home:");
+ scottish_nobles_go_home();
+ } else {
+ goto_moray();
+ }
+}
+
+function goto_moray() {
+ delete game.going_home;
+ delete game.bruce_home;
+ delete game.comyn_home;
+
+ if (is_on_map(MORAY)) {
+ game.state = 'moray';
+ game.active = SCOTLAND;
+ game.who = MORAY;
+ } else {
+ goto_scottish_king();
+ }
+}
+
+states.moray = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for Scotland to move Moray.";
+ view.prompt = "Nobles go Home: Move Moray to his home area, remain where he is, or disband.";
+ gen_action(view, 'disband');
+ if (is_within_castle_limit(game.location[MORAY]))
+ gen_action(view, 'area', game.location[MORAY]);
+ if (is_friendly_or_neutral_area("Moray"))
+ gen_action(view, 'area', "Moray");
+ },
+ disband: function () {
+ game.turn_log.push(["Moray", "Pool"]);
+ disband(MORAY);
+ game.who = null;
+ goto_scottish_king();
+ },
+ area: function (to) {
+ let from = game.location[MORAY];
+ if (to != from)
+ game.turn_log.push(["Moray", to]);
+ game.location[MORAY] = to;
+ game.who = null;
+ goto_scottish_king();
+ },
+}
+
+function goto_scottish_king() {
+ print_turn_log_no_count("Scottish nobles go home:");
+
+ if (is_on_map(KING)) {
+ game.state = 'scottish_king';
+ game.active = SCOTLAND;
+ game.who = KING;
+ } else {
+ goto_edward_wintering();
+ }
+}
+
+states.scottish_king = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for Scotland to move the King.";
+ view.prompt = "Scottish King: Move the King to a cathedral, remain where he is, or disband.";
+ gen_action(view, 'disband');
+ if (is_within_castle_limit(game.location[KING]))
+ gen_action(view, 'area', game.location[KING]);
+ for (let where in AREAS) {
+ if (is_cathedral_area(where))
+ if (is_friendly_or_neutral_area(where))
+ gen_action(view, 'area', where);
+ }
+ },
+ disband: function () {
+ log("Scottish King disbands.");
+ disband(KING);
+ game.who = null;
+ goto_edward_wintering();
+ },
+ area: function (to) {
+ if (game.location[KING] != to) {
+ log("Scottish King moves to " + to + ".");
+ game.location[KING] = to;
+ }
+ game.who = null;
+ goto_edward_wintering();
+ },
+}
+
+function is_in_scotland(who) {
+ return is_on_map(who) && game.location[who] != ENGLAND;
+}
+
+function goto_edward_wintering() {
+ if (game.edward == 1 && game.year != 1306 && is_in_scotland(EDWARD) && !game.wintered_last_year) {
+ game.active = ENGLAND;
+ game.who = EDWARD;
+ game.state = 'edward_wintering';
+ return;
+ }
+
+ if (game.edward == 1 && game.year == 1306) {
+ log("Edward I dies.");
+ game.edward = 2;
+ }
+
+ if (is_on_map(EDWARD)) {
+ log("Edward disbands.");
+ disband(EDWARD);
+ }
+
+ game.wintered_last_year = false;
+ goto_english_disbanding();
+}
+
+states.edward_wintering = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for England to winter in Scotland or disband.";
+ view.prompt = "Edward Wintering: Winter in Scotland or disband.";
+ gen_action(view, 'disband');
+ gen_action(view, 'area', game.location[EDWARD]);
+ },
+ disband: function () {
+ log("Edward disbands.");
+ disband(EDWARD);
+ game.who = null;
+ game.wintered_last_year = false;
+ goto_english_disbanding();
+ },
+ area: function (to) {
+ log("Edward winters in " + to + ".");
+ game.who = null;
+ game.wintered_last_year = true;
+ goto_english_disbanding();
+ },
+}
+
+function goto_english_disbanding() {
+ game.active = ENGLAND;
+ game.turn_log = [];
+ let ask = false;
+ for (let b in BLOCKS) {
+ let where = game.location[b];
+
+ // All blocks in England must disband.
+ if (where == ENGLAND) {
+ game.turn_log.push([ENGLAND]);
+ disband(b);
+ }
+
+ if (block_owner(b) == ENGLAND && is_on_map(b)) {
+ // Knights, Archers, & Hobelars must disband except when wintering with Edward.
+ let type = block_type(b);
+ if (type == 'knights' || type == 'archers' || type == 'hobelars') {
+ if (where == game.location[EDWARD]) {
+ ask = true;
+ } else {
+ game.turn_log.push([where]);
+ disband(b);
+ }
+ }
+
+ // Infantry may remain in Scotland subject to Castle Limits or wintering with Edward.
+ if (type == 'infantry') {
+ ask = true;
+ }
+ }
+ }
+ if (ask) {
+ game.state = 'english_disbanding';
+ clear_undo();
+ } else {
+ print_turn_log("disbands");
+ goto_wallace();
+ }
+}
+
+states.english_disbanding = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for England to disband.";
+
+ gen_action_undo(view);
+
+ // Mandatory disbanding
+ let okay_to_end = true;
+ for (let b in BLOCKS) {
+ if (block_owner(b) == ENGLAND && is_on_map(b)) {
+ let where = game.location[b];
+ let type = block_type(b);
+ if (type == 'infantry') {
+ if (!is_within_castle_limit(where) && where != game.location[EDWARD]) {
+ okay_to_end = false;
+ gen_action(view, 'block', b);
+ }
+ }
+ }
+ }
+
+ if (!okay_to_end)
+ {
+ view.prompt = "English Disbanding: Disband units in excess of castle limits.";
+ }
+ else
+ {
+ // Voluntary disbanding
+ view.prompt = "English Disbanding: You may disband units to the pool.";
+ gen_action(view, 'end_disbanding');
+ for (let b in BLOCKS) {
+ if (block_owner(b) == ENGLAND && is_on_map(b)) {
+ let type = block_type(b);
+ if (type == 'knights' || type == 'archers' || type == 'hobelars')
+ gen_action(view, 'block', b);
+ if (type == 'infantry')
+ gen_action(view, 'block', b);
+ }
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ game.turn_log.push([game.location[who]]);
+ disband(who);
+ },
+ end_disbanding: function () {
+ print_turn_log("disbands");
+ clear_undo();
+ goto_wallace();
+ },
+ undo: pop_undo
+}
+
+function goto_wallace() {
+ game.active = SCOTLAND;
+ if (is_on_map(WALLACE) && is_friendly_or_neutral_area("Selkirk")) {
+ game.state = 'wallace';
+ game.who = WALLACE;
+ } else {
+ goto_scottish_disbanding();
+ }
+}
+
+states.wallace = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for Scotland to move Wallace.";
+ view.prompt = "Scottish Disbanding: Move Wallace to Selkirk and gain 2 steps or remain where he is.";
+ gen_action(view, 'area', game.location[WALLACE]);
+ gen_action(view, 'area', "Selkirk");
+ },
+ area: function (to) {
+ if (to == "Selkirk") {
+ if (to != game.location[WALLACE])
+ log("Wallace goes home to " + to + ".");
+ game.steps[WALLACE] = Math.min(block_max_steps(WALLACE), game.steps[WALLACE] + 2);
+ log("Wallace gains 2 steps.");
+ }
+ game.location[WALLACE] = to;
+ game.who = null;
+ goto_scottish_disbanding();
+ },
+}
+
+function goto_scottish_disbanding() {
+ game.active = SCOTLAND;
+ game.turn_log = [];
+ let ask = false;
+ for (let b in BLOCKS) {
+ if (block_owner(b) == SCOTLAND && is_on_map(b)) {
+ let type = block_type(b);
+ if (type != 'nobles')
+ ask = true;
+ }
+ }
+ if (ask) {
+ game.state = 'scottish_disbanding';
+ clear_undo();
+ } else {
+ print_turn_log("disbands");
+ goto_scottish_builds();
+ }
+}
+
+states.scottish_disbanding = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for Scotland to disband.";
+
+ gen_action_undo(view);
+
+ // Mandatory disbanding
+ let okay_to_end = true;
+ for (let b in BLOCKS) {
+ if (block_owner(b) == SCOTLAND && is_on_map(b)) {
+ let where = game.location[b];
+ if (b == WALLACE && where == "Selkirk")
+ continue;
+ let type = block_type(b);
+ if (type != 'nobles') {
+ if (!is_within_castle_limit(where)) {
+ okay_to_end = false;
+ gen_action(view, 'block', b);
+ }
+ }
+ }
+ }
+
+ if (!okay_to_end) {
+ view.prompt = "Scottish Disbanding: Disband units in excess of castle limits.";
+ } else {
+ // Voluntary disbanding
+ view.prompt = "Scottish Disbanding: You may disband units to the pool.";
+ gen_action(view, 'end_disbanding');
+ for (let b in BLOCKS) {
+ if (block_owner(b) == SCOTLAND && is_on_map(b)) {
+ let type = block_type(b);
+ if (type != 'nobles')
+ gen_action(view, 'block', b);
+ }
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ game.turn_log.push([game.location[who]]);
+ disband(who);
+ },
+ end_disbanding: function () {
+ print_turn_log("disbands");
+ clear_undo();
+ goto_scottish_builds();
+ },
+ undo: pop_undo
+}
+
+function goto_scottish_builds() {
+ game.active = SCOTLAND;
+
+ if (!game.french_knights && count_scottish_nobles() >= 8) {
+ log("French knights added to pool.");
+ game.french_knights = true;
+ game.location[FRENCH_KNIGHTS] = S_BAG;
+ game.steps[FRENCH_KNIGHTS] = block_max_steps(FRENCH_KNIGHTS);
+ }
+
+ game.rp = {};
+ for (let where in AREAS) {
+ if (is_friendly_area(where)) {
+ game.rp[where] = castle_limit(where);
+ }
+ }
+ game.state = 'scottish_builds';
+ game.turn_log = [];
+ clear_undo();
+}
+
+states.scottish_builds = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for Scotland to build.";
+ view.prompt = "Scottish Builds: Deploy or reinforce armies.";
+ gen_action_undo(view);
+ gen_action(view, 'end_builds');
+ for (let where in game.rp) {
+ let rp = game.rp[where];
+ if (rp > 0) {
+ for (let b in BLOCKS)
+ if (game.location[b] == where && game.steps[b] < block_max_steps(b))
+ gen_action(view, 'block', b);
+ if (is_under_castle_limit(where))
+ gen_action(view, 'area', where);
+ }
+ }
+ },
+ area: function (where) {
+ let who;
+ if (where == "Lanark" || where == "Badenoch")
+ who = draw_from_bag(S_BAG, [ NORSE, FRENCH_KNIGHTS ]);
+ else
+ who = draw_from_bag(S_BAG);
+ if (who) {
+ clear_undo(); // no undo after drawing from the bag!
+ game.turn_log.push([where]);
+ game.location[who] = where;
+ game.steps[who] = 1;
+ --game.rp[where];
+ }
+ },
+ block: function (who) {
+ push_undo();
+ let where = game.location[who];
+ game.turn_log.push([where]);
+ --game.rp[where];
+ ++game.steps[who];
+ },
+ end_builds: function () {
+ print_turn_log("builds");
+ game.rp = null;
+ clear_undo();
+ goto_english_builds();
+ },
+ undo: pop_undo
+}
+
+function goto_english_builds() {
+ game.active = ENGLAND;
+ game.rp = {};
+ for (let where in AREAS)
+ if (is_friendly_area(where))
+ game.rp[where] = castle_limit(where);
+ game.state = 'english_builds';
+ game.turn_log = [];
+}
+
+states.english_builds = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for England to build.";
+ view.prompt = "English Builds: Deploy or reinforce armies.";
+ gen_action_undo(view);
+ gen_action(view, 'end_builds');
+ for (let where in game.rp) {
+ let rp = game.rp[where];
+ if (rp > 0) {
+ for (let b in BLOCKS) {
+ if (game.location[b] == where && game.steps[b] < block_max_steps(b)) {
+ let type = block_type(b);
+ if (type == 'nobles' || type == 'infantry')
+ gen_action(view, 'block', b);
+ }
+ }
+ }
+ }
+ },
+ block: function (who) {
+ push_undo();
+ let where = game.location[who];
+ game.turn_log.push([where]);
+ --game.rp[where];
+ ++game.steps[who];
+ },
+ end_builds: function () {
+ print_turn_log("builds");
+ game.rp = null;
+ goto_english_feudal_levy();
+ },
+ undo: pop_undo
+}
+
+function goto_english_feudal_levy() {
+ if (!is_on_map(EDWARD)) {
+ let count = Math.ceil(count_blocks_in_area(E_BAG) / 2);
+ log("English feudal levy:\n" + count + " England");
+ deploy_english(count);
+ }
+ end_winter_turn();
+}
+
+function end_winter_turn() {
+ if (++game.year > game.end_year)
+ goto_game_over();
+ else
+ start_year();
+}
+
+function goto_game_over() {
+ if (!game.victory) {
+ let e = count_english_nobles();
+ let s = count_scottish_nobles();
+ if (e > s) {
+ game.victory = "England wins by controlling the most nobles!";
+ game.result = ENGLAND;
+ } else if (s > e) {
+ game.victory = "Scotland wins by controlling the most nobles!";
+ game.result = SCOTLAND;
+ } else {
+ game.log("Tied for majority of nobles.");
+ if (is_on_map(WALLACE)) {
+ game.victory = "Tied for control of nobles. Scotland wins because Wallace is on the map!";
+ game.result = SCOTLAND;
+ } else {
+ game.victory = "Tied for control of nobles. England wins because Wallace is dead or in the draw pool!";
+ game.result = ENGLAND;
+ }
+ }
+ }
+ log(game.victory);
+ game.active = "None";
+ game.state = 'game_over';
+}
+
+states.game_over = {
+ prompt: function (view, current) {
+ view.prompt = game.victory;
+ }
+}
+
+function make_battle_view() {
+ let battle = {
+ EA: [], EB: [], EC: [], ER: [],
+ SA: [], SB: [], SC: [], SR: [],
+ flash: game.flash
+ };
+
+ battle.title = game.attacker[game.where] + " attacks " + game.where;
+ battle.title += " \u2014 round " + game.battle_round + " of 3";
+
+ function fill_cell(cell, owner, fn) {
+ for (let b in BLOCKS)
+ if (game.location[b] == game.where & block_owner(b) == owner && fn(b))
+ cell.push([b, game.steps[b], game.moved[b]?1:0])
+ }
+
+ fill_cell(battle.ER, ENGLAND, b => is_battle_reserve(b));
+ fill_cell(battle.EA, ENGLAND, b => !is_battle_reserve(b) && block_initiative(b) == 'A');
+ fill_cell(battle.EB, ENGLAND, b => !is_battle_reserve(b) && block_initiative(b) == 'B');
+ fill_cell(battle.EC, ENGLAND, b => !is_battle_reserve(b) && block_initiative(b) == 'C');
+ fill_cell(battle.SR, SCOTLAND, b => is_battle_reserve(b));
+ fill_cell(battle.SA, SCOTLAND, b => !is_battle_reserve(b) && block_initiative(b) == 'A');
+ fill_cell(battle.SB, SCOTLAND, b => !is_battle_reserve(b) && block_initiative(b) == 'B');
+ fill_cell(battle.SC, SCOTLAND, b => !is_battle_reserve(b) && block_initiative(b) == 'C');
+
+ return battle;
+}
+
+exports.setup = function (scenario, players) {
+ if (players.length != 2)
+ throw new Error("Invalid player count: " + players.length);
+ game = {
+ attacker: {},
+ border_limit: {},
+ last_used: {},
+ location: {},
+ log: [],
+ main_border: {},
+ main_origin: {},
+ moved: {},
+ moves: 0,
+ prompt: null,
+ reserves: [],
+ show_cards: false,
+ steps: {},
+ who: null,
+ where: null,
+ }
+ if (scenario == "The Bruce")
+ setup_the_bruce();
+ else if (scenario == "Braveheart")
+ setup_braveheart();
+ else if (scenario == "Campaign")
+ setup_campaign();
+ else
+ throw new Error("Unknown scenario:", scenario);
+ start_year();
+ return game;
+}
+
+exports.action = function (state, current, action, arg) {
+ game = state;
+ // TODO: check current, action and argument against action list
+ if (true) {
+ let S = states[game.state];
+ if (action in S)
+ S[action](arg, current);
+ else
+ throw new Error("Invalid action: " + action);
+ }
+ return state;
+}
+
+exports.resign = function (state, current) {
+ game = state;
+ if (game.state != 'game_over') {
+ log("");
+ log(current + " resigned.");
+ game.active = "None";
+ game.state = 'game_over';
+ game.victory = current + " resigned.";
+ game.result = ENEMY[current];
+ }
+}
+
+exports.view = function(state, current) {
+ game = state;
+
+ let view = {
+ log: game.log,
+ year: game.year,
+ edward: game.edward,
+ e_vp: count_english_nobles(),
+ s_vp: count_scottish_nobles(),
+ e_card: (game.show_cards || current == ENGLAND) ? game.e_card : 0,
+ s_card: (game.show_cards || current == SCOTLAND) ? game.s_card : 0,
+ hand: (current == ENGLAND) ? game.e_hand : (current == SCOTLAND) ? game.s_hand : [],
+ who: (game.active == current) ? game.who : null,
+ where: game.where,
+ known: {},
+ secret: { Scotland: {}, England: {} },
+ battle: null,
+ active: game.active,
+ prompt: null,
+ actions: null,
+ };
+
+ states[game.state].prompt(view, current);
+
+ if (states[game.state].show_battle)
+ view.battle = make_battle_view();
+
+ for (let b in BLOCKS) {
+ let a = game.location[b];
+ if (current == block_owner(b) || game.state == 'game_over') {
+ if (a)
+ view.known[b] = [a, game.steps[b], game.moved[b] ? 1 : 0];
+ } else {
+ if (a) {
+ let list = view.secret[block_owner(b)];
+ if (!(a in list))
+ list[a] = [0, 0];
+ list[a][0]++;
+ if (game.moved[b])
+ list[a][1]++;
+ }
+ }
+ }
+
+ return view;
+}
diff --git a/thumbnail.jpg b/thumbnail.jpg
new file mode 100644
index 0000000..3a6264b
--- /dev/null
+++ b/thumbnail.jpg
Binary files differ
diff --git a/turn_marker.jpg b/turn_marker.jpg
new file mode 100644
index 0000000..860ca5f
--- /dev/null
+++ b/turn_marker.jpg
Binary files differ
diff --git a/ui.js b/ui.js
new file mode 100644
index 0000000..5557a18
--- /dev/null
+++ b/ui.js
@@ -0,0 +1,740 @@
+"use strict";
+
+const ENGLAND = "England";
+const SCOTLAND = "Scotland";
+const ENEMY = { Scotland: "England", England: "Scotland" }
+const ENGLAND_BAG = "E. Bag";
+const SCOTLAND_BAG = "S. Bag";
+
+const NOBLES = [
+ "Angus", "Argyll", "Atholl", "Bruce", "Buchan", "Comyn", "Dunbar",
+ "Galloway", "Lennox", "Mar", "Mentieth", "Ross", "Steward"
+];
+
+let block_style = window.localStorage['hammer-of-the-scots/block-style'] || 'oldblocks';
+document.querySelector("body").classList.remove("oldblocks");
+document.querySelector("body").classList.remove("newblocks");
+document.querySelector("body").classList.add(block_style);
+
+function old_block_style() {
+ block_style = 'oldblocks';
+ document.querySelector("body").classList.remove("oldblocks");
+ document.querySelector("body").classList.remove("newblocks");
+ document.querySelector("body").classList.add(block_style);
+ window.localStorage['hammer-of-the-scots/block-style'] = block_style;
+ update_map();
+}
+
+function new_block_style() {
+ block_style = 'newblocks';
+ document.querySelector("body").classList.remove("oldblocks");
+ document.querySelector("body").classList.remove("newblocks");
+ document.querySelector("body").classList.add(block_style);
+ window.localStorage['hammer-of-the-scots/block-style'] = block_style;
+ update_map();
+}
+
+function toggle_blocks() {
+ document.getElementById("map").classList.toggle("hide_blocks");
+}
+
+let game = null;
+
+let ui = {
+ cards: {},
+ areas: {},
+ known: {},
+ secret: { England: {}, Scotland: {} },
+ battle_menu: {},
+ battle_block: {},
+ present: new Set(),
+}
+
+function on_focus_area(evt) {
+ let where = evt.target.area;
+ document.getElementById("status").textContent = where;
+}
+
+function on_blur_area(evt) {
+ document.getElementById("status").textContent = "";
+}
+
+function on_click_area(evt) {
+ let where = evt.target.area;
+ send_action('area', where);
+}
+
+const STEP_TEXT = [ 0, "I", "II", "III", "IIII" ];
+
+function block_name(who) {
+ if (who == "Edward")
+ return game.edward == 1 ? "Edward I" : "Edward II";
+ if (who == "King")
+ return "Scottish King";
+ return BLOCKS[who].name;
+}
+
+function on_focus_secret_block(evt) {
+ let owner = evt.target.owner;
+ let text = (owner == ENGLAND) ? "English" : "Scottish";
+ document.getElementById("status").textContent = text;
+}
+
+function on_blur_secret_block(evt) {
+ document.getElementById("status").textContent = "";
+}
+
+function on_click_secret_block(evt) {
+}
+
+function on_focus_map_block(evt) {
+ let b = evt.target.block;
+ let s = game.known[b][1];
+ let text = block_name(b);
+ text += " " + BLOCKS[b].move + "-" + STEP_TEXT[s] + "-" + BLOCKS[b].combat;
+ if (BLOCKS[b].mortal)
+ text += ' \u271d';
+ document.getElementById("status").textContent = text;
+}
+
+function on_blur_map_block(evt) {
+ document.getElementById("status").textContent = "";
+}
+
+function on_click_map_block(evt) {
+ let b = evt.target.block;
+ send_action('block', b);
+}
+
+function is_battle_reserve(who, list) {
+ for (let [b, s, m] of list)
+ if (who == b)
+ return true;
+ return false;
+}
+
+function on_focus_battle_block(evt) {
+ let b = evt.target.block;
+ let msg = block_name(b);
+ if (is_battle_reserve(b, game.battle.ER))
+ msg = "English Reserve";
+ if (is_battle_reserve(b, game.battle.SR))
+ msg = "Scottish Reserve";
+ if (game.actions && game.actions.battle_fire && game.actions.battle_fire.includes(b))
+ msg = "Fire with " + msg;
+ if (game.actions && game.actions.battle_hit && game.actions.battle_hit.includes(b))
+ msg = "Take hit on " + msg;
+ document.getElementById("status").textContent = msg;
+}
+
+function on_blur_battle_block(evt) {
+ document.getElementById("status").textContent = "";
+}
+
+function on_click_battle_block(evt) {
+ let b = evt.target.block;
+ send_action('block', b);
+}
+
+function on_focus_battle_fire(evt) {
+ document.getElementById("status").textContent =
+ "Fire with " + block_name(evt.target.block);
+}
+
+function on_focus_battle_retreat(evt) {
+ document.getElementById("status").textContent =
+ "Retreat with " + block_name(evt.target.block);
+}
+
+function on_focus_battle_pass(evt) {
+ document.getElementById("status").textContent =
+ "Pass with " + block_name(evt.target.block);
+}
+
+function on_focus_battle_hit(evt) {
+ document.getElementById("status").textContent =
+ "Take hit on " + block_name(evt.target.block);
+}
+
+function on_blur_battle_button(evt) {
+ document.getElementById("status").textContent = "";
+}
+
+function on_click_battle_hit(evt) { send_action('battle_hit', evt.target.block); }
+function on_click_battle_fire(evt) { send_action('battle_fire', evt.target.block); }
+function on_click_battle_retreat(evt) { send_action('battle_retreat', evt.target.block); }
+function on_click_battle_pass(evt) { send_action('battle_pass', evt.target.block); }
+
+function on_click_card(evt) {
+ let c = evt.target.id.split("+")[1] | 0;
+ send_action('play', c);
+}
+
+function on_herald(noble) {
+ send_action('noble', noble);
+}
+
+function on_button_undo(evt) {
+ send_action('undo');
+}
+
+function on_button_play_event(evt) {
+ send_action('play_event');
+}
+
+function on_button_end_move_phase(evt) {
+ send_action('end_move_phase');
+}
+
+function on_button_end_regroup(evt) {
+ send_action('end_regroup');
+}
+
+function on_button_end_retreat(evt) {
+ send_action('end_retreat');
+}
+
+function on_button_eliminate(evt) {
+ send_action('eliminate');
+}
+
+function on_button_disband(evt) {
+ send_action('disband');
+}
+
+function on_button_end_disbanding(evt) {
+ send_action('end_disbanding');
+}
+
+function on_button_end_builds(evt) {
+ send_action('end_builds');
+}
+
+function on_button_end_pillage(evt) {
+ send_action('end_pillage');
+}
+
+function on_button_pass(evt) {
+ send_action('pass');
+}
+
+function on_crown_bruce(evt) {
+ send_action('crown_bruce');
+}
+
+function on_crown_comyn(evt) {
+ send_action('crown_comyn');
+}
+
+function on_return_of_the_king(evt) {
+ send_action('return_of_the_king');
+}
+
+function build_battle_button(menu, b, c, click, enter, img_src) {
+ let img = new Image();
+ img.draggable = false;
+ img.classList.add("action");
+ img.classList.add(c);
+ img.setAttribute("src", img_src);
+ img.addEventListener("click", click);
+ img.addEventListener("mouseenter", enter);
+ img.addEventListener("mouseleave", on_blur_battle_button);
+ img.block = b;
+ menu.appendChild(img);
+}
+
+function build_battle_block(b, block) {
+ let element = document.createElement("div");
+ element.classList.add("block");
+ element.classList.add("known");
+ element.classList.add(BLOCKS[b].owner);
+ element.classList.add("block_" + block.image);
+ element.addEventListener("mouseenter", on_focus_battle_block);
+ element.addEventListener("mouseleave", on_blur_battle_block);
+ element.addEventListener("click", on_click_battle_block);
+ element.block = b;
+ ui.battle_block[b] = element;
+
+ let menu_list = document.createElement("div");
+ menu_list.classList.add("battle_menu_list");
+ build_battle_button(menu_list, b, "hit",
+ on_click_battle_hit, on_focus_battle_hit,
+ "/images/cross-mark.svg");
+ build_battle_button(menu_list, b, "fire",
+ on_click_battle_fire, on_focus_battle_fire,
+ "/images/pointy-sword.svg");
+ build_battle_button(menu_list, b, "retreat",
+ on_click_battle_retreat, on_focus_battle_retreat,
+ "/images/flying-flag.svg");
+ build_battle_button(menu_list, b, "pass",
+ on_click_battle_pass, on_focus_battle_pass,
+ "/images/sands-of-time.svg");
+
+ let menu = document.createElement("div");
+ menu.classList.add("battle_menu");
+ menu.appendChild(element);
+ menu.appendChild(menu_list);
+ ui.battle_menu[b] = menu;
+}
+
+function build_known_block(b, block) {
+ let element = document.createElement("div");
+ element.classList.add("block");
+ element.classList.add("known");
+ element.classList.add(BLOCKS[b].owner);
+ element.classList.add("block_" + block.image);
+ element.addEventListener("mouseenter", on_focus_map_block);
+ element.addEventListener("mouseleave", on_blur_map_block);
+ element.addEventListener("click", on_click_map_block);
+ element.block = b;
+ return element;
+}
+
+function build_secret_block(b, block) {
+ let element = document.createElement("div");
+ element.classList.add("block");
+ element.classList.add("secret");
+ element.classList.add(BLOCKS[b].owner);
+ element.addEventListener("mouseenter", on_focus_secret_block);
+ element.addEventListener("mouseleave", on_blur_secret_block);
+ element.addEventListener("click", on_click_secret_block);
+ element.owner = BLOCKS[b].owner;
+ return element;
+}
+
+function build_map() {
+ let svgmap = document.getElementById("svgmap");
+
+ ui.blocks_element = document.getElementById("blocks");
+ ui.offmap_element = document.getElementById("offmap");
+
+ for (let c = 1; c <= 25; ++c) {
+ ui.cards[c] = document.getElementById("card+"+c);
+ ui.cards[c].addEventListener("click", on_click_card);
+ }
+
+ for (let name in AREAS) {
+ let area = AREAS[name];
+ let element = svgmap.getElementById("area+"+name);
+ if (element) {
+ element.area = name;
+ element.addEventListener("mouseenter", on_focus_area);
+ element.addEventListener("mouseleave", on_blur_area);
+ element.addEventListener("click", on_click_area);
+ ui.areas[name] = element;
+ }
+ ui.secret.England[name] = [];
+ ui.secret.Scotland[name] = [];
+ }
+ ui.secret.England.offmap = [];
+ ui.secret.Scotland.offmap = [];
+
+ for (let b in BLOCKS) {
+ let block = BLOCKS[b];
+ build_battle_block(b, block);
+ ui.known[b] = build_known_block(b, block);
+ ui.secret[BLOCKS[b].owner].offmap.push(build_secret_block(b, block));
+ }
+}
+
+build_map();
+
+function update_steps(b, steps, element) {
+ element.classList.remove("r1");
+ element.classList.remove("r2");
+ element.classList.remove("r3");
+ element.classList.add("r"+(BLOCKS[b].steps - steps));
+}
+
+function layout_blocks(location, north, south) {
+ let wrap = 4;
+ let s = north.length;
+ let k = south.length;
+ let n = s + k;
+ let row, rows = [];
+ let i = 0;
+
+ switch (location) {
+ case ENGLAND_BAG:
+ case SCOTLAND_BAG:
+ wrap = 28;
+ break;
+ case "Selkirk":
+ case "Lothian":
+ case "Dunbar":
+ case "Lanark":
+ case "Lennox":
+ case "Argyll":
+ case "Garmoran":
+ case "Mentieth":
+ wrap = 3;
+ break;
+ case "England":
+ wrap = 5;
+ }
+
+ function new_line() {
+ rows.push(row = []);
+ i = 0;
+ }
+
+ new_line();
+
+ while (north.length > 0) {
+ if (i == wrap)
+ new_line();
+ row.push(north.shift());
+ ++i;
+ }
+
+ // Break early if north and south fit in exactly two rows
+ if (s > 0 && s <= wrap && k > 0 && k <= wrap)
+ new_line();
+
+ while (south.length > 0) {
+ if (i == wrap)
+ new_line();
+ row.push(south.shift());
+ ++i;
+ }
+
+ for (let j = 0; j < rows.length; ++j)
+ for (i = 0; i < rows[j].length; ++i)
+ position_block(location, j, rows.length, i, rows[j].length, rows[j][i]);
+}
+
+function position_block(location, row, n_rows, col, n_cols, element) {
+ let area = AREAS[location];
+ let block_size = 60+6;
+ let padding = 4;
+ let offset = block_size + padding;
+ let row_size = (n_rows-1) * offset;
+ let col_size = (n_cols-1) * offset;
+ let x = area.x - block_size/2;
+ let y = area.y - block_size/2;
+
+ let layout_major = 0.5;
+ let layout_minor = 0.5;
+ switch (location) {
+ case ENGLAND_BAG:
+ case SCOTLAND_BAG:
+ layout_major = 0;
+ layout_minor = 0;
+ break;
+ case ENGLAND:
+ layout_major = 1;
+ layout_minor = 1;
+ break;
+ case "Fife":
+ layout_major = 0.25;
+ layout_minor = 0.5;
+ break;
+ case "Mentieth":
+ layout_major = 0.5;
+ layout_minor = 0.25;
+ break;
+ }
+
+ x -= col_size * layout_major;
+ y -= row_size * layout_minor;
+
+ x += col * offset;
+ y += row * offset;
+
+ element.style.left = (x|0)+"px";
+ element.style.top = (y|0)+"px";
+}
+
+function show_block(element) {
+ if (element.parentElement != ui.blocks_element)
+ ui.blocks_element.appendChild(element);
+}
+
+function hide_block(element) {
+ if (element.parentElement != ui.offmap_element)
+ ui.offmap_element.appendChild(element);
+}
+
+function update_map(player) {
+ let overflow = { England: [], Scotland: [] };
+ let layout = {};
+
+ document.getElementById("turn").setAttribute("class", "turn year_" + game.year);
+
+ for (let area in AREAS)
+ layout[area] = { secret: [], known: [] };
+
+ // Move secret blocks to overflow queue if there are too many in a location
+ for (let area in AREAS) {
+ for (let color of [ENGLAND, SCOTLAND]) {
+ if (game.secret[color]) {
+ let max = game.secret[color][area] ? game.secret[color][area][0] : 0;
+ while (ui.secret[color][area].length > max) {
+ overflow[color].push(ui.secret[color][area].pop());
+ }
+ }
+ }
+ }
+
+ // Add secret blocks if there are too few in a location
+ for (let area in AREAS) {
+ for (let color of [ENGLAND, SCOTLAND]) {
+ if (game.secret[color]) {
+ let max = game.secret[color][area] ? game.secret[color][area][0] : 0;
+ while (ui.secret[color][area].length < max) {
+ if (overflow[color].length > 0) {
+ ui.secret[color][area].push(overflow[color].pop());
+ } else {
+ let element = ui.secret[color].offmap.pop();
+ show_block(element);
+ ui.secret[color][area].push(element);
+ }
+ }
+ }
+ }
+ }
+
+ // Remove any blocks left in the overflow queue
+ for (let color of [ENGLAND, SCOTLAND]) {
+ while (overflow[color].length > 0) {
+ let element = overflow[color].pop();
+ hide_block(element);
+ ui.secret[color].offmap.push(element);
+ }
+ }
+
+ // Hide formerly known blocks
+ for (let b in BLOCKS) {
+ if (!(b in game.known)) {
+ hide_block(ui.known[b]);
+ }
+ }
+
+ // Add secret blocks to layout
+ for (let area in AREAS) {
+ for (let color of [ENGLAND, SCOTLAND]) {
+ let i = 0, n = 0, m = 0;
+ if (game.secret[color] && game.secret[color][area]) {
+ n = game.secret[color][area][0];
+ m = game.secret[color][area][1];
+ }
+ for (let element of ui.secret[color][area]) {
+ if (i++ < n - m)
+ element.classList.remove("moved");
+ else
+ element.classList.add("moved");
+ layout[area].secret.push(element);
+ }
+ }
+ }
+
+ // Add known blocks to layout
+ for (let b in game.known) {
+ let area = game.known[b][0];
+ if (area) {
+ let steps = game.known[b][1];
+ let moved = game.known[b][2];
+ let element = ui.known[b];
+
+ layout[area].known.push(element);
+
+ show_block(element);
+ update_steps(b, steps, element);
+
+ if (moved)
+ element.classList.add("moved");
+ else
+ element.classList.remove("moved");
+ }
+ }
+
+ // Layout blocks on map
+ for (let area in AREAS) {
+ if (player == ENGLAND)
+ layout_blocks(area, layout[area].secret, layout[area].known);
+ else
+ layout_blocks(area, layout[area].known, layout[area].secret);
+ }
+
+ // Mark selections and highlights
+
+ for (let where in AREAS) {
+ if (ui.areas[where]) {
+ ui.areas[where].classList.remove('highlight');
+ ui.areas[where].classList.remove('where');
+ }
+ }
+ if (game.actions && game.actions.area)
+ for (let where of game.actions.area)
+ ui.areas[where].classList.add('highlight');
+ if (game.where)
+ ui.areas[game.where].classList.add('where');
+
+ for (let b in BLOCKS) {
+ ui.known[b].classList.remove('highlight');
+ ui.known[b].classList.remove('selected');
+ }
+ if (!game.battle) {
+ if (game.actions && game.actions.block)
+ for (let b of game.actions.block)
+ ui.known[b].classList.add('highlight');
+ if (game.who)
+ ui.known[game.who].classList.add('selected');
+ }
+}
+
+function update_cards() {
+ let cards = game.hand;
+ for (let c = 1; c <= 25; ++c) {
+ ui.cards[c].classList.remove('enabled');
+ if (cards && cards.includes(c))
+ ui.cards[c].classList.add('show');
+ else
+ ui.cards[c].classList.remove('show');
+ }
+
+ if (game.actions && game.actions.play) {
+ for (let c of game.actions.play)
+ ui.cards[c].classList.add('enabled');
+ }
+
+ if (!game.e_card)
+ document.querySelector("#england_card").className = "small_card card_back";
+ else
+ document.querySelector("#england_card").className = "small_card " + CARDS[game.e_card].image;
+ if (!game.s_card)
+ document.querySelector("#scotland_card").className = "small_card card_back";
+ else
+ document.querySelector("#scotland_card").className = "small_card " + CARDS[game.s_card].image;
+}
+
+function update_battle(player) {
+ function fill_cell(name, list, reserve) {
+ let cell = window[name];
+
+ ui.present.clear();
+
+ for (let [block, steps, moved] of list) {
+ ui.present.add(block);
+
+ if (block == game.who)
+ ui.battle_block[block].classList.add("selected");
+ else
+ ui.battle_block[block].classList.remove("selected");
+
+ ui.battle_block[block].classList.remove("highlight");
+ ui.battle_menu[block].classList.remove('hit');
+ ui.battle_menu[block].classList.remove('fire');
+ ui.battle_menu[block].classList.remove('retreat');
+ ui.battle_menu[block].classList.remove('pass');
+
+ if (game.actions && game.actions.block && game.actions.block.includes(block))
+ ui.battle_block[block].classList.add("highlight");
+ if (game.actions && game.actions.battle_fire && game.actions.battle_fire.includes(block))
+ ui.battle_menu[block].classList.add('fire');
+ if (game.actions && game.actions.battle_retreat && game.actions.battle_retreat.includes(block))
+ ui.battle_menu[block].classList.add('retreat');
+ if (game.actions && game.actions.battle_pass && game.actions.battle_pass.includes(block))
+ ui.battle_menu[block].classList.add('pass');
+ if (game.actions && game.actions.battle_hit && game.actions.battle_hit.includes(block))
+ ui.battle_menu[block].classList.add('hit');
+
+ update_steps(block, steps, ui.battle_block[block], false);
+ if (reserve)
+ ui.battle_block[block].classList.add("secret");
+ else
+ ui.battle_block[block].classList.remove("secret");
+ if (moved)
+ ui.battle_block[block].classList.add("moved");
+ else
+ ui.battle_block[block].classList.remove("moved");
+ if (reserve)
+ ui.battle_block[block].classList.remove("known");
+ else
+ ui.battle_block[block].classList.add("known");
+ }
+
+ for (let b in BLOCKS) {
+ if (ui.present.has(b)) {
+ if (!cell.contains(ui.battle_menu[b]))
+ cell.appendChild(ui.battle_menu[b]);
+ } else {
+ if (cell.contains(ui.battle_menu[b]))
+ cell.removeChild(ui.battle_menu[b]);
+ }
+ }
+ }
+
+ if (player == ENGLAND) {
+ fill_cell("FR", game.battle.ER, true);
+ fill_cell("FA", game.battle.EA, false);
+ fill_cell("FB", game.battle.EB, false);
+ fill_cell("FC", game.battle.EC, false);
+ fill_cell("EA", game.battle.SA, false);
+ fill_cell("EB", game.battle.SB, false);
+ fill_cell("EC", game.battle.SC, false);
+ fill_cell("ER", game.battle.SR, true);
+ } else {
+ fill_cell("ER", game.battle.ER, true);
+ fill_cell("EA", game.battle.EA, false);
+ fill_cell("EB", game.battle.EB, false);
+ fill_cell("EC", game.battle.EC, false);
+ fill_cell("FA", game.battle.SA, false);
+ fill_cell("FB", game.battle.SB, false);
+ fill_cell("FC", game.battle.SC, false);
+ fill_cell("FR", game.battle.SR, true);
+ }
+}
+
+function on_update(state, player) {
+ game = state;
+
+ show_action_button("#undo_button", "undo");
+ show_action_button("#pass_button", "pass");
+ show_action_button("#play_event_button", "play_event");
+ show_action_button("#end_move_phase_button", "end_move_phase");
+ show_action_button("#end_regroup_button", "end_regroup");
+ show_action_button("#end_retreat_button", "end_retreat");
+ show_action_button("#eliminate_button", "eliminate");
+ show_action_button("#disband_button", "disband");
+ show_action_button("#end_disbanding_button", "end_disbanding");
+ show_action_button("#end_builds_button", "end_builds");
+ show_action_button("#end_pillage_button", "end_pillage");
+ show_action_button("#crown_bruce_button", "crown_bruce");
+ show_action_button("#crown_comyn_button", "crown_comyn");
+ show_action_button("#return_of_the_king_button", "return_of_the_king");
+
+ document.getElementById("england_vp").textContent = game.e_vp;
+ document.getElementById("scotland_vp").textContent = game.s_vp;
+
+ update_cards();
+ update_map(player);
+
+ if (game.actions && game.actions.noble) {
+ document.querySelector(".herald").classList.add("show");
+ for (let noble of NOBLES) {
+ let element = document.getElementById("herald+" + noble);
+ if (game.actions.noble.includes(noble))
+ element.classList.add("show");
+ else
+ element.classList.remove("show");
+ }
+ } else {
+ document.querySelector(".herald").classList.remove("show");
+ }
+
+ if (game.battle) {
+ document.querySelector(".battle_header").textContent = game.battle.title;
+ document.querySelector(".battle_message").textContent = game.battle.flash;
+ document.querySelector(".battle").classList.add("show");
+ update_battle(player);
+ } else {
+ document.querySelector(".battle").classList.remove("show");
+ }
+}
+
+drag_element_with_mouse(".battle", ".battle_header");
+drag_element_with_mouse(".herald", ".herald_header");
+scroll_with_middle_mouse(".grid_center", 2);
+
+init_client([ "England", "Scotland" ]);