From 3a41d017ad2a16302f6159228d887defc09f9536 Mon Sep 17 00:00:00 2001 From: iainp5 Date: Fri, 16 Aug 2024 08:38:55 +0100 Subject: Update rules.js all events and debugging --- rules.js | 7027 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 6124 insertions(+), 903 deletions(-) diff --git a/rules.js b/rules.js index 90dab53..abe0a25 100644 --- a/rules.js +++ b/rules.js @@ -1,7 +1,13 @@ //"use strict" -const { finished } = require("nodemailer/lib/xoauth2/index.js") -const data = require("./data.js") +const { getMaxListeners } = require("ws") + +const { spaces, cards, power_cards } = require("./data.js") +const { resolveContent } = require("nodemailer/lib/shared/index.js") +const { pipeline, PassThrough } = require("nodemailer/lib/xoauth2/index.js") +const e = require("express") +const { getTestMessageUrl } = require("nodemailer") + var game, view, states = {} @@ -13,269 +19,22 @@ const last_strategy_card = 110 const dem_tst_req = [5, 5, 6, 6, 7, 8, 9, 10] const com_tst_req = [6, 6, 7, 7, 8, 7, 6, 5] -const scoring_cards = [17, 18, 19, 21, 22, 23] +const scoring_cards = [22, 23, 42, 43, 55, 95] +const leader_cards = [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48] const leaders = [1, 4, 5, 6, 7] const support_loss_roll = [0, 0, 1, 1, 2, 2, 3, 4] const vp_roll = [0, 0, 1, 1, 2, 2, 3, 4] -const countries = ['East Germany', 'Poland', 'Czechoslovakia', 'Hungary', 'Romania', 'Bulgaria'] +const countries = ['Poland', 'Hungary', 'East_Germany', 'Bulgaria', 'Czechoslovakia', 'Romania'] +const elite_spaces = [12, 15, 27, 43, 51, 69] const all_power_cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52 ] - -const spaces = [ -{name: 'Schwerin', name_unique: 'Schwerin', space_id: 1, socio: 4, stability: 3, battleground: 0, country: 'East Germany', box: {x: 111, y: 61, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [2, 3, , , ]}, -{name: 'Rostock', name_unique: 'Rostock', space_id: 2, socio: 4, stability: 3, battleground: 0, country: 'East Germany', box: {x: 228, y: 41, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [1, 3, , , ]}, -{name: 'Berlin', name_unique: 'Berlin', space_id: 3, socio: 2, stability: 3, battleground: 1, country: 'East Germany', box: {x: 251, y: 113, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [1, 2, 5, 9, ]}, -{name: 'German Writers', name_unique: 'German Writers', space_id: 4, socio: 5, stability: 2, battleground: 0, country: 'East Germany', box: {x: 58, y: 185, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [5, , , , ]}, -{name: 'Walter Ulbricht Academy', name_unique: 'Walter Ulbricht Academy', space_id: 5, socio: 6, stability: 1, battleground: 0, country: 'East Germany', box: {x: 175, y: 187, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [3, 4, , , ]}, -{name: 'Lutherian Church', name_unique: 'Lutherian Church', space_id: 6, socio: 7, stability: 5, battleground: 1, country: 'East Germany', box: {x: 300, y: 212, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [9, , , , ]}, -{name: 'Magdeburg', name_unique: 'Magdeburg', space_id: 7, socio: 4, stability: 3, battleground: 1, country: 'East Germany', box: {x: 58, y: 275, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [8, 10, 11, , ]}, -{name: 'Halle', name_unique: 'Halle', space_id: 8, socio: 4, stability: 3, battleground: 0, country: 'East Germany', box: {x: 175, y: 278, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [7, 10, 11, , ]}, -{name: 'Leipzig', name_unique: 'Leipzig', space_id: 9, socio: 4, stability: 3, battleground: 1, country: 'East Germany', box: {x: 297, y: 297, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [3, 6, 8, 11, 12]}, -{name: 'Erfurt', name_unique: 'Erfurt', space_id: 10, socio: 3, stability: 4, battleground: 0, country: 'East Germany', box: {x: 23, y: 356, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [7, , , , ]}, -{name: 'Karl-Marx-Stadt', name_unique: 'Karl-Marx-Stadt', space_id: 11, socio: 4, stability: 3, battleground: 1, country: 'East Germany', box: {x: 138, y: 385, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [7, 8, 9, 12, ]}, -{name: 'Dresden', name_unique: 'Dresden', space_id: 12, socio: 1, stability: 4, battleground: 1, country: 'East Germany', box: {x: 262, y: 375, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [9, 11, 19, 27, ]}, -{name: 'Szczecin', name_unique: 'Szczecin', space_id: 13, socio: 4, stability: 3, battleground: 0, country: 'Poland', box: {x: 434, y: 204, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [14, 16, , , ]}, -{name: 'Gdansk', name_unique: 'Gdansk', space_id: 14, socio: 4, stability: 3, battleground: 1, country: 'Poland', box: {x: 699, y: 215, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [13, 15, 16, 17, 18]}, -{name: 'Bydgoszcz', name_unique: 'Bydgoszcz', space_id: 15, socio: 1, stability: 4, battleground: 0, country: 'Poland', box: {x: 679, y: 304, h: 65, w: 105}, demInfl: 0, comInfl: 1, demCtrl: 0, comCtrl: 0, adjacent: [15, 17, , , ]}, -{name: 'Poznan', name_unique: 'Poznan', space_id: 16, socio: 4, stability: 3, battleground: 1, country: 'Poland', box: {x: 521, y: 355, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [13, 14, 19, 20, ]}, -{name: 'Warszawa', name_unique: 'Warszawa', space_id: 17, socio: 2, stability: 3, battleground: 1, country: 'Poland', box: {x: 806, y: 383, h: 65, w: 105}, demInfl: 0, comInfl: 1, demCtrl: 0, comCtrl: 0, adjacent: [14, 15, 18, 21, 24]}, -{name: 'Bialystok', name_unique: 'Bialystok', space_id: 18, socio: 3, stability: 4, battleground: 0, country: 'Poland', box: {x: 940, y: 342, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [14, 17, 24, , ]}, -{name: 'Wroclaw', name_unique: 'Wroclaw', space_id: 19, socio: 4, stability: 3, battleground: 1, country: 'Poland', box: {x: 462, y: 443, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [12, 16, 20, 22, ]}, -{name: 'Catholic Church', name_unique: 'Catholic Church Poland', space_id: 20, socio: 7, stability: 5, battleground: 0, country: 'Poland', box: {x: 625, y: 437, h: 65, w: 105}, demInfl: 5, comInfl: 0, demCtrl: 1, comCtrl: 0, adjacent: [16, 19, 21, 22, 23]}, -{name: 'Lodz', name_unique: 'Lodz', space_id: 21, socio: 4, stability: 3, battleground: 1, country: 'Poland', box: {x: 749, y: 486, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [17, 20, 23, 24, ]}, -{name: 'Katowice', name_unique: 'Katowice', space_id: 22, socio: 4, stability: 3, battleground: 0, country: 'Poland', box: {x: 570, y: 569, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [19, 20, 21, 33, ]}, -{name: 'Krakow', name_unique: 'Krakow', space_id: 23, socio: 4, stability: 3, battleground: 1, country: 'Poland', box: {x: 711, y: 598, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [20, 21, 23, 25, ]}, -{name: 'Lublin', name_unique: 'Lublin', space_id: 24, socio: 3, stability: 4, battleground: 0, country: 'Poland', box: {x: 879, y: 603, h: 65, w: 105}, demInfl: 0, comInfl: 1, demCtrl: 0, comCtrl: 0, adjacent: [17, 18, 21, , ]}, -{name: 'Jagiellian University', name_unique: 'Jagiellian University', space_id: 25, socio: 6, stability: 1, battleground: 0, country: 'Poland', box: {x: 679, y: 681, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [23, 26, , , ]}, -{name: 'Polish Writers', name_unique: 'Polish Writers', space_id: 26, socio: 5, stability: 2, battleground: 0, country: 'Poland', box: {x: 832, y: 694, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [25, , , , ]}, -{name: 'Plzen', name_unique: 'Plzen', space_id: 27, socio: 1, stability: 4, battleground: 0, country: 'Czechoslovakia', box: {x: 159, y: 483, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [12, 29, , , ]}, -{name: 'Ceske Budejovice', name_unique: 'Ceske Budejovice', space_id: 28, socio: 3, stability: 3, battleground: 0, country: 'Czechoslovakia', box: {x: 196, y: 601, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [28, 29, , , ]}, -{name: 'Praha', name_unique: 'Praha', space_id: 29, socio: 2, stability: 3, battleground: 1, country: 'Czechoslovakia', box: {x: 317, y: 614, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [27, 28, 30, 32, ]}, -{name: 'Charles University', name_unique: 'Charles University', space_id: 30, socio: 6, stability: 1, battleground: 1, country: 'Czechoslovakia', box: {x: 380, y: 532, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [29, 31, , , ]}, -{name: 'Czech Writers', name_unique: 'Czech Writers', space_id: 31, socio: 5, stability: 2, battleground: 1, country: 'Czechoslovakia', box: {x: 444, y: 607, h: 65, w: 105}, demInfl: 2, comInfl: 0, demCtrl: 1, comCtrl: 0, adjacent: [30, , , , ]}, -{name: 'Brno', name_unique: 'Brno', space_id: 32, socio: 4, stability: 3, battleground: 1, country: 'Czechoslovakia', box: {x: 403, y: 711, h: 65, w: 105}, demInfl: 0, comInfl: 1, demCtrl: 0, comCtrl: 0, adjacent: [29, 33, 34, , ]}, -{name: 'Ostrava', name_unique: 'Ostrava', space_id: 33, socio: 4, stability: 3, battleground: 1, country: 'Czechoslovakia', box: {x: 523, y: 681, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [22, 32, 34, 35, ]}, -{name: 'Bratislava', name_unique: 'Bratislava', space_id: 34, socio: 4, stability: 3, battleground: 1, country: 'Czechoslovakia', box: {x: 417, y: 797, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [32, 33, 35, , ]}, -{name: 'Catholic Church', name_unique: 'Catholic Church Czech', space_id: 35, socio: 7, stability: 5, battleground: 0, country: 'Czechoslovakia', box: {x: 538, y: 794, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [33, 34, 36, , ]}, -{name: 'Presov', name_unique: 'Presov', space_id: 36, socio: 3, stability: 4, battleground: 0, country: 'Czechoslovakia', box: {x: 658, y: 794, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [35, 37, , , ]}, -{name: 'Kosice', name_unique: 'Kosice', space_id: 37, socio: 3, stability: 4, battleground: 0, country: 'Czechoslovakia', box: {x: 777, y: 815, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [36, 42, , , ]}, -{name: 'Catholic Church', name_unique: 'Catholic Church Hungary', space_id: 38, socio: 7, stability: 5, battleground: 0, country: 'Hungary', box: {x: 314, y: 886, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [39, 43, , , ]}, -{name: 'Gyor', name_unique: 'Gyor', space_id: 39, socio: 4, stability: 3, battleground: 0, country: 'Hungary', box: {x: 434, y: 887, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [38, 40, 43, 44, ]}, -{name: 'Tatabanya', name_unique: 'Tatabanya', space_id: 40, socio: 4, stability: 3, battleground: 0, country: 'Hungary', box: {x: 549, y: 886, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [39, 41, 45, , ]}, -{name: 'Miskolc', name_unique: 'Miskolc', space_id: 41, socio: 4, stability: 3, battleground: 1, country: 'Hungary', box: {x: 664, y: 901, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [40, 42, 45, , ]}, -{name: 'Debrecen', name_unique: 'Debrecen', space_id: 42, socio: 4, stability: 3, battleground: 1, country: 'Hungary', box: {x: 781, y: 938, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [37, 41, , , ]}, -{name: 'Szombathely', name_unique: 'Szombathely', space_id: 43, socio: 1, stability: 4, battleground: 0, country: 'Hungary', box: {x: 316, y: 963, h: 65, w: 105}, demInfl: 0, comInfl: 1, demCtrl: 0, comCtrl: 0, adjacent: [38, 39, 44, , ]}, -{name: 'Szekesfehervar', name_unique: 'Szekesfehervar', space_id: 44, socio: 4, stability: 3, battleground: 0, country: 'Hungary', box: {x: 442, y: 962, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [39, 43, 45, , ]}, -{name: 'Budapest', name_unique: 'Budapest', space_id: 45, socio: 2, stability: 3, battleground: 1, country: 'Hungary', box: {x: 630, y: 983, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [41, 42, 44, 47, 48]}, -{name: 'Hungarian Writers', name_unique: 'Hungarian Writers', space_id: 46, socio: 5, stability: 2, battleground: 0, country: 'Hungary', box: {x: 348, y: 1040, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [47, , , , ]}, -{name: 'Eotvos Lorand University', name_unique: 'Eotvos Lorand University', space_id: 47, socio: 6, stability: 1, battleground: 0, country: 'Hungary', box: {x: 512, y: 1034, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [46, 45, , , ]}, -{name: 'Szeged', name_unique: 'Szeged', space_id: 48, socio: 3, stability: 4, battleground: 1, country: 'Hungary', box: {x: 632, y: 1073, h: 65, w: 105}, demInfl: 1, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [45, 49, 50, , ]}, -{name: 'Pecs', name_unique: 'Pecs', space_id: 49, socio: 3, stability: 4, battleground: 1, country: 'Hungary', box: {x: 486, y: 1105, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [48, , , , ]}, -{name: 'Timisoara', name_unique: 'Timisoara', space_id: 50, socio: 4, stability: 3, battleground: 1, country: 'Romania', box: {x: 597, y: 1204, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [48, 51, 60, , ]}, -{name: 'Cluj-Napoca', name_unique: 'Cluj-Napoca', space_id: 51, socio: 1, stability: 4, battleground: 1, country: 'Romania', box: {x: 756, y: 1125, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [50, 54, 58, , ]}, -{name: 'Targu Mures', name_unique: 'Targu Mures', space_id: 52, socio: 3, stability: 4, battleground: 0, country: 'Romania', box: {x: 915, y: 1136, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [53, 56, , , ]}, -{name: 'Iasi', name_unique: 'Iasi', space_id: 53, socio: 4, stability: 3, battleground: 1, country: 'Romania', box: {x: 1072, y: 1097, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [52, 57, 62, , ]}, -{name: 'Babes-Bolyai University', name_unique: 'Babes-Bolyai University', space_id: 54, socio: 6, stability: 1, battleground: 0, country: 'Romania', box: {x: 746, y: 1203, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [51, 55, , , ]}, -{name: 'Romanian Writers', name_unique: 'Romanian Writers', space_id: 55, socio: 5, stability: 2, battleground: 0, country: 'Romania', box: {x: 739, y: 1278, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [54, , , , ]}, -{name: 'Hargita/Covasna', name_unique: 'Hargita/Covasna', space_id: 56, socio: 8, stability: 4, battleground: 0, country: 'Romania', box: {x: 928, y: 1227, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [52, , , , ]}, -{name: 'Brasov', name_unique: 'Brasov', space_id: 57, socio: 4, stability: 3, battleground: 1, country: 'Romania', box: {x: 1049, y: 1225, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [53, 59, 61, , ]}, -{name: 'Orthodox Church', name_unique: 'Orthodox Church Romania', space_id: 58, socio: 7, stability: 3, battleground: 0, country: 'Romania', box: {x: 855, y: 1338, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [51, 60, , , ]}, -{name: 'Ploiesti', name_unique: 'Ploiesti', space_id: 59, socio: 4, stability: 3, battleground: 0, country: 'Romania', box: {x: 1061, y: 1316, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [57, 61, 62, , ]}, -{name: 'Craiova', name_unique: 'Craiova', space_id: 60, socio: 3, stability: 4, battleground: 0, country: 'Romania', box: {x: 763, y: 1411, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [50, 58, 61, , ]}, -{name: 'Bucuresti', name_unique: 'Bucuresti', space_id: 61, socio: 2, stability: 3, battleground: 1, country: 'Romania', box: {x: 929, y: 1445, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [51, 57, 59, 60, 63]}, -{name: 'Galatii', name_unique: 'Galatii', space_id: 62, socio: 4, stability: 3, battleground: 1, country: 'Romania', box: {x: 1104, y: 1399, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [53, 59, 63, , ]}, -{name: 'Constanta', name_unique: 'Constanta', space_id: 63, socio: 4, stability: 3, battleground: 0, country: 'Romania', box: {x: 1130, y: 1517, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [61, 62, 72, , ]}, -{name: 'Pleven', name_unique: 'Pleven', space_id: 64, socio: 3, stability: 4, battleground: 0, country: 'Bulgaria', box: {x: 764, y: 1534, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [67, , , , ]}, -{name: 'Orthodox Church', name_unique: 'Orthodox Church Bulgaria', space_id: 65, socio: 7, stability: 3, battleground: 0, country: 'Bulgaria', box: {x: 882, y: 1540, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [66, 68, , , ]}, -{name: 'Ruse', name_unique: 'Ruse', space_id: 66, socio: 4, stability: 3, battleground: 1, country: 'Bulgaria', box: {x: 998, y: 1540, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [65, 69, 70, 71, 72]}, -{name: 'Sofia University', name_unique: 'Sofia University', space_id: 67, socio: 6, stability: 1, battleground: 0, country: 'Bulgaria', box: {x: 645, y: 1650, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [68, 73, , , ]}, -{name: 'Sofia', name_unique: 'Sofia', space_id: 68, socio: 2, stability: 3, battleground: 1, country: 'Bulgaria', box: {x: 768, y: 1653, h: 65, w: 105}, demInfl: 0, comInfl: 2, demCtrl: 0, comCtrl: 0, adjacent: [64, 65, 67, 69, 74]}, -{name: 'Stara Zagora', name_unique: 'Stara Zagora', space_id: 69, socio: 1, stability: 4, battleground: 0, country: 'Bulgaria', box: {x: 886, y: 1694, h: 65, w: 105}, demInfl: 0, comInfl: 1, demCtrl: 0, comCtrl: 0, adjacent: [66, 68, 71, , ]}, -{name: 'Razgrad', name_unique: 'Razgrad', space_id: 70, socio: 8, stability: 4, battleground: 0, country: 'Bulgaria', box: {x: 954, y: 1620, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [66, , , , ]}, -{name: 'Burgas', name_unique: 'Burgas', space_id: 71, socio: 4, stability: 3, battleground: 1, country: 'Bulgaria', box: {x: 1004, y: 1695, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [66, 69, 72, , ]}, -{name: 'Varna', name_unique: 'Varna', space_id: 72, socio: 4, stability: 3, battleground: 1, country: 'Bulgaria', box: {x: 1086, y: 1613, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [63, 66, 71, , ]}, -{name: 'Bulgarian Writers', name_unique: 'Bulgarian Writers', space_id: 73, socio: 5, stability: 2, battleground: 0, country: 'Bulgaria', box: {x: 652, y: 1726, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [67, , , , ]}, -{name: 'Plovdiv', name_unique: 'Plovdiv', space_id: 74, socio: 4, stability: 3, battleground: 1, country: 'Bulgaria', box: {x: 771, y: 1739, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [68, 75, , , ]}, -{name: 'Sliven', name_unique: 'Sliven', space_id: 75, socio: 3, stability: 4, battleground: 0, country: 'Bulgaria', box: {x: 894, y: 1768, h: 65, w: 105}, demInfl: 0, comInfl: 0, demCtrl: 0, comCtrl: 0, adjacent: [75, , , , ]}, - ] - -const cards = [ - null, - {number: 1, period: 1, side: 'C', name: 'Legacy of Martial Law*', ops: 2, remove: 1, playable: 1}, - {number: 2, period: 1, side: 'D', name: 'Solidarity Legalized*', ops: 4, remove: 1, playable: 1}, - {number: 3, period: 1, side: 'D', name: 'Walesa*', ops: 3, remove: 1, playable: 0}, - {number: 4, period: 1, side: 'D', name: 'Michnik*', ops: 1, remove: 1, playable: 1}, - {number: 5, period: 1, side: 'D', name: 'General Strike', ops: 3, remove: 0, playable: 1}, - {number: 6, period: 1, side: 'C', name: 'Brought in for Questioning', ops: 3, remove: 0, playable: 1}, - {number: 7, period: 1, side: 'C', name: 'State Run Media*', ops: 2, remove: 1, playable: 1}, - {number: 8, period: 3, side: 'C', name: 'The Chinese Solution*', ops: 1, remove: 1, playable: 1}, - {number: 9, period: 1, side: 'C', name: 'The Wall*', ops: 1, remove: 1, playable: 1}, - {number: 10, period: 1, side: 'C', name: 'Cult of Personality*', ops: 3, remove: 1, playable: 1}, - {number: 11, period: 1, side: 'C', name: 'Dissident Arrested', ops: 2, remove: 0, playable: 1}, - {number: 12, period: 1, side: 'C', name: 'Apparatchiks*', ops: 2, remove: 1, playable: 1}, - {number: 13, period: 1, side: 'C', name: 'Stasi*', ops: 1, remove: 1, playable: 1}, - {number: 14, period: 2, side: 'C', name: 'Ceausescu*', ops: 3, remove: 1, playable: 1}, - {number: 15, period: 1, side: 'C', name: 'Honecker*', ops: 3, remove: 1, playable: 1}, - {number: 16, period: 1, side: 'C', name: 'Nomenklatura*', ops: 2, remove: 1, playable: 1}, - {number: 17, period: 2, side: 'N', name: 'Power Struggle - East Germany', ops: 0, remove: 0, playable: 1}, - {number: 18, period: 2, side: 'N', name: 'Power Struggle - Czechoslovakia', ops: 0, remove: 0, playable: 1}, - {number: 19, period: 2, side: 'N', name: 'Power Struggle - Bulgaria', ops: 0, remove: 0, playable: 1}, - {number: 20, period: 2, side: 'N', name: 'Workers Revolt', ops: 2, remove: 0, playable: 1}, - {number: 21, period: 3, side: 'N', name: 'Power Struggle - Romania', ops: 0, remove: 0, playable: 1}, - {number: 22, period: 1, side: 'N', name: 'Power Struggle - Poland', ops: 0, remove: 0, playable: 1}, - {number: 23, period: 1, side: 'N', name: 'Power Struggle - Hungary', ops: 0, remove: 0, playable: 1}, - {number: 24, period: 3, side: 'C', name: 'Betrayal*', ops: 3, remove: 1, playable: 1}, - {number: 25, period: 2, side: 'D', name: 'Genscher*', ops: 2, remove: 1, playable: 1}, - {number: 26, period: 2, side: 'C', name: 'Securitate*', ops: 2, remove: 1, playable: 1}, - {number: 27, period: 1, side: 'D', name: 'Consumerism', ops: 3, remove: 0, playable: 1}, - {number: 28, period: 1, side: 'C', name: 'Factory Party Cells', ops: 3, remove: 0, playable: 1}, - {number: 29, period: 1, side: 'D', name: 'Jan Palach Week*', ops: 1, remove: 1, playable: 1}, - {number: 30, period: 1, side: 'C', name: 'Tear Gas*', ops: 1, remove: 1, playable: 1}, - {number: 31, period: 1, side: 'D', name: 'Intelligentsia', ops: 2, remove: 0, playable: 1}, - {number: 32, period: 1, side: 'C', name: 'Peasant Parties*', ops: 2, remove: 1, playable: 1}, - {number: 33, period: 2, side: 'D', name: 'Legacy of 1968*', ops: 4, remove: 1, playable: 1}, - {number: 34, period: 1, side: 'D', name: 'Fidesz*', ops: 2, remove: 1, playable: 1}, - {number: 35, period: 2, side: 'C', name: 'Systematization*', ops: 3, remove: 1, playable: 1}, - {number: 36, period: 3, side: 'D', name: 'Public Against Violence*', ops: 3, remove: 1, playable: 1}, - {number: 37, period: 1, side: 'C', name: 'Nagy Reburied*', ops: 3, remove: 1, playable: 1}, - {number: 38, period: 1, side: 'D', name: 'Roundtable Talks', ops: 3, remove: 0, playable: 1}, - {number: 39, period: 2, side: 'D', name: 'Toxic Waste*', ops: 2, remove: 1, playable: 1}, - {number: 40, period: 3, side: 'C', name: 'Adamec*', ops: 2, remove: 1, playable: 1}, - {number: 41, period: 3, side: 'D', name: 'My First Banana*', ops: 3, remove: 1, playable: 1}, - {number: 42, period: 1, side: 'D', name: 'St. Nicholas Church*', ops: 1, remove: 1, playable: 1}, - {number: 43, period: 3, side: 'N', name: 'Tank Column/Tank Man*', ops: 2, remove: 1, playable: 1}, - {number: 44, period: 2, side: 'N', name: 'Inflationary Currency*', ops: 3, remove: 1, playable: 1}, - {number: 45, period: 2, side: 'D', name: 'Soviet Troop Withdrawals*', ops: 4, remove: 1, playable: 1}, - {number: 46, period: 2, side: 'D', name: 'Goodbye Lenin!*', ops: 3, remove: 1, playable: 1}, - {number: 47, period: 2, side: 'C', name: 'Bulgarian Turks expelled*', ops: 3, remove: 1, playable: 1}, - {number: 48, period: 3, side: 'D', name: 'Shock Therapy*', ops: 3, remove: 1, playable: 1}, - {number: 49, period: 3, side: 'N', name: 'Stand Fast*', ops: 3, remove: 1, playable: 1}, - {number: 50, period: 2, side: 'D', name: 'This Sinatra Doctrine*', ops: 3, remove: 1, playable: 1}, - {number: 51, period: 2, side: 'C', name: '40th Anniversary Celebration*', ops: 2, remove: 1, playable: 1}, - {number: 52, period: 2, side: 'C', name: 'Normalization*', ops: 3, remove: 1, playable: 1}, - {number: 53, period: 2, side: 'C', name: 'Li Peng*', ops: 2, remove: 1, playable: 1}, - {number: 54, period: 2, side: 'D', name: 'The Crowd Turns Against Ceausescu*', ops: 3, remove: 1, playable: 1}, - {number: 55, period: 1, side: 'C', name: 'Perestroika*', ops: 3, remove: 1, playable: 1}, - {number: 56, period: 2, side: 'D', name: 'Foreign Television*', ops: 2, remove: 1, playable: 1}, - {number: 57, period: 2, side: 'C', name: 'Central Committee Reshuffle*', ops: 2, remove: 1, playable: 1}, - {number: 58, period: 2, side: 'D', name: 'Austria-Hungary Border Reopened*', ops: 2, remove: 1, playable: 1}, - {number: 59, period: 3, side: 'C', name: 'Massacre in Timisoara*', ops: 3, remove: 1, playable: 0}, - {number: 60, period: 1, side: 'D', name: 'Hungarian Democratic Forum*', ops: 3, remove: 1, playable: 1}, - {number: 61, period: 2, side: 'D', name: 'The Monday Demonstrations*', ops: 4, remove: 1, playable: 0}, - {number: 62, period: 1, side: 'N', name: 'Prudence', ops: 4, remove: 0, playable: 1}, - {number: 63, period: 3, side: 'D', name: 'Army Backs Revolution*', ops: 3, remove: 1, playable: 1}, - {number: 64, period: 1, side: 'D', name: 'Papal Visit*', ops: 2, remove: 1, playable: 1}, - {number: 65, period: 3, side: 'C', name: 'Politburo Intrigue*', ops: 2, remove: 1, playable: 1}, - {number: 66, period: 3, side: 'D', name: 'Civic Forum*', ops: 4, remove: 1, playable: 1}, - {number: 67, period: 2, side: 'N', name: 'Reformer Rehabilitated*', ops: 2, remove: 1, playable: 1}, - {number: 68, period: 2, side: 'D', name: 'Klaus and Komarek*', ops: 3, remove: 1, playable: 1}, - {number: 69, period: 3, side: 'C', name: 'New Year\'s Eve Party*', ops: 2, remove: 1, playable: 1}, - {number: 70, period: 3, side: 'D', name: 'Government Resigns*', ops: 3, remove: 1, playable: 1}, - {number: 71, period: 2, side: 'D', name: 'Kiss of Death*', ops: 3, remove: 1, playable: 1}, - {number: 72, period: 2, side: 'D', name: 'Peasant Parties Revolt*', ops: 3, remove: 1, playable: 1}, - {number: 73, period: 1, side: 'C', name: 'Poszgay Defends the Revolution*', ops: 2, remove: 1, playable: 1}, - {number: 74, period: 2, side: 'D', name: 'FRG Embassies*', ops: 3, remove: 1, playable: 1}, - {number: 75, period: 2, side: 'D', name: 'Exit Visas*', ops: 3, remove: 1, playable: 1}, - {number: 76, period: 2, side: 'C', name: 'Warsaw Pact Summit*', ops: 2, remove: 1, playable: 1}, - {number: 77, period: 3, side: 'C', name: 'Social Democratic Platform Adopted*', ops: 2, remove: 1, playable: 1}, - {number: 78, period: 1, side: 'N', name: 'Gorbachev Charms the West', ops: 4, remove: 0, playable: 1}, - {number: 79, period: 2, side: 'C', name: 'The Third Way*', ops: 2, remove: 1, playable: 1}, - {number: 80, period: 3, side: 'D', name: 'Domino Theory*', ops: 3, remove: 1, playable: 1}, - {number: 81, period: 3, side: 'C', name: 'Modrow*', ops: 2, remove: 1, playable: 1}, - {number: 82, period: 3, side: 'C', name: 'Spitzel*', ops: 1, remove: 1, playable: 1}, - {number: 83, period: 2, side: 'D', name: 'The Baltic Way*', ops: 3, remove: 1, playable: 0}, - {number: 84, period: 3, side: 'D', name: 'Breakaway Baltic Republics*', ops: 4, remove: 1, playable: 0}, - {number: 85, period: 1, side: 'N', name: 'Common European Home', ops: 2, remove: 0, playable: 1}, - {number: 86, period: 3, side: 'D', name: '\"The Wall Must Go!*\"', ops: 3, remove: 0, playable: 1}, - {number: 87, period: 3, side: 'D', name: 'Kohl Proposes Reunification*', ops: 3, remove: 1, playable: 1}, - {number: 88, period: 1, side: 'D', name: 'Sajudis*', ops: 2, remove: 1, playable: 1}, - {number: 89, period: 1, side: 'D', name: 'Eco-Glasnost*', ops: 2, remove: 1, playable: 1}, - {number: 90, period: 2, side: 'C', name: 'GrenzTruppen*', ops: 2, remove: 1, playable: 1}, - {number: 91, period: 1, side: 'D', name: 'Dash for the West*', ops: 3, remove: 1, playable: 1}, - {number: 92, period: 1, side: 'C', name: 'Deutsche Marks*', ops: 4, remove: 1, playable: 1}, - {number: 93, period: 2, side: 'D', name: 'New Forum*', ops: 1, remove: 1, playable: 1}, - {number: 94, period: 3, side: 'D', name: 'Union of Democratic Forces*', ops: 4, remove: 1, playable: 1}, - {number: 95, period: 1, side: 'C', name: 'The July Concept*', ops: 3, remove: 1, playable: 1}, - {number: 96, period: 1, side: 'D', name: 'Helsinki Final Act*', ops: 1, remove: 1, playable: 1}, - {number: 97, period: 3, side: 'D', name: 'The Tyrant is Gone*', ops: 2, remove: 1, playable: 0}, - {number: 98, period: 2, side: 'D', name: 'Laszlo Tokes*', ops: 2, remove: 1, playable: 1}, - {number: 99, period: 3, side: 'C', name: 'Ligachev*', ops: 3, remove: 1, playable: 1}, - {number: 100, period: 2, side: 'D', name: 'Yakovlev Counsels Gorbachev*', ops: 2, remove: 1, playable: 1}, - {number: 101, period: 3, side: 'C', name: 'Elena*', ops: 1, remove: 1, playable: 1}, - {number: 102, period: 3, side: 'C', name: 'National Salvation Front*', ops: 3, remove: 1, playable: 1}, - {number: 103, period: 2, side: 'C', name: 'Nepotism*', ops: 3, remove: 1, playable: 1}, - {number: 104, period: 2, side: 'D', name: 'Presidential Visit*', ops: 3, remove: 1, playable: 1}, - {number: 105, period: 2, side: 'D', name: 'Samizdat*', ops: 3, remove: 1, playable: 1}, - {number: 106, period: 2, side: 'D', name: '\"We are the People!\"', ops: 3, remove: 0, playable: 1}, - {number: 107, period: 2, side: 'D', name: 'Foreign Currency Debt Burden', ops: 1, remove: 0, playable: 1}, - {number: 108, period: 1, side: 'C', name: 'Heal Our Bleeding Wound', ops: 3, remove: 0, playable: 1}, - {number: 109, period: 3, side: 'C', name: 'Kremlin Coup!*', ops: 3, remove: 1, playable: 0}, - {number: 110, period: 3, side: 'D', name: 'Malta Summit*', ops: 3, remove: 1, playable: 1}, - ] - -const power_cards = [ -null, -{number: 1, name: 'Strike', value: 6, socio: 0, url: 'ps2'}, -{number: 2, name: 'Strike', value: 6, socio: 0, url: 'ps2'}, -{number: 3, name: 'Strike', value: 5, socio: 0, url: 'ps3'}, -{number: 4, name: 'Strike', value: 5, socio: 0, url: 'ps3'}, -{number: 5, name: 'Strike', value: 4, socio: 0, url: 'ps4'}, -{number: 6, name: 'Strike', value: 4, socio: 0, url: 'ps4'}, -{number: 7, name: 'Strike', value: 4, socio: 0, url: 'ps4'}, -{number: 8, name: 'Strike', value: 4, socio: 0, url: 'ps4'}, -{number: 9, name: 'Strike', value: 3, socio: 0, url: 'ps5'}, -{number: 10, name: 'Strike', value: 3, socio: 0, url: 'ps5'}, -{number: 11, name: 'Strike', value: 3, socio: 0, url: 'ps5'}, -{number: 12, name: 'Strike', value: 3, socio: 0, url: 'ps5'}, -{number: 13, name: 'March', value: 6, socio: 0, url: 'ps6'}, -{number: 14, name: 'March', value: 6, socio: 0, url: 'ps6'}, -{number: 15, name: 'March', value: 5, socio: 0, url: 'ps7'}, -{number: 16, name: 'March', value: 5, socio: 0, url: 'ps7'}, -{number: 17, name: 'March', value: 4, socio: 0, url: 'ps8'}, -{number: 18, name: 'March', value: 4, socio: 0, url: 'ps8'}, -{number: 19, name: 'March', value: 4, socio: 0, url: 'ps8'}, -{number: 20, name: 'March', value: 4, socio: 0, url: 'ps8'}, -{number: 21, name: 'March', value: 3, socio: 0, url: 'ps9'}, -{number: 22, name: 'March', value: 3, socio: 0, url: 'ps9'}, -{number: 23, name: 'March', value: 3, socio: 0, url: 'ps9'}, -{number: 24, name: 'March', value: 3, socio: 0, url: 'ps9'}, -{number: 25, name: 'Rally in the Square', value: 1, socio: 0, url: 'ps1'}, -{number: 26, name: 'Rally in the Square', value: 1, socio: 0, url: 'ps1'}, -{number: 27, name: 'Rally in the Square', value: 1, socio: 0, url: 'ps1'}, -{number: 28, name: 'Rally in the Square', value: 1, socio: 0, url: 'ps1'}, -{number: 29, name: 'Rally in the Square', value: 1, socio: 0, url: 'ps1'}, -{number: 30, name: 'Rally in the Square', value: 1, socio: 0, url: 'ps1'}, -{number: 31, name: 'Petition', value: 6, socio: 0, url: 'ps10'}, -{number: 32, name: 'Petition', value: 6, socio: 0, url: 'ps10'}, -{number: 33, name: 'Petition', value: 6, socio: 0, url: 'ps10'}, -{number: 34, name: 'Petition', value: 5, socio: 0, url: 'ps11'}, -{number: 35, name: 'Petition', value: 5, socio: 0, url: 'ps11'}, -{number: 36, name: 'Petition', value: 5, socio: 0, url: 'ps11'}, -{number: 37, name: 'Elite Leader', value: 3, socio: 1, url: 'ps16'}, -{number: 38, name: 'Elite Leader', value: 3, socio: 1, url: 'ps17'}, -{number: 39, name: 'Elite Leader', value: 3, socio: 1, url: 'ps18'}, -{number: 40, name: 'Elite Leader', value: 3, socio: 1, url: 'ps19'}, -{number: 41, name: 'Intellectual Leader', value: 3, socio: 5, url: 'ps12'}, -{number: 42, name: 'Intellectual Leader', value: 3, socio: 5, url: 'ps13'}, -{number: 43, name: 'Intellectual Leader', value: 3, socio: 5, url: 'ps14'}, -{number: 44, name: 'Intellectual Leader', value: 3, socio: 5, url: 'ps15'}, -{number: 45, name: 'Worker Leader', value: 3, socio: 4, url: 'ps20'}, -{number: 46, name: 'Worker Leader', value: 3, socio: 4, url: 'ps21'}, -{number: 47, name: 'Church Leader', value: 3, socio: 7, url: 'ps23'}, -{number: 48, name: 'Student Leader', value: 3, socio: 6, url: 'ps22'}, -{number: 49, name: 'Scare Tactics', value: 0, socio: 0, url: 'ps26'}, -{number: 50, name: 'Support Surges', value: 0, socio: 0, url: 'ps25'}, -{number: 51, name: 'Support Falters', value: 0, socio: 0, url: 'ps24'}, -{number: 52, name: 'Tactic Fails', value: 0, socio: 0, url: 'ps27'}, -{number: 53, name: 'Rally in the Square', value: 3, socio: 0, url: 'ps1'}, -{number: 54, name: 'Petition', value: 3, socio: 0, url: 'ps10'} -] +const numberless_cards = [25, 26, 27, 28, 29, 30, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52] +const auto_resolve_events = [5, 8, 9, 13, 17, 25, 26, 30, 35, 50, 53, 59, 62, 63, 65, 72, 74, 99, 102, 108] +const switch_events = [6, 20, 71] exports.scenarios = [ "Standard" ] exports.roles = [ DEM, COM ] - - // --- SET UP --- exports.setup = function (seed, scenario, options) { @@ -285,9 +44,25 @@ exports.setup = function (seed, scenario, options) { undo: [], active: null, state: "com_init", - - played_card: [], + return: '', + vm: null, + vm_event: 0, + vm_event_to_do: false, + vm_infl_to_do: false, + vm_active_country: 0, + vm_influence_added: {}, + vm_max_infl: 0, + + played_card: 0, + stasi_card: 0, + samizdat_card: 0, + table_cards: [], + austria_hungary_border_reopened: false, + austria_hungary_border_reopened_tracker: true, + austria_hungary_border_reopened_checked: false, + temp: 0, available_ops: 0, + vm_available_ops: 0, starting_infl: { com_starting_infl: 0, dem_starting_infl: 0 @@ -305,20 +80,26 @@ exports.setup = function (seed, scenario, options) { com_tst_attempted: 0, dem_tst_attempted_this_turn: 0, com_tst_attempted_this_turn:0, + tst_success: false, + tst_7: false, + tst_8: false, vp: 0, - pieces: [], + pieces: [null], strategy_deck: [], strategy_discard: [], + discard: false, + view_opp_hand: false, strategy_removed: [], + persistent_events: {austria_hungary_border_reopened: false, civic_forum: false, eco_glasnost: false, elena: false, foreign_currency_debt_burden: '', frg_embassies: false, general_strike: false, genscher: false, grenztruppen: false, helsinki_final_act: false, honecker: false, li_peng: false, ligachev: false, national_salvation_front: false, perestroika: false, presidential_visit: false, prudence: '', roundtable_talks: false, securitate: false, sinatra_doctrine: false, solidarity_legalised: false, stand_fast: '', stasi: false, st_nicholas_church: false, systematization: 0, tear_gas: false, the_tyrant_is_gone: 0, the_wall: false, the_wall_must_go: false, we_are_the_people: false, yakovlev: false}, power_struggle_deck: [], power_struggle_discard: [], dem_hand_limit: 8, com_hand_limit: 8, democrat_hand: [], communist_hand: [], - democrat_set_aside: [], + communist_hand_red: [], pwr_struggle_in: [], is_pwr_struggle: false, @@ -326,19 +107,25 @@ exports.setup = function (seed, scenario, options) { com_pwr_hand_limit: 0, dem_pwr_hand: [], com_pwr_hand: [], + ceausescu_cards: [], raised_stakes_discard: 0, raised_stakes: 0, raised_stakes_round: 0, rally_win: 0, petition_win: 0, - respond: 0, - times_held: {'East Germany': 0, 'Poland': 0, 'Czechoslovakia': 0, 'Hungary': 0, 'Romania': 0, 'Bulgaria': 0}, - revolutions: {'East Germany': false, 'Poland': false, 'Czechoslovakia': false, 'Hungary': false, 'Romania': false, 'Bulgaria': false}, + phase: 0, + times_held: {'East_Germany': 0, 'Poland': 0, 'Czechoslovakia': 0, 'Hungary': 0, 'Romania': 0, 'Bulgaria': 0}, + revolutions: {'East_Germany': false, 'Poland': false, 'Czechoslovakia': false, 'Hungary': false, 'Romania': false, 'Bulgaria': false}, + scored_countries: {'East_Germany': false, 'Poland': false, 'Czechoslovakia': false, 'Hungary': false, 'Romania': false, 'Bulgaria': false}, remove_opponent_infl: false, - tactics_fails: '' + tactics_fails: '', + warsaw_pact_summit: false, + the_wall_must_go: {dem_wins: 0, com_wins: 0, dem_roll: 0, com_roll: 0}, + tyrant_space: 0 } log_h1("1989 Dawn of Freedom") + game.active = COM start_game() @@ -349,10 +136,21 @@ function start_game() { //starting influence // Draw cards + /* const card_numbers = cards.filter(card => card !== null && card !== undefined).map(card => card.number); + console.log('card numbers: ', card_numbers) */ game.strategy_deck = draw_deck(cards) reset_power() + game.playable_cards = cards.map(card => { + if (card === null) return null + return { + number: card.number, + playable: card.playable + }}) + //console.log('game.strategy_deck: ', game.strategy_deck[1]) draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.dem_hand_limit, game.com_hand_limit) - spaces.forEach(space => { + //.log('game.strategy_deck: ', game.strategy_deck[1], 'democrat_hand:', game.democrat_hand) + spaces.forEach((space, index) => { + if(index === 0 ) return game.pieces.push({ name_unique: space.name_unique, space_id: space.space_id, @@ -360,12 +158,13 @@ function start_game() { comInfl: space.comInfl, demCtrl: space.demCtrl, comCtrl: space.comCtrl, - stability: space.stability + stability: space.stability, + adjacent: space.adjacent }); }); - game.valid_spaces = valid_spaces(); - //Communist starts by placing 2 influence + game.valid_spaces = valid_spaces_setup() game.available_ops = 2 + game.phase = 0 log_h1("Place starting influence") log_side() } @@ -381,7 +180,7 @@ exports.view = function(state, player) { actions: null, played_card: game.played_card, - selected_space: game.selected_space, + table_cards: game.table_cards, valid_spaces: game.valid_spaces, valid_cards: game.valid_cards, @@ -393,13 +192,18 @@ exports.view = function(state, player) { stability: game.stability, dem_tst: game.dem_tst_position, com_tst: game.com_tst_position, - + persistent_events: game.persistent_events, strategy_deck: game.strategy_deck.length, strategy_discard: game.strategy_discard, + discard: game.discard, + show_opp_hand: game.view_opp_hand, democrat_hand: game.democrat_hand.length, communist_hand: game.communist_hand.length, + democrat_power_hand: game.dem_pwr_hand.length, + communist_power_hand: game.com_pwr_hand.length, + ceausescu_cards: game.ceausescu_cards, is_pwr_struggle: game.is_pwr_struggle, times_held: game.times_held, revolutions: game.revolutions, @@ -415,19 +219,31 @@ exports.view = function(state, player) { view.drawn = game.vm.draw if (player === game.active) { + if (game.selected_space > 0 ) { + view.valid_spaces = [game.selected_space] + } else { view.valid_spaces = game.valid_spaces + } } else { view.valid_spaces = [] } + if (player === game.active) { + view.valid_cards = game.valid_cards + } else { + view.valid_cards = [] + } + if (player === DEM) { view.hand = game.democrat_hand - view.set_aside = game.democrat_set_aside - view.power_hand = game.dem_pwr_hand + view.opp_hand = game.communist_hand_red + view.set_aside = game.democrat_set_aside /*Is this being used? */ + view.power_hand = game.dem_pwr_hand.sort((a, b) => a - b) } else if (player === COM) { view.hand = game.communist_hand - view.power_hand = game.com_pwr_hand + view.opp_hand = game.dem_pwr_hand.sort((a, b) => a - b) /*Does the Communist ever see Democrat hand? */ + view.power_hand = game.com_pwr_hand.sort((a, b) => a - b) } if (game.state === "game_over") { @@ -440,7 +256,7 @@ exports.view = function(state, player) { else view.prompt = `Waiting for ${game.active} to ${inactive}` } else { - view.prompt = "Unknown state: " + game.state + view.prompt = "A Unknown state: " + game.state } } else { view.actions = {} @@ -448,7 +264,7 @@ exports.view = function(state, player) { if (states[game.state]) states[game.state].prompt(player) else - view.prompt = "Unknown state: " + game.state + view.prompt = "B Unknown state: " + game.state if (view.actions.undo === undefined) { if (game.undo && game.undo.length > 0) view.actions.undo = 1 @@ -472,6 +288,7 @@ function gen_action(action, argument) { view.actions[action] = [] view.actions[action].push(argument) } + //console.log('view.actions: ', view.actions, 'view.actions[action]: ', view.actions[action]) } function gen_action_infl(space){ @@ -491,6 +308,7 @@ function gen_action_scoring(){ } exports.action = function (state, player, action, arg) { + //console.log('exports.action called with state:' , state, 'player:', player, 'action: ', action, 'arg: ', arg) game = state if (states[game.state] && action in states[game.state]) { states[game.state][action](arg, player) @@ -512,13 +330,14 @@ states.com_init = { view.prompt = 'Place starting influence: done.'; gen_action("done"); return; + } else if (game.starting_infl.dem_starting_infl === 2) { + view.prompt = `Place your last ${game.available_ops} starting influence.` + } else { + view.prompt = `Place ${game.available_ops} starting influence.` } - view.prompt = `Place ${game.available_ops} starting influence` - for (let space_id of game.valid_spaces) { - const space = spaces.find(s => s.space_id === space_id); - if (space) { - gen_action_infl(space.name_unique); + if (space_id) { + gen_action_infl(spaces[space_id].name_unique); } } }, @@ -528,41 +347,38 @@ states.com_init = { }, done() { - view.prompt='Influence added' + view.prompt='Influence added.' game.starting_infl.com_starting_infl++ if (game.starting_infl.com_starting_infl == 1){ game.available_ops = 3 game.state = 'dem_init' - valid_spaces() + valid_spaces_setup() next_player() } else if (game.starting_infl.com_starting_infl == 2) { game.available_ops = 4 game.state = 'dem_init' - valid_spaces() + valid_spaces_setup() next_player() } else if (game.starting_infl.com_starting_infl == 3) { - new_turn() - clear_undo() - game.state = 'choose_card' + game.state = 'start_game' } } } states.dem_init = { - inactive: 'place starting influence', + inactive: 'place starting influence.', prompt() { if (game.available_ops == 0) { view.prompt = 'Place starting influence: done.'; gen_action("done"); return; + } else if (game.starting_infl.com_starting_infl === 2) { + view.prompt = `Place your last ${game.available_ops} starting influence.` + } else { + view.prompt = `Place ${game.available_ops} starting influence` } - view.prompt = `Place ${game.available_ops} starting influence` - for (let space_id of game.valid_spaces) { - const space = spaces.find(s => s.space_id === space_id); - if (space) { - gen_action_infl(space.name_unique); - } + gen_action_infl(spaces[space_id].name_unique); } }, infl(space) { @@ -578,11 +394,24 @@ states.dem_init = { game.available_ops = 2 } game.state = 'com_init' - valid_spaces() + valid_spaces_setup() next_player() } } +states.start_game = { + inactive: 'start Turn 1.', + prompt() { + view.prompt = 'Start Turn 1.' + gen_action('start') + }, + start() { + new_turn() + clear_undo() + game.state = 'choose_card' + } +} + states.choose_card = { inactive: 'choose a card', prompt() { @@ -606,19 +435,46 @@ states.choose_card = { }, card(card) { push_undo() - log(`Played ${cards[card].name}`) game.played_card = card let find_card if (game.active === COM) { - find_card = game.communist_hand.indexOf(card); - const [playedCard] = game.communist_hand.splice(find_card, 1); + find_card = game.communist_hand.indexOf(card) + game.communist_hand.splice(find_card, 1) } else { - find_card = game.democrat_hand.indexOf(card); - const [playedCard] = game.democrat_hand.splice(find_card, 1); + find_card = game.democrat_hand.indexOf(card) + game.democrat_hand.splice(find_card, 1) } - game.strategy_discard.push(card) game.available_ops = cards[card].ops - + + //Check events which affect game ops + if (game.persistent_events['perestroika'] && game.active === COM) { + log('+1 op from C25') + game.available_ops ++ + } + if (game.persistent_events['sinatra_doctrine'] && game.active === DEM) { + log('+1 op from C50') + game.available_ops ++ + } + + if ((game.active === DEM && game.dem_tst_position >= 2 && game.com_tst_position <= 1 && cards[card].ops === 1) || (game.active === COM && game.com_tst_position >=2 && game.dem_tst_position <= 1 && cards[card].ops === 1)) { + log('+1 op from Tiananmen Square Track') + game.available_ops ++ + } + + if ((game.active === DEM && game.persistent_events['prudence'] === DEM) || (game.active === COM && game.persistent_events['prudence'] === COM)) { + if (game.available_ops > 1) { + log('-1 op from C8') + game.available_ops -- + } + } + + //Check Ligachev + if (game.active === DEM && game.persistent_events['ligachev'] && card !== 14) { + log('-3 VP from Ligachev') + game.vp -= 3 + check_vp() + game.persistent_events['ligachev'] = false + } }, done () { game.state = 'play_card' @@ -626,406 +482,835 @@ states.choose_card = { } states.play_card ={ - inactive: 'play a card', + get inactive() { + return `play ${cards[game.played_card].name}.` + }, prompt () { - if (game.is_pwr_struggle) { - view.prompt = 'Draw cards' - gen_action('draw') + if (game.phase >= 1) { + view.prompt = 'Event: done.' + gen_action('done') return } + if (scoring_cards.includes(game.played_card)) { + view.prompt = 'Play for:' + gen_action('event') + return + } view.prompt = 'Play for:' - - if (scoring_cards.includes(game.played_card)) { - gen_action('scoring'); - } else { - if (cards[game.played_card].playable ===1) { + + //Check for Tiananmen Square Track awards special abilities + if ((game.active === DEM && cards[game.played_card].side !== 'C' && game.dem_tst_position >= 8 && game.com_tst_position < 8 && !game.tst_8) || (game.active === COM && cards[game.played_card].side !== 'D' && game.com_tst_position >= 8 && game.dem_tst_position < 8 && !game.tst_8)){ + gen_action('tst_8') + } + + // Special check for Reformer Rehabilitated + if ((game.active === DEM && game.playable_cards[game.played_card] === 2 && (game.dem_tst_position > game.com_tst_position)) || (game.active === COM && game.playable_cards[game.played_card] === 2 && (game.dem_tst_position < game.com_tst_position))) { gen_action('event') - } - gen_action('influence') - if (game.active === DEM && game.dem_tst_attempted_this_turn === 0 || game.active === COM && game.com_tst_attempted_this_turn === 0) { + } + + //Continue with normal logic + if ((game.active === DEM && cards[game.played_card].side === 'D' && game.playable_cards[game.played_card].playable === 1) || (game.active === COM && cards[game.played_card].side === 'C' && game.playable_cards[game.played_card].playable ===1) || cards[game.played_card].side === 'N') { + gen_action('event') + } else if ((game.active === DEM && (cards[game.played_card].side === 'C' && game.playable_cards[game.played_card].playable ===1)) || game.active === COM && (cards[game.played_card].side === 'D' && game.playable_cards[game.played_card].playable ===1)) { + gen_action('opp_event') + } + gen_action('influence') + if (game.active === DEM && game.dem_tst_attempted_this_turn === 0 || game.active === COM && game.com_tst_attempted_this_turn === 0) { gen_action('tst') } - gen_action('support_check') - } + gen_action('support_check') }, - scoring() { + event() { push_undo() - if (game.played_card === 17) { game.pwr_struggle_in ="East Germany" } - if (game.played_card === 18) { game.pwr_struggle_in = "Czechoslovakia" } - if (game.played_card === 19) { game.pwr_struggle_in = "Bulgaria"} - if (game.played_card === 21) { game.pwr_struggle_in = "Romania" } - if (game.played_card === 22) { game.pwr_struggle_in = "Poland" } - if (game.played_card === 23) { game.pwr_struggle_in = "Hungary" } - game.is_pwr_struggle = true + log(`Played C${cards[game.played_card].number} for the event`) + if (scoring_cards.includes(game.played_card)) {game.phase = 0} + else {game.phase = 1} + game.return = game.active + if (switch_events.includes(game.played_card)) {next_player()} + goto_vm(game.played_card) }, - draw() { - push_undo() - let presence = check_presence(game.pwr_struggle_in) - if (presence.dem_spaces > 0) { - game.dem_pwr_hand_limit = 6 + 2*(presence.dem_spaces - 1) - } else { - game.dem_pwr_hand_limit = 0 - } - if (presence.com_spaces > 0 ) { - game.com_pwr_hand_limit = 6 + 2*(presence.com_spaces - 1) - } else { - game.com_pwr_hand_limit = 0 + opp_event() { + log(`Played C${cards[game.played_card].number} for the event`) + game.phase = 1 /*Do I still need this?*/ + game.vm_infl_to_do = true + game.return = game.active + if (auto_resolve_events.includes(game.played_card) || switch_events.includes(game.played_card)) { + goto_vm(game.played_card)} + else { + next_player() + goto_vm(game.played_card) } - draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand_limit, game.com_pwr_hand_limit) - game.valid_cards = all_power_cards - game.state = 'raise_stakes' - }, - event() { - push_undo() - call_event(game.played_card) }, - influence(influence) { + influence() { push_undo() + log(`Played C${cards[game.played_card].number} for influence`) + + // Check if Common European Home played for influence + if (game.played_card === 21) { + if (game.active === DEM) { + game.vp -- + log('-1 VP') + check_vp() + } else { + game.vp ++ + log('+1 VP') + check_vp() + } + } + // Check if card is opponent card with event that needs to be resolved + if ((game.active === DEM && cards[game.played_card].side === "C" && game.playable_cards[game.played_card].playable === 1) || (game.active === COM && cards[game.played_card].side === "D" && game.playable_cards[game.played_card].playable === 1 )) { + game.phase = 1 /*Do I need this? */ + game.vm_event_to_do = true + } game.state='add_influence' - valid_spaces() + valid_spaces_infl() }, - tst(tst) { + tst() { push_undo() + log(`Played C${cards[game.played_card].number} to the Tiananmen Square Track`) game.state='tiananmen_square_attempt' }, - support_check(space) { + support_check() { push_undo() + log(`Played C${cards[game.played_card].number} for support checks`) + + // Check if card is opponent card with event that needs to be resolved + if (game.phase === 0 && game.active === DEM && cards[game.played_card].side === "C" && game.playable_cards[game.played_card].playable === 1 || game.phase === 0 && game.active === COM && cards[game.played_card].side === "D" && game.playable_cards[game.played_card].playable === 1 ) { + game.vm_event_to_do = true + } game.available_ops = 2 game.state='support_check_prep' - valid_spaces() + valid_spaces_sc() + }, + tst_8() { /*Play card for ops and event */ + game.vm_event_to_do = true + game.vm_infl_to_do = true + game.tst_8 = true + game.state = 'vm_tst_8' + }, + done () { + end_round() } + } -states.add_influence = { - inactive: 'add influence', - prompt () { - if (game.available_ops == 0) { - view.prompt = 'Place influence: done.'; - gen_action("done"); - return; +states.resolve_opponent_event = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.vm_infl_to_do) { + view.prompt = 'Event resolved. Choose to play card for:' + gen_action('influence') + gen_action('support_check') + } else if (game.vm_event_to_do) { + // Check for Tiananmen Square Track ability - play opponent card without triggering event + if ((game.active === DEM && game.dem_tst_position >= 7 && game.com_tst_position < 7 && !game.tst_7) || (game.active === COM && game.com_tst_position >= 7 && game.dem_tst_position < 7 && !game.tst_7)){ + gen_action('tst_7') + } + view.prompt = 'You must resolve the opponent event.' + gen_action('event') + } else { + view.prompt = 'Event resolved. End the action round.' + gen_action('done') } - - view.prompt = `Add influence: ${game.available_ops} remaining` - - // Generate actions for valid spaces - for (let space_id of game.valid_spaces) { - const space = spaces.find(s => s.space_id === space_id); - if (space) { - gen_action_infl(space.name_unique); - } + }, + influence(){ + push_undo() + game.state = 'finish_add_infl' + valid_spaces_infl() + }, + support_check() { + push_undo() + game.available_ops = 2 + game.state = 'finish_support_check_prep' + valid_spaces_sc() + }, + event() { + game.vm_event_to_do = false + game.return_state = 'resolve_opponent_event' + if (auto_resolve_events.includes(game.played_card) || switch_events.includes(game.played_card)) { + game.return = game.active + goto_vm(game.played_card)} + else { + if (game.active === DEM) { + game.return = COM + } else { + game.return = DEM + } + next_player() + goto_vm(game.played_card) } - }, - infl(space) { - add_infl(space) + tst_7() { + push_undo() + game.tst_7 = true + game.vm_event_to_do = false }, done() { - view.prompt = 'Influence added' + /*if(game.round_player === COM && game.active === DEM) { + log_h3('End of Communist Action Round') + change_player() + } */ end_round() } } -states.tiananmen_square_attempt = { - inactive: 'do Tiananmen Square', +states.finish_add_infl = { + inactive: 'add influence.', prompt () { - if (game.active === DEM && game.dem_tst_attempted_this_turn > 0 || game.active === COM && game.com_tst_attempted_this_turn > 0) { - view.prompt = 'Tiananmen Square Track attempt done' - gen_action('done') - return + if (game.available_ops === 0) { + view.prompt = 'Place influence: done.' + gen_action("done") + return; + } + + view.prompt = `Add influence: ${game.available_ops} remaining` + + // Generate actions for valid spaces + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique) + //} } - view.prompt = 'Roll a die' - gen_action('roll') }, - roll(roll) { - do_tst_attempt () - clear_undo() - }, - done () { - game.available_ops = 0 + infl(space) { + add_infl(space) + }, + done() { end_round() } } -states.support_check_prep = { +states.finish_support_check_prep = { + inactive: 'do support checks', prompt () { if (game.available_ops === 0) { view.prompt = 'Support checks: done' gen_action('done') - return - } - if (game.available_ops > 1) { - view.prompt = `Select a space. ${game.available_ops} support checks remaining` - } else { - view.prompt = ` Select a space. ${game.available_ops} support check remaining` - } + //return + } else { + view.prompt = `Select a space. ${pluralize(game.available_ops, 'support check')} remaining.` } - for (let space_id of game.valid_spaces) { - const space = spaces.find(s => s.space_id === space_id); - if (space) { - gen_action_sc(space.name_unique); - } + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); */ + if (space_id) { + gen_action_sc(spaces[space_id].name_unique) + } } }, sc(space) { - game.selected_space = space - game.state = 'do_support_check' + game.selected_space = find_space_index(space) + game.state = 'finish_do_support_check' }, done () { - game.available_ops = 0 end_round() } } -states.do_support_check = { +states.finish_do_support_check = { inactive: 'do support checks', prompt () { - view.prompt = `Target: ${game.selected_space}. Roll a die` + view.prompt = `Target: ${spaces[game.selected_space].name_unique}. Roll a die.` gen_action('roll') }, roll() { - do_sc(game.selected_space) - valid_spaces() + clear_undo() + do_sc(spaces[game.selected_space].name_unique) game.available_ops-- - game.state = 'support_check_prep' + game.state = 'finish_support_check_prep' return } } -states.raise_stakes = { - inactive: 'raise the stakes', - +states.add_influence = { + inactive: 'add influence.', prompt () { - if (game.raised_stakes_round === 2) { - console.log('game raised stakes round == 2') - gen_action('struggle') - return - } - if (game.raised_stakes_discard === 3) { - view.prompt = 'Raise the stakes: done' - gen_action('done') - } else if (game.raised_stakes_discard > 0) { - console.log('in stakes >= 0') - view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes` - } else { - view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes` - gen_action('done') - } - for (let card of game.valid_cards) { - gen_action_card(card) - } - }, - card(card) { - log(`Discarded ${power_cards[card].name}`) - - let find_card - if (game.active === COM) { - find_card = game.com_pwr_hand.indexOf(card); - const [playedCard] = game.com_pwr_hand.splice(find_card, 1); - } else { - find_card = game.dem_pwr_hand.indexOf(card); - const [playedCard] = game.dem_pwr_hand.splice(find_card, 1); - } - game.power_struggle_discard.push(card) + if (game.available_ops === 0) { + view.prompt = 'Place influence: done.' + gen_action("done") + return + } - game.raised_stakes_discard ++ - if (game.raised_stakes_discard === 3) { - game.raised_stakes++ - } + view.prompt = `Add influence: ${game.available_ops} remaining.` - }, - done () { - if (game.raised_stakes_discard === 0 ) { - log('Did not raise the stakes') + // Generate actions for valid spaces + for (let space_id of game.valid_spaces) { + /* const space = spaces.find(s => s && s.space_id === space_id); + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} } - game.raised_stakes_discard = 0 - game.raised_stakes_round ++ - next_player() }, - struggle () { - do_valid_cards() - game.state = 'power_struggle' + infl(space) { + add_infl(space) + }, + done() { + if(game.vm_event_to_do) { + game.state = 'resolve_opponent_event'} + else { + end_round()} } - } -states.power_struggle = { - inactive: 'play a card', +states.tiananmen_square_attempt = { + inactive: 'do Tiananmen Square Attempt.', prompt () { - if (game.respond === 0 && game.valid_cards.length > 0) { - view.prompt = "Play a card" - for (let card of game.valid_cards) { - gen_action_card(card) - } - } else if (game.respond === 0 && game.valid_cards.length === 0) { - view.prompt = 'No valid cards. You must concede.' - gen_action('concede') - } else if (game.respond === 1 && game.valid_cards.length > 0) { - view.prompt = `${power_cards[game.played_power_card].name} played. You must match or concede` - gen_action('concede') - for (let card of game.valid_cards) { - gen_action_card(card) - } - } else if (game.respond === 1 && game.valid_cards.length === 0) { - view.prompt = `${power_cards[game.played_power_card].name} played. You must concede` - gen_action('concede') - - } else if (game.respond === 2) { - view.prompt = 'You matched. Roll a die' - gen_action('roll') - } else if (game.respond === 3) { - view.prompt = 'Play leader as:' - if (game.tactics_fails !== "Strike") {gen_action('strike')} - if (game.tactics_fails !== "March") {gen_action('march')} - if (game.tactics_fails !== "Rally in the Square") {gen_action('rally')} - if (game.tactics_fails !== "Petition") {gen_action('petition')} - } else if (game.respond === 4) { - view.prompt = 'Draw 2 cards' - gen_action('draw') - } else if (game.respond === 5) { - view.prompt = 'Remove 1 opponent influence' - - for (let space_id of game.valid_spaces) { - const space = spaces.find(s => s.space_id === space_id); - if (space) { - gen_action_infl(space.name_unique); - } + if ((game.active === DEM && game.dem_tst_attempted_this_turn > 0 )|| (game.active === COM && game.com_tst_attempted_this_turn > 0)) { + if (game.tst_success) { + view.prompt = 'Tiananmen Square Track attempt successful.' + } else { + view.prompt = 'Tiananmen Square Track attempt failed.' } - } else if (game.respond === 6) { - view.prompt = 'Remove influence: done' gen_action('done') - } else if (game.respond === 7 && game.available_ops > 0) { - view.prompt = 'Discard 2 cards' + return + } + view.prompt = 'Tiananmen Square Track attempt: Roll a die.' + gen_action('roll') + }, + roll() { + clear_undo() + do_tst_attempt () + }, + done () { + game.tst_success = false + end_round() + } +} + +states.tst_goddess = { + inactive: 'choose whether to discard a card.', + prompt() { + if (game.phase === 0) { + view.prompt = 'Tiananmen Square Track award: you may discard a non-Power Struggle Card and draw a replacement.' for (let card of game.valid_cards) { gen_action_card(card) - } - } else if (game.respond === 7 && game.available_ops === 0) { - view.prompt = 'Discard cards: done' + } + gen_action('pass') + } else { + view.prompt = 'Discard a card: done.' gen_action('done') - } + } }, card(card) { push_undo() discard(card) - if (game.respond === 0 && card >= 37 && card <= 48) { - game.played_power_card = card - game.respond = 3 - } else if (game.respond === 0 && card === 49){ - log(`Played: ${power_cards[card].name}`) - game.played_power_card = card - game.respond = 5 - valid_spaces() - } else if (game.respond === 0 && card === 50) { - log(`Played: ${power_cards[card].name}`) - game.played_power_card = card - game.respond = 4 - } else if (game.respond === 0 && card === 51) { - log(`Played: ${power_cards[card].name}`) - game.played_power_card = card - game.respond = 7 - game.available_ops = 2 - next_player() - if (game.active === DEM) {game.valid_cards = game.dem_pwr_hand} - else {game.valid_cards = game.com_pwr_hand} - } - else if (game.respond === 0) { - log(`Played: ${power_cards[card].name} ${power_cards[card].value}`) - game.played_power_card = card - game.respond = 1 - next_player() - do_valid_cards() - - } else if (game.respond === 1) { + game.valid_cards = [] + game.phase++ + if (game.active === DEM) { + draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.democrat_hand.length +1, game.communist_hand.length) + } else { + draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.democrat_hand.length, game.communist_hand.length +1) + } + }, + pass() { + log('Did not discard') + log_h2("Action Round " + game.round) + if (game.active === DEM) { + next_player() + } else { + log_side() + } + game.state = 'choose_card' + }, + done() { + + log_h2("Action Round " + game.round) + if (game.active === DEM) { + next_player() + } else { + log_side() + } + game.phase = 0 + game.state = 'choose_card' + } +} + + + +states.support_check_prep = { + inactive: 'do support checks', + prompt () { + if (game.available_ops === 0) { + view.prompt = 'Support checks: done' + gen_action('done') + //return + } + if (game.available_ops > 0) { + view.prompt = `Select a space. ${pluralize(game.available_ops, 'support check')} remaining.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_sc(spaces[space_id].name_unique); + //} + } + } + }, + sc(space) { + push_undo() + game.selected_space = find_space_index(space) + + // Check for Austria-Hungary Border Reopened - check on first support check only + console.log('game.austria_hungary_border_reopened_checked', game.austria_hungary_border_reopened_checked) + if (!game.austria_hungary_border_reopened_checked) { + game.austria_hungary_border_reopened_checked = true + console.log('in ahb check, country, ', spaces[game.selected_space].country, 'ahb', game.persistent_events['austria_hungary_border_reopened']) + if (spaces[game.selected_space].country === 'East_Germany' && game.persistent_events['austria_hungary_border_reopened'] && game.active === DEM) { + game.state = 'austria_hungary_border_reopened_check' + } + game.state = 'do_support_check' + } else { + game.state = 'do_support_check' + } + }, + done () { + if (game.is_pwr_struggle) {/*Crowd Turns Against Ceausescu should be the only time you end up here during a power struggle */ + if (game.return !== game.active) { + next_player() + } + game.state = 'raise_stakes_1' + return + } + game.austria_hungary_border_reopened_checked = false + game.austria_hungary_border_reopened_used = false + if (game.vm_event_to_do) { + game.state = 'resolve_opponent_event' + } else { + end_round() + } + } +} + +states.do_support_check = { + inactive: 'do support checks.', + prompt () { + view.prompt = `Target: ${spaces[game.selected_space].name_unique}. Roll a die.` + gen_action('roll') + }, + roll() { + clear_undo() + do_sc(spaces[game.selected_space].name_unique) + game.available_ops-- + if (game.available_ops === 0) { + game.valid_spaces = [] + } + game.state = 'support_check_prep' + return + } +} + +states.austria_hungary_border_reopened_check = { + inactive: 'decide Austria-Hungary Border Reopened', + prompt() { + view.prompt = 'Austria-Hungary Border Reopened: will both support checks be in East Germany?' + gen_action('yes') + gen_action('no') + }, + yes() { + game.austria_hungary_border_reopened_used = true + game.state = 'do_support_check' + }, + no() { + game.state = 'do_support_check' + } +} + +//======================= POWER STRUGGLE =============================== + +states.draw_power_cards = { + inactive: 'draw cards.', + prompt() { + view.prompt = 'Draw cards.' + gen_action('draw') + }, + draw() { + push_undo() + let presence = check_presence(game.pwr_struggle_in) + if (presence.dem_spaces > 0) { + game.dem_pwr_hand_limit = 6 + 2*(presence.dem_spaces - 1) + } else { + game.dem_pwr_hand_limit = 0 + } + if (presence.com_spaces > 0 ) { + game.com_pwr_hand_limit = 6 + 2*(presence.com_spaces - 1) + } else { + game.com_pwr_hand_limit = 0 + } + // Events which affect cards drawn + + if (game.persistent_events['roundtable_talks']) { + log('Democrat receives 2 cards from Communist due to C17') + game.dem_pwr_hand_limit += 2 + game.com_pwr_hand_limit -= 2 + discard_from_table(17) + game.persistent_events['roundtable_talks'] = false + } + + if (game.persistent_events['national_salvation_front'] && (game.pwr_struggle_in === 'Romania' || game.pwr_struggle_in === 'Bulgaria')) { + log('Communist receives 2 cards from Democrat due to National Salvation Front') + game.dem_pwr_hand_limit -= 2 + game.com_pwr_hand_limit += 2 + permanently_remove(102) + game.persistent_events['national_salvation_front'] = false + } + + //Draw Power Cards + game.is_pwr_struggle = true + draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand_limit, game.com_pwr_hand_limit) + game.valid_cards = all_power_cards + + //Check if The Crowd Turns Against Ceausescu occurs + if (game.persistent_events['the_crowd_turns_against_ceausescu'] && game.pwr_struggle_in === 'Romania') { + if (game.active === COM) { + game.return = COM + next_player()} + game.state = 'the_crowd_turns_against_ceausescu_prep' + } else { + game.state = 'raise_stakes_1' + } + } +} + +states.the_crowd_turns_against_ceausescu_prep = { + get inactive() { + return `resolve ${cards[54].name}.` + }, + prompt() { + view.prompt = 'The Crowd Turns Against Ceausescu: draw cards.' + gen_action('draw') + }, + draw() { + draw_cards(game.power_struggle_deck, game.ceausescu_cards, game.com_pwr_hand, 15, game.com_pwr_hand.length) + console.log('game.ceausescu_cards', game.ceausescu_cards) + game.temp = game.ceausescu_cards.filter(card => card && card >=25 && card <= 30).length + log(`Drew ${game.temp} Rally in the Squares.`) + game.temp = game.temp * 3 + game.state = 'the_crowd_turns_against_ceausescu' + } +} + +states.the_crowd_turns_against_ceausescu = { + get inactive() { + return `resolve ${cards[54].name}.` + }, + prompt() { + view.prompt = `You have ${game.temp} influence points. Play for:` + gen_action('influence') + gen_action('support_check') + }, + influence() { + push_undo() + game.ceausescu_cards = [] + valid_spaces_infl() + game.state = 'the_crowd_turns_against_ceausescu_infl' /* Send this to add_infl. Add check at end of add_infl similar to valid_spaces*/ + }, + support_check() { + push_undo() + game.ceausescu_cards = [] + valid_spaces_sc() + game.available_ops = 2 + game.state = 'support_check_prep' + } +} + +states.the_crowd_turns_against_ceausescu_infl = { + inactive: 'add influence.', + prompt () { + if (game.temp === 0) + { + view.prompt = 'Place influence: done.'; + gen_action("done"); + return; + } + + view.prompt = `Add influence: ${game.temp} remaining` + for (let space of game.valid_spaces) { + gen_action_infl(spaces[space.space_id].name_unique) + } + }, + infl(space) { + add_infl(space) + }, + done() { + if (game.return !== game.active) { + next_player() + } + game.state = 'raise_stakes_1' + } +} + +states.raise_stakes_1 = { + inactive: 'raise the stakes', + + prompt () { + console.log('game.raised_stakes_discard', game.raised_stakes_discard) + if (game.raised_stakes_discard === 3) { + view.prompt = 'Raise the stakes: done' + gen_action('done') + } else if (game.raised_stakes_discard > 0) { + view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes` + } else { + view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes` + gen_action('pass') + } + for (let card of game.valid_cards) { + gen_action_card(card) + } + }, + card(card) { + push_undo() + log(`Discarded P${power_cards[card].number}`) /*Set this to include value as with power struggle*/ + discard(card) + + game.raised_stakes_discard ++ + if (game.raised_stakes_discard === 3) { + game.raised_stakes++ + } + + + }, + pass(){ + log('Did not raise the stakes') + game.raised_stakes_discard = 0 + next_player() + game.state = 'raise_stakes_2' + }, + done () { + log('Raised the stakes') + game.raised_stakes_discard = 0 + next_player() + game.state = 'raise_stakes_2' + } +} + +states.raise_stakes_2 = { + inactive: 'raise the stakes', + + prompt () { + + if (game.raised_stakes_discard === 3) { + view.prompt = 'Raise the stakes: done' + gen_action('done') + } else if (game.raised_stakes_discard > 0) { + view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes` + } else { + view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes` + gen_action('pass') + } + for (let card of game.valid_cards) { + gen_action_card(card) + } + }, + card(card) { + push_undo() + log(`Discarded P${power_cards[card].number}`) + discard(card) + + game.raised_stakes_discard ++ + if (game.raised_stakes_discard === 3) { + game.raised_stakes++ + } + + }, + pass() { + log('Did not raise the stakes') + game.raised_stakes_discard = 0 + game.valid_cards = [] + next_player() + game.state = 'begin_power_struggle' + }, + done () { + game.raised_stakes_discard = 0 + game.valid_cards = [] + next_player() + game.state = 'begin_power_struggle' + }, +} + +states.begin_power_struggle = { + inactive: 'begin power struggle.', + prompt() { + view.prompt = 'Begin power struggle.' + gen_action('struggle') + }, + struggle () { + do_valid_cards() + game.state = 'power_struggle' + } +} + +states.power_struggle = { + inactive: 'play a card', + prompt () { + if (game.phase === 0) { + if (game.valid_cards.length > 0) { + view.prompt = "Play a card" + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else if ( game.valid_cards.length === 0) { + view.prompt = 'No valid cards. You must concede.' + gen_action('concede') + } + } + if (game.phase === 1) { + if (game.valid_cards.length > 0) { + view.prompt = `${power_cards[game.played_power_card].name} played. You must match or concede.` + gen_action('concede') + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else if (game.valid_cards.length === 0) { + view.prompt = `${power_cards[game.played_power_card].name} played. You must concede.` + gen_action('concede') + } + } + else if (game.phase === 2) { + view.prompt = 'You matched. Roll a die' + gen_action('roll') + } + else if (game.phase === 3) { + view.prompt = 'Play leader as:' + if (game.tactics_fails !== "Strike") {gen_action('strike')} + if (game.tactics_fails !== "March") {gen_action('march')} + if (game.tactics_fails !== "Rally in the Square") {gen_action('rally')} + if (game.tactics_fails !== "Petition") {gen_action('petition')} + } + }, + card(card) { + push_undo() + discard(card) + game.valid_cards=[] + game.return_state = 'power_struggle' + if (card === 52) { + log_gap(`Played P52: P${power_cards[game.played_power_card].number} no longer playable`) + + } else { + if (game.phase === 0 && leader_cards.includes(card)) {} /* Log nothing. Probably a better way to do this */ + else if (numberless_cards.includes(card)) { + log_gap(`Played: P${card}`) + } else { + log_gap(`Played: P${card} V${power_cards[card].value}`) + } + } + if (game.phase === 0) { + if (card >= 37 && card <= 48) { /*When a leader is played */ + game.played_power_card = card + game.phase = 3 + } else if (card === 49){ /*Scare Tactics */ + game.return = '' + goto_vm(349) /*Can I combine these 3 into a single stage where you goto_vm(300 + card) ? */ + } else if (card === 50) { /*Support Surges */ + if (game.active === DEM) { + game.return = COM + } else { + game.return = DEM + } + goto_vm(350) + } else if (game.phase === 0 && card === 51) { /*Support Falters */ + next_player() + goto_vm(351) + } else { + game.played_power_card = card + game.phase = 1 + next_player() + do_valid_cards() + } + } else if (game.phase === 1) { if (card === 52) { - log(`Played Tactic Fails: ${power_cards[game.played_power_card].name} no longer playable`) game.tactics_fails = power_cards[game.played_power_card].name - game.respond = 0 + game.phase = 0 next_player() do_valid_cards() + } else if (power_cards[game.played_power_card].value === 1) { + log('Takes initiative') + game.phase = 0 + do_valid_cards() } else { - log(`Played: ${power_cards[card].name} ${power_cards[card].value}. Roll for initiative`) - game.respond = 2} - } else if (game.respond === 7) { - discard(card) - game.available_ops -- - } + game.phase = 2 + } + } }, roll () { let roll = Math.floor(Math.random() * 6) + 1 log(`Rolled a ${roll}`) if (roll >= power_cards[game.played_power_card].value) { log('Initiative roll successful') - game.respond = 0 + game.phase = 0 do_valid_cards() } else { log(`Initiative roll failed. Required ${power_cards[game.played_power_card].value} or more`) - game.respond = 0 + game.phase = 0 next_player() do_valid_cards() } }, concede () { - log('Condeded') + log('Conceded') log_h2('Aftermath') log_h3('Support Loss') - if (game.played_power_card >= 25 && game.played_power_card <= 30) {game.rally_win = 2} - if (game.played_power_card >= 31 && game.played_power_card <= 36) {game.petition_win = 2} - game.respond = 0 + if ((game.played_power_card >= 25 && game.played_power_card <= 30) || game.played_power_card === 53) {game.rally_win = 2} + if ((game.played_power_card >= 31 && game.played_power_card <= 36) || game.played_power_card === 54) {game.petition_win = 2} + game.phase = 0 game.state = 'support_loss' }, strike () { - log(`Played: ${power_cards[game.played_power_card].name} as a Strike`) + log(`Played: P${power_cards[game.played_power_card].number} as a Strike`) game.played_power_card = 9 - game.respond = 1 + game.phase = 1 next_player() do_valid_cards() }, march () { - log(`Played: ${power_cards[game.played_power_card].name} as a Strike`) + log(`Played: P${power_cards[game.played_power_card].number} as a Strike`) game.played_power_card = 21 - game.respond = 1 + game.phase = 1 next_player() do_valid_cards() }, rally () { - log(`Played: ${power_cards[game.played_power_card].name} as a Rally in the Square`) + log(`Played: P${power_cards[game.played_power_card].number} as a Rally in the Square`) game.played_power_card = 53 - game.respond = 1 + game.phase = 1 next_player() do_valid_cards() }, petition () { - log(`Played: ${power_cards[game.played_power_card].name} as a Strike`) + log(`Played: P${power_cards[game.played_power_card].number} as a Petition`) game.played_power_card = 54 - game.respond = 1 + game.phase = 1 next_player() do_valid_cards() }, - draw () { + /*draw () { if (game.active === DEM) { draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand.length+2, game.com_pwr_hand.length) } else {draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand.length, game.com_pwr_hand.length+2)} - game.respond = 0 + game.phase = 0 next_player() do_valid_cards() - }, - infl(space) { + },*/ + /*infl(space) { game.remove_opponent_infl = true remove_infl(space) - game.respond = 6 + game.phase = 6 }, - /* Think the code below is now redundant */ - discard () { + discard () { /*Is this still needed? if (game.active === DEM) {discard_card(game.dem_pwr_hand)} else {discard_card(game.com_pwr_hand)} - }, + game.available_ops -- + }, */ done () { - if (game.respond === 7) { - game.respond = 0 + if (game.phase === 7) { /*Is this ever called anymore? */ + game.phase = 0 + log_msg_gap('Takes initiative') do_valid_cards() } else { - game.respond = 0 + game.phase = 0 next_player() do_valid_cards() } @@ -1035,55 +1320,66 @@ states.power_struggle = { states.support_loss ={ inactive: 'do Support Loss', prompt () { - if (game.respond === 0) { - view.prompt = 'You lost the Power Struggle. Roll a die for Support Loss' + if (game.phase === 0) { + view.prompt = 'You lost the Power Struggle. Roll a die for Support Loss.' gen_action('roll') - } else if (game.respond === 1 && game.available_ops > 0 && game.valid_spaces.length > 0) { - view.prompt = `Remove ${game.available_ops} influence` + } else if (game.phase === 1 && game.available_ops > 0 && game.valid_spaces.length > 0) { + view.prompt = `Remove ${game.available_ops} influence.` for (let space_id of game.valid_spaces) { - const space = spaces.find(s => s.space_id === space_id); - if (space) { - gen_action_infl(space.name_unique); - } + /*const space = spaces.find(s => s && s.space_id === space_id); Don't think this is needed + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} } - } else if (game.respond === 1 && game.available_ops === 0 ) { + } else if (game.phase === 1 && game.available_ops === 0 ) { view.prompt = 'Support Loss: finished' gen_action('done') - } else if (game.respond === 1 && game.valid_spaces.length === 0) { + } else if (game.phase === 1 && game.valid_spaces.length === 0) { view.prompt = 'No remaining influence to remove.' gen_action('done') } }, roll () { - let roll = Math.floor(Math.random() * 6) + let roll = Math.floor(Math.random() * 6) + 1 log(`Rolled a ${roll}`) roll = roll + game.raised_stakes + game.rally_win - game.petition_win + + // Roll modifiers + if (game.active === COM && game.persistent_events['yakovlev']) { + log('+1 from Yakovlev Counsels Gorbachev') + roll ++ + } + if (roll < 0) {roll = 0} else if (roll > 7) {roll = 7} + if (game.raised_stakes !== 0) { - log(`+${game.raised_stakes} from raising the stakes`) + log(`+${game.raised_stakes} from Raising the Stakes`) } if (game.rally_win !== 0) { - log('+2 from winning on a Rally in the Square') + log('+2 from winning on a P25') } if (game.petition_win !== 0) { - log('-2 from winning on a Petition') + log('-2 from winning on a P31') } log(`Modified roll: ${roll}`) game.available_ops = support_loss_roll[roll] - game.respond++ - valid_spaces() + game.phase++ + valid_spaces_support_loss() }, infl (space) { + game.remove_opponent_infl = false /* Don't know why this is needed... */ remove_infl(space) - valid_spaces() + if (game.available_ops === 0 ) { + game.valid_spaces = [] + } }, done () { next_player() log_h3('Victory Point') - game.respond = 0 + game.phase = 0 game.state = 'vp_roll' } } @@ -1091,13 +1387,13 @@ states.support_loss ={ states.vp_roll = { inactive: 'do VP Roll', prompt () { - if (game.respond === 0) { + if (game.phase === 0) { view.prompt = 'Roll a die for Victory' gen_action('roll') - } else if (game.respond === 1) { + } else if (game.phase === 1) { view.prompt = 'Take power' gen_action('take') - } else if (game.respond === 4) { + } else if (game.phase === 2) { view.prompt = 'Proceed to scoring' gen_action('scoring') } @@ -1106,36 +1402,44 @@ states.vp_roll = { let roll = Math.floor(Math.random() * 6) + 1 log(`Rolled a ${roll}`) roll = roll + game.raised_stakes + game.rally_win - game.petition_win + if (game.active === DEM && game.persistent_events['yakovlev']) { + log('+1 from Yakovlev Counsels Gorbachev') + roll ++ + } if (roll < 0) {roll = 0} else if (roll > 7) {roll = 7} if (game.raised_stakes !== 0) { - log(`+${game.raised_stakes} from raising the stakes`) + log(`+${game.raised_stakes} from Raising the Stakes`) } if (game.rally_win !== 0) { - log('+2 from winning on a Rally in the Square') + log('+2 from winning on a P25') } if (game.petition_win !== 0) { - log('-2 from winning on a Petition') + log('-2 from winning on a P31') } log(`Modified roll: ${roll}`) let vp_change = vp_roll[roll] log(`Gain ${vp_change} VP`) - if (roll >= 4) {log('Democrat takes power')} + if (roll >= 4) if (game.active === DEM) {game.vp += vp_change} else {game.vp -= vp_change} if (game.active === DEM && roll >= 4) { - game.respond = 1 + game.phase = 1 } else { - game.respond = 0 + game.phase = 0 + if (game.active === DEM) {next_player()} game.state = 'choose_power' } }, take () { + push_undo() + permanently_remove(game.played_card) take_power(game.pwr_struggle_in) - game.respond = 4 + game.phase = 2 }, scoring () { + push_undo() score_country(game.pwr_struggle_in) game.state = 'score_country' }, @@ -1144,51 +1448,378 @@ states.vp_roll = { states.choose_power = { inactive: 'choose whether to remain in power.', prompt () { - if (game.respond === 0) { + if (game.phase === 0) { view.prompt = 'Choose whether to remain in power' gen_action('retain') gen_action('surrender') - } else if (game.respond === 1) { + } else if (game.phase === 1) { view.prompt = 'Proceed to scoring.' gen_action('scoring') } }, retain() { + push_undo() retain_power(game.pwr_struggle_in) - game.respond = 1 + game.phase = 1 }, surrender () { + push_undo() take_power(game.pwr_struggle_in) - game.respond = 1 + permanently_remove(game.played_card) + game.phase = 1 }, scoring () { + push_undo() score_country(game.pwr_struggle_in) - if (game_over()) { - game.state = 'game_over' - } else {game.state = 'score_country'} + check_vp() + game.state = 'score_country' } } states.score_country = { inactive: `score country`, prompt () { - view.prompt = 'Scoring: done' + view.prompt = 'Scoring: done.' gen_action('done') }, done () { reset_power() + /*if (game.return !== game.active) { + next_player()}*/ + game.state = 'finish_scoring' + } +} + +states.finish_scoring ={ + inactive: 'finish scoring.', + prompt() { + view.prompt = 'End power struggle.' + gen_action('done') + } , + done() { + log('Power Struggle resolved') /*At this point log card dicarded or permanently removed? */ + check_vp() end_round() } } +// ======================================= END TURN STATES ========================================== + +states.end_turn_4_5_4 = { + inactive: 'verify held cards.', + prompt() { + view.prompt = 'End Turn: verify held cards.' + gen_action('check') + }, + check() { + log_h2('Verify held cards') + const dem_has_scoring_card = game.democrat_hand.some(card => scoring_cards.includes(card)) + const com_has_scoring_card = game.communist_hand.some(card => scoring_cards.includes(card)) + if (!dem_has_scoring_card && !com_has_scoring_card) { + log('No held scoring cards') + } + + if (dem_has_scoring_card && com_has_scoring_card) { + log('Both players have held scoring cards') + game.state = 'game_end_tie' + } + else if (dem_has_scoring_card) { + log('Democrat player has a held scoring card') + goto_game_over(COM, `${COM} won by held scoring card!`) + } + else if (com_has_scoring_card) { + log('Communist player has a held scoring card') + goto_game_over(DEM, `${DEM} won by held scoring card!`) + } + else if (game.persistent_events['new_years_eve_party']) { + log('No held scoring cards') + game.state = 'new_years_eve_party' + } + else if(game.turn === 10) { + clear_undo() + game.state = 'final_scoring_held' + log_h2('Final Scoring') + } else { + new_turn() + } + } +} + +states.final_scoring_held = { + inactive: 'resolve final scoring.', + prompt() { + view.prompt = 'Final Scoring: Communist scores VP bonus for the number of countries they retain power.' + gen_action('bonus') + }, + bonus() { + const held_countries = Object.values(game.revolutions).filter(value => value === false).length + let vp_gain = 4*held_countries + log(`Communist holds ${held_countries}: gains ${vp_gain} VP`) + game.vp -= 4*held_countries + game.scored_countries = {'East_Germany': false, 'Poland': false, 'Czechoslovakia': false, 'Hungary': false, 'Romania': false, 'Bulgaria': false} + game.state = 'final_scoring' + } +} + +states.final_scoring = { + inactive: 'score countries.', + prompt() { + if (game.scored_countries['East_Germany'] && game.scored_countries['Poland'] && game.scored_countries['Czechoslovakia'] && game.scored_countries['Hungary'] && game.scored_countries['Romania'] && game.scored_countries['Bulgaria']) { + view.prompt = 'Country scoring: done.' + gen_action('done') + } else { + view.prompt = 'Choose a country to score' + if (!game.scored_countries['East_Germany']) {gen_action('east_germany')} + if (!game.scored_countries['Poland']) {gen_action('poland')} + if (!game.scored_countries['Czechoslovakia']) {gen_action('czechoslovakia')} + if (!game.scored_countries['Hungary']) {gen_action('hungary')} + if (!game.scored_countries['Romania']) {gen_action('romania')} + if (!game.scored_countries['Bulgaria']) {gen_action('bulgaria')} + } + }, + east_germany() { + score_country('East_Germany') + game.scored_countries['East_Germany'] = true + }, + poland() { + score_country('Poland') + game.scored_countries['Poland'] = true + }, + czechoslovakia() { + score_country('Czechoslovakia') + game.scored_countries['Czechoslovakia'] = true + }, + hungary() { + score_country('Hungary') + game.scored_countries['Hungary'] = true + }, + romania() { + score_country('Romania') + game.scored_countries['Romania'] = true + }, + bulgaria() { + score_country('Bulgaria') + game.scored_countries['Bulgaria'] = true + }, + done() { + if (game.vp > 0) { + goto_game_over(DEM, `${DEM} wins on Victory Point Track!`) + } else if (game.vp < 0) { + goto_game_over(COM, `${COM} wins on Victory Point Track!`) + } else if (game.vp === 0) { + goto_game_over('', `The game is tied!`) /*Not sure what to pass for result */ + } + } +} + states.game_over = { - inactive: 'victory' + get inactive() { + return game.victory + }, + prompt() { + view.prompt = game.victory + }, +} + +// ========================== EVENT SPECIFIC STATES ================================= + +states.general_strike = { + inactive: 'discard a card.', + prompt() { + if (game.played_card === 0 ) { + view.prompt = 'General Strike: you must discard a card.' + available_cards = game.communist_hand + for (let card of available_cards) { + gen_action_card(card) + } + } else if (game.phase === 1) { + view.prompt = 'Discard a card: finished.' + gen_action('done') + } else if (game.played_card > 0 ) { + view.prompt = 'Roll a die.' + gen_action('roll') + } + }, + card (card) { + push_undo() + log(`Discarded C${cards[card].number}`) + game.played_card = card + let find_card + find_card = game.communist_hand.indexOf(card); + game.communist_hand.splice(find_card, 1); + if (game.persistent_events['perestroika'] && game.active === COM) { + log('+1 op from C25') + game.available_ops = cards[card].ops +1 + } else {game.available_ops = cards[card].ops} + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + log(`+${game.available_ops} from C${cards[game.played_card].number}.`) + let total = roll + game.available_ops + + if (total > 5) { + log('The strike is over.') + permanently_remove(5) + game.persistent_events['general_strike'] = false + } else { + log('The strike continues.') + } + game.phase = 1 + }, + done () { + end_round() + } +} + +states.honecker ={ + inactive: 'resolve Honecker.', + prompt() { + view.prompt = 'Honecker: you may take an extra action round.' + gen_action('extra') + gen_action('pass') + }, + extra() { + push_undo() + game.round++ + game.round_player = COM + game.persistent_events['honecker'] = false + game.state = 'choose_card' + }, + pass() { + log('C15: passed') + game.persistent_events['honecker'] = false + end_round() + } +} + +states.new_years_eve_party = { + get inactive() { + return `resolve ${cards[104].name}.` + }, + prompt() { + if (!game.is_pwr_struggle) { + view.prompt = 'You may choose a country to have a final power struggle.' + if (!game.revolutions['East_Germany']) {gen_action('east_germany')} + if (!game.revolutions['Poland']) {gen_action('poland')} + if (!game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (!game.revolutions['Hungary']) {gen_action('hungary')} + if (!game.revolutions['Romania']) {gen_action('romania')} + if (!game.revolutions['Bulgaria']) {gen_action('bulgaria')} + gen_action('pass') + } else { + gen_action('end') + } + }, + east_germany() { + game.pwr_struggle_in = 'East_Germany' + goto_vm(42) + }, + poland() { + game.pwr_struggle_in = 'Poland' + goto_vm(22) + }, + czechoslovakia() { + game.pwr_struggle_in = 'Czechoslovakia' + goto_vm(55) + }, + hungary() { + game.pwr_struggle_in = 'Hungary' + goto_vm(23) + }, + romania() { + game.pwr_struggle_in = 'Romania' + goto_vm(95) + }, + bulgaria () { + game.pwr_struggle_in = 'Bulgaria' + goto_vm(43) + }, + pass() { + if (game.vp > 0) { + goto_game_over(DEM, `New Year's Eve Party: ${DEM} wins on Victory Point Track!`) + } else if (game.vp < 0) { + goto_game_over(COM, `New Year's Eve Party: ${COM} wins on Victory Point Track!`) + } else if (game.vp === 0) { + goto_game_over('', `New Year's Eve Party: The game is tied!`) /*Not sure what to pass for result */ + } + }, + end() { + if (game.vp > 0) { + goto_game_over(DEM, `New Year's Eve Party: ${DEM} wins on Victory Point Track!`) + } else if (game.vp < 0) { + goto_game_over(COM, `New Year's Eve Party: ${COM} wins on Victory Point Track!`) + } else if (game.vp === 0) { + goto_game_over('', `New Year's Eve Party: The game is tied!`) /*Not sure what to pass for result */ + } + } +} + +states.stasi_end_round = { + inactive: 'choose next card due to Stasi.', + prompt() { + if (game.stasi_card === 0 ) { + view.prompt = 'Stasi: you must select your next card to play.' + let available_cards = game.democrat_hand + for (let card of available_cards) { + gen_action_card(card) + } + } else { + view.prompt = 'Stasi: choose card done.' + gen_action('done') + } + }, + card(card) { + push_undo() + log_gap(`Stasi: selected C${cards[card].number}`) + game.stasi_card = card + }, + done() { + game.round_player = COM + game.round ++ + log_h2(`Action Round ${game.round}`) + next_player() + game.valid_spaces = [] + if (game.persistent_events['general_strike']) { + game.state = 'general_strike' + } else { + game.state = 'choose_card' + } + } } -states.test = { - inactive: 'test', +states.stasi_play_card = { + inactive: 'play a card.', prompt () { - view.prompt = "test" + if (game.played_card > 0) { + game.state = 'play_card' + view.prompt = 'Play card: done' + gen_action("done"); + return; + } + + view.prompt = `Stasi: you must play ${cards[game.stasi_card].name}.` + let available_cards = [game.stasi_card] + for (let card of available_cards) { + gen_action_card(card) + } + }, + card(card) { + push_undo() + log_msg_gap(`Stasi: played C${cards[card].number}`) + game.played_card = card + let find_card + find_card = game.democrat_hand.indexOf(card); + const [playedCard] = game.democrat_hand.splice(find_card, 1); + game.available_ops = cards[card].ops + if (game.available_ops > 1 && game.persistent_events['prudence'] === DEM) { + game.available_ops-- + } + }, + done () { + game.state = 'play_card' + game.stasi_card = 0 } } @@ -1197,106 +1828,230 @@ states.test = { function add_infl(space) { - log(`Added 1 influence in ${space}.`) push_undo() const clicked_space = find_space_index(space) - - if (check_control(space)) { + //console.log('at start, event', game.persistent_events['austria_hungary_border_reopened'], 'ahbr', game.austria_hungary_border_reopened, 'tracker', game.austria_hungary_border_reopened_tracker) + log(`Added 1 influence in %${clicked_space}.`) + + if (spaces[clicked_space].country !== 'East_Germany'){ + game.austria_hungary_border_reopened_tracker = false + } + + // Check Genscher + if (game.persistent_events['genscher'] && game.active === DEM && spaces[clicked_space].country === 'East_Germany') { + game.available_ops-- + } else if (check_control(clicked_space)) { game.available_ops -= 2 } else { game.available_ops-- } + // Update influence values if (game.active === COM) { game.pieces[clicked_space].comInfl++ } else { game.pieces[clicked_space].demInfl++ } - game.pieces[clicked_space].demCtrl = 0 - game.pieces[clicked_space].comCtrl = 0 + // Check whether spaces are controlled + check_control_change(clicked_space) - if ((game.pieces[clicked_space].demInfl - game.pieces[clicked_space].comInfl) >= game.pieces[clicked_space].stability) { - game.pieces[clicked_space].demCtrl = 1 - } - if ((game.pieces[clicked_space].comInfl - game.pieces[clicked_space].demInfl) >= game.pieces[clicked_space].stability) { - game.pieces[clicked_space].comCtrl = 1 + // Check Austria Hungary Border Reoponed is true and condition has been met + if (game.available_ops === 0 && game.active === DEM && game.persistent_events['austria_hungary_border_reopened'] && game.austria_hungary_border_reopened_tracker && !game.austria_hungary_border_reopened) { + game.available_ops ++ + log('+1 influence from Austria-Hungary Border Reopened') + game.austria_hungary_border_reopened = true + game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country === 'East_Germany') } + // If only 1 IP remaining, may not place in opponent controlled spaces + // Check for Genscher + + if (game.available_ops === 1) { + if (game.active === DEM) { + if (!game.persistent_events['genscher']) { + game.valid_spaces = game.valid_spaces.filter(n => game.pieces[n].comCtrl !== 1) + } else { + game.valid_spaces = game.valid_spaces.filter(n => !(game.pieces[n].comCtrl === 1 && spaces[n].country !== 'East_Germany')) + } + } else { + game.valid_spaces = game.valid_spaces.filter(n => game.pieces[n].demCtrl !== 1) + } + } + + //Clear valid spaces if no IP remaining + if (game.available_ops === 0 ) { + game.valid_spaces = [] + } } function remove_infl(space) { - log(`Removed 1 influence from ${space}.`) push_undo() const clicked_space = find_space_index(space) - + log(`Removed 1 influence from %${clicked_space}.`) + if (game.remove_opponent_infl === true) { if (game.active === COM) { game.pieces[clicked_space].demInfl-- + if (game.pieces[clicked_space].demInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } } else { game.pieces[clicked_space].comInfl-- + if (game.pieces[clicked_space].comInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } } - - if ((game.pieces[clicked_space].demInfl - game.pieces[clicked_space].comInfl) < game.pieces[clicked_space].stability) { - game.pieces[clicked_space].demCtrl = 0 - } - if ((game.pieces[clicked_space].comInfl - game.pieces[clicked_space].demInfl) < game.pieces[clicked_space].stability) { - game.pieces[clicked_space].comCtrl = 0 - } + check_control_change(clicked_space) + } else { if (game.active === COM) { game.pieces[clicked_space].comInfl-- + if (game.pieces[clicked_space].comInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } } else { game.pieces[clicked_space].demInfl-- + if (game.pieces[clicked_space].demInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } } - - if ((game.pieces[clicked_space].demInfl - game.pieces[clicked_space].comInfl) < game.pieces[clicked_space].stability) { - game.pieces[clicked_space].demCtrl = 0 - } - if ((game.pieces[clicked_space].comInfl - game.pieces[clicked_space].demInfl) < game.pieces[clicked_space].stability) { - game.pieces[clicked_space].comCtrl = 0 - } + check_control_change(clicked_space) } game.available_ops-- } function do_sc(space) { - log(`Target: ${space}`) + log_gap(`Target: ${space}`) + let clicked_space = find_space_index(space) + + //Check Helsinki Final Act + + if (game.persistent_events['helsinki_final_act'] && (spaces[clicked_space].socio === 5 || spaces[clicked_space].socio === 6) ) { + log('+1 VP from Helsinki Final Act') + game.vp ++ + check_vp() + } + + // Continue with Support Check Logic + let roll = Math.floor(Math.random() * 6) + 1 log(`Rolled a ${roll}`) + console.log('game.vm_event', game.vm_event) + console.log('game.is_pwr_struggle', game.is_pwr_struggle) + //Check if support check is being done with game.played_card or a subsequent card (e.g. Common European Home, Dash for the West, etc) + if (game.vm_event > 0) { + roll+= cards[game.vm_event].ops + log(`+${cards[game.vm_event].ops} from card ops`) + } + // Check for the Crowd Turns Against Ceausescu - roll += cards[game.played_card].ops - log(`+${cards[game.played_card].ops} from card ops`) - + else if (game.is_pwr_struggle) { + roll += game.temp + log(`+${game.temp} from Ceausescu`) + } + + // Check if in Tiananmen Square Track Award + + else if (game.state === 'vm_tst_6_sc') { + roll = 2 + log('+2 from Tiananmen Square Track award') + } + else { + // Check for Perestoika + if (game.active === COM && game.persistent_events['perestroika']) { + roll++ + } + roll += cards[game.played_card].ops + log(`+${cards[game.played_card].ops} from card ops`) + } + + if (game.support_check_modifier > 0) { + roll += game.support_check_modifier + log(`+${game.support_check_modifier} from event`) + } + + // Events which modify SC rolls + + if (game.persistent_events['tear_gas'] && spaces[clicked_space.socio === 6]) { + roll ++ + log('+1 from C30') + permanently_remove(30) + game.persistent_events['tear_gas'] = false + } + if (game.active === DEM && spaces[clicked_space].region === 'Eastern Europe' && game.persistent_events['frg_embassies']) { + roll++ + log('+1 from C74') + } + if (game.warsaw_pact_summit) { + roll += 2 + log('+2 from C76') + } + if (game.active === DEM && spaces[clicked_space].country === 'East_Germany' && game.persistent_events['grenztruppen']) { + roll-- + log('-1 from C59') + } + if ((game.active === COM && game.persistent_events['stand_fast'] === DEM && game.pieces[clicked_space].demCtrl === 1) || (game.active === DEM && game.persistent_events['stand_fast'] === COM && game.pieces[clicked_space].comCtrl === 1)){ + roll-- + log('-1 from C100') + } + if (game.active === DEM && game.persistent_events['elena'] && spaces[clicked_space].country === 'Romania') { + roll-- + log('-1 from C101') + } + if (game.active === DEM && game.austria_hungary_border_reopened_used) { + roll++ + log(`+1 from C58`) + } + + // Continue with logic - check for adjacency + + // Events which affect adjacency - The Wall + const adj = count_adj(space) - if (adj.dem_adj > 0 || adj.com_adj > 0 ){ - if (game.active === DEM) { - roll += adj.dem_adj - roll -= adj.com_adj - if (adj.dem_adj > 0) { - log(`+${adj.dem_adj} from adjacent control`) - } - if (adj.com_adj > 0) { - log(`-${adj.com_adj} from adjacent opponent control`) - } - } else { - roll += adj.com_adj - roll -= adj.dem_adj - if (adj.com_adj > 0) { - log(`+${adj.com_adj} from adjacent control`) - } - if (adj.dem_adj > 0) { - log(`-${adj.dem_adj} from adjacent opponent control`) + if (game.active === COM && game.persistent_events['the_wall'] && spaces[clicked_space].country === 'East_Germany') { + log('No adjacency for Democrats due to The Wall') + permanently_remove(9) + roll += adj.com_adj + if (adj.com_adj > 0) { + log(`+${adj.com_adj} from adjacent control`) + } + game.persistent_events['the_wall'] = false + permanently_remove(9) + + // Standard adjacency + } else { + if (adj.dem_adj > 0 || adj.com_adj > 0 ){ + if (game.active === DEM) { + roll += adj.dem_adj + roll -= adj.com_adj + if (adj.dem_adj > 0) { + log(`+${adj.dem_adj} from adjacent control`) + } + if (adj.com_adj > 0) { + log(`-${adj.com_adj} from adjacent opponent control`) + } + } else { + roll += adj.com_adj + roll -= adj.dem_adj + if (adj.com_adj > 0) { + log(`+${adj.com_adj} from adjacent control`) + } + if (adj.dem_adj > 0) { + log(`-${adj.dem_adj} from adjacent opponent control`) + } } } + } + // Support check calcs log(`Total support check strength: ${roll}`) const stability = spaces[find_space_index(space)].stability log(`Stability is ${stability}. Defence is ${stability*2}`) const change_infl = Math.max(0, roll - stability*2) if (change_infl > 0) { - log(`${change_infl} point swing`) + log_msg_gap(`${change_infl} point swing`) let clicked_space = find_space_index(space) if(game.active === DEM) { if (change_infl > game.pieces[clicked_space].comInfl) { @@ -1306,6 +2061,9 @@ function do_sc(space) { } else { game.pieces[clicked_space].comInfl -= change_infl } + if (game.pieces[clicked_space].comInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space) + } } else { if (change_infl > game.pieces[clicked_space].demInfl) { const residual = change_infl - game.pieces[clicked_space].demInfl @@ -1314,133 +2072,196 @@ function do_sc(space) { } else { game.pieces[clicked_space].demInfl -= change_infl } + if (game.pieces[clicked_space].demInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space) + } } - game.pieces[clicked_space].demCtrl = 0 - game.pieces[clicked_space].comCtrl = 0 - if ((game.pieces[clicked_space].demInfl - game.pieces[clicked_space].comInfl) >= game.pieces[clicked_space].stability) { - game.pieces[clicked_space].demCtrl = 1 - } - if ((game.pieces[clicked_space].comInfl - game.pieces[clicked_space].demInfl) >= game.pieces[clicked_space].stability) { - game.pieces[clicked_space].comCtrl = 1 - } + check_control_change(clicked_space) + } else { - log('No change in influence') + log_msg_gap('No change in influence') } + if (game.active === COM && game.persistent_events['eco_glasnost'] && spaces[clicked_space].space_id === 66) { + log_msg_gap('+1 VP from Eco Glasnost') + game.vp++ + check_vp() + } + + // If Austria-Hungary Border Reopened used, all future support checks must be in East Germany + if (game.austria_hungary_border_reopened_used) { + game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country === 'East_Germany') + } + game.selected_space = 0 clear_undo() } -function valid_spaces() { +function valid_spaces_setup() { + game.valid_spaces = [] let valid_spaces_set = new Set(); if (game.state === 'com_init') { - for (let space of game.pieces) { - if (space.demInfl === 0) { + for (let space of game.pieces) { + if (space && space.demInfl === 0) { valid_spaces_set.add(space.space_id); } } } else if (game.state === 'dem_init') { for (let space of game.pieces) { - if (space.comInfl === 0) { + if (space && space.comInfl === 0) { valid_spaces_set.add(space.space_id); } } - } else if (game.state === 'support_check_prep' || game.state === 'do_support_check') { - if (game.active === DEM) { - for (let space of game.pieces) { - if (space.comInfl !== 0) { - valid_spaces_set.add(space.space_id); + } + // Convert the set to an array before returning + game.valid_spaces = Array.from(valid_spaces_set); + return game.valid_spaces; +} + +function valid_spaces_sc() { + let valid_spaces_set = new Set(); + if (game.active === DEM) { + for (let space of game.pieces) { + if (space && space.comInfl !== 0 ) { + valid_spaces_set.add(space.space_id); + } + } + } else { + for (let space of game.pieces) { + if (space && space.demInfl !== 0 ) { + if (game.persistent_events['solidarity_legalised']) { + if (space.space_id === 14) {continue} } - } - } else { - for (let space of game.pieces) { - if (space.demInfl !== 0) { - valid_spaces_set.add(space.space_id); + if (game.persistent_events['civic_forum']) { + if (space.space_id === 31) {continue} + } + if (game.persistent_events['we_are_the_people']) { + if (space.space_id === 9) {continue} + } + valid_spaces_set.add(space.space_id); + } + } + + //Check for Foreign Currency Debt Burden + if (game.persistent_events['foreign_currency_debt_burden'] !== '') { + for (let n of valid_spaces_set) { + if (spaces[n].country === game.persistent_events['foreign_currency_debt_burden']) { + valid_spaces_set.delete(n); } } } - } else if (game.state === 'support_loss') { + } + + // Convert the set to an array before returning + game.valid_spaces = Array.from(valid_spaces_set); + + //Check for the Crown Turns Against Ceausescu + if (game.is_pwr_struggle && game.pwr_struggle_in === 'Romania' && game.persistent_events['the_crowd_turns_against_ceausescu']) { + game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country === 'Romania') + } + return game.valid_spaces; +} + +function valid_spaces_support_loss() { + let valid_spaces_set = new Set(); + if (game.state === 'support_loss') { if (game.active === DEM) { for (let piece of game.pieces) { - let space = spaces.find(s => s.space_id === piece.space_id); + if (!piece) continue + let space = spaces.find(s => s && s.space_id === piece.space_id); if (space && piece.demInfl > 0 && space.country === game.pwr_struggle_in) { valid_spaces_set.add(space.space_id); } } } else { for (let piece of game.pieces) { - let space = spaces.find(s => s.space_id === piece.space_id); + if (!piece) continue + let space = spaces.find(s => s && s.space_id === piece.space_id); if (space && piece.comInfl > 0 && space.country === game.pwr_struggle_in) { valid_spaces_set.add(space.space_id); } } } - } else if (game.state === 'power_struggle') { - if (game.active === DEM) { - for (let piece of game.pieces) { - let space = spaces.find(s => s.space_id === piece.space_id); - if (space && piece.comInfl > 0 && space.country === game.pwr_struggle_in) { - valid_spaces_set.add(space.space_id); - } + } + // Convert the set to an array before returning + game.valid_spaces = Array.from(valid_spaces_set); + return game.valid_spaces; +} + +function valid_spaces_support_falters() { + let valid_spaces_set = new Set(); + if (game.active === DEM) { + for (let piece of game.pieces) { + if (!piece) continue + let space = spaces.find(s => s && s.space_id === piece.space_id); + if (space && piece.comInfl > 0 && space.country === game.pwr_struggle_in) { + valid_spaces_set.add(space.space_id); } - } else { - for (let piece of game.pieces) { - let space = spaces.find(s => s.space_id === piece.space_id); - if (space && piece.demInfl > 0 && space.country === game.pwr_struggle_in) { - valid_spaces_set.add(space.space_id); - } + } + } else { + for (let piece of game.pieces) { + if (!piece) continue + let space = spaces.find(s => s && s.space_id === piece.space_id); + if (space && piece.demInfl > 0 && space.country === game.pwr_struggle_in) { + valid_spaces_set.add(space.space_id); } } } + // Convert the set to an array before returning + game.valid_spaces = Array.from(valid_spaces_set); + return game.valid_spaces; +} - else { - // Iterate over all spaces to find the ones with the player's influence - for (let piece of game.pieces) { - const player_influence = game.active === COM ? piece.comInfl : piece.demInfl; +function valid_spaces_infl() { + let valid_spaces_set = new Set(); + // Iterate over all spaces to find the ones with the player's influence + for (let piece of game.pieces) { + if (!piece) continue + const player_influence = game.active === COM ? piece.comInfl : piece.demInfl; - // If the piece has the player's influence, add it and its adjacent spaces to the set - if (player_influence > 0) { - valid_spaces_set.add(piece.space_id); - - // Find the corresponding space in the `spaces` array to get the adjacency information - const space = spaces.find(s => s.space_id === piece.space_id); - if (space) { - for (let adj_space_id of space.adjacent) { - if (adj_space_id) { - const adj_piece = game.pieces.find(p => p.space_id === adj_space_id); - const adj_space = spaces.find(s => s.space_id === adj_space_id); - - // Check if the adjacent space is controlled by the opponent - const opponent_control = game.active === COM ? adj_piece.demCtrl : adj_piece.comCtrl; - - // Only add the adjacent space if the available_ops >= 2 or the space is not controlled by the opponent - if (game.available_ops >= 2 || !opponent_control) { - valid_spaces_set.add(adj_space.space_id); - } - } + // If the piece has the player's influence, add it and its adjacent spaces to the set + if (player_influence > 0) { + valid_spaces_set.add(piece.space_id); + + // Check adjacency information + for (let adj_space_id of piece.adjacent) { + if (adj_space_id) { + const adj_piece = game.pieces.find(p => p && p.space_id === adj_space_id); + + // Check if the adjacent space is controlled by the opponent + const opponent_control = game.active === COM ? adj_piece.demCtrl : adj_piece.comCtrl; + //Check for Genscher. Can always place in East Germany even with 1 op + if (game.active === DEM && adj_piece.country === 'East_Germany' && game.persistent_events['genscher']){ + valid_spaces_set.add(adj_piece.space_id) + } + + // Otherwise, only add the adjacent space if the available_ops >= 2 or the space is not controlled by the opponent + if (game.available_ops >= 2 || !opponent_control) { + valid_spaces_set.add(adj_piece.space_id) } - } + } } - } - } - game.valid_spaces = Array.from(valid_spaces_set); - return game.valid_spaces; + } + } + // Convert the set to an array before returning + game.valid_spaces = Array.from(valid_spaces_set); + return game.valid_spaces; } function valid_cards(player_hand, presence) { const valid_cards_set= new Set(); - if (game.respond === 0) { + if (game.phase === 0) { for (let c of player_hand) { let card = power_cards.find(card => card && card.number === c); if (card.number === 52) {continue} // Never add tactics fails - if (card.name === game.tactics_fails) {continue} + if (card.name === game.tactics_fails) {continue} //Cannot play the suit of Tactics Fails if (card.socio === 0) { valid_cards_set.add(card.number); } else if (leaders.includes(card.socio) && presence[card.socio]) { valid_cards_set.add(card.number); } } - } else if (game.respond === 1) { + } else if (game.phase === 1) { for (let c of player_hand) { let card = power_cards.find(card => card && card.number === c); if (card.name === power_cards[game.played_power_card].name) { @@ -1470,24 +2291,51 @@ function count_adj(name_unique) { for (let adj_space_id of space.adjacent) { if (adj_space_id) { - const adj_piece = game.pieces.find(piece => piece.space_id === adj_space_id); + const adj_piece = game.pieces.find(piece => piece && piece.space_id === adj_space_id); if (adj_piece) { if (adj_piece.demCtrl === 1) { + console.log(adj_piece.name_unique, 'is dem controlled') dem_adj++ } if (adj_piece.comCtrl === 1) { + console.log(adj_piece.name_unique, 'is com controlled') com_adj++ } } } } + console.log('dem_adj: ', dem_adj, 'com_adj: ', com_adj) + return {dem_adj, com_adj} +} + +function count_adj_worker(space_id) { + const space = spaces[space_id] + let dem_adj = 0 + let com_adj = 0 + + for (let adj_space_id of space.adjacent) { + if (adj_space_id) { + const adj_space = spaces[adj_space_id] + if (adj_space && adj_space.socio === 4) { + const adj_piece = game.pieces.find(piece => piece && piece.space_id === adj_space_id ); + if (adj_piece) { + if (adj_piece.demCtrl === 1 ) { + dem_adj++ + } + if (adj_piece.comCtrl === 1 ) { + com_adj++ + } + } + } + } + } return {dem_adj, com_adj} } -function check_control(space) { - if (game.active === 'COM' && space.demCtrl === 1) { +function check_control(space_id) { + if (game.active === COM && game.pieces[space_id].demCtrl === 1) { return true; - } else if (game.active === 'DEM' && space.comCtrl === 1) { + } else if (game.active === DEM && game.pieces[space_id].comCtrl === 1) { return true; } else { return false; @@ -1500,21 +2348,35 @@ function do_tst_attempt() { roll += game.available_ops log(`+${game.available_ops} from the card operations value`) + + // TIANANMEN SQUARE MODIFIERS + if (game.active === DEM && game.dem_tst_attempted === 1 || game.active === COM && game.com_tst_attempted === 1) { - roll += 1; + roll ++; log('+1 modifier from previous Tiananmen Square Track attempts') } if ((game.active === DEM && cards[game.played_card].side === 'D') || (game.active === COM && cards[game.played_card].side === 'C')) { - roll += 1; + roll ++; log('+1 for playing own card'); } + if (game.active === COM && game.persistent_events['li_peng']) { + roll ++ + log('+1 from Li Peng') + } log(`Modified die roll: ${roll}`) + + // TIANANMEN SQUARE ATTEMPT + game.return = game.active + game.return_state = 'tiananmen_square_attempt' if (game.active === DEM) { game.dem_tst_attempted_this_turn = 1 if (roll >= dem_tst_req[game.dem_tst_position]) { log(`${dem_tst_req[game.dem_tst_position]} required: success`) + game.tst_success = true game.dem_tst_position++ game.dem_tst_attempted = 0 + if (game.dem_tst_position === 3 && game.com_tst_position < 3) {goto_vm(203)} + if (game.dem_tst_position === 4 && game.com_tst_position < 4) {goto_vm(204)} } else { log(`${dem_tst_req[game.dem_tst_position]} required: fail`) game.dem_tst_attempted = 1 @@ -1523,13 +2385,20 @@ function do_tst_attempt() { game.com_tst_attempted_this_turn = 1 if (roll >= com_tst_req[game.com_tst_position]) { log(`${com_tst_req[game.com_tst_position]} required: success`) + game.tst_success = true game.com_tst_position++ game.com_tst_attempted = 0 + if (game.com_tst_position === 3 && game.dem_tst_position < 3) {goto_vm(203)} + if (game.com_tst_position === 4 && game.dem_tst_position < 4) {goto_vm(204)} } else { log(`${com_tst_req[game.com_tst_position]} required: fail`) game.com_tst_attempted = 1 } } + // Check whether The Reformer is playable: + if ((game.dem_tst_position !== game.com_tst_position)) { + game.playable_cards[67] = 2 + } } function check_presence(country) { @@ -1543,9 +2412,9 @@ function check_presence(country) { for (let space of spaces) { - if (space.country === country) { + if (space && space.country === country) { - let piece = game.pieces.find(p => p.space_id === space.space_id); + let piece = game.pieces.find(p => p && p.space_id === space.space_id); if (piece.demCtrl === 1) { dem_spaces++; @@ -1604,29 +2473,29 @@ function battlegrounds(country) { } function take_power(country) { + log(`Democrat takes power in ${game.pwr_struggle_in}`) game.revolutions[country] = true + } function retain_power(country){ game.times_held[country]++ let vp_gain = get_value(country)*game.times_held[country] - log(`Communist gains ${vp_gain}VP from holding power`) + log(`Chooses to retain power`) + log(`-${vp_gain} VP`) game.vp -= vp_gain } -function find_country(country) { - return countries.indexOf(country) -} - function score_country(country) { - log_h3('Scoring') + log_h3(`Scoring: ${country}`) let status let presence = check_presence(country) - if (presence.dem_domination) {status = "Democrat has domination"} - else if (presence.com_domination) {status = "Communist has domination"} - else if (presence.dem_control) {status = "Democrat has control"} + console.log('presence: ', presence) + if (presence.dem_control) {status = "Democrat has control"} else if (presence.com_control) {status = "Communist has control"} + else if (presence.dem_domination) {status = "Democrat has domination"} + else if (presence.com_domination) {status = "Communist has domination"} else {status = "No domination or control"} log(`${status}`) log(`${presence.dem_battlegrounds} Democrat battlegrounds`) @@ -1637,7 +2506,8 @@ function score_country(country) { if (presence.dem_spaces > 0) {dem_vp += value} if (presence.dem_domination) {dem_vp += value} if (presence.dem_control && country !== "Hungary") { - dem_vp += value} + dem_vp += value + } else if (presence.dem_control && country === "Hungary") {dem_vp += 2} dem_vp += presence.dem_battlegrounds @@ -1654,41 +2524,245 @@ function score_country(country) { function get_value(country) { let value - if (country === "East Germany" || country === "Poland") {value = 3} - else if (country === "Czechoslovakia" || country === "Romania" || country === "Bulgaria") {value = 2} + if (country === "East_Germany" || country === "Poland") {value = 3} + else if (country === "Czechoslovakia" || country === "Romania") {value = 2} else value = 1 return value } +function permanently_remove(card) { + console.log('card:', card) + log(`C${cards[card].number} permanently removed`) + let card_index = game.strategy_discard.indexOf(card) + if (card_index !== -1) { + console.log('sub 1 called') + game.strategy_discard.splice(card_index, 1) + } + card_index = game.table_cards.indexOf(card) + if (card_index !== -1) { + console.log('sub 2 called') + game.table_cards.splice(card_index, 1) + } + game.strategy_removed.push(card) + console.log('game.strategy_removed', game.strategy_removed) +} + +function check_vp() { + if (game.vp >= 20) { + goto_game_over(DEM, `${DEM} won an Automatic Victory!`) + } else if(game.vp <= -20) { + goto_game_over(COM, `${COM} won an Automatic Victory!`) + } +} + function game_over() { if (game.vp >= 20 || game.vp <= -20) { return true } else { return false} } +function goto_game_over(result, victory) { + game.state = "game_over" + game.active = "None" + game.result = result + game.victory = victory + log_h1("Game Over") + log(game.victory) + //return true + +} + // =========== MOVING THROUGH TURNS ============ function end_round() { + //Check if the game is over! + if (game.state === 'game_over') { + console.log('in end') + return} + + //Check if the card has been removed or played to table. If not, discard. + if (!game.strategy_removed.includes(game.played_card) && !game.table_cards.includes(game.played_card)) { + game.strategy_discard.push(game.played_card) + } + + //Reset game.played_card = 0 + game.temp = 0 + game.vm_event = 0 + game.phase = 0 + game.remove_opponent_infl = false game.is_pwr_struggle = false - if (game.active === DEM && game.round === 7) { - new_turn() - game.state = 'choose_card' + game.vm_infl_to_do = false /*Can get rid of this and use game.return_state? */ + game.vm_event_to_do = false + game.vm_active_country = '' + game.return_state = '' + game.discard = false + game.warsaw_pact_summit = false + game.vm_influence_added = {} + game.return = '' + game.valid_cards = [] + game.valid_spaces = [] + + // Check for duplicate card entries + let card_check = [...game.strategy_deck, ...game.strategy_discard, ...game.strategy_removed, ...game.table_cards, ...game.communist_hand, ... game.democrat_hand]; + + function check_duplicates(array) { + return new Set(array).size !== array.length; + } + + function find_duplicates(array) { + const duplicates = array.filter((item, index) => array.indexOf(item) !== index); + return [...new Set(duplicates)]; + } + + console.log('game.strategy_deck', game.strategy_deck, 'game.strategy_discard', game.strategy_discard, 'game.strategy_removed', game.strategy_removed, 'game.table_cards', game.table_cards, 'game.communist_hand', game.communist_hand, 'game.democrat_hand', game.democrat_hand) + + if (check_duplicates(card_check)) { + const duplicates = find_duplicates(card_check) + console.log('discard', game.strategy_discard, 'removed', game.strategy_removed, 'game.table_cards', game.table_cards, 'com hand', game.communist_hand, 'dem hand', game.democrat_hand) + throw new Error(`Duplicate cards detected: ${duplicates.join(', ')}`) + } + console.log('cards in game', card_check.length) + card_check = card_check.sort((a, b) => a - b) + console.log('cards in game', card_check) + if (game.turn <= 3) { + if (card_check.length !== 40) { + throw new Error(`Wrong number of cards: ${card_check.length}`) + } + } else if (game.turn <=7) { + if (card_check.length !== 81) { + throw new Error(`Wrong number of cards: ${card_check.length}`) + } + } else if (card_check.length !== 110) { + throw new Error(`Wrong number of cards: ${card_check.length}`) + } + + + + // Resolve Events + + if (game.persistent_events['austria_hungary_border_reopened']) { + game.austria_hungary_border_reopened = false + game.austria_hungary_border_reopened_tracker = true + } + + console.log('game.dem_tst_position ', game.dem_tst_position , 'game.com_tst_position ', game.com_tst_position ) + // Check if last round and if so resolve end turn events + if (game.round_player === DEM && game.round === 7) { + if(game.persistent_events['honecker']) { + next_player() + game.state = 'honecker' + return + } /*else if (game.persistent_events['new_years_eve_party']) { + game.state = 'new_years_eve_party' + return + } */ + else if (game.dem_tst_position >= 6 && game.com_tst_position <= 5) { + log_h2('Tiananmen Square Track Award') + if (game.active !== DEM) { + next_player() + } + game.return = game.active + clear_undo() + game.return_state = 'end_turn_4_5_4' + goto_vm(206) + return + } else if (game.com_tst_position >= 6 && game.dem_tst_position <= 5) { + log_h2('Tiananmen Square Track Award') + if (game.active !== COM) { + next_player() + } + game.return = game.active + clear_undo() + game.return_state = 'end_turn_4_5_4' + goto_vm(206) return } + else { + clear_undo() + game.state = 'end_turn_4_5_4' + return + } + } + + // Resolve end action round - if (game.active===COM) { + if(game.round_player === COM && game.stasi_card > 0 ) { game.round_player = DEM - } else { - game.round_player = COM - game.round ++ - log_h2(`Action Round ${game.round}`) + if (game.active !== DEM) { + next_player() + } + game.state = 'stasi_play_card' + return + } else if (game.round_player === COM && game.round === 8) { + clear_undo() + game.state = 'end_turn_4_5_4' + return + } else if (game.round_player===COM) { + game.round_player = DEM + if (game.active !== DEM) { + next_player() + } + game.state = 'choose_card' + return } - next_player() - game.state = 'choose_card' - game.valid_spaces = [] + if (game.round_player === DEM) { + if(game.persistent_events['stasi']) { + //console.log('stasi sub function') + if (game.active !== DEM) { + next_player() + } + game.state = 'stasi_end_round' + return + } else if(game.round_player === DEM && game.persistent_events['general_strike']){ + game.state = 'general_strike' + game.round ++ + log_h2(`Action Round ${game.round}`) + game.round_player = COM + if (game.active !== COM) { + next_player() + } + return + } else { + game.state = 'choose_card' + game.round_player = COM + game.round ++ + if (game.active !== COM) { + next_player() + } + log_h2(`Action Round ${game.round}`) + } + } + //game.state = 'choose_card' Does this do anything any more? } +/* +function end_turn(){ + /*End Turn sequence + TST support check + Verify held cards + New Year's Eve Party + Advance Turn Marker + +// CHECK FOR OPTIONAL SUPPORT CHECK + if (game.dem_tst_position >=6 && game.com_tst_position <= 5) { + if (game.active !== DEM) { + next_player_() + } + game.state = 'tst_support_check' + } + if (game.com_tst_position >=6 && game.dem_tst_position <= 5) { + if (game.active !== COM) { + next_player_() + } + game.state = 'tst_support_check' + } + + +//CHECK HELD CARDS + +} */ + function new_turn() { clear_undo() game.turn ++ @@ -1698,6 +2772,55 @@ function new_turn() { game.round_player = COM game.dem_tst_attempted_this_turn = 0 game.com_tst_attempted_this_turn = 0 + game.tst_7 = false + game.tst_8 = false + game.persistent_events['perestroika'] = false + game.persistent_events['prudence'] = '' + game.persistent_events['sinatra_doctrine'] = false + game.persistent_events['stasi'] = false + game.persistent_events['honecker'] = false + + //Remove Events on the table which last only 1 turn + console.log('in new turn') + if (game.persistent_events['austria_hungary_border_reopened']) { + game.persistent_events['austria_hungary_border_reopened'] = false + permanently_remove(58) + } + if (game.persistent_events['elena']) { + game.persistent_events['elena'] = false + permanently_remove(101) + } + if (game.persistent_events['grenztruppen']) { + game.persistent_events['grenztruppen'] = false + permanently_remove(59) + } + + if (game.persistent_events['foreign_currency_debt_burden'] !== '') { + game.persistent_events['foreign_currency_debt_burden'] = '' + permanently_remove(49) + } + + if (game.persistent_events['frg_embassies']) { + console.log('in new turn - frg embassies check') + game.persistent_events['frg_embassies'] = false + permanently_remove(74) + } + + if (game.persistent_events['genscher']) { + game.persistent_events['genscher'] = false + permanently_remove(63) + } + + if (game.persistent_events['stand_fast'] !== '') { + game.persistent_events['stand_fast'] = '' + permanently_remove(100) + } + + if (game.samizdat_card > 0 ) { + game.democrat_hand.push(game.samizdat_card) + game.samizdat_card = 0 + } + log_h1("Turn " + game.turn) if (game.turn === 4) { @@ -1707,15 +2830,50 @@ function new_turn() { add_lateyear() } if (game.turn > 1) { + if (game.persistent_events['presidential_visit']) { + game.com_hand_limit = 7 + log('Communist draws 7 cards due to Presidential Visit') + permanently_remove(65) + game.persistent_events['presidential_visit'] = false + } + console.log('deck', game.strategy_deck) + console.log('game.com_hand_limit', game.com_hand_limit, 'communist hand before draw', game.communist_hand) draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.dem_hand_limit, game.com_hand_limit) + game.com_hand_limit = 8 + console.log('communist hand after draw', game.communist_hand) + } - log_h2("Action Round " + game.round) - log_side() + + //Check if TST effects need to be resolved + if (game.dem_tst_position >=5 && game.com_tst_position <= 4) { + log_h2('Tiananmen Square Track award') + if(game.active !== DEM) { next_player() } + for (let card of game.democrat_hand) { + if (scoring_cards.includes(card)) continue + game.valid_cards.push(card) + } + game.state = 'tst_goddess' /* Goddess only name of Democrat bonus, not Communist*/ + return + } + else if (game.com_tst_position >=5 && game.dem_tst_position <= 4) { + log_h2('Tiananmen Square Track award') + if(game.active !== COM) { next_player() } + for (let card of game.communist_hand) { + if (scoring_cards.includes(card)) continue + game.valid_cards.push(card) + } + game.state = 'tst_goddess' + } else { + log_h2("Action Round " + game.round) + log_side() + //console.log('in start new AR call, game.active', game.active) + game.state = 'choose_card' + } } function next_player() { clear_undo() - + //console.log('next player called') if (game.active === DEM) game.active = COM else @@ -1724,12 +2882,17 @@ function next_player() { log_side() } -function find_space_index(name_unique) { - return game.pieces.findIndex(piece => piece && piece.name_unique === name_unique); +function change_player() { + clear_undo() + //console.log('next player called') + if (game.active === DEM) + game.active = COM + else + game.active = DEM } -function find_card_index(card) { - return cards.findIndex(card => card && card.number === card); +function find_space_index(name_unique) { + return game.pieces.findIndex(piece => piece && piece.name_unique === name_unique); } function draw_deck(deck) { @@ -1737,50 +2900,64 @@ function draw_deck(deck) { } function draw_cards(deck, democrat_hand, communist_hand, dem_hand_limit, com_hand_limit) { + //console.log('game.valid_cards at start of draw cards: ', game.valid_cards) let turn = 'communist'; // Start with the communist player + //console.log('game.strategy_deck', game.strategy_deck) + //console.log('deck', deck, 'democrat_hand', democrat_hand, 'communist_hand', communist_hand, 'dem_hand_limit', dem_hand_limit, 'com_hand_limit', com_hand_limit) while (democrat_hand.length < dem_hand_limit || communist_hand.length < com_hand_limit) { + //console.log('deck.length: ', deck.length) + //console.log('discard.length', game.strategy_discard ) if (deck.length === 0) { log_h3('--- Reshuffle ---') + deck.push(...game.strategy_discard) game.strategy_discard = [] } else if (turn === 'communist' && communist_hand.length < com_hand_limit) { communist_hand.push(draw_card(deck)); + //console.log('game.valid_cards after communist draw: ', JSON.stringify(game.valid_cards)); turn = 'democrat'; } else if(turn === 'communist' && communist_hand.length === com_hand_limit) { turn = 'democrat'; } else if (turn === 'democrat' && democrat_hand.length < dem_hand_limit) { democrat_hand.push(draw_card(deck)); + //console.log('democrat_hand: ', democrat_hand) + + //console.log('game.valid_cards after democrat draw: ', JSON.stringify(game.valid_cards)); turn = 'communist'; } else if (turn === 'democrat' && democrat_hand.length === dem_hand_limit) { turn = 'communist'; } } + clear_undo() -} +} function draw_card(deck) { - const randomIndex = Math.floor(Math.random() * deck.length); + //console.log('draw card called with:', deck) + const randomIndex = Math.floor(Math.random() * deck.length) + //console.log('card chosen:', randomIndex) return deck.splice(randomIndex, 1)[0]; } function discard(card) { + //console.log('in discard(card)') let find_card if (!game.is_pwr_struggle) { if (game.active === COM) { - find_card = game.communist_hand.indexOf(card); - game.communist_hand.splice(find_card, 1); + find_card = game.communist_hand.indexOf(card) + game.communist_hand.splice(find_card, 1) } else { - find_card = game.democrat_hand.indexOf(card); - game.democrat_hand.splice(find_card, 1); + find_card = game.democrat_hand.indexOf(card) + game.democrat_hand.splice(find_card, 1) } game.strategy_discard.push(card) + log(`Discarded C${cards[card].number}`) } else if (game.is_pwr_struggle) { - log(`Discarded ${power_cards[card].name}`) if (game.active === COM) { find_card = game.com_pwr_hand.indexOf(card); game.com_pwr_hand.splice(find_card, 1); @@ -1789,45 +2966,104 @@ function discard(card) { game.dem_pwr_hand.splice(find_card, 1); } game.power_struggle_discard.push(card) + //log(`Discarded P${power_cards[card].number}`) + } + +} + +function discard_card(hand) { + let find_card + let card = Math.floor(Math.random()*hand.length) + let discarded_card = hand.splice(card, 1)[0] + if (game.is_pwr_struggle) { + if (numberless_cards.includes(discarded_card)) { + log_gap(`Discarded: P${discarded_card}`) + } else { + log_gap(`Discarded: P${discarded_card} V${power_cards[discarded_card].value}`) + } + } else { + log(`Discarded C${cards[discarded_card].number}`) + game.strategy_discard.push(discarded_card) } + return discarded_card +} +function discard_from_table(card) { + find_card = game.table_cards.indexOf(card) + game.table_cards.splice(find_card, 1) + game.strategy_discard.push(card) } + function add_midyear() { - const mid_year = cards.filter(card => card && card.period === 2).map(card => card.number) - game.strategy_deck.push(...mid_year) + const mid_year = cards.filter(card => card && card.period === 2).map(card => card.number); + game.strategy_deck.push(...mid_year); log_h3('Mid-year cards added to draw deck') } + function add_lateyear() { - const late_year = cards.filter(card => card && card.period === 2).map(card => card.number) + const late_year = cards.filter(card => card && card.period === 3).map(card => card.number) game.strategy_deck.push(...late_year) - log_h3('Late-year cards added to draw deck') + log_h3('Late-year cards added to draw deck') } function reset_power() { - game.power_struggle_deck = power_cards.filter(card => card !== null).map(card => card.number) + game.power_struggle_deck = power_cards.filter(card => card !== null && card.number <= 52).map(card => card.number) game.dem_pwr_hand = [] game.com_pwr_hand = [] - game.respond = 0 + game.phase = 1 game.raised_stakes_round = 0 - game.raise_stakes = 0 + game.raised_stakes = 0 + game.rally_win = 0 + game.petition_win = 0 game.tactics_fails = '' + + if (game.persistent_events['peasant_parties_revolt']){ + permanently_remove(72) + game.table_cards = game.table_cards.filter(card => card !== 72) + game.persistent_events['peasant_parties_revolt'] = false + } + if (game.persistent_events['yakovlev']) { + permanently_remove(62) + game.table_cards = game.table_cards.filter(card => card !== 62) + game.persistent_events['yakovlev'] = false + } + if (game.persistent_events['the_crowd_turns_against_ceausescu']){ + permanently_remove(54) + game.table_cards = game.table_cards.filter(card => card !== 54) + game.persistent_events['the_crowd_turns_against_ceausescu'] = false + } } -// === COMMON LIBRARY === +function check_control_change(space_id) { + game.pieces[space_id].demCtrl = 0 + game.pieces[space_id].comCtrl = 0 + + if ((game.pieces[space_id].demInfl - game.pieces[space_id].comInfl) >= game.pieces[space_id].stability) { + game.pieces[space_id].demCtrl = 1 + } + if ((game.pieces[space_id].comInfl - game.pieces[space_id].demInfl) >= game.pieces[space_id].stability) { + game.pieces[space_id].comCtrl = 1 + } + + // Check if the Tyrant is Gone has been fulfilled + if (game.persistent_events['the_tyrant_is_gone'] > 0 && game.pieces[game.persistent_events['the_tyrant_is_gone']].demCtrl === 1) { + log('+2 VP from The Tyrant is Gone') + game.persistent_events['the_tyrant_is_gone'] = 0 + } +} -function shuffle(list) { - // Fisher-Yates shuffle - for (let i = list.length - 1; i > 0; --i) { - let j = random(i + 1) - let tmp = list[j] - list[j] = list[i] - list[i] = tmp +function check_systematisation() { + // Check for Systematisation - may not use this space + if (game.persistent_events['systematization'] > 0) { + game.valid_spaces = game.valid_spaces.filter(n => n !== game.persistent_events['systematization']) } - return list } +const pluralize = (count, noun, suffix = 's') => + `${count} ${noun}${count !== 1 ? suffix : ''}` + // ======== LOG COMMANDS ============= function log(msg) { @@ -1860,6 +3096,17 @@ function log_h3(msg) { log(".h3 " + msg) } +function log_gap(msg) { + log_br() + game.log.push(msg) +} + +function log_msg_gap(msg) { + game.log.push(msg) + log_br() +} + + function log_side() { log_br() if (game.active === DEM) @@ -1931,127 +3178,4101 @@ function object_copy(original) { } -/* =================== EVENTS ================================ */ +/* =================== VM FUNCTIONS ========================== */ -global.event_1 = function() {console.log('event 1 called')} -global.event_2 = function() {console.log('event 2 called')} -global.event_3 = function() {console.log('event 3 called')} -global.event_4 = function() {console.log('event 4 called')} -global.event_5 = function() {console.log('event 5 called')} -global.event_6 = function() {console.log('event 6 called')} -global.event_7 = function() {console.log('event 7 called')} -global.event_8 = function() {console.log('event 8 called')} -global.event_9 = function() {console.log('event 9 called')} -global.event_10 = function() {console.log('event 10 called')} -global.event_11 = function() {console.log('event 11 called')} -global.event_12 = function() {console.log('event 12 called')} -global.event_13 = function() {console.log('event 13 called')} -global.event_14 = function() {console.log('event 14 called')} -global.event_15 = function() {console.log('event 15 called')} -global.event_16 = function() {console.log('event 16 called')} -global.event_17 = function() {console.log('event 17 called')} -global.event_18 = function() {console.log('event 18 called')} -global.event_19 = function() {console.log('event 19 called')} -global.event_20 = function() {console.log('event 20 called')} -global.event_21 = function() {console.log('event 21 called')} -global.event_22 = function() {console.log('event 22 called')} -global.event_23 = function() {console.log('event 23 called')} -global.event_24 = function() {console.log('event 24 called')} -global.event_25 = function() {console.log('event 25 called')} -global.event_26 = function() {console.log('event 26 called')} -global.event_27 = function() {console.log('event 27 called')} -global.event_28 = function() {console.log('event 28 called')} -global.event_29 = function() {console.log('event 29 called')} -global.event_30 = function() {console.log('event 30 called')} -global.event_31 = function() {console.log('event 31 called')} -global.event_32 = function() {console.log('event 32 called')} -global.event_33 = function() {console.log('event 33 called')} -global.event_34 = function() {console.log('event 34 called')} -global.event_35 = function() {console.log('event 35 called')} -global.event_36 = function() {console.log('event 36 called')} -global.event_37 = function() {console.log('event 37 called')} -global.event_38 = function() {console.log('event 38 called')} -global.event_39 = function() {console.log('event 39 called')} -global.event_40 = function() {console.log('event 40 called')} -global.event_41 = function() {console.log('event 41 called')} -global.event_42 = function() {console.log('event 42 called')} -global.event_43 = function() {console.log('event 43 called')} -global.event_44 = function() {console.log('event 44 called')} -global.event_45 = function() {console.log('event 45 called')} -global.event_46 = function() {console.log('event 46 called')} -global.event_47 = function() {console.log('event 47 called')} -global.event_48 = function() {console.log('event 48 called')} -global.event_49 = function() {console.log('event 49 called')} -global.event_50 = function() {console.log('event 50 called')} -global.event_51 = function() {console.log('event 51 called')} -global.event_52 = function() {console.log('event 52 called')} -global.event_53 = function() {console.log('event 53 called')} -global.event_54 = function() {console.log('event 54 called')} -global.event_55 = function() {console.log('event 55 called')} -global.event_56 = function() {console.log('event 56 called')} -global.event_57 = function() {console.log('event 57 called')} -global.event_58 = function() {console.log('event 58 called')} -global.event_59 = function() {console.log('event 59 called')} -global.event_60 = function() {console.log('event 60 called')} -global.event_61 = function() {console.log('event 61 called')} -global.event_62 = function() {console.log('event 62 called')} -global.event_63 = function() {console.log('event 63 called')} -global.event_64 = function() {console.log('event 64 called')} -global.event_65 = function() {console.log('event 65 called')} -global.event_66 = function() {console.log('event 66 called')} -global.event_67 = function() {console.log('event 67 called')} -global.event_68 = function() {console.log('event 68 called')} -global.event_69 = function() {console.log('event 69 called')} -global.event_70 = function() {console.log('event 70 called')} -global.event_71 = function() {console.log('event 71 called')} -global.event_72 = function() {console.log('event 72 called')} -global.event_73 = function() {console.log('event 73 called')} -global.event_74 = function() {console.log('event 74 called')} -global.event_75 = function() {console.log('event 75 called')} -global.event_76 = function() {console.log('event 76 called')} -global.event_77 = function() {console.log('event 77 called')} -global.event_78 = function() {console.log('event 78 called')} -global.event_79 = function() {console.log('event 79 called')} -global.event_80 = function() {console.log('event 80 called')} -global.event_81 = function() {console.log('event 81 called')} -global.event_82 = function() {console.log('event 82 called')} -global.event_83 = function() {console.log('event 83 called')} -global.event_84 = function() {console.log('event 84 called')} -global.event_85 = function() {console.log('event 85 called')} -global.event_86 = function() {console.log('event 86 called')} -global.event_87 = function() {console.log('event 87 called')} -global.event_88 = function() {console.log('event 88 called')} -global.event_89 = function() {console.log('event 89 called')} -global.event_90 = function() {console.log('event 90 called')} -global.event_91 = function() {console.log('event 91 called')} -global.event_92 = function() {console.log('event 92 called')} -global.event_93 = function() {console.log('event 93 called')} -global.event_94 = function() {console.log('event 94 called')} -global.event_95 = function() {console.log('event 95 called')} -global.event_96 = function() {console.log('event 96 called')} -global.event_97 = function() {console.log('event 97 called')} -global.event_98 = function() {console.log('event 98 called')} -global.event_99 = function() {console.log('event 99 called')} -global.event_100 = function() {console.log('event 100 called')} -global.event_101 = function() {console.log('event 101 called')} -global.event_102 = function() {console.log('event 102 called')} -global.event_103 = function() {console.log('event 103 called')} -global.event_104 = function() {console.log('event 104 called')} -global.event_105 = function() {console.log('event 105 called')} -global.event_106 = function() {console.log('event 106 called')} -global.event_107 = function() {console.log('event 107 called')} -global.event_108 = function() {console.log('event 108 called')} -global.event_109 = function() {console.log('event 109 called')} -global.event_110 = function() {console.log('event 110 called')} - - -function call_event(card) { - const event_function = `event_${card}` - console.log('checking for function: ', event_function) - console.log('available function: ', Object.keys(global)) - if (typeof global[event_function] === 'function') { - global[event_function](); - } else { - console.error(`Event function ${event_function} not found.`); +function goto_vm(proc) { + let old_vm = game.vm; + + game.state = "vm"; + game.vm = { + prompt: 0, + fp: proc, + ip: 0, + }; + + if (old_vm) { + game.vm.return_vm = old_vm; } + + vm_exec(); +} + +function vm_exec() { + vm_inst(0)(); +} + +function vm_inst(a) { + console.log('game.vm.fp', game.vm.fp, 'game.vm.ip', game.vm.ip) + return CODE[game.vm.fp][game.vm.ip][a] +} + +function vm_next() { + game.vm.ip++; + console.log('vm_next called, game.vm.ip', game.vm.ip) + vm_exec(); +} + +function vm_operand(a) { + let x = CODE[game.vm.fp][game.vm.ip][a] + if (a > 0 && typeof x === "function") + return x() + return x +} + +function vm_assert_argcount(n) { + const argcount = CODE[game.vm.fp][game.vm.ip].length - 1 + if (argcount !== n) + throw Error(`ASSERT Invalid number of arguments on event ${game.vm.fp}: ${argcount} instead of ${n}`) +} + +function vm_log() { + log(vm_operand(1)); + vm_next(); +} + +function vm_if() { + if (!vm_operand(1)) { + let balance = 1 + while (balance > 0) { + ++game.vm.ip + switch (vm_operand(0)) { + case vm_if: + ++balance + break + case vm_endif: + --balance + break + case vm_else: + if (balance === 1) + --balance + break + } + if (game.vm.ip < 0 || game.vm.ip > CODE[game.vm.fp].length) + throw "ERROR" + } + } + vm_next() +} + +function vm_else() { + vm_goto(vm_endif, vm_if, 1, 1) +} + +function vm_endif() { + vm_next() +} + +function vm_return() { + /* let return_vm = game.vm.return_vm; + console.log('in vm_return') + + // Return control to the phasing player + if (return_vm) { + game.vm = return_vm; + vm_next(); + } else { + // End of VM execution, return to normal game state + game.state = "play_card"; + } */ + + game.support_check_modifier = 0 + game.view_opp_hand = false + console.log('in vm_return, game.vm_return:', game.vm_return, 'game.return_state:', game.return_state, 'game.vm_infl_to_do', game.vm_infl_to_do, 'game.vm_event_to_do', game.vm_event_to_do) + /*if (!game.vm_infl_to_do && !game.vm_event_to_do) { + if (game.round_player !== game.active) { + change_player() + log_h2('End of Action Round') + } + end_round() + return + } /*Go direct to end round if card fully resolved */ + if (game.return !== game.active) { + next_player()} + if (game.return_state === 'power_struggle') { + do_valid_cards() + } + if (game.return_state && game.return_state !== '') { + game.state = game.return_state + console.log( 'game.state', game.state) + } + else if (game.vm_infl_to_do) {game.state = 'resolve_opponent_event'} /*Can use game.return state for this? */ + else {game.state = "play_card"} +} + +/* ================== VM ACTIONS =========================== */ + +function vm_valid_spaces () { + //vm_assert_argcount(6) + let space_1 = vm_operand(1) + let space_2 = vm_operand(2) + let space_3 = vm_operand(3) + let space_4 = vm_operand(4) + let space_5 = vm_operand(5) + let space_6 = vm_operand(6) + game.valid_spaces = [space_1, space_2, space_3, space_4, space_5, space_6] + game.valid_spaces = game.valid_spaces.filter( n => n ) + + // Check for Systematisation - may not use this space + check_systematisation() + + vm_next() +} + +function vm_valid_spaces_opponent () { + let valid_spaces = [] + if (game.active === DEM) { + for (let i = 1; i < game.pieces.length; i++) { + let gamePiece = game.pieces[i] + + if (gamePiece.comInfl > 0) { + valid_spaces.push(gamePiece.space_id) + } + } + } else { + for (let i = 1; i < game.pieces.length; i++) { + let gamePiece = game.pieces[i] + + if (gamePiece.demInfl > 0) { + valid_spaces.push(gamePiece.space_id) + } + } + } + game.valid_spaces = valid_spaces + vm_next() +} + +function vm_valid_spaces_socio () { + let valid_spaces = [] + for (let i = 1; i < game.pieces.length; i++) { + let gamePiece = game.pieces[i] + let space = spaces[i] + + if (space.socio === vm_operand(1)) { + valid_spaces.push(gamePiece.space_id) + } + } + game.valid_spaces = valid_spaces + + // Check for Systematisation - may not use this space + if (game.persistent_events['systematization'] > 0) { + game.valid_spaces = game.valid_spaces.filter(n => n !== game.persistent_events['systematization']) + } + vm_next() } + +function vm_valid_spaces_opponent_socio () { + let valid_spaces = [] + if (game.active === DEM) { + for (let i = 1; i < game.pieces.length; i++) { + let gamePiece = game.pieces[i] + let space = spaces[i] + + if (gamePiece.comInfl > 0 && space.socio === vm_operand(1)) { + valid_spaces.push(gamePiece.space_id) + } + } + } else { + for (let i = 1; i < game.pieces.length; i++) { + let gamePiece = game.pieces[i] + let space = spaces[i] + + if (gamePiece.demInfl > 0 && space.socio === vm_operand(1)) { + valid_spaces.push(gamePiece.space_id) + } + } + } + game.valid_spaces = valid_spaces + // Check for Systematisation - may not use this space + if (game.persistent_events['systematization'] > 0) { + game.valid_spaces = game.valid_spaces.filter(n => n !== game.persistent_events['systematization']) + } + vm_next() +} + +function vm_valid_spaces_country () { + let country + if (vm_operand(1)) {country = vm_operand(1)} + else {country = game.vm_active_country} + for (let space of spaces) { + if (!space) continue + if (space.country === country) { + game.valid_spaces.push(space.space_id); + } + } + // Check for Systematisation - may not use this space + if (game.persistent_events['systematization'] > 0) { + game.valid_spaces = game.valid_spaces.filter(n => n !== game.persistent_events['systematization']) + } + vm_next() +} + +function vm_valid_spaces_sc () { + let valid_spaces = [] + for (let space of game.pieces) { + if (!space) continue + if (game.active === DEM) { + if (space.comInfl >0) { + valid_spaces.push(space.space_id); + } + } else { + if (space.demInfl >0) { + valid_spaces.push(space.space_id); + } + if (game.persistent_events['civic_forum']) { + if (space.space_id === 31) {continue} + } + if (game.persistent_events['we_are_the_people']) { + if (space.space_id === 9) {continue} + } + } + } + game.valid_spaces = valid_spaces + if (game.persistent_events['foreign_currency_debt_burden'] !== '') { + game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country !== game.persistent_events['foreign_currency_debt_burden']) + } + vm_next() +} + +function vm_valid_spaces_country_opp () { + let country = '' + + if (vm_operand(1)) { + country = vm_operand(1) } + else { + country = game.vm_active_country + } + for (let space of spaces) { + if (!space) continue + if (game.active === DEM) { + if (space.country === country && game.pieces[space.space_id].comInfl >0) { + game.valid_spaces.push(space.space_id); + } + } else { + if (space.country === country && game.pieces[space.space_id].demInfl >0) { + game.valid_spaces.push(space.space_id); + } + } + } + vm_next() +} + +function vm_valid_spaces_country_sc () { + let valid_spaces = [] + let country = '' + console.log('in vm_valid_spaces_country_sc') + if (vm_operand(1)) { + country = vm_operand(1) } + else { + country = game.vm_active_country + } + for (let space of spaces) { + if (!space) continue + if (game.active === DEM) { + if (space.country === country && game.pieces[space.space_id].comInfl >0) { + valid_spaces.push(space.space_id); + } + } else { + if (space.country === country && game.pieces[space.space_id].demInfl >0) { + if (game.persistent_events['solidarity_legalised'] && space.space_id === 14) {continue} + if (game.persistent_events['civic_forum'] && space.space_id === 31) {continue} + if (game.persistent_events['we_are_the_people'] && space.space_id === 9) {continue} + valid_spaces.push(space.space_id); + } + } + } + game.valid_spaces = valid_spaces + + if (!game.is_pwr_struggle && game.persistent_events['foreign_currency_debt_burden'] !== '') { + game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country !== game.persistent_events['foreign_currency_debt_burden']) + } + vm_next() +} + +function vm_valid_spaces_country_socio_2() { + let valid_spaces = [] + for (let space of spaces) { + if (!space) continue + if ((space.country === vm_operand(1) && space.socio === vm_operand(2)) || (space.country === vm_operand(1) && space.socio === vm_operand(3))) { + valid_spaces.push(space.space_id); + } + } + game.valid_spaces = valid_spaces + vm_next() +} + +function vm_valid_spaces_region_socio() { + let valid_spaces = [] + for (let space of spaces) { + if (!space) continue + if (space.region === vm_operand(1) && space.socio === vm_operand(2)) { + valid_spaces.push(space.space_id); + } + } + game.valid_spaces = valid_spaces + vm_next() +} + +function vm_valid_spaces_region_opp() { + let valid_spaces = [] + for (let space of spaces) { + if (!space) continue + let s = space.space_id + if ((game.active === DEM && space.region === vm_operand(1) && game.pieces[s].comInfl > 0 ) || (game.active === COM && space.region === vm_operand(1) && game.pieces[s].demInfl > 0 )) { + valid_spaces.push(space.space_id); + } + } + game.valid_spaces = valid_spaces + vm_next() +} + +function vm_valid_spaces_solidarity_legalised() { + let valid_spaces = [] + for (let space of spaces) { + if (!space) continue + let uncontrolled = game.pieces[space.space_id].demCtrl === 0 && game.pieces[space.space_id].comCtrl === 0 + if ((space.country === 'Poland' && uncontrolled && space.socio === 3) || (space.country === 'Poland' && uncontrolled && space.socio === 4)) { + valid_spaces.push(space.space_id); + } + } + game.valid_spaces = valid_spaces + vm_next() +} + +function vm_active_country () { + game.valid_spaces = game.valid_spaces.filter(space_id => { + let space = spaces.find(s => s && s.space_id === space_id); + return space && space.country === game.vm_active_country; + }); + vm_next() +} + +function vm_take_control_prep() { + game.vm_available_ops = vm_operand(1) + game.state = 'vm_take_control' +} + +function vm_take_control(space) { + let clicked_space = find_space_index(space) + if (game.active === DEM) { + let current_infl = game.pieces[clicked_space].demInfl + let opponent_infl = game.pieces[clicked_space].comInfl + let stability = spaces[clicked_space].stability + + if ((current_infl - opponent_infl) < stability) { + game.pieces[clicked_space].demInfl += stability - current_infl + opponent_infl + game.pieces[clicked_space].demCtrl = 1 + game.pieces[clicked_space].comCtrl = 0 + } + } else if (game.active === COM) { + let current_infl = game.pieces[clicked_space].comInfl + let opponent_infl = game.pieces[clicked_space].demInfl + let stability = spaces[clicked_space].stability + + if ((current_infl - opponent_infl) < stability) { + game.pieces[clicked_space].comInfl += stability - current_infl + opponent_infl + game.pieces[clicked_space].comCtrl = 1 + game.pieces[clicked_space].demCtrl = 0 + } + } + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space) + log(`Took control of ${spaces[clicked_space].name_unique}`) + vm_next() +} + + +function vm_do_add_infl(space) { + push_undo() + const clicked_space = find_space_index(space) + log(`Added 1 influence in %${clicked_space}.`) + + if (spaces[clicked_space].country !== 'East_Germany'){ + game.austria_hungary_border_reopened_tracker = false + } + + // Check Genscher + if (game.persistent_events['genscher'] && game.active === DEM && spaces[clicked_space].country === 'East_Germany') { + game.vm_available_ops-- + } else if (check_control(clicked_space)) { + game.vm_available_ops -= 2 + } else { + game.vm_available_ops-- +} + + // Update influence values + if (game.active === COM) { + game.pieces[clicked_space].comInfl++ + } else { + game.pieces[clicked_space].demInfl++ + } + + // Check Austria Hungary Border Reoponed is true and condition has been met + if (game.vm_available_ops === 0 && game.active === DEM && game.persistent_events['austria_hungary_border_reopened'] && game.austria_hungary_border_reopened_tracker && !game.austria_hungary_border_reopened) { + game.vm_available_ops ++ + log('+1 influence from Austria-Hungary Border Reopened') + game.austria_hungary_border_reopened = true + game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country === 'East_Germany') + } + + // If only 1 IP remaining, may not place in opponent controlled spaces + // Check for Genscher + + if (game.vm_available_ops === 1) { + if (game.active === DEM) { + if (!game.persistent_events['genscher']) { + game.valid_spaces = game.valid_spaces.filter(n => game.pieces[n].comCtrl !== 1) + } else { + game.valid_spaces = game.valid_spaces.filter(n => !(game.pieces[n].comCtrl === 1 && spaces[n].country !== 'East_Germany')) + } + } else { + game.valid_spaces = game.valid_spaces.filter(n => game.pieces[n].demCtrl !== 1) + } + } + + // Check whether spaces are controlled + check_control_change(clicked_space) + + if (game.vm_available_ops === 0) {game.valid_spaces = []} + //console.log('game pieces:', game.pieces[clicked_space]) +} + +function vm_do_add_infl_free(space) { + push_undo() + const clicked_space = find_space_index(space) + log(`Added 1 influence in %${clicked_space}.`) + + // Update influence values + if (game.active === COM) { + game.pieces[clicked_space].comInfl++ + } else { + game.pieces[clicked_space].demInfl++ + } + game.vm_available_ops-- + // Check whether spaces are controlled + check_control_change(clicked_space) + + if (game.vm_available_ops === 0) {game.valid_spaces = []} + //console.log('game pieces:', game.pieces[clicked_space]) +} + +function vm_add_infl() { + if (vm_operand(1)) {game.vm_available_ops = vm_operand(1)} + game.state = 'vm_add_infl' +} + +function vm_add_infl_free() { + if (vm_operand(1)) {game.vm_available_ops = vm_operand(1)} + game.state = 'vm_add_infl_free' +} + +function vm_add_x_infl() { + game.vm_available_ops = vm_operand(1) + game.state = 'vm_add_x_infl' +} + +function vm_do_add_x_infl(space) { + push_undo() + const clicked_space = find_space_index(space) + log(`Added ${game.vm_available_ops} influence in %${clicked_space}.`) + + + if (game.active === COM) { + game.pieces[clicked_space].comInfl += game.vm_available_ops + } else { + game.pieces[clicked_space].demInfl += game.vm_available_ops + } + check_control_change(clicked_space) + game.vm_available_ops = 0 + game.valid_spaces = [] +} + +function vm_add_limited_infl() { + game.vm_available_ops = vm_operand(1) + game.vm_max_infl = vm_operand(2) + game.state = 'vm_add_limited_infl' +} + +function vm_do_add_limited_infl(space, max_infl) { + push_undo() + const clicked_space = find_space_index(space) + log(`Added 1 influence in %${clicked_space}.`) + game.vm_available_ops -- + + if (!game.vm_influence_added) { + game.vm_influence_added = {}; + } + + if (!game.vm_influence_added[clicked_space]) { + game.vm_influence_added[clicked_space] = 0; + } + + if (game.active === COM) { + game.pieces[clicked_space].comInfl ++ + } else { + game.pieces[clicked_space].demInfl ++ + } + + game.vm_influence_added[clicked_space] ++ + + //console.log('valid_spaces before update', game.valid_spaces) + //console.log('influence added:', game.vm_influence_added[clicked_space], 'max infl', max_infl) + if (game.vm_influence_added[clicked_space] === max_infl) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } + check_control_change(clicked_space) + if (game.vm_available_ops === 0) {game.valid_spaces = [] } +} + +function vm_remove_infl() { + game.vm_available_ops = vm_operand(1) + game.state = 'vm_remove_infl' +} + +function vm_remove_opp_infl() { + game.vm_available_ops = vm_operand(1) + game.remove_opponent_infl = true + game.state = 'vm_remove_infl' +} + +function vm_remove_x_opp_infl() { + game.vm_available_ops = vm_operand(1) + game.remove_opponent_infl = true + game.state = 'vm_remove_x_infl' +} + +function vm_do_remove_infl(space) { + push_undo() + const clicked_space = find_space_index(space) + log(`Removed 1 influence from %${clicked_space}.`) + + + if (!game.vm_influence_added) { + game.vm_influence_added = {}; + } + + if (!game.vm_influence_added[clicked_space]) { + game.vm_influence_added[clicked_space] = 0; + } + if (game.remove_opponent_infl === true) { + if (game.active === COM) { + game.pieces[clicked_space].demInfl-- + if (game.pieces[clicked_space].demInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } + } else { + game.pieces[clicked_space].comInfl-- + if (game.pieces[clicked_space].comInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } + } + + + } else { + if (game.active === COM) { + game.pieces[clicked_space].comInfl-- + if (game.pieces[clicked_space].comInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } + } else { + game.pieces[clicked_space].demInfl-- + if (game.pieces[clicked_space].demInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } + } + } + check_control_change(clicked_space) + game.vm_influence_added[clicked_space]++ + game.vm_available_ops-- + if (game.vm_available_ops===0) {game.valid_spaces = []} +} + +function vm_do_remove_x_infl(space) { + push_undo() + const clicked_space = find_space_index(space) + log(`Removed ${game.vm_available_ops} influence from %${clicked_space}.`) + + if (game.remove_opponent_infl) { + if (game.active === COM) { + game.pieces[clicked_space].demInfl -= game.vm_available_ops + } else { + game.pieces[clicked_space].comInfl -= game.vm_available_ops + } + } else { + if (game.active === COM) { + game.pieces[clicked_space].comInfl -= game.vm_available_ops + } else { + game.pieces[clicked_space].demInfl -= game.vm_available_ops + } + } + + check_control_change(clicked_space) + + game.vm_available_ops = 0 + game.valid_spaces = [] +} + +function vm_remove_limited_opp_infl() { + game.vm_available_ops = vm_operand(1) + game.vm_max_infl = vm_operand(2) + game.remove_opponent_infl = true + game.state = 'vm_remove_limited_infl' +} + +function vm_do_remove_limited_infl(space, max_infl) { + push_undo() + const clicked_space = find_space_index(space) + log(`Removed influence from %${clicked_space}.`) + game.vm_available_ops -- + + + if (!game.vm_influence_added) { + game.vm_influence_added = {}; + } + + if (!game.vm_influence_added[clicked_space]) { + game.vm_influence_added[clicked_space] = 0; + } + + if (game.active === COM) { + game.pieces[clicked_space].demInfl -- + if (game.pieces[clicked_space].demInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space) + } + } else { + game.pieces[clicked_space].comInfl -- + if (game.pieces[clicked_space].comInfl === 0) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space) + } + } + + game.vm_influence_added[clicked_space] ++ + + if (game.vm_influence_added[clicked_space] === max_infl) { + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space); + } + + check_control_change(clicked_space) +} + +function vm_remove_all_infl() { + game.vm_available_ops = vm_operand(1) + game.state = 'vm_remove_all_infl' +} + +function vm_do_remove_all_infl(space) { + push_undo() + const clicked_space = find_space_index(space) + log(`Removed all influence from %${clicked_space}.`) + + if (game.remove_opponent_infl === true) { + if (game.active === COM) { + game.pieces[clicked_space].demInfl = 0 + } else { + game.pieces[clicked_space].comInfl = 0 + } + check_control_change(clicked_space) + + } else { + if (game.active === COM) { + game.pieces[clicked_space].comInfl = 0 + } else { + game.pieces[clicked_space].demInfl = 0 + } + check_control_change(clicked_space) + } + game.vm_available_ops -- + game.valid_spaces = game.valid_spaces.filter(id => id !== clicked_space) +} + +function vm_replace_all_infl(space_id) { + if (game.active === DEM) { + game.pieces[space_id].demInfl += game.pieces[space_id].comInfl + game.pieces[space_id].comInfl = 0 + } else { + game.pieces[space_id].comInfl += game.pieces[space_id].demInfl + game.pieces[space_id].demInfl = 0 + } + check_control_change(space_id) +} + +function vm_support_check() { + game.vm_available_ops = vm_operand(1) + game.state = 'vm_support_check_prep' +} + +function vm_support_check_modified() { + game.vm_available_ops = vm_operand(1) + game.support_check_modifier = vm_operand(2) + game.state = 'vm_support_check_prep' +} + +function vm_switch_infl(space){ + push_undo() + let clicked_space = find_space_index(space) + game.pieces[clicked_space].demInfl -= game.vm_available_ops + game.pieces[clicked_space].comInfl += game.vm_available_ops + log(`Replaced ${game.vm_available_ops} influence in ${spaces[clicked_space].name_unique}`) + game.vm_available_ops = 0 + check_control_change(clicked_space) +} + +/* ===================== EVENT SPECIFIC FUNCTIONS ========== */ + +function vm_40th_anniversary_celebration() { + if (game.vp < 0 ) {game.vm_available_ops = 4} + else {game.vm_available_ops = 2} + vm_next() +} + +function vm_40th_anniversary_celebration_vp() { + game.vp -- + log('-1VP') + check_vp() + vm_next() +} + +function vm_adamec() { + game.state = 'vm_adamec' +} + +function vm_army_backs_revolution() { + game.persistent_events['securitate'] = false + game.playable_cards[70].playable = 0 + vm_next() +} + +function vm_austria_hungary_border_reopened() { + game.persistent_events['austria_hungary_border_reopened'] = true + game.austria_hungary_border_reopened = false + game.austria_hungary_border_reopened_tracker = true + game.table_cards.push(58) + vm_next() +} + +function vm_betrayal() { + if (game.pieces[58].demInfl > 0 ) { game.valid_spaces.push(58) } + if (game.pieces[65].demInfl >0 ) { game.valid_spaces.push(65) } + game.vm_available_ops = Math.max(game.pieces[58].demInfl, game.pieces[65].demInfl) + game.state = 'vm_switch_infl' +} + +function vm_breakaway_baltic_republics() { + log('+5 VP') + game.vp += 5 + game.stability++ + check_vp() + game.playable_cards[109].playable = 1 + game.playable_cards[14].playable = 0 + if (game.pieces[56].demCtrl === 0) {game.valid_spaces.push(56)} + if (game.pieces[70].demCtrl === 0) {game.valid_spaces.push(70)} + vm_next() +} + +function vm_brought_in_for_questioning() { + if (game.active === COM) { + game.active = DEM + game.return = game.active + } + game.phase = 0 + game.state = 'vm_brought_in_for_questioning' +} + +function vm_bulgarian_turks_expelled(){ + game.remove_opponent_infl = true + game.vp -= 2 + log('-2VP') + check_vp() + if (game.pieces[70].demInfl > 0) {game.valid_spaces = [70]} + vm_next() +} + +function vm_ceausescu() { + let adj_cluj = false + if (game.pieces[50].demInfl > 0 ) {adj_cluj = true} + if (game.pieces[54].demInfl > 0 ) {adj_cluj = true} + if (game.pieces[58].demInfl > 0 ) {adj_cluj = true} + if (game.pieces[61].demInfl > 0 ) {adj_cluj = true} + + if (adj_cluj && game.pieces[61].comInfl>0) { + game.valid_spaces = [61] + game.vm_available_ops = 1 + next_player() + game.state = 'vm_remove_infl' + } + else {vm_next()} +} + +function vm_central_committee_reshuffle() { + game.state = 'vm_central_committee_reshuffle' +} + +function vm_civic_forum() { + log('+1 VP') + game.vp++ + check_vp() + game.persistent_events['civic_forum'] = true + if (game.pieces[31].demCtrl === 1) { + vm_next() + } else { + permanently_remove(90) + vm_return() + } +} + +function vm_common_european_home() { + let valid_cards = []; + for (let c of cards) { + //if (c === null) {continue} + if (game.active === DEM) { + if (c && c.side === 'C') { + valid_cards.push(c.number) + } + } else { + if (c && c.side === 'D') { + valid_cards.push(c.number) + } + } + } + game.valid_cards = valid_cards + game.state = 'vm_common_european_home' +} + +function vm_dash_for_the_west() { + game.valid_cards = [] + for (let c of game.strategy_discard) { + if (cards[c].side === 'D' && cards[c].remove === 1 && game.playable_cards[c].playable === 1) { + game.valid_cards.push(c) + } + } + game.state = 'vm_dash_for_the_west' +} + +function vm_deutsche_marks() { + let max_value = 1; + for (let c of game.democrat_hand) { + if (cards[c].ops > max_value) { + max_value = cards[c].ops + } + } + let valid_cards = []; + for (let c of game.democrat_hand) { + if (cards[c].ops === max_value) { + valid_cards.push(c); + } + } + game.valid_cards = valid_cards + game.state = 'vm_deutsche_marks_prep' +} + +function vm_domino_theory() { + game.discard = true + for (let card of game.strategy_discard) { + if (scoring_cards.includes(card)) {game.valid_cards.push(card) } + } + game.phase = 0 + game.state = 'vm_play_event_from_discard' +} + +function vm_eco_glasnost() { + game.persistent_events['eco_glasnost'] = true + permanently_remove(39) + vm_next() +} + +function vm_elena(){ + game.persistent_events['elena'] = true + game.table_cards.push(101) + vm_next() +} + +function vm_eliminate(space_id) { + log(`Eliminated ${spaces[space_id].name}`) + const adjacent_spaces = spaces[space_id].adjacent.filter(Number.isInteger); + + // Remove clicked_space from the adjacency lists of its adjacent spaces + adjacent_spaces.forEach(s => { + game.pieces[s].adjacent = spaces[s].adjacent.filter(id => id !== space_id); + }); + + // Connect adjacent spaces to each other + for (let i = 0; i < adjacent_spaces.length; i++) { + for (let j = i + 1; j < adjacent_spaces.length; j++) { + if (!game.pieces[adjacent_spaces[i]].adjacent.includes(adjacent_spaces[j])) { + game.pieces[adjacent_spaces[i]].adjacent.push(adjacent_spaces[j]); + } + if (!game.pieces[adjacent_spaces[j]].adjacent.includes(adjacent_spaces[i])) { + game.pieces[adjacent_spaces[j]].adjacent.push(adjacent_spaces[i]); + } + } + } + + // Clear the adjacency list of the clicked space + game.pieces[space_id].adjacent = []; + + // Eliminate the democrat influence and move the communist influence to Bucharesti + game.pieces[space_id].demInfl = 0 + game.pieces[61].comInfl += game.pieces[space_id].comInfl + log(`${game.pieces[space_id].comInfl} relocated to Bucharesti`) + game.pieces[space_id].comInfl = 0 + check_control_change(space_id) + + } + +function vm_exit_visas() { + game.state = 'vm_exit_visas' +} + +function vm_foreign_currency_debt_burden() { + log('+1VP') + game.vp++ + check_vp() + game.table_cards.push(49) + game.state = 'vm_foreign_currency_debt_burden' +} + +function vm_foreign_television() { + for (let piece of game.pieces) { + if (!piece) continue + if (piece.space_id === 12) {continue} /*Does not apply to Dresden*/ + if (piece.comInfl > 0 ) { + game.valid_spaces.push(piece.space_id) + } + } + vm_next() +} +function vm_frg_embassies() { + game.persistent_events['frg_embassies'] = true + game.table_cards.push(74) + vm_next() +} + +function vm_general_strike() { + game.persistent_events['general_strike'] = true + game.table_cards.push(5) + vm_next() +} + +function vm_genscher() { + game.persistent_events['genscher'] = true + game.table_cards.push(63) + log(`C63 in effect`) + vm_next() +} + +function vm_goodbye_lenin() { + game.view_opp_hand = true + // Select Red cards to show + for (let card of game.communist_hand) { + console.log('checking card ', card, 'red', cards[card].red) + if (cards[card].red) { + game.communist_hand_red.push(card) + } + console.log('game.communist_hand_red', game.communist_hand_red) + } + //Check if these cards are playabl + for (let card of game.communist_hand_red) { + if (game.playable_cards[card].playable === 1) { + game.valid_cards.push(card) + } + } + console.log('valid_cards', game.valid_cards) + game.state = 'vm_goodbye_lenin' +} + +function vm_government_resigns() { + for (let space of game.pieces) { + if (space && spaces[space.space_id].socio === 1 && space.comInfl > 0 && space.comCtrl === 0 && space.demCtrl === 0) { + game.valid_spaces.push(space.space_id) + } + } + game.remove_opponent_infl = true + vm_next() +} + +function vm_grenztruppen() { + console.log('in grenztruppen - player active:', game.active) + game.persistent_events['grenztruppen'] = true + game.table_cards.push(59) + vm_next() +} + +function vm_heal_our_bleeding_wounds() { + let change_vp = 0 + if (game.turn <= 3) {change_vp = -3 } + else if (game.turn <= 7) {change_vp = -1} + else change_vp = 3 + log(`${change_vp} VP`) + game.vp += change_vp + check_vp() + vm_next() +} + +function vm_helsinki_final_act() { + game.persistent_events['helsinki_final_act'] = true + vm_next() +} + +function vm_honecker() { + game.persistent_events['honecker'] = true + game.discard = true + game.valid_cards = [] + for (let c of game.strategy_discard) { + if (scoring_cards.includes(c)) { + continue} + else { + game.valid_cards.push(c) + } + } + game.state = 'vm_honecker' +} + +function vm_inflationary_currency() { + game.state = 'vm_inflationary_currency' +} + +function vm_inflationary_currency_discard() { + for (let card of game.communist_hand){ + if (game.persistent_events['perestroika']) { + if (cards[card].ops >= 2) { + game.valid_cards.push(card) + } + } else if (game.persistent_events['prudence'] === COM ) { + if (cards[card].ops >= 4) { + game.valid_cards.push(card) + } + } else { + if (cards[card].ops >= 3) { + game.valid_cards.push(card) + } + } + } + next_player() + game.state = 'vm_inflationary_currency_discard' +} + +function vm_kiss_of_death() { + game.state = 'vm_kiss_of_death' +} + +function vm_klaus_and_komarek() { + if (game.pieces[29].comInfl > 0 ) {game.valid_spaces = [29]} + vm_next() +} + +function vm_kohl_proposes_reunification() { + log('+2 VP') + game.vp += 2 + check_vp() + if (game.persistent_events['the_wall_must_go']) { + game.temp = 87 + game.state = 'vm_common_european_home' + } else { + permanently_remove(87) + vm_return() + } + +} + +function vm_kremlin_coup() { + log('-3 VP') + game.vp -= 3 + check_vp() + + elite_spaces.forEach(space => { + if (revolutions[spaces[space].country]) { + game.valid_spaces.push(space); + } + }) + game.state = 'vm_kremlin_coup_take_control' +} + +function vm_laszlo_tokes() { + game.playable_cards[107].playable = 1 + game.state = 'vm_laszlo_tokes' +} + +function vm_legacy_of_martial_law() { + game.vm_available_ops = 1 + game.state = 'vm_switch_infl' +} + +function vm_legacy_of_1968() { + for (let space of game.pieces) { + if (space && (space.comCtrl === 0 && spaces[space.space_id].country === 'Czechoslovakia')) { + game.valid_spaces.push(space.space_id); + } + } + vm_next() +} + +function vm_li_peng() { + game.persistent_events['li_peng'] = true + game.table_cards.push(53) + vm_next() +} + +function vm_ligachev() { + game.persistent_events['ligachev'] = true + vm_next() +} + +function vm_malta_summit() { + game.state = 'vm_malta_summit' +} + +function vm_modrow() { + game.playable_cards[15].playable = 0 + game.state = 'vm_modrow' +} + +function vm_national_salvation_front() { + game.persistent_events['national_salvation_front'] = true + game.table_cards.push(102) + vm_next() +} + +function vm_nepotism() { + game.state = 'vm_nepotism' +} + +function vm_new_years_eve_party() { + game.state = 'vm_new_years_eve_party' +} + +function vm_nomenklatura() { + game.state = 'vm_nomenklatura' +} + +function vm_normalisation() { + if (game.pieces[27].demInfl >0) {game.valid_spaces.push(27)} + if (game.pieces[29].demInfl > 0) {game.valid_spaces.push(29)} + game.remove_opponent_infl = true + vm_next() +} + +function vm_peasant_parties_revolt() { + game.persistent_events['peasant_parties_revolt'] = true + log_msg_gap('C72 in effect') + game.table_cards.push(72) + vm_next() +} + +function vm_perestroika() { + game.persistent_events['perestroika'] = true + log_msg_gap('C25 in effect') + permanently_remove(25) + vm_next() +} + +function vm_poszgay() { + let valid_spaces = [] + for (let space of spaces) { + if (space && space.country === 'Hungary' && game.pieces[space.space_id].demCtrl === 0) { + valid_spaces.push(space.space_id); + } + } + game.valid_spaces = valid_spaces + vm_next() +} + +function vm_power_struggle() { + game.is_pwr_struggle = true + + //Check if Power Struggle is because of an event + if (game.vm_event > 0) { + game.pwr_struggle_in = countries[scoring_cards.indexOf(game.vm_event)] + } + + //Otherwise set Power Struggle country normally + else { + game.pwr_struggle_in = countries[scoring_cards.indexOf(game.played_card)] + } + + //Check for Securitate + if (game.pwr_struggle_in === 'Romania' && game.persistent_events['securitate']) { + game.view_opp_hand = true + } + game.state = 'draw_power_cards' +} + +function vm_presidential_visit() { + game.persistent_events['presidential_visit'] = true + game.table_cards.push(65) + vm_next() +} + +function vm_prudence() { + if (game.active === DEM) { + game.persistent_events['prudence'] = COM + } else {game.persistent_events['prudence'] = DEM} + log_msg_gap('C8 in effect') + vm_next() +} + +function vm_public_against_violence() { + game.valid_spaces = [] + if (game.pieces[34].comInfl > 0 ) {game.valid_spaces.push(34)} + vm_next() +} + +function vm_reformer_rehabilitated () { + game.discard = true + for (let card of game.strategy_discard) { + if (card === game.played_card) continue + if (game.table_cards.includes(card)) continue + if (scoring_cards.includes(card)) continue + + game.valid_cards.push(card) + } + game.state = 'vm_play_event_from_discard' +} + +function vm_roundtable_talks() { + game.persistent_events['roundtable_talks'] = true + game.table_cards.push(17) + log_msg_gap('C17 in effect') + vm_next() +} + +function vm_sajudis() { + game.playable_cards[81].playable = 1 + game.stability++ + log('+1 VP') + game.vp++ + check_vp() + vm_next() +} + +function vm_samizdat() { + game.state = 'vm_samizdat' +} + +function vm_securitate() { + game.persistent_events['securitate'] = true + game.table_cards.push(70) + vm_next() +} + +function vm_shock_therapy() { + game.state = 'vm_shock_therapy' +} + +function vm_social_democratic_platform_adopted() { + game.state = 'vm_social_democratic_platform_adopted' +} + +function vm_solidarity_legalised() { + log_msg_gap(`C2 in effect`) + game.playable_cards[3].playable = 1 + game.persistent_events['solidarity_legalised'] = true + vm_next() +} + +function vm_st_nicholas_church () { + game.persistent_events['st_nicholas_church'] = true + game.playable_cards[61].playable = 1 + permanently_remove(24) + vm_next() +} + +function vm_stasi() { + log_msg_gap('C13 in effect') + game.persistent_events['stasi'] = true + vm_next() +} + +function vm_stand_fast() { + if (game.active === DEM) { + game.persistent_events['stand_fast'] = DEM + } else {game.persistent_events['stand_fast'] = COM} + game.table_cards.push(100) + vm_next() +} + +function vm_systematization() { + game.state = 'vm_systematization' +} + +function vm_tank_column() { + if (game.active === DEM) { + game.dem_tst_position++ + } else {game.com_tst_position++} + vm_next() +} + +function vm_tear_gas () { + game.persistent_events['tear_gas']= true + game.table_cards.push(30) + log_msg_gap('C30 in effect') + vm_next() +} + +function vm_the_baltic_way() { + game.playable_cards[84].playable = 1 + game.stability++ + if (game.pieces[56].demCtrl === 0) {game.valid_spaces.push(56)} + if (game.pieces[70].demCtrl === 0) {game.valid_spaces.push(70)} + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() +} + +function vm_the_chinese_solution() { + game.state = 'vm_the_chinese_solution' +} + +function vm_the_crowd_turns_against_ceausescu() { + game.persistent_events['the_crowd_turns_against_ceausescu'] = true + game.table_cards.push(54) + vm_next() +} + +function vm_the_monday_demonstrations() { + if (game.pieces[6].demCtrl === 0) {game.valid_spaces.push(6)} + if (game.pieces[9].demCtrl === 0) {game.valid_spaces.push(9)} + vm_next() +} + +function vm_the_sintra_doctrine() { + game.persistent_events['sinatra_doctrine'] = true + log_msg_gap('C50 in effect') + vm_next() +} + +function vm_the_third_way() { + log('-2VP') + vm_next() +} + +function vm_the_tyrant_is_gone() { + game.valid_spaces = [] + for (let space of game.pieces) { + if (space && space.demInfl === 0 && spaces[space.space_id].country === 'Romania') { + if (space.space_id === game.persistent_events['systematization']) {continue} + game.valid_spaces.push(space.space_id) + } + } + game.playable_cards[107] = 0 + game.state = 'vm_the_tyrant_is_gone' +} + +function vm_the_wall () { + game.persistent_events['the_wall']= true + game.strategy_removed.push(9) + //game.table_cards.push(9) + log_msg_gap('C9 in effect') + vm_next() +} + +function vm_the_wall_must_go() { + game.the_wall_must_go = {} + game.the_wall_must_go['dem_wins'] = 0 + game.the_wall_must_go['com_wins'] = 0 + game.the_wall_must_go['dem_roll'] = 0 + game.the_wall_must_go['com_roll'] = 0 + game.state = 'vm_the_wall_must_go' +} + +function vm_warsaw_pact_summit() { + game.warsaw_pact_summit = true + game.state = 'vm_warsaw_pact_summit' +} + +function vm_we_are_the_people() { + if (game.pieces[6].demInfl > 0) {game.valid_spaces = [6]} + game.persistent_events['we_are_the_people'] = true + game.vm_influence_added[6] = 0 + game.vm_available_ops = 4 + game.state = 'vm_we_are_the_people_remove' +} + +function vm_workers_revolt() { + if (game.active === DEM) { + for (let space of spaces) { + if (!space) continue + let country = space.country + if (!game.revolutions[`${country}`] && game.pieces[space.space_id].comInfl > 0 && space.socio === 4) { + game.valid_spaces.push(space.space_id); + } + } + } else { + for (let space of spaces) { + let country = space.country + if (game.revolutions[`${country}`] && game.pieces[space.space_id].demInfl > 0 && space.socio === 4) { + game.valid_spaces.push(space.space_id); + } + } + } + game.state = 'vm_workers_revolt' +} + +function vm_yakovlev_counsels_gorbachev() { + game.persistent_events['yakovlev'] = true + game.table_cards.push(62) + vm_next() +} + +function vm_permanently_remove () { + // Check if the event is being played as the result of another card, e.g. Dash for the West + if (game.vm_event !== 0) { + permanently_remove(game.vm_event) + } + if (game.played_card !== 21) { + permanently_remove(game.played_card) + } /*This means the card that called the event being played is also removed. Is there ever a time when this is a problem? Common European Home fix added */ + vm_next() +} + +function discarded_card() { + return game.temp > 0 +} + +// =================== TIANANMEN SQUARE TRACK FUNCTIONS ==================== + +function vm_tst_3() { + log_gap('Tiananmen Square Track award') + game.state = 'vm_tst_3_prep' +} + +function vm_tst_4() { + log_gap('Tiananmen Square Track award') + game.vm_available_ops = 2 + game.remove_opponent_infl = true + game.state = 'vm_tst_4' +} +function vm_tst_6() { + log_h3('Tiananmen Square Track award') + game.vm_available_ops = 1 + game.temp = 1 //Set temp to 1, so that Card 1 is called during the support check, which has 2 ops + game.state = 'vm_tst_6' +} + +function vm_tst_8() { + game.state = 'vm_goodbye_lenin_ops' // Use this to resolve ops. +} + +// ==================== POWER STRUGGLE FUNCTIONS ====================== + +function vm_scare_tactics() { + game.vm_active_country = game.pwr_struggle_in + vm_next() +} +function vm_support_surges() { + game.state = 'vm_support_surges' +} + +function vm_support_falters() { + game.vm_available_ops = 2 + game.return === game.active + game.state = 'vm_support_falters' +} + + +/* ================== VM STATES ============================== */ + +states.vm_take_control = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt () { + if (game.valid_spaces.length === 0) { + view.prompt = 'All spaces already controlled. Continue.' + gen_action('done') + } else if (game.vm_available_ops > 0 ) { + view.prompt = 'Select a space to take control.' + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Done' + gen_action('done') + } + }, + infl(space) { + vm_take_control(space) + }, + done() { + vm_next() + } +} + +states.vm_add_infl = { + inactive: 'add influence.', + prompt () { + if (game.vm_available_ops > 0 && game.valid_spaces.length === 0 ) { + view.prompt = 'No available spaces remaining. Add influence: done.' + gen_action('done') + } + else if (game.vm_available_ops > 0 ) { + view.prompt = `Add influence. ${game.vm_available_ops} remaining.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Add influence: done.' + gen_action('done') + } + }, + infl(space) { + vm_do_add_infl(space) + }, + done () { + game.vm_event_done = true + vm_next() + } +} + +states.vm_add_infl_free = { + inactive: 'add influence.', + prompt () { + if (game.vm_available_ops > 0 && game.valid_spaces.length === 0 ) { + view.prompt = 'No available spaces remaining. Add influence: done.' + gen_action('done') + } + else if (game.vm_available_ops > 0 ) { + view.prompt = `Add influence. ${game.vm_available_ops} remaining.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Add influence: done.' + gen_action('done') + } + }, + infl(space) { + vm_do_add_infl_free(space) + }, + done () { + game.vm_event_done = true + vm_next() + } +} + +states.vm_add_x_infl = { + inactive: 'add influence.', + prompt () { + if (game.vm_available_ops > 0 ) { + view.prompt = `Add ${game.vm_available_ops} influence.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Done' + gen_action('done') + } + }, + infl(space) { + vm_do_add_x_infl(space) + }, + done () { + game.vm_event_done = true + vm_next() + } +} + +states.vm_add_limited_infl = { + inactive: 'add influence.', + prompt () { + if (game.vm_available_ops > 0 && game.valid_spaces.length > 0) { + view.prompt = `Add influence. ${game.vm_available_ops} influence remaining.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Done' + gen_action('done') + } + }, + infl(space) { + vm_do_add_limited_infl(space, game.vm_max_infl) + }, + done () { + game.vm_event_done = true + vm_next() + } +} + +states.vm_remove_infl = { + inactive: 'remove influence', + prompt () { + if (game.vm_available_ops === 0 || game.valid_spaces.length === 0) { + view.prompt = 'Remove influence: done.' + gen_action('done') + return + } + view.prompt = 'Select a space to remove influence' + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} + } + }, + infl(space) { + vm_do_remove_infl(space) + const clicked_space = find_space_index(space) + game.vm_active_country = spaces[clicked_space].country + }, + done() { + vm_next() + } +} + + +states.vm_remove_x_infl = { + inactive: 'remove influence.', + prompt () { + if (game.vm_available_ops > 0 ) { + view.prompt = `Remove ${game.vm_available_ops} influence.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Remove influence: done' + gen_action('done') + } + }, + infl(space) { + vm_do_remove_x_infl(space) + }, + done () { + game.vm_event_done = true + vm_next() + } +} + +states.vm_remove_limited_infl = { + inactive: 'remove influence.', + prompt () { + if (game.vm_available_ops > 0 && game.valid_spaces.length > 0) { + view.prompt = `Remove influence.` + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Done' + gen_action('done') + } + }, + infl(space) { + vm_do_remove_limited_infl(space, game.vm_max_infl) + }, + done () { + game.vm_event_done = true + vm_next() + } +} + +states.vm_remove_all_infl = { + inactive: 'remove influence', + prompt () { + if (game.vm_available_ops === 0 || game.valid_spaces.length === 0) { + view.prompt = 'Remove influence: done.' + gen_action('done') + return + } + view.prompt = 'Remove influence' + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + // } + } + }, + infl(space) { + vm_do_remove_all_infl(space) + const clicked_space = find_space_index(space) + game.vm_active_country = spaces[clicked_space].country + }, + done() { + vm_next() + } +} + +states.vm_support_check_prep = { + inactive: 'do support check', + prompt () { + if (game.vm_available_ops === 0) { + view.prompt = 'Support check: done' + gen_action('done') + } else if (game.valid_spaces.length === 0) { + view.prompt = 'No valid targets for support check.' + gen_action('done') + } else { + if (game.vm_available_ops > 0) { + view.prompt = `Select a space. ${pluralize(game.vm_available_ops, 'support check')} remaining.` + } + for (let space_id of game.valid_spaces) { + if (!space_id) continue + gen_action_sc(spaces[space_id].name_unique); + } + } + }, + sc(space) { + push_undo() + game.selected_space = find_space_index(space) + game.state = 'vm_do_support_check' + }, + done () { + game.vm_available_ops = 0 + vm_next () + } +} + +states.vm_do_support_check = { + inactive: 'do support checks', + prompt () { + view.prompt = `Target: ${spaces[game.selected_space].name_unique}. Roll a die` + gen_action('roll') + }, + roll() { + clear_undo() + do_sc(spaces[game.selected_space].name_unique) + game.vm_available_ops-- + if (game.vm_available_ops === 0) { + game.valid_spaces = [] + } + game.state = 'vm_support_check_prep' + return + } +} + +states.vm_tiananmen_square_attempt = { + inactive: 'do Tiananmen Square', + prompt () { + if (game.active === DEM && game.dem_tst_attempted_this_turn > 0 || game.active === COM && game.com_tst_attempted_this_turn > 0) { + view.prompt = 'Tiananmen Square Track attempt: done.' + gen_action('done') + return + } + view.prompt = 'Roll a die' + gen_action('roll') + }, + roll() { + clear_undo() + do_tst_attempt () + }, + done () { + vm_next() + } +} + +//================================== EVENT SPECIFIC STATES ====================================== + +states.vm_adamec = { + get inactive() { + return `resolve ${cards[88].name}.` + }, + prompt() { + view.prompt = 'Roll a die.' + gen_action('roll') + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + let worker_spaces = spaces.filter(space => space && space.country === 'Czechoslovakia' && space.socio === 4 && game.pieces[space.space_id].demCtrl === 1).length + if (worker_spaces > 0) { + log(`-${worker_spaces} from Democrat controlled worker spaces`) + roll -= worker_spaces + } + if (roll > 2) { + log('Adamec succeeds') + vm_next() + return + } + log('Adamec fails: modified 3 or more required') + permanently_remove(88) + vm_return() + } +} + +states.vm_brought_in_for_questioning = { + inactive: 'discard a card', + prompt() { + if (game.phase === 1) { + view.prompt = 'Discard a card: done' + gen_action('done') + } else if (game.democrat_hand.length === 0) { + view.prompt = 'Brought in for Questioning. No cards to discard.' + gen_action('done') + } else { + view.prompt = 'Brought in for Questioning. You must discard a card.' + gen_action('discard') + } + }, + discard() { + game.temp = discard_card(game.democrat_hand) + game.phase = 1 + if (cards[game.temp].side === 'C') { + game.return = game.active + if (!auto_resolve_events.includes(game.temp)) { + next_player() + } + goto_vm(game.temp) + } + }, + done() { + vm_return() + } +} + +states.vm_central_committee_reshuffle = { + get inactive() { + return `resolve ${cards[57].name}.` + }, + prompt() { + view.prompt = 'Choose a country to add influence.' + if (!game.revolutions['East_Germany']) {gen_action('east_germany')} + if (!game.revolutions['Poland']) {gen_action('poland')} + if (!game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (!game.revolutions['Hungary']) {gen_action('hungary')} + if (!game.revolutions['Romania']) {gen_action('romania')} + if (!game.revolutions['Bulgaria']) {gen_action('bulgaria')} + }, + east_germany() {game.valid_spaces = [1,2,3,4,5,6,7,8,9,10,11,12] + vm_next() + }, + poland() {game.valid_spaces = [13,14,15,16,17,18,19,20,21,22,23,24,25,26] + vm_next() + }, + czechoslovakia() {game.valid_spaces = [27,28,29,30,31,32,33,34,35,36,37] + vm_next() + }, + hungary() {game.valid_spaces = [38,39,40,41,42,43,44,45,46,47,48,49] + vm_next() + }, + romania() {game.valid_spaces = [50,51,52,53,54,55,56,57,58,59,60,61,62,63] + vm_next() + }, + bulgaria () {game.valid_spaces = [64,65,66,67,68,69,70,71,72,73,74,75] + vm_next() + }, + +} + +states.vm_common_european_home = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.temp === 0) { + view.prompt = 'Choose a card to play' + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else { + view.prompt = `Play ${cards[game.temp].name} for:` + gen_action('influence') + gen_action('support_check') + if (game.active === DEM && game.temp === 87 ) { + return /*Special condition if card is actually Kohl Proposes Reunification*/ + } + if (game.active === DEM && game.dem_tst_attempted_this_turn === 0 || game.active === COM && game.com_tst_attempted_this_turn === 0) { + gen_action('tst') + } + } + }, + card(card) { + log(`Played with C${cards[card].number}`) + game.valid_cards = [] + discard(card) + game.temp = card + }, + influence(){ + push_undo() + game.vm_available_ops = cards[game.temp].ops + valid_spaces_infl() + game.state = 'vm_add_infl' + }, + support_check() { + push_undo() + game.vm_available_ops = 2 + game.state = 'vm_support_check_prep' + valid_spaces_sc() + }, + tst() { + game.state = 'vm_tiananmen_square_attempt' + } +} + +states.vm_dash_for_the_west = { + get inactive() { + return `resolve ${cards[36].name}.` + }, + prompt() { + if (game.phase === 1) { + view.prompt = 'Roll a die' + gen_action('roll') + } else { + view.prompt = 'Roll a die: done.' + gen_action('done') + } + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + let com_control = check_presence('East_Germany').com_spaces + + if (roll > com_control) { + log(`More than the ${com_control} controlled spaces in East Germany`) + log('+1 VP') + game.vp++ + check_vp() + game.discard = true + game.state = 'vm_play_event_from_discard' + } else { + log(`Fail: more than a ${com_control} required`) + game.phase++ + } + clear_undo() + }, + done() { + vm_next() + } +} + +states.vm_play_event_from_discard = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.valid_cards.length === 0) { + view.prompt = 'No valid cards in discard.' + gen_action('done') + } else if (game.temp === 0) {view.prompt = 'Choose a card. Event occurs immediately.' + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else { + view.prompt = 'Choose a card: done.' + gen_action('done') + } + }, + card(card) { + push_undo() + log(`Chose C${cards[card].number}`) + game.vm_event = card + game.vm_available_ops = cards[card].ops + game.discard = false + game.return = game.active + console.log('card:', card) + if (switch_events.includes(card)) {next_player()} + goto_vm(card) + }, + done(){ + game.discard = false + vm_next() + } +} + +states.vm_deutsche_marks_prep = { + inactive: 'choose a card.', + prompt() { + view.prompt = 'Choose a card to give.' + for (let card of game.valid_cards) { + gen_action_card(card) + } + }, + card(card) { + log(`Gave C${cards[card].number}`) + game.valid_cards = [] + discard(card) + next_player() + game.state = 'vm_deutsche_marks' + game.temp = card + } +} + +states.vm_deutsche_marks = { + get inactive() { + return `resolve ${cards[20].name}.` + }, + prompt() { + if(cards[game.temp].side === 'C' && game.playable_cards[game.temp].playable === 1) { + view.prompt = `You must play ${cards[game.temp].name} for the event.` + gen_action('event') + } else { + view.prompt = 'Play card for:' + gen_action('influence') + gen_action('support_check') + if (game.com_tst_attempted_this_turn === 0) { + gen_action('tst') + } + } + }, + event() { + log(`Played C${cards[game.temp].number} for the event`) + game.return === game.active + goto_vm(game.temp) + }, + influence() { + push_undo() + log(`Played C${cards[game.temp].number} for influence`) + game.vm_available_ops = cards[game.temp].ops + if (game.persistent_events['perestroika']) {game.vm_available_ops++ } + valid_spaces_infl() + game.state = 'vm_add_infl' + }, + support_check() { + push_undo() + log(`Played C${cards[game.temp].number} for support checks`) + game.vm_available_ops = 2 + game.state='vm_support_check_prep' + valid_spaces_sc() + }, + tst() { + push_undo() + log(`Played C${cards[game.temp].number} to the Tiananmen Square Track`) + game.state='vm_tiananmen_square_attempt' + } +} + +states.vm_exit_visas = { + get inactive() { + return `resolve ${cards[75].name}.` + }, + prompt() { + view.prompt = 'You may discard cards from your hand and draw replacements.' + for (let card of game.democrat_hand) { + gen_action_card(card) + } + gen_action('done') + }, + card(card){ + push_undo() + discard(card) + game.temp++ + }, + done() { + push_undo() + game.state = 'vm_exit_visas_finish' + } +} + +states.vm_exit_visas_finish = { + get inactive() { + return `resolve ${cards[75].name}.` + }, + prompt() { + if (game.temp > 0 ) { + view.prompt = 'Draw replacement cards.' + gen_action('draw') + } else { + view.prompt = 'Discard cards: done.' + gen_action('done') + } + }, + draw() { + clear_undo() + draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.democrat_hand.length + game.temp, game.communist_hand.length) + game.temp = 0 + }, + done() { + vm_next() + } +} + +states.vm_foreign_currency_debt_burden = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Choose a country. The Communist may not make support checks there for the rest of the turn.' + gen_action('east_germany') + gen_action('poland') + gen_action('czechoslovakia') + gen_action('hungary') + gen_action('bulgaria') + }, + east_germany() { + game.persistent_events['foreign_currency_debt_burden'] = 'East_Germany' + log('Selected East Germany') + vm_next() + }, + poland() { + game.persistent_events['foreign_currency_debt_burden'] = 'Poland' + log('Selected Poland') + vm_next() + }, + czechoslovakia() { + game.persistent_events['foreign_currency_debt_burden'] = 'Czechoslovakia' + log('Selected Czechoslovakia') + vm_next() + }, + hungary() { + game.persistent_events['foreign_currency_debt_burden'] = 'Hungary' + log('Selected Hungary') + vm_next() + }, + bulgaria() { + game.persistent_events['foreign_currency_debt_burden'] = 'Bulgaria' + log('Selected Bulgaria') + vm_next() + } +} + +states.vm_goodbye_lenin = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.valid_cards.length > 0 ) { + view.prompt = 'Choose a card to play for the event, or play Goodbye Lenin for operations' + for (let card of game.valid_cards) { + gen_action_card(card) + gen_action('ops') + } + } else { + view.prompt = 'Communist has no valid cards. Play Goodbye Lenin for operations.' + gen_action('ops') + } + }, + card(card) { + log(`Chose to play ${cards[card].name} for the event`) + let card_index = game.communist_hand.indexOf(card) + game.communist_hand.splice(card_index, 1) + goto_vm(card) + }, + ops() { + game.state = 'vm_goodbye_lenin_ops' + } +} + +states.vm_goodbye_lenin_ops = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = `Play ${cards[game.played_card].name} for:` + gen_action('influence') + gen_action('support_check') + if ((game.active === DEM && game.dem_tst_attempted_this_turn === 0 ) || (game.active === COM && game.com_tst_attempted_this_turn === 0 )) { + gen_action('tst') + } + }, + influence(){ + push_undo() + game.vm_available_ops = cards[game.played_card].ops + valid_spaces_infl() + game.state = 'vm_add_infl' + }, + support_check() { + push_undo() + game.vm_available_ops = 2 + game.state = 'vm_support_check_prep' + valid_spaces_sc() + }, + tst() { + game.state = 'vm_tiananmen_square_attempt' + } +} + +states.vm_honecker = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.temp === 0) {view.prompt = 'Choose a card to add to your hand.' + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else { + view.prompt = 'Choose a card: done.' + gen_action('done') + } + }, + card(card) { + push_undo() + game.valid_cards = [] + log(`Took C${cards[card].number} into hand`) + game.temp = card + let card_index = game.strategy_discard.indexOf(card) + game.strategy_discard.splice(card_index, 1) + game.communist_hand.push(card) + console.log('removed after honecker', game.strategy_removed) + }, + done(){ + game.discard = false + vm_next() + } + +} + +states.vm_inflationary_currency = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Choose a country.' + if (game.active === DEM) { + if (!game.revolutions['East_Germany']) {gen_action('east_germany')} + if (!game.revolutions['Poland']) {gen_action('poland')} + if (!game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (!game.revolutions['Hungary']) {gen_action('hungary')} + if (!game.revolutions['Romania']) {gen_action('romania')} + if (!game.revolutions['Bulgaria']) {gen_action('bulgaria')} + } else { + if (game.revolutions['East_Germany']) {gen_action('east_germany')} + if (game.revolutions['Poland']) {gen_action('poland')} + if (game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (game.revolutions['Hungary']) {gen_action('hungary')} + if (game.revolutions['Romania']) {gen_action('romania')} + if (game.revolutions['Bulgaria']) {gen_action('bulgaria')} + } + }, + east_germany() {game.vm_active_country = 'East_Germany' + vm_next() + }, + poland() { game.vm_active_country = 'Poland' + vm_next() + }, + czechoslovakia() { game.vm_active_country = 'Czechoslovakia' + vm_next() + }, + hungary() { game.vm_active_country = 'Hungary' + vm_next() + }, + romania() { game.vm_active_country = 'Romania' + vm_next() + }, + bulgaria () { game.vm_active_country = 'Bulgaria' + vm_next() + }, +} + +states.vm_inflationary_currency_discard = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.valid_cards.length === 0 ) { + view.prompt = 'No valid cards to discard. You must pass.' + gen_action('pass') + } else if (game.temp === 0 ) { + view.prompt = 'You may discard a 3 op or higher value card to cancel the support check.' + gen_action('pass') + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else { + view.prompt = 'Discard a card: done.' + gen_action('done') + } + }, + card(card) { + game.temp = discard(card) + }, + pass() { + log('Did not discard') + next_player() + game.vm_available_ops = 1 + vm_next() + //game.state = 'vm_support_check_prep' + }, + done() { + vm_next() + } +} + + +states.vm_kiss_of_death = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.temp === 0) { + view.prompt = 'You must randomly discard a card.' + gen_action('discard') + } + }, + discard() { + game.vm_event = discard_card(game.communist_hand) + next_player() + game.state = 'vm_kiss_of_death_finish' + }, +} + +states.vm_kiss_of_death_finish = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.vm_event > 0 && (cards[game.vm_event].side === 'D' || cards[game.vm_event].side === 'N')) { + view.prompt = `Play ${cards[game.vm_event].name} for the event.` + gen_action('event') + } else { + view.prompt = 'Event does not occur.' + gen_action('done') + } + }, + event() { + game.return = game.active + goto_vm(game.vm_event) + }, + done() { + vm_next() + } +} + +states.vm_kremlin_coup_take_control = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.valid_spaces.length === 0){ + view.prompt = 'No spaces remaining. Kremlin Coup: done.' + gen_action('done') + } else { + view.prompt = `Select a country's elite space.` + for (let space_id of game.valid_spaces) { + gen_action_infl(spaces[space_id].name_unique); + } + } + }, + infl(space) { + vm_take_control(space) + game.vm_active_country = spaces[find_space_index(space)].country + if (game.vm_active_country = 'East_Germany') {game.temp = 3 } + if (game.vm_active_country = 'Poland') {game.temp = 17} + if (game.vm_active_country = 'Czechoslovakia') {game.temp = 29} + if (game.vm_active_country = 'Hungary') {game.temp = 45} + if (game.vm_active_country = 'Romania') {game.temp = 61} + if (game.vm_active_country = 'Bulgaria') {game.temp = 68} + game.state = 'vm_kremlin_coup_sc_prep' + }, + done() { + vm_next() + } +} + +states.vm_kremlin_coup_sc_prep = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = `Conduct a support check in ${game.vm_active_country}'s Bureaucratic space.` + for (let space_id of game.temp) { + gen_action_sc(spaces[space_id].name_unique); + } + }, + sc(space) { + game.selected_space = find_space_index(space) + game.state = 'vm_kremlin_coup_sc' + } +} + +states.vm_kremlin_coup_sc = { + inactive: 'do support checks', + prompt () { + view.prompt = `Target: ${spaces[game.selected_space].name_unique}. Roll a die` + gen_action('roll') + }, + roll() { + clear_undo() + do_sc(spaces[game.selected_space].name_unique) + game.state = 'vm_kremlin_coup_sc_prep' + return + } +} + +states.vm_laszlo_tokes = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = `Play Laszlo Tokes for:` + gen_action('influence') + gen_action('support_check') + }, + influence(){ + push_undo() + if (game.persistent_events['sinatra_doctrine']) { + log(`+1 op from C50`) + game.vm_available_ops = 3 + } else { + game.vm_available_ops = 2 + } + valid_spaces_infl() + game.valid_spaces = game.valid_spaces.filter(space_id => spaces[space_id].country === 'Romania') + game.state = 'vm_add_infl' + }, + support_check() { + push_undo() + game.vm_available_ops = 2 + game.state = 'vm_support_check_prep' + valid_spaces_sc() + game.valid_spaces = game.valid_spaces.filter(space_id => spaces[space_id].country === 'Romania') + } +} + +states.vm_switch_infl = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.vm_available_ops > 0 ) { + view.prompt = 'Select a space to replace opponent influence.' + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) { */ + gen_action_infl(spaces[space_id].name_unique); + //} + } + } else { + view.prompt = 'Inluence replaced.' + gen_action('done') + } + }, + infl(space) { + vm_switch_infl(space) + if (game.vm_available_ops === 0) { + game.valid_spaces = [] + } + }, + done() { + vm_next() + } +} + +states.vm_malta_summit = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.phase === 1) { + view.prompt = 'Roll a die.' + gen_action('roll') + } else { + view.prompt = 'Done' + gen_action('done') + } + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + if (game.stability > 0) { + log(`+${game.stability} from USSR Stability Track`) + } + if (roll + game.stability > 3) { + log('Summit successful') + game.vp += 3 + log('+3 VP') + check_vp() + if (game.pieces[12].comInfl > 0 ) {game.valid_spaces.push(12)} + if (game.pieces[15].comInfl > 0 ) {game.valid_spaces.push(15)} + if (game.pieces[27].comInfl > 0 ) {game.valid_spaces.push(27)} + if (game.pieces[43].comInfl > 0 ) {game.valid_spaces.push(43)} + if (game.pieces[51].comInfl > 0 ) {game.valid_spaces.push(51)} + if (game.pieces[69].comInfl > 0 ) {game.valid_spaces.push(69)} + game.vm_available_ops = 5 + game.remove_opponent_infl = true + game.state = 'vm_remove_infl' + } + else { + log('Summit failed') + game.phase++ + } + }, + done() { + vm_next() + } +} + +states.vm_modrow = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Roll a die.' + gen_action('roll') + }, + roll(){ + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + let dem_spaces = spaces.filter(space => space && space.country === 'East_Germany' && game.pieces[space.space_id].demCtrl === 1).length + if (roll > dem_spaces) { + log(`Rolled a ${roll}: success`) + vm_next() + } else { + log(`Rolled a ${roll}`) + log(`Fail. More than ${dem_spaces} required`) + permanently_remove(83) + vm_return() + } + } +} + +states.vm_nepotism = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.phase === 1 ) { + view.prompt = 'Roll a die.' + gen_action('roll') + } else { + view.prompt = 'Roll a die: done.' + gen_action('done') + } + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + if (roll < 3) { + log(`Rolled a ${roll}: adds 4 influence`) + game.vm_available_ops = 4} + else if (roll < 5 ) { + log(`Rolled a ${roll}: adds 3 influence`) + game.vm_available_ops = 3} + else { + log(`Rolled a ${roll}: adds 1 influence`) + game.vm_available_ops = 1} + game.phase = 2 + }, + done() { + vm_next() + } +} + +states.vm_new_years_eve_party = { + get inactive() { + return `resolve ${cards[104].name}.` + }, + prompt() { + view.prompt = 'Choose whether the game ends at the end of this turn.' + gen_action('end') + gen_action('continue') + }, + end() { + push_undo() + game.persistent_events['new_years_eve_party'] = true + log('Chooses to end the game. There will be no final scoring') + let power = Object.values(game.revolutions).filter(value => value === false).length + if (power > 3) { + log(`Communist holds power in ${power} countries. -3 VP`) + game.vp -= 3 + } else { + log(`Communist holds power in ${power} countries. +3 VP`) + game.vp += 3 + } + check_vp() + game.table_cards.push(104) + vm_next() + }, + continue() { + log('Chooses to continue') + permanently_remove(104) + } +} + +states.vm_nomenklatura = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Choose: remove Democratic influence from an elite space or add influence to an elite space.' + gen_action('remove') + gen_action('add') + }, + remove() { + push_undo() + game.valid_spaces = [] + for (let i = 0; i < game.pieces.length; i++) { + let piece = game.pieces[i] + let space = spaces[i] + + if (space.socio === 1 && piece.demInfl > 0) { + game.valid_spaces.push(piece.space_id) + } + } + game.vm_available_ops = 1 + game.state = 'vm_nomenklatura_remove' + }, + add() { + push_undo() + game.valid_spaces = [] + for (let space of spaces) { + if (!space) continue + if (space.socio === 1) { + game.valid_spaces.push(space.space_id) + } + } + game.vm_available_ops = 3 + game.state = 'vm_nomenklatura_add' + } +} + +states.vm_nomenklatura_remove = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.vm_available_ops === 0 || game.valid_spaces.length === 0 ) { + view.prompt = 'Remove influence: done.' + gen_action('done') + } else { + view.prompt = 'Remove all Democratic influence from an elite space.' + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); */ + gen_action_infl(spaces[space_id].name_unique); + } + } + }, + infl(space) { + vm_do_remove_all_infl(space) + }, + done() { + vm_next() + } +} + +states.vm_nomenklatura_add = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.vm_available_ops === 0 || game.valid_spaces.length === 0 ) { + view.prompt = 'Add influence: done.' + gen_action('done') + } else { + view.prompt = `Add influence to elite spaces. ${game.vm_available_ops} influence remaining.` + for (let space_id of game.valid_spaces) { + gen_action_infl(spaces[space_id].name_unique); + } + } + }, + infl(space) { + vm_do_add_infl(space) + }, + done() { + vm_next() + } +} + +states.vm_samizdat = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Samizdat: you may set aside a card from your hand and draw a replacement.' + for (let card of game.democrat_hand) { + gen_action_card(card) + } + gen_action('done') + }, + card(card) { + push_undo() + game.samizdat_card = card + game.democrat_hand = game.democrat_hand.filter(c => c !== card) + log('Set aside a card') + }, + done() { + if (game.samizdat_card > 0) {game.state = 'vm_samizdat_finish'} + else {vm_next()} + } +} + +states.vm_samizdat_finish = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.phase === 2) { + view.prompt = 'Samizdat: done.' + gen_action('done') + } else { + view.prompt = 'Draw a replacement card.' + gen_action('draw') + } + }, + draw() { + clear_undo() + game.democrat_hand.push(draw_card(game.strategy_deck)) + game.phase ++ + }, + done() { + vm_next() + } +} + +states.vm_shock_therapy = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.vm_active_country === '' ) { + view.prompt = 'Shock Therapy: choose a country where you hold Power:' + if (game.revolutions['East_Germany']) {gen_action('east_germany')} + if (game.revolutions['Poland']) {gen_action('poland')} + if (game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (game.revolutions['Hungary']) {gen_action('hungary')} + if (game.revolutions['Romania']) {gen_action('romania')} + if (game.revolutions['Bulgaria']) {gen_action('bulgaria')} + } else if (game.phase === 2) { + view.prompt = 'Shock Therapy: done.' + gen_action('done') + } else { + view.prompt = 'Roll a die.' + gen_action('roll') + } + }, + east_germany() {game.vm_active_country = 'East_Germany'}, + poland() { game.vm_active_country = 'Poland'}, + czechoslovakia() { game.vm_active_country = 'Czechoslovakia'}, + hungary() { game.vm_active_country = 'Hungary'}, + romania() { game.vm_active_country = 'Romania'}, + bulgaria () { game.vm_active_country = 'Bulgaria'}, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + for (let space of game.pieces) { + if (space && space.country === game.vm_active_country && space.comCtrl === 1 && (space.socio === 3 || space.socio === 4)) { + game.temp++ + } + } + log(`-${game.temp} from Communist controlled Worker and Farmer spaces`) + log(`Modified roll: ${roll - game.temp}`) + if ((roll - game.temp) > 2) { + log('Shock Therapy is successful. +3 VP') + vm_next() + } else { + log('Shock Therapy is unsuccessful. Required 3 or more') + game.phase++ + } + }, + done() { + permanently_remove(93) + vm_return() + } +} + +states.vm_social_democratic_platform_adopted = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Select a country where the Democrat holds Power.' + if (game.revolutions['East_Germany']) {gen_action('east_germany')} + if (game.revolutions['Poland']) {gen_action('poland')} + if (game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (game.revolutions['Hungary']) {gen_action('hungary')} + if (game.revolutions['Romania']) {gen_action('romania')} + if (game.revolutions['Bulgaria']) {gen_action('bulgaria')} + }, + east_germany() { + game.vm_active_country = 'East_Germany' + vm_next() + }, + poland() { + game.vm_active_country = 'Poland' + vm_next()}, + czechoslovakia() { + game.vm_active_country = 'Czechoslovakia' + vm_next()}, + hungary() { + game.vm_active_country = 'Hungary' + vm_next() + }, + romania() { + game.vm_active_country = 'Romania' + vm_next() + }, + bulgaria () { + game.vm_active_country = 'Bulgaria' + vm_next()} +} + +states.vm_systematization = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.persistent_events['systematization'] === 0) { + view.prompt = 'Systematization: eliminate a space in Romania.' + for (let space_id of game.valid_spaces) { + gen_action_infl(spaces[space_id].name_unique); + } + } else { + view.prompt = 'Systematization: done.' + gen_action('done') + } + }, + infl(space) { + push_undo() + vm_eliminate(find_space_index(space)) + game.valid_spaces = [] + game.persistent_events['systematization'] = find_space_index(space) + }, + done() { + vm_next() + } +} + +states.vm_the_chinese_solution = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'You may give up 3VP to conduct support checks in a country where you hold power.' + if (!game.revolutions['East_Germany']) {gen_action('east_germany')} + if (!game.revolutions['Poland']) {gen_action('poland')} + if (!game.revolutions['Czechoslovakia']) {gen_action('czechoslovakia')} + if (!game.revolutions['Hungary']) {gen_action('hungary')} + if (!game.revolutions['Romania']) {gen_action('romania')} + if (!game.revolutions['Bulgaria']) {gen_action('bulgaria')} + gen_action('pass') + }, + east_germany() {game.vm_active_country = 'East_Germany' + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() + }, + poland() { game.vm_active_country = 'Poland' + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() + }, + czechoslovakia() { game.vm_active_country = 'Czechoslovakia' + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() + }, + hungary() { game.vm_active_country = 'Hungary' + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() + }, + romania() { game.vm_active_country = 'Romania' + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() + }, + bulgaria () { game.vm_active_country = 'Bulgaria' + log('+3 VP') + game.vp += 3 + check_vp() + vm_next() + }, + pass() { + permanently_remove(96) + vm_return() + } +} + +states.vm_the_tyrant_is_gone = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.persistent_events['the_tyrant_is_gone']=== 0) { + view.prompt = 'Select a space in Romania.' + for (let space_id of game.valid_spaces) { + if (!space_id) continue + gen_action_infl(spaces[space_id].name_unique); + } + } else { + view.prompt = 'Select a space: done.' + gen_action('done') + } + }, + infl(space) { + push_undo() + game.persistent_events['the_tyrant_is_gone'] = find_space_index(space) + }, + done () { + vm_next() + } +} + +states.vm_the_wall_must_go = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.the_wall_must_go['dem_wins'] === 2 || game.the_wall_must_go['com_wins'] === 2) { + view.prompt = 'The Wall Must Go! Done.' + gen_action('done') + } else { + view.prompt = ('The Wall Must Go! Roll a die:') + gen_action('roll') + } + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + if (game.active === DEM) { + let controlled_spaces = spaces.filter(space => space && space.country === 'East_Germany' && game.pieces[space.space_id].demCtrl === 1).length + if (controlled_spaces > 0) { + log(`+${controlled_spaces} from controlled spaces in East Germany`) + log(`Modified roll: ${roll + controlled_spaces}`) + roll += controlled_spaces + } + game.the_wall_must_go['dem_roll'] = roll + } else { + let controlled_spaces = spaces.filter(space => space && space.country === 'East_Germany' && game.pieces[space.space_id].comCtrl === 1).length + if (controlled_spaces > 0) { + log(`+${controlled_spaces} from controlled spaces in East Germany`) + log(`Modified roll: ${roll + controlled_spaces}`) + roll += controlled_spaces + } + game.the_wall_must_go['com_roll'] = roll + + } + if (game.the_wall_must_go['dem_roll'] > 0 && game.the_wall_must_go['com_roll'] > 0) { + if (game.the_wall_must_go['dem_roll'] > game.the_wall_must_go['com_roll'] ) { + log('Democrat wins') + game.the_wall_must_go['dem_wins']++ + } else if (game.the_wall_must_go['dem_roll'] === game.the_wall_must_go['com_roll'] ) { + log('Tie. Re-roll') + } else { + log('Communist wins') + game.the_wall_must_go['com_wins']++ + } + game.the_wall_must_go['dem_roll'] = 0 + game.the_wall_must_go['com_roll'] = 0 + log(`Democrat: ${game.the_wall_must_go['dem_wins']}, Communist: ${game.the_wall_must_go['com_wins']}`) + } + if (game.the_wall_must_go['dem_wins'] === 2) { + log('The Democrat wins The Wall Must Go!') + return + } + if (game.the_wall_must_go['com_wins'] === 2) { + log('The Communist wins The Wall Must Go!') + return + } + next_player() + }, + done() { + if (game.the_wall_must_go['dem_wins'] === 2) { + game.persistent_events['the_wall_must_go'] = true + log('+3 VP') + game.vp += 3 + check_vp() + for (let space of game.pieces) { + if (space) {console.log('space.space_id', space.space_id)} + if (space && spaces[space.space_id].country === 'East_Germany' && space.comInfl > 0){ + game.valid_spaces.push(space.space_id) + } + } + if (game.active === DEM) {next_player()} + vm_next () + } else { + permanently_remove(86) + vm_return() + } + } +} + +states.vm_warsaw_pact_summit = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Choose to play for support checks or influence.' + gen_action('influence') + gen_action('support_check') + }, + influence(){ + push_undo() + for (let space of game.pieces) { + if (space && space.demInfl === 0) { + game.valid_spaces.push(space.space_id); + } + } + game.vm_available_ops = 4 + game.state = 'vm_add_infl' + }, + support_check(){ + push_undo() + for (let i = 1; i < game.pieces.length; i++) { + let gamePiece = game.pieces[i] + let space = spaces[i] + if (gamePiece.demInfl > 0 && (space.socio === 5 || space.socio === 6)) { + game.valid_spaces.push(gamePiece.space_id) + } + } + game.vm_available_ops = 2 + game.state = 'vm_support_check_prep' + } +} + +states.vm_we_are_the_people_remove = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.pieces[6].demInfl === 0) { + view.prompt = 'No influence to remove.' + gen_action('done') + } else if (game.vm_available_ops > 0 ) { + view.prompt = 'Remove up to 4 influence from the Lutherian Church' + gen_action('done') + for (let space_id of game.valid_spaces) { + gen_action_infl(spaces[space_id].name_unique); + } + } else { + view.prompt = 'Remove influence: done.' + gen_action('done') + } + }, + infl(space) { + vm_do_remove_infl(space) + }, + done() { + if (!game.vm_influence_added[6]) { + vm_next() + } else { + game.valid_spaces = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + game.state = 'vm_we_are_the_people_add' + } + } +} +states.vm_we_are_the_people_add = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (!game.vm_influence_added[6]) { + view.prompt = 'Add influence: done.' + gen_action('done') + return + } + + view.prompt = `You must add the ${game.vm_influence_added[6]} influence to spaces in Germany` + gen_action('done') + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id);*/ + gen_action_infl(spaces[space_id].name_unique); + } + }, + infl(space) { + vm_do_add_infl(space) + game.vm_influence_added++ + }, + done() { + vm_next() + } +} + +states.vm_workers_revolt = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + view.prompt = 'Select a target for the Workers Revolt.' + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + //} + } + }, + infl(space) { + game.temp = find_space_index(space) + game.state = 'vm_workers_revolt_finish' + } +} + + +states.vm_workers_revolt_finish = { + get inactive() { + return `resolve ${cards[game.played_card].name}.` + }, + prompt() { + if (game.temp > 0) { + view.prompt = `Target: ${spaces[game.temp].name}. Roll a die.` + gen_action('roll') + } else { + view.prompt = 'Workers Revolt: done.' + gen_action('done') + } + + }, + roll() { + clear_undo() + let roll = Math.floor(Math.random() * 6) + 1 + log(`Rolled a ${roll}`) + let adj = count_adj(spaces[game.temp].name_unique) + if (game.active === DEM) { + log(`-${adj.com_adj} from opponent controlled spaces`) + roll -= adj.com_adj + } else { + log(`-${adj.dem_adj} from opponent controlled spaces`) + roll -= adj.dem_adj + } + if (roll >= 4) { + log('Workers Revolt successful') + vm_replace_all_infl(game.temp) + } else {log('Workers Revolt fails')} + game.temp = 0 + }, + done() { + vm_next() + } +} + +// ==================== TIANANMEN SQUARE TRACK STATES ===================== + +states.vm_tst_3_prep = { + inactive: 'resolve Tiananmen Square Track award.', + prompt() { + view.prompt = 'Tiananmen Square Track award: draw 3 cards.' + gen_action('draw') + }, + draw() { + if (game.active === DEM) { + game.temp = game.democrat_hand.length + draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.democrat_hand.length + 3, game.communist_hand.length) + game.valid_cards = [game.democrat_hand[game.temp], game.democrat_hand[game.temp + 1], game.democrat_hand[game.temp + 2]] + } else { + game.temp = game.communist_hand.length + draw_cards(game.strategy_deck, game.democrat_hand, game.communist_hand, game.democrat_hand.length, game.communist_hand.length + 3) + game.valid_cards = [game.communist_hand[game.temp], game.communist_hand[game.temp + 1], game.communist_hand[game.temp + 2]] + } + game.temp = 0 + game.state = 'vm_tst_3' + } +} + +states.vm_tst_3 = { + inactive: 'resolve Tiananmen Square Track bonus.', + prompt() { + if (game.temp < 2) { + view.prompt = `Discard 2 of the drawn cards` + for (let card of game.valid_cards) { + gen_action_card(card) + } + } else { + view.prompt = 'Discard cards: done.' + gen_action('done') + } + }, + card(card) { + push_undo() + discard(card) + game.temp ++ + if (game.temp === 2) { + game.valid_cards = [] + } + }, + done() { + vm_next() + } +} + +states.vm_tst_4 = { + inactive: 'remove influence', + prompt () { + if (game.vm_available_ops === 0 || game.valid_spaces.length === 0) { + view.prompt = 'Remove influence: done.' + gen_action('done') + return + } + view.prompt = 'Tiananmen Square Track award: select a space to remove influence' + + for (let space_id of game.valid_spaces) { + /*const space = spaces.find(s => s && s.space_id === space_id); + if (space) {*/ + gen_action_infl(spaces[space_id].name_unique); + // } + } + }, + infl(space) { + vm_do_remove_infl(space) + }, + done() { + vm_next() + } +} + +states.vm_tst_6 = { + inactive: 'make their free support check.', + prompt() { + if (game.vm_available_ops === 0) { + view.prompt = 'Tiananmen Square Track award support check: done' + gen_action('done') + return + } else { + view.prompt = 'Tiananmen Square Track award: you have a free 2 op support check.' + for (let space_id of game.valid_spaces) { + if (space_id) { + gen_action_sc(spaces[space_id].name_unique); + } + } + } + }, + sc(space) { + push_undo() + game.selected_space = find_space_index(space) + game.state = 'vm_tst_6_sc' + }, + done () { + vm_next() + } +} + +/* states.vm_tst_6_prep = { + inactive: 'make their free support check.', + prompt () { + if (game.vm_available_ops === 0) { + view.prompt = 'Tiananmen Square Track award support check: done' + gen_action('done') + return + } else { + view.prompt = `Select a space for the support check.` + for (let space_id of game.valid_spaces) { + if (space_id) { + gen_action_sc(spaces[space_id].name_unique); + } + } + } + }, + sc(space) { + push_undo() + game.selected_space = find_space_index(space) + game.state = 'vm_tst_6_sc' + }, + done () { + vm_next() + } +} */ + +states.vm_tst_6_sc = { + inactive: 'do support check.', + prompt () { + view.prompt = `Target: ${spaces[game.selected_space].name_unique}. Roll a die` + gen_action('roll') + }, + roll() { + clear_undo() + do_sc(spaces[game.selected_space].name_unique) + game.vm_available_ops-- + game.state = 'vm_tst_6' + return + } +} + +states.vm_tst_8 = { + inactive: 'use Tiananmen Square Track award.', + prompt() { + if (game.vm_event_to_do && game.vm_infl_to_do) { + view.prompt = 'Choose whether to play for event or operations first.' + gen_action('event') + gen_action('ops') + } + else if (!game.vm_event_to_do && game.vm_infl_to_do) { + view.prompt = 'Event resolved. Use card for operations.' + gen_action('ops') + } + else if (game.vm_event_to_do && !game.vm_infl_to_do) { + view.prompt = 'Operations resolved. Use card for event.' + gen_action('event') + } + else if (!game.vm_event_to_do && !game.vm_infl_to_do) { + view.prompt = 'Event and operations: done.' + gen_action('done') + } + }, + event() { + game.vm_event_to_do = false + game.return_state = 'vm_tst_8' + game.return = game.active + goto_vm(game.played_card) + }, + ops() { + game.vm_infl_to_do = false + game.return = game.active + game.return_state = 'vm_tst_8' + goto_vm(208) + }, + done() { + game.tst_8 = true + end_round() + } +} + + +states.vm_tst_8_ops = { + inactive: 'play card for operations.', + prompt() { + view.prompt = `Play ${cards[game.played_card].name} for:` + gen_action('influence') + gen_action('support_check') + if ((game.active === DEM && game.dem_tst_attempted_this_turn === 0 ) || (game.active === COM && game.com_tst_attempted_this_turn === 0 )) { + gen_action('tst') + } + }, + influence(){ + push_undo() + game.vm_available_ops = cards[game.played_card].ops + valid_spaces_infl() + game.state = 'vm_add_infl' + }, + support_check() { + push_undo() + game.vm_available_ops = 2 + game.state = 'vm_support_check_prep' + }, + tst() { + game.state = 'vm_tiananmen_square_attempt' + } +} + +// ========================= POWER STRUGGLE STATES ======================== + +states.vm_support_surges = { + inactive: 'draw cards.', + prompt() { + view.prompt = 'Draw 2 cards' + gen_action('draw') + }, + draw() { + if (game.active === DEM) { + draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand.length+2, game.com_pwr_hand.length) + } else { + draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand.length, game.com_pwr_hand.length+2) + } + game.phase = 0 + log('Drew 2 cards') + log('Surrenders initiative') + vm_next() + } +} + +states.vm_support_falters = { + inactive: 'discard cards.', + prompt() { + if (game.vm_available_ops > 0) { + view.prompt = 'Discard a card' + gen_action('discard') + } else { + view.prompt = 'Discard cards: done.' + gen_action('done') + } + }, + discard() { + console.log('game.com_pwr_hand', game.com_pwr_hand) + if (game.active === DEM) {discard_card(game.dem_pwr_hand)} + else {discard_card(game.com_pwr_hand)} + game.vm_available_ops -- + }, + done() { + log_msg_gap('Takes initiative') + game.return = game.active + vm_next() + } +} + +/* =================== EVENTS ================================ */ + +const CODE = [] +CODE[1] = [//Legacy of Martial Law* + [vm_valid_spaces_country_opp, 'Poland'], + [vm_legacy_of_martial_law], + [vm_valid_spaces_country_sc, 'Poland'], + [vm_support_check, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[2] = [//Solidarity Legalised* + [vm_solidarity_legalised], + [vm_valid_spaces_solidarity_legalised], + [vm_add_limited_infl, 9, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[3] = [//Walesa + [vm_valid_spaces_country, 'Poland'], + [vm_add_infl_free, 4], + [vm_valid_spaces_country_sc, 'Poland'], + [vm_support_check, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[4] = [//Michnik + [vm_valid_spaces, 26], + [vm_add_x_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[5] = [//General strike + [vm_general_strike], + [vm_return] +] +CODE[6] = [//Brought in for Questioning + [vm_brought_in_for_questioning], + [vm_return] +] +CODE[7] = [//State Run Media* + [vm_valid_spaces_opponent], + [vm_remove_limited_opp_infl, 4, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[8] = [//Prudence + [vm_prudence], + [vm_return] +] +CODE[9] = [// The Wall* + [vm_the_wall], + [vm_permanently_remove] + [vm_return] +] +CODE[10] = [//Cult of Personality + [vm_valid_spaces_country_socio_2, 'Romania', 3, 4], + [vm_add_limited_infl, 4, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[11] = [//Dissident arrested + [vm_valid_spaces_opponent_socio, 5], + [vm_remove_x_opp_infl, 2], + [vm_return] +] +CODE[12] = [//Apparatchicks + [vm_valid_spaces_socio, 2], + [vm_add_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[13] = [// Stasi + [vm_stasi], + [vm_permanently_remove], + [vm_return] +] +CODE[14] = [//Gorbachev Charms the West + [vm_valid_spaces_opponent], + [vm_remove_opp_infl, 2], + [vm_valid_spaces_sc], + [vm_support_check, 1], + [vm_return] +] +CODE[15] = [//Honecker + [vm_honecker], + [vm_permanently_remove], + [vm_return] +] +CODE[16] = [//Nomenklatura* + [vm_nomenklatura], + [vm_permanently_remove], + [vm_return] +] +CODE[17] = [//Roundtable talks + [vm_roundtable_talks], + [vm_return] +] +CODE[18] = [//Poszgay Defends the Revolution + [vm_poszgay], + [vm_add_limited_infl, 4, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[19] = [// Papal vist + [vm_valid_spaces, 20, 35, 38], + [vm_add_x_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[20] = [//Deutsche Marks* + [vm_deutsche_marks], + [vm_permanently_remove], + [vm_return] +] +CODE[21] = [//Common European Home + [vm_common_european_home], + [vm_return] +] +CODE[22] = [//Power Struggle - Poland + [vm_power_struggle], + [vm_return] +] +CODE[23] = [//Power Struggle - Hungary + [vm_power_struggle], + [vm_return] +] +CODE[24] = [// St Nicolas Church + [vm_valid_spaces, 6], + [vm_take_control_prep, 1], + [vm_st_nicholas_church], + [vm_return] +] +CODE[25] = [// Perestroika + [vm_perestroika], + [vm_return] +] +CODE[26] = [//Helsinki Final Act* + [vm_helsinki_final_act], + [vm_permanently_remove], + [vm_return] +] +CODE[27] = [// Consumerism + [vm_valid_spaces_opponent_socio, 4], + [vm_remove_opp_infl, 1], + [vm_valid_spaces_opponent_socio, 4], + [vm_active_country], + [vm_support_check, 1], + [vm_return] +] +CODE[28] = [//Factory Party Cells + [vm_valid_spaces_opponent_socio, 4], + [vm_remove_limited_opp_infl, 3, 2], + [vm_return] + +] +CODE[29] = [//Jan Palach Week* + [vm_valid_spaces, 30], + [vm_add_x_infl, 6], + [vm_permanently_remove], + [vm_return] +] +CODE[30] = [// Tear Gas + [vm_tear_gas], + [vm_return] +] +CODE[31] = [// Intelligentsia + [vm_valid_spaces, 4, 26, 31, 46, 55, 73], + [vm_add_limited_infl, 4, 2], + [vm_return] +] +CODE[32] = [//Peasant Parties* + [vm_valid_spaces_socio, 3], + [vm_add_limited_infl, 4, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[33] = [//Sajudis* + [vm_valid_spaces, 56, 70], + [vm_take_control_prep, 1], + [vm_sajudis], + [vm_permanently_remove], + [vm_return] +] +CODE[34] = [//Fidesz* + [vm_valid_spaces, 47], + [vm_add_x_infl, 6], + [vm_permanently_remove], + [vm_return] +] +CODE[35] = [//Heal our Bleeding Wounds* + [vm_heal_our_bleeding_wounds], + [vm_permanently_remove], + [vm_return] +] +CODE[36] = [//Dash for the West* + [vm_dash_for_the_west], + [vm_permanently_remove], + [vm_return] +] +CODE[37] = [//Nagy Reburied* + [vm_valid_spaces, 43], + [vm_remove_all_infl, 1], + [vm_valid_spaces_country, 'Hungary'], + [vm_add_limited_infl, 4, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[38] = [// July Concept + [vm_valid_spaces_country, 'Bulgaria'], + [vm_add_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[39] = [//Eco-Glasnost* + [vm_valid_spaces, 66], + [vm_add_x_infl, 4], + [vm_eco_glasnost], + [vm_return] +] +CODE[40] = [//Hungarian Democratic Forum + [vm_valid_spaces_country, 'Hungary'], + [vm_add_infl_free, 3], + [vm_valid_spaces_country_sc, 'Hungary'], + [vm_support_check, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[41] = [//Ceausescu* + [vm_valid_spaces_country_sc, 'Romania'], + [vm_remove_opp_infl, 3], + [vm_valid_spaces_country_sc, 'Romania'], + [vm_support_check, 1], + [vm_ceausescu], + [vm_permanently_remove], + [vm_return] +] +CODE[42] = [//Power Struggle - East Germany + [vm_power_struggle], + [vm_return] +] +CODE[43] = [//Power Struggle - Bulgaria + [vm_power_struggle], + [vm_return] +] +CODE[44] = [ // Inflationary Currency + [ vm_inflationary_currency ], + [ vm_valid_spaces_country_sc ], + [ vm_remove_opp_infl, 2 ], + [ vm_inflationary_currency_discard ], + [ vm_if, ()=>discarded_card() ], + [ vm_valid_spaces_country_sc ], + [ vm_support_check, 1 ], + [ vm_endif ], + [ vm_permanently_remove ], + [ vm_return ], + [ vm_return ], +] +CODE[45] = [//Soviet Troop Withdrawals* + [vm_valid_spaces_region_opp, 'Eastern Europe'], + [vm_remove_limited_opp_infl, 5, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[46] = [//Goodbye Lenin!* + [vm_goodbye_lenin], + [vm_permanently_remove], + [vm_return] +] +CODE[47] = [//Bulgarian Turks Expelled* + [vm_bulgarian_turks_expelled], + [vm_remove_all_infl, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[48] = [//We are the People!* + [vm_we_are_the_people], + [vm_permanently_remove], + [vm_return] +] +CODE[49] = [//Foreign Currency Debt Burden* + [vm_foreign_currency_debt_burden], + [vm_return] +] +CODE[50] = [//The Sinatra Doctrine* + [vm_the_sintra_doctrine], + [vm_permanently_remove], + [vm_return] +] +CODE[51] = [//40th Anniverstary Celebration + [vm_40th_anniversary_celebration], + [vm_valid_spaces_country, 'East_Germany'], + [vm_add_infl_free], + [vm_40th_anniversary_celebration_vp], + [vm_permanently_remove], + [vm_return] + +] +CODE[52] = [//Normalisation + [vm_normalisation], + [vm_remove_all_infl, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[53] = [//Li Peng* + [vm_li_peng], + [vm_return] +] +CODE[54] = [//The Crowd Turns Against Ceausescu* + [vm_the_crowd_turns_against_ceausescu], + [vm_return] +] +CODE[55] = [//Power Struggle - Czechoslovakia + [vm_power_struggle], + [vm_return] +] +CODE[56] = [//Foreign Television + [vm_foreign_television], + [vm_remove_limited_opp_infl, 4 ,2], + [vm_permanently_remove], + [vm_return] +] +CODE[57] = [//Central Committee Reshuffle* + [vm_central_committee_reshuffle], + [vm_add_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[58] = [//Austria-Hungary Border Reopened* + [vm_austria_hungary_border_reopened], + [vm_return] + ] +CODE[59] = [//GrenzTruppen* + [vm_grenztruppen], + [vm_return] + ] +CODE[60] = [//Toxic Waste* + [vm_valid_spaces_socio, 4], + [vm_add_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[61] = [//The Monday Demonstrations* + [vm_the_monday_demonstrations], + [vm_take_control_prep, 2], + [vm_valid_spaces_country_sc, 'East_Germany'], + [vm_support_check, 5], + [vm_permanently_remove], + [vm_return] +] +CODE[62] = [//Yakovlev Counsels Gorbachev* + [vm_yakovlev_counsels_gorbachev], + [vm_return] +] +CODE[63] = [//Genscher* + [vm_genscher], + [vm_return] +] +CODE[64] = [//Legacy of 1968* + [vm_legacy_of_1968], + [vm_add_limited_infl, 11, 1], + [vm_permanently_remove], + [vm_return] + ] +CODE[65] = [//Presidential Visit* + [vm_presidential_visit], + [vm_return] +] +CODE[66] = [//New Forum + [vm_valid_spaces_country, 'East_Germany'], + [vm_add_limited_infl, 3, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[67] = [//Reformer Rehabilitated* + [vm_reformer_rehabilitated], + [vm_return] + ] +CODE[68] = [//Klaus and Komarek* + [vm_klaus_and_komarek], + [vm_remove_x_opp_infl, 2], + [vm_valid_spaces, 29], + [vm_add_x_infl, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[69] = [//Systematization* + [vm_valid_spaces_country, 'Romania'], + [vm_systematization], + [vm_permanently_remove], + [vm_return] +] +CODE[70] = [//Securitate* + [vm_securitate], + [vm_return], +] +CODE[71] = [//Kiss of Death* + [vm_permanently_remove], + [vm_kiss_of_death], + [vm_return] +] +CODE[72] = [//Peasant Parties Revolt + [vm_peasant_parties_revolt], + [vm_return] + ] +CODE[73] = [//Laszlo Tokes* + [vm_valid_spaces, 50, 56], + [vm_add_limited_infl, 2, 1], + [vm_laszlo_tokes], + [vm_permanently_remove], + [vm_return] +] +CODE[74] = [//FRG Embassies + [vm_frg_embassies], + [vm_return] +] +CODE[75] = [//Exit Visas* + [vm_exit_visas], + [vm_permanently_remove], + [vm_return] +] +CODE[76] = [//Warsaw Pact Summit + [vm_warsaw_pact_summit], + [vm_permanently_remove], + [vm_return] +] +CODE[77] = [//Samizdat + [vm_samizdat], + [vm_permanently_remove], + [vm_return] +] +CODE[78] = [//Workers Revolt + [vm_workers_revolt], + [vm_return] +] +CODE[79] = [//The Third Way* + [vm_the_third_way], + [vm_valid_spaces, 4], + [vm_add_x_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[80] = [//Nepotism* + [vm_nepotism], + [vm_valid_spaces_region_socio, 'Balkans', 4], + [vm_add_infl], + [vm_permanently_remove], + [vm_return] +] +CODE[81] = [//The Baltic Way* + [vm_the_baltic_way], + [vm_take_control_prep, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[82] = [//Spitzel* + [vm_valid_spaces_country_sc, 'East_Germany'], + [vm_remove_opp_infl, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[83] = [//Modrow* + [vm_modrow], + [vm_valid_spaces_country, 'East_Germany'], + [vm_add_limited_infl, 4, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[84] = [//Breakaway Baltic Republics* + [vm_breakaway_baltic_republics], + [vm_take_control_prep, 1], + [vm_valid_spaces_sc], + [vm_support_check, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[85] = [//Tank Column/Tank Man* + [vm_tank_column], + [vm_permanently_remove], + [vm_return] +] +CODE[86] = [//The Wall Must Go!* + [vm_the_wall_must_go], + [vm_remove_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[87] = [//Kohl Proposes Reunification* + [vm_kohl_proposes_reunification], + [vm_permanently_remove], + [vm_return] +] +CODE[88] = [//Adamec* + [vm_adamec], + [vm_valid_spaces_country, 'Czechoslovakia'], + [vm_add_limited_infl, 4, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[89] = [//Domino Theory* + [vm_domino_theory], + [vm_permanently_remove], + [vm_return] +] +CODE[90] = [//Civic Forum* + [vm_valid_spaces_country, 'Czechoslovakia'], + [vm_add_infl_free, 4], + [vm_civic_forum], + [vm_valid_spaces_country_sc, 'Czechoslovakia'], + [vm_support_check, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[91] = [//My First Banana* + [vm_valid_spaces_country_opp, 'East_Germany'], + [vm_remove_opp_infl, 2], + [vm_valid_spaces_country_sc, 'East_Germany'], + [vm_support_check, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[92] = [//vm_betrayal + [vm_betrayal], + [vm_permanently_remove], + [vm_return] +] +CODE[93] = [//Shock Therapy* + [vm_shock_therapy], + [vm_valid_spaces_country], + [vm_add_infl, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[94] = [//Union of Democratic Forces* + [vm_valid_spaces_country_sc, 'Bulgaria'], + [vm_remove_opp_infl, 4], + [vm_valid_spaces_country_sc, 'Bulgaria'], + [vm_support_check, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[95] = [//Power Struggle - Romania + [vm_power_struggle], + [vm_return] +] +CODE[96] = [//The Chinese Solution* + [vm_the_chinese_solution], + [vm_valid_spaces_country_sc], + [vm_support_check_modified, 5, 3], + [vm_permanently_remove], + [vm_return] +] +CODE[97] = [//The Tyrant is Gone* + [vm_valid_spaces, 51], + [vm_remove_opp_infl, 4], + [vm_the_tyrant_is_gone], + [vm_permanently_remove], + [vm_return] +] +CODE[98] = [//Politbuto Intrigue* + [vm_valid_spaces_country_sc, 'Bulgaria'], + [vm_remove_limited_opp_infl, 3, 2], + [vm_valid_spaces_country_sc, 'Bulgaria'], + [vm_support_check, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[99] = [//Ligachev* + [vm_ligachev], + [vm_permanently_remove], + [vm_return] +] +CODE[100] = [//Stand Fast* + [vm_stand_fast], + [vm_permanently_remove], + [vm_return] +] +CODE[101] = [//Elena* + [vm_valid_spaces, 51], + [vm_add_infl, 2], + [vm_elena], + [vm_return] +] +CODE[102] = [//National Salvation Front* + [vm_national_salvation_front], + [vm_return] +] +CODE[103] = [//Government Resigns* + [vm_government_resigns], + [vm_remove_all_infl, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[104] = [//New Year's Eve Party* + [vm_new_years_eve_party], + [vm_return] +] +CODE[105] = [//Public Against Violence* + [vm_valid_spaces, 36, 37], + [vm_add_limited_infl, 4 ,2], + [vm_public_against_violence], + [vm_support_check_modified, 1, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[106] = [//Social Democratic Platform Adopted* + [vm_social_democratic_platform_adopted], + [vm_valid_spaces_country], + [vm_add_infl, 2], + [vm_valid_spaces_country_sc], + [vm_support_check, 1], + [vm_permanently_remove], + [vm_return] +] +CODE[107] = [//Massacre in Timisoara* + [vm_valid_spaces_country_sc, 'Romania'], + [vm_support_check_modified, 2, 2], + [vm_permanently_remove], + [vm_return] +] +CODE[108] = [//Army Backs Revolution* + [vm_army_backs_revolution], + [vm_permanently_remove], + [vm_return] +] +CODE[109] = [//Kremlin Coup* + [vm_kremlin_coup], + [vm_take_control_prep, 6], + [vm_permanently_remove], + [vm_return] +] +CODE[110] = [//Malta Summit* + [vm_malta_summit], + [vm_permanently_remove], + [vm_return] +] + +// ============= TIANANMEN SQUARE TRACK AWARDS ==================== +CODE[203] = [//Tiananmen Square space 3 award + [vm_tst_3], + [vm_return] +] +CODE[204] = [//Tiananmen Square space 4 award + [vm_valid_spaces_sc], + [vm_tst_4], + [vm_return] +] +CODE[206] = [//Tiananmen Square space 6 + [vm_valid_spaces_sc], + [vm_tst_6], + [vm_return] +] +CODE[208] = [//Tiananmen Square space 8 event + [vm_tst_8], + [vm_return] +] + +// ============= POWER STRUGGLE WILDCARDS ========================= + +CODE[349] = [//Scare Tactics + [vm_scare_tactics], + [vm_valid_spaces_country_sc], + [vm_remove_opp_infl, 1], + [vm_return] +] +CODE[350] = [//Support Surges + [vm_support_surges], + [vm_return] +] +CODE[351] = [//Support Falters + [vm_support_falters], + [vm_return] +] -- cgit v1.2.3