diff options
-rw-r--r-- | play.css | 9 | ||||
-rw-r--r-- | play.js | 45 | ||||
-rw-r--r-- | rules.js | 455 |
3 files changed, 319 insertions, 190 deletions
@@ -15,13 +15,21 @@ body.America header.your_turn { background-color: hsl(211, 50%, 75%) } #turn_info { background-color: hsl(35, 25%, 50%); } #log .h { border-top: 1px solid black; border-bottom: 1px solid black; text-align: center; margin: 6px 0; } +#log .h { background-color: hsl(35, 45%, 82%); } #log .h.turn { background-color: hsl(35, 45%, 70%); } #log .h.britain { background-color: hsl(15, 90%, 80%) } #log .h.america { background-color: hsl(211, 50%, 80%) } +#log .n { margin: 6px 0; } +#log .m { margin-top: 6px; } + #log .tip { cursor: pointer; } #log .tip:hover { text-decoration: underline; } +#log div { padding-left: 20px; text-indent: -12px; } +#log div.i { padding-left: 32px; text-indent: -12px; } +#log div.ii { padding-left: 44px; text-indent: -12px; } + #tooltip { display: none; pointer-events: none; @@ -132,6 +140,7 @@ body.America header.your_turn { background-color: hsl(211, 50%, 75%) } background-image: url(bang.svg); background-size: contain; background-repeat: no-repeat; + opacity: 75%; z-index: 2000; } @@ -4,6 +4,8 @@ global view, data, roles, send_action, action_button */ +// TODO: show "reshuffle" flag next to card deck display + /* COMMON */ function set_has(set, item) { @@ -294,8 +296,8 @@ function lerp(a, b, t) { } function show_combat_marker() { - let x = Math.round(lerp(data.spaces[view.move.from].x, data.spaces[view.move.to].x, 0.75)) - let y = Math.round(lerp(data.spaces[view.move.from].y, data.spaces[view.move.to].y, 0.75)) + let x = Math.round(lerp(data.spaces[view.move.from].x, data.spaces[view.move.to].x, 0.67)) + let y = Math.round(lerp(data.spaces[view.move.from].y, data.spaces[view.move.to].y, 0.67)) ui.combat.style.left = x - 20 + "px" ui.combat.style.top = y - 20 + "px" ui.pieces_element.appendChild(ui.combat) @@ -383,8 +385,8 @@ function get_army_xy_lerp(s1, s2) { y = data.spaces[s1].y + (dy * 1/2) | 0 } - if (Math.abs(dx) < 180 && Math.abs(dy) < 60) - y -= 20 + if (Math.abs(dx) < 180 && Math.abs(dy) < 60) y -= 20 + if (Math.abs(dx) < 180 && Math.abs(dy) < 40) y -= 20 return [ x - 15, y ] } @@ -550,7 +552,9 @@ function on_update() { continue let [ x, y ] = (s < 66) ? ui.layout_static[s] : get_static_xy(s) - if (s >= 66) + if (s === 68) + y -= 20 + else if (s >= 66) y -= 60 if (view.move && view.move.who === g) @@ -797,11 +801,14 @@ function on_blur_card_tip() { function on_log(text) { let p = document.createElement("div") - text = text.replace(/&/g, "&") - text = text.replace(/</g, "<") - text = text.replace(/>/g, ">") - if (text.startsWith("=t")) { + if (text.startsWith(">>")) { + p.className = "ii" + text = text.substring(2) + } else if (text.startsWith(">")) { + p.className = "i" + text = text.substring(1) + } else if (text.startsWith("=t")) { p.className = "h turn" text = text.substring(2) } else if (text.startsWith("=a")) { @@ -810,8 +817,28 @@ function on_log(text) { } else if (text.startsWith("=b")) { p.className = "h britain" text = text.substring(3) + } else if (text.startsWith("=!")) { + p.className = "h" + text = text.substring(3) } + if ( + text.startsWith("Played ") || + text.startsWith("Discarded ") || + text.startsWith("Exchanged ") || + text.startsWith("Retreated ") || + text.startsWith("Surrendered ") || + text === "Removed card." + ) + p.className = "n" + + if (text.startsWith("Moved G")) + p.className = "m" + + text = text.replace(/&/g, "&") + text = text.replace(/</g, "<") + text = text.replace(/>/g, ">") + text = text.replace(/C(\d+)/g, sub_card) text = text.replace(/S(\d+)/g, sub_space) text = text.replace(/G(\d+)/g, sub_general) @@ -279,13 +279,10 @@ function active_hand() { return game.active === P_AMERICA ? game.a_hand : game.b_hand } -function play_card(c, reason) { - if (reason) - log("Played C" + c + " " + reason + ".") - else - log("Played C" + c + " for Event.") - if (CARDS[c].reshuffle === "if_played") +function play_card(c) { + if (CARDS[c].reshuffle === "if_played") { set_flag(F_RESHUFFLE) + } set_delete(active_hand(), c) if (CARDS[c].once) { log("Removed card.") @@ -299,11 +296,7 @@ function discard_card_from_hand(hand, c) { set_flag(F_RESHUFFLE) } -function discard_card(c, reason) { - if (reason) - log("Discarded C" + c + " " + reason + ".") - else - log("Discarded C" + c + ".") +function discard_card(c) { discard_card_from_hand(active_hand(), c) } @@ -793,13 +786,13 @@ function capture_washington() { function capture_british_general(where) { let g = find_british_general(where) - log(general_name(g) + " captured!") + log("Captured G" + g + ".") move_general(g, CAPTURED_GENERALS) } function capture_american_or_french_general(where) { let g = find_american_or_french_general(where) - log(general_name(g) + " captured!") + log("Captured G" + g + ".") if (g === WASHINGTON) capture_washington() else @@ -843,65 +836,6 @@ function has_no_american_unit(where) { return true } -function place_british_reinforcements(who, count, where) { - let already_there = find_british_general(where) - if (who !== NOBODY && already_there !== NOBODY) { - move_general(already_there, BRITISH_REINFORCEMENTS) - } - if (who !== NOBODY) { - log(`${count} CU and G${who} at S${where}.`) - move_general(who, where) - } else { - log(`${count} CU at S${where}.`) - } - if (count > 0) { - move_british_cu(BRITISH_REINFORCEMENTS, where, count) - if (has_enemy_general(where)) - capture_enemy_general(where) - if (game.congress === where) - disperse_continental_congress() - } -} - -function place_american_reinforcements(who, count, where) { - let already_there = find_american_or_french_general(where) - if (who !== NOBODY && already_there !== NOBODY) { - // Never replace Washington - if (already_there === WASHINGTON) - who = NOBODY - else - move_general(already_there, AMERICAN_REINFORCEMENTS) - } - if (who !== NOBODY) { - log(`${count} CU and G${who} at S${where}.`) - move_general(who, where) - } else { - log(`${count} CU at S${where}.`) - } - place_american_cu(where, count) - if (has_enemy_general(where)) - capture_enemy_general(where) -} - -function place_french_reinforcements(who, where) { - let already_there = find_american_or_french_general(where) - if (who !== NOBODY && already_there !== NOBODY) { - // Never replace Washington - if (already_there === WASHINGTON) - who = NOBODY - else - move_general(already_there, AMERICAN_REINFORCEMENTS) - } - if (who !== NOBODY) { - log(`${count} CU and G${who} at S${where}.`) - move_general(who, where) - } else { - log(`${count} CU at S${where}.`) - } - move_french_cu(FRENCH_REINFORCEMENTS, where, count_french_cu(FRENCH_REINFORCEMENTS)) - move_french_cu(AMERICAN_REINFORCEMENTS, where, count_french_cu(AMERICAN_REINFORCEMENTS)) -} - function pickup_max_british_cu(move) { move.carry_british = count_unmoved_british_cu(move.from) if (move.carry_british > 5) @@ -931,7 +865,7 @@ function move_army(army) { } function overrun(where) { - logp("overran CU in " + where) + log("Overrun.") if (game.active === P_BRITAIN) { if (count_american_cu(where) > 0) remove_american_cu(where, 1) @@ -942,19 +876,35 @@ function overrun(where) { } } +function log_retreat(g, cu, to) { + if (g !== NOBODY) { + if (cu > 0) + log("Retreated G" + g + " with " + cu + " CU to S" + to + ".") + else + log("Retreated G" + g + " to S" + to + ".") + } else { + log("Retreated " + cu + " CU to S" + to + ".") + } +} + function retreat_american_army(from, to) { let g = find_american_or_french_general(from) if (g !== NOBODY) move_general(g, to) - move_american_cu(from, to, count_american_cu(from)) - move_french_cu(from, to, count_french_cu(from)) + let a_cu = count_american_cu(from) + let f_cu = count_french_cu(from) + move_american_cu(from, to, a_cu) + move_french_cu(from, to, f_cu) + log_retreat(g, a_cu + f_cu, to) } function retreat_british_army(from, to) { let g = find_british_general(from) if (g !== NOBODY) move_general(g, to) - move_british_cu(from, to, count_british_cu(from)) + let b_cu = count_british_cu(from) + move_british_cu(from, to, b_cu) + log_retreat(g, b_cu, to) } function surrender_american_army(where) { @@ -974,7 +924,7 @@ function surrender_british_army(where) { } function disperse_continental_congress() { - log("Contintental Congress dispersed!") + log("Dispersed Contintental Congress.") game.congress = CONTINENTAL_CONGRESS_DISPERSED set_flag(F_CONGRESS_WAS_DISPERSED) } @@ -988,13 +938,26 @@ function gen_place_american_pc_in_colony(list_of_colonies) { gen_action_space(space) } +function filter_place_american_pc_in_colony(list_of_colonies) { + let result = [] + for (let colony of list_of_colonies) { + for (let space of COLONIES[colony]) { + if (has_no_pc(space) && has_no_british_playing_piece(space)) { + result.push(colony) + break + } + } + } + return result +} + /* SETUP PHASE */ function goto_committees_of_correspondence() { log("=a Committes of Correspondence") game.active = P_AMERICA game.state = "committees_of_correspondence" - game.colonies = THE_13_COLONIES.slice() + game.colonies = filter_place_american_pc_in_colony(THE_13_COLONIES) } states.committees_of_correspondence = { @@ -1062,7 +1025,7 @@ function goto_start_year() { log("=t Year " + game.year) // Prisoner exchange - // TODO: manual? + // TODO: manual reinforcements phase? for (let g of BRITISH_GENERALS) if (is_general_at_location(g, CAPTURED_GENERALS)) move_general(g, BRITISH_REINFORCEMENTS) @@ -1180,6 +1143,15 @@ states.choose_first_player = { function goto_strategy_phase(new_active) { game.active = new_active game.state = "strategy_phase" + + let hand = active_hand() + if (hand.length === 0) { + game.active = ENEMY[game.active] + hand = active_hand() + if (hand.length === 0) + return goto_winter_attrition_phase() + } + if (game.active === P_AMERICA) log("=a America") else @@ -1213,7 +1185,6 @@ states.strategy_phase = { push_undo() let d = game.did_discard_event set_add(active_hand(), d) - log("Picked up up C" + d) game.state = "exchange" }, } @@ -1228,8 +1199,10 @@ states.exchange = { gen_action_card("card", c) }, card(c) { + let x = game.did_discard_event + set_delete(active_hand(), c) game.did_discard_event = 0 - discard_card(c, " in exchange") + log("Exchanged C" + c + " for C" + x + ".") game.state = "strategy_phase" }, } @@ -1240,14 +1213,22 @@ states.strategy_phase_ops = { let c = game.card view.selected_card = game.card view.prompt = "Use " + card_name(c) + "." + if (can_activate_general(c)) view.actions.activate = 1 + else + view.actions.activate = 0 + if (can_play_reinforcements()) view.actions.reinforce = 1 + else + view.actions.reinforce = 0 + if (game.active === P_AMERICA && game.a_queue + CARDS[c].count < 3) view.actions.queue = 1 if (game.active === P_BRITAIN && game.b_queue + CARDS[c].count < 3) view.actions.queue = 1 + view.actions.pc_action = 1 }, @@ -1255,24 +1236,31 @@ states.strategy_phase_ops = { let c = game.card game.did_discard_event = 0 clear_queue() - play_card(c, "for PC") + log("Played C" + c + ".") + play_card(c) goto_ops_pc(CARDS[c].count) }, activate() { let c = game.card game.did_discard_event = 0 + log("Played C" + c + ".") + play_card(c) goto_ops_general(c) }, reinforce() { let c = game.card game.did_discard_event = 0 clear_queue() + log("Played C" + c + ".") + play_card(c) goto_ops_reinforcements(c) }, queue() { let c = game.card game.did_discard_event = 0 - play_card(c, "to queue") + log("Played C" + c + ".") + play_card(c) + log("Operations Queue.") if (game.active === P_BRITAIN) game.b_queue += CARDS[c].count else @@ -1336,7 +1324,8 @@ states.strategy_phase_event = { let c = game.card game.did_discard_event = c clear_queue() - discard_card(c, "for PC action") + log("Discarded C" + c + ".") + discard_card(c) game.state = "discard_event_pc_action" }, } @@ -1364,13 +1353,13 @@ function end_strategy_card() { } while (game.b_draw > 0) { - log("B drew replacement card.") + log("British replacement card.") set_add(game.b_hand, deal_card()) game.b_draw-- } while (game.a_draw > 0) { - log("A drew replacement card.") + log("American replacement card.") set_add(game.a_hand, deal_card()) game.a_draw-- } @@ -1391,6 +1380,8 @@ states.end_strategy_card = { } function next_strategy_card() { + clear_undo() + game.card = 0 if (!has_flag(F_FRENCH_ALLIANCE_TRIGGERED) && game.french_alliance === 9) { @@ -1408,14 +1399,6 @@ function next_strategy_card() { reset_moved_cu() goto_strategy_phase(ENEMY[game.active]) - - let hand = active_hand() - if (hand.length === 0) { - game.active = ENEMY[game.active] - hand = active_hand() - if (hand.length === 0) - return goto_winter_attrition_phase() - } } function clear_queue() { @@ -1577,9 +1560,67 @@ function gen_american_pc_ops() { /* PLAY OPS CARD FOR REINFORCEMENTS */ +function place_british_reinforcements(who, count, where) { + let already_there = find_british_general(where) + if (who !== NOBODY && already_there !== NOBODY) { + move_general(already_there, BRITISH_REINFORCEMENTS) + } + if (who !== NOBODY) { + log(`Reinforced ${count} CU and G${who} at S${where}.`) + move_general(who, where) + } else { + log(`Reinforced ${count} CU at S${where}.`) + } + if (count > 0) { + move_british_cu(BRITISH_REINFORCEMENTS, where, count) + if (has_enemy_general(where)) + capture_enemy_general(where) + if (game.congress === where) + disperse_continental_congress() + } +} + +function place_american_reinforcements(who, count, where) { + let already_there = find_american_or_french_general(where) + if (who !== NOBODY && already_there !== NOBODY) { + // Never replace Washington + if (already_there === WASHINGTON) + who = NOBODY + else + move_general(already_there, AMERICAN_REINFORCEMENTS) + } + if (who !== NOBODY) { + log(`Reinforced ${count} CU and G${who} at S${where}.`) + move_general(who, where) + } else { + log(`Reinforced ${count} CU at S${where}.`) + } + place_american_cu(where, count) + if (has_enemy_general(where)) + capture_enemy_general(where) +} + +function place_french_reinforcements(who, where) { + let already_there = find_american_or_french_general(where) + if (who !== NOBODY && already_there !== NOBODY) { + // Never replace Washington + if (already_there === WASHINGTON) + who = NOBODY + else + move_general(already_there, AMERICAN_REINFORCEMENTS) + } + if (who !== NOBODY) { + log(`Reinforced ${count} CU and G${who} at S${where}.`) + move_general(who, where) + } else { + log(`Reinforced ${count} CU at S${where}.`) + } + move_french_cu(FRENCH_REINFORCEMENTS, where, count_french_cu(FRENCH_REINFORCEMENTS)) + move_french_cu(AMERICAN_REINFORCEMENTS, where, count_french_cu(AMERICAN_REINFORCEMENTS)) +} + function goto_ops_reinforcements(c) { let count = CARDS[c].count - play_card(c, "for reinforcements") if (game.active === P_BRITAIN) { game.reinforcements[0] = c game.count = count_british_cu(BRITISH_REINFORCEMENTS) @@ -1736,7 +1777,6 @@ function gen_american_reinforcements_where(general) { /* PLAY OPS CARD TO MOVE A GENERAL */ function goto_ops_general(c) { - play_card(c, "to activate a general") if (game.active === P_BRITAIN) { game.count = CARDS[c].count + game.b_queue game.b_queue = 0 @@ -1951,6 +1991,14 @@ function goto_ops_general_move(g, marblehead) { pickup_max_british_cu(game.move) else pickup_max_american_cu(game.move) + + /* + let cu = game.move.carry_american + game.move.carry_french + game.move.carry_british + if (cu > 0) + log(`Moved G${g} with ${cu} CU\nfrom S${where}`) + else + */ + log(`Moved G${g}\nfrom S${where}`) } function format_move_prompt() { @@ -2006,29 +2054,40 @@ states.ops_general_move = { drop_british_cu() { push_undo() --game.move.carry_british - if (has_general_moved(game.move.who)) + if (has_general_moved(game.move.who)) { + log(">>dropped CU") mark_moved_british_cu(location_of_general(game.move.who), 1) + } }, drop_american_cu() { push_undo() --game.move.carry_american - if (has_general_moved(game.move.who)) + if (has_general_moved(game.move.who)) { + log(">>dropped CU") mark_moved_american_cu(location_of_general(game.move.who), 1) + } }, drop_french_cu() { push_undo() --game.move.carry_french - if (has_general_moved(game.move.who)) + if (has_general_moved(game.move.who)) { + log(">>dropped CU") mark_moved_french_cu(location_of_general(game.move.who), 1) + } }, space(to) { push_undo() - set_general_moved(game.move.who) let from = location_of_general(game.move.who) let cu = game.move.carry_british + game.move.carry_american + game.move.carry_french + if (!has_general_moved(game.move.who)) { + log(">>with " + cu + " CU") + } + + set_general_moved(game.move.who) + let may_intercept = false if (game.active === P_BRITAIN) { let is_sea_move = path_type(from, to) === "sea" @@ -2045,6 +2104,8 @@ states.ops_general_move = { game.move.count -= 1 } + log(">to S" + game.move.to) + move_army(game.move) if (may_intercept) @@ -2302,7 +2363,7 @@ states.intercept_roll = { let g = game.intercept.who let die = roll_d6() if (die <= GENERALS[g].agility) { - log(g + " intercepted (" + die + " <= " + GENERALS[g].agility + ")") + log("Intercept G" + g + "\nrolled " + die + " <= " + GENERALS[g].agility + "\nfrom S" + game.intercept.from) game.move.did_intercept = 1 move_army(game.intercept) @@ -2312,7 +2373,7 @@ states.intercept_roll = { else end_intercept() } else { - log(g + " failed to intercept (" + die + " > " + GENERALS[g].agility + ")") + log("Intercept G" + g + "\nrolled " + die + " > " + GENERALS[g].agility + "\nfailure") delete game.intercept if (can_intercept_to(game.move.to)) game.state = "intercept_who" @@ -2425,7 +2486,7 @@ states.retreat_before_battle_roll = { agility += 2 let roll = roll_d6() if (roll <= agility) { - logp("successfully retreated before battle: " + roll + " <= " + agility) + log("Retreat G" + who + "\nrolled " + roll + " <= " + agility + "\nto S" + to) move_army(game.retreat) if (has_enemy_general(to)) capture_enemy_general(to) @@ -2434,7 +2495,7 @@ states.retreat_before_battle_roll = { delete game.retreat goto_remove_general_after_retreat_before_battle(to) } else { - logp("failed to retreat before battle: " + roll + " > " + agility) + log("Retreat G" + who + "\nrolled " + roll + " > " + agility + "\nfailure") delete game.retreat end_retreat_before_battle() } @@ -2514,6 +2575,7 @@ states.remove_benedict_arnold_defender = { } function goto_play_attacker_battle_card() { + log("=! Battle at S" + game.move.to) game.active = game.combat.attacker game.state = "play_attacker_battle_card" } @@ -2529,7 +2591,8 @@ states.play_attacker_battle_card = { }, card_battle_play(c) { push_undo() - play_card(c, "for +2 DRM") + log(`${game.active} played C${c} for +2 DRM.`) + play_card(c) if (game.active === P_BRITAIN) { game.b_draw += 1 game.combat.b_bonus += 2 @@ -2544,7 +2607,8 @@ states.play_attacker_battle_card = { }, card_battle_discard(c) { push_undo() - discard_card(c, "for +1 DRM") + log(`${game.active} discarded C${c} for +1 DRM.`) + discard_card(c) if (game.active === P_BRITAIN) { game.b_draw += 1 game.combat.b_bonus += 1 @@ -2579,6 +2643,8 @@ states.play_attacker_battle_card_confirm = { function goto_play_defender_battle_card() { game.state = "play_defender_battle_card" game.active = ENEMY[game.combat.attacker] + if (active_hand().length === 0) + resolve_battle() } states.play_defender_battle_card = { @@ -2593,7 +2659,8 @@ states.play_defender_battle_card = { }, card_battle_play(c) { push_undo() - play_card(c, "for +2 DRM") + log(`${game.active} played C${c} for +2 DRM.`) + play_card(c) if (game.active === P_BRITAIN) { game.b_draw += 1 game.combat.b_bonus += 2 @@ -2608,7 +2675,8 @@ states.play_defender_battle_card = { }, card_battle_discard(c) { push_undo() - discard_card(c, "for +1 DRM") + log(`${game.active} discarded C${c} for +1 DRM.`) + discard_card(c) if (game.active === P_BRITAIN) { game.b_draw += 1 game.combat.b_bonus += 1 @@ -2775,9 +2843,9 @@ function resolve_battle() { let a_br = 0 if (b_g !== NOBODY) - b_log.push("General: " + b_g) + b_log.push("General: G" + b_g) if (a_g !== NOBODY) - a_log.push("General: " + a_g) + a_log.push("General: G" + a_g) if (b_g !== NOBODY) { let roll = roll_d6() @@ -2853,6 +2921,17 @@ function resolve_battle() { a_log.push("Battle Roll: " + a_roll) a_log.push("Battle Total: " + (a_roll + a_drm)) + if (game.combat.attacker === P_BRITAIN) { + log("BRITISH ATTACK:\n" + b_log.join("\n")) + log("AMERICAN DEFENSE:\n" + a_log.join("\n")) + } else { + log("AMERICAN ATTACK:\n" + a_log.join("\n")) + log("BRITISH DEFENSE:\n" + b_log.join("\n")) + } + + a_log = [] + b_log = [] + let victor if (game.active === P_BRITAIN) victor = b_roll + b_drm >= a_roll + a_drm ? P_BRITAIN : P_AMERICA @@ -2876,16 +2955,23 @@ function resolve_battle() { // Special case: winning general with no CU on enemy PC is captured if (victor === P_BRITAIN) { + log("RESULT:\nBritish victory!") if (b_g && count_british_cu(game.move.to) === 0 && has_american_pc(game.move.to)) capture_british_general(game.move.to) } else { + log("RESULT:\nAmerican victory!") if (a_g && count_american_and_french_cu(game.move.to) === 0 && has_british_pc(game.move.to)) capture_american_or_french_general(game.move.to) } - log("BRITISH BATTLE REPORT:\n" + b_log.join("\n")) - log("AMERICAN BATTLE REPORT:\n" + a_log.join("\n")) - log(victor + " victory in " + game.move.to + "!") + + if (game.combat.attacker === P_BRITAIN) { + log("BRITISH LOSSES:\n" + b_log.join("\n")) + log("AMERICAN LOSSES:\n" + a_log.join("\n")) + } else { + log("AMERICAN LOSSES:\n" + a_log.join("\n")) + log("BRITISH LOSSES:\n" + b_log.join("\n")) + } if (victor === P_AMERICA) advance_french_alliance(1) @@ -2996,7 +3082,7 @@ states.retreat_after_battle = { }, space(to) { push_undo() - logp("retreated to " + to) + if (game.active === P_BRITAIN) retreat_british_army(game.move.to, to) else @@ -3017,7 +3103,7 @@ states.retreat_after_battle = { game.state = "retreat_after_battle_confirm" }, surrender() { - logp("surrendered") + log("Surrendered.") if (game.active === P_BRITAIN) surrender_british_army(game.move.to) else @@ -3056,7 +3142,6 @@ function end_battle() { /* EVENTS */ events.campaign = function (c, card) { - play_card(c) game.state = "campaign" game.campaign = card.count if (game.active === P_BRITAIN) @@ -3068,20 +3153,16 @@ events.campaign = function (c, card) { } events.the_war_ends = function (c, card) { - log("Played C" + c) - log("The war will end in " + card.year) set_delete(active_hand(), c) game.war_ends = c end_strategy_card() } events.remove_random_british_card = function (c, card) { - play_card(c) remove_random_card(game.b_hand) } events.remove_random_american_card = function (c, card) { - play_card(c) remove_random_card(game.a_hand) } @@ -3090,7 +3171,7 @@ function remove_random_card(hand) { if (hand.length > 0) { let i = random(hand.length) let c = hand[i] - log("Discarded C" + c + ".") + log("Opponent discarded C" + c + ".") discard_card_from_hand(hand, c) if (CARDS[c].type === "mandatory-event") do_event(c) @@ -3105,7 +3186,7 @@ function advance_french_alliance(count) { game.french_alliance += count if (game.french_alliance > 9) game.french_alliance = 9 - log("French alliance advanced to " + count) + log("French Alliance advanced to " + count + ".") } } @@ -3118,7 +3199,6 @@ function lose_regular_advantage() { } events.baron_von_steuben_trains_the_continental_army = function (c, card) { - play_card(c) if (is_general_on_map(WASHINGTON)) game.state = "baron_von_steuben_trains_the_continental_army" else @@ -3133,7 +3213,7 @@ states.baron_von_steuben_trains_the_continental_army = { }, general(_) { let where = location_of_general(WASHINGTON) - logp("placed 2 CU with Washington in " + where) + log("Placed 2 CU and Washington at S" + where + ".") place_american_cu(where, 2) lose_regular_advantage() end_strategy_card() @@ -3141,7 +3221,6 @@ states.baron_von_steuben_trains_the_continental_army = { } events.advance_french_alliance = function (c, card) { - play_card(c) // TODO: advance alliance manual? // game.state = "advance_french_alliance" advance_french_alliance(card.count) @@ -3149,14 +3228,12 @@ events.advance_french_alliance = function (c, card) { } events.remove_french_navy = function (c, card) { - play_card(c) // TODO: remove french navy manual? game.french_navy = game.year + 1 end_strategy_card() } events.remove_british_pc_from = function (c, card) { - play_card(c) game.count = card.count game.where = card.where game.state = "remove_british_pc_from" @@ -3187,7 +3264,6 @@ states.remove_british_pc_from = { } events.remove_american_pc = function (c, card) { - play_card(c) game.count = card.count game.state = "remove_american_pc" } @@ -3214,7 +3290,6 @@ states.remove_american_pc = { } events.remove_american_pc_from = function (c, card) { - play_card(c) game.count = card.count game.where = card.where game.state = "remove_american_pc_from" @@ -3245,7 +3320,6 @@ states.remove_american_pc_from = { } events.remove_american_pc_from_non_port = function (c, card) { - play_card(c) game.count = card.count game.where = card.where game.state = "remove_american_pc_from_non_port" @@ -3281,7 +3355,6 @@ states.remove_american_pc_from_non_port = { } events.remove_american_pc_within_two_spaces_of_a_british_general = function (c, card) { - play_card(c) game.count = card.count game.state = "remove_american_pc_within_two_spaces_of_a_british_general" } @@ -3327,7 +3400,6 @@ states.remove_american_pc_within_two_spaces_of_a_british_general = { } events.place_american_pc = function (c, card) { - play_card(c) game.count = card.count game.state = "place_american_pc" } @@ -3353,16 +3425,13 @@ states.place_american_pc = { } events.place_american_pc_in = function (c, card) { - play_card(c) - game.count = card.count - game.where = card.where + game.where = filter_place_american_pc_in_colony(card.where) game.state = "place_american_pc_in" } states.place_american_pc_in = { prompt() { view.prompt = "Place American PC markers in " + game.where.join(", ") + ". " + game.count + " left." - view.actions.pass = 1 gen_place_american_pc_in_colony(game.where) }, space(where) { @@ -3372,14 +3441,9 @@ states.place_american_pc_in = { end_strategy_card() } }, - pass() { - delete game.where - end_strategy_card() - }, } events.lord_sandwich_coastal_raids = function (c, card) { - play_card(c) game.state = "lord_sandwich_coastal_raids" game.count = 2 delete game.where @@ -3418,7 +3482,6 @@ function gen_lord_sandwich_coastal_raids(first_removed) { } events.remove_american_cu = function (c, card) { - play_card(c) game.state = "remove_american_cu" } @@ -3443,7 +3506,6 @@ states.remove_american_cu = { } events.remove_british_cu = function (c, card) { - play_card(c) game.state = "remove_british_cu" game.count = card.count } @@ -3467,7 +3529,6 @@ states.remove_british_cu = { } events.pennsylvania_and_new_jersey_line_mutinies = function (c, card) { - play_card(c) set_flag(F_MUTINIES) game.state = "pennsylvania_and_new_jersey_line_mutinies" game.count = 2 @@ -3503,7 +3564,6 @@ function gen_pennsylvania_and_new_jersey_line_mutinies(first_removed) { } events.john_glovers_marblehead_regiment = function (c, card) { - play_card(c) game.state = "john_glovers_marblehead_regiment_who" game.count = 3 // strategy rating for gen_activate_general } @@ -3519,18 +3579,24 @@ states.john_glovers_marblehead_regiment_who = { } events.declaration_of_independence = function (c, card) { - play_card(c) game.save = game.active game.active = P_AMERICA - game.colonies = THE_13_COLONIES.slice() game.state = "declaration_of_independence" + game.colonies = filter_place_american_pc_in_colony(THE_13_COLONIES) } states.declaration_of_independence = { prompt() { - view.prompt = "Declaration of Independence: Place 1 PC marker in each of the 13 colonies. " - view.prompt += game.colonies.length + " left." - view.actions.pass = 1 + if (game.colonies.length > 0) { + view.prompt = "Declaration of Independence: Place a PC marker in " + if (game.colonies.length <= 3) + view.prompt += game.colonies.map(colony_name).join(" and ") + "." + else + view.prompt += "each of the 13 colonies." + } else { + view.prompt = "Declaration of Independence: Done." + view.actions.next = 1 + } gen_place_american_pc_in_colony(game.colonies) }, space(space) { @@ -3538,24 +3604,25 @@ states.declaration_of_independence = { let colony = SPACES[space].colony set_delete(game.colonies, colony) place_american_pc(space) - if (game.colonies.length === 0) - end_declaration_of_independence() }, - pass() { - push_undo() + next() { + clear_undo() end_declaration_of_independence() - }, + } } function end_declaration_of_independence() { game.active = game.save delete game.save delete game.colonies - end_strategy_card() + if (end_strategy_card()) + next_strategy_card() } function do_event(c) { let card = CARDS[c] + log("Played C" + c + ".") + play_card(c) if (card.event in events) events[card.event](c, card) else @@ -3656,16 +3723,18 @@ states.george_washington_captured_during_move = { function apply_single_winter_attrition(remove_cu, space) { let die = roll_d6() - log("Attrition roll " + die + " in " + space) + log("Roll " + die + " at S" + space) if (die <= 3) { - log("Lost 1 CU in " + space) + log(">Lost 1 CU") remove_cu(space, 1) + } else { + log(">Lost 0 CU") } } function apply_winter_attrition(remove_cu, space, n) { let half = Math.floor(n / 2) - log("Lost " + half + " CU in " + space) + log("Lost " + half + " CU at S" + space + ".") remove_cu(space, half) } @@ -3701,16 +3770,17 @@ function has_american_winter_attrition(s) { } function goto_american_winter_attrition() { - log("=a Winter Attrition") game.active = P_AMERICA game.attrition = [] for (let s of all_spaces) if (has_american_winter_attrition(s)) game.attrition.push(s) - if (game.attrition.length > 0) + if (game.attrition.length > 0) { + log("=a Winter Attrition") game.state = "american_winter_attrition" - else + } else { end_american_winter_attrition() + } } function end_american_winter_attrition() { @@ -3719,7 +3789,6 @@ function end_american_winter_attrition() { } function goto_british_winter_attrition() { - log("=b Winter Attrition") game.active = P_BRITAIN game.attrition = [] for (let space of all_spaces) { @@ -3728,10 +3797,12 @@ function goto_british_winter_attrition() { if (n_british > 0 && !wq) game.attrition.push(space) } - if (game.attrition.length > 0) + if (game.attrition.length > 0) { + log("=b Winter Attrition") game.state = "british_winter_attrition" - else + } else { end_british_winter_attrition() + } } function end_british_winter_attrition() { @@ -3787,11 +3858,11 @@ states.american_winter_attrition = { // TODO: let player choose (but why would they ever choose French?) let half = Math.floor(n_total / 2) let lose_american = Math.min(half, n_american) - log("Lost " + lose_american + " American CU in " + s) + log(lose_american + " American CU at " + s) remove_american_cu(s, n_american) half -= lose_american if (half > 0) { - log("Lost " + half + " French CU in " + s) + log(half + " French CU at " + s) remove_french_cu(s, half) } } @@ -3846,6 +3917,16 @@ function gen_place_french_navy() { view.actions.sea = [ 0, 1, 2, 3, 4, 5, 6 ] } +const ZONE_NAME = [ + "Canada", + "MA/RI", + "CT/NY", + "PA/DE", + "MD/VA", + "NC/SC", + "GA", +] + states.place_french_navy_trigger = { prompt() { view.prompt = "Place the French Navy in a blockade zone." @@ -3853,7 +3934,7 @@ states.place_french_navy_trigger = { }, sea(zone) { push_undo() - logp("placed French Navy.") + log("French Navy at " + ZONE_NAME[zone] + ".") game.french_navy = zone goto_place_rochambeau() }, @@ -3888,7 +3969,7 @@ states.place_rochambeau = { }, space(to) { push_undo() - logp("placed Rochambeau .") + log("Placed 5 CU and Rochambeau at S" + to + ".") move_general(ROCHAMBEAU, to) move_french_cu(FRENCH_REINFORCEMENTS, to, 5) if (count_friendly_generals(to) > 1) @@ -3939,7 +4020,7 @@ states.place_french_navy = { gen_place_french_navy() }, sea(zone) { - logp("placed French Navy.") + log("French Navy at " + ZONE_NAME[zone] + ".") game.french_navy = zone goto_political_control_phase() }, @@ -3948,9 +4029,9 @@ states.place_french_navy = { /* POLITICAL CONTROL PHASE: RETURN CONGRESS */ function goto_political_control_phase() { - log("# Political Control Phase") + game.active = P_AMERICA if (game.congress === CONTINENTAL_CONGRESS_DISPERSED) { - game.active = P_AMERICA + log("=a Continental Congress") game.state = "return_continental_congress" } else { goto_place_pc_markers_segment() @@ -3978,11 +4059,12 @@ states.return_continental_congress = { }, space(where) { push_undo() + log("Returned Continental Congress to S" + where + ".") game.congress = where - goto_place_pc_markers_segment() + goto_place_pc_markers_segment(false) }, pass() { - goto_place_pc_markers_segment() + goto_place_pc_markers_segment(false) }, } @@ -4006,6 +4088,20 @@ function has_british_place_pc_markers_segment() { function goto_place_pc_markers_segment() { if (has_american_place_pc_markers_segment()) { + log("=a Place PC Markers") + game.active = P_AMERICA + game.state = "place_american_pc_markers_segment" + } else if (has_british_place_pc_markers_segment()) { + log("=b Place PC Markers") + game.active = P_BRITAIN + game.state = "place_british_pc_markers_segment" + } else { + goto_remove_isolated_pc_marker_segment() + } +} + +function resume_place_pc_markers_segment() { + if (has_american_place_pc_markers_segment()) { game.active = P_AMERICA game.state = "place_american_pc_markers_segment" } else if (has_british_place_pc_markers_segment()) { @@ -4042,7 +4138,7 @@ states.place_american_pc_markers_segment = { flip_pc(s) }, next() { - goto_place_pc_markers_segment() + resume_place_pc_markers_segment() }, } @@ -4072,7 +4168,7 @@ states.place_british_pc_markers_segment = { flip_pc(s) }, next() { - goto_place_pc_markers_segment() + resume_place_pc_markers_segment() }, } @@ -4160,6 +4256,7 @@ function goto_remove_isolated_american_pc_segment() { set_add(game.isolated, space) if (game.isolated.length > 0) { + log("=a Remove Isolated PC Markers") game.active = P_AMERICA game.state = "remove_isolated_pc_segment" } else { @@ -4182,6 +4279,7 @@ function goto_remove_isolated_british_pc_segment() { set_add(game.isolated, space) if (game.isolated.length > 0) { + log("=b Remove Isolated PC Markers") game.active = P_BRITAIN game.state = "remove_isolated_pc_segment" } else { @@ -4201,7 +4299,6 @@ states.remove_isolated_pc_segment = { } }, space(s) { - log("Removed American PC from " + s) set_delete(game.isolated, s) remove_pc(s) }, @@ -4424,10 +4521,6 @@ function log(s) { game.log.push(s) } -function logp(s) { - game.log.push(game.active + " " + s) -} - function log_br() { if (game.log.length > 0 && game.log[game.log.length - 1] !== "") game.log.push("") |