summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-10-17 10:48:13 +0200
committerTor Andersson <tor@ccxvii.net>2024-10-17 10:54:45 +0200
commit9d4e9253df7b3430bbe7e8313320388970ae494f (patch)
tree45579e73cbd9438cd1acc568b4c8c9ff848b7c64
parente654baad3c06b56b6076688b11bfb0e6ef9ea84f (diff)
downloadmaria-9d4e9253df7b3430bbe7e8313320388970ae494f.tar.gz
Use singleton game.selected for movement and setup.
Only multi-select during combat and retreat.
-rw-r--r--rules.js165
1 files changed, 63 insertions, 102 deletions
diff --git a/rules.js b/rules.js
index 5fcc9a2..4fa6c6a 100644
--- a/rules.js
+++ b/rules.js
@@ -2,6 +2,8 @@
// TODO: game.selected - singleton instead of array
+// TODO: re-entering supply trains during movement (10.2)
+
// TODO: austria/pragmatic action step - show both sides cards and interleave movement on flanders map
// 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?)
@@ -376,19 +378,25 @@ function format_card_list_prompt(list) {
}
function format_selected() {
- if (game.selected.length === 0)
- return "nobody"
- return game.selected.map(p => piece_name[p]).join(" and ")
+ if (Array.isArray(game.selected)) {
+ if (game.selected.length === 0)
+ return "nobody"
+ return game.selected.map(p => piece_name[p]).join(" and ")
+ } else {
+ if (game.selected < 0)
+ return "nobody"
+ return piece_name[game.selected]
+ }
}
function log_move_to(to) {
- let from = game.pos[game.selected[0]]
- log("@" + game.selected.join(",") + ";" + from + "," + to)
+ let from = game.pos[game.selected]
+ log("@" + game.selected + ";" + from + "," + to)
}
function log_move_path() {
if (game.move_path.length > 1)
- log("@" + game.selected.join(",") + ";" + game.move_path.join(","))
+ log("@" + game.selected + ";" + game.move_path.join(","))
}
/* OBJECTIVES */
@@ -701,7 +709,7 @@ function goto_start_turn() {
log("# Turn " + game.turn)
- game.selected = null
+ game.selected = -1
delete game.ia_lost
// MARIA: politics
@@ -962,76 +970,44 @@ function end_tactical_cards() {
/* TRANSFER TROOPS */
+function find_unstacked_general() {
+ let here = game.pos[game.selected]
+ for (let p of all_power_generals[game.power])
+ if (game.pos[p] === here && game.selected !== p)
+ return p
+ return -1
+}
+
function count_stacked_take() {
- let n = 0
- for (let p of game.selected)
- n += 8 - game.troops[p]
- return n
+ return 8 - game.troops[game.selected]
}
function count_unstacked_take() {
- let here = game.pos[game.selected[0]]
- let n = 0
- for (let p of all_power_generals[game.power])
- if (game.pos[p] === here && !set_has(game.selected, p))
- n += 8 - game.troops[p]
- return n
+ let p = find_unstacked_general()
+ if (p < 0)
+ return 0
+ return 8 - game.troops[p]
}
function count_stacked_give() {
- let n = 0
- for (let p of game.selected)
- n += game.troops[p] - 1
- return n
+ return game.troops[game.selected] - 1
}
function count_unstacked_give() {
- let here = game.pos[game.selected[0]]
- let n = 0
- for (let p of all_power_generals[game.power])
- if (game.pos[p] === here && !set_has(game.selected, p))
- n += game.troops[p] - 1
- return n
+ let p = find_unstacked_general()
+ if (p < 0)
+ return 0
+ return game.troops[p] - 1
}
function take_troops(total) {
- let here = game.pos[game.selected[0]]
-
- let n = total
- for (let p of game.selected) {
- let x = Math.max(0, Math.min(n, 8 - game.troops[p]))
- game.troops[p] += x
- n -= x
- }
-
- n = total
- for (let p of all_power_generals_rev[game.power]) {
- if (game.pos[p] === here && !set_has(game.selected, p)) {
- let x = Math.max(0, Math.min(n, game.troops[p] - 1))
- game.troops[p] -= x
- n -= x
- }
- }
+ game.troops[game.selected] += total
+ game.troops[find_unstacked_general()] -= total
}
function give_troops(total) {
- let here = game.pos[game.selected[0]]
-
- let n = total
- for (let p of all_power_generals[game.power]) {
- if (game.pos[p] === here && !set_has(game.selected, p)) {
- let x = Math.max(0, Math.min(n, 8 - game.troops[p]))
- game.troops[p] += x
- n -= x
- }
- }
-
- n = total
- for (let p of game.selected) {
- let x = Math.max(0, Math.min(n, game.troops[p] - 1))
- game.troops[p] -= x
- n -= x
- }
+ game.troops[game.selected] -= total
+ game.troops[find_unstacked_general()] += total
}
/* MOVEMENT */
@@ -1111,8 +1087,7 @@ states.movement = {
set_active_to_power(piece_power[p])
- // Note: Can only move one piece at a time in Maria!
- game.selected = [ p ]
+ game.selected = p
game.count = 0
@@ -1183,14 +1158,12 @@ function can_move_general_to(from, to) {
function move_general_to(to, is_force_march) {
let pow = game.power
- let who = game.selected[0]
+ let who = game.selected
let from = game.pos[who]
let stop = false
- for (let p of game.selected) {
- set_add(game.moved, p)
- game.pos[p] = to
- }
+ set_add(game.moved, game.selected)
+ game.pos[game.selected] = to
// Cannot conquer if force marching.
// Cannot conquer if out of supply.
@@ -1231,7 +1204,7 @@ function move_general_to(to, is_force_march) {
// uniting stacks: flag all as moved and stop moving
for (let p of all_coop_generals(pow)) {
- if (game.pos[p] === to && !set_has(game.selected, p)) {
+ if (game.pos[p] === to && game.selected !== p) {
set_add(game.moved, p)
stop = true
}
@@ -1256,7 +1229,7 @@ states.move_supply_train = {
prompt("Move supply train" + format_move(2))
view.selected = game.selected
- let who = game.selected[0]
+ let who = game.selected
let here = game.pos[who]
if (game.count < 2 + game.main)
@@ -1276,12 +1249,12 @@ states.move_supply_train = {
this.stop()
},
stop() {
- let who = game.selected[0]
+ let who = game.selected
set_add(game.moved, who)
end_move_piece()
},
space(to) {
- let who = game.selected[0]
+ let who = game.selected
let from = game.pos[who]
game.move_path.push(to)
@@ -1303,16 +1276,10 @@ states.move_general = {
prompt("Move " + format_selected() + format_move(movement_range()))
view.selected = game.selected
- let who = game.selected[0]
+ let who = game.selected
let here = game.pos[who]
if (game.count === 0) {
- if (game.selected.length > 1) {
- for (let p of game.selected) {
- gen_action_piece(p)
- }
- }
-
if (data.cities.main_roads[here].length > 0)
view.actions.force_march = 1
@@ -1352,19 +1319,18 @@ states.move_general = {
if (game.count === 0) {
this.space(game.pos[p])
} else {
- if (p === game.selected[0])
+ if (p === game.selected)
this.stop()
else
this.space(game.pos[p])
}
},
stop() {
- for (let p of game.selected)
- set_add(game.moved, p)
+ set_add(game.moved, game.selected)
end_move_piece()
},
space(to) {
- let who = game.selected[0]
+ let who = game.selected
let from = game.pos[who]
game.move_path.push(to)
@@ -1423,12 +1389,12 @@ states.force_march = {
prompt("Force March " + format_selected() + ".")
view.selected = game.selected
- let here = game.pos[game.selected[0]]
+ let here = game.pos[game.selected]
for (let s of search_force_march(null, here))
gen_action_space(s)
},
space(to) {
- let here = game.pos[game.selected[0]]
+ let here = game.pos[game.selected]
let came_from = []
search_force_march(came_from, here)
@@ -1500,7 +1466,7 @@ function end_move_piece() {
}
delete game.move_path
- game.selected = null
+ game.selected = -1
game.state = "movement"
set_active_to_current_action_step()
@@ -1724,7 +1690,7 @@ states.recruit = {
spend_recruit_cost()
if (game.pos[p] === ELIMINATED) {
- game.selected = [ p ]
+ game.selected = p
game.state = "re_enter"
} else {
game.recruit.troops += 1
@@ -1769,7 +1735,7 @@ states.re_enter = {
prompt("Re-enter " + format_selected() + ".")
view.selected = game.selected
- let p = game.selected[0]
+ let p = game.selected
let can_re_enter_at = is_general(p) ? can_re_enter_general : can_re_enter_supply_train
if (is_map_space(game.recruit.re_enter)) {
@@ -1782,14 +1748,14 @@ states.re_enter = {
}
},
space(s) {
- let p = game.selected[0]
+ let p = game.selected
game.pos[p] = s
map_set(game.recruit.pieces, p, s)
if (is_general(p)) {
game.recruit.troops += 1
game.troops[p] = 1
}
- game.selected = null
+ game.selected = -1
game.state = "recruit"
},
}
@@ -2326,6 +2292,7 @@ function search_retreat(loser, winner, range) {
return result
}
+// TODO: remove hussars when retreating across them
states.retreat = {
inactive: "retreat defeated general",
prompt() {
@@ -2789,7 +2756,7 @@ exports.setup = function (seed, _scenario, _options) {
moved: [],
retro: [],
- selected: [],
+ selected: -1,
count: 0,
}
@@ -2818,7 +2785,7 @@ states.setup = {
} else {
let n_stacks = 0
for (let p of all_power_generals[game.power]) {
- if (is_map_space(game.pos[p]) && !set_has(game.moved, p)) {
+ if (game.pos[p] !== ELIMINATED && !set_has(game.moved, p)) {
gen_action_piece(p)
n_stacks ++
}
@@ -2834,7 +2801,7 @@ states.setup = {
piece(p) {
push_undo()
set_add(game.moved, p)
- game.selected = [ p ]
+ game.selected = p
game.state = "setup_general"
},
end_setup() {
@@ -2865,7 +2832,7 @@ states.setup_general = {
prompt("Add troops to " + format_selected() + ".")
view.selected = game.selected
- let who = game.selected[0]
+ let who = game.selected
let n_self_min = setup_min_troops[who]
let n_self_max = setup_max_troops[who]
@@ -2884,14 +2851,8 @@ states.setup_general = {
view.actions.value.push(i)
},
value(v) {
- let save = game.selected.length - 1
- for (let p of game.selected) {
- let n = Math.min(8, v - save)
- game.troops[p] += n
- v -= n
- --save
- }
- game.selected = null
+ game.troops[game.selected] += v
+ game.selected = -1
game.state = "setup"
},
}