diff options
author | Tor Andersson <tor@ccxvii.net> | 2024-10-17 00:54:56 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2024-10-17 00:57:05 +0200 |
commit | a9b211ca1e938b56acf24d16a9b9aa68fe5ad67d (patch) | |
tree | b87422357d8146fabb5c690ba5c48d1a022dea38 | |
parent | 551c834b8b842517926a7101edb7ab5bede35b80 (diff) | |
download | maria-a9b211ca1e938b56acf24d16a9b9aa68fe5ad67d.tar.gz |
Force march.
-rw-r--r-- | play.js | 5 | ||||
-rw-r--r-- | rules.js | 142 |
2 files changed, 114 insertions, 33 deletions
@@ -120,7 +120,7 @@ const piece_name = [ "Saxon ST", "Pragmatic Army ST", "Austrian ST", "Austrian ST", "Austrian ST", - "hussars", "hussars", + "Hussars", "Hussars", ] let suit_class = [ "spades", "clubs", "hearts", "diamonds", "reserve" ] @@ -972,11 +972,12 @@ function on_update() { action_button_with_argument("value", v, v) for (let p = 0; p < 20; ++p) { - action_button_with_argument("unstack", p, "Unstack " + piece_abbr[p]) action_button_with_argument("promote", p, "Promote " + piece_abbr[p]) action_button_with_argument("demote", p, "Demote " + piece_abbr[p]) } + action_button("force_march", "Force march") + action_button("take", "Take") action_button("give", "Give") action_button("recruit", "Recruit") @@ -6,6 +6,10 @@ // PLAN: move all austria on bohemia first, then alternate pragmatic and austria activations on flanders map // TODO: confirm mixed stack creation on flanders map (force "undo" to previous location if denied?) +// TODO: supreme commander in mixed stacks +// TODO: TC subsidies +// TODO: subsidy markers? + const R_LOUIS_XV = "Louis XV" const R_FREDERICK = "Frederick" const R_MARIA_THERESA = "Maria Theresa" @@ -111,6 +115,8 @@ const all_power_trains = [ [ 27, 28, 29 ], ] +const last_piece = 29 + const all_hussars = [ 30, 31 ] const piece_power = [ @@ -404,11 +410,18 @@ function make_protect_range(result, start, here, range) { } } +function is_enemy_controlled_fortress(s) { + // TODO + return false +} + function is_conquest_space(_pow, s) { + // TODO return set_has(all_objectives, s) } function is_reconquest_space(_pow, s) { + // TODO return set_has(all_objectives, s) } @@ -541,8 +554,8 @@ function count_unused_troops_on_map() { } function has_any_piece(to) { - for (let s of game.pos) - if (s === to) + for (let p = 0; p <= last_piece; ++p) + if (game.pos[p] === to) return true return false } @@ -1169,7 +1182,7 @@ function can_move_general_to(to) { return true } -function move_general_to(to) { +function move_general_to(to, is_force_march) { let pow = game.power let who = game.selected[0] let from = game.pos[who] @@ -1180,24 +1193,30 @@ function move_general_to(to) { game.pos[p] = to } - // conquer space - if (is_conquest_space(pow, from) && !set_has(game.conquest, from)) { - if (is_protected_from_conquest(from)) { - set_add(game.retro, from) - } else { - set_add(game.move_conq, from) - set_add(game.conquest, from) + // Cannot conquer if force marching. + // Cannot conquer if out of supply. + if (!is_force_march && !is_out_of_supply(who)) { + + // conquer space + if (is_conquest_space(pow, from) && !set_has(game.conquest, from)) { + if (is_protected_from_conquest(from)) { + set_add(game.retro, from) + } else { + set_add(game.move_conq, from) + set_add(game.conquest, from) + } } - } - // re-conquer space - if (is_reconquest_space(pow, from) && set_has(game.conquest, from)) { - if (is_protected_from_reconquest(from)) { - set_add(game.retro, from) - } else { - set_add(game.move_reconq, from) - set_delete(game.conquest, from) + // re-conquer space + if (is_reconquest_space(pow, from) && set_has(game.conquest, from)) { + if (is_protected_from_reconquest(from)) { + set_add(game.retro, from) + } else { + set_add(game.move_reconq, from) + set_delete(game.conquest, from) + } } + } // eliminate supply train @@ -1292,10 +1311,12 @@ states.move_general = { if (game.selected.length > 1) { for (let p of game.selected) { gen_action_piece(p) - gen_action_unstack(p) } } + if (data.cities.main_roads[here].length > 0) + view.actions.force_march = 1 + let s_take = count_stacked_take() let s_give = count_stacked_give() let u_take = count_unstacked_take() @@ -1328,15 +1349,9 @@ states.move_general = { give() { game.state = "move_give" }, - unstack(p) { - set_delete(game.selected, p) - }, piece(p) { if (game.count === 0) { - if (set_has(game.selected, p)) - set_delete(game.selected, p) - else - this.space(game.pos[p]) + this.space(game.pos[p]) } else { if (p === game.selected[0]) this.stop() @@ -1358,9 +1373,78 @@ states.move_general = { if (!set_has(data.cities.main_roads[from], to)) game.main = 0 - if (move_general_to(to) || ++game.count === movement_range() + game.main) + if (move_general_to(to, false) || ++game.count === movement_range() + game.main) end_move_piece() }, + force_march() { + game.state = "force_march" + } +} + +function is_adjacent_to_enemy_piece(here) { + for (let next of data.cities.adjacent[here]) + if (has_enemy_piece(next)) + return true + return false +} + +function search_force_march(came_from, start) { + let seen = [ start ] + let queue = [ start << 4 ] + while (queue.length > 0) { + let item = queue.shift() + let here = item >> 4 + let dist = (item & 15) + 1 + for (let next of data.cities.main_roads[here]) { + if (set_has(seen, next)) + continue + if (is_enemy_controlled_fortress(next)) + continue + if (has_any_piece(next)) + continue + if (is_adjacent_to_enemy_piece(next)) + continue + if (came_from) + map_set(came_from, next, here) + set_add(seen, next) + if (dist < 8) + queue.push((next << 4) | dist) + } + } + set_delete(seen, start) + return seen +} + +// TODO: choose not-shortest path to capture hussars during force march? +states.force_march = { + inactive: "move", + prompt() { + prompt("Force March " + format_selected() + ".") + view.selected = game.selected + + let here = game.pos[game.selected[0]] + for (let s of search_force_march(null, here)) + gen_action_space(s) + }, + space(to) { + let here = game.pos[game.selected[0]] + let came_from = [] + + search_force_march(came_from, here) + + let path = [] + while (to !== here) { + path.unshift(to) + to = map_get(came_from, to) + } + + for (let s of path) { + game.move_path.push(s) + move_general_to(s, true) + } + + end_move_piece() + }, } states.move_take = { @@ -2980,10 +3064,6 @@ function gen_action_card(c) { gen_action("card", c) } -function gen_action_unstack(p) { - gen_action("unstack", p) -} - function log(msg) { game.log.push(msg) } |