summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rules.js143
1 files changed, 110 insertions, 33 deletions
diff --git a/rules.js b/rules.js
index a6c7f06..cb9afff 100644
--- a/rules.js
+++ b/rules.js
@@ -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()
}
}