diff options
author | Tor Andersson <tor@ccxvii.net> | 2023-06-22 22:50:57 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2023-07-07 18:39:37 +0200 |
commit | fcfed0cab586ecf3e2e6803e27f7cb0b38cb0898 (patch) | |
tree | 81b7f834e61c3c9b9848f2e20f8c94689febe3c2 | |
parent | 5b91837ae8c298ca0110854c48a1bf2fb6bea69a (diff) | |
download | time-of-crisis-fcfed0cab586ecf3e2e6803e27f7cb0b38cb0898.tar.gz |
Pretender (part 1).
Create, display, and gain legacy.
Also renumber cards.
-rw-r--r-- | play.css | 33 | ||||
-rw-r--r-- | play.html | 13 | ||||
-rw-r--r-- | play.js | 137 | ||||
-rw-r--r-- | rules.js | 283 | ||||
-rw-r--r-- | tools/gencards.js | 52 |
5 files changed, 376 insertions, 142 deletions
@@ -182,7 +182,6 @@ body.military svg .sea.action { .capital.action { display: block; border: 5px solid white; - background-color: #fff8; box-shadow: 0 0 6px white, inset 0 0 6px black; z-index: 2; } @@ -435,6 +434,7 @@ body.p2 #Galatia_NPG { display: block } transform: translate(0px, 0px); } +#played .influence_m1, #played .influence_s1, #played .influence_p1, .card.used { filter: brightness(75%) } @@ -480,6 +480,16 @@ body.p2 #Galatia_NPG { display: block } .card.influence_s2{background-image:url(cards.1x/influence_s2.jpg)} .card.influence_s3{background-image:url(cards.1x/influence_s3.jpg)} .card.influence_s4{background-image:url(cards.1x/influence_s4.jpg)} +.card.influence_s4b{background-image:url(cards.1x/influence_s4b.jpg)} +.card.influence_m2x{background-image:url(cards.1x/influence_m2x.jpg)} +.card.influence_m3x{background-image:url(cards.1x/influence_m3x.jpg)} +.card.influence_m4x{background-image:url(cards.1x/influence_m4x.jpg)} +.card.influence_p2x{background-image:url(cards.1x/influence_p2x.jpg)} +.card.influence_p3x{background-image:url(cards.1x/influence_p3x.jpg)} +.card.influence_p4x{background-image:url(cards.1x/influence_p4x.jpg)} +.card.influence_s2x{background-image:url(cards.1x/influence_s2x.jpg)} +.card.influence_s3x{background-image:url(cards.1x/influence_s3x.jpg)} +.card.influence_s4x{background-image:url(cards.1x/influence_s4x.jpg)} @media (min-resolution:97dpi) { .card.event_back{background-image:url(cards.2x/event_back.jpg)} @@ -511,22 +521,21 @@ body.p2 #Galatia_NPG { display: block } .card.influence_s2{background-image:url(cards.2x/influence_s2.jpg)} .card.influence_s3{background-image:url(cards.2x/influence_s3.jpg)} .card.influence_s4{background-image:url(cards.2x/influence_s4.jpg)} +.card.influence_s4b{background-image:url(cards.2x/influence_s4b.jpg)} +.card.influence_m2x{background-image:url(cards.2x/influence_m2x.jpg)} +.card.influence_m3x{background-image:url(cards.2x/influence_m3x.jpg)} +.card.influence_m4x{background-image:url(cards.2x/influence_m4x.jpg)} +.card.influence_p2x{background-image:url(cards.2x/influence_p2x.jpg)} +.card.influence_p3x{background-image:url(cards.2x/influence_p3x.jpg)} +.card.influence_p4x{background-image:url(cards.2x/influence_p4x.jpg)} +.card.influence_s2x{background-image:url(cards.2x/influence_s2x.jpg)} +.card.influence_s3x{background-image:url(cards.2x/influence_s3x.jpg)} +.card.influence_s4x{background-image:url(cards.2x/influence_s4x.jpg)} } .influence_m1 + .influence_m1 { margin-left: -180px; } .influence_p1 + .influence_p1 { margin-left: -180px; } .influence_s1 + .influence_s1 { margin-left: -180px; } -/* -.influence_m2 + .influence_m2 { margin-left: -180px; } -.influence_p2 + .influence_p2 { margin-left: -180px; } -.influence_s2 + .influence_s2 { margin-left: -180px; } -.influence_m3 + .influence_m3 { margin-left: -180px; } -.influence_p3 + .influence_p3 { margin-left: -180px; } -.influence_s3 + .influence_s3 { margin-left: -180px; } -.influence_m4 + .influence_m4 { margin-left: -180px; } -.influence_p4 + .influence_p4 { margin-left: -180px; } -.influence_s4 + .influence_s4 { margin-left: -180px; } -*/ #played .influence_m1 + .influence_p1 { margin-left: -180px } #played .influence_m1 + .influence_s1 { margin-left: -180px } @@ -106,19 +106,6 @@ <div id="Syria_Capital" class="capital" style="left:2173px;top:1192px"></div> <div id="Thracia_Capital" class="capital" style="left:1593px;top:630px"></div> -<div id="Italia_Quaestor" class="quaestor hide" style="left:971px;top:829px"></div> -<div id="Aegyptus_Quaestor" class="quaestor hide" style="left:1643px;top:1462px"></div> -<div id="Africa_Quaestor" class="quaestor hide" style="left:590px;top:1284px"></div> -<div id="Asia_Quaestor" class="quaestor hide" style="left:1622px;top:994px"></div> -<div id="Britannia_Quaestor" class="quaestor hide" style="left:174px;top:254px"></div> -<div id="Galatia_Quaestor" class="quaestor hide" style="left:1897px;top:925px"></div> -<div id="Gallia_Quaestor" class="quaestor hide" style="left:403px;top:501px"></div> -<div id="Hispania_Quaestor" class="quaestor hide" style="left:97px;top:974px"></div> -<div id="Macedonia_Quaestor" class="quaestor hide" style="left:1327px;top:930px"></div> -<div id="Pannonia_Quaestor" class="quaestor hide" style="left:1097px;top:620px"></div> -<div id="Syria_Quaestor" class="quaestor hide" style="left:1977px;top:1274px"></div> -<div id="Thracia_Quaestor" class="quaestor hide" style="left:1445px;top:714px"></div> - <div id="Aegyptus_NPG" class="no_place_governor" style="left:1793px;top:1380px"></div> <div id="Africa_NPG" class="no_place_governor" style="left:741px;top:1204px"></div> <div id="Britannia_NPG" class="no_place_governor" style="left:325px;top:177px"></div> @@ -5,6 +5,63 @@ // === SYNC with rules.js === +const CARD_M1 = [ 0, 11 ] +const CARD_S1 = [ 12, 23 ] +const CARD_P1 = [ 24, 35 ] +const CARD_M2 = [ 36, 44 ] +const CARD_S2 = [ 45, 53 ] +const CARD_P2 = [ 54, 62 ] +const CARD_M2X = [ 63, 71 ] +const CARD_S2X = [ 72, 80 ] +const CARD_P2X = [ 81, 89 ] +const CARD_M3 = [ 90, 97 ] +const CARD_S3 = [ 98, 105 ] +const CARD_P3 = [ 106, 113 ] +const CARD_M3X = [ 114, 121 ] +const CARD_S3X = [ 122, 129 ] +const CARD_P3X = [ 130, 137 ] +const CARD_M4 = [ 138, 143 ] +const CARD_S4 = [ 144, 149 ] +const CARD_S4B = [ 150, 155 ] +const CARD_P4 = [ 156, 161 ] +const CARD_M4X = [ 162, 167 ] +const CARD_S4X = [ 168, 173 ] +const CARD_P4X = [ 174, 179 ] + +const CARD_INDEX = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 20, 20, + 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, +] + +const CARD_INFO = [ + { name: "M1", type: 0, cost: 1, event: "None" }, + { name: "S1", type: 1, cost: 1, event: "None" }, + { name: "P1", type: 2, cost: 1, event: "None" }, + { name: "M2", type: 0, cost: 2, event: "Castra" }, + { name: "S2", type: 1, cost: 2, event: "Tribute" }, + { name: "P2", type: 2, cost: 2, event: "Quaestor" }, + { name: "M2X", type: 0, cost: 2, event: "Cavalry" }, + { name: "S2X", type: 1, cost: 2, event: "Princeps Senatus" }, + { name: "P2X", type: 2, cost: 2, event: "Ambitus" }, + { name: "M3", type: 0, cost: 3, event: "Flanking Maneuver" }, + { name: "S3", type: 1, cost: 3, event: "Foederati" }, + { name: "P3", type: 2, cost: 3, event: "Mob" }, + { name: "M3X", type: 0, cost: 3, event: "Force March" }, + { name: "S3X", type: 1, cost: 3, event: "Frumentarii" }, + { name: "P3X", type: 2, cost: 3, event: "Mobile Vulgus" }, + { name: "M4", type: 0, cost: 4, event: "Praetorian Guard" }, + { name: "S4", type: 1, cost: 4, event: "Damnatio Memoriae" }, + { name: "S4B", type: 1, cost: 4, event: "Damnatio Memoriae (exp)" }, + { name: "P4", type: 2, cost: 4, event: "Pretender" }, + { name: "M4X", type: 0, cost: 4, event: "Spiculum" }, + { name: "S4X", type: 1, cost: 4, event: "Triumph" }, + { name: "P4X", type: 2, cost: 4, event: "Demagogue" }, +] + const ITALIA = 0 const ASIA = 1 const GALLIA = 2 @@ -129,6 +186,16 @@ function is_breakaway(province) { function is_seat_of_power(province) { return view.seat_of_power & (1 << province) } +function find_governor(f) { + let n = view.legacy.length * 6 + for (let id = 0; id < n; ++id) + if (f(id, get_governor_location(id))) + return id + return -1 +} +function get_province_governor(where) { + return find_governor((id, loc) => loc === where) +} // === END SYNC === @@ -227,6 +294,21 @@ const LAYOUT_SUPPORT = [ BOXES["Syria Support"], ] +const LAYOUT_QUAESTOR = [ + [ 971, 829 ], + [ 1622, 994 ], + [ 403, 501 ], + [ 1327, 930 ], + [ 1097, 620 ], + [ 1445, 714 ], + [ 1643, 1462 ], + [ 590, 1284 ], + [ 97, 974 ], + [ 174, 254 ], + [ 1897, 925 ], + [ 1977, 1274 ], +] + const LAYOUT_SEA = [ [ 0, 0 ] ] const LAYOUT_HOMELAND = [ @@ -529,6 +611,8 @@ let ui = { neutral_governors: [], barbarian_leaders: [], rival_emperors: [], + seat_of_power: [], + breakaway: [], legions: [], barbarians: [ [], [], [], [], [] ], generals: [ [], [], [], [] ], @@ -629,29 +713,25 @@ function is_action(action, arg) { } function on_init() { - let c = 1 - function init_cards(n, className) { - for (let i = 0; i < n; ++i) - ui.cards[c + i] = create("div", { className, my_action: "card", my_id: c + i }) - c += n + for (let c = 0; c < CARD_INDEX.length; ++c) { + let name = CARD_INFO[CARD_INDEX[c]].name + ui.cards[c] = create("div", { className: "card influence_" + name.toLowerCase(), my_action: "card", my_id: c }) } - init_cards(12, "card influence_m1") - init_cards(12, "card influence_s1") - init_cards(12, "card influence_p1") - init_cards(9, "card influence_m2") - init_cards(9, "card influence_s2") - init_cards(9, "card influence_p2") - init_cards(8, "card influence_m3") - init_cards(8, "card influence_s3") - init_cards(8, "card influence_p3") - init_cards(6, "card influence_m4") - init_cards(6, "card influence_s4") - init_cards(6, "card influence_p4") - for (let i = 0; i < 33; ++i) ui.legions[i] = create_piece(i, "legion", "legion", "legion_" + i) + for (let p = 0; p < 4; ++p) { + for (let i = 0; i < 12; ++i) { + ui.seat_of_power[p * 12 + i] = create_thing({ className: PLAYER_CLASS[p] + " seat_of_power hide" }) + ui.seat_of_power[p * 12 + i].style.left = LAYOUT_QUAESTOR[i][0] + "px" + ui.seat_of_power[p * 12 + i].style.top = LAYOUT_QUAESTOR[i][1] + "px" + ui.breakaway[p * 12 + i] = create_thing({ className: PLAYER_CLASS[p] + " breakaway hide" }) + ui.breakaway[p * 12 + i].style.left = LAYOUT_QUAESTOR[i][0] + "px" + ui.breakaway[p * 12 + i].style.top = LAYOUT_QUAESTOR[i][1] + "px" + } + } + ui.barbarian_leaders[0] = create_piece(0, "barbarian_leader", "goths", "cniva") ui.barbarian_leaders[1] = create_piece(1, "barbarian_leader", "sassanids", "ardashir") ui.barbarian_leaders[2] = create_piece(2, "barbarian_leader", "sassanids", "shapur") @@ -676,7 +756,9 @@ function on_init() { ui.mcastra[region] = create_thing({ className: "castra hide" }) ui.militia[region] = create_thing({ className: "militia hide", my_action: "militia", my_id: region }) ui.capital[region] = document.getElementById(REGION_NAME[region] + "_Capital") - ui.quaestor[region] = document.getElementById(REGION_NAME[region] + "_Quaestor") + ui.quaestor[region] = create_thing({ className: "quaestor hide" }) + ui.quaestor[region].style.left = LAYOUT_QUAESTOR[region][0] + "px" + ui.quaestor[region].style.top = LAYOUT_QUAESTOR[region][1] + "px" // at most 3 mobs per province ui.mobs[region * 3 + 0] = create_piece(region, "mob", "mob") @@ -851,6 +933,23 @@ function on_update() { } for (let region = 0; region < 12; ++region) { + for (let p = 0; p < 4; ++p) { + let gov = get_province_governor(region) + if (gov > 0 && (gov/6|0) === p) { + if (is_seat_of_power(region)) + show(ui.seat_of_power[region + p * 12]) + else + hide(ui.seat_of_power[region + p * 12]) + if (is_breakaway(region)) + show(ui.breakaway[region + p * 12]) + else + hide(ui.breakaway[region + p * 12]) + } else { + hide(ui.seat_of_power[region + p * 12]) + hide(ui.breakaway[region + p * 12]) + } + } + if (has_quaestor(region)) show(ui.quaestor[region]) else @@ -316,115 +316,118 @@ const EVENT_INFLATION = 13 const EVENT_GOOD_AUGURIES = 14 const EVENT_DIOCLETIAN = 15 -// 12x -const CARD_M1 = [ 1, 12 ] -const CARD_S1 = [ 13, 24 ] -const CARD_P1 = [ 25, 36 ] - -// 9x -const CARD_M2 = [ 37, 45 ] -const CARD_S2 = [ 46, 54 ] -const CARD_P2 = [ 55, 63 ] - -// 8x -const CARD_M3 = [ 64, 71 ] -const CARD_S3 = [ 72, 79 ] -const CARD_P3 = [ 80, 87 ] - -// 6x -const CARD_M4 = [ 88, 93 ] -const CARD_S4 = [ 94, 99 ] -const CARD_P4 = [ 100, 105 ] +const CARD_M1 = [ 0, 11 ] +const CARD_S1 = [ 12, 23 ] +const CARD_P1 = [ 24, 35 ] +const CARD_M2 = [ 36, 44 ] +const CARD_S2 = [ 45, 53 ] +const CARD_P2 = [ 54, 62 ] +const CARD_M2X = [ 63, 71 ] +const CARD_S2X = [ 72, 80 ] +const CARD_P2X = [ 81, 89 ] +const CARD_M3 = [ 90, 97 ] +const CARD_S3 = [ 98, 105 ] +const CARD_P3 = [ 106, 113 ] +const CARD_M3X = [ 114, 121 ] +const CARD_S3X = [ 122, 129 ] +const CARD_P3X = [ 130, 137 ] +const CARD_M4 = [ 138, 143 ] +const CARD_S4 = [ 144, 149 ] +const CARD_S4B = [ 150, 155 ] +const CARD_P4 = [ 156, 161 ] +const CARD_M4X = [ 162, 167 ] +const CARD_S4X = [ 168, 173 ] +const CARD_P4X = [ 174, 179 ] + +const CARD_INDEX = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 20, 20, + 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, +] + +const CARD_INFO = [ + { name: "M1", type: 0, cost: 1, event: "None" }, + { name: "S1", type: 1, cost: 1, event: "None" }, + { name: "P1", type: 2, cost: 1, event: "None" }, + { name: "M2", type: 0, cost: 2, event: "Castra" }, + { name: "S2", type: 1, cost: 2, event: "Tribute" }, + { name: "P2", type: 2, cost: 2, event: "Quaestor" }, + { name: "M2X", type: 0, cost: 2, event: "Cavalry" }, + { name: "S2X", type: 1, cost: 2, event: "Princeps Senatus" }, + { name: "P2X", type: 2, cost: 2, event: "Ambitus" }, + { name: "M3", type: 0, cost: 3, event: "Flanking Maneuver" }, + { name: "S3", type: 1, cost: 3, event: "Foederati" }, + { name: "P3", type: 2, cost: 3, event: "Mob" }, + { name: "M3X", type: 0, cost: 3, event: "Force March" }, + { name: "S3X", type: 1, cost: 3, event: "Frumentarii" }, + { name: "P3X", type: 2, cost: 3, event: "Mobile Vulgus" }, + { name: "M4", type: 0, cost: 4, event: "Praetorian Guard" }, + { name: "S4", type: 1, cost: 4, event: "Damnatio Memoriae" }, + { name: "S4B", type: 1, cost: 4, event: "Damnatio Memoriae (exp)" }, + { name: "P4", type: 2, cost: 4, event: "Pretender" }, + { name: "M4X", type: 0, cost: 4, event: "Spiculum" }, + { name: "S4X", type: 1, cost: 4, event: "Triumph" }, + { name: "P4X", type: 2, cost: 4, event: "Demagogue" }, +] function card_name(c) { - if (c >= CARD_M1[0] && c <= CARD_M1[1]) return "M1" - if (c >= CARD_M2[0] && c <= CARD_M2[1]) return "M2" - if (c >= CARD_M3[0] && c <= CARD_M3[1]) return "M3" - if (c >= CARD_M4[0] && c <= CARD_M4[1]) return "M4" - if (c >= CARD_S1[0] && c <= CARD_S1[1]) return "S1" - if (c >= CARD_S2[0] && c <= CARD_S2[1]) return "S2" - if (c >= CARD_S3[0] && c <= CARD_S3[1]) return "S3" - if (c >= CARD_S4[0] && c <= CARD_S4[1]) return "S4" - if (c >= CARD_P1[0] && c <= CARD_P1[1]) return "P1" - if (c >= CARD_P2[0] && c <= CARD_P2[1]) return "P2" - if (c >= CARD_P3[0] && c <= CARD_P3[1]) return "P3" - if (c >= CARD_P4[0] && c <= CARD_P4[1]) return "P4" - return "??" + return CARD_INFO[CARD_INDEX[c]].name } function card_cost(c) { - if (c >= CARD_M1[0] && c <= CARD_M1[1]) return 1 - if (c >= CARD_M2[0] && c <= CARD_M2[1]) return 2 - if (c >= CARD_M3[0] && c <= CARD_M3[1]) return 3 - if (c >= CARD_M4[0] && c <= CARD_M4[1]) return 4 - if (c >= CARD_S1[0] && c <= CARD_S1[1]) return 1 - if (c >= CARD_S2[0] && c <= CARD_S2[1]) return 2 - if (c >= CARD_S3[0] && c <= CARD_S3[1]) return 3 - if (c >= CARD_S4[0] && c <= CARD_S4[1]) return 4 - if (c >= CARD_P1[0] && c <= CARD_P1[1]) return 1 - if (c >= CARD_P2[0] && c <= CARD_P2[1]) return 2 - if (c >= CARD_P3[0] && c <= CARD_P3[1]) return 3 - if (c >= CARD_P4[0] && c <= CARD_P4[1]) return 4 - return "??" + return CARD_INFO[CARD_INDEX[c]].cost +} + +function card_influence(c) { + return CARD_INFO[CARD_INDEX[c]].type } function card_event_name(c) { - if (c >= CARD_M1[0] && c <= CARD_M1[1]) return "None" - if (c >= CARD_M2[0] && c <= CARD_M2[1]) return "Castra" - if (c >= CARD_M3[0] && c <= CARD_M3[1]) return "Flanking Maneuver" - if (c >= CARD_M4[0] && c <= CARD_M4[1]) return "Praetorian Guard" - if (c >= CARD_S1[0] && c <= CARD_S1[1]) return "None" - if (c >= CARD_S2[0] && c <= CARD_S2[1]) return "Tribute" - if (c >= CARD_S3[0] && c <= CARD_S3[1]) return "Foederati" - if (c >= CARD_S4[0] && c <= CARD_S4[1]) return "Damnatio Memoriae" - if (c >= CARD_P1[0] && c <= CARD_P1[1]) return "None" - if (c >= CARD_P2[0] && c <= CARD_P2[1]) return "Quaestor" - if (c >= CARD_P3[0] && c <= CARD_P3[1]) return "Mob" - if (c >= CARD_P4[0] && c <= CARD_P4[1]) return "Pretender" - return "None" + return CARD_INFO[CARD_INDEX[c]].event +} + +const PLAY_CARD_EVENT = { + "Castra": play_castra, + // "Flanking Maneuver": play_flanking_maneuver, + "Praetorian Guard": play_praetorian_guard, + "Tribute": play_tribute, + "Foederati": play_foederati, + // "Damnatio Memoriae": play_damnatio_memoriae, + // "Damnatio Memoriae (exp)": play_damnatio_memoriae_exp, + "Quaestor": play_quaestor, + "Mob": play_mob, + "Pretender": play_pretender, +} + +const CAN_PLAY_CARD_EVENT = { + "Castra": can_play_castra, + // "Flanking Maneuver": can_play_flanking_maneuver, + "Praetorian Guard": can_play_praetorian_guard, + "Tribute": can_play_tribute, + "Foederati": can_play_foederati, + // "Damnatio Memoriae": can_play_damnatio_memoriae, + // "Damnatio Memoriae (exp)": can_play_damnatio_memoriae_exp, + "Quaestor": can_play_quaestor, + "Mob": can_play_mob, + "Pretender": can_play_pretender, } function can_play_card_event(c) { - if (c >= CARD_M1[0] && c <= CARD_M1[1]) return false - if (c >= CARD_M2[0] && c <= CARD_M2[1]) return can_play_castra() - if (c >= CARD_M3[0] && c <= CARD_M3[1]) return false // "Flanking Maneuver" - if (c >= CARD_M4[0] && c <= CARD_M4[1]) return can_play_praetorian_guard() - if (c >= CARD_S1[0] && c <= CARD_S1[1]) return false - if (c >= CARD_S2[0] && c <= CARD_S2[1]) return can_play_tribute() - if (c >= CARD_S3[0] && c <= CARD_S3[1]) return can_play_foederati() - if (c >= CARD_S4[0] && c <= CARD_S4[1]) return false // "Damnatio Memoriae" - if (c >= CARD_P1[0] && c <= CARD_P1[1]) return false - if (c >= CARD_P2[0] && c <= CARD_P2[1]) return can_play_quaestor() - if (c >= CARD_P3[0] && c <= CARD_P3[1]) return can_play_mob() - if (c >= CARD_P4[0] && c <= CARD_P4[1]) return false // "Pretender" - return false + let f = CAN_PLAY_CARD_EVENT[card_event_name(c)] + return f ? f() : false } function play_card_event(c) { - if (c >= CARD_M2[0] && c <= CARD_M2[1]) play_castra() - if (c >= CARD_M3[0] && c <= CARD_M3[1]) play_flanking_maneuver() - if (c >= CARD_M4[0] && c <= CARD_M4[1]) play_praetorian_guard() - if (c >= CARD_S2[0] && c <= CARD_S2[1]) play_tribute() - if (c >= CARD_S3[0] && c <= CARD_S3[1]) play_foederati() - if (c >= CARD_S4[0] && c <= CARD_S4[1]) play_damnatio_memoriae() - if (c >= CARD_P2[0] && c <= CARD_P2[1]) play_quaestor() - if (c >= CARD_P3[0] && c <= CARD_P3[1]) play_mob() - if (c >= CARD_P4[0] && c <= CARD_P4[1]) play_pretender() + PLAY_CARD_EVENT[card_event_name(c)]() } function add_card_ip(c) { - if (c >= CARD_M1[0] && c <= CARD_M1[1]) return game.ip[MILITARY] += 1 - if (c >= CARD_M2[0] && c <= CARD_M2[1]) return game.ip[MILITARY] += 2 - if (c >= CARD_M3[0] && c <= CARD_M3[1]) return game.ip[MILITARY] += 3 - if (c >= CARD_M4[0] && c <= CARD_M4[1]) return game.ip[MILITARY] += 4 - if (c >= CARD_S1[0] && c <= CARD_S1[1]) return game.ip[SENATE] += 1 - if (c >= CARD_S2[0] && c <= CARD_S2[1]) return game.ip[SENATE] += 2 - if (c >= CARD_S3[0] && c <= CARD_S3[1]) return game.ip[SENATE] += 3 - if (c >= CARD_S4[0] && c <= CARD_S4[1]) return game.ip[SENATE] += 4 - if (c >= CARD_P1[0] && c <= CARD_P1[1]) return game.ip[POPULACE] += 1 - if (c >= CARD_P2[0] && c <= CARD_P2[1]) return game.ip[POPULACE] += 2 - if (c >= CARD_P3[0] && c <= CARD_P3[1]) return game.ip[POPULACE] += 3 - if (c >= CARD_P4[0] && c <= CARD_P4[1]) return game.ip[POPULACE] += 4 + let cost = CARD_INFO[CARD_INDEX[c]].cost + let type = CARD_INFO[CARD_INDEX[c]].type + game.ip[type] += cost } function is_region(where) { @@ -1955,7 +1958,7 @@ function play_castra() { function can_play_quaestor() { let where = get_selected_region() if (game.selected_governor >= 0 && is_province(where)) - return !has_quaestor(where) + return !has_quaestor(where) && !is_breakaway(where) && !is_seat_of_power(where) return false } @@ -2100,6 +2103,85 @@ states.mob = { }, } +// CARD: PRETENDER + +function find_seat_of_power() { + for (let where = 1; where < 12; ++where) + if (is_seat_of_power(where) && is_own_province(where)) + return where + return -1 +} + +function is_possible_seat_of_power(from) { + if (is_own_province(from) && get_support(from) >= 3) + for (let to of ADJACENT[from]) + if (is_own_province(to) && get_support(to) >= 3) + return true + return false +} + +function can_play_pretender() { + if (is_emperor_player()) + return false + if (is_pretender_player()) + return false + for (let where = 1; where < 12; ++where) + if (is_possible_seat_of_power(where)) + return true + return false +} + +function play_pretender() { + game.state = "pretender_seat_of_power" +} + +states.pretender_seat_of_power = { + prompt() { + prompt("Pretender: Place a Seat of Power.") + view.color = POPULACE + for (let where = 0; where < 12; ++where) + for (let where = 1; where < 12; ++where) + if (is_possible_seat_of_power(where)) + gen_action_region(where) + }, + region(where) { + push_undo() + log("Seat of Power in S" + where) + add_seat_of_power(where) + remove_quaestor(where) // no effect anymore + goto_pretender_breakaway() + }, +} + +function goto_pretender_breakaway() { + let seat = find_seat_of_power() + for (let where of ADJACENT[seat]) { + if (get_support(where) >= 3 && !is_breakaway(where) && is_own_province(where)) { + game.state = "pretender_breakaway" + return + } + } + game.state = "take_actions" +} + +states.pretender_breakaway = { + prompt() { + prompt("Pretender: Place Breakaway markers.") + view.color = POPULACE + let seat = find_seat_of_power() + for (let where of ADJACENT[seat]) + if (get_support(where) >= 3 && !is_breakaway(where) && is_own_province(where)) + gen_action_region(where) + }, + region(where) { + push_undo() + log("Breakaway in S" + where) + add_breakaway(where) + remove_quaestor(where) // no effect anymore + goto_pretender_breakaway() + }, +} + // === COMBAT === function goto_battle_vs_general(where, attacker, target) { @@ -2505,7 +2587,10 @@ function goto_combat_victory() { } function award_legacy(p, reason, n) { - log(PLAYER_NAMES[p] + " gained " + n + " Legacy for " + reason + ".") + if (n > 0) + log(PLAYER_NAMES[p] + " gained " + n + " Legacy for " + reason + ".") + if (n < 0) + log(PLAYER_NAMES[p] + " lost " + n + " Legacy for " + reason + ".") game.legacy[p] += n } @@ -2680,7 +2765,7 @@ function goto_expand_pretender_empire() { function goto_gain_legacy() { log_h3("Gain Legacy") - if (is_only_pretender()) + if (is_only_pretender_player()) award_legacy(game.current, "Pretender", count_own_breakaway_provinces()) if (is_emperor_player()) @@ -2699,8 +2784,8 @@ function goto_legitimize_claim() { states.legitimize_claim = { prompt() { prompt("Gain Legacy: Remove Seat of Power and Breakaway markers in your provinces.") - for (let where = 1; where < 12; ++where) { - if (is_own_province(where) && is_seat_of_power(where) || is_breakaway(where)) { + for (let where = 1; where < 12; ++where) + if (is_own_province(where) && is_seat_of_power(where) || is_breakaway(where)) gen_action_region(where) }, region(where) { @@ -3151,7 +3236,7 @@ exports.setup = function (seed, scenario, options) { game.hand[player] = [] game.draw[player] = setup_player_deck(player) game.discard[player] = [] - game.draw[player].push(game.market[2].pop()) + for (let i = 0; i < 9; ++i) set_add(game.draw[player], game.market[i].pop()) } update_neutral_italia() @@ -3216,6 +3301,8 @@ exports.view = function (state, player_name) { amphitheater: game.amphitheater, basilica: game.basilica, limes: game.limes, + seat_of_power: game.seat_of_power, + breakaway: game.breakaway, governors: game.governors, generals: game.generals, diff --git a/tools/gencards.js b/tools/gencards.js new file mode 100644 index 0000000..ee88c70 --- /dev/null +++ b/tools/gencards.js @@ -0,0 +1,52 @@ +var ix = 0 +var xx = 0 + +const M = 0 +const S = 1 +const P = 2 + +const CARD_INDEX = [] +const CARD_INFO = [] + +function mk(n, type, cost, name, event) { + CARD_INFO[xx] = { name, type, cost, event } + var a = ix + var b = ix + n - 1 + for (let i = 0; i < n; ++i) + CARD_INDEX[a + i] = xx + console.log("const CARD_" + name + " = [ " + a + ", " + b + " ]") + ix = b + 1 + xx += 1 +} + +mk(12, M, 1, "M1", "None") +mk(12, S, 1, "S1", "None") +mk(12, P, 1, "P1", "None") + +mk(9, M, 2, "M2", "Castra") +mk(9, S, 2, "S2", "Tribute") +mk(9, P, 2, "P2", "Quaestor") + +mk(9, M, 2, "M2X", "Cavalry") +mk(9, S, 2, "S2X", "Princeps Senatus") +mk(9, P, 2, "P2X", "Ambitus") + +mk(8, M, 3, "M3", "Flanking Maneuver") +mk(8, S, 3, "S3", "Foederati") +mk(8, P, 3, "P3", "Mob") + +mk(8, M, 3, "M3X", "Force March") +mk(8, S, 3, "S3X", "Frumentarii") +mk(8, P, 3, "P3X", "Mobile Vulgus") + +mk(6, M, 4, "M4", "Praetorian Guard") +mk(6, S, 4, "S4", "Damnatio Memoriae") +mk(6, S, 4, "S4B", "Damnatio Memoriae (exp)") +mk(6, P, 4, "P4", "Pretender") + +mk(6, M, 4, "M4X", "Spiculum") +mk(6, S, 4, "S4X", "Triumph") +mk(6, P, 4, "P4X", "Demagogue") + +console.log("const CARD_INDEX = " + JSON.stringify(CARD_INDEX)) +console.log("const CARD_INFO = " + JSON.stringify(CARD_INFO)) |