summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-05-07 15:00:52 +0200
committerTor Andersson <tor@ccxvii.net>2023-05-24 21:06:18 +0200
commit06baa3704a7e7466fb5fca11aba6a81a43f5ea3a (patch)
tree191f01e810b1db96c702eeb65914b9a63ecd257a
parentdff733bdbae936c674628a7cc88c08c0feef9d05 (diff)
downloadred-flag-over-paris-06baa3704a7e7466fb5fca11aba6a81a43f5ea3a.tar.gz
Events.
-rw-r--r--play.js27
-rw-r--r--rules.js1073
2 files changed, 1044 insertions, 56 deletions
diff --git a/play.js b/play.js
index 4d3bffb..af717c9 100644
--- a/play.js
+++ b/play.js
@@ -313,7 +313,7 @@ function layout_disc(s, disc) {
disc.classList.remove("hide")
disc.style.left = (space_layout_disc[s].x - 50 - 12) + "px"
disc.style.top = (space_layout_disc[s].y - 20 - 8) + "px"
- disc.style.zIndex = 51;
+ disc.style.zIndex = 51
}
else
disc.classList.add("hide")
@@ -411,11 +411,11 @@ function on_update() {
for (let i = 0; i < 36; ++i) {
if (view.pieces[i] >= 0) {
layout[view.pieces[i]].push(ui.cubes[i])
- ui.cubes[i].classList.remove("hide");
+ ui.cubes[i].classList.remove("hide")
ui.cubes[i].classList.toggle("action", is_piece_action(i))
}
else {
- ui.cubes[i].classList.add("hide");
+ ui.cubes[i].classList.add("hide")
}
}
for (let i = 0; i < space_count; ++i) {
@@ -432,28 +432,31 @@ function on_update() {
ui.cards[i].classList.toggle("selected", i === view.selected_card)
}
- action_button("commune", "Commune");
- action_button("versailles", "Versailles");
+ action_button("commune", "Commune")
+ action_button("versailles", "Versailles")
- action_button("spend", "Spend");
- action_button("draw", "Draw");
+ action_button("spend", "Spend")
+ action_button("draw", "Draw")
action_button("momentum", "Momentum")
action_button("event", "Event")
action_button("political", "Political")
action_button("military", "Military")
+ action_button("public_opinion", "Public Opinion")
+ action_button("paris", "Paris")
action_button("ops", "Operations")
action_button("place", "Place")
action_button("remove", "Remove")
action_button("replace", "Replace")
- action_button("end_remove", "End Remove");
- action_button("end_turn", "End Turn");
+ action_button("end_remove", "End Remove")
+ action_button("end_ops", "End Operations")
+ action_button("end_event", "End Event")
- action_button("skip", "Skip");
- action_button("done", "Done");
- action_button("undo", "Undo");
+ action_button("skip", "Skip")
+ action_button("done", "Done")
+ action_button("undo", "Undo")
}
build_user_interface()
diff --git a/rules.js b/rules.js
index 40853de..ac7e15e 100644
--- a/rules.js
+++ b/rules.js
@@ -159,6 +159,8 @@ const first_space = NATIONAL_ASSEMBLY
const last_space = PERE_LACHAISE
const space_count = last_space + 1
+const ANY = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
+
const POLITICAL = [
NATIONAL_ASSEMBLY,
ROYALISTS,
@@ -177,28 +179,6 @@ const MILITARY = [
PERE_LACHAISE,
]
-function is_political_space(s) {
- return (
- s === NATIONAL_ASSEMBLY ||
- s === ROYALISTS ||
- s === REPUBLICANS ||
- s === PRESS ||
- s === CATHOLIC_CHURCH ||
- s === SOCIAL_MOVEMENTS
- )
-}
-
-function is_military_space(s) {
- return (
- s === MONT_VALERIEN ||
- s === FORT_D_ISSY ||
- s === CHATEAU_DE_VINCENNES ||
- s === BUTTE_MONTMARTRE ||
- s === BUTTE_AUX_CAILLES ||
- s === PERE_LACHAISE
- )
-}
-
const INSTITUTIONAL = [ NATIONAL_ASSEMBLY, ROYALISTS, REPUBLICANS ]
const PUBLIC_OPINION = [ PRESS, CATHOLIC_CHURCH, SOCIAL_MOVEMENTS ]
@@ -239,6 +219,28 @@ const ADJACENT_FROM = [
[ MONT_VALERIEN, FORT_D_ISSY ],
]
+function is_political_space(s) {
+ return (
+ s === NATIONAL_ASSEMBLY ||
+ s === ROYALISTS ||
+ s === REPUBLICANS ||
+ s === PRESS ||
+ s === CATHOLIC_CHURCH ||
+ s === SOCIAL_MOVEMENTS
+ )
+}
+
+function is_military_space(s) {
+ return (
+ s === MONT_VALERIEN ||
+ s === FORT_D_ISSY ||
+ s === CHATEAU_DE_VINCENNES ||
+ s === BUTTE_MONTMARTRE ||
+ s === BUTTE_AUX_CAILLES ||
+ s === PERE_LACHAISE
+ )
+}
+
// === GAME STATE ===
function discard_card(c) {
@@ -296,9 +298,37 @@ function can_advance_momentum() {
}
function can_play_event(c) {
- if (game.active === COMMUNE)
- return is_commune_card(c) || is_neutral_card(c)
- return is_versailles_card(c) || is_neutral_card(c)
+ if (game.active === COMMUNE && is_versailles_card(c))
+ return false
+ if (game.active === VERSAILLES && is_commune_card(c))
+ return false
+
+ // Cards 38 through 41 can only be played if you have the initiative
+ if (c >= 38 && c <= 41)
+ if (game.active !== game.initiative)
+ return false
+
+ // Otto von Bismarck - must remove blue cube from National Assembly
+ if (c === 12)
+ if (!has_versailles_cube(NATIONAL_ASSEMBLY))
+ return false
+
+ // Le Reveil - cannot be played if Socialist Newspaper Ban
+ if (c === 21)
+ if (game.snb)
+ return false
+
+ // Victor Hugo - must decrease both player momentums
+ if (c === 38)
+ if (game.red_momentum < 1 || game.blue_momentum < 1)
+ return false
+
+ // Freemason Parade - must remove red & blue cubes from one Military space
+ if (c === 41)
+ if (!can_play_freemason_parade())
+ return false
+
+ return true
}
var c_count = new Array(space_count).fill(0)
@@ -442,6 +472,12 @@ function count_friendly_cubes(s) {
return count_versailles_cubes(s)
}
+function count_friendly_discs(s) {
+ if (game.active === COMMUNE)
+ return count_commune_discs(s)
+ return count_versailles_discs(s)
+}
+
function count_enemy_pieces(s) {
if (game.active === COMMUNE)
return count_versailles_pieces(s)
@@ -500,6 +536,18 @@ function find_friendly_disc(s) {
return find_versailles_disc(s)
}
+function find_available_disc() {
+ return find_friendly_disc(-1)
+}
+
+function has_commune_cube(s) {
+ return find_commune_cube(s) >= 0
+}
+
+function has_versailles_cube(s) {
+ return find_versailles_cube(s) >= 0
+}
+
function has_enemy_cube(s) {
return find_enemy_cube(s) >= 0
}
@@ -524,6 +572,23 @@ function is_disc(p) {
return p >= 36
}
+function can_place_cube(s) {
+ console.log("can_place_cube", s, find_available_cube(), count_friendly_cubes(s))
+ return find_available_cube() >= 0 && count_friendly_cubes(s) < 4
+}
+
+function can_place_disc(s) {
+ return find_available_disc() >= 0 && count_friendly_discs(s) < 1
+}
+
+function can_replace_cube(s) {
+ return has_enemy_cube(s) && can_place_cube(s)
+}
+
+function can_remove_cube(s) {
+ return has_enemy_cube(s)
+}
+
function remove_piece(p) {
if (is_commune_cube(p)) {
if (game.red_momentum >= 1 && count_commune_cubes(RED_CUBE_POOL[0]) < 2)
@@ -549,6 +614,14 @@ function place_piece(p, s) {
game.pieces[p] = s
}
+function place_cube(s) {
+ game.pieces[find_available_cube()] = s
+}
+
+function place_disc(s) {
+ game.pieces[find_available_disc()] = s
+}
+
function find_available_cube() {
let p = -1
if (game.active === COMMUNE) {
@@ -635,6 +708,10 @@ function versailles_political_vp() {
return -game.political_vp
}
+function where_present(list) {
+ return list.filter(s => is_present(s))
+}
+
// === CHOOSE OBJECTIVE CARD ===
states.choose_objective_card = {
@@ -798,21 +875,25 @@ states.play_card = {
gen_action_card(final)
},
event() {
+ push_undo()
log("Event.")
discard_card(game.what)
goto_play_event(game.what)
},
political() {
+ push_undo()
log("Ops.")
discard_card(game.what)
goto_operations(card_ops[game.what], POLITICAL)
},
military() {
+ push_undo()
log("Ops.")
discard_card(game.what)
goto_operations(card_ops[game.what], MILITARY)
},
momentum() {
+ push_undo()
log(`Momentum.`)
if (game.scenario === "Censorship")
recycle_card(game.what)
@@ -830,6 +911,7 @@ states.play_card = {
this.momentum()
},
card(c) {
+ push_undo()
log(`Discarded for #${c}.`)
if (c === game.discard) {
discard_card(game.what)
@@ -851,10 +933,12 @@ states.play_final = {
view.actions.military = 1
},
political() {
+ push_undo()
discard_final()
goto_operations(4, POLITICAL)
},
military() {
+ push_undo()
discard_final()
goto_operations(4, MILITARY)
},
@@ -873,6 +957,7 @@ function advance_revolutionary_momentum(x) {
game.red_momentum += x
for (let i = game.red_momentum; i < 3; ++i)
for_each_commune_cube(RED_CUBE_POOL[i], p => game.pieces[p] = -1)
+ game.momentum_active = game.active
game.active = VERSAILLES
if (x > 0 && game.red_momentum >= 2)
game.state = "revolutionary_momentum_trigger"
@@ -884,6 +969,7 @@ function advance_prussian_collaboration(x) {
game.blue_momentum += x
for (let i = 0; i < game.blue_momentum; ++i)
for_each_versailles_cube(PRUSSIAN_COLLABORATION[i], p => game.pieces[p] = BLUE_CUBE_POOL)
+ game.momentum_active = game.active
game.active = COMMUNE
if (x > 0 && game.blue_momentum >= 2)
game.state = "prussian_collaboration_trigger"
@@ -895,11 +981,12 @@ states.revolutionary_momentum_trigger = {
prompt() {
view.prompt = "Revolutionary Momentum: Place a cube in an Institutional space."
for (let s of INSTITUTIONAL)
- gen_action_space(s)
+ if (can_place_cube(s))
+ gen_action_space(s)
view.actions.skip = 1
},
space(s) {
- place_piece(find_available_cube(), s)
+ place_cube(s)
end_momentum_trigger()
},
skip() {
@@ -911,11 +998,12 @@ states.prussian_collaboration_trigger = {
prompt() {
view.prompt = "Prussian Collaboration: Place a cube in a Public Opinion space."
for (let s of PUBLIC_OPINION)
- gen_action_space(s)
+ if (can_place_cube(s))
+ gen_action_space(s)
view.actions.skip = 1
},
space(s) {
- place_piece(find_available_cube(), s)
+ place_cube(s)
end_momentum_trigger()
},
skip() {
@@ -924,8 +1012,12 @@ states.prussian_collaboration_trigger = {
}
function end_momentum_trigger() {
- game.active = enemy_player()
- resume_strategy_phase()
+ game.active = game.momentum_active
+ delete game.momentum_active
+ if (game.vm)
+ vm_next()
+ else
+ resume_strategy_phase()
}
// === OPERATIONS ===
@@ -1121,11 +1213,11 @@ function can_operations_place() {
function can_operations_place_space(s) {
if (is_present(s) || is_adjacent_to_control(s)) {
- if (count_friendly_cubes(s) >= 4)
- return false
- let d = has_enemy_disc(s)
- if (!d || game.count >= 2)
- return true
+ if (can_place_cube(s)) {
+ let d = has_enemy_disc(s)
+ if (!d || game.count >= 2)
+ return true
+ }
}
return false
}
@@ -1136,7 +1228,7 @@ states.operations_place = {
for (let s of game.spaces)
if (can_operations_place_space(s))
gen_action_space(s)
- view.actions.end_turn = 1
+ view.actions.end_ops = 1
},
space(s) {
push_undo()
@@ -1144,10 +1236,10 @@ states.operations_place = {
game.count -= 2
else
game.count -= 1
- place_piece(find_available_cube(), s)
+ place_cube(s)
resume_operations_place()
},
- end_turn() {
+ end_ops() {
end_operations()
},
}
@@ -1166,9 +1258,9 @@ function goto_operations_done() {
states.operations_done = {
prompt() {
view.prompt = "Operations: All done."
- view.actions.end_turn = 1
+ view.actions.end_ops = 1
},
- end_turn() {
+ end_ops() {
end_operations()
},
}
@@ -1200,12 +1292,510 @@ function goto_pivotal_space_bonus_actions() {
// === EVENTS ===
function goto_play_event(c) {
- switch (c) {
- // TODO
- }
+ update_presence_and_control()
+ goto_vm(c)
+}
+
+function end_event() {
+ game.vm = null
resume_strategy_phase()
}
+function goto_vm(proc) {
+ game.state = "vm"
+ game.vm = {
+ prompt: 0,
+ fp: proc,
+ ip: 0,
+ }
+ vm_exec()
+}
+
+function event_prompt(str) {
+ if (typeof str === "undefined")
+ str = CODE[game.vm.fp][game.vm.prompt][1]
+ if (typeof str === "function")
+ str = str()
+ view.prompt = card_names[game.vm.fp] + ": " + str
+}
+
+function vm_inst(a) {
+ return CODE[game.vm.fp][game.vm.ip][a]
+}
+
+function vm_operand(a) {
+ let x = CODE[game.vm.fp][game.vm.ip][a]
+ if (a > 0 && typeof x === "function")
+ return x()
+ return x
+}
+
+function vm_exec() {
+ console.log("VM", game.vm.fp, game.vm.ip, vm_inst(0).name)
+ vm_inst(0)()
+}
+
+function vm_next() {
+ game.vm.ip ++
+ vm_exec()
+}
+
+function vm_asm() {
+ vm_operand(1)
+ vm_next()
+}
+
+function vm_goto() {
+ game.state = vm_operand(1)
+}
+
+function vm_return() {
+ game.state = "vm_return"
+}
+
+states.vm_return = {
+ prompt() {
+ event_prompt("All done.")
+ view.actions.end_event = 1
+ },
+ end_event,
+}
+
+function vm_if() {
+ if (!vm_operand(1)) {
+ let balance = 1
+ while (balance > 0) {
+ ++game.vm.ip
+ switch (vm_operand(0)) {
+ case vm_if:
+ ++balance
+ break
+ case vm_endif:
+ --balance
+ break
+ case vm_else:
+ if (balance === 1)
+ --balance
+ break
+ }
+ if (game.vm.ip < 0 || game.vm.ip > CODE[game.vm.fp].length)
+ throw "ERROR"
+ }
+ }
+ vm_next()
+}
+
+function vm_else() {
+ vm_goto(vm_endif, vm_if, 1, 1)
+}
+
+function vm_endif() {
+ vm_next()
+}
+
+function vm_endswitch() {
+ vm_next()
+}
+
+function vm_switch() {
+ game.vm.choice = null
+ game.state = "vm_switch"
+}
+
+function vm_case() {
+ if (game.vm.choice === vm_operand(1)) {
+ vm_next()
+ } else {
+ do
+ ++game.vm.ip
+ while (vm_inst(0) !== vm_case && vm_inst(0) !== vm_endswitch)
+ vm_exec()
+ }
+}
+
+function vm_player() {
+ // TODO: pause for undo?
+ game.active = vm_operand(1)
+ vm_next()
+}
+
+function vm_ops() {
+ goto_operations(vm_operand(1), vm_operand_spaces(2))
+}
+
+function vm_increase_revolutionary_momentum() {
+ if (game.red_momentum < 3)
+ game.state = "vm_increase_revolutionary_momentum"
+ else
+ vm_next()
+}
+
+function vm_increase_prussian_collaboration() {
+ if (game.blue_momentum < 3)
+ game.state = "vm_increase_prussian_collaboration"
+ else
+ vm_next()
+}
+
+function vm_decrease_revolutionary_momentum() {
+ if (game.red_momentum > 1)
+ game.state = "vm_decrease_revolutionary_momentum"
+ else
+ vm_next()
+}
+
+function vm_decrease_prussian_collaboration() {
+ if (game.blue_momentum > 1)
+ game.state = "vm_decrease_prussian_collaboration"
+ else
+ vm_next()
+}
+
+function vm_operand_spaces(x) {
+ let s = vm_operand(x)
+ if (typeof s === "number")
+ return [ s ]
+ return s
+}
+
+function vm_remove_up_to() {
+ game.vm.upto = 1
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ goto_vm_remove()
+}
+
+function vm_remove() {
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ goto_vm_remove()
+}
+
+function vm_remove_own() {
+ game.vm.spaces = vm_operand_spaces(1)
+ game.state = "vm_remove_own"
+}
+
+function vm_replace_up_to() {
+ game.vm.upto = 1
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ game.state = "vm_replace"
+ goto_vm_replace()
+}
+
+function vm_replace_different() {
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2).slice() // make a copy for safe mutation
+ game.state = "vm_replace_different"
+}
+
+function vm_replace() {
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ goto_vm_replace()
+}
+
+function vm_place_removed_up_to() {
+ game.vm.removed = 1
+ game.vm.upto = 1
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ goto_vm_place()
+}
+
+function vm_place_up_to() {
+ game.vm.upto = 1
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ goto_vm_place()
+}
+
+function vm_place() {
+ game.vm.count = vm_operand(1)
+ game.vm.spaces = vm_operand_spaces(2)
+ goto_vm_place()
+}
+
+function vm_may_place_disc() {
+ game.vm.upto = 1
+ game.vm.count = 1
+ game.vm.spaces = vm_operand_spaces(1)
+ game.state = "vm_place_disc"
+}
+
+function vm_place_disc() {
+ game.vm.count = 1
+ game.vm.spaces = vm_operand_spaces(1)
+ game.state = "vm_place_disc"
+}
+
+function vm_move_up_to() {
+ game.vm.count = 1
+ game.vm.a = vm_operand_spaces(1)
+ game.vm.b = vm_operand_spaces(2)
+ game.state = "vm_move"
+}
+
+function vm_move_between_up_to() {
+ game.vm.count = 1
+ game.vm.a = vm_operand_spaces(1)
+ game.vm.b = vm_operand_spaces(2)
+ game.state = "vm_move_between"
+}
+
+// === EVENT STATES ===
+
+states.vm_switch = {
+ prompt() {
+ event_prompt()
+ for (let choice of vm_operand(1)) {
+ if (choice === "mont_valerien")
+ gen_action_space(MONT_VALERIEN)
+ else if (choice === "butte_montmartre")
+ gen_action_space(BUTTE_MONTMARTRE)
+ else
+ view.actions[choice] = 1
+ }
+ },
+ place() {
+ push_undo()
+ game.vm.choice = "place"
+ vm_next()
+ },
+ replace() {
+ push_undo()
+ game.vm.choice = "replace"
+ vm_next()
+ },
+ remove() {
+ push_undo()
+ game.vm.choice = "remove"
+ vm_next()
+ },
+ momentum() {
+ push_undo()
+ game.vm.choice = "momentum"
+ vm_next()
+ },
+ ops() {
+ push_undo()
+ game.vm.choice = "ops"
+ vm_next()
+ },
+ public_opinion() {
+ push_undo()
+ game.vm.choice = "public_opinion"
+ vm_next()
+ },
+ paris() {
+ push_undo()
+ game.vm.choice = "paris"
+ vm_next()
+ },
+ space(s) {
+ push_undo()
+ if (s === MONT_VALERIEN)
+ game.vm.choice = "mont_valerien"
+ if (s === BUTTE_MONTMARTRE)
+ game.vm.choice = "butte_montmartre"
+ vm_next()
+ },
+}
+
+states.vm_increase_revolutionary_momentum = {
+ prompt() {
+ event_prompt("Increase Revolutionary Momentum.")
+ view.actions.red_momentum = 1
+ },
+ red_momentum() {
+ push_undo()
+ advance_revolutionary_momentum(1)
+ },
+}
+
+states.vm_increase_prussian_collaboration = {
+ prompt() {
+ event_prompt("Increase Prussian Collaboration.")
+ view.actions.blue_momentum = 1
+ },
+ blue_momentum() {
+ push_undo()
+ advance_prussian_collaboration(1)
+ },
+}
+
+states.vm_decrease_revolutionary_momentum = {
+ prompt() {
+ event_prompt("Decrease Revolutionary Momentum.")
+ view.actions.red_momentum = 1
+ },
+ red_momentum() {
+ push_undo()
+ advance_revolutionary_momentum(-1)
+ },
+}
+
+states.vm_decrease_prussian_collaboration = {
+ prompt() {
+ event_prompt("Decrease Prussian Collaboration.")
+ view.actions.blue_momentum = 1
+ },
+ blue_momentum() {
+ push_undo()
+ advance_prussian_collaboration(-1)
+ },
+}
+
+function can_vm_place() {
+ for (let s of game.vm.spaces)
+ if (can_place_cube(s))
+ return true
+ return false
+}
+
+function goto_vm_place() {
+ if (can_vm_place())
+ game.state = "vm_place"
+ else
+ vm_next()
+}
+
+states.vm_place = {
+ prompt() {
+ event_prompt("Place " + game.vm.count + " cube.")
+ if (game.vm.upto)
+ view.actions.skip = 1
+ for (let s of game.vm.spaces)
+ if (can_place_cube(s))
+ gen_action_space(s)
+ },
+ space(s) {
+ push_undo()
+ place_cube(s)
+ if (--game.vm.count === 0 || !can_vm_place())
+ vm_next()
+ },
+ skip() {
+ push_undo()
+ vm_next()
+ },
+}
+
+function can_vm_place_disc() {
+ for (let s of game.vm.spaces)
+ if (can_place_disc(s))
+ return true
+ return false
+}
+
+function goto_vm_place_disc() {
+ if (can_vm_place_disc())
+ game.state = "vm_place_disc"
+ else
+ vm_next()
+}
+
+states.vm_place_disc = {
+ prompt() {
+ event_prompt("Place a disc.")
+ if (game.vm.upto)
+ view.actions.skip = 1
+ for (let s of game.vm.spaces)
+ if (can_place_disc(s))
+ gen_action_space(s)
+ },
+ space(s) {
+ push_undo()
+ place_disc(s)
+ vm_next()
+ },
+ skip() {
+ push_undo()
+ vm_next()
+ },
+}
+
+function can_vm_replace() {
+ for (let s of game.vm.spaces)
+ if (can_replace_cube(s))
+ return true
+ return false
+}
+
+function goto_vm_replace() {
+ if (can_vm_replace())
+ game.state = "vm_replace"
+ else
+ vm_next()
+}
+
+states.vm_replace = {
+ prompt() {
+ event_prompt("Replace " + game.vm.count + " cubes.")
+ if (game.vm.upto)
+ view.actions.skip = 1
+ for (let s of game.vm.spaces)
+ if (can_replace_cube(s))
+ for_each_enemy_cube(s, gen_action_piece)
+ },
+ piece(p) {
+ push_undo()
+ let s = game.pieces[p]
+ remove_piece(p)
+ place_cube(s)
+ if (--game.vm.count === 0 || !can_vm_replace())
+ vm_next()
+ },
+ skip() {
+ push_undo()
+ vm_next()
+ },
+}
+
+function can_vm_remove() {
+ for (let s of game.vm.spaces)
+ if (can_remove_cube(s))
+ return true
+ return false
+}
+
+function goto_vm_remove() {
+ if (can_vm_remove())
+ game.state = "vm_remove"
+ else
+ vm_next()
+}
+
+states.vm_remove = {
+ prompt() {
+ event_prompt("Remove " + game.vm.count + " cubes.")
+ if (game.vm.upto)
+ view.actions.skip = 1
+ for (let s of game.vm.spaces)
+ if (can_remove_cube(s))
+ for_each_enemy_cube(s, gen_action_piece)
+ },
+ piece(p) {
+ push_undo()
+ remove_piece(p)
+ if (--game.vm.count === 0 || !can_vm_remove())
+ vm_next()
+ },
+ skip() {
+ push_undo()
+ vm_next()
+ },
+}
+
+// === COMPLICATED EVENT STATES ===
+
+function can_play_freemason_parade() {
+ for (let s of MILITARY)
+ if (has_commune_cube(s) && has_versailles_cube(s))
+ return true
+ return false
+}
// === SETUP ===
@@ -1760,3 +2350,398 @@ function map_delete(map, item) {
}
}
}
+
+// === GENERATED EVENT CODE ===
+
+const CODE = []
+
+CODE[1] = [ // Jules Ducatel
+ [ vm_if, ()=>(game.round === 4) ],
+ [ vm_goto, "reveal_commune_hand" ],
+ [ vm_else ],
+ [ vm_goto, "reveal_commune_objective" ],
+ [ vm_endif ],
+ [ vm_ops, 1, MILITARY ],
+ [ vm_return ],
+]
+
+CODE[2] = [ // The Murder of Vincenzini
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_remove_up_to, 3, POLITICAL ],
+ [ vm_return ],
+]
+
+CODE[3] = [ // Brassardiers
+ [ vm_replace, 1, ()=>(where_present(MILITARY)) ],
+ [ vm_return ],
+]
+
+CODE[4] = [ // Jules Ferry
+ [ vm_switch, ["place","replace"] ],
+ [ vm_case, "place" ],
+ [ vm_place_up_to, 2, REPUBLICANS ],
+ [ vm_case, "replace" ],
+ [ vm_replace, 1, NATIONAL_ASSEMBLY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[5] = [ // Le Figaro
+ [ vm_switch, ["place","replace"] ],
+ [ vm_case, "place" ],
+ [ vm_place_up_to, 2, PRESS ],
+ [ vm_case, "replace" ],
+ [ vm_replace, 1, PUBLIC_OPINION ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[6] = [ // Général Louis Valentin
+ [ vm_goto, "general_louis_valentin" ],
+ [ vm_return ],
+]
+
+CODE[7] = [ // Général Espivent
+ [ vm_remove_up_to, 2, SOCIAL_MOVEMENTS ],
+ [ vm_return ],
+]
+
+CODE[8] = [ // Les Amis de l'Ordre
+ [ vm_place, 2, PARIS ],
+ [ vm_return ],
+]
+
+CODE[9] = [ // Socialist Newspaper Ban
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_remove_up_to, 2, PRESS ],
+ [ vm_asm, ()=>game.snb=1 ],
+ [ vm_return ],
+]
+
+CODE[10] = [ // Fortification of Mont-Valérien
+ [ vm_place_up_to, 1, MONT_VALERIEN ],
+ [ vm_if, ()=>(is_control(MONT_VALERIEN)) ],
+ [ vm_may_place_disc, MONT_VALERIEN ],
+ [ vm_endif ],
+ [ vm_return ],
+]
+
+CODE[11] = [ // Adolphe Thiers
+ [ vm_increase_prussian_collaboration ],
+ [ vm_place_up_to, 2, ROYALISTS ],
+ [ vm_return ],
+]
+
+CODE[12] = [ // Otto von Bismarck
+ [ vm_remove_own, NATIONAL_ASSEMBLY ],
+ [ vm_increase_prussian_collaboration ],
+ [ vm_ops, 2, MILITARY ],
+ [ vm_return ],
+]
+
+CODE[13] = [ // Général Ernest de Cissey
+ [ vm_ops, 4, FORT_D_ISSY ],
+ [ vm_return ],
+]
+
+CODE[14] = [ // Colonel de Lochner
+ [ vm_switch, ["mont_valerien","butte_montmartre"] ],
+ [ vm_case, "mont_valerien" ],
+ [ vm_ops, 3, MONT_VALERIEN ],
+ [ vm_case, "butte_montmartre" ],
+ [ vm_ops, 3, BUTTE_MONTMARTRE ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[15] = [ // Jules Favre
+ [ vm_increase_prussian_collaboration ],
+ [ vm_place_up_to, 1, REPUBLICANS ],
+ [ vm_return ],
+]
+
+CODE[16] = [ // Hostage Decree
+ [ vm_remove, 20, CATHOLIC_CHURCH ],
+ [ vm_return ],
+]
+
+CODE[17] = [ // Maréchal Macmahon
+ [ vm_ops, 4, PARIS ],
+ [ vm_return ],
+]
+
+CODE[18] = [ // Paule Minck
+ [ vm_replace, 1, ()=>(where_present(MILITARY)) ],
+ [ vm_return ],
+]
+
+CODE[19] = [ // Walery Wroblewski
+ [ vm_place_disc, ()=>(where_present(PARIS)) ],
+ [ vm_return ],
+]
+
+CODE[20] = [ // Banque de France
+ [ vm_decrease_revolutionary_momentum ],
+ [ vm_place_up_to, 1, PARIS ],
+ [ vm_may_place_disc, PARIS ],
+ [ vm_return ],
+]
+
+CODE[21] = [ // Le Réveil
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_place_up_to, 1, PRESS ],
+ [ vm_return ],
+]
+
+CODE[22] = [ // Execution of Generals
+ [ vm_increase_prussian_collaboration ],
+ [ vm_replace_up_to, 2, ()=>(where_present(PARIS)) ],
+ [ vm_return ],
+]
+
+CODE[23] = [ // Les Cantinières
+ [ vm_place_removed_up_to, 2, ()=>(where_present(MILITARY)) ],
+ [ vm_return ],
+]
+
+CODE[24] = [ // Eugène Protot
+ [ vm_ops, 3, INSTITUTIONAL ],
+ [ vm_return ],
+]
+
+CODE[25] = [ // Paul Cluseret
+ [ vm_ops, 2, PARIS ],
+ [ vm_return ],
+]
+
+CODE[26] = [ // Gaston Crémieux
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_place_up_to, 2, SOCIAL_MOVEMENTS ],
+ [ vm_return ],
+]
+
+CODE[27] = [ // Luise Michel
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_switch, ["public_opinion","paris"] ],
+ [ vm_case, "public_opinion" ],
+ [ vm_ops, 1, PUBLIC_OPINION ],
+ [ vm_case, "paris" ],
+ [ vm_ops, 1, PARIS ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[28] = [ // Jaroslav Dombrowski
+ [ vm_place_up_to, 1, PARIS ],
+ [ vm_may_place_disc, PARIS ],
+ [ vm_return ],
+]
+
+CODE[29] = [ // Raoul Rigault
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_move_up_to, 2, CATHOLIC_CHURCH, PARIS ],
+ [ vm_return ],
+]
+
+CODE[30] = [ // Karl Marx
+ [ vm_goto, "karl_marx" ],
+ [ vm_return ],
+]
+
+CODE[31] = [ // Blanquists
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_ops, 2, MILITARY ],
+ [ vm_return ],
+]
+
+CODE[32] = [ // Général Lullier
+ [ vm_ops, 4, CHATEAU_DE_VINCENNES ],
+ [ vm_return ],
+]
+
+CODE[33] = [ // Jules Vallès
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_ops, 2, PUBLIC_OPINION ],
+ [ vm_return ],
+]
+
+CODE[34] = [ // Charles Delescluze
+ [ vm_switch, ["military","political"] ],
+ [ vm_case, "military" ],
+ [ vm_ops, 3, MILITARY ],
+ [ vm_case, "political" ],
+ [ vm_ops, 3, POLITICAL ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[35] = [ // Conciliation
+ [ vm_move_between_up_to, 2, PUBLIC_OPINION, PARIS ],
+ [ vm_return ],
+]
+
+CODE[36] = [ // Georges Clemenceau
+ [ vm_move_up_to, 3, PARIS, INSTITUTIONAL ],
+ [ vm_return ],
+]
+
+CODE[37] = [ // Archbishop Georges Darboy
+ [ vm_move_up_to, 4, ANY, CATHOLIC_CHURCH ],
+ [ vm_return ],
+]
+
+CODE[38] = [ // Victor Hugo
+ [ vm_decrease_revolutionary_momentum ],
+ [ vm_decrease_prussian_collaboration ],
+ [ vm_ops, 4, PUBLIC_OPINION ],
+ [ vm_return ],
+]
+
+CODE[39] = [ // Léon Gambetta
+ [ vm_replace_up_to, 1, INSTITUTIONAL ],
+ [ vm_if, ()=>(game.active === COMMUNE) ],
+ [ vm_decrease_prussian_collaboration ],
+ [ vm_else ],
+ [ vm_decrease_revolutionary_momentum ],
+ [ vm_endif ],
+ [ vm_return ],
+]
+
+CODE[40] = [ // Elihu Washburne
+ [ vm_if, ()=>(game.active === COMMUNE) ],
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_else ],
+ [ vm_increase_prussian_collaboration ],
+ [ vm_endif ],
+ [ vm_ops, 2, INSTITUTIONAL ],
+ [ vm_return ],
+]
+
+CODE[41] = [ // Freemason Parade
+ [ vm_goto, "freemason_parade" ],
+ [ vm_switch, ["place","replace"] ],
+ [ vm_case, "place" ],
+ [ vm_place_up_to, 2, INSTITUTIONAL ],
+ [ vm_case, "replace" ],
+ [ vm_replace, 1, INSTITUTIONAL ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[42] = [ // Paris Cannons
+ [ vm_switch, ["momentum","ops"] ],
+ [ vm_case, "momentum" ],
+ [ vm_if, ()=>(game.active === COMMUNE) ],
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_else ],
+ [ vm_increase_prussian_collaboration ],
+ [ vm_endif ],
+ [ vm_case, "ops" ],
+ [ vm_ops, 3, PARIS ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[43] = [ // Aux Barricades!
+ [ vm_ops, 2, PARIS ],
+ [ vm_player, COMMUNE ],
+ [ vm_may_place_disc, BUTTE_AUX_CAILLES ],
+ [ vm_return ],
+]
+
+CODE[44] = [ // Commune's Stronghold
+ [ vm_switch, ["ops","remove"] ],
+ [ vm_case, "ops" ],
+ [ vm_ops, 2, MILITARY ],
+ [ vm_case, "remove" ],
+ [ vm_remove, 1, ANY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[45] = [ // Fighting in Issy Village
+ [ vm_ops, 2, FORTS ],
+ [ vm_player, VERSAILLES ],
+ [ vm_may_place_disc, FORT_D_ISSY ],
+ [ vm_return ],
+]
+
+CODE[46] = [ // Battle of Mont-Valérien
+ [ vm_ops, 3, FORTS ],
+ [ vm_if, ()=>(game.current === COMMUNE) ],
+ [ vm_decrease_prussian_collaboration ],
+ [ vm_else ],
+ [ vm_increase_prussian_collaboration ],
+ [ vm_endif ],
+ [ vm_return ],
+]
+
+CODE[47] = [ // Raid on Château de Vincennes
+ [ vm_switch, ["ops","remove"] ],
+ [ vm_case, "ops" ],
+ [ vm_ops, 2, MILITARY ],
+ [ vm_case, "remove" ],
+ [ vm_remove, 1, ANY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[48] = [ // Revolution in the Press
+ [ vm_switch, ["ops","replace"] ],
+ [ vm_case, "ops" ],
+ [ vm_ops, 3, PUBLIC_OPINION ],
+ [ vm_case, "replace" ],
+ [ vm_replace, 1, ANY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[49] = [ // Pius IX
+ [ vm_switch, ["replace","remove"] ],
+ [ vm_case, "replace" ],
+ [ vm_replace_different, 2, POLITICAL ],
+ [ vm_case, "remove" ],
+ [ vm_remove, 1, ANY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[50] = [ // Socialist International
+ [ vm_ops, 2, PUBLIC_OPINION ],
+ [ vm_if, ()=>(game.current === COMMUNE) ],
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_else ],
+ [ vm_decrease_revolutionary_momentum ],
+ [ vm_endif ],
+ [ vm_return ],
+]
+
+CODE[51] = [ // Royalists Dissension
+ [ vm_switch, ["ops","remove"] ],
+ [ vm_case, "ops" ],
+ [ vm_ops, 2, INSTITUTIONAL ],
+ [ vm_case, "remove" ],
+ [ vm_remove, 1, ANY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[52] = [ // Rise of Republicanism
+ [ vm_switch, ["ops","replace"] ],
+ [ vm_case, "ops" ],
+ [ vm_ops, 3, INSTITUTIONAL ],
+ [ vm_case, "replace" ],
+ [ vm_replace, 1, MILITARY ],
+ [ vm_endswitch ],
+ [ vm_return ],
+]
+
+CODE[53] = [ // Legitimacy
+ [ vm_ops, 3, POLITICAL ],
+ [ vm_if, ()=>(game.active === COMMUNE) ],
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_else ],
+ [ vm_increase_prussian_collaboration ],
+ [ vm_endif ],
+ [ vm_return ],
+]