diff options
-rw-r--r-- | play.js | 1 | ||||
-rw-r--r-- | rules.js | 158 |
2 files changed, 137 insertions, 22 deletions
@@ -630,6 +630,7 @@ function on_update() { action_button("rommel", "Rommel") action_button("eliminate", "Eliminate") + action_button("overrun", "Overrun") action_button("retreat", "Retreat") action_button("probe", "Probe") @@ -452,6 +452,13 @@ function has_undisrupted_axis_unit(x) { return false } +function has_disrupted_axis_unit(x) { + for (let u = first_axis_unit; u <= last_axis_unit; ++u) + if (is_unit_disrupted(u) && unit_hex(u) === x) + return true + return false +} + function has_undisrupted_allied_unit(x) { for (let u = first_allied_unit; u <= last_allied_unit; ++u) if (!is_unit_disrupted(u) && unit_hex(u) === x) @@ -459,6 +466,37 @@ function has_undisrupted_allied_unit(x) { return false } +function has_disrupted_allied_unit(x) { + for (let u = first_allied_unit; u <= last_allied_unit; ++u) + if (is_unit_disrupted(u) && unit_hex(u) === x) + return true + return false +} + +function has_unshielded_disrupted_axis_unit(x) { + let undisrupted = false + let disrupted = false + for (let u = first_axis_unit; u <= last_axis_unit; ++u) + if (unit_hex(u) === x) + if (is_unit_disrupted(u)) + disrupted = true + else + undisrupted = true + return disrupted && !undisrupted +} + +function has_unshielded_disrupted_allied_unit(x) { + let undisrupted = false + let disrupted = false + for (let u = first_allied_unit; u <= last_allied_unit; ++u) + if (unit_hex(u) === x) + if (is_unit_disrupted(u)) + disrupted = true + else + undisrupted = true + return disrupted && !undisrupted +} + function is_axis_hex(x) { let has_axis = has_axis_unit(x) let has_allied = has_allied_unit(x) @@ -507,6 +545,16 @@ function has_undisrupted_enemy_unit(x) { return has_undisrupted_allied_unit(x) } +function has_unshielded_disrupted_enemy_unit(x) { + if (game.active === ALLIED) + return has_unshielded_disrupted_axis_unit(x) + return has_unshielded_disrupted_allied_unit(x) +} + +function is_overrun_hex(x) { + return has_undisrupted_friendly_unit(x) && has_unshielded_disrupted_enemy_unit(x) +} + function is_new_battle_hex(a) { if (is_battle_hex(a)) return !set_has(game.axis_hexes, a) && !set_has(game.allied_hexes, a) @@ -1578,7 +1626,19 @@ states.move = { if (has_retreat_hex) gen_action('retreat') - gen_action('end_move') + // Overrun + let has_overrun_hex = false + for (let x of all_hexes) { + if (is_overrun_hex(x)) { + has_overrun_hex = true + break + } + } + + if (has_overrun_hex) + gen_action('overrun') + else + gen_action('end_move') } else { // Deselect @@ -1603,6 +1663,22 @@ states.move = { log_br() game.state = 'retreat_from' }, + overrun() { + let n = 0 + let where = 0 + for (let x of all_hexes) { + if (is_overrun_hex(x)) { + n ++ + where = x + } + } + if (n === 1) { + goto_overrun(where) + } else { + push_undo() + game.state = 'overrun' + } + }, end_move() { clear_undo() log_br() @@ -1610,6 +1686,24 @@ states.move = { } } +states.overrun = { + prompt() { + view.prompt = `Overrun!` + for (let x of all_hexes) + if (is_overrun_hex(x)) + gen_action_hex(x) + }, + hex(where) { + goto_overrun(where) + }, +} + +function goto_overrun(where) { + // return to move state afterwards + game.state = 'move' + goto_rout(where, true) +} + function gen_move(search_fn) { let rommel1 = (game.rommel === 1) ? 1 : 0 let rommel2 = (game.rommel === 2) ? 1 : 0 @@ -1942,7 +2036,7 @@ states.refuse_battle_move = { view.prompt = `Refuse Battle: Withdraw units.` if (game.selected < 0) { let done = true - for_each_undisrupted_friendly_unit_in_hex(game.from1, u => { + for_each_undisrupted_friendly_unit_in_hex(game.refuse, u => { gen_action_unit(u) done = false }) @@ -1951,9 +2045,9 @@ states.refuse_battle_move = { } else { let speed = unit_speed(game.selected) gen_action_unit(game.selected) - search_withdraw_retreat(game.from1, speed) + search_withdraw_retreat(game.refuse, speed) for (let to of all_hexes) - if (to != game.from1 && can_move_to(to, speed)) + if (to != game.refuse && can_move_to(to, speed)) gen_action_hex(to) } }, @@ -1969,8 +2063,8 @@ states.refuse_battle_move = { }, end_retreat() { clear_undo() - release_hex_control(game.from1) - game.from1 = 0 + release_hex_control(game.refuse) + game.refuse = 0 goto_refuse_battle() } } @@ -1982,7 +2076,7 @@ states.refuse_battle_move = { // withdraw by group move // eliminated if cannot -function goto_rout(from, side) { +function goto_rout(from, enemy) { // save old state so we can recover game.rout = { state: game.state, @@ -1991,16 +2085,17 @@ function goto_rout(from, side) { attrition: [], } - if (side !== game.active) + if (enemy) set_enemy_player() game.pursuit = from game.state = 'rout_attrition' + game.flash = "Rout attrition!" } states.rout_attrition = { prompt() { - view.prompt = "Rout: Suffer attrition!" + view.prompt = "Rout: All units lose one step of rout attrition." for_each_friendly_unit_in_hex(game.rout.from, u => { if (!set_has(game.rout.attrition, u)) gen_action_unit(u) @@ -2015,23 +2110,30 @@ states.rout_attrition = { done = false }) if (done) { - goto_pursuit_fire_during_rout() delete game.rout.attrition + goto_rout_fire(game.rout.from) } }, } +function goto_rout_move() { + if (has_friendly_unit(game.rout.from)) + game.state = 'rout_move' + else + end_rout() +} + states.rout_move = { prompt() { view.prompt = `Rout: Withdraw units.` if (game.selected < 0) { let done = true - for_each_friendly_unit_in_hex(game.from1, u => { + for_each_friendly_unit_in_hex(game.rout.from, u => { gen_action_unit(u) done = false }) if (done) - gen_action('end_retreat') + gen_action('end_rout') } else { let speed = unit_speed(game.selected) let eliminate = true @@ -2063,14 +2165,20 @@ states.rout_move = { set_unit_disrupted(who) }, end_rout() { - clear_undo() - game.state = game.rout.state - if (game.active !== game.rout.active) - set_active_enemy() - delete game.rout + end_rout() } } +function end_rout() { + clear_undo() + game.state = game.rout.state + release_hex_control(game.rout.from) + set_delete(game.active_battles, game.rout.from) + if (game.active !== game.rout.active) + set_enemy_player() + delete game.rout +} + // ==== COMBAT PHASE === function goto_combat_phase() { @@ -2469,6 +2577,7 @@ states.probe_hits = { function goto_rout_fire(where) { clear_undo() + set_enemy_player() game.hits = 0 game.pursuit = where if (can_rout_fire(true)) @@ -2690,12 +2799,12 @@ states.rout_hits = { }, next() { clear_undo() - end_pursuit_fire() + end_rout_fire() }, } function end_pursuit_fire() { - game.from1 = game.pursuit + game.flash = "" game.pursuit = 0 if (game.retreat) { game.state = 'retreat_move' @@ -2705,9 +2814,9 @@ function end_pursuit_fire() { } function end_rout_fire() { - game.from1 = game.pursuit + game.flash = "" game.pursuit = 0 - game.state = 'rout_move' + goto_rout_move() } // === DEPLOYMENT === @@ -3293,6 +3402,12 @@ exports.setup = function (seed, scenario, options) { retreat: 0, retreat_units: null, + // refuse battle + refuse: 0, + + // rout + rout: null, + // combat active_battles: [], assault_battles: [], @@ -3327,7 +3442,6 @@ exports.view = function(state, current) { // allied_supply_line: game.allied_supply_line, } - if (game.rommel) view.rommel = game.rommel if (game.from1) view.from1 = game.from1 if (game.from2) view.from2 = game.from2 if (game.to1) view.to1 = game.to1 |