From fe2bc3961ec3b3164786074b37e36581b81fa68c Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sun, 23 Feb 2025 18:37:17 +0100 Subject: New client and client data processing tools. --- images/texture.png | Bin 0 -> 27561 bytes land-and-freedom.css | 930 --------------------------------------- land-and-freedom.scss | 525 ---------------------- package.json | 5 +- play.css | 379 ++++++++++++++++ play.html | 108 ++--- play.js | 1060 ++++++++++++++++++++++++--------------------- play.ts | 623 -------------------------- rules.js | 2 +- rules.ts | 2 +- tools/colors.js | 143 ++++++ tools/gencolor.js | 27 ++ tools/gentextures.sh | 4 + tools/parse-layout.js | 167 +++++++ tools/rock_overlay@2x.png | Bin 0 -> 160515 bytes 15 files changed, 1330 insertions(+), 2645 deletions(-) create mode 100644 images/texture.png delete mode 100644 land-and-freedom.css delete mode 100644 land-and-freedom.scss create mode 100644 play.css delete mode 100644 play.ts create mode 100644 tools/colors.js create mode 100644 tools/gencolor.js create mode 100644 tools/gentextures.sh create mode 100644 tools/parse-layout.js create mode 100644 tools/rock_overlay@2x.png diff --git a/images/texture.png b/images/texture.png new file mode 100644 index 0000000..963f0ad Binary files /dev/null and b/images/texture.png differ diff --git a/land-and-freedom.css b/land-and-freedom.css deleted file mode 100644 index 0fb77dc..0000000 --- a/land-and-freedom.css +++ /dev/null @@ -1,930 +0,0 @@ -main { - background-color: #7b904b; -} - -/* MAP */ -#mapwrap { - width: 1000px; - height: 850px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2666666667); -} - -#map { - background-repeat: no-repeat; - background-size: 100% 100%; - width: 1000px; - height: 850px; - overflow: clip; -} - -#map { - background-image: url(images/map75.png); -} - -@media (min-resolution: 97dpi) { - #map { - background-image: url(images/map100.png); - } -} -#current_events .card:last-child { - transform: scale(1.2); -} - -/* CURRENT CARD */ -#turn_info { - border-bottom: 1px solid black; - overflow: clip; - background-color: gray; - white-space: normal; - padding: 8px 0px; -} - -#turn_info .card { - margin: 0 auto; -} - -@media (max-height: 800px) { - #turn_info { - height: 95px; - } - #turn_info:hover { - height: auto; - } -} -@media (max-height: 600px) { - #turn_info { - display: none; - } -} -.game_info { - padding: 3px 4px; - border-bottom: 1px solid black; - font-size: 16px; - line-height: 1.5; - grid-column: 1; - grid-row: 1; - display: flex; - flex-direction: column; - background: floralwhite; -} - -#roles { - grid-column: 1; - grid-row: 2; -} - -.role_medallions { - grid-row: 3; - grid-column: 1/3; - padding: 3px 4px; - display: flex; - flex-direction: row-reverse; - gap: 4px; -} - -.role_info { - grid-row: 4; - grid-column: 1/3; -} - -#role_Anarchist { - background-color: rgb(93, 89, 106); -} - -#role_Communist { - background-color: rgb(237, 36, 27); -} - -#role_Moderate { - background-color: rgb(134, 44, 97); -} - -.role { - color: floralwhite; -} -.role a { - color: floralwhite; -} - -#selectable_cards { - display: flex; - justify-content: center; - flex-wrap: wrap; - padding: 12px; - gap: 12px; - min-height: 260px; -} - -#selectable_cards:empty { - display: none; -} - -.panel { - min-width: 1271px; - max-width: 1271px; - background-color: #58641d; - margin: 12px auto; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2666666667); - border: 2px solid #333; -} - -.panel_body { - display: flex; - justify-content: center; - flex-wrap: wrap; - padding: 12px; - gap: 12px; - min-height: 260px; -} - -.panel_body[data-active=inactive] { - display: none; -} - -.panel_header { - color: floralwhite; - user-select: none; - font-weight: bold; - text-align: center; - border-bottom: 2px solid #333; - background-color: red; -} - -#player_area_header { - background-color: #273b09; - display: flex; - border-bottom: none; -} -#player_area_header .player_area_tab { - cursor: pointer; - width: 25%; - border-bottom: 2px solid #333; - border-left: 1px solid #333; - border-right: 1px solid #333; -} -#player_area_header .player_area_tab[data-active=active] { - width: 25%; - background-color: #58641d; - border-bottom: none; -} -#player_area_header #hand_tab { - border-left: none; -} -#player_area_header #trash_tab { - border-right: none; -} - -#player_area_header[data-faction-id=a], -.panel_header[data-faction-id=a] { - background-color: rgb(93, 89, 106); -} - -#player_area_header[data-faction-id=c], -.panel_header[data-faction-id=c] { - background-color: rgb(237, 36, 27); -} - -#player_area_header[data-faction-id=m], -.panel_header[data-faction-id=m] { - background-color: rgb(134, 44, 97); -} - -.front { - position: absolute; - box-sizing: border-box; - width: 93px; - height: 102px; - display: flex; - flex-direction: column; - align-items: center; - padding: 4px; - border-radius: 20px; -} - -.contributions { - display: flex; - flex-direction: row; - gap: 2px; - margin-top: 15px; - height: 25px; - z-index: -1; -} -.contributions .faction_token { - z-index: -1; -} - -.front .value { - font-weight: bold; - font-size: 30px; - margin-top: auto; - z-index: -1; -} - -#madrid_front { - width: 104px; - height: 114px; - border-radius: 23px; -} - -#madrid_front .contributions { - padding: 0px 2px; -} - -.card { - background-size: 100% 100%; - width: 198px; - height: 270px; - border-radius: 5px; - box-shadow: 0 0 0 1px #333; -} - -.card[data-card-id="1"] { - background-image: url("images/cards100/card_1.png"); -} - -.card[data-card-id="2"] { - background-image: url("images/cards100/card_2.png"); -} - -.card[data-card-id="3"] { - background-image: url("images/cards100/card_3.png"); -} - -.card[data-card-id="4"] { - background-image: url("images/cards100/card_4.png"); -} - -.card[data-card-id="5"] { - background-image: url("images/cards100/card_5.png"); -} - -.card[data-card-id="6"] { - background-image: url("images/cards100/card_6.png"); -} - -.card[data-card-id="7"] { - background-image: url("images/cards100/card_7.png"); -} - -.card[data-card-id="8"] { - background-image: url("images/cards100/card_8.png"); -} - -.card[data-card-id="9"] { - background-image: url("images/cards100/card_9.png"); -} - -.card[data-card-id="10"] { - background-image: url("images/cards100/card_10.png"); -} - -.card[data-card-id="11"] { - background-image: url("images/cards100/card_11.png"); -} - -.card[data-card-id="12"] { - background-image: url("images/cards100/card_12.png"); -} - -.card[data-card-id="13"] { - background-image: url("images/cards100/card_13.png"); -} - -.card[data-card-id="14"] { - background-image: url("images/cards100/card_14.png"); -} - -.card[data-card-id="15"] { - background-image: url("images/cards100/card_15.png"); -} - -.card[data-card-id="16"] { - background-image: url("images/cards100/card_16.png"); -} - -.card[data-card-id="17"] { - background-image: url("images/cards100/card_17.png"); -} - -.card[data-card-id="18"] { - background-image: url("images/cards100/card_18.png"); -} - -.card[data-card-id="19"] { - background-image: url("images/cards100/card_19.png"); -} - -.card[data-card-id="20"] { - background-image: url("images/cards100/card_20.png"); -} - -.card[data-card-id="21"] { - background-image: url("images/cards100/card_21.png"); -} - -.card[data-card-id="22"] { - background-image: url("images/cards100/card_22.png"); -} - -.card[data-card-id="23"] { - background-image: url("images/cards100/card_23.png"); -} - -.card[data-card-id="24"] { - background-image: url("images/cards100/card_24.png"); -} - -.card[data-card-id="25"] { - background-image: url("images/cards100/card_25.png"); -} - -.card[data-card-id="26"] { - background-image: url("images/cards100/card_26.png"); -} - -.card[data-card-id="27"] { - background-image: url("images/cards100/card_27.png"); -} - -.card[data-card-id="28"] { - background-image: url("images/cards100/card_28.png"); -} - -.card[data-card-id="29"] { - background-image: url("images/cards100/card_29.png"); -} - -.card[data-card-id="30"] { - background-image: url("images/cards100/card_30.png"); -} - -.card[data-card-id="31"] { - background-image: url("images/cards100/card_31.png"); -} - -.card[data-card-id="32"] { - background-image: url("images/cards100/card_32.png"); -} - -.card[data-card-id="33"] { - background-image: url("images/cards100/card_33.png"); -} - -.card[data-card-id="34"] { - background-image: url("images/cards100/card_34.png"); -} - -.card[data-card-id="35"] { - background-image: url("images/cards100/card_35.png"); -} - -.card[data-card-id="36"] { - background-image: url("images/cards100/card_36.png"); -} - -.card[data-card-id="37"] { - background-image: url("images/cards100/card_37.png"); -} - -.card[data-card-id="38"] { - background-image: url("images/cards100/card_38.png"); -} - -.card[data-card-id="39"] { - background-image: url("images/cards100/card_39.png"); -} - -.card[data-card-id="40"] { - background-image: url("images/cards100/card_40.png"); -} - -.card[data-card-id="41"] { - background-image: url("images/cards100/card_41.png"); -} - -.card[data-card-id="42"] { - background-image: url("images/cards100/card_42.png"); -} - -.card[data-card-id="43"] { - background-image: url("images/cards100/card_43.png"); -} - -.card[data-card-id="44"] { - background-image: url("images/cards100/card_44.png"); -} - -.card[data-card-id="45"] { - background-image: url("images/cards100/card_45.png"); -} - -.card[data-card-id="46"] { - background-image: url("images/cards100/card_46.png"); -} - -.card[data-card-id="47"] { - background-image: url("images/cards100/card_47.png"); -} - -.card[data-card-id="48"] { - background-image: url("images/cards100/card_48.png"); -} - -.card[data-card-id="49"] { - background-image: url("images/cards100/card_49.png"); -} - -.card[data-card-id="50"] { - background-image: url("images/cards100/card_50.png"); -} - -.card[data-card-id="51"] { - background-image: url("images/cards100/card_51.png"); -} - -.card[data-card-id="52"] { - background-image: url("images/cards100/card_52.png"); -} - -.card[data-card-id="53"] { - background-image: url("images/cards100/card_53.png"); -} - -.card[data-card-id="54"] { - background-image: url("images/cards100/card_54.png"); -} - -.card[data-card-id="55"] { - background-image: url("images/cards100/card_55.png"); -} - -.card[data-card-id="56"] { - background-image: url("images/cards100/card_56.png"); -} - -.card[data-card-id="57"] { - background-image: url("images/cards100/card_57.png"); -} - -.card[data-card-id="58"] { - background-image: url("images/cards100/card_58.png"); -} - -.card[data-card-id="59"] { - background-image: url("images/cards100/card_59.png"); -} - -.card[data-card-id="60"] { - background-image: url("images/cards100/card_60.png"); -} - -.card[data-card-id="61"] { - background-image: url("images/cards100/card_61.png"); -} - -.card[data-card-id="62"] { - background-image: url("images/cards100/card_62.png"); -} - -.card[data-card-id="63"] { - background-image: url("images/cards100/card_63.png"); -} - -.card[data-card-id="64"] { - background-image: url("images/cards100/card_64.png"); -} - -.card[data-card-id="65"] { - background-image: url("images/cards100/card_65.png"); -} - -.card[data-card-id="66"] { - background-image: url("images/cards100/card_66.png"); -} - -.card[data-card-id="67"] { - background-image: url("images/cards100/card_67.png"); -} - -.card[data-card-id="68"] { - background-image: url("images/cards100/card_68.png"); -} - -.card[data-card-id="69"] { - background-image: url("images/cards100/card_69.png"); -} - -.card[data-card-id="70"] { - background-image: url("images/cards100/card_70.png"); -} - -.card[data-card-id="71"] { - background-image: url("images/cards100/card_71.png"); -} - -.card[data-card-id="72"] { - background-image: url("images/cards100/card_72.png"); -} - -.card[data-card-id="73"] { - background-image: url("images/cards100/card_73.png"); -} - -.card[data-card-id="74"] { - background-image: url("images/cards100/card_74.png"); -} - -.card[data-card-id="75"] { - background-image: url("images/cards100/card_75.png"); -} - -.card[data-card-id="76"] { - background-image: url("images/cards100/card_76.png"); -} - -.card[data-card-id="77"] { - background-image: url("images/cards100/card_77.png"); -} - -.card[data-card-id="78"] { - background-image: url("images/cards100/card_78.png"); -} - -.card[data-card-id="79"] { - background-image: url("images/cards100/card_79.png"); -} - -.card[data-card-id="80"] { - background-image: url("images/cards100/card_80.png"); -} - -.card[data-card-id="81"] { - background-image: url("images/cards100/card_81.png"); -} - -.card[data-card-id="82"] { - background-image: url("images/cards100/card_82.png"); -} - -.card[data-card-id="83"] { - background-image: url("images/cards100/card_83.png"); -} - -.card[data-card-id="84"] { - background-image: url("images/cards100/card_84.png"); -} - -.card[data-card-id="85"] { - background-image: url("images/cards100/card_85.png"); -} - -.card[data-card-id="86"] { - background-image: url("images/cards100/card_86.png"); -} - -.card[data-card-id="87"] { - background-image: url("images/cards100/card_87.png"); -} - -.card[data-card-id="88"] { - background-image: url("images/cards100/card_88.png"); -} - -.card[data-card-id="89"] { - background-image: url("images/cards100/card_89.png"); -} - -.card[data-card-id="90"] { - background-image: url("images/cards100/card_90.png"); -} - -.card[data-card-id="91"] { - background-image: url("images/cards100/card_91.png"); -} - -.card[data-card-id="92"] { - background-image: url("images/cards100/card_92.png"); -} - -.card[data-card-id="93"] { - background-image: url("images/cards100/card_93.png"); -} - -.card[data-card-id="94"] { - background-image: url("images/cards100/card_94.png"); -} - -.card[data-card-id="95"] { - background-image: url("images/cards100/card_95.png"); -} - -.card[data-card-id="96"] { - background-image: url("images/cards100/card_96.png"); -} - -.card[data-card-id="97"] { - background-image: url("images/cards100/card_97.png"); -} - -.card[data-card-id="98"] { - background-image: url("images/cards100/card_98.png"); -} - -.card[data-card-id="99"] { - background-image: url("images/cards100/card_99.png"); -} - -.card[data-card-id="100"] { - background-image: url("images/cards100/card_100.png"); -} - -.card[data-card-id="101"] { - background-image: url("images/cards100/card_101.png"); -} - -.card[data-card-id="102"] { - background-image: url("images/cards100/card_102.png"); -} - -.card[data-card-id="103"] { - background-image: url("images/cards100/card_103.png"); -} - -.card[data-card-id="104"] { - background-image: url("images/cards100/card_104.png"); -} - -.card[data-card-id="105"] { - background-image: url("images/cards100/card_105.png"); -} - -.card[data-card-id="106"] { - background-image: url("images/cards100/card_106.png"); -} - -.card[data-card-id="107"] { - background-image: url("images/cards100/card_107.png"); -} - -.card[data-card-id="108"] { - background-image: url("images/cards100/card_108.png"); -} - -.card.event { - position: absolute; - width: 132px; - height: 180px; -} - -.blank_marker { - box-sizing: border-box; - position: absolute; - background-color: red; - width: 29px; - height: 29px; - border-radius: 50%; - box-shadow: 0 0 0 1px #333; - margin-top: 1px; -} - -.faction_token { - box-sizing: border-box; - background-size: 100% 100%; -} - -#log .faction_token { - display: inline-block; - width: 25px; - height: 25px; - border-radius: 2px; - vertical-align: middle; - margin: 0px 1px; -} - -#glory .faction_token { - position: absolute; - width: 34px; - height: 34px; - border-radius: 4px; -} - -.contributions .faction_token { - width: 25px; - height: 25px; - border-radius: 4px; -} - -.faction_token[data-faction-id=a] { - border: 1px #333 solid; - background-image: url("images/factions/anarchists.png"); -} - -.faction_token[data-faction-id=c] { - border: 1px #333 solid; - background-image: url("images/factions/communitsts.png"); -} - -.faction_token[data-faction-id=m] { - border: 1px #333 solid; - background-image: url("images/factions/moderates.png"); -} - -.standee { - box-sizing: border-box; - position: absolute; - width: 29px; - height: 35px; - background-size: cover; - background-repeat: no-repeat; - border-radius: 4px; - box-shadow: 0 0 0 1px #333; - transition-property: top, left; - transition-duration: 700ms; - transition-timing-function: ease; - z-index: 1; -} - -.blank_marker.action, -.bonus.action, -.card.action, -.front.action, -.medallion.action, -.standee.action { - box-shadow: 0 0 0 3px yellow; -} - -.blank_marker.action { - z-index: 2; -} - -.blank_marker.action:hover, -.bonus.action:hover, -.card.action:hover, -.card.selected, -.front.action:hover, -.medallion.action:hover, -.standee.action:hover { - box-shadow: 0 0 0 3px blue; -} - -.blank_marker.action:hover { - opacity: 0.5; -} - -.standee[data-standee-id="0"] { - background-image: url("images/standees/standee_0.png"); -} - -.standee[data-standee-id="1"] { - background-image: url("images/standees/standee_1.png"); -} - -.standee[data-standee-id="2"] { - background-image: url("images/standees/standee_2.png"); -} - -.standee[data-standee-id="3"] { - background-image: url("images/standees/standee_3.png"); -} - -.standee[data-standee-id="4"] { - background-image: url("images/standees/standee_4.png"); -} - -.bonus { - box-sizing: border-box; - position: absolute; - width: 54px; - height: 54px; - background-size: cover; - background-repeat: no-repeat; - border-radius: 50%; -} - -.bonus[data-bonus-id="0"][data-bonus-on="0"] { - background-image: url("images/bonus/bonus_0_off.png"); -} - -.bonus[data-bonus-id="0"][data-bonus-on="1"] { - background-image: url("images/bonus/bonus_0_on.png"); -} - -.bonus[data-bonus-id="1"][data-bonus-on="0"] { - background-image: url("images/bonus/bonus_1_off.png"); -} - -.bonus[data-bonus-id="1"][data-bonus-on="1"] { - background-image: url("images/bonus/bonus_1_on.png"); -} - -.initiative_token { - width: 47px; - height: 47px; - background-size: cover; - background-repeat: no-repeat; - margin-right: auto; - background-image: url("images/initiative_clockwise.png"); -} - -.initiative_token[data-year="2"] { - background-image: url("images/initiative_counter_clockwise.png"); -} - -.medallion { - width: 47px; - height: 47px; - background-size: cover; - background-repeat: no-repeat; - box-shadow: 0 0 0 1px #333; - border-radius: 10px; -} - -#medallions .medallion { - box-sizing: border-box; - position: absolute; -} - -.medallion[data-medallion-id="0"] { - background-image: url("images/medallions/medallion_0.png"); -} - -.medallion[data-medallion-id="1"] { - background-image: url("images/medallions/medallion_1.png"); -} - -.medallion[data-medallion-id="2"] { - background-image: url("images/medallions/medallion_2.png"); -} - -.medallion[data-medallion-id="3"] { - background-image: url("images/medallions/medallion_3.png"); -} - -.medallion[data-medallion-id="4"] { - background-image: url("images/medallions/medallion_4.png"); -} - -.medallion[data-medallion-id="5"] { - background-image: url("images/medallions/medallion_5.png"); -} - -.medallion[data-medallion-id="6"] { - background-image: url("images/medallions/medallion_6.png"); -} - -.medallion[data-medallion-id="7"] { - background-image: url("images/medallions/medallion_7.png"); -} - -.medallion[data-medallion-id="8"] { - background-image: url("images/medallions/medallion_8.png"); -} - -#log { - background-color: floralwhite; -} - -#log .h1, -#log .h2 { - font-size: 10px; - padding-top: 2px; - padding-bottom: 2px; - text-align: center; -} - -#log .h1 { - background-color: rgb(233, 223, 200); -} - -#log .h2 { - background-color: rgb(233, 223, 200); -} - -#log .h2.anarchist { - background-color: rgb(93, 89, 106); - color: floralwhite; -} - -#log .h2.communist { - background-color: rgb(237, 36, 27); - color: floralwhite; -} - -#log .h2.moderate { - background-color: rgb(134, 44, 97); - color: floralwhite; -} - -#log .h2.fascist { - background-color: rgb(183, 144, 105); -} - -#log div.i { - padding-left: 32px; - text-indent: -12px; -} - -#log div.ii { - padding-left: 44px; - text-indent: -12px; -} diff --git a/land-and-freedom.scss b/land-and-freedom.scss deleted file mode 100644 index 07c55b2..0000000 --- a/land-and-freedom.scss +++ /dev/null @@ -1,525 +0,0 @@ -// @use "sass:math"; -@use 'sass:map'; - -$selectable-color: yellow; // yellow; -$selected-color: blue; //blue; - -$anarchist-color: rgb(93, 89, 106); -$communist-color: rgb(237, 36, 27); -$moderate-color: rgb(134, 44, 97); -$fascist-color: rgb(183, 144, 105); -$log-text-background-color: rgb(233 223 200); - -main { - // background-color: rgb(213, 196, 131); - // background-color: darkolivegreen; - background-color: #7b904b; -} - -/* MAP */ - -#mapwrap { - width: 1000px; - height: 850px; - // background-color: #999f85; - box-shadow: 1px 2px 4px #0004; -} - -// #map { -// background-repeat: no-repeat; -// background-size: cover; -// width: 1275px; -// height: 1650px; -// overflow: clip; -// } - -#map { - background-repeat: no-repeat; - background-size: 100% 100%; - width: 1000px; - height: 850px; - overflow: clip; -} - -#map { - background-image: url(images/map75.png); -} -@media (min-resolution: 97dpi) { - #map { - background-image: url(images/map100.png); - } -} - -#current_events { - .card:last-child { - transform: scale(1.2); - } -} - -/* CURRENT CARD */ - -#turn_info { - border-bottom: 1px solid black; - // padding: 12px; - overflow: clip; - background-color: gray; - white-space: normal; - padding: 8px 0px; -} - -#turn_info .card { - margin: 0 auto; -} - -@media (max-height: 800px) { - #turn_info { height: 95px; } - #turn_info:hover { height: auto; } -} - -@media (max-height: 600px) { - #turn_info { - display: none; - } -} - -.game_info { - padding: 3px 4px; - border-bottom: 1px solid black; - font-size: 16px; - line-height: 1.5; - grid-column: 1; - grid-row: 1; - display: flex; - flex-direction: column; - background: floralwhite; -} - -#roles { - grid-column: 1; - grid-row: 2; -} - -.role_medallions { - grid-row: 3; - grid-column: 1 / 3; - padding: 3px 4px; - display: flex; - flex-direction: row-reverse; - gap: 4px; -} - -.role_info { - grid-row: 4; - grid-column: 1 / 3; -} - -// #role_Anarchist::before { -// background-color: $anarchist-color; -// content: ' '; -// display: block; -// height: 100%; -// left: 0; -// opacity: 0.6; -// position: absolute; -// top: 0; -// width: 100%; -// z-index: -1; -// } - -#role_Anarchist { - background-color: $anarchist-color; -} - -#role_Communist { - background-color: $communist-color; -} - -#role_Moderate { - background-color: $moderate-color; -} - -.role { - color: floralwhite; - - a { - color: floralwhite; - } -} - -#selectable_cards { - display: flex; - justify-content: center; - flex-wrap: wrap; - padding: 12px; - gap: 12px; - min-height: 260px; -} - -#selectable_cards:empty { - display: none; -} - -.panel { - min-width: 1271px; - max-width: 1271px; - // background-color: hsl(34, 10%, 35%); - background-color: #58641d; - margin: 12px auto; - box-shadow: 1px 2px 4px #0004; - border: 2px solid #333; -} - -.panel_body { - display: flex; - justify-content: center; - flex-wrap: wrap; - padding: 12px; - gap: 12px; - min-height: 260px; -} - -.panel_body[data-active="inactive"] { - display: none; -} - -.panel_header { - color: floralwhite; - user-select: none; - font-weight: bold; - text-align: center; - border-bottom: 2px solid #333; - background-color: red; -} - -#player_area_header { - background-color: #273b09; - display: flex; - border-bottom: none; - - .player_area_tab { - cursor: pointer; - width: 25%; - border-bottom: 2px solid #333; - border-left: 1px solid #333; - border-right: 1px solid #333; - } - - .player_area_tab[data-active="active"] { - width: 25%; - background-color: #58641d; - border-bottom: none; - } - - #hand_tab { - border-left: none; - } - - #trash_tab { - border-right: none; - } -} - -#player_area_header[data-faction-id='a'], -.panel_header[data-faction-id='a'] { - background-color: $anarchist-color; -} - -#player_area_header[data-faction-id='c'], -.panel_header[data-faction-id='c'] { - background-color: $communist-color; -} - -#player_area_header[data-faction-id='m'], -.panel_header[data-faction-id='m'] { - background-color: $moderate-color; -} - -// #hand, -// .tableau { -// display: flex; -// flex-direction: row; -// gap: 8px; -// margin-top: 16px; -// padding: 16px; -// justify-content: center; -// } - -.front { - position: absolute; - box-sizing: border-box; - width: 93px; - height: 102px; - display: flex; - flex-direction: column; - align-items: center; - padding: 4px; - border-radius: 20px; - // background-color: yellow; - // opacity: 0.5; -} - -.contributions { - display: flex; - flex-direction: row; - gap: 2px; - // width: 100%; - margin-top: 15px; - // background-color: yellow; - // opacity: 0.5; - height: 25px; - z-index: -1; - - .faction_token { - z-index: -1; - } -} - -.front .value { - font-weight: bold; - font-size: 30px; - margin-top: auto; - z-index: -1; -} - -#madrid_front { - width: 104px; - height: 114px; - border-radius: 23px; -} - -#madrid_front .contributions { - padding: 0px 2px; -} - -// .front[data-front-id='m'] { -// width: 104px; -// height: 114px; -// border-radius: 23px; -// } - -.card { - background-size: 100% 100%; - // width: 275px; - // height: 375px; - width: 198px; - height: 270px; - // border: 1px solid black; - border-radius: 5px; - box-shadow: 0 0 0 1px #333; -} - -@for $i from 1 through 108 { - .card[data-card-id='#{$i}'] { - background-image: url('images/cards100/card_#{$i}.png'); - } -} - -.card.event { - position: absolute; - // opacity: 0.5; - width: 132px; - height: 180px; -} - -.blank_marker { - box-sizing: border-box; - position: absolute; - background-color: red; - width: 29px; - height: 29px; - border-radius: 50%; - box-shadow: 0 0 0 1px #333; - margin-top: 1px; -} - -.faction_token { - box-sizing: border-box; - // background-color: yellow; - // opacity: 0.5; - background-size: 100% 100%; - // box-shadow: 0 0 0 1px #333; -} - -#log .faction_token { - display: inline-block; - width: 25px; - height: 25px; - border-radius: 2px; - vertical-align: middle; - margin: 0px 1px; -} - -#glory .faction_token { - position: absolute; - width: 34px; - height: 34px; - border-radius: 4px; -} - -.contributions .faction_token { - width: 25px; - height: 25px; - border-radius: 4px; -} - -.faction_token[data-faction-id='a'] { - border: 1px #333 solid; - background-image: url('images/factions/anarchists.png'); -} - -.faction_token[data-faction-id='c'] { - border: 1px #333 solid; - background-image: url('images/factions/communitsts.png'); -} - -.faction_token[data-faction-id='m'] { - border: 1px #333 solid; - background-image: url('images/factions/moderates.png'); -} - -.standee { - box-sizing: border-box; - position: absolute; - width: 29px; - height: 35px; - background-size: cover; - background-repeat: no-repeat; - border-radius: 4px; - box-shadow: 0 0 0 1px #333; - transition-property: top, left; - transition-duration: 700ms; - transition-timing-function: ease; - z-index: 1; - // opacity: 0.6; -} - -.blank_marker.action, -.bonus.action, -.card.action, -.front.action, -.medallion.action, -.standee.action { - box-shadow: 0 0 0 3px $selectable-color; -} - -.blank_marker.action { - z-index: 2; -} - -.blank_marker.action:hover, -.bonus.action:hover, -.card.action:hover, -.card.selected, -.front.action:hover, -.medallion.action:hover, -.standee.action:hover { - box-shadow: 0 0 0 3px $selected-color; -} - -.blank_marker.action:hover { - opacity: 0.5; -} - -// .standee.action:hover { -// box-shadow: 0 0 0 2px blue; -// } - -@for $i from 0 through 4 { - .standee[data-standee-id='#{$i}'] { - background-image: url('images/standees/standee_#{$i}.png'); - } -} - -.bonus { - box-sizing: border-box; - position: absolute; - width: 54px; - height: 54px; - background-size: cover; - background-repeat: no-repeat; - border-radius: 50%; -} - -@for $i from 0 through 1 { - .bonus[data-bonus-id='#{$i}'][data-bonus-on='0'] { - background-image: url('images/bonus/bonus_#{$i}_off.png'); - } - .bonus[data-bonus-id='#{$i}'][data-bonus-on='1'] { - background-image: url('images/bonus/bonus_#{$i}_on.png'); - } -} - -.initiative_token { - width: 47px; - height: 47px; - background-size: cover; - background-repeat: no-repeat; - margin-right: auto; - background-image: url('images/initiative_clockwise.png'); -} - -.initiative_token[data-year='2'] { - background-image: url('images/initiative_counter_clockwise.png'); -} - -.medallion { - width: 47px; - height: 47px; - background-size: cover; - background-repeat: no-repeat; - box-shadow: 0 0 0 1px #333; - border-radius: 10px; -} - -#medallions .medallion { - box-sizing: border-box; - position: absolute; -} - -@for $i from 0 through 8 { - .medallion[data-medallion-id='#{$i}'] { - background-image: url('images/medallions/medallion_#{$i}.png'); - } -} - -#log { - background-color: floralwhite; -} -#log .h1, -#log .h2 { - font-size: 10px; - padding-top: 2px; - padding-bottom: 2px; - text-align: center; -} -#log .h1 { - // background-color: hsl(4, 40%, 73%); - background-color: $log-text-background-color; -} -#log .h2 { - // background-color: hsl(250, 40%, 83%); - background-color: $log-text-background-color; -} -#log .h2.anarchist { - background-color: $anarchist-color; - color: floralwhite; -} -#log .h2.communist { - background-color: $communist-color; - color: floralwhite; -} -#log .h2.moderate { - background-color: $moderate-color; - color: floralwhite; -} -#log .h2.fascist { - background-color: $fascist-color; -} -#log div.i { - padding-left: 32px; - text-indent: -12px; -} -#log div.ii { - padding-left: 44px; - text-indent: -12px; -} diff --git a/package.json b/package.json index b63e15d..3463451 100644 --- a/package.json +++ b/package.json @@ -4,16 +4,13 @@ "description": "Land and Freedom for RTT", "main": "rules.js", "scripts": { - "build:scss": "sass --no-source-map land-and-freedom.scss land-and-freedom.css", "build:ts": "tsc", - "watch:scss": "sass --no-source-map --watch land-and-freedom.scss land-and-freedom.css", "watch:ts": "tsc --watch", - "build": "npm run build:ts && npm run build:scss" + "build": "npm run build:ts" }, "author": "Frans Bongers", "license": "ISC", "devDependencies": { - "sass": "^1.81.0", "typescript": "^5.7.2" } } diff --git a/play.css b/play.css new file mode 100644 index 0000000..de4ba00 --- /dev/null +++ b/play.css @@ -0,0 +1,379 @@ +main { background-color: #666; } + +body.Anarchist header.your_turn { background-color: hsl(257, 10%, 65%); } +body.Communist header.your_turn { background-color: hsl(0, 55%, 65%); } +body.Moderate header.your_turn { background-color: hsl(325, 30%, 65%); } +body header.fascist.your_turn { background-color: hsl(30, 35%, 65%); } + +#role_Anarchist { background-color: hsl(257, 10%, 70%); } +#role_Communist { background-color: hsl(0, 55%, 70%); } +#role_Moderate { background-color: hsl(325, 30%, 70%); } + +#log div.h.a { background-color: hsl(257, 10%, 75%); } +#log div.h.c { background-color: hsl(0, 55%, 75%); } +#log div.h.m { background-color: hsl(325, 30%, 75%); } +#log div.h.f { background-color: hsl(30, 35%, 75%); } + +.panel { background-image: url(images/texture.png) } +.panel { background-color: hsl(0, 0%, 60%); } +.panel.anarchist { background-color: hsl(257, 10%, 60%); } +.panel.communist { background-color: hsl(0, 35%, 60%); } +.panel.moderate { background-color: hsl(325, 20%, 60%); } +.panel.fascist { background-color: hsl(30, 30%, 60%); } + +.panel .panel_header { background-color: hsl(0, 0%, 75%); } +.panel.anarchist .panel_header { background-color: hsl(257, 10%, 75%); } +.panel.communist .panel_header { background-color: hsl(0, 60%, 75%); } +.panel.moderate .panel_header { background-color: hsl(325, 35%, 75%); } +.panel.fascist .panel_header { background-color: hsl(30, 40%, 75%); } + +.track.action { border-color: cyan !important; } +.front.action { border-color: cyan !important; } +.token.action { + box-shadow: 0 0 0 1px black, 0 0 0 5px cyan !important; +} + +.card.action { box-shadow: 0 0 0 4px cyan !important; } +.card.selected { box-shadow: 0 0 0 4px blue !important; } + + + +#log div:empty { + min-height: 6px; +} + +#log .h { + background-color: tan; + border-top: 1px solid black; border-bottom: 1px solid black; + margin: 8px 0; +} + +#log div { padding-left: 20px; text-indent: -12px; } +#log div.i { padding-left: 32px; text-indent: -12px; } +#log div.ii { padding-left: 44px; text-indent: -12px; } + +#mapwrap { + width: 1650px; + height: 1275px; + border: 1px solid black; + border-top: none; + box-shadow: 2px 2px 4px #0004; +} + +#map { + width: 1650px; + height: 1275px; + background-size: 1650px 1275px; + background-image: url(images/map75.jpg); +} + +@media (min-resolution: 97dpi) { + #map { background-image: url(images/map150.jpg); } +} + +/* PANELS */ + +.panel:has(.panel_body:empty) { + display: none; +} + +.panel { + padding: 4px; + max-width: calc(1650px - 8px); + min-height: 281px; + margin: 24px auto; + border: 1px solid black; + box-shadow: 2px 2px 4px #0004; +} + +.panel_header { + padding: 3px 6px; + border: 1px solid black; + text-align: center; + font-weight: bold; + box-shadow: 1px 1px 4px #0003; +} + +.panel_body { + display: flex; + flex-wrap: wrap; + gap: 16px; + padding: 12px; +} + +/* SPACES */ + +.track { + position: absolute; + border: 4px solid transparent; + width: 50px; + height: 52px; +} + +.front { + position: absolute; + border: 6px solid transparent; + border-radius: 34px; +} + +/* CONTAINERS */ + +.front_container { + position: absolute; + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 4px; +} + +.front_container div { + margin-right: -30px; + margin-bottom: -30px; +} + +.medallion_container { + position: absolute; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + width: 70px; + height: 70px; +} + +.glory_container { + position: absolute; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 9px; + padding: 4px; +} + +.fascist_deck { + position: absolute; + display: flex; + flex-wrap: wrap; + height: 282px; +} + +.fascist_deck .card { + margin-right: -210px; +} + +.fascist_deck .card_118 { margin-top: -8px; } +.fascist_deck .card_119 { margin-top: -4px; } +.fascist_deck .card_120 { margin-top: 0px; } + +.current_events { + position: absolute; + width: 208px; + height: 282px; +} + +.token_pool { + height: 64px; + display: flex; + flex-wrap: wrap; + padding: 0 0 12px 24px; + gap: 8px; + align-items: center; + +} + +/* TOKENS */ + +#pieces > .token { + position: absolute; +} + +.token { + border: 3px solid black; + width: 45px; + height: 45px; +} + +/* :r! node tools/gencolor.js */ +.token.white { background-color: #bbbbbb; border-color: #d6d6d6 #737373 #737373 #d6d6d6; box-shadow: 0 0 0 1px #323232, 0px 1px 4px #0008; } +.token.red { background-color: #ef0500; border-color: #ff5d49 #b40000 #b40000 #ff5d49; box-shadow: 0 0 0 1px #790000, 0px 1px 4px #0008; } +.token.pink { background-color: #da997b; border-color: #fdba9b #94593c #94593c #fdba9b; box-shadow: 0 0 0 1px #521d00, 0px 1px 4px #0008; } +.token.brown { background-color: #bbb079; border-color: #dbd097 #786d38 #786d38 #dbd097; box-shadow: 0 0 0 1px #3b3000, 0px 1px 4px #0008; } +.token.gray { background-color: #a6a6a8; border-color: #c9c9cb #676769 #676769 #c9c9cb; box-shadow: 0 0 0 1px #2f2f30, 0px 1px 4px #0008; } + +.token.blank { width: 45px; height: 45px; } +.token.round { width: 58px; height: 58px; } +.token.square { width: 45px; height: 45px; } +.token.standee { width: 44px; height: 54px; } +.token.medallion { width: 53px; height: 53px; } + +.token.round, .token.blank { border-radius: 50%; } +.token.standee { border-radius: 8px; } +.token.medallion { border-radius: 8px; } + +/* CARDS */ + +.card { + background-size: 100% 100%; + width: 206px; + height: 281px; + border-radius: 10px; + box-shadow: 0 0 0 1px black, 1px 1px 4px #0006; +} + +/* IMAGES */ + +.front_plus { background-image: url(images/tokens75/front_plus.png); } +.front_minus { background-image: url(images/tokens75/front_minus.png); } + +.standee_0 { background-image: url(images/tokens75/standee_0.png); } +.standee_1 { background-image: url(images/tokens75/standee_1.png); } +.standee_2 { background-image: url(images/tokens75/standee_2.png); } +.standee_3 { background-image: url(images/tokens75/standee_3.png); } +.standee_4 { background-image: url(images/tokens75/standee_4.png); } + +.medallion_0 { background-image: url(images/tokens75/medallion_0.png); } +.medallion_1 { background-image: url(images/tokens75/medallion_1.png); } +.medallion_2 { background-image: url(images/tokens75/medallion_2.png); } +.medallion_3 { background-image: url(images/tokens75/medallion_3.png); } +.medallion_4 { background-image: url(images/tokens75/medallion_4.png); } +.medallion_5 { background-image: url(images/tokens75/medallion_5.png); } +.medallion_6 { background-image: url(images/tokens75/medallion_6.png); } +.medallion_7 { background-image: url(images/tokens75/medallion_7.png); } +.medallion_8 { background-image: url(images/tokens75/medallion_8.png); } +.medallion_9 { background-image: url(images/tokens75/medallion_9.png); } + +.bonus_morale { background-image: url(images/tokens75/bonus_morale_on.png); } +.bonus_morale.off { background-image: url(images/tokens75/bonus_morale_off.png); } +.bonus_teamwork { background-image: url(images/tokens75/bonus_teamwork_on.png); } +.bonus_teamwork.off { background-image: url(images/tokens75/bonus_teamwork_off.png); } + +.player.anarchist { background-image: url(images/tokens75/player_anarchist.png); } +.player.communist { background-image: url(images/tokens75/player_communist.png); } +.player.moderate { background-image: url(images/tokens75/player_moderate.png); } + +.initiative { background-image: url("images/tokens75/initiative_cw.png"); } +.initiative.ccw { background-image: url("images/tokens75/initiative_ccw.png"); } + +.hero_point { background-image: url("images/tokens75/hero_point.png"); } + +.card_1 { background-image: url(images/cards75/card_1.avif); } +.card_2 { background-image: url(images/cards75/card_2.avif); } +.card_3 { background-image: url(images/cards75/card_3.avif); } +.card_4 { background-image: url(images/cards75/card_4.avif); } +.card_5 { background-image: url(images/cards75/card_5.avif); } +.card_6 { background-image: url(images/cards75/card_6.avif); } +.card_7 { background-image: url(images/cards75/card_7.avif); } +.card_8 { background-image: url(images/cards75/card_8.avif); } +.card_9 { background-image: url(images/cards75/card_9.avif); } +.card_10 { background-image: url(images/cards75/card_10.avif); } +.card_11 { background-image: url(images/cards75/card_11.avif); } +.card_12 { background-image: url(images/cards75/card_12.avif); } +.card_13 { background-image: url(images/cards75/card_13.avif); } +.card_14 { background-image: url(images/cards75/card_14.avif); } +.card_15 { background-image: url(images/cards75/card_15.avif); } +.card_16 { background-image: url(images/cards75/card_16.avif); } +.card_17 { background-image: url(images/cards75/card_17.avif); } +.card_18 { background-image: url(images/cards75/card_18.avif); } +.card_19 { background-image: url(images/cards75/card_19.avif); } +.card_20 { background-image: url(images/cards75/card_20.avif); } +.card_21 { background-image: url(images/cards75/card_21.avif); } +.card_22 { background-image: url(images/cards75/card_22.avif); } +.card_23 { background-image: url(images/cards75/card_23.avif); } +.card_24 { background-image: url(images/cards75/card_24.avif); } +.card_25 { background-image: url(images/cards75/card_25.avif); } +.card_26 { background-image: url(images/cards75/card_26.avif); } +.card_27 { background-image: url(images/cards75/card_27.avif); } +.card_28 { background-image: url(images/cards75/card_28.avif); } +.card_29 { background-image: url(images/cards75/card_29.avif); } +.card_30 { background-image: url(images/cards75/card_30.avif); } +.card_31 { background-image: url(images/cards75/card_31.avif); } +.card_32 { background-image: url(images/cards75/card_32.avif); } +.card_33 { background-image: url(images/cards75/card_33.avif); } +.card_34 { background-image: url(images/cards75/card_34.avif); } +.card_35 { background-image: url(images/cards75/card_35.avif); } +.card_36 { background-image: url(images/cards75/card_36.avif); } +.card_37 { background-image: url(images/cards75/card_37.avif); } +.card_38 { background-image: url(images/cards75/card_38.avif); } +.card_39 { background-image: url(images/cards75/card_39.avif); } +.card_40 { background-image: url(images/cards75/card_40.avif); } +.card_41 { background-image: url(images/cards75/card_41.avif); } +.card_42 { background-image: url(images/cards75/card_42.avif); } +.card_43 { background-image: url(images/cards75/card_43.avif); } +.card_44 { background-image: url(images/cards75/card_44.avif); } +.card_45 { background-image: url(images/cards75/card_45.avif); } +.card_46 { background-image: url(images/cards75/card_46.avif); } +.card_47 { background-image: url(images/cards75/card_47.avif); } +.card_48 { background-image: url(images/cards75/card_48.avif); } +.card_49 { background-image: url(images/cards75/card_49.avif); } +.card_50 { background-image: url(images/cards75/card_50.avif); } +.card_51 { background-image: url(images/cards75/card_51.avif); } +.card_52 { background-image: url(images/cards75/card_52.avif); } +.card_53 { background-image: url(images/cards75/card_53.avif); } +.card_54 { background-image: url(images/cards75/card_54.avif); } +.card_55 { background-image: url(images/cards75/card_55.avif); } +.card_56 { background-image: url(images/cards75/card_56.avif); } +.card_57 { background-image: url(images/cards75/card_57.avif); } +.card_58 { background-image: url(images/cards75/card_58.avif); } +.card_59 { background-image: url(images/cards75/card_59.avif); } +.card_60 { background-image: url(images/cards75/card_60.avif); } +.card_61 { background-image: url(images/cards75/card_61.avif); } +.card_62 { background-image: url(images/cards75/card_62.avif); } +.card_63 { background-image: url(images/cards75/card_63.avif); } +.card_64 { background-image: url(images/cards75/card_64.avif); } +.card_65 { background-image: url(images/cards75/card_65.avif); } +.card_66 { background-image: url(images/cards75/card_66.avif); } +.card_67 { background-image: url(images/cards75/card_67.avif); } +.card_68 { background-image: url(images/cards75/card_68.avif); } +.card_69 { background-image: url(images/cards75/card_69.avif); } +.card_70 { background-image: url(images/cards75/card_70.avif); } +.card_71 { background-image: url(images/cards75/card_71.avif); } +.card_72 { background-image: url(images/cards75/card_72.avif); } +.card_73 { background-image: url(images/cards75/card_73.avif); } +.card_74 { background-image: url(images/cards75/card_74.avif); } +.card_75 { background-image: url(images/cards75/card_75.avif); } +.card_76 { background-image: url(images/cards75/card_76.avif); } +.card_77 { background-image: url(images/cards75/card_77.avif); } +.card_78 { background-image: url(images/cards75/card_78.avif); } +.card_79 { background-image: url(images/cards75/card_79.avif); } +.card_80 { background-image: url(images/cards75/card_80.avif); } +.card_81 { background-image: url(images/cards75/card_81.avif); } +.card_82 { background-image: url(images/cards75/card_82.avif); } +.card_83 { background-image: url(images/cards75/card_83.avif); } +.card_84 { background-image: url(images/cards75/card_84.avif); } +.card_85 { background-image: url(images/cards75/card_85.avif); } +.card_86 { background-image: url(images/cards75/card_86.avif); } +.card_87 { background-image: url(images/cards75/card_87.avif); } +.card_88 { background-image: url(images/cards75/card_88.avif); } +.card_89 { background-image: url(images/cards75/card_89.avif); } +.card_90 { background-image: url(images/cards75/card_90.avif); } +.card_91 { background-image: url(images/cards75/card_91.avif); } +.card_92 { background-image: url(images/cards75/card_92.avif); } +.card_93 { background-image: url(images/cards75/card_93.avif); } +.card_94 { background-image: url(images/cards75/card_94.avif); } +.card_95 { background-image: url(images/cards75/card_95.avif); } +.card_96 { background-image: url(images/cards75/card_96.avif); } +.card_97 { background-image: url(images/cards75/card_97.avif); } +.card_98 { background-image: url(images/cards75/card_98.avif); } +.card_99 { background-image: url(images/cards75/card_99.avif); } +.card_100 { background-image: url(images/cards75/card_100.avif); } +.card_101 { background-image: url(images/cards75/card_101.avif); } +.card_102 { background-image: url(images/cards75/card_102.avif); } +.card_103 { background-image: url(images/cards75/card_103.avif); } +.card_104 { background-image: url(images/cards75/card_104.avif); } +.card_105 { background-image: url(images/cards75/card_105.avif); } +.card_106 { background-image: url(images/cards75/card_106.avif); } +.card_107 { background-image: url(images/cards75/card_107.avif); } +.card_108 { background-image: url(images/cards75/card_108.avif); } +.card_109 { background-image: url(images/cards75/card_109.avif); } +.card_110 { background-image: url(images/cards75/card_110.avif); } +.card_111 { background-image: url(images/cards75/card_111.avif); } +.card_112 { background-image: url(images/cards75/card_112.avif); } +.card_113 { background-image: url(images/cards75/card_113.avif); } +.card_114 { background-image: url(images/cards75/card_114.avif); } +.card_115 { background-image: url(images/cards75/card_115.avif); } +.card_116 { background-image: url(images/cards75/card_116.avif); } +.card_117 { background-image: url(images/cards75/card_117.avif); } +.card_118 { background-image: url(images/cards75/card_118.avif); } +.card_119 { background-image: url(images/cards75/card_119.avif); } +.card_120 { background-image: url(images/cards75/card_120.avif); } diff --git a/play.html b/play.html index d89b2a9..edc11f3 100644 --- a/play.html +++ b/play.html @@ -9,15 +9,10 @@ - + - - -
@@ -26,104 +21,59 @@
  • Rulebook +
  • Cards
  • Player Aid: Anarchist
  • Player Aid: Communist
  • Player Aid: Moderate
  • +
    -
    -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    +
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    Hand
    -
    Deck
    -
    Discard Pile
    -
    Trash
    -
    -
    -
    -
    -
    + +
    +
    Fascist Cards
    +
    +
    + +
    +
    Trash
    +
    + +
    +
    Hand
    +
    +
    +
    -
    -
    Anarchist Tableau
    +
    +
    Anarchist Tableau
    +
    -
    -
    Communist Tableau
    +
    +
    Communist Tableau
    +
    -
    -
    Moderate Tableau
    +
    +
    Moderate Tableau
    +
    diff --git a/play.js b/play.js index 5b002e8..9ef91e1 100644 --- a/play.js +++ b/play.js @@ -1,495 +1,591 @@ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -const BONUSES_COUNT = 2; -const CARD_COUNT = 109; -const GLORY_COUNT = 9; -const medallionS_COUNT = 9; -const STANDEES_COUNT = 5; -const TRACK_COUNT = 5; -const TRACK_LENGTH = 11; -const FACTIONS = ['a', 'c', 'm']; +"use strict" + +/* global view, action_button, send_action */ + +// TODO: pool for hero points to animate ? +// TODO: pool for faction markers to animate ? + const ui = { - bag_of_glory: document.getElementById('bag_of_glory'), - map: document.getElementById('map'), - medallions_container: document.getElementById('medallions'), - markers: document.getElementById('markers'), - fronts: { - a: { - front: document.getElementById('aragon_front'), - value: document.querySelector('#aragon_front .value'), - contributions: document.querySelector('#aragon_front .contributions'), - }, - m: { - front: document.getElementById('madrid_front'), - value: document.querySelector('#madrid_front .value'), - contributions: document.querySelector('#madrid_front .contributions'), - }, - n: { - front: document.getElementById('northern_front'), - value: document.querySelector('#northern_front .value'), - contributions: document.querySelector('#northern_front .contributions'), - }, - s: { - front: document.getElementById('southern_front'), - value: document.querySelector('#southern_front .value'), - contributions: document.querySelector('#southern_front .contributions'), - }, - }, - glory_container: document.getElementById('glory'), - hand: document.getElementById('hand'), - player_area: document.getElementById('player_area'), - current_events: document.getElementById('current_events'), - roles: { - a: { - hero_points: document.querySelector('#role_Anarchist .role_stat'), - medallions: document.querySelector('#role_Anarchist .role_medallions'), - }, - c: { - hero_points: document.querySelector('#role_Communist .role_stat'), - medallions: document.querySelector('#role_Communist .role_medallions'), - }, - m: { - hero_points: document.querySelector('#role_Moderate .role_stat'), - medallions: document.querySelector('#role_Moderate .role_medallions'), - }, - pool: { - hero_points: document.getElementById('pool_hero_points'), - }, - Anarchist: document.getElementById('role_Anarchist'), - Communist: document.getElementById('role_Communist'), - Moderate: document.getElementById('role_Moderate'), - container: document.getElementById('roles'), - }, - player_area_tabs: { - hand_tab: document.getElementById('hand_tab'), - deck_tab: document.getElementById('deck_tab'), - discard_tab: document.getElementById('discard_tab'), - trash_tab: document.getElementById('trash_tab'), - }, - player_area_cards: { - hand: document.getElementById('hand'), - deck: document.getElementById('deck'), - discard: document.getElementById('discard'), - trash: document.getElementById('trash'), - }, - player_areas: { - container: document.getElementById('player_areas'), - Anarchist: document.getElementById('player_area_Anarchist'), - Communist: document.getElementById('player_area_Communist'), - Moderate: document.getElementById('player_area_Moderate'), - }, - selectable_cards: document.getElementById('selectable_cards'), - tableaus: { - a: document.getElementById('tableau_a'), - c: document.getElementById('tableau_c'), - m: document.getElementById('tableau_m'), - }, - tracks: document.getElementById('tracks'), - hero_points: document.querySelector('#role_Anarchist .role_stat'), - turn_info: document.getElementById('turn_info'), - turn_info_card: document.getElementById('turn_info_card'), - year: document.getElementById('year'), - blank_markers: [], - bonuses: [], - tokens_on_front: {}, - glory: [], - initiative_token: undefined, - medallions: [], - spaces: [], - standees: [], - pieces: [], - cards: [], -}; -let action_register = []; -const LAYOUT_BONUSES = [ - [435, 481], - [493, 481], -]; -const LAYOUT_CURRENT_EVENTS = [ - [172, 648], - [309, 648], - [445, 648], - [584, 648], -]; -const LAYOUT_GLORY = [ - [801, 647], - [860, 647], - [897, 647], - [848, 718], - [775, 771], - [812, 771], - [849, 771], - [885, 771], - [922, 771], -]; -const LAYOUT_medallionS = [ - [364, 556], - [415, 556], - [466, 556], - [517, 556], - [568, 556], -]; -const LAYOUT_TRACKS = [ - [ - [581, 46], - [618, 46], - [655, 46], - [691, 46], - [728, 46], - [765, 46], - [801, 46], - [838, 46], - [874, 46], - [911, 46], - [948, 46], - ], - [ - [581, 156], - [618, 156], - [655, 156], - [691, 156], - [728, 156], - [765, 156], - [801, 156], - [838, 156], - [874, 156], - [911, 156], - [948, 156], - ], - [ - [581, 267], - [618, 267], - [655, 267], - [691, 267], - [728, 267], - [765, 267], - [801, 267], - [838, 267], - [874, 267], - [911, 267], - [948, 267], - ], - [ - [581, 378], - [618, 378], - [655, 378], - [691, 378], - [728, 378], - [765, 378], - [801, 378], - [838, 378], - [874, 378], - [911, 378], - [948, 378], - ], - [ - [581, 489], - [618, 489], - [655, 489], - [691, 489], - [728, 489], - [765, 489], - [801, 489], - [838, 489], - [874, 489], - [911, 489], - [948, 489], - ], -]; + header: document.querySelector("header"), + hand_panel: document.getElementById("hand_panel"), + + map_container: document.getElementById("pieces"), + + fascist_cards: document.getElementById("fascist_cards"), + trash: document.getElementById("trash"), + hand: document.getElementById("hand"), + + player_areas: document.getElementById("player_areas"), + panels: { + a: document.getElementById("player_area_a"), + c: document.getElementById("player_area_c"), + m: document.getElementById("player_area_m"), + }, + tableaus: { + a: document.getElementById("tableau_a"), + c: document.getElementById("tableau_c"), + m: document.getElementById("tableau_m"), + }, + tokens: { + a: document.getElementById("tokens_a"), + c: document.getElementById("tokens_c"), + m: document.getElementById("tokens_m"), + }, + + // spaces + tracks_x: [], + tracks: [], + fronts: [], + con_fronts: [], + str_fronts: [], + + // tokens + standees: [], + bonuses: [], + medallions: [], + blank_markers: [], + + // cards + cards: [], +} + +/* :r! node tools/parse-layout.js */ +const boxes = { + "Northern": [149,146,149,149], + "Aragon": [563,275,149,149], + "Southern": [341,641,149,149], + "Madrid": [195,398,161,161], + "Liberty": [955,65,662,59], + "Collectivization": [954,231,663,60], + "SovietSupport": [954,564,663,59], + "ForeignAid": [954,730,663,59], + "Government": [1015,398,602,58], + "Medallion1": [608,834,69,70], + "Medallion2": [690,834,70,70], + "Medallion3": [772,834,70,70], + "Medallion4": [855,834,70,70], + "Medallion5": [937,834,70,70], + "CurrentYearDeck": [38,976,187,261], + "CurrentEvent1": [301,976,187,261], + "CurrentEvent2": [526,976,187,261], + "CurrentEvent3": [751,976,187,261], + "CurrentEvent4": [976,976,187,261], + "Glory1": [1320,966,59,59], + "Glory2": [1418,966,119,59], + "Glory3": [1399,1075,58,58], + "Glory4": [1278,1153,300,59], + "Bonus1": [728,726,74,73], + "Bonus2": [818,726,74,73], +} + +function toggle_pieces() { // eslint-disable-line no-unused-vars + ui.map_container.classList.toggle("hide") +} + +let animation_register = [] + +function register_animation(e) { + animation_register.push(e) +} + +function remember_position(e) { + if (e.parentElement) { + let prect = e.parentElement.getBoundingClientRect() + let rect = e.getBoundingClientRect() + e.my_visible = 1 + e.my_parent = e.parentElement + e.my_px = prect.x + e.my_py = prect.y + e.my_x = rect.x + e.my_y = rect.y + } else { + e.my_visible = 0 + e.my_parent = null + e.my_x = 0 + e.my_y = 0 + e.my_z = 0 + } +} + +function animate_position(e) { + if (e.parentElement && e.my_visible) { + let prect = e.parentElement.getBoundingClientRect() + let rect = e.getBoundingClientRect() + let dx, dy + if (e.parentElement === e.my_parent) { + // animate element within animated element... + dx = (e.my_x - e.my_px) - (rect.x - prect.x) + dy = (e.my_y - e.my_py) - (rect.y - prect.y) + } else { + dx = e.my_x - rect.x + dy = e.my_y - rect.y + } + + // fade in + if (!e.my_parent) { + e.animate( + [ + { opacity: 0 }, + { opacity: 1 } + ], + { duration: 500, easing: "ease" } + ) + } + + if (dx !== 0 || dy !== 0) { + let dist = Math.sqrt((dx * dx) + (dy * dy)) + let time = Math.max(500, Math.min(1000, dist / 2)) + e.animate( + [ + { transform: `translate(${dx}px, ${dy}px)`, }, + { transform: "translate(0, 0)", }, + ], + { duration: time, easing: "ease" } + ) + } + } +} + + +let action_register = [] + function register_action(e, action, id) { - e.my_action = action; - e.my_id = id; - e.onmousedown = on_click_action; - action_register.push(e); + e.my_action = action + e.my_id = id + e.onmousedown = on_click_action + action_register.push(e) } + function on_click_action(evt) { - if (evt.button === 0) - if (send_action(evt.target.my_action, evt.target.my_id)) - evt.stopPropagation(); -} -function on_click_tab(evt) { - evt.stopPropagation(); - const { id } = evt.target; - Object.entries(ui.player_area_tabs).forEach(([tab, elt]) => { - const cards_area = ui.player_area_cards[tab.split('_')[0]]; - if (tab === id) { - elt.setAttribute('data-active', 'active'); - cards_area.setAttribute('data-active', 'active'); - } - else { - elt.setAttribute('data-active', 'inactive'); - cards_area.setAttribute('data-active', 'inactive'); - } - }); + if (evt.button === 0) + if (send_action(evt.target.my_action, evt.target.my_id)) + evt.stopPropagation() } + function is_action(action, arg) { - if (arg === undefined) - return !!(view.actions && view.actions[action] === 1); - return !!(view.actions && - view.actions[action] && - view.actions[action].includes(arg)); + if (arg === undefined) + return !!(view.actions && view.actions[action] === 1) + return !!(view.actions && view.actions[action] && view.actions[action].includes(arg)) +} + +let on_init_once = false + +function build_track(t, action_name, track_name, a, b) { + let [x, y, w, h] = boxes[track_name] + let e + + ui.tracks[t] = [] + ui.tracks_x[t] = [] + for (let s = a; s <= b; ++s) { + const bm = t * 11 + s + + e = (ui.blank_markers[bm] = document.createElement("div")) + e.className = "red token blank hide" + e.style.top = Math.round(y+4) + "px" + e.style.left = Math.round(x+3) + "px" + register_action(e, "blank_marker", bm) + ui.map_container.appendChild(e) + + ui.tracks_x[t][s] = Math.round(x) + 4 + "px" + e = ui.tracks[t][s] = document.createElement("div") + e.className = "track" + e.style.top = y + "px" + e.style.left = Math.round(x) + "px" + register_action(e, action_name, s) + ui.map_container.appendChild(e) + + x += 60.5 + } + + e = (ui.standees[t] = document.createElement("div")) + e.className = "white token standee standee_" + t + e.style.top = y - 10 + "px" + e.style.left = boxes[track_name][0] + 4 + "px" + register_action(e, "standee", t) + register_animation(e) + ui.map_container.appendChild(ui.standees[t]) } -let on_init_once = false; + +function build_bonus(b, box_name, cname) { + var [x, y, w, h] = boxes[box_name] + var e = ui.bonuses[b] = document.createElement("div") + e.className = "red token round " + cname + e.style.top = Math.round(y + w/2 - 32) + "px" + e.style.left = Math.round(x + w/2 - 32) + "px" + register_action(e, "bonus", b) + ui.map_container.appendChild(e) +} + +function build_front(i, action_id, box_name) { + var [x, y, w, h] = boxes[box_name] + var e + + e = ui.con_fronts[i] = document.createElement("div") + e.className = "front_container" + e.style.top = y + 5 + "px" + e.style.left = x + "px" + e.style.width = w - 25 + "px" + e.style.height = 55 + "px" + ui.map_container.appendChild(e) + + e = ui.str_fronts[i] = document.createElement("div") + e.className = "front_container" + e.style.top = y + h - 55 - 5+ "px" + e.style.left = x + "px" + e.style.width = w - 25 + "px" + e.style.height = 55 + "px" + ui.map_container.appendChild(e) + + e = ui.fronts[i] = document.createElement("div") + e.className = "front" + e.style.top = Math.round(y-3) + "px" + e.style.left = Math.round(x-3) + "px" + e.style.width = Math.round(w - 6) + "px" + e.style.height = Math.round(h - 6) + "px" + register_action(e, "front", action_id) + ui.map_container.appendChild(e) +} + function on_init() { - if (on_init_once) - return; - on_init_once = true; - Object.values(ui.player_area_tabs).forEach((element) => { - element.addEventListener('click', on_click_tab); - }); - for (const player of view.player_order) { - ui.player_areas.container.insertAdjacentElement('beforeend', ui.player_areas[player]); - ui.roles.container.insertAdjacentElement('beforeend', ui.roles[player]); - } - ui.roles.container.insertAdjacentElement('beforeend', ui.turn_info); - if (view.current === 'Observer') { - ui.player_area.style.display = 'none'; - } - else { - document - .getElementById('player_area_header') - .setAttribute('data-faction-id', view.current_player_faction); - } - for (let t = 0; t < TRACK_COUNT; ++t) { - for (let s = 0; s < TRACK_LENGTH; ++s) { - const bm = t * 11 + s; - let e = (ui.blank_markers[bm] = document.createElement('div')); - e.className = 'blank_marker'; - register_action(e, 'blank_marker', bm); - } - } - for (let b = 0; b < BONUSES_COUNT; ++b) { - let e = (ui.bonuses[b] = document.createElement('div')); - e.className = 'bonus'; - e.setAttribute('data-bonus-id', '' + b); - e.style.left = LAYOUT_BONUSES[b][0] + 'px'; - e.style.top = LAYOUT_BONUSES[b][1] + 'px'; - LAYOUT_BONUSES; - register_action(e, 'bonus', b); - ui.map.appendChild(ui.bonuses[b]); - } - for (let g = 0; g < GLORY_COUNT; ++g) { - let e = (ui.glory[g] = document.createElement('div')); - e.className = 'faction_token'; - ui.glory_container.appendChild(ui.glory[g]); - e.style.left = LAYOUT_GLORY[g][0] + 'px'; - e.style.top = LAYOUT_GLORY[g][1] + 'px'; - } - for (let m = 0; m < medallionS_COUNT; ++m) { - let e = (ui.medallions[m] = document.createElement('div')); - e.className = 'medallion'; - e.setAttribute('data-medallion-id', '' + m); - register_action(e, 'medallion', m); - } - for (let s = 0; s < STANDEES_COUNT; ++s) { - let e = (ui.standees[s] = document.createElement('div')); - e.className = 'standee'; - e.setAttribute('data-standee-id', '' + s); - register_action(e, 'standee', s); - ui.tracks.appendChild(ui.standees[s]); - } - for (let c = 1; c < CARD_COUNT; ++c) { - let e = (ui.cards[c] = document.createElement('div')); - e.className = 'card'; - e.setAttribute('data-card-id', '' + data.cards[c].id); - register_action(e, 'card', c); - } - let e = (ui.initiative_token = document.createElement('div')); - e.className = 'initiative_token'; - data.fronts.forEach((front) => { - ui.tokens_on_front[front.id] = {}; - FACTIONS.forEach((faction_id) => { - let e = (ui.tokens_on_front[front.id][faction_id] = - document.createElement('div')); - e.className = 'faction_token'; - e.setAttribute('data-faction-id', faction_id); - }); - }); - Object.keys(ui.fronts).forEach((front_id) => { - register_action(ui.fronts[front_id].front, 'front', front_id); - }); + var i, e + + if (on_init_once) + return + on_init_once = true + + ui.roles_list = document.getElementById("roles"), + ui.roles = { + a: document.getElementById("role_Anarchist"), + c: document.getElementById("role_Communist"), + m: document.getElementById("role_Moderate"), + } + + build_track(0, "tr_liberty", "Liberty", 0, 10) + build_track(1, "tr_collectivization", "Collectivization", 0, 10) + build_track(2, "tr_government", "Government", 1, 10) + build_track(3, "tr_soviet_support", "SovietSupport", 0, 10) + build_track(4, "tr_foreign_aid", "ForeignAid", 0, 10) + + build_bonus(0, "Bonus1", "bonus_morale") + build_bonus(1, "Bonus2", "bonus_teamwork") + + build_front(0, "a", "Aragon") + build_front(1, "m", "Madrid") + build_front(2, "n", "Northern") + build_front(3, "s", "Southern") + + ui.medallion_container = [] + for (i = 0; i < 5; ++i) { + e = ui.medallion_container[i] = document.createElement("div") + e.className = "medallion_container" + e.style.top = boxes["Medallion"+(i+1)][1] + "px" + e.style.left = boxes["Medallion"+(i+1)][0] + "px" + ui.map_container.appendChild(e) + } + + ui.raw_glory_container = [] + for (i = 0; i < 4; ++i) { + e = ui.raw_glory_container[i] = document.createElement("div") + e.className = "glory_container" + e.style.left = boxes["Glory" + (i+1)][0] + "px" + e.style.top = boxes["Glory" + (i+1)][1] + "px" + ui.map_container.appendChild(e) + } + ui.glory_container = [ + ui.raw_glory_container[0], + ui.raw_glory_container[1], + ui.raw_glory_container[1], + ui.raw_glory_container[2], + ui.raw_glory_container[3], + ui.raw_glory_container[3], + ui.raw_glory_container[3], + ui.raw_glory_container[3], + ui.raw_glory_container[3], + ] + + e = ui.fascist_deck = document.createElement("div") + e.className = "fascist_deck" + e.style.top = boxes["CurrentYearDeck"][1] - 10 + "px" + e.style.left = boxes["CurrentYearDeck"][0] - 10 + "px" + ui.map_container.appendChild(e) + + ui.current_events = [] + for (i = 0; i < 4; ++i) { + e = (ui.current_events[i] = document.createElement("div")) + e.className = "current_events" + e.style.left = boxes["CurrentEvent" + (i+1)][0] - 10 + "px" + e.style.top = boxes["CurrentEvent" + (i+1)][1] - 10 + "px" + ui.map_container.appendChild(e) + } + + for (i = 0; i < 9; ++i) { + e = (ui.medallions[i] = document.createElement("div")) + e.className = "pink token medallion medallion_" + i + register_action(e, "medallion", i) + register_animation(e) + } + + for (i = 1; i <= 120; ++i) { + e = (ui.cards[i] = document.createElement("div")) + e.className = "card card_" + i + register_action(e, "card", i) + register_animation(e) + } + + e = ui.initiative = document.createElement("div") + e.className = "red token round initiative" + register_animation(e) } + function place_cards(e, cards) { - e.replaceChildren(); - for (let c of cards) { - ui.cards[c].classList.remove('selected'); - e.appendChild(ui.cards[c]); - if (view.selected_cards.includes(c)) { - ui.cards[c].classList.add('selected'); - } - } + if (cards) { + for (var c of cards) { + e.appendChild(ui.cards[c]) + ui.cards[c].classList.toggle("selected", view.selected_cards.includes(c)) + } + } +} + +const faction_class = { + "Anarchist": "anarchist", + "Communist": "communist", + "Moderate": "moderate", + "a": "anarchist", + "c": "communist", + "m": "moderate", +} + +function update_front(str_container, con_container, front) { + var i, n, e, cn + + str_container.replaceChildren() + if (front.value < 0) { + n = -front.value + cn = "brown token front_minus" + } else { + n = front.value + cn = "pink token front_plus" + } + for (i = 0; i < n; ++i) { + e = document.createElement("div") + e.className = cn + str_container.appendChild(e) + } + + con_container.replaceChildren() + for (i of ["a", "c", "m"]) { + if (front.contributions.includes(i)) { + e = document.createElement("div") + e.className = "red token player " + faction_class[i] + con_container.appendChild(e) + } + } +} + +function update_medallions(container, list) { + for (var i of list) + container.appendChild(ui.medallions[i]) +} + +function update_hero_points(container, n) { + for (var i = 0; i < n; ++i) { + var e = document.createElement("div") + e.className = "token pink hero_point" + container.appendChild(e) + } +} + +function update_stat_line(x) { + var i, line + line = "" + for (i = 0; i < view.hero_points[x]; ++i) + line += "\u272b" + if (view.initiative === x) + line += " \u2bc5" + return line } -function on_update() { - console.log('on_update', view); - on_init(); - for (let key of Object.keys(view.hero_points)) { - ui.roles[key].hero_points.replaceChildren(`Hero Points: ${view.hero_points[key]}`); - } - ui.bag_of_glory.replaceChildren(`Bag of Glory: ${view.bag_of_glory_count}`); - ui.current_events.replaceChildren(); - for (let i = 0; i < view.current_events.length; i++) { - const cardId = view.current_events[i]; - ui.current_events.appendChild(ui.cards[cardId]); - ui.cards[cardId].classList.add('event'); - ui.cards[cardId].style.left = LAYOUT_CURRENT_EVENTS[i][0] + 'px'; - ui.cards[cardId].style.top = LAYOUT_CURRENT_EVENTS[i][1] + 'px'; - } - ui.markers.replaceChildren(); - for (let bm of view.triggered_track_effects) { - const s = bm % 11; - const t = Math.floor(bm / 11); - ui.markers.appendChild(ui.blank_markers[bm]); - ui.blank_markers[bm].style.left = LAYOUT_TRACKS[t][s][0] + 'px'; - ui.blank_markers[bm].style.top = LAYOUT_TRACKS[t][s][1] + 'px'; - } - for (let bonus_id of Object.keys(view.bonuses)) { - ui.bonuses[bonus_id].setAttribute('data-bonus-on', view.bonuses[bonus_id] + 0); - } - place_cards(ui.hand, view.hand); - ui.player_area_tabs.hand_tab.replaceChildren(`Hand (${view.hand.length})`); - place_cards(ui.player_area_cards.deck, view.deck); - ui.player_area_tabs.deck_tab.replaceChildren(`Deck (${view.deck.length})`); - place_cards(ui.player_area_cards.discard, view.discard); - ui.player_area_tabs.discard_tab.replaceChildren(`Discard (${view.discard.length})`); - place_cards(ui.player_area_cards.trash, view.trash); - ui.player_area_tabs.trash_tab.replaceChildren(`Trash (${view.trash.length})`); - place_cards(ui.selectable_cards, view.selectable_cards); - for (let faction_id of FACTIONS) { - place_cards(ui.tableaus[faction_id], view.tableaus[faction_id]); - } - for (let i = 0; i < view.tracks.length; ++i) { - ui.standees[i].style.left = LAYOUT_TRACKS[i][view.tracks[i]][0] + 'px'; - ui.standees[i].style.top = LAYOUT_TRACKS[i][view.tracks[i]][1] + 'px'; - } - for (let front_id of Object.keys(view.fronts)) { - const front_data = view.fronts[front_id]; - ui.fronts[front_id].value.replaceChildren(front_data.status !== null ? front_data.status : front_data.value); - ui.fronts[front_id].contributions.replaceChildren(); - for (let faction_id of front_data.contributions) { - ui.fronts[front_id].contributions.appendChild(ui.tokens_on_front[front_id][faction_id]); - } - } - ui.medallions_container.replaceChildren(); - for (let i = 0; i < view.medallions.pool.length; ++i) { - if (view.medallions.pool[i] !== null) { - const id = view.medallions.pool[i]; - ui.medallions[id].style.left = LAYOUT_medallionS[i][0] + 'px'; - ui.medallions[id].style.top = LAYOUT_medallionS[i][1] + 'px'; - ui.medallions_container.appendChild(ui.medallions[id]); - } - } - for (let f of FACTIONS) { - ui.roles[f].medallions.replaceChildren(); - for (let m of view.medallions[f]) { - ui.roles[f].medallions.appendChild(ui.medallions[m]); - } - } - ui.roles[view.initiative].medallions.appendChild(ui.initiative_token); - ui.initiative_token.setAttribute('data-year', view.year); - if (view.played_card === null) { - ui.turn_info.style.display = 'none'; - } - else { - ui.turn_info.style.display = ''; - ui.turn_info_card.setAttribute('data-card-id', view.played_card + ''); - } - Object.values(ui.glory).forEach((elt) => elt.removeAttribute('data-faction-id')); - for (let g = 0; g < view.glory.length; ++g) { - ui.glory[g].setAttribute('data-faction-id', view.glory[g]); - } - for (let e of action_register) - e.classList.toggle('action', is_action(e.my_action, e.my_id)); - ui.year.replaceChildren(`Year ${view.year}`); - action_button('add_to_front', '+1 to a Front'); - action_button('d_liberty', 'Decrease Liberty'); - action_button('soviet_support', 'Soviet Support'); - action_button('collectivization', 'Collectivization'); - action_button('d_collectivization', 'Decrease Collectivization'); - action_button('d_foreign_aid', 'Decrease Foreign Aid'); - action_button('d_government', 'Decrease Government'); - action_button('d_soviet_support', 'Decrease Soviet Support'); - action_button('foreign_aid', 'Foreign Aid'); - action_button('government', 'Government'); - action_button('liberty', 'Liberty'); - action_button('government_to_center', 'Government towards center'); - action_button('teamwork_on', 'Teamwork Bonus On'); - action_button('Anarchist', 'Anarchist'); - action_button('Communist', 'Communist'); - action_button('Moderate', 'Moderate'); - action_button('gain_hp', 'Gain Hero Points'); - action_button('lose_hp', 'Lose Hero Points'); - action_button('draw_card', 'Draw a card'); - action_button('draw_cards', 'Draw cards'); - action_button('play_to_tableau', 'Play card to Tableau'); - action_button('play_for_event', 'Play card for Event'); - action_button('use_ap', 'Use Action Points'); - action_button('use_morale_bonus', 'Use Morale Bonus'); - action_button('move_track', 'Move a Track'); - action_button('turn_on_bonus', 'Turn on a Bonus'); - action_button('add_glory', 'Add to Bag of Glory'); - action_button('draw_glory', 'Draw from Bag of Glory'); - action_button('up', 'Up'); - action_button('down', 'Down'); - action_button('next', 'Next'); - action_button('remove_blank_marker', 'Remove Blank marker'); - action_button('confirm', 'Confirm'); - action_button('yes', 'Yes'); - action_button('no', 'No'); - action_button('skip', 'Skip'); - action_button('spend_hp', 'Spend Hero Points'); - action_button('use_momentum', 'Play second card (Momentum)'); - action_button('done', 'Done'); - action_button('end_turn', 'End turn'); - action_button('undo', 'Undo'); + +function on_update() { // eslint-disable-line no-unused-vars + var i, x, e + + on_init() + + animation_register.forEach(remember_position) + + ui.player_areas.replaceChildren() + ui.roles_list.replaceChildren() + for (i = 0; i < 3; ++i) { + ui.player_areas.appendChild(ui.panels[view.player_order[i]]) + ui.roles_list.appendChild(ui.roles[view.player_order[i]]) + } + + ui.header.classList.toggle("fascist", !!view.fascist) + + ui.initiative.classList.toggle("ccw", (view.year & 1) === 0) + roles.Anarchist.stat.textContent = update_stat_line("a") + roles.Communist.stat.textContent = update_stat_line("c") + roles.Moderate.stat.textContent = update_stat_line("m") + + // TODO: played card (side panel?) + + // TODO: player draw/discard/trash + // TODO: bag of glory + + ui.fascist_deck.replaceChildren() + if (view.year === 1) + place_cards(ui.fascist_deck, [ 120, 119, 118 ]) + else if (view.year === 2) + place_cards(ui.fascist_deck, [ 120, 119 ]) + else + place_cards(ui.fascist_deck, [ 120]) + + ui.fascist_cards.replaceChildren() + place_cards(ui.fascist_cards, view.fascist_cards) + + ui.trash.replaceChildren() + place_cards(ui.trash, view.trash) + + ui.hand_panel.classList = "panel " + faction_class[player] + ui.hand.replaceChildren() + place_cards(ui.hand, view.hand) + + ui.tableaus.a.replaceChildren() + ui.tableaus.c.replaceChildren() + ui.tableaus.m.replaceChildren() + ui.tableaus.a.appendChild(ui.cards[117]) + ui.tableaus.c.appendChild(ui.cards[116]) + ui.tableaus.m.appendChild(ui.cards[115]) + place_cards(ui.tableaus.a, view.tableaus.a) + place_cards(ui.tableaus.c, view.tableaus.c) + place_cards(ui.tableaus.m, view.tableaus.m) + + for (i = 0; i <= 1; ++i) { + ui.bonuses[i].classList.toggle("red", !!view.bonuses[i]) + ui.bonuses[i].classList.toggle("gray", !view.bonuses[i]) + ui.bonuses[i].classList.toggle("off", !view.bonuses[i]) + } + + for (i = 0; i < 4; ++i) { + ui.current_events[i].replaceChildren() + if (i < view.current_events.length) + ui.current_events[i].appendChild(ui.cards[view.current_events[i]]) + } + + for (i = 0; i < 5; ++i) + ui.standees[i].style.left = ui.tracks_x[i][view.tracks[i]] + + for (i = 0; i < 55; ++i) { + if (ui.blank_markers[i]) + ui.blank_markers[i].classList.toggle("hide", + !view.triggered_track_effects.includes(i)) + } + + for (i = 0; i < 5; ++i) { + ui.medallion_container[i].replaceChildren() + if (i < view.medallions.pool.length) { + x = view.medallions.pool[i] + if (x !== null) + ui.medallion_container[i].appendChild(ui.medallions[x]) + } + } + + ui.tokens.a.replaceChildren() + ui.tokens.c.replaceChildren() + ui.tokens.m.replaceChildren() + ui.tokens[view.initiative].appendChild(ui.initiative) + update_medallions(ui.tokens.a, view.medallions.a) + update_medallions(ui.tokens.c, view.medallions.c) + update_medallions(ui.tokens.m, view.medallions.m) + update_hero_points(ui.tokens.a, view.hero_points.a) + update_hero_points(ui.tokens.c, view.hero_points.c) + update_hero_points(ui.tokens.m, view.hero_points.m) + + update_front(ui.str_fronts[0], ui.con_fronts[0], view.fronts.a) + update_front(ui.str_fronts[1], ui.con_fronts[1], view.fronts.m) + update_front(ui.str_fronts[2], ui.con_fronts[2], view.fronts.n) + update_front(ui.str_fronts[3], ui.con_fronts[3], view.fronts.s) + + for (e of ui.raw_glory_container) + e.replaceChildren() + for (i = 0; i < view.glory.length; ++i) { + x = view.glory[i] + e = document.createElement("div") + e.className = "red token player " + faction_class[x] + ui.glory_container[i].appendChild(e) + } + + action_button("add_to_front", "+1 to a Front") + action_button("d_liberty", "Decrease Liberty") + action_button("soviet_support", "Soviet Support") + action_button("collectivization", "Collectivization") + action_button("d_collectivization", "Decrease Collectivization") + action_button("d_foreign_aid", "Decrease Foreign Aid") + action_button("d_government", "Decrease Government") + action_button("d_soviet_support", "Decrease Soviet Support") + action_button("foreign_aid", "Foreign Aid") + action_button("government", "Government") + action_button("liberty", "Liberty") + action_button("government_to_center", "Government towards center") + action_button("teamwork_on", "Teamwork Bonus On") + action_button("Anarchist", "Anarchist") + action_button("Communist", "Communist") + action_button("Moderate", "Moderate") + action_button("gain_hp", "Gain Hero Points") + action_button("lose_hp", "Lose Hero Points") + action_button("draw_card", "Draw a card") + action_button("draw_cards", "Draw cards") + action_button("play_to_tableau", "Play card to Tableau") + action_button("play_for_event", "Play card for Event") + action_button("use_ap", "Use Action Points") + action_button("use_morale_bonus", "Use Morale Bonus") + action_button("move_track", "Move a Track") + action_button("turn_on_bonus", "Turn on a Bonus") + action_button("add_glory", "Add to Bag of Glory") + action_button("draw_glory", "Draw from Bag of Glory") + action_button("up", "Up") + action_button("down", "Down") + action_button("next", "Next") + action_button("remove_blank_marker", "Remove Blank marker") + action_button("confirm", "Confirm") + action_button("yes", "Yes") + action_button("no", "No") + action_button("skip", "Skip") + action_button("spend_hp", "Spend Hero Points") + action_button("use_momentum", "Play second card (Momentum)") + action_button("done", "Done") + action_button("end_turn", "End turn") + action_button("undo", "Undo") + + for (e of action_register) + e.classList.toggle("action", is_action(e.my_action, e.my_id)) + + animation_register.forEach(animate_position) } -const IMG_FTA = ''; -const IMG_FTC = ''; -const IMG_FTM = ''; -function on_log(text) { - let p = document.createElement('div'); - if (text.match(/^>>/)) { - text = text.substring(2); - p.className = 'ii'; - } - if (text.match(/^>/)) { - text = text.substring(1); - p.className = 'i'; - } - if (text.match(/^\.h1/)) { - text = text.substring(4); - p.className = 'h1'; - } - else if (text.match(/^\.h2\.Moderate/)) { - text = text.substring(13); - p.className = 'h2 moderate'; - } - else if (text.match(/^\.h2\.Anarchist/)) { - text = text.substring(14); - p.className = 'h2 anarchist'; - } - else if (text.match(/^\.h2\.Communist/)) { - text = text.substring(14); - p.className = 'h2 communist'; - } - else if (text.match(/^\.h2\.fascist/)) { - text = text.substring(11); - p.className = 'h2 fascist'; - } - else if (text.match(/^\.h2\.glory/)) { - text = text.substring(9); - p.className = 'h2 glory'; - } - else if (text.match(/^\.h2/)) { - text = text.substring(4); - p.className = 'h2'; - } - else if (text.match(/^\.h3/)) { - text = text.substring(4); - p.className = 'h3'; - } - text = text.replace(//g, IMG_FTA); - text = text.replace(//g, IMG_FTC); - text = text.replace(//g, IMG_FTM); - p.innerHTML = text; - return p; + +function on_log(text) { // eslint-disable-line no-unused-vars + let p = document.createElement("div") + + if (text.match(/^>>/)) { + text = text.substring(2) + p.className = "ii" + } + if (text.match(/^>/)) { + text = text.substring(1) + p.className = "i" + } + + text = text.replace(/&/g, "&") + text = text.replace(//g, ">") + text = text.replace(/-( ?[\d(])/g, "\u2212$1") + + // text = text.replace(/C(\d+)/g, sub_card) + + if (text.startsWith("#")) { + p.className = "h " + text[1] + text = text.substring(3) + } + + p.innerHTML = text + return p } diff --git a/play.ts b/play.ts deleted file mode 100644 index 5080b37..0000000 --- a/play.ts +++ /dev/null @@ -1,623 +0,0 @@ -'use strict'; - -import { StaticData, View } from './types'; - -declare function action_button(action: string, text: string): void; -// declare function register_action(element: HTMLElement, type: string, s: number): void; -declare function send_action(action: string, text: string): boolean; -declare const data: StaticData; -declare const view: View; - -/* global view, player, send_action, action_button */ - -const BONUSES_COUNT = 2; -// const PIECE_COUNT = 32; -const CARD_COUNT = 109; -const GLORY_COUNT = 9; -const medallionS_COUNT = 9; -const STANDEES_COUNT = 5; -const TRACK_COUNT = 5; -const TRACK_LENGTH = 11; -const FACTIONS = ['a', 'c', 'm']; -// const ROLES = ['Anarchist', 'Communist', 'Moderate']; - -const ui = { - bag_of_glory: document.getElementById('bag_of_glory'), - map: document.getElementById('map'), - medallions_container: document.getElementById('medallions'), - markers: document.getElementById('markers'), - fronts: { - a: { - front: document.getElementById('aragon_front'), - value: document.querySelector('#aragon_front .value'), - contributions: document.querySelector('#aragon_front .contributions'), - }, - m: { - front: document.getElementById('madrid_front'), - value: document.querySelector('#madrid_front .value'), - contributions: document.querySelector('#madrid_front .contributions'), - }, - n: { - front: document.getElementById('northern_front'), - value: document.querySelector('#northern_front .value'), - contributions: document.querySelector('#northern_front .contributions'), - }, - s: { - front: document.getElementById('southern_front'), - value: document.querySelector('#southern_front .value'), - contributions: document.querySelector('#southern_front .contributions'), - }, - }, - glory_container: document.getElementById('glory'), - hand: document.getElementById('hand'), - player_area: document.getElementById('player_area'), - current_events: document.getElementById('current_events'), - roles: { - a: { - hero_points: document.querySelector('#role_Anarchist .role_stat'), - medallions: document.querySelector('#role_Anarchist .role_medallions'), - }, - c: { - hero_points: document.querySelector('#role_Communist .role_stat'), - medallions: document.querySelector('#role_Communist .role_medallions'), - }, - m: { - hero_points: document.querySelector('#role_Moderate .role_stat'), - medallions: document.querySelector('#role_Moderate .role_medallions'), - }, - pool: { - hero_points: document.getElementById('pool_hero_points'), - }, - Anarchist: document.getElementById('role_Anarchist'), - Communist: document.getElementById('role_Communist'), - Moderate: document.getElementById('role_Moderate'), - container: document.getElementById('roles'), - }, - player_area_tabs: { - hand_tab: document.getElementById('hand_tab'), - deck_tab: document.getElementById('deck_tab'), - discard_tab: document.getElementById('discard_tab'), - trash_tab: document.getElementById('trash_tab'), - }, - player_area_cards: { - hand: document.getElementById('hand'), - deck: document.getElementById('deck'), - discard: document.getElementById('discard'), - trash: document.getElementById('trash'), - }, - player_areas: { - container: document.getElementById('player_areas'), - Anarchist: document.getElementById('player_area_Anarchist'), - Communist: document.getElementById('player_area_Communist'), - Moderate: document.getElementById('player_area_Moderate'), - }, - selectable_cards: document.getElementById('selectable_cards'), - tableaus: { - a: document.getElementById('tableau_a'), - c: document.getElementById('tableau_c'), - m: document.getElementById('tableau_m'), - }, - tracks: document.getElementById('tracks'), - hero_points: document.querySelector('#role_Anarchist .role_stat'), - turn_info: document.getElementById('turn_info'), - turn_info_card: document.getElementById('turn_info_card'), - year: document.getElementById('year'), - blank_markers: [], - bonuses: [], - // fronts: {}, - tokens_on_front: {}, - // front_values: {}, - glory: [], - initiative_token: undefined, - medallions: [], - spaces: [], - standees: [], - pieces: [], - cards: [], -}; - -let action_register = []; - -const LAYOUT_BONUSES = [ - [435, 481], - [493, 481], -]; - -const LAYOUT_CURRENT_EVENTS = [ - [172, 648], - [309, 648], - [445, 648], - [584, 648], -]; - -const LAYOUT_GLORY = [ - [801, 647], - [860, 647], - [897, 647], - [848, 718], - [775, 771], - [812, 771], - [849, 771], - [885, 771], - [922, 771], -]; - -const LAYOUT_medallionS = [ - [364, 556], - [415, 556], - [466, 556], - [517, 556], - [568, 556], -]; - -const LAYOUT_TRACKS = [ - [ - [581, 46], - [618, 46], - [655, 46], - [691, 46], - [728, 46], - [765, 46], - [801, 46], - [838, 46], - [874, 46], - [911, 46], - [948, 46], - ], - [ - [581, 156], - [618, 156], - [655, 156], - [691, 156], - [728, 156], - [765, 156], - [801, 156], - [838, 156], - [874, 156], - [911, 156], - [948, 156], - ], - [ - [581, 267], - [618, 267], - [655, 267], - [691, 267], - [728, 267], - [765, 267], - [801, 267], - [838, 267], - [874, 267], - [911, 267], - [948, 267], - ], - [ - [581, 378], - [618, 378], - [655, 378], - [691, 378], - [728, 378], - [765, 378], - [801, 378], - [838, 378], - [874, 378], - [911, 378], - [948, 378], - ], - [ - [581, 489], - [618, 489], - [655, 489], - [691, 489], - [728, 489], - [765, 489], - [801, 489], - [838, 489], - [874, 489], - [911, 489], - [948, 489], - ], -]; - -// @ts-ignore -// (function build_map() { -// data.fronts.forEach((front) => { -// const { id, top, left } = front; -// const element = (ui.fronts[front.id] = document.createElement('div')); -// element.classList.add('front'); -// element.style.left = `${left}px`; -// element.style.top = `${top}px`; -// element.setAttribute('data-front-id', `${id}`); -// ui.map.appendChild(element); -// register_action(element, 'front', id); - -// // Contribution tokens - -// // Value of front -// const front_value_element = (ui.front_values[front.id] = -// document.createElement('span')); -// front_value_element.classList.add('value'); -// element.appendChild(front_value_element); -// }); -// })(); - -function register_action( - e: HTMLElement & { my_action?: string; my_id?: string | number }, - action: string, - id: string | number -) { - e.my_action = action; - e.my_id = id; - e.onmousedown = on_click_action; - action_register.push(e); -} - -function on_click_action(evt) { - if (evt.button === 0) - if (send_action(evt.target.my_action, evt.target.my_id)) - evt.stopPropagation(); -} - -function on_click_tab(evt) { - evt.stopPropagation(); - const { id } = evt.target as HTMLElement; - - Object.entries(ui.player_area_tabs).forEach(([tab, elt]) => { - const cards_area = ui.player_area_cards[tab.split('_')[0]]; - if (tab === id) { - elt.setAttribute('data-active', 'active'); - cards_area.setAttribute('data-active', 'active'); - } else { - elt.setAttribute('data-active', 'inactive'); - cards_area.setAttribute('data-active', 'inactive'); - } - }); -} - -function is_action(action, arg) { - if (arg === undefined) return !!(view.actions && view.actions[action] === 1); - return !!( - view.actions && - view.actions[action] && - view.actions[action].includes(arg) - ); -} - -let on_init_once = false; - -function on_init() { - if (on_init_once) return; - on_init_once = true; - - Object.values(ui.player_area_tabs).forEach((element) => { - element.addEventListener('click', on_click_tab); - }); - - // Reorder tableaus and roles based on player order - for (const player of view.player_order) { - ui.player_areas.container.insertAdjacentElement( - 'beforeend', - ui.player_areas[player] - ); - ui.roles.container.insertAdjacentElement('beforeend', ui.roles[player]); - } - ui.roles.container.insertAdjacentElement('beforeend', ui.turn_info); - - if (view.current === 'Observer') { - ui.player_area.style.display = 'none'; - } else { - document - .getElementById('player_area_header') - .setAttribute('data-faction-id', view.current_player_faction); - } - - // Create blank_markers - for (let t = 0; t < TRACK_COUNT; ++t) { - for (let s = 0; s < TRACK_LENGTH; ++s) { - const bm = t * 11 + s; - let e = (ui.blank_markers[bm] = document.createElement('div')); - e.className = 'blank_marker'; - register_action(e, 'blank_marker', bm); - } - } - - // create bonus markers - for (let b = 0; b < BONUSES_COUNT; ++b) { - let e = (ui.bonuses[b] = document.createElement('div')); - e.className = 'bonus'; - e.setAttribute('data-bonus-id', '' + b); - e.style.left = LAYOUT_BONUSES[b][0] + 'px'; - e.style.top = LAYOUT_BONUSES[b][1] + 'px'; - LAYOUT_BONUSES; - register_action(e, 'bonus', b); - ui.map.appendChild(ui.bonuses[b]); - } - - // Create glory - for (let g = 0; g < GLORY_COUNT; ++g) { - let e = (ui.glory[g] = document.createElement('div')); - e.className = 'faction_token'; - ui.glory_container.appendChild(ui.glory[g]); - e.style.left = LAYOUT_GLORY[g][0] + 'px'; - e.style.top = LAYOUT_GLORY[g][1] + 'px'; - } - - // create track medallions - for (let m = 0; m < medallionS_COUNT; ++m) { - let e = (ui.medallions[m] = document.createElement('div')); - e.className = 'medallion'; - e.setAttribute('data-medallion-id', '' + m); - register_action(e, 'medallion', m); - } - - // create track standees - for (let s = 0; s < STANDEES_COUNT; ++s) { - let e = (ui.standees[s] = document.createElement('div')); - e.className = 'standee'; - e.setAttribute('data-standee-id', '' + s); - register_action(e, 'standee', s); - ui.tracks.appendChild(ui.standees[s]); - } - - // create card elements - for (let c = 1; c < CARD_COUNT; ++c) { - let e = (ui.cards[c] = document.createElement('div')); - e.className = 'card'; - e.setAttribute('data-card-id', '' + data.cards[c].id); - register_action(e, 'card', c); - } - - // create initiative marker - let e = (ui.initiative_token = document.createElement('div')); - e.className = 'initiative_token'; - - // create tokens to add to fronts - data.fronts.forEach((front) => { - ui.tokens_on_front[front.id] = {}; - FACTIONS.forEach((faction_id) => { - let e = (ui.tokens_on_front[front.id][faction_id] = - document.createElement('div')); - e.className = 'faction_token'; - e.setAttribute('data-faction-id', faction_id); - }); - }); - - Object.keys(ui.fronts).forEach((front_id) => { - register_action(ui.fronts[front_id].front, 'front', front_id); - }); -} - -function place_cards(e: HTMLElement, cards: number[]) { - e.replaceChildren(); - for (let c of cards) { - ui.cards[c].classList.remove('selected'); - e.appendChild(ui.cards[c]); - if (view.selected_cards.includes(c)) { - ui.cards[c].classList.add('selected'); - } - } -} - -// @ts-ignore -function on_update() { - console.log('on_update', view); - on_init(); - - for (let key of Object.keys(view.hero_points)) { - ui.roles[key].hero_points.replaceChildren( - `Hero Points: ${view.hero_points[key]}` - ); - } - ui.bag_of_glory.replaceChildren(`Bag of Glory: ${view.bag_of_glory_count}`); - - // for (let s = 0; s < SPACE_COUNT; ++s) ui.spaces[s].replaceChildren(); - - // for (let p = 0; p < PIECE_COUNT; ++p) { - // let s = view.location[p]; - // ui.spaces[s].appendChild(ui.pieces[p]); - // } - ui.current_events.replaceChildren(); - for (let i = 0; i < view.current_events.length; i++) { - const cardId = view.current_events[i]; - ui.current_events.appendChild(ui.cards[cardId]); - ui.cards[cardId].classList.add('event'); - ui.cards[cardId].style.left = LAYOUT_CURRENT_EVENTS[i][0] + 'px'; - ui.cards[cardId].style.top = LAYOUT_CURRENT_EVENTS[i][1] + 'px'; - } - - ui.markers.replaceChildren(); - for (let bm of view.triggered_track_effects) { - const s = bm % 11; - const t = Math.floor(bm / 11); - ui.markers.appendChild(ui.blank_markers[bm]); - ui.blank_markers[bm].style.left = LAYOUT_TRACKS[t][s][0] + 'px'; - ui.blank_markers[bm].style.top = LAYOUT_TRACKS[t][s][1] + 'px'; - } - - for (let bonus_id of Object.keys(view.bonuses)) { - ui.bonuses[bonus_id].setAttribute( - 'data-bonus-on', - view.bonuses[bonus_id] + 0 - ); - } - - place_cards(ui.hand, view.hand); - ui.player_area_tabs.hand_tab.replaceChildren(`Hand (${view.hand.length})`); - place_cards(ui.player_area_cards.deck, view.deck); - ui.player_area_tabs.deck_tab.replaceChildren(`Deck (${view.deck.length})`); - place_cards(ui.player_area_cards.discard, view.discard); - ui.player_area_tabs.discard_tab.replaceChildren(`Discard (${view.discard.length})`); - place_cards(ui.player_area_cards.trash, view.trash); - ui.player_area_tabs.trash_tab.replaceChildren(`Trash (${view.trash.length})`); - - place_cards(ui.selectable_cards, view.selectable_cards); - - for (let faction_id of FACTIONS) { - place_cards(ui.tableaus[faction_id], view.tableaus[faction_id]); - } - - for (let i = 0; i < view.tracks.length; ++i) { - // ui.tracks.appendChild(ui.standees[i]); - ui.standees[i].style.left = LAYOUT_TRACKS[i][view.tracks[i]][0] + 'px'; - ui.standees[i].style.top = LAYOUT_TRACKS[i][view.tracks[i]][1] + 'px'; - } - - for (let front_id of Object.keys(view.fronts)) { - const front_data = view.fronts[front_id]; - // ui.fronts[front_id].value.replaceChildren(front_data.value); - ui.fronts[front_id].value.replaceChildren( - front_data.status !== null ? front_data.status : front_data.value - ); - ui.fronts[front_id].contributions.replaceChildren(); - for (let faction_id of front_data.contributions) { - ui.fronts[front_id].contributions.appendChild( - ui.tokens_on_front[front_id][faction_id] - ); - } - } - - ui.medallions_container.replaceChildren(); - for (let i = 0; i < view.medallions.pool.length; ++i) { - if (view.medallions.pool[i] !== null) { - const id = view.medallions.pool[i]; - ui.medallions[id].style.left = LAYOUT_medallionS[i][0] + 'px'; - ui.medallions[id].style.top = LAYOUT_medallionS[i][1] + 'px'; - ui.medallions_container.appendChild(ui.medallions[id]); - } - } - for (let f of FACTIONS) { - ui.roles[f].medallions.replaceChildren(); - for (let m of view.medallions[f]) { - ui.roles[f].medallions.appendChild(ui.medallions[m]); - } - } - ui.roles[view.initiative].medallions.appendChild(ui.initiative_token); - ui.initiative_token.setAttribute('data-year', view.year); - - if (view.played_card === null) { - ui.turn_info.style.display = 'none'; - } else { - ui.turn_info.style.display = ''; - ui.turn_info_card.setAttribute('data-card-id', view.played_card + ''); - } - - Object.values(ui.glory).forEach((elt: HTMLElement) => elt.removeAttribute('data-faction-id')); - for (let g = 0; g < view.glory.length; ++g) { - ui.glory[g].setAttribute('data-faction-id', view.glory[g]); - } - - for (let e of action_register) - e.classList.toggle('action', is_action(e.my_action, e.my_id)); - - ui.year.replaceChildren(`Year ${view.year}`); - - action_button('add_to_front', '+1 to a Front'); - action_button('d_liberty', 'Decrease Liberty'); - action_button('soviet_support', 'Soviet Support'); - action_button('collectivization', 'Collectivization'); - - action_button('d_collectivization', 'Decrease Collectivization'); - action_button('d_foreign_aid', 'Decrease Foreign Aid'); - action_button('d_government', 'Decrease Government'); - - action_button('d_soviet_support', 'Decrease Soviet Support'); - - action_button('foreign_aid', 'Foreign Aid'); - action_button('government', 'Government'); - action_button('liberty', 'Liberty'); - action_button('government_to_center', 'Government towards center'); - - action_button('teamwork_on', 'Teamwork Bonus On'); - action_button('Anarchist', 'Anarchist'); - action_button('Communist', 'Communist'); - action_button('Moderate', 'Moderate'); - action_button('gain_hp', 'Gain Hero Points'); - action_button('lose_hp', 'Lose Hero Points'); - action_button('draw_card', 'Draw a card'); - action_button('draw_cards', 'Draw cards'); - // action_button('draw_card', 'Draw card'); - action_button('play_to_tableau', 'Play card to Tableau'); - action_button('play_for_event', 'Play card for Event'); - action_button('use_ap', 'Use Action Points'); - action_button('use_morale_bonus', 'Use Morale Bonus'); - - action_button('move_track', 'Move a Track'); - action_button('turn_on_bonus', 'Turn on a Bonus'); - - action_button('add_glory', 'Add to Bag of Glory'); - action_button('draw_glory', 'Draw from Bag of Glory'); - action_button('up', 'Up'); - action_button('down', 'Down'); - action_button('next', 'Next'); - action_button('remove_blank_marker', 'Remove Blank marker'); - action_button('confirm', 'Confirm'); - action_button('yes', 'Yes'); - action_button('no', 'No'); - action_button('skip', 'Skip'); - action_button('spend_hp', 'Spend Hero Points'); - action_button('use_momentum', 'Play second card (Momentum)'); - action_button('done', 'Done'); - action_button('end_turn', 'End turn'); - action_button('undo', 'Undo'); -} - -const IMG_FTA = ''; -const IMG_FTC = ''; -const IMG_FTM = ''; - -// @ts-ignore -function on_log(text) { - let p = document.createElement('div'); - - if (text.match(/^>>/)) { - text = text.substring(2); - p.className = 'ii'; - } - - if (text.match(/^>/)) { - text = text.substring(1); - p.className = 'i'; - } - - // text = text.replace(/&/g, '&'); - // text = text.replace(//g, '>'); - // text = text.replace(/C(\d+)/g, sub_card_name) - // text = text.replace(/S(\d+)/g, sub_space_name) - // text = text.replace(/U(\d+)/g, sub_unit_name) - - // TODO dice icons - // text = text.replace(/\bD\d\b/g, sub_icon) - - if (text.match(/^\.h1/)) { - text = text.substring(4); - p.className = 'h1'; - } else if (text.match(/^\.h2\.Moderate/)) { - text = text.substring(13); - p.className = 'h2 moderate'; - } else if (text.match(/^\.h2\.Anarchist/)) { - text = text.substring(14); - p.className = 'h2 anarchist'; - } else if (text.match(/^\.h2\.Communist/)) { - text = text.substring(14); - p.className = 'h2 communist'; - } else if (text.match(/^\.h2\.fascist/)) { - text = text.substring(11); - p.className = 'h2 fascist'; - } else if (text.match(/^\.h2\.glory/)) { - text = text.substring(9); - p.className = 'h2 glory'; - } else if (text.match(/^\.h2/)) { - text = text.substring(4); - p.className = 'h2'; - } else if (text.match(/^\.h3/)) { - text = text.substring(4); - p.className = 'h3'; - } - - text = text.replace(//g, IMG_FTA) - text = text.replace(//g, IMG_FTC) - text = text.replace(//g, IMG_FTM) - - p.innerHTML = text; - return p; -} diff --git a/rules.js b/rules.js index 46a9176..25d80b0 100644 --- a/rules.js +++ b/rules.js @@ -80,7 +80,7 @@ function gen_spend_hero_points() { } function action(state, player, action, arg) { game = state; - if (action !== 'undo' && game.state !== 'choose_card' && !game.fascist) { + if (action !== 'undo' && game.state !== 'choose_card') { push_undo(); } let S = states[game.state]; diff --git a/rules.ts b/rules.ts index cc35bdf..e509a17 100644 --- a/rules.ts +++ b/rules.ts @@ -174,7 +174,7 @@ export function action( ) { game = state; - if (action !== 'undo' && game.state !== 'choose_card' && !game.fascist) { + if (action !== 'undo' && game.state !== 'choose_card') { push_undo(); } diff --git a/tools/colors.js b/tools/colors.js new file mode 100644 index 0000000..16378f7 --- /dev/null +++ b/tools/colors.js @@ -0,0 +1,143 @@ +"use strict" + +function rgb_from_any(color) { + if (typeof color === "string") + color = parse_hex(color) + switch (color.mode) { + case "rgb": return color + case "lrgb": return rgb_from_lrgb(color) + case "oklab": return rgb_from_oklab(color) + } +} + +function lrgb_from_any(color) { + switch (color.mode) { + case "rgb": return lrgb_from_rgb(color) + case "lrgb": return color + case "oklab": return lrgb_from_oklab(color) + } +} + +function oklab_from_any(color) { + switch (color.mode) { + case "rgb": return oklab_from_rgb(color) + case "lrgb": return oklab_from_lrgb(color) + case "oklab": return color + } +} + +function format_hex(color) { + let { r, g, b } = rgb_from_any(color) + let adj = 1 + r = Math.round(Math.max(0, Math.min(1, r)) * 255) + g = Math.round(Math.max(0, Math.min(1, g)) * 255) + b = Math.round(Math.max(0, Math.min(1, b)) * 255) + let x = (r << 16) | (g << 8) | b + return "#" + x.toString(16).padStart(6, "0") +} + +function parse_hex(str) { + let x = parseInt(str.substring(1), 16) + return { + mode: "rgb", + r: ((x >> 16) & 255) / 255.0, + g: ((x >> 8) & 255) / 255.0, + b: ((x) & 255) / 255.0 + } +} + +function lrgb_from_rgb({ r, g, b }) { + function to_linear(c) { + let ac = Math.abs(c) + if (ac < 0.04045) + return c / 12.92 + return (Math.sign(c) || 1) * Math.pow((ac + 0.055) / 1.055, 2.4) + } + return { + mode: "lrgb", + r: to_linear(r), + g: to_linear(g), + b: to_linear(b) + } +} + +function rgb_from_lrgb({ r, g, b }) { + function from_linear(c) { + let ac = Math.abs(c) + if (ac > 0.0031308) + return (Math.sign(c) || 1) * (1.055 * Math.pow(ac, 1 / 2.4) - 0.055) + return c * 12.92 + } + return { + mode: "rgb", + r: from_linear(r), + g: from_linear(g), + b: from_linear(b) + } +} + +function oklab_from_lrgb({ r, g, b }) { + let L = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b) + let M = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b) + let S = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b) + return { + mode: "oklab", + l: 0.2104542553 * L + 0.793617785 * M - 0.0040720468 * S, + a: 1.9779984951 * L - 2.428592205 * M + 0.4505937099 * S, + b: 0.0259040371 * L + 0.7827717662 * M - 0.808675766 * S + } +} + +function lrgb_from_oklab({ l, a, b }) { + let L = Math.pow(l + 0.3963377774 * a + 0.2158037573 * b, 3) + let M = Math.pow(l - 0.1055613458 * a - 0.0638541728 * b, 3) + let S = Math.pow(l - 0.0894841775 * a - 1.291485548 * b, 3) + return { + mode: "lrgb", + r: +4.0767416621 * L - 3.3077115913 * M + 0.2309699292 * S, + g: -1.2684380046 * L + 2.6097574011 * M - 0.3413193965 * S, + b: -0.0041960863 * L - 0.7034186147 * M + 1.707614701 * S + } +} + +function oklab_from_rgb(rgb) { + return oklab_from_lrgb(lrgb_from_rgb(rgb)) +} + +function rgb_from_oklab(oklab) { + return rgb_from_lrgb(lrgb_from_oklab(oklab)) +} + +function format_hsl(rgb) { + let { r, g, b } = rgb_from_any(color) + let cmin = Math.min(r, g, b) + let cmax = Math.max(r, g, b) + let delta = cmax - cmin + let h = 0, s = 0, l = 0 + + if (delta == 0) + h = 0 + else if (cmax == r) + h = ((g - b) / delta) % 6 + else if (cmax == g) + h = (b - r) / delta + 2 + else + h = (r - g) / delta + 4 + + h = Math.round(h * 60) + + if (h < 0) + h += 360 + + l = (cmax + cmin) / 2 + + s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)) + + s = Math.round(s * 100) + l = Math.round(l * 100) + + return "hsl(" + h + "," + s + "%," + l + "%)" +} + +if (typeof module === "object") + module.exports = { format_hex, parse_hex, rgb_from_any, lrgb_from_any, oklab_from_any, format_hsl } diff --git a/tools/gencolor.js b/tools/gencolor.js new file mode 100644 index 0000000..ea804e6 --- /dev/null +++ b/tools/gencolor.js @@ -0,0 +1,27 @@ +"use strict" + +const colors = require("./colors.js") + +function lerp(v0, v1, t) { + return v0 + t * (v1 - v0) +} + +function lerp_rgb(rgb, x=0, t=0) { + let lab = colors.oklab_from_any(colors.parse_hex(rgb)) + lab.l = lerp(lab.l, x, t) + return colors.format_hex(lab) +} + +function make_colors(rgb, sel) { + let bg = lerp_rgb(rgb, 1.0, 0.0) + let hi = lerp_rgb(rgb, 1.0, 0.4) + let sh = lerp_rgb(rgb, 0.2, 0.4) + let bd = lerp_rgb(rgb, 0.2, 0.8) + console.log(sel + ` { background-color: ${bg}; border-color: ${hi} ${sh} ${sh} ${hi}; box-shadow: 0 0 0 1px ${bd}, 0px 1px 4px #0008; }`) +} + +make_colors("#bbbbbb", ".token.white") +make_colors("#ef0500", ".token.red") +make_colors("#da997b", ".token.pink") +make_colors("#bbb079", ".token.brown") +make_colors("#a6a6a8", ".token.gray") diff --git a/tools/gentextures.sh b/tools/gentextures.sh new file mode 100644 index 0000000..b9eabb9 --- /dev/null +++ b/tools/gentextures.sh @@ -0,0 +1,4 @@ +#!/bin/bash +pngtopnm tools/rock_overlay@2x.png | pnmnorm | pgmtoppm "#000000-#111111" | ppmquant 2 | pnmtopng > tools/texture_mask.png +convert tools/texture_mask.png -alpha copy -fx '#fff' images/texture.png +zopflipng -m -y images/texture.png images/texture.png diff --git a/tools/parse-layout.js b/tools/parse-layout.js new file mode 100644 index 0000000..5dcf4f8 --- /dev/null +++ b/tools/parse-layout.js @@ -0,0 +1,167 @@ +const fs = require("fs") + +const { round, floor, ceil } = Math + +let boxes = {} +let nodes = [] +let edges = [] +let mode, name, x, y, w, h, cx, cy, rx, ry, x2, y2 +let scale = 1 + +function flush() { + if (mode === 'path') { + edges.push({ x1: x, y1: y, x2, y2 }) + } + if (mode === 'rect') { + boxes[name] = [ x * scale |0, y * scale |0, w * scale |0, h * scale |0 ] + nodes.push({ name, x: x + w/2, y: y + h/2 }) + } + if (mode === 'circle') { + x = cx - rx + y = cy - ry + w = rx * 2 + h = ry * 2 + boxes[name] = [ x * scale |0, y * scale |0, w * scale |0, h * scale |0 ] + nodes.push({ name, x: cx, y: cy }) + } + x = y = x2 = y2 = w = h = cx = cy = rx = ry = 0 + name = null +} + +function parse_path_data(path) { + let cx = 0 + let cy = 0 + let abs = 0 + for (let i = 0; i < path.length;) { + switch (path[i]) { + case 'M': + x = cx = Number(path[i+1]) + y = cy = Number(path[i+2]) + i += 3 + abs = true + break + case 'm': + x = cx = cx + Number(path[i+1]) + y = cy = cy + Number(path[i+2]) + i += 3 + abs = false + break + case 'C': + x2 = cx = Number(path[i+5]) + y2 = cy = Number(path[i+6]) + i += 7 + abs = true + break + case 'L': + i += 1 + abs = true + break + case 'H': + x2 = cx = Number(path[i+1]) + i += 2 + abs = true + break + case 'V': + y2 = cy = Number(path[i+1]) + i += 2 + abs = true + break + case 'c': + x2 = cx = cx + Number(path[i+5]) + y2 = cy = cy + Number(path[i+6]) + i += 7 + break + case 'l': + i += 1 + abs = false + break + case 'h': + x2 = cx = cx + Number(path[i+1]) + i += 2 + abs = false + break + case 'v': + y2 = cy = cy + Number(path[i+1]) + i += 2 + abs = false + break + default: + if (abs) { + x2 = cx = Number(path[i+0]) + y2 = cy = Number(path[i+1]) + } else { + x2 = cx = cx + Number(path[i+0]) + y2 = cy = cy + Number(path[i+1]) + } + i += 2 + break + } + } +} + +for (let line of fs.readFileSync("tools/layout.svg", "utf-8").split("\n")) { + line = line.trim() + if (line.startsWith("