diff options
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 236 |
1 files changed, 117 insertions, 119 deletions
@@ -241,6 +241,9 @@ const S25_WOFFORD = find_card(25, "Wofford") const S25_ZOOK = find_card(25, "Zook") const S25_KELLY = find_card(25, "Kelly") +const S26_PEACH_ORCHARD = find_scenario(26) +const S26_FATAL_BLUNDER = find_card(26, "Fatal Blunder") + // === SETUP === exports.setup = function (seed, scenario, options) { @@ -558,6 +561,15 @@ function is_pool_die_range(i, lo, hi) { return false } +function placed_any_dice_on_wing(w) { + for (let i = 0; i < game.placed.length; i += 2) { + let c = game.placed[i] + if (data.cards[c].wing === w) + return true + } + return false +} + const place_dice_once = { "(1)": true, "(2)": true, @@ -1064,6 +1076,7 @@ states.roll = { else view.prompt = "Roll the dice in your pool." view.actions.roll = 1 + view.actions.end_turn = 0 }, roll() { clear_undo() @@ -1141,9 +1154,7 @@ states.place_on_card = { } function end_roll_phase() { - clear_undo() - map_clear(game.placed) - game.place_max = null + push_undo() // Remove placed dice to add cube on special cards. for (let c of game.front[player_index()]) { @@ -1160,6 +1171,60 @@ function end_roll_phase() { if (get_player_dice_location(p, i) < 0) set_player_dice_value(p, i, 0) + if (game.scenario === S26_PEACH_ORCHARD) { + if (is_card_in_play(S26_FATAL_BLUNDER)) { + if (!placed_any_dice_on_wing(PINK)) { + game.state = "fatal_blunder" + return + } + } + } + + end_turn() +} + +states.fatal_blunder = { + prompt() { + view.prompt = "Fatal Blunder!" + if (is_card_in_play(S26_FATAL_BLUNDER)) { + gen_action_card(S26_FATAL_BLUNDER) + } else { + let done = true + for (let c of game.front[0]) { + if (data.cards[c].wing === PINK) { + gen_action_card(c) + done = false + } + } + if (done) + view.actions.end_turn = 1 + } + }, + card(c) { + if (c === S26_FATAL_BLUNDER) { + log("Fatal Blunder!") + eliminate_card(S26_FATAL_BLUNDER) + game.morale[0] ++ + } else { + log("C" + c + " routed.") + eliminate_card(c) + game.morale[0] -- + game.morale[1] ++ + } + }, + end_turn() { + if (check_morale_victory()) + return + end_turn() + } +} + +function end_turn() { + clear_undo() + + map_clear(game.placed) + game.place_max = null + set_opponent_active() goto_start_turn() } @@ -1413,6 +1478,7 @@ states.action = { prompt() { view.prompt = "Take an action." view.actions.roll = 1 + view.actions.end_turn = 0 let p = player_index() for (let c of game.front[p]) { @@ -2089,6 +2155,8 @@ function get_attack_hits(c, a) { case "1 hit per die. 1 self per action. (But see Sharpshooters.)": case "1 hit per die. 1 self per action. (But see 4th Alabama.)": case "1 hit per die. 1 self per action. (But see Semmes.)": + case "1 hit per die (also take dice from 141st Pennsylvania). 1 self per action.": + case "1 hit per die (also take dice from 68th Pennsylvania). 1 self per action.": return count_dice_on_card(c) case "1 hit per pair.": case "1 hit per pair. 1 self per action.": @@ -2121,6 +2189,8 @@ function get_attack_self(c, a) { case "1 hit per die. 1 self per action. (But see Sharpshooters.)": case "1 hit per die. 1 self per action. (But see 4th Alabama.)": case "1 hit per die. 1 self per action. (But see Semmes.)": + case "1 hit per die (also take dice from 141st Pennsylvania). 1 self per action.": + case "1 hit per die (also take dice from 68th Pennsylvania). 1 self per action.": case "1 hit per pair. 1 self per action.": case "1 hit, PLUS 1 hit per die. 1 self per action.": case "1 hit, PLUS 1 hit per die. 1 self per action. Fightin' Irish!": @@ -2128,7 +2198,7 @@ function get_attack_self(c, a) { } } -// === ROUTING === +// === ROUTING/PURSUIT/REMOVE/FORCE-RETIRE === function find_card_owner(c) { if (set_has(game.front[0], c) || set_has(game.reserve[0], c)) @@ -2142,15 +2212,16 @@ function should_rout_card(c) { if (!data.cards[c].special) { if (map_get(game.sticks, c, 0) === 0) return true + } - let rout_with = card_has_rule(c, "rout_with") - if (rout_with) { - for (let other of rout_with) - if (is_card_in_play(other)) - return false - return true - } + let rout_with = card_has_rule(c, "rout_with") + if (rout_with) { + for (let other of rout_with) + if (is_card_in_play(other)) + return false + return true } + return false } @@ -2215,18 +2286,51 @@ function goto_routing() { function resume_routing() { game.state = "routing" + for (let p = 0; p <= 1; ++p) { for (let c of game.front[p]) - if (should_rout_card(c)) + if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c) || should_pursue(c)) return for (let c of game.reserve[p]) - if (should_rout_card(c)) + if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c)) return } + end_routing() } +states.routing = { + prompt() { + view.prompt = "Routing: Remove routing and pursuing cards from play!" + for (let p = 0; p <= 1; ++p) { + for (let c of game.front[p]) + if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c) || should_pursue(c)) + gen_action_card(c) + for (let c of game.reserve[p]) + if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c)) + gen_action_card(c) + } + }, + card(c) { + if (should_rout_card(c)) { + log(card_name(c) + " routed.") + let p = find_card_owner(c) + game.routed[p] += data.cards[c].morale + } else if (should_retire_card(c)) { + log(card_name(c) + " retired.") + } else if (should_pursue(c)) { + log(card_name(c) + " pursued.") + } else { + log(card_name(c) + " removed.") + } + eliminate_card(c) + resume_routing() + }, +} + function end_routing() { + console.log("END ROUTING", game.routed) + // Normal morale loss and gain if (game.morale[0] > 0 && game.morale[1] > 0) { if ((game.routed[0] > 0 && !game.routed[1]) || (game.routed[1] > 0 && !game.routed[0])) { @@ -2272,115 +2376,9 @@ function end_routing() { game.routed = null - goto_pursuit() -} - -states.routing = { - prompt() { - view.prompt = "Rout cards!" - for (let p = 0; p <= 1; ++p) { - for (let c of game.front[p]) - if (should_rout_card(c)) - gen_action_card(c) - for (let c of game.reserve[p]) - if (should_rout_card(c)) - gen_action_card(c) - } - }, - card(c) { - if (should_rout_card(c)) { - log(card_name(c) + " routed.") - let p = find_card_owner(c) - game.routed[p] += data.cards[c].morale - } else if (should_retire_card(c)) { - log(card_name(c) + " retired.") - } else { - log(card_name(c) + " removed.") - } - eliminate_card(c) - resume_routing() - }, -} - -// === PURSUIT === - -function goto_pursuit() { - resume_pursuit() -} - -function resume_pursuit() { - game.state = "pursuit" - for (let p = 0; p <= 1; ++p) - for (let c of game.front[p]) - if (should_pursue(c)) - return - end_pursuit() -} - -function end_pursuit() { - goto_removing() -} - -states.pursuit = { - prompt() { - view.prompt = "Pursue cards!" - for (let p = 0; p <= 1; ++p) - for (let c of game.front[p]) - if (should_pursue(c)) - gen_action_card(c) - }, - card(c) { - log(card_name(c) + " pursued.") - eliminate_card(c) - resume_pursuit() - }, -} - -// === REMOVING === - -function goto_removing() { - resume_removing() -} - -function resume_removing() { - game.state = "removing" - for (let p = 0; p <= 1; ++p) { - for (let c of game.front[p]) - if (should_remove_card(c) || should_retire_card(c)) - return - for (let c of game.reserve[p]) - if (should_remove_card(c) || should_retire_card(c)) - return - } - end_removing() -} - -function end_removing() { goto_reserve() } -states.removing = { - prompt() { - view.prompt = "Remove or retire cards!" - for (let p = 0; p <= 1; ++p) { - for (let c of game.front[p]) - if (should_remove_card(c) || should_retire_card(c)) - gen_action_card(c) - for (let c of game.reserve[p]) - if (should_remove_card(c) || should_retire_card(c)) - gen_action_card(c) - } - }, - card(c) { - if (should_retire_card(c)) - log(card_name(c) + " retired.") - else - log(card_name(c) + " removed.") - eliminate_card(c) - resume_removing() - }, -} - // === RESERVE === function should_enter_reserve(c) { |