summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js366
1 files changed, 210 insertions, 156 deletions
diff --git a/rules.js b/rules.js
index 09f5a11..70891a4 100644
--- a/rules.js
+++ b/rules.js
@@ -7,6 +7,11 @@ exports.scenarios = [
"Historical"
];
+exports.roles = [
+ "American",
+ "British",
+];
+
const CARDS = require('./cards');
const DATA = require('./data');
const SPACES = DATA.SPACES;
@@ -63,34 +68,82 @@ let states = {};
let events = {};
let game;
+let view;
function random(n) {
- return Math.floor(((game.seed = game.seed * 48271 % 0x7fffffff) / 0x7fffffff) * n);
+ return (game.seed = game.seed * 200105 % 34359738337) % n
+}
+
+function logbr() {
+ if (game.log.length > 0 && game.log[game.log.length-1] !== "")
+ game.log.push("");
}
function log(s) {
game.log.push(s);
}
+function logp(s) {
+ game.log.push(game.active[0] + " " + s);
+}
+
+function object_copy(original) {
+ if (Array.isArray(original)) {
+ let n = original.length
+ let copy = new Array(n)
+ for (let i = 0; i < n; ++i) {
+ let v = original[i]
+ if (typeof v === "object" && v !== null)
+ copy[i] = object_copy(v)
+ else
+ copy[i] = v
+ }
+ return copy
+ } else {
+ let copy = {}
+ for (let i in original) {
+ let v = original[i]
+ if (typeof v === "object" && v !== null)
+ copy[i] = object_copy(v)
+ else
+ copy[i] = v
+ }
+ return copy
+ }
+}
+
function clear_undo() {
- game.undo = [];
+ if (game.undo) {
+ game.undo.length = 0
+ }
}
function push_undo() {
- game.undo.push(JSON.stringify(game, (k,v) => {
- if (k === 'undo') return undefined;
- if (k === 'log') return v.length;
- return v;
- }));
+ if (game.undo) {
+ let copy = {}
+ for (let k in game) {
+ let v = game[k]
+ if (k === "undo")
+ continue
+ else if (k === "log")
+ v = v.length
+ else if (typeof v === "object" && v !== null)
+ v = object_copy(v)
+ copy[k] = v
+ }
+ game.undo.push(copy)
+ }
}
function pop_undo() {
- let undo = game.undo;
- let save_log = game.log;
- Object.assign(game, JSON.parse(undo.pop()));
- game.undo = undo;
- save_log.length = game.log;
- game.log = save_log;
+ if (game.undo) {
+ let save_log = game.log
+ let save_undo = game.undo
+ game = save_undo.pop()
+ save_log.length = game.log
+ game.log = save_log
+ game.undo = save_undo
+ }
}
function remove_from_array(array, item) {
@@ -199,7 +252,7 @@ function create_deck() {
}
function reshuffle_deck() {
- game.log.push("The deck is reshuffled.");
+ log("Reshuffled the deck.");
game.reshuffle = false;
game.deck = game.deck.concat(game.discard);
game.discard = [];
@@ -230,9 +283,9 @@ function active_hand() {
function play_card(c, reason) {
if (reason)
- game.log.push(game.active[0] + " plays [" + c + ": " + CARDS[c].title + "] " + reason);
+ log(game.active[0] + " played #" + c + " " + reason);
else
- game.log.push(game.active[0] + " plays [" + c + ": " + CARDS[c].title + "]");
+ log(game.active[0] + " played #" + c);
if (CARDS[c].reshuffle == 'if_played')
game.reshuffle = true;
remove_from_array(active_hand(), c);
@@ -240,7 +293,7 @@ function play_card(c, reason) {
if (!CARDS[c].once)
game.discard.push(c);
else
- game.log.push("Card " + c + " removed from game.");
+ log("Removed card " + c + ".");
}
function discard_card_from_hand(hand, c) {
@@ -248,16 +301,16 @@ function discard_card_from_hand(hand, c) {
game.discard.push(c);
if (CARDS[c].reshuffle == 'if_discarded')
game.reshuffle = true;
- game.log.push(game.active[0] + " discards [" + c + ": " + CARDS[c].title + "]");
+ logp("discarded #" + c);
}
function discard_card(c, reason) {
game.last_played = c;
discard_card_from_hand(active_hand(), c);
if (reason)
- game.log.push(game.active[0] + " discards [" + c + ": " + CARDS[c].title + "] " + reason);
+ logp("discarded #" + c + " " + reason);
else
- game.log.push(game.active[0] + " discards [" + c + ": " + CARDS[c].title + "]");
+ logp("discarded #" + c);
}
function can_exchange_for_discard(c) {
@@ -392,30 +445,30 @@ function is_adjacent_to_american_pc(a) {
}
function place_british_pc(space) {
- game.log.push("B places PC in " + space);
+ logp("placed PC in " + space);
if (game.british_pc_space_list)
remove_from_array(game.british_pc_space_list, space);
game.pc[space] = BRITISH;
}
function place_american_pc(space) {
- game.log.push("A places PC in " + space);
+ logp("placed PC in " + space);
game.pc[space] = AMERICAN;
}
function remove_pc(space) {
if (game.active == BRITISH)
- game.log.push("B removes PC in " + space);
+ logp("removed PC in " + space);
else
- game.log.push("A removes PC in " + space);
+ logp("removed PC in " + space);
game.pc[space] = undefined;
}
function flip_pc(space) {
if (game.active == BRITISH)
- game.log.push("B flips PC in " + space);
+ logp("flipped PC in " + space);
else
- game.log.push("A flips PC in " + space);
+ logp("flipped PC in " + space);
game.pc[space] = ENEMY[game.pc[space]];
}
@@ -693,13 +746,13 @@ function capture_washington() {
function capture_british_general(where) {
let g = find_british_general(where);
- game.log.push(g + " is captured!");
+ log(g + " was captured!");
move_general(g, CAPTURED_GENERALS);
}
function capture_american_or_french_general(where) {
let g = find_american_or_french_general(where);
- game.log.push(g + " is captured!");
+ log(g + " was captured!");
if (g == WASHINGTON)
capture_washington();
else
@@ -715,7 +768,7 @@ function capture_enemy_general(where) {
function remove_benedict_arnold() {
if (game.generals[ARNOLD].location) {
- game.log.push("Arnold is removed from the game!");
+ log("Removed Arnold from the game!");
game.generals[ARNOLD].location = null;
}
}
@@ -756,11 +809,11 @@ function place_british_reinforcements(who, count, where) {
move_general(already_there, BRITISH_REINFORCEMENTS);
}
if (who) {
- game.log.push("B reinforces " + where + " with " + who);
+ logp("reinforced " + where + " with " + who);
move_general(who, where);
}
if (count > 0) {
- game.log.push("B reinforces " + where + " with " + count + " CU");
+ logp("reinforced " + where + " with " + count + " CU");
move_british_cu(BRITISH_REINFORCEMENTS, where, count);
}
}
@@ -775,10 +828,10 @@ function place_american_reinforcements(who, count, where) {
move_general(already_there, AMERICAN_REINFORCEMENTS);
}
if (who) {
- game.log.push("A reinforces " + where + " with " + who);
+ logp("reinforced " + where + " with " + who);
move_general(who, where);
}
- game.log.push("A reinforces " + where + " with " + count + " CU");
+ logp("reinforced " + where + " with " + count + " CU");
place_american_cu(where, count);
}
@@ -792,10 +845,10 @@ function place_french_reinforcements(who, where) {
move_general(already_there, AMERICAN_REINFORCEMENTS);
}
if (who) {
- game.log.push("A reinforces " + where + " with " + who);
+ logp("reinforced " + where + " with " + who);
move_general(who, where);
}
- game.log.push("A reinforces " + where + " with the French CU");
+ logp("reinforced " + where + " with the French CU");
move_cu(FRENCH, FRENCH_REINFORCEMENTS, where, count_french_cu(FRENCH_REINFORCEMENTS));
move_cu(FRENCH, AMERICAN_REINFORCEMENTS, where, count_french_cu(AMERICAN_REINFORCEMENTS));
}
@@ -848,7 +901,7 @@ function intercept_army(who, from, to) {
}
function overrun(where) {
- game.log.push(game.active[0] + " overruns CU in " + where);
+ logp("overran CU in " + where);
let cu;
if (game.active == BRITISH)
cu = find_american_cu(where) || find_french_cu(where);
@@ -889,7 +942,7 @@ function surrender_british_army(where) {
}
function disperse_continental_congress(where) {
- game.log.push("Contintental Congress dispersed!");
+ log("Contintental Congress dispersed!");
game.congress = CONTINENTAL_CONGRESS_DISPERSED;
game.congress_was_dispersed = true;
}
@@ -897,25 +950,25 @@ function disperse_continental_congress(where) {
/* MOVE GENERATORS */
function gen_action(action, argument) {
- if (!game.actions)
- game.actions = {}
+ if (!view.actions)
+ view.actions = {}
if (argument != undefined) {
- if (!(action in game.actions))
- game.actions[action] = [ argument ];
+ if (!(action in view.actions))
+ view.actions[action] = [ argument ];
else
- game.actions[action].push(argument);
+ view.actions[action].push(argument);
} else {
- game.actions[action] = 1;
+ view.actions[action] = 1;
}
}
function gen_action_undo() {
- if (!game.actions)
- game.actions = {}
+ if (!view.actions)
+ view.actions = {}
if (game.undo && game.undo.length > 0)
- game.actions.undo = 1;
+ view.actions.undo = 1;
else
- game.actions.undo = 0;
+ view.actions.undo = 0;
}
function gen_pass() {
@@ -1003,15 +1056,16 @@ function gen_place_american_pc_in(list_of_colonies) {
function goto_committees_of_correspondence() {
log(".h2.american Committes of Correspondence");
- log("");
+ logbr();
game.active = AMERICAN;
game.state = 'committees_of_correspondence';
game.coc = THE_13_COLONIES.slice();
}
states.committees_of_correspondence = {
+ inactive: "Committees of Correspondence",
prompt: function (current) {
- game.prompt = "Committees of Correspondence: Place 1 PC marker in each of the 13 colonies. " + game.coc.length + " left.";
+ view.prompt = "Committees of Correspondence: Place 1 PC marker in each of the 13 colonies. " + game.coc.length + " left.";
if (game.coc.length > 0)
gen_place_american_pc_in(game.coc);
else
@@ -1030,9 +1084,9 @@ states.committees_of_correspondence = {
}
function goto_for_the_king() {
- log("");
+ logbr();
log(".h2.british For the King");
- log("");
+ logbr();
delete game.coc;
game.active = BRITISH;
game.state = 'for_the_king';
@@ -1041,8 +1095,9 @@ function goto_for_the_king() {
}
states.for_the_king = {
+ inactive: "For the King",
prompt: function (current) {
- game.prompt = "For the King: Place 3 PC markers. " + game.count + " left.";
+ view.prompt = "For the King: Place 3 PC markers. " + game.count + " left.";
if (game.count > 0)
gen_british_pc_ops();
else
@@ -1075,7 +1130,7 @@ function automatic_victory() {
game.active = "None";
game.result = BRITISH;
game.state = 'game_over';
- game.log.push(game.victory);
+ log(game.victory);
return true;
}
if (n_british == 0) {
@@ -1083,16 +1138,16 @@ function automatic_victory() {
game.active = "None";
game.result = AMERICAN;
game.state = 'game_over';
- game.log.push(game.victory);
+ log(game.victory);
return true;
}
return false;
}
function goto_start_year() {
- log("");
+ logbr();
log(".h1 Year " + game.year);
- log("");
+ logbr();
// Prisoner exchange
for (let g of BRITISH_GENERALS)
@@ -1142,7 +1197,7 @@ function goto_start_year() {
states.british_declare_first = {
prompt: function (current) {
- game.prompt = "Declare yourself as the first player by playing a campaign card?";
+ view.prompt = "Declare yourself as the first player by playing a campaign card?";
gen_pass();
for (let c of CAMPAIGN_CARDS) {
if (game.b_hand.includes(c)) {
@@ -1152,7 +1207,7 @@ states.british_declare_first = {
},
card_campaign: function (c) {
delete game.congress_was_dispersed;
- game.log.push("B goes first by playing a campaign card");
+ logp("went first by playing a campaign card");
game.active = BRITISH;
goto_campaign(c);
},
@@ -1168,16 +1223,16 @@ states.british_declare_first = {
states.choose_first_player = {
prompt: function (current) {
- game.prompt = "Choose who will play the first strategy card.";
+ view.prompt = "Choose who will play the first strategy card.";
gen_action('american_first');
gen_action('british_first');
},
american_first: function (c) {
- game.log.push("A goes first");
+ logp("went first");
goto_strategy_phase(AMERICAN);
},
british_first: function (c) {
- game.log.push("B goes first");
+ logp("went first");
goto_strategy_phase(BRITISH);
},
}
@@ -1187,17 +1242,18 @@ states.choose_first_player = {
function goto_strategy_phase(new_active) {
game.active = new_active;
game.state = 'strategy_phase';
- log("");
+ logbr();
if (game.active === AMERICAN)
log(".h2.american American Turn");
else
log(".h2.british British Turn");
- log("");
+ logbr();
}
states.strategy_phase = {
+ inactive: "strategy phase",
prompt: function (current) {
- game.prompt = "Play a strategy card.";
+ view.prompt = "Play a strategy card.";
gen_strategy_plays(active_hand());
},
card_campaign: function (c) {
@@ -1250,7 +1306,7 @@ states.strategy_phase = {
let d = game.discard.pop();
discard_card(c);
active_hand().push(d);
- game.log.push(game.active[0] + " picks up " + d + ": " + CARDS[d].title);
+ logp("picked up up #" + d);
},
}
@@ -1272,7 +1328,7 @@ function end_strategy_card() {
}
if (!game.french_alliance_triggered && game.french_alliance == 9) {
- game.log.push("The French sign an alliance with the Americans!");
+ log("The French signed an alliance with the Americans!");
game.french_alliance_triggered = true;
if (game.french_navy == FRENCH_REINFORCEMENTS) {
game.save_active = game.active;
@@ -1350,7 +1406,7 @@ function gen_strategy_plays(hand) {
states.discard_event_pc_action = {
prompt: function (current) {
- game.prompt = "Place, flip, or remove PC marker.";
+ view.prompt = "Place, flip, or remove PC marker.";
gen_pass();
if (game.active == BRITISH)
gen_british_discard_event_pc_action();
@@ -1419,7 +1475,7 @@ function goto_ops_pc(count) {
states.ops_pc = {
prompt: function (current) {
- game.prompt = "Place or flip PC markers. " + game.count + " left.";
+ view.prompt = "Place or flip PC markers. " + game.count + " left.";
gen_pass();
if (game.count > 0) {
if (game.active == BRITISH)
@@ -1507,8 +1563,8 @@ function goto_ops_reinforcements(c) {
states.ops_british_reinforcements_who = {
prompt: function (current) {
- game.prompt = "Reinforcements: choose an available general or pass to bring only CU."
- game.prompt += " Carrying " + game.count + " British CU.";
+ view.prompt = "Reinforcements: choose an available general or pass to bring only CU."
+ view.prompt += " Carrying " + game.count + " British CU.";
gen_pass();
gen_british_reinforcements_who();
},
@@ -1532,8 +1588,8 @@ states.ops_british_reinforcements_who = {
states.ops_british_reinforcements_where = {
prompt: function (current) {
- game.prompt = "Reinforcements: choose a port space.";
- game.prompt += " Carrying " + game.count + " British CU.";
+ view.prompt = "Reinforcements: choose a port space.";
+ view.prompt += " Carrying " + game.count + " British CU.";
gen_british_reinforcements_where();
},
drop_british_cu: function () {
@@ -1551,7 +1607,7 @@ states.ops_british_reinforcements_where = {
states.ops_american_reinforcements_who = {
prompt: function (current) {
- game.prompt = "Reinforcements: choose an available general or pass to bring only CU.";
+ view.prompt = "Reinforcements: choose an available general or pass to bring only CU.";
gen_pass();
gen_american_reinforcements_who();
},
@@ -1569,7 +1625,7 @@ states.ops_american_reinforcements_who = {
states.ops_american_reinforcements_where = {
prompt: function (current) {
- game.prompt = "Reinforcements: choose a space.";
+ view.prompt = "Reinforcements: choose a space.";
gen_american_reinforcements_where(game.who);
},
place_reinforcements: function (space) {
@@ -1646,11 +1702,11 @@ function goto_ops_general(c) {
states.ops_general_who = {
prompt: function (current) {
if (game.campaign && game.landing_party)
- game.prompt = "Campaign: Activate a general or use a landing party. " + game.campaign + " left.";
+ view.prompt = "Campaign: Activate a general or use a landing party. " + game.campaign + " left.";
else if (game.campaign)
- game.prompt = "Campaign: Activate a general. " + game.campaign + " left.";
+ view.prompt = "Campaign: Activate a general. " + game.campaign + " left.";
else
- game.prompt = "Activate a general with strategy rating " + game.count + " or lower.";
+ view.prompt = "Activate a general with strategy rating " + game.count + " or lower.";
if (game.landing_party)
gen_landing_party();
gen_activate_general();
@@ -1714,7 +1770,7 @@ function goto_remove_general(where) {
states.remove_general = {
prompt: function (current) {
- game.prompt = "Remove a general to the reinforcements box.";
+ view.prompt = "Remove a general to the reinforcements box.";
gen_remove_general();
},
select_general: function (g) {
@@ -1732,7 +1788,7 @@ function goto_remove_general_after_intercept() {
states.remove_general_after_intercept = {
prompt: function (current) {
- game.prompt = "Remove a general to the reinforcements box.";
+ view.prompt = "Remove a general to the reinforcements box.";
gen_remove_general();
},
select_general: function (g) {
@@ -1751,7 +1807,7 @@ function goto_remove_general_after_retreat(where) {
states.remove_general_after_retreat = {
prompt: function (current) {
- game.prompt = "Remove a general to the reinforcements box.";
+ view.prompt = "Remove a general to the reinforcements box.";
gen_remove_general();
},
select_general: function (g) {
@@ -1807,27 +1863,27 @@ function goto_ops_general_move(g, marblehead) {
states.ops_general_move = {
prompt: function (current) {
- game.prompt = "Move " + game.who + " with ";
+ view.prompt = "Move " + game.who + " with ";
if (game.carry_british > 0) {
- game.prompt += game.carry_british + " British CU.";
+ view.prompt += game.carry_british + " British CU.";
} else if (game.carry_french + game.carry_american > 0) {
if (game.carry_french > 0) {
if (game.carry_american > 0) {
- game.prompt += game.carry_french + " French CU and ";
- game.prompt += game.carry_american + " American CU.";
+ view.prompt += game.carry_french + " French CU and ";
+ view.prompt += game.carry_american + " American CU.";
} else {
- game.prompt += game.carry_french + " French CU.";
+ view.prompt += game.carry_french + " French CU.";
}
} else {
- game.prompt += game.carry_american + " American CU.";
+ view.prompt += game.carry_american + " American CU.";
}
} else {
- game.prompt += game.carry_american + " no CU.";
+ view.prompt += game.carry_american + " no CU.";
}
if (game.count == 1)
- game.prompt += " " + game.count + " move left.";
+ view.prompt += " " + game.count + " move left.";
else if (game.count > 1)
- game.prompt += " " + game.count + " moves left.";
+ view.prompt += " " + game.count + " moves left.";
// Cannot stop on enemy general
if (!has_enemy_general(location_of_general(game.who)))
@@ -1946,16 +2002,15 @@ function goto_intercept(from, where) {
states.intercept = {
prompt: function (current) {
- game.prompt = "Intercept " + game.save_who + " in " + game.where + "?";
+ view.prompt = "Intercept " + game.save_who + " in " + game.where + "?";
gen_pass();
gen_intercept();
},
select_general: function (g) {
- // TODO: roll for intercept!
game.moved[g] = 1;
let die = roll_d6();
if (die <= GENERALS[g].agility) {
- game.log.push(g + " intercepts (" + die + " <= " + GENERALS[g].agility + ")");
+ log(g + " intercepted (" + die + " <= " + GENERALS[g].agility + ")");
game.did_intercept = 1;
let save_carry_british = game.carry_british;
@@ -1974,7 +2029,7 @@ states.intercept = {
else
end_intercept();
} else {
- game.log.push(g + " fails to intercept (" + die + " > " + GENERALS[g].agility + ")");
+ log(g + " failed to intercept (" + die + " > " + GENERALS[g].agility + ")");
if (!can_intercept_to(game.where))
end_intercept();
}
@@ -2103,8 +2158,8 @@ function goto_campaign(c) {
/* EVENTS */
events.the_war_ends = function (c, card) {
- game.log.push(game.active[0] + " plays " + c + ": " + CARDS[c].title);
- game.log.push("The war will end in " + card.year);
+ logp("played #" + c);
+ log("The war will end in " + card.year);
game.last_played = c;
remove_from_array(active_hand(), c);
if (game.war_ends)
@@ -2140,13 +2195,13 @@ function advance_french_alliance(count) {
game.french_alliance += count;
if (game.french_alliance > 9)
game.french_alliance = 9;
- game.log.push("French alliance advances to " + count);
+ log("French alliance advanced to " + count);
}
}
function lose_regular_advantage() {
if (game.regulars) {
- game.log.push("The British Regulars Advantage is lost!");
+ log("British Regulars Advantage lost!");
game.regulars = false;
advance_french_alliance(2);
}
@@ -2156,7 +2211,7 @@ events.baron_von_steuben_trains_the_continental_army = function (c, card) {
play_card(c);
if (is_general_on_map(WASHINGTON)) {
let where = location_of_general(WASHINGTON);
- game.log.push("A places 2 CU with Washington in " + where);
+ logp("placed 2 CU with Washington in " + where);
place_american_cu(where, 2);
lose_regular_advantage();
}
@@ -2184,7 +2239,7 @@ events.remove_british_pc_from = function (c, card) {
states.remove_british_pc_from = {
prompt: function (current) {
- game.prompt = "Remove British PC markers from " + game.where.join(", ") + ". " + game.count + " left.";
+ view.prompt = "Remove British PC markers from " + game.where.join(", ") + ". " + game.count + " left.";
gen_pass();
gen_remove_british_pc_from(game.where);
},
@@ -2209,7 +2264,7 @@ events.remove_american_pc = function (c, card) {
states.remove_american_pc = {
prompt: function (current) {
- game.prompt = "Remove American PC markers. " + game.count + " left.";
+ view.prompt = "Remove American PC markers. " + game.count + " left.";
gen_pass();
gen_remove_american_pc();
},
@@ -2233,7 +2288,7 @@ events.remove_american_pc_from = function (c, card) {
states.remove_american_pc_from = {
prompt: function (current) {
- game.prompt = "Remove American PC markers from " + game.where.join(", ") + ". " + game.count + " left.";
+ view.prompt = "Remove American PC markers from " + game.where.join(", ") + ". " + game.count + " left.";
gen_pass();
gen_remove_american_pc_from(game.where);
},
@@ -2259,7 +2314,7 @@ events.remove_american_pc_from_non_port = function (c, card) {
states.remove_american_pc_from_non_port = {
prompt: function (current) {
- game.prompt = "Remove American PC markers from non-Port space in " + game.where.join(", ") + ". " + game.count + " left.";
+ view.prompt = "Remove American PC markers from non-Port space in " + game.where.join(", ") + ". " + game.count + " left.";
gen_pass();
gen_remove_american_pc_from_non_port(game.where);
},
@@ -2284,7 +2339,7 @@ events.remove_american_pc_within_two_spaces_of_a_british_general = function (c,
states.remove_american_pc_within_two_spaces_of_a_british_general = {
prompt: function (current) {
- game.prompt = "Remove American PC markers within two spaces of a British general. " + game.count + " left.";
+ view.prompt = "Remove American PC markers within two spaces of a British general. " + game.count + " left.";
gen_pass();
gen_remove_american_pc_within_two_spaces_of_a_british_general();
},
@@ -2309,7 +2364,7 @@ events.place_american_pc = function (c, card) {
states.place_american_pc = {
prompt: function (current) {
- game.prompt = "Place American PC markers. " + game.count + " left.";
+ view.prompt = "Place American PC markers. " + game.count + " left.";
gen_pass();
gen_place_american_pc();
},
@@ -2333,7 +2388,7 @@ events.place_american_pc_in = function (c, card) {
states.place_american_pc_in = {
prompt: function (current) {
- game.prompt = "Place American PC markers in " + game.where.join(", ") + ". " + game.count + " left.";
+ view.prompt = "Place American PC markers in " + game.where.join(", ") + ". " + game.count + " left.";
gen_pass();
gen_place_american_pc_in(game.where);
},
@@ -2359,7 +2414,7 @@ events.lord_sandwich_coastal_raids = function (c, card) {
states.lord_sandwich_coastal_raids = {
prompt: function (current) {
- game.prompt = "Remove two or flip one American PC in a port space.";
+ view.prompt = "Remove two or flip one American PC in a port space.";
gen_pass();
gen_lord_sandwich_coastal_raids(game.where);
},
@@ -2395,7 +2450,7 @@ events.remove_american_cu = function (c, card) {
states.remove_american_cu = {
prompt: function (current) {
- game.prompt = "Remove one American CU from any space.";
+ view.prompt = "Remove one American CU from any space.";
gen_pass();
gen_remove_american_cu();
},
@@ -2433,7 +2488,7 @@ events.pennsylvania_and_new_jersey_line_mutinies = function (c, card) {
states.pennsylvania_and_new_jersey_line_mutinies = {
prompt: function (current) {
- game.prompt = "Remove two American CUs from the map, one each from two different spaces.";
+ view.prompt = "Remove two American CUs from the map, one each from two different spaces.";
gen_pass();
gen_pennsylvania_and_new_jersey_line_mutinies(game.where);
},
@@ -2465,7 +2520,7 @@ events.john_glovers_marblehead_regiment = function (c, card) {
states.john_glovers_marblehead_regiment_who = {
prompt: function (current) {
- game.prompt = "Activate an American general.";
+ view.prompt = "Activate an American general.";
gen_activate_general();
},
select_general: function (g) {
@@ -2483,8 +2538,8 @@ events.declaration_of_independence = function (c, card) {
states.declaration_of_independence = {
prompt: function (current) {
- game.prompt = "Declaration of Independence: Place 1 PC marker in each of the 13 colonies. ";
- game.prompt += game.doi.length + " left.";
+ view.prompt = "Declaration of Independence: Place 1 PC marker in each of the 13 colonies. ";
+ view.prompt += game.doi.length + " left.";
gen_pass();
gen_place_american_pc_in(game.doi);
},
@@ -2520,7 +2575,7 @@ function goto_george_washington_captured() {
states.george_washington_captured = {
prompt: function (current) {
- game.prompt = "George Washington is captured! Remove American PC markers. " + game.count + " left.";
+ view.prompt = "George Washington is captured! Remove American PC markers. " + game.count + " left.";
gen_pass();
gen_remove_american_pc();
},
@@ -2587,7 +2642,7 @@ function goto_retreat_before_battle() {
states.retreat_before_battle = {
prompt: function (current) {
- game.prompt = "Attempt retreat before battle?";
+ view.prompt = "Attempt retreat before battle?";
gen_pass();
gen_defender_retreat();
},
@@ -2597,12 +2652,12 @@ states.retreat_before_battle = {
agility += 2;
let roll = roll_d6();
if (roll <= agility) {
- game.log.push("A successfully retreats before battle: " + roll + " <= " + agility);
+ logp("successfully retreated before battle: " + roll + " <= " + agility);
pickup_max_american_cu(game.where);
move_army(game.who, game.where, to);
goto_remove_general_after_retreat_before_battle(to);
} else {
- game.log.push("A fails to retreat before battle: " + roll + " > " + agility);
+ logp("failed to retreat before battle: " + roll + " > " + agility);
end_retreat_before_battle();
}
},
@@ -2623,7 +2678,7 @@ function goto_remove_general_after_retreat_before_battle(to) {
states.remove_general_after_retreat_before_battle = {
prompt: function (current) {
- game.prompt = "Remove a general to the reinforcements box.";
+ view.prompt = "Remove a general to the reinforcements box.";
gen_remove_general();
},
select_general: function (g) {
@@ -2715,7 +2770,7 @@ function goto_play_attacker_battle_card() {
states.play_attacker_battle_card = {
prompt: function (current) {
- game.prompt = "Attack: Play or discard event for DRM.";
+ view.prompt = "Attack: Play or discard event for DRM.";
gen_pass();
gen_battle_card();
},
@@ -2755,7 +2810,7 @@ function goto_play_defender_battle_card() {
states.play_defender_battle_card = {
prompt: function (current) {
- game.prompt = "Defend: Play or discard event for DRM.";
+ view.prompt = "Defend: Play or discard event for DRM.";
gen_pass();
gen_battle_card();
},
@@ -3010,9 +3065,9 @@ function resolve_battle() {
capture_american_or_french_general(game.where);
}
- game.log.push("BRITISH BATTLE REPORT:\n" + b_log.join("\n"));
- game.log.push("AMERICAN BATTLE REPORT:\n" + a_log.join("\n"));
- game.log.push(victor + " victory in " + game.where + "!");
+ log("BRITISH BATTLE REPORT:\n" + b_log.join("\n"));
+ log("AMERICAN BATTLE REPORT:\n" + a_log.join("\n"));
+ log(victor + " victory in " + game.where + "!");
if (victor == AMERICAN)
advance_french_alliance(1);
@@ -3036,7 +3091,7 @@ function goto_retreat_after_battle(victor) {
states.retreat_after_battle = {
prompt: function (current) {
- game.prompt = "Retreat after battle.";
+ view.prompt = "Retreat after battle.";
gen_action('surrender');
if (game.active == game.attacker)
gen_attacker_retreat();
@@ -3044,7 +3099,7 @@ states.retreat_after_battle = {
gen_defender_retreat();
},
move: function (to) {
- game.log.push(game.active[0] + " retreats to " + to);
+ logp("retreated to " + to);
if (game.active == BRITISH)
retreat_british_army(game.where, to);
else
@@ -3060,7 +3115,7 @@ states.retreat_after_battle = {
let where = game.where;
end_battle();
- game.log.push(active[0] + " surrenders");
+ logp("surrendered");
if (active == BRITISH)
surrender_british_army(where);
else
@@ -3071,6 +3126,9 @@ states.retreat_after_battle = {
function end_battle() {
game.active = game.attacker;
+ if (game.active == BRITISH && game.congress == game.where)
+ disperse_continental_congress(game.where);
+
if (game.british_losses >= 3)
lose_regular_advantage();
@@ -3097,22 +3155,22 @@ function end_battle() {
function apply_single_winter_attrition(owner, space) {
let die = roll_d6();
- game.log.push(owner[0] + " attrition roll " + die + " in " + space);
+ log(owner[0] + " attrition roll " + die + " in " + space);
if (die <= 3) {
- game.log.push(owner[0] + " lose 1 CU in " + space);
+ log(owner[0] + " lost 1 CU in " + space);
remove_cu(owner, space, 1);
}
}
function apply_winter_attrition(owner, space, n) {
let half = Math.floor(n / 2);
- game.log.push(owner[0] + " lose " + half + " CU in " + space);
+ log(owner[0] + " lost " + half + " CU in " + space);
remove_cu(owner, space, half);
}
function goto_winter_attrition_phase() {
- game.log.push("");
- game.log.push("Winter Attrition");
+ logbr();
+ log("Winter Attrition");
for (let space in SPACES) {
let wq = is_winter_quarter_space(space);
@@ -3148,13 +3206,13 @@ function goto_winter_attrition_phase() {
// TODO: let player choose (but why would he ever choose the french?)
let lose_american = Math.min(half, n_american);
- game.log.push(owner[0] + " lose " + lose_american + " American CU in " + space);
+ log(owner[0] + " lost " + lose_american + " American CU in " + space);
remove_cu(AMERICAN, space, n_american);
half -= lose_american;
n_american -= lose_american;
if (half > 0) {
- game.log.push(owner[0] + " lose " + half + " French CU in " + space);
+ log(owner[0] + " lost " + half + " French CU in " + space);
remove_cu(FRENCH, space, half);
}
}
@@ -3187,11 +3245,11 @@ function gen_place_french_navy() {
states.place_french_navy_trigger = {
prompt: function (current) {
- game.prompt = "Place the French Navy in a blockade zone.";
+ view.prompt = "Place the French Navy in a blockade zone.";
gen_place_french_navy();
},
place_navy: function (zone) {
- game.log.push("A places French Navy.");
+ logp("placed French Navy.");
game.french_navy = zone;
game.active = game.save_active;
delete game.save_active;
@@ -3201,11 +3259,11 @@ states.place_french_navy_trigger = {
states.place_french_navy = {
prompt: function (current) {
- game.prompt = "Place the French Navy in a blockade zone.";
+ view.prompt = "Place the French Navy in a blockade zone.";
gen_place_french_navy();
},
place_navy: function (zone) {
- game.log.push("A places French Navy.");
+ logp("placed French Navy.");
game.french_navy = zone;
goto_political_control_phase();
},
@@ -3289,7 +3347,7 @@ function spread_british_path(seen, from) {
}
function remove_isolated_american_pc_segment() {
- game.log.push("Removing isolated American PC");
+ log("Removed isolated American PC");
let seen = {};
for (let space in SPACES) {
if (is_american_pc_root(space)) {
@@ -3303,7 +3361,7 @@ function remove_isolated_american_pc_segment() {
}
function remove_isolated_british_pc_segment() {
- game.log.push("Removing isolated British PC");
+ log("Removed isolated British PC");
let seen = {};
for (let space in SPACES) {
if (is_british_pc_root(space)) {
@@ -3340,7 +3398,7 @@ function goto_political_control_phase() {
states.return_continental_congress = {
prompt: function () {
- game.prompt = "Return Continental Congress to a space in the 13 colonies.";
+ view.prompt = "Return Continental Congress to a space in the 13 colonies.";
if (gen_place_continental_congress() == 0)
gen_pass();
},
@@ -3362,7 +3420,7 @@ function goto_political_control_phase_2() {
states.european_war = {
prompt: function () {
- game.prompt = "European War: Remove 2 British CU from any spaces. " + game.count + " left.";
+ view.prompt = "European War: Remove 2 British CU from any spaces. " + game.count + " left.";
gen_pass();
gen_remove_british_cu();
},
@@ -3394,7 +3452,7 @@ function norths_government_falls() {
game.active = "None";
game.state = 'game_over';
- game.log.push(game.victory);
+ log(game.victory);
}
function goto_end_phase() {
@@ -3418,17 +3476,13 @@ function goto_end_phase() {
states.game_over = {
prompt: function () {
- game.prompt = game.victory;
+ view.prompt = game.victory;
}
}
/* CLIENT/SERVER COMMS */
-exports.ready = function (scenario, options, players) {
- return players.length === 2;
-}
-
-exports.setup = function (seed, scenario, players) {
+exports.setup = function (seed, scenario, options) {
setup_game(seed);
return game;
}
@@ -3447,23 +3501,21 @@ exports.action = function (state, current, action, arg) {
throw new Error("Invalid action: " + action);
}
}
+
+ update_colony_control();
+
return game;
}
function list_actions(current) {
- game.actions = {}
- game.prompt = "";
+ view.actions = {}
states[game.state].prompt(current);
}
exports.view = function(state, current) {
game = state;
- list_actions(current);
-
- update_colony_control();
-
- let view = {
+ view = {
active: state.active,
year: state.year,
war_ends: state.war_ends,
@@ -3498,11 +3550,13 @@ exports.view = function(state, current) {
view.hand = [];
if (current == state.active) {
+ list_actions(current);
gen_action_undo();
- view.prompt = state.prompt;
- view.actions = state.actions;
} else {
- view.prompt = "Waiting for " + game.active + " player \u2014 " + game.prompt;
+ let inactive = states[game.state].inactive;
+ if (typeof inactive !== 'string')
+ inactive = game.state;
+ view.prompt = "Waiting for " + game.active + " player \u2014 " + inactive + ".";
}
return view;