summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-10-23 19:16:27 +0200
committerTor Andersson <tor@ccxvii.net>2024-10-23 20:00:04 +0200
commitd1a4e47292f347556a6506c2b20f6adf8e69d619 (patch)
treeb6791604c01a8ff8c3a5262ae887e76945b7bdbe /rules.js
parent456d08d10840405e34f20af321e1802bcf156c53 (diff)
downloadmaria-d1a4e47292f347556a6506c2b20f6adf8e69d619.tar.gz
Saxony's defection and neutrality.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js596
1 files changed, 474 insertions, 122 deletions
diff --git a/rules.js b/rules.js
index 01532bf..d1c1e75 100644
--- a/rules.js
+++ b/rules.js
@@ -4,6 +4,8 @@
/* TODO
+check push_undo/clear_undo for political phase and political changes
+
show who controls which power in player list
set-aside victory marker areas
@@ -26,13 +28,10 @@ tc subsidies
minor when major fortress enemy occupied
subsidy contracts
-arenberg supply exception
-arenberg re-entry exception
-
-victory boxes
-politics
imperial election
+expeditionary corps
+
political changes
prussia annexes silesia
france reduces military objectives
@@ -105,6 +104,8 @@ const IMPERIAL_ELECTION = 24
const ELIMINATED = data.cities.name.length
const ARENBERG = 17
+const SAXONY_GENERAL = 19
+const SAXONY_TRAIN = 29
const all_powers = [ 0, 1, 2, 3, 4, 5 ]
const all_major_powers = [ 0, 1, 2, 3 ]
@@ -318,9 +319,15 @@ const all_prussia_saxony_generals = [
...all_power_generals[P_SAXONY],
]
-const all_austria_pragmatic_generals = [
+const all_austria_saxony_generals = [
...all_power_generals[P_AUSTRIA],
- ...all_power_generals[P_PRAGMATIC],
+ ...all_power_generals[P_SAXONY],
+]
+
+const all_austria_pragmatic_saxony_trains = [
+ ...all_power_trains[P_AUSTRIA],
+ ...all_power_trains[P_PRAGMATIC],
+ ...all_power_trains[P_SAXONY],
]
const all_france_bavaria_trains = [
@@ -333,48 +340,70 @@ const all_prussia_saxony_trains = [
...all_power_trains[P_SAXONY],
]
-const all_austria_pragmatic_trains = [
+const all_austria_saxony_trains = [
...all_power_trains[P_AUSTRIA],
- ...all_power_trains[P_PRAGMATIC],
+ ...all_power_generals[P_SAXONY],
]
-const all_france_allied_trains = [
+const all_france_bavaria_prussia_trains = [
+ ...all_power_trains[P_FRANCE],
+ ...all_power_trains[P_BAVARIA],
+ ...all_power_trains[P_PRUSSIA],
+]
+
+const all_france_bavaria_prussia_saxony_trains = [
...all_power_trains[P_FRANCE],
...all_power_trains[P_BAVARIA],
...all_power_trains[P_PRUSSIA],
...all_power_trains[P_SAXONY],
]
-const all_austria_allied_trains = [
+const all_austria_pragmatic_trains = [
...all_power_trains[P_AUSTRIA],
...all_power_trains[P_PRAGMATIC],
]
-const all_austria_allied_generals = [
+const all_austria_pragmatic_generals = [
...all_power_generals[P_AUSTRIA],
...all_power_generals[P_PRAGMATIC],
]
-const all_france_allied_generals = [
+const all_austria_pragmatic_saxony_generals = [
+ ...all_power_generals[P_AUSTRIA],
+ ...all_power_generals[P_PRAGMATIC],
+ ...all_power_generals[P_SAXONY],
+]
+
+const all_france_bavaria_prussia_generals = [
...all_power_generals[P_FRANCE],
...all_power_generals[P_BAVARIA],
...all_power_generals[P_PRUSSIA],
- ...all_power_generals[P_SAXONY],
]
-const all_powers_prussia_saxony_pragmatic_austria = [ P_PRUSSIA, P_SAXONY, P_PRAGMATIC, P_AUSTRIA ]
-const all_powers_france_bavaria_pragmatic_austria = [ P_FRANCE, P_BAVARIA, P_PRAGMATIC, P_AUSTRIA ]
-const all_powers_france_bavaria_prussia_saxony = [ P_FRANCE, P_BAVARIA, P_PRUSSIA, P_SAXONY ]
-const all_powers_pragmatic_austria = [ P_PRAGMATIC, P_AUSTRIA ]
+const all_france_bavaria_prussia_saxony_generals = [
+ ...all_power_generals[P_FRANCE],
+ ...all_power_generals[P_BAVARIA],
+ ...all_power_generals[P_PRUSSIA],
+ ...all_power_generals[P_SAXONY],
+]
const all_powers_none = []
-const all_powers_france_bavaria = [ P_FRANCE, P_BAVARIA ]
-const all_powers_bavaria = [ P_BAVARIA ]
+const all_powers_prussia = [ P_PRUSSIA ]
const all_powers_pragmatic = [ P_PRAGMATIC ]
const all_powers_austria = [ P_AUSTRIA ]
-const all_powers_prussia_saxony = [ P_PRUSSIA, P_SAXONY ]
+const all_powers_bavaria = [ P_BAVARIA ]
const all_powers_saxony = [ P_SAXONY ]
+const all_powers_france_bavaria = [ P_FRANCE, P_BAVARIA ]
+const all_powers_prussia_saxony = [ P_PRUSSIA, P_SAXONY ]
+const all_powers_austria_saxony = [ P_AUSTRIA, P_SAXONY ]
const all_powers_bavaria_saxony = [ P_BAVARIA, P_SAXONY ]
+const all_powers_prussia_saxony_pragmatic_austria = [ P_PRUSSIA, P_SAXONY, P_PRAGMATIC, P_AUSTRIA ]
+const all_powers_france_bavaria_pragmatic_austria = [ P_FRANCE, P_BAVARIA, P_PRAGMATIC, P_AUSTRIA ]
+const all_powers_france_bavaria_prussia_pragmatic = [ P_FRANCE, P_BAVARIA, P_PRUSSIA, P_PRAGMATIC ]
+const all_powers_france_bavaria_prussia = [ P_FRANCE, P_BAVARIA, P_PRUSSIA ]
+const all_powers_france_bavaria_prussia_saxony = [ P_FRANCE, P_BAVARIA, P_PRUSSIA, P_SAXONY ]
+const all_powers_pragmatic_austria = [ P_PRAGMATIC, P_AUSTRIA ]
+const all_powers_pragmatic_austria_saxony = [ P_PRAGMATIC, P_AUSTRIA, P_SAXONY ]
function coop_major_power(pow) {
if (pow === P_BAVARIA)
@@ -398,58 +427,87 @@ function coop_minor_power(pow) {
return pow
}
-function all_friendly_minor_powers(pow) {
- switch (pow) {
+function is_hostile_to_austria() {
+ switch (game.power) {
case P_FRANCE:
case P_BAVARIA:
case P_PRUSSIA:
+ return true
case P_SAXONY:
- return all_powers_bavaria_saxony
+ return is_saxony_prussian()
case P_PRAGMATIC:
case P_AUSTRIA:
- return all_powers_none
+ return false
}
}
-function all_coop_powers(pow) {
- switch (pow) {
+// TODO: simplify all these lists and stuff
+
+function all_controlled_powers(pow) {
+ switch (coop_major_power(pow)) {
case P_FRANCE:
- case P_BAVARIA:
return all_powers_france_bavaria
case P_PRUSSIA:
- case P_SAXONY:
- return all_powers_prussia_saxony
+ if (is_saxony_prussian())
+ return all_powers_prussia_saxony
+ return all_powers_prussia
case P_PRAGMATIC:
+ return all_powers_pragmatic
case P_AUSTRIA:
- return all_powers_pragmatic_austria
+ if (is_saxony_austrian())
+ return all_powers_austria_saxony
+ return all_powers_austria
}
}
-function all_controlled_powers(pow) {
- switch (pow) {
+function all_controlled_generals(pow) {
+ switch (coop_major_power(pow)) {
case P_FRANCE:
- case P_BAVARIA:
- return all_powers_france_bavaria
+ return all_france_bavaria_generals
case P_PRUSSIA:
- case P_SAXONY:
- return all_powers_prussia_saxony
+ if (is_saxony_prussian())
+ return all_prussia_saxony_generals
+ return all_power_generals[P_PRUSSIA]
case P_PRAGMATIC:
- return all_powers_pragmatic
+ return all_power_generals[P_PRAGMATIC]
case P_AUSTRIA:
- return all_powers_austria
+ if (is_saxony_austrian())
+ return all_austria_saxony_generals
+ return all_power_generals[P_AUSTRIA]
}
}
-function is_hostile_to_austria() {
- switch (game.power) {
+function all_controlled_trains(pow) {
+ switch (coop_major_power(pow)) {
+ case P_FRANCE:
+ return all_france_bavaria_trains
+ case P_PRUSSIA:
+ if (is_saxony_prussian())
+ return all_prussia_saxony_trains
+ return all_power_trains[P_PRUSSIA]
+ case P_PRAGMATIC:
+ return all_power_trains[P_PRAGMATIC]
+ case P_AUSTRIA:
+ if (is_saxony_austrian())
+ return all_austria_saxony_trains
+ return all_power_trains[P_AUSTRIA]
+ }
+}
+
+function all_friendly_minor_powers(pow) {
+ switch (pow) {
case P_FRANCE:
case P_BAVARIA:
case P_PRUSSIA:
case P_SAXONY:
- return true
+ if (is_saxony_prussian())
+ return all_powers_bavaria_saxony
+ return all_powers_bavaria
case P_PRAGMATIC:
case P_AUSTRIA:
- return false
+ if (is_saxony_austrian())
+ return all_powers_saxony
+ return all_powers_none
}
}
@@ -458,10 +516,17 @@ function all_enemy_powers(pow) {
case P_FRANCE:
case P_BAVARIA:
case P_PRUSSIA:
+ if (is_saxony_prussian())
+ return all_powers_pragmatic_austria
+ return all_powers_pragmatic_austria_saxony
case P_SAXONY:
+ if (is_saxony_prussian())
+ return all_powers_france_bavaria_prussia
return all_powers_pragmatic_austria
case P_PRAGMATIC:
case P_AUSTRIA:
+ if (is_saxony_austrian())
+ return all_powers_france_bavaria_prussia
return all_powers_france_bavaria_prussia_saxony
}
}
@@ -472,94 +537,89 @@ function all_non_coop_powers(pow) {
case P_BAVARIA:
return all_powers_prussia_saxony_pragmatic_austria
case P_PRUSSIA:
- case P_SAXONY:
return all_powers_france_bavaria_pragmatic_austria
+ case P_SAXONY:
+ if (is_saxony_prussian())
+ return all_powers_france_bavaria_pragmatic_austria
+ return all_powers_france_bavaria_prussia_pragmatic
case P_PRAGMATIC:
case P_AUSTRIA:
+ if (is_saxony_austrian())
+ return all_powers_france_bavaria_prussia
return all_powers_france_bavaria_prussia_saxony
}
}
function all_coop_generals(pow) {
- switch (pow) {
+ switch (coop_major_power(pow)) {
case P_FRANCE:
- case P_BAVARIA:
return all_france_bavaria_generals
case P_PRUSSIA:
- case P_SAXONY:
- return all_prussia_saxony_generals
+ if (is_saxony_prussian())
+ return all_prussia_saxony_generals
+ return all_power_generals[P_PRUSSIA]
case P_PRAGMATIC:
case P_AUSTRIA:
+ if (is_saxony_austrian())
+ return all_austria_pragmatic_saxony_generals
return all_austria_pragmatic_generals
}
}
-function all_controlled_generals(pow) {
- switch (pow) {
- case P_FRANCE:
- case P_BAVARIA:
- return all_france_bavaria_generals
- case P_PRUSSIA:
- case P_SAXONY:
- return all_prussia_saxony_generals
- case P_PRAGMATIC:
- return all_power_generals[P_PRAGMATIC]
- case P_AUSTRIA:
- return all_power_generals[P_AUSTRIA]
- }
+function all_france_allied_generals() {
+ if (is_saxony_prussian())
+ return all_france_bavaria_prussia_saxony_generals
+ return all_france_bavaria_prussia_generals
}
-function all_controlled_trains(pow) {
- switch (pow) {
- case P_FRANCE:
- case P_BAVARIA:
- return all_france_bavaria_trains
- case P_PRUSSIA:
- case P_SAXONY:
- return all_prussia_saxony_trains
- case P_PRAGMATIC:
- return all_power_trains[P_PRAGMATIC]
- case P_AUSTRIA:
- return all_power_trains[P_AUSTRIA]
- }
+function all_france_allied_trains() {
+ if (is_saxony_prussian())
+ return all_france_bavaria_prussia_saxony_trains
+ return all_france_bavaria_prussia_trains
+}
+
+function all_austria_allied_generals() {
+ if (is_saxony_austrian())
+ return all_austria_pragmatic_saxony_generals
+ return all_austria_pragmatic_generals
+}
+
+function all_austria_allied_trains() {
+ if (is_saxony_austrian())
+ return all_austria_pragmatic_saxony_trains
+ return all_austria_pragmatic_trains
}
function all_allied_trains(pow) {
- switch (pow) {
+ switch (coop_major_power(pow)) {
case P_FRANCE:
- case P_BAVARIA:
case P_PRUSSIA:
- case P_SAXONY:
- return all_france_allied_trains
+ return all_france_allied_trains()
case P_AUSTRIA:
case P_PRAGMATIC:
- return all_austria_allied_trains
+ return all_austria_allied_trains()
}
}
function all_enemy_trains(pow) {
- switch (pow) {
+ switch (coop_major_power(pow)) {
case P_FRANCE:
- case P_BAVARIA:
case P_PRUSSIA:
- case P_SAXONY:
- return all_austria_allied_trains
+ return all_austria_allied_trains()
case P_AUSTRIA:
case P_PRAGMATIC:
- return all_france_allied_trains
+ return all_france_allied_trains()
}
}
function all_enemy_generals(pow) {
- switch (pow) {
+ switch (coop_major_power(pow)) {
case P_FRANCE:
- case P_BAVARIA:
case P_PRUSSIA:
- case P_SAXONY:
- return all_austria_allied_generals
+ return all_austria_allied_generals()
case P_AUSTRIA:
case P_PRAGMATIC:
- return all_france_allied_generals
+ return all_france_allied_generals()
}
}
@@ -675,6 +735,18 @@ function is_home_country(s) {
}
}
+function is_home_country_for_return(s) {
+ // TODO: Silesia
+ switch (game.power) {
+ case P_FRANCE: return set_has(data.country.France, s) || set_has(data.country.Bavaria, s)
+ case P_PRUSSIA: return set_has(data.country.Prussia, s)
+ case P_PRAGMATIC: return set_has(data.country.Netherlands, s)
+ case P_AUSTRIA: return set_has(data.country.Austria, s)
+ case P_BAVARIA: return set_has(data.country.Bavaria, s)
+ case P_SAXONY: return set_has(data.country.Saxony, s)
+ }
+}
+
function is_enemy_home_country(s) {
for (let other of all_enemy_powers(game.power))
if (set_has(all_home_country_fortresses[other], s))
@@ -816,7 +888,10 @@ function player_from_power(pow) {
case P_AUSTRIA:
return R_MARIA_THERESA
case P_SAXONY:
- return R_FREDERICK
+ if (is_saxony_prussian())
+ return R_FREDERICK
+ else
+ return R_MARIA_THERESA
case P_BAVARIA:
return R_LOUIS_XV
}
@@ -1360,8 +1435,9 @@ function set_in_supply(p) {
}
function search_supply_path_avoid_hussars(who) {
+ let pow = piece_power[who]
let from = game.pos[who]
- let trains = all_power_trains[piece_power[who]]
+ let trains = all_power_trains[pow]
if (is_home_country(from))
return 1
@@ -1382,6 +1458,8 @@ function search_supply_path_avoid_hussars(who) {
continue
if (has_enemy_piece(next))
continue
+ if (is_forbidden_neutral_space(pow, next))
+ continue
set_add(seen, next)
if (dist < 6)
queue.push((next << 4) | dist)
@@ -1392,8 +1470,9 @@ function search_supply_path_avoid_hussars(who) {
}
function search_supply_path(who) {
+ let pow = piece_power[who]
let from = game.pos[who]
- let trains = all_power_trains[piece_power[who]]
+ let trains = all_power_trains[pow]
if (who === ARENBERG) {
if (set_has(data.country.Netherlands, from))
@@ -1418,6 +1497,8 @@ function search_supply_path(who) {
continue
if (has_enemy_piece(next))
continue
+ if (is_forbidden_neutral_space(pow, next))
+ continue
set_add(seen, next)
if (dist < 6)
queue.push((next << 4) | dist)
@@ -1708,19 +1789,44 @@ function goto_movement() {
game.move_conq = []
}
+function is_forbidden_neutral_space(pow, to) {
+ if (is_saxony_neutral()) {
+ if (pow === P_SAXONY)
+ return !set_has(data.country.Saxony, to)
+ else
+ return set_has(data.country.Saxony, to)
+ }
+ if (is_prussia_neutral()) {
+ // TODO: Silesia home country
+ if (pow === P_PRUSSIA)
+ return !set_has(data.country.Prussia, to)
+ else
+ return set_has(data.country.Prussia, to)
+ }
+ return false
+}
+
+function can_move_piece_to(p, from, to) {
+ if (is_general(p))
+ return can_move_general_to(p, from, to)
+ return can_move_train_to(p, from, to)
+}
+
function can_train_move_anywhere(p) {
let from = game.pos[p]
for (let to of data.cities.adjacent[from])
- if (can_move_train_to(to))
+ if (can_move_train_to(p, from, to))
return true
return false
}
function can_general_move_anywhere(p) {
let from = game.pos[p]
+ console.log("MOVE CHEK", p, piece_abbr[p])
for (let to of data.cities.adjacent[from])
- if (can_move_general_to(from, to))
+ if (can_move_general_to(p, from, to))
return true
+ console.log(" fail")
return false
}
@@ -1730,7 +1836,10 @@ states.movement = {
let done_generals = true
let done_trains = true
+console.log("MOVE", game.moved, all_controlled_generals(game.power))
+
for (let p of all_controlled_generals(game.power)) {
+ console.log(">P", piece_abbr[p])
if (!set_has(game.moved, p) && is_piece_on_map(p)) {
if (can_general_move_anywhere(p)) {
gen_action_piece(p)
@@ -1821,7 +1930,11 @@ function format_move(max) {
return ` up to ${n} cities.`
}
-function can_move_train_to(to) {
+function can_move_train_to(p, from, to) {
+ if (is_forbidden_neutral_space(piece_power[p], to))
+ return false
+ if (is_illegal_cross_map_move(from, to))
+ return false
return !has_any_piece(to)
}
@@ -1834,7 +1947,9 @@ function is_illegal_cross_map_move(from, to) {
)
}
-function can_move_general_to(from, to) {
+function can_move_general_to(p, from, to) {
+ if (is_forbidden_neutral_space(piece_power[p], to))
+ return false
if (is_illegal_cross_map_move(from, to))
return false
if (has_friendly_supply_train(to))
@@ -1909,11 +2024,11 @@ states.move_supply_train = {
if (game.count < 2 + game.main)
for (let next of data.cities.main_roads[here])
- if (!has_any_piece(next))
+ if (can_move_train_to(who, here, next))
gen_action_space(next)
if (game.count < 2)
for (let next of data.cities.roads[here])
- if (!has_any_piece(next))
+ if (can_move_train_to(who, here, next))
gen_action_space(next)
if (game.count > 0)
@@ -1983,12 +2098,12 @@ states.move_general = {
if (game.count < 3 + game.main)
for (let next of data.cities.main_roads[here])
- if (can_move_general_to(here, next))
+ if (can_move_general_to(who, here, next))
gen_action_space_or_piece(next)
if (game.count < 3)
for (let next of data.cities.roads[here])
- if (can_move_general_to(here, next))
+ if (can_move_general_to(who, here, next))
gen_action_space_or_piece(next)
},
take() {
@@ -2034,7 +2149,7 @@ function is_adjacent_to_enemy_piece(here) {
return false
}
-function search_force_march(came_from, start) {
+function search_force_march(p, came_from, start) {
let seen = [ start ]
let queue = [ start << 4 ]
while (queue.length > 0) {
@@ -2050,7 +2165,7 @@ function search_force_march(came_from, start) {
continue
if (is_adjacent_to_enemy_piece(next))
continue
- if (!can_move_general_to(here, next))
+ if (!can_move_general_to(p, here, next))
continue
if (came_from)
map_set(came_from, next, here)
@@ -2071,14 +2186,14 @@ states.force_march = {
view.selected = game.selected
let here = game.pos[game.selected]
- for (let s of search_force_march(null, here))
+ for (let s of search_force_march(game.selected, null, here))
gen_action_space(s)
},
space(to) {
let here = game.pos[game.selected]
let came_from = []
- search_force_march(came_from, here)
+ search_force_march(game.selected, came_from, here)
let path = []
while (to !== here) {
@@ -2335,17 +2450,9 @@ states.re_enter_train_where = {
gen_re_enter_train_at_power_fortress(coop_minor_power(game.power))
},
space(to) {
- game.pos[game.selected] = to
+ enter_train_at(game.selected, to)
game.selected = -1
game.state = "re_enter_train"
-
- // remove hussars
- for (let p of all_hussars) {
- if (game.pos[p] === to) {
- log("P" + p + " removed.")
- game.pos[p] = ELIMINATED
- }
- }
},
}
@@ -2554,6 +2661,18 @@ function enter_general_at(p, s) {
}
}
+function enter_train_at(p, s) {
+ game.pos[p] = s
+
+ // remove hussars
+ for (let p of all_hussars) {
+ if (game.pos[p] === s) {
+ log("P" + p + " removed.")
+ game.pos[p] = ELIMINATED
+ }
+ }
+}
+
states.re_enter_general_where = {
inactive: "recruit",
prompt() {
@@ -2614,6 +2733,12 @@ function end_recruit() {
log("Recruited nothing.")
}
+ if (game.special_saxony_recruit) {
+ delete game.special_saxony_recruit
+ end_saxony_neutral()
+ return
+ }
+
end_winter_stage()
}
@@ -2623,13 +2748,19 @@ function goto_combat() {
let from = []
let to = []
- for (let p of all_controlled_generals(game.power))
+ for (let p of all_controlled_generals(game.power)) {
+ if (piece_power[p] === P_SAXONY && is_saxony_neutral())
+ continue
if (is_piece_on_map(p))
set_add(from, game.pos[p])
+ }
- for (let p of all_enemy_generals(game.power))
+ for (let p of all_enemy_generals(game.power)) {
+ if (piece_power[p] === P_SAXONY && is_saxony_neutral())
+ continue
if (is_piece_on_map(p))
set_add(to, game.pos[p])
+ }
game.combat = []
for (let a of from) {
@@ -3583,6 +3714,8 @@ function end_politics() {
}
}
+ game.stage = 100 // hack for saxony's defection return
+
goto_adjust_political_tracks()
}
@@ -3677,7 +3810,6 @@ function end_execute_political_card() {
}
const TRACK_NAME = { saxony: "Saxony marker", russia: "Russia marker", italy: "Italy marker" }
-const TRACK_SIZE = { saxony: 5, russia: 9, italy: 9 }
states.political_shift = {
inactive: "execute political card",
@@ -3739,7 +3871,6 @@ states.political_troop_power = {
states.political_troops_draw = {
inactive: "execute political card",
prompt() {
- let info = event_troops[current_political_effect()]
prompt("Draw " + format_card_list_prompt(game.draw) + ".")
view.draw = game.draw
view.actions.next = 1
@@ -3759,7 +3890,6 @@ states.political_troops_draw = {
states.political_troops_place = {
inactive: "execute political card",
prompt() {
- let info = event_troops[current_political_effect()]
if (game.count > 1)
prompt("Recieve " + game.count + " troops.")
else if (game.count === 1)
@@ -3832,6 +3962,7 @@ states.saxony_shift = {
view.actions.pass = 1
},
shift(_) {
+ clear_undo()
log("Saxony marker shifted " + game.count + " right.")
let save_saxony = game.saxony
game.saxony = Math.max(1, Math.min(5, game.saxony + game.count))
@@ -3839,13 +3970,15 @@ states.saxony_shift = {
// Saxony defection
if (save_saxony < 3 && is_saxony_neutral())
- throw "TODO Saxony became neutral!"
+ goto_saxony_becomes_neutral()
else if (save_saxony < 5 && is_saxony_austrian_ally())
- throw "TODO Saxony became austrian!"
+ goto_saxony_becomes_austrian_ally()
else
next_combat()
},
pass() {
+ clear_undo()
+
log("Saxony marker not shifted.")
game.count = 0
next_combat()
@@ -3898,13 +4031,232 @@ function goto_saxony_defection() {
delete game.save_saxony
if (save_saxony < 3 && is_saxony_neutral())
- throw "TODO Saxony became neutral!"
+ goto_saxony_becomes_neutral()
else if (save_saxony < 5 && is_saxony_austrian_ally())
- throw "TODO Saxony became austrian!"
+ goto_saxony_becomes_austrian_ally()
end_adjust_political_tracks()
}
+/* SAXONY'S DEFECTION */
+
+function search_nearest_city(p) {
+ let from = game.pos[p]
+ let result = []
+ let min_dist = 1000
+
+ let seen = [ from ]
+ let queue = [ from << 4 ]
+ while (queue.length > 0) {
+ let item = queue.shift()
+ let here = item >> 4
+ let dist = (item & 15) + 1
+ for (let next of data.cities.adjacent[here]) {
+ if (set_has(seen, next))
+ continue
+ set_add(seen, next)
+
+ if (can_move_piece_to(p, from, next)) {
+ if (dist <= min_dist) {
+ min_dist = dist
+ set_add(result, next)
+ }
+ }
+
+ if (dist < min_dist)
+ queue.push((next << 4) | dist)
+ }
+ }
+
+ return result
+}
+
+function search_nearest_home_city(p) {
+ let from = game.pos[p]
+ let result = []
+ let min_dist = 1000
+
+ let seen = [ from ]
+ let queue = [ from << 4 ]
+ while (queue.length > 0) {
+ let item = queue.shift()
+ let here = item >> 4
+ let dist = (item & 15) + 1
+ for (let next of data.cities.adjacent[here]) {
+ if (set_has(seen, next))
+ continue
+ set_add(seen, next)
+
+ if (is_home_country_for_return(next)) {
+ if (can_move_piece_to(p, from, next)) {
+ if (dist <= min_dist) {
+ min_dist = dist
+ set_add(result, next)
+ }
+ }
+ }
+
+ if (dist < min_dist)
+ queue.push((next << 4) | dist)
+ }
+ }
+
+ return result
+}
+
+function power_has_any_piece_in_list(pow, list) {
+ for (let p of all_power_generals[pow])
+ if (set_has(list, game.pos[p]))
+ return true
+ for (let p of all_power_trains[pow])
+ if (set_has(list, game.pos[p]))
+ return true
+}
+
+function goto_saxony_becomes_neutral() {
+ set_active_to_power(P_SAXONY)
+
+ log_br()
+ log("Saxony becomes neutral!")
+
+ // Return all victory markers
+ log(">Removed victory markers")
+ for (let s of all_home_country_fortresses[P_SAXONY]) {
+ let pow = map_get(game.victory, s, -1)
+ if (pow >= 0) {
+ map_delete(game.victory, s)
+ }
+ }
+
+ goto_saxony_return_foreign_pieces()
+}
+
+function goto_saxony_return_foreign_pieces() {
+ for (let pow of all_powers) {
+ if (pow === P_SAXONY)
+ continue
+ if (power_has_any_piece_in_list(pow, data.country.Saxony)) {
+ set_active_to_power(pow)
+ game.state = "saxony_return_foreign_who"
+ return
+ }
+ }
+
+ set_active_to_power(P_SAXONY)
+ game.state = "saxony_return_home"
+}
+
+states.saxony_return_foreign_who = {
+ inactive: "return foreign pieces from Saxony",
+ prompt() {
+ prompt("Return pieces to the nearest city in their home country.")
+ for (let p of all_power_generals[game.power])
+ if (set_has(data.country.Saxony, game.pos[p]))
+ gen_action_piece(p)
+ for (let p of all_power_trains[game.power])
+ if (set_has(data.country.Saxony, game.pos[p]))
+ gen_action_piece(p)
+ },
+ piece(p) {
+ game.selected = p
+ game.state = "saxony_return_foreign_where"
+ },
+}
+
+states.saxony_return_foreign_where = {
+ inactive: "return foreign pieces from Saxony",
+ prompt() {
+ prompt("Return pieces to the nearest city in their home country.")
+ view.selected = game.selected
+ for (let s of search_nearest_home_city(game.selected))
+ gen_action_space(s)
+ },
+ space(s) {
+ log(">P" + game.selected + " to S" + s)
+ if (is_general(game.selected))
+ enter_general_at(game.selected, s)
+ else
+ enter_train_at(game.selected, s)
+ game.selected = -1
+ goto_saxony_return_foreign_pieces()
+ },
+}
+
+states.saxony_return_home = {
+ inactive: "become neutral",
+ prompt() {
+ prompt("Return pieces to their set-up cities.")
+ let done = true
+ for (let p of [ SAXONY_GENERAL, SAXONY_TRAIN ]) {
+ if (is_piece_on_map(p) && game.pos[p] !== setup_piece_position[p]) {
+ gen_action_piece(p)
+ done = false
+ }
+ }
+ if (done)
+ view.actions.next = 1
+ },
+ piece(p) {
+ let s = setup_piece_position[p]
+ game.pos[p] = s
+ log(">P" + p + " to S" + s)
+ },
+ next() {
+ end_saxony_neutral()
+ },
+}
+
+function goto_saxony_becomes_austrian_ally() {
+ set_active_to_power(P_SAXONY)
+
+ log_br()
+ log("Saxony becomes Austrian ally!")
+
+ game.selected = SAXONY_GENERAL
+
+ if (game.pos[SAXONY_GENERAL] === ELIMINATED) {
+ game.special_saxony_recruit = 1
+ goto_recruit()
+ throw "STOP TEST"
+ return
+ }
+
+ if (has_general_of_power(game.pos[SAXONY_GENERAL], P_PRUSSIA))
+ game.state = "saxony_move_general"
+ else
+ end_saxony_neutral()
+}
+
+states.saxony_move_general = {
+ inactive: "re-enter general",
+ prompt() {
+ prompt("Move " + format_selected() + " to the nearest empty city.")
+ view.selected = game.selected
+ for (let s of search_nearest_city(game.selected))
+ gen_action_space(s)
+ },
+ space(s) {
+ log(">P" + game.selected + " to S" + s)
+ enter_general_at(game.selected, s)
+ end_saxony_neutral()
+ },
+}
+
+function end_saxony_neutral() {
+ game.selected = -1
+ if (game.stage === 100)
+ end_adjust_political_tracks()
+ else
+ next_combat()
+}
+
+/* NEUTRALITY */
+
+function is_prussia_neutral() {
+ // TODO
+ return false
+}
+
/* SETUP */
const POWER_FROM_SETUP_STAGE = [