From b9f53c30064066e39e18b35697a1e4be21472c15 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 6 Jun 2024 13:45:08 +0200 Subject: x --- play.css | 214 ++++++++++++++++++++++++++++++++++++++---------------------- play.html | 25 ++++++- play.js | 132 ++++++++++++++++++++++++------------- rules.js | 221 +++++++++++++++++++++----------------------------------------- 4 files changed, 316 insertions(+), 276 deletions(-) diff --git a/play.css b/play.css index 95fe951..76fc72e 100644 --- a/play.css +++ b/play.css @@ -11,6 +11,7 @@ #prompt { font-family: "Suit Symbols", var(--font-widget); font-variant-numeric: tabular-nums; + white-space: wrap; } body { @@ -39,13 +40,12 @@ body { #political_display { position: relative; - margin: 0 auto; width: 877px; height: 620px; background-size: cover; background-image: url(Maria.Political.Display.075.jpg); background-color: #ece1a9; - box-shadow: 2px 2px 4px #0006; + Xbox-shadow: 2px 2px 4px #0006; border: 1px solid #0008; } @@ -77,34 +77,29 @@ svg .main_road { --color-light-bavaria: hsl(36, 70%, 80%); --color-light-prussia: hsl(210, 80%, 75%); --color-light-saxony: hsl(140, 50%, 70%); - --color-light-pragmatic: hsl(0, 0%, 75%); + --color-light-pragmatic: hsl(264, 10%, 75%); --color-light-austria: hsl(0, 0%, 97%); --color-light-political: hsl(50, 73%, 78%); + --color-light-discard: hsl(52, 37%, 80%); --color-medium-france: hsl(0, 35%, 70%); --color-medium-bavaria: hsl(36, 65%, 70%); --color-medium-prussia: hsl(210, 30%, 60%); --color-medium-saxony: hsl(140, 20%, 55%); - --color-medium-pragmatic: hsl(0, 0%, 65%); + --color-medium-pragmatic: hsl(264, 10%, 65%); --color-medium-austria: hsl(0, 0%, 90%); --color-medium-political: hsl(50, 35%, 60%); - - --color-dark-france: hsl(358, 85%, 52%); - --color-dark-bavaria: hsl(36, 65%, 52%); - --color-dark-prussia: hsl(198, 100%, 24%); - --color-dark-saxony: hsl(139, 72%, 28%); - --color-dark-pragmatic: hsl(0, 0%, 87%); - --color-dark-austria: hsl(0, 0%, 97%); + --color-medium-discard: hsl(52, 25%, 70%); --color-role-louis: hsl(0, 70%, 80%); --color-role-frederick: hsl(210, 80%, 75%); --color-role-maria: hsl(0, 0%, 97%); - --color-clubs: #007c49; - --color-diamonds: #c2263e; - --color-hearts: #ed1c24; - --color-spades: #274085; - --color-reserve: #0094c9; + --color-clubs: #0079a1; + --color-diamonds: #9d403f; + --color-hearts: #ed1c23; + --color-spades: #00507c; + --color-reserve: #59594c; } /* PANELS */ @@ -130,8 +125,7 @@ svg .main_road { justify-content: start; flex-wrap: wrap; padding: 18px; - gap: 18px; - min-height: 256px; + min-height: calc(257px + 4px); } #hand_france_header { background-color: var(--color-light-france) } @@ -151,6 +145,8 @@ svg .main_road { #political_header { background-color: var(--color-light-political) } #political_panel { background-color: var(--color-medium-political) } +#discard_pile_header { background-color: var(--color-light-discard); } +#discard_pile_panel { background-color: var(--color-medium-discard); } /* LOG */ @@ -195,6 +191,8 @@ svg .main_road { #log span.suit { font-size: 11px; } +span.value { padding: 0 1px } + span.suit.reserve { padding: 0 1px; } span.suit.spades { color: var(--color-spades) } @@ -412,6 +410,19 @@ span.suit.reserve { color: var(--color-reserve); font-weight: bold; font-family: .number.n7 { background-position: -84px 0px; } .number.n8 { background-position: -98px 0px; } +/* CARD COUNTING AIDS */ + +@media (hover: hover) { + #shift_button { + display: none; + } +} + +body.shift span.value.deck_1 { background-color: #9513 } +body.shift span.value.deck_2 { background-color: #04f2 } +body.shift span.value.deck_3 { background-color: #0f03 } +body.shift span.value.deck_4 { background-color: #f002 } + /* CARDS */ .card { @@ -444,9 +455,26 @@ span.suit.reserve { color: var(--color-reserve); font-weight: bold; font-family: .card.polcard { cursor: zoom-in } .card.polcard.zoom { cursor: zoom-out } -.draw-break { margin-left: 145px; } -.card.tc { margin-right: -145px; } -.panel_body { padding-right: calc(18px + 145px); } +.draw-break { margin-left: 167px; } +.card.tc { margin-right: calc(-167px + 40px); } +.card.tc.reverse { margin-right: calc(-167px + 20px); } +.card.tc.pile { margin-right: calc(-167px + 6px); } +.card.tc.hand { margin-right: calc(-167px + 10px); } +.card.polcard.pile { margin-right: calc(-167px + 6px); } + +.panel_body { padding-right: calc(18px + 167px); } +.panel_body { gap: 18px 0; } +#discard_pile_body { padding: 18px; gap: 18px; } + +#political_body { padding: 4px 0; display: body; } +#political_panel { width: 879px } +#discard_pile_panel { max-width: calc(230px * 4 + 18px * 5) } + +.card_pile { + display: flex; + flex-wrap: wrap; + width: 230px; +} .card.tc.H10 { background-image: url(cards/Maria.TC.01.075.jpg) } .card.tc.H9 { background-image: url(cards/Maria.TC.02.075.jpg) } @@ -491,15 +519,15 @@ span.suit.reserve { color: var(--color-reserve); font-weight: bold; font-family: .card.tc.reverse.deck_3 { background-image: url(cards/Maria.TC.reverse.deck_3.075.jpg) } .card.tc.reverse.deck_4 { background-image: url(cards/Maria.TC.reverse.deck_4.075.jpg) } -.card.polcard.c01 { background-image: url(cards/Maria.PolCard.01.075.jpg) } -.card.polcard.c02 { background-image: url(cards/Maria.PolCard.02.075.jpg) } -.card.polcard.c03 { background-image: url(cards/Maria.PolCard.03.075.jpg) } -.card.polcard.c04 { background-image: url(cards/Maria.PolCard.04.075.jpg) } -.card.polcard.c05 { background-image: url(cards/Maria.PolCard.05.075.jpg) } -.card.polcard.c06 { background-image: url(cards/Maria.PolCard.06.075.jpg) } -.card.polcard.c07 { background-image: url(cards/Maria.PolCard.07.075.jpg) } -.card.polcard.c08 { background-image: url(cards/Maria.PolCard.08.075.jpg) } -.card.polcard.c09 { background-image: url(cards/Maria.PolCard.09.075.jpg) } +.card.polcard.c1 { background-image: url(cards/Maria.PolCard.01.075.jpg) } +.card.polcard.c2 { background-image: url(cards/Maria.PolCard.02.075.jpg) } +.card.polcard.c3 { background-image: url(cards/Maria.PolCard.03.075.jpg) } +.card.polcard.c4 { background-image: url(cards/Maria.PolCard.04.075.jpg) } +.card.polcard.c5 { background-image: url(cards/Maria.PolCard.05.075.jpg) } +.card.polcard.c6 { background-image: url(cards/Maria.PolCard.06.075.jpg) } +.card.polcard.c7 { background-image: url(cards/Maria.PolCard.07.075.jpg) } +.card.polcard.c8 { background-image: url(cards/Maria.PolCard.08.075.jpg) } +.card.polcard.c9 { background-image: url(cards/Maria.PolCard.09.075.jpg) } .card.polcard.c10 { background-image: url(cards/Maria.PolCard.10.075.jpg) } .card.polcard.c11 { background-image: url(cards/Maria.PolCard.11.075.jpg) } .card.polcard.c12 { background-image: url(cards/Maria.PolCard.12.075.jpg) } @@ -515,70 +543,97 @@ span.suit.reserve { color: var(--color-reserve); font-weight: bold; font-family: .card.polcard.c22 { background-image: url(cards/Maria.PolCard.22.075.jpg) } .card.polcard.c23 { background-image: url(cards/Maria.PolCard.23.075.jpg) } .card.polcard.c24 { background-image: url(cards/Maria.PolCard.24.075.jpg) } -.card.polcard.impelection { background-image: url(cards/Maria.PolCard.ImpElection.075.jpg) } +.card.polcard.c25 { background-image: url(cards/Maria.PolCard.ImpElection.075.jpg) } + .card.polcard.reverse.deck_1 { background-image: url(cards/Maria.PolCard.reverse.deck_1.075.jpg) } .card.polcard.reverse.deck_2 { background-image: url(cards/Maria.PolCard.reverse.deck_2.075.jpg) } .card.polcard.reverse.deck_3 { background-image: url(cards/Maria.PolCard.reverse.deck_3.075.jpg) } .card.polcard.reverse.deck_4 { background-image: url(cards/Maria.PolCard.reverse.deck_4.075.jpg) } +.card.polcard.c1.zoom { background-image: url(cards/Maria.PolCard.01.150.jpg) } +.card.polcard.c2.zoom { background-image: url(cards/Maria.PolCard.02.150.jpg) } +.card.polcard.c3.zoom { background-image: url(cards/Maria.PolCard.03.150.jpg) } +.card.polcard.c4.zoom { background-image: url(cards/Maria.PolCard.04.150.jpg) } +.card.polcard.c5.zoom { background-image: url(cards/Maria.PolCard.05.150.jpg) } +.card.polcard.c6.zoom { background-image: url(cards/Maria.PolCard.06.150.jpg) } +.card.polcard.c7.zoom { background-image: url(cards/Maria.PolCard.07.150.jpg) } +.card.polcard.c8.zoom { background-image: url(cards/Maria.PolCard.08.150.jpg) } +.card.polcard.c9.zoom { background-image: url(cards/Maria.PolCard.09.150.jpg) } +.card.polcard.c10.zoom { background-image: url(cards/Maria.PolCard.10.150.jpg) } +.card.polcard.c11.zoom { background-image: url(cards/Maria.PolCard.11.150.jpg) } +.card.polcard.c12.zoom { background-image: url(cards/Maria.PolCard.12.150.jpg) } +.card.polcard.c13.zoom { background-image: url(cards/Maria.PolCard.13.150.jpg) } +.card.polcard.c14.zoom { background-image: url(cards/Maria.PolCard.14.150.jpg) } +.card.polcard.c15.zoom { background-image: url(cards/Maria.PolCard.15.150.jpg) } +.card.polcard.c16.zoom { background-image: url(cards/Maria.PolCard.16.150.jpg) } +.card.polcard.c17.zoom { background-image: url(cards/Maria.PolCard.17.150.jpg) } +.card.polcard.c18.zoom { background-image: url(cards/Maria.PolCard.18.150.jpg) } +.card.polcard.c19.zoom { background-image: url(cards/Maria.PolCard.19.150.jpg) } +.card.polcard.c20.zoom { background-image: url(cards/Maria.PolCard.20.150.jpg) } +.card.polcard.c21.zoom { background-image: url(cards/Maria.PolCard.21.150.jpg) } +.card.polcard.c22.zoom { background-image: url(cards/Maria.PolCard.22.150.jpg) } +.card.polcard.c23.zoom { background-image: url(cards/Maria.PolCard.23.150.jpg) } +.card.polcard.c24.zoom { background-image: url(cards/Maria.PolCard.24.150.jpg) } +.card.polcard.c25.zoom { background-image: url(cards/Maria.PolCard.ImpElection.150.jpg) } + /* @2x */ @media (min-resolution: 97dpi) { #map { background-image: url(Maria.Gameboard.150.jpg) } #political_display { background-image: url(Maria.Political.Display.150.jpg) } - .card.tc.c01 { background-image: url(cards/Maria.TC.01.150.jpg) } - .card.tc.c02 { background-image: url(cards/Maria.TC.02.150.jpg) } - .card.tc.c03 { background-image: url(cards/Maria.TC.03.150.jpg) } - .card.tc.c04 { background-image: url(cards/Maria.TC.04.150.jpg) } - .card.tc.c05 { background-image: url(cards/Maria.TC.05.150.jpg) } - .card.tc.c06 { background-image: url(cards/Maria.TC.06.150.jpg) } - .card.tc.c07 { background-image: url(cards/Maria.TC.07.150.jpg) } - .card.tc.c08 { background-image: url(cards/Maria.TC.08.150.jpg) } - .card.tc.c09 { background-image: url(cards/Maria.TC.09.150.jpg) } - .card.tc.c10 { background-image: url(cards/Maria.TC.10.150.jpg) } - .card.tc.c11 { background-image: url(cards/Maria.TC.11.150.jpg) } - .card.tc.c12 { background-image: url(cards/Maria.TC.12.150.jpg) } - .card.tc.c13 { background-image: url(cards/Maria.TC.13.150.jpg) } - .card.tc.c14 { background-image: url(cards/Maria.TC.14.150.jpg) } - .card.tc.c15 { background-image: url(cards/Maria.TC.15.150.jpg) } - .card.tc.c16 { background-image: url(cards/Maria.TC.16.150.jpg) } - .card.tc.c17 { background-image: url(cards/Maria.TC.17.150.jpg) } - .card.tc.c18 { background-image: url(cards/Maria.TC.18.150.jpg) } - .card.tc.c19 { background-image: url(cards/Maria.TC.19.150.jpg) } - .card.tc.c20 { background-image: url(cards/Maria.TC.20.150.jpg) } - .card.tc.c21 { background-image: url(cards/Maria.TC.21.150.jpg) } - .card.tc.c22 { background-image: url(cards/Maria.TC.22.150.jpg) } - .card.tc.c23 { background-image: url(cards/Maria.TC.23.150.jpg) } - .card.tc.c24 { background-image: url(cards/Maria.TC.24.150.jpg) } - .card.tc.c25 { background-image: url(cards/Maria.TC.25.150.jpg) } - .card.tc.c26 { background-image: url(cards/Maria.TC.26.150.jpg) } - .card.tc.c27 { background-image: url(cards/Maria.TC.27.150.jpg) } - .card.tc.c28 { background-image: url(cards/Maria.TC.28.150.jpg) } - .card.tc.c29 { background-image: url(cards/Maria.TC.29.150.jpg) } - .card.tc.c30 { background-image: url(cards/Maria.TC.30.150.jpg) } - .card.tc.c31 { background-image: url(cards/Maria.TC.31.150.jpg) } - .card.tc.c32 { background-image: url(cards/Maria.TC.32.150.jpg) } - .card.tc.c33 { background-image: url(cards/Maria.TC.33.150.jpg) } - .card.tc.c34 { background-image: url(cards/Maria.TC.34.150.jpg) } - .card.tc.c35 { background-image: url(cards/Maria.TC.35.150.jpg) } - .card.tc.c36 { background-image: url(cards/Maria.TC.36.150.jpg) } - .card.tc.c37 { background-image: url(cards/Maria.TC.37.150.jpg) } - .card.tc.c38 { background-image: url(cards/Maria.TC.38.150.jpg) } + .card.tc.H10 { background-image: url(cards/Maria.TC.01.150.jpg) } + .card.tc.H9 { background-image: url(cards/Maria.TC.02.150.jpg) } + .card.tc.H8 { background-image: url(cards/Maria.TC.03.150.jpg) } + .card.tc.H7 { background-image: url(cards/Maria.TC.04.150.jpg) } + .card.tc.H6 { background-image: url(cards/Maria.TC.05.150.jpg) } + .card.tc.H5 { background-image: url(cards/Maria.TC.06.150.jpg) } + .card.tc.H4 { background-image: url(cards/Maria.TC.07.150.jpg) } + .card.tc.H3 { background-image: url(cards/Maria.TC.08.150.jpg) } + .card.tc.H2 { background-image: url(cards/Maria.TC.09.150.jpg) } + .card.tc.R { background-image: url(cards/Maria.TC.10.150.jpg) } + .card.tc.S10 { background-image: url(cards/Maria.TC.11.150.jpg) } + .card.tc.S9 { background-image: url(cards/Maria.TC.12.150.jpg) } + .card.tc.S8 { background-image: url(cards/Maria.TC.13.150.jpg) } + .card.tc.S7 { background-image: url(cards/Maria.TC.14.150.jpg) } + .card.tc.S6 { background-image: url(cards/Maria.TC.15.150.jpg) } + .card.tc.S5 { background-image: url(cards/Maria.TC.16.150.jpg) } + .card.tc.S4 { background-image: url(cards/Maria.TC.17.150.jpg) } + .card.tc.S3 { background-image: url(cards/Maria.TC.18.150.jpg) } + .card.tc.S2 { background-image: url(cards/Maria.TC.19.150.jpg) } + .card.tc.D10 { background-image: url(cards/Maria.TC.21.150.jpg) } + .card.tc.D9 { background-image: url(cards/Maria.TC.22.150.jpg) } + .card.tc.D8 { background-image: url(cards/Maria.TC.23.150.jpg) } + .card.tc.D7 { background-image: url(cards/Maria.TC.24.150.jpg) } + .card.tc.D6 { background-image: url(cards/Maria.TC.25.150.jpg) } + .card.tc.D5 { background-image: url(cards/Maria.TC.26.150.jpg) } + .card.tc.D4 { background-image: url(cards/Maria.TC.27.150.jpg) } + .card.tc.D3 { background-image: url(cards/Maria.TC.28.150.jpg) } + .card.tc.D2 { background-image: url(cards/Maria.TC.29.150.jpg) } + .card.tc.C10 { background-image: url(cards/Maria.TC.30.150.jpg) } + .card.tc.C9 { background-image: url(cards/Maria.TC.31.150.jpg) } + .card.tc.C8 { background-image: url(cards/Maria.TC.32.150.jpg) } + .card.tc.C7 { background-image: url(cards/Maria.TC.33.150.jpg) } + .card.tc.C6 { background-image: url(cards/Maria.TC.34.150.jpg) } + .card.tc.C5 { background-image: url(cards/Maria.TC.35.150.jpg) } + .card.tc.C4 { background-image: url(cards/Maria.TC.36.150.jpg) } + .card.tc.C3 { background-image: url(cards/Maria.TC.37.150.jpg) } + .card.tc.C2 { background-image: url(cards/Maria.TC.38.150.jpg) } + .card.tc.reverse.deck_1 { background-image: url(cards/Maria.TC.reverse.deck_1.150.jpg) } .card.tc.reverse.deck_2 { background-image: url(cards/Maria.TC.reverse.deck_2.150.jpg) } .card.tc.reverse.deck_3 { background-image: url(cards/Maria.TC.reverse.deck_3.150.jpg) } .card.tc.reverse.deck_4 { background-image: url(cards/Maria.TC.reverse.deck_4.150.jpg) } - .card.polcard.c01 { background-image: url(cards/Maria.PolCard.01.150.jpg) } - .card.polcard.c02 { background-image: url(cards/Maria.PolCard.02.150.jpg) } - .card.polcard.c03 { background-image: url(cards/Maria.PolCard.03.150.jpg) } - .card.polcard.c04 { background-image: url(cards/Maria.PolCard.04.150.jpg) } - .card.polcard.c05 { background-image: url(cards/Maria.PolCard.05.150.jpg) } - .card.polcard.c06 { background-image: url(cards/Maria.PolCard.06.150.jpg) } - .card.polcard.c07 { background-image: url(cards/Maria.PolCard.07.150.jpg) } - .card.polcard.c08 { background-image: url(cards/Maria.PolCard.08.150.jpg) } - .card.polcard.c09 { background-image: url(cards/Maria.PolCard.09.150.jpg) } + .card.polcard.c1 { background-image: url(cards/Maria.PolCard.01.150.jpg) } + .card.polcard.c2 { background-image: url(cards/Maria.PolCard.02.150.jpg) } + .card.polcard.c3 { background-image: url(cards/Maria.PolCard.03.150.jpg) } + .card.polcard.c4 { background-image: url(cards/Maria.PolCard.04.150.jpg) } + .card.polcard.c5 { background-image: url(cards/Maria.PolCard.05.150.jpg) } + .card.polcard.c6 { background-image: url(cards/Maria.PolCard.06.150.jpg) } + .card.polcard.c7 { background-image: url(cards/Maria.PolCard.07.150.jpg) } + .card.polcard.c8 { background-image: url(cards/Maria.PolCard.08.150.jpg) } + .card.polcard.c9 { background-image: url(cards/Maria.PolCard.09.150.jpg) } .card.polcard.c10 { background-image: url(cards/Maria.PolCard.10.150.jpg) } .card.polcard.c11 { background-image: url(cards/Maria.PolCard.11.150.jpg) } .card.polcard.c12 { background-image: url(cards/Maria.PolCard.12.150.jpg) } @@ -594,7 +649,8 @@ span.suit.reserve { color: var(--color-reserve); font-weight: bold; font-family: .card.polcard.c22 { background-image: url(cards/Maria.PolCard.22.150.jpg) } .card.polcard.c23 { background-image: url(cards/Maria.PolCard.23.150.jpg) } .card.polcard.c24 { background-image: url(cards/Maria.PolCard.24.150.jpg) } - .card.polcard.impelection { background-image: url(cards/Maria.PolCard.ImpElection.150.jpg) } + .card.polcard.c25 { background-image: url(cards/Maria.PolCard.ImpElection.150.jpg) } + .card.polcard.reverse.deck_1 { background-image: url(cards/Maria.PolCard.reverse.deck_1.150.jpg) } .card.polcard.reverse.deck_2 { background-image: url(cards/Maria.PolCard.reverse.deck_2.150.jpg) } .card.polcard.reverse.deck_3 { background-image: url(cards/Maria.PolCard.reverse.deck_3.150.jpg) } diff --git a/play.html b/play.html index 2cc2490..4f7e2b5 100644 --- a/play.html +++ b/play.html @@ -94,9 +94,9 @@ -
+
Political Display
-
+
@@ -106,12 +106,31 @@
+
+
+
+
+
+
+
+
+
+
+
-
+
+
Decks & Discard Piles
+
+
+
+
+
+
+
diff --git a/play.js b/play.js index daf430c..3d8235d 100644 --- a/play.js +++ b/play.js @@ -18,6 +18,10 @@ function toggle_pieces() { } } +function toggle_shift() { + document.body.classList.toggle("shift") +} + /* DATA */ const P_FRANCE = 0 @@ -108,12 +112,12 @@ const piece_name = [ "BatthyƔny", "Neipperg", "Arenberg", - "supply train", "supply train", - "supply train", - "supply train", "supply train", - "supply train", - "supply train", - "supply train", "supply train", "supply train", + "French ST", "French ST", + "Bavarian ST", + "Prussian ST", "Prussian ST", + "Saxon ST", + "Pragmatic Army ST", + "Austrian ST", "Austrian ST", "Austrian ST", "hussars", "hussars", ] @@ -160,7 +164,6 @@ function make_road(c1, c2, type) { document.getElementById("roads").appendChild(e) } - /* PANEL ORDER */ const panel_order = [ P_FRANCE, P_BAVARIA, P_PRUSSIA, P_SAXONY, P_PRAGMATIC, P_AUSTRIA, P_AUSTRIA+1 ] @@ -234,6 +237,12 @@ const ui = { pieces_element: document.getElementById("pieces"), markers_element: document.getElementById("markers"), political_display: document.getElementById("political_display"), + discard: [ + document.getElementById("discard_1"), + document.getElementById("discard_2"), + document.getElementById("discard_3"), + document.getElementById("discard_4"), + ], power_panel_list: document.getElementById("power_panel_list"), power_header: [ document.getElementById("hand_france_header"), @@ -334,6 +343,16 @@ function make_tc_deck_back(n) { return list } +function make_tc_deck_discard(n) { + let list = [] + for (let i = 0; i < 10; ++i) { + let e = document.createElement("div") + e.className = "card tc pile reverse " + n + list.push(e) + } + return list +} + function make_political_card(fc) { let e = document.createElement("div") if (fc === 0) @@ -427,6 +446,13 @@ function on_init() { make_tc_deck_back("deck_4"), ] + ui.tc_discard = [ + make_tc_deck_discard("deck_1"), + make_tc_deck_discard("deck_2"), + make_tc_deck_discard("deck_3"), + make_tc_deck_discard("deck_4"), + ] + ui.combat = document.createElement("div") ui.combat.id = "combat" ui.combat.style.zIndex = 2000 @@ -552,7 +578,11 @@ function on_blur_city() { } function on_focus_piece(evt) { - ui.status.textContent = piece_name[evt.target.my_id] + let p = evt.target.my_id + if (p < 20 && view.troops[p] > 0) + ui.status.textContent = piece_name[evt.target.my_id] + " (" + view.troops[p] + " troops)" + else + ui.status.textContent = piece_name[evt.target.my_id] } function on_blur_piece() { @@ -609,16 +639,15 @@ function get_cylinder_power(id) { } function layout_general(id, s) { - let e = ui.pieces[id] let x, y, n if (s === REMOVED) { - if (e.parentElement === ui.pieces_element) + if (ui.pieces[id].parentElement === ui.pieces_element) + e.remove() + if (ui.troops[id].parentElement === ui.pieces_element) e.remove() return } - if (e.parentElement !== ui.pieces_element) - ui.pieces_element.appendChild(e) if (s === ELIMINATED) { n = layout_general_offset_elim(id) @@ -632,6 +661,9 @@ function layout_general(id, s) { let selected = set_has(view.selected, id) + let e = ui.pieces[id] + if (e.parentElement !== ui.pieces_element) + ui.pieces_element.appendChild(e) e.style.left = (x - 21) + "px" e.style.top = (y - 29 - 15 * n) + "px" e.style.zIndex = y + n @@ -639,10 +671,9 @@ function layout_general(id, s) { e.classList.toggle("oos", (view.oos & (1 <\u2660', - '\u2663', - '\u2665', - '\u2666', - 'R' -] +const colorize_1 = '$1' +const colorize_2 = '$1' +const colorize_3 = '$1' +const colorize_4 = '$1' function colorize(text) { + text = text.replace(/1\^(\d+)/g, colorize_1) + text = text.replace(/2\^(\d+)/g, colorize_2) + text = text.replace(/3\^(\d+)/g, colorize_3) + text = text.replace(/4\^(\d+)/g, colorize_4) + text = text.replace(/(\d+)R/g, colorize_R) text = text.replaceAll("\u2660", colorize_S) text = text.replaceAll("\u2663", colorize_C) text = text.replaceAll("\u2665", colorize_H) text = text.replaceAll("\u2666", colorize_D) - text = text.replace(/(\d+)R/g, colorize_R) return text } -function on_update() { -// let text = colorize(view.prompt) -// if (text !== view.prompt) -// ui.prompt.innerHTML = text +function on_prompt(text) { + return colorize(view.prompt) +} +function on_update() { ui.header.classList.toggle("france", view.power === P_FRANCE) ui.header.classList.toggle("bavaria", view.power === P_BAVARIA) ui.header.classList.toggle("prussia", view.power === P_PRUSSIA) @@ -791,6 +824,7 @@ function on_update() { ui.hand[pow].replaceChildren() view.hand[pow].sort(cmp_tc) for (let c of view.hand[pow]) { + console.log("C", c, c&15) if ((c & 15) === 0) ui.hand[pow].appendChild(ui.tc_back[c>>7][back[c>>7]++]) else @@ -816,6 +850,12 @@ function on_update() { ui.political_display.appendChild(ui.fate[c]) */ + for (let deck = 0; deck < 4; ++deck) { + ui.discard[deck].replaceChildren() + for (let i = 0; i < view.discard[deck]; ++i) + ui.discard[deck].appendChild(ui.tc_discard[deck][i]) + } + ui.markers_element.replaceChildren() /* for (let s of view.conquest) @@ -833,7 +873,7 @@ function on_update() { action_button_with_argument("value", v, v) for (let p = 0; p < 20; ++p) { - action_button_with_argument("detach", p, "Detach " + piece_abbr[p]) + action_button_with_argument("unstack", p, "Unstack " + piece_abbr[p]) action_button_with_argument("promote", p, "Promote " + piece_abbr[p]) action_button_with_argument("demote", p, "Demote " + piece_abbr[p]) } @@ -879,8 +919,13 @@ function sub_space(match, p1) { return `${n}` } -function sub_tc(match, p1) { - return value + suit_text[suit] +function sub_path(pieces_and_spaces) { + let ps = pieces_and_spaces[0].split(",") + let ss = pieces_and_spaces[1].split(",") + let x = ss[ss.length-1] + let ps_name = ps.map(p => piece_name[p]).join(" and ") + let ss_name = data.cities.name[x] + return `${ps_name} to ${ss_name}.` } function on_log(text) { @@ -905,29 +950,24 @@ function on_log(text) { text = text.replace(//g, ">") + text = text.replaceAll(" 1 troops", " 1 troop") + + text = colorize(text) text = text.replace(/S(\d+)/g, sub_space) text = text.replace(/P(\d+)/g, sub_piece) - text = colorize(text) - if (text.match(/^\$(\d+)/)) { - let fx = parseInt(text.substring(1)) - if (fx < 48 + 6) - text = `
${fate_flavor_text[fx]}
${fate_effect_text[fx]}
` - else - text = `
${fate_flavor_text[fx]}
` - } - else if (text.match(/^# /)) { - p.className = "h fate" + if (text.startsWith("#")) { + p.className = "h turn" text = text.substring(2) } - else if (text.match(/^\.s1/)) - text = the_war_in_the_west_text - else if (text.match(/^\.s2/)) - text = the_austrian_theater_text - else if (text.match(/^=\d/)) { + else if (text.startsWith("=")) { p.className = "h " + power_class[text[1]] text = power_name[text[1]] } + else if (text.startsWith("@")) { + p.className = "move_tip" + text = sub_path(text.substring(1).split(";")) + } p.innerHTML = text return p diff --git a/rules.js b/rules.js index bdb4a00..e1659f2 100644 --- a/rules.js +++ b/rules.js @@ -1,115 +1,3 @@ -"use strict" - -/* -var game, view - -// piece list: -// generals, trains, and hussars - have location (loc) -// generals - have strength (str) - -// space list: -// objective/fortress have control (0 or power) - -const data = require("./data") -let objectives = {} -let anti_objectives = { Austria: [], "Pragmatic Army": [], France: [], Prussia: [] } -let prot_objectives = { Austria: [], "Pragmatic Army": [], France: [], Prussia: [] } - -let whose_objective = { - Austria: [ "France", "Prussia" ], - Bavaria: [ "Austria" ], - France: [ "Austria", "Pragmatic Army" ], - Netherlands: [ "France" ], - Prussia: [ "Austria" ], - Saxony: [ "Austria" ], - Silesia: [ "Austria", "Prussia" ], - HRE: [ "Austria", "Pragmatic Army", "France" ], -} - -let protect_objective = { - Austria: [ "Austria" ], - Bavaria: [ "France" ], - France: [ "France" ], - Netherlands: [ "Pragmatic Army" ], - Prussia: [ "Prussia" ], - Saxony: [ "Prussia" ], - Silesia: [ "Austria", "Prussia" ], - HRE: [ "Austria", "Pragmatic Army", "France" ], -} - -for (let type of [ "major_fortress", "minor_fortress" ]) { - let group = object_group_by(data.type[type], s => data.cities.country[s]) - for (let region in group) { - if (objectives[region] === undefined) - objectives[region] = [] - for (let s of group[region]) { - set_add(objectives[region], s) - console.log(region) - for (let list of whose_objective[region]) - set_add(anti_objectives[list], s) - for (let list of protect_objective[region]) - set_add(prot_objectives[list], s) - } - - } -} -for (let x in anti_objectives) - console.log(x, anti_objectives[x].length) -console.log(objectives) -console.log("TAKE", anti_objectives) -console.log("PROT", prot_objectives) - -exports.roles = [ - "Louis XV", - "Frederick", - "Maria Theresa", -] - -exports.scenarios = [ "Standard", "Introductory" ] - -const P_AUSTRIA = 0 -const P_PRUSSIA = 1 -const P_SAXONY = 2 -const P_PRAGMATIC = 3 -const P_FRANCE = 4 -const P_BAVARIA = 5 - -const PLAYERS = { - "Maria Theresa": [ P_AUSTRIA ], - "Frederick": [ P_PRUSSIA, P_SAXONY, P_PRAGMATIC ], - "Louis XV": [ P_FRANCE, P_BAVARIA ], -} - -const MAJOR_POWERS = [ P_AUSTRIA, P_PRUSSIA, P_FRANCE, P_PRAGMATIC ] - -const MINOR_POWERS = [ P_BAVARIA, P_SAXONY ] - -const ALLIED = [ - [ P_FRANCE, P_BAVARIA, P_PRUSSIA, P_SAXONY ], - [ P_AUSTRIA, P_PRAGMATIC ], -] - -const COOPERATE = [ - [ P_FRANCE, P_BAVARIA ], - [ P_PRUSSIA, P_SAXONY ], - [ P_AUSTRIA, P_PRAGMATIC ], -] - -*/ - - - - - - - - - - - - - - "use strict" const R_LOUIS_XV = "Louis XV" @@ -314,22 +202,36 @@ function to_value(c) { return c & 15 } -function format_card(c) { +function format_card_prompt(c) { if (is_reserve(c)) return "8R" return to_value(c) + suit_name[to_suit(c)] } +function format_card(c) { + return (to_deck(c)+1) + "^" + format_card_prompt(c) +} + +function format_reserve(c, v) { + return (to_deck(c)+1) + "^" + v + "R" +} + function is_reserve(c) { return to_suit(c) === RESERVE } -function format_cards(list) { +function format_card_list(list) { if (list.length > 0) return list.map(format_card).join(", ") return "nothing" } +function format_card_list_prompt(list) { + if (list.length > 0) + return list.map(format_card_prompt).join(", ") + return "nothing" +} + function format_selected() { if (game.selected.length === 0) return "nobody" @@ -682,19 +584,29 @@ function find_largest_discard(u) { throw "OUT OF CARDS" } -function next_tactics_deck() { - let held = [ 0, 0, 0, 0, 0 ] +function count_used_cards() { + let held = [ 0, 0, 0, 0 ] // count cards in hands for (let pow of all_powers) { for (let c of game.hand[pow]) held[to_deck(c)]++ } + + // count cards currently being held if (game.draw) for (let c of game.draw) held[to_deck(c)]++ - if (game.oo > 0) - held[to_deck(game.oo)]++ + + // count cards remaining in deck + for (let c of game.deck) + held[to_deck(c)]++ + + return held +} + +function next_tactics_deck() { + let held = count_used_cards() // find next unused deck for (let i = 1; i < 5; ++i) { @@ -726,6 +638,13 @@ function next_tactics_deck() { shuffle_bigint(game.deck) } +function total_discard_list() { + let discard = count_used_cards() + for (let i = 0; i < 4; ++i) + discard[i] = Math.ceil((38 - discard[i]) / 5) + return discard +} + function draw_tc(n) { game.draw = [] @@ -763,7 +682,7 @@ states.tactical_cards_show = { inactive: "draw tactical cards", prompt() { view.draw = game.draw - prompt("Draw " + format_cards(game.draw) + ".") + prompt("Draw " + format_card_list_prompt(game.draw) + ".") view.actions.end_cards = 1 }, end_cards() { @@ -942,10 +861,10 @@ states.movement = { game.count = 0 - if (data.cities.major_roads[here].length > 0) - game.major = 1 + if (data.cities.main_roads[here].length > 0) + game.main = 1 else - game.major = 0 + game.main = 0 if (is_supply_train(p)) game.state = "move_supply_train" @@ -973,7 +892,7 @@ states.movement = { function format_move(max) { let n = max - game.count - if (game.major) + if (game.main) return ` up to ${n} cities (${n+1} on main roads).` return ` up to ${n} cities.` } @@ -1075,8 +994,8 @@ states.move_supply_train = { let who = game.selected[0] let here = game.pos[who] - if (game.count < 2 + game.major) - for (let next of data.cities.major_roads[here]) + if (game.count < 2 + game.main) + for (let next of data.cities.main_roads[here]) if (!has_any_piece(next)) gen_action_space(next) if (game.count < 2) @@ -1107,13 +1026,13 @@ states.move_supply_train = { log(">to S" + to) - if (!set_has(data.cities.major_roads[from], to)) - game.major = 0 + if (!set_has(data.cities.main_roads[from], to)) + game.main = 0 set_add(game.moved, who) game.pos[who] = to - if (++game.count === 2 + game.major) + if (++game.count === 2 + game.main) end_move_piece() }, } @@ -1131,7 +1050,7 @@ states.move_general = { if (game.selected.length > 1) { for (let p of game.selected) { gen_action_piece(p) - gen_action_detach(p) + gen_action_unstack(p) } } @@ -1151,8 +1070,8 @@ states.move_general = { view.actions.stop = 1 } - if (game.count < movement_range() + game.major) - for (let next of data.cities.major_roads[here]) + if (game.count < movement_range() + game.main) + for (let next of data.cities.main_roads[here]) if (can_move_general_to(next)) gen_action_space_or_piece(next) @@ -1167,7 +1086,7 @@ states.move_general = { give() { game.state = "move_give" }, - detach(p) { + unstack(p) { set_delete(game.selected, p) }, piece(p) { @@ -1199,10 +1118,10 @@ states.move_general = { log(">to S" + to) - if (!set_has(data.cities.major_roads[from], to)) - game.major = 0 + if (!set_has(data.cities.main_roads[from], to)) + game.main = 0 - if (move_general_to(to) || ++game.count === movement_range() + game.major) + if (move_general_to(to) || ++game.count === movement_range() + game.main) end_move_piece() }, } @@ -1698,22 +1617,22 @@ function format_combat(value) { let d = format_combat_stack(game.defender) let s = signed_number(value) let p = POWER_NAME[game.power] - return `${a} vs ${d}. ${p} is at ${s}` + return `${a} vs ${d}. ${p} is at ${s}.` } function inactive_attack() { - return "combat " + format_combat(game.count) + return "Waiting for " + format_combat(game.count) } function inactive_defend() { - return "combat " + format_combat(-game.count) + return "Waiting for " + format_combat(-game.count) } function prompt_combat(value, extra = null) { - let text = "Combat " + format_combat(value) + "." + let text = format_combat(value) if (extra) text += " " + extra - prompt(text) + view.prompt = text } function set_active_attacker() { @@ -1764,6 +1683,7 @@ function gen_play_card(suit) { } function gen_play_reserve() { + view.draw = [ game.reserve ] view.actions.value = [ 1, 2, 3, 4, 5, 6, 7, 8 ] } @@ -1778,13 +1698,15 @@ function play_card(c, sign) { } function play_reserve(v, sign) { + let c = game.reserve + delete game.reserve let prefix = (sign < 0 ? ">>" : ">") + POWER_NAME[game.power] if (sign < 0) game.count -= v else game.count += v let score = signed_number(sign * game.count) - log(`${prefix} ${v}R = ${score}`) + log(`${prefix} ${format_reserve(c, v)} = ${score}`) } function play_combat_card(c, sign, resume, next_state) { @@ -1792,6 +1714,7 @@ function play_combat_card(c, sign, resume, next_state) { array_remove_item(game.hand[game.power], c) if (is_reserve(c)) { game.state = next_state + game.reserve = c } else { play_card(c, sign) resume() @@ -2486,8 +2409,6 @@ function make_tactics_deck(n) { function make_tactics_discard(n) { return make_tactics_deck(n).filter(c => { - if (c === game.oo) - return false if (game.draw && set_has(game.draw, c)) return false for (let pow of all_powers) @@ -2693,6 +2614,7 @@ exports.view = function (state, player) { troops: mask_troops(player), hand: mask_hand(player), pt: total_troops_list(), + discard: total_discard_list(), power: game.power, retro: game.retro, @@ -2705,11 +2627,14 @@ exports.view = function (state, player) { if (game.state === "game_over") { view.prompt = game.victory + view.troops = game.troops + view.hand = game.hand } else if (game.active !== player) { let inactive = states[game.state].inactive || game.state if (typeof inactive === "function") - inactive = inactive() - view.prompt = `Waiting for ${POWER_NAME[game.power]} to ${inactive}.` + view.prompt = inactive() + else + view.prompt = `Waiting for ${POWER_NAME[game.power]} to ${inactive}.` } else { view.actions = {} if (states[game.state]) @@ -2730,11 +2655,11 @@ exports.view = function (state, player) { /* COMMON FRAMEWORK */ function goto_game_over(result, victory) { + log("# The End") game.active = "None" game.state = "game_over" game.result = result game.victory = victory - log("# Game Over") log(game.victory) return true } @@ -2790,8 +2715,8 @@ function gen_action_card(c) { gen_action("card", c) } -function gen_action_detach(p) { - gen_action("detach", p) +function gen_action_unstack(p) { + gen_action("unstack", p) } function log(msg) { -- cgit v1.2.3