summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--create.html3
-rw-r--r--events.txt72
-rw-r--r--info/cards.html14
-rw-r--r--play.css20
-rw-r--r--play.js18
-rw-r--r--rules.js449
6 files changed, 508 insertions, 68 deletions
diff --git a/create.html b/create.html
index bcd5a34..e69de29 100644
--- a/create.html
+++ b/create.html
@@ -1,3 +0,0 @@
-<p>
-<label><input type="checkbox" name="censorship" value="true">Censorship Phase variant</label>
-</p>
diff --git a/events.txt b/events.txt
index 430b120..528f726 100644
--- a/events.txt
+++ b/events.txt
@@ -378,3 +378,75 @@ CARD 53 - Legitimacy
increase_prussian_collaboration
endif
+# C3i Censorship Cards
+
+CARD 54 - Louis Rossel
+ prompt "Move up to all cubes in Forts or Paris."
+ switch ["forts","paris"]
+ case "forts"
+ move_within FORTS
+ case "paris"
+ move_within PARIS
+ endswitch
+ # forbid General Lullier from being played
+ asm game.louis_rossel=1
+
+CARD 55 - Gustave Flourens
+ increase_revolutionary_momentum
+ prompt "Move up to 1 from Public Opinion to Military."
+ move_up_to 1 PUBLIC_OPINION MILITARY
+
+CARD 56 - Jean-Baptiste Clément
+ prompt "Place up to 2 in Public Opinion (use removed cubes)."
+ place_removed_up_to 2 PUBLIC_OPINION
+
+CARD 57 - Elizabeth Dimitrieff
+ asm clear_undo()
+ asm game.red_hand.push(draw_strategy_card())
+ asm game.red_hand.push(draw_strategy_card())
+ asm game.vm.count = 2
+ goto "elizabeth_dimitrieff_discard"
+
+CARD 58 - Paris Bombarded
+ asm init_paris_bombarded()
+ goto "paris_bombarded"
+
+CARD 59 - Général Gallifet
+ prompt "Remove up to 3 in Paris where present."
+ remove_up_to 3 (where_present(PARIS))
+ asm add_political_vp(VERSAILLES, -1)
+
+CARD 60 - Sapper Tactics
+ prompt "Remove one Barricade where present."
+ remove_disc (where_present(ANY))
+
+CARD 61 - Georges Vaysset
+ asm clear_undo()
+ asm log("Commune hand:")
+ asm { for (let c of game.red_hand) logi("C" + c) }
+ goto "georges_vaysset"
+
+CARD 62 - Colonne Vendôme
+ # must have initiative
+ if (game.active === COMMUNE)
+ decrease_prussian_collaboration
+ else
+ decrease_revolutionary_momentum
+ endif
+ prompt "Replace up to 1 in Institutional."
+ replace_up_to 1 INSTITUTIONAL
+
+CARD 63 - Versailles' Left
+ # must have initiative
+ prompt "Replace up to 1 in Republicans."
+ replace_up_to 1 REPUBLICANS
+ asm update_presence_and_control()
+ asm game.versailles_left = game.active
+ if (has_commune_cube(RED_BONUS_CUBES[2]))
+ if (game.active === COMMUNE && is_commune_control(REPUBLICANS))
+ goto "versailles_left"
+ endif
+ if (game.active === VERSAILLES && is_versailles_control(REPUBLICANS))
+ goto "versailles_left"
+ endif
+ endif
diff --git a/info/cards.html b/info/cards.html
index abd00f7..c7266ea 100644
--- a/info/cards.html
+++ b/info/cards.html
@@ -81,4 +81,18 @@ img {
<img src="../cards.1x/objective_12.jpg">
</div>
+<div class="list">
+<img src="../cards.1x/strategy_42.jpg">
+<img src="../cards.1x/bonus_1.jpg">
+<img src="../cards.1x/bonus_2.jpg">
+<img src="../cards.1x/bonus_3.jpg">
+<img src="../cards.1x/bonus_4.jpg">
+<img src="../cards.1x/bonus_5.jpg">
+<img src="../cards.1x/bonus_6.jpg">
+<img src="../cards.1x/bonus_7.jpg">
+<img src="../cards.1x/bonus_8.jpg">
+<img src="../cards.1x/bonus_9.jpg">
+<img src="../cards.1x/bonus_10.jpg">
+</div>
+
</body>
diff --git a/play.css b/play.css
index db3f5de..4d140ff 100644
--- a/play.css
+++ b/play.css
@@ -347,6 +347,16 @@ body.Versailles header.your_turn { background-color: hsl(199, 45%, 70%); }
.card_51{background-image:url(cards.1x/objective_10.jpg)}
.card_52{background-image:url(cards.1x/objective_11.jpg)}
.card_53{background-image:url(cards.1x/objective_12.jpg)}
+.card_54{background-image:url(cards.1x/bonus_1.jpg)}
+.card_55{background-image:url(cards.1x/bonus_2.jpg)}
+.card_56{background-image:url(cards.1x/bonus_3.jpg)}
+.card_57{background-image:url(cards.1x/bonus_4.jpg)}
+.card_58{background-image:url(cards.1x/bonus_5.jpg)}
+.card_59{background-image:url(cards.1x/bonus_6.jpg)}
+.card_60{background-image:url(cards.1x/bonus_7.jpg)}
+.card_61{background-image:url(cards.1x/bonus_8.jpg)}
+.card_62{background-image:url(cards.1x/bonus_9.jpg)}
+.card_63{background-image:url(cards.1x/bonus_10.jpg)}
@media (min-resolution:97dpi) {
.card_strategy_back{background-image:url(cards.2x/strategy_42.jpg)}
@@ -404,4 +414,14 @@ body.Versailles header.your_turn { background-color: hsl(199, 45%, 70%); }
.card_51{background-image:url(cards.2x/objective_10.jpg)}
.card_52{background-image:url(cards.2x/objective_11.jpg)}
.card_53{background-image:url(cards.2x/objective_12.jpg)}
+.card_54{background-image:url(cards.2x/bonus_1.jpg)}
+.card_55{background-image:url(cards.2x/bonus_2.jpg)}
+.card_56{background-image:url(cards.2x/bonus_3.jpg)}
+.card_57{background-image:url(cards.2x/bonus_4.jpg)}
+.card_58{background-image:url(cards.2x/bonus_5.jpg)}
+.card_59{background-image:url(cards.2x/bonus_6.jpg)}
+.card_60{background-image:url(cards.2x/bonus_7.jpg)}
+.card_61{background-image:url(cards.2x/bonus_8.jpg)}
+.card_62{background-image:url(cards.2x/bonus_9.jpg)}
+.card_63{background-image:url(cards.2x/bonus_10.jpg)}
}
diff --git a/play.js b/play.js
index 17df5ce..3e0300b 100644
--- a/play.js
+++ b/play.js
@@ -20,6 +20,8 @@ let ui = {
const card_names = [
"Initiative",
+
+ // Strategy
"Jules Ducatel",
"The Murder of Vincenzini",
"Brassardiers",
@@ -61,6 +63,8 @@ const card_names = [
"Léon Gambetta",
"Elihu Washburne",
"Freemason Parade",
+
+ // Objective
"Paris Cannons",
"Aux Barricades!",
"Commune's Stronghold",
@@ -73,6 +77,18 @@ const card_names = [
"Royalists Dissension",
"Rise of Republicanism",
"Legitimacy",
+
+ // Bonus Strategy
+ "Louis Rossel",
+ "Gustave Flourens",
+ "Jean-Baptiste Clément",
+ "Elizabeth Dimitrieff",
+ "Paris Bombarded",
+ "Général Gallifet",
+ "Sapper Tactics",
+ "Georges Vaysset",
+ "Colonne Vendôme",
+ "Versailles' Left",
]
const space_names = [
@@ -283,7 +299,7 @@ function build_user_interface() {
create("div", { className: "card card_objective_back" }),
]
- for (let c = 1; c <= 41 + 12; ++c) {
+ for (let c = 1; c <= 41 + 12 + 10; ++c) {
elt = ui.cards[c] = create("div", {
className: `card card_${c}`,
my_card: c,
diff --git a/rules.js b/rules.js
index 72165e7..aeecf6f 100644
--- a/rules.js
+++ b/rules.js
@@ -5,10 +5,11 @@ const VERSAILLES = "Versailles"
var game, view, states = {}
-exports.scenarios = [ "Standard" ]
-
+exports.scenarios = [ "Censorship", "Standard" ]
exports.roles = [ COMMUNE, VERSAILLES ]
+// === DATA ===
+
const first_commune_cube = 0
const last_commune_cube = 17
const first_versailles_cube = 18
@@ -19,10 +20,14 @@ const last_commune_disc = 37
const first_versailles_disc = 38
const last_versailles_disc = 39
+const BONUS = 53 // offset to bonus cards
+
const crisis_names = [ "Escalation", "Tension", "Final Crisis" ]
const card_names = [
"Initiative",
+
+ // Strategy
"Jules Ducatel",
"The Murder of Vincenzini",
"Brassardiers",
@@ -64,6 +69,8 @@ const card_names = [
"Léon Gambetta",
"Elihu Washburne",
"Freemason Parade",
+
+ // Objective
"Paris Cannons",
"Aux Barricades!",
"Commune's Stronghold",
@@ -76,6 +83,18 @@ const card_names = [
"Royalists Dissension",
"Rise of Republicanism",
"Legitimacy",
+
+ // Censorship Strategy
+ "Louis Rossel",
+ "Gustave Flourens",
+ "Jean-Baptiste Clément",
+ "Elizabeth Dimitrieff",
+ "Paris Bombarded",
+ "Général Gallifet",
+ "Sapper Tactics",
+ "Georges Vaysset",
+ "Colonne Vendôme",
+ "Versailles' Left",
]
const card_ops = [
@@ -88,6 +107,12 @@ const card_ops = [
3, 3, 3, 3, 3, 3, 3,
// Objective
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // Commune - Censorship
+ 2, 1, 1, 1,
+ // Versailles - Censorship
+ 2, 1, 1, 1,
+ // Neutral - Censorship
+ 3, 3,
]
const space_names = [
@@ -383,15 +408,15 @@ function is_objective_card(c) {
}
function is_commune_card(c) {
- return c >= 18 && c <= 34
+ return (c >= 18 && c <= 34) || (c >= (BONUS+1) && c <= (BONUS+4))
}
function is_versailles_card(c) {
- return c >= 1 && c <= 17
+ return (c >= 1 && c <= 17) || (c >= (BONUS+5) && c <= (BONUS+8))
}
function is_neutral_card(c) {
- return c >= 35 && c <= 41
+ return (c >= 35 && c <= 41) || (c >= (BONUS+9) && c <= (BONUS+10))
}
function enemy_player() {
@@ -423,7 +448,8 @@ function can_play_event(c) {
return false
// Cards 38 through 41 can only be played if you have the initiative
- if (c >= 38 && c <= 41)
+ // Cards 62 through 63
+ if ((c >= 38 && c <= 41) || (c >= 62 && c <= 63))
if (game.active !== game.initiative)
return false
@@ -454,6 +480,11 @@ function can_play_event(c) {
if (game.snb)
return false
+ // General Lullier - cannot be played if Louis Rossel has been played
+ if (c === 32)
+ if (game.louis_rossel)
+ return false
+
// Victor Hugo - must decrease both player momentums
if (c === 38)
if (game.red_momentum < 1 || game.blue_momentum < 1)
@@ -562,6 +593,16 @@ function is_adjacent_to_control(here) {
return false
}
+function is_adjacent_to_control_in_dimension(here, dim) {
+ console.log("CHK", space_names[here])
+ for (let s of ADJACENT_TO[here]) {
+ console.log(" =>", space_names[s], is_control(s), dim.includes(s))
+ if (is_control(s) && dim.includes(s))
+ return true
+ }
+ return false
+}
+
function is_commune_control_dimension(dim) {
for (let s of dim)
if (!is_commune_control(s))
@@ -580,11 +621,6 @@ function count_cubes(s) {
return count_commune_cubes(s) + count_versailles_cubes(s)
}
-function for_each_cube(s, f) {
- for_each_commune_cube(s, f)
- for_each_versailles_cube(s, f)
-}
-
function count_commune_cubes(s) {
let n = 0
for (let p = first_commune_cube; p <= last_commune_cube; ++p)
@@ -617,14 +653,6 @@ function count_versailles_discs(s) {
return n
}
-function count_commune_pieces(s) {
- return count_commune_cubes(s) + count_commune_discs(s)
-}
-
-function count_versailles_pieces(s) {
- return count_versailles_cubes(s) + count_versailles_discs(s)
-}
-
function count_friendly_cubes(s) {
if (game.active === COMMUNE)
return count_commune_cubes(s)
@@ -637,12 +665,6 @@ function count_friendly_discs(s) {
return count_versailles_discs(s)
}
-function count_enemy_pieces(s) {
- if (game.active === COMMUNE)
- return count_versailles_pieces(s)
- return count_commune_pieces(s)
-}
-
function find_commune_cube(s) {
for (let p = first_commune_cube; p <= last_commune_cube; ++p)
if (game.pieces[p] === s)
@@ -719,10 +741,6 @@ function has_enemy_disc(s) {
return find_enemy_disc(s) >= 0
}
-function has_enemy_piece(s) {
- return has_enemy_cube(s) || has_enemy_disc(s)
-}
-
function is_commune_cube(p) {
return p >= first_commune_cube && p <= last_commune_cube
}
@@ -739,10 +757,6 @@ function is_versailles_disc(p) {
return p >= first_versailles_disc && p <= last_versailles_disc
}
-function is_disc(p) {
- return p >= 36
-}
-
function can_place_cube_in_any(list) {
for (let s of list)
if (can_place_cube(s))
@@ -779,6 +793,10 @@ function can_place_disc(s) {
return count_friendly_discs(s) < 1
}
+function can_remove_disc(s) {
+ return has_enemy_disc(s)
+}
+
function can_replace_cube(s) {
return has_enemy_cube(s) && can_place_cube(s)
}
@@ -888,13 +906,6 @@ function for_each_enemy_disc(s, f) {
for_each_commune_disc(s, f)
}
-function for_each_friendly_disc(s, f) {
- if (game.active === COMMUNE)
- for_each_commune_disc(s, f)
- else
- for_each_versailles_disc(s, f)
-}
-
function for_each_commune_cube(s, f) {
for (let p = first_commune_cube; p <= last_commune_cube; ++p)
if (game.pieces[p] === s)
@@ -1498,15 +1509,15 @@ function end_crisis_breach() {
delete game.breach_active
delete game.breach_next
switch (next) {
- case "strategy":
- end_crisis_breach_strategy()
- break
- case "pivotal":
- end_crisis_breach_pivotal()
- break
- case "objective":
- end_crisis_breach_objective()
- break
+ case "strategy":
+ end_crisis_breach_strategy()
+ break
+ case "pivotal":
+ end_crisis_breach_pivotal()
+ break
+ case "objective":
+ end_crisis_breach_objective()
+ break
}
}
@@ -1518,7 +1529,8 @@ function assess_commune_crisis_track(i, an) {
game.red_breach = i + 1
log_h3("Commune - " + crisis_names[i])
if (i === 2 && game.blue_breach < 3) {
- add_political_vp(COMMUNE, -1)
+ if (game.versailles_left !== COMMUNE)
+ add_political_vp(COMMUNE, -1)
}
}
return b > 0
@@ -1534,7 +1546,8 @@ function assess_versailles_crisis_track(i, an) {
game.blue_breach = i + 1
log_h3("Versailles - " + crisis_names[i])
if (i === 2 && game.red_breach < 3) {
- add_political_vp(VERSAILLES, -1)
+ if (game.versailles_left !== VERSAILLES)
+ add_political_vp(VERSAILLES, -1)
}
}
return b > 0
@@ -2106,7 +2119,6 @@ states.turncoat = {
states.pivotal_done = {
inactive: "confirm action",
prompt() {
- let dimension = DIMENSION_SPACES[game.where]
view.prompt = "Pivotal Bonus Action in " + DIMENSION_NAME[game.where] + ": Done."
view.actions.done = 1
},
@@ -2779,12 +2791,6 @@ function vm_replace_up_to() {
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)
@@ -2826,6 +2832,12 @@ function vm_place_disc() {
goto_vm_place_disc()
}
+function vm_remove_disc() {
+ game.vm.count = 1
+ game.vm.spaces = vm_operand_spaces(1)
+ goto_vm_remove_disc()
+}
+
function vm_move_up_to() {
game.vm.count = vm_operand(1)
game.vm.a = vm_operand_spaces(2)
@@ -2833,6 +2845,13 @@ function vm_move_up_to() {
goto_vm_move()
}
+function vm_move_within() {
+ game.vm.spaces = vm_operand_spaces(1)
+ game.vm.a = []
+ game.vm.b = []
+ goto_vm_move_within()
+}
+
// === EVENT STATES ===
states.vm_switch = {
@@ -2887,6 +2906,11 @@ states.vm_switch = {
game.vm.choice = "paris"
vm_next()
},
+ forts() {
+ push_undo()
+ game.vm.choice = "forts"
+ vm_next()
+ },
}
states.vm_increase_revolutionary_momentum = {
@@ -3181,6 +3205,41 @@ states.vm_remove_own = {
},
}
+function can_vm_remove_disc() {
+ for (let s of game.vm.spaces)
+ if (can_remove_disc(s))
+ return true
+ return false
+}
+
+function goto_vm_remove_disc() {
+ if (can_vm_remove_disc())
+ game.state = "vm_remove_disc"
+ else
+ vm_next()
+}
+
+states.vm_remove_disc = {
+ inactive: "remove a disc",
+ prompt() {
+ event_prompt()
+ for (let s of game.vm.spaces)
+ if (can_remove_disc(s))
+ for_each_enemy_disc(s, gen_action_piece)
+ },
+ piece(p) {
+ push_undo()
+ let s = game.pieces[p]
+ if (game.active === COMMUNE)
+ log("Removed BD from S" + s + ".")
+ else
+ log("Removed RD from S" + s + ".")
+ remove_piece(p)
+ if (--game.vm.count === 0 || !can_vm_remove_disc())
+ vm_next()
+ },
+}
+
function can_vm_move() {
let from = false
let to = false
@@ -3235,6 +3294,61 @@ states.vm_move = {
},
}
+function can_vm_move_within() {
+ let max = 0
+ for (let s of game.vm.spaces) {
+ let n = count_friendly_cubes(s)
+ if (n > max)
+ max = n
+ }
+ return max > 0 && max < 4
+}
+
+function goto_vm_move_within() {
+ game.who = -1
+ if (can_vm_move_within())
+ game.state = "vm_move_within"
+ else
+ vm_next()
+}
+
+states.vm_move_within = {
+ inactive: "move a cube",
+ prompt() {
+ event_prompt()
+ view.actions.done = 1
+ if (game.who < 0) {
+ for (let s of game.vm.spaces)
+ if (!game.vm.b.includes(s))
+ for_each_friendly_cube(s, gen_action_piece)
+ } else {
+ view.selected_cube = game.who
+ for (let s of game.vm.spaces)
+ if (s !== game.pieces[game.who] && !game.vm.a.includes(s))
+ if (count_friendly_cubes(s) < 4)
+ gen_action_space(s)
+ }
+ },
+ piece(p) {
+ push_undo()
+ game.who = p
+ },
+ space(to) {
+ let from = game.pieces[game.who]
+ if (!game.vm.a.includes(from))
+ game.vm.a.push(from)
+ if (!game.vm.b.includes(to))
+ game.vm.b.push(to)
+ move_piece(game.who, to)
+ log("Moved " + piece_abbr(game.who) + " from S" + from + " to S" + to + ".")
+ game.who = -1
+ },
+ done() {
+ push_undo()
+ vm_next()
+ },
+}
+
// === COMPLICATED EVENT STATES ===
states.reveal_commune_objective = {
@@ -3377,6 +3491,122 @@ states.freemason_parade = {
},
}
+states.georges_vaysset = {
+ inactive: "look at Commune player's hand, take a card, then give them a card",
+ prompt() {
+ event_prompt("Take a card from your opponent's hand.")
+ view.hand = game.red_hand
+ for (let c of game.red_hand)
+ gen_action_card(c)
+ },
+ card(c) {
+ push_undo()
+ log("Took C" + c + ".")
+ array_remove_item(game.red_hand, c)
+ game.blue_hand.push(c)
+ game.state = "georges_vaysset_2"
+ },
+}
+
+states.georges_vaysset_2 = {
+ inactive: "look at Commune player's hand, take a card, then give them a card",
+ prompt() {
+ event_prompt("Give a card to your opponent.")
+ for (let c of game.blue_hand)
+ gen_action_card(c)
+ },
+ card(c) {
+ push_undo()
+ log("Gave C" + c + ".")
+ array_remove_item(game.blue_hand, c)
+ game.red_hand.push(c)
+ vm_next()
+ },
+}
+
+states.elizabeth_dimitrieff_discard = {
+ inactive: "discard 2 cards",
+ prompt() {
+ event_prompt("Discard 2 cards.")
+ for (let c of game.red_hand)
+ gen_action_card(c)
+ },
+ card(c) {
+ push_undo()
+ log("Discarded C" + c + ".")
+ array_remove_item(game.red_hand, c)
+ game.discard.push(c)
+ if (--game.vm.count === 0)
+ vm_next()
+ },
+}
+
+states.versailles_left = {
+ inactive: "add bonus cubes",
+ prompt() {
+ event_prompt("Move bonus cubes to Pool.")
+ if (game.active === VERSAILLES)
+ for_each_versailles_cube(BLUE_BONUS_CUBES[2], gen_action_piece)
+ else
+ for_each_commune_cube(RED_BONUS_CUBES[2], gen_action_piece)
+ },
+ piece(p) {
+ remove_piece(p)
+ if (game.active === VERSAILLES) {
+ log("Added BC to Pool.")
+ if (!has_friendly_cube(BLUE_BONUS_CUBES[2]))
+ vm_next()
+ }
+ if (game.active === COMMUNE) {
+ log("Added RC to Pool.")
+ if (!has_friendly_cube(RED_BONUS_CUBES[2]))
+ vm_next()
+ }
+ },
+}
+
+function init_paris_bombarded() {
+ game.vm.count = 3
+ game.vm.spaces = []
+ for (let s of PARIS)
+ if (is_adjacent_to_control_in_dimension(s, FORTS))
+ game.vm.spaces.push(s)
+}
+
+states.paris_bombarded = {
+ inactive: "attempt remove operations",
+ prompt() {
+ event_prompt("Attempt up to 3 Remove Operations with strength 2.")
+ for (let s of game.vm.spaces)
+ if (has_enemy_cube(s))
+ for_each_enemy_cube(s, gen_action_piece)
+ view.actions.skip = 1
+ },
+ piece(p) {
+ clear_undo()
+ let s = game.pieces[p]
+ let pn = piece_abbr(p)
+ log("Remove " + pn + " from S" + s + ".")
+ let c = draw_strategy_card()
+ let str = 2
+ let ops = card_ops[c]
+ logi("Drew C" + c)
+ logi("Strength " + str + " vs " + ops)
+ if (str >= ops) {
+ remove_piece(p)
+ update_presence_and_control()
+ logi("Success")
+ } else {
+ logi("Failure")
+ }
+ if (--game.vm.count === 0)
+ vm_next()
+ },
+ skip() {
+ vm_next()
+ },
+}
+
// === SETUP ===
exports.setup = function (seed, scenario, options) {
@@ -3470,8 +3700,8 @@ exports.setup = function (seed, scenario, options) {
log_h1("Red Flag Over Paris")
- if (options.censorship) {
- log("Censorship Phase Variant.")
+ if (options.censorship && scenario === "Standard") {
+ log("Censorship Phase.")
game.censorship = 1
}
@@ -3482,6 +3712,13 @@ exports.setup = function (seed, scenario, options) {
for (let c = 42; c <= 53; ++c)
game.objective_deck.push(c)
+ if (scenario === "Censorship") {
+ log("Censorship Variant.")
+ game.censorship = 1
+ for (let c = 54; c <= 63; ++c)
+ game.strategy_deck.push(c)
+ }
+
shuffle(game.strategy_deck)
shuffle(game.objective_deck)
@@ -3670,10 +3907,6 @@ function log_h3(msg) {
log(".h3 " + msg)
}
-function log_sep() {
- log(".hr")
-}
-
// === COMMON LIBRARY ===
function clear_undo() {
@@ -4231,3 +4464,91 @@ CODE[53] = [ // Legitimacy
[ vm_endif ],
[ vm_return ],
]
+
+CODE[54] = [ // Louis Rossel
+ [ vm_prompt, "Move up to all cubes in Forts or Paris." ],
+ [ vm_switch, ["forts","paris"] ],
+ [ vm_case, "forts" ],
+ [ vm_move_within, FORTS ],
+ [ vm_case, "paris" ],
+ [ vm_move_within, PARIS ],
+ [ vm_endswitch ],
+ [ vm_asm, ()=>game.louis_rossel=1 ],
+ [ vm_return ],
+]
+
+CODE[55] = [ // Gustave Flourens
+ [ vm_increase_revolutionary_momentum ],
+ [ vm_prompt, "Move up to 1 from Public Opinion to Military." ],
+ [ vm_move_up_to, 1, PUBLIC_OPINION, MILITARY ],
+ [ vm_return ],
+]
+
+CODE[56] = [ // Jean-Baptiste Clément
+ [ vm_prompt, "Place up to 2 in Public Opinion (use removed cubes)." ],
+ [ vm_place_removed_up_to, 2, PUBLIC_OPINION ],
+ [ vm_return ],
+]
+
+CODE[57] = [ // Elizabeth Dimitrieff
+ [ vm_asm, ()=>clear_undo() ],
+ [ vm_asm, ()=>game.red_hand.push(draw_strategy_card()) ],
+ [ vm_asm, ()=>game.red_hand.push(draw_strategy_card()) ],
+ [ vm_asm, ()=>game.vm.count = 2 ],
+ [ vm_goto, "elizabeth_dimitrieff_discard" ],
+ [ vm_return ],
+]
+
+CODE[58] = [ // Paris Bombarded
+ [ vm_asm, ()=>init_paris_bombarded() ],
+ [ vm_goto, "paris_bombarded" ],
+ [ vm_return ],
+]
+
+CODE[59] = [ // Général Gallifet
+ [ vm_prompt, "Remove up to 3 in Paris where present." ],
+ [ vm_remove_up_to, 3, ()=>(where_present(PARIS)) ],
+ [ vm_asm, ()=>add_political_vp(VERSAILLES, -1) ],
+ [ vm_return ],
+]
+
+CODE[60] = [ // Sapper Tactics
+ [ vm_prompt, "Remove one Barricade where present." ],
+ [ vm_remove_disc, ()=>(where_present(ANY)) ],
+ [ vm_return ],
+]
+
+CODE[61] = [ // Georges Vaysset
+ [ vm_asm, ()=>clear_undo() ],
+ [ vm_asm, ()=>log("Commune hand:") ],
+ [ vm_asm, ()=>{ for (let c of game.red_hand) logi("C" + c) } ],
+ [ vm_goto, "georges_vaysset" ],
+ [ vm_return ],
+]
+
+CODE[62] = [ // Colonne Vendôme
+ [ vm_if, ()=>(game.active === COMMUNE) ],
+ [ vm_decrease_prussian_collaboration ],
+ [ vm_else ],
+ [ vm_decrease_revolutionary_momentum ],
+ [ vm_endif ],
+ [ vm_prompt, "Replace up to 1 in Institutional." ],
+ [ vm_replace_up_to, 1, INSTITUTIONAL ],
+ [ vm_return ],
+]
+
+CODE[63] = [ // Versailles' Left
+ [ vm_prompt, "Replace up to 1 in Republicans." ],
+ [ vm_replace_up_to, 1, REPUBLICANS ],
+ [ vm_asm, ()=>update_presence_and_control() ],
+ [ vm_asm, ()=>game.versailles_left = game.active ],
+ [ vm_if, ()=>(has_commune_cube(RED_BONUS_CUBES[2])) ],
+ [ vm_if, ()=>(game.active === COMMUNE && is_commune_control(REPUBLICANS)) ],
+ [ vm_goto, "versailles_left" ],
+ [ vm_endif ],
+ [ vm_if, ()=>(game.active === VERSAILLES && is_versailles_control(REPUBLICANS)) ],
+ [ vm_goto, "versailles_left" ],
+ [ vm_endif ],
+ [ vm_endif ],
+ [ vm_return ],
+]