summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-07-14 20:29:37 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-17 13:11:25 +0100
commit107df9df212cc7d67791618e1b8c34ebbf97aeaa (patch)
tree69ae83ffe901ab01621cee4a8816aa98eedebedd /rules.js
parent397bea71ffd9f30180bf6e446740e8a5e06d3dc6 (diff)
downloadrommel-in-the-desert-107df9df212cc7d67791618e1b8c34ebbf97aeaa.tar.gz
pursuit fire
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js199
1 files changed, 163 insertions, 36 deletions
diff --git a/rules.js b/rules.js
index 4bdecee..6df7316 100644
--- a/rules.js
+++ b/rules.js
@@ -1471,11 +1471,6 @@ function stop_move(who) {
game.state = 'move_who'
}
-// === PURSUIT FIRE ===
-
-function goto_pursuit_fire() {
-}
-
// === REFUSE BATTLE ===
function gen_withdraw_group_move(who, from) {
@@ -1485,6 +1480,7 @@ function gen_withdraw_group_move(who, from) {
}
function goto_refuse_battle() {
+ clear_undo()
if (game.active_battles.length > 0) {
set_passive_player()
game.state = 'refuse_battle'
@@ -1504,13 +1500,10 @@ states.refuse_battle = {
hex(x) {
push_undo()
set_delete(game.active_battles, x)
- game.battle = x
- game.from1 = x
+ game.pursuit = x
goto_pursuit_fire(x)
- }
+ },
next() {
- clear_undo()
- set_active_player()
goto_combat_phase()
}
}
@@ -1561,6 +1554,8 @@ states.refuse_battle_to = {
// ==== COMBAT PHASE ===
function goto_combat_phase() {
+ clear_undo()
+ set_active_player()
game.state = 'select_active_battles'
}
@@ -1667,7 +1662,7 @@ const xxx_fire = {
},
}
-function count_normal_steps() {
+function count_normal_steps_in_battle() {
let steps = [ 0, 0, 0, 0 ]
for (let u = 0; u < units.length; ++u)
if (is_enemy_unit(u) && unit_hex(u) === game.battle)
@@ -1675,7 +1670,7 @@ function count_normal_steps() {
return steps
}
-function count_elite_steps() {
+function count_elite_steps_in_battle() {
let steps = [ 0, 0, 0, 0 ]
for (let u = 0; u < units.length; ++u)
if (is_enemy_unit(u) && unit_hex(u) === game.battle)
@@ -1683,7 +1678,7 @@ function count_elite_steps() {
return steps
}
-function count_hp() {
+function count_hp_in_battle() {
let hp = [ 0, 0, 0, 0 ]
for (let u = 0; u < units.length; ++u)
if (is_enemy_unit(u) && unit_hex(u) === game.battle)
@@ -1691,11 +1686,35 @@ function count_hp() {
return hp
}
+function count_normal_steps_in_pursuit() {
+ let steps = 0
+ for (let u = 0; u < units.length; ++u)
+ if (is_enemy_unit(u) && unit_hex(u) === game.pursuit)
+ steps += unit_steps(u)
+ return steps
+}
+
+function count_elite_steps_in_pursuit() {
+ let steps = 0
+ for (let u = 0; u < units.length; ++u)
+ if (is_enemy_unit(u) && unit_hex(u) === game.pursuit)
+ steps += unit_steps(u)
+ return steps
+}
+
+function count_hp_in_pursuit() {
+ let hp = 0
+ for (let u = 0; u < units.length; ++u)
+ if (is_enemy_unit(u) && unit_hex(u) === game.pursuit)
+ hp += unit_hp(u)
+ return hp
+}
+
const xxx_fire_target = {
prompt() {
view.prompt = `Select a target class.`
- let hp = count_hp()
+ let hp = count_hp_in_battle()
for (let i = 0; i < 4; ++i)
hp[i] -= game.hits[i]
@@ -1760,32 +1779,30 @@ const xxx_fire_hits = {
prompt() {
view.prompt = `Apply hits.`
- let normal_steps = count_normal_steps()
- let elite_steps = count_elite_steps()
+ let normal_steps = count_normal_steps_in_battle()
+ let elite_steps = count_elite_steps_in_battle()
let done = true
- for (let u = 0; u < units.length; ++u) {
- if (is_friendly_unit(u) && unit_hex(u) === game.battle) {
- let c = unit_class(u)
- if (is_unit_elite(u)) {
- if (game.hits[c] >= 2) {
+ for_each_friendly_unit_in_hex(game.battle, u => {
+ let c = unit_class(u)
+ if (is_unit_elite(u)) {
+ if (game.hits[c] >= 2) {
+ gen_action_unit(u)
+ done = false
+ }
+ } else {
+ if (game.hits[c] >= 1) {
+ // If mixed elite and non-elite: must assign ALL damage.
+ if (elite_steps[c] > 0 && normal_steps[c] === 1 && (game.hits[c] & 1) === 0) {
+ // Eliminating the last non-elite must not leave an odd
+ // number of hits remaining.
+ } else {
gen_action_unit(u)
done = false
}
- } else {
- if (game.hits[c] >= 1) {
- // If mixed elite and non-elite: must assign ALL damage.
- if (elite_steps[c] > 0 && normal_steps[c] === 1 && (game.hits[c] & 1) === 0) {
- // Eliminating the last non-elite must not leave an odd
- // number of hits remaining.
- } else {
- gen_action_unit(u)
- done = false
- }
- }
}
}
- }
+ })
if (done)
gen_action_next()
},
@@ -1875,6 +1892,113 @@ function end_combat_phase() {
end_player_turn()
}
+// === PURSUIT FIRE ===
+
+function goto_pursuit_fire() {
+ clear_undo()
+ set_active_player()
+ game.state = 'pursuit_fire'
+ game.hits = 0
+}
+
+function slowest_enemy_unit_speed(where) {
+ let r = 4
+ for (let u = 0; u < units.length; ++u) {
+ if (is_enemy_unit(u) && unit_hex(u) === where) {
+ let s = unit_speed(u)
+ if (s < r)
+ r = s
+ }
+ }
+ return r
+}
+
+function roll_pursuit_fire(n) {
+ for (let i = 0; i < n; ++i) {
+ let roll = random(6) + 1
+ log(`Pursuit fire ${roll}.`)
+ if (roll >= 4)
+ game.hits++
+ }
+}
+
+states.pursuit_fire = {
+ inactive: "pursuit fire (fire)",
+ prompt() {
+ view.prompt = `Pursuit Fire.`
+ let slowest = slowest_enemy_unit_speed(game.pursuit)
+ for_each_friendly_unit_in_hex(game.pursuit, u => {
+ if (unit_speed(u) >= slowest && !is_unit_fired(u))
+ gen_action_unit(u)
+ })
+ gen_action('next')
+ },
+ unit(who) {
+ let slowest = slowest_enemy_unit_speed(game.pursuit)
+ if (unit_speed(who) > slowest)
+ roll_pursuit_fire(2)
+ else
+ roll_pursuit_fire(1)
+ set_unit_fired(who)
+ },
+ next() {
+ goto_pursuit_hits()
+ }
+}
+
+function goto_pursuit_hits() {
+ if (game.hits > 0) {
+ set_passive_player()
+ let hp = count_hp_in_pursuit()
+ if (game.hits > hp)
+ game.hits = hp
+ game.state = 'pursuit_hits'
+ } else {
+ end_pursuit_fire()
+ }
+}
+
+states.pursuit_hits = {
+ inactive: "pursuit fire (hits)",
+ prompt() {
+ view.prompt = `Pursuit Fire: Apply ${game.hits} hits.`
+
+ let normal_steps = count_normal_steps_in_pursuit()
+ let elite_steps = count_elite_steps_in_pursuit()
+
+ let done = true
+ for_each_friendly_unit_in_hex(game.pursuit, u => {
+ if (is_unit_elite(u)) {
+ if (game.hits >= 2) {
+ gen_action_unit(u)
+ done = false
+ }
+ } else {
+ if (game.hits >= 1) {
+ // If mixed elite and non-elite: must assign ALL damage.
+ if (elite_steps > 0 && normal_steps === 1 && (game.hits & 1) === 0) {
+ // Eliminating the last non-elite must not leave an odd
+ // number of hits remaining.
+ } else {
+ gen_action_unit(u)
+ done = false
+ }
+ }
+ }
+ })
+ if (done)
+ gen_action('next')
+ },
+ unit(who) {
+ push_undo()
+ game.hits -= reduce_unit(who)
+ },
+ next() {
+ clear_undo()
+ end_pursuit_fire()
+ },
+}
+
// === DEPLOYMENT ===
states.free_deployment = {
@@ -2454,8 +2578,10 @@ exports.setup = function (seed, scenario, options) {
move_road: 4,
// combat
+ partial_retreats: [], // remember partial retreats to forbid initiating combat
active_battles: [],
assault_battles: [],
+ pursuit: 0,
battle: 0,
fired: [],
hits: null,
@@ -2492,10 +2618,11 @@ exports.view = function(state, current) {
if (game.to1) view.to1 = game.to1
if (game.to2) view.to2 = game.to2
+ if (game.pursuit) view.pursuit = game.pursuit
if (game.battle) view.battle = game.battle
- if (game.fired) view.fired = game.fired
- if (game.hits) view.hits = game.hits
- if (game.flash) view.flash = game.flash
+ if (game.fired !== undefined) view.fired = game.fired
+ if (game.hits !== undefined) view.hits = game.hits
+ if (game.flash !== undefined) view.flash = game.flash
return common_view(current)
}