summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-10-17 00:54:56 +0200
committerTor Andersson <tor@ccxvii.net>2024-10-17 00:57:05 +0200
commita9b211ca1e938b56acf24d16a9b9aa68fe5ad67d (patch)
treeb87422357d8146fabb5c690ba5c48d1a022dea38
parent551c834b8b842517926a7101edb7ab5bede35b80 (diff)
downloadmaria-a9b211ca1e938b56acf24d16a9b9aa68fe5ad67d.tar.gz
Force march.
-rw-r--r--play.js5
-rw-r--r--rules.js142
2 files changed, 114 insertions, 33 deletions
diff --git a/play.js b/play.js
index 1c08fbd..0f92565 100644
--- a/play.js
+++ b/play.js
@@ -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")
diff --git a/rules.js b/rules.js
index bbfda27..1e01c09 100644
--- a/rules.js
+++ b/rules.js
@@ -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)
}