summaryrefslogtreecommitdiff
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
parentd31416c59ce6cf5d62db6fbdc6586472fbb00c4b (diff)
downloadwaterloo-campaign-1815-74d2e6efd24db8570cd64f74c7de109c5b094c70.tar.gz
Place HQ.
-rw-r--r--data.js2
-rw-r--r--play.js9
-rw-r--r--rules.js113
3 files changed, 107 insertions, 17 deletions
diff --git a/data.js b/data.js
index 31eb29b..4ee2e26 100644
--- a/data.js
+++ b/data.js
@@ -20,8 +20,8 @@ data.map = {
],
bridges: [[1117,1218],[1121,1221],[1215,1314],[1736,1737],[1737,1738],[1221,1120]],
towns: [1015,1018,1021,1024,1026,1100,1117,1118,1129,1201,1204,1209,1211,1215,1217,1221,1239,1340,1401,1407,1423,1433,1516,1526,1528,1534,1601,1603,1605,1623,1631,1716,1728,1737,1800,1810,1821,1825,1830,1903,1911,1915,1916,1919,1922,1928,1932,2001,2027,2035,2119,2122,2123,2219,2222,2223,2230,2308,2315,2317,2324,2327,2333,2337,2404,2500,2521,2529,2537,2604,2609,2618,2623,2715,2721,2723,2725,2730,2733,2736,2739,2827,2829,2840,2911,2936,3002,3013,3018,3020,3031,3125,3129,3135,3138,3204,3206,3226,3231,3233,3234,3240,3313,3327,3328,3402,3408,3417,3418,3438,3441,3512,3514,3523,3528,3614,3616,3617,3631,3636,3705,3708,3715,3718,3719,3723,3803,3828,3832,3915,3919,3925,3933,4006,4038],
- only_streams: [1124,1224,1300,1324,1501,1502,1600,2038,2138,2507,2524,2540,2624,2625,2637,2641,2718,2737,2741,2808,2817,2820,2821,2838,2905,2907,2920,2921,2938,3021,3025,3041,3118,3141,3205,3207,3219,3220,3221,3222,3223,3225,3323,3324,3325,3406,3506,3517,3518,3520,3521,3534,3536,3604,3619,3622,3623,3624,3637,3706,3707,3735,3739,3806,3820,3837,3920,3937,4007,4021,4027,4039],
streams: [1021,1024,1120,1124,1224,1300,1314,1324,1401,1415,1501,1502,1514,1600,1601,1603,1604,1704,1837,1937,2038,2138,2407,2507,2524,2540,2604,2608,2609,2620,2621,2624,2625,2637,2641,2704,2708,2718,2719,2721,2724,2725,2737,2740,2741,2805,2808,2817,2820,2821,2825,2838,2840,2905,2906,2907,2915,2916,2917,2920,2921,2925,2938,2940,3006,3017,3018,3019,3020,3021,3022,3025,3039,3040,3041,3106,3117,3118,3121,3122,3125,3141,3205,3207,3219,3220,3221,3222,3223,3225,3226,3305,3306,3320,3323,3324,3325,3406,3423,3502,3503,3506,3517,3518,3520,3521,3523,3534,3535,3536,3604,3605,3606,3607,3619,3622,3623,3624,3635,3637,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3719,3723,3735,3736,3739,3802,3803,3806,3813,3820,3824,3825,3836,3837,3840,3906,3920,3925,3937,3938,3939,4007,4021,4026,4027,4038,4039],
+ brussels_couillet_road: [1018,1117,1217,1218,1317,1417,1516,1617,1716,1817,1917,2018,2117,2218,2317,2418,2517,2618,2717,2818,2917,3018,3116,3117,3216,3316,3416,3515,3616,3616,3715,3815,3915,4015],
names: {
1015: "Mortigny",
1018: "Couillet",
diff --git a/play.js b/play.js
index 0ad5f78..8c85772 100644
--- a/play.js
+++ b/play.js
@@ -221,8 +221,8 @@ function on_update() {
} else if (hex === 100 || hex === 101) {
// AVAILABLE DETACHMENTS
ui.pieces[id].classList.remove("hide")
- ui.pieces[id].classList.remove("flip")
- let x = 600 + 20 + ui.stack[hex] * 50
+ ui.pieces[id].classList.toggle("flip", (view.pieces[id] & 1) === 1)
+ let x = 600 + 20 + ui.stack[hex] * 60
let y = 1650 + 20 + 60 * (hex-100)
ui.stack[hex] += 1
ui.pieces[id].style.top = y + "px"
@@ -263,11 +263,8 @@ function on_update() {
}
}
- action_button("edit_town", "Town")
- action_button("edit_stream", "Stream")
- action_button("edit_road", "Road")
-
action_button("next", "Next")
+ action_button("done", "Done")
action_button("pass", "Pass")
action_button("undo", "Undo")
}
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