diff options
-rw-r--r-- | rules.js | 143 |
1 files changed, 110 insertions, 33 deletions
@@ -60,6 +60,7 @@ const min = Math.min const abs = Math.abs var states = {} +var after_rout = {} var game = null var view = null @@ -555,6 +556,14 @@ function is_overrun_hex(x) { return has_undisrupted_friendly_unit(x) && has_unshielded_disrupted_enemy_unit(x) } +function is_enemy_rout_hex(x) { + return has_undisrupted_friendly_unit(x) && has_unshielded_disrupted_enemy_unit(x) +} + +function is_friendly_rout_hex(x) { + return has_undisrupted_enemy_unit(x) && has_unshielded_disrupted_friendly_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) @@ -690,6 +699,15 @@ function count_battle_hexes() { return n } +function has_friendly_units_in_battle() { + let result = false + for_each_undisrupted_friendly_unit_in_hex(game.battle, u => { + if (!is_unit_retreating(u)) + result = true + }) + return result +} + function count_normal_steps_in_battle() { let steps = [ 0, 0, 0, 0 ] for_each_undisrupted_enemy_unit_in_hex(game.battle, u => { @@ -1694,14 +1712,15 @@ states.overrun = { gen_action_hex(x) }, hex(where) { + // return to move state afterwards + game.state = 'move' goto_overrun(where) }, } function goto_overrun(where) { - // return to move state afterwards - game.state = 'move' - goto_rout(where, true) + log_h3(`Overrun at #${where}`) + goto_rout(where, true, null) } function gen_move(search_fn) { @@ -1952,7 +1971,17 @@ function end_probe() { function goto_retreat_move() { set_active_player() - game.state = 'retreat_move' + let done = true + for (let u of game.retreat_units) { + if (unit_hex(u) === game.retreat) { + done = false + break + } + } + if (done) + end_retreat() + else + game.state = 'retreat_move' } states.retreat_move = { @@ -1987,17 +2016,37 @@ states.retreat_move = { set_unit_disrupted(who) }, end_retreat() { - clear_undo() - if (!is_battle_hex(game.retreat)) - release_hex_control(game.retreat) - game.retreat_units = null - if (can_select_retreat_hex()) - game.state = 'retreat_from' - else - end_move_phase() + end_retreat() } } +function end_retreat() { + clear_undo() + if (!is_battle_hex(game.retreat)) + release_hex_control(game.retreat) + game.retreat_units = null + + // no shielding units remain + if (is_friendly_rout_hex(game.retreat)) + goto_rout(game.retreat, false, "end_retreat_2") + + // rear-guard eliminated all enemy units + else if (is_enemy_rout_hex(game.retreat)) + goto_rout(game.retreat, true, "end_retreat_2") + + else + end_retreat_2() +} + +function end_retreat_2() { + if (can_select_retreat_hex()) + game.state = 'retreat_from' + else + end_move_phase() +} + +after_rout.end_retreat_2 = end_retreat_2 + // === REFUSE BATTLE === function goto_refuse_battle() { @@ -2022,6 +2071,7 @@ states.refuse_battle = { hex(x) { push_undo() log_h3(`Refused battle at #${x}`) + game.refuse = x set_delete(game.active_battles, x) goto_pursuit_fire_during_refuse_battle(x) }, @@ -2030,6 +2080,14 @@ states.refuse_battle = { } } +function goto_refuse_battle_move() { + set_passive_player() + if (has_undisrupted_friendly_unit(game.refuse)) + game.state = 'refuse_battle_move' + else + end_refuse_battle_move() +} + states.refuse_battle_move = { inactive: "refuse battle (withdraw group move)", prompt() { @@ -2062,13 +2120,26 @@ states.refuse_battle_move = { set_unit_disrupted(who) }, end_retreat() { - clear_undo() - release_hex_control(game.refuse) - game.refuse = 0 - goto_refuse_battle() + end_refuse_battle_move() } } +function end_refuse_battle_move() { + clear_undo() + if (is_friendly_rout_hex(game.refuse)) + goto_rout(game.refuse, false, "end_refuse_battle_move_2") + else + end_refuse_battle_move_2() +} + +function end_refuse_battle_move_2() { + release_hex_control(game.refuse) + game.refuse = 0 + goto_refuse_battle() +} + +after_rout.end_refuse_battle_move_2 = end_refuse_battle_move_2 + // === ROUT === // rout attrition @@ -2076,11 +2147,12 @@ states.refuse_battle_move = { // withdraw by group move // eliminated if cannot -function goto_rout(from, enemy) { - // save old state so we can recover +function goto_rout(from, enemy, after) { + // remember current state so we can resume after routing game.rout = { state: game.state, active: game.active, + after: after, from: from, attrition: [], } @@ -2176,7 +2248,10 @@ function end_rout() { set_delete(game.active_battles, game.rout.from) if (game.active !== game.rout.active) set_enemy_player() + let after = game.rout.after delete game.rout + if (after) + after_rout[after]() } // ==== COMBAT PHASE === @@ -2333,6 +2408,8 @@ function end_battle() { end_combat_phase() } +after_rout.end_battle = end_battle + function apply_battle_fire(tc) { let who = pop_selected() @@ -2420,7 +2497,6 @@ function gen_battle_target() { function gen_battle_hits() { let normal_steps = count_normal_steps_in_battle() let elite_steps = count_elite_steps_in_battle() - let done = true for_each_undisrupted_friendly_unit_in_hex(game.battle, u => { if (!is_unit_retreating(u)) { @@ -2446,6 +2522,7 @@ function gen_battle_hits() { }) if (done) gen_action_next() + return done } function apply_battle_hit(who) { @@ -2455,9 +2532,9 @@ function apply_battle_hit(who) { states.battle_fire = { prompt() { if (game.active === game.phasing) - view.prompt = `Offensive Fire!` + view.prompt = `Battle: Offensive Fire!` else - view.prompt = `Defensive Fire!` + view.prompt = `Battle: Defensive Fire!` if (game.selected < 0) gen_battle_fire() else @@ -2483,10 +2560,9 @@ states.battle_fire = { states.battle_hits = { prompt() { if (game.active === game.phasing) - view.prompt = `Apply hits from Defensive Fire.` + view.prompt = `Battle: Apply hits from Defensive Fire.` else - view.prompt = `Apply hits from Offensive Fire.` - view.prompt = `Apply hits.` + view.prompt = `Battle: Apply hits from Offensive Fire.` gen_battle_hits() }, unit(who) { @@ -2495,7 +2571,9 @@ states.battle_hits = { }, next() { clear_undo() - if (game.active === game.phasing) { + if (is_friendly_rout_hex(game.battle)) { + goto_rout(game.battle, false, "end_battle") + } else if (game.active === game.phasing) { // goto offensive fire game.state = 'battle_fire' game.hits = [ 0, 0, 0, 0 ] @@ -2508,9 +2586,9 @@ states.battle_hits = { states.probe_fire = { prompt() { if (game.active !== game.phasing) - view.prompt = `Offensive Fire!` + view.prompt = `Probe: Offensive Fire!` else - view.prompt = `Defensive Fire!` + view.prompt = `Probe: Defensive Fire!` if (game.selected < 0) gen_battle_fire() else @@ -2536,10 +2614,9 @@ states.probe_fire = { states.probe_hits = { prompt() { if (game.active !== game.phasing) - view.prompt = `Apply hits from Defensive Fire.` + view.prompt = `Probe: Apply hits from Defensive Fire.` else - view.prompt = `Apply hits from Offensive Fire.` - view.prompt = `Apply hits.` + view.prompt = `Probe: Apply hits from Offensive Fire.` gen_battle_hits() }, unit(who) { @@ -2548,7 +2625,7 @@ states.probe_hits = { }, next() { clear_undo() - if (game.active !== game.phasing) { + if (game.active !== game.phasing && has_friendly_units_in_battle()) { // goto offensive fire game.state = 'probe_fire' game.hits = [ 0, 0, 0, 0 ] @@ -2807,9 +2884,9 @@ function end_pursuit_fire() { game.flash = "" game.pursuit = 0 if (game.retreat) { - game.state = 'retreat_move' + goto_retreat_move() } else { - game.state = 'refuse_battle_move' + goto_refuse_battle_move() } } |