summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.css10
-rw-r--r--play.html24
-rw-r--r--play.js86
-rw-r--r--rules.js225
4 files changed, 305 insertions, 40 deletions
diff --git a/play.css b/play.css
index c915ed1..93df297 100644
--- a/play.css
+++ b/play.css
@@ -51,6 +51,16 @@ body {
border: 1px solid #0008;
}
+.pc_pile {
+ position: absolute;
+ top: 325px;
+}
+
+#display_prussia { left: 42px; }
+#display_france { left: 246px; }
+#display_pragmatic { left: 449px; }
+#display_austria { left: 653px; }
+
header { background-color: hsl(44, 35%, 80%); color: #000c; }
header.your_turn { color: black; }
header.your_turn.france { background-color: var(--color-light-france); }
diff --git a/play.html b/play.html
index 07dd3e8..1152bce 100644
--- a/play.html
+++ b/play.html
@@ -98,24 +98,28 @@
<div id="political_header" class="panel_header">Political Display</div>
<div id="political_body">
<div id="political_display">
- <div id="display_track_saxony"></div>
- <div id="display_track_russia"></div>
- <div id="display_track_italy"></div>
- <div id="display_prussia"></div>
- <div id="display_france"></div>
- <div id="display_pragmatic_army"></div>
- <div id="display_austria"></div>
+ <div id="pol_tracks"></div>
+ <div class="pc_pile card_pile" id="display_prussia"></div>
+ <div class="pc_pile card_pile" id="display_france"></div>
+ <div class="pc_pile card_pile" id="display_pragmatic"></div>
+ <div class="pc_pile card_pile" id="display_austria"></div>
</div>
<div style="display:flex;flex-wrap:wrap;gap:18px;margin:18px;">
- <div class="card_pile">
+ <div id="pc_deck" class="card_pile">
+ <div class="pile card polcard reverse deck_4"></div>
+ <div class="pile card polcard reverse deck_3"></div>
+ <div class="pile card polcard reverse deck_2"></div>
+ <div class="pile card polcard reverse deck_1"></div>
+ <!--
<div id="pcp4" class="card polcard pile reverse deck_4"></div>
<div id="pcp3" class="card polcard pile reverse deck_3"></div>
<div id="pcp2" class="card polcard pile reverse deck_2"></div>
<div id="pcp1" class="card polcard pile reverse deck_1"></div>
<div id="pcp_imp" class="card polcard c25"></div>
+ -->
+ </div>
+ <div id="pc_show" style="display:flex;flex-wrap:wrap;gap:18px;">
</div>
- <div class="card polcard c1"></div>
- <div class="card polcard c2"></div>
</div>
</div>
</div>
diff --git a/play.js b/play.js
index e012337..f34d5f6 100644
--- a/play.js
+++ b/play.js
@@ -59,6 +59,7 @@ const F_EMPEROR_AUSTRIA = 2
const F_ITALY_FRANCE = 4
const F_ITALY_AUSTRIA = 8
const F_SILESIA_ANNEXED = 16
+const F_IMPERIAL_ELECTION = 32
const SPADES = 0
const CLUBS = 1
@@ -71,6 +72,7 @@ const IMPERIAL_ELECTION = 25
const ELIMINATED = data.cities.name.length
const all_powers = [ 0, 1, 2, 3, 4, 5 ]
+const all_major_powers = [ 0, 1, 2, 3 ]
const all_power_generals = [
[ 0, 1, 2, 3, 4 ],
@@ -358,7 +360,15 @@ const ui = {
spaces_element: document.getElementById("spaces"),
pieces_element: document.getElementById("pieces"),
markers_element: document.getElementById("markers"),
- political_display: document.getElementById("political_display"),
+ pol_tracks: document.getElementById("pol_tracks"),
+ pc_deck: document.getElementById("pc_deck"),
+ pc_show: document.getElementById("pc_show"),
+ pc_display: [
+ document.getElementById("display_france"),
+ document.getElementById("display_prussia"),
+ document.getElementById("display_pragmatic"),
+ document.getElementById("display_austria"),
+ ],
discard: [
document.getElementById("discard_1"),
document.getElementById("discard_2"),
@@ -486,12 +496,18 @@ function make_tc_deck_hand(n) {
return list
}
-function make_political_card(fc) {
+function make_political_card(pc) {
let e = document.createElement("div")
- if (fc === 0)
- e.className = "card political reverse"
+ if (pc === 0)
+ e.className = "card polcard reverse"
else
- e.className = "card political c" + fc
+ e.className = "card polcard c" + pc
+ return e
+}
+
+function make_political_back(deck) {
+ let e = document.createElement("div")
+ e.className = "pile card polcard reverse deck_" + deck
return e
}
@@ -612,8 +628,16 @@ function on_init() {
ui.italy.className = "marker political_marker_italy"
ui.political = []
- for (let fc = 0; fc <= 18; ++fc)
- ui.political[fc] = make_political_card(fc)
+ for (let pc = 1; pc <= 25; ++pc)
+ ui.political[pc] = make_political_card(pc)
+
+ ui.political_back = [
+ [],
+ [ make_political_back(4), make_political_back(3), make_political_back(2), make_political_back(1) ],
+ [ make_political_back(4), make_political_back(3), make_political_back(2) ],
+ [ make_political_back(4), make_political_back(3) ],
+ [ make_political_back(4) ],
+ ]
for (let a = 0; a <= last_city; ++a) {
let e = (ui.cities[a] = document.createElement("div"))
@@ -908,7 +932,7 @@ function layout_political_marker(e, col, row) {
let y = 72 + row * 86 + 16
e.style.left = (x - 16) + "px"
e.style.top = (y - 16) + "px"
- ui.political_display.appendChild(e)
+ ui.pol_tracks.appendChild(e)
}
function layout_retro(s, pow) {
@@ -997,6 +1021,14 @@ function on_prompt(text) {
return colorize(text)
}
+let back = [ 0, 0, 0, 0 ]
+
+function show_tc(c) {
+ if ((c & 15) === 0)
+ return ui.tc_back[c>>7][back[c>>7]++]
+ return ui.tc[c]
+}
+
function on_update() {
ui.header.classList.toggle("france", view.power === P_FRANCE)
ui.header.classList.toggle("bavaria", view.power === P_BAVARIA)
@@ -1009,6 +1041,8 @@ function on_update() {
used_elector.fill(0)
used_retro.fill(0)
+ back.fill(0)
+
sort_power_panel(true)
for (let p = 0; p < 20; ++p)
@@ -1018,8 +1052,6 @@ function on_update() {
for (let p = 30; p < 32; ++p)
layout_hussar(p, view.pos[p])
- let back = [ 0, 0, 0, 0 ]
-
for (let pow of all_powers) {
/*
let banner = `${power_name[pow]} \u2014 ${view.pt[pow]} troops`
@@ -1040,10 +1072,7 @@ function on_update() {
} else {
view.hand[pow].sort(cmp_tc)
for (let c of view.hand[pow]) {
- if ((c & 15) === 0)
- ui.hand[pow].appendChild(ui.tc_back[c>>7][back[c>>7]++])
- else
- ui.hand[pow].appendChild(ui.tc[c])
+ ui.hand[pow].appendChild(show_tc(c))
}
}
}
@@ -1056,11 +1085,31 @@ function on_update() {
ui.hand[view.power].appendChild(ui.tc[c])
}
- ui.political_display.replaceChildren()
+ ui.pol_tracks.replaceChildren()
layout_political_marker(ui.saxony, view.saxony, 0)
layout_political_marker(ui.russia, view.russia, 1)
layout_political_marker(ui.italy, view.italy, 2)
+ ui.pc_deck.replaceChildren()
+ for (let e of ui.political_back[view.pol_deck])
+ ui.pc_deck.appendChild(e)
+ if (view.flags & F_IMPERIAL_ELECTION)
+ ui.pc_deck.appendChild(ui.political[25])
+
+ for (let pow of all_major_powers) {
+ ui.pc_display[pow].replaceChildren()
+ for (let tc of view.saved[pow])
+ ui.pc_display[pow].appendChild(show_tc(tc))
+ if (view.display[pow] >= 0)
+ ui.pc_display[pow].appendChild(show_tc(view.display[pow]))
+ }
+
+ ui.pc_show.replaceChildren()
+ if (view.political) {
+ for (let pc of view.political)
+ ui.pc_show.appendChild(ui.political[pc])
+ }
+
for (let deck = 0; deck < 4; ++deck) {
ui.discard[deck].replaceChildren()
for (let i = 0; i < view.discard[deck]; ++i)
@@ -1164,6 +1213,12 @@ function on_update() {
/* LOG */
+function sub_political(match, p1) {
+ let x = p1 | 0
+ let n = political_name[x]
+ return `<span class="political_tip ${p}" onmouseenter="on_focus_political_tip(${x})" onmouseleave="on_blur_political_tip(${x})">${n}</span>`
+}
+
function sub_piece(match, p1) {
let x = p1 | 0
let n = piece_log_name[x]
@@ -1213,6 +1268,7 @@ function on_log(text) {
text = colorize(text)
text = text.replace(/S(\d+)/g, sub_space)
text = text.replace(/P(\d+)/g, sub_piece)
+ text = text.replace(/C(\d+)/g, sub_political)
if (text.startsWith("#")) {
p.className = "h turn"
diff --git a/rules.js b/rules.js
index 8a123f6..357fe73 100644
--- a/rules.js
+++ b/rules.js
@@ -6,23 +6,20 @@
show who controls which power in player list
+set-aside victory marker areas
+
austria/pragmatic move order on flanders (start with pragmatic)
only stack if agree (undo/move to previous space)
winter scoring
-tc draw
- no TCs for minor power if major fortress enemy controlled
+when are subsidies given?
+ example france subsidy to prussia
+ at france's stage?
+ at prussia's stage?
-- advanced --
-VICTORY BOXES
- vp for winning (tracks)
- electors (check victory markers)
- emperor (bit)
- italy (bit)
- silesia (bit)
-
silesia home country for prussia
tc subsidies
@@ -49,7 +46,6 @@ neutrality
// PLAN: move all austria on bohemia first, then alternate pragmatic and austria activations on flanders map
// TODO: confirm mixed stack creation on flanders map (force "undo" to previous location if denied?)
-// TODO: supreme commander in mixed stacks
// TODO: TC subsidies
// TODO: subsidy markers?
@@ -93,6 +89,7 @@ const F_EMPEROR_AUSTRIA = 2
const F_ITALY_FRANCE = 4
const F_ITALY_AUSTRIA = 8
const F_SILESIA_ANNEXED = 16
+const F_IMPERIAL_ELECTION = 32 // imperial election card revealed!
const SPADES = 0
const CLUBS = 1
@@ -105,6 +102,7 @@ const IMPERIAL_ELECTION = 25
const ELIMINATED = data.cities.name.length
const all_powers = [ 0, 1, 2, 3, 4, 5 ]
+const all_major_powers = [ 0, 1, 2, 3 ]
const all_power_generals = [
[ 0, 1, 2, 3, 4 ],
@@ -1093,6 +1091,12 @@ function count_used_cards() {
held[to_deck(c)]++
}
+ // count cards in saved political display
+ for (let pow of all_major_powers) {
+ for (let c of game.saved[pow])
+ held[to_deck(c)]++
+ }
+
// count cards currently being held
if (game.draw)
for (let c of game.draw)
@@ -3112,8 +3116,6 @@ function finish_combat() {
lose_vp(game.loser_power, n)
}
- delete game.loser_power
- delete game.winner_power
delete game.lost_generals
delete game.lost_troops
@@ -3218,11 +3220,151 @@ function check_instant_victory() {
/* POLITICS */
+const POWER_FROM_POLITICAL_STAGE = [
+ P_PRUSSIA,
+ P_FRANCE,
+ P_PRAGMATIC,
+ P_AUSTRIA,
+]
+
+function set_active_political_power() {
+ set_active_to_power(POWER_FROM_POLITICAL_STAGE[game.stage])
+}
+
function goto_politics() {
- end_politics()
+ game.political = []
+ game.display = [ 0, 0, 0, 0 ]
+ game.stage = 0
+
+ while (game.political.length < 2) {
+ let pc = game.pol_deck.pop()
+ if (pc === IMPERIAL_ELECTION)
+ game.flags |= F_IMPERIAL_ELECTION
+ else
+ game.political.push(pc)
+ }
+
+ if (game.winner_power >= 0) {
+ set_active_to_power(game.winner_power)
+ game.state = "determine_trump_suit"
+ } else {
+ for (;;) {
+ draw_tc(1)
+ log("Trump " + format_card(game.draw[0]) + ".")
+ if (!is_reserve(game.draw[0])) {
+ game.trump = to_suit(game.draw[0])
+ break
+ }
+ delete game.draw
+ }
+ goto_place_tc_on_display()
+ }
+}
+
+states.determine_trump_suit = {
+ inactive: "determine the political trump suit",
+ prompt() {
+ prompt("Determine the political trump suit.")
+ view.actions.suit = [ 0, 1, 2, 3 ]
+ },
+ suit(s) {
+ game.trump = s
+ goto_place_tc_on_display()
+ }
+}
+
+function goto_place_tc_on_display() {
+ set_active_political_power()
+ game.state = "place_tc_on_display"
+}
+
+states.place_tc_on_display = {
+ inactive: "place TC on political display",
+ prompt() {
+ prompt(`Place TC on political display (${suit_name[game.trump]} is trump).`)
+ for (let c of game.hand[game.power])
+ gen_action_card(c)
+ view.actions.pass = 1
+ },
+ card(c) {
+ push_undo()
+ log(power_name[game.power] + " placed a TC.")
+ set_delete(game.hand[game.power], c)
+ game.display[game.power] = c
+ game.state = "place_tc_on_display_done"
+ },
+ pass() {
+ log(power_name[game.power] + " passed.")
+ end_place_tc_on_display()
+ },
+}
+
+states.place_tc_on_display_done = {
+ inactive: "place TC on political display",
+ prompt() {
+ prompt(`Place TC on political display (${suit_name[game.trump]} is trump) done.`)
+ view.actions.next = 1
+ },
+ next() {
+ end_place_tc_on_display()
+ },
+}
+
+function end_place_tc_on_display() {
+ if (++game.stage === 4)
+ goto_determine_order_of_influence()
+ else
+ goto_place_tc_on_display()
+}
+
+function goto_determine_order_of_influence() {
+ // Turn cards face-up and return bluff cards
+ for (let pow of all_major_powers) {
+ let c = game.display[pow]
+ if (c > 0) {
+ if (to_suit(c) === game.trump) {
+ log(power_name[pow] + " played " + format_card(c) + ".")
+ set_add(game.saved[pow], c)
+ } else {
+ log(power_name[pow] + " bluffed " + format_card(c) + ".")
+ set_add(game.hand[pow], c)
+ }
+ }
+ }
+ delete game.display
+
+ game.stage = 4
+ goto_select_political_cards()
+}
+
+function goto_select_political_cards() {
+ if (--game.stage < 0)
+ end_politics()
+ set_active_to_power(most_influence())
+ game.state = "select_political_card"
+}
+
+states.select_political_card = {
+ inactive: "select a political card",
+ prompt() {
+ prompt(`Select a political card or save your TC.`)
+ for (let pc of game.political)
+ gen_action_political(pc)
+ view.actions.pass = 1
+ },
+ political(pc) {
+ push_undo()
+ log(power_name[game.power] + " chose C" + pc + ".")
+ throw "TODO"
+ },
+ pass() {
+ log(power_name[game.power] + " saved its TC.")
+ goto_select_political_cards()
+ },
}
function end_politics() {
+ delete game.political
if (check_instant_victory())
return
goto_place_hussars()
@@ -3238,8 +3380,7 @@ const POWER_FROM_SETUP_STAGE = [
]
function set_active_setup_power() {
- game.power = POWER_FROM_SETUP_STAGE[game.stage]
- game.active = current_player()
+ set_active_to_power(POWER_FROM_SETUP_STAGE[game.stage])
}
const setup_initial_tcs = [ 2, 9, 3, 5, 5, 3 ]
@@ -3366,6 +3507,9 @@ function make_tactics_discard(n) {
for (let pow of all_powers)
if (set_has(game.hand[pow], c))
return false
+ for (let pow of all_major_powers)
+ if (set_has(game.saved[pow], c))
+ return false
return true
})
}
@@ -3389,9 +3533,16 @@ exports.setup = function (seed, _scenario, _options) {
italy: 5, // political track
flags: 0, // emperor vp, italy vp, silesia annexed, etc
+ // for tracking VP gains/losses and political trump suit
+ winner_power: -1,
+ loser_power: -1,
+ trump: SPADES,
+
pol_deck: null,
deck: null,
hand: [ [], [], [], [], [], [] ],
+ saved: [ [], [], [], [] ],
+ display: [ [], [], [], [] ],
pos: setup_piece_position.slice(),
oos: 0,
@@ -3526,6 +3677,16 @@ function end_setup() {
/* VIEW */
+function mask_pol_deck() {
+ if (game.pol_deck.length > 0) {
+ let top = game.pol_deck[game.pol_deck.length - 1]
+ if (top === IMPERIAL_ELECTION)
+ return 2
+ return 1 + ((top-1) / 6 | 0)
+ }
+ return 0
+}
+
function mask_troops(player) {
let view_troops = []
for (let pow of all_powers) {
@@ -3559,6 +3720,30 @@ function mask_hand(player) {
return view_hand
}
+function mask_display(player) {
+ let view_display = []
+ for (let pow of all_major_powers) {
+ if (game.display[pow] === 0)
+ view_display[pow] = -1
+ else if (player_from_power(pow) === player)
+ view_display[pow] = game.display[pow]
+ else
+ view_display[pow] = game.display[pow] & ~127
+ }
+ return view_display
+}
+
+function mask_saved(player) {
+ let view_saved = []
+ for (let pow of all_major_powers) {
+ if (player_from_power(pow) === player)
+ view_saved[pow] = game.saved[pow]
+ else
+ view_saved[pow] = game.saved[pow].map(c => c & ~127)
+ }
+ return view_saved
+}
+
function total_troops_list() {
let list = []
for (let pow of all_powers) {
@@ -3594,6 +3779,9 @@ exports.view = function (state, player) {
pt: total_troops_list(),
discard: total_discard_list(),
+ pol_deck: mask_pol_deck(),
+ saved: mask_saved(player),
+
power: game.power,
retro: game.retro,
}
@@ -3603,6 +3791,9 @@ exports.view = function (state, player) {
view.defender = game.defender
}
+ if (game.display)
+ view.display = mask_display(player)
+
if (game.state === "game_over") {
view.prompt = game.victory
view.troops = game.troops
@@ -3693,6 +3884,10 @@ function gen_action_card(c) {
gen_action("card", c)
}
+function gen_action_political(c) {
+ gen_action("political", c)
+}
+
function log(msg) {
game.log.push(msg)
}