summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data.js3365
-rw-r--r--play.css545
-rw-r--r--play.html120
-rw-r--r--play.js674
-rw-r--r--rules.js387
-rw-r--r--tools/gendata.js488
-rw-r--r--tools/layout.json3728
-rw-r--r--tools/layout.svg343
-rw-r--r--tools/parse-layout-old.js466
-rw-r--r--tools/parse-layout.js325
-rw-r--r--tools/process-layout.js164
-rw-r--r--tools/rotate_year.sh8
12 files changed, 8610 insertions, 2003 deletions
diff --git a/data.js b/data.js
index 902705d..7053e68 100644
--- a/data.js
+++ b/data.js
@@ -1,828 +1,2545 @@
-"use strict"
-
-var data
-
-;(function () {
-
-function array_insert(array, index, item) {
- for (let i = array.length; i > index; --i)
- array[i] = array[i - 1]
- array[index] = item
-}
-
-function set_add(set, item) {
- let a = 0
- let b = set.length - 1
- while (a <= b) {
- let m = (a + b) >> 1
- let x = set[m]
- if (item < x)
- b = m - 1
- else if (item > x)
- a = m + 1
- else
- return
- }
- array_insert(set, a, item)
-}
-
-function make_index_from_list(list) {
- let map = {}
- for (let i = 0; i < list.length; ++i)
- map[list[i]] = i
- return map
-}
-
-const BOXES = {}
-
-// === GENERALS ===
-
-const generals = [
- { name: "Arnold", owner: "American", strategy: 1, battle: 3, agility: 2, bonus: false },
- { name: "Gates", owner: "American", strategy: 2, battle: 2, agility: 1, bonus: false },
- { name: "Greene", owner: "American", strategy: 1, battle: 4, agility: 2, bonus: true },
- { name: "Lafayette", owner: "American", strategy: 1, battle: 2, agility: 1, bonus: false },
- { name: "Lee", owner: "American", strategy: 2, battle: 1, agility: 1, bonus: false },
- { name: "Lincoln", owner: "American", strategy: 2, battle: 1, agility: 1, bonus: false },
- { name: "Washington", owner: "American", strategy: 1, battle: 5, agility: 2, bonus: true },
-
- { name: "Rochambeau", owner: "French", strategy: 2, battle: 4, agility: 2, bonus: false },
-
- { name: "Burgoyne", owner: "British", strategy: 2, battle: 2, agility: 1, bonus: false },
- { name: "Carleton", owner: "British", strategy: 3, battle: 3, agility: 2, bonus: false },
- { name: "Clinton", owner: "British", strategy: 3, battle: 4, agility: 2, bonus: false },
- { name: "Cornwallis", owner: "British", strategy: 2, battle: 4, agility: 2, bonus: false },
- { name: "Howe", owner: "British", strategy: 3, battle: 6, agility: 3, bonus: false },
-]
-
-const general_index = make_index_from_list(generals.map(x=>x.name))
-
-// === SPACES ===
-
-const spaces = []
-const space_index = {}
-
-const colony_name = [ "Canada", "NH", "NY", "MA", "CT", "RI", "PA", "NJ", "MD", "DE", "VA", "NC", "SC", "GA" ]
-const colony_spaces = colony_name.map(x => [])
-
-const Canada = 0
-const NH = 1
-const NY = 2
-const MA = 3
-const CT = 4
-const RI = 5
-const PA = 6
-const NJ = 7
-const MD = 8
-const DE = 9
-const VA = 10
-const NC = 11
-const SC = 12
-const GA = 13
-
-function box(category, A, x, y) {
- x += 40
- y += 36
- BOXES[A] = { name: A, category: category, x: x, y: y }
-}
-
-function space(colony, name, x, y, type) {
- x += 40
- y += 36
- if (type === "winter-quarters") {
- x += 1
- y += 1
- }
-
- let ix = spaces.length
- space_index[name] = ix
- spaces.push({ name: name, colony, type, port: 0, path: [], wilderness: [], adjacent: [], x, y })
- set_add(colony_spaces[colony], ix)
-}
-
-function not_space(type, name, x, y) {
- // box that's not a space
- x += 40
- y += 36
- let ix = spaces.length
- space_index[name] = ix
- spaces.push({ name, type, x, y })
-}
-
-function line(A, B, type) {
- A = space_index[A]
- B = space_index[B]
- set_add(spaces[A].adjacent, B)
- set_add(spaces[B].adjacent, A)
- set_add(spaces[A][type], B)
- set_add(spaces[B][type], A)
-}
-
-space(Canada, "Fort Detroit", 55, 673, "regular-space")
-space(Canada, "Montreal", 1000, 159, "fortified-port")
-space(Canada, "Quebec", 1122, 57, "fortified-port")
-space(CT, "Hartford", 1183, 749, "winter-quarters")
-space(CT, "New Haven", 1088, 736, "regular-space")
-space(DE, "Wilmington DE", 885, 1079, "winter-quarters")
-space(GA, "Augusta", 140, 2060, "regular-space")
-space(GA, "Savannah", 227, 2271, "regular-space")
-space(GA, "St. Mary's", 180, 2394, "regular-space")
-space(MA, "Barnstable", 1394, 705, "regular-space")
-space(MA, "Boston", 1327, 592, "winter-quarters")
-space(MA, "Falmouth", 1334, 410, "regular-space")
-space(MA, "Lexington Concord", 1218, 628, "regular-space")
-space(MA, "Springfield", 1095, 624, "winter-quarters")
-space(MD, "Baltimore", 769, 1105, "winter-quarters")
-space(MD, "Fort Cumberland", 446, 1098, "regular-space")
-space(MD, "Frederick Town", 646, 1097, "regular-space")
-space(NC, "Charlotte", 215, 1653, "regular-space")
-space(NC, "Gilbert Town", 123, 1568, "regular-space")
-space(NC, "Hillsboro", 484, 1582, "regular-space")
-space(NC, "New Bern", 764, 1670, "regular-space")
-space(NC, "Salem", 308, 1561, "regular-space")
-space(NC, "Wake (Raleigh)", 606, 1671, "regular-space")
-space(NC, "Wilmington NC", 676, 1816, "regular-space")
-space(NH, "Brattleboro", 1102, 486, "regular-space")
-space(NH, "Concord", 1214, 460, "regular-space")
-space(NH, "Norwich", 1125, 342, "winter-quarters")
-space(NJ, "Monmouth", 998, 1074, "regular-space")
-space(NJ, "Morristown", 864, 831, "regular-space")
-space(NJ, "New Brunswick", 961, 942, "regular-space")
-space(NY, "Albany", 965, 626, "winter-quarters")
-space(NY, "Fort Niagara", 461, 526, "regular-space")
-space(NY, "Fort Stanwix", 877, 483, "winter-quarters")
-space(NY, "Genesee", 668, 582, "regular-space")
-space(NY, "Long Island", 1147, 868, "regular-space")
-space(NY, "New York", 1024, 838, "winter-quarters")
-space(NY, "Oswego", 768, 424, "regular-space")
-space(NY, "Saratoga", 992, 496, "regular-space")
-space(NY, "Ticonderoga", 993, 355, "winter-quarters")
-space(NY, "Westchester", 955, 747, "regular-space")
-space(PA, "Bassett Town", 147, 984, "regular-space")
-space(PA, "Harrisburg", 555, 880, "regular-space")
-space(PA, "Philadelphia", 846, 961, "fortified-port")
-space(PA, "Pittsburgh", 439, 958, "winter-quarters")
-space(PA, "Reading", 684, 900, "regular-space")
-space(PA, "Wyoming Valley", 685, 747, "winter-quarters")
-space(PA, "York", 589, 992, "regular-space")
-space(RI, "Newport", 1289, 736, "winter-quarters")
-space(SC, "Camden", 346, 1773, "regular-space")
-space(SC, "Charleston", 444, 2050, "fortified-port")
-space(SC, "Cheraw", 496, 1795, "regular-space")
-space(SC, "Eutaw Springs", 404, 1905, "regular-space")
-space(SC, "Fort Prince George", 74, 1773, "regular-space")
-space(SC, "Georgetown", 574, 1915, "regular-space")
-space(SC, "Ninety Six", 222, 1932, "regular-space")
-space(VA, "Abingdon", 61, 1451, "regular-space")
-space(VA, "Alexandria", 653, 1217, "winter-quarters")
-space(VA, "Charlottesville", 434, 1257, "winter-quarters")
-space(VA, "Fincastle", 349, 1402, "regular-space")
-space(VA, "Fort Chiswell", 212, 1408, "regular-space")
-space(VA, "Lynch's Ferry", 486, 1444, "regular-space")
-space(VA, "Norfolk", 781, 1450, "winter-quarters")
-space(VA, "Petersburg", 634, 1446, "regular-space")
-space(VA, "Point Pleasant", 132, 1218, "regular-space")
-space(VA, "Richmond", 608, 1323, "winter-quarters")
-space(VA, "Yorktown", 767, 1317, "regular-space")
-
-not_space("box", "British Leader Reinforcements", 1425, 1745)
-not_space("box", "French Reinforcements", 150, 340)
-not_space("box", "American Leader Reinforcements", 400, 310)
-not_space("box", "Captured Generals", 1463, 80)
-not_space("box", "Continental Congress Dispersed", 545, 350)
-
-box("SEA", "Sea1", 1277, 65, "blockade")
-box("SEA", "Sea2", 1469, 514, "blockade")
-box("SEA", "Sea3", 1213, 981, "blockade")
-box("SEA", "Sea4", 1058, 1174, "blockade")
-box("SEA", "Sea5", 947, 1395, "blockade")
-box("SEA", "Sea6", 637, 2027, "blockade")
-box("SEA", "Sea7", 359, 2358, "blockade")
-
-box("ALLIANCE", "French Alliance Track 0", 898, 2240)
-box("ALLIANCE", "French Alliance Track 1", 964, 2240)
-box("ALLIANCE", "French Alliance Track 2", 1030, 2240)
-box("ALLIANCE", "French Alliance Track 3", 1096, 2240)
-box("ALLIANCE", "French Alliance Track 4", 1162, 2240)
-box("ALLIANCE", "French Alliance Track 5", 1228, 2240)
-box("ALLIANCE", "French Alliance Track 6", 1294, 2240)
-box("ALLIANCE", "French Alliance Track 7", 1360, 2240)
-box("ALLIANCE", "French Alliance Track 8", 1426, 2240)
-box("ALLIANCE", "French Alliance Track 9", 1492, 2240)
-
-box("TURN", "Game Turn 1775", 898, 2370)
-box("TURN", "Game Turn 1776", 964, 2370)
-box("TURN", "Game Turn 1777", 1030, 2370)
-box("TURN", "Game Turn 1778", 1096, 2370)
-box("TURN", "Game Turn 1779", 1162, 2370)
-box("TURN", "Game Turn 1780", 1228, 2370)
-box("TURN", "Game Turn 1781", 1294, 2370)
-box("TURN", "Game Turn 1782", 1360, 2370)
-box("TURN", "Game Turn 1783", 1426, 2370)
-
-box("CONTROL", "Canada", 1376, 967)
-box("CONTROL", "NH", 1458, 1006)
-box("CONTROL", "NY", 1375, 1081)
-box("CONTROL", "MA", 1491, 1081)
-box("CONTROL", "CT", 1455, 1156)
-box("CONTROL", "RI", 1533, 1156)
-box("CONTROL", "PA", 1299, 1194)
-box("CONTROL", "NJ", 1376, 1189)
-box("CONTROL", "MD", 1299, 1266)
-box("CONTROL", "DE", 1376, 1266)
-box("CONTROL", "VA", 1241, 1337)
-box("CONTROL", "NC", 1260, 1407)
-box("CONTROL", "SC", 1212, 1479)
-box("CONTROL", "GA", 1164, 1550)
-
-function wilderness(A, B) {
- line(A, B, "wilderness")
-}
-
-function path(A, B) {
- line(A, B, "path")
-}
-
-function sea(space, zone) {
- spaces[space_index[space]].port = zone
-}
-
-wilderness("Quebec", "Falmouth")
-wilderness("Fort Detroit", "Bassett Town")
-wilderness("Bassett Town", "Point Pleasant")
-
-path("Quebec", "Montreal")
-path("Montreal", "Ticonderoga")
-path("Montreal", "Oswego")
-path("Oswego", "Fort Niagara")
-path("Oswego", "Fort Stanwix")
-path("Fort Niagara", "Fort Detroit")
-path("Fort Niagara", "Genesee")
-path("Ticonderoga", "Norwich")
-path("Ticonderoga", "Saratoga")
-path("Norwich", "Brattleboro")
-path("Norwich", "Concord")
-path("Concord", "Falmouth")
-path("Concord", "Brattleboro")
-path("Saratoga", "Brattleboro")
-path("Saratoga", "Albany")
-path("Brattleboro", "Springfield")
-path("Fort Stanwix", "Albany")
-path("Albany", "Springfield")
-path("Lexington Concord", "Springfield")
-path("Lexington Concord", "Boston")
-path("Falmouth", "Boston")
-path("Barnstable", "Boston")
-path("Newport", "Boston")
-path("Newport", "Hartford")
-path("Springfield", "Hartford")
-path("New Haven", "Hartford")
-path("New Haven", "New York")
-path("New Haven", "Westchester")
-path("New York", "Westchester")
-path("New York", "Long Island")
-path("Newport", "Lexington Concord")
-path("Albany", "Westchester")
-path("Fort Stanwix", "Genesee")
-path("Genesee", "Wyoming Valley")
-path("Fort Niagara", "Pittsburgh")
-path("Morristown", "Westchester")
-path("Morristown", "Wyoming Valley")
-path("Morristown", "Reading")
-path("Morristown", "New Brunswick")
-path("Morristown", "New York")
-path("New York", "New Brunswick")
-path("Monmouth", "New Brunswick")
-path("Philadelphia", "New Brunswick")
-path("Monmouth", "Philadelphia")
-path("Reading", "Philadelphia")
-path("Wyoming Valley", "Reading")
-path("Wilmington DE", "Philadelphia")
-path("Wilmington DE", "Baltimore")
-path("Bassett Town", "Pittsburgh")
-path("Fort Cumberland", "Pittsburgh")
-path("Harrisburg", "Pittsburgh")
-path("Harrisburg", "York")
-path("Reading", "York")
-path("Harrisburg", "Reading")
-path("Frederick Town", "York")
-path("Frederick Town", "Baltimore")
-path("Frederick Town", "Alexandria")
-path("Frederick Town", "Charlottesville")
-path("Frederick Town", "Fort Cumberland")
-path("Richmond", "Alexandria")
-path("Richmond", "Yorktown")
-path("Richmond", "Petersburg")
-path("Richmond", "Lynch's Ferry")
-path("Richmond", "Charlottesville")
-path("Richmond", "Norfolk")
-path("Fincastle", "Charlottesville")
-path("Fincastle", "Lynch's Ferry")
-path("Fincastle", "Fort Chiswell")
-path("Point Pleasant", "Fort Chiswell")
-path("Abingdon", "Fort Chiswell")
-path("Abingdon", "Gilbert Town")
-path("Fort Prince George", "Gilbert Town")
-path("Charlotte", "Gilbert Town")
-path("Charlotte", "Salem")
-path("Hillsboro", "Salem")
-path("Cheraw", "Salem")
-path("Lynch's Ferry", "Salem")
-path("Charlotte", "Camden")
-path("Abingdon", "Fort Prince George")
-path("New Bern", "Norfolk")
-path("Petersburg", "Norfolk")
-path("Petersburg", "Wake (Raleigh)")
-path("New Bern", "Wake (Raleigh)")
-path("Hillsboro", "Wake (Raleigh)")
-path("Petersburg", "Hillsboro")
-path("Petersburg", "Lynch's Ferry")
-path("Wilmington NC", "Wake (Raleigh)")
-path("Wilmington NC", "Cheraw")
-path("Wilmington NC", "Georgetown")
-path("Cheraw", "Georgetown")
-path("Cheraw", "Camden")
-path("Ninety Six", "Fort Prince George")
-path("Ninety Six", "Camden")
-path("Ninety Six", "Augusta")
-path("Eutaw Springs", "Camden")
-path("Eutaw Springs", "Charleston")
-path("Georgetown", "Charleston")
-path("Savannah", "Charleston")
-path("Alexandria", "Baltimore")
-path("Savannah", "Augusta")
-path("Savannah", "St. Mary's")
-path("Charlottesville", "Lynch's Ferry")
-
-sea("Quebec", 1)
-sea("Montreal", 1)
-
-sea("Falmouth", 2)
-sea("Boston", 2)
-sea("Barnstable", 2)
-sea("Newport", 2)
-
-sea("New Haven", 3)
-sea("New York", 3)
-sea("Long Island", 3)
-
-sea("Philadelphia", 4)
-sea("Wilmington DE", 4)
-
-sea("Baltimore", 5)
-sea("Alexandria", 5)
-sea("Yorktown", 5)
-sea("Norfolk", 5)
-
-sea("New Bern", 6)
-sea("Wilmington NC", 6)
-sea("Charleston", 6)
-
-sea("Savannah", 7)
-sea("St. Mary's", 7)
-
-// === CARDS ===
-
-const CARD_3_OPS = { title: "3 OPS", type: "ops", count: 3 }
-const CARD_2_OPS = { title: "2 OPS", type: "ops", count: 2 }
-const CARD_1_OPS = { title: "1 OPS", type: "ops", count: 1 }
-
-const cards = [
- null,
-
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
- CARD_3_OPS,
-
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
- CARD_2_OPS,
-
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
- CARD_1_OPS,
-
- /* 67 */
- {
- title: "Minor Campaign",
- type: "campaign",
- count: 2,
- },
-
- /* 68 */
- {
- title: "Minor Campaign",
- type: "campaign",
- count: 2,
- },
-
- /* 69 */
- {
- title: "Minor Campaign",
- type: "campaign",
- count: 2,
- },
-
- /* 70 */
- {
- title: "Major Campaign",
- type: "campaign",
- count: 3,
- },
-
- /* 71 */
- {
- full_title: "North's Government Falls - The War Ends in 1779",
- title: "The War Ends in 1779",
- type: "mandatory-event",
- event: "the_war_ends",
- year: 1779,
- },
-
- /* 72 */
- {
- full_title: "North's Government Falls - The War Ends in 1780",
- title: "The War Ends in 1780",
- type: "mandatory-event",
- event: "the_war_ends",
- year: 1780,
- },
-
- /* 73 */
- {
- full_title: "North's Government Falls - The War Ends in 1781",
- title: "The War Ends in 1781",
- type: "mandatory-event",
- event: "the_war_ends",
- year: 1781,
- },
-
- /* 74 */
- {
- full_title: "North's Government Falls - The War Ends in 1782",
- title: "The War Ends in 1782",
- type: "mandatory-event",
- event: "the_war_ends",
- year: 1782,
- },
-
- /* 75 */
- {
- full_title: "North's Government Falls - The War Ends in 1783",
- title: "The War Ends in 1783",
- type: "mandatory-event",
- event: "the_war_ends",
- year: 1783,
- },
-
- /* 76 */
- {
- title: "Henry Know Continental Artillery Commander",
- type: "american-battle",
- },
-
- /* 77 */
- {
- title: "Jane McCrea Indian Atrocity Sparks Outrage",
- type: "american-event",
- event: "place_american_pc",
- count: 2,
- once: true,
- },
-
- /* 78 */
- {
- title: "Iroquois Uprising!",
- type: "british-event",
- event: "remove_american_pc_from_non_port",
- where: [ NH, NY, PA ],
- count: 2,
- },
-
- /* 79 */
- {
- title: "Joseph Brant Leads an Iroquois Raid",
- type: "british-event",
- event: "remove_american_pc_from_non_port",
- where: [ NH, NY, PA ],
- count: 2,
- },
-
- /* 80 */
- {
- title: "Lt. Colonel Simcoe's Queen's Rangers",
- type: "british-event",
- event: "remove_american_pc_within_two_spaces_of_a_british_general",
- count: 2,
- },
-
- /* 81 */
- {
- title: "D'Estaing Sails for the Caribbean",
- type: "british-event",
- when: "after_french_alliance",
- event: "remove_french_navy",
- },
-
- /* 82 */
- {
- title: "Banastre Tarleton's Waxhaws Massacre",
- type: "british-event-or-battle",
- event: "remove_american_cu",
- },
-
- /* 83 */
- {
- title: "Lord George Germaine Offers Royal Amnesty",
- type: "british-event",
- event: "remove_american_pc",
- count: 2,
- },
-
- /* 84 */
- {
- title: "George Rogers Clark Leads a Western Offensive",
- type: "american-event",
- event: "remove_random_british_card",
- },
-
- /* 85 */
- {
- title: "Don Bernardo Galvez Captures Pensacola",
- type: "american-event",
- when: "european_war_in_effect",
- event: "remove_british_cu",
- count: 2,
- },
-
- /* 86 */
- {
- title: "Baron von Steuben Trains the Continental Army",
- type: "american-event",
- event: "baron_von_steuben_trains_the_continental_army",
- },
-
- /* 87 */
- {
- title: "Lord North Offers a Royal Amnesty",
- type: "british-event",
- event: "remove_american_pc",
- count: 4,
- once: true,
- },
-
- /* 88 */
- {
- title: "The Swamp Fox, Francis Marion",
- type: "american-event",
- event: "remove_british_pc_from",
- where: [ NC, SC, GA ],
- count: 2,
- },
-
- /* 89 */
- {
- title: "The Gamecock: Thomas Sumter",
- type: "american-event",
- event: "remove_british_pc_from",
- where: [ NC, SC, GA ],
- count: 2,
- },
-
- /* 90 */
- {
- title: "Josiah Martin Rallies North Carolina Loyalists",
- type: "british-event",
- event: "remove_american_pc_from",
- where: [ NC ],
- count: 2,
- },
-
- /* 91 */
- {
- title: 'Thomas Paine Publishes Pamphlets "Common Sense" and "The American Crisis"',
- type: "american-event",
- event: "place_american_pc_in",
- where: [ NH, NY, MA, CT, RI, PA, NJ, MD, DE, VA, NC, SC, GA ],
- count: 3,
- once: true,
- },
-
- /* 92 */
- {
- title: "Nathan Hale, American Martyr",
- type: "american-event",
- event: "place_american_pc",
- count: 2,
- once: true,
- },
-
- /* 93 */
- {
- title: "John Glover's Marblehead Regiment",
- type: "american-event",
- event: "john_glovers_marblehead_regiment",
- },
-
- /* 94 */
- {
- title: "Pennsylvania and New Jersey Line Mutinies",
- type: "british-event",
- event: "pennsylvania_and_new_jersey_line_mutinies",
- },
-
- /* 95 */
- {
- title: "William Pitt Urges Peace Talks",
- type: "british-event",
- when: "before_french_alliance",
- event: "remove_american_pc",
- count: 2,
- reshuffle: "if_played",
- },
-
- /* 96 */
- {
- title: "Hortelez et Cie: Clandestine French and Spanish Aid",
- type: "american-event",
- when: "before_french_alliance",
- event: "advance_french_alliance",
- reshuffle: "if_discarded",
- count: 2,
- },
-
- /* 97 */
- {
- title: "Admiral Suffren Wins a Naval Victory",
- type: "american-event",
- when: "after_french_alliance",
- event: "remove_random_british_card",
- },
-
- /* 98 */
- {
- title: '"Mad" Anthony Wayne',
- type: "american-battle",
- },
-
- /* 99 */
- {
- title: "Declaration of Independence",
- type: "mandatory-event",
- event: "declaration_of_independence",
- once: true,
- reshuffle: "if_played",
- tournament: true,
- },
-
- /* 100 */
- {
- title: "Benedict Arnold's Treason Undermines the Patriot Cause",
- type: "british-battle",
- event: "remove_benedict_arnold",
- once: true,
- },
-
- /* 101 */
- {
- title: "Benjamin Franklin: Minister to France",
- type: "mandatory-event",
- event: "advance_french_alliance",
- count: 4,
- once: true,
- tournament: true,
- },
-
- /* 102 */
- {
- title: "Admiral Rodney Captures St. Eustatius",
- type: "british-event",
- event: "remove_random_american_card",
- when: "european_war_in_effect",
- once: true,
- },
-
- /* 103 */
- {
- title: "Thaddeus Kosciuszco Constructs Engineering Works",
- type: "american-battle",
- },
-
- /* 104 */
- {
- title: "Light Horse Harry Lee",
- type: "american-battle",
- },
-
- /* 105 */
- {
- title: "Morgan's Riflemen",
- type: "american-battle",
- },
-
- /* 106 */
- {
- title: "John Paul Jones' Shipping Raids",
- type: "american-event",
- event: "remove_random_british_card",
- },
-
- /* 107 */
- {
- title: "British Light Infantry",
- type: "british-battle",
- },
-
- /* 108 */
- {
- title: "Lord Sandwich Coastal Raids",
- type: "british-event",
- event: "lord_sandwich_coastal_raids",
+const data = {
+ "layout": {
+ "sea": [
+ [
+ 1268,
+ 60,
+ 97,
+ 83
+ ],
+ [
+ 1461,
+ 508,
+ 97,
+ 84
+ ],
+ [
+ 1205,
+ 975,
+ 97,
+ 83
+ ],
+ [
+ 1049,
+ 1169,
+ 97,
+ 83
+ ],
+ [
+ 938,
+ 1389,
+ 97,
+ 83
+ ],
+ [
+ 629,
+ 2022,
+ 97,
+ 83
+ ],
+ [
+ 351,
+ 2352,
+ 97,
+ 83
+ ]
+ ],
+ "colony": [
+ [
+ 1416,
+ 1004
+ ],
+ [
+ 1498,
+ 1043
+ ],
+ [
+ 1415,
+ 1118
+ ],
+ [
+ 1532,
+ 1117
+ ],
+ [
+ 1495,
+ 1192
+ ],
+ [
+ 1573,
+ 1192
+ ],
+ [
+ 1339,
+ 1230
+ ],
+ [
+ 1416,
+ 1225
+ ],
+ [
+ 1339,
+ 1303
+ ],
+ [
+ 1416,
+ 1303
+ ],
+ [
+ 1282,
+ 1373
+ ],
+ [
+ 1300,
+ 1444
+ ],
+ [
+ 1252,
+ 1515
+ ],
+ [
+ 1204,
+ 1587
+ ]
+ ],
+ "french_alliance_track": {
+ "0": [
+ 937,
+ 2277
+ ],
+ "1": [
+ 1003,
+ 2277
+ ],
+ "2": [
+ 1069,
+ 2277
+ ],
+ "3": [
+ 1135,
+ 2277
+ ],
+ "4": [
+ 1202,
+ 2277
+ ],
+ "5": [
+ 1268,
+ 2277
+ ],
+ "6": [
+ 1334,
+ 2277
+ ],
+ "7": [
+ 1400,
+ 2277
+ ],
+ "8": [
+ 1467,
+ 2277
+ ],
+ "9": [
+ 1533,
+ 2277
+ ]
+ },
+ "turn": {
+ "1775": [
+ 936,
+ 2404
+ ],
+ "1776": [
+ 1002,
+ 2404
+ ],
+ "1777": [
+ 1068,
+ 2404
+ ],
+ "1778": [
+ 1134,
+ 2404
+ ],
+ "1779": [
+ 1201,
+ 2404
+ ],
+ "1780": [
+ 1267,
+ 2404
+ ],
+ "1781": [
+ 1333,
+ 2404
+ ],
+ "1782": [
+ 1399,
+ 2404
+ ],
+ "1783": [
+ 1465,
+ 2404
+ ]
+ },
+ "card_box": {
+ "BRC": [
+ 1004,
+ 2054
+ ],
+ "ARC1": [
+ 1237,
+ 2054
+ ],
+ "ARC2": [
+ 1470,
+ 2054
+ ],
+ "War Ends Card": [
+ 1166,
+ 1778
+ ]
+ },
+ "box": {
+ "British Reinforcement Box": [
+ 1358,
+ 1673,
+ 214,
+ 206
+ ],
+ "American Leader Reinforcements": [
+ 294,
+ 258,
+ 214,
+ 206
+ ],
+ "French Reinforcements": [
+ 63,
+ 258,
+ 214,
+ 207
+ ],
+ "Continental Congress Dispersed": [
+ 542,
+ 332,
+ 88,
+ 104
+ ],
+ "Captured Generals": [
+ 1400,
+ 46,
+ 205,
+ 136
+ ]
+ }
},
-
- /* 109 */
- {
- title: "Edward Bancroft, British Double Agent",
- type: "british-event",
- event: "remove_random_american_card",
+ "spaces": [
+ {
+ "name": "Charleston",
+ "type": "fortified_port",
+ "adjacent": [
+ 30,
+ 40,
+ 59
+ ],
+ "path": [
+ 30,
+ 40,
+ 59
+ ],
+ "wilderness": [],
+ "port": 5,
+ "colony": 12,
+ "x": 484,
+ "y": 2086
+ },
+ {
+ "name": "Montreal",
+ "type": "fortified_port",
+ "adjacent": [
+ 3,
+ 18,
+ 53
+ ],
+ "path": [
+ 3,
+ 18,
+ 53
+ ],
+ "wilderness": [],
+ "port": 0,
+ "colony": 0,
+ "x": 1040,
+ "y": 195
+ },
+ {
+ "name": "Philadelphia",
+ "type": "fortified_port",
+ "adjacent": [
+ 19,
+ 47,
+ 50,
+ 56
+ ],
+ "path": [
+ 19,
+ 47,
+ 50,
+ 56
+ ],
+ "wilderness": [],
+ "port": 3,
+ "colony": 6,
+ "x": 886,
+ "y": 998
+ },
+ {
+ "name": "Quebec",
+ "type": "fortified_port",
+ "adjacent": [
+ 1,
+ 31
+ ],
+ "path": [
+ 1
+ ],
+ "wilderness": [
+ 31
+ ],
+ "port": 0,
+ "colony": 0,
+ "x": 1163,
+ "y": 94
+ },
+ {
+ "name": "Albany",
+ "type": "winter_quarters",
+ "adjacent": [
+ 9,
+ 17,
+ 58,
+ 62
+ ],
+ "path": [
+ 9,
+ 17,
+ 58,
+ 62
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 1007,
+ "y": 664
+ },
+ {
+ "name": "Alexandria",
+ "type": "winter_quarters",
+ "adjacent": [
+ 6,
+ 16,
+ 38
+ ],
+ "path": [
+ 6,
+ 16,
+ 38
+ ],
+ "wilderness": [],
+ "port": 4,
+ "colony": 10,
+ "x": 694,
+ "y": 1254
+ },
+ {
+ "name": "Baltimore",
+ "type": "winter_quarters",
+ "adjacent": [
+ 5,
+ 19,
+ 38
+ ],
+ "path": [
+ 5,
+ 19,
+ 38
+ ],
+ "wilderness": [],
+ "port": 4,
+ "colony": 8,
+ "x": 811,
+ "y": 1143
+ },
+ {
+ "name": "Boston",
+ "type": "winter_quarters",
+ "adjacent": [
+ 12,
+ 23,
+ 31,
+ 44
+ ],
+ "path": [
+ 12,
+ 23,
+ 31,
+ 44
+ ],
+ "wilderness": [],
+ "port": 1,
+ "colony": 3,
+ "x": 1368,
+ "y": 629
+ },
+ {
+ "name": "Charlottesville",
+ "type": "winter_quarters",
+ "adjacent": [
+ 16,
+ 32,
+ 38,
+ 46
+ ],
+ "path": [
+ 16,
+ 32,
+ 38,
+ 46
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 475,
+ "y": 1294
+ },
+ {
+ "name": "Fort Stanwix",
+ "type": "winter_quarters",
+ "adjacent": [
+ 4,
+ 39,
+ 53
+ ],
+ "path": [
+ 4,
+ 39,
+ 53
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 918,
+ "y": 521
+ },
+ {
+ "name": "Hartford",
+ "type": "winter_quarters",
+ "adjacent": [
+ 10,
+ 12,
+ 17
+ ],
+ "path": [
+ 10,
+ 12,
+ 17
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 4,
+ "x": 1224,
+ "y": 786
+ },
+ {
+ "name": "New York",
+ "type": "winter_quarters",
+ "adjacent": [
+ 45,
+ 48,
+ 50,
+ 51,
+ 62
+ ],
+ "path": [
+ 45,
+ 48,
+ 50,
+ 51,
+ 62
+ ],
+ "wilderness": [],
+ "port": 2,
+ "colony": 2,
+ "x": 1065,
+ "y": 875
+ },
+ {
+ "name": "Newport",
+ "type": "winter_quarters",
+ "adjacent": [
+ 7,
+ 10,
+ 44
+ ],
+ "path": [
+ 7,
+ 10,
+ 44
+ ],
+ "wilderness": [],
+ "port": 1,
+ "colony": 5,
+ "x": 1330,
+ "y": 773
+ },
+ {
+ "name": "Norfolk",
+ "type": "winter_quarters",
+ "adjacent": [
+ 16,
+ 49,
+ 54
+ ],
+ "path": [
+ 16,
+ 49,
+ 54
+ ],
+ "wilderness": [],
+ "port": 4,
+ "colony": 10,
+ "x": 822,
+ "y": 1488
+ },
+ {
+ "name": "Norwich",
+ "type": "winter_quarters",
+ "adjacent": [
+ 18,
+ 25,
+ 29
+ ],
+ "path": [
+ 18,
+ 25,
+ 29
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 1,
+ "x": 1166,
+ "y": 379
+ },
+ {
+ "name": "Pittsburgh",
+ "type": "winter_quarters",
+ "adjacent": [
+ 24,
+ 34,
+ 36,
+ 42
+ ],
+ "path": [
+ 24,
+ 34,
+ 36,
+ 42
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 6,
+ "x": 480,
+ "y": 995
+ },
+ {
+ "name": "Richmond",
+ "type": "winter_quarters",
+ "adjacent": [
+ 5,
+ 8,
+ 13,
+ 46,
+ 54,
+ 65
+ ],
+ "path": [
+ 5,
+ 8,
+ 13,
+ 46,
+ 54,
+ 65
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 649,
+ "y": 1360
+ },
+ {
+ "name": "Springfield",
+ "type": "winter_quarters",
+ "adjacent": [
+ 4,
+ 10,
+ 25,
+ 44
+ ],
+ "path": [
+ 4,
+ 10,
+ 25,
+ 44
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 3,
+ "x": 1137,
+ "y": 661
+ },
+ {
+ "name": "Ticonderoga",
+ "type": "winter_quarters",
+ "adjacent": [
+ 1,
+ 14,
+ 58
+ ],
+ "path": [
+ 1,
+ 14,
+ 58
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 1035,
+ "y": 393
+ },
+ {
+ "name": "Wilmington DE",
+ "type": "winter_quarters",
+ "adjacent": [
+ 2,
+ 6
+ ],
+ "path": [
+ 2,
+ 6
+ ],
+ "wilderness": [],
+ "port": 3,
+ "colony": 9,
+ "x": 926,
+ "y": 1117
+ },
+ {
+ "name": "Wyoming Valley",
+ "type": "winter_quarters",
+ "adjacent": [
+ 39,
+ 48,
+ 56
+ ],
+ "path": [
+ 39,
+ 48,
+ 56
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 6,
+ "x": 726,
+ "y": 784
+ },
+ {
+ "name": "Abingdon",
+ "type": "regular",
+ "adjacent": [
+ 33,
+ 37,
+ 41
+ ],
+ "path": [
+ 33,
+ 37,
+ 41
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 101,
+ "y": 1487
+ },
+ {
+ "name": "Augusta",
+ "type": "regular",
+ "adjacent": [
+ 52,
+ 59
+ ],
+ "path": [
+ 52,
+ 59
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 13,
+ "x": 180,
+ "y": 2096
+ },
+ {
+ "name": "Barnstable",
+ "type": "regular",
+ "adjacent": [
+ 7
+ ],
+ "path": [
+ 7
+ ],
+ "wilderness": [],
+ "port": 1,
+ "colony": 3,
+ "x": 1434,
+ "y": 741
+ },
+ {
+ "name": "Bassett Town",
+ "type": "regular",
+ "adjacent": [
+ 15,
+ 35,
+ 55
+ ],
+ "path": [
+ 15
+ ],
+ "wilderness": [
+ 35,
+ 55
+ ],
+ "port": -1,
+ "colony": 6,
+ "x": 187,
+ "y": 1020
+ },
+ {
+ "name": "Brattleboro",
+ "type": "regular",
+ "adjacent": [
+ 14,
+ 17,
+ 29,
+ 58
+ ],
+ "path": [
+ 14,
+ 17,
+ 29,
+ 58
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 1,
+ "x": 1141,
+ "y": 522
+ },
+ {
+ "name": "Camden",
+ "type": "regular",
+ "adjacent": [
+ 27,
+ 28,
+ 30,
+ 52
+ ],
+ "path": [
+ 27,
+ 28,
+ 30,
+ 52
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 12,
+ "x": 386,
+ "y": 1809
+ },
+ {
+ "name": "Charlotte",
+ "type": "regular",
+ "adjacent": [
+ 26,
+ 41,
+ 57
+ ],
+ "path": [
+ 26,
+ 41,
+ 57
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 11,
+ "x": 255,
+ "y": 1689
+ },
+ {
+ "name": "Cheraw",
+ "type": "regular",
+ "adjacent": [
+ 26,
+ 40,
+ 57,
+ 63
+ ],
+ "path": [
+ 26,
+ 40,
+ 57,
+ 63
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 12,
+ "x": 536,
+ "y": 1831
+ },
+ {
+ "name": "Concord",
+ "type": "regular",
+ "adjacent": [
+ 14,
+ 25,
+ 31
+ ],
+ "path": [
+ 14,
+ 25,
+ 31
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 1,
+ "x": 1254,
+ "y": 497
+ },
+ {
+ "name": "Eutaw Springs",
+ "type": "regular",
+ "adjacent": [
+ 0,
+ 26
+ ],
+ "path": [
+ 0,
+ 26
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 12,
+ "x": 444,
+ "y": 1942
+ },
+ {
+ "name": "Falmouth",
+ "type": "regular",
+ "adjacent": [
+ 3,
+ 7,
+ 29
+ ],
+ "path": [
+ 7,
+ 29
+ ],
+ "wilderness": [
+ 3
+ ],
+ "port": 1,
+ "colony": 3,
+ "x": 1374,
+ "y": 446
+ },
+ {
+ "name": "Fincastle",
+ "type": "regular",
+ "adjacent": [
+ 8,
+ 33,
+ 46
+ ],
+ "path": [
+ 8,
+ 33,
+ 46
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 389,
+ "y": 1438
+ },
+ {
+ "name": "Fort Chiswell",
+ "type": "regular",
+ "adjacent": [
+ 21,
+ 32,
+ 55
+ ],
+ "path": [
+ 21,
+ 32,
+ 55
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 252,
+ "y": 1444
+ },
+ {
+ "name": "Fort Cumberland",
+ "type": "regular",
+ "adjacent": [
+ 15,
+ 38
+ ],
+ "path": [
+ 15,
+ 38
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 8,
+ "x": 487,
+ "y": 1134
+ },
+ {
+ "name": "Fort Detroit",
+ "type": "regular",
+ "adjacent": [
+ 24,
+ 36
+ ],
+ "path": [
+ 36
+ ],
+ "wilderness": [
+ 24
+ ],
+ "port": -1,
+ "colony": 0,
+ "x": 95,
+ "y": 708
+ },
+ {
+ "name": "Fort Niagara",
+ "type": "regular",
+ "adjacent": [
+ 15,
+ 35,
+ 39,
+ 53
+ ],
+ "path": [
+ 15,
+ 35,
+ 39,
+ 53
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 502,
+ "y": 562
+ },
+ {
+ "name": "Fort Prince George",
+ "type": "regular",
+ "adjacent": [
+ 21,
+ 41,
+ 52
+ ],
+ "path": [
+ 21,
+ 41,
+ 52
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 12,
+ "x": 114,
+ "y": 1809
+ },
+ {
+ "name": "Frederick Town",
+ "type": "regular",
+ "adjacent": [
+ 5,
+ 6,
+ 8,
+ 34,
+ 64
+ ],
+ "path": [
+ 5,
+ 6,
+ 8,
+ 34,
+ 64
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 8,
+ "x": 686,
+ "y": 1133
+ },
+ {
+ "name": "Genesee",
+ "type": "regular",
+ "adjacent": [
+ 9,
+ 20,
+ 36
+ ],
+ "path": [
+ 9,
+ 20,
+ 36
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 708,
+ "y": 618
+ },
+ {
+ "name": "Georgetown",
+ "type": "regular",
+ "adjacent": [
+ 0,
+ 28,
+ 63
+ ],
+ "path": [
+ 0,
+ 28,
+ 63
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 12,
+ "x": 614,
+ "y": 1951
+ },
+ {
+ "name": "Gilbert Town",
+ "type": "regular",
+ "adjacent": [
+ 21,
+ 27,
+ 37
+ ],
+ "path": [
+ 21,
+ 27,
+ 37
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 11,
+ "x": 163,
+ "y": 1604
+ },
+ {
+ "name": "Harrisburg",
+ "type": "regular",
+ "adjacent": [
+ 15,
+ 56,
+ 64
+ ],
+ "path": [
+ 15,
+ 56,
+ 64
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 6,
+ "x": 595,
+ "y": 916
+ },
+ {
+ "name": "Hillsboro",
+ "type": "regular",
+ "adjacent": [
+ 54,
+ 57,
+ 61
+ ],
+ "path": [
+ 54,
+ 57,
+ 61
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 11,
+ "x": 524,
+ "y": 1618
+ },
+ {
+ "name": "Lexington Concord",
+ "type": "regular",
+ "adjacent": [
+ 7,
+ 12,
+ 17
+ ],
+ "path": [
+ 7,
+ 12,
+ 17
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 3,
+ "x": 1258,
+ "y": 664
+ },
+ {
+ "name": "Long Island",
+ "type": "regular",
+ "adjacent": [
+ 11
+ ],
+ "path": [
+ 11
+ ],
+ "wilderness": [],
+ "port": 2,
+ "colony": 2,
+ "x": 1186,
+ "y": 904
+ },
+ {
+ "name": "Lynch's Ferry",
+ "type": "regular",
+ "adjacent": [
+ 8,
+ 16,
+ 32,
+ 54,
+ 57
+ ],
+ "path": [
+ 8,
+ 16,
+ 32,
+ 54,
+ 57
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 526,
+ "y": 1480
+ },
+ {
+ "name": "Monmouth",
+ "type": "regular",
+ "adjacent": [
+ 2,
+ 50
+ ],
+ "path": [
+ 2,
+ 50
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 7,
+ "x": 1037,
+ "y": 1110
+ },
+ {
+ "name": "Morristown",
+ "type": "regular",
+ "adjacent": [
+ 11,
+ 20,
+ 50,
+ 56,
+ 62
+ ],
+ "path": [
+ 11,
+ 20,
+ 50,
+ 56,
+ 62
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 7,
+ "x": 904,
+ "y": 867
+ },
+ {
+ "name": "New Bern",
+ "type": "regular",
+ "adjacent": [
+ 13,
+ 61
+ ],
+ "path": [
+ 13,
+ 61
+ ],
+ "wilderness": [],
+ "port": 5,
+ "colony": 11,
+ "x": 804,
+ "y": 1706
+ },
+ {
+ "name": "New Brunswick",
+ "type": "regular",
+ "adjacent": [
+ 2,
+ 11,
+ 47,
+ 48
+ ],
+ "path": [
+ 2,
+ 11,
+ 47,
+ 48
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 7,
+ "x": 1001,
+ "y": 978
+ },
+ {
+ "name": "New Haven",
+ "type": "regular",
+ "adjacent": [
+ 11,
+ 62
+ ],
+ "path": [
+ 11,
+ 62
+ ],
+ "wilderness": [],
+ "port": 2,
+ "colony": 4,
+ "x": 1128,
+ "y": 772
+ },
+ {
+ "name": "Ninety Six",
+ "type": "regular",
+ "adjacent": [
+ 22,
+ 26,
+ 37
+ ],
+ "path": [
+ 22,
+ 26,
+ 37
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 12,
+ "x": 263,
+ "y": 1968
+ },
+ {
+ "name": "Oswego",
+ "type": "regular",
+ "adjacent": [
+ 1,
+ 9,
+ 36
+ ],
+ "path": [
+ 1,
+ 9,
+ 36
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 808,
+ "y": 460
+ },
+ {
+ "name": "Petersburg",
+ "type": "regular",
+ "adjacent": [
+ 13,
+ 16,
+ 43,
+ 46,
+ 61
+ ],
+ "path": [
+ 13,
+ 16,
+ 43,
+ 46,
+ 61
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 10,
+ "x": 675,
+ "y": 1482
+ },
+ {
+ "name": "Point Pleasant",
+ "type": "regular",
+ "adjacent": [
+ 24,
+ 33
+ ],
+ "path": [
+ 33
+ ],
+ "wilderness": [
+ 24
+ ],
+ "port": -1,
+ "colony": 10,
+ "x": 172,
+ "y": 1254
+ },
+ {
+ "name": "Reading",
+ "type": "regular",
+ "adjacent": [
+ 2,
+ 20,
+ 42,
+ 48,
+ 64
+ ],
+ "path": [
+ 2,
+ 20,
+ 42,
+ 48,
+ 64
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 6,
+ "x": 724,
+ "y": 936
+ },
+ {
+ "name": "Salem",
+ "type": "regular",
+ "adjacent": [
+ 27,
+ 28,
+ 43,
+ 46
+ ],
+ "path": [
+ 27,
+ 28,
+ 43,
+ 46
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 11,
+ "x": 349,
+ "y": 1597
+ },
+ {
+ "name": "Saratoga",
+ "type": "regular",
+ "adjacent": [
+ 4,
+ 18,
+ 25
+ ],
+ "path": [
+ 4,
+ 18,
+ 25
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 1032,
+ "y": 532
+ },
+ {
+ "name": "Savannah",
+ "type": "regular",
+ "adjacent": [
+ 0,
+ 22,
+ 60
+ ],
+ "path": [
+ 0,
+ 22,
+ 60
+ ],
+ "wilderness": [],
+ "port": 6,
+ "colony": 13,
+ "x": 267,
+ "y": 2307
+ },
+ {
+ "name": "St. Mary's",
+ "type": "regular",
+ "adjacent": [
+ 59
+ ],
+ "path": [
+ 59
+ ],
+ "wilderness": [],
+ "port": 6,
+ "colony": 13,
+ "x": 220,
+ "y": 2430
+ },
+ {
+ "name": "Wake (Raleigh)",
+ "type": "regular",
+ "adjacent": [
+ 43,
+ 49,
+ 54,
+ 63
+ ],
+ "path": [
+ 43,
+ 49,
+ 54,
+ 63
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 11,
+ "x": 646,
+ "y": 1707
+ },
+ {
+ "name": "Westchester",
+ "type": "regular",
+ "adjacent": [
+ 4,
+ 11,
+ 48,
+ 51
+ ],
+ "path": [
+ 4,
+ 11,
+ 48,
+ 51
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 2,
+ "x": 995,
+ "y": 783
+ },
+ {
+ "name": "Wilmington",
+ "type": "regular",
+ "adjacent": [
+ 28,
+ 40,
+ 61
+ ],
+ "path": [
+ 28,
+ 40,
+ 61
+ ],
+ "wilderness": [],
+ "port": 5,
+ "colony": 11,
+ "x": 716,
+ "y": 1852
+ },
+ {
+ "name": "York",
+ "type": "regular",
+ "adjacent": [
+ 38,
+ 42,
+ 56
+ ],
+ "path": [
+ 38,
+ 42,
+ 56
+ ],
+ "wilderness": [],
+ "port": -1,
+ "colony": 6,
+ "x": 629,
+ "y": 1028
+ },
+ {
+ "name": "Yorktown",
+ "type": "regular",
+ "adjacent": [
+ 16
+ ],
+ "path": [
+ 16
+ ],
+ "wilderness": [],
+ "port": 4,
+ "colony": 10,
+ "x": 807,
+ "y": 1353
+ },
+ {
+ "name": "American Leader Reinforcements",
+ "type": "box",
+ "adjacent": [],
+ "path": [],
+ "wilderness": [],
+ "port": -1,
+ "colony": -1,
+ "x": 401,
+ "y": 361
+ },
+ {
+ "name": "British Reinforcement Box",
+ "type": "box",
+ "adjacent": [],
+ "path": [],
+ "wilderness": [],
+ "port": -1,
+ "colony": -1,
+ "x": 1465,
+ "y": 1776
+ },
+ {
+ "name": "Captured Generals",
+ "type": "box",
+ "adjacent": [],
+ "path": [],
+ "wilderness": [],
+ "port": -1,
+ "colony": -1,
+ "x": 1503,
+ "y": 114
+ },
+ {
+ "name": "Continental Congress Dispersed",
+ "type": "box",
+ "adjacent": [],
+ "path": [],
+ "wilderness": [],
+ "port": -1,
+ "colony": -1,
+ "x": 586,
+ "y": 384
+ },
+ {
+ "name": "French Reinforcements",
+ "type": "box",
+ "adjacent": [],
+ "path": [],
+ "wilderness": [],
+ "port": -1,
+ "colony": -1,
+ "x": 170,
+ "y": 362
+ }
+ ],
+ "space_index": {
+ "Charleston": 0,
+ "Montreal": 1,
+ "Philadelphia": 2,
+ "Quebec": 3,
+ "Albany": 4,
+ "Alexandria": 5,
+ "Baltimore": 6,
+ "Boston": 7,
+ "Charlottesville": 8,
+ "Fort Stanwix": 9,
+ "Hartford": 10,
+ "New York": 11,
+ "Newport": 12,
+ "Norfolk": 13,
+ "Norwich": 14,
+ "Pittsburgh": 15,
+ "Richmond": 16,
+ "Springfield": 17,
+ "Ticonderoga": 18,
+ "Wilmington DE": 19,
+ "Wyoming Valley": 20,
+ "Abingdon": 21,
+ "Augusta": 22,
+ "Barnstable": 23,
+ "Bassett Town": 24,
+ "Brattleboro": 25,
+ "Camden": 26,
+ "Charlotte": 27,
+ "Cheraw": 28,
+ "Concord": 29,
+ "Eutaw Springs": 30,
+ "Falmouth": 31,
+ "Fincastle": 32,
+ "Fort Chiswell": 33,
+ "Fort Cumberland": 34,
+ "Fort Detroit": 35,
+ "Fort Niagara": 36,
+ "Fort Prince George": 37,
+ "Frederick Town": 38,
+ "Genesee": 39,
+ "Georgetown": 40,
+ "Gilbert Town": 41,
+ "Harrisburg": 42,
+ "Hillsboro": 43,
+ "Lexington Concord": 44,
+ "Long Island": 45,
+ "Lynch's Ferry": 46,
+ "Monmouth": 47,
+ "Morristown": 48,
+ "New Bern": 49,
+ "New Brunswick": 50,
+ "New Haven": 51,
+ "Ninety Six": 52,
+ "Oswego": 53,
+ "Petersburg": 54,
+ "Point Pleasant": 55,
+ "Reading": 56,
+ "Salem": 57,
+ "Saratoga": 58,
+ "Savannah": 59,
+ "St. Mary's": 60,
+ "Wake (Raleigh)": 61,
+ "Westchester": 62,
+ "Wilmington": 63,
+ "York": 64,
+ "Yorktown": 65,
+ "American Leader Reinforcements": 66,
+ "British Reinforcement Box": 67,
+ "Captured Generals": 68,
+ "Continental Congress Dispersed": 69,
+ "French Reinforcements": 70
},
-
- /* 110 */
- {
- title: "Hessian Infantry Bayonet Charge",
- type: "british-battle",
+ "colonies": [
+ [
+ 1,
+ 3,
+ 35
+ ],
+ [
+ 14,
+ 25,
+ 29
+ ],
+ [
+ 4,
+ 9,
+ 11,
+ 18,
+ 36,
+ 39,
+ 45,
+ 53,
+ 58,
+ 62
+ ],
+ [
+ 7,
+ 17,
+ 23,
+ 31,
+ 44
+ ],
+ [
+ 10,
+ 51
+ ],
+ [
+ 12
+ ],
+ [
+ 2,
+ 15,
+ 20,
+ 24,
+ 42,
+ 56,
+ 64
+ ],
+ [
+ 47,
+ 48,
+ 50
+ ],
+ [
+ 6,
+ 34,
+ 38
+ ],
+ [
+ 19
+ ],
+ [
+ 5,
+ 8,
+ 13,
+ 16,
+ 21,
+ 32,
+ 33,
+ 46,
+ 54,
+ 55,
+ 65
+ ],
+ [
+ 27,
+ 41,
+ 43,
+ 49,
+ 57,
+ 61,
+ 63
+ ],
+ [
+ 0,
+ 26,
+ 28,
+ 30,
+ 37,
+ 40,
+ 52
+ ],
+ [
+ 22,
+ 59,
+ 60
+ ]
+ ],
+ "seas": [
+ [
+ 1,
+ 3
+ ],
+ [
+ 7,
+ 12,
+ 23,
+ 31
+ ],
+ [
+ 11,
+ 45,
+ 51
+ ],
+ [
+ 2,
+ 19
+ ],
+ [
+ 5,
+ 6,
+ 13,
+ 65
+ ],
+ [
+ 0,
+ 49,
+ 63
+ ],
+ [
+ 59,
+ 60
+ ]
+ ],
+ "generals": [
+ {
+ "name": "Arnold",
+ "owner": "American",
+ "strategy": 1,
+ "battle": 3,
+ "agility": 2,
+ "bonus": false
+ },
+ {
+ "name": "Gates",
+ "owner": "American",
+ "strategy": 2,
+ "battle": 2,
+ "agility": 1,
+ "bonus": false
+ },
+ {
+ "name": "Greene",
+ "owner": "American",
+ "strategy": 1,
+ "battle": 4,
+ "agility": 2,
+ "bonus": true
+ },
+ {
+ "name": "Lafayette",
+ "owner": "American",
+ "strategy": 1,
+ "battle": 2,
+ "agility": 1,
+ "bonus": false
+ },
+ {
+ "name": "Lee",
+ "owner": "American",
+ "strategy": 2,
+ "battle": 1,
+ "agility": 1,
+ "bonus": false
+ },
+ {
+ "name": "Lincoln",
+ "owner": "American",
+ "strategy": 2,
+ "battle": 1,
+ "agility": 1,
+ "bonus": false
+ },
+ {
+ "name": "Washington",
+ "owner": "American",
+ "strategy": 1,
+ "battle": 5,
+ "agility": 2,
+ "bonus": true
+ },
+ {
+ "name": "Rochambeau",
+ "owner": "French",
+ "strategy": 2,
+ "battle": 4,
+ "agility": 2,
+ "bonus": false
+ },
+ {
+ "name": "Burgoyne",
+ "owner": "British",
+ "strategy": 2,
+ "battle": 2,
+ "agility": 1,
+ "bonus": false
+ },
+ {
+ "name": "Carleton",
+ "owner": "British",
+ "strategy": 3,
+ "battle": 3,
+ "agility": 2,
+ "bonus": false
+ },
+ {
+ "name": "Clinton",
+ "owner": "British",
+ "strategy": 3,
+ "battle": 4,
+ "agility": 2,
+ "bonus": false
+ },
+ {
+ "name": "Cornwallis",
+ "owner": "British",
+ "strategy": 2,
+ "battle": 4,
+ "agility": 2,
+ "bonus": false
+ },
+ {
+ "name": "Howe",
+ "owner": "British",
+ "strategy": 3,
+ "battle": 6,
+ "agility": 3,
+ "bonus": false
+ }
+ ],
+ "general_index": {
+ "Arnold": 0,
+ "Gates": 1,
+ "Greene": 2,
+ "Lafayette": 3,
+ "Lee": 4,
+ "Lincoln": 5,
+ "Washington": 6,
+ "Rochambeau": 7,
+ "Burgoyne": 8,
+ "Carleton": 9,
+ "Clinton": 10,
+ "Cornwallis": 11,
+ "Howe": 12
},
-]
-
-data = {
- BOXES,
- cards,
- general_index,
- generals,
- space_index,
- spaces,
- colony_name,
- colony_spaces,
+ "colony_name": [
+ "Canada",
+ "NH",
+ "NY",
+ "MA",
+ "CT",
+ "RI",
+ "PA",
+ "NJ",
+ "MD",
+ "DE",
+ "VA",
+ "NC",
+ "SC",
+ "GA"
+ ],
+ "cards": [
+ null,
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "3 OPS",
+ "type": "ops",
+ "count": 3
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "2 OPS",
+ "type": "ops",
+ "count": 2
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "1 OPS",
+ "type": "ops",
+ "count": 1
+ },
+ {
+ "title": "Minor Campaign",
+ "type": "campaign",
+ "count": 2
+ },
+ {
+ "title": "Minor Campaign",
+ "type": "campaign",
+ "count": 2
+ },
+ {
+ "title": "Minor Campaign",
+ "type": "campaign",
+ "count": 2
+ },
+ {
+ "title": "Major Campaign",
+ "type": "campaign",
+ "count": 3
+ },
+ {
+ "full_title": "North's Government Falls - The War Ends in 1779",
+ "title": "The War Ends in 1779",
+ "type": "mandatory-event",
+ "event": "the_war_ends",
+ "year": 1779
+ },
+ {
+ "full_title": "North's Government Falls - The War Ends in 1780",
+ "title": "The War Ends in 1780",
+ "type": "mandatory-event",
+ "event": "the_war_ends",
+ "year": 1780
+ },
+ {
+ "full_title": "North's Government Falls - The War Ends in 1781",
+ "title": "The War Ends in 1781",
+ "type": "mandatory-event",
+ "event": "the_war_ends",
+ "year": 1781
+ },
+ {
+ "full_title": "North's Government Falls - The War Ends in 1782",
+ "title": "The War Ends in 1782",
+ "type": "mandatory-event",
+ "event": "the_war_ends",
+ "year": 1782
+ },
+ {
+ "full_title": "North's Government Falls - The War Ends in 1783",
+ "title": "The War Ends in 1783",
+ "type": "mandatory-event",
+ "event": "the_war_ends",
+ "year": 1783
+ },
+ {
+ "title": "Henry Know Continental Artillery Commander",
+ "type": "american-battle"
+ },
+ {
+ "title": "Jane McCrea Indian Atrocity Sparks Outrage",
+ "type": "american-event",
+ "event": "place_american_pc",
+ "count": 2,
+ "once": true
+ },
+ {
+ "title": "Iroquois Uprising!",
+ "type": "british-event",
+ "event": "remove_american_pc_from_non_port",
+ "where": [
+ 1,
+ 2,
+ 6
+ ],
+ "count": 2
+ },
+ {
+ "title": "Joseph Brant Leads an Iroquois Raid",
+ "type": "british-event",
+ "event": "remove_american_pc_from_non_port",
+ "where": [
+ 1,
+ 2,
+ 6
+ ],
+ "count": 2
+ },
+ {
+ "title": "Lt. Colonel Simcoe's Queen's Rangers",
+ "type": "british-event",
+ "event": "remove_american_pc_within_two_spaces_of_a_british_general",
+ "count": 2
+ },
+ {
+ "title": "D'Estaing Sails for the Caribbean",
+ "type": "british-event",
+ "when": "after_french_alliance",
+ "event": "remove_french_navy"
+ },
+ {
+ "title": "Banastre Tarleton's Waxhaws Massacre",
+ "type": "british-event-or-battle",
+ "event": "remove_american_cu"
+ },
+ {
+ "title": "Lord George Germaine Offers Royal Amnesty",
+ "type": "british-event",
+ "event": "remove_american_pc",
+ "count": 2
+ },
+ {
+ "title": "George Rogers Clark Leads a Western Offensive",
+ "type": "american-event",
+ "event": "remove_random_british_card"
+ },
+ {
+ "title": "Don Bernardo Galvez Captures Pensacola",
+ "type": "american-event",
+ "when": "european_war_in_effect",
+ "event": "remove_british_cu",
+ "count": 2
+ },
+ {
+ "title": "Baron von Steuben Trains the Continental Army",
+ "type": "american-event",
+ "event": "baron_von_steuben_trains_the_continental_army"
+ },
+ {
+ "title": "Lord North Offers a Royal Amnesty",
+ "type": "british-event",
+ "event": "remove_american_pc",
+ "count": 4,
+ "once": true
+ },
+ {
+ "title": "The Swamp Fox, Francis Marion",
+ "type": "american-event",
+ "event": "remove_british_pc_from",
+ "where": [
+ 11,
+ 12,
+ 13
+ ],
+ "count": 2
+ },
+ {
+ "title": "The Gamecock: Thomas Sumter",
+ "type": "american-event",
+ "event": "remove_british_pc_from",
+ "where": [
+ 11,
+ 12,
+ 13
+ ],
+ "count": 2
+ },
+ {
+ "title": "Josiah Martin Rallies North Carolina Loyalists",
+ "type": "british-event",
+ "event": "remove_american_pc_from",
+ "where": [
+ 11
+ ],
+ "count": 2
+ },
+ {
+ "title": "Thomas Paine Publishes Pamphlets \"Common Sense\" and \"The American Crisis\"",
+ "type": "american-event",
+ "event": "place_american_pc_in",
+ "where": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13
+ ],
+ "count": 3,
+ "once": true
+ },
+ {
+ "title": "Nathan Hale, American Martyr",
+ "type": "american-event",
+ "event": "place_american_pc",
+ "count": 2,
+ "once": true
+ },
+ {
+ "title": "John Glover's Marblehead Regiment",
+ "type": "american-event",
+ "event": "john_glovers_marblehead_regiment"
+ },
+ {
+ "title": "Pennsylvania and New Jersey Line Mutinies",
+ "type": "british-event",
+ "event": "pennsylvania_and_new_jersey_line_mutinies"
+ },
+ {
+ "title": "William Pitt Urges Peace Talks",
+ "type": "british-event",
+ "when": "before_french_alliance",
+ "event": "remove_american_pc",
+ "count": 2,
+ "reshuffle": "if_played"
+ },
+ {
+ "title": "Hortelez et Cie: Clandestine French and Spanish Aid",
+ "type": "american-event",
+ "when": "before_french_alliance",
+ "event": "advance_french_alliance",
+ "reshuffle": "if_discarded",
+ "count": 2
+ },
+ {
+ "title": "Admiral Suffren Wins a Naval Victory",
+ "type": "american-event",
+ "when": "after_french_alliance",
+ "event": "remove_random_british_card"
+ },
+ {
+ "title": "\"Mad\" Anthony Wayne",
+ "type": "american-battle"
+ },
+ {
+ "title": "Declaration of Independence",
+ "type": "mandatory-event",
+ "event": "declaration_of_independence",
+ "once": true,
+ "reshuffle": "if_played",
+ "tournament": true
+ },
+ {
+ "title": "Benedict Arnold's Treason Undermines the Patriot Cause",
+ "type": "british-battle",
+ "event": "remove_benedict_arnold",
+ "once": true
+ },
+ {
+ "title": "Benjamin Franklin: Minister to France",
+ "type": "mandatory-event",
+ "event": "advance_french_alliance",
+ "count": 4,
+ "once": true,
+ "tournament": true
+ },
+ {
+ "title": "Admiral Rodney Captures St. Eustatius",
+ "type": "british-event",
+ "event": "remove_random_american_card",
+ "when": "european_war_in_effect",
+ "once": true
+ },
+ {
+ "title": "Thaddeus Kosciuszco Constructs Engineering Works",
+ "type": "american-battle"
+ },
+ {
+ "title": "Light Horse Harry Lee",
+ "type": "american-battle"
+ },
+ {
+ "title": "Morgan's Riflemen",
+ "type": "american-battle"
+ },
+ {
+ "title": "John Paul Jones' Shipping Raids",
+ "type": "american-event",
+ "event": "remove_random_british_card"
+ },
+ {
+ "title": "British Light Infantry",
+ "type": "british-battle"
+ },
+ {
+ "title": "Lord Sandwich Coastal Raids",
+ "type": "british-event",
+ "event": "lord_sandwich_coastal_raids"
+ },
+ {
+ "title": "Edward Bancroft, British Double Agent",
+ "type": "british-event",
+ "event": "remove_random_american_card"
+ },
+ {
+ "title": "Hessian Infantry Bayonet Charge",
+ "type": "british-battle"
+ }
+ ]
}
-
-})()
-
-if (typeof module === "object")
- module.exports = data
+if (typeof module === 'object') module.exports = data
diff --git a/play.css b/play.css
index 99ff1ca..e6017c6 100644
--- a/play.css
+++ b/play.css
@@ -1,62 +1,5 @@
-main { background-color: slategray; }
-header { background-color: silver; }
-aside { background-color: #f5e8d7; }
-body.America header.your_turn { background-color: skyblue; }
-body.Britain header.your_turn { background-color: salmon; }
-#role_Britain { background-color: salmon; }
-#role_America { background-color: skyblue; }
-
-#log > div { padding-left: 20px; text-indent: -12px; }
-
-#log .h1 {
- background-color: tan;
- font-weight: bold;
- text-align: center;
- padding: 3px;
-}
-
-#log .h2 {
- background-color: tan;
- text-align: center;
- padding: 1px;
-}
-
-#log .h1, #log .h2 {
- border-top: 1px solid black;
- border-bottom: 1px solid black;
-}
-
-#log .h2.american { background-color: skyblue; }
-#log .h2.british { background-color: salmon; }
-
-#log .card_tip:hover { text-decoration: dotted underline; }
-
-:root {
- --piece-shadow: 1px 1px 4px #0008;
-}
-
-aside {
- width: 230px;
-}
-
-#turn_info {
-}
-
-#turn_info {
- background-color: tan;
-}
-
-#turn_info .card {
- margin: 5px auto;
-}
-
-.hand {
- margin: 15px;
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- min-height: 370px;
- gap: 15px;
+main {
+ background-color: slategray;
}
#tooltip {
@@ -72,6 +15,18 @@ aside {
display: block;
}
+#mapwrap {
+ width: 1650px;
+ height: 2550px;
+}
+
+#map {
+ width: 1650px;
+ height: 2550px;
+ background-size: 1650px 2550px;
+ box-shadow: 1px 1px 8px #0008;
+}
+
@media (max-width: 800px) {
#tooltip {
top: 0;
@@ -94,64 +49,80 @@ aside {
#popup li.title { text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
#popup li.disabled { display: none }
-/* MAP WITH MARKERS, CUs, LEADERS, AND SPACES */
+#popup li.title {
+ background-color: moccasin;
+}
+/* SPACES */
-#mapwrap {
- width: 1650px;
- height: 2550px;
+.space {
+ position: absolute;
+ border: 5px solid transparent;
}
-#map {
- width: 1650px;
- height: 2550px;
- background-size: 1650px 2550px;
- box-shadow: 1px 1px 8px #0008;
+.space.regular {
+ border-radius: 50%;
+}
+
+.space.fortified_port {
+ transform: rotate(45deg);
}
-#map.hide_markers > div {
- visibility: hidden;
+.space.sea {
+ border-radius: 12px;
+}
+
+.space.action {
+ border-color: white;
+ box-shadow: 0 0 2px 1px #000c, inset 0 0 2px 1px #000c;
+}
+
+.space.selected {
+ border-color: aqua;
+ box-shadow: 0 0 2px 1px #000c, inset 0 0 2px 1px #000c;
}
+.space.action.Canada { background-color: #e4795080 }
+.space.action.NY { background-color: #52954680 }
+.space.action.NH { background-color: #ded36380 }
+.space.action.MA { background-color: #6e407a80 }
+.space.action.CT { background-color: #d6b5be80 }
+.space.action.RI { background-color: #31a9d080 }
+.space.action.PA { background-color: #64408980 }
+.space.action.NJ { background-color: #ca4d5b80 }
+.space.action.MD { background-color: #e5a02380 }
+.space.action.DE { background-color: #dcca8780 }
+.space.action.VA { background-color: #409d8280 }
+.space.action.NC { background-color: #d9819480 }
+.space.action.SC { background-color: #ffe05d80 }
+.space.action.GA { background-color: #6d9ab480 }
+
/* MARKERS */
.marker {
position: absolute;
background-size: 100%;
border: 1px solid black;
- box-shadow: var(--piece-shadow);
-}
-
-.marker.turn {
- width: 55px;
- height: 55px;
-}
-
-.marker.french-alliance {
- width: 55px;
- height: 55px;
+ box-shadow: 1px 1px 4px #0008;
}
-.marker.congress {
+.marker.large {
width: 55px;
height: 55px;
}
-.marker.french-navy {
+.marker.tall {
width: 64px;
height: 130px;
}
-.marker.control {
+.marker.small {
width: 45px;
height: 45px;
- visibility: hidden;
}
-.marker.control.british { visibility: visible; }
-.marker.control.american { visibility: visible; }
-
-.pc {
+.marker.pc {
+ pointer-events: none;
border: none;
box-shadow: none;
width: 58px;
@@ -159,130 +130,101 @@ aside {
filter: drop-shadow(1px 1px 2px #0008);
}
-.cu {
- width: calc(60px - 6px);
- height: 60px;
- line-height: 50px;
- padding-left: 6px;
- font-size: 30px;
- color: white;
- text-shadow: 0px 0px 3px black;
+.marker.cu {
+ pointer-events: none;
+ width: calc(60px - 8px - 8px);
+ height: calc(60px - 14px - 18px);
+ line-height: 28px;
+ padding: 14px 8px 18px 8px;
+ font-size: 28px;
font-weight: bold;
+ color: white;
+ text-shadow:
+ -1px -1px 2px #0008,
+ 1px 1px 2px #0008,
+ -1px 1px 2px #0008,
+ 1px -1px 2px #0008
+ ;
border-radius: 50%;
}
-
-.general.tall {
- width: 64px;
- height: 130px;
-}
-
-.general.small {
- width: 45px;
- height: 45px;
+.general.action {
+ box-shadow: 0 0 0 3px yellow, 0 0 2px 4px black;
}
-.general.offmap {
- display: none;
+.general.selected {
+ box-shadow: 0 0 0 3px aqua, 0 0 2px 4px black;
}
-.general.british.action, .general.british.selected { box-shadow: 0 0 5px 5px white; }
-.general.american.action, .general.american.selected { box-shadow: 0 0 5px 5px white; }
-.general.french.action, .general.french.selected { box-shadow: 0 0 5px 5px white; }
-.general { z-index: 2; }
-.general:hover { z-index: 3; }
-.general.selected { z-index: 4; }
-.marker.congress { z-index: 5 }
-.cu { z-index: 1; }
-.space { z-index: 6; }
+/* CARDS */
-.space {
- position: absolute;
- border: 7px solid transparent;
- display: none;
-}
-.space.enabled {
- display: block;
- cursor: pointer;
- border: 7px solid transparent;
- box-shadow: 0 0 0 4px white, inset 0 0 0 2px white;
-}
-.space.regular-space {
- border-radius: 100px;
-}
-.space.fortified-port {
- transform: rotate(45deg);
-}
-.space.blockade {
- border-radius: 15px;
- border: 7px solid white;
- box-shadow: none;
-}
-.space.highlight {
- cursor: pointer;
- display: block;
+#last_played {
+ margin: 4px auto;
}
-/* CARDS */
+#hand {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ min-height: 352px;
+ padding: 12px;
+ gap: 12px;
+ margin: 24px 0;
+}
.card {
width: 250px;
height: 350px;
- background-size: 100%;
border-radius: 16px;
+ background-size: 100%;
border: 1px solid black;
- box-shadow: var(--piece-shadow);
- display: none;
+ box-shadow: 1px 1px 4px #0008;
}
-#turn_info .card {
- width: 125px;
- height: 175px;
- border-radius: 8px;
-}
-
-.card.show {
- display: block;
-}
-
-#tooltip.card {
- background-position: center;
- background-size: 500px 700px;
- width: 372px;
- height: 524px;
- border-radius: 20px;
+.card.shrink {
+ width: 187px;
+ height: 262px;
+ border-radius: 12px;
}
#war_ends {
- left:1073px;
- top:1647px;
- position:absolute;
- width: 187px;
- height: 262px;
- transform: rotate(90deg);
- background-size: 187px 262px;
+ position: absolute;
+ left: 1034px;
+ top: 1684px;
+
+ width: 262px;
+ height: 187px;
border-radius: 12px;
- display: none;
+ background-size: 100%;
border: 1px solid black;
+ box-shadow: 1px 1px 4px #0008;
+
+ display: none;
}
+
#war_ends.year_1779 { display: block; }
#war_ends.year_1780 { display: block; }
#war_ends.year_1781 { display: block; }
#war_ends.year_1782 { display: block; }
#war_ends.year_1783 { display: block; }
-#played_british_reinforcements { left: 909px; }
-#played_american_reinforcements_1 { left: 1142px; }
-#played_american_reinforcements_2 { left: 1375px; }
.reinforcements {
- position:absolute;
+ position: absolute;
top: 1922px;
+
width: 187px;
height: 262px;
border-radius: 12px;
- display: none;
border: 1px solid black;
+ box-shadow: 1px 1px 4px #0008;
+
+ display: none;
}
+
+#played_british_reinforcements { left: 909px; }
+#played_american_reinforcements_1 { left: 1142px; }
+#played_american_reinforcements_2 { left: 1375px; }
+
.reinforcements.ops_1 { display: block; }
.reinforcements.ops_2 { display: block; }
.reinforcements.ops_3 { display: block; }
@@ -291,16 +233,18 @@ aside {
#map { background-image: url(map75.jpg); }
-.marker.french-navy { background-image: url(markers.1x/french_navy_tall.png); }
+.marker.french_navy { background-image: url(markers.1x/french_navy.png); }
+.marker.french_navy.tall { background-image: url(markers.1x/french_navy_tall.png); }
.marker.turn { background-image: url(markers.1x/game_turn_regulars.png); }
-.marker.turn.no-regulars { background-image: url(markers.1x/game_turn_no_regulars.png); }
-.marker.french-alliance { background-image: url(markers.1x/french_alliance.png); }
-.marker.french-alliance.european-war { background-image: url(markers.1x/european_war.png); }
+.marker.turn.no_regulars { background-image: url(markers.1x/game_turn_no_regulars.png); }
+.marker.french_alliance { background-image: url(markers.1x/french_alliance.png); }
+.marker.french_alliance.european_war { background-image: url(markers.1x/european_war.png); }
.marker.congress { background-image: url(markers.1x/continental_congress.png); }
.marker.congress { background-image: url(markers.1x/continental_congress.png); }
.marker.control.british { background-image: url(markers.1x/colony_british.png); }
.marker.control.american { background-image: url(markers.1x/colony_american.png); }
+
.cu.american { background-image: url(markers.1x/cu_american.png); }
.cu.british { background-image: url(markers.1x/cu_british.png); }
.cu.french { background-image: url(markers.1x/cu_french.png); }
@@ -336,125 +280,124 @@ aside {
.general.small.Cornwallis { background-image: url(markers.1x/general_cornwallis.png); }
.general.small.Howe { background-image: url(markers.1x/general_howe.png); }
-#war_ends.year_1779 { background-image:url(cards75/WWcard-071.png); }
-#war_ends.year_1780 { background-image:url(cards75/WWcard-072.png); }
-#war_ends.year_1781 { background-image:url(cards75/WWcard-073.png); }
-#war_ends.year_1782 { background-image:url(cards75/WWcard-074.png); }
-#war_ends.year_1783 { background-image:url(cards75/WWcard-075.png); }
-
-.reinforcements.ops_1 { background-image:url(cards75/WWcard-045.png); }
-.reinforcements.ops_2 { background-image:url(cards75/WWcard-023.png); }
-.reinforcements.ops_3 { background-image:url(cards75/WWcard-001.png); }
-
-.card_back{background-image:url(cards100/WW-CardBack.png)}
-.card_1{background-image:url(cards100/WWcard-001.png)}
-.card_2{background-image:url(cards100/WWcard-001.png)}
-.card_3{background-image:url(cards100/WWcard-001.png)}
-.card_4{background-image:url(cards100/WWcard-001.png)}
-.card_5{background-image:url(cards100/WWcard-001.png)}
-.card_6{background-image:url(cards100/WWcard-001.png)}
-.card_7{background-image:url(cards100/WWcard-001.png)}
-.card_8{background-image:url(cards100/WWcard-001.png)}
-.card_9{background-image:url(cards100/WWcard-001.png)}
-.card_10{background-image:url(cards100/WWcard-001.png)}
-.card_11{background-image:url(cards100/WWcard-001.png)}
-.card_12{background-image:url(cards100/WWcard-001.png)}
-.card_13{background-image:url(cards100/WWcard-001.png)}
-.card_14{background-image:url(cards100/WWcard-001.png)}
-.card_15{background-image:url(cards100/WWcard-001.png)}
-.card_16{background-image:url(cards100/WWcard-001.png)}
-.card_17{background-image:url(cards100/WWcard-001.png)}
-.card_18{background-image:url(cards100/WWcard-001.png)}
-.card_19{background-image:url(cards100/WWcard-001.png)}
-.card_20{background-image:url(cards100/WWcard-001.png)}
-.card_21{background-image:url(cards100/WWcard-001.png)}
-.card_22{background-image:url(cards100/WWcard-001.png)}
-.card_23{background-image:url(cards100/WWcard-023.png)}
-.card_24{background-image:url(cards100/WWcard-023.png)}
-.card_25{background-image:url(cards100/WWcard-023.png)}
-.card_26{background-image:url(cards100/WWcard-023.png)}
-.card_27{background-image:url(cards100/WWcard-023.png)}
-.card_28{background-image:url(cards100/WWcard-023.png)}
-.card_29{background-image:url(cards100/WWcard-023.png)}
-.card_30{background-image:url(cards100/WWcard-023.png)}
-.card_31{background-image:url(cards100/WWcard-023.png)}
-.card_32{background-image:url(cards100/WWcard-023.png)}
-.card_33{background-image:url(cards100/WWcard-023.png)}
-.card_34{background-image:url(cards100/WWcard-023.png)}
-.card_35{background-image:url(cards100/WWcard-023.png)}
-.card_36{background-image:url(cards100/WWcard-023.png)}
-.card_37{background-image:url(cards100/WWcard-023.png)}
-.card_38{background-image:url(cards100/WWcard-023.png)}
-.card_39{background-image:url(cards100/WWcard-023.png)}
-.card_40{background-image:url(cards100/WWcard-023.png)}
-.card_41{background-image:url(cards100/WWcard-023.png)}
-.card_42{background-image:url(cards100/WWcard-023.png)}
-.card_43{background-image:url(cards100/WWcard-023.png)}
-.card_44{background-image:url(cards100/WWcard-023.png)}
-.card_45{background-image:url(cards100/WWcard-045.png)}
-.card_46{background-image:url(cards100/WWcard-045.png)}
-.card_47{background-image:url(cards100/WWcard-045.png)}
-.card_48{background-image:url(cards100/WWcard-045.png)}
-.card_49{background-image:url(cards100/WWcard-045.png)}
-.card_50{background-image:url(cards100/WWcard-045.png)}
-.card_51{background-image:url(cards100/WWcard-045.png)}
-.card_52{background-image:url(cards100/WWcard-045.png)}
-.card_53{background-image:url(cards100/WWcard-045.png)}
-.card_54{background-image:url(cards100/WWcard-045.png)}
-.card_55{background-image:url(cards100/WWcard-045.png)}
-.card_56{background-image:url(cards100/WWcard-045.png)}
-.card_57{background-image:url(cards100/WWcard-045.png)}
-.card_58{background-image:url(cards100/WWcard-045.png)}
-.card_59{background-image:url(cards100/WWcard-045.png)}
-.card_60{background-image:url(cards100/WWcard-045.png)}
-.card_61{background-image:url(cards100/WWcard-045.png)}
-.card_62{background-image:url(cards100/WWcard-045.png)}
-.card_63{background-image:url(cards100/WWcard-045.png)}
-.card_64{background-image:url(cards100/WWcard-045.png)}
-.card_65{background-image:url(cards100/WWcard-045.png)}
-.card_66{background-image:url(cards100/WWcard-045.png)}
-.card_67{background-image:url(cards100/WWcard-067.png)}
-.card_68{background-image:url(cards100/WWcard-067.png)}
-.card_69{background-image:url(cards100/WWcard-067.png)}
-.card_70{background-image:url(cards100/WWcard-070.png)}
-.card_71{background-image:url(cards100/WWcard-071.png)}
-.card_72{background-image:url(cards100/WWcard-072.png)}
-.card_73{background-image:url(cards100/WWcard-073.png)}
-.card_74{background-image:url(cards100/WWcard-074.png)}
-.card_75{background-image:url(cards100/WWcard-075.png)}
-.card_76{background-image:url(cards100/WWcard-076.png)}
-.card_77{background-image:url(cards100/WWcard-077.png)}
-.card_78{background-image:url(cards100/WWcard-078.png)}
-.card_79{background-image:url(cards100/WWcard-079.png)}
-.card_80{background-image:url(cards100/WWcard-080.png)}
-.card_81{background-image:url(cards100/WWcard-081.png)}
-.card_82{background-image:url(cards100/WWcard-082.png)}
-.card_83{background-image:url(cards100/WWcard-083.png)}
-.card_84{background-image:url(cards100/WWcard-084.png)}
-.card_85{background-image:url(cards100/WWcard-085.png)}
-.card_86{background-image:url(cards100/WWcard-086.png)}
-.card_87{background-image:url(cards100/WWcard-087.png)}
-.card_88{background-image:url(cards100/WWcard-088.png)}
-.card_89{background-image:url(cards100/WWcard-089.png)}
-.card_90{background-image:url(cards100/WWcard-090.png)}
-.card_91{background-image:url(cards100/WWcard-091.png)}
-.card_92{background-image:url(cards100/WWcard-092.png)}
-.card_93{background-image:url(cards100/WWcard-093.png)}
-.card_94{background-image:url(cards100/WWcard-094.png)}
-.card_95{background-image:url(cards100/WWcard-095.png)}
-.card_96{background-image:url(cards100/WWcard-096.png)}
-.card_97{background-image:url(cards100/WWcard-097.png)}
-.card_98{background-image:url(cards100/WWcard-098.png)}
-.card_99{background-image:url(cards100/WWcard-099.png)}
-.card_100{background-image:url(cards100/WWcard-100.png)}
-.card_101{background-image:url(cards100/WWcard-101.png)}
-.card_102{background-image:url(cards100/WWcard-102.png)}
-.card_103{background-image:url(cards100/WWcard-103.png)}
-.card_104{background-image:url(cards100/WWcard-104.png)}
-.card_105{background-image:url(cards100/WWcard-105.png)}
-.card_106{background-image:url(cards100/WWcard-106.png)}
-.card_107{background-image:url(cards100/WWcard-107.png)}
-.card_108{background-image:url(cards100/WWcard-108.png)}
-.card_109{background-image:url(cards100/WWcard-109.png)}
-.card_110{background-image:url(cards100/WWcard-110.png)}
-
+#war_ends.year_1779 { background-image:url(cards75/card_7_rot.png); }
+#war_ends.year_1780 { background-image:url(cards75/card_8_rot.png); }
+#war_ends.year_1781 { background-image:url(cards75/card_9_rot.png); }
+#war_ends.year_1782 { background-image:url(cards75/card_10_rot.png); }
+#war_ends.year_1783 { background-image:url(cards75/card_11_rot.png); }
+
+.reinforcements.ops_3 { background-image:url(cards75/card_2.png); }
+.reinforcements.ops_2 { background-image:url(cards75/card_3.png); }
+.reinforcements.ops_1 { background-image:url(cards75/card_4.png); }
+
+.card_0{background-image:url(cards100/card_1.png)}
+.card_1{background-image:url(cards100/card_2.png)}
+.card_2{background-image:url(cards100/card_2.png)}
+.card_3{background-image:url(cards100/card_2.png)}
+.card_4{background-image:url(cards100/card_2.png)}
+.card_5{background-image:url(cards100/card_2.png)}
+.card_6{background-image:url(cards100/card_2.png)}
+.card_7{background-image:url(cards100/card_2.png)}
+.card_8{background-image:url(cards100/card_2.png)}
+.card_9{background-image:url(cards100/card_2.png)}
+.card_10{background-image:url(cards100/card_2.png)}
+.card_11{background-image:url(cards100/card_2.png)}
+.card_12{background-image:url(cards100/card_2.png)}
+.card_13{background-image:url(cards100/card_2.png)}
+.card_14{background-image:url(cards100/card_2.png)}
+.card_15{background-image:url(cards100/card_2.png)}
+.card_16{background-image:url(cards100/card_2.png)}
+.card_17{background-image:url(cards100/card_2.png)}
+.card_18{background-image:url(cards100/card_2.png)}
+.card_19{background-image:url(cards100/card_2.png)}
+.card_20{background-image:url(cards100/card_2.png)}
+.card_21{background-image:url(cards100/card_2.png)}
+.card_22{background-image:url(cards100/card_2.png)}
+.card_23{background-image:url(cards100/card_3.png)}
+.card_24{background-image:url(cards100/card_3.png)}
+.card_25{background-image:url(cards100/card_3.png)}
+.card_26{background-image:url(cards100/card_3.png)}
+.card_27{background-image:url(cards100/card_3.png)}
+.card_28{background-image:url(cards100/card_3.png)}
+.card_29{background-image:url(cards100/card_3.png)}
+.card_30{background-image:url(cards100/card_3.png)}
+.card_31{background-image:url(cards100/card_3.png)}
+.card_32{background-image:url(cards100/card_3.png)}
+.card_33{background-image:url(cards100/card_3.png)}
+.card_34{background-image:url(cards100/card_3.png)}
+.card_35{background-image:url(cards100/card_3.png)}
+.card_36{background-image:url(cards100/card_3.png)}
+.card_37{background-image:url(cards100/card_3.png)}
+.card_38{background-image:url(cards100/card_3.png)}
+.card_39{background-image:url(cards100/card_3.png)}
+.card_40{background-image:url(cards100/card_3.png)}
+.card_41{background-image:url(cards100/card_3.png)}
+.card_42{background-image:url(cards100/card_3.png)}
+.card_43{background-image:url(cards100/card_3.png)}
+.card_44{background-image:url(cards100/card_3.png)}
+.card_45{background-image:url(cards100/card_4.png)}
+.card_46{background-image:url(cards100/card_4.png)}
+.card_47{background-image:url(cards100/card_4.png)}
+.card_48{background-image:url(cards100/card_4.png)}
+.card_49{background-image:url(cards100/card_4.png)}
+.card_50{background-image:url(cards100/card_4.png)}
+.card_51{background-image:url(cards100/card_4.png)}
+.card_52{background-image:url(cards100/card_4.png)}
+.card_53{background-image:url(cards100/card_4.png)}
+.card_54{background-image:url(cards100/card_4.png)}
+.card_55{background-image:url(cards100/card_4.png)}
+.card_56{background-image:url(cards100/card_4.png)}
+.card_57{background-image:url(cards100/card_4.png)}
+.card_58{background-image:url(cards100/card_4.png)}
+.card_59{background-image:url(cards100/card_4.png)}
+.card_60{background-image:url(cards100/card_4.png)}
+.card_61{background-image:url(cards100/card_4.png)}
+.card_62{background-image:url(cards100/card_4.png)}
+.card_63{background-image:url(cards100/card_4.png)}
+.card_64{background-image:url(cards100/card_4.png)}
+.card_65{background-image:url(cards100/card_4.png)}
+.card_66{background-image:url(cards100/card_4.png)}
+.card_67{background-image:url(cards100/card_5.png)}
+.card_68{background-image:url(cards100/card_5.png)}
+.card_69{background-image:url(cards100/card_5.png)}
+.card_70{background-image:url(cards100/card_6.png)}
+.card_71{background-image:url(cards100/card_7.png)}
+.card_72{background-image:url(cards100/card_8.png)}
+.card_73{background-image:url(cards100/card_9.png)}
+.card_74{background-image:url(cards100/card_10.png)}
+.card_75{background-image:url(cards100/card_11.png)}
+.card_76{background-image:url(cards100/card_12.png)}
+.card_77{background-image:url(cards100/card_13.png)}
+.card_78{background-image:url(cards100/card_14.png)}
+.card_79{background-image:url(cards100/card_15.png)}
+.card_80{background-image:url(cards100/card_16.png)}
+.card_81{background-image:url(cards100/card_17.png)}
+.card_82{background-image:url(cards100/card_18.png)}
+.card_83{background-image:url(cards100/card_19.png)}
+.card_84{background-image:url(cards100/card_20.png)}
+.card_85{background-image:url(cards100/card_21.png)}
+.card_86{background-image:url(cards100/card_22.png)}
+.card_87{background-image:url(cards100/card_23.png)}
+.card_88{background-image:url(cards100/card_24.png)}
+.card_89{background-image:url(cards100/card_25.png)}
+.card_90{background-image:url(cards100/card_26.png)}
+.card_91{background-image:url(cards100/card_27.png)}
+.card_92{background-image:url(cards100/card_28.png)}
+.card_93{background-image:url(cards100/card_29.png)}
+.card_94{background-image:url(cards100/card_30.png)}
+.card_95{background-image:url(cards100/card_31.png)}
+.card_96{background-image:url(cards100/card_32.png)}
+.card_97{background-image:url(cards100/card_33.png)}
+.card_98{background-image:url(cards100/card_34.png)}
+.card_99{background-image:url(cards100/card_35.png)}
+.card_100{background-image:url(cards100/card_36.png)}
+.card_101{background-image:url(cards100/card_37.png)}
+.card_102{background-image:url(cards100/card_38.png)}
+.card_103{background-image:url(cards100/card_39.png)}
+.card_104{background-image:url(cards100/card_40.png)}
+.card_105{background-image:url(cards100/card_41.png)}
+.card_106{background-image:url(cards100/card_42.png)}
+.card_107{background-image:url(cards100/card_43.png)}
+.card_108{background-image:url(cards100/card_44.png)}
+.card_109{background-image:url(cards100/card_45.png)}
+.card_110{background-image:url(cards100/card_46.png)}
diff --git a/play.html b/play.html
index 9a69f17..8379323 100644
--- a/play.html
+++ b/play.html
@@ -62,7 +62,7 @@
<div class="role_info"></div>
</div>
</div>
- <div id="turn_info"><div id="last_played" class="card show card_back"></div></div>
+ <div id="turn_info"><div id="last_played" class="card shrink card_0"></div></div>
<div id="log"></div>
</aside>
@@ -70,11 +70,8 @@
<div id="mapwrap">
<div id="map">
- <div id="pc"></div>
- <div id="cu"></div>
- <div id="generals"></div>
- <div id="markers"></div>
<div id="spaces"></div>
+ <div id="pieces"></div>
<div id="war_ends"></div>
<div id="played_british_reinforcements" class="reinforcements"></div>
<div id="played_american_reinforcements_1" class="reinforcements"></div>
@@ -82,118 +79,7 @@
</div>
</div>
-<div class="hand">
-<div id="card+1" class="card card_1"></div>
-<div id="card+2" class="card card_1"></div>
-<div id="card+3" class="card card_1"></div>
-<div id="card+4" class="card card_1"></div>
-<div id="card+5" class="card card_1"></div>
-<div id="card+6" class="card card_1"></div>
-<div id="card+7" class="card card_1"></div>
-<div id="card+8" class="card card_1"></div>
-<div id="card+9" class="card card_1"></div>
-<div id="card+10" class="card card_1"></div>
-<div id="card+11" class="card card_1"></div>
-<div id="card+12" class="card card_1"></div>
-<div id="card+13" class="card card_1"></div>
-<div id="card+14" class="card card_1"></div>
-<div id="card+15" class="card card_1"></div>
-<div id="card+16" class="card card_1"></div>
-<div id="card+17" class="card card_1"></div>
-<div id="card+18" class="card card_1"></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_23"></div>
-<div id="card+24" class="card card_23"></div>
-<div id="card+25" class="card card_23"></div>
-<div id="card+26" class="card card_23"></div>
-<div id="card+27" class="card card_23"></div>
-<div id="card+28" class="card card_23"></div>
-<div id="card+29" class="card card_23"></div>
-<div id="card+30" class="card card_23"></div>
-<div id="card+31" class="card card_23"></div>
-<div id="card+32" class="card card_23"></div>
-<div id="card+33" class="card card_23"></div>
-<div id="card+34" class="card card_23"></div>
-<div id="card+35" class="card card_23"></div>
-<div id="card+36" class="card card_23"></div>
-<div id="card+37" class="card card_23"></div>
-<div id="card+38" class="card card_23"></div>
-<div id="card+39" class="card card_23"></div>
-<div id="card+40" class="card card_23"></div>
-<div id="card+41" class="card card_23"></div>
-<div id="card+42" class="card card_23"></div>
-<div id="card+43" class="card card_23"></div>
-<div id="card+44" class="card card_23"></div>
-<div id="card+45" class="card card_45"></div>
-<div id="card+46" class="card card_45"></div>
-<div id="card+47" class="card card_45"></div>
-<div id="card+48" class="card card_45"></div>
-<div id="card+49" class="card card_45"></div>
-<div id="card+50" class="card card_45"></div>
-<div id="card+51" class="card card_45"></div>
-<div id="card+52" class="card card_45"></div>
-<div id="card+53" class="card card_45"></div>
-<div id="card+54" class="card card_45"></div>
-<div id="card+55" class="card card_45"></div>
-<div id="card+56" class="card card_45"></div>
-<div id="card+57" class="card card_45"></div>
-<div id="card+58" class="card card_45"></div>
-<div id="card+59" class="card card_45"></div>
-<div id="card+60" class="card card_45"></div>
-<div id="card+61" class="card card_45"></div>
-<div id="card+62" class="card card_45"></div>
-<div id="card+63" class="card card_45"></div>
-<div id="card+64" class="card card_45"></div>
-<div id="card+65" class="card card_45"></div>
-<div id="card+66" class="card card_45"></div>
-<div id="card+67" class="card card_67"></div>
-<div id="card+68" class="card card_68"></div>
-<div id="card+69" class="card card_69"></div>
-<div id="card+70" class="card card_70"></div>
-<div id="card+71" class="card card_71"></div>
-<div id="card+72" class="card card_72"></div>
-<div id="card+73" class="card card_73"></div>
-<div id="card+74" class="card card_74"></div>
-<div id="card+75" class="card card_75"></div>
-<div id="card+76" class="card card_76"></div>
-<div id="card+77" class="card card_77"></div>
-<div id="card+78" class="card card_78"></div>
-<div id="card+79" class="card card_79"></div>
-<div id="card+80" class="card card_80"></div>
-<div id="card+81" class="card card_81"></div>
-<div id="card+82" class="card card_82"></div>
-<div id="card+83" class="card card_83"></div>
-<div id="card+84" class="card card_84"></div>
-<div id="card+85" class="card card_85"></div>
-<div id="card+86" class="card card_86"></div>
-<div id="card+87" class="card card_87"></div>
-<div id="card+88" class="card card_88"></div>
-<div id="card+89" class="card card_89"></div>
-<div id="card+90" class="card card_90"></div>
-<div id="card+91" class="card card_91"></div>
-<div id="card+92" class="card card_92"></div>
-<div id="card+93" class="card card_93"></div>
-<div id="card+94" class="card card_94"></div>
-<div id="card+95" class="card card_95"></div>
-<div id="card+96" class="card card_96"></div>
-<div id="card+97" class="card card_97"></div>
-<div id="card+98" class="card card_98"></div>
-<div id="card+99" class="card card_99"></div>
-<div id="card+100" class="card card_100"></div>
-<div id="card+101" class="card card_101"></div>
-<div id="card+102" class="card card_102"></div>
-<div id="card+103" class="card card_103"></div>
-<div id="card+104" class="card card_104"></div>
-<div id="card+105" class="card card_105"></div>
-<div id="card+106" class="card card_106"></div>
-<div id="card+107" class="card card_107"></div>
-<div id="card+108" class="card card_108"></div>
-<div id="card+109" class="card card_109"></div>
-<div id="card+110" class="card card_110"></div>
-</div>
+<div id="hand"></div>
</main>
diff --git a/play.js b/play.js
index cd613d8..fd5c7e1 100644
--- a/play.js
+++ b/play.js
@@ -1,5 +1,45 @@
"use strict"
+/*
+ global view, data, player, send_action, action_button, scroll_with_middle_mouse
+*/
+
+/* COMMON */
+
+function set_has(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return true
+ }
+ return false
+}
+
+function map_get(map, key, missing) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m << 1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return map[(m << 1) + 1]
+ }
+ return missing
+}
+
+/* DATA */
+
const PC_NONE = 0
const PC_BRITISH = 1
const PC_AMERICAN = 2
@@ -14,11 +54,10 @@ const CU_FRENCH_MASK = 7 << CU_FRENCH_SHIFT
const GENERALS = data.generals
const CARDS = data.cards
const SPACES = data.spaces
-const COLONIES = data.colony_spaces
-const BOXES = data.BOXES
+const COLONIES = data.colonies
+const BOXES = data.layout
-const CONTINENTAL_CONGRESS_DISPERSED = data.space_index["Continental Congress Dispersed"]
-const BLOCKADE_ZONES = [ "Sea1", "Sea2", "Sea3", "Sea4", "Sea5", "Sea6", "Sea7" ]
+const BLOCKADE_ZONES = [ 0, 1, 2, 3, 4, 5, 6 ]
const P_BRITAIN = "Britain"
const P_AMERICA = "America"
@@ -29,35 +68,482 @@ const F_MUTINIES = 16
const space_count = 66
const general_count = data.generals.length
+const CAPTURED_GENERALS = data.space_index["Captured Generals"]
+const CONTINENTAL_CONGRESS_DISPERSED = data.space_index["Continental Congress Dispersed"]
+const BRITISH_REINFORCEMENTS = data.space_index["British Reinforcement Box"]
+const AMERICAN_REINFORCEMENTS = data.space_index["American Leader Reinforcements"]
+const FRENCH_REINFORCEMENTS = data.space_index["French Reinforcements"]
+const NOWHERE = data.spaces.length
+
+function is_british_general(g) {
+ return g >= 8
+}
+
+/* ACCESSORS */
+
+function get_space_pc(space) {
+ return view.cupc[space] & 3
+}
+
+function has_british_pc(space) {
+ return get_space_pc(space) === PC_BRITISH
+}
+
+function has_american_pc(space) {
+ return get_space_pc(space) === PC_AMERICAN
+}
+
+function count_british_cu(s) {
+ return (view.cupc[s] & CU_BRITISH_MASK) >>> CU_BRITISH_SHIFT
+}
+
+function count_american_cu(s) {
+ return (view.cupc[s] & CU_AMERICAN_MASK) >>> CU_AMERICAN_SHIFT
+}
+
+function count_french_cu(s) {
+ return (view.cupc[s] & CU_FRENCH_MASK) >>> CU_FRENCH_SHIFT
+}
+
+/* BUILD UI */
+
let ui = {
- cards: {},
+ favicon: document.getElementById("favicon"),
+ header: document.querySelector("header"),
+ status: document.getElementById("status"),
+
+ last_played: document.getElementById("last_played"),
+ hand: document.getElementById("hand"),
+ spaces_element: document.getElementById("spaces"),
+ pieces_element: document.getElementById("pieces"),
+
+ cards: [],
spaces: [],
+ seas: [],
+ a_pc: [],
+ b_pc: [],
+ a_colony: [],
+ b_colony: [],
+
+ a_cu: [],
+ b_cu: [],
+ f_cu: [],
+
generals: [],
- pc: [],
- cu: [],
- control: [],
+}
- blockade: {},
+function create(t, p, ...c) {
+ let e = document.createElement(t)
+ Object.assign(e, p)
+ e.append(c)
+ return e
}
-function on_focus_card_tip(card_number) {
- document.getElementById("tooltip").className = "card show card_" + card_number
+let action_register = []
+
+function register_action(target, action, id) {
+ target.my_action = action
+ target.my_id = id
+ target.onmousedown = on_click_action
+ action_register.push(target)
}
-function on_blur_card_tip() {
- document.getElementById("tooltip").classList = "card"
+function is_action(action, arg) {
+ if (arg === undefined)
+ return !!(view.actions && view.actions[action] === 1)
+ return !!(view.actions && view.actions[action] && set_has(view.actions[action], arg))
}
-function on_focus_last_card() {
- if (typeof view.last_card === 'number') {
- document.getElementById("tooltip").className = "card show card_" + view.last_card
+function on_click_action(evt) {
+ if (evt.button === 0)
+ send_action(evt.target.my_action, evt.target.my_id)
+}
+
+const SPACE_W = { fortified_port: 68, winter_quarters: 78, regular: 80, box: 100 }
+
+function build_marker(cn, x, y, w, h) {
+ let e = document.createElement("div")
+ e.className = cn
+ e.style.top = Math.round(y - h/2) + "px"
+ e.style.left = Math.round(x - w/2) + "px"
+ return e
+}
+
+function build_piece(cn, w, h) {
+ let e = document.createElement("div")
+ e.className = cn
+ e.my_dx = w >> 1
+ e.my_dy = h >> 1
+ return e
+}
+
+function on_init() {
+ for (let c = 0; c <= 110; ++c) {
+ let e = ui.cards[c] = document.createElement("div")
+ e.className = "card card_" + c
+ if (c > 0) {
+ e.my_id = c
+ e.onclick = on_click_card
+ }
+ }
+
+ for (let s = 0; s < data.spaces.length; ++s) {
+ let info = data.spaces[s]
+
+ let e = ui.spaces[s] = document.createElement("div")
+ let x = info.x
+ let y = info.y
+ let w = SPACE_W[info.type]
+ let h = SPACE_W[info.type]
+
+ if (info.type === "box") {
+ x = data.layout.box[info.name][0]
+ y = data.layout.box[info.name][1]
+ w = data.layout.box[info.name][2]
+ h = data.layout.box[info.name][3]
+ }
+
+ e.className = "space " + info.type + " " + data.colony_name[info.colony]
+ e.style.left = x - w/2 + "px"
+ e.style.top = y - h/2 + "px"
+ e.style.width = w - 10 + "px"
+ e.style.height = h - 10 + "px"
+
+ register_action(e, "space", s)
+
+ ui.spaces_element.appendChild(e)
+
+ ui.b_pc[s] = build_marker("marker pc british", x, y, 58, 66)
+ ui.a_pc[s] = build_marker("marker pc american", x, y, 58, 66)
+
+ if (info.type === "box") {
+ x += w/2
+ y += h - 50
+ ui.b_cu[s] = build_marker("marker cu british", x, y, 60+2, 60+2)
+ ui.a_cu[s] = build_marker("marker cu american", x, y, 60+2, 60+2)
+ ui.f_cu[s] = build_marker("marker cu french", x, y, 60+2, 60+2)
+ } else {
+ ui.b_cu[s] = build_marker("marker cu british", x-20, y+15, 60+2, 60+2)
+ ui.a_cu[s] = build_marker("marker cu american", x-20, y+15, 60+2, 60+2)
+ ui.f_cu[s] = build_marker("marker cu french", x+10, y+15, 60+2, 60+2)
+ }
}
+
+ ui.b_mcu = build_piece("marker cu british", 60+2, 60+2)
+ ui.a_mcu = build_piece("marker cu american", 60+2, 60+2)
+ ui.f_mcu = build_piece("marker cu french", 60+2, 60+2)
+
+ for (let s = 0; s < 7; ++s) {
+ let e = ui.seas[s] = document.createElement("div")
+ let [ x, y, w, h ] = data.layout.sea[s]
+ e.className = "space sea"
+ e.style.left = x + "px"
+ e.style.top = y + "px"
+ e.style.width = w - 14 + "px"
+ e.style.height = h - 14 + "px"
+
+ register_action(e, "sea", s)
+
+ ui.spaces_element.appendChild(e)
+ }
+
+ for (let g = 0; g < general_count; ++g) {
+ let e = ui.generals[g] = build_piece("marker general small " + data.generals[g].name, 45+2, 45+2)
+ register_action(e, "general", g)
+ }
+
+ for (let i = 0; i < 14; ++i) {
+ let [ x, y ] = data.layout.colony[i]
+ ui.a_colony[i] = build_marker("marker small control american", x, y, 45+2, 45+2)
+ ui.b_colony[i] = build_marker("marker small control british", x, y, 45+2, 45+2)
+ }
+
+ ui.turn_marker = build_piece("marker large turn", 55+2, 55+2)
+ ui.french_alliance = build_piece("marker large french_alliance", 55+2, 55+2)
}
-function on_blur_last_card() {
- document.getElementById("tooltip").classList = "card"
+on_init()
+
+/* UPDATE UI */
+
+function show_marker(e) {
+ ui.pieces_element.appendChild(e)
+}
+
+function toggle_marker(e, cond) {
+ if (cond)
+ show_marker(e)
+}
+
+function toggle_marker_with_number(e, n) {
+ if (n > 0) {
+ show_marker(e)
+ e.textContent = n
+ } else {
+ e.textContent = 0
+ }
+}
+
+function show_marker_at(e, x, y) {
+ show_marker(e)
+ e.style.left = x - e.my_dx + "px"
+ e.style.top = y - e.my_dy + "px"
+}
+
+function show_marker_at_xy(e, xy) {
+ show_marker_at(e, xy[0], xy[1])
+}
+
+function toggle_marker_with_number_at(e, n, x, y) {
+ if (n > 0) {
+ show_marker(e)
+ e.textContent = n
+ e.style.left = x - e.my_dx + "px"
+ e.style.top = y - e.my_dy + "px"
+ }
+}
+
+function player_info(player, nc, nq) {
+ let info = ""
+ if (player == P_AMERICA) {
+ if ((view.flags & F_MUTINIES) || view.congress === CONTINENTAL_CONGRESS_DISPERSED)
+ info += "\u{1f6ab} "
+ }
+ if (nq > 0)
+ info += nq + "\u{231b} "
+ info += nc + "\u{1f3b4}"
+ return info
+}
+
+function general_offset(g) {
+ let n = 0
+ for (let i = 0; i < g; ++i) {
+ if (view.move && view.move.who === i)
+ continue
+ if (view.loca[i] === view.loca[g])
+ ++n
+ }
+ return n
}
+function general_total(g) {
+ let n = 0
+ for (let i = 0; i < general_count; ++i) {
+ if (view.move && view.move.who === i)
+ continue
+ if (view.loca[i] === view.loca[g])
+ ++n
+ }
+ return n
+}
+
+function on_update() {
+ let e
+
+ roles.America.stat.textContent = player_info(P_AMERICA, view.a_cards, view.a_queue)
+ roles.Britain.stat.textContent = player_info(P_BRITAIN, view.b_cards, view.b_queue)
+
+ ui.last_played.className = "card shrink card_" + view.last_played
+
+ ui.pieces_element.replaceChildren()
+
+ for (let s = 0; s < data.spaces.length; ++s) {
+ toggle_marker(ui.b_pc[s], has_british_pc(s))
+ toggle_marker(ui.a_pc[s], has_american_pc(s))
+
+ if (view.move && view.move.to === s) {
+ toggle_marker_with_number(ui.a_cu[s], count_american_cu(s) - view.move.carry_american)
+ toggle_marker_with_number(ui.f_cu[s], count_french_cu(s) - view.move.carry_french)
+ toggle_marker_with_number(ui.b_cu[s], count_british_cu(s) - view.move.carry_british)
+ } else {
+ toggle_marker_with_number(ui.a_cu[s], count_american_cu(s))
+ toggle_marker_with_number(ui.f_cu[s], count_french_cu(s))
+ toggle_marker_with_number(ui.b_cu[s], count_british_cu(s))
+ }
+ }
+
+ if (view.move) {
+ let s = view.move.to
+ let x = data.spaces[s].x
+ let y = data.spaces[s].y
+ if (s >= 66)
+ y -= 40
+
+ if (view.move.carry_american > 0 && view.move.carry_french > 0) {
+ toggle_marker_with_number_at(ui.a_mcu, view.move.carry_american, x-15, y - 40)
+ toggle_marker_with_number_at(ui.f_mcu, view.move.carry_french, x+15, y - 40)
+ } else {
+ toggle_marker_with_number_at(ui.a_mcu, view.move.carry_american, x, y - 40)
+ toggle_marker_with_number_at(ui.f_mcu, view.move.carry_french, x, y - 40)
+ }
+ toggle_marker_with_number_at(ui.b_mcu, view.move.carry_british, x, y - 40)
+ }
+
+ for (let g = 0; g < general_count; ++g) {
+ let s = view.loca[g]
+ if (s === NOWHERE)
+ continue
+
+ let { x, y } = data.spaces[s]
+
+ if (s !== FRENCH_REINFORCEMENTS && count_french_cu(s) > 0)
+ x += 30
+
+ if (view.move && view.move.who === g) {
+ ui.generals[g].classList.add("selected")
+ if (s >= 66)
+ y -= 40
+ y -= 40
+ x += 30
+ } else {
+ ui.generals[g].classList.remove("selected")
+ if (s < 66) {
+ let offset = general_offset(g)
+ x += offset * (45 + 9)
+ y += 15
+ } else {
+ let offset = -(general_total(g) - 1) / 2 + general_offset(g)
+ x += offset * (45 + 9)
+ y -= 15
+ }
+ }
+
+ show_marker_at(ui.generals[g], x, y)
+ }
+
+ for (let i = 0; i < 14; ++i) {
+ let control = 0
+ for (let s of data.colonies[i]) {
+ if (has_british_pc(s))
+ --control
+ else if (has_american_pc(s))
+ ++control
+ }
+ toggle_marker(ui.b_colony[i], control < 0)
+ toggle_marker(ui.a_colony[i], control > 0)
+ }
+
+ ui.turn_marker.classList.toggle("no_regulars", !(view.flags & F_REGULARS))
+ ui.french_alliance.classList.toggle("european_war", !!(view.flags & F_EUROPEAN_WAR))
+
+ show_marker_at_xy(ui.turn_marker, data.layout.turn[view.year])
+ show_marker_at_xy(ui.french_alliance, data.layout.french_alliance_track[view.french_alliance])
+
+ ui.hand.replaceChildren()
+ if (view.hand)
+ for (let c of view.hand)
+ ui.hand.appendChild(ui.cards[c])
+
+ e = document.getElementById("war_ends")
+ if (view.war_ends)
+ e.className = "year_" + CARDS[view.war_ends].year
+ else
+ e.className = ""
+
+ e = document.getElementById("played_british_reinforcements")
+ if (view.reinforcements[0] > 0)
+ e.className = "ops_" + CARDS[view.reinforcements[0]].count
+ else
+ e.className = ""
+
+ e = document.getElementById("played_american_reinforcements_1")
+ if (view.reinforcements[1] > 0)
+ e.className = "ops_" + CARDS[view.reinforcements[1]].count
+ else
+ e.className = ""
+
+ e = document.getElementById("played_american_reinforcements_2")
+ if (view.reinforcements[2] > 0)
+ e.className = "ops_" + CARDS[view.reinforcements[2]].count
+ else
+ e.className = ""
+
+ for (let e of action_register)
+ e.classList.toggle("action", is_action(e.my_action, e.my_id))
+
+ action_button("pickup_french_cu", "Take French CU")
+ action_button("pickup_british_cu", "Take CU")
+ action_button("pickup_american_cu", "Take CU")
+ action_button("drop_french_cu", "Drop French CU")
+ action_button("drop_british_cu", "Drop CU")
+ action_button("drop_american_cu", "Drop CU")
+
+ action_button("britain_first", "Britain")
+ action_button("america_first", "America")
+ action_button("surrender", "Surrender")
+ action_button("next", "Next")
+ action_button("done", "Done")
+ action_button("pass", "Pass")
+ action_button("undo", "Undo")
+}
+
+/* POPUP MENU */
+
+function show_popup_menu(evt, menu_id, card, title) {
+ let menu = document.getElementById(menu_id)
+
+ let show = false
+ for (let item of menu.querySelectorAll("li")) {
+ let action = item.dataset.action
+ if (action) {
+ if (is_action(action, card)) {
+ show = true
+ item.classList.add("action")
+ item.classList.remove("disabled")
+ item.onclick = function () {
+ send_action(action, card)
+ hide_popup_menu()
+ evt.stopPropagation()
+ }
+ } else {
+ item.classList.remove("action")
+ item.classList.add("disabled")
+ item.onclick = null
+ }
+ }
+ }
+
+ if (show) {
+ menu.onmouseleave = hide_popup_menu
+ menu.style.display = "block"
+ if (title) {
+ let item = menu.querySelector("li.title")
+ if (item) {
+ item.onclick = hide_popup_menu
+ item.textContent = title
+ }
+ }
+
+ let w = menu.clientWidth
+ let h = menu.clientHeight
+ let x = Math.max(5, Math.min(evt.clientX - w / 2, window.innerWidth - w - 5))
+ let y = Math.max(5, Math.min(evt.clientY - 12, window.innerHeight - h - 40))
+ menu.style.left = x + "px"
+ menu.style.top = y + "px"
+
+ evt.stopPropagation()
+ } else {
+ menu.style.display = "none"
+ }
+}
+
+function hide_popup_menu() {
+ document.getElementById("popup").style.display = "none"
+}
+
+function on_click_card(evt) {
+ if (view.actions) {
+ let c = evt.target.my_id
+ if (is_action("card", c))
+ send_action("card", c)
+ else
+ show_popup_menu(evt, "popup", c, data.cards[c].title)
+ }
+}
+
+/* LOG */
+
+/* OLD ---
function on_log(text) {
let p = document.createElement("div")
text = text.replace(/&/g, "&amp;")
@@ -83,6 +569,25 @@ function on_log(text) {
return p
}
+
+function on_focus_card_tip(card_number) {
+ document.getElementById("tooltip").className = "card show card_" + card_number
+}
+
+function on_blur_card_tip() {
+ document.getElementById("tooltip").classList = "card"
+}
+
+function on_focus_last_card() {
+ if (typeof view.last_card === 'number') {
+ document.getElementById("tooltip").className = "card show card_" + view.last_card
+ }
+}
+
+function on_blur_last_card() {
+ document.getElementById("tooltip").classList = "card"
+}
+
function clearList(container) {
while (container.firstChild)
container.removeChild(container.firstChild)
@@ -127,7 +632,7 @@ function update_marker(e, space) {
if (typeof space === "number")
box = SPACES[space]
else
- box = BOXES[space]
+ return
e.style.left = ((box.x - e.foo.w / 2) | 0) + "px"
e.style.top = ((box.y - e.foo.h / 2) | 0) + "px"
}
@@ -138,82 +643,14 @@ function update_marker_xy(e, x, y) {
}
function build_map() {
- function buildNode(type, x, y, colony) {
- let e = document.createElement("div")
- let w, h
- e.classList.add("space")
- e.classList.add(type)
- if (colony && colony != "SEA")
- e.classList.add("colony_" + colony)
- if (type === "regular-space") {
- w = 66
- h = 66
- } else if (type === "winter-quarters") {
- w = 66
- h = 66
- } else if (type === "fortified-port") {
- w = 54
- h = 54
- } else if (type === "blockade") {
- w = 96
- h = 80
- } else {
- w = 60
- h = 60
- }
- let b = 7
- w -= 2
- h -= 2
- e.style.left = x - w / 2 - b + "px"
- e.style.top = y - h / 2 - b + "px"
- e.style.width = w + "px"
- e.style.height = h + "px"
- return e
- }
-
- for (let i = 0; i < SPACES.length; ++i) {
- let space = SPACES[i]
- if (space.colony != null) {
- let e = buildNode(space.type, space.x, space.y, space.colony)
- e.my_id = i
- e.addEventListener("mouseenter", onFocusNode)
- e.addEventListener("mouseleave", onBlurNode)
- e.addEventListener("click", on_space)
- ui.spaces[i] = e
- document.getElementById("spaces").appendChild(e)
- ui.pc[i] = build_marker("pc", name + "-pc", space.x, space.y, 58, 66, [ "pc" ])
- }
- }
-
- for (let zone of BLOCKADE_ZONES) {
- let e = buildNode("blockade", BOXES[zone].x, BOXES[zone].y, "SEA")
- e.setAttribute("id", zone)
- e.addEventListener("click", on_space)
- document.getElementById("spaces").appendChild(e)
- ui.blockade[zone] = e
- }
-
- ui.turn = build_marker("markers", "GameTurn", BOXES["Game Turn 1775"].x, BOXES["Game Turn 1775"].y, 55, 55, [
- "turn",
- ])
-
- ui.french_alliance = build_marker(
- "markers",
- "FrenchAlliance",
- BOXES["French Alliance Track 0"].x,
- BOXES["French Alliance Track 0"].y,
- 55,
- 55,
- [ "french-alliance" ]
- )
ui.french_navy = build_marker(
"markers",
"FrenchNavy",
- SPACES[data.space_index["French Reinforcements"]].x - 130 / 2 - 10,
+ SPACES[data.space_index["French Reinforcements"]].x - 64 - 10,
SPACES[data.space_index["French Reinforcements"]].y - 32,
- 64,
- 130,
+ //64, 130,
+ 55, 55,
[ "french-navy" ]
)
@@ -227,44 +664,11 @@ function build_map() {
[ "congress" ]
)
- for (let c = 0; c <= 13; ++c) {
- let name = data.colony_name[c]
- ui.control[c] = build_marker("markers", "control_" + name, BOXES[name].x, BOXES[name].y, 45, 45, [ "control" ])
- }
-
- for (let c = 1; c <= 110; ++c) {
- ui.cards[c] = document.getElementById("card+" + c)
- ui.cards[c].addEventListener("click", on_card)
- }
-
- for (let g = 0; g < general_count; ++g) {
- let color = GENERALS[g].owner.toLowerCase()
- let name = GENERALS[g].name
- //ui.generals[g] = build_marker("generals", g, 0, 0, 64, 130, [ "general", "tall", color, name, "offmap" ])
- ui.generals[g] = build_marker("generals", g, 0, 0, 45, 45, [ "general", "small", color, name, "offmap" ])
- ui.generals[g].addEventListener("click", on_general)
- }
-}
-
-function get_space_pc(space) {
- return view.cupc[space] & 3
-}
-
-function count_british_cu(s) {
- return (view.cupc[s] & CU_BRITISH_MASK) >>> CU_BRITISH_SHIFT
-}
-
-function count_american_cu(s) {
- return (view.cupc[s] & CU_AMERICAN_MASK) >>> CU_AMERICAN_SHIFT
-}
-
-function count_french_cu(s) {
- return (view.cupc[s] & CU_FRENCH_MASK) >>> CU_FRENCH_SHIFT
}
function update_units() {
- const generalX = -22
- const generalY = 22
+ const generalX = 50
+ const generalY = 0
const cuX = 20
const cuY = 10
@@ -283,12 +687,9 @@ function update_units() {
ui.french_alliance.classList.remove("european-war")
if (view.french_navy < 0) {
- let x = SPACES[data.space_index["French Reinforcements"]].x - 130 / 2 - 10
+ let x = SPACES[data.space_index["French Reinforcements"]].x - 64 - 10
let y = SPACES[data.space_index["French Reinforcements"]].y - 32
- let w = 126 / 2
- let h = 252 / 2
- ui.french_navy.style.left = ((x - w / 2) | 0) + "px"
- ui.french_navy.style.top = ((y - h / 2) | 0) + "px"
+ update_marker_xy(ui.french_navy, x, y)
} else {
let s
if (view.french_navy > 1700)
@@ -329,15 +730,23 @@ function update_units() {
ui.control[c].className = "marker control"
}
+ let count = []
+ for (let g in GENERALS) {
+ let loc = view.loca[g]
+ count[loc] = (count[loc] | 0) + 1
+ }
+
let offset = []
for (let g in GENERALS) {
let e = ui.generals[g]
let loc = view.loca[g]
let space = SPACES[loc] || BOXES[loc]
if (space) {
+ let n = count[loc]
let o = offset[loc] | 0
- // update_marker_xy(e, space.x + o * generalX, space.y + o * generalY - 32)
- update_marker_xy(e, space.x + o * generalX + 20, space.y + o * generalY - 20)
+ let oo = 0 + o // -(n-1)/2 + o
+ // update_marker_xy(e, space.x + oo * generalX, space.y + oo * generalY - 32)
+ update_marker_xy(e, space.x + oo * generalX + 20, space.y + oo * generalY - 10)
e.classList.remove("offmap")
offset[loc] = ++o
} else {
@@ -592,3 +1001,4 @@ function on_general(evt) {
function toggle_markers() {
document.querySelector("#map").classList.toggle("hide_markers")
}
+*/
diff --git a/rules.js b/rules.js
index 39f5e6f..e9a1d24 100644
--- a/rules.js
+++ b/rules.js
@@ -10,7 +10,7 @@ const data = require("./data.js")
const CARDS = data.cards
const SPACES = data.spaces
-const COLONIES = data.colony_spaces
+const COLONIES = data.colonies
const GENERALS = data.generals
const Canada = 0
@@ -76,7 +76,7 @@ const WILMINGTON_NC = data.space_index["Wilmington NC"]
const CAPTURED_GENERALS = data.space_index["Captured Generals"]
const CONTINENTAL_CONGRESS_DISPERSED = data.space_index["Continental Congress Dispersed"]
-const BRITISH_REINFORCEMENTS = data.space_index["British Leader Reinforcements"]
+const BRITISH_REINFORCEMENTS = data.space_index["British Reinforcement Box"]
const AMERICAN_REINFORCEMENTS = data.space_index["American Leader Reinforcements"]
const FRENCH_REINFORCEMENTS = data.space_index["French Reinforcements"]
const NOWHERE = data.spaces.length
@@ -339,16 +339,16 @@ function is_map_space(s) {
}
function is_port(where) {
- return SPACES[where].port
+ return SPACES[where].port >= 0
}
function is_non_blockaded_port(where) {
let port = SPACES[where].port
- return (port > 0 && port !== game.french_navy)
+ return (port >= 0 && port !== game.french_navy)
}
function is_fortified_port(where) {
- return SPACES[where].type === "fortified-port"
+ return SPACES[where].type === "fortified_port"
}
function is_continental_congress_dispersed() {
@@ -360,7 +360,7 @@ function is_winter_quarter_space(where) {
if (set_has(SOUTH_OF_WINTER_ATTRITION_LINE, colony))
return true // south of winter attrition line
let type = SPACES[where].type
- if (type === "winter-quarters" || type === "fortified-port")
+ if (type === "winter_quarters" || type === "fortified_port")
return true
return false
}
@@ -421,9 +421,9 @@ function is_adjacent_to_british_pc(a) {
for (let b of SPACES[a].adjacent)
if (has_british_pc(b))
return true
- if (SPACES[a].port) {
+ if (is_port(a)) {
for (let b of all_spaces) {
- if (SPACES[b].port)
+ if (is_port(b))
if (has_british_pc(b))
return true
}
@@ -971,7 +971,7 @@ function gen_remove_british_pc_from(list_of_colonies) {
for (let colony of list_of_colonies) {
for (let space of COLONIES[colony]) {
if (has_british_pc(space) && has_no_british_cu(space)) {
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
}
}
@@ -980,7 +980,7 @@ function gen_remove_british_pc_from(list_of_colonies) {
function gen_remove_american_pc() {
for (let space of all_spaces) {
if (has_american_pc(space) && has_no_american_unit(space)) {
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
}
}
@@ -989,7 +989,7 @@ function gen_remove_american_pc_from(list_of_colonies) {
for (let colony of list_of_colonies) {
for (let space of COLONIES[colony]) {
if (has_american_pc(space) && has_no_american_unit(space)) {
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
}
}
@@ -998,9 +998,9 @@ function gen_remove_american_pc_from(list_of_colonies) {
function gen_remove_american_pc_from_non_port(list_of_colonies) {
for (let colony of list_of_colonies) {
for (let space of COLONIES[colony]) {
- if (!SPACES[space].port) {
+ if (!is_port(space)) {
if (has_american_pc(space) && has_no_american_unit(space)) {
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1023,13 +1023,13 @@ function gen_remove_american_pc_within_two_spaces_of_a_british_general() {
}
for (let space of candidates)
if (has_american_pc(space) && has_no_american_unit(space))
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
function gen_place_american_pc() {
for (let space of all_spaces) {
if (has_no_pc(space) && has_no_british_playing_piece(space)) {
- gen_action("place_american_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1038,7 +1038,7 @@ function gen_place_american_pc_in(list_of_colonies) {
for (let colony of list_of_colonies) {
for (let space of COLONIES[colony]) {
if (has_no_pc(space) && has_no_british_playing_piece(space)) {
- gen_action("place_american_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1047,7 +1047,7 @@ function gen_place_american_pc_in(list_of_colonies) {
/* SETUP PHASE */
function goto_committees_of_correspondence() {
- log(".h2.american Committes of Correspondence")
+ log("=a Committes of Correspondence")
logbr()
game.active = P_AMERICA
game.state = "committees_of_correspondence"
@@ -1062,15 +1062,15 @@ states.committees_of_correspondence = {
if (game.colonies.length > 0)
gen_place_american_pc_in(game.colonies)
else
- gen_pass()
+ view.actions.next = 1
},
- place_american_pc(space) {
+ space(s) {
push_undo()
- let colony = SPACES[space].colony
+ let colony = SPACES[s].colony
set_delete(game.colonies, colony)
- place_american_pc(space)
+ place_american_pc(s)
},
- pass() {
+ next() {
clear_undo()
delete game.colonies
goto_for_the_king()
@@ -1079,7 +1079,7 @@ states.committees_of_correspondence = {
function goto_for_the_king() {
logbr()
- log(".h2.british For the King")
+ log("=b For the King")
logbr()
game.active = P_BRITAIN
game.state = "for_the_king"
@@ -1094,14 +1094,14 @@ states.for_the_king = {
if (game.count > 0)
gen_british_pc_ops()
else
- gen_pass()
+ view.actions.next = 1
},
- place_british_pc(space) {
+ space(s) {
push_undo()
- place_british_pc(space)
+ place_british_pc(s)
--game.count
},
- pass() {
+ next() {
clear_undo()
gen_british_pc_ops_end()
goto_start_year()
@@ -1139,7 +1139,7 @@ function automatic_victory() {
function goto_start_year() {
logbr()
- log(".h1 Year " + game.year)
+ log("# Year " + game.year)
logbr()
// Prisoner exchange
@@ -1211,7 +1211,7 @@ states.british_declare_first = {
gen_pass()
for (let c of CAMPAIGN_CARDS) {
if (game.b_hand.includes(c)) {
- gen_action("card_campaign", c)
+ gen_action_card("card_campaign", c)
}
}
},
@@ -1254,9 +1254,9 @@ function goto_strategy_phase(new_active) {
game.state = "strategy_phase"
logbr()
if (game.active === P_AMERICA)
- log(".h2.american American Turn")
+ log("=a America")
else
- log(".h2.british British Turn")
+ log("=b Britain")
logbr()
}
@@ -1374,38 +1374,38 @@ function gen_strategy_plays(hand) {
let card = CARDS[c]
switch (card.type) {
case "mandatory-event":
- gen_action("card_play_event", c)
+ gen_action_card("card_play_event", c)
break
case "campaign":
- gen_action("card_campaign", c)
+ gen_action_card("card_campaign", c)
break
case "ops":
if (can_exchange_for_discard(c))
- gen_action("exchange_for_discard", c)
+ gen_action_card("exchange_for_discard", c)
if (can_activate_general(c))
- gen_action("card_ops_general", c)
- gen_action("card_ops_pc", c)
+ gen_action_card("card_ops_general", c)
+ gen_action_card("card_ops_pc", c)
if (can_play_reinforcements())
- gen_action("card_ops_reinforcements", c)
+ gen_action_card("card_ops_reinforcements", c)
if (card.count < 3)
- gen_action("card_ops_queue", c)
+ gen_action_card("card_ops_queue", c)
break
case "british-event":
case "british-event-or-battle":
if (game.active === P_BRITAIN)
if (can_play_event(c))
- gen_action("card_play_event", c)
- gen_action("card_discard_event", c)
+ gen_action_card("card_play_event", c)
+ gen_action_card("card_discard_event", c)
break
case "american-event":
if (game.active === P_AMERICA)
if (can_play_event(c))
- gen_action("card_play_event", c)
- gen_action("card_discard_event", c)
+ gen_action_card("card_play_event", c)
+ gen_action_card("card_discard_event", c)
break
case "british-battle":
case "american-battle":
- gen_action("card_discard_event", c)
+ gen_action_card("card_discard_event", c)
break
}
}
@@ -1422,20 +1422,22 @@ states.discard_event_pc_action = {
else
gen_american_discard_event_pc_action()
},
- place_british_pc(space) {
- place_british_pc(space)
- end_strategy_card()
- },
- place_american_pc(space) {
- place_american_pc(space)
- end_strategy_card()
- },
- remove_pc(space) {
- remove_pc(space)
- end_strategy_card()
- },
- flip_pc(space) {
- flip_pc(space)
+ space(s) {
+ if (game.active === P_BRITAIN) {
+ if (has_no_pc(s))
+ place_british_pc(s)
+ else if (has_british_army(s))
+ flip_pc(s)
+ else
+ remove_pc(s)
+ } else {
+ if (has_no_pc(s))
+ place_american_pc(s)
+ else if (has_british_army(s))
+ flip_pc(s)
+ else
+ remove_pc(s)
+ }
end_strategy_card()
},
pass() {
@@ -1447,11 +1449,11 @@ function gen_british_discard_event_pc_action() {
for (let space of all_spaces) {
if (is_adjacent_to_british_pc(space)) {
if (has_no_pc(space) && has_no_american_unit(space))
- gen_action("place_british_pc", space)
+ gen_action_space(space)
else if (has_american_pc(space) && has_british_army(space))
- gen_action("flip_pc", space)
+ gen_action_space(space)
else if (has_american_pc(space) && has_no_american_unit(space))
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1461,11 +1463,11 @@ function gen_american_discard_event_pc_action() {
if (is_adjacent_to_american_pc(space)) {
if (has_no_pc(space) && has_no_british_cu(space)) {
if (allowed_to_place_american_pc())
- gen_action("place_american_pc", space)
+ gen_action_space(space)
} else if (has_british_pc(space) && has_american_or_french_general(space)) {
- gen_action("flip_pc", space)
+ gen_action_space(space)
} else if (has_british_pc(space) && has_no_british_cu(space)) {
- gen_action("remove_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1491,19 +1493,19 @@ states.ops_pc = {
gen_american_pc_ops()
}
},
- place_british_pc(space) {
- push_undo()
- place_british_pc(space)
- --game.count
- },
- place_american_pc(space) {
- push_undo()
- place_american_pc(space)
- --game.count
- },
- flip_pc(space) {
+ space(s) {
push_undo()
- flip_pc(space)
+ if (game.active === P_BRITAIN) {
+ if (has_american_pc(s))
+ flip_pc(s)
+ else
+ place_british_pc(s)
+ } else {
+ if (has_british_pc(s))
+ flip_pc(s)
+ else
+ place_american_pc(s)
+ }
--game.count
},
pass() {
@@ -1525,13 +1527,13 @@ function gen_british_pc_ops_start() {
function gen_british_pc_ops() {
for (let space of game.british_pc_space_list)
- gen_action("place_british_pc", space)
+ gen_action_space(space)
for (let space of all_spaces) {
if (has_british_army(space)) {
if (has_no_pc(space))
- gen_action("place_british_pc", space)
+ gen_action_space(space)
else if (has_american_pc(space))
- gen_action("flip_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1544,9 +1546,9 @@ function gen_american_pc_ops() {
for (let space of all_spaces) {
if (has_no_pc(space) && has_no_british_cu(space)) {
if (allowed_to_place_american_pc())
- gen_action("place_american_pc", space)
+ gen_action_space(space)
} else if (has_british_pc(space) && has_american_or_french_general(space)) {
- gen_action("flip_pc", space)
+ gen_action_space(space)
}
}
}
@@ -1574,6 +1576,7 @@ states.ops_british_reinforcements_who = {
prompt() {
view.prompt = "Reinforcements: choose an available general or pass to bring only CU."
view.prompt += " Carrying " + game.count + " British CU."
+ view.move = { to: BRITISH_REINFORCEMENTS, who: NOBODY, carry_british: game.count }
gen_pass()
gen_british_reinforcements_who()
},
@@ -1583,7 +1586,7 @@ states.ops_british_reinforcements_who = {
pickup_british_cu() {
++game.count
},
- select_general(g) {
+ general(g) {
push_undo()
game.state = "ops_british_reinforcements_where"
game.who = g
@@ -1599,6 +1602,7 @@ states.ops_british_reinforcements_where = {
prompt() {
view.prompt = "Reinforcements: choose a port space."
view.prompt += " Carrying " + game.count + " British CU."
+ view.move = { to: BRITISH_REINFORCEMENTS, who: game.who, carry_british: game.count }
gen_british_reinforcements_where()
},
drop_british_cu() {
@@ -1607,7 +1611,7 @@ states.ops_british_reinforcements_where = {
pickup_british_cu() {
++game.count
},
- place_reinforcements(space) {
+ space(space) {
place_british_reinforcements(game.who, game.count, space)
end_strategy_card()
delete game.who
@@ -1617,10 +1621,11 @@ states.ops_british_reinforcements_where = {
states.ops_american_reinforcements_who = {
prompt() {
view.prompt = "Reinforcements: choose an available general or pass to bring only CU."
+ view.move = { to: AMERICAN_REINFORCEMENTS, who: NOBODY, carry_american: game.count }
gen_pass()
gen_american_reinforcements_who()
},
- select_general(g) {
+ general(g) {
push_undo()
game.state = "ops_american_reinforcements_where"
game.who = g
@@ -1635,9 +1640,10 @@ states.ops_american_reinforcements_who = {
states.ops_american_reinforcements_where = {
prompt() {
view.prompt = "Reinforcements: choose a space."
+ view.move = { to: AMERICAN_REINFORCEMENTS, who: game.who, carry_american: game.count }
gen_american_reinforcements_where(game.who)
},
- place_reinforcements(space) {
+ space(space) {
if (game.who === ROCHAMBEAU)
place_french_reinforcements(game.who, space)
else
@@ -1650,7 +1656,7 @@ states.ops_american_reinforcements_where = {
function gen_british_reinforcements_who() {
for (let g of BRITISH_GENERALS) {
if (is_general_at_location(g, BRITISH_REINFORCEMENTS)) {
- gen_action("select_general", g)
+ gen_action_general(g)
}
}
if (game.count > 0)
@@ -1663,7 +1669,7 @@ function gen_british_reinforcements_where() {
for (let space of all_spaces) {
if (is_non_blockaded_port(space))
if (!has_american_or_french_cu(space) && !has_american_pc(space))
- gen_action("place_reinforcements", space)
+ gen_action_space(space)
}
if (game.count > 0)
gen_action("drop_british_cu")
@@ -1674,7 +1680,7 @@ function gen_british_reinforcements_where() {
function gen_american_reinforcements_who() {
for (let g of AMERICAN_GENERALS) {
if (is_general_at_location(g, AMERICAN_REINFORCEMENTS)) {
- gen_action("select_general", g)
+ gen_action_general(g)
}
}
}
@@ -1683,10 +1689,10 @@ function gen_american_reinforcements_where(general) {
for (let space of all_spaces) {
if (!has_british_cu(space) && !has_british_pc(space)) {
if (general === ROCHAMBEAU) {
- if (SPACES[space].port)
- gen_action("place_reinforcements", space)
+ if (is_port(space))
+ gen_action_space(space)
} else {
- gen_action("place_reinforcements", space)
+ gen_action_space(space)
}
}
}
@@ -1729,7 +1735,7 @@ states.ops_general_who = {
flip_pc(where)
end_strategy_card()
},
- select_general(g) {
+ general(g) {
push_undo()
goto_ops_general_move(g, false)
},
@@ -1761,13 +1767,13 @@ function gen_activate_general() {
function gen_activate_british_general() {
for (let g of BRITISH_GENERALS)
if (is_general_on_map(g) && GENERALS[g].strategy <= game.count && !has_general_moved(g))
- gen_action("select_general", g)
+ gen_action_general(g)
}
function gen_activate_american_general() {
for (let g of AMERICAN_GENERALS)
if (is_general_on_map(g) && GENERALS[g].strategy <= game.count && !has_general_moved(g))
- gen_action("select_general", g)
+ gen_action_general(g)
}
function goto_remove_general(where) {
@@ -1778,9 +1784,9 @@ function goto_remove_general(where) {
states.remove_general = {
prompt() {
view.prompt = "Remove a general to the reinforcements box."
- gen_remove_general()
+ gen_remove_general(game.where)
},
- select_general(g) {
+ general(g) {
if (game.active === P_BRITAIN)
move_general(g, BRITISH_REINFORCEMENTS)
else
@@ -1796,9 +1802,9 @@ function goto_remove_general_after_intercept() {
states.remove_general_after_intercept = {
prompt() {
view.prompt = "Remove a general to the reinforcements box."
- gen_remove_general()
+ gen_remove_general(game.move.to)
},
- select_general(g) {
+ general(g) {
if (game.active === P_BRITAIN)
move_general(g, BRITISH_REINFORCEMENTS)
else
@@ -1815,9 +1821,9 @@ function goto_remove_general_after_retreat(where) {
states.remove_general_after_retreat = {
prompt() {
view.prompt = "Remove a general to the reinforcements box."
- gen_remove_general()
+ gen_remove_general(game.where)
},
- select_general(g) {
+ general(g) {
if (game.active === P_BRITAIN)
move_general(g, BRITISH_REINFORCEMENTS)
else
@@ -1826,24 +1832,24 @@ states.remove_general_after_retreat = {
},
}
-function gen_remove_general() {
+function gen_remove_general(where) {
if (game.active === P_BRITAIN)
- return gen_remove_british_general()
+ return gen_remove_british_general(where)
else
- return gen_remove_american_general()
+ return gen_remove_american_general(where)
}
-function gen_remove_british_general() {
+function gen_remove_british_general(where) {
for (let g of BRITISH_GENERALS)
- if (is_general_at_location(g, game.where))
- gen_action("select_general", g)
+ if (is_general_at_location(g, where))
+ gen_action_general(g)
}
-function gen_remove_american_general() {
+function gen_remove_american_general(where) {
for (let g of AMERICAN_GENERALS)
if (g !== WASHINGTON)
- if (is_general_at_location(g, game.where))
- gen_action("select_general", g)
+ if (is_general_at_location(g, where))
+ gen_action_general(g)
}
function goto_ops_general_move(g, marblehead) {
@@ -1942,7 +1948,7 @@ states.ops_general_move = {
mark_moved_french_cu(location_of_general(game.move.who), 1)
},
- move(to) {
+ space(to) {
push_undo()
set_general_moved(game.move.who)
@@ -2011,7 +2017,7 @@ function gen_intercept() {
if (has_american_army(space)) {
let g = find_american_or_french_general(space)
if (g && !has_general_moved(g))
- gen_action("select_general", g)
+ gen_action_general(g)
}
}
}
@@ -2028,7 +2034,7 @@ states.intercept = {
gen_pass()
gen_intercept()
},
- select_general(g) {
+ general(g) {
set_general_moved(g)
let die = roll_d6()
if (die <= GENERALS[g].agility) {
@@ -2145,10 +2151,10 @@ function gen_move_general() {
if (game.move.mobility && has_enemy_cu(to)) {
if (game.move.count - mp >= 1)
- gen_action("move", to)
+ gen_action_space(to)
} else {
if (game.move.count - mp >= 0)
- gen_action("move", to)
+ gen_action_space(to)
}
}
if (game.active === P_BRITAIN && game.count === 4) {
@@ -2161,7 +2167,7 @@ function gen_move_general() {
if (alone && has_enemy_general(to))
continue
// TODO: duplicate action if can move by normal road
- gen_action("move", to)
+ gen_action_space(to)
}
}
}
@@ -2271,7 +2277,7 @@ states.remove_british_pc_from = {
gen_pass()
gen_remove_british_pc_from(game.where)
},
- remove_pc(where) {
+ space(where) {
remove_pc(where)
if (--game.count === 0) {
delete game.where
@@ -2296,7 +2302,7 @@ states.remove_american_pc = {
gen_pass()
gen_remove_american_pc()
},
- remove_pc(where) {
+ space(where) {
remove_pc(where)
if (--game.count === 0) {
end_strategy_card()
@@ -2320,7 +2326,7 @@ states.remove_american_pc_from = {
gen_pass()
gen_remove_american_pc_from(game.where)
},
- remove_pc(where) {
+ space(where) {
remove_pc(where)
if (--game.count === 0) {
delete game.where
@@ -2347,7 +2353,7 @@ states.remove_american_pc_from_non_port = {
gen_pass()
gen_remove_american_pc_from_non_port(game.where)
},
- remove_pc(where) {
+ space(where) {
remove_pc(where)
if (--game.count === 0) {
delete game.where
@@ -2372,7 +2378,7 @@ states.remove_american_pc_within_two_spaces_of_a_british_general = {
gen_pass()
gen_remove_american_pc_within_two_spaces_of_a_british_general()
},
- remove_pc(where) {
+ space(where) {
remove_pc(where)
if (--game.count === 0) {
delete game.where
@@ -2447,16 +2453,17 @@ states.lord_sandwich_coastal_raids = {
gen_pass()
gen_lord_sandwich_coastal_raids(game.where)
},
- place_british_pc(where) {
- place_british_pc(where)
+ space(where) {
+ if (has_american_pc(space)) {
+ game.where = where
+ remove_pc(where)
+ if (--game.count === 0)
+ end_strategy_card()
+ } else {
+ place_british_pc(where)
+ }
end_strategy_card()
},
- remove_pc(where) {
- game.where = where
- remove_pc(where)
- if (--game.count === 0)
- end_strategy_card()
- },
pass() {
end_strategy_card()
},
@@ -2464,11 +2471,11 @@ states.lord_sandwich_coastal_raids = {
function gen_lord_sandwich_coastal_raids(first_removed) {
for (let space of all_spaces) {
- if (SPACES[space].port)
+ if (is_port(space))
if (has_american_pc(space) && has_no_american_unit(space))
- gen_action("remove_pc", space)
+ gen_action_space(space)
if (space === first_removed)
- gen_action("place_british_pc", space)
+ gen_action_space(space)
}
}
@@ -2578,7 +2585,7 @@ states.john_glovers_marblehead_regiment_who = {
view.prompt = "Activate an American general."
gen_activate_general()
},
- select_general(g) {
+ general(g) {
goto_ops_general_move(g, true)
},
}
@@ -2638,7 +2645,7 @@ states.george_washington_captured = {
gen_pass()
gen_remove_american_pc()
},
- remove_pc(where) {
+ space(where) {
remove_pc(where)
if (--game.count === 0) {
end_george_washington_captured()
@@ -2706,7 +2713,7 @@ states.retreat_before_battle = {
gen_pass()
gen_defender_retreat()
},
- move(to) {
+ space(to) {
let who = find_american_or_french_general(game.move.to)
let agility = GENERALS[who].agility
if (GENERALS[who].bonus)
@@ -2739,9 +2746,9 @@ function goto_remove_general_after_retreat_before_battle(where) {
states.remove_general_after_retreat_before_battle = {
prompt() {
view.prompt = "Remove a general to the reinforcements box."
- gen_remove_general()
+ gen_remove_general(game.where)
},
- select_general(g) {
+ general(g) {
if (game.active === P_BRITAIN)
move_general(g, BRITISH_REINFORCEMENTS)
else
@@ -2786,7 +2793,7 @@ function gen_defender_retreat() {
let from = game.move.to
for (let to of SPACES[from].adjacent) {
if (can_defender_retreat(to))
- gen_action("move", to)
+ gen_action_space(to)
}
if (game.active === P_BRITAIN) {
let can_sea_retreat = false
@@ -2802,7 +2809,7 @@ function gen_defender_retreat() {
for (let to of all_spaces) {
if (to !== from && is_non_blockaded_port(to)) {
if (!has_american_pc(to) && !has_american_or_french_cu(to)) {
- gen_action("move", to)
+ gen_action_space(to)
}
}
}
@@ -2812,7 +2819,7 @@ function gen_defender_retreat() {
function gen_attacker_retreat() {
if (can_attacker_retreat())
- gen_action("move", game.move.from)
+ gen_action_space(game.move.from)
}
function end_retreat_before_battle() {
@@ -2906,12 +2913,12 @@ function gen_battle_card() {
switch (card.type) {
case "british-battle":
case "british-event-or-battle":
- gen_action("card_battle_play", c)
+ gen_action_card("card_battle_play", c)
break
case "british-event":
case "american-event":
case "american-battle":
- gen_action("card_battle_discard", c)
+ gen_action_card("card_battle_discard", c)
break
}
} else {
@@ -2920,10 +2927,10 @@ function gen_battle_card() {
case "british-event-or-battle":
case "british-event":
case "american-event":
- gen_action("card_battle_discard", c)
+ gen_action_card("card_battle_discard", c)
break
case "american-battle":
- gen_action("card_battle_play", c)
+ gen_action_card("card_battle_play", c)
break
}
}
@@ -2952,7 +2959,7 @@ function roll_loser_combat_losses(log) {
}
function roll_winner_combat_losses(log, losing_general) {
- let agility = losing_general ? GENERALS[losing_general].agility : 0
+ let agility = losing_general !== NOBODY ? GENERALS[losing_general].agility : 0
let roll = roll_d6()
log.push("Enemy Agility Rating: " + agility)
log.push("Winner Combat Loss Roll: " + roll)
@@ -3011,12 +3018,14 @@ function resolve_battle() {
let b_br = 0
let a_br = 0
- if (b_g)
+ if (b_g !== NOBODY)
b_log.push("General: " + b_g)
- if (a_g)
+ if (a_g !== NOBODY)
a_log.push("General: " + a_g)
- if (b_g) {
+console.log("GENS", a_g, b_g)
+
+ if (b_g !== NOBODY) {
let roll = roll_d6()
if (roll <= 3)
b_br = Math.min(Math.floor(GENERALS[b_g].battle / 2), b_cu)
@@ -3025,7 +3034,7 @@ function resolve_battle() {
b_log.push("Actual Battle Rating Roll: " + roll)
}
- if (a_g) {
+ if (a_g !== NOBODY) {
let roll = roll_d6()
if (roll <= 3)
a_br = Math.min(Math.floor(GENERALS[a_g].battle / 2), a_cu)
@@ -3153,7 +3162,7 @@ states.retreat_after_battle = {
else
gen_defender_retreat()
},
- move(to) {
+ space(to) {
logp("retreated to " + to)
if (game.active === P_BRITAIN)
retreat_british_army(game.move.to, to)
@@ -3283,13 +3292,7 @@ function goto_french_naval_phase() {
}
function gen_place_french_navy() {
- gen_action("place_navy", "Sea1")
- gen_action("place_navy", "Sea2")
- gen_action("place_navy", "Sea3")
- gen_action("place_navy", "Sea4")
- gen_action("place_navy", "Sea5")
- gen_action("place_navy", "Sea6")
- gen_action("place_navy", "Sea7")
+ view.actions.sea = [ 0, 1, 2, 3, 4, 5, 6 ]
}
states.place_french_navy_trigger = {
@@ -3297,7 +3300,7 @@ states.place_french_navy_trigger = {
view.prompt = "Place the French Navy in a blockade zone."
gen_place_french_navy()
},
- place_navy(zone) {
+ sea(zone) {
logp("placed French Navy.")
game.french_navy = zone
goto_place_rochambeau()
@@ -3329,13 +3332,13 @@ states.place_rochambeau = {
for (let space in SPACES) {
if (is_port(space)) {
if (!has_british_cu(space) && !has_british_pc(space)) {
- gen_action("place_reinforcements", space)
+ gen_action_space(space)
can_place = true
}
}
}
},
- place_reinforcements(space) {
+ space(space) {
logp("placed Rochambeau .")
move_general(ROCHAMBEAU, space)
move_cu(FRENCH, FRENCH_REINFORCEMENTS, space, 5)
@@ -3354,7 +3357,7 @@ states.place_french_navy = {
view.prompt = "Place the French Navy in a blockade zone."
gen_place_french_navy()
},
- place_navy(zone) {
+ sea(zone) {
logp("placed French Navy.")
game.french_navy = zone
goto_political_control_phase()
@@ -3576,17 +3579,29 @@ states.game_over = {
/* CLIENT/SERVER COMMS */
function gen_action(action, argument) {
- if (argument === undefined) {
- view.actions[action] = 1
- } else {
- if (!(action in view.actions))
- view.actions[action] = []
- set_add(view.actions[action], argument)
- }
+ if (!(action in view.actions))
+ view.actions[action] = []
+ set_add(view.actions[action], argument)
+}
+
+function gen_action_sea(s) {
+ gen_action("sea", s)
+}
+
+function gen_action_space(s) {
+ gen_action("space", s)
+}
+
+function gen_action_general(g) {
+ gen_action("general", g)
+}
+
+function gen_action_card(action, c) {
+ gen_action(action, c)
}
function gen_pass() {
- gen_action("pass")
+ view.actions.pass = 1
}
exports.scenarios = [ "Standard" ]
@@ -3624,33 +3639,35 @@ exports.view = function (state, current) {
view = {
prompt: null,
- log: state.log,
- year: state.year,
- flags: state.flags,
- war_ends: state.war_ends,
- reinforcements: state.reinforcements,
- french_alliance: state.french_alliance,
- congress: state.congress,
- french_navy: state.french_navy,
+ log: game.log,
+ year: game.year,
+ flags: game.flags,
+ war_ends: game.war_ends,
+ reinforcements: game.reinforcements,
+ french_alliance: game.french_alliance,
+ congress: game.congress,
+ french_navy: game.french_navy,
+
+ loca: game.loca,
+ cupc: game.cupc,
- loca: state.loca,
- cupc: state.cupc,
+ a_cards: game.a_hand.length,
+ b_cards: game.b_hand.length,
+ a_queue: game.a_queue,
+ b_queue: game.b_queue,
+ last_played: game.last_played,
- a_cards: state.a_hand.length,
- b_cards: state.b_hand.length,
- a_queue: state.a_queue,
- b_queue: state.b_queue,
- last_played: state.last_played,
+ move: game.move
}
if (current === P_AMERICA)
- view.hand = state.a_hand
+ view.hand = game.a_hand
else if (current === P_BRITAIN)
- view.hand = state.b_hand
+ view.hand = game.b_hand
else
view.hand = []
- if (current === state.active) {
+ if (current === game.active) {
view.actions = {}
states[game.state].prompt()
if (game.undo && game.undo.length > 0)
diff --git a/tools/gendata.js b/tools/gendata.js
new file mode 100644
index 0000000..72379ec
--- /dev/null
+++ b/tools/gendata.js
@@ -0,0 +1,488 @@
+"use strict"
+
+const fs = require("fs")
+
+let data = JSON.parse(fs.readFileSync("tools/data.json", "utf-8"))
+
+function make_index_from_list(list) {
+ let map = {}
+ for (let i = 0; i < list.length; ++i)
+ map[list[i]] = i
+ return map
+}
+
+/* GENERALS */
+
+data.generals = [
+ { name: "Arnold", owner: "American", strategy: 1, battle: 3, agility: 2, bonus: false },
+ { name: "Gates", owner: "American", strategy: 2, battle: 2, agility: 1, bonus: false },
+ { name: "Greene", owner: "American", strategy: 1, battle: 4, agility: 2, bonus: true },
+ { name: "Lafayette", owner: "American", strategy: 1, battle: 2, agility: 1, bonus: false },
+ { name: "Lee", owner: "American", strategy: 2, battle: 1, agility: 1, bonus: false },
+ { name: "Lincoln", owner: "American", strategy: 2, battle: 1, agility: 1, bonus: false },
+ { name: "Washington", owner: "American", strategy: 1, battle: 5, agility: 2, bonus: true },
+
+ { name: "Rochambeau", owner: "French", strategy: 2, battle: 4, agility: 2, bonus: false },
+
+ { name: "Burgoyne", owner: "British", strategy: 2, battle: 2, agility: 1, bonus: false },
+ { name: "Carleton", owner: "British", strategy: 3, battle: 3, agility: 2, bonus: false },
+ { name: "Clinton", owner: "British", strategy: 3, battle: 4, agility: 2, bonus: false },
+ { name: "Cornwallis", owner: "British", strategy: 2, battle: 4, agility: 2, bonus: false },
+ { name: "Howe", owner: "British", strategy: 3, battle: 6, agility: 3, bonus: false },
+]
+
+data.general_index = make_index_from_list(data.generals.map(x=>x.name))
+
+/* COLONIES */
+
+data.colony_name = [ "Canada", "NH", "NY", "MA", "CT", "RI", "PA", "NJ", "MD", "DE", "VA", "NC", "SC", "GA" ]
+
+const Canada = 0
+const NH = 1
+const NY = 2
+const MA = 3
+const CT = 4
+const RI = 5
+const PA = 6
+const NJ = 7
+const MD = 8
+const DE = 9
+const VA = 10
+const NC = 11
+const SC = 12
+const GA = 13
+
+/* CARDS */
+
+const CARD_3_OPS = { title: "3 OPS", type: "ops", count: 3 }
+const CARD_2_OPS = { title: "2 OPS", type: "ops", count: 2 }
+const CARD_1_OPS = { title: "1 OPS", type: "ops", count: 1 }
+
+data.cards = [
+ null,
+
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+ CARD_3_OPS,
+
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+ CARD_2_OPS,
+
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+ CARD_1_OPS,
+
+ /* 67 */
+ {
+ title: "Minor Campaign",
+ type: "campaign",
+ count: 2,
+ },
+
+ /* 68 */
+ {
+ title: "Minor Campaign",
+ type: "campaign",
+ count: 2,
+ },
+
+ /* 69 */
+ {
+ title: "Minor Campaign",
+ type: "campaign",
+ count: 2,
+ },
+
+ /* 70 */
+ {
+ title: "Major Campaign",
+ type: "campaign",
+ count: 3,
+ },
+
+ /* 71 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1779",
+ title: "The War Ends in 1779",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1779,
+ },
+
+ /* 72 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1780",
+ title: "The War Ends in 1780",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1780,
+ },
+
+ /* 73 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1781",
+ title: "The War Ends in 1781",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1781,
+ },
+
+ /* 74 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1782",
+ title: "The War Ends in 1782",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1782,
+ },
+
+ /* 75 */
+ {
+ full_title: "North's Government Falls - The War Ends in 1783",
+ title: "The War Ends in 1783",
+ type: "mandatory-event",
+ event: "the_war_ends",
+ year: 1783,
+ },
+
+ /* 76 */
+ {
+ title: "Henry Know Continental Artillery Commander",
+ type: "american-battle",
+ },
+
+ /* 77 */
+ {
+ title: "Jane McCrea Indian Atrocity Sparks Outrage",
+ type: "american-event",
+ event: "place_american_pc",
+ count: 2,
+ once: true,
+ },
+
+ /* 78 */
+ {
+ title: "Iroquois Uprising!",
+ type: "british-event",
+ event: "remove_american_pc_from_non_port",
+ where: [ NH, NY, PA ],
+ count: 2,
+ },
+
+ /* 79 */
+ {
+ title: "Joseph Brant Leads an Iroquois Raid",
+ type: "british-event",
+ event: "remove_american_pc_from_non_port",
+ where: [ NH, NY, PA ],
+ count: 2,
+ },
+
+ /* 80 */
+ {
+ title: "Lt. Colonel Simcoe's Queen's Rangers",
+ type: "british-event",
+ event: "remove_american_pc_within_two_spaces_of_a_british_general",
+ count: 2,
+ },
+
+ /* 81 */
+ {
+ title: "D'Estaing Sails for the Caribbean",
+ type: "british-event",
+ when: "after_french_alliance",
+ event: "remove_french_navy",
+ },
+
+ /* 82 */
+ {
+ title: "Banastre Tarleton's Waxhaws Massacre",
+ type: "british-event-or-battle",
+ event: "remove_american_cu",
+ },
+
+ /* 83 */
+ {
+ title: "Lord George Germaine Offers Royal Amnesty",
+ type: "british-event",
+ event: "remove_american_pc",
+ count: 2,
+ },
+
+ /* 84 */
+ {
+ title: "George Rogers Clark Leads a Western Offensive",
+ type: "american-event",
+ event: "remove_random_british_card",
+ },
+
+ /* 85 */
+ {
+ title: "Don Bernardo Galvez Captures Pensacola",
+ type: "american-event",
+ when: "european_war_in_effect",
+ event: "remove_british_cu",
+ count: 2,
+ },
+
+ /* 86 */
+ {
+ title: "Baron von Steuben Trains the Continental Army",
+ type: "american-event",
+ event: "baron_von_steuben_trains_the_continental_army",
+ },
+
+ /* 87 */
+ {
+ title: "Lord North Offers a Royal Amnesty",
+ type: "british-event",
+ event: "remove_american_pc",
+ count: 4,
+ once: true,
+ },
+
+ /* 88 */
+ {
+ title: "The Swamp Fox, Francis Marion",
+ type: "american-event",
+ event: "remove_british_pc_from",
+ where: [ NC, SC, GA ],
+ count: 2,
+ },
+
+ /* 89 */
+ {
+ title: "The Gamecock: Thomas Sumter",
+ type: "american-event",
+ event: "remove_british_pc_from",
+ where: [ NC, SC, GA ],
+ count: 2,
+ },
+
+ /* 90 */
+ {
+ title: "Josiah Martin Rallies North Carolina Loyalists",
+ type: "british-event",
+ event: "remove_american_pc_from",
+ where: [ NC ],
+ count: 2,
+ },
+
+ /* 91 */
+ {
+ title: 'Thomas Paine Publishes Pamphlets "Common Sense" and "The American Crisis"',
+ type: "american-event",
+ event: "place_american_pc_in",
+ where: [ NH, NY, MA, CT, RI, PA, NJ, MD, DE, VA, NC, SC, GA ],
+ count: 3,
+ once: true,
+ },
+
+ /* 92 */
+ {
+ title: "Nathan Hale, American Martyr",
+ type: "american-event",
+ event: "place_american_pc",
+ count: 2,
+ once: true,
+ },
+
+ /* 93 */
+ {
+ title: "John Glover's Marblehead Regiment",
+ type: "american-event",
+ event: "john_glovers_marblehead_regiment",
+ },
+
+ /* 94 */
+ {
+ title: "Pennsylvania and New Jersey Line Mutinies",
+ type: "british-event",
+ event: "pennsylvania_and_new_jersey_line_mutinies",
+ },
+
+ /* 95 */
+ {
+ title: "William Pitt Urges Peace Talks",
+ type: "british-event",
+ when: "before_french_alliance",
+ event: "remove_american_pc",
+ count: 2,
+ reshuffle: "if_played",
+ },
+
+ /* 96 */
+ {
+ title: "Hortelez et Cie: Clandestine French and Spanish Aid",
+ type: "american-event",
+ when: "before_french_alliance",
+ event: "advance_french_alliance",
+ reshuffle: "if_discarded",
+ count: 2,
+ },
+
+ /* 97 */
+ {
+ title: "Admiral Suffren Wins a Naval Victory",
+ type: "american-event",
+ when: "after_french_alliance",
+ event: "remove_random_british_card",
+ },
+
+ /* 98 */
+ {
+ title: '"Mad" Anthony Wayne',
+ type: "american-battle",
+ },
+
+ /* 99 */
+ {
+ title: "Declaration of Independence",
+ type: "mandatory-event",
+ event: "declaration_of_independence",
+ once: true,
+ reshuffle: "if_played",
+ tournament: true,
+ },
+
+ /* 100 */
+ {
+ title: "Benedict Arnold's Treason Undermines the Patriot Cause",
+ type: "british-battle",
+ event: "remove_benedict_arnold",
+ once: true,
+ },
+
+ /* 101 */
+ {
+ title: "Benjamin Franklin: Minister to France",
+ type: "mandatory-event",
+ event: "advance_french_alliance",
+ count: 4,
+ once: true,
+ tournament: true,
+ },
+
+ /* 102 */
+ {
+ title: "Admiral Rodney Captures St. Eustatius",
+ type: "british-event",
+ event: "remove_random_american_card",
+ when: "european_war_in_effect",
+ once: true,
+ },
+
+ /* 103 */
+ {
+ title: "Thaddeus Kosciuszco Constructs Engineering Works",
+ type: "american-battle",
+ },
+
+ /* 104 */
+ {
+ title: "Light Horse Harry Lee",
+ type: "american-battle",
+ },
+
+ /* 105 */
+ {
+ title: "Morgan's Riflemen",
+ type: "american-battle",
+ },
+
+ /* 106 */
+ {
+ title: "John Paul Jones' Shipping Raids",
+ type: "american-event",
+ event: "remove_random_british_card",
+ },
+
+ /* 107 */
+ {
+ title: "British Light Infantry",
+ type: "british-battle",
+ },
+
+ /* 108 */
+ {
+ title: "Lord Sandwich Coastal Raids",
+ type: "british-event",
+ event: "lord_sandwich_coastal_raids",
+ },
+
+ /* 109 */
+ {
+ title: "Edward Bancroft, British Double Agent",
+ type: "british-event",
+ event: "remove_random_american_card",
+ },
+
+ /* 110 */
+ {
+ title: "Hessian Infantry Bayonet Charge",
+ type: "british-battle",
+ },
+]
+
+/* OUTPUT */
+
+console.log("const data = " + JSON.stringify(data,0,'\t'))
+console.log("if (typeof module === 'object') module.exports = data")
diff --git a/tools/layout.json b/tools/layout.json
new file mode 100644
index 0000000..78b8e34
--- /dev/null
+++ b/tools/layout.json
@@ -0,0 +1,3728 @@
+{
+ "boxes": {
+ "fortified_port": [
+ {
+ "x": 450,
+ "y": 2052,
+ "w": 68,
+ "h": 68,
+ "name": "Charleston"
+ },
+ {
+ "x": 852,
+ "y": 964,
+ "w": 68,
+ "h": 67,
+ "name": "Philadelphia"
+ },
+ {
+ "x": 1006,
+ "y": 161,
+ "w": 68,
+ "h": 68,
+ "name": "Montreal"
+ },
+ {
+ "x": 1129,
+ "y": 60,
+ "w": 67,
+ "h": 67,
+ "name": "Quebec"
+ }
+ ],
+ "winter_quarters": [
+ {
+ "x": 995,
+ "y": 353,
+ "w": 79,
+ "h": 79,
+ "name": "Ticonderoga"
+ },
+ {
+ "x": 1126,
+ "y": 339,
+ "w": 79,
+ "h": 79,
+ "name": "Norwich"
+ },
+ {
+ "x": 878,
+ "y": 481,
+ "w": 79,
+ "h": 79,
+ "name": "Fort Stanwix"
+ },
+ {
+ "x": 967,
+ "y": 624,
+ "w": 79,
+ "h": 79,
+ "name": "Albany"
+ },
+ {
+ "x": 1097,
+ "y": 622,
+ "w": 79,
+ "h": 78,
+ "name": "Springfield"
+ },
+ {
+ "x": 1328,
+ "y": 590,
+ "w": 79,
+ "h": 78,
+ "name": "Boston"
+ },
+ {
+ "x": 1291,
+ "y": 733,
+ "w": 78,
+ "h": 79,
+ "name": "Newport"
+ },
+ {
+ "x": 1185,
+ "y": 747,
+ "w": 78,
+ "h": 78,
+ "name": "Hartford"
+ },
+ {
+ "x": 1025,
+ "y": 835,
+ "w": 79,
+ "h": 79,
+ "name": "New York"
+ },
+ {
+ "x": 687,
+ "y": 745,
+ "w": 78,
+ "h": 78,
+ "name": "Wyoming Valley"
+ },
+ {
+ "x": 441,
+ "y": 955,
+ "w": 78,
+ "h": 79,
+ "name": "Pittsburgh"
+ },
+ {
+ "x": 887,
+ "y": 1077,
+ "w": 78,
+ "h": 79,
+ "name": "Wilmington DE"
+ },
+ {
+ "x": 771,
+ "y": 1103,
+ "w": 79,
+ "h": 79,
+ "name": "Baltimore"
+ },
+ {
+ "x": 654,
+ "y": 1215,
+ "w": 79,
+ "h": 78,
+ "name": "Alexandria"
+ },
+ {
+ "x": 610,
+ "y": 1321,
+ "w": 78,
+ "h": 78,
+ "name": "Richmond"
+ },
+ {
+ "x": 436,
+ "y": 1254,
+ "w": 78,
+ "h": 79,
+ "name": "Charlottesville"
+ },
+ {
+ "x": 783,
+ "y": 1448,
+ "w": 78,
+ "h": 79,
+ "name": "Norfolk"
+ }
+ ],
+ "regular": [
+ {
+ "x": 226.5,
+ "y": 2266.5,
+ "w": 81,
+ "h": 81,
+ "name": "Savannah"
+ },
+ {
+ "x": 139.01387,
+ "y": 2055.9861,
+ "w": 81,
+ "h": 81,
+ "name": "Augusta"
+ },
+ {
+ "x": 222.01385,
+ "y": 1927.5,
+ "w": 81,
+ "h": 81,
+ "name": "Ninety Six"
+ },
+ {
+ "x": 403.05807,
+ "y": 1901.0138,
+ "w": 81,
+ "h": 81,
+ "name": "Eutaw Springs"
+ },
+ {
+ "x": 573.5592,
+ "y": 1910.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Georgetown"
+ },
+ {
+ "x": 675.0592,
+ "y": 1811.8098,
+ "w": 81,
+ "h": 81,
+ "name": "Wilmington"
+ },
+ {
+ "x": 495.05920000000003,
+ "y": 1790.0598,
+ "w": 81,
+ "h": 81,
+ "name": "Cheraw"
+ },
+ {
+ "x": 345.3092,
+ "y": 1768.3098,
+ "w": 81,
+ "h": 81,
+ "name": "Camden"
+ },
+ {
+ "x": 605.8092,
+ "y": 1666.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Wake (Raleigh)"
+ },
+ {
+ "x": 763.3092,
+ "y": 1665.5598,
+ "w": 81,
+ "h": 81,
+ "name": "New Bern"
+ },
+ {
+ "x": 483.55920000000003,
+ "y": 1577.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Hillsboro"
+ },
+ {
+ "x": 308.3092,
+ "y": 1556.0598,
+ "w": 81,
+ "h": 81,
+ "name": "Salem"
+ },
+ {
+ "x": 214.5592,
+ "y": 1648.5598,
+ "w": 81,
+ "h": 81,
+ "name": "Charlotte"
+ },
+ {
+ "x": 122.3092,
+ "y": 1563.3098,
+ "w": 81,
+ "h": 81,
+ "name": "Gilbert Town"
+ },
+ {
+ "x": 73.5592,
+ "y": 1768.8098,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Prince George"
+ },
+ {
+ "x": 60.260580000000004,
+ "y": 1446.7491,
+ "w": 81,
+ "h": 81,
+ "name": "Abingdon"
+ },
+ {
+ "x": 211.40466,
+ "y": 1403.6156,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Chiswell"
+ },
+ {
+ "x": 348.58337,
+ "y": 1397.2516,
+ "w": 81,
+ "h": 81,
+ "name": "Fincastle"
+ },
+ {
+ "x": 485.93884,
+ "y": 1439.1477,
+ "w": 81,
+ "h": 81,
+ "name": "Lynch's Ferry"
+ },
+ {
+ "x": 634.07404,
+ "y": 1441.644,
+ "w": 81,
+ "h": 81,
+ "name": "Petersburg"
+ },
+ {
+ "x": 766.12952,
+ "y": 1312.0383,
+ "w": 81,
+ "h": 81,
+ "name": "Yorktown"
+ },
+ {
+ "x": 131.70384,
+ "y": 1213.4077,
+ "w": 81,
+ "h": 81,
+ "name": "Point Pleasant"
+ },
+ {
+ "x": 146.95384,
+ "y": 979.7827,
+ "w": 81,
+ "h": 81,
+ "name": "Bassett Town"
+ },
+ {
+ "x": 446.21503,
+ "y": 1093.475,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Cumberland"
+ },
+ {
+ "x": 645.7276,
+ "y": 1092.4473,
+ "w": 81,
+ "h": 81,
+ "name": "Frederick Town"
+ },
+ {
+ "x": 588.75372,
+ "y": 987.3384000000001,
+ "w": 81,
+ "h": 81,
+ "name": "York"
+ },
+ {
+ "x": 683.25372,
+ "y": 895.58838,
+ "w": 81,
+ "h": 81,
+ "name": "Reading"
+ },
+ {
+ "x": 554.00372,
+ "y": 875.33838,
+ "w": 81,
+ "h": 81,
+ "name": "Harrisburg"
+ },
+ {
+ "x": 863.60297,
+ "y": 826.91376,
+ "w": 81,
+ "h": 81,
+ "name": "Morristown"
+ },
+ {
+ "x": 960.8301,
+ "y": 937.04565,
+ "w": 81,
+ "h": 81,
+ "name": "New Brunswick"
+ },
+ {
+ "x": 996.8300999999999,
+ "y": 1069.7957,
+ "w": 81,
+ "h": 81,
+ "name": "Monmouth"
+ },
+ {
+ "x": 1145.8301,
+ "y": 863.54565,
+ "w": 81,
+ "h": 81,
+ "name": "Long Island"
+ },
+ {
+ "x": 1087.5801,
+ "y": 731.54565,
+ "w": 81,
+ "h": 81,
+ "name": "New Haven"
+ },
+ {
+ "x": 954.33008,
+ "y": 742.29565,
+ "w": 81,
+ "h": 81,
+ "name": "Westchester"
+ },
+ {
+ "x": 1217.8301,
+ "y": 623.54565,
+ "w": 81,
+ "h": 81,
+ "name": "Lexington Concord"
+ },
+ {
+ "x": 1393.8301,
+ "y": 700.54565,
+ "w": 81,
+ "h": 81,
+ "name": "Barnstable"
+ },
+ {
+ "x": 1333.5618,
+ "y": 405.97501,
+ "w": 81,
+ "h": 81,
+ "name": "Falmouth"
+ },
+ {
+ "x": 1213.5618,
+ "y": 456.47501,
+ "w": 81,
+ "h": 81,
+ "name": "Concord"
+ },
+ {
+ "x": 1100.8118,
+ "y": 481.97504000000004,
+ "w": 81,
+ "h": 81,
+ "name": "Brattleboro"
+ },
+ {
+ "x": 991.3118,
+ "y": 491.22504000000004,
+ "w": 81,
+ "h": 81,
+ "name": "Saratoga"
+ },
+ {
+ "x": 767.56177,
+ "y": 419.47504,
+ "w": 81,
+ "h": 81,
+ "name": "Oswego"
+ },
+ {
+ "x": 667.56177,
+ "y": 577.97504,
+ "w": 81,
+ "h": 81,
+ "name": "Genesee"
+ },
+ {
+ "x": 461.06177,
+ "y": 521.47504,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Niagara"
+ },
+ {
+ "x": 54.828918,
+ "y": 667.84613,
+ "w": 81,
+ "h": 81,
+ "name": "Fort Detroit"
+ },
+ {
+ "x": 179.39716,
+ "y": 2389.0383,
+ "w": 81,
+ "h": 81,
+ "name": "St. Mary's"
+ }
+ ],
+ "sea": [
+ {
+ "x": 351,
+ "y": 2352,
+ "w": 97,
+ "h": 83,
+ "name": "Sea7"
+ },
+ {
+ "x": 629,
+ "y": 2022,
+ "w": 97,
+ "h": 83,
+ "name": "Sea6"
+ },
+ {
+ "x": 938,
+ "y": 1389,
+ "w": 97,
+ "h": 83,
+ "name": "Sea5"
+ },
+ {
+ "x": 1049,
+ "y": 1169,
+ "w": 97,
+ "h": 83,
+ "name": "Sea4"
+ },
+ {
+ "x": 1205,
+ "y": 975,
+ "w": 97,
+ "h": 83,
+ "name": "Sea3"
+ },
+ {
+ "x": 1461,
+ "y": 508,
+ "w": 97,
+ "h": 84,
+ "name": "Sea2"
+ },
+ {
+ "x": 1268,
+ "y": 60,
+ "w": 97,
+ "h": 83,
+ "name": "Sea1"
+ }
+ ],
+ "colony": [
+ {
+ "x": 1171,
+ "y": 1558,
+ "w": 66,
+ "h": 57,
+ "name": "GA"
+ },
+ {
+ "x": 1218,
+ "y": 1486,
+ "w": 67,
+ "h": 58,
+ "name": "SC"
+ },
+ {
+ "x": 1267,
+ "y": 1415,
+ "w": 66,
+ "h": 57,
+ "name": "NC"
+ },
+ {
+ "x": 1248,
+ "y": 1344,
+ "w": 67,
+ "h": 58,
+ "name": "VA"
+ },
+ {
+ "x": 1306,
+ "y": 1274,
+ "w": 66,
+ "h": 57,
+ "name": "MD"
+ },
+ {
+ "x": 1383,
+ "y": 1274,
+ "w": 66,
+ "h": 57,
+ "name": "DE"
+ },
+ {
+ "x": 1306,
+ "y": 1201,
+ "w": 66,
+ "h": 58,
+ "name": "PA"
+ },
+ {
+ "x": 1383,
+ "y": 1196,
+ "w": 66,
+ "h": 58,
+ "name": "NJ"
+ },
+ {
+ "x": 1462,
+ "y": 1163,
+ "w": 66,
+ "h": 58,
+ "name": "CT"
+ },
+ {
+ "x": 1540,
+ "y": 1163,
+ "w": 66,
+ "h": 58,
+ "name": "RI"
+ },
+ {
+ "x": 1498,
+ "y": 1088,
+ "w": 67,
+ "h": 58,
+ "name": "MA"
+ },
+ {
+ "x": 1382,
+ "y": 1089,
+ "w": 66,
+ "h": 58,
+ "name": "NY"
+ },
+ {
+ "x": 1465,
+ "y": 1014,
+ "w": 66,
+ "h": 58,
+ "name": "NH"
+ },
+ {
+ "x": 1383,
+ "y": 975,
+ "w": 66,
+ "h": 57,
+ "name": "Canada"
+ }
+ ],
+ "box": [
+ {
+ "x": 1358,
+ "y": 1673,
+ "w": 214,
+ "h": 206,
+ "name": "British Reinforcement Box"
+ },
+ {
+ "x": 294,
+ "y": 258,
+ "w": 214,
+ "h": 206,
+ "name": "American Leader Reinforcements"
+ },
+ {
+ "x": 63,
+ "y": 258,
+ "w": 214,
+ "h": 207,
+ "name": "French Reinforcements"
+ },
+ {
+ "x": 542,
+ "y": 332,
+ "w": 88,
+ "h": 104,
+ "name": "Continental Congress Dispersed"
+ },
+ {
+ "x": 1400,
+ "y": 46,
+ "w": 205,
+ "h": 136,
+ "name": "Captured Generals"
+ }
+ ],
+ "Card Boxes": [
+ {
+ "x": 904,
+ "y": 1915,
+ "w": 199,
+ "h": 277,
+ "name": "BRC"
+ },
+ {
+ "x": 1137,
+ "y": 1915,
+ "w": 199,
+ "h": 277,
+ "name": "ARC1"
+ },
+ {
+ "x": 1370,
+ "y": 1915,
+ "w": 199.00003,
+ "h": 277,
+ "name": "ARC2"
+ },
+ {
+ "x": 1027,
+ "y": 1679,
+ "w": 278,
+ "h": 198.99998,
+ "name": "War Ends Card"
+ }
+ ],
+ "Game Turn": [
+ {
+ "x": 904,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1775"
+ },
+ {
+ "x": 970,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1776"
+ },
+ {
+ "x": 1036,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1777"
+ },
+ {
+ "x": 1102,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1778"
+ },
+ {
+ "x": 1168,
+ "y": 2368,
+ "w": 65,
+ "h": 72,
+ "name": "1779"
+ },
+ {
+ "x": 1235,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1780"
+ },
+ {
+ "x": 1301,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1781"
+ },
+ {
+ "x": 1367,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1782"
+ },
+ {
+ "x": 1433,
+ "y": 2368,
+ "w": 64,
+ "h": 72,
+ "name": "1783"
+ }
+ ],
+ "French Alliance Track": [
+ {
+ "x": 905,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "0"
+ },
+ {
+ "x": 971,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "1"
+ },
+ {
+ "x": 1037,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "2"
+ },
+ {
+ "x": 1103,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "3"
+ },
+ {
+ "x": 1169,
+ "y": 2241,
+ "w": 65,
+ "h": 71,
+ "name": "4"
+ },
+ {
+ "x": 1236,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "5"
+ },
+ {
+ "x": 1302,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "6"
+ },
+ {
+ "x": 1368,
+ "y": 2241,
+ "w": 64,
+ "h": 71,
+ "name": "7"
+ },
+ {
+ "x": 1434,
+ "y": 2241,
+ "w": 65,
+ "h": 71,
+ "name": "8"
+ },
+ {
+ "x": 1501,
+ "y": 2241,
+ "w": 63,
+ "h": 71,
+ "name": "9"
+ }
+ ]
+ },
+ "points": {
+ "fortified_port": [
+ {
+ "x": 484,
+ "y": 2086,
+ "name": "Charleston"
+ },
+ {
+ "x": 886,
+ "y": 997.5,
+ "name": "Philadelphia"
+ },
+ {
+ "x": 1040,
+ "y": 195,
+ "name": "Montreal"
+ },
+ {
+ "x": 1162.5,
+ "y": 93.5,
+ "name": "Quebec"
+ }
+ ],
+ "winter_quarters": [
+ {
+ "x": 1034.5,
+ "y": 392.5,
+ "name": "Ticonderoga"
+ },
+ {
+ "x": 1165.5,
+ "y": 378.5,
+ "name": "Norwich"
+ },
+ {
+ "x": 917.5,
+ "y": 520.5,
+ "name": "Fort Stanwix"
+ },
+ {
+ "x": 1006.5,
+ "y": 663.5,
+ "name": "Albany"
+ },
+ {
+ "x": 1136.5,
+ "y": 661,
+ "name": "Springfield"
+ },
+ {
+ "x": 1367.5,
+ "y": 629,
+ "name": "Boston"
+ },
+ {
+ "x": 1330,
+ "y": 772.5,
+ "name": "Newport"
+ },
+ {
+ "x": 1224,
+ "y": 786,
+ "name": "Hartford"
+ },
+ {
+ "x": 1064.5,
+ "y": 874.5,
+ "name": "New York"
+ },
+ {
+ "x": 726,
+ "y": 784,
+ "name": "Wyoming Valley"
+ },
+ {
+ "x": 480,
+ "y": 994.5,
+ "name": "Pittsburgh"
+ },
+ {
+ "x": 926,
+ "y": 1116.5,
+ "name": "Wilmington DE"
+ },
+ {
+ "x": 810.5,
+ "y": 1142.5,
+ "name": "Baltimore"
+ },
+ {
+ "x": 693.5,
+ "y": 1254,
+ "name": "Alexandria"
+ },
+ {
+ "x": 649,
+ "y": 1360,
+ "name": "Richmond"
+ },
+ {
+ "x": 475,
+ "y": 1293.5,
+ "name": "Charlottesville"
+ },
+ {
+ "x": 822,
+ "y": 1487.5,
+ "name": "Norfolk"
+ }
+ ],
+ "regular": [
+ {
+ "x": 267,
+ "y": 2307,
+ "name": "Savannah"
+ },
+ {
+ "x": 179.51387,
+ "y": 2096.4861,
+ "name": "Augusta"
+ },
+ {
+ "x": 262.51385,
+ "y": 1968,
+ "name": "Ninety Six"
+ },
+ {
+ "x": 443.55807,
+ "y": 1941.5138,
+ "name": "Eutaw Springs"
+ },
+ {
+ "x": 614.0592,
+ "y": 1951.0598,
+ "name": "Georgetown"
+ },
+ {
+ "x": 715.5592,
+ "y": 1852.3098,
+ "name": "Wilmington"
+ },
+ {
+ "x": 535.5592,
+ "y": 1830.5598,
+ "name": "Cheraw"
+ },
+ {
+ "x": 385.8092,
+ "y": 1808.8098,
+ "name": "Camden"
+ },
+ {
+ "x": 646.3092,
+ "y": 1707.0598,
+ "name": "Wake (Raleigh)"
+ },
+ {
+ "x": 803.8092,
+ "y": 1706.0598,
+ "name": "New Bern"
+ },
+ {
+ "x": 524.0592,
+ "y": 1618.0598,
+ "name": "Hillsboro"
+ },
+ {
+ "x": 348.8092,
+ "y": 1596.5598,
+ "name": "Salem"
+ },
+ {
+ "x": 255.0592,
+ "y": 1689.0598,
+ "name": "Charlotte"
+ },
+ {
+ "x": 162.8092,
+ "y": 1603.8098,
+ "name": "Gilbert Town"
+ },
+ {
+ "x": 114.0592,
+ "y": 1809.3098,
+ "name": "Fort Prince George"
+ },
+ {
+ "x": 100.76058,
+ "y": 1487.2491,
+ "name": "Abingdon"
+ },
+ {
+ "x": 251.90466,
+ "y": 1444.1156,
+ "name": "Fort Chiswell"
+ },
+ {
+ "x": 389.08337,
+ "y": 1437.7516,
+ "name": "Fincastle"
+ },
+ {
+ "x": 526.43884,
+ "y": 1479.6477,
+ "name": "Lynch's Ferry"
+ },
+ {
+ "x": 674.57404,
+ "y": 1482.144,
+ "name": "Petersburg"
+ },
+ {
+ "x": 806.62952,
+ "y": 1352.5383,
+ "name": "Yorktown"
+ },
+ {
+ "x": 172.20384,
+ "y": 1253.9077,
+ "name": "Point Pleasant"
+ },
+ {
+ "x": 187.45384,
+ "y": 1020.2827,
+ "name": "Bassett Town"
+ },
+ {
+ "x": 486.71503,
+ "y": 1133.975,
+ "name": "Fort Cumberland"
+ },
+ {
+ "x": 686.2276,
+ "y": 1132.9473,
+ "name": "Frederick Town"
+ },
+ {
+ "x": 629.25372,
+ "y": 1027.8384,
+ "name": "York"
+ },
+ {
+ "x": 723.75372,
+ "y": 936.08838,
+ "name": "Reading"
+ },
+ {
+ "x": 594.50372,
+ "y": 915.83838,
+ "name": "Harrisburg"
+ },
+ {
+ "x": 904.10297,
+ "y": 867.41376,
+ "name": "Morristown"
+ },
+ {
+ "x": 1001.3301,
+ "y": 977.54565,
+ "name": "New Brunswick"
+ },
+ {
+ "x": 1037.3301,
+ "y": 1110.2957,
+ "name": "Monmouth"
+ },
+ {
+ "x": 1186.3301,
+ "y": 904.04565,
+ "name": "Long Island"
+ },
+ {
+ "x": 1128.0801,
+ "y": 772.04565,
+ "name": "New Haven"
+ },
+ {
+ "x": 994.83008,
+ "y": 782.79565,
+ "name": "Westchester"
+ },
+ {
+ "x": 1258.3301,
+ "y": 664.04565,
+ "name": "Lexington Concord"
+ },
+ {
+ "x": 1434.3301,
+ "y": 741.04565,
+ "name": "Barnstable"
+ },
+ {
+ "x": 1374.0618,
+ "y": 446.47501,
+ "name": "Falmouth"
+ },
+ {
+ "x": 1254.0618,
+ "y": 496.97501,
+ "name": "Concord"
+ },
+ {
+ "x": 1141.3118,
+ "y": 522.47504,
+ "name": "Brattleboro"
+ },
+ {
+ "x": 1031.8118,
+ "y": 531.72504,
+ "name": "Saratoga"
+ },
+ {
+ "x": 808.06177,
+ "y": 459.97504,
+ "name": "Oswego"
+ },
+ {
+ "x": 708.06177,
+ "y": 618.47504,
+ "name": "Genesee"
+ },
+ {
+ "x": 501.56177,
+ "y": 561.97504,
+ "name": "Fort Niagara"
+ },
+ {
+ "x": 95.328918,
+ "y": 708.34613,
+ "name": "Fort Detroit"
+ },
+ {
+ "x": 219.89716,
+ "y": 2429.5383,
+ "name": "St. Mary's"
+ }
+ ],
+ "sea": [
+ {
+ "x": 399.5,
+ "y": 2393.5,
+ "name": "Sea7"
+ },
+ {
+ "x": 677.5,
+ "y": 2063.5,
+ "name": "Sea6"
+ },
+ {
+ "x": 986.5,
+ "y": 1430.5,
+ "name": "Sea5"
+ },
+ {
+ "x": 1097.5,
+ "y": 1210.5,
+ "name": "Sea4"
+ },
+ {
+ "x": 1253.5,
+ "y": 1016.5,
+ "name": "Sea3"
+ },
+ {
+ "x": 1509.5,
+ "y": 550,
+ "name": "Sea2"
+ },
+ {
+ "x": 1316.5,
+ "y": 101.5,
+ "name": "Sea1"
+ }
+ ],
+ "colony": [
+ {
+ "x": 1204,
+ "y": 1586.5,
+ "name": "GA"
+ },
+ {
+ "x": 1251.5,
+ "y": 1515,
+ "name": "SC"
+ },
+ {
+ "x": 1300,
+ "y": 1443.5,
+ "name": "NC"
+ },
+ {
+ "x": 1281.5,
+ "y": 1373,
+ "name": "VA"
+ },
+ {
+ "x": 1339,
+ "y": 1302.5,
+ "name": "MD"
+ },
+ {
+ "x": 1416,
+ "y": 1302.5,
+ "name": "DE"
+ },
+ {
+ "x": 1339,
+ "y": 1230,
+ "name": "PA"
+ },
+ {
+ "x": 1416,
+ "y": 1225,
+ "name": "NJ"
+ },
+ {
+ "x": 1495,
+ "y": 1192,
+ "name": "CT"
+ },
+ {
+ "x": 1573,
+ "y": 1192,
+ "name": "RI"
+ },
+ {
+ "x": 1531.5,
+ "y": 1117,
+ "name": "MA"
+ },
+ {
+ "x": 1415,
+ "y": 1118,
+ "name": "NY"
+ },
+ {
+ "x": 1498,
+ "y": 1043,
+ "name": "NH"
+ },
+ {
+ "x": 1416,
+ "y": 1003.5,
+ "name": "Canada"
+ }
+ ],
+ "box": [
+ {
+ "x": 1465,
+ "y": 1776,
+ "name": "British Reinforcement Box"
+ },
+ {
+ "x": 401,
+ "y": 361,
+ "name": "American Leader Reinforcements"
+ },
+ {
+ "x": 170,
+ "y": 361.5,
+ "name": "French Reinforcements"
+ },
+ {
+ "x": 586,
+ "y": 384,
+ "name": "Continental Congress Dispersed"
+ },
+ {
+ "x": 1502.5,
+ "y": 114,
+ "name": "Captured Generals"
+ }
+ ],
+ "Card Boxes": [
+ {
+ "x": 1003.5,
+ "y": 2053.5,
+ "name": "BRC"
+ },
+ {
+ "x": 1236.5,
+ "y": 2053.5,
+ "name": "ARC1"
+ },
+ {
+ "x": 1469.500015,
+ "y": 2053.5,
+ "name": "ARC2"
+ },
+ {
+ "x": 1166,
+ "y": 1778.49999,
+ "name": "War Ends Card"
+ }
+ ],
+ "Game Turn": [
+ {
+ "x": 936,
+ "y": 2404,
+ "name": "1775"
+ },
+ {
+ "x": 1002,
+ "y": 2404,
+ "name": "1776"
+ },
+ {
+ "x": 1068,
+ "y": 2404,
+ "name": "1777"
+ },
+ {
+ "x": 1134,
+ "y": 2404,
+ "name": "1778"
+ },
+ {
+ "x": 1200.5,
+ "y": 2404,
+ "name": "1779"
+ },
+ {
+ "x": 1267,
+ "y": 2404,
+ "name": "1780"
+ },
+ {
+ "x": 1333,
+ "y": 2404,
+ "name": "1781"
+ },
+ {
+ "x": 1399,
+ "y": 2404,
+ "name": "1782"
+ },
+ {
+ "x": 1465,
+ "y": 2404,
+ "name": "1783"
+ }
+ ],
+ "French Alliance Track": [
+ {
+ "x": 937,
+ "y": 2276.5,
+ "name": "0"
+ },
+ {
+ "x": 1003,
+ "y": 2276.5,
+ "name": "1"
+ },
+ {
+ "x": 1069,
+ "y": 2276.5,
+ "name": "2"
+ },
+ {
+ "x": 1135,
+ "y": 2276.5,
+ "name": "3"
+ },
+ {
+ "x": 1201.5,
+ "y": 2276.5,
+ "name": "4"
+ },
+ {
+ "x": 1268,
+ "y": 2276.5,
+ "name": "5"
+ },
+ {
+ "x": 1334,
+ "y": 2276.5,
+ "name": "6"
+ },
+ {
+ "x": 1400,
+ "y": 2276.5,
+ "name": "7"
+ },
+ {
+ "x": 1466.5,
+ "y": 2276.5,
+ "name": "8"
+ },
+ {
+ "x": 1532.5,
+ "y": 2276.5,
+ "name": "9"
+ }
+ ]
+ },
+ "edges": {
+ "path": [
+ {
+ "x1": 227.01265,
+ "y1": 2390.0517,
+ "x2": 242.96720000000002,
+ "y2": 2339.5508,
+ "name": null,
+ "name1": "St. Mary's",
+ "name2": "Savannah"
+ },
+ {
+ "x1": 199.02401,
+ "y1": 2132.0174,
+ "x2": 254.46493,
+ "y2": 2269.0997,
+ "name": null,
+ "name1": "Augusta",
+ "name2": "Savannah"
+ },
+ {
+ "x1": 276.94694,
+ "y1": 2268.2133,
+ "x2": 450.40404,
+ "y2": 2099.316,
+ "name": null,
+ "name1": "Savannah",
+ "name2": "Charleston"
+ },
+ {
+ "x1": 201.99439,
+ "y1": 2062.6086,
+ "x2": 241.40983,
+ "y2": 2001.6522,
+ "name": null,
+ "name1": "Augusta",
+ "name2": "Ninety Six"
+ },
+ {
+ "x1": 145.20426,
+ "y1": 1830.9903,
+ "x2": 237.45150999999998,
+ "y2": 1937.1538,
+ "name": null,
+ "name1": "Fort Prince George",
+ "name2": "Ninety Six"
+ },
+ {
+ "x1": 284.32538,
+ "y1": 1934.4039,
+ "x2": 357.40648999999996,
+ "y2": 1837.6152,
+ "name": null,
+ "name1": "Ninety Six",
+ "name2": "Camden"
+ },
+ {
+ "x1": 404.96645,
+ "y1": 1843.7387,
+ "x2": 429.42317,
+ "y2": 1904.1378000000002,
+ "name": null,
+ "name1": "Camden",
+ "name2": "Eutaw Springs"
+ },
+ {
+ "x1": 460.98711,
+ "y1": 1978.2779,
+ "x2": 477.36157999999995,
+ "y2": 2045.6090000000002,
+ "name": null,
+ "name1": "Eutaw Springs",
+ "name2": "Charleston"
+ },
+ {
+ "x1": 496.23604,
+ "y1": 2051.5256,
+ "x2": 576.1504,
+ "y2": 1963.1115,
+ "name": null,
+ "name1": "Charleston",
+ "name2": "Georgetown"
+ },
+ {
+ "x1": 646.98186,
+ "y1": 1928.7791,
+ "x2": 689.27224,
+ "y2": 1883.0305,
+ "name": null,
+ "name1": "Georgetown",
+ "name2": "Wilmington"
+ },
+ {
+ "x1": 556.73449,
+ "y1": 1865.4894,
+ "x2": 590.69173,
+ "y2": 1919.571,
+ "name": null,
+ "name1": "Cheraw",
+ "name2": "Georgetown"
+ },
+ {
+ "x1": 575.69233,
+ "y1": 1829.9903,
+ "x2": 676.98091,
+ "y2": 1842.365,
+ "name": null,
+ "name1": "Cheraw",
+ "name2": "Wilmington"
+ },
+ {
+ "x1": 425.11313,
+ "y1": 1812.7409,
+ "x2": 497.1111,
+ "y2": 1822.0322,
+ "name": null,
+ "name1": "Camden",
+ "name2": "Cheraw"
+ },
+ {
+ "x1": 286.90869,
+ "y1": 1713.7435,
+ "x2": 358.4066,
+ "y2": 1780.7,
+ "name": null,
+ "name1": "Charlotte",
+ "name2": "Camden"
+ },
+ {
+ "x1": 149.36454,
+ "y1": 1641.7822,
+ "x2": 120.95485000000001,
+ "y2": 1769.7419,
+ "name": null,
+ "name1": "Gilbert Town",
+ "name2": "Fort Prince George"
+ },
+ {
+ "x1": 91.330808,
+ "y1": 1526.2489,
+ "x2": 98.12225600000001,
+ "y2": 1772.4086,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "Fort Prince George"
+ },
+ {
+ "x1": 193.54031,
+ "y1": 1630.0024,
+ "x2": 227.19063,
+ "y2": 1659.8424,
+ "name": null,
+ "name1": "Gilbert Town",
+ "name2": "Charlotte"
+ },
+ {
+ "x1": 278.7005,
+ "y1": 1656.8285,
+ "x2": 316.11605,
+ "y2": 1620.4962,
+ "name": null,
+ "name1": "Charlotte",
+ "name2": "Salem"
+ },
+ {
+ "x1": 385.32252,
+ "y1": 1600.0801,
+ "x2": 488.73627999999997,
+ "y2": 1612.1214,
+ "name": null,
+ "name1": "Salem",
+ "name2": "Hillsboro"
+ },
+ {
+ "x1": 370.08352,
+ "y1": 1630.7156,
+ "x2": 509.69412,
+ "y2": 1800.5745,
+ "name": null,
+ "name1": "Salem",
+ "name2": "Cheraw"
+ },
+ {
+ "x1": 669.35138,
+ "y1": 1740.1481,
+ "x2": 704.3551299999999,
+ "y2": 1813.8239,
+ "name": null,
+ "name1": "Wake (Raleigh)",
+ "name2": "Wilmington"
+ },
+ {
+ "x1": 560.0883,
+ "y1": 1635.6726,
+ "x2": 619.77668,
+ "y2": 1677.2911000000001,
+ "name": null,
+ "name1": "Hillsboro",
+ "name2": "Wake (Raleigh)"
+ },
+ {
+ "x1": 686.53009,
+ "y1": 1705.2652,
+ "x2": 763.91786,
+ "y2": 1704.3802,
+ "name": null,
+ "name1": "Wake (Raleigh)",
+ "name2": "New Bern"
+ },
+ {
+ "x1": 672.10609,
+ "y1": 1522.7905,
+ "x2": 654.12084,
+ "y2": 1667.7282,
+ "name": null,
+ "name1": "Petersburg",
+ "name2": "Wake (Raleigh)"
+ },
+ {
+ "x1": 555.65124,
+ "y1": 1592.7885,
+ "x2": 647.69018,
+ "y2": 1511.7075000000002,
+ "name": null,
+ "name1": "Hillsboro",
+ "name2": "Petersburg"
+ },
+ {
+ "x1": 714.73008,
+ "y1": 1482.1667,
+ "x2": 782.7696100000001,
+ "y2": 1484.375,
+ "name": null,
+ "name1": "Petersburg",
+ "name2": "Norfolk"
+ },
+ {
+ "x1": 822.35191,
+ "y1": 1526.7073,
+ "x2": 811.0189,
+ "y2": 1666.6615,
+ "name": null,
+ "name1": "Norfolk",
+ "name2": "New Bern"
+ },
+ {
+ "x1": 382.48926,
+ "y1": 1573.8725,
+ "x2": 494.40279,
+ "y2": 1501.6245,
+ "name": null,
+ "name1": "Salem",
+ "name2": "Lynch's Ferry"
+ },
+ {
+ "x1": 425.69638,
+ "y1": 1447.0844,
+ "x2": 489.44458999999995,
+ "y2": 1465.5004999999999,
+ "name": null,
+ "name1": "Fincastle",
+ "name2": "Lynch's Ferry"
+ },
+ {
+ "x1": 551.06786,
+ "y1": 1449.2093,
+ "x2": 610.61031,
+ "y2": 1393.6397,
+ "name": null,
+ "name1": "Lynch's Ferry",
+ "name2": "Richmond"
+ },
+ {
+ "x1": 662.68958,
+ "y1": 1398.8774,
+ "x2": 669.6478999999999,
+ "y2": 1442.3761000000002,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Petersburg"
+ },
+ {
+ "x1": 564.95299,
+ "y1": 1489.0395,
+ "x2": 634.49253,
+ "y2": 1488.5332,
+ "name": null,
+ "name1": "Lynch's Ferry",
+ "name2": "Petersburg"
+ },
+ {
+ "x1": 687.89742,
+ "y1": 1388.0028,
+ "x2": 783.35299,
+ "y2": 1463.584,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Norfolk"
+ },
+ {
+ "x1": 687.6891,
+ "y1": 1357.2536,
+ "x2": 766.5200900000001,
+ "y2": 1354.1287,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Yorktown"
+ },
+ {
+ "x1": 654.48163,
+ "y1": 1323.1295,
+ "x2": 670.77284,
+ "y2": 1290.5471,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "Alexandria"
+ },
+ {
+ "x1": 513.48556,
+ "y1": 1299.7969,
+ "x2": 610.02451,
+ "y2": 1338.5457000000001,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "Richmond"
+ },
+ {
+ "x1": 504.31918,
+ "y1": 1333.0042,
+ "x2": 534.06834,
+ "y2": 1442.8345000000002,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "Lynch's Ferry"
+ },
+ {
+ "x1": 403.38632,
+ "y1": 1400.343,
+ "x2": 442.32085,
+ "y2": 1332.546,
+ "name": null,
+ "name1": "Fincastle",
+ "name2": "Charlottesville"
+ },
+ {
+ "x1": 186.99475,
+ "y1": 1293.3804,
+ "x2": 237.99332,
+ "y2": 1404.5856,
+ "name": null,
+ "name1": "Point Pleasant",
+ "name2": "Fort Chiswell"
+ },
+ {
+ "x1": 136.12124,
+ "y1": 1468.0004,
+ "x2": 211.86909,
+ "y2": 1448.4593,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "Fort Chiswell"
+ },
+ {
+ "x1": 288.28357,
+ "y1": 1440.7096,
+ "x2": 351.32347,
+ "y2": 1440.0012,
+ "name": null,
+ "name1": "Fort Chiswell",
+ "name2": "Fincastle"
+ },
+ {
+ "x1": 137.20438,
+ "y1": 1503.9995,
+ "x2": 165.32871999999998,
+ "y2": 1564.081,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "Gilbert Town"
+ },
+ {
+ "x1": 513.91845,
+ "y1": 1258.4465,
+ "x2": 651.77343,
+ "y2": 1152.0509,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "Frederick Town"
+ },
+ {
+ "x1": 697.18887,
+ "y1": 1171.3421,
+ "x2": 699.64694,
+ "y2": 1214.8824,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "Alexandria"
+ },
+ {
+ "x1": 732.5,
+ "y1": 1218.25,
+ "x2": 773,
+ "y2": 1180.25,
+ "name": null,
+ "name1": "Alexandria",
+ "name2": "Baltimore"
+ },
+ {
+ "x1": 726.27128,
+ "y1": 1134.3849,
+ "x2": 772.0616600000001,
+ "y2": 1136.1348,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "Baltimore"
+ },
+ {
+ "x1": 646.35681,
+ "y1": 1128.5516,
+ "x2": 526.5687,
+ "y2": 1131.7183,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "Fort Cumberland"
+ },
+ {
+ "x1": 479.11158,
+ "y1": 1033.8876,
+ "x2": 481.27809,
+ "y2": 1094.6774,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "Fort Cumberland"
+ },
+ {
+ "x1": 228.78524,
+ "y1": 1014.3049,
+ "x2": 440.57096,
+ "y2": 999.43028,
+ "name": null,
+ "name1": "Bassett Town",
+ "name2": "Pittsburgh"
+ },
+ {
+ "x1": 518.94388,
+ "y1": 974.55593,
+ "x2": 562.69245,
+ "y2": 940.5152,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "Harrisburg"
+ },
+ {
+ "x1": 619.31595,
+ "y1": 949.01496,
+ "x2": 628.64909,
+ "y2": 988.30569,
+ "name": null,
+ "name1": "Harrisburg",
+ "name2": "York"
+ },
+ {
+ "x1": 663.85645,
+ "y1": 1006.0968,
+ "x2": 701.35537,
+ "y2": 969.8478600000001,
+ "name": null,
+ "name1": "York",
+ "name2": "Reading"
+ },
+ {
+ "x1": 759.31202,
+ "y1": 949.84833,
+ "x2": 850.2562499999999,
+ "y2": 985.27606,
+ "name": null,
+ "name1": "Reading",
+ "name2": "Philadelphia"
+ },
+ {
+ "x1": 908.63011,
+ "y1": 1030.8842,
+ "x2": 920.09917,
+ "y2": 1078.0530999999999,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "Wilmington DE"
+ },
+ {
+ "x1": 849.98819,
+ "y1": 1137.6914,
+ "x2": 886.79237,
+ "y2": 1129.1957,
+ "name": null,
+ "name1": "Baltimore",
+ "name2": "Wilmington DE"
+ },
+ {
+ "x1": 920.40337,
+ "y1": 1023.0968,
+ "x2": 1003.9483,
+ "y2": 1088.1015,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "Monmouth"
+ },
+ {
+ "x1": 1017.8464,
+ "y1": 1017.1381,
+ "x2": 1033.8495,
+ "y2": 1070.3896,
+ "name": null,
+ "name1": "New Brunswick",
+ "name2": "Monmouth"
+ },
+ {
+ "x1": 924.64522,
+ "y1": 988.37335,
+ "x2": 959.76472,
+ "y2": 981.72244,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "New Brunswick"
+ },
+ {
+ "x1": 930.01556,
+ "y1": 893.89157,
+ "x2": 978.18087,
+ "y2": 943.47351,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "New Brunswick"
+ },
+ {
+ "x1": 1023.785,
+ "y1": 945.87857,
+ "x2": 1045.4705999999999,
+ "y2": 913.01603,
+ "name": null,
+ "name1": "New Brunswick",
+ "name2": "New York"
+ },
+ {
+ "x1": 1104.2595,
+ "y1": 880.08247,
+ "x2": 1148.1712,
+ "y2": 892.11777,
+ "name": null,
+ "name1": "New York",
+ "name2": "Long Island"
+ },
+ {
+ "x1": 757.18708,
+ "y1": 913.72435,
+ "x2": 865.1994500000001,
+ "y2": 873.7064499999999,
+ "name": null,
+ "name1": "Reading",
+ "name2": "Morristown"
+ },
+ {
+ "x1": 875.47542,
+ "y1": 846.43457,
+ "x2": 765.68563,
+ "y2": 792.2419600000001,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "Wyoming Valley"
+ },
+ {
+ "x1": 738.76731,
+ "y1": 823.40775,
+ "x2": 738.06503,
+ "y2": 897.7891099999999,
+ "name": null,
+ "name1": "Wyoming Valley",
+ "name2": "Reading"
+ },
+ {
+ "x1": 631.8156,
+ "y1": 917.26592,
+ "x2": 685.64742,
+ "y2": 927.89062,
+ "name": null,
+ "name1": "Harrisburg",
+ "name2": "Reading"
+ },
+ {
+ "x1": 472.16664,
+ "y1": 954.99649,
+ "x2": 513.40231,
+ "y2": 600.77474,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "Fort Niagara"
+ },
+ {
+ "x1": 539.27641,
+ "y1": 576.31715,
+ "x2": 669.27295,
+ "y2": 609.48294,
+ "name": null,
+ "name1": "Fort Niagara",
+ "name2": "Genesee"
+ },
+ {
+ "x1": 706.18851,
+ "y1": 658.02319,
+ "x2": 715.39658,
+ "y2": 749.39563,
+ "name": null,
+ "name1": "Genesee",
+ "name2": "Wyoming Valley"
+ },
+ {
+ "x1": 132.80092,
+ "y1": 694.85067,
+ "x2": 461.55159,
+ "y2": 564.35025,
+ "name": null,
+ "name1": "Fort Detroit",
+ "name2": "Fort Niagara"
+ },
+ {
+ "x1": 539.23485,
+ "y1": 548.69292,
+ "x2": 789.97769,
+ "y2": 496.6111,
+ "name": null,
+ "name1": "Fort Niagara",
+ "name2": "Oswego"
+ },
+ {
+ "x1": 836.16704,
+ "y1": 488.73628,
+ "x2": 878.6646400000001,
+ "y2": 509.9893,
+ "name": null,
+ "name1": "Oswego",
+ "name2": "Fort Stanwix"
+ },
+ {
+ "x1": 878.3123,
+ "y1": 537.08199,
+ "x2": 746.55996,
+ "y2": 607.91092,
+ "name": null,
+ "name1": "Fort Stanwix",
+ "name2": "Genesee"
+ },
+ {
+ "x1": 957,
+ "y1": 560,
+ "x2": 991.63883,
+ "y2": 624.02415,
+ "name": null,
+ "name1": "Fort Stanwix",
+ "name2": "Albany"
+ },
+ {
+ "x1": 1010.4299,
+ "y1": 624.89909,
+ "x2": 1022.0962999999999,
+ "y2": 570.90064,
+ "name": null,
+ "name1": "Albany",
+ "name2": "Saratoga"
+ },
+ {
+ "x1": 1004.3885,
+ "y1": 700.522,
+ "x2": 999.43028,
+ "y2": 744.4374300000001,
+ "name": null,
+ "name1": "Albany",
+ "name2": "Westchester"
+ },
+ {
+ "x1": 932.1405,
+ "y1": 839.35144,
+ "x2": 964.0133999999999,
+ "y2": 809.60347,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "Westchester"
+ },
+ {
+ "x1": 1023.5129,
+ "y1": 809.60227,
+ "x2": 1036.2685999999999,
+ "y2": 834.04814,
+ "name": null,
+ "name1": "Westchester",
+ "name2": "New York"
+ },
+ {
+ "x1": 939.93195,
+ "y1": 871.22554,
+ "x2": 1024.9296,
+ "y2": 874.0588,
+ "name": null,
+ "name1": "Morristown",
+ "name2": "New York"
+ },
+ {
+ "x1": 1086.554,
+ "y1": 834.75403,
+ "x2": 1104.9714000000001,
+ "y2": 805.7095599999999,
+ "name": null,
+ "name1": "New York",
+ "name2": "New Haven"
+ },
+ {
+ "x1": 1031.3044,
+ "y1": 778.43648,
+ "x2": 1090.0944,
+ "y2": 774.89491,
+ "name": null,
+ "name1": "Westchester",
+ "name2": "New Haven"
+ },
+ {
+ "x1": 1044.054,
+ "y1": 660.14813,
+ "x2": 1096.4692,
+ "y2": 660.85645,
+ "name": null,
+ "name1": "Albany",
+ "name2": "Springfield"
+ },
+ {
+ "x1": 1175,
+ "y1": 699,
+ "x2": 1206.8827,
+ "y2": 748.06237,
+ "name": null,
+ "name1": "Springfield",
+ "name2": "Hartford"
+ },
+ {
+ "x1": 1167.1178,
+ "y1": 782.06644,
+ "x2": 1185.6344,
+ "y2": 783.0435299999999,
+ "name": null,
+ "name1": "Hartford",
+ "name2": "Hartford"
+ },
+ {
+ "x1": 1260.0896,
+ "y1": 777.72817,
+ "x2": 1292.672,
+ "y2": 777.01985,
+ "name": null,
+ "name1": "Hartford",
+ "name2": "Newport"
+ },
+ {
+ "x1": 1302.6717,
+ "y1": 733.18767,
+ "x2": 1279.8807000000002,
+ "y2": 698.3136900000001,
+ "name": null,
+ "name1": "Newport",
+ "name2": "Lexington Concord"
+ },
+ {
+ "x1": 1331.171,
+ "y1": 733.77117,
+ "x2": 1351.0039000000002,
+ "y2": 667.52295,
+ "name": null,
+ "name1": "Newport",
+ "name2": "Boston"
+ },
+ {
+ "x1": 1296.7971,
+ "y1": 651.52331,
+ "x2": 1328.6711,
+ "y2": 640.35704,
+ "name": null,
+ "name1": "Lexington Concord",
+ "name2": "Boston"
+ },
+ {
+ "x1": 1175.6754,
+ "y1": 664.60645,
+ "x2": 1217.9658000000002,
+ "y2": 664.8146399999999,
+ "name": null,
+ "name1": "Springfield",
+ "name2": "Lexington Concord"
+ },
+ {
+ "x1": 1134.7598,
+ "y1": 561.23425,
+ "x2": 1131.1766,
+ "y2": 622.77415,
+ "name": null,
+ "name1": "Brattleboro",
+ "name2": "Springfield"
+ },
+ {
+ "x1": 1394.6692,
+ "y1": 667.23127,
+ "x2": 1414.9186,
+ "y2": 707.23019,
+ "name": null,
+ "name1": "Boston",
+ "name2": "Barnstable"
+ },
+ {
+ "x1": 1364.92,
+ "y1": 593.56667,
+ "x2": 1367.9199,
+ "y2": 485.77797000000004,
+ "name": null,
+ "name1": "Boston",
+ "name2": "Falmouth"
+ },
+ {
+ "x1": 1338.8788,
+ "y1": 466.6535,
+ "x2": 1293.3386,
+ "y2": 488.06953,
+ "name": null,
+ "name1": "Falmouth",
+ "name2": "Concord"
+ },
+ {
+ "x1": 1216.5493,
+ "y1": 512.27725,
+ "x2": 1181.9667,
+ "y2": 520.52701,
+ "name": null,
+ "name1": "Concord",
+ "name2": "Brattleboro"
+ },
+ {
+ "x1": 1102.9274,
+ "y1": 532.27665,
+ "x2": 1072.3866,
+ "y2": 535.48497,
+ "name": null,
+ "name1": "Brattleboro",
+ "name2": "Saratoga"
+ },
+ {
+ "x1": 1034.1376,
+ "y1": 433.48783,
+ "x2": 1035.5543,
+ "y2": 493.69446999999997,
+ "name": null,
+ "name1": "Ticonderoga",
+ "name2": "Saratoga"
+ },
+ {
+ "x1": 1073.4544,
+ "y1": 390.62944,
+ "x2": 1126.5731,
+ "y2": 383.19275,
+ "name": null,
+ "name1": "Ticonderoga",
+ "name2": "Norwich"
+ },
+ {
+ "x1": 1162.009,
+ "y1": 418.15493,
+ "x2": 1151.5095000000001,
+ "y2": 483.69482999999997,
+ "name": null,
+ "name1": "Norwich",
+ "name2": "Brattleboro"
+ },
+ {
+ "x1": 1203.25,
+ "y1": 416.5,
+ "x2": 1232.1321,
+ "y2": 462.69531,
+ "name": null,
+ "name1": "Norwich",
+ "name2": "Concord"
+ },
+ {
+ "x1": 1038.3875,
+ "y1": 237.28501,
+ "x2": 1037.6792,
+ "y2": 350.61516,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Ticonderoga"
+ },
+ {
+ "x1": 1006.805,
+ "y1": 219.53548,
+ "x2": 828.01842,
+ "y2": 424.98807,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Oswego"
+ },
+ {
+ "x1": 1073.095,
+ "y1": 174.99511,
+ "x2": 1130,
+ "y2": 122.25,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Quebec"
+ },
+ {
+ "x1": 652.36158,
+ "y1": 1060.8876,
+ "x2": 670.77809,
+ "y2": 1096.1774,
+ "name": null,
+ "name1": "York",
+ "name2": "Frederick Town"
+ }
+ ],
+ "wilderness": [
+ {
+ "x1": 90.648464,
+ "y1": 748.27474,
+ "x2": 167.28328,
+ "y2": 986.1757699999999,
+ "name": null,
+ "name1": "Fort Detroit",
+ "name2": "Bassett Town"
+ },
+ {
+ "x1": 196.33447,
+ "y1": 1058.8038,
+ "x2": 170.79522,
+ "y2": 1212.0665999999999,
+ "name": null,
+ "name1": "Bassett Town",
+ "name2": "Point Pleasant"
+ },
+ {
+ "x1": 1196,
+ "y1": 127,
+ "x2": 1346.2935,
+ "y2": 418.71331,
+ "name": "Quebec-Falmouth",
+ "name1": "Quebec",
+ "name2": "Falmouth"
+ }
+ ],
+ "sea": [
+ {
+ "x1": 1040,
+ "y1": 195,
+ "x2": 1316.5,
+ "y2": 101.5,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Sea1"
+ },
+ {
+ "x1": 1162.5,
+ "y1": 93.5,
+ "x2": 1316.5,
+ "y2": 101.5,
+ "name": null,
+ "name1": "Quebec",
+ "name2": "Sea1"
+ },
+ {
+ "x1": 1374.0618,
+ "y1": 446.47501,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Falmouth",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1367.5,
+ "y1": 629,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Boston",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1434.3301,
+ "y1": 741.04565,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Barnstable",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1330,
+ "y1": 772.5,
+ "x2": 1509.5,
+ "y2": 550,
+ "name": null,
+ "name1": "Newport",
+ "name2": "Sea2"
+ },
+ {
+ "x1": 1186.3301,
+ "y1": 904.04565,
+ "x2": 1253.5,
+ "y2": 1016.5,
+ "name": null,
+ "name1": "Long Island",
+ "name2": "Sea3"
+ },
+ {
+ "x1": 1128.0801,
+ "y1": 772.04565,
+ "x2": 1253.5,
+ "y2": 1016.5,
+ "name": null,
+ "name1": "New Haven",
+ "name2": "Sea3"
+ },
+ {
+ "x1": 1064.5,
+ "y1": 874.5,
+ "x2": 1253.5,
+ "y2": 1016.5,
+ "name": null,
+ "name1": "New York",
+ "name2": "Sea3"
+ },
+ {
+ "x1": 926,
+ "y1": 1116.5,
+ "x2": 1097.5,
+ "y2": 1210.5,
+ "name": null,
+ "name1": "Wilmington DE",
+ "name2": "Sea4"
+ },
+ {
+ "x1": 886,
+ "y1": 997.5,
+ "x2": 1097.5,
+ "y2": 1210.5,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "Sea4"
+ },
+ {
+ "x1": 810.5,
+ "y1": 1142.5,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Baltimore",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 693.5,
+ "y1": 1254,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Alexandria",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 806.62952,
+ "y1": 1352.5383,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Yorktown",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 822,
+ "y1": 1487.5,
+ "x2": 986.5,
+ "y2": 1430.5,
+ "name": null,
+ "name1": "Norfolk",
+ "name2": "Sea5"
+ },
+ {
+ "x1": 803.8092,
+ "y1": 1706.0598,
+ "x2": 677.5,
+ "y2": 2063.5,
+ "name": null,
+ "name1": "New Bern",
+ "name2": "Sea6"
+ },
+ {
+ "x1": 715.5592,
+ "y1": 1852.3098,
+ "x2": 677.5,
+ "y2": 2063.5,
+ "name": null,
+ "name1": "Wilmington",
+ "name2": "Sea6"
+ },
+ {
+ "x1": 484,
+ "y1": 2086,
+ "x2": 677.5,
+ "y2": 2063.5,
+ "name": null,
+ "name1": "Charleston",
+ "name2": "Sea6"
+ },
+ {
+ "x1": 267,
+ "y1": 2307,
+ "x2": 399.5,
+ "y2": 2393.5,
+ "name": null,
+ "name1": "Savannah",
+ "name2": "Sea7"
+ },
+ {
+ "x1": 220.5,
+ "y1": 2429.5,
+ "x2": 399.5,
+ "y2": 2393.5,
+ "name": null,
+ "name1": "St. Mary's",
+ "name2": "Sea7"
+ }
+ ],
+ "colony": [
+ {
+ "x1": 1250.8815,
+ "y1": 498.65267,
+ "x2": 1503.0411,
+ "y2": 1042.6374,
+ "name": null,
+ "name1": "Concord",
+ "name2": "NH"
+ },
+ {
+ "x1": 1136.1348,
+ "y1": 519.90207,
+ "x2": 1503.0411,
+ "y2": 1042.6374,
+ "name": null,
+ "name1": "Brattleboro",
+ "name2": "NH"
+ },
+ {
+ "x1": 1172.9671,
+ "y1": 382.48926,
+ "x2": 1503.0411000000001,
+ "y2": 1042.6374,
+ "name": null,
+ "name1": "Norwich",
+ "name2": "NH"
+ },
+ {
+ "x1": 1537.0402,
+ "y1": 1120.5519,
+ "x2": 1138.968,
+ "y2": 660.14813,
+ "name": null,
+ "name1": "MA",
+ "name2": "Springfield"
+ },
+ {
+ "x1": 1255.1314,
+ "y1": 671.48115,
+ "x2": 1537.0402,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Lexington Concord",
+ "name2": "MA"
+ },
+ {
+ "x1": 1437.8763,
+ "y1": 745.14575,
+ "x2": 1537.0402,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Barnstable",
+ "name2": "MA"
+ },
+ {
+ "x1": 1365.6283,
+ "y1": 633.23222,
+ "x2": 1537.0402000000001,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Boston",
+ "name2": "MA"
+ },
+ {
+ "x1": 1365.6283,
+ "y1": 437.73771,
+ "x2": 1537.0402000000001,
+ "y2": 1120.5519,
+ "name": null,
+ "name1": "Falmouth",
+ "name2": "MA"
+ },
+ {
+ "x1": 1333.0459,
+ "y1": 770.64503,
+ "x2": 1576.7057,
+ "y2": 1192.7998,
+ "name": null,
+ "name1": "Newport",
+ "name2": "RI"
+ },
+ {
+ "x1": 1212.6326,
+ "y1": 780.56142,
+ "x2": 1503.0411,
+ "y2": 1197.0497,
+ "name": null,
+ "name1": "Hartford",
+ "name2": "CT"
+ },
+ {
+ "x1": 1126.2184,
+ "y1": 772.06166,
+ "x2": 1503.0411,
+ "y2": 1197.0497,
+ "name": null,
+ "name1": "New Haven",
+ "name2": "CT"
+ },
+ {
+ "x1": 1408.5453,
+ "y1": 1122.5186,
+ "x2": 1058.6385,
+ "y2": 878.85875,
+ "name": null,
+ "name1": "NY",
+ "name2": "New York"
+ },
+ {
+ "x1": 1416.6269,
+ "y1": 1116.302,
+ "x2": 987.38895,
+ "y2": 781.97805,
+ "name": null,
+ "name1": "NY",
+ "name2": "Westchester"
+ },
+ {
+ "x1": 1002.9718,
+ "y1": 665.81464,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Albany",
+ "name2": "NY"
+ },
+ {
+ "x1": 1031.3044,
+ "y1": 535.48497,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Saratoga",
+ "name2": "NY"
+ },
+ {
+ "x1": 1034.1376,
+ "y1": 390.98902,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Ticonderoga",
+ "name2": "NY"
+ },
+ {
+ "x1": 913.72435,
+ "y1": 511.40231,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Fort Stanwix",
+ "name2": "NY"
+ },
+ {
+ "x1": 807.47733,
+ "y1": 461.82037,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Oswego",
+ "name2": "NY"
+ },
+ {
+ "x1": 708.31345,
+ "y1": 623.31583,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Genesee",
+ "name2": "NY"
+ },
+ {
+ "x1": 488.73628,
+ "y1": 558.151,
+ "x2": 1416.6269,
+ "y2": 1116.302,
+ "name": null,
+ "name1": "Fort Niagara",
+ "name2": "NY"
+ },
+ {
+ "x1": 83.580987,
+ "y1": 716.81321,
+ "x2": 1418.0435,
+ "y2": 1001.5552,
+ "name": null,
+ "name1": "Fort Detroit",
+ "name2": "Canada"
+ },
+ {
+ "x1": 1415.2103,
+ "y1": 1226.7989,
+ "x2": 903.80796,
+ "y2": 859.89253,
+ "name": null,
+ "name1": "NJ",
+ "name2": "Morristown"
+ },
+ {
+ "x1": 993.05545,
+ "y1": 970.38942,
+ "x2": 1415.2103,
+ "y2": 1226.7989,
+ "name": null,
+ "name1": "New Brunswick",
+ "name2": "NJ"
+ },
+ {
+ "x1": 1045.4706,
+ "y1": 1114.8854,
+ "x2": 1415.2103000000002,
+ "y2": 1226.7988999999998,
+ "name": null,
+ "name1": "Monmouth",
+ "name2": "NJ"
+ },
+ {
+ "x1": 1345.7956,
+ "y1": 1233.882,
+ "x2": 716.81321,
+ "y2": 934.97375,
+ "name": null,
+ "name1": "PA",
+ "name2": "Reading"
+ },
+ {
+ "x1": 1345.7956,
+ "y1": 1233.882,
+ "x2": 628.98234,
+ "y2": 1031.3044,
+ "name": null,
+ "name1": "PA",
+ "name2": "York"
+ },
+ {
+ "x1": 594.9833,
+ "y1": 912.30772,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Harrisburg",
+ "name2": "PA"
+ },
+ {
+ "x1": 722.47972,
+ "y1": 784.8113,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Wyoming Valley",
+ "name2": "PA"
+ },
+ {
+ "x1": 470.32013,
+ "y1": 995.88871,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Pittsburgh",
+ "name2": "PA"
+ },
+ {
+ "x1": 179.91162,
+ "y1": 1025.6379,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Bassett Town",
+ "name2": "PA"
+ },
+ {
+ "x1": 925.57679,
+ "y1": 1115.901,
+ "x2": 1425.4283,
+ "y2": 1302.2184,
+ "name": null,
+ "name1": "Wilmington DE",
+ "name2": "DE"
+ },
+ {
+ "x1": 1333.2713,
+ "y1": 1315.2406,
+ "x2": 804.37031,
+ "y2": 1143.9488,
+ "name": null,
+ "name1": "MD",
+ "name2": "Baltimore"
+ },
+ {
+ "x1": 672.14505,
+ "y1": 1127.9215,
+ "x2": 1333.2712999999999,
+ "y2": 1315.2405999999999,
+ "name": null,
+ "name1": "Frederick Town",
+ "name2": "MD"
+ },
+ {
+ "x1": 478.8157,
+ "y1": 1132.93,
+ "x2": 1333.2712999999999,
+ "y2": 1315.2406,
+ "name": null,
+ "name1": "Fort Cumberland",
+ "name2": "MD"
+ },
+ {
+ "x1": 805.37201,
+ "y1": 1355.3089,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Yorktown",
+ "name2": "VA"
+ },
+ {
+ "x1": 820.39761,
+ "y1": 1484.529,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Norfolk",
+ "name2": "VA"
+ },
+ {
+ "x1": 672.14505,
+ "y1": 1480.5222,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Petersburg",
+ "name2": "VA"
+ },
+ {
+ "x1": 643.09556,
+ "y1": 1356.3106,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Richmond",
+ "name2": "VA"
+ },
+ {
+ "x1": 695.1843,
+ "y1": 1262.1502,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Alexandria",
+ "name2": "VA"
+ },
+ {
+ "x1": 479.81741,
+ "y1": 1295.2065,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Charlottesville",
+ "name2": "VA"
+ },
+ {
+ "x1": 527.89932,
+ "y1": 1483.5273,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Lynch's Ferry",
+ "name2": "VA"
+ },
+ {
+ "x1": 388.66212,
+ "y1": 1440.4539,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Fincastle",
+ "name2": "VA"
+ },
+ {
+ "x1": 248.42321,
+ "y1": 1450.471,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Fort Chiswell",
+ "name2": "VA"
+ },
+ {
+ "x1": 166.28328,
+ "y1": 1249.128,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Point Pleasant",
+ "name2": "VA"
+ },
+ {
+ "x1": 97.165529,
+ "y1": 1485.5307,
+ "x2": 1279.1792,
+ "y2": 1372.3379,
+ "name": null,
+ "name1": "Abingdon",
+ "name2": "VA"
+ },
+ {
+ "x1": 162.27645,
+ "y1": 1606.7372,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Gilbert Town",
+ "name2": "NC"
+ },
+ {
+ "x1": 335.57167,
+ "y1": 1597.7218,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Salem",
+ "name2": "NC"
+ },
+ {
+ "x1": 244.41638,
+ "y1": 1691.8823,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Charlotte",
+ "name2": "NC"
+ },
+ {
+ "x1": 517.88225,
+ "y1": 1624.7679,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Hillsboro",
+ "name2": "NC"
+ },
+ {
+ "x1": 646.10068,
+ "y1": 1711.9164,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Wake (Raleigh)",
+ "name2": "NC"
+ },
+ {
+ "x1": 802.36689,
+ "y1": 1711.9164,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "New Bern",
+ "name2": "NC"
+ },
+ {
+ "x1": 713.21502,
+ "y1": 1850.1519,
+ "x2": 1301.2167,
+ "y2": 1441.4556,
+ "name": null,
+ "name1": "Wilmington",
+ "name2": "NC"
+ },
+ {
+ "x1": 1258.1433,
+ "y1": 1528.6041,
+ "x2": 615.04778,
+ "y2": 1957.3345,
+ "name": null,
+ "name1": "SC",
+ "name2": "Georgetown"
+ },
+ {
+ "x1": 482.82253,
+ "y1": 2090.5614,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Charleston",
+ "name2": "SC"
+ },
+ {
+ "x1": 442.75427,
+ "y1": 1942.3089,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Eutaw Springs",
+ "name2": "SC"
+ },
+ {
+ "x1": 534.91126,
+ "y1": 1833.1229,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Cheraw",
+ "name2": "SC"
+ },
+ {
+ "x1": 379.64676,
+ "y1": 1809.0819,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Camden",
+ "name2": "SC"
+ },
+ {
+ "x1": 257.43857,
+ "y1": 1972.3601,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Ninety Six",
+ "name2": "SC"
+ },
+ {
+ "x1": 114.19454,
+ "y1": 1813.0887,
+ "x2": 1258.1433,
+ "y2": 1528.6041,
+ "name": null,
+ "name1": "Fort Prince George",
+ "name2": "SC"
+ },
+ {
+ "x1": 173.29522,
+ "y1": 2094.5683,
+ "x2": 1208.058,
+ "y2": 1596.7201,
+ "name": null,
+ "name1": "Augusta",
+ "name2": "GA"
+ },
+ {
+ "x1": 266.45392,
+ "y1": 2315.9454,
+ "x2": 1208.058,
+ "y2": 1596.7201,
+ "name": null,
+ "name1": "Savannah",
+ "name2": "GA"
+ },
+ {
+ "x1": 220.37543,
+ "y1": 2437.1519,
+ "x2": 1208.058,
+ "y2": 1596.7201,
+ "name": null,
+ "name1": "St. Mary's",
+ "name2": "GA"
+ },
+ {
+ "x1": 1408.5453,
+ "y1": 1122.5186,
+ "x2": 1186.3301,
+ "y2": 904.04565,
+ "name": null,
+ "name1": "NY",
+ "name2": "Long Island"
+ },
+ {
+ "x1": 886,
+ "y1": 997.5,
+ "x2": 1345.7956,
+ "y2": 1233.882,
+ "name": null,
+ "name1": "Philadelphia",
+ "name2": "PA"
+ },
+ {
+ "x1": 1162.5,
+ "y1": 93.5,
+ "x2": 1418.0435,
+ "y2": 1001.5552,
+ "name": null,
+ "name1": "Quebec",
+ "name2": "Canada"
+ },
+ {
+ "x1": 1040,
+ "y1": 195,
+ "x2": 1418.0435,
+ "y2": 1001.5552,
+ "name": null,
+ "name1": "Montreal",
+ "name2": "Canada"
+ }
+ ]
+ },
+ "labels": [
+ {
+ "x": 1527.1014,
+ "y": 2281.8875,
+ "name": "9"
+ },
+ {
+ "x": 1468.5017,
+ "y": 2409.605,
+ "name": "1783"
+ },
+ {
+ "x": 1399.8848,
+ "y": 2412.6101,
+ "name": "1782"
+ },
+ {
+ "x": 1329.2645,
+ "y": 2408.6033,
+ "name": "1781"
+ },
+ {
+ "x": 1265.1553,
+ "y": 2410.1057,
+ "name": "1780"
+ },
+ {
+ "x": 1201.0461,
+ "y": 2410.1057,
+ "name": "1779"
+ },
+ {
+ "x": 1138.4395,
+ "y": 2409.605,
+ "name": "1778"
+ },
+ {
+ "x": 1062.8105,
+ "y": 2408.1025,
+ "name": "1777"
+ },
+ {
+ "x": 998.2005,
+ "y": 2408.6033,
+ "name": "1776"
+ },
+ {
+ "x": 928.08105,
+ "y": 2411.1077,
+ "name": "1775"
+ },
+ {
+ "x": 1476.0145,
+ "y": 2284.8926,
+ "name": "8"
+ },
+ {
+ "x": 1416.9138,
+ "y": 2286.896,
+ "name": "7"
+ },
+ {
+ "x": 1342.2867,
+ "y": 2285.3933,
+ "name": "6"
+ },
+ {
+ "x": 1264.6544,
+ "y": 2282.3882,
+ "name": "5"
+ },
+ {
+ "x": 1213.5674,
+ "y": 2279.884,
+ "name": "4"
+ },
+ {
+ "x": 1144.4497,
+ "y": 2280.3848,
+ "name": "3"
+ },
+ {
+ "x": 1082.3439,
+ "y": 2282.3882,
+ "name": "2"
+ },
+ {
+ "x": 1004.2108,
+ "y": 2285.8943,
+ "name": "1"
+ },
+ {
+ "x": 932.08789,
+ "y": 2283.8909,
+ "name": "0"
+ },
+ {
+ "x": 166.09312,
+ "y": 365.55655,
+ "name": "French Reinforcements"
+ },
+ {
+ "x": 395.46118,
+ "y": 363.54544,
+ "name": "American Leader Reinforcements"
+ },
+ {
+ "x": 1308.392,
+ "y": 100.05029,
+ "name": "Sea1"
+ },
+ {
+ "x": 1503.4926,
+ "y": 111.18933,
+ "name": "Captured Generals"
+ },
+ {
+ "x": 1155,
+ "y": 95,
+ "name": "Quebec"
+ },
+ {
+ "x": 1030,
+ "y": 200,
+ "name": "Montreal"
+ },
+ {
+ "x": 1170,
+ "y": 380,
+ "name": "Norwich"
+ },
+ {
+ "x": 1030,
+ "y": 400,
+ "name": "Ticonderoga"
+ },
+ {
+ "x": 815,
+ "y": 470,
+ "name": "Oswego"
+ },
+ {
+ "x": 910,
+ "y": 515,
+ "name": "Fort Stanwix"
+ },
+ {
+ "x": 1025,
+ "y": 540,
+ "name": "Saratoga"
+ },
+ {
+ "x": 1145,
+ "y": 535,
+ "name": "Brattleboro"
+ },
+ {
+ "x": 1240,
+ "y": 500,
+ "name": "Concord"
+ },
+ {
+ "x": 1363.8234,
+ "y": 463.28925,
+ "name": "Falmouth"
+ },
+ {
+ "x": 1363.3225,
+ "y": 632.07678,
+ "name": "Boston"
+ },
+ {
+ "x": 1428.9343,
+ "y": 738.75854,
+ "name": "Barnstable"
+ },
+ {
+ "x": 1330,
+ "y": 772.5,
+ "name": "Newport"
+ },
+ {
+ "x": 1254.1365,
+ "y": 673.64758,
+ "name": "Lexington Concord"
+ },
+ {
+ "x": 1215.0699,
+ "y": 800.36346,
+ "name": "Hartford"
+ },
+ {
+ "x": 1110.3916,
+ "y": 778.82678,
+ "name": "New Haven"
+ },
+ {
+ "x": 1121.9113,
+ "y": 655.61688,
+ "name": "Springfield"
+ },
+ {
+ "x": 997.19879,
+ "y": 667.63739,
+ "name": "Albany"
+ },
+ {
+ "x": 989.18512,
+ "y": 794.85413,
+ "name": "Westchester"
+ },
+ {
+ "x": 1057.802,
+ "y": 875.99231,
+ "name": "New York"
+ },
+ {
+ "x": 1188.0239,
+ "y": 912.55463,
+ "name": "Long Island"
+ },
+ {
+ "x": 1001.3301,
+ "y": 977.54565,
+ "name": "New Brunswick"
+ },
+ {
+ "x": 1033.7611,
+ "y": 1103.8805,
+ "name": "Monmouth"
+ },
+ {
+ "x": 893.0213,
+ "y": 871.98547,
+ "name": "Morristown"
+ },
+ {
+ "x": 715.7193,
+ "y": 630.07336,
+ "name": "Genesee"
+ },
+ {
+ "x": 501.56177,
+ "y": 561.97504,
+ "name": "Fort Niagara"
+ },
+ {
+ "x": 83.14164,
+ "y": 710.2099,
+ "name": "Fort Detroit"
+ },
+ {
+ "x": 181.30887,
+ "y": 1032.7594,
+ "name": "Bassett Town"
+ },
+ {
+ "x": 471.30289,
+ "y": 1001.2056,
+ "name": "Pittsburgh"
+ },
+ {
+ "x": 598.0188,
+ "y": 923.07251,
+ "name": "Harrisburg"
+ },
+ {
+ "x": 723.75372,
+ "y": 936.08838,
+ "name": "Reading"
+ },
+ {
+ "x": 624.56396,
+ "y": 1030.756,
+ "name": "York"
+ },
+ {
+ "x": 718.72443,
+ "y": 786.84045,
+ "name": "Wyoming Valley"
+ },
+ {
+ "x": 872.98718,
+ "y": 1009.2193,
+ "name": "Philadelphia"
+ },
+ {
+ "x": 909.04865,
+ "y": 1123.4138,
+ "name": "Wilmington DE"
+ },
+ {
+ "x": 800.36346,
+ "y": 1153.465,
+ "name": "Baltimore"
+ },
+ {
+ "x": 661.62714,
+ "y": 1143.448,
+ "name": "Frederick Town"
+ },
+ {
+ "x": 682.16211,
+ "y": 1260.1469,
+ "name": "Alexandria"
+ },
+ {
+ "x": 467.79694,
+ "y": 1297.21,
+ "name": "Charlottesville"
+ },
+ {
+ "x": 636.08362,
+ "y": 1367.8302,
+ "name": "Richmond"
+ },
+ {
+ "x": 808.37714,
+ "y": 1357.3123,
+ "name": "Yorktown"
+ },
+ {
+ "x": 819.89679,
+ "y": 1495.5479,
+ "name": "Norfolk"
+ },
+ {
+ "x": 660.62543,
+ "y": 1496.5496,
+ "name": "Petersburg"
+ },
+ {
+ "x": 512.87372,
+ "y": 1485.5306,
+ "name": "Lynch's Ferry"
+ },
+ {
+ "x": 386.15784,
+ "y": 1446.4642,
+ "name": "Fincastle"
+ },
+ {
+ "x": 237.90529,
+ "y": 1447.9667,
+ "name": "Fort Chiswell"
+ },
+ {
+ "x": 160.7739,
+ "y": 1260.1469,
+ "name": "Point Pleasant"
+ },
+ {
+ "x": 91.656143,
+ "y": 1496.5496,
+ "name": "Abingdon"
+ },
+ {
+ "x": 162.8092,
+ "y": 1603.8098,
+ "name": "Gilbert Town"
+ },
+ {
+ "x": 341.58191,
+ "y": 1604.7338,
+ "name": "Salem"
+ },
+ {
+ "x": 514.87714,
+ "y": 1625.2688,
+ "name": "Hillsboro"
+ },
+ {
+ "x": 646.3092,
+ "y": 1707.0598,
+ "name": "Wake (Raleigh)"
+ },
+ {
+ "x": 815.88995,
+ "y": 1717.4258,
+ "name": "New Bern"
+ },
+ {
+ "x": 713.71588,
+ "y": 1857.1638,
+ "name": "Wilmington"
+ },
+ {
+ "x": 605.0307,
+ "y": 1954.3293,
+ "name": "Georgetown"
+ },
+ {
+ "x": 523.89252,
+ "y": 1833.6237,
+ "name": "Cheraw"
+ },
+ {
+ "x": 368.62799,
+ "y": 1816.5947,
+ "name": "Camden"
+ },
+ {
+ "x": 249.42491,
+ "y": 1701.8993,
+ "name": "Charlotte"
+ },
+ {
+ "x": 110.68857,
+ "y": 1818.5981,
+ "name": "Fort Prince George"
+ },
+ {
+ "x": 252.93089,
+ "y": 1970.8575,
+ "name": "Ninety Six"
+ },
+ {
+ "x": 434.7406,
+ "y": 1951.3242,
+ "name": "Eutaw Springs"
+ },
+ {
+ "x": 478.8157,
+ "y": 2099.0759,
+ "name": "Charleston"
+ },
+ {
+ "x": 264.4505,
+ "y": 2315.4446,
+ "name": "Savannah"
+ },
+ {
+ "x": 179.8063,
+ "y": 2104.0845,
+ "name": "Augusta"
+ },
+ {
+ "x": 215.3669,
+ "y": 2438.6543,
+ "name": "St. Mary's"
+ },
+ {
+ "x": 1008.5179,
+ "y": 2050.7935,
+ "name": "BRC"
+ },
+ {
+ "x": 1231.9423,
+ "y": 2050.9939,
+ "name": "ARC1"
+ },
+ {
+ "x": 1466.2352,
+ "y": 2057.8745,
+ "name": "ARC2"
+ },
+ {
+ "x": 1465,
+ "y": 1776,
+ "name": "British Reinforcement Box"
+ },
+ {
+ "x": 1167.4889,
+ "y": 1789.0479,
+ "name": "War Ends Card"
+ },
+ {
+ "x": 1197.0392,
+ "y": 1587.2039,
+ "name": "GA"
+ },
+ {
+ "x": 1252.1331,
+ "y": 1520.0896,
+ "name": "SC"
+ },
+ {
+ "x": 1300,
+ "y": 1443.5,
+ "name": "NC"
+ },
+ {
+ "x": 1290.6989,
+ "y": 1383.3567,
+ "name": "VA"
+ },
+ {
+ "x": 1339,
+ "y": 1302.5,
+ "name": "MD"
+ },
+ {
+ "x": 1407.3976,
+ "y": 1313.7382,
+ "name": "DE"
+ },
+ {
+ "x": 1414.9104,
+ "y": 1234.1024,
+ "name": "NJ"
+ },
+ {
+ "x": 1339,
+ "y": 1230,
+ "name": "PA"
+ },
+ {
+ "x": 1504.0623,
+ "y": 1195.0358,
+ "name": "CT"
+ },
+ {
+ "x": 1577.6877,
+ "y": 1194.535,
+ "name": "RI"
+ },
+ {
+ "x": 1534.1135,
+ "y": 1122.913,
+ "name": "MA"
+ },
+ {
+ "x": 1406.8969,
+ "y": 1122.4121,
+ "name": "NY"
+ },
+ {
+ "x": 1498,
+ "y": 1043,
+ "name": "NH"
+ },
+ {
+ "x": 1416,
+ "y": 1003.5,
+ "name": "Canada"
+ },
+ {
+ "x": 1509.5,
+ "y": 550,
+ "name": "Sea2"
+ },
+ {
+ "x": 1253.5,
+ "y": 1016.5,
+ "name": "Sea3"
+ },
+ {
+ "x": 1088.8549,
+ "y": 1218.0751,
+ "name": "Sea4"
+ },
+ {
+ "x": 981.17151,
+ "y": 1441.9565,
+ "name": "Sea5"
+ },
+ {
+ "x": 671.14337,
+ "y": 2067.0212,
+ "name": "Sea6"
+ },
+ {
+ "x": 393.67065,
+ "y": 2394.5793,
+ "name": "Sea7"
+ },
+ {
+ "x": 585,
+ "y": 385,
+ "name": "Continental Corgress Dispersed Box"
+ },
+ {
+ "x": 479.92914,
+ "y": 1140.5603,
+ "name": "Fort Cumberland"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tools/layout.svg b/tools/layout.svg
index 506d903..9805857 100644
--- a/tools/layout.svg
+++ b/tools/layout.svg
@@ -40,9 +40,9 @@
inkscape:window-height="480"
id="namedview8"
showgrid="false"
- inkscape:zoom="0.5"
- inkscape:cx="1894.5029"
- inkscape:cy="1424.4221"
+ inkscape:zoom="0.71155804"
+ inkscape:cx="871.00863"
+ inkscape:cy="553.26207"
inkscape:current-layer="svg6"
inkscape:snap-center="false"
inkscape:snap-others="true"
@@ -55,31 +55,32 @@
<image
sodipodi:absref="/home/tor/src/rally/public/washingtons-war/tools/mapmask.png"
xlink:href="mapmask.png"
- x="0"
- y="0"
- width="1650"
- height="2550"
- image-rendering="pixelated"
- sodipodi:insensitive="true"
+ style="display:inline"
id="image2"
- style="display:inline" />
+ sodipodi:insensitive="true"
+ image-rendering="pixelated"
+ height="2550"
+ width="1650"
+ y="0"
+ x="0" />
<image
sodipodi:absref="/home/tor/src/rally/public/washingtons-war/tools/map75.png"
xlink:href="map75.png"
- x="0"
- y="0"
- width="1650"
- height="2550"
- image-rendering="pixelated"
- opacity="0.535871"
- id="image4"
- style="display:inline"
+ sodipodi:insensitive="true"
inkscape:label="texture"
- sodipodi:insensitive="true" />
+ style="display:inline"
+ id="image4"
+ opacity="0.535871"
+ image-rendering="pixelated"
+ height="2550"
+ width="1650"
+ y="0"
+ x="0" />
<g
id="g2693"
- inkscape:label="fortress"
- style="display:none">
+ inkscape:label="fortified_port"
+ style="display:none"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect887"
@@ -112,7 +113,8 @@
<g
id="g2712"
inkscape:label="winter_quarters"
- style="display:none">
+ style="display:none"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect845"
@@ -235,8 +237,9 @@
</g>
<g
id="g2687"
- inkscape:label="space"
- style="display:none">
+ inkscape:label="regular"
+ style="display:none"
+ sodipodi:insensitive="true">
<circle
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="circle910"
@@ -587,7 +590,8 @@
<g
id="g2555"
inkscape:label="sea"
- style="display:inline">
+ style="display:inline"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1000"
@@ -641,7 +645,8 @@
<g
id="g2546"
inkscape:label="colony"
- style="display:inline">
+ style="display:inline"
+ sodipodi:insensitive="true">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1016"
@@ -744,85 +749,83 @@
<g
id="g2584"
inkscape:label="box"
- style="display:inline"
- sodipodi:insensitive="true">
+ style="display:inline">
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.99946"
+ id="rect1092"
+ width="214"
+ height="206"
+ x="1358"
+ y="1673"
+ inkscape:label="British Reinforcement Box" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.00286"
+ id="rect1096"
+ width="214"
+ height="206"
+ x="294"
+ y="258"
+ inkscape:label="American Leader Reinforcements" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.08098"
+ id="rect1098"
+ width="214"
+ height="207"
+ x="63"
+ y="258"
+ inkscape:label="French Reinforcements" />
<rect
style="opacity:1;fill:#000000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1606"
width="88"
height="104"
x="542"
- y="332" />
+ y="332"
+ inkscape:label="Continental Congress Dispersed" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1044"
- width="64"
- height="71"
- x="905"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1046"
- width="64"
- height="71"
- x="971"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1048"
- width="64"
- height="71"
- x="1037"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1050"
- width="64"
- height="71"
- x="1103"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1052"
- width="65"
- height="71"
- x="1169"
- y="2241" />
- <rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1054"
- width="64"
- height="71"
- x="1236"
- y="2241" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.23342"
+ id="rect1094"
+ width="205"
+ height="136"
+ x="1400"
+ y="46"
+ inkscape:label="Captured Generals" />
+ </g>
+ <g
+ id="g607"
+ inkscape:label="Card Boxes">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1056"
- width="64"
- height="71"
- x="1302"
- y="2241" />
+ id="rect1084"
+ width="199"
+ height="277"
+ x="904"
+ y="1915" />
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1058"
- width="64"
- height="71"
- x="1368"
- y="2241" />
+ id="rect1086"
+ width="199"
+ height="277"
+ x="1137"
+ y="1915" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1060"
- width="65"
- height="71"
- x="1434"
- y="2241" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.97641"
+ id="rect1088"
+ width="199.00003"
+ height="277"
+ x="1370"
+ y="1915" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1062"
- width="63"
- height="71"
- x="1501"
- y="2241" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.0365"
+ id="rect1090"
+ width="278"
+ height="198.99998"
+ x="1027"
+ y="1679" />
+ </g>
+ <g
+ id="g580"
+ inkscape:label="Game Turn">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
id="rect1066"
@@ -886,62 +889,80 @@
height="72"
x="1433"
y="2368" />
+ </g>
+ <g
+ id="g569"
+ inkscape:label="French Alliance Track">
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1084"
- width="199"
- height="277"
- x="904"
- y="1915" />
+ id="rect1044"
+ width="64"
+ height="71"
+ x="905"
+ y="2241" />
<rect
style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
- id="rect1086"
- width="199"
- height="277"
- x="1137"
- y="1915" />
+ id="rect1046"
+ width="64"
+ height="71"
+ x="971"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.97641"
- id="rect1088"
- width="199.00003"
- height="277"
- x="1370"
- y="1915" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1048"
+ width="64"
+ height="71"
+ x="1037"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.0365"
- id="rect1090"
- width="278"
- height="198.99998"
- x="1027"
- y="1679" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1050"
+ width="64"
+ height="71"
+ x="1103"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:2.99946"
- id="rect1092"
- width="214"
- height="206"
- x="1358"
- y="1673" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1052"
+ width="65"
+ height="71"
+ x="1169"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.23342"
- id="rect1094"
- width="205"
- height="136"
- x="1400"
- y="46" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1054"
+ width="64"
+ height="71"
+ x="1236"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.00286"
- id="rect1096"
- width="214"
- height="206"
- x="294"
- y="258" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1056"
+ width="64"
+ height="71"
+ x="1302"
+ y="2241" />
<rect
- style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3.08098"
- id="rect1098"
- width="214"
- height="207"
- x="63"
- y="258" />
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1058"
+ width="64"
+ height="71"
+ x="1368"
+ y="2241" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1060"
+ width="65"
+ height="71"
+ x="1434"
+ y="2241" />
+ <rect
+ style="opacity:0.99;fill:#ff0000;fill-opacity:0.46748;stroke:none;stroke-width:3"
+ id="rect1062"
+ width="63"
+ height="71"
+ x="1501"
+ y="2241" />
</g>
<g
id="g2117"
@@ -1202,36 +1223,43 @@
sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 759.31202,949.84833 92.08074,31.1658"
- id="path1918" />
+ d="m 759.31202,949.84833 90.94423,35.42773"
+ id="path1918"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 905.22459,1026.3462 1.41662,2.8332 13.45796,48.8737"
- id="path1920" />
+ d="m 908.63011,1030.8842 11.46906,47.1689"
+ id="path1920"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 845.72626,1138.2597 46.74868,-9.9164"
- id="path1922" />
+ d="m 849.98819,1137.6914 36.80418,-8.4957"
+ id="path1922"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 913.01603,1019.9714 96.33067,71.5396"
- id="path1924" />
+ d="m 920.40337,1023.0968 83.54493,65.0047"
+ id="path1924"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 1017.8464,1017.1381 17.7079,58.0817"
- id="path1926" />
+ d="m 1017.8464,1017.1381 16.0031,53.2515"
+ id="path1926"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 920.09917,990.93051 39.66555,-9.20807"
- id="path1928" />
+ d="m 924.64522,988.37335 35.1195,-6.65091"
+ id="path1928"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 930.01556,893.89157 48.16531,49.58194"
id="path1930" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 1027.7628,947.01508 17.7078,-33.99905"
- id="path1932" />
+ d="m 1023.785,945.87857 21.6856,-32.86254"
+ id="path1932"
+ sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1104.2595,880.08247 43.9117,12.0353"
@@ -1451,7 +1479,8 @@
style="opacity:1;fill:none;fill-opacity:0.46748;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:5, 5;stroke-dashoffset:0;stroke-opacity:1"
d="m 1196,127 c 74.0155,102.10344 61.3742,165.34334 150.2935,291.71331"
id="path2123"
- sodipodi:nodetypes="cc" />
+ sodipodi:nodetypes="cc"
+ inkscape:label="Quebec-Falmouth" />
</g>
<g
id="g2298"
@@ -1542,7 +1571,8 @@
<g
id="g2530"
inkscape:label="colony"
- style="display:none">
+ style="display:none"
+ sodipodi:insensitive="true">
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#f50000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
d="m 1250.8815,498.65267 252.1596,543.98473"
@@ -1816,7 +1846,8 @@
<g
id="g1810"
inkscape:label="labels"
- style="display:none">
+ style="display:inline"
+ sodipodi:insensitive="true">
<text
xml:space="preserve"
style="font-size:14px;font-family:sans-serif;-inkscape-font-specification:sans-serif;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:12, 6, 3, 6;stroke-dashoffset:0;stroke-opacity:1"
@@ -2406,7 +2437,7 @@
sodipodi:role="line"
id="tspan1376"
x="909.04865"
- y="1123.4138">Wilmington</tspan></text>
+ y="1123.4138">Wilmington DE</tspan></text>
<text
xml:space="preserve"
style="font-size:14px;font-family:sans-serif;-inkscape-font-specification:sans-serif;opacity:1;fill:#000000;fill-opacity:0.46748;stroke:none;stroke-width:3"
diff --git a/tools/parse-layout-old.js b/tools/parse-layout-old.js
new file mode 100644
index 0000000..b382849
--- /dev/null
+++ b/tools/parse-layout-old.js
@@ -0,0 +1,466 @@
+"use strict"
+
+/* COMMON PARSING */
+
+const fs = require("fs")
+
+let points = {}
+let circles = {}
+let rects = {}
+let edges = {}
+let labels = []
+
+let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2
+
+function array_insert(array, index, item) {
+ for (let i = array.length; i > index; --i)
+ array[i] = array[i - 1]
+ array[index] = item
+}
+
+function set_add(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return
+ }
+ array_insert(set, a, item)
+}
+
+function add_point(x, y) {
+ if (!(name in points))
+ points[name] = []
+ points[name].push({x,y})
+}
+
+function add_circle(cx, cy, rx, ry) {
+ if (!(name in circles))
+ circles[name] = []
+ circles[name].push({x:cx-rx,y:cy-ry,w:rx*2,h:ry*2})
+}
+
+function add_rect(x, y, w, h) {
+ if (!(name in rects))
+ rects[name] = []
+ rects[name].push({x,y,w,h})
+}
+
+function add_edge(x1, y1, x2, y2) {
+ if (!(name in edges))
+ edges[name] = []
+ edges[name].push({x1,y1,x2,y2})
+}
+
+function flush() {
+ if (mode === 'path') {
+ add_edge(x, y, x2, y2)
+ }
+ if (mode === 'rect') {
+ add_rect(x, y, w, h)
+ add_point(x + w/2, y + h/2)
+ }
+ if (mode === 'circle') {
+ add_circle(cx, cy, rx, ry)
+ add_point(cx, cy)
+ }
+ x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0
+}
+
+function parse_path_data(path) {
+ let cx = 0
+ let cy = 0
+ let abs = 0
+ for (let i = 0; i < path.length;) {
+ switch (path[i]) {
+ case 'M':
+ x2 = x = cx = Number(path[i+1])
+ y2 = y = cy = Number(path[i+2])
+ i += 3
+ abs = true
+ break
+ case 'm':
+ x2 = x = cx = cx + Number(path[i+1])
+ y2 = y = cy = cy + Number(path[i+2])
+ i += 3
+ abs = false
+ break
+ case 'C':
+ x2 = cx = Number(path[i+5])
+ y2 = cy = Number(path[i+6])
+ i += 7
+ abs = true
+ break
+ case 'L':
+ i += 1
+ abs = true
+ break
+ case 'H':
+ x2 = cx = Number(path[i+1])
+ i += 2
+ abs = true
+ break
+ case 'V':
+ y2 = cy = Number(path[i+1])
+ i += 2
+ abs = true
+ break
+ case 'c':
+ x2 = cx = cx + Number(path[i+5])
+ y2 = cy = cy + Number(path[i+6])
+ i += 7
+ abs = false
+ break
+ case 'l':
+ i += 1
+ abs = false
+ break
+ case 'h':
+ x2 = cx = cx + Number(path[i+1])
+ i += 2
+ abs = false
+ break
+ case 'v':
+ y2 = cy = cy + Number(path[i+1])
+ i += 2
+ abs = false
+ break
+ default:
+ if (abs) {
+ x2 = cx = Number(path[i+0])
+ y2 = cy = Number(path[i+1])
+ } else {
+ x2 = cx = cx + Number(path[i+0])
+ y2 = cy = cy + Number(path[i+1])
+ }
+ i += 2
+ break
+ }
+ }
+}
+
+for (let line of fs.readFileSync("tools/layout.svg", "utf-8").split("\n")) {
+ line = line.trim()
+ if (line.startsWith("<rect")) {
+ flush()
+ mode = "rect"
+ x = y = w = h = 0
+ }
+ else if (line.startsWith("<ellipse") || line.startsWith("<circle")) {
+ flush()
+ mode = "circle"
+ cx = cy = rx = ry = 0
+ }
+ else if (line.startsWith("<path")) {
+ flush()
+ mode = "path"
+ }
+ else if (line.startsWith("<g")) {
+ flush()
+ mode = "g"
+ }
+ else if (line.startsWith('x="'))
+ x = (Number(line.split('"')[1]))
+ else if (line.startsWith('y="'))
+ y = (Number(line.split('"')[1]))
+ else if (line.startsWith('width="'))
+ w = (Number(line.split('"')[1]))
+ else if (line.startsWith('height="'))
+ h = (Number(line.split('"')[1]))
+ else if (line.startsWith('cx="'))
+ cx = (Number(line.split('"')[1]))
+ else if (line.startsWith('cy="'))
+ cy = (Number(line.split('"')[1]))
+ else if (line.startsWith('r="'))
+ rx = ry = (Number(line.split('"')[1]))
+ else if (line.startsWith('rx="'))
+ rx = (Number(line.split('"')[1]))
+ else if (line.startsWith('ry="'))
+ ry = (Number(line.split('"')[1]))
+ else if (line.startsWith('inkscape:label="') && mode === "g")
+ name = line.split('"')[1]
+ else if (line.startsWith('d="'))
+ parse_path_data(line.split('"')[1].split(/[ ,]/))
+ if (line.includes("</tspan>")) {
+ let name = line.replace(/^[^>]*>/, "").replace(/<\/tspan.*/, "")
+ labels.push({x, y, name})
+ }
+}
+
+flush()
+
+function find_closest_label(x, y) {
+ let nd = Infinity, nn = null
+
+ for (let n of labels) {
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = n
+ }
+ }
+
+ if (!nn) {
+ console.log("NOT FOUND", x, y)
+ return null
+ }
+
+ if (nd > 50) {
+ console.log("NO LABEL", x, y, nd)
+ return null
+ }
+
+ return nn.name
+}
+
+function find_closest_node(nodes, x, y) {
+ let nd = Infinity, nn = -1
+
+ for (let i = 0; i < nodes.length; ++i) {
+ let n = nodes[i]
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = i
+ }
+ }
+
+ if (nd > 100)
+ return -1
+
+ return nn
+}
+
+function label_boxes(top) {
+ for (let key in top) {
+ console.log("BOX", key)
+ for (let item of top[key])
+ item.name = find_closest_label(item.x + item.w/2, item.y + item.h/2)
+ }
+}
+
+function label_points(top) {
+ for (let key in top) {
+ console.log("POINT", key)
+ for (let item of top[key])
+ item.name = find_closest_label(item.x, item.y)
+ }
+}
+
+label_boxes(rects)
+label_boxes(circles)
+label_points(points)
+
+function connect_edge_2way(node_list, edge_name) {
+ console.log("EDGE", edge_name)
+ for (let e of edges[edge_name]) {
+ let a = find_closest_node(node_list, e.x1, e.y1)
+ let b = find_closest_node(node_list, e.x2, e.y2)
+ if (a < 0 || b < 0)
+ console.log("CANNOT FIND EDGE", e, node_list[a], node_list[b])
+ if (!node_list[a][edge_name])
+ node_list[a][edge_name] = []
+ if (!node_list[b][edge_name])
+ node_list[b][edge_name] = []
+ set_add(node_list[a][edge_name], b)
+ set_add(node_list[b][edge_name], a)
+ }
+}
+
+function connect_edge_1way(a_list, b_list, edge_name, prop_name) {
+ console.log("EDGE", edge_name)
+ for (let e of edges[edge_name]) {
+ let a1 = find_closest_node(a_list, e.x1, e.y1)
+ let a2 = find_closest_node(a_list, e.x2, e.y2)
+ let b1 = find_closest_node(b_list, e.x1, e.y1)
+ let b2 = find_closest_node(b_list, e.x2, e.y2)
+ let a = a1 >= 0 ? a1 : a2
+ let b = b1 >= 0 ? b1 : b2
+ if (a < 0 || b < 0)
+ console.log("CANNOT FIND EDGE", e, a_list[a], b_list[b])
+ if (!a_list[a][prop_name])
+ a_list[a][prop_name] = []
+ set_add(a_list[a][prop_name], b)
+ }
+}
+
+/* WASHINGTON'S WAR */
+
+function sort_alpha(list) {
+ list.sort((a,b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
+}
+
+sort_alpha(points.fortress)
+sort_alpha(points.winter_quarters)
+sort_alpha(points.space)
+points.colony.reverse()
+
+const data = {}
+
+data.spaces = [ ...points.fortress, ...points.winter_quarters, ...points.space ]
+data.colonies = [ ...points.colony ]
+data.seas = [ ...points.sea ]
+
+connect_edge_2way(data.spaces, "path")
+connect_edge_2way(data.spaces, "wilderness")
+connect_edge_1way(data.colonies, data.spaces, "colony", "spaces")
+connect_edge_1way(data.seas, data.spaces, "sea", "spaces")
+
+console.log(JSON.stringify(data,0,4))
+
+/*
+function find_closest_node(list, x, y) {
+ let nd = Infinity, nn = null
+
+ for (let n of list) {
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = n
+ }
+ }
+
+ if (!nn) {
+ console.log("NOT FOUND", x, y)
+ return [ null, 0 ]
+ }
+
+ return [ nn, nd ]
+}
+
+function find_enclosing_rect(list, x, y) {
+ for (let [x1, y1, x2, y2] of list) {
+ if (x >= x1 && x <= x2)
+ if (y >= y1 && y <= y2)
+ return true
+ }
+ return false
+}
+
+
+function make_spaces(points) {
+ let spaces = []
+ for (let [x,y] of points) {
+ let [ name, dist ] = find_closest_node(labels, x, y)
+ if (dist > 50) console.log("DISTANCE TOO FAR", x, y, dist)
+
+ spaces.push({ name: name.name, x, y })
+ }
+ return spaces
+}
+
+let data = {}
+
+data.spaces = make_spaces([ ...points.fortress, ...points.winter_quarters, ...points.space ])
+
+console.log(data)
+
+function find_closest_point(x, y) {
+ let nd = Infinity, nn = -1
+
+ for (let i = 0; i < points.length; ++i) {
+ let n = points[i]
+ let d = Math.hypot(n.x - x, n.y - y)
+ if (d < nd) {
+ nd = d
+ nn = i
+ }
+ }
+
+ return nn
+}
+
+// FIND and label all points!
+let all_labels = labels.slice()
+let cities = []
+for (let key in points) {
+ for (let [x, y] of points[key]) {
+ let [ node, dist ] = find_closest_node(labels, x, y)
+ if (dist > 15) {
+ console.log("DISTANCE TOO FAR", key,x,y, "dist=" + dist, "name=" + node.name)
+ }
+ if (node) {
+ labels = labels.filter(x => x !== node)
+ let suit = "UNKNOWN"
+
+ if (find_enclosing_rect(rects.$CLUBS, x, y))
+ suit = CLUBS
+ else if (find_enclosing_rect(rects.$HEARTS, x, y))
+ suit = HEARTS
+ else if (find_enclosing_rect(rects.$DIAMONDS, x, y))
+ suit = DIAMONDS
+ else if (find_enclosing_rect(rects.$SPADES, x, y))
+ suit = SPADES
+ else
+ console.log("NOT ASSIGNED SUIT", x, y)
+
+ let country = "UNKNOWN"
+ if (find_enclosing_rect(rects.$Empire, x, y)) {
+ country = EMPIRE
+ }
+ else if (find_enclosing_rect(rects.$Austria, x, y)) {
+ country = AUSTRIA
+ }
+ else if (find_enclosing_rect(rects.$Hanover, x, y)) {
+ country = HANOVER
+ }
+ else if (find_enclosing_rect(rects.$Saxony, x, y)) {
+ country = SAXONY
+ }
+ else if (find_enclosing_rect(rects.$Sweden, x, y)) {
+ country = SWEDEN
+ }
+ else if (find_enclosing_rect(rects.$Poland, x, y)) {
+ country = POLAND
+ }
+ else if (find_enclosing_rect(rects.$Prussia, x, y)) {
+ country = PRUSSIA
+ }
+
+ if (country === "UNKNOWN")
+ console.log("no country:", node)
+
+ cities.push({
+ name: node.name,
+ country,
+ suit,
+ type: key,
+ x: Math.round(x),
+ y: Math.round(y),
+ adjacent: [],
+ major_roads: [],
+ roads: [],
+ })
+ } else {
+ let [ dupname, dupdist ] = find_closest_node(all_labels, x, y)
+ console.log("ALREADY USED", dupname, dupdist, x, y)
+ }
+ }
+}
+
+for (let e of edges.major_road) {
+ let a = find_closest_point(e.x1, e.y1)
+ let b = find_closest_point(e.x2, e.y2)
+ set_add(cities[a].major_roads, b)
+ set_add(cities[b].major_roads, a)
+ set_add(cities[a].adjacent, b)
+ set_add(cities[b].adjacent, a)
+}
+
+for (let e of edges.road) {
+ let a = find_closest_point(e.x1, e.y1)
+ let b = find_closest_point(e.x2, e.y2)
+ set_add(cities[a].roads, b)
+ set_add(cities[b].roads, a)
+ set_add(cities[a].adjacent, b)
+ set_add(cities[b].adjacent, a)
+}
+
+console.log("if (typeof module === 'object') module.exports = data")
+*/
diff --git a/tools/parse-layout.js b/tools/parse-layout.js
index b382849..6f77adf 100644
--- a/tools/parse-layout.js
+++ b/tools/parse-layout.js
@@ -1,61 +1,30 @@
"use strict"
-/* COMMON PARSING */
-
const fs = require("fs")
let points = {}
-let circles = {}
-let rects = {}
+let boxes = {}
let edges = {}
+let mode, group, name, x, y, w, h, cx, cy, rx, ry, x2, y2
let labels = []
-
-let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2
-
-function array_insert(array, index, item) {
- for (let i = array.length; i > index; --i)
- array[i] = array[i - 1]
- array[index] = item
-}
-
-function set_add(set, item) {
- let a = 0
- let b = set.length - 1
- while (a <= b) {
- let m = (a + b) >> 1
- let x = set[m]
- if (item < x)
- b = m - 1
- else if (item > x)
- a = m + 1
- else
- return
- }
- array_insert(set, a, item)
-}
+let labels_uniq = {}
function add_point(x, y) {
- if (!(name in points))
- points[name] = []
- points[name].push({x,y})
-}
-
-function add_circle(cx, cy, rx, ry) {
- if (!(name in circles))
- circles[name] = []
- circles[name].push({x:cx-rx,y:cy-ry,w:rx*2,h:ry*2})
+ if (!(group in points))
+ points[group] = []
+ points[group].push({x,y,name})
}
function add_rect(x, y, w, h) {
- if (!(name in rects))
- rects[name] = []
- rects[name].push({x,y,w,h})
+ if (!(group in boxes))
+ boxes[group] = []
+ boxes[group].push({x,y,w,h,name})
}
function add_edge(x1, y1, x2, y2) {
- if (!(name in edges))
- edges[name] = []
- edges[name].push({x1,y1,x2,y2})
+ if (!(group in edges))
+ edges[group] = []
+ edges[group].push({x1,y1,x2,y2,name})
}
function flush() {
@@ -64,13 +33,14 @@ function flush() {
}
if (mode === 'rect') {
add_rect(x, y, w, h)
- add_point(x + w/2, y + h/2)
+ add_point( x + w/2, y + h/2 )
}
if (mode === 'circle') {
- add_circle(cx, cy, rx, ry)
- add_point(cx, cy)
+ add_rect(cx - rx, cy - ry, rx * 2, ry * 2)
+ add_point( cx, cy )
}
x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0
+ name = null
}
function parse_path_data(path) {
@@ -184,18 +154,23 @@ for (let line of fs.readFileSync("tools/layout.svg", "utf-8").split("\n")) {
else if (line.startsWith('ry="'))
ry = (Number(line.split('"')[1]))
else if (line.startsWith('inkscape:label="') && mode === "g")
+ group = line.split('"')[1]
+ else if (line.startsWith('inkscape:label="') && mode !== "g")
name = line.split('"')[1]
else if (line.startsWith('d="'))
parse_path_data(line.split('"')[1].split(/[ ,]/))
if (line.includes("</tspan>")) {
let name = line.replace(/^[^>]*>/, "").replace(/<\/tspan.*/, "")
+ if (name in labels_uniq)
+ console.log("DUPLICATE LABEL", name)
labels.push({x, y, name})
+ labels_uniq[name] = 1
}
}
flush()
-function find_closest_label(x, y) {
+function find_label(x, y, limit) {
let nd = Infinity, nn = null
for (let n of labels) {
@@ -206,261 +181,35 @@ function find_closest_label(x, y) {
}
}
- if (!nn) {
- console.log("NOT FOUND", x, y)
- return null
- }
-
- if (nd > 50) {
- console.log("NO LABEL", x, y, nd)
+ if (!nn || nd > limit) {
+ console.log("LABEL NOT FOUND", x, y)
return null
}
return nn.name
}
-function find_closest_node(nodes, x, y) {
- let nd = Infinity, nn = -1
-
- for (let i = 0; i < nodes.length; ++i) {
- let n = nodes[i]
- let d = Math.hypot(n.x - x, n.y - y)
- if (d < nd) {
- nd = d
- nn = i
+for (let group in points) {
+ for (let item of points[group]) {
+ if (item.name === null) {
+ item.name = find_label(item.x, item.y, 72)
}
}
-
- if (nd > 100)
- return -1
-
- return nn
}
-function label_boxes(top) {
- for (let key in top) {
- console.log("BOX", key)
- for (let item of top[key])
- item.name = find_closest_label(item.x + item.w/2, item.y + item.h/2)
- }
-}
-
-function label_points(top) {
- for (let key in top) {
- console.log("POINT", key)
- for (let item of top[key])
- item.name = find_closest_label(item.x, item.y)
- }
-}
-
-label_boxes(rects)
-label_boxes(circles)
-label_points(points)
-
-function connect_edge_2way(node_list, edge_name) {
- console.log("EDGE", edge_name)
- for (let e of edges[edge_name]) {
- let a = find_closest_node(node_list, e.x1, e.y1)
- let b = find_closest_node(node_list, e.x2, e.y2)
- if (a < 0 || b < 0)
- console.log("CANNOT FIND EDGE", e, node_list[a], node_list[b])
- if (!node_list[a][edge_name])
- node_list[a][edge_name] = []
- if (!node_list[b][edge_name])
- node_list[b][edge_name] = []
- set_add(node_list[a][edge_name], b)
- set_add(node_list[b][edge_name], a)
- }
-}
-
-function connect_edge_1way(a_list, b_list, edge_name, prop_name) {
- console.log("EDGE", edge_name)
- for (let e of edges[edge_name]) {
- let a1 = find_closest_node(a_list, e.x1, e.y1)
- let a2 = find_closest_node(a_list, e.x2, e.y2)
- let b1 = find_closest_node(b_list, e.x1, e.y1)
- let b2 = find_closest_node(b_list, e.x2, e.y2)
- let a = a1 >= 0 ? a1 : a2
- let b = b1 >= 0 ? b1 : b2
- if (a < 0 || b < 0)
- console.log("CANNOT FIND EDGE", e, a_list[a], b_list[b])
- if (!a_list[a][prop_name])
- a_list[a][prop_name] = []
- set_add(a_list[a][prop_name], b)
- }
-}
-
-/* WASHINGTON'S WAR */
-
-function sort_alpha(list) {
- list.sort((a,b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
-}
-
-sort_alpha(points.fortress)
-sort_alpha(points.winter_quarters)
-sort_alpha(points.space)
-points.colony.reverse()
-
-const data = {}
-
-data.spaces = [ ...points.fortress, ...points.winter_quarters, ...points.space ]
-data.colonies = [ ...points.colony ]
-data.seas = [ ...points.sea ]
-
-connect_edge_2way(data.spaces, "path")
-connect_edge_2way(data.spaces, "wilderness")
-connect_edge_1way(data.colonies, data.spaces, "colony", "spaces")
-connect_edge_1way(data.seas, data.spaces, "sea", "spaces")
-
-console.log(JSON.stringify(data,0,4))
-
-/*
-function find_closest_node(list, x, y) {
- let nd = Infinity, nn = null
-
- for (let n of list) {
- let d = Math.hypot(n.x - x, n.y - y)
- if (d < nd) {
- nd = d
- nn = n
- }
- }
-
- if (!nn) {
- console.log("NOT FOUND", x, y)
- return [ null, 0 ]
- }
-
- return [ nn, nd ]
-}
-
-function find_enclosing_rect(list, x, y) {
- for (let [x1, y1, x2, y2] of list) {
- if (x >= x1 && x <= x2)
- if (y >= y1 && y <= y2)
- return true
- }
- return false
-}
-
-
-function make_spaces(points) {
- let spaces = []
- for (let [x,y] of points) {
- let [ name, dist ] = find_closest_node(labels, x, y)
- if (dist > 50) console.log("DISTANCE TOO FAR", x, y, dist)
-
- spaces.push({ name: name.name, x, y })
- }
- return spaces
-}
-
-let data = {}
-
-data.spaces = make_spaces([ ...points.fortress, ...points.winter_quarters, ...points.space ])
-
-console.log(data)
-
-function find_closest_point(x, y) {
- let nd = Infinity, nn = -1
-
- for (let i = 0; i < points.length; ++i) {
- let n = points[i]
- let d = Math.hypot(n.x - x, n.y - y)
- if (d < nd) {
- nd = d
- nn = i
+for (let group in boxes) {
+ for (let item of boxes[group]) {
+ if (item.name === null) {
+ item.name = find_label(item.x+item.w/2, item.y+item.w/2, 72)
}
}
-
- return nn
}
-// FIND and label all points!
-let all_labels = labels.slice()
-let cities = []
-for (let key in points) {
- for (let [x, y] of points[key]) {
- let [ node, dist ] = find_closest_node(labels, x, y)
- if (dist > 15) {
- console.log("DISTANCE TOO FAR", key,x,y, "dist=" + dist, "name=" + node.name)
- }
- if (node) {
- labels = labels.filter(x => x !== node)
- let suit = "UNKNOWN"
-
- if (find_enclosing_rect(rects.$CLUBS, x, y))
- suit = CLUBS
- else if (find_enclosing_rect(rects.$HEARTS, x, y))
- suit = HEARTS
- else if (find_enclosing_rect(rects.$DIAMONDS, x, y))
- suit = DIAMONDS
- else if (find_enclosing_rect(rects.$SPADES, x, y))
- suit = SPADES
- else
- console.log("NOT ASSIGNED SUIT", x, y)
-
- let country = "UNKNOWN"
- if (find_enclosing_rect(rects.$Empire, x, y)) {
- country = EMPIRE
- }
- else if (find_enclosing_rect(rects.$Austria, x, y)) {
- country = AUSTRIA
- }
- else if (find_enclosing_rect(rects.$Hanover, x, y)) {
- country = HANOVER
- }
- else if (find_enclosing_rect(rects.$Saxony, x, y)) {
- country = SAXONY
- }
- else if (find_enclosing_rect(rects.$Sweden, x, y)) {
- country = SWEDEN
- }
- else if (find_enclosing_rect(rects.$Poland, x, y)) {
- country = POLAND
- }
- else if (find_enclosing_rect(rects.$Prussia, x, y)) {
- country = PRUSSIA
- }
-
- if (country === "UNKNOWN")
- console.log("no country:", node)
-
- cities.push({
- name: node.name,
- country,
- suit,
- type: key,
- x: Math.round(x),
- y: Math.round(y),
- adjacent: [],
- major_roads: [],
- roads: [],
- })
- } else {
- let [ dupname, dupdist ] = find_closest_node(all_labels, x, y)
- console.log("ALREADY USED", dupname, dupdist, x, y)
- }
+for (let group in edges) {
+ for (let item of edges[group]) {
+ item.name1 = find_label(item.x1, item.y1, 72)
+ item.name2 = find_label(item.x2, item.y2, 72)
}
}
-for (let e of edges.major_road) {
- let a = find_closest_point(e.x1, e.y1)
- let b = find_closest_point(e.x2, e.y2)
- set_add(cities[a].major_roads, b)
- set_add(cities[b].major_roads, a)
- set_add(cities[a].adjacent, b)
- set_add(cities[b].adjacent, a)
-}
-
-for (let e of edges.road) {
- let a = find_closest_point(e.x1, e.y1)
- let b = find_closest_point(e.x2, e.y2)
- set_add(cities[a].roads, b)
- set_add(cities[b].roads, a)
- set_add(cities[a].adjacent, b)
- set_add(cities[b].adjacent, a)
-}
-
-console.log("if (typeof module === 'object') module.exports = data")
-*/
+fs.writeFileSync("tools/layout.json", JSON.stringify({boxes,points,edges,labels}, null, 4))
diff --git a/tools/process-layout.js b/tools/process-layout.js
new file mode 100644
index 0000000..6de0844
--- /dev/null
+++ b/tools/process-layout.js
@@ -0,0 +1,164 @@
+"use strict"
+
+const fs = require("fs")
+
+let layout = JSON.parse(fs.readFileSync("tools/layout.json", "utf-8"))
+
+function array_insert(array, index, item) {
+ for (let i = array.length; i > index; --i)
+ array[i] = array[i - 1]
+ array[index] = item
+}
+
+function set_add(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return
+ }
+ array_insert(set, a, item)
+}
+
+function find_enclosing_rect(list, x, y) {
+ for (let {x1, y1, x2, y2} of list) {
+ if (x >= x1 && x <= x2)
+ if (y >= y1 && y <= y2)
+ return true
+ }
+ return false
+}
+
+const SEAS = [ "Sea1", "Sea2", "Sea3", "Sea4", "Sea5", "Sea6", "Sea7" ]
+const COLONIES = [ "Canada", "NH", "NY", "MA", "CT", "RI", "PA", "NJ", "MD", "DE", "VA", "NC", "SC", "GA", ]
+
+let seas = SEAS.map(x => [])
+let colonies = COLONIES.map(x => [])
+
+let spaces = []
+let space_index = {}
+
+function add_space(type, name, x, y) {
+ let id = spaces.length
+ spaces.push({
+ name,
+ type,
+ adjacent: [],
+ path: [],
+ wilderness: [],
+ port: -1,
+ colony: -1,
+ x: Math.round(x),
+ y: Math.round(y),
+ })
+}
+
+function add_edge(type, a, b) {
+ let ax = space_index[a]
+ let bx = space_index[b]
+ set_add(spaces[ax][type], bx)
+ set_add(spaces[bx][type], ax)
+ set_add(spaces[ax].adjacent, bx)
+ set_add(spaces[bx].adjacent, ax)
+}
+
+function add_oneway(type, a, b, list2, set2) {
+ let ax = space_index[a]
+ let bx = space_index[b]
+ if (ax !== undefined) {
+ let k = list2.indexOf(b)
+ spaces[ax][type] = k
+ set_add(set2[k], ax)
+ }
+ if (bx !== undefined) {
+ let k = list2.indexOf(a)
+ spaces[bx][type] = k
+ set_add(set2[k], bx)
+ }
+}
+
+for (let item of layout.points.fortified_port)
+ add_space("fortified_port", item.name, item.x, item.y)
+for (let item of layout.points.winter_quarters)
+ add_space("winter_quarters", item.name, item.x, item.y)
+for (let item of layout.points.regular)
+ add_space("regular", item.name, item.x, item.y)
+for (let item of layout.points.box)
+ add_space("box", item.name, item.x, item.y)
+
+const TYPE_SORT = [ "fortified_port", "winter_quarters", "regular", "box" ]
+
+spaces.sort((a,b) => {
+ let at = TYPE_SORT.indexOf(a.type)
+ let bt = TYPE_SORT.indexOf(b.type)
+ if (at < bt) return -1
+ if (at > bt) return 1
+ if (a.name < b.name) return -1
+ if (a.name > b.name) return 1
+ return b.y - a.y
+})
+
+for (let i = 0; i < spaces.length; ++i)
+ space_index[spaces[i].name] = i
+
+for (let item of layout.edges.sea)
+ add_oneway("port", item.name1, item.name2, SEAS, seas)
+for (let item of layout.edges.colony)
+ add_oneway("colony", item.name1, item.name2, COLONIES, colonies)
+
+for (let item of layout.edges.path)
+ add_edge("path", item.name1, item.name2)
+for (let item of layout.edges.wilderness)
+ add_edge("wilderness", item.name1, item.name2)
+
+
+function map_point(group, name) {
+ let item = layout.points[group].find(item => item.name === name)
+ return [ item.x, item.y ].map(Math.round)
+}
+
+function map_box(group, name) {
+ let item = layout.boxes[group].find(item => item.name === name)
+ return [ item.x, item.y, item.w, item.h ].map(Math.round)
+}
+
+function map_point_list(group, names) {
+ return names.map(n => map_point(group, n))
+}
+
+function map_box_list(group, names) {
+ return names.map(n => map_box(group, n))
+}
+
+function map_box_dict(list) {
+ let out = {}
+ for (let item of list)
+ out[item.name] = [ item.x, item.y, item.w, item.h ].map(Math.round)
+ return out
+}
+
+function map_point_dict(list) {
+ let out = {}
+ for (let item of list)
+ out[item.name] = [ item.x, item.y ].map(Math.round)
+ return out
+}
+
+let boxes = {
+ sea: map_box_list("sea", SEAS),
+ colony: map_point_list("colony", COLONIES),
+ french_alliance_track: map_point_dict(layout.points["French Alliance Track"]),
+ turn: map_point_dict(layout.points["Game Turn"]),
+ card_box: map_point_dict(layout.points["Card Boxes"]),
+ box: map_box_dict(layout.boxes.box),
+}
+
+let data = { layout: boxes, spaces, space_index, colonies, seas }
+
+fs.writeFileSync("tools/data.json", JSON.stringify(data))
diff --git a/tools/rotate_year.sh b/tools/rotate_year.sh
new file mode 100644
index 0000000..96a6c2b
--- /dev/null
+++ b/tools/rotate_year.sh
@@ -0,0 +1,8 @@
+for DIR in cards75 cards100 cards150 cards200
+do
+ convert -rotate 90 $DIR/card_7.png $DIR/card_7_rot.png
+ convert -rotate 90 $DIR/card_8.png $DIR/card_8_rot.png
+ convert -rotate 90 $DIR/card_9.png $DIR/card_9_rot.png
+ convert -rotate 90 $DIR/card_10.png $DIR/card_10_rot.png
+ convert -rotate 90 $DIR/card_11.png $DIR/card_11_rot.png
+done