diff options
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 304 |
1 files changed, 162 insertions, 142 deletions
@@ -7,6 +7,11 @@ exports.scenarios = [ "Historical" ]; +exports.roles = [ + "American", + "British", +]; + const CARDS = require('./cards'); const DATA = require('./data'); const SPACES = DATA.SPACES; @@ -63,15 +68,25 @@ 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 * 69621 % 0x7fffffff) / 0x7fffffff) * n | 0; +} + +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 clear_undo() { game.undo = []; } @@ -85,10 +100,10 @@ function push_undo() { } function pop_undo() { - let undo = game.undo; + let save_undo = game.undo; let save_log = game.log; - game = JSON.parse(undo.pop()); - game.undo = undo; + game = JSON.parse(save_undo.pop()); + game.undo = save_undo; save_log.length = game.log; game.log = save_log; } @@ -199,7 +214,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 +245,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 +255,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 +263,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 +407,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 +708,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 +730,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 +771,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 +790,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 +807,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 +863,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 +904,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 +912,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 +1018,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 +1046,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 +1057,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 +1092,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 +1100,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 +1159,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 +1169,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 +1185,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 +1204,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 +1268,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 +1290,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 +1368,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 +1437,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 +1525,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 +1550,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 +1569,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 +1587,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 +1664,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 +1732,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 +1750,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 +1769,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 +1825,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 +1964,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 +1991,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 +2120,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 +2157,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 +2173,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 +2201,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 +2226,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 +2250,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 +2276,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 +2301,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 +2326,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 +2350,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 +2376,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 +2412,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 +2450,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 +2482,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 +2500,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 +2537,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 +2604,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 +2614,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 +2640,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 +2732,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 +2772,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 +3027,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 +3053,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 +3061,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 +3077,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 +3088,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 +3117,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 +3168,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 +3207,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 +3221,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 +3309,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 +3323,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 +3360,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 +3382,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 +3414,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,7 +3438,7 @@ function goto_end_phase() { states.game_over = { prompt: function () { - game.prompt = game.victory; + view.prompt = game.victory; } } @@ -3447,23 +3467,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 +3516,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; |