summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-05-07 11:57:00 +0200
committerTor Andersson <tor@ccxvii.net>2023-05-24 21:06:18 +0200
commitdff733bdbae936c674628a7cc88c08c0feef9d05 (patch)
tree380cbeae8bc1ba98a3ec9ddecf3fad22f5675f3d
parent1683dfb66009b504c36fb17d12558c55369fd4c4 (diff)
downloadred-flag-over-paris-dff733bdbae936c674628a7cc88c08c0feef9d05.tar.gz
No card popup menu.
-rw-r--r--play.html67
-rw-r--r--play.js155
-rw-r--r--rules.js567
3 files changed, 460 insertions, 329 deletions
diff --git a/play.html b/play.html
index c722096..ea94d46 100644
--- a/play.html
+++ b/play.html
@@ -40,19 +40,25 @@ body.Versailles header.your_turn { background-color: skyblue; }
/* PANELS */
.panel_grid {
- display: grid;
- grid-template-columns: min-content 1fr;
- max-width: 1500px;
- margin: 18px auto;
- gap: 18px;
+ display: flex;
+ flex-wrap: wrap;
+ margin: 20px auto;
+ justify-content: center;
+ gap: 20px;
}
-#hand_panel {
- grid-column: 1 / 3;
+#hand, #final, #discard, #objective, #set_aside {
+ min-height: 350px;
}
-#objective {
- min-width: 250px;
+#hand { min-width: 1060px }
+#final { min-width: 250px }
+#objective { min-width: 520px }
+#set_aside { min-width: 790px }
+#discard { min-width: 250px }
+
+#hand, #set_aside {
+ flex-grow: 1
}
.panel {
@@ -72,12 +78,11 @@ body.Versailles header.your_turn { background-color: skyblue; }
display: flex;
justify-content: start;
flex-wrap: wrap;
- padding: 18px;
- gap: 18px;
- min-height: 350px;
+ padding: 20px;
+ gap: 20px;
}
-body.Observer #final_panel { display: none }
+body.Observer #set_aside_panel { display: none }
/* CARDS */
@@ -91,19 +96,6 @@ body.Observer #final_panel { display: none }
box-shadow: 1px 1px 5px rgba(0,0,0,0.5);
}
-.card_info {
- padding: 12px 0;
- border-bottom: 1px solid black;
- background-color: gray;
-}
-
-.card_info .card {
- margin: 0 auto;
- width: 125px;
- height: 175px;
- border-radius: 8px;
-}
-
#tooltip {
position: fixed;
z-index: 100;
@@ -143,6 +135,7 @@ body.Observer #final_panel { display: none }
}
.piece {
+ pointer-events: none;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
@@ -153,6 +146,7 @@ body.Observer #final_panel { display: none }
}
.piece.action {
+ pointer-events: auto;
filter:
drop-shadow(0 -2px 0 white)
drop-shadow(0 2px 0 white)
@@ -164,6 +158,10 @@ body.Observer #final_panel { display: none }
box-shadow: 0 0 0 3px white;
}
+.card.selected {
+ box-shadow: 0 0 0 3px yellow;
+}
+
/* original size (72dpi?) */
.piece.cube { width: 28px; height: 30px; }
.piece.disc { width: 40px; height: 32px; }
@@ -404,7 +402,6 @@ body.Observer #final_panel { display: none }
<div class="role_user">-</div>
</div>
</div>
- <div class="card_info"><div id="discarded_card" class="card card_strategy_back"></div></div>
</div>
<div id="log"></div>
</aside>
@@ -431,14 +428,24 @@ body.Observer #final_panel { display: none }
<div id="hand" class="panel_body"></div>
</div>
+<div id="final_panel" class="panel">
+<div id="final_header" class="panel_header">Final</div>
+<div id="final" class="panel_body"></div>
+</div>
+
+<div id="discard_panel" class="panel">
+<div id="discard_header" class="panel_header">Discard</div>
+<div id="discard" class="panel_body"></div>
+</div>
+
<div id="objective_panel" class="panel">
<div id="objective_header" class="panel_header">Objective</div>
<div id="objective" class="panel_body"></div>
</div>
-<div id="final_panel" class="panel">
-<div id="final_header" class="panel_header">Set-aside cards</div>
-<div id="final" class="panel_body"></div>
+<div id="set_aside_panel" class="panel">
+<div id="set_aside_header" class="panel_header">Set-aside cards</div>
+<div id="set_aside" class="panel_body"></div>
</div>
</div>
diff --git a/play.js b/play.js
index 1c3c137..4d3bffb 100644
--- a/play.js
+++ b/play.js
@@ -157,6 +157,12 @@ const boxes = {
"Prussian Collaboration 3": [306,330,157,39],
}
+function is_action(action) {
+ if (view.actions && view.actions[action])
+ return true
+ return false
+}
+
function is_card_action(action, card) {
if (view.actions && view.actions[action] && view.actions[action].includes(card))
return true
@@ -183,6 +189,27 @@ function on_focus_space(evt) {
document.getElementById("status").textContent = evt.target.my_name
}
+function on_click_red_momentum(evt) {
+ if (evt.button === 0) {
+ if (send_action('red_momentum'))
+ evt.stopPropagation()
+ }
+}
+
+function on_click_blue_momentum(evt) {
+ if (evt.button === 0) {
+ if (send_action('blue_momentum'))
+ evt.stopPropagation()
+ }
+}
+
+function on_click_card(evt) {
+ if (evt.button === 0) {
+ if (send_action('card', evt.target.my_card))
+ evt.stopPropagation()
+ }
+}
+
function on_click_space(evt) {
if (evt.button === 0) {
if (send_action('space', evt.target.my_space))
@@ -207,6 +234,9 @@ function on_click_disc(evt) {
function build_user_interface() {
let elt
+ document.getElementById("red_momentum").addEventListener("mousedown", on_click_red_momentum)
+ document.getElementById("blue_momentum").addEventListener("mousedown", on_click_blue_momentum)
+
for (let c = 1; c <= 41 + 12; ++c) {
elt = ui.cards[c] = document.createElement("div")
elt.className = `card card_${c}`
@@ -336,11 +366,6 @@ function on_log(text) {
}
function on_update() {
- if (view.discard)
- document.getElementById("discarded_card").className = `card card_${view.discard}`
- else
- document.getElementById("discarded_card").className = `card card_strategy_back`
-
if (view.initiative === "Commune")
document.getElementById("commune_info").textContent = "\u2756"
else
@@ -351,22 +376,35 @@ function on_update() {
document.getElementById("versailles_info").textContent = ""
ui.round_marker.className = `piece pawn round${view.round}`
- ui.red_momentum.className = `piece cylinder red m${view.red_momentum}`
- ui.blue_momentum.className = `piece cylinder blue m${view.blue_momentum}`
+ if (is_action("red_momentum"))
+ ui.red_momentum.className = `piece cylinder red m${view.red_momentum} action`
+ else
+ ui.red_momentum.className = `piece cylinder red m${view.red_momentum}`
+ if (is_action("blue_momentum"))
+ ui.blue_momentum.className = `piece cylinder blue m${view.blue_momentum} action`
+ else
+ ui.blue_momentum.className = `piece cylinder blue m${view.blue_momentum}`
ui.military_vp.className = `piece cylinder purple vp${5+view.military_vp}`
ui.political_vp.className = `piece cylinder orange vp${5+view.political_vp}`
document.getElementById("hand").replaceChildren()
document.getElementById("final").replaceChildren()
+ document.getElementById("discard").replaceChildren()
+ document.getElementById("set_aside").replaceChildren()
document.getElementById("objective").replaceChildren()
+ if (view.final)
+ document.getElementById("final").appendChild(ui.cards[view.final])
+ if (view.discard)
+ document.getElementById("discard").appendChild(ui.cards[view.discard])
if (view.hand)
for (let c of view.hand)
document.getElementById("hand").appendChild(ui.cards[c])
- if (view.final)
- for (let c of view.final)
- document.getElementById("final").appendChild(ui.cards[c])
+ if (view.set_aside)
+ for (let c of view.set_aside)
+ document.getElementById("set_aside").appendChild(ui.cards[c])
if (view.objective)
- document.getElementById("objective").appendChild(ui.cards[view.objective])
+ for (let c of view.objective)
+ document.getElementById("objective").appendChild(ui.cards[c])
for (let i = 0; i < space_names.length; ++i)
layout[i] = []
@@ -391,6 +429,7 @@ function on_update() {
for (let i = 1; i < ui.cards.length; ++i) {
ui.cards[i].classList.toggle("action", is_card_action('card', i))
+ ui.cards[i].classList.toggle("selected", i === view.selected_card)
}
action_button("commune", "Commune");
@@ -399,95 +438,23 @@ function on_update() {
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("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("skip", "Skip");
action_button("done", "Done");
action_button("undo", "Undo");
}
-/* CARD ACTION MENU */
-
-let current_popup_card = 0
-
-function show_popup_menu(evt, list) {
- document.querySelectorAll("#popup div").forEach(e => e.classList.remove('enabled'))
- for (let item of list) {
- let e = document.getElementById("menu_" + item)
- e.classList.add('enabled')
- }
- let popup = document.getElementById("popup")
- popup.style.display = 'block'
- popup.style.left = (evt.clientX-50) + "px"
- popup.style.top = (evt.clientY-12) + "px"
- ui.cards[current_popup_card].classList.add("selected")
-}
-
-function hide_popup_menu() {
- let popup = document.getElementById("popup")
- popup.style.display = 'none'
- if (current_popup_card) {
- ui.cards[current_popup_card].classList.remove("selected")
- current_popup_card = 0
- }
-}
-
-function on_card_event() {
- if (send_action('card_event', current_popup_card))
- hide_popup_menu()
-}
-
-function on_card_ops() {
- if (send_action('card_ops', current_popup_card))
- hide_popup_menu()
-}
-
-function on_card_ops_political() {
- if (send_action('card_ops_political', current_popup_card))
- hide_popup_menu()
-}
-
-function on_card_ops_military() {
- if (send_action('card_ops_military', current_popup_card))
- hide_popup_menu()
-}
-
-function on_card_use_discarded() {
- if (send_action('card_use_discarded', current_popup_card))
- hide_popup_menu()
-}
-
-function on_card_advance_momentum() {
- if (send_action('card_advance_momentum', current_popup_card))
- hide_popup_menu()
-}
-
-function on_click_card(evt) {
- if (evt.button === 0) {
- if (view.actions) {
- let card = evt.target.my_card
- if (is_card_action('card', card)) {
- send_action('card', card)
- } else {
- let menu = []
- if (is_card_action('card_event', card))
- menu.push('card_event')
- if (is_card_action('card_ops_political', card))
- menu.push('card_ops_political')
- if (is_card_action('card_ops_military', card))
- menu.push('card_ops_military')
- if (is_card_action('card_use_discarded', card))
- menu.push('card_use_discarded')
- if (is_card_action('card_advance_momentum', card))
- menu.push('card_advance_momentum')
- if (menu.length > 0) {
- current_popup_card = card
- show_popup_menu(evt, menu)
- }
- }
- }
- }
-}
-
build_user_interface()
scroll_with_middle_mouse("main")
diff --git a/rules.js b/rules.js
index 02d9a69..40853de 100644
--- a/rules.js
+++ b/rules.js
@@ -1,5 +1,7 @@
"use strict"
+// TODO: no card menu
+
const COMMUNE = "Commune";
const VERSAILLES = "Versailles";
@@ -134,118 +136,118 @@ const BLUE_CRISIS_TRACK = [25, 26, 27, 28]
const BLUE_BONUS_CUBES = [29, 30, 31]
const PRUSSIAN_COLLABORATION = [32, 33, 34]
-const S_NATIONAL_ASSEMBLY = 0
-const S_ROYALISTS = 1
-const S_REPUBLICANS = 2
+const NATIONAL_ASSEMBLY = 0
+const ROYALISTS = 1
+const REPUBLICANS = 2
-const S_PRESS = 3
-const S_CATHOLIC_CHURCH = 4
-const S_SOCIAL_MOVEMENTS = 5
+const PRESS = 3
+const CATHOLIC_CHURCH = 4
+const SOCIAL_MOVEMENTS = 5
-const S_MONT_VALERIEN = 6
-const S_FORT_D_ISSY = 7
-const S_CHATEAU_DE_VINCENNES = 8
+const MONT_VALERIEN = 6
+const FORT_D_ISSY = 7
+const CHATEAU_DE_VINCENNES = 8
-const S_BUTTE_MONTMARTRE = 9
-const S_BUTTE_AUX_CAILLES = 10
-const S_PERE_LACHAISE = 11
+const BUTTE_MONTMARTRE = 9
+const BUTTE_AUX_CAILLES = 10
+const PERE_LACHAISE = 11
-const S_PRUSSIAN_OCCUPIED_TERRITORY = 12
-const S_VERSAILLES_HQ = 13
+const PRUSSIAN_OCCUPIED_TERRITORY = 12
+const VERSAILLES_HQ = 13
-const first_space = S_NATIONAL_ASSEMBLY
-const last_space = S_PERE_LACHAISE
+const first_space = NATIONAL_ASSEMBLY
+const last_space = PERE_LACHAISE
const space_count = last_space + 1
const POLITICAL = [
- S_NATIONAL_ASSEMBLY,
- S_ROYALISTS,
- S_REPUBLICANS,
- S_PRESS,
- S_CATHOLIC_CHURCH,
- S_SOCIAL_MOVEMENTS,
+ NATIONAL_ASSEMBLY,
+ ROYALISTS,
+ REPUBLICANS,
+ PRESS,
+ CATHOLIC_CHURCH,
+ SOCIAL_MOVEMENTS,
]
const MILITARY = [
- S_MONT_VALERIEN,
- S_FORT_D_ISSY,
- S_CHATEAU_DE_VINCENNES,
- S_BUTTE_MONTMARTRE,
- S_BUTTE_AUX_CAILLES,
- S_PERE_LACHAISE,
+ MONT_VALERIEN,
+ FORT_D_ISSY,
+ CHATEAU_DE_VINCENNES,
+ BUTTE_MONTMARTRE,
+ BUTTE_AUX_CAILLES,
+ PERE_LACHAISE,
]
function is_political_space(s) {
return (
- s === S_NATIONAL_ASSEMBLY ||
- s === S_ROYALISTS ||
- s === S_REPUBLICANS ||
- s === S_PRESS ||
- s === S_CATHOLIC_CHURCH ||
- s === S_SOCIAL_MOVEMENTS
+ s === NATIONAL_ASSEMBLY ||
+ s === ROYALISTS ||
+ s === REPUBLICANS ||
+ s === PRESS ||
+ s === CATHOLIC_CHURCH ||
+ s === SOCIAL_MOVEMENTS
)
}
function is_military_space(s) {
return (
- s === S_MONT_VALERIEN ||
- s === S_FORT_D_ISSY ||
- s === S_CHATEAU_DE_VINCENNES ||
- s === S_BUTTE_MONTMARTRE ||
- s === S_BUTTE_AUX_CAILLES ||
- s === S_PERE_LACHAISE
+ s === MONT_VALERIEN ||
+ s === FORT_D_ISSY ||
+ s === CHATEAU_DE_VINCENNES ||
+ s === BUTTE_MONTMARTRE ||
+ s === BUTTE_AUX_CAILLES ||
+ s === PERE_LACHAISE
)
}
-const DIM_INSTITUTIONAL = [ S_NATIONAL_ASSEMBLY, S_ROYALISTS, S_REPUBLICANS ]
-const DIM_PUBLIC_OPINION = [ S_PRESS, S_CATHOLIC_CHURCH, S_SOCIAL_MOVEMENTS ]
+const INSTITUTIONAL = [ NATIONAL_ASSEMBLY, ROYALISTS, REPUBLICANS ]
+const PUBLIC_OPINION = [ PRESS, CATHOLIC_CHURCH, SOCIAL_MOVEMENTS ]
-const DIM_FORTS = [ S_MONT_VALERIEN, S_FORT_D_ISSY, S_CHATEAU_DE_VINCENNES ]
-const DIM_PARIS = [ S_BUTTE_MONTMARTRE, S_BUTTE_AUX_CAILLES, S_PERE_LACHAISE ]
+const FORTS = [ MONT_VALERIEN, FORT_D_ISSY, CHATEAU_DE_VINCENNES ]
+const PARIS = [ BUTTE_MONTMARTRE, BUTTE_AUX_CAILLES, PERE_LACHAISE ]
const ADJACENT_TO = [
- [ S_ROYALISTS, S_REPUBLICANS ],
- [ S_PRESS, S_CATHOLIC_CHURCH ],
- [ S_PRESS, S_SOCIAL_MOVEMENTS ],
- [ S_ROYALISTS, S_REPUBLICANS, S_CATHOLIC_CHURCH, S_SOCIAL_MOVEMENTS ],
- [ S_ROYALISTS, S_PRESS ],
- [ S_REPUBLICANS, S_PRESS ],
- [ S_BUTTE_MONTMARTRE, S_VERSAILLES_HQ ],
- [ S_CHATEAU_DE_VINCENNES, S_BUTTE_AUX_CAILLES, S_VERSAILLES_HQ ],
- [ S_FORT_D_ISSY, S_PERE_LACHAISE, S_PRUSSIAN_OCCUPIED_TERRITORY ],
- [ S_MONT_VALERIEN, S_BUTTE_AUX_CAILLES, S_PERE_LACHAISE ],
- [ S_FORT_D_ISSY, S_BUTTE_MONTMARTRE, S_PERE_LACHAISE ],
- [ S_CHATEAU_DE_VINCENNES, S_BUTTE_MONTMARTRE, S_BUTTE_AUX_CAILLES, S_PRUSSIAN_OCCUPIED_TERRITORY ],
- [ S_CHATEAU_DE_VINCENNES, S_PERE_LACHAISE ],
- [ S_MONT_VALERIEN, S_FORT_D_ISSY ],
+ [ ROYALISTS, REPUBLICANS ],
+ [ PRESS, CATHOLIC_CHURCH ],
+ [ PRESS, SOCIAL_MOVEMENTS ],
+ [ ROYALISTS, REPUBLICANS, CATHOLIC_CHURCH, SOCIAL_MOVEMENTS ],
+ [ ROYALISTS, PRESS ],
+ [ REPUBLICANS, PRESS ],
+ [ BUTTE_MONTMARTRE, VERSAILLES_HQ ],
+ [ CHATEAU_DE_VINCENNES, BUTTE_AUX_CAILLES, VERSAILLES_HQ ],
+ [ FORT_D_ISSY, PERE_LACHAISE, PRUSSIAN_OCCUPIED_TERRITORY ],
+ [ MONT_VALERIEN, BUTTE_AUX_CAILLES, PERE_LACHAISE ],
+ [ FORT_D_ISSY, BUTTE_MONTMARTRE, PERE_LACHAISE ],
+ [ CHATEAU_DE_VINCENNES, BUTTE_MONTMARTRE, BUTTE_AUX_CAILLES, PRUSSIAN_OCCUPIED_TERRITORY ],
+ [ CHATEAU_DE_VINCENNES, PERE_LACHAISE ],
+ [ MONT_VALERIEN, FORT_D_ISSY ],
]
const ADJACENT_FROM = [
[ ],
- [ S_NATIONAL_ASSEMBLY, S_PRESS, S_CATHOLIC_CHURCH ],
- [ S_NATIONAL_ASSEMBLY, S_PRESS, S_SOCIAL_MOVEMENTS ],
- [ S_ROYALISTS, S_REPUBLICANS, S_CATHOLIC_CHURCH, S_SOCIAL_MOVEMENTS ],
- [ S_ROYALISTS, S_PRESS ],
- [ S_REPUBLICANS, S_PRESS ],
- [ S_BUTTE_MONTMARTRE, S_VERSAILLES_HQ ],
- [ S_CHATEAU_DE_VINCENNES, S_BUTTE_AUX_CAILLES, S_VERSAILLES_HQ ],
- [ S_FORT_D_ISSY, S_PERE_LACHAISE, S_PRUSSIAN_OCCUPIED_TERRITORY ],
- [ S_MONT_VALERIEN, S_BUTTE_AUX_CAILLES, S_PERE_LACHAISE ],
- [ S_FORT_D_ISSY, S_BUTTE_MONTMARTRE, S_PERE_LACHAISE ],
- [ S_CHATEAU_DE_VINCENNES, S_BUTTE_MONTMARTRE, S_BUTTE_AUX_CAILLES, S_PRUSSIAN_OCCUPIED_TERRITORY ],
- [ S_CHATEAU_DE_VINCENNES, S_PERE_LACHAISE ],
- [ S_MONT_VALERIEN, S_FORT_D_ISSY ],
+ [ NATIONAL_ASSEMBLY, PRESS, CATHOLIC_CHURCH ],
+ [ NATIONAL_ASSEMBLY, PRESS, SOCIAL_MOVEMENTS ],
+ [ ROYALISTS, REPUBLICANS, CATHOLIC_CHURCH, SOCIAL_MOVEMENTS ],
+ [ ROYALISTS, PRESS ],
+ [ REPUBLICANS, PRESS ],
+ [ BUTTE_MONTMARTRE, VERSAILLES_HQ ],
+ [ CHATEAU_DE_VINCENNES, BUTTE_AUX_CAILLES, VERSAILLES_HQ ],
+ [ FORT_D_ISSY, PERE_LACHAISE, PRUSSIAN_OCCUPIED_TERRITORY ],
+ [ MONT_VALERIEN, BUTTE_AUX_CAILLES, PERE_LACHAISE ],
+ [ FORT_D_ISSY, BUTTE_MONTMARTRE, PERE_LACHAISE ],
+ [ CHATEAU_DE_VINCENNES, BUTTE_MONTMARTRE, BUTTE_AUX_CAILLES, PRUSSIAN_OCCUPIED_TERRITORY ],
+ [ CHATEAU_DE_VINCENNES, PERE_LACHAISE ],
+ [ MONT_VALERIEN, FORT_D_ISSY ],
]
// === GAME STATE ===
function discard_card(c) {
- array_remove_item(player_hand(game.active), c)
+ array_remove_item(player_hand(), c)
game.discard = c
}
function recycle_card(c) {
- array_remove_item(player_hand(game.active), c)
+ array_remove_item(player_hand(), c)
game.strategy_deck.unshift(c)
}
@@ -253,10 +255,6 @@ function is_objective_card(c) {
return c >= 42 && c <= 53
}
-function is_strategy_card(c) {
- return !is_objective_card(c) && c !== 17 && c !== 34
-}
-
function is_commune_card(c) {
return c >= 18 && c <= 34
}
@@ -275,12 +273,18 @@ function enemy_player() {
return COMMUNE
}
-function player_hand(current) {
- if (current === COMMUNE)
+function player_hand() {
+ if (game.active === COMMUNE)
return game.red_hand
return game.blue_hand
}
+function player_set_aside(current) {
+ if (game.active === COMMUNE)
+ return game.red_set_aside
+ return game.blue_set_aside
+}
+
function is_space(s) {
return s >= first_space && s <= last_space
}
@@ -332,13 +336,13 @@ function update_presence_and_control() {
game.control = 0
// Permanent Presence
- game.presence |= (1 << (S_PERE_LACHAISE))
- game.presence |= (1 << (S_SOCIAL_MOVEMENTS))
- game.presence |= (1 << (S_ROYALISTS + space_count))
+ game.presence |= 1 << PERE_LACHAISE
+ game.presence |= 1 << SOCIAL_MOVEMENTS
+ game.presence |= 1 << (ROYALISTS + space_count)
for (let s = first_space; s <= last_space; ++s) {
- let c_bit = (1 << (s))
- let v_bit = (1 << (s + space_count))
+ let c_bit = 1 << s
+ let v_bit = 1 << (s + space_count)
if (c_count[s] > 0)
game.presence |= c_bit
if (v_count[s] > 0)
@@ -348,47 +352,46 @@ function update_presence_and_control() {
if (v_count[s] > c_count[s])
game.control |= v_bit
}
-
}
-function is_present(side, s) {
- if (side === COMMUNE)
+function is_present(s) {
+ if (game.active === COMMUNE)
return game.presence & (1 << (s))
return game.presence & (1 << (s + space_count))
}
function is_commune_control(s) {
- if (s === S_VERSAILLES_HQ)
+ if (s === VERSAILLES_HQ)
return false
- if (s === S_PRUSSIAN_OCCUPIED_TERRITORY)
+ if (s === PRUSSIAN_OCCUPIED_TERRITORY)
return false
return game.control & (1 << (s))
}
function is_versailles_control(s) {
- if (s === S_VERSAILLES_HQ)
+ if (s === VERSAILLES_HQ)
return true
- if (s === S_PRUSSIAN_OCCUPIED_TERRITORY)
+ if (s === PRUSSIAN_OCCUPIED_TERRITORY)
return game.blue_momentum === 3
return game.control & (1 << (s + space_count))
}
-function is_control(side, s) {
- if (side === COMMUNE)
+function is_control(s) {
+ if (game.active === COMMUNE)
return is_commune_control(s)
return is_versailles_control(s)
}
-function is_adjacent_to_control(side, here) {
+function is_adjacent_to_control(here) {
for (let s of ADJACENT_TO[here])
- if (is_control(side, s))
+ if (is_control(s))
return true
return false
}
-function is_control_dimension(side, dim) {
+function is_control_dimension(dim) {
for (let s of dim)
- if (!is_control(side, s))
+ if (!is_control(s))
return false
return true
}
@@ -433,6 +436,12 @@ 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)
+ return count_versailles_cubes(s)
+}
+
function count_enemy_pieces(s) {
if (game.active === COMMUNE)
return count_versailles_pieces(s)
@@ -517,7 +526,14 @@ function is_disc(p) {
function remove_piece(p) {
if (is_commune_cube(p)) {
- game.pieces[p] = RED_CUBE_POOL[0] // TODO...
+ if (game.red_momentum >= 1 && count_commune_cubes(RED_CUBE_POOL[0]) < 2)
+ game.pieces[p] = RED_CUBE_POOL[0]
+ else if (game.red_momentum >= 2 && count_commune_cubes(RED_CUBE_POOL[1]) < 1)
+ game.pieces[p] = RED_CUBE_POOL[1]
+ else if (game.red_momentum >= 3 && count_commune_cubes(RED_CUBE_POOL[2]) < 1)
+ game.pieces[p] = RED_CUBE_POOL[2]
+ else
+ game.pieces[p] = -1
} else if (is_versailles_cube(p)) {
game.pieces[p] = BLUE_CUBE_POOL
} else {
@@ -525,6 +541,10 @@ function remove_piece(p) {
}
}
+function remove_piece_from_play(p) {
+ game.pieces[p] = -1
+}
+
function place_piece(p, s) {
game.pieces[p] = s
}
@@ -552,6 +572,7 @@ function find_available_cube() {
return p
}
}
+ return -1
}
function for_each_enemy_cube(s, f) {
@@ -619,24 +640,24 @@ function versailles_political_vp() {
states.choose_objective_card = {
inactive: "choose an objective card",
prompt(current) {
- view.prompt = "Choose an Objective card."
- for (let c of player_hand(current))
- if (is_objective_card(c))
+ view.prompt = "Choose an Objective card to keep."
+ if (current === COMMUNE)
+ for (let c of game.red_objective)
+ gen_action_card(c)
+ else
+ for (let c of game.blue_objective)
gen_action_card(c)
},
card(c, current) {
- if (current === COMMUNE) {
- game.red_objective = c
- game.red_hand = game.red_hand.filter(c => !is_objective_card(c))
- } else {
- game.blue_objective = c
- game.blue_hand = game.blue_hand.filter(c => !is_objective_card(c))
- }
- if (game.red_objective > 0 && game.blue_objective > 0)
+ if (current === COMMUNE)
+ game.red_objective = [ c ]
+ else
+ game.blue_objective = [ c ]
+ if (game.red_objective.length === 1 && game.blue_objective.length === 1)
end_choose_objective_card()
- else if (game.red_objective > 0)
+ else if (game.red_objective.length === 1)
game.active = VERSAILLES
- else if (game.blue_objective > 0)
+ else if (game.blue_objective.length === 1)
game.active = COMMUNE
else
game.active = "Both"
@@ -660,9 +681,9 @@ function goto_initiative_phase() {
}
states.initiative_phase = {
- inactive: "decide player order",
+ inactive: "decide initiative",
prompt() {
- view.prompt = "Decide player order."
+ view.prompt = "Decide who will have the initiative."
view.actions.commune = 1
view.actions.versailles = 1
},
@@ -696,9 +717,8 @@ states.censorship_phase = {
inactive: "censorship phase",
prompt() {
view.prompt = "Discard a card from your hand."
- for (let c of player_hand(game.active))
- if (is_strategy_card(c))
- gen_action("card", c)
+ for (let c of player_hand())
+ gen_action("card", c)
},
card(c) {
log(`Discarded #${c}.`)
@@ -719,83 +739,195 @@ function goto_strategy_phase() {
}
function resume_strategy_phase() {
- game.active = enemy_player()
- goto_strategy_phase()
+ if (game.red_hand.length === 1 && game.blue_hand.length === 1) {
+ goto_set_aside_cards()
+ } else {
+ game.active = enemy_player()
+ goto_strategy_phase()
+ }
+}
+
+function has_final_crisis_card() {
+ if (game.active === COMMUNE)
+ return game.red_final
+ return game.blue_final
}
states.strategy_phase = {
inactive: "play a card",
prompt() {
view.prompt = "Play a card."
- let hand = player_hand(game.active)
- let n_strategy = 0
- for (let c of hand)
- if (is_strategy_card(c))
- n_strategy += 1
- for (let c of hand) {
- if (is_strategy_card(c)) {
- if (can_play_event(c))
- gen_action("card_event", c)
- gen_action("card_ops_political", c)
- gen_action("card_ops_military", c)
- if (game.discard > 0 && can_play_event(game.discard))
- gen_action("card_use_discarded", c)
- if (can_advance_momentum())
- gen_action("card_advance_momentum", c)
- }
- if (c === 17 || c === 34) {
- if (n_strategy > 0) {
- gen_action("card_ops_political", c)
- gen_action("card_ops_military", c)
- }
- }
- }
+ for (let c of player_hand())
+ gen_action_card(c)
},
- card_event(c) {
+ card(c) {
push_undo()
- log(`Played #${c} for event.`)
- discard_card(c)
- goto_play_event()
+ log(`Played #${c}.`)
+ game.what = c
+ game.state = "play_card"
},
- card_ops_political(c) {
- push_undo()
- if (c === 17 || c === 34)
- return goto_final_crisis_discard(c, POLITICAL)
- log(`Played #${c} for ${card_ops[c]} Political ops.`)
- discard_card(c)
- goto_operations(card_ops[c], POLITICAL)
+}
+
+states.play_card = {
+ prompt() {
+ let c = game.what
+
+ view.selected_card = game.what
+
+ view.actions.political = 1
+ view.actions.military = 1
+
+ if (can_play_event(c))
+ view.actions.event = 1
+ else
+ view.actions.event = 0
+
+ if (can_advance_momentum()) {
+ view.actions.momentum = 1
+ if (game.active === COMMUNE)
+ view.actions.red_momentum = 1
+ else
+ view.actions.blue_momentum = 1
+ }
+
+ if (game.discard > 0 && can_play_event(game.discard))
+ gen_action_card(game.discard)
+
+ let final = has_final_crisis_card()
+ if (final > 0)
+ gen_action_card(final)
},
- card_ops_military(c) {
- push_undo()
- if (c === 17 || c === 34)
- return goto_final_crisis_discard(c, MILITARY)
- log(`Played #${c} for ${card_ops[c]} Military ops.`)
- discard_card(c)
- goto_operations(card_ops[c], MILITARY)
+ event() {
+ log("Event.")
+ discard_card(game.what)
+ goto_play_event(game.what)
},
- card_advance_momentum(c) {
- push_undo()
- log(`Played #${c} to advance momentum.`)
+ political() {
+ log("Ops.")
+ discard_card(game.what)
+ goto_operations(card_ops[game.what], POLITICAL)
+ },
+ military() {
+ log("Ops.")
+ discard_card(game.what)
+ goto_operations(card_ops[game.what], MILITARY)
+ },
+ momentum() {
+ log(`Momentum.`)
if (game.scenario === "Censorship")
- recycle_card(c)
+ recycle_card(game.what)
else
- discard_card(c)
+ discard_card(game.what)
if (game.active === COMMUNE)
- game.red_momentum += 1
+ advance_revolutionary_momentum(1)
else
- game.blue_momentum += 1
- // TODO: momentum trigger
- resume_strategy_phase()
+ advance_prussian_collaboration(1)
},
- card_use_discarded(c) {
- push_undo()
- log(`Discarded #${c} to play #${game.discard}.`)
- let old_c = game.discard
- discard_card(c)
- goto_play_event(old_c)
+ red_momentum() {
+ this.momentum()
+ },
+ blue_momentum() {
+ this.momentum()
+ },
+ card(c) {
+ log(`Discarded for #${c}.`)
+ if (c === game.discard) {
+ discard_card(game.what)
+ game.what = c
+ goto_play_event(c)
+ } else {
+ discard_card(game.what)
+ game.what = c
+ game.state = "play_final"
+ }
+ },
+}
+
+states.play_final = {
+ prompt() {
+ view.prompt = card_names[game.what] + ": Use up to 4 Operations Points."
+ view.selected_card = game.what
+ view.actions.political = 1
+ view.actions.military = 1
+ },
+ political() {
+ discard_final()
+ goto_operations(4, POLITICAL)
+ },
+ military() {
+ discard_final()
+ goto_operations(4, MILITARY)
+ },
+}
+
+function discard_final() {
+ if (game.active === COMMUNE)
+ game.red_final = 0
+ else
+ game.blue_final = 0
+}
+
+// === PLAYER MOMENTUM TRACKS ===
+
+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.active = VERSAILLES
+ if (x > 0 && game.red_momentum >= 2)
+ game.state = "revolutionary_momentum_trigger"
+ else
+ end_momentum_trigger()
+}
+
+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.active = COMMUNE
+ if (x > 0 && game.blue_momentum >= 2)
+ game.state = "prussian_collaboration_trigger"
+ else
+ end_momentum_trigger()
+}
+
+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)
+ view.actions.skip = 1
+ },
+ space(s) {
+ place_piece(find_available_cube(), s)
+ end_momentum_trigger()
+ },
+ skip() {
+ end_momentum_trigger()
+ },
+}
+
+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)
+ view.actions.skip = 1
+ },
+ space(s) {
+ place_piece(find_available_cube(), s)
+ end_momentum_trigger()
+ },
+ skip() {
+ end_momentum_trigger()
},
}
+function end_momentum_trigger() {
+ game.active = enemy_player()
+ resume_strategy_phase()
+}
+
// === OPERATIONS ===
function goto_operations(count, spaces) {
@@ -805,25 +937,24 @@ function goto_operations(count, spaces) {
}
function goto_final_crisis_discard(c, spaces) {
+ log("Played #" + c + ".")
game.state = "discard_final_crisis"
game.count = 4
game.spaces = spaces
- array_remove_item(player_hand(game.active), c)
}
states.discard_final_crisis = {
inactive: "discard a card to play final crisis",
prompt() {
view.prompt = "Discard a card to play Final Crisis card for ops."
- let hand = player_hand(game.active)
+ let hand = player_hand()
for (let c of hand)
- if (is_strategy_card(c))
- gen_action("card", c)
+ gen_action("card", c)
},
card(c) {
push_undo()
log(`Discarded #${c} to play Final Crisis card for ops.`)
- array_remove_item(player_hand(game.active), c)
+ array_remove_item(player_hand(), c)
game.discard = c
goto_operations_remove()
},
@@ -847,7 +978,7 @@ function can_operations_remove() {
}
function can_operations_remove_space(s) {
- if (is_present(game.active, s) || is_adjacent_to_control(game.active, s)) {
+ if (is_present(s) || is_adjacent_to_control(s)) {
let c = has_enemy_cube(s)
let d = has_enemy_disc(s)
if (c || d) {
@@ -864,11 +995,11 @@ function can_operations_remove_space(s) {
function military_strength(s) {
let str = 0
for (let next of ADJACENT_FROM[s])
- if (is_control(game.active, next))
+ if (is_control(next))
str += 1
- if (is_present(game.active, s))
+ if (is_present(s))
str += 1
- if (is_control(game.active, s))
+ if (is_control(s))
str += 1
return str
}
@@ -989,7 +1120,9 @@ function can_operations_place() {
}
function can_operations_place_space(s) {
- if (is_present(game.active, s) || is_adjacent_to_control(game.active, 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
@@ -999,7 +1132,7 @@ function can_operations_place_space(s) {
states.operations_place = {
prompt() {
- view.prompt = "Operations: Place cubes into Political spaces."
+ view.prompt = "Operations: Place cubes."
for (let s of game.spaces)
if (can_operations_place_space(s))
gen_action_space(s)
@@ -1045,6 +1178,25 @@ function end_operations() {
resume_strategy_phase()
}
+// === SET ASIDE CARDS ===
+
+function goto_set_aside_cards() {
+ for (let c of game.red_hand)
+ game.red_set_aside.push(c)
+ game.red_hand = []
+
+ for (let c of game.blue_hand)
+ game.blue_set_aside.push(c)
+ game.blue_hand = []
+
+ goto_pivotal_space_bonus_actions()
+}
+
+function goto_pivotal_space_bonus_actions() {
+ game.state = "pivotal_space_bonus_actions"
+ game.active = game.initiative
+}
+
// === EVENTS ===
function goto_play_event(c) {
@@ -1077,13 +1229,15 @@ exports.setup = function (seed, scenario, options) {
objective_deck: [],
discard: 0,
- red_hand: [ 34 ],
- red_final: [],
- red_objective: 0,
+ red_final: 34,
+ red_hand: [],
+ red_set_aside: [],
+ red_objective: [],
- blue_hand: [ 17 ],
- blue_final: [],
- blue_objective: 0,
+ blue_final: 17,
+ blue_hand: [],
+ blue_set_aside: [],
+ blue_objective: [],
presence: 0,
control: 0,
@@ -1105,9 +1259,9 @@ exports.setup = function (seed, scenario, options) {
RED_BONUS_CUBES[1],
RED_BONUS_CUBES[2],
RED_BONUS_CUBES[2],
- S_PRESS,
- S_SOCIAL_MOVEMENTS,
- S_PERE_LACHAISE,
+ PRESS,
+ SOCIAL_MOVEMENTS,
+ PERE_LACHAISE,
// Versailles cubes
BLUE_CRISIS_TRACK[0],
BLUE_CRISIS_TRACK[1],
@@ -1119,14 +1273,14 @@ exports.setup = function (seed, scenario, options) {
BLUE_BONUS_CUBES[1],
BLUE_BONUS_CUBES[2],
BLUE_BONUS_CUBES[2],
- BLUE_CUBE_POOL,
- BLUE_CUBE_POOL,
- BLUE_CUBE_POOL,
- BLUE_CUBE_POOL,
- BLUE_CUBE_POOL,
- BLUE_CUBE_POOL,
- S_ROYALISTS,
- S_PRESS,
+ PRUSSIAN_COLLABORATION[0],
+ PRUSSIAN_COLLABORATION[1],
+ PRUSSIAN_COLLABORATION[1],
+ PRUSSIAN_COLLABORATION[2],
+ PRUSSIAN_COLLABORATION[2],
+ PRUSSIAN_COLLABORATION[2],
+ ROYALISTS,
+ PRESS,
// Commune discs
-1, -1,
// Versailles discs
@@ -1155,14 +1309,14 @@ exports.setup = function (seed, scenario, options) {
if (game.scenario === "Censorship")
n = 5
- for (let i = 0; i < 5; ++i) {
+ for (let i = 0; i < n; ++i) {
game.red_hand.push(game.strategy_deck.pop())
game.blue_hand.push(game.strategy_deck.pop())
}
for (let i = 0; i < 2; ++i) {
- game.red_hand.push(game.objective_deck.pop())
- game.blue_hand.push(game.objective_deck.pop())
+ game.red_objective.push(game.objective_deck.pop())
+ game.blue_objective.push(game.objective_deck.pop())
}
return game
@@ -1197,17 +1351,20 @@ exports.view = function(state, player) {
discard: game.discard,
hand: 0,
final: 0,
+ set_aside: 0,
objective: 0
}
if (player === COMMUNE) {
view.hand = game.red_hand
view.final = game.red_final
+ view.set_aside = game.red_set_aside
view.objective = game.red_objective
}
if (player === VERSAILLES) {
view.hand = game.blue_hand
view.final = game.blue_final
+ view.set_aside = game.blue_set_aside
view.objective = game.blue_objective
}