summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-08-13 16:35:03 +0200
committerTor Andersson <tor@ccxvii.net>2023-10-01 16:11:22 +0200
commit74d2e6efd24db8570cd64f74c7de109c5b094c70 (patch)
treef455ce39830c51ff51dea38c2e1d6b684259fdf3 /rules.js
parentd31416c59ce6cf5d62db6fbdc6586472fbb00c4b (diff)
downloadwaterloo-campaign-1815-74d2e6efd24db8570cd64f74c7de109c5b094c70.tar.gz
Place HQ.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js113
1 files changed, 103 insertions, 10 deletions
diff --git a/rules.js b/rules.js
index ef09538..3f2f371 100644
--- a/rules.js
+++ b/rules.js
@@ -41,6 +41,20 @@ const GRAND_BATTERY = data.pieces.findIndex(pc => pc.name === "Grand Battery")
const HILL_1 = data.pieces.findIndex(pc => pc.name === "II Corps (Hill*)")
const HILL_2 = data.pieces.findIndex(pc => pc.name === "II Corps (Hill**)")
+const brussels_couillet_road_x3 = []
+for (let a of data.map.brussels_couillet_road) {
+ set_add(brussels_couillet_road_x3, a)
+ for_each_adjacent(a, (b) => {
+ set_add(brussels_couillet_road_x3, b)
+ for_each_adjacent(b, (c) => {
+ set_add(brussels_couillet_road_x3, c)
+ for_each_adjacent(c, (d) => {
+ set_add(brussels_couillet_road_x3, d)
+ })
+ })
+ })
+}
+
function make_piece_list(f) {
let list = []
for (let p = 0; p < data.pieces.length; ++p)
@@ -114,6 +128,10 @@ function piece_command_range(p) {
return data.pieces[p].range1
}
+function pieces_are_same_side(a, b) {
+ return data.pieces[a].side === data.pieces[b].side
+}
+
function is_empty_hex(x) {
for (let p = 0; p < data.pieces.length; ++p)
if (piece_hex(p) === x)
@@ -383,7 +401,15 @@ function goto_command_phase() {
function goto_hq_placement_step() {
game.active = P1
- game.state = "hq_placement_step"
+ game.state = "place_hq"
+ for (let p of p1_hqs) {
+ set_piece_hex(p, AVAILABLE_P1)
+ set_piece_mode(p, 0)
+ }
+ for (let p of p2_hqs) {
+ set_piece_hex(p, AVAILABLE_P2)
+ set_piece_mode(p, 0)
+ }
}
function end_hq_placement_step() {
@@ -393,16 +419,82 @@ function end_hq_placement_step() {
goto_blown_unit_return_step()
}
-states.hq_placement_step = {
+states.place_hq = {
prompt() {
prompt("HQ Placement Step.")
- view.actions.next = 1
+ let done = true
+ for (let p of friendly_hqs()) {
+ gen_action_piece(p)
+ if (!piece_is_on_map(p))
+ done = false
+ }
+ if (done)
+ view.actions.next = 1
+ },
+ piece(p) {
+ if (piece_is_on_map(p)) {
+ set_piece_mode(p, 1 - piece_mode(p))
+ } else {
+ push_undo()
+ game.who = p
+ game.state = "place_hq_where"
+ }
},
next() {
end_hq_placement_step()
},
}
+function gen_place_hq(from, here, n) {
+ for_each_adjacent(here, next => {
+ if (calc_distance(next, from) <= calc_distance(here, from))
+ return
+ if (n > 1)
+ gen_place_hq(from, next, n - 1)
+ // TODO RULES: as the crow flies or must trace path?
+ if (is_enemy_zoc_or_zoi(next) || hex_has_any_piece(next, friendly_hqs()))
+ return
+ gen_action_hex(next)
+ })
+}
+
+states.place_hq_where = {
+ prompt() {
+ prompt("HQ Placement Step.")
+ gen_action_piece(game.who)
+ view.actions.normal = piece_mode(game.who) ? 1 : 0
+ view.actions.battle = piece_mode(game.who) ? 0 : 1
+
+ update_zoc()
+
+ // within 3 of any unit
+ for (let p of friendly_units()) {
+ let x = piece_hex(p)
+ if (is_map_hex(x) && pieces_are_same_side(p, game.who)) {
+ if (!is_enemy_zoc_or_zoi(x) && !hex_has_any_piece(x, friendly_hqs()))
+ gen_action_hex(x)
+ gen_place_hq(x, x, 3)
+ }
+ }
+
+ // if not possible, within 3 of a brussels to couillet road hex
+ if (!view.actions.hex) {
+ for (let x of brussels_couillet_road_x3) {
+ if (is_empty_hex(x))
+ gen_action_hex(x)
+ }
+ }
+ },
+ piece(p) {
+ pop_undo()
+ },
+ hex(x) {
+ set_piece_hex(game.who, x)
+ game.who = -1
+ game.state = "place_hq"
+ },
+}
+
// === B: BLOWN UNIT RETURN STEP ===
function goto_blown_unit_return_step() {
@@ -432,7 +524,7 @@ states.blown_unit_return_step = {
// === C: CAVALRY CORPS RECOVERY STEP ===
-// TODO: merge with steps F and G to save time
+// TODO: automated?
function goto_cavalry_corps_recovery_step() {
game.active = P1
@@ -526,7 +618,7 @@ states.place_detachment_who = {
for (let p of friendly_detachments()) {
let x = piece_hex(p)
if (x === AVAILABLE_P1 || x === AVAILABLE_P2) {
- if (data.pieces[p].side === data.pieces[game.target].side) {
+ if (pieces_are_same_side(p, game.target)) {
// SPECIAL: french grand battery and old guard
if (p === GRAND_BATTERY || p === OLD_GUARD) {
if (game.target === NAPOLEON_HQ && piece_mode(NAPOLEON_HQ))
@@ -578,7 +670,11 @@ states.place_detachment_where = {
for (let row = 0; row < data.map.rows; ++row) {
for (let col = 0; col < data.map.cols; ++col) {
let x = 1000 + row * 100 + col
- if (move_seen[x-1000] && !is_friendly_zoc_or_zoi(x))
+ if (
+ move_seen[x-1000] &&
+ !is_friendly_zoc_or_zoi(x) &&
+ !hex_has_any_piece(x, friendly_detachments())
+ )
gen_action_hex(x)
}
}
@@ -675,8 +771,7 @@ states.british_line_of_communication_angst_2 = {
// === F: ADVANCE FORMATION ===
// === G: BATTLE FORMATION ===
-// NOTE: merged step F and step G to save time
-// TODO: move step C here
+// TODO: automated?
function goto_advance_formation() {
game.active = P1
@@ -1125,8 +1220,6 @@ function search_withdrawal(here) {
function search_retreat(result, here, from, n) {
for_each_adjacent(here, next => {
- console.log("search retreat", next, here, from)
-
// must move further away
if (calc_distance(next, from) <= calc_distance(here, from))
return