summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data.js757
-rw-r--r--play.css9
-rw-r--r--play.js705
-rw-r--r--rules.js448
4 files changed, 1043 insertions, 876 deletions
diff --git a/data.js b/data.js
index 01229e9..10e0480 100644
--- a/data.js
+++ b/data.js
@@ -1,52 +1,4 @@
-"use strict";
-
-let AREAS = {
- "Ireland":{"x":120,"y":475},
- "Isle of Man":{"x":360,"y":525},
- "Scotland":{"x":635,"y":180},
- "Northumbria":{"x":885,"y":280},
- "Cumbria":{"x":680,"y":405},
- "North Yorks":{"x":890,"y":535},
- "East Yorks":{"x":1120,"y":545},
- "South Yorks":{"x":985,"y":710},
- "Lancaster":{"x":750,"y":690},
- "Caernarvon":{"x":480,"y":890},
- "Chester":{"x":720,"y":900},
- "Derby":{"x":960,"y":880},
- "Lincoln":{"x":1210,"y":820},
- "Pembroke":{"x":340,"y":1220},
- "Powys":{"x":565,"y":1100},
- "Hereford":{"x":715,"y":1125},
- "Warwick":{"x":890,"y":1090},
- "Leicester":{"x":1080,"y":1055},
- "Rutland":{"x":1265,"y":1060},
- "East Anglia":{"x":1505,"y":1040},
- "Glamorgan":{"x":570,"y":1330},
- "Gloucester":{"x":840,"y":1300},
- "Oxford":{"x":1035,"y":1290},
- "Middlesex":{"x":1235,"y":1305},
- "Essex":{"x":1440,"y":1255},
- "Somerset":{"x":750,"y":1510},
- "Wilts":{"x":920,"y":1460},
- "Sussex":{"x":1140,"y":1550},
- "Kent":{"x":1415,"y":1490},
- "Cornwall":{"x":400,"y":1660},
- "Dorset":{"x":810,"y":1640},
- "France":{"x":225,"y":160},
- "Calais":{"x":1465,"y":1795},
- "Irish Sea":{"x":280,"y":685},
- "North Sea":{"x":1425,"y":460},
- "English Channel":{"x":915,"y":1820},
- "Pool":{x:0,y:0},
- "Minor":{x:0,y:0},
- "LPool":{x:1688-50,y:50},
- "LMinor":{x:1688-50-210,y:50},
- "YPool":{x:50,y:1950-50},
- "YMinor":{x:50+210,y:1950-50},
-}
-
-let BORDERS = {};
-let BLOCKS = {};
+"use strict"
const CARDS = {
1: { name: "Force March", event: "force_march", actions: 1, image: "card_force_march" },
@@ -74,337 +26,444 @@ const CARDS = {
23: { name: "a 2", actions: 2, image: "card_2" },
24: { name: "a 2", actions: 2, image: "card_2" },
25: { name: "a 2", actions: 2, image: "card_2" },
-};
-
-(function () {
- for (let a in AREAS) {
- AREAS[a].exits = [];
- AREAS[a].shields = [];
- AREAS[a].wrap = 3;
- AREAS[a].layout_axis = 'X';
- AREAS[a].layout_major = 0.5;
- AREAS[a].layout_minor = 0.5;
+}
+
+let BORDERS = {}
+
+let BLOCKS = []
+let block_index = {}
+
+let AREAS = []
+let area_index = {}
+
+function init_areas() {
+ let AREA_XY = {
+ "Ireland":{"x":120,"y":475},
+ "Isle of Man":{"x":360,"y":525},
+ "Scotland":{"x":635,"y":180},
+ "Northumbria":{"x":885,"y":280},
+ "Cumbria":{"x":680,"y":405},
+ "North Yorks":{"x":890,"y":535},
+ "East Yorks":{"x":1120,"y":545},
+ "South Yorks":{"x":985,"y":710},
+ "Lancaster":{"x":750,"y":690},
+ "Caernarvon":{"x":480,"y":890},
+ "Chester":{"x":720,"y":900},
+ "Derby":{"x":960,"y":880},
+ "Lincoln":{"x":1210,"y":820},
+ "Pembroke":{"x":340,"y":1220},
+ "Powys":{"x":565,"y":1100},
+ "Hereford":{"x":715,"y":1125},
+ "Warwick":{"x":890,"y":1090},
+ "Leicester":{"x":1080,"y":1055},
+ "Rutland":{"x":1265,"y":1060},
+ "East Anglia":{"x":1505,"y":1040},
+ "Glamorgan":{"x":570,"y":1330},
+ "Gloucester":{"x":840,"y":1300},
+ "Oxford":{"x":1035,"y":1290},
+ "Middlesex":{"x":1235,"y":1305},
+ "Essex":{"x":1440,"y":1255},
+ "Somerset":{"x":750,"y":1510},
+ "Wilts":{"x":920,"y":1460},
+ "Sussex":{"x":1140,"y":1550},
+ "Kent":{"x":1415,"y":1490},
+ "Cornwall":{"x":400,"y":1660},
+ "Dorset":{"x":810,"y":1640},
+ "France":{"x":225,"y":160},
+ "Calais":{"x":1465,"y":1795},
+ "Irish Sea":{"x":280,"y":685},
+ "North Sea":{"x":1425,"y":460},
+ "English Channel":{"x":915,"y":1820},
+
+ "Dead":{x:0,y:0},
+ "Pool":{x:0,y:0},
+ "Minor":{x:0,y:0},
+ "LPool":{x:1688-50,y:50},
+ "LMinor":{x:1688-50-210,y:50},
+ "YPool":{x:50,y:1950-50},
+ "YMinor":{x:50+210,y:1950-50},
}
- function border(a, b, type) {
- if (a > b) [a, b] = [b, a];
- let id = a + "/" + b;
- BORDERS[id] = type;
- AREAS[a].exits.push(b);
- AREAS[b].exits.push(a);
+ let AREA_CITY = {
+ "Somerset": "Bristol",
+ "Warwick": "Coventry",
+ "Middlesex": "London",
+ "Northumbria": "Newcastle",
+ "East Anglia": "Norwich",
+ "Wilts": "Salisbury",
+ "South Yorks": "York",
}
- function yellow(A,B) { border(A,B,"major"); }
- function blue(A,B) { border(A,B,"river"); }
- function red(A,B) { border(A,B,"minor"); }
- function sea(A,B,major) { border(A,B,"sea"); if (major) AREAS[B].major_port = true; }
+ let AREA_CATHEDRAL = {
+ "Kent": "Canterbury",
+ "South Yorks": "York",
+ }
+
+ let AREA_CROWN = [
+ "Cumbria",
+ "South Yorks",
+ "Caernarvon",
+ "Chester",
+ "Derby",
+ "Pembroke",
+ "Warwick",
+ "Gloucester",
+ "Middlesex",
+ "Sussex",
+ "Cornwall",
+ ]
function layout(a, wrap, axis, major, minor) {
- AREAS[a].wrap = wrap;
- AREAS[a].layout_axis = axis;
- AREAS[a].layout_major = (1 - major) / 2;
- AREAS[a].layout_minor = (1 - minor) / 2;
+ area_index[a] = AREAS.length
+ AREAS.push({
+ name: a,
+ city: AREA_CITY[a] || null,
+ cathedral: AREA_CATHEDRAL[a] || null,
+ crown: AREA_CROWN.includes(a),
+ major_port: false,
+ shields: [],
+ exits: [],
+ layout: {
+ x: AREA_XY[a].x,
+ y: AREA_XY[a].y,
+ wrap,
+ axis,
+ major: (1 - major) / 2,
+ minor: (1 - minor) / 2,
+ },
+ })
}
- layout("LPool", 13, 'Y', 1, -1);
- layout("LMinor", 5, 'X', -1, 0);
- layout("YPool", 13, 'Y', -1, 1);
- layout("YMinor", 5, 'X', 1, 0);
-
- layout("France", 4, 'X', 0, 0);
- layout("Calais", 4, 'X', 0, 0);
-
- layout("Ireland", 3, 'Y', -1, -1);
- layout("Scotland", 3, 'X', -1, -1);
- layout("Northumbria", 4, 'Y', 0, 0);
- layout("Rutland", 4, 'Y', 0, 0);
- layout("Leicester", 4, 'Y', 0, 0);
-
- layout("North Sea", 10, 'Y', 1, 0);
- layout("Irish Sea", 10, 'Y', 1, 0);
- layout("English Channel", 10, 'X', 0, 0);
-
- layout("Cornwall", 4, 'X', 0, 0);
- layout("Dorset", 4, 'X', 0, 0);
- layout("Sussex", 4, 'X', 0, 0);
- layout("Kent", 4, 'X', 0, 0);
- layout("Somerset", 4, 'X', -1, -1);
-
- layout("East Anglia", 4, 'X', 0, 0);
- layout("Powys", 4, 'Y', 0, 0);
- layout("Hereford", 4, 'Y', 0, 0);
- layout("Oxford", 3, 'Y', 0, 0);
-
- layout("Derby", 4, 'X', 0, 0);
- layout("Caernarvon", 4, 'X', 0, 0);
- layout("Essex", 3, 'X', 0, 0);
- layout("Cumbria", 4, 'X', 0, 0);
- layout("Glamorgan", 4, 'X', 0, 0);
- layout("Pembroke", 4, 'X', 0, -1);
-
- red("Scotland", "Cumbria");
- red("Scotland", "Northumbria");
- red("Cumbria", "Northumbria");
- red("Cumbria", "North Yorks");
- red("Cumbria", "Lancaster");
- blue("Northumbria", "North Yorks");
- blue("Northumbria", "East Yorks");
-
- yellow("North Yorks", "East Yorks");
- yellow("North Yorks", "South Yorks");
- red("North Yorks", "Lancaster");
- blue("East Yorks", "South Yorks");
- red("Lancaster", "South Yorks");
- blue("Lancaster", "Chester");
- red("Lancaster", "Derby");
- yellow("South Yorks", "Derby");
- blue("South Yorks", "Lincoln");
-
- blue("Caernarvon", "Chester");
- red("Caernarvon", "Powys");
- red("Caernarvon", "Pembroke");
- yellow("Chester", "Powys");
- yellow("Chester", "Derby");
- blue("Chester", "Hereford");
- yellow("Chester", "Warwick");
- blue("Derby", "Warwick");
- blue("Derby", "Leicester");
- blue("Derby", "Lincoln");
- yellow("Lincoln", "Leicester");
- blue("Lincoln", "Rutland");
-
- red("Pembroke", "Powys");
- yellow("Pembroke", "Glamorgan");
- red("Powys", "Hereford");
- blue("Powys", "Glamorgan");
- blue("Hereford", "Warwick");
- blue("Hereford", "Gloucester");
- blue("Hereford", "Glamorgan");
- yellow("Warwick", "Leicester");
- blue("Warwick", "Oxford");
- blue("Warwick", "Gloucester");
- yellow("Leicester", "Rutland");
- blue("Leicester", "Essex");
- yellow("Leicester", "Middlesex");
- yellow("Leicester", "Oxford");
- blue("Rutland", "East Anglia");
- blue("Rutland", "Essex");
- yellow("East Anglia", "Essex");
-
- yellow("Gloucester", "Oxford");
- blue("Gloucester", "Wilts");
- yellow("Gloucester", "Somerset");
- yellow("Oxford", "Middlesex");
- blue("Oxford", "Wilts");
- blue("Oxford", "Sussex");
- blue("Middlesex", "Sussex");
- blue("Middlesex", "Kent");
- yellow("Middlesex", "Essex");
-
- yellow("Cornwall", "Somerset");
- yellow("Cornwall", "Dorset");
- yellow("Somerset", "Wilts");
- yellow("Somerset", "Dorset");
- yellow("Wilts", "Dorset");
- yellow("Wilts", "Sussex");
- blue("Sussex", "Dorset");
- yellow("Sussex", "Kent");
-
- sea("Irish Sea", "Ireland", true);
- sea("Irish Sea", "Isle of Man");
- sea("Irish Sea", "Scotland", true);
- sea("Irish Sea", "Cumbria");
- sea("Irish Sea", "Lancaster");
- sea("Irish Sea", "Chester", true);
- sea("Irish Sea", "Caernarvon");
- sea("Irish Sea", "Pembroke");
- sea("Irish Sea", "Glamorgan", true);
- sea("Irish Sea", "Somerset", true);
- sea("Irish Sea", "Cornwall", true);
-
- sea("North Sea", "Scotland", true);
- sea("North Sea", "Northumbria", true);
- sea("North Sea", "East Yorks", true);
- sea("North Sea", "Lincoln");
- sea("North Sea", "Rutland");
- sea("North Sea", "East Anglia", true);
- sea("North Sea", "Essex");
- sea("North Sea", "Middlesex", true);
- sea("North Sea", "Kent", true);
-
- sea("English Channel", "Cornwall", true);
- sea("English Channel", "Dorset");
- sea("English Channel", "Sussex", true);
- sea("English Channel", "Kent", true);
-
- sea("English Channel", "Calais", true);
- sea("North Sea", "Calais", true);
-
- sea("English Channel", "France", true);
- sea("Irish Sea", "France", true);
-
- AREAS["Somerset"].city = "Bristol";
- AREAS["Warwick"].city = "Coventry";
- AREAS["Middlesex"].city = "London";
- AREAS["Northumbria"].city = "Newcastle";
- AREAS["East Anglia"].city = "Norwich";
- AREAS["Wilts"].city = "Salisbury";
- AREAS["South Yorks"].city = "York";
-
- AREAS["Kent"].cathedral = "Canterbury";
- AREAS["South Yorks"].cathedral = "York";
-
- AREAS["Cumbria"].crown = true;
- AREAS["South Yorks"].crown = true;
- AREAS["Caernarvon"].crown = true;
- AREAS["Chester"].crown = true;
- AREAS["Derby"].crown = true;
- AREAS["Pembroke"].crown = true;
- AREAS["Warwick"].crown = true;
- AREAS["Gloucester"].crown = true;
- AREAS["Middlesex"].crown = true;
- AREAS["Sussex"].crown = true;
- AREAS["Cornwall"].crown = true;
+ // pools
+ layout("Dead", 3, 'X', 0, 0)
+ layout("Pool", 3, 'X', 0, 0)
+ layout("Minor", 3, 'X', 0, 0)
+
+ // seas
+ layout("English Channel", 10, 'X', 0, 0)
+ layout("Irish Sea", 10, 'Y', 1, 0)
+ layout("North Sea", 10, 'Y', 1, 0)
+
+ // exile areas
+ layout("Calais", 4, 'X', 0, 0)
+ layout("France", 4, 'X', 0, 0)
+ layout("Ireland", 3, 'Y', -1, -1)
+ layout("Scotland", 3, 'X', -1, -1)
+
+ layout("Caernarvon", 4, 'X', 0, 0)
+ layout("Chester", 3, 'X', 0, 0)
+ layout("Cornwall", 4, 'X', 0, 0)
+ layout("Cumbria", 4, 'X', 0, 0)
+ layout("Derby", 4, 'X', 0, 0)
+ layout("Dorset", 4, 'X', 0, 0)
+ layout("East Anglia", 4, 'X', 0, 0)
+ layout("East Yorks", 3, 'X', 0, 0)
+ layout("Essex", 3, 'X', 0, 0)
+ layout("Glamorgan", 4, 'X', 0, 0)
+ layout("Gloucester", 3, 'X', 0, 0)
+ layout("Hereford", 4, 'Y', 0, 0)
+ layout("Isle of Man", 3, 'X', 0, 0)
+ layout("Kent", 4, 'X', 0, 0)
+ layout("Lancaster", 3, 'X', 0, 0)
+ layout("Leicester", 4, 'Y', 0, 0)
+ layout("Lincoln", 3, 'X', 0, 0)
+ layout("Middlesex", 3, 'X', 0, 0)
+ layout("North Yorks", 3, 'X', 0, 0)
+ layout("Northumbria", 4, 'Y', 0, 0)
+ layout("Oxford", 3, 'Y', 0, 0)
+ layout("Pembroke", 4, 'X', 0, -1)
+ layout("Powys", 4, 'Y', 0, 0)
+ layout("Rutland", 4, 'Y', 0, 0)
+ layout("Somerset", 4, 'X', -1, -1)
+ layout("South Yorks", 3, 'X', 0, 0)
+ layout("Sussex", 4, 'X', 0, 0)
+ layout("Warwick", 3, 'X', 0, 0)
+ layout("Wilts", 3, 'X', 0, 0)
+
+ // only used for layout in ui
+ layout("LPool", 13, 'Y', 1, -1)
+ layout("LMinor", 5, 'X', -1, 0)
+ layout("YPool", 13, 'Y', -1, 1)
+ layout("YMinor", 5, 'X', 1, 0)
+}
+
+function init_borders() {
+ function border(a, b, type) {
+ a = area_index[a]
+ b = area_index[b]
+ let id = (a < b) ? a * 100 + b : b * 100 + a
+ BORDERS[id] = type
+ AREAS[a].exits.push(b)
+ AREAS[b].exits.push(a)
+ }
+ function yellow(A,B) { border(A,B,"major"); }
+ function blue(A,B) { border(A,B,"river"); }
+ function red(A,B) { border(A,B,"minor"); }
+ function sea(A,B,major) { border(A,B,"sea"); if (major) AREAS[area_index[B]].major_port = true; }
+
+ red("Scotland", "Cumbria")
+ red("Scotland", "Northumbria")
+ red("Cumbria", "Northumbria")
+ red("Cumbria", "North Yorks")
+ red("Cumbria", "Lancaster")
+ blue("Northumbria", "North Yorks")
+ blue("Northumbria", "East Yorks")
+
+ yellow("North Yorks", "East Yorks")
+ yellow("North Yorks", "South Yorks")
+ red("North Yorks", "Lancaster")
+ blue("East Yorks", "South Yorks")
+ red("Lancaster", "South Yorks")
+ blue("Lancaster", "Chester")
+ red("Lancaster", "Derby")
+ yellow("South Yorks", "Derby")
+ blue("South Yorks", "Lincoln")
+
+ blue("Caernarvon", "Chester")
+ red("Caernarvon", "Powys")
+ red("Caernarvon", "Pembroke")
+ yellow("Chester", "Powys")
+ yellow("Chester", "Derby")
+ blue("Chester", "Hereford")
+ yellow("Chester", "Warwick")
+ blue("Derby", "Warwick")
+ blue("Derby", "Leicester")
+ blue("Derby", "Lincoln")
+ yellow("Lincoln", "Leicester")
+ blue("Lincoln", "Rutland")
+
+ red("Pembroke", "Powys")
+ yellow("Pembroke", "Glamorgan")
+ red("Powys", "Hereford")
+ blue("Powys", "Glamorgan")
+ blue("Hereford", "Warwick")
+ blue("Hereford", "Gloucester")
+ blue("Hereford", "Glamorgan")
+ yellow("Warwick", "Leicester")
+ blue("Warwick", "Oxford")
+ blue("Warwick", "Gloucester")
+ yellow("Leicester", "Rutland")
+ blue("Leicester", "Essex")
+ yellow("Leicester", "Middlesex")
+ yellow("Leicester", "Oxford")
+ blue("Rutland", "East Anglia")
+ blue("Rutland", "Essex")
+ yellow("East Anglia", "Essex")
+
+ yellow("Gloucester", "Oxford")
+ blue("Gloucester", "Wilts")
+ yellow("Gloucester", "Somerset")
+ yellow("Oxford", "Middlesex")
+ blue("Oxford", "Wilts")
+ blue("Oxford", "Sussex")
+ blue("Middlesex", "Sussex")
+ blue("Middlesex", "Kent")
+ yellow("Middlesex", "Essex")
+
+ yellow("Cornwall", "Somerset")
+ yellow("Cornwall", "Dorset")
+ yellow("Somerset", "Wilts")
+ yellow("Somerset", "Dorset")
+ yellow("Wilts", "Dorset")
+ yellow("Wilts", "Sussex")
+ blue("Sussex", "Dorset")
+ yellow("Sussex", "Kent")
+
+ sea("Irish Sea", "Ireland", true)
+ sea("Irish Sea", "Isle of Man")
+ sea("Irish Sea", "Scotland", true)
+ sea("Irish Sea", "Cumbria")
+ sea("Irish Sea", "Lancaster")
+ sea("Irish Sea", "Chester", true)
+ sea("Irish Sea", "Caernarvon")
+ sea("Irish Sea", "Pembroke")
+ sea("Irish Sea", "Glamorgan", true)
+ sea("Irish Sea", "Somerset", true)
+ sea("Irish Sea", "Cornwall", true)
+
+ sea("North Sea", "Scotland", true)
+ sea("North Sea", "Northumbria", true)
+ sea("North Sea", "East Yorks", true)
+ sea("North Sea", "Lincoln")
+ sea("North Sea", "Rutland")
+ sea("North Sea", "East Anglia", true)
+ sea("North Sea", "Essex")
+ sea("North Sea", "Middlesex", true)
+ sea("North Sea", "Kent", true)
+
+ sea("English Channel", "Cornwall", true)
+ sea("English Channel", "Dorset")
+ sea("English Channel", "Sussex", true)
+ sea("English Channel", "Kent", true)
+
+ sea("English Channel", "Calais", true)
+ sea("North Sea", "Calais", true)
+
+ sea("English Channel", "France", true)
+ sea("Irish Sea", "France", true)
+
+ for (let a of AREAS)
+ a.exits.sort((a,b)=>a-b)
+}
+
+function init_blocks() {
function block(image, owner, type, name, steps, combat, loyalty, extra, extra2) {
- let id = name;
- let enemy = null;
+ let id = name
+ let enemy = null
if (name === "Bombard")
- id = name + "/" + owner[0];
+ id = name + "/" + owner[0]
if (loyalty) {
- id = name + "/" + owner[0];
+ id = name + "/" + owner[0]
if (owner === "York")
- enemy = name + "/L";
+ enemy = name + "/L"
else
- enemy = name + "/Y";
+ enemy = name + "/Y"
}
- if (id in BLOCKS)
- throw new Error("Duplicate block: " + id);
- BLOCKS[id] = {
- type: type,
- owner: owner,
+ if (id in block_index)
+ throw new Error("Duplicate block: " + id)
+ let i = block_index[id] = BLOCKS.length
+ BLOCKS.push({
+ id: id,
name: name,
+ owner: owner,
+ type: type,
shield: name,
steps: steps,
combat: combat,
+ initiative: combat[0],
+ fire_power: combat[1] | 0,
+ loyalty: loyalty || 0,
+ enemy: enemy || -1,
+ heir: 0,
+ home: null,
image: image,
- };
- if (loyalty)
- BLOCKS[id].loyalty = loyalty;
- if (enemy)
- BLOCKS[id].enemy = enemy;
+ })
if (extra) {
if (type === 'heir') {
- BLOCKS[id].heir = extra;
- BLOCKS[id].shield = extra2;
+ BLOCKS[i].heir = extra
+ if (extra2)
+ BLOCKS[i].shield = extra2
}
if (type === 'church' || type === 'levies')
- BLOCKS[id].home = extra;
+ BLOCKS[i].home = extra
if (type === 'nobles')
- BLOCKS[id].shield = extra;
+ BLOCKS[i].shield = extra
}
+
+ // console.log(`const B_${id.toUpperCase().replace(/[ \/]/g, "_").replace(/[()]/g, "")} = block_index["${id}"]`)
}
- block(11, "York", "heir", "York", 4, "B3", 0, 1);
- block(12, "York", "heir", "March", 3, "A3", 0, 2);
- block(13, "York", "heir", "Rutland", 3, "B1", 0, 3);
- block(14, "York", "heir", "Clarence", 3, "B2", 1, 4);
- block(15, "York", "heir", "Gloucester", 3, "B3", 0, 5);
-
- block(16, "York", "nobles", "Essex", 3, "B1", 0);
- block(17, "York", "nobles", "Hastings", 3, "B2", 0);
- block(21, "York", "nobles", "Herbert", 3, "A2", 0);
- block(22, "York", "nobles", "Worcester", 2, "B2", 0);
- block(23, "York", "nobles", "Suffolk", 3, "B2", 0);
- block(24, "York", "nobles", "Norfolk", 4, "B2", 0);
- block(25, "York", "nobles", "Buckingham", 4, "B2", 1);
- block(26, "York", "nobles", "Exeter", 3, "A1", 1);
- block(27, "York", "nobles", "Rivers", 2, "B2", 2);
- block(31, "York", "nobles", "Northumberland", 4, "B3", 1);
- block(32, "York", "nobles", "Shrewsbury", 3, "A1", 1);
- block(33, "York", "nobles", "Stanley", 4, "B2", 1);
- block(34, "York", "nobles", "Arundel", 3, "B2", 0);
- block(35, "York", "nobles", "Warwick", 4, "B3", 3);
- block(36, "York", "nobles", "Kent", 3, "A2", 2);
- block(37, "York", "nobles", "Salisbury", 3, "B2", 2);
- block(41, "York", "nobles", "Westmoreland", 3, "B2", 2);
-
- block(51, "York", "mercenaries", "Irish Mercenary", 4, "B2", 0);
- block(52, "York", "mercenaries", "Burgundian Mercenary", 3, "A3", 0);
- block(53, "York", "mercenaries", "Calais Mercenary", 3, "B4", 0);
- block(46, "York", "church", "Canterbury (church)", 3, "C1", 2, "Canterbury");
- block(47, "York", "church", "York (church)", 3, "C2", 1, "York");
- block(42, "York", "levies", "London (levy)", 4, "C3", 0, "London");
- block(43, "York", "levies", "Norwich (levy)", 4, "C2", 0, "Norwich");
- block(44, "York", "levies", "Salisbury (levy)", 4, "C2", 0, "Salisbury");
- block(45, "York", "bombard", "Bombard", 3, "D3", 0);
-
- block(91, "Lancaster", "heir", "Henry VI", 4, "B2", 0, 1);
- block(92, "Lancaster", "heir", "Prince Edward", 3, "B1", 0, 2);
- block(93, "Lancaster", "heir", "Exeter", 3, "A1", 2, 3, "Exeter");
- block(94, "Lancaster", "heir", "Somerset", 3, "A2", 0, 4, "Somerset");
- block(95, "Lancaster", "heir", "Richmond", 3, "B2", 0, 5, "Richmond");
-
- block(67, "Lancaster", "nobles", "Westmoreland", 3, "B2", 2);
- block(71, "Lancaster", "nobles", "Northumberland", 4, "B3", 2);
- block(72, "Lancaster", "nobles", "Shrewsbury", 3, "A1", 2);
- block(73, "Lancaster", "nobles", "Stanley", 4, "B2", 1);
- block(75, "Lancaster", "nobles", "Warwick", 4, "B3", 3);
- block(76, "Lancaster", "nobles", "Kent", 3, "A2", 2);
- block(77, "Lancaster", "nobles", "Salisbury", 3, "B2", 2);
- block(81, "Lancaster", "nobles", "Oxford", 3, "A2", 0);
- block(82, "Lancaster", "nobles", "Pembroke", 3, "B2", 0);
- block(83, "Lancaster", "nobles", "Devon", 2, "B2", 0);
- block(84, "Lancaster", "nobles", "Beaumont", 3, "B2", 0);
- block(85, "Lancaster", "nobles", "Buckingham", 4, "B2", 1);
- block(86, "Lancaster", "nobles", "Clarence", 3, "B2", 1);
- block(87, "Lancaster", "nobles", "Rivers", 2, "B2", 1);
- block(96, "Lancaster", "nobles", "Clifford", 3, "A2", 0);
- block(97, "Lancaster", "nobles", "Wiltshire", 3, "B2", 0);
-
- block(55, "Lancaster", "mercenaries", "Scots Mercenary", 4, "B3");
- block(56, "Lancaster", "mercenaries", "Welsh Mercenary", 3, "A2");
- block(57, "Lancaster", "mercenaries", "French Mercenary", 4, "B3");
- block(61, "Lancaster", "church", "Canterbury (church)", 3, "C1", 1, "Canterbury");
- block(62, "Lancaster", "church", "York (church)", 3, "C2", 2, "York");
- block(63, "Lancaster", "bombard", "Bombard", 3, "D3");
- block(64, "Lancaster", "levies", "Coventry (levy)", 4, "C2", 0, "Coventry");
- block(65, "Lancaster", "levies", "Bristol (levy)", 4, "C2", 0, "Bristol");
- block(66, "Lancaster", "levies", "Newcastle (levy)", 4, "C3", 0, "Newcastle");
- block(74, "Lancaster", "levies", "York (levy)", 4, "C3", 0, "York");
-
- block(54, "Rebel", "rebel", "Rebel", 4, "A2");
+ block(11, "York", "heir", "York", 4, "B3", 0, 1)
+ block(12, "York", "heir", "March", 3, "A3", 0, 2)
+ block(13, "York", "heir", "Rutland", 3, "B1", 0, 3)
+ block(14, "York", "heir", "Clarence", 3, "B2", 1, 4)
+ block(15, "York", "heir", "Gloucester", 3, "B3", 0, 5)
+
+ block(16, "York", "nobles", "Essex", 3, "B1", 0)
+ block(17, "York", "nobles", "Hastings", 3, "B2", 0)
+ block(21, "York", "nobles", "Herbert", 3, "A2", 0)
+ block(22, "York", "nobles", "Worcester", 2, "B2", 0)
+ block(23, "York", "nobles", "Suffolk", 3, "B2", 0)
+ block(24, "York", "nobles", "Norfolk", 4, "B2", 0)
+ block(25, "York", "nobles", "Buckingham", 4, "B2", 1)
+ block(26, "York", "nobles", "Exeter", 3, "A1", 1)
+ block(27, "York", "nobles", "Rivers", 2, "B2", 2)
+ block(31, "York", "nobles", "Northumberland", 4, "B3", 1)
+ block(32, "York", "nobles", "Shrewsbury", 3, "A1", 1)
+ block(33, "York", "nobles", "Stanley", 4, "B2", 1)
+ block(34, "York", "nobles", "Arundel", 3, "B2", 0)
+ block(35, "York", "nobles", "Warwick", 4, "B3", 3)
+ block(36, "York", "nobles", "Kent", 3, "A2", 2)
+ block(37, "York", "nobles", "Salisbury", 3, "B2", 2)
+ block(41, "York", "nobles", "Westmoreland", 3, "B2", 2)
+
+ block(51, "York", "mercenaries", "Irish Mercenary", 4, "B2", 0)
+ block(52, "York", "mercenaries", "Burgundian Mercenary", 3, "A3", 0)
+ block(53, "York", "mercenaries", "Calais Mercenary", 3, "B4", 0)
+ block(46, "York", "church", "Canterbury (church)", 3, "C1", 2, "Canterbury")
+ block(47, "York", "church", "York (church)", 3, "C2", 1, "York")
+ block(42, "York", "levies", "London (levy)", 4, "C3", 0, "London")
+ block(43, "York", "levies", "Norwich (levy)", 4, "C2", 0, "Norwich")
+ block(44, "York", "levies", "Salisbury (levy)", 4, "C2", 0, "Salisbury")
+ block(45, "York", "bombard", "Bombard", 3, "D3", 0)
+
+ block(91, "Lancaster", "heir", "Henry VI", 4, "B2", 0, 1)
+ block(92, "Lancaster", "heir", "Prince Edward", 3, "B1", 0, 2)
+ block(93, "Lancaster", "heir", "Exeter", 3, "A1", 2, 3, "Exeter")
+ block(94, "Lancaster", "heir", "Somerset", 3, "A2", 0, 4, "Somerset")
+ block(95, "Lancaster", "heir", "Richmond", 3, "B2", 0, 5, "Richmond")
+
+ block(67, "Lancaster", "nobles", "Westmoreland", 3, "B2", 2)
+ block(71, "Lancaster", "nobles", "Northumberland", 4, "B3", 2)
+ block(72, "Lancaster", "nobles", "Shrewsbury", 3, "A1", 2)
+ block(73, "Lancaster", "nobles", "Stanley", 4, "B2", 1)
+ block(75, "Lancaster", "nobles", "Warwick", 4, "B3", 3)
+ block(76, "Lancaster", "nobles", "Kent", 3, "A2", 2)
+ block(77, "Lancaster", "nobles", "Salisbury", 3, "B2", 2)
+ block(81, "Lancaster", "nobles", "Oxford", 3, "A2", 0)
+ block(82, "Lancaster", "nobles", "Pembroke", 3, "B2", 0)
+ block(83, "Lancaster", "nobles", "Devon", 2, "B2", 0)
+ block(84, "Lancaster", "nobles", "Beaumont", 3, "B2", 0)
+ block(85, "Lancaster", "nobles", "Buckingham", 4, "B2", 1)
+ block(86, "Lancaster", "nobles", "Clarence", 3, "B2", 1)
+ block(87, "Lancaster", "nobles", "Rivers", 2, "B2", 1)
+ block(96, "Lancaster", "nobles", "Clifford", 3, "A2", 0)
+ block(97, "Lancaster", "nobles", "Wiltshire", 3, "B2", 0)
+
+ block(55, "Lancaster", "mercenaries", "Scots Mercenary", 4, "B3")
+ block(56, "Lancaster", "mercenaries", "Welsh Mercenary", 3, "A2")
+ block(57, "Lancaster", "mercenaries", "French Mercenary", 4, "B3")
+ block(61, "Lancaster", "church", "Canterbury (church)", 3, "C1", 1, "Canterbury")
+ block(62, "Lancaster", "church", "York (church)", 3, "C2", 2, "York")
+ block(63, "Lancaster", "bombard", "Bombard", 3, "D3")
+ block(64, "Lancaster", "levies", "Coventry (levy)", 4, "C2", 0, "Coventry")
+ block(65, "Lancaster", "levies", "Bristol (levy)", 4, "C2", 0, "Bristol")
+ block(66, "Lancaster", "levies", "Newcastle (levy)", 4, "C3", 0, "Newcastle")
+ block(74, "Lancaster", "levies", "York (levy)", 4, "C3", 0, "York")
+
+ block(54, "Rebel", "rebel", "Rebel", 4, "A2")
+
+ for (let b of BLOCKS)
+ if (b.enemy !== -1)
+ b.enemy = block_index[b.enemy]
+}
+function init_shields() {
function shields(area, list) {
- AREAS[area].shields = list;
+ AREAS[area_index[area]].shields = list
}
- shields("Isle of Man", ["Stanley"]);
- shields("Northumbria", ["Northumberland", "Westmoreland"]);
- shields("Cumbria", ["Northumberland", "Clifford"]);
- shields("North Yorks", ["Salisbury", "Clifford"]);
- shields("East Yorks", ["Kent", "Salisbury", "Northumberland"]);
- shields("South Yorks", ["York", "Shrewsbury"]);
- shields("Lancaster", ["Lancaster", "Stanley"]);
- shields("Caernarvon", ["Norfolk"]);
- shields("Lincoln", ["Lancaster", "Beaumont"]);
- shields("Pembroke", ["Richmond", "Pembroke"]);
- shields("Hereford", ["York"]);
- shields("Warwick", ["Buckingham", "Warwick"]);
- shields("Leicester", ["Hastings", "Rivers"]);
- shields("Rutland", ["York", "Worcester"]);
- shields("East Anglia", ["Norfolk", "Suffolk"]);
- shields("Glamorgan", ["Buckingham", "Norfolk", "Herbert", "Warwick"]);
- shields("Oxford", ["Suffolk"]);
- shields("Essex", ["Oxford", "Essex"]);
- shields("Wilts", ["Wiltshire"]);
- shields("Sussex", ["Arundel"]);
- shields("Kent", ["Buckingham"]);
- shields("Cornwall", ["Devon", "Exeter"]);
- shields("Dorset", ["Somerset"]);
- shields("Calais", ["Warwick"]);
-
-})();
+ shields("Isle of Man", ["Stanley"])
+ shields("Northumbria", ["Northumberland", "Westmoreland"])
+ shields("Cumbria", ["Northumberland", "Clifford"])
+ shields("North Yorks", ["Salisbury", "Clifford"])
+ shields("East Yorks", ["Kent", "Salisbury", "Northumberland"])
+ shields("South Yorks", ["York", "Shrewsbury"])
+ shields("Lancaster", ["Lancaster", "Stanley"])
+ shields("Caernarvon", ["Norfolk"])
+ shields("Lincoln", ["Lancaster", "Beaumont"])
+ shields("Pembroke", ["Richmond", "Pembroke"])
+ shields("Hereford", ["York"])
+ shields("Warwick", ["Buckingham", "Warwick"])
+ shields("Leicester", ["Hastings", "Rivers"])
+ shields("Rutland", ["York", "Worcester"])
+ shields("East Anglia", ["Norfolk", "Suffolk"])
+ shields("Glamorgan", ["Buckingham", "Norfolk", "Herbert", "Warwick"])
+ shields("Oxford", ["Suffolk"])
+ shields("Essex", ["Oxford", "Essex"])
+ shields("Wilts", ["Wiltshire"])
+ shields("Sussex", ["Arundel"])
+ shields("Kent", ["Buckingham"])
+ shields("Cornwall", ["Devon", "Exeter"])
+ shields("Dorset", ["Somerset"])
+ shields("Calais", ["Warwick"])
+}
+
+init_areas()
+init_borders()
+init_blocks()
+init_shields()
if (typeof module !== 'undefined')
- module.exports = { CARDS, BLOCKS, AREAS, BORDERS }
+ module.exports = { CARDS, BLOCKS, AREAS, BORDERS, block_index, area_index }
diff --git a/play.css b/play.css
index c9251be..5cd3648 100644
--- a/play.css
+++ b/play.css
@@ -15,6 +15,7 @@ header.your_turn { background-color: orange; }
#log .Y { background-color: gainsboro; }
#log .h3 { background-color: lightsteelblue; }
#log .h4 { font-style: italic; text-decoration: underline; }
+#log .tip:hover { text-decoration: underline; cursor: pointer; }
.hand {
margin: 25px;
@@ -123,6 +124,14 @@ header.your_turn { background-color: orange; }
#map svg path.area.where.highlight {
stroke: white;
}
+#map svg path.area.tip {
+ opacity: 1;
+ stroke-opacity: 1;
+ stroke: yellow;
+ stroke-width: 40;
+ stroke-dasharray: 80 40;
+ fill: none;
+}
#map.hide_blocks #blocks {
visibility: hidden;
diff --git a/play.js b/play.js
index ccac1cb..b236266 100644
--- a/play.js
+++ b/play.js
@@ -1,19 +1,47 @@
-"use strict";
+"use strict"
-const LANCASTER = "Lancaster";
-const YORK = "York";
-const REBEL = "Rebel";
+const LANCASTER = "Lancaster"
+const YORK = "York"
const ENEMY = { York: "Lancaster", Lancaster: "York" }
-const POOL = "Pool";
-const DEAD = "Dead";
-const MINOR = "Minor";
-
-const NOBODY = -1
const NOWHERE = 0
+const POOL = 1
+const MINOR = 2
-const KING_TEXT = "\u2756";
-const PRETENDER_TEXT = "";
+const L_POOL = area_index["LPool"]
+const Y_POOL = area_index["YPool"]
+const L_MINOR = area_index["LMinor"]
+const Y_MINOR = area_index["YMinor"]
+
+const NOBODY = -1
+const B_YORK = block_index["York"]
+const B_MARCH = block_index["March"]
+const B_RUTLAND = block_index["Rutland"]
+const B_CLARENCE_Y = block_index["Clarence/Y"]
+const B_GLOUCESTER = block_index["Gloucester"]
+const B_EXETER_Y = block_index["Exeter/Y"]
+const B_WARWICK_Y = block_index["Warwick/Y"]
+const B_KENT_Y = block_index["Kent/Y"]
+const B_SALISBURY_Y = block_index["Salisbury/Y"]
+const B_IRISH_MERCENARY = block_index["Irish Mercenary"]
+const B_BURGUNDIAN_MERCENARY = block_index["Burgundian Mercenary"]
+const B_CALAIS_MERCENARY = block_index["Calais Mercenary"]
+const B_HENRY_VI = block_index["Henry VI"]
+const B_PRINCE_EDWARD = block_index["Prince Edward"]
+const B_EXETER_L = block_index["Exeter/L"]
+const B_SOMERSET = block_index["Somerset"]
+const B_RICHMOND = block_index["Richmond"]
+const B_WARWICK_L = block_index["Warwick/L"]
+const B_KENT_L = block_index["Kent/L"]
+const B_SALISBURY_L = block_index["Salisbury/L"]
+const B_CLARENCE_L = block_index["Clarence/L"]
+const B_SCOTS_MERCENARY = block_index["Scots Mercenary"]
+const B_WELSH_MERCENARY = block_index["Welsh Mercenary"]
+const B_FRENCH_MERCENARY = block_index["French Mercenary"]
+const B_REBEL = block_index["Rebel"]
+
+const KING_TEXT = "\u2756"
+const PRETENDER_TEXT = ""
const LONG_NAME = {
"Somerset": "Duke of Somerset",
@@ -49,7 +77,7 @@ const LONG_NAME = {
}
function toggle_blocks() {
- document.getElementById("map").classList.toggle("hide_blocks");
+ document.getElementById("map").classList.toggle("hide_blocks")
}
let ui = {
@@ -62,6 +90,9 @@ let ui = {
present: new Set(),
}
+for (let a of AREAS)
+ a.nbname = a.name.replace(/ /g, "\xa0")
+
function on_focus_space_tip(x) {
ui.areas[x].classList.add("tip")
}
@@ -76,7 +107,7 @@ function on_click_space_tip(x) {
function sub_space_name(match, p1, offset, string) {
let x = p1 | 0
- let n = AREAS[x].name
+ let n = AREAS[x].nbname
return `<span class="tip" onmouseenter="on_focus_space_tip(${x})" onmouseleave="on_blur_space_tip(${x})" onclick="on_click_space_tip(${x})">${n}</span>`
}
@@ -115,158 +146,158 @@ function on_log(text) {
function is_known_block(b) {
if (view.game_over && player === 'Observer')
- return true;
- return block_owner(b) === player;
+ return true
+ return block_owner(b) === player
}
function on_focus_area(evt) {
- let where = evt.target.area;
- let text = where;
+ let where = evt.target.area
+ let text = AREAS[where].name
if (AREAS[where].city)
- text += " (" + AREAS[where].city + ")";
+ text += " (" + AREAS[where].city + ")"
if (AREAS[where].crown)
- text += " - Crown"; // " \u2655";
+ text += " - Crown" // " \u2655"
if (where === "South Yorks" || where === "Kent")
- text += " - Church"; // " -" \u2657";
+ text += " - Church" // " -" \u2657"
if (AREAS[where].major_port)
- text += " - Port";
+ text += " - Port"
if (AREAS[where].shields.length > 0)
- text += " - " + AREAS[where].shields.join(", ");
- document.getElementById("status").textContent = text;
+ text += " - " + AREAS[where].shields.join(", ")
+ document.getElementById("status").textContent = text
}
function on_blur_area(evt) {
- document.getElementById("status").textContent = "";
+ document.getElementById("status").textContent = ""
}
function on_click_area(evt) {
- let where = evt.target.area;
- send_action('area', where);
+ let where = evt.target.area
+ send_action('area', where)
}
-const STEP_TEXT = [ 0, "I", "II", "III", "IIII" ];
-const HEIR_TEXT = [ 0, '\u00b9', '\u00b2', '\u00b3', '\u2074', '\u2075' ];
+const STEP_TEXT = [ 0, "I", "II", "III", "IIII" ]
+const HEIR_TEXT = [ 0, '\u00b9', '\u00b2', '\u00b3', '\u2074', '\u2075' ]
function block_name(who) {
- if (who === NOBODY) return "Nobody";
- let name = BLOCKS[who].name;
- let long_name = LONG_NAME[name];
- return long_name ? long_name : name;
+ if (who === NOBODY) return "Nobody"
+ let name = BLOCKS[who].name
+ let long_name = LONG_NAME[name]
+ return long_name ? long_name : name
}
function block_owner(who) {
- if (who === REBEL) {
+ if (who === B_REBEL) {
if (view.pretender !== NOBODY)
- return BLOCKS[view.pretender].owner;
+ return BLOCKS[view.pretender].owner
if (view.king !== NOBODY)
- return ENEMY[BLOCKS[view.king].owner];
- return YORK;
+ return ENEMY[BLOCKS[view.king].owner]
+ return YORK
}
- return BLOCKS[who].owner;
+ return BLOCKS[who].owner
}
function on_focus_map_block(evt) {
- let b = evt.target.block;
+ let b = evt.target.block
if (is_known_block(b)) {
- let s = BLOCKS[b].steps;
- let text = block_name(b) + " ";
+ let s = BLOCKS[b].steps
+ let text = block_name(b) + " "
if (BLOCKS[b].type === 'heir')
- text += "H" + HEIR_TEXT[BLOCKS[b].heir] + "-";
+ text += "H" + HEIR_TEXT[BLOCKS[b].heir] + "-"
if (BLOCKS[b].loyalty)
- text += BLOCKS[b].loyalty + "-";
+ text += BLOCKS[b].loyalty + "-"
else if (BLOCKS[b].type === 'nobles')
- text += "\u2740-";
- text += STEP_TEXT[s] + "-" + BLOCKS[b].combat;
- document.getElementById("status").textContent = text;
+ text += "\u2740-"
+ text += STEP_TEXT[s] + "-" + BLOCKS[b].combat
+ document.getElementById("status").textContent = text
} else {
- let owner = block_owner(b);
- if (b === REBEL)
- owner = "Rebel";
- document.getElementById("status").textContent = owner;
+ let owner = block_owner(b)
+ if (b === B_REBEL)
+ owner = "Rebel"
+ document.getElementById("status").textContent = owner
}
}
function on_blur_map_block(evt) {
- document.getElementById("status").textContent = "";
+ document.getElementById("status").textContent = ""
}
function on_click_map_block(evt) {
- let b = evt.target.block;
+ let b = evt.target.block
if (!view.battle)
- send_action('block', b);
+ send_action('block', b)
}
function on_focus_battle_block(evt) {
- let b = evt.target.block;
- let msg = block_name(b);
+ let b = evt.target.block
+ let msg = block_name(b)
if (view.battle.LR.includes(b))
- msg = "Lancaster Reserve";
+ msg = "Lancaster Reserve"
if (view.battle.YR.includes(b))
- msg = "York Reserve";
+ msg = "York Reserve"
if (view.actions && view.actions.battle_fire && view.actions.battle_fire.includes(b))
- msg = "Fire with " + msg;
+ msg = "Fire with " + msg
else if (view.actions && view.actions.battle_retreat && view.actions.battle_retreat.includes(b))
- msg = "Retreat with " + msg;
+ msg = "Retreat with " + msg
else if (view.actions && view.actions.battle_charge && view.actions.battle_charge.includes(b))
- msg = "Charge " + msg;
+ msg = "Charge " + msg
else if (view.actions && view.actions.battle_treachery && view.actions.battle_treachery.includes(b))
- msg = "Attempt treachery on " + msg;
+ msg = "Attempt treachery on " + msg
else if (view.actions && view.actions.battle_hit && view.actions.battle_hit.includes(b))
- msg = "Take hit on " + msg;
+ msg = "Take hit on " + msg
- document.getElementById("status").textContent = msg;
+ document.getElementById("status").textContent = msg
}
function on_blur_battle_block(evt) {
- document.getElementById("status").textContent = "";
+ document.getElementById("status").textContent = ""
}
function on_click_battle_block(evt) {
- let b = evt.target.block;
- send_action('block', b);
+ let b = evt.target.block
+ send_action('block', b)
}
function on_focus_battle_fire(evt) {
document.getElementById("status").textContent =
- "Fire with " + block_name(evt.target.block);
+ "Fire with " + block_name(evt.target.block)
}
function on_focus_battle_retreat(evt) {
document.getElementById("status").textContent =
- "Retreat with " + block_name(evt.target.block);
+ "Retreat with " + block_name(evt.target.block)
}
function on_focus_battle_pass(evt) {
document.getElementById("status").textContent =
- "Pass with " + block_name(evt.target.block);
+ "Pass with " + block_name(evt.target.block)
}
function on_focus_battle_hit(evt) {
document.getElementById("status").textContent =
- "Take hit on " + block_name(evt.target.block);
+ "Take hit on " + block_name(evt.target.block)
}
function on_focus_battle_charge(evt) {
if (block_owner(evt.target.block) === view.active)
document.getElementById("status").textContent =
- "Charge with " + block_name(evt.target.block);
+ "Charge with " + block_name(evt.target.block)
else
document.getElementById("status").textContent =
- "Charge " + block_name(evt.target.block);
+ "Charge " + block_name(evt.target.block)
}
function on_focus_battle_treachery(evt) {
if (block_owner(evt.target.block) === view.active)
document.getElementById("status").textContent =
- "Attempt treachery with " + block_name(evt.target.block);
+ "Attempt treachery with " + block_name(evt.target.block)
else
document.getElementById("status").textContent =
- "Attempt treachery on " + block_name(evt.target.block);
+ "Attempt treachery on " + block_name(evt.target.block)
}
function on_blur_battle_button(evt) {
- document.getElementById("status").textContent = "";
+ document.getElementById("status").textContent = ""
}
function on_click_battle_hit(evt) { send_action('battle_hit', evt.target.block); }
@@ -277,468 +308,478 @@ function on_click_battle_treachery(evt) { send_action('battle_treachery', evt.ta
function on_click_battle_pass(evt) {
if (window.confirm("Are you sure that you want to PASS with " + block_name(evt.target.block) + "?"))
- send_action('battle_pass', evt.target.block);
+ send_action('battle_pass', evt.target.block)
}
function on_click_card(evt) {
- let c = evt.target.id.split("+")[1] | 0;
- send_action('play', c);
+ let c = evt.target.id.split("+")[1] | 0
+ send_action('play', c)
}
function build_battle_button(menu, b, c, click, enter, img_src) {
- let img = new Image();
- img.draggable = false;
- img.classList.add("action");
- img.classList.add(c);
- img.setAttribute("src", img_src);
- img.addEventListener("click", click);
- img.addEventListener("mouseenter", enter);
- img.addEventListener("mouseleave", on_blur_battle_button);
- img.block = b;
- menu.appendChild(img);
+ let img = new Image()
+ img.draggable = false
+ img.classList.add("action")
+ img.classList.add(c)
+ img.setAttribute("src", img_src)
+ img.addEventListener("click", click)
+ img.addEventListener("mouseenter", enter)
+ img.addEventListener("mouseleave", on_blur_battle_button)
+ img.block = b
+ menu.appendChild(img)
}
function build_battle_block(b, block) {
- let element = document.createElement("div");
- element.classList.add("block");
- element.classList.add("known");
- element.classList.add(BLOCKS[b].owner);
- element.classList.add("block_" + block.image);
- element.addEventListener("mouseenter", on_focus_battle_block);
- element.addEventListener("mouseleave", on_blur_battle_block);
- element.addEventListener("click", on_click_battle_block);
- element.block = b;
- ui.battle_block[b] = element;
-
- let menu_list = document.createElement("div");
- menu_list.classList.add("battle_menu_list");
+ let element = document.createElement("div")
+ element.classList.add("block")
+ element.classList.add("known")
+ element.classList.add(BLOCKS[b].owner)
+ element.classList.add("block_" + block.image)
+ element.addEventListener("mouseenter", on_focus_battle_block)
+ element.addEventListener("mouseleave", on_blur_battle_block)
+ element.addEventListener("click", on_click_battle_block)
+ element.block = b
+ ui.battle_block[b] = element
+
+ let menu_list = document.createElement("div")
+ menu_list.classList.add("battle_menu_list")
build_battle_button(menu_list, b, "treachery",
on_click_battle_treachery, on_focus_battle_treachery,
- "/images/rose.svg");
+ "/images/rose.svg")
build_battle_button(menu_list, b, "charge",
on_click_battle_charge, on_focus_battle_charge,
- "/images/mounted-knight.svg");
+ "/images/mounted-knight.svg")
build_battle_button(menu_list, b, "hit",
on_click_battle_hit, on_focus_battle_hit,
- "/images/cross-mark.svg");
+ "/images/cross-mark.svg")
- // menu_list.appendChild(document.createElement("br"));
+ // menu_list.appendChild(document.createElement("br"))
build_battle_button(menu_list, b, "fire",
on_click_battle_fire, on_focus_battle_fire,
- "/images/pointy-sword.svg");
+ "/images/pointy-sword.svg")
build_battle_button(menu_list, b, "retreat",
on_click_battle_retreat, on_focus_battle_retreat,
- "/images/flying-flag.svg");
+ "/images/flying-flag.svg")
build_battle_button(menu_list, b, "pass",
on_click_battle_pass, on_focus_battle_pass,
- "/images/sands-of-time.svg");
+ "/images/sands-of-time.svg")
- let menu = document.createElement("div");
- menu.classList.add("battle_menu");
- menu.appendChild(element);
- menu.appendChild(menu_list);
- menu.block = b;
- ui.battle_menu[b] = menu;
+ let menu = document.createElement("div")
+ menu.classList.add("battle_menu")
+ menu.appendChild(element)
+ menu.appendChild(menu_list)
+ menu.block = b
+ ui.battle_menu[b] = menu
}
function build_map_block(b, block) {
- let element = document.createElement("div");
- element.classList.add("block");
- element.classList.add("known");
- element.classList.add(BLOCKS[b].owner);
- element.classList.add("block_" + block.image);
- element.addEventListener("mouseenter", on_focus_map_block);
- element.addEventListener("mouseleave", on_blur_map_block);
- element.addEventListener("click", on_click_map_block);
- element.block = b;
- ui.blocks[b] = element;
+ let element = document.createElement("div")
+ element.classList.add("block")
+ element.classList.add("known")
+ element.classList.add(BLOCKS[b].owner)
+ element.classList.add("block_" + block.image)
+ element.addEventListener("mouseenter", on_focus_map_block)
+ element.addEventListener("mouseleave", on_blur_map_block)
+ element.addEventListener("click", on_click_map_block)
+ element.block = b
+ ui.blocks[b] = element
}
function build_map() {
- let element;
+ let element
- ui.blocks_element = document.getElementById("blocks");
- ui.offmap_element = document.getElementById("offmap");
+ ui.blocks_element = document.getElementById("blocks")
+ ui.offmap_element = document.getElementById("offmap")
for (let c = 1; c <= 25; ++c) {
- ui.cards[c] = document.getElementById("card+"+c);
- ui.cards[c].addEventListener("click", on_click_card);
+ ui.cards[c] = document.getElementById("card+"+c)
+ ui.cards[c].addEventListener("click", on_click_card)
}
for (let c = 1; c <= 7; ++c)
- ui.card_backs[c] = document.getElementById("back+"+c);
+ ui.card_backs[c] = document.getElementById("back+"+c)
- for (let name in AREAS) {
- let area = AREAS[name];
- element = document.getElementById("svgmap").getElementById("area_"+name.replace(/ /g, "_"));
+ for (let area = 0; area < AREAS.length; ++area) {
+ let name = AREAS[area].name
+ element = document.getElementById("svgmap").getElementById("area_"+name.replace(/ /g, "_"))
if (element) {
- element.area = name;
- element.addEventListener("mouseenter", on_focus_area);
- element.addEventListener("mouseleave", on_blur_area);
- element.addEventListener("click", on_click_area);
- ui.areas[name] = element;
+ element.area = area
+ element.addEventListener("mouseenter", on_focus_area)
+ element.addEventListener("mouseleave", on_blur_area)
+ element.addEventListener("click", on_click_area)
+ ui.areas[area] = element
}
}
- for (let b in BLOCKS) {
- let block = BLOCKS[b];
- build_battle_block(b, block);
- build_map_block(b, block);
+ for (let b = 0; b < BLOCKS.length; ++b) {
+ let block = BLOCKS[b]
+ build_battle_block(b, block)
+ build_map_block(b, block)
}
}
function update_steps(b, steps, element) {
- element.classList.remove("r1");
- element.classList.remove("r2");
- element.classList.remove("r3");
- element.classList.add("r"+(BLOCKS[b].steps - steps));
+ element.classList.remove("r1")
+ element.classList.remove("r2")
+ element.classList.remove("r3")
+ element.classList.add("r"+(BLOCKS[b].steps - steps))
+}
+
+function compare_layout_blocks(a, b) {
+ let ad = view.dead.includes(a.block)
+ let bd = view.dead.includes(b.block)
+ if (ad && !bd) return 1
+ if (bd && !ad) return -1
+ return a.block - b.block
}
function layout_blocks(area, secret, known) {
- let wrap = AREAS[area].wrap;
- let s = secret.length;
- let k = known.length;
- let n = s + k;
- let row, rows = [];
- let i = 0;
+ secret.sort(compare_layout_blocks)
+ known.sort(compare_layout_blocks)
+
+ let wrap = AREAS[area].layout.wrap
+ let s = secret.length
+ let k = known.length
+ let n = s + k
+ let row, rows = []
+ let i = 0
function new_line() {
- rows.push(row = []);
- i = 0;
+ rows.push(row = [])
+ i = 0
}
- new_line();
+ new_line()
while (secret.length > 0) {
if (i === wrap)
- new_line();
- row.push(secret.shift());
- ++i;
+ new_line()
+ row.push(secret.shift())
+ ++i
}
// Break early if secret and known fit in exactly two rows, and more than three blocks total
if (s > 0 && s <= wrap && k > 0 && k <= wrap && n > 3)
- new_line();
+ new_line()
while (known.length > 0) {
if (i === wrap)
- new_line();
- row.push(known.shift());
- ++i;
+ new_line()
+ row.push(known.shift())
+ ++i
}
- if (AREAS[area].layout_minor > 0.5)
- rows.reverse();
+ if (AREAS[area].layout.minor > 0.5)
+ rows.reverse()
for (let j = 0; j < rows.length; ++j)
for (i = 0; i < rows[j].length; ++i)
- position_block(area, j, rows.length, i, rows[j].length, rows[j][i]);
+ position_block(area, j, rows.length, i, rows[j].length, rows[j][i])
}
function position_block(area, row, n_rows, col, n_cols, element) {
- let space = AREAS[area];
- let block_size = 60+6;
- let padding = 4;
- let offset = block_size + padding;
- let row_size = (n_rows-1) * offset;
- let col_size = (n_cols-1) * offset;
- let x = space.x - block_size/2;
- let y = space.y - block_size/2;
-
- if (space.layout_axis === 'X') {
- x -= col_size * space.layout_major;
- y -= row_size * space.layout_minor;
- x += col * offset;
- y += row * offset;
+ let space = AREAS[area]
+ let block_size = 60+6
+ let padding = 4
+ let offset = block_size + padding
+ let row_size = (n_rows-1) * offset
+ let col_size = (n_cols-1) * offset
+ let x = space.layout.x - block_size/2
+ let y = space.layout.y - block_size/2
+
+ if (space.layout.axis === 'X') {
+ x -= col_size * space.layout.major
+ y -= row_size * space.layout.minor
+ x += col * offset
+ y += row * offset
} else {
- y -= col_size * space.layout_major;
- x -= row_size * space.layout_minor;
- y += col * offset;
- x += row * offset;
+ y -= col_size * space.layout.major
+ x -= row_size * space.layout.minor
+ y += col * offset
+ x += row * offset
}
- element.style.left = (x|0)+"px";
- element.style.top = (y|0)+"px";
+ element.style.left = (x|0)+"px"
+ element.style.top = (y|0)+"px"
}
function show_block(element) {
if (element.parentElement !== ui.blocks_element)
- ui.blocks_element.appendChild(element);
+ ui.blocks_element.appendChild(element)
}
function hide_block(element) {
if (element.parentElement !== ui.offmap_element)
- ui.offmap_element.appendChild(element);
+ ui.offmap_element.appendChild(element)
}
function is_dead(who) {
- return view.location[who] === NOWHERE;
+ return view.location[who] === NOWHERE
}
function is_perma_dead(who) {
- if (BLOCKS[who].loyalty === undefined)
- return true;
+ if (BLOCKS[who].loyalty === 0)
+ return true
switch (who) {
- case "Warwick/Y": return is_dead("Warwick/L") && is_dead("Warwick/Y");
- case "Kent/Y": return is_dead("Kent/L") && is_dead("Kent/Y");
- case "Salisbury/Y": return is_dead("Salisbury/L") && is_dead("Salisbury/Y");
- case "Clarence/Y": return is_dead("Clarence/L") && is_dead("Clarence/Y");
- case "Exeter/L": return is_dead("Exeter/L") && is_dead("Exeter/Y");
+ case B_WARWICK_Y: return is_dead(B_WARWICK_Y) && is_dead(B_WARWICK_L)
+ case B_KENT_Y: return is_dead(B_KENT_Y) && is_dead(B_KENT_L)
+ case B_SALISBURY_Y: return is_dead(B_SALISBURY_Y) && is_dead(B_SALISBURY_L)
+ case B_CLARENCE_Y: return is_dead(B_CLARENCE_Y) && is_dead(B_CLARENCE_L)
+ case B_EXETER_L: return is_dead(B_EXETER_Y) && is_dead(B_EXETER_L)
}
- return false;
+ return false
}
function update_map() {
- let overflow = { Lancaster: [], York: [], Rebel: [] };
- let layout = {};
+ let overflow = { Lancaster: [], York: [], Rebel: [] }
+ let layout = {}
document.getElementById("turn_info").textContent =
"Campaign " + view.campaign +
"\nKing: " + block_name(view.king) +
- "\nPretender: " + block_name(view.pretender);
-
- layout[DEAD] = { Lancaster: [], York: [] };
- for (let area in AREAS)
- layout[area] = { Lancaster: [], York: [] };
-
- for (let b in view.location) {
- let info = BLOCKS[b];
- let element = ui.blocks[b];
- let area = view.location[b];
- let moved = view.moved[b] ? " moved" : "";
- let image = " block_" + info.image;
- let steps = " r" + (info.steps - view.steps[b]);
- let known = is_known_block(b);
-
- // perma-dead nobles
- if (area === NOWHERE && is_perma_dead(b)) {
- area = DEAD;
- moved = " moved";
- known = 1;
- steps = "";
- }
-
- if (area !== NOWHERE) {
+ "\nPretender: " + block_name(view.pretender)
+
+ for (let area = 0; area < AREAS.length; ++area)
+ layout[area] = { Lancaster: [], York: [] }
+
+ for (let b = 0; b < BLOCKS.length; ++b) {
+ let info = BLOCKS[b]
+ let element = ui.blocks[b]
+ let area = view.location[b]
+ let moved = view.moved.includes(b) ? " moved" : ""
+ let image = " block_" + info.image
+ let steps = " r" + (info.steps - view.steps[b])
+ let known = is_known_block(b)
+
+ if (area !== NOWHERE || is_perma_dead(b)) {
+ // perma-dead nobles
+ if (area === NOWHERE || view.dead.includes(b)) {
+ moved = " moved"
+ known = 1
+ steps = ""
+ }
if (known) {
- element.classList = info.owner + " known block" + image + steps + moved;
+ element.classList = info.owner + " known block" + image + steps + moved
} else {
- element.classList = info.owner + " block" + moved;
+ element.classList = info.owner + " block" + moved
}
+
if (block_owner(b) === LANCASTER)
- layout[area].Lancaster.push(element);
+ layout[area].Lancaster.push(element)
else
- layout[area].York.push(element);
- show_block(element);
+ layout[area].York.push(element)
+
+ show_block(element)
} else {
- hide_block(element);
+ hide_block(element)
}
}
- for (let area in AREAS) {
+ for (let area = 1; area < AREAS.length; ++area) {
if (area === POOL) {
- layout_blocks("LPool", layout[POOL].Lancaster, layout[DEAD].Lancaster);
- layout_blocks("YPool", layout[POOL].York, layout[DEAD].York);
+ layout_blocks(L_POOL, layout[POOL].Lancaster, layout[NOWHERE].Lancaster)
+ layout_blocks(Y_POOL, layout[POOL].York, layout[NOWHERE].York)
} else if (area === MINOR) {
- layout_blocks("LMinor", layout[area].Lancaster, []);
- layout_blocks("YMinor", layout[area].York, []);
+ layout_blocks(L_MINOR, layout[area].Lancaster, [])
+ layout_blocks(Y_MINOR, layout[area].York, [])
} else {
- layout_blocks(area, layout[area].Lancaster, layout[area].York);
+ layout_blocks(area, layout[area].Lancaster, layout[area].York)
}
}
- for (let area in AREAS) {
+ for (let area = 0; area < AREAS.length; ++area) {
if (ui.areas[area]) {
- ui.areas[area].classList.remove('highlight');
- ui.areas[area].classList.remove('where');
+ ui.areas[area].classList.remove('highlight')
+ ui.areas[area].classList.remove('where')
}
}
if (view.actions && view.actions.area)
for (let area of view.actions.area)
- ui.areas[area].classList.add('highlight');
+ ui.areas[area].classList.add('highlight')
if (view.where !== NOWHERE)
- ui.areas[view.where].classList.add('where');
+ ui.areas[view.where].classList.add('where')
- for (let b in BLOCKS) {
- ui.blocks[b].classList.remove('highlight');
- ui.blocks[b].classList.remove('selected');
+ for (let b = 0; b < BLOCKS.length; ++b) {
+ ui.blocks[b].classList.remove('highlight')
+ ui.blocks[b].classList.remove('selected')
}
if (!view.battle) {
if (view.actions && view.actions.block)
for (let b of view.actions.block)
- ui.blocks[b].classList.add('highlight');
+ ui.blocks[b].classList.add('highlight')
if (view.who !== NOBODY)
- ui.blocks[view.who].classList.add('selected');
+ ui.blocks[view.who].classList.add('selected')
}
}
function update_cards() {
- let cards = view.hand;
+ let cards = view.hand
for (let c = 1; c <= 25; ++c) {
- ui.cards[c].classList.remove('enabled');
+ ui.cards[c].classList.remove('enabled')
if (cards && cards.includes(c))
- ui.cards[c].classList.add('show');
+ ui.cards[c].classList.add('show')
else
- ui.cards[c].classList.remove('show');
+ ui.cards[c].classList.remove('show')
}
- let n = view.hand.length;
+ let n = view.hand.length
for (let c = 1; c <= 7; ++c)
if (c <= n && player === 'Observer')
- ui.card_backs[c].classList.add("show");
+ ui.card_backs[c].classList.add("show")
else
- ui.card_backs[c].classList.remove("show");
+ ui.card_backs[c].classList.remove("show")
if (view.actions && view.actions.play) {
for (let c of view.actions.play)
- ui.cards[c].classList.add('enabled');
+ ui.cards[c].classList.add('enabled')
}
if (!view.l_card)
- document.getElementById("lancaster_card").className = "show card card_back";
+ document.getElementById("lancaster_card").className = "show card card_back"
else
- document.getElementById("lancaster_card").className = "show card " + CARDS[view.l_card].image;
+ document.getElementById("lancaster_card").className = "show card " + CARDS[view.l_card].image
if (!view.y_card)
- document.getElementById("york_card").className = "show card card_back";
+ document.getElementById("york_card").className = "show card card_back"
else
- document.getElementById("york_card").className = "show card " + CARDS[view.y_card].image;
+ document.getElementById("york_card").className = "show card " + CARDS[view.y_card].image
}
function compare_blocks(a, b) {
- let aa = BLOCKS[a].combat;
- let bb = BLOCKS[b].combat;
+ let aa = BLOCKS[a].combat
+ let bb = BLOCKS[b].combat
// Bombard
- if (aa === "D3" && view.battle.round <= 1) aa = "A3";
- if (bb === "D3" && view.battle.round <= 1) bb = "A3";
+ if (aa === "D3" && view.battle.round <= 1) aa = "A3"
+ if (bb === "D3" && view.battle.round <= 1) bb = "A3"
if (aa === bb)
- return (a < b) ? -1 : (a > b) ? 1 : 0;
- return (aa < bb) ? -1 : (aa > bb) ? 1 : 0;
+ return (a < b) ? -1 : (a > b) ? 1 : 0
+ return (aa < bb) ? -1 : (aa > bb) ? 1 : 0
}
function sort_battle_row(root) {
- let swapped;
- let children = root.children;
+ let swapped
+ let children = root.children
do {
- swapped = false;
+ swapped = false
for (let i = 1; i < children.length; ++i) {
if (compare_blocks(children[i-1].block, children[i].block) > 0) {
- children[i].after(children[i-1]);
- swapped = true;
+ children[i].after(children[i-1])
+ swapped = true
}
}
- } while (swapped);
+ } while (swapped)
}
function update_battle() {
function fill_cell(name, list, reserve) {
- let cell = window[name];
+ let cell = window[name]
- ui.present.clear();
+ ui.present.clear()
for (let block of list) {
- ui.present.add(block);
+ ui.present.add(block)
if (!cell.contains(ui.battle_menu[block]))
- cell.appendChild(ui.battle_menu[block]);
+ cell.appendChild(ui.battle_menu[block])
if (block === view.who)
- ui.battle_block[block].classList.add("selected");
+ ui.battle_block[block].classList.add("selected")
else
- ui.battle_block[block].classList.remove("selected");
+ ui.battle_block[block].classList.remove("selected")
- ui.battle_block[block].classList.remove("highlight");
- ui.battle_menu[block].classList.remove('hit');
- ui.battle_menu[block].classList.remove('fire');
- ui.battle_menu[block].classList.remove('retreat');
- ui.battle_menu[block].classList.remove('pass');
- ui.battle_menu[block].classList.remove('charge');
- ui.battle_menu[block].classList.remove('treachery');
+ ui.battle_block[block].classList.remove("highlight")
+ ui.battle_menu[block].classList.remove('hit')
+ ui.battle_menu[block].classList.remove('fire')
+ ui.battle_menu[block].classList.remove('retreat')
+ ui.battle_menu[block].classList.remove('pass')
+ ui.battle_menu[block].classList.remove('charge')
+ ui.battle_menu[block].classList.remove('treachery')
if (view.actions && view.actions.block && view.actions.block.includes(block))
- ui.battle_block[block].classList.add("highlight");
+ ui.battle_block[block].classList.add("highlight")
if (view.actions && view.actions.battle_fire && view.actions.battle_fire.includes(block))
- ui.battle_menu[block].classList.add('fire');
+ ui.battle_menu[block].classList.add('fire')
if (view.actions && view.actions.battle_retreat && view.actions.battle_retreat.includes(block))
- ui.battle_menu[block].classList.add('retreat');
+ ui.battle_menu[block].classList.add('retreat')
if (view.actions && view.actions.battle_pass && view.actions.battle_pass.includes(block))
- ui.battle_menu[block].classList.add('pass');
+ ui.battle_menu[block].classList.add('pass')
if (view.actions && view.actions.battle_hit && view.actions.battle_hit.includes(block))
- ui.battle_menu[block].classList.add('hit');
+ ui.battle_menu[block].classList.add('hit')
if (view.actions && view.actions.battle_charge && view.actions.battle_charge.includes(block))
- ui.battle_menu[block].classList.add('charge');
+ ui.battle_menu[block].classList.add('charge')
if (view.actions && view.actions.battle_treachery && view.actions.battle_treachery.includes(block))
- ui.battle_menu[block].classList.add('treachery');
+ ui.battle_menu[block].classList.add('treachery')
- update_steps(block, view.steps[block], ui.battle_block[block]);
+ update_steps(block, view.steps[block], ui.battle_block[block])
if (reserve)
- ui.battle_block[block].classList.add("secret");
+ ui.battle_block[block].classList.add("secret")
else
- ui.battle_block[block].classList.remove("secret");
- if (view.moved[block])
- ui.battle_block[block].classList.add("moved");
+ ui.battle_block[block].classList.remove("secret")
+ if (view.moved.includes(block))
+ ui.battle_block[block].classList.add("moved")
else
- ui.battle_block[block].classList.remove("moved");
+ ui.battle_block[block].classList.remove("moved")
if (reserve)
- ui.battle_block[block].classList.remove("known");
+ ui.battle_block[block].classList.remove("known")
else
- ui.battle_block[block].classList.add("known");
+ ui.battle_block[block].classList.add("known")
}
- for (let b in BLOCKS) {
+ for (let b = 0; b < BLOCKS.length; ++b) {
if (!ui.present.has(b)) {
if (cell.contains(ui.battle_menu[b]))
- cell.removeChild(ui.battle_menu[b]);
+ cell.removeChild(ui.battle_menu[b])
}
}
- sort_battle_row(cell);
+ sort_battle_row(cell)
}
if (player === LANCASTER) {
- fill_cell("FR", view.battle.LR, true);
- fill_cell("FF", view.battle.LF, false);
- fill_cell("EF", view.battle.YF, false);
- fill_cell("ER", view.battle.YR, true);
+ fill_cell("FR", view.battle.LR, true)
+ fill_cell("FF", view.battle.LF, false)
+ fill_cell("EF", view.battle.YF, false)
+ fill_cell("ER", view.battle.YR, true)
} else {
- fill_cell("ER", view.battle.LR, true);
- fill_cell("EF", view.battle.LF, false);
- fill_cell("FF", view.battle.YF, false);
- fill_cell("FR", view.battle.YR, true);
+ fill_cell("ER", view.battle.LR, true)
+ fill_cell("EF", view.battle.LF, false)
+ fill_cell("FF", view.battle.YF, false)
+ fill_cell("FR", view.battle.YR, true)
}
}
function on_update() {
- let king = block_owner(view.king);
- document.getElementById("lancaster_vp").textContent = (king === LANCASTER ? KING_TEXT : PRETENDER_TEXT);
- document.getElementById("york_vp").textContent = (king === YORK ? KING_TEXT : PRETENDER_TEXT);
-
- action_button("eliminate", "Eliminate");
- action_button("execute_clarence", "Execute Clarence");
- action_button("execute_exeter", "Execute Exeter");
- action_button("end_action_phase", "End action phase");
- action_button("end_supply_phase", "End supply phase");
- action_button("end_political_turn", "End political turn");
- action_button("end_exile_limits", "End exile limits");
- action_button("end_regroup", "End regroup");
- action_button("end_retreat", "End retreat");
- action_button("pass", "Pass");
- action_button("undo", "Undo");
-
- update_cards();
- update_map();
+ let king = block_owner(view.king)
+ document.getElementById("lancaster_vp").textContent = (king === LANCASTER ? KING_TEXT : PRETENDER_TEXT)
+ document.getElementById("york_vp").textContent = (king === YORK ? KING_TEXT : PRETENDER_TEXT)
+
+ action_button("eliminate", "Eliminate")
+ action_button("execute_clarence", "Execute Clarence")
+ action_button("execute_exeter", "Execute Exeter")
+ action_button("end_action_phase", "End action phase")
+ action_button("end_supply_phase", "End supply phase")
+ action_button("end_political_turn", "End political turn")
+ action_button("end_exile_limits", "End exile limits")
+ action_button("end_regroup", "End regroup")
+ action_button("end_retreat", "End retreat")
+ action_button("pass", "Pass")
+ action_button("undo", "Undo")
+
+ update_cards()
+ update_map()
if (view.battle) {
- document.getElementById("battle_header").textContent = view.battle.title;
- document.getElementById("battle_message").textContent = view.battle.flash;
- document.getElementById("battle").classList.add("show");
- update_battle();
+ document.getElementById("battle_header").textContent = view.battle.title
+ document.getElementById("battle_message").textContent = view.battle.flash
+ document.getElementById("battle").classList.add("show")
+ update_battle()
} else {
- document.getElementById("battle").classList.remove("show");
+ document.getElementById("battle").classList.remove("show")
}
}
-build_map();
+build_map()
-drag_element_with_mouse("#battle", "#battle_header");
-scroll_with_middle_mouse("main", 2);
+drag_element_with_mouse("#battle", "#battle_header")
+scroll_with_middle_mouse("main", 2)
diff --git a/rules.js b/rules.js
index 8a5e58f..aa1e069 100644
--- a/rules.js
+++ b/rules.js
@@ -13,24 +13,75 @@ exports.scenarios = [
exports.roles = [ "York", "Lancaster" ]
-const { CARDS, BLOCKS, AREAS, BORDERS } = require('./data')
+const { CARDS, BLOCKS, AREAS, BORDERS, block_index, area_index } = require('./data')
-delete AREAS.LPool
-delete AREAS.YPool
-delete AREAS.LMinor
-delete AREAS.YMinor
+const first_area = 6 // first real area (skip pools and seas)
+const last_area = AREAS.length - 4 // skip layout areas at end
+const block_count = BLOCKS.length
+
+// roles
const LANCASTER = "Lancaster"
const YORK = "York"
-const REBEL = "Rebel"
const ENEMY = { Lancaster: "York", York: "Lancaster" }
const OBSERVER = "Observer"
const BOTH = "Both"
-const POOL = "Pool"
-const MINOR = "Minor"
-const NOBODY = -1
+// areas
const NOWHERE = 0
+const POOL = 1
+const MINOR = 2
+
+const IRISH_SEA = area_index["Irish Sea"]
+const NORTH_SEA = area_index["North Sea"]
+const ENGLISH_CHANNEL = area_index["English Channel"]
+
+const IRELAND = area_index["Ireland"]
+const SCOTLAND = area_index["Scotland"]
+const FRANCE = area_index["France"]
+const CALAIS = area_index["Calais"]
+
+const CAERNARVON = area_index["Caernarvon"]
+const PEMBROKE = area_index["Pembroke"]
+const POWYS = area_index["Powys"]
+const GLAMORGAN = area_index["Glamorgan"]
+
+const CORNWALL = area_index["Cornwall"]
+const EAST_YORKS = area_index["East Yorks"]
+const HEREFORD = area_index["Hereford"]
+const ISLE_OF_MAN = area_index["Isle of Man"]
+const MIDDLESEX = area_index["Middlesex"]
+const NORTH_YORKS = area_index["North Yorks"]
+const RUTLAND = area_index["Rutland"]
+const SOUTH_YORKS = area_index["South Yorks"]
+
+// blocks
+const NOBODY = -1
+const B_YORK = block_index["York"]
+const B_MARCH = block_index["March"]
+const B_RUTLAND = block_index["Rutland"]
+const B_CLARENCE_Y = block_index["Clarence/Y"]
+const B_GLOUCESTER = block_index["Gloucester"]
+const B_EXETER_Y = block_index["Exeter/Y"]
+const B_WARWICK_Y = block_index["Warwick/Y"]
+const B_KENT_Y = block_index["Kent/Y"]
+const B_SALISBURY_Y = block_index["Salisbury/Y"]
+const B_IRISH_MERCENARY = block_index["Irish Mercenary"]
+const B_BURGUNDIAN_MERCENARY = block_index["Burgundian Mercenary"]
+const B_CALAIS_MERCENARY = block_index["Calais Mercenary"]
+const B_HENRY_VI = block_index["Henry VI"]
+const B_PRINCE_EDWARD = block_index["Prince Edward"]
+const B_EXETER_L = block_index["Exeter/L"]
+const B_SOMERSET = block_index["Somerset"]
+const B_RICHMOND = block_index["Richmond"]
+const B_WARWICK_L = block_index["Warwick/L"]
+const B_KENT_L = block_index["Kent/L"]
+const B_SALISBURY_L = block_index["Salisbury/L"]
+const B_CLARENCE_L = block_index["Clarence/L"]
+const B_SCOTS_MERCENARY = block_index["Scots Mercenary"]
+const B_WELSH_MERCENARY = block_index["Welsh Mercenary"]
+const B_FRENCH_MERCENARY = block_index["French Mercenary"]
+const B_REBEL = block_index["Rebel"]
// serif cirled numbers
const DIE_HIT = [ 0, '\u2776', '\u2777', '\u2778', '\u2779', '\u277A', '\u277B' ]
@@ -39,10 +90,6 @@ const DIE_MISS = [ 0, '\u2460', '\u2461', '\u2462', '\u2463', '\u2464', '\u2465'
const ATTACK_MARK = "*"
const RESERVE_MARK = ""
-// List for fast iteration
-const BLOCKLIST = Object.keys(BLOCKS)
-const AREALIST = Object.keys(AREAS)
-
let states = {}
let game = null
@@ -75,14 +122,14 @@ function log(s) {
}
function log_move_start(from) {
- game.turn_buf = [ from ]
+ game.turn_buf = [ "#" + from ]
}
function log_move_continue(to, mark) {
if (mark)
- game.turn_buf.push(to + mark)
+ game.turn_buf.push("#" + to + mark)
else
- game.turn_buf.push(to)
+ game.turn_buf.push("#" + to)
}
function log_move_end() {
@@ -198,9 +245,7 @@ function is_royal_heir(who) {
}
function is_dead(who) {
- if (who in BLOCKS)
- return game.location[who] === NOWHERE
- return game.location[who+"/L"] === NOWHERE && game.location[who+"/Y"] === NOWHERE
+ return game.location[who] === NOWHERE
}
function is_shield_area_for(where, who, combat) {
@@ -208,22 +253,22 @@ function is_shield_area_for(where, who, combat) {
let needle = BLOCKS[who].shield
// Nevilles going to exile in Calais
- if (where === "Calais") {
- if (who === "Warwick/L" || who === "Kent/L" || who === "Salisbury/L")
+ if (where === CALAIS) {
+ if (who === B_WARWICK_L || who === B_KENT_L || who === B_SALISBURY_L)
return false
- if (count_blocks_exclude_mercenaries("Calais") < 4) {
- if (who === "Kent/Y")
- return is_area_friendly_to("East Yorks", LANCASTER)
- if (who === "Salisbury/Y")
- return is_area_friendly_to("North Yorks", LANCASTER)
+ if (count_blocks_exclude_mercenaries(CALAIS) < 4) {
+ if (who === B_KENT_Y)
+ return is_area_friendly_to(EAST_YORKS, LANCASTER)
+ if (who === B_SALISBURY_Y)
+ return is_area_friendly_to(NORTH_YORKS, LANCASTER)
}
}
// Exeter and Clarence as enemy nobles
- if (who === "Exeter/Y")
- return where === "Cornwall"
- if (who === "Clarence/L")
- return (where === "South Yorks" || where === "Rutland" || where === "Hereford")
+ if (who === B_EXETER_Y)
+ return where === CORNWALL
+ if (who === B_CLARENCE_L)
+ return (where === SOUTH_YORKS || where === RUTLAND || where === HEREFORD)
// Everyone can always use their own shield
if (haystack && haystack.includes(needle))
@@ -231,11 +276,11 @@ function is_shield_area_for(where, who, combat) {
// Nevilles can use each other's shields if their owner is dead
if (is_neville(who)) {
- if (is_dead("Warwick") && haystack.includes("Warwick"))
+ if (is_dead(B_WARWICK_L) && is_dead(B_WARWICK_Y) && haystack.includes("Warwick"))
return true
- if (is_dead("Kent") && haystack.includes("Kent"))
+ if (is_dead(B_KENT_L) && is_dead(B_KENT_Y) && haystack.includes("Kent"))
return true
- if (is_dead("Salisbury") && haystack.includes("Salisbury"))
+ if (is_dead(B_SALISBURY_L) && is_dead(B_SALISBURY_Y) && haystack.includes("Salisbury"))
return true
}
@@ -250,11 +295,11 @@ function is_shield_area_for(where, who, combat) {
let available = false
if (haystack.includes("Lancaster"))
available = true
- if (is_dead("Exeter") && haystack.includes("Exeter"))
+ if (is_dead(B_EXETER_L) && is_dead(B_EXETER_Y) && haystack.includes("Exeter"))
available = true
- if (is_dead("Somerset") && haystack.includes("Somerset"))
+ if (is_dead(B_SOMERSET) && haystack.includes("Somerset"))
available = true
- if (is_dead("Richmond") && haystack.includes("Richmond"))
+ if (is_dead(B_RICHMOND) && haystack.includes("Richmond"))
available = true
if (available)
return !combat || find_senior_heir_in_area(LANCASTER, where) === who
@@ -295,21 +340,21 @@ function is_home_for(where, who) {
}
function is_available_home_for(where, who) {
- if (who === "Clarence/L")
+ if (who === B_CLARENCE_L)
return is_home_for(where, who) && is_vacant_area(where)
return is_home_for(where, who) && is_friendly_or_vacant_area(where)
}
function count_available_homes(who) {
let count = 0
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (is_available_home_for(where, who))
++count
return count
}
function available_home(who) {
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (is_available_home_for(where, who))
return where
}
@@ -324,7 +369,7 @@ function go_home_if_possible(who) {
let home = available_home(who)
if (game.location[who] !== home) {
game.location[who] = home
- game.turn_log.push([block_name(who), game.location[who]]) // TODO: "Home"?
+ game.turn_log.push([block_name(who), "#" + game.location[who]]) // TODO: "Home"?
}
} else {
return true
@@ -336,8 +381,7 @@ function go_home_if_possible(who) {
function is_on_map_not_in_exile_or_man(who) {
let where = game.location[who]
return where !== NOWHERE && where !== MINOR && where !== POOL &&
- where !== "Isle of Man" &&
- !is_exile_area(where)
+ where !== ISLE_OF_MAN && !is_exile_area(where)
}
function is_land_area(where) {
@@ -353,12 +397,12 @@ function is_area_friendly_to(where, owner) {
}
function is_london_friendly_to(owner) {
- return is_area_friendly_to("Middlesex", owner)
+ return is_area_friendly_to(MIDDLESEX, owner)
}
function count_lancaster_nobles_and_heirs() {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (block_owner(b) === LANCASTER &&
(block_type(b) === 'nobles' || block_type(b) === 'church' || block_type(b) === 'heir'))
if (is_on_map_not_in_exile_or_man(b))
@@ -370,7 +414,7 @@ function count_lancaster_nobles_and_heirs() {
function count_york_nobles_and_heirs() {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (block_owner(b) === YORK &&
(block_type(b) === 'nobles' || block_type(b) === 'church' || block_type(b) === 'heir'))
if (is_on_map_not_in_exile_or_man(b))
@@ -393,7 +437,7 @@ function block_home(who) {
}
function block_owner(who) {
- if (who === REBEL) {
+ if (who === B_REBEL) {
if (game.pretender !== NOBODY)
return block_owner(game.pretender)
else if (game.king !== NOBODY)
@@ -407,11 +451,11 @@ function block_owner(who) {
function block_initiative(who) {
if (block_type(who) === 'bombard')
return game.battle_round <= 1 ? 'A' : 'D'
- return BLOCKS[who].combat[0]
+ return BLOCKS[who].initiative
}
function block_printed_fire_power(who) {
- return BLOCKS[who].combat[1] | 0
+ return BLOCKS[who].fire_power
}
function block_fire_power(who, where) {
@@ -427,7 +471,7 @@ function block_fire_power(who, where) {
++combat
if (is_levy(who) && block_home(who) === has_city(where))
++combat
- if (who === "Welsh Mercenary" && is_wales(where))
+ if (who === B_WELSH_MERCENARY && is_wales(where))
++combat
}
return combat
@@ -471,7 +515,7 @@ function block_loyalty(source, target) {
if (target_name === "Northumberland" || target_name === "Westmoreland")
return 0
}
- return BLOCKS[target].loyalty | 0
+ return BLOCKS[target].loyalty
}
function can_defect(source, target) {
@@ -483,11 +527,11 @@ function can_defect(source, target) {
function can_attempt_treason_event() {
if (game.treason === game.attacker[game.where]) {
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (is_defender(b) && can_defect(NOBODY, b))
return true
} else {
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (is_attacker(b) && can_defect(NOBODY, b))
return true
}
@@ -497,14 +541,14 @@ function can_attempt_treason_event() {
function treachery_tag(who) {
if (who === game.king) return 'King'
if (who === game.pretender) return 'Pretender'
- if (who === "Warwick/L" || who === "Warwick/Y") return 'Warwick'
+ if (who === B_WARWICK_L || who === B_WARWICK_Y) return 'Warwick'
return game.active
}
function can_attempt_treachery(who) {
let once = treachery_tag(who)
if (set_has(game.battle_list, who) && !set_has(game.treachery, once)) {
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (game.active === game.attacker[game.where]) {
if (is_defender(b) && can_defect(who, b))
return true
@@ -538,7 +582,7 @@ function is_block_alive(b) {
}
function border_id(a, b) {
- return (a < b) ? a + "/" + b : b + "/" + a
+ return (a < b) ? a * 100 + b : b * 100 + a
}
function border_was_last_used_by_enemy(from, to) {
@@ -564,7 +608,7 @@ function reset_border_limits() {
function count_friendly(where) {
let p = game.active
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && block_owner(b) === p && !set_has(game.dead, b))
++count
return count
@@ -573,7 +617,7 @@ function count_friendly(where) {
function count_enemy(where) {
let p = ENEMY[game.active]
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && block_owner(b) === p && !set_has(game.dead, b))
++count
return count
@@ -582,7 +626,7 @@ function count_enemy(where) {
function count_enemy_excluding_reserves(where) {
let p = ENEMY[game.active]
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && block_owner(b) === p)
if (!set_has(game.reserves, b))
++count
@@ -612,19 +656,19 @@ function is_major_port(where) {
}
function is_sea_area(where) {
- return where === 'Irish Sea' || where === 'North Sea' || where === 'English Channel'
+ return where === IRISH_SEA || where === NORTH_SEA || where === ENGLISH_CHANNEL
}
function is_wales(where) {
- return where === "Caernarvon" || where === "Pembroke" || where === "Powys" || where === "Glamorgan"
+ return where === CAERNARVON || where === PEMBROKE || where === POWYS || where === GLAMORGAN
}
function is_lancaster_exile_area(where) {
- return where === "France" || where === "Scotland"
+ return where === FRANCE || where === SCOTLAND
}
function is_york_exile_area(where) {
- return where === "Calais" || where === "Ireland"
+ return where === CALAIS || where === IRELAND
}
function is_exile_area(where) {
@@ -644,7 +688,7 @@ function is_pretender_exile_area(where) {
}
function can_recruit_to(who, to) {
- if (who === "Welsh Mercenary")
+ if (who === B_WELSH_MERCENARY)
return is_wales(to) && is_friendly_or_vacant_area(to)
switch (block_type(who)) {
case 'heir':
@@ -678,14 +722,14 @@ function can_recruit(who) {
if (game.active === game.piracy) return false
if (can_activate(who) && game.location[who] === POOL)
- for (let to of AREALIST)
+ for (let to = first_area; to <= last_area; ++to)
if (can_recruit_to(who, to))
return true
return false
}
function have_contested_areas() {
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (is_area_on_map(where) && is_contested_area(where))
return true
return false
@@ -697,7 +741,7 @@ function count_pinning(where) {
function count_pinned(where) {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && block_owner(b) === game.active)
if (!set_has(game.reserves, b))
++count
@@ -717,7 +761,7 @@ function can_block_sea_move_to(who, from, to) {
return false
if (game.active === game.force_march)
return false
- if (who === REBEL || who === "Scots Mercenary" || who === "Welsh Mercenary")
+ if (who === B_REBEL || who === B_SCOTS_MERCENARY || who === B_WELSH_MERCENARY)
return false
if (block_type(who) === 'bombard' || block_type(who) === 'levies')
return false
@@ -863,7 +907,7 @@ function can_block_muster_via(who, from, next, muster) {
if (next === muster)
return true
if (border_type(from, next) !== 'minor') {
- if (AREAS[next].exits.includes(muster))
+ if (set_has(AREAS[next].exits, muster))
if (can_block_land_move_to(who, next, muster))
return true
}
@@ -886,7 +930,7 @@ function can_block_muster(who, muster) {
}
function can_muster_to(muster) {
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (can_block_muster(b, muster))
return true
return false
@@ -924,12 +968,12 @@ function disband(who) {
function check_instant_victory() {
// Check Clarence/Y and Exeter/L specifically (they're not heirs if converted)
- if (is_dead("York") && is_dead("March") && is_dead("Rutland") && is_dead("Clarence/Y") && is_dead("Gloucester")) {
+ if (is_dead(B_YORK) && is_dead(B_MARCH) && is_dead(B_RUTLAND) && is_dead(B_CLARENCE_Y) && is_dead(B_GLOUCESTER)) {
log("All York heirs were eliminated!")
game.victory = "Lancaster won by eliminating all enemy heirs!"
game.result = LANCASTER
}
- if (is_dead("Henry VI") && is_dead("Prince Edward") && is_dead("Exeter/L") && is_dead("Somerset") && is_dead("Richmond")) {
+ if (is_dead(B_HENRY_VI) && is_dead(B_PRINCE_EDWARD) && is_dead(B_EXETER_L) && is_dead(B_SOMERSET) && is_dead(B_RICHMOND)) {
log("All Lancaster heirs were eliminated!")
game.victory = "York won by eliminating all enemy heirs!"
game.result = YORK
@@ -939,12 +983,12 @@ function check_instant_victory() {
function eliminate_block(who) {
log(block_name(who) + " was eliminated.")
game.flash += " " + block_name(who) + " was eliminated."
- if (who === "Exeter/Y") {
+ if (who === B_EXETER_Y) {
game.location[who] = NOWHERE
++game.killed_heirs[LANCASTER]
return check_instant_victory()
}
- if (who === "Clarence/L") {
+ if (who === B_CLARENCE_L) {
game.location[who] = NOWHERE
++game.killed_heirs[YORK]
return check_instant_victory()
@@ -963,12 +1007,12 @@ function eliminate_block(who) {
}
if (is_mercenary(who)) {
switch (who) {
- case "Welsh Mercenary": game.location[who] = POOL; break
- case "Irish Mercenary": game.location[who] = "Ireland"; break
- case "Burgundian Mercenary": game.location[who] = "Calais"; break
- case "Calais Mercenary": game.location[who] = "Calais"; break
- case "Scots Mercenary": game.location[who] = "Scotland"; break
- case "French Mercenary": game.location[who] = "France"; break
+ case B_WELSH_MERCENARY: game.location[who] = POOL; break
+ case B_IRISH_MERCENARY: game.location[who] = IRELAND; break
+ case B_BURGUNDIAN_MERCENARY: game.location[who] = CALAIS; break
+ case B_CALAIS_MERCENARY: game.location[who] = CALAIS; break
+ case B_SCOTS_MERCENARY: game.location[who] = SCOTLAND; break
+ case B_FRENCH_MERCENARY: game.location[who] = FRANCE; break
}
game.steps[who] = block_max_steps(who)
set_add(game.dead, who)
@@ -989,7 +1033,7 @@ function reduce_block(who) {
function count_attackers() {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (is_attacker(b))
++count
return count
@@ -997,7 +1041,7 @@ function count_attackers() {
function count_defenders() {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (is_defender(b))
++count
return count
@@ -1005,7 +1049,7 @@ function count_defenders() {
function count_blocks_exclude_mercenaries(where) {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && !is_mercenary(b) && !(game.reduced && set_has(game.reduced, b)))
++count
return count
@@ -1013,32 +1057,32 @@ function count_blocks_exclude_mercenaries(where) {
function count_blocks(where) {
let count = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && !(game.reduced && set_has(game.reduced, b)))
++count
return count
}
function add_blocks_exclude_mercenaries(list, where) {
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && !is_mercenary(b) && !(game.reduced && set_has(game.reduced, b)))
set_add(list, b)
}
function add_blocks(list, where) {
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where && !(game.reduced && set_has(game.reduced, b)))
set_add(list, b)
}
function check_supply_penalty() {
game.supply = []
- for (let where of AREALIST) {
+ for (let where = first_area; where <= last_area; ++where) {
if (is_friendly_area(where)) {
- if (where === "Calais" || where === "France") {
+ if (where === CALAIS || where === FRANCE) {
if (count_blocks_exclude_mercenaries(where) > 4)
add_blocks_exclude_mercenaries(game.supply, where)
- } else if (where === "Ireland" || where === "Scotland") {
+ } else if (where === IRELAND || where === SCOTLAND) {
if (count_blocks_exclude_mercenaries(where) > 2)
add_blocks_exclude_mercenaries(game.supply, where)
} else if (has_city(where)) {
@@ -1055,12 +1099,12 @@ function check_supply_penalty() {
function check_exile_limits() {
game.exiles = []
- for (let where of AREALIST) {
+ for (let where = first_area; where <= last_area; ++where) {
if (is_friendly_area(where)) {
- if (where === "Calais" || where === "France") {
+ if (where === CALAIS || where === FRANCE) {
if (count_blocks_exclude_mercenaries(where) > 4)
add_blocks_exclude_mercenaries(game.exiles, where)
- } else if (where === "Ireland" || where === "Scotland") {
+ } else if (where === IRELAND || where === SCOTLAND) {
if (count_blocks_exclude_mercenaries(where) > 2)
add_blocks_exclude_mercenaries(game.exiles, where)
}
@@ -1075,20 +1119,20 @@ function check_exile_limits() {
// SETUP
function find_block(owner, name) {
- if (name in BLOCKS)
- return name
+ if (name in block_index)
+ return block_index[name]
name = name + "/" + owner[0]
- if (name in BLOCKS)
- return name
+ if (name in block_index)
+ return block_index[name]
throw new Error("Block not found: " + name)
}
function deploy(who, where) {
if (where === "Enemy")
return
- if (!(where in AREAS))
+ if (!(where in area_index))
throw new Error("Area not found: " + where)
- game.location[who] = where
+ game.location[who] = area_index[where]
game.steps[who] = BLOCKS[who].steps
}
@@ -1101,7 +1145,7 @@ function deploy_york(name, where) {
}
function reset_blocks() {
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
game.location[b] = NOWHERE
game.steps[b] = block_max_steps(b)
}
@@ -1112,8 +1156,8 @@ function setup_game() {
game.campaign = 1
game.end_campaign = 3
- game.pretender = "York"
- game.king = "Henry VI"
+ game.pretender = B_YORK
+ game.king = B_HENRY_VI
deploy_lancaster("Henry VI", "Middlesex")
deploy_lancaster("Somerset", "Dorset")
@@ -1186,8 +1230,8 @@ function setup_kingmaker() {
game.campaign = 2
game.end_campaign = 2
- game.pretender = "Henry VI"
- game.king = "March"
+ game.pretender = B_HENRY_VI
+ game.king = B_MARCH
deploy_york("March", "Middlesex")
deploy_york("Gloucester", "South Yorks")
@@ -1242,7 +1286,7 @@ function setup_kingmaker() {
deploy_lancaster("Canterbury (church)", "Enemy")
// Prisoner!
- set_add(game.dead, "Henry VI")
+ set_add(game.dead, B_HENRY_VI)
}
function setup_richard_iii() {
@@ -1250,8 +1294,8 @@ function setup_richard_iii() {
game.campaign = 3
game.end_campaign = 3
- game.pretender = "Richmond"
- game.king = "Gloucester"
+ game.pretender = B_RICHMOND
+ game.king = B_GLOUCESTER
deploy_york("Gloucester", "Middlesex")
deploy_york("Norfolk", "East Anglia")
@@ -1298,11 +1342,11 @@ function setup_richard_iii() {
// Kingmaker scenario special rule
function free_henry_vi() {
- if (set_has(game.dead, "Henry VI")) {
- if ((game.active === LANCASTER && is_friendly_area("Middlesex")) ||
- (game.active === YORK && is_enemy_area("Middlesex"))) {
+ if (set_has(game.dead, B_HENRY_VI)) {
+ if ((game.active === LANCASTER && is_friendly_area(MIDDLESEX)) ||
+ (game.active === YORK && is_enemy_area(MIDDLESEX))) {
log("Henry VI rescued!")
- set_delete(game.dead, "Henry VI")
+ set_delete(game.dead, B_HENRY_VI)
}
}
}
@@ -1312,6 +1356,7 @@ function free_henry_vi() {
function start_campaign() {
logbr()
log(".h1 Campaign " + game.campaign)
+ logbr()
// TODO: Use board game mulligan rules instead of automatically redealing?
do {
@@ -1328,6 +1373,7 @@ function start_game_turn() {
logbr()
log(".h1 Turn " + game.turn + " of campaign " + game.campaign + ".")
+ logbr()
// Reset movement and attack tracking state
reset_border_limits()
@@ -1451,6 +1497,7 @@ function reveal_cards() {
function start_player_turn() {
logbr()
log(".h2 " + game.active)
+
reset_border_limits()
let lc = CARDS[game.l_card]
let yc = CARDS[game.y_card]
@@ -1517,7 +1564,7 @@ states.plague_event = {
return view.prompt = "Plague: Waiting for " + game.active + " to choose a city."
view.prompt = "Plague: Choose an enemy city area."
gen_action(view, 'pass')
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (is_enemy_area(where) && has_city(where))
gen_action(view, 'area', where)
},
@@ -1525,7 +1572,7 @@ states.plague_event = {
log("Plague ravaged " + has_city(where) + "!")
game.where = where
game.plague = []
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === where)
set_add(game.plague, b)
game.active = ENEMY[game.active]
@@ -1550,6 +1597,7 @@ states.apply_plague = {
if (game.plague.length === 0) {
delete game.plague
game.active = ENEMY[game.active]
+ game.where = NOWHERE
end_player_turn()
}
},
@@ -1568,7 +1616,7 @@ states.muster_event = {
view.prompt = "Muster: Choose one friendly or vacant muster area."
gen_action_undo(view)
gen_action(view, 'end_action_phase')
- for (let where of AREALIST) {
+ for (let where = first_area; where <= last_area; ++where) {
if (is_friendly_or_vacant_area(where))
if (can_muster_to(where))
gen_action(view, 'area', where)
@@ -1594,7 +1642,7 @@ states.muster_who = {
view.prompt = "Muster: Move blocks to the designated muster area."
gen_action_undo(view)
gen_action(view, 'end_action_phase')
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (can_block_muster(b, game.where))
gen_action(view, 'block', b)
},
@@ -1728,7 +1776,7 @@ states.action_phase = {
gen_action_undo(view)
gen_action(view, 'end_action_phase')
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
let from = game.location[b]
if (can_recruit(b)) {
if (game.moves > 0)
@@ -1768,11 +1816,13 @@ states.action_phase = {
if (game.moves > 0 && game.turn_log.length === 0 && game.recruit_log.length === 0)
logp("did nothing.")
- if (game.turn_log.length > 0)
+ if (game.turn_log.length > 0) {
print_turn_log(game.active + " moved:")
+ }
game.turn_log = game.recruit_log
- if (game.turn_log.length > 0)
+ if (game.turn_log.length > 0) {
print_turn_log(game.active + " recruited:")
+ }
game.turn_log = null
game.recruit_log = null
@@ -1790,12 +1840,12 @@ states.recruit_where = {
view.prompt = "Recruit " + block_name(game.who) + " where?"
gen_action_undo(view)
gen_action(view, 'block', game.who)
- for (let to of AREALIST)
+ for (let to = first_area; to <= last_area; ++to)
if (can_recruit_to(game.who, to))
gen_action(view, 'area', to)
},
area: function (to) {
- game.recruit_log.push([to])
+ game.recruit_log.push(["#" + to])
--game.moves
game.location[game.who] = to
set_add(game.moved, game.who)
@@ -1929,7 +1979,7 @@ function end_move() {
if (game.distance > 0) {
log_move_end()
if (!set_has(game.activated, game.origin)) {
- logp("activated " + game.origin + ".")
+ logp("activated #" + game.origin + ".")
set_add(game.activated, game.origin)
game.moves --
}
@@ -1963,7 +2013,7 @@ states.battle_phase = {
if (is_inactive_player(current))
return view.prompt = "Waiting for " + game.active + " to choose a battle."
view.prompt = "Choose the next battle to fight!"
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (is_area_on_map(where) && is_contested_area(where))
gen_action(view, 'area', where)
},
@@ -2000,7 +2050,7 @@ function resume_battle() {
function end_battle() {
if (game.turn_log && game.turn_log.length > 0)
- print_turn_log("Retreated from " + game.where + ":")
+ print_turn_log("Retreated from #" + game.where + ":")
free_henry_vi()
game.flash = ""
game.battle_round = 0
@@ -2018,7 +2068,7 @@ states.treason_event = {
return view.prompt = "Treason: Waiting for " + game.active + " to choose a target."
view.prompt = "Treason: Choose a target or pass."
gen_action(view, 'pass')
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (game.active === game.attacker[game.where]) {
if (is_defender(b) && can_defect(NOBODY, b)) {
gen_action(view, 'battle_treachery', b)
@@ -2051,7 +2101,7 @@ states.treason_event = {
}
function bring_on_reserves(owner, moved) {
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === owner && game.location[b] === game.where) {
set_delete(game.reserves, b)
if (moved)
@@ -2065,10 +2115,10 @@ function bring_on_reserves(owner, moved) {
function start_battle_round() {
if (++game.battle_round <= 4) {
if (game.turn_log && game.turn_log.length > 0)
- print_turn_log("Retreated from " + game.where + ":")
+ print_turn_log("Retreated from #" + game.where + ":")
game.turn_log = []
- log("~ Battle Round " + game.battle_round + " ~")
+ log(".h4 Battle Round " + game.battle_round)
reset_border_limits()
set_clear(game.moved)
@@ -2107,7 +2157,7 @@ function pump_battle_round() {
function filter_battle_blocks(ci, is_candidate) {
let output = null
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (is_candidate(b) && !set_has(game.moved, b) && !set_has(game.dead, b)) {
if (block_initiative(b) === ci) {
if (!output)
@@ -2286,7 +2336,7 @@ function can_block_fire(who) {
function find_minor_heir(owner) {
let candidate = NOBODY
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b] === MINOR)
if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir)
candidate = b
@@ -2296,7 +2346,7 @@ function find_minor_heir(owner) {
function find_senior_heir(owner) {
let candidate = NOBODY
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (block_owner(b) === owner && block_type(b) === 'heir' && !is_dead(b))
if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir)
candidate = b
@@ -2305,7 +2355,7 @@ function find_senior_heir(owner) {
function find_next_king(owner) {
let candidate = NOBODY
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b] !== NOWHERE)
if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir)
candidate = b
@@ -2314,7 +2364,7 @@ function find_next_king(owner) {
function find_senior_heir_in_area(owner, where) {
let candidate = NOBODY
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b] === where) {
if (is_battle_reserve(b))
continue
@@ -2376,10 +2426,10 @@ states.battle_round = {
gen_action(view, 'battle_treachery', game.king)
if (can_attempt_treachery(game.pretender))
gen_action(view, 'battle_treachery', game.pretender)
- if (can_attempt_treachery("Warwick/L"))
- gen_action(view, 'battle_treachery', "Warwick/L")
- if (can_attempt_treachery("Warwick/Y"))
- gen_action(view, 'battle_treachery', "Warwick/Y")
+ if (can_attempt_treachery(B_WARWICK_L))
+ gen_action(view, 'battle_treachery', B_WARWICK_L)
+ if (can_attempt_treachery(B_WARWICK_Y))
+ gen_action(view, 'battle_treachery', B_WARWICK_Y)
},
battle_fire: function (who) {
fire_with_block(who)
@@ -2417,7 +2467,7 @@ states.battle_charge = {
return view.prompt = "Heir Charge: Waiting for " + game.active + " to choose a target."
view.prompt = "Heir Charge: Choose a target."
gen_action(view, 'undo')
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (game.active === game.attacker[game.where]) {
if (is_defender(b)) {
gen_action(view, 'battle_charge', b)
@@ -2449,7 +2499,7 @@ states.battle_treachery = {
return view.prompt = "Treachery: Waiting for " + game.active + " to choose a target."
view.prompt = "Treachery: Choose a target."
gen_action(view, 'undo')
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (game.active === game.attacker[game.where]) {
if (is_defender(b) && can_defect(game.who, b)) {
gen_action(view, 'battle_treachery', b)
@@ -2511,11 +2561,11 @@ function apply_hit(who) {
function list_victims(p) {
let is_candidate = (p === game.attacker[game.where]) ? is_attacker : is_defender
let max = 0
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (is_candidate(b) && game.steps[b] > max)
max = game.steps[b]
let list = []
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (is_candidate(b) && game.steps[b] === max)
set_add(list, b)
return list
@@ -2565,7 +2615,7 @@ states.retreat_in_battle = {
} else {
game.flash = block_name(game.who) + " retreated."
log_battle(game.flash)
- game.turn_log.push([game.active, to])
+ game.turn_log.push([game.active, "#" + to])
use_border(game.where, to)
game.location[game.who] = to
resume_battle()
@@ -2598,7 +2648,7 @@ states.sea_retreat_to = {
},
area: function (to) {
let sea = game.location[game.who]
- game.turn_log.push([game.active, sea, to])
+ game.turn_log.push([game.active, "#" + sea, "#" + to])
game.flash = block_name(game.who) + " retreated."
log_battle(game.flash)
game.location[game.who] = to
@@ -2619,7 +2669,7 @@ function goto_regroup() {
game.active = game.attacker[game.where]
if (is_enemy_area(game.where))
game.active = ENEMY[game.active]
- log(game.active + " won the battle in " + game.where + "!")
+ log(game.active + " won the battle in #" + game.where + "!")
game.state = 'regroup'
game.turn_log = []
clear_undo()
@@ -2632,7 +2682,7 @@ states.regroup = {
view.prompt = "Regroup: Choose an army to move."
gen_action_undo(view)
gen_action(view, 'end_regroup')
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (game.location[b] === game.where) {
if (game.active === game.piracy) {
if (set_has(game.is_pirate, b))
@@ -2687,7 +2737,7 @@ states.regroup_to = {
game.location[game.who] = to
game.state = 'sea_regroup_to'
} else {
- game.turn_log.push([game.where, to])
+ game.turn_log.push(["#"+game.where, "#"+to])
move_block(game.who, game.where, to)
game.who = NOBODY
game.state = 'regroup'
@@ -2736,10 +2786,10 @@ function goto_supply_phase() {
}
function goto_execute_clarence() {
- if (is_block_alive("Clarence/L")) {
+ if (is_block_alive(B_CLARENCE_L)) {
game.active = LANCASTER
game.state = 'execute_clarence'
- game.who = "Clarence/L"
+ game.who = B_CLARENCE_L
} else {
goto_execute_exeter()
}
@@ -2755,7 +2805,7 @@ states.execute_clarence = {
},
execute_clarence: function () {
logp("executed Clarence.")
- eliminate_block("Clarence/L")
+ eliminate_block(B_CLARENCE_L)
game.who = NOBODY
if (game.result)
return goto_game_over()
@@ -2768,10 +2818,10 @@ states.execute_clarence = {
}
function goto_execute_exeter() {
- if (is_block_alive("Exeter/Y")) {
+ if (is_block_alive(B_EXETER_Y)) {
game.active = YORK
game.state = 'execute_exeter'
- game.who = "Exeter/Y"
+ game.who = B_EXETER_Y
} else {
goto_enter_pretender_heir()
}
@@ -2787,7 +2837,7 @@ states.execute_exeter = {
},
execute_exeter: function () {
logp("executed Exeter.")
- eliminate_block("Exeter/Y")
+ eliminate_block(B_EXETER_Y)
game.who = NOBODY
if (game.result)
return goto_game_over()
@@ -2815,7 +2865,7 @@ states.enter_pretender_heir = {
if (is_inactive_player(current))
return view.prompt = "Waiting for " + game.active + " to enter pretender heirs."
view.prompt = "Death of an Heir: Enter " + block_name(game.who) + " in an exile area."
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (is_pretender_exile_area(where))
gen_action(view, 'area', where)
},
@@ -2856,7 +2906,7 @@ states.supply_limits_pretender = {
},
block: function (who) {
push_undo()
- game.turn_log.push([game.location[who]])
+ game.turn_log.push(["#" + game.location[who]])
set_add(game.reduced, who)
reduce_block(who)
check_supply_penalty()
@@ -2890,7 +2940,7 @@ states.enter_royal_heir = {
return view.prompt = "Waiting for " + game.active + " to enter royal heirs."
view.prompt = "Death of an Heir: Enter " + block_name(game.who) + " in a Crown area."
let can_enter = false
- for (let where of AREALIST) {
+ for (let where = first_area; where <= last_area; ++where) {
if (is_crown_area(where) && is_friendly_or_vacant_area(where)) {
gen_action(view, 'area', where)
can_enter = true
@@ -2940,7 +2990,7 @@ states.supply_limits_king = {
},
block: function (who) {
push_undo()
- game.turn_log.push([game.location[who]])
+ game.turn_log.push(["#" + game.location[who]])
set_add(game.reduced, who)
reduce_block(who)
check_supply_penalty()
@@ -2967,45 +3017,45 @@ function goto_political_turn() {
game.turn_log = []
// Levies disband
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (!is_land_area(game.location[b]))
continue
switch (block_type(b)) {
case 'bombard':
case 'levies':
case 'rebel':
- game.turn_log.push([game.location[b]])
+ game.turn_log.push(["#" + game.location[b]])
disband(b)
break
case 'mercenaries':
switch (b) {
- case "Welsh Mercenary":
- game.turn_log.push([game.location[b]])
+ case B_WELSH_MERCENARY:
+ game.turn_log.push(["#" + game.location[b]])
disband(b)
break
- case "Irish Mercenary":
- if (game.location[b] !== "Ireland") {
- game.turn_log.push([game.location[b], "Ireland"])
- game.location[b] = "Ireland"
+ case B_IRISH_MERCENARY:
+ if (game.location[b] !== IRELAND) {
+ game.turn_log.push(["#" + game.location[b], "#" + IRELAND])
+ game.location[b] = IRELAND
}
break
- case "Burgundian Mercenary":
- case "Calais Mercenary":
- if (game.location[b] !== "Calais") {
- game.turn_log.push([game.location[b], "Calais"])
- game.location[b] = "Calais"
+ case B_BURGUNDIAN_MERCENARY:
+ case B_CALAIS_MERCENARY:
+ if (game.location[b] !== CALAIS) {
+ game.turn_log.push(["#" + game.location[b], "#" + CALAIS])
+ game.location[b] = CALAIS
}
break
- case "Scots Mercenary":
- if (game.location[b] !== "Scotland") {
- game.turn_log.push([game.location[b], "Scotland"])
- game.location[b] = "Scotland"
+ case B_SCOTS_MERCENARY:
+ if (game.location[b] !== SCOTLAND) {
+ game.turn_log.push(["#" + game.location[b], "#" + SCOTLAND])
+ game.location[b] = SCOTLAND
}
break
- case "French Mercenary":
- if (game.location[b] !== "France") {
- game.turn_log.push([game.location[b], "France"])
- game.location[b] = "France"
+ case B_FRENCH_MERCENARY:
+ if (game.location[b] !== FRANCE) {
+ game.turn_log.push(["#" + game.location[b], "#" + FRANCE])
+ game.location[b] = FRANCE
}
break
}
@@ -3024,13 +3074,13 @@ function goto_political_turn() {
if (l_count > y_count && block_owner(game.king) === YORK) {
game.king = find_senior_heir(LANCASTER)
game.pretender = find_senior_heir(YORK)
- log(game.king + " usurped the throne!")
+ log(block_name(game.king) + " usurped the throne!")
} else if (y_count > l_count && block_owner(game.king) === LANCASTER) {
game.king = find_senior_heir(YORK)
game.pretender = find_senior_heir(LANCASTER)
- log(game.king + " usurped the throne!")
+ log(block_name(game.king) + " usurped the throne!")
} else {
- log(game.king + " remained king.")
+ log(block_name(game.king) + " remained king.")
}
// Game ends after last Usurpation check
@@ -3048,7 +3098,7 @@ function goto_pretender_goes_home() {
game.state = 'pretender_goes_home'
game.turn_log = []
let choices = false
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (block_owner(b) === game.active && is_block_on_map(b))
if (go_home_if_possible(b))
choices = true
@@ -3066,7 +3116,7 @@ states.pretender_goes_home = {
return view.prompt = "Waiting for the Pretender to go to exile."
gen_action_undo(view)
let done = true
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === game.active && is_block_on_map(b) && !set_has(game.moved, b)) {
if (!is_in_exile(b)) {
if (is_heir(b)) {
@@ -3083,7 +3133,7 @@ states.pretender_goes_home = {
}
if (done) {
view.prompt = "Pretender Goes Home: You may move nobles to another home."
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === game.active && is_block_on_map(b) && !set_has(game.moved, b)) {
if (!is_in_exile(b)) {
if (is_at_home(b)) {
@@ -3121,7 +3171,7 @@ states.pretender_goes_home_to = {
else
view.prompt = "Pretender Goes Home: Move " + block_name(game.who) + " to home."
gen_action(view, 'block', game.who)
- for (let where of AREALIST) {
+ for (let where = first_area; where <= last_area; ++where) {
if (where !== game.location[game.who]) {
if (is_heir(game.who)) {
if (is_friendly_exile_area(where))
@@ -3134,9 +3184,9 @@ states.pretender_goes_home_to = {
},
area: function (to) {
if (is_exile_area(to))
- game.turn_log.push([block_name(game.who), to]) // TODO: "Exile"?
+ game.turn_log.push([block_name(game.who), "#" + to]) // TODO: "Exile"?
else
- game.turn_log.push([block_name(game.who), to]) // TODO: "Home"?
+ game.turn_log.push([block_name(game.who), "#" + to]) // TODO: "Home"?
set_add(game.moved, game.who)
game.location[game.who] = to
game.who = NOBODY
@@ -3171,7 +3221,7 @@ states.exile_limits_pretender = {
block: function (who) {
push_undo()
let where = game.location[who]
- logp("disbanded in " + where + ".")
+ logp("disbanded in #" + where + ".")
game.exiles = game.exiles.filter(b => game.location[b] !== where)
disband(who)
},
@@ -3188,7 +3238,7 @@ function goto_king_goes_home() {
game.state = 'king_goes_home'
game.turn_log = []
let choices = false
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (block_owner(b) === game.active && is_block_on_map(b))
if (go_home_if_possible(b))
choices = true
@@ -3206,7 +3256,7 @@ states.king_goes_home = {
return view.prompt = "Waiting for the King to go home."
gen_action_undo(view)
let done = true
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === game.active && is_block_on_map(b) && !set_has(game.moved, b)) {
if (!is_in_exile(b)) {
if (!is_at_home(b)) {
@@ -3220,7 +3270,7 @@ states.king_goes_home = {
}
if (done) {
view.prompt = "King Goes Home: You may move nobles and heirs to another home."
- for (let b of BLOCKLIST) {
+ for (let b = 0; b < block_count; ++b) {
if (block_owner(b) === game.active && is_block_on_map(b) && !set_has(game.moved, b)) {
if (!is_in_exile(b)) {
if (is_at_home(b)) {
@@ -3255,13 +3305,13 @@ states.king_goes_home_to = {
return view.prompt = "Waiting for the King to go home."
view.prompt = "King Goes Home: Move " + block_name(game.who) + " to home."
gen_action(view, 'block', game.who)
- for (let where of AREALIST)
+ for (let where = first_area; where <= last_area; ++where)
if (where !== game.location[game.who])
if (is_available_home_for(where, game.who))
gen_action(view, 'area', where)
},
area: function (to) {
- game.turn_log.push([block_name(game.who), to]) // TODO: "Home"?
+ game.turn_log.push([block_name(game.who), "#" + to]) // TODO: "Home"?
set_add(game.moved, game.who)
game.location[game.who] = to
game.who = NOBODY
@@ -3296,7 +3346,7 @@ states.exile_limits_king = {
block: function (who) {
push_undo()
let where = game.location[who]
- logp("disbanded in " + where + ".")
+ logp("disbanded in #" + where + ".")
game.exiles = game.exiles.filter(b => game.location[b] !== where)
disband(who)
},
@@ -3309,7 +3359,7 @@ states.exile_limits_king = {
function end_political_turn() {
// Campaign reset
set_clear(game.dead)
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
game.steps[b] = block_max_steps(b)
++game.campaign
@@ -3343,11 +3393,11 @@ function make_battle_view() {
flash: game.flash
}
- battle.title = game.attacker[game.where] + " attacks " + game.where
+ battle.title = game.attacker[game.where] + " attacks " + AREAS[game.where].name
battle.title += " \u2014 round " + game.battle_round + " of 4"
function fill_cell(cell, owner, fn) {
- for (let b of BLOCKLIST)
+ for (let b = 0; b < block_count; ++b)
if (game.location[b] === game.where & block_owner(b) === owner && !set_has(game.dead, b) && fn(b))
cell.push(b)
}
@@ -3366,16 +3416,20 @@ exports.setup = function (seed, scenario, options) {
log: [],
undo: [],
+ state: null,
active: null,
+ turn: 0,
moves: 0,
who: NOBODY,
where: NOWHERE,
show_cards: false,
killed_heirs: { Lancaster: 0, York: 0 },
+ king: NOBODY,
+ pretender: NOBODY,
- location: {},
- steps: {},
+ location: [],
+ steps: [],
moved: [],
dead: [],
reserves: [],
@@ -3399,7 +3453,10 @@ exports.setup = function (seed, scenario, options) {
else
throw new Error("Unknown scenario:", scenario)
+ logbr()
log(".h1 " + scenario)
+ logbr()
+
start_campaign()
return game
}
@@ -3453,6 +3510,7 @@ exports.view = function(state, current) {
location: game.location,
steps: game.steps,
moved: game.moved,
+ dead: game.dead,
battle: null,
prompt: null,
}