diff options
-rw-r--r-- | data.js | 2 | ||||
-rw-r--r-- | play.js | 9 | ||||
-rw-r--r-- | rules.js | 113 |
3 files changed, 107 insertions, 17 deletions
@@ -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", @@ -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") } @@ -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 |