//"use strict" const { spaces, cards, power_cards } = require("./data.js") var game, view, states = {} const DEM = "Democrat" const COM = "Communist" const first_strategy_card = 1 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 = [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 = ['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 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, 54, 58, 59, 62, 63, 65, 70, 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) { game = { seed: seed, log: [], undo: [], summary: [], active: null, state: "com_init", return: '', vm: null, vm_event: 0, vm_event_to_do: false, vm_infl_to_do: false, played_card: 0, table_cards: [], available_ops: 0, vm_available_ops: 0, valid_spaces: [], valid_cards: [], vp: 0, turn: 0, round: 0, round_player: COM, stability: 0, dem_tst_position: 0, com_tst_position: 0, dem_tst_attempted: 0, com_tst_attempted: 0, dem_tst_attempted_this_turn: 0, com_tst_attempted_this_turn: 0, demInfl: [], comInfl: [], strategy_deck: [], strategy_discard: [], discard: false, view_opp_hand: false, strategy_removed: [], persistent_events: [], power_struggle_deck: [], power_struggle_discard: [], dem_hand_limit: 8, com_hand_limit: 8, democrat_hand: [], communist_hand: [], pwr_struggle_in: [], is_pwr_struggle: false, dem_pwr_hand_limit: 0, com_pwr_hand_limit: 0, dem_pwr_hand: [], com_pwr_hand: [], raised_stakes_discard: 0, raised_stakes: 0, raised_stakes_round: 0, phase: 0, times_held: [0, 0, 0, 0, 0, 0], revolutions: [false, false, false, false, false, false], remove_opponent_infl: false, tactics_fails: '', } log_h1("1989 Dawn of Freedom") game.active = COM start_game() return game } function start_game() { //starting influence // Draw cards console.log('start game') game.strategy_deck = draw_deck(cards) reset_power() //Set starting influence spaces.forEach((space, index) => { if (space !== null) { game.demInfl[index] = space.demInfl game.comInfl[index] = space.comInfl } }) //Set starting placement ops game.starting_infl = { com_starting_infl: 0, dem_starting_infl: 0 }, // Set variable event cards where event is playable at start of game game.playable_cards = [14, 15, 21, 70] //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) //.log('game.strategy_deck: ', game.strategy_deck[1], 'democrat_hand:', game.democrat_hand) game.valid_spaces = valid_spaces_setup() game.available_ops = 2 game.phase = 0 log_h1("Place starting Support Points") log_side() } exports.view = function(state, player) { game = state view = { log: game.log, active: game.active, prompt: null, actions: null, played_card: game.played_card, table_cards: game.table_cards, valid_spaces: game.valid_spaces, valid_cards: game.valid_cards, demInfl: game.demInfl, comInfl: game.comInfl, turn: game.turn, round: game.round, round_player: game.round_player, vp: game.vp, stability: game.stability, dem_tst: game.dem_tst_position, com_tst: game.com_tst_position, persistent_events: game.persistent_events, systematization: game.systematization, the_tyrant_is_gone: game.the_tyrant_is_gone, strategy_deck: game.strategy_deck.length, strategy_removed: game.strategy_removed, 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, hand: [], set_aside: [], pwr_hand: [], } if (game.is_pwr_struggle) { view.strategy_discard = game.power_struggle_discard } else { view.strategy_discard = game.strategy_discard } if (player === game.active && game.vm && game.vm.draw) 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 if (game.communist_hand_red) { 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.opp_hand = game.dem_pwr_hand.sort((a, b) => a - b) view.power_hand = game.com_pwr_hand.sort((a, b) => a - b) } if (player === DEM) { view.samizdat = game.samizdat_card } if (game.state === "game_over") { view.prompt = game.victory } else if (player === "Observer" || (game.active !== player && game.active !== "Both")) { if (states[game.state]) { let inactive = states[game.state].inactive if (typeof inactive === "function") view.prompt = `Waiting for ${game.active} ${inactive()}` else view.prompt = `Waiting for ${game.active} to ${inactive}` } else { view.prompt = "A Unknown state: " + game.state } } else { view.actions = {} if (states[game.state]) states[game.state].prompt(player) else view.prompt = "B Unknown state: " + game.state if (view.actions.undo === undefined) { if (game.undo && game.undo.length > 0) view.actions.undo = 1 else view.actions.undo = 0 } } return view } // === ACTIONS =========== function gen_action(action, argument) { //console.log('gen_action called with ', action, ' and ', argument) if (argument === undefined) { //console.log('argument undefined') view.actions[action] = 1 } else { if (!(action in view.actions)) { //console.log('push 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){ gen_action("infl", space) } function gen_action_card(card){ gen_action("card", card) } function gen_action_sc(space){ gen_action("sc", space) } function gen_action_scoring(){ 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) } else { if (action === "undo" && game.undo && game.undo.length > 0) pop_undo() else throw new Error("Invalid action: " + action) } return game } // ============= GAME STATES ======================= states.com_init = { inactive: 'place starting SPs.', prompt() { console.log('state:', game.state, 'game.valid_spaces', game.valid_spaces) if (game.available_ops == 0) { view.prompt = 'Place starting SPs: done.'; gen_action("done"); return; } else if (game.starting_infl.dem_starting_infl === 2) { view.prompt = `Place your last ${pluralize(game.available_ops,'starting SP')}.` } else { view.prompt = `Place ${pluralize(game.available_ops,'starting SP')}.` } for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } }, infl(space) { add_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } game.starting_infl.com_starting_infl++ if (game.starting_infl.com_starting_infl == 1){ game.available_ops = 3 game.state = 'dem_init' valid_spaces_setup() next_player() } else if (game.starting_infl.com_starting_infl == 2) { game.available_ops = 4 game.state = 'dem_init' valid_spaces_setup() next_player() } else if (game.starting_infl.com_starting_infl == 3) { delete game.starting_infl game.state = 'start_game' } } } states.dem_init = { inactive: 'place starting SPs.', prompt() { console.log('state:', game.state) if (game.available_ops == 0) { view.prompt = 'Place starting SPs: done.'; gen_action("done"); return; } else if (game.starting_infl.com_starting_infl === 2) { view.prompt = `Place your last ${pluralize(game.available_ops,'starting SP')}.` } else { view.prompt = `Place ${pluralize(game.available_ops,'starting SP')}.` } for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } }, infl(space) { add_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } game.starting_infl.dem_starting_infl++ if (game.starting_infl.dem_starting_infl == 1){ game.available_ops = 3 } else if (game.starting_infl.dem_starting_infl == 2) { game.available_ops = 2 } game.state = 'com_init' valid_spaces_setup() next_player() } } states.start_game = { inactive: 'start Turn 1.', prompt() { console.log('state:', game.state) 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() { console.log('state:', game.state) if ((game.active===DEM && game.democrat_hand.length === 0) || game.active === COM && game.communist_hand.length === 0) { view.prompt = 'No cards remaining: you must pass.' gen_action('pass') } else { view.prompt = 'Choose a card.' let available_cards if (game.active === DEM) { available_cards = game.democrat_hand } else { available_cards = game.communist_hand } for (let card of available_cards) { gen_action_card(card) } } }, card(card) { push_undo() //Check if player is at risk of losing game due to held scoring card if (!scoring_cards.includes(card)) { let scoring_cards_count = count_scoring_cards() if (game.round !== 8 && scoring_cards_count >= (8-game.round)){ game.temp = card game.state = 'confirm_card' return } } select_card(card) }, pass() { log('No cards remaining. Passed') end_round() } } states.confirm_card = { inactive: 'choose a card.', prompt() { let scoring_cards_count = count_scoring_cards() view.prompt = `${pluralize(scoring_cards_count,'scoring card')} in hand with ${pluralize(8-game.round,'turn')} remaining. Scoring cards may not be held. Continue?` gen_action('continue') }, continue() { select_card(game.temp) } } states.play_card ={ get inactive() { return `play ${clean_name(cards[game.played_card].name)}.` }, prompt () { if (game.phase >= 1) { view.prompt = `${clean_name(cards[game.played_card].name)}: done.` gen_action('done') return } view.prompt = `Play ${clean_name(cards[game.played_card].name)} for:` if (scoring_cards.includes(game.played_card)) { /*view.prompt = 'Play for:'*/ gen_action('event') return } // Check for Reformer Rehabilitated //console.log('game.active', game.active, 'game.playable_cards[67].playable', game.playable_cards[67].playable) if (game.played_card === 67 && game.playable_cards.includes(67)){ if (game.active === DEM && (game.dem_tst_position > game.com_tst_position)) { gen_action('event') } if (game.active === COM && (game.dem_tst_position < game.com_tst_position)) { gen_action('event') } } //Check for events console.log('event_is_playable(game.played_card)', event_is_playable(game.played_card)) if (event_is_playable(game.played_card)) { console.log('card is playable') //Check for Tiananmen Square Track awards special abilities console.log('game.tst_7', game.tst_7) if ((game.active === DEM && cards[game.played_card].side === 'C' && game.dem_tst_position >= 7 && game.com_tst_position < 7 && !game.tst_7) || (game.active === COM && cards[game.played_card].side === 'D' && game.com_tst_position >= 7 && game.dem_tst_position < 7 && !game.tst_7)){ gen_action('tst_7') } 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') } //Continue with normal logic get_events(game.played_card) } gen_action('influence') gen_action('support_check') if ((game.active === DEM && game.dem_tst_attempted_this_turn === 0 && game.dem_tst_position < 8 ) || (game.active === COM && game.com_tst_attempted_this_turn === 0 && game.com_tst_position < 8)) { gen_action('tst') } }, event() { push_undo() console.log('played event, game.active', game.active, 'game.view_opp_hand', game.view_opp_hand) log_gap(`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()} game.vm_event = game.played_card goto_vm(game.vm_event) }, opp_event() { push_undo() log_gap(`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 game.vm_event = game.played_card if (auto_resolve_events.includes(game.played_card) || switch_events.includes(game.played_card)) { goto_vm(game.vm_event)} else { next_player() log(`C${game.vm_event}`) goto_vm(game.vm_event) } }, influence() { push_undo() log_gap(`Played C${cards[game.played_card].number} to place SPs`) // Check if Common European Home played for influence if (game.played_card === 21) { if (game.active === DEM) { game.vp -- log('-1 VP') if (check_vp()) { return } } else { game.vp ++ log('+1 VP') if (check_vp()) { return } } } // Check if card is opponent card with event that needs to be resolved if (cards[game.played_card].playable || game.playable_cards.includes(game.played_card)) { if ((game.active === DEM && cards[game.played_card].side === "C" ) || (game.active === COM && cards[game.played_card].side === "D")) { //game.phase = 1 /*Do I need this? */ game.vm_event_to_do = true } } // If ABHR - Set AHBR tracker to true if (game.persistent_events.includes(58)) { game.austria_hungary_border_reopened_tracker = true } game.state='add_influence' valid_spaces_infl() }, tst() { push_undo() log_gap(`Played C${cards[game.played_card].number} to the Tiananmen Square Track`) game.state='tiananmen_square_attempt' }, support_check() { push_undo() log_gap(`Played C${cards[game.played_card].number} for support checks`) // Check if card is opponent card with event that needs to be resolved if (cards[game.played_card].playable || game.playable_cards.includes(game.played_card)) { if ((game.active === DEM && cards[game.played_card].side === "C" ) || (game.active === COM && cards[game.played_card].side === "D")) { game.vm_event_to_do = true } } game.available_ops = 2 game.state='support_check_prep' valid_spaces_sc() }, tst_7() { /*Cancel opponent event */ push_undo() log(`Played C${game.played_card}. Event cancelled using TST Award`) game.tst_7 = true game.vm_infl_to_do = true game.state = 'resolve_opponent_event' }, tst_8() { /*Play card for ops and event */ push_undo() 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.resolve_opponent_event = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { console.log('in resolve opponent event: discard', game.strategy_discard) 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 = `${clean_name(cards[game.played_card].name)}: you must resolve the opponent event.` gen_action('opp_event') } else { view.prompt = 'Event resolved. End the action round.' gen_action('done') } }, influence(){ push_undo() // If ABHR - Set AHBR tracker to true if (game.persistent_events.includes(58)) { game.austria_hungary_border_reopened_tracker = true } 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() }, opp_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 log(`Played C${game.played_card} for the event`) goto_vm(game.played_card)} else { if (game.active === DEM) { game.return = COM } else { game.return = DEM } next_player() log(`C${game.played_card}`) goto_vm(game.played_card) } }, tst_7() { push_undo() log('Event cancelled using TST Award') game.tst_7 = true game.vm_event_to_do = false }, done() { /*if(game.round_player === COM && game.active === DEM) { log_h3('End of Communist Action Round') change_player() } */ end_round() } } states.finish_add_infl = { inactive: 'add SPs.', prompt () { if (game.available_ops === 0) { view.prompt = 'Place SPs: done.' gen_action("done") return; } view.prompt = `Add SPs: ${game.available_ops} remaining` // Generate actions for valid spaces for (let space_id of game.valid_spaces) { gen_action_infl(space_id) } }, infl(space) { add_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } end_round() } } states.finish_support_check_prep = { inactive: 'do support checks.', prompt () { if (game.available_ops === 0) { view.prompt = 'Support checks: done.' gen_action('done') //return } else { view.prompt = `Select a space. ${pluralize(game.available_ops, 'support check')} remaining.` for (let space_id of game.valid_spaces) { gen_action_sc(space_id) } } }, sc(space) { push_undo() game.selected_space = 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.persistent_events.includes(58)){ if (game.active === DEM && game.available_ops > 1) { //console.log('in ahb check, country, ', spaces[game.selected_space].country, 'ahb', 'austria_hungary_border_reopened']) if (spaces[game.selected_space].country === 'East_Germany' && game.persistent_events.includes(58) && game.active === DEM) { game.state = 'finish_austria_hungary_border_reopened_check' return } } } game.state = 'finish_do_support_check' }, done () { end_round() } } states.finish_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_tracker = true game.state = 'finish_do_support_check' }, no() { game.state = 'finish_do_support_check' } } states.finish_do_support_check = { inactive: 'do support checks', prompt () { view.prompt = `Support check: ${spaces[game.selected_space].name_unique}. Roll a die.` gen_action('roll') }, roll() { clear_undo() do_sc(game.selected_space) game.available_ops-- if (game.available_ops === 0) { game.valid_spaces = [] } game.state = 'finish_support_check_prep' return } } states.add_influence = { inactive: 'add SPs.', prompt () { if (game.available_ops <= 0) { view.prompt = 'Place SPs: done.' gen_action("done") return } view.prompt = `Add SPs: ${game.available_ops} remaining.` // Generate actions for valid spaces for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } }, infl(space) { add_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } if(game.vm_event_to_do) { reset_austria_hungary_border_reopened() game.state = 'resolve_opponent_event'} else { end_round()} } } states.tiananmen_square_attempt = { inactive: 'do Tiananmen Square Attempt.', prompt () { view.prompt = 'Tiananmen Square Track attempt: Roll a die.' gen_action('roll') }, roll() { clear_undo() do_tst_attempt () } } states.tiananmen_square_attempt_success = { inactive: 'do Tiananmen Square Attempt.', prompt () { if (game.vm_event > 200) { view.prompt = 'Tiananmen Square Track attempt successful. Go to TST Award.' } else { view.prompt = 'Tiananmen Square Track attempt successful.' } gen_action('done') }, done () { if (game.vm_event > 200) { goto_vm(game.vm_event) } else { game.state = 'tiananmen_square_attempt_done' } } } states.tiananmen_square_attempt_fail = { inactive: 'do Tiananmen Square Attempt.', prompt () { view.prompt = 'Tiananmen Square Track attempt failed.' gen_action('done') }, done () { game.state = 'tiananmen_square_attempt_done' } } states.tiananmen_square_attempt_done = { inactive: 'do Tiananmen Square Attempt.', prompt () { view.prompt = 'Tiananmen Square Track attempt: done.' gen_action('done') }, done () { 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) } gen_action('pass') /*} else { view.prompt = 'Discard a card: done.' gen_action('done') }*/ }, card(card) { push_undo() discard(card) game.valid_cards = [] game.state = 'tst_goddess_draw' //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() } if (game.persistent_events.includes(5)) { game.state = 'general_strike' } else { game.state = 'choose_card' } }, done() { log_h2("Action Round " + game.round) if (game.active === DEM) { next_player() } else { log_side() } game.phase = 0 if (game.persistent_events.includes(5)) { game.state = 'general_strike' } else { game.state = 'choose_card' } } } states.tst_goddess_draw = { inactive: 'choose whether to discard a card.', prompt() { view.prompt = 'Draw a replacement card.' gen_action('draw') }, draw() { 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) } log_h2("Action Round " + game.round) if (game.active === DEM) { next_player() } else { log_side() } game.phase = 0 if (game.persistent_events.includes(5)) { game.state = 'general_strike' } else { 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) { gen_action_sc(space_id) } } }, sc(space) { push_undo() game.selected_space = 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.persistent_events.includes(58)) { if (game.active === DEM && game.available_ops > 1) { if (spaces[game.selected_space].country === 'East_Germany' && game.persistent_events.includes(58) && game.active === DEM) { game.state = 'austria_hungary_border_reopened_check' return } //game.state = 'do_support_check' } /*else { */ } game.state = 'do_support_check' console.log('game.state after space selected:', game.state) //} }, 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 } if (game.vm_event_to_do) { reset_austria_hungary_border_reopened() game.state = 'resolve_opponent_event' } else { end_round() } } } states.do_support_check = { inactive: 'do support checks.', prompt () { console.log('in do_support_check') view.prompt = `Support check: ${spaces[game.selected_space].name_unique}. Roll a die.` gen_action('roll') }, roll() { clear_undo() do_sc(game.selected_space) 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_tracker = 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() game.power_struggle_deck = [...all_power_cards] console.log('game.power_struggle_deck.length', game.power_struggle_deck.length) console.log('called draw cards, country', game.pwr_struggle_in, 'game.active', game.active, 'game.view_opp_hand', game.view_opp_hand) console.log('test3') let presence = check_presence(game.pwr_struggle_in) console.log('test2') 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.includes(17) && game.com_pwr_hand_limit >= 2) { 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 = game.persistent_events.filter(n => n !== 17) } if (game.persistent_events.includes(72)) { let farmer_check for (let space of spaces) { if (space && space.country === game.pwr_struggle_in && space.socio === 3 && check_dem_control(space.space_id)) { farmer_check = true } } if (farmer_check && game.com_pwr_hand_limit > 0) { log('Democrat receives 1 cards from Communist due to C72') game.dem_pwr_hand_limit += 1 game.com_pwr_hand_limit -= 1 permanently_remove(72) game.persistent_events = game.persistent_events.filter(n => n !== 72) } } if (game.persistent_events.includes(102) && game.dem_pwr_hand_limit >=2 && (game.pwr_struggle_in === 'Romania' || game.pwr_struggle_in === 'Bulgaria')) { log('Communist receives 2 cards from Democrat due to C102') game.dem_pwr_hand_limit -= 2 game.com_pwr_hand_limit += 2 permanently_remove(102) game.persistent_events = game.persistent_events.filter(n => n !== 102) } //Draw Power Cards game.is_pwr_struggle = true console.log('game.dem_pwr_hand_limit', game.dem_pwr_hand_limit, 'game.com_pwr_hand_limit', game.com_pwr_hand_limit) 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 log(`Communist: ${game.com_pwr_hand.length} cards`) log(`Democrat: ${game.dem_pwr_hand.length} cards`) //Check if The Crowd Turns Against Ceausescu occurs if (game.table_cards.includes(54) && game.pwr_struggle_in === 'Romania') { console.log('draw cards: crowd subcheck, game.active', game.active) if (game.active === COM) { game.return = COM next_player() } log_h3('The Crowd Turns Against Ceausescu') game.persistent_events.push(54) game.state = 'the_crowd_turns_against_ceausescu_prep' } else { log_h2('Raise the Stakes') game.state = 'raise_stakes_1' console.log('game.state', game.state, 'game.active', game.active, 'game.view_opp_hand', game.view_opp_hand) } } } states.the_crowd_turns_against_ceausescu_prep = { get inactive() { return `resolve ${clean_name(cards[54].name)}.` }, prompt() { view.prompt = 'The Crowd Turns Against Ceausescu: draw cards.' gen_action('draw') }, draw() { game.ceausescu_cards = [] 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 ${pluralize(game.temp, 'Rally in the Square')}.`) game.vm_available_ops = game.temp * 3 game.state = 'vm_the_crowd_turns_against_ceausescu' } } states.vm_the_crowd_turns_against_ceausescu = { get inactive() { return `resolve ${clean_name(cards[54].name)}.` }, prompt() { view.prompt = `You have ${game.vm_available_ops} operations points. Play for:` gen_action('influence') gen_action('support_check') }, influence() { push_undo() delete game.ceausescu_cards valid_spaces_infl() game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country === 'Romania') 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() delete game.ceausescu_cards valid_spaces_sc() game.available_ops = 2 game.state = 'support_check_prep' } } states.the_crowd_turns_against_ceausescu_infl = { inactive: 'add SPs.', prompt () { if (game.vm_available_ops === 0) { view.prompt = 'Place SPs: done.'; gen_action("done"); return; } view.prompt = `Add SPs: ${game.vm_available_ops} remaining` for (let space of game.valid_spaces) { gen_action_infl(space) } }, infl(space) { vm_do_add_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } if (game.return !== game.active) { next_player() } log_h2('Raise the Stakes') game.state = 'raise_stakes_1' } } states.raise_stakes_1 = { inactive: 'raise the stakes', prompt () { console.log('raise the stakes: game.played_power_card', game.played_power_card, 'game.active', game.active, 'game.view_opp_hand', game.view_opp_hand) if (game.raised_stakes_discard === 3) { view.prompt = 'Raise the stakes: done.' gen_action('done') } else { view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes.` if (game.raised_stakes_discard === 0) { gen_action('pass') } for (let card of game.valid_cards) { gen_action_card(card) } } }, card(card) { push_undo() if (numberless_cards.includes(card)) { log(`Discarded: P${card}`) } else { log(`Discarded: P${card} V${power_cards[card].value}`) } discard(card) game.raised_stakes_discard ++ if (game.raised_stakes_discard === 3) { game.raised_stakes++ game.valid_cards = [] } }, pass(){ log('Did not raise the stakes') game.raised_stakes_discard = 0 next_player() game.state = 'raise_stakes_2' }, done () { log_gap('Raised the stakes') game.raised_stakes_discard = 0 next_player() game.valid_cards = [...all_power_cards] 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 { view.prompt = `Discard ${3-game.raised_stakes_discard} cards to raise the stakes.` if (game.raised_stakes_discard === 0) { gen_action('pass') } for (let card of game.valid_cards) { gen_action_card(card) } } }, card(card) { push_undo() if (numberless_cards.includes(card)) { log(`Discarded: P${card}`) } else { log(`Discarded: P${card} V${power_cards[card].value}`) } discard(card) game.raised_stakes_discard ++ if (game.raised_stakes_discard === 3) { game.raised_stakes++ game.valid_cards = [] } }, pass() { log('Did not raise the stakes') game.raised_stakes_discard = 0 game.valid_cards = [] log_h2('Play Cards') next_player() game.state = 'begin_power_struggle' }, done () { log_gap('Raised the stakes') game.raised_stakes_discard = 0 game.valid_cards = [] log_h2('Play 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 () { console.log('game.tactics_fails', game.tactics_fails) 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) { game.tactics_fails = power_cards[game.played_power_card].name 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 { game.phase = 2 } } }, roll () { let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${roll}`) if (roll >= power_cards[game.played_power_card].value) { log('Initiative roll successful') game.phase = 0 do_valid_cards() } else { log(`Initiative roll failed. Required ${power_cards[game.played_power_card].value} or more`) game.phase = 0 next_player() do_valid_cards() } }, concede () { push_undo() log('Conceded') log_h2('Aftermath') log_h3('Support Loss') //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} if (game.phase === 0) { game.played_power_card = 0 /*If conceded when held the initiative but had no playable cards, ignore the last played card */ } game.phase = 0 game.state = 'support_loss' }, strike () { log(`Played: P${power_cards[game.played_power_card].number} as a Strike`) game.played_power_card = 9 game.phase = 1 next_player() do_valid_cards() }, march () { log(`Played: P${power_cards[game.played_power_card].number} as a March`) game.played_power_card = 21 game.phase = 1 next_player() do_valid_cards() }, rally () { log(`Played: P${power_cards[game.played_power_card].number} as a Rally in the Square`) game.played_power_card = 53 game.phase = 1 next_player() do_valid_cards() }, petition () { log(`Played: P${power_cards[game.played_power_card].number} as a Petition`) game.played_power_card = 54 game.phase = 1 next_player() do_valid_cards() }, /*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 next_player() do_valid_cards() },*/ /*infl(space) { game.remove_opponent_infl = true remove_infl(space) game.phase = 6 }, 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.phase === 7) { /*Is this ever called anymore? */ game.phase = 0 log_msg_gap('Takes initiative') do_valid_cards() } else { game.phase = 0 next_player() do_valid_cards() } } } states.support_loss ={ inactive: 'do Support Loss.', prompt () { console.log('game.played_power_card', game.played_power_card) if (game.phase === 0) { view.prompt = 'You lost the Power Struggle. Roll a die for Support Loss.' gen_action('roll') } else if (game.phase === 1 && game.available_ops > 0 && game.valid_spaces.length > 0) { view.prompt = `Support Loss: remove ${pluralize(game.available_ops,'SP')}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id) } } else if (game.phase === 1 && game.available_ops === 0 ) { view.prompt = 'Support Loss: finished.' gen_action('done') } else if (game.phase === 1 && game.valid_spaces.length === 0) { view.prompt = 'Support Loss: no remaining SPs to remove.' gen_action('done') } }, roll () { clear_undo() let roll = Math.floor(Math.random() * 6) + 1 let rally_win = 0 let petition_win = 0 log(`Roll: D${roll}`) if ((game.played_power_card >= 25 && game.played_power_card <= 30) || game.played_power_card === 53) { rally_win = 2} if ((game.played_power_card >= 31 && game.played_power_card <= 36) || game.played_power_card === 54) { petition_win = 2} let modified_roll = roll + game.raised_stakes + rally_win - petition_win // Roll modifiers if (game.active === COM && game.persistent_events.includes(62)) { log('+1 from C62') modified_roll ++ } if (modified_roll < 0) {modified_roll = 0} else if (modified_roll > 7) {modified_roll = 7} if (game.raised_stakes !== 0) { log(`+${game.raised_stakes} from Raising the Stakes`) } if (rally_win !== 0) { log('+2 from winning on a P25') } if (petition_win !== 0) { log('-2 from winning on a P31') } if (modified_roll !== roll) { log(`Modified roll: ${modified_roll}`) } game.available_ops = support_loss_roll[modified_roll] if (game.available_ops === 0) { log('Does not remove SPs') } game.phase++ valid_spaces_support_loss() }, infl (space) { game.remove_opponent_infl = false /* Don't know why this is needed... */ remove_infl(space) if (game.available_ops === 0 ) { game.valid_spaces = [] } }, done () { if (game.summary.length > 0) { pop_summary() log_br() } next_player() log_h3('Victory Point') game.phase = 0 game.state = 'vp_roll' } } states.vp_roll = { inactive: 'do VP Roll', prompt () { if (game.phase === 0) { view.prompt = 'Roll a die for Victory.' gen_action('roll') } else if (game.phase === 1) { view.prompt = 'Take power.' gen_action('take') } else if (game.phase === 2) { view.prompt = 'Proceed to scoring.' gen_action('scoring') } }, roll () { let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${roll}`) let rally_win = 0 let petition_win = 0 if ((game.played_power_card >= 25 && game.played_power_card <= 30) || game.played_power_card === 53) {rally_win = 2} if ((game.played_power_card >= 31 && game.played_power_card <= 36) || game.played_power_card === 54) {petition_win = 2} let modified_roll = roll + game.raised_stakes + rally_win - petition_win if (game.active === DEM && game.persistent_events.includes(62)) { log('+1 from C62') modified_roll ++ } if (modified_roll < 0) {modified_roll = 0} else if (modified_roll > 7) {modified_roll = 7} if (game.raised_stakes !== 0) { log(`+${game.raised_stakes} from Raising the Stakes`) } if (rally_win !== 0) { log('+2 from winning on a P25') } if (petition_win !== 0) { log('-2 from winning on a P31') } if (modified_roll !== roll) { log(`Modified roll: ${modified_roll}`) } let vp_change = vp_roll[modified_roll] if (game.active === DEM) { log(`+${vp_change} VP`) } else { log(`-${vp_change} VP`) } if (roll >= 4) console.log('VP before', game.vp) if (game.active === DEM) {game.vp += vp_change} else {game.vp -= vp_change} console.log('VP after', game.vp) if (game.active === DEM && modified_roll >= 4) { game.phase = 1 } else { game.phase = 0 if (game.active === DEM) {next_player()} game.state = 'choose_power' } }, take () { push_undo() //Find name of scoring card let scoring_card = scoring_cards[countries.indexOf(game.pwr_struggle_in)] permanently_remove(scoring_card) take_power(game.pwr_struggle_in) game.phase = 2 }, scoring () { push_undo() log_h2('Scoring') score_country(game.pwr_struggle_in) game.state = 'finish_scoring' }, } states.choose_power = { inactive: 'choose whether to remain in power.', prompt () { if (game.phase === 0) { view.prompt = 'Choose whether to remain in power.' gen_action('retain') gen_action('surrender') } else if (game.phase === 1) { view.prompt = 'Proceed to scoring.' gen_action('scoring') } }, retain() { push_undo() retain_power(game.pwr_struggle_in) game.phase = 1 }, surrender () { push_undo() take_power(game.pwr_struggle_in) permanently_remove(game.played_card) game.phase = 1 }, scoring () { push_undo() score_country(game.pwr_struggle_in) //Check if The Tyrant is Gone occurs if (game.table_cards.includes(97) && game.pwr_struggle_in === 'Romania' && game.persistent_events.includes(54)) { game.return_state = 'finish_scoring' game.state = 'the_tyrant_is_gone' } else { game.state = 'finish_scoring' } } } /* states.score_country = { inactive: `score country`, prompt () { view.prompt = 'Scoring: done.' gen_action('done') }, done () { reset_power() /*if (game.return !== game.active) { next_player()} game.state = 'finish_scoring' } } */ states.the_tyrant_is_gone ={ inactive: 'resolve The Tyrant is Gone.', prompt() { view.prompt = 'Play The Tyrant is Gone for the event.' gen_action('event') }, event() { if (game.active !== DEM) { next_player() } if (game.round_player === DEM) { game.return = COM } else { game.return = DEM } log_h3(`C97`) game.vm_event = 97 goto_vm(game.vm_event) } } states.finish_scoring ={ inactive: 'finish scoring.', prompt() { view.prompt = 'End power struggle.' gen_action('done') } , done() { console.log('game.return_state', game.return_state) log_msg_gap('Power Struggle resolved') /*At this point log card dicarded or permanently removed? */ if (game.persistent_events.includes(111)) { game.state = 'new_years_eve_party' return } if (check_vp()) { return } reset_power() 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.includes(104)) { log_h1(`New Year's Eve Party`) //Check if the Communist receives VP from The Tyrant is Gone if (game.persistent_events.includes(97)) { game.vp -= 2 log(`Communist receives 2 VP from C97`) } game.persistent_events.push(111) game.state = 'new_years_eve_party' } else if(game.turn === 10) { clear_undo() log_h2('Final Scoring') //Check if the Communist receives VP from The Tyrant is Gone if (game.persistent_events.includes(97)) { game.vp -= 2 log(`Communist receives 2 VP from C97`) } game.state = 'final_scoring_held' } else { game.return_state = '' game.state = 'end_turn' } } } states.end_turn = { inactive: 'end the turn.', prompt() { view.prompt = 'End Turn: done.' gen_action('done') }, done() { 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() { console.log('game.revolutions: ', game.revolutions) const held_countries = game.revolutions.filter(value => value === false).length let vp_gain = 4*held_countries log(`Communist holds ${held_countries} countries: -${vp_gain} VP`) game.vp -= 4*held_countries game.temp = {'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.temp['East_Germany'] && game.temp['Poland'] && game.temp['Czechoslovakia'] && game.temp['Hungary'] && game.temp['Romania'] && game.temp['Bulgaria']) { view.prompt = 'Country scoring: done.' gen_action('done') } else { view.prompt = 'Choose a country to score' if (!game.temp['East_Germany']) {gen_action('east_germany')} if (!game.temp['Poland']) {gen_action('poland')} if (!game.temp['Czechoslovakia']) {gen_action('czechoslovakia')} if (!game.temp['Hungary']) {gen_action('hungary')} if (!game.temp['Romania']) {gen_action('romania')} if (!game.temp['Bulgaria']) {gen_action('bulgaria')} } }, east_germany() { score_country('East_Germany') game.temp['East_Germany'] = true }, poland() { score_country('Poland') game.temp['Poland'] = true }, czechoslovakia() { score_country('Czechoslovakia') game.temp['Czechoslovakia'] = true }, hungary() { score_country('Hungary') game.temp['Hungary'] = true }, romania() { score_country('Romania') game.temp['Romania'] = true }, bulgaria() { score_country('Bulgaria') game.temp['Bulgaria'] = true }, done() { delete game.temp 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 = { 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 or play a Scoring Card.' available_cards = game.communist_hand for (let card of available_cards) { gen_action_card(card) } } else if (game.phase >= 1) { view.prompt = 'General Strike: done.' gen_action('done') } else if (game.played_card > 0 ) { view.prompt = 'General Strike: roll a die.' gen_action('roll') } }, card (card) { push_undo() game.played_card = card let find_card find_card = game.communist_hand.indexOf(card) game.communist_hand.splice(find_card, 1) game.available_ops = get_card_ops(card) if (scoring_cards.includes(card)) { game.vm_event = card log(`Played C${card} for the event`) game.return_state = 'general_strike' goto_vm(game.vm_event) } else { log(`Discarded C${cards[card].number}`) } }, roll() { clear_undo() let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${roll}`) logi(`+${game.available_ops} ops`) let total = roll + game.available_ops log(`Total: ${total}`) if (total > 5) { log('The strike is over.') permanently_remove(5) game.persistent_events = game.persistent_events.filter(n => n !== 5) } else { log('The strike continues. Required 6 or more') } 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 = game.persistent_events.filter(n => n !== 15) game.state = 'choose_card' }, pass() { log('C15: passed') game.persistent_events = game.persistent_events.filter(n => n !== 15) end_round() } } states.new_years_eve_party = { get inactive() { return `resolve ${clean_name(cards[104].name)}.` }, prompt() { if (!game.is_pwr_struggle) { view.prompt = `New Year's Eve Party: you may choose a country to have a final power struggle.` if (!game.revolutions[0]) {gen_action('poland')} if (!game.revolutions[1]) {gen_action('hungary')} if (!game.revolutions[2]) {gen_action('east_germany')} if (!game.revolutions[3]) {gen_action('bulgaria')} if (!game.revolutions[4]) {gen_action('czechoslovakia')} if (!game.revolutions[5]) {gen_action('romania')} gen_action('pass') } else { view.prompt = `New Year's Eve Party: done.` gen_action('end') } }, east_germany() { push_undo() log('Chose to score East Germany') game.vm_event = 42 goto_vm(42) }, poland() { push_undo() log('Chose to score Poland') game.vm_event = 22 goto_vm(22) }, czechoslovakia() { push_undo() log('Chose to score Czechoslovakia') game.vm_event = 55 goto_vm(55) }, hungary() { push_undo() log('Chose to score Hungary') game.vm_event = 23 goto_vm(23) }, romania() { push_undo() log('Chose to score Romania') game.vm_event = 95 goto_vm(95) }, bulgaria () { push_undo() log('Chose to score Bulgaria') game.vm_event = 43 goto_vm(43) }, pass() { push_undo() log('No final power struggle') if (game.vp > 0) { goto_game_over(DEM, `C104: ${DEM} wins on Victory Point Track!`) } else if (game.vp < 0) { goto_game_over(COM, `C104: ${COM} wins on Victory Point Track!`) } else if (game.vp === 0) { goto_game_over('', `C104: The game is tied!`) /*Not sure what to pass for result */ } }, end() { if (game.vp > 0) { goto_game_over(DEM, `C104: ${DEM} wins on Victory Point Track!`) } else if (game.vp < 0) { goto_game_over(COM, `C104: ${COM} wins on Victory Point Track!`) } else if (game.vp === 0) { goto_game_over('', `C104: The game is tied!`) /*Not sure what to pass for result */ } } } states.stasi_end_round = { inactive: 'choose next card due to Stasi.', prompt() { console.log('game.stasi_card', game.stasi_card) if (!game.stasi_card || game.stasi_card === 0 ) { let available_cards = game.democrat_hand if (available_cards.length === 0) { view.prompt = 'Stasi: no cards remaining.' gen_action('pass') return } view.prompt = 'Stasi: you must select your next card to play.' 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 }, pass() { log('Stasi: Democrat has no remaining cards') game.stasi_card = 0 end_stasi_choose_card() }, done() { push_undo() if (game.stasi_card === 21) { game.state = 'stasi_confirm' } else { end_stasi_choose_card() } } } states.stasi_confirm = { inactive: 'choose next card due to Stasi.', prompt() { if (game.stasi_card === 21 ) { view.prompt = `If Common European Home selected, it must be played for Operations. Otherwise select the opponent's card instead.` gen_action('done') } }, done() { game.playable_cards = game.playable_cards.filter( n => n !== 21) end_stasi_choose_card() } } states.stasi_play_card = { inactive: 'play a card.', prompt () { /*Should get rid of the play card 'done' prompt for consistency with general play */ /*if (game.played_card > 0) { game.state = 'play_card' view.prompt = 'Play card: done.' gen_action("done"); return;*/ //} else if (game.stasi_card === 0) { view.prompt = 'Stasi: you must pass.' gen_action('pass') } else { view.prompt = `Stasi: you must play ${clean_name(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${card}`) game.played_card = card let find_card find_card = game.democrat_hand.indexOf(card); game.democrat_hand.splice(find_card, 1); game.available_ops = get_card_ops(card) game.stasi_card = 0 if (game.democrat_hand.includes(21) && cards[card].side === "C") { game.state = 'stasi_resolve_common_european_home' } else { game.state = 'play_card' } }, pass () { log('No cards remaining. Passed') end_round() }, done () { game.stasi_card = 0 if (game.democrat_hand.includes(21)) { game.state = 'stasi_resolve_common_european_home' } else { game.state = 'play_card' } } } states.stasi_resolve_common_european_home = { inactive: 'play a card.', prompt () { view.prompt = `Do you wish to play ${clean_name(cards[game.played_card].name)} with Common European Home?` gen_action('yes') gen_action('no') }, yes() { log(`Played with Common European Home`) silent_discard(21) game.vm_infl_to_do = true game.vm_event_to_do = false game.state = 'resolve_opponent_event' }, no() { game.state = 'play_card' } } // ==================== SUPPORTING STATE FUNCTIONS ============================= function add_infl(space) { push_undo() console.log('adding infl to', 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 %${space}`) log_summary(`Added £ SP in %${space}`) //If AHBR - check AHBR conditions if (game.persistent_events.includes(58)) { if (spaces[space].country !== 'East_Germany'){ game.austria_hungary_border_reopened_tracker = false } } // Check Genscher if (game.persistent_events.includes(63) && game.active === DEM && spaces[space].country === 'East_Germany') { game.available_ops-- log_summary(`(-1 op due to C63)`) } else if (check_opp_control(space)) { game.available_ops -= 2 //Check if Austria Hungary Border Reopened was used to place last SP in a controlled space in East Germany. If so, game.available_op will be negative if (game.available_ops < 0) { log_summary(`(Used +1 op from C58)`) } } else { game.available_ops-- } // Update influence values if (game.active === COM) { game.comInfl[space]++ } else { game.demInfl[space]++ } // Check whether spaces are controlled check_control_change(space) // Check Austria Hungary Border Reopened is true and condition has been met if (game.available_ops === 0 && game.active === DEM && game.persistent_events.includes(58) && game.austria_hungary_border_reopened_tracker) { game.available_ops ++ log('+1 op from C58') game.austria_hungary_border_reopened_tracker = false 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 & Austria Hungary Border Reopened if (game.available_ops === 1) { //console.log(`in Genscher / AHBR check, game.persistent_events['genscher']`, game.persistent_events['genscher']) if (game.active === DEM) { if (game.persistent_events.includes(63) || (game.persistent_events.includes(58) && game.austria_hungary_border_reopened_tracker)) { console.log('in gensher subcheck - remove non-East German controlled ') game.valid_spaces = game.valid_spaces.filter(n => !(check_opp_control(n) && spaces[n].country !== 'East_Germany')) } else { console.log('remove all controlled spaces') game.valid_spaces = game.valid_spaces.filter(n => !check_opp_control(n)) } } else { console.log('remove all dem controlled spaces') game.valid_spaces = game.valid_spaces.filter(n => !check_opp_control(n)) } } //Clear valid spaces if no IP remaining. if (game.available_ops <= 0 ) { game.valid_spaces = [] } } function remove_infl(space) { push_undo() //log(`Removed 1 influence from %${space}.`) log_summary(`Removed £ SP from %${space}.`) if (game.remove_opponent_infl === true) { if (game.active === COM) { game.demInfl[space]-- if (game.demInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } else { game.comInfl[space]-- if (game.comInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } check_control_change(space) } else { if (game.active === COM) { game.comInfl[space]-- if (game.comInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } else { game.demInfl[space]-- if (game.demInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } check_control_change(space) } game.available_ops-- } function do_sc(space) { clear_undo() log_gap(`Support check: %${space}`) //Check Helsinki Final Act if (game.active === COM && game.persistent_events.includes(26) && (spaces[space].socio === 5 || spaces[space].socio === 6) ) { log('+1 VP from C26') game.vp ++ if (check_vp()) { game.state = 'game.over' console.log('after check_vp, game.state', game.state) return } } console.log('continue support check, game.state', game.state) // Continue with Support Check Logic let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${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 //else if (game.is_pwr_struggle) { roll += game.vm_available_ops logi(`+${game.vm_available_ops} from Ceausescu`) } // Check if in Tiananmen Square Track Award else if (game.state === 'vm_tst_6_sc') { roll += get_tst_6_ops() roll += 2 logi('+2 TST award') } else { //let modifier = 0 let card_ops = get_card_ops(this_card()) roll += card_ops logi(`+${card_ops} ops`) } if (game.support_check_modifier > 0) { roll += game.support_check_modifier logi(`+${game.support_check_modifier} event`) } // Events which modify SC rolls //Tear Gas if (game.active === COM && game.persistent_events.includes(30) && spaces[space].socio === 6) { roll ++ logi('+1 C30') permanently_remove(30) game.persistent_events = game.persistent_events.filter(n => n !== 30) } //FRG Embassies if (game.active === DEM && spaces[space].region === 'Eastern Europe' && game.persistent_events.includes(74)) { roll++ logi('+1 C74') } //GrenzTruppen if (game.active === DEM && spaces[space].country === 'East_Germany' && game.persistent_events.includes(59)) { roll-- logi('-1 C59') } //Stand Fast if ((game.active === COM && game.stand_fast === DEM && check_dem_control(space)) || (game.active === DEM && game.stand_fast === COM && check_com_control(space))){ roll-- logi('-1 C100') } //Elena if (game.active === DEM && game.persistent_events.includes(101) && spaces[space].country === 'Romania') { roll-- logi('-1 C101') } //Austria Hungary Border Reopened if (game.active === DEM && game.persistent_events.includes(58) && game.austria_hungary_border_reopened_tracker) { roll++ logi(`+1 C58`) } // Continue with logic - check for adjacency // Events which affect adjacency - The Wall const adj = count_adj(space) console.log('adj', adj) if (game.active === COM && game.persistent_events.includes(9) && spaces[space].country === 'East_Germany') { logi('No adjacency for Democrats due to C9') logi('C9 no longer in effect') roll += adj.com_adj if (adj.com_adj > 0) { logi(`+${adj.com_adj} adjacency`) } game.persistent_events = game.persistent_events.filter(n => n !== 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) { logi(`+${adj.dem_adj} adjacency`) } if (adj.com_adj > 0) { logi(`-${adj.com_adj} opponent adjacency`) } } else { roll += adj.com_adj roll -= adj.dem_adj if (adj.com_adj > 0) { logi(`+${adj.com_adj} adjacency`) } if (adj.dem_adj > 0) { logi(`-${adj.dem_adj} opponent adjacency`) } } } } // Support check calcs log(`Total: ${roll}`) const stability = spaces[space].stability logi(`-${stability*2} (stability * 2)`) const change_infl = Math.max(0, roll - stability*2) if (change_infl > 0) { log_msg_gap(`Change: ${change_infl} SP`) if(game.active === DEM) { if (change_infl > game.comInfl[space]) { const residual = change_infl - game.comInfl[space] game.comInfl[space] = 0 game.demInfl[space] += residual } else { game.comInfl[space] -= change_infl } if (game.comInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space) } } else { if (change_infl > game.demInfl[space]) { const residual = change_infl - game.demInfl[space] game.demInfl[space] = 0 game.comInfl[space] += residual } else { game.demInfl[space] -= change_infl } if (game.demInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space) } } check_control_change(space) } else { log_msg_gap('Change: 0 SP') } if (game.active === COM && game.persistent_events.includes(39) && spaces[space].space_id === 66) { log_msg_gap('+1 VP from C39') game.vp++ if (check_vp()) { return } } // If Austria-Hungary Border Reopened used, all future support checks must be in East Germany if (game.persistent_events.includes(58)){ if (game.austria_hungary_border_reopened_tracker) { game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country === 'East_Germany') } } game.selected_space = 0 } function valid_spaces_setup() { game.valid_spaces = [] let valid_spaces_set = new Set(); //console.log('in vs setup, state', game.state) for (let i =1 ; i <= 75 ; i++) { space = spaces[i] if (game.state === 'com_init') { infl = game.demInfl[i] if (infl === 0) { valid_spaces_set.add(space.space_id); } } else if (game.state === 'dem_init') { infl = game.comInfl[i] if (infl === 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(); console.log('valid spaces sc, persistent events', game.persistent_events) for (let i = 1 ; i <= 75; i++) { space = spaces[i] if (game.active === DEM) { infl = game.comInfl[i] if (infl !== 0 ) { valid_spaces_set.add(space.space_id); } } else { infl = game.demInfl[i] if (infl !== 0 ) { // Check Solidarity Legalised if (game.persistent_events.includes(2) && space.space_id === 14) {continue} // Check Civic Forum if (game.persistent_events.includes(90) && space.space_id === 30) {continue} // Check We Are the People if (game.persistent_events.includes(48) && space.space_id === 9) {continue} //Check for Foreign Currency Debt Burden if (game.persistent_events.includes(49) && space.country === game.foreign_currency_debt_burden) {continue} { valid_spaces_set.add(space.space_id); } } } } // 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.includes(54)) { 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(); for (let i = 1; i < game.demInfl.length; i++) { //console.log('spaces.length', game.demInfl.length, 'i', i) space = spaces[i] if (game.active === DEM) { infl = game.demInfl[i] if (infl > 0 && space.country === game.pwr_struggle_in) { valid_spaces_set.add(space.space_id); } } else { infl = game.comInfl[i] if (infl > 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) { 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; } */ function valid_spaces_infl() { /*if (game.state.startsWith('vm')) { console.log('valid_spaces_infl called from VM') } else { console.log('valid_spaces_infl called not from VM') }*/ // Check if function is called from the VM or not, take relevant ops variable let ops = game.state.startsWith('vm') ? game.vm_available_ops : game.available_ops; let valid_spaces_set = new Set(); // Iterate over all spaces to find the ones with the player's influence for (let i = 1; i < game.demInfl.length; i++) { //piece = game.pieces[i] space = spaces[i] let player_influence = game.active === COM ? game.comInfl[i] : game.demInfl[i]; // 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(space.space_id); // Check adjacency information let adjacent_spaces = get_adjusted_adjacency(space.space_id) for (let adj_space_id of adjacent_spaces) { //console.log('adj_space_id', adj_space_id) if (adj_space_id) { const adj_piece = spaces[adj_space_id]; //console.log('adjacent piece name', adj_piece.name_unique) // Check if the adjacent space is controlled by the opponent const opponent_control = check_opp_control(adj_piece.space_id) //console.log('controlled?', opponent_control) //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.includes(63)){ // console.log('space added with 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 (ops >= 2 || !opponent_control) { valid_spaces_set.add(adj_piece.space_id) } } } } } // 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.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} //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.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) { valid_cards_set.add(card.number); } else if (leaders.includes(card.socio) && presence[card.socio]) { valid_cards_set.add(card.number); } else if (card.number === 52) {valid_cards_set.add(card.number)} } } game.valid_cards = Array.from(valid_cards_set); return game.valid_cards; } function do_valid_cards() { let presence = check_presence(game.pwr_struggle_in) if (game.active === DEM) { valid_cards(game.dem_pwr_hand, presence.dem_leaders) } else { valid_cards(game.com_pwr_hand, presence.com_leaders)} } function count_adj(id) { const space = spaces[id] let dem_adj = 0 let com_adj = 0 let adjacent_spaces = get_adjusted_adjacency(space.space_id) for (let adj_space_id of adjacent_spaces) { if (adj_space_id) { const adj_piece = spaces.find(piece => piece && piece.space_id === adj_space_id); console.log('adj_piece.space_id', adj_piece.space_id, 'space', space) if (adj_piece && adj_piece.space_id !== space.space_id) { if (check_dem_control(adj_piece.space_id)) { console.log('added DEM space', spaces[adj_piece.space_id].name) dem_adj++ } if (check_com_control(adj_piece.space_id)) { console.log('added COM space', spaces[adj_piece.space_id].name) 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_id) { //console.log('in check control, space', spaces[space_id].name_unique) if ( (game.comInfl[space_id] - game.demInfl[space_id]) >= spaces[space_id].stability) { return true; } else if ((game.demInfl[space_id] - game.comInfl[space_id]) >= spaces[space_id].stability) { //console.log('true') return true; } else { //console.log('false') return false; } } function check_opp_control(space_id) { if (spaces[space_id].country === 'Romania') { //console.log('in check opp control, space', spaces[space_id].name_unique) } if (game.active === DEM && ((game.comInfl[space_id] - game.demInfl[space_id]) >= spaces[space_id].stability)) { if (spaces[space_id].country === 'Romania') { //console.log('control true') } return true; } else if (game.active === COM && ((game.demInfl[space_id] - game.comInfl[space_id]) >= spaces[space_id].stability)) { //console.log('true') return true; } else { //console.log('false') return false; } } function check_dem_control(space_id) { if ((game.demInfl[space_id] - game.comInfl[space_id]) >= spaces[space_id].stability) { return true; } else { return false; } } function check_com_control(space_id) { if ((game.comInfl[space_id] - game.demInfl[space_id]) >= spaces[space_id].stability) { return true; } else { return false; } } function do_tst_attempt() { let roll = Math.floor(Math.random() * 6) + 1; log(`Roll: D${roll}`); roll += game.available_ops logi(`+${game.available_ops} from card ops`) // TIANANMEN SQUARE MODIFIERS if (game.active === DEM && game.dem_tst_attempted === 1 || game.active === COM && game.com_tst_attempted === 1) { roll ++; logi('+1 from previous TST attempts') } if (game.active === DEM && game.dem_tst_position >= 1 && game.com_tst_position === 0) { roll ++ logi('+1 from TST award') } if (game.active === COM && game.com_tst_position >= 1 && game.dem_tst_position === 0) { roll ++ logi('+1 from TST award') } if ((game.active === DEM && cards[game.played_card].side === 'D') || (game.active === COM && cards[game.played_card].side === 'C')) { roll ++; logi('+1 for playing own card'); } if (game.active === COM && game.persistent_events.includes(53)) { roll ++ logi('+1 from C53') } log(`Total: ${roll}`) // TIANANMEN SQUARE ATTEMPT game.return = game.active game.return_state = 'tiananmen_square_attempt_done' 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.dem_tst_position++ game.dem_tst_attempted = 0 //Check if they have reached box 7 or 8 first if (game.dem_tst_position === 7 && game.com_tst_position < 7) { game.tst_7 = false } if (game.dem_tst_position === 8 && game.com_tst_position < 8) { game.tst_8 = false } //Check if they have caught up to box 7 or 8 if (game.dem_tst_position >= 7 && game.com_tst_position >= 7) { delete game.tst_7 } if (game.dem_tst_position >= 8 && game.com_tst_position >= 8) { delete game.tst_8 } //Check if TST events occur if (game.dem_tst_position === 3 && game.com_tst_position < 3) {game.vm_event = 203} else if (game.dem_tst_position === 4 && game.com_tst_position < 4) {game.vm_event = 204} game.state = 'tiananmen_square_attempt_success' } else { log(`${dem_tst_req[game.dem_tst_position]} required: fail`) game.dem_tst_attempted = 1 game.state = 'tiananmen_square_attempt_fail' } } else { 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.com_tst_position++ game.com_tst_attempted = 0 //Check if they have reached box 7 or 8 first if (game.com_tst_position === 7 && game.dem_tst_position < 7) { game.tst_7 = false } if (game.com_tst_position === 8 && game.dem_tst_position < 8) { game.tst_8 = false } //Check if they have caught up to box 7 or 8 if (game.com_tst_position >= 7 && game.dem_tst_position >= 7) { delete game.tst_7 } if (game.com_tst_position >= 8 && game.dem_tst_position >= 8) { delete game.tst_8 } //Check if TST events occur if (game.com_tst_position === 3 && game.dem_tst_position < 3) {game.vm_event = 203} else if (game.com_tst_position === 4 && game.dem_tst_position < 4) {game.vm_event = 204} game.state = 'tiananmen_square_attempt_success' } else { log(`${com_tst_req[game.com_tst_position]} required: fail`) game.com_tst_attempted = 1 game.state = 'tiananmen_square_attempt_fail' } } } function check_presence(country) { let dem_spaces = 0; let com_spaces = 0; let dem_battlegrounds = 0; let com_battlegrounds = 0; let dem_leaders = {1: false, 4: false, 5: false, 6: false, 7: false}; let com_leaders = {1: false, 4: false, 5: false, 6: false, 7: false}; for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (space.country === country) { if (check_dem_control(i)) { dem_spaces++; if (space.battleground === 1) { dem_battlegrounds++; } if (leaders.includes(space.socio)) { dem_leaders[space.socio] = true; } } if (check_com_control(i)) { com_spaces++; if (space.battleground === 1) { com_battlegrounds++; } if (leaders.includes(space.socio)) { com_leaders[space.socio] = true; } } } } // Determine domination let dem_domination = dem_battlegrounds > com_battlegrounds && dem_spaces > com_spaces && dem_spaces - dem_battlegrounds > 0; let com_domination = com_battlegrounds > dem_battlegrounds && com_spaces > dem_spaces && com_spaces - com_battlegrounds > 0; // Determine control let total_battlegrounds = battlegrounds(country); let dem_control = dem_battlegrounds === total_battlegrounds && dem_spaces > com_spaces; let com_control = com_battlegrounds === total_battlegrounds && com_spaces > dem_spaces; return { dem_spaces: dem_spaces, com_spaces: com_spaces, dem_battlegrounds: dem_battlegrounds, com_battlegrounds: com_battlegrounds, dem_domination: dem_domination, com_domination: com_domination, dem_control: dem_control, com_control: com_control, dem_leaders: dem_leaders, com_leaders: com_leaders }; } function battlegrounds(country) { let battlegrounds = 0; if (country === "Hungary") { battlegrounds = 4 } else if (country === "Bulgaria") { battlegrounds = 5 } else { battlegrounds = 6 } return battlegrounds; } function take_power(country) { log(`Democrat takes power in ${game.pwr_struggle_in}`) game.revolutions[find_country_index(country)] = true game.times_held[find_country_index(country)] = 1 } function retain_power(country){ game.times_held[find_country_index(country)]++ let vp_gain = get_value(country)*game.times_held[find_country_index(country)] log(`Chooses to retain power`) log(`-${vp_gain} VP`) game.vp -= vp_gain } function score_country(country) { log_h3(`Scoring: ${country}`) //Get scoring values let value_presence = get_value(country) let value_domination = value_presence*2 let value_control if (country !== "Hungary") { value_control = value_presence*3 } else { value_control = 4 } //Log for scoring let dem_vp = 0 let com_vp = 0 //Check for presence let presence = check_presence(country) console.log('presence: ', presence) //If one side has domination or control if (presence.dem_control || presence.dem_domination) { log(`Democrat:`) if (presence.dem_control) { log(`Control: +${value_control} VP`) dem_vp += value_control } else { log(`Domination: +${value_domination} VP`) dem_vp += value_domination } log(`Battlegrounds: +${presence.dem_battlegrounds} VP`) dem_vp += presence.dem_battlegrounds log(`Total: +${dem_vp} VP`) log_gap('Communist:') if (presence.com_spaces > 0) { log(`Presence: -${value_presence} VP`) com_vp -= value_presence if (presence.com_battlegrounds >0) { log(`Battlegrounds: -${presence.com_battlegrounds} VP`) com_vp -= presence.com_battlegrounds } log(`Total: ${com_vp} VP`) } else { log('No presence: 0 VP') } } else if (presence.com_control || presence.com_domination) { log('Communist:') if (presence.com_control) { log(`Control: -${value_control} VP`) com_vp -= value_control } else { log(`Domination: -${value_domination} VP`) com_vp -= value_domination } log(`Battlegrounds: -${presence.com_battlegrounds} VP`) com_vp -= presence.com_battlegrounds log(`Total: ${com_vp} VP`) log_gap('Democrat:') if (presence.dem_spaces > 0) { log(`Presence: +${value_presence} VP`) dem_vp += value_presence if (presence.dem_battlegrounds > 0) { log(`Battlegrounds: +${presence.dem_battlegrounds} VP`) dem_vp += presence.dem_battlegrounds } log (`Total: +${dem_vp} VP`) } else { log('No presence: 0 VP') } } //Otherwise, presence and battlegrounds else { log("No domination or control") log_gap(`Communist:`) if (presence.com_spaces > 0) { log(`Presence: -${value_presence} VP`) com_vp -= value_presence if (presence.com_battlegrounds > 0) { log(`Battlegrounds: -${presence.com_battlegrounds} VP`) com_vp -= presence.com_battlegrounds } else { log('No battlegrounds') } log(`Total: ${com_vp} VP`) } else { log('No presence: 0 VP') } log_gap('Democrat:') if (presence.dem_spaces > 0) { log(`Presence: +${value_presence} VP`) dem_vp += value_presence if (presence.dem_battlegrounds > 0) { log(`Battlegrounds: +${presence.dem_battlegrounds} VP`) dem_vp += presence.dem_battlegrounds } else { log('No battlegrounds') } log(`Total: +${dem_vp} VP`) } else { log('No presence: 0 VP') } } //Calculate change VP /*let dem_vp = 0 if (presence.dem_spaces > 0) {dem_vp += value_presence} if (presence.dem_domination) {dem_vp += value_presence} if (presence.dem_control && country !== "Hungary") { dem_vp += value_control } else if (presence.dem_control && country === "Hungary") {dem_vp += 2} dem_vp += presence.dem_battlegrounds let com_vp = 0 if (presence.com_spaces > 0) {com_vp += value_presence} if (presence.com_domination) {com_vp += value_presence} if (presence.com_control && country !== "Hungary") {com_vp += value_presence} else if (presence.com_control && country === "Hungary") {com_vp += 2} com_vp += presence.com_battlegrounds */ let change_vp = dem_vp + com_vp game.vp += change_vp if (change_vp > 0 ) { log_gap(`Final change VP: +${change_vp} VP`) } else { log_gap(`Final change VP: ${change_vp} VP`) } } function get_value(country) { let value 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('permanently removing card:', card) if (game.strategy_removed.includes(card)) {return} log_msg_gap(`C${cards[card].number} permanently removed`) remove_from_discard(card) 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!`) console.log('after goto_game_over, game.state', game.state) return true } else if(game.vp <= -20) { goto_game_over(COM, `${COM} won an Automatic Victory!`) return true } return false } 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) console.log('game over, game.state', game.state) return } function reset_austria_hungary_border_reopened() { //game.austria_hungary_border_reopened_checked = false game.austria_hungary_border_reopened_tracker = false } function end_stasi_choose_card() { game.round_player = COM game.round ++ log_h2(`Action Round ${game.round}`) next_player() game.valid_spaces = [] if (game.persistent_events.includes(5)) { log_h3('C5') game.state = 'general_strike' } else { game.state = 'choose_card' } } function check_reformer() { if (game.dem_tst_position !== game.com_tst_position) { if (!game.playable_cards.includes(67)) { game.playable_cards.push(67) } } else { game.playable_cards = game.playable_cards.filter(n => n !== 67) } } function count_scoring_cards() { let scoring_check if (game.active === DEM) { scoring_check = game.democrat_hand.filter(card => scoring_cards.includes(card)).length } else { scoring_check = game.communist_hand.filter(card => scoring_cards.includes(card)).length } return scoring_check } function select_card(card){ game.played_card = card game.temp = 0 let find_card if (game.active === COM) { 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) } game.available_ops = get_card_ops(card) //Check Ligachev if (game.active === DEM && game.persistent_events.includes(99) && card !== 14) { log('-3 VP from C99') game.vp -= 3 if (check_vp()) { return } game.persistent_events = game.persistent_events.filter(n => n !== 99) } game.state = 'play_card' console.log('game.state', game.state) } function find_event(card) { return variable_events.indexOf(card) } function get_events(card){ if (event_is_playable(card)) { if (cards[card].side === 'D') { if (game.active === DEM) {gen_action('event')} if (game.active === COM) {gen_action('opp_event')} } else if (cards[card].side === 'C') { if (game.active === COM) {gen_action('event')} if (game.active === DEM) {gen_action('opp_event')} } else { gen_action('event') } } } function event_is_playable(card) { //Reformer never playable here if (card === 67) { return false } //Check for Common European Hmme under Stasi else if (game.persistent_events.includes(13) && card === 21 && game.active === DEM) { return false } //Check for The Chinese Solution else if (game.com_tst_position === 8 && card === 96) { return true } //Then check normally else if (cards[card].playable) { return true } else if (game.playable_cards.includes(card)) { return true } else { return false } } function get_card_ops(card) { let ops = 0 if (card) { ops = cards[card].ops } if (game.persistent_events.includes(25) && game.active === COM) { if(game.state === 'choose_card' || game.state === 'stasi_play_card') { log('+1 op from C25') } ops ++ } if (game.persistent_events.includes(50) && game.active === DEM) { if(game.state === 'choose_card' || game.state === 'stasi_play_card' || game.state === 'vm_laszlo_tokes') { log('+1 op from C50') } 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)) { if(game.state === 'choose_card' || game.state === 'stasi_play_card') { log('+1 op from Tiananmen Square Track') } ops ++ } if ((game.active === DEM && game.prudence && game.prudence.DEM !== 0)) { if(game.state === 'choose_card' || game.state === 'stasi_play_card' || game.state === 'vm_laszlo_tokes') { if (ops > 2) { log(`${pluralize(game.prudence.DEM,'op')} from C8`) } else { if (ops > 1) { log(`-1 op from C8`) } } } ops += game.prudence.DEM if (ops < 1) { ops = 1 } } if (game.active === COM && game.prudence && game.prudence.COM < 0) { if(game.state === 'choose_card') { if (ops > 2) { log(`${pluralize(game.prudence.COM,'op')} from C8`) } else if (ops > 1) { log(`-1 op from C8`) } } ops += game.prudence.COM if (ops < 1) { ops = 1 } } return ops } function get_tst_6_ops() { let ops = 0 if (game.persistent_events.includes(25) && game.active === COM) { log('+1 op from C25') ops ++ } if (game.persistent_events.includes(50) && game.active === DEM) { log('+1 op from C50') ops ++ } if ((game.active === DEM && game.prudence && game.prudence.DEM !== 0)) { if (ops > 0) { log(`${pluralize(game.prudence.DEM,'op')} from C8`) } else { log(`-1 op from C8`) } ops += game.prudence.DEM if (ops < -1) { ops = -1 } } if (game.active === COM && game.prudence && game.prudence.COM < 0) { if (ops > 0) { log(`${pluralize(game.prudence.COM,'op')} from C8`) } else { log(`-1 op from C8`) } ops += game.prudence.COM if (ops < -1) { ops = -1 } } return ops } // =========== 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, and if a card has been not been played. If not, discard. if (!game.strategy_removed.includes(game.played_card) && !game.table_cards.includes(game.played_card) && game.played_card > 0) { 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 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.return = '' game.valid_cards = [] game.valid_spaces = [] check_common_european_home() //game.playable_cards[find_event(21)] = true reset_austria_hungary_border_reopened() /*This should be redundant! */ // Check for duplicate card entries let card_check if (game.samizdat_card > 0) { card_check = [...game.strategy_deck, ...game.strategy_discard, ...game.strategy_removed, ...game.table_cards, ...game.communist_hand, ... game.democrat_hand, game.samizdat_card]; } else { 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}`) } console.log('game.dem_tst_position ', game.dem_tst_position , 'game.com_tst_position ', game.com_tst_position ) //Check if the Reformer is playable check_reformer() // Check if last round and if so resolve end turn events if (game.round_player === DEM && game.round === 7) { if(game.persistent_events.includes(15)) { if (game.active !== COM) { next_player() } game.state = 'honecker' 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 //Stasi check if(game.round_player === COM && game.persistent_events.includes(13)) { //If in Honecker, turn ends if (game.round === 8) { clear_undo() game.state = 'end_turn_4_5_4' return } //Otherwise go to Stasi game.round_player = DEM if (game.active !== DEM) { next_player() } else { log_h3('Democratic Action Round') log_h3('C13') } if (game.democrat_hand.includes(game.stasi_card)) { game.state = 'stasi_play_card' } else { game.stasi_card = 0 game.state = 'choose_card' } return } //Check if in extra Action Round else if (game.round_player === COM && game.round === 8) { clear_undo() game.state = 'end_turn_4_5_4' return } //Normal round end else if (game.round_player===COM) { game.round_player = DEM if (game.active !== DEM) { next_player() } else { log_h3('Democratic Action Round') } game.state = 'choose_card' return } if (game.round_player === DEM) { console.log('checking stasi', game.persistent_events.includes(13)) if(game.persistent_events.includes(13)) { 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.includes(5)){ game.state = 'general_strike' game.round ++ log_h2(`Action Round ${game.round}`) game.round_player = COM if (game.active !== COM) { next_player() } log_h3('C5') return } else { game.state = 'choose_card' game.round_player = COM game.round ++ log_h2(`Action Round ${game.round}`) if (game.active !== COM) { next_player() } } } //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 ++ game.round = 1 game.valid_spaces=[] game.active = COM game.round_player = COM game.dem_tst_attempted_this_turn = 0 game.com_tst_attempted_this_turn = 0 if (game.tst_7) {game.tst_7 = false} if (game.tst_8) {game.tst_8 = false} //Remove events that only last one turn game.persistent_events = game.persistent_events.filter(n => n !== 25) /*Perestroika*/ game.persistent_events = game.persistent_events.filter(n => n !== 50) /*Sinatra Doctrine*/ game.persistent_events = game.persistent_events.filter(n => n !== 13) /*Stasi*/ game.persistent_events = game.persistent_events.filter(n => n !== 15) /*Honecker*/ delete game.prudence delete game.stasi_card //Austria Hungary Border Reopened if (game.persistent_events.includes(58)) { game.persistent_events = game.persistent_events.filter(n => n !== 58) delete game.austria_hungary_border_reopened_tracker log(`C58 no longer in effect`) //permanently_remove(58) } //Elena if (game.persistent_events.includes(101)) { game.persistent_events = game.persistent_events.filter(n => n !== 101) log(`C101 no longer in effect`) //permanently_remove(101) } //GrenzTruppen if (game.persistent_events.includes(59)) { game.persistent_events = game.persistent_events.filter(n => n !== 59) log(`C59 no longer in effect`) //permanently_remove(59) } //Foreign Currency Debt Burden if (game.persistent_events.includes(49)) { game.persistent_events = game.persistent_events.filter(n => n !== 49) delete game.foreign_currency_debt_burden log(`C49 no longer in effect`) //permanently_remove(49) } //FRG Embassies if (game.persistent_events.includes(74)) { game.persistent_events = game.persistent_events.filter(n => n !== 74) log(`C74 no longer in effect`) discard_from_table(74) permanently_remove(74) } //Genscher if (game.persistent_events.includes(63)) { game.persistent_events = game.persistent_events.filter(n => n !== 63) log(`C63 no longer in effect`) discard_from_table(63) permanently_remove(63) } //Stand Fast if (game.persistent_events.includes(100)) { game.persistent_events = game.persistent_events.filter(n => n !== 100) delete game.stand_fast log(`C100 no longer in effect`) //permanently_remove(100) } if (game.samizdat_card > 0 ) { game.democrat_hand.push(game.samizdat_card) delete game.samizdat_card } log_h1("Turn " + game.turn) if (game.turn === 4) { add_midyear() } if (game.turn === 8) { add_lateyear() } if (game.turn > 1) { if (game.persistent_events.includes(65)) { game.com_hand_limit = 7 log('Communist draws 7 cards due to C65') //permanently_remove(65) game.persistent_events = game.persistent_events.filter(n => n !== 65) } //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) } //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) if (game.persistent_events.includes(5)) { log_h3('C5') game.state = 'general_strike' } else { game.state = 'choose_card' } } } function next_player() { clear_undo() //console.log('next player called') if (game.active === DEM) game.active = COM else game.active = DEM log_side() } function change_player() { clear_undo() //console.log('next player called') if (game.active === DEM) game.active = COM else game.active = DEM } function find_space_index(name_unique) { return spaces.findIndex(space => space && space.name_unique === name_unique) } function find_country_index(country) { return countries.indexOf(country) } function draw_deck(deck) { return deck.filter(card => card && card.period === 1).map(card => card.number) } 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) { //console.log('draw card called with:', deck) //console.log('game.strategy_deck before', game.strategy_deck) if (deck.length === 0) { log_h3('--- Reshuffle ---') deck.push(...game.strategy_discard) game.strategy_discard = [] } const randomIndex = Math.floor(Math.random() * deck.length) //console.log('card chosen:', randomIndex) //console.log('game.strategy_deck after', game.strategy_deck) 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) } else { 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) { if (game.active === COM) { find_card = game.com_pwr_hand.indexOf(card); game.com_pwr_hand.splice(find_card, 1); } else { find_card = game.dem_pwr_hand.indexOf(card); game.dem_pwr_hand.splice(find_card, 1); } game.power_struggle_discard.push(card) //log(`Discarded P${power_cards[card].number}`) } } function silent_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) } else { find_card = game.democrat_hand.indexOf(card) game.democrat_hand.splice(find_card, 1) } game.strategy_discard.push(card) } else if (game.is_pwr_struggle) { if (game.active === COM) { find_card = game.com_pwr_hand.indexOf(card); game.com_pwr_hand.splice(find_card, 1); } else { find_card = game.dem_pwr_hand.indexOf(card); game.dem_pwr_hand.splice(find_card, 1); } game.power_struggle_discard.push(card) } } function remove_from_discard(card) { let card_index = game.strategy_discard.indexOf(card) if (card_index !== -1) { game.strategy_discard.splice(card_index, 1) } } 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); log_h3('Mid-year cards added to draw deck') } function add_lateyear() { 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') } function reset_power() { game.power_struggle_deck = [] game.power_struggle_discard = [] game.dem_pwr_hand = [] game.com_pwr_hand = [] game.phase = 1 game.raised_stakes_round = 0 game.raised_stakes = 0 game.played_power_card = 0 game.tactics_fails = '' game.view_opp_hand = false if (game.persistent_events.includes(72)){ permanently_remove(72) game.table_cards = game.table_cards.filter(card => card !== 72) game.persistent_events = game.persistent_events.filter(n => n !== 72) } if (game.persistent_events.includes(62)) { permanently_remove(62) game.table_cards = game.table_cards.filter(card => card !== 62) game.persistent_events = game.persistent_events.filter(n => n !== 62) } if (game.persistent_events.includes(54) && game.pwr_struggle_in === 'Romania'){ permanently_remove(54) //game.table_cards = game.table_cards.filter(card => card !== 54) } if (game.pwr_struggle_in === 'Romania' && game.persistent_events.includes(70)){ //permanently_remove(70) //game.table_cards = game.table_cards.filter(card => card !== 70) game.persistent_events = game.persistent_events.filter(n => n !== 70) } } function check_control_change(space_id) { // Check if the Tyrant is Gone has been fulfilled if (game.the_tyrant_is_gone > 0 && check_dem_control(game.the_tyrant_is_gone)) { console.log('in tyrant') log('+2 VP from C97') game.vp += 2 if (check_vp()) { return } game.persistent_events = game.persistent_events.filter(n => n !== 97) delete game.the_tyrant_is_gone } } function check_systematization() { // Check for Systematization - may not use this space if (game.systematization > 0) { game.valid_spaces = game.valid_spaces.filter(n => n !== game.systematization) } } function check_common_european_home() { if (!game.playable_cards.includes(21)) { game.playable_cards.push(21) } } function this_card() { return game.vm_event > 0 ? game.vm_event : game.played_card } /* function get_ops(card) { let ops = cards[card].ops if (game.active === COM) { //Check TST op bonus if (ops === 1 && game.com_tst_position >=2 && game.dem_tst_position <=1) { ops++ } //Events that influence ops if (game.persistent_events.includes(25)) { ops++ } if (game.prudence.COM && game.prudence.COM <0) { ops += game.prudence.COM } } else { //Check TST op bonus if (ops === 1 && game.dem_tst_position >=2 && game.com_tst_position <=1) { ops++ } //Events that influence ops if (game.persistent_events.includes(50)) { ops++ } if (game.prudence.DEM && game.prudence.DEM <0) { ops += game.prudence.DEM } } //Ops can never be less than one if (ops <1) { ops = 1 } return ops } */ const pluralize = (count, noun, suffix = 's') => `${count} ${noun}${Math.abs(count) !== 1 ? suffix : ''}` function clean_name(str) { if (str && str.slice(-1) === '*') { return str.slice(0, -1) } else { return str; } } function country_name(country) { return country.replace(/_/g, ' ') } // ======== LOG FUNCTIONS ============= function log(msg) { game.log.push(msg) } function log_br() { if (game.log.length > 0 && game.log[game.log.length - 1] !== "") game.log.push("") } function logi(msg) { game.log.push(">" + msg) } function log_h1(msg) { log_br() log(".h1 " + msg) log_br() } function log_h2(msg) { log_br() log(".h2 " + msg) log_br() } function log_h3(msg) { log_br() 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) log(".h2d " + game.active) else log(".h2c " + game.active) log_br() } function log_sep() { log(".hr") } function log_action(msg) { log_br() log(msg) } // ============= SUMMARY FUNCTIONS ============= function push_summary() { if (game.summary) throw "TOO MANY SUMMARIES" game.summary = [] } function log_summary(msg) { if (msg.startsWith('Added') || msg.startsWith('Removed')) { for (let item of game.summary) { if (item[1] === msg) { item[0]++ return } } } game.summary.push([1, msg]) } function pop_summary() { console.log('summary', game.summary) if (game.summary.length > 0) { for (let [n, msg] of game.summary) { if (n > 1) { log(msg.replace("£ SP", `${n} SPs`)); } else { log(msg.replace("£ SP", `${n} SP`)); } } } game.summary = [] } function log_summary_place(p) { let from = piece_space(p) if (from !== AVAILABLE) log_summary("% " + piece_name(p) + " from S" + from) else log_summary("% " + piece_name(p)) } function log_summary_move_to_from(p, to) { log_summary("% " + piece_name(p) + " to S" + to + " from S" + piece_space(p)) } function log_summary_remove(p) { log_summary("Removed % " + piece_name(p)) } function log_summary_activated(p) { log_summary("Activated % " + piece_faction_name(p)) } // ============ UNDO FUNCTIONS ================== function clear_undo() { if (game.undo.length > 0) game.undo = [] } function push_undo() { let copy = {} for (let k in game) { let v = game[k] if (k === "undo") continue else if (k === "log") v = v.length else if (typeof v === "object" && v !== null) v = object_copy(v) copy[k] = v } game.undo.push(copy) } function pop_undo() { let save_log = game.log let save_undo = game.undo game = save_undo.pop() save_log.length = game.log game.log = save_log game.undo = save_undo } // Fast deep copy for objects without cycles function object_copy(original) { if (Array.isArray(original)) { let n = original.length let copy = new Array(n) for (let i = 0; i < n; ++i) { let v = original[i] if (typeof v === "object" && v !== null) copy[i] = object_copy(v) else copy[i] = v } return copy } else { let copy = {} for (let i in original) { let v = original[i] if (typeof v === "object" && v !== null) copy[i] = object_copy(v) else copy[i] = v } return copy } } /* =================== VM FUNCTIONS ========================== */ 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() { console.log('game.temp', game.temp) console.log('vm_operand(1)', vm_operand(1)) 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_goto_step(step) { console.log('vm_goto_step called, target:', step) console.log('game.vm.ip', game.vp.ip) for (let i = game.vm.ip; i < CODE[game.vm.fp].length; i++) { console.log('i', i) console.log('step', CODE[game.vm.fp][i][0]) if (CODE[game.vm.fp][i][0] === step) { game.vm.ip = i; vm_exec(); return; } } console.log("ERROR: Target operation not found in the current procedure."); } function vm_goto(op, nop, dir, step) { console.log('vm_inst(0)', vm_inst(0), op, nop) console.log('vm_inst(0)', vm_inst(1), op, nop) let balance = 1 while (balance > 0) { game.vm.ip += dir if (vm_inst(0) === op) --balance if (vm_inst(0) === nop) ++balance if (game.vm.ip < 0 || game.vm.ip > CODE[game.vm.fp].length) throw "ERROR" } game.vm.ip += step vm_exec() } function event_prompt(str) { //console.log('event_prompt called with', str) if (typeof str === "undefined") str = CODE[game.vm.fp][game.vm.prompt][1] if (typeof str === "function") str = str() //console.log('str:', str) if (!str) { str = "" } return str } function vm_prompt() { if (game.vm.prompt) game.vm._prompt = game.vm.prompt game.vm.prompt = game.vm.ip vm_next() } function pop_vm_prompt() { if (game.vm._prompt) { game.vm.prompt = game.vm._prompt delete game.vm._prompt } else { game.vm.prompt = 0 } } function vm_return() { console.log('in vm_return') //Remove temporary vm variables delete game.support_check_modifier delete game.vm_max_infl delete game.vm_influence_added delete game.communist_hand_red game.vm_event = 0 /*Reset to 0 now that event has been completed. Hopefully this doesn't cause issues! */ if (game.persistent_events.includes(58)) { reset_austria_hungary_border_reopened() } //Check if end event state is needed if (game.is_pwr_struggle || game.state === 'vm_tst_6') { vm_end_event() } else { if ((game.active === DEM && game.round_player !==DEM) || (game.active === COM && game.round_player !== COM)) { game.state = 'vm_end_event' } else { vm_end_event() } } } function vm_end_event() { //game.view_opp_hand = false console.log('in vm_return, game.return:', game.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_opp_hand_false() { game.view_opp_hand = false vm_next() } function vm_valid_spaces() { 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 Systematization - may not use this space check_systematization() vm_next() } function vm_valid_spaces_opponent () { let valid_spaces = [] for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (game.active === DEM) { let infl = game.comInfl[i] if (infl > 0) { valid_spaces.push(space.space_id) } } else { infl = game.demInfl[i] if (infl > 0) { valid_spaces.push(space.space_id) } } } game.valid_spaces = valid_spaces console.log('game.valid_spaces', game.valid_spaces) vm_next() } function vm_valid_spaces_socio () { let valid_spaces = [] for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (space.socio === vm_operand(1)) { valid_spaces.push(space.space_id) } } game.valid_spaces = valid_spaces // Check for Systematization - may not use this space if (game.systematization && game.systematization > 0) { game.valid_spaces = game.valid_spaces.filter(n => n !== game.systematization) } vm_next() } function vm_valid_spaces_opponent_socio () { let valid_spaces = [] for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (game.active === DEM) { let infl = game.comInfl[i] if (infl > 0 && space.socio === vm_operand(1)) { valid_spaces.push(space.space_id) } } else { let infl = game.demInfl[i] if (infl > 0 && space.socio === vm_operand(1)) { valid_spaces.push(space.space_id) } } } game.valid_spaces = valid_spaces // Check for Systematization - may not use this space if (game.systematization && game.systematization > 0) { game.valid_spaces = game.valid_spaces.filter(n => n !== game.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 Systematization - may not use this space if (game.systematization && game.systematization > 0) { game.valid_spaces = game.valid_spaces.filter(n => n !== game.systematization) } vm_next() } function vm_valid_spaces_sc () { valid_spaces_sc() 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.comInfl[space.space_id] >0) { game.valid_spaces.push(space.space_id); } } else { if (space.country === country && game.demInfl[space.space_id]>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.comInfl[space.space_id] >0) { valid_spaces.push(space.space_id); } } else { if (space.country === country && game.demInfl[space.space_id] >0) { //Check Solidarity Legalised if (game.persistent_events.includes(2) && space.space_id === 14) {continue} //Check Civic Forum if (game.persistent_events.includes(90) && space.space_id === 30) {continue} //Check We are the People if (game.persistent_events.includes(48) && space.space_id === 9) {continue} valid_spaces.push(space.space_id); //Check Foreign Currency Debt Burden if (game.persistent_events.includes(49) && space.country === game.foreign_currency_debt_burden) {continue} } } } game.valid_spaces = valid_spaces //Check for Foreign Currency Debt Burden /*if (game.persistent_events.includes(49) && game.active === COM) { game.valid_spaces = game.valid_spaces.filter(n => spaces[n].country !== game.foreign_currency_debt_burden) }*/ vm_next() } function vm_valid_spaces_country_socio_2() { for (let space of spaces) { if (!space) continue if (space.space_id === game.systematization) continue if ((space.country === vm_operand(1) && space.socio === vm_operand(2)) || (space.country === vm_operand(1) && space.socio === vm_operand(3))) { game.valid_spaces.push(space.space_id); } } vm_next() } function vm_valid_spaces_region_socio() { let valid_spaces = [] for (let space of spaces) { if (!space) continue if (space.space_id === game.systematization) 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.comInfl[s] > 0 ) || (game.active === COM && space.region === vm_operand(1) && game.demInfl[s] > 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 i = 1; i < spaces.length; i++) { let space = spaces[i] let uncontrolled = (!check_control(i) && !check_opp_control(i)) 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' console.log('in vm_take_control_prep game.state', game.state) } function vm_take_control(space) { if (game.active === DEM) { let current_infl = game.demInfl[space] let opponent_infl = game.comInfl[space] let stability = spaces[space].stability if ((current_infl - opponent_infl) < stability) { game.demInfl[space] += stability - current_infl + opponent_infl //game.pieces[space].demCtrl = 1 //game.pieces[space].comCtrl = 0 } } else if (game.active === COM) { let current_infl = game.comInfl[space] let opponent_infl = game.demInfl[space] let stability = spaces[space].stability if ((current_infl - opponent_infl) < stability) { game.comInfl[space] += stability - current_infl + opponent_infl //game.pieces[space].comCtrl = 1 //game.pieces[space].demCtrl = 0 } } game.valid_spaces = game.valid_spaces.filter(id => id !== space) log(`Took control of %${space}`) } function vm_do_add_infl(space) { push_undo() console.log('in vm_do_add_infl, space', space, 'ops', game.vm_available_ops, 'ahbr tracker', game.austria_hungary_border_reopened_tracker, 'ahbr in events', game.persistent_events.includes(58)) //log(`Added 1 influence in %${space}.`) log_summary(`Added £ SP in %${space}.`) //If AHBR - check AHBR condition if (game.persistent_events.includes(58)) { if (spaces[space].country !== 'East_Germany'){ game.austria_hungary_border_reopened_tracker = false } } // Check Genscher if (game.persistent_events.includes(63) && game.active === DEM && spaces[space].country === 'East_Germany') { game.vm_available_ops-- log_summary(`(-1 op due to C63)`) } else if (check_opp_control(space)) { game.vm_available_ops -= 2 //Check if Austria Hungary Border Reopened was used to place last SP in a controlled space in East Germany. If so, game.vm_available_op will be negative if (game.vm_available_ops < 0) { log_summary(`(Used +1 op from C58)`) } } else { game.vm_available_ops-- } // Update influence values if (game.active === COM) { game.comInfl[space]++ } else { game.demInfl[space]++ } // Check whether spaces are controlled check_control_change(space) console.log('before check, ahbr in events', game.persistent_events.includes(58), 'tracker', game.austria_hungary_border_reopened_tracker) // Check Austria Hungary Border Reopened is true and condition has been met if (game.vm_available_ops === 0 && game.active === DEM && game.persistent_events.includes(58) && game.austria_hungary_border_reopened_tracker) { console.log('in award extra op') game.vm_available_ops ++ log('+1 Op from C58') game.austria_hungary_border_reopened_tracker = false 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 & Austria Hungary Border Reopened if (game.vm_available_ops === 1) { if (game.active === DEM) { //Check Genscher and AHBR if (game.persistent_events.includes(63) || (game.persistent_events.includes(58) && game.austria_hungary_border_reopened_tracker)) { console.log('in gensher subcheck - remove non-East German controlled ') game.valid_spaces = game.valid_spaces.filter(n => !(check_com_control(n) && spaces[n].country !== 'East_Germany')) } else { console.log('remove all controlled spaces') game.valid_spaces = game.valid_spaces.filter(n => !check_com_control(n)) } } else { game.valid_spaces = game.valid_spaces.filter(n => !check_dem_control(n)) } } //Clear valid spaces if no IP remaining. if (game.vm_available_ops <= 0 ) { game.valid_spaces = [] } } function vm_do_add_infl_free(space) { push_undo() //log(`Added 1 influence in %${space}.`) log_summary(`Added £ SP in %${space}.`) // Update influence values if (game.active === COM) { game.comInfl[space]++ } else { game.demInfl[space]++ } game.vm_available_ops-- // Check whether spaces are controlled check_control_change(space) //console.log('game pieces:', game.pieces[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() log(`Added ${game.vm_available_ops} SPs in %${space}.`) if (game.active === COM) { game.comInfl[space] += game.vm_available_ops } else { game.demInfl[space] += game.vm_available_ops } check_control_change(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() //log(`Added 1 influence in %${space}.`) log_summary(`Added £ SP in %${space}.`) game.vm_available_ops -- if (!game.vm_influence_added) { game.vm_influence_added = {}; } if (!game.vm_influence_added[space]) { game.vm_influence_added[space] = 0; } if (game.active === COM) { game.comInfl[space] ++ } else { game.demInfl[space] ++ } game.vm_influence_added[space] ++ //console.log('valid_spaces before update', game.valid_spaces) //console.log('influence added:', game.vm_influence_added[space], 'max infl', max_infl) if (game.vm_influence_added[space] === max_infl) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } check_control_change(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() //log(`Removed 1 influence from %${space}.`) log_summary(`Removed £ SP from %${space}.`) if (!game.vm_influence_added) { game.vm_influence_added = {}; } if (!game.vm_influence_added[space]) { game.vm_influence_added[space] = 0; } if (game.remove_opponent_infl === true) { if (game.active === COM) { game.demInfl[space]-- if (game.demInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } else { game.comInfl[space]-- if (game.comInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } } else { if (game.active === COM) { game.comInfl[space]-- if (game.comInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } else { game.demInfl[space]-- if (game.demInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } } } check_control_change(space) game.vm_influence_added[space]++ game.vm_available_ops-- if (game.vm_available_ops===0) {game.valid_spaces = []} } function vm_do_remove_x_infl(space) { push_undo() if (game.remove_opponent_infl) { if (game.active === COM) { if (game.demInfl[space] >= game.vm_available_ops) { game.demInfl[space] -= game.vm_available_ops } else { game.vm_available_ops = game.demInfl[space] game.demInfl[space] -= game.vm_available_ops } } else { if (game.comInfl[space] >= game.vm_available_ops) { game.comInfl[space] -= game.vm_available_ops } else { game.vm_available_ops = game.comInfl[space] game.comInfl[space] -= game.vm_available_ops } } } else { if (game.active === COM) { if (game.comInfl[space] >= game.vm_available_ops) { game.comInfl[space] -= game.vm_available_ops } else { game.vm_available_ops = game.comInfl[space] game.comInfl[space] -= game.vm_available_ops } } else { if (game.demInfl[space] >= game.vm_available_ops) { game.demInfl[space] -= game.vm_available_ops } else { game.vm_available_ops = game.demInfl[space] game.demInfl[space] -= game.vm_available_ops } } } log(`Removed ${game.vm_available_ops} SPs from %${space}`) check_control_change(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() log(`Removed SP from %${space}.`) game.vm_available_ops -- if (!game.vm_influence_added) { game.vm_influence_added = {}; } if (!game.vm_influence_added[space]) { game.vm_influence_added[space] = 0; } if (game.active === COM) { game.demInfl[space] -- if (game.demInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space) } } else { game.comInfl[space] -- if (game.comInfl[space] === 0) { game.valid_spaces = game.valid_spaces.filter(id => id !== space) } } game.vm_influence_added[space] ++ if (game.vm_influence_added[space] === max_infl) { game.valid_spaces = game.valid_spaces.filter(id => id !== space); } check_control_change(space) if (game.vm_available_ops === 0) {game.valid_spaces = []} } 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() log(`Removed all SP from %${space}.`) if (game.remove_opponent_infl === true) { if (game.active === COM) { game.demInfl[space] = 0 } else { game.comInfl[space] = 0 } check_control_change(space) } else { if (game.active === COM) { game.comInfl[space] = 0 } else { game.demInfl[space] = 0 } check_control_change(space) } game.vm_available_ops -- game.valid_spaces = game.valid_spaces.filter(id => id !== space) } function vm_replace_all_infl(space_id) { if (game.active === DEM) { game.demInfl[space_id] += game.comInfl[space_id] game.comInfl[space_id] = 0 } else { game.comInfl[space_id] += game.demInfl[space_id] game.demInfl[space_id] = 0 } check_control_change(space_id) } function vm_1_support_check() { game.vm_available_ops = 1 game.state = 'vm_1_support_check_prep' } 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(id){ push_undo() game.demInfl[id] -= game.vm_available_ops game.comInfl[id] += game.vm_available_ops log(`Replaced ${pluralize(game.vm_available_ops,'SP')} in %${id}`) game.vm_available_ops = 0 check_control_change(id) } /* ===================== 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') if (check_vp()) { return } vm_next() } function vm_adamec() { game.state = 'vm_adamec' } function vm_army_backs_revolution() { game.persistent_events = game.persistent_events.filter(n => n !== 70) game.playable_cards = game.playable_cards.filter(n => n !== 70) /*if (game.table_cards.includes(70)) { permanently_remove(70) }*/ vm_next() } function vm_austria_hungary_border_reopened() { game.persistent_events.push(58) permanently_remove(58) game.austria_hungary_border_reopened_tracker = false //game.table_cards.push(58) //remove_from_discard(58) vm_next() } function vm_betrayal() { if (game.demInfl[58] > 0 ) { game.valid_spaces.push(58) } if (game.demInfl[65] >0 ) { game.valid_spaces.push(65) } game.vm_available_ops = Math.max(game.demInfl[58], game.demInfl[65]) game.state = 'vm_switch_infl' } function vm_breakaway_baltic_republics() { log('+5 VP') game.vp += 5 game.stability++ if (check_vp()) { return } game.playable_cards.push(109) game.playable_cards = game.playable_cards.filter(n => n !== 14) if (!check_dem_control(56) && game.systematization !== 56) {game.valid_spaces.push(56)} if (!check_dem_control(70)) {game.valid_spaces.push(70)} vm_next() } function vm_brought_in_for_questioning() { if (game.active === COM) { game.active = DEM } //game.return = game.active console.log('in bifg, game.return', game.return) 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') if (check_vp()) { return } if (game.demInfl[70] > 0) {game.valid_spaces = [70]} vm_next() } function vm_ceausescu() { let adj_cluj = false if (game.demInfl[50] > 0 ) {adj_cluj = true} if (game.demInfl[54] > 0 ) {adj_cluj = true} if (game.demInfl[58] > 0 ) {adj_cluj = true} if (game.demInfl[61] > 0 ) {adj_cluj = true} if (adj_cluj && game.comInfl[61]>0) { game.valid_spaces = [61] game.vm_available_ops = 1 //next_player() game.remove_opponent_infl = false 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++ if (check_vp()) { return } game.persistent_events.push(90) if (check_dem_control(31)) { 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_choose' } 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 && (cards[c].playable || game.playable_cards.includes(c))) { 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.push(39) vm_next() } function vm_elena(){ game.persistent_events.push(101) vm_next() } function vm_eliminate(space_id) { log(`Eliminated %${space_id}`) const adjacent_spaces = spaces[space_id].adjacent.filter(Number.isInteger); //console.log('adjacency before: Iasi', game.pieces[53].adjacent, 'Ploesti:', game.pieces[59].adjacent, 'Bucharesti:', game.pieces[61].adjacent) // Eliminate the democrat influence and move the communist influence to Bucuresti game.demInfl[space_id] = 0 game.comInfl[61] += game.comInfl[space_id] if (game.comInfl[space_id] > 0 ) { log(`${pluralize(game.comInfl[space_id],'Communist SP')} relocated to %61`) } game.comInfl[space_id] = 0 //Update control in the eliminated space and in Bucuresti check_control_change(space_id) check_control_change(61) } function get_adjusted_adjacency(space_id) { let adjacent_spaces = spaces[space_id].adjacent; if (adjacent_spaces.includes(game.systematization)) { //console.log('in get adjusted adjacency, systemization',game.systematization) //console.log('adjacent_spaces', adjacent_spaces) } if (game.systematization !== 0) { //console.log('in systematization check') let eliminated_space_id = game.systematization; return adjacent_spaces.map(adj_space_id => { if (adj_space_id === eliminated_space_id) { // Replace the eliminated space with its adjacencies //console.log('in map check, return', spaces[eliminated_space_id].adjacent) return spaces[eliminated_space_id].adjacent; } //console.log('2nd check, return', adj_space_id) return adj_space_id; }).flat(); // Flatten in case the eliminated space has multiple adjacencies } //console.log('final adjacent spaces', adjacent_spaces) return adjacent_spaces; } function vm_exit_visas() { game.state = 'vm_exit_visas' } function vm_foreign_currency_debt_burden() { log('+1VP') game.vp++ if (check_vp()) { return } //game.table_cards.push(49) //remove_from_discard(49) game.persistent_events.push(49) game.state = 'vm_foreign_currency_debt_burden' } function vm_foreign_television() { for (let i = 1 ; i < spaces.length; i++) { if (i === 12) {continue} /*Does not apply to Dresden*/ if (game.comInfl[i] > 0 ) { game.valid_spaces.push(i) } } vm_next() } function vm_frg_embassies() { game.persistent_events.push(74) game.table_cards.push(74) remove_from_discard(74) log('C74 in effect') vm_next() } function vm_general_strike() { game.persistent_events.push(5) game.table_cards.push(5) remove_from_discard(5) log('C5 in effect') vm_next() } function vm_genscher() { game.persistent_events.push(63) game.table_cards.push(63) remove_from_discard(63) log(`C63 in effect`) vm_next() } function vm_goodbye_lenin() { game.view_opp_hand = true game.communist_hand_red = [] // 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) } } //Check if these cards are playabl for (let card of game.communist_hand_red) { if (cards[card].playable || game.playable_cards.includes(card)) { game.valid_cards.push(card) } } game.state = 'vm_goodbye_lenin' } function vm_government_resigns() { for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (space.socio === 1 && game.comInfl[i] > 0 && !check_control(i)) { game.valid_spaces.push(i) } } game.remove_opponent_infl = true vm_next() } function vm_grenztruppen() { console.log('in grenztruppen - player active:', game.active) game.persistent_events.push(59) permanently_remove(59) //game.table_cards.push(59) //remove_from_discard(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 if (change_vp >0) { log(`+${change_vp} VP`) } else { log(`-${change_vp} VP`) } game.vp += change_vp if (check_vp()) { return } vm_next() } function vm_helsinki_final_act() { game.persistent_events.push(26) vm_next() } function vm_honecker() { game.persistent_events.push(15) game.valid_cards = [] for (let c of game.strategy_discard) { if (scoring_cards.includes(c)) { continue} else { game.valid_cards.push(c) } } game.discard = true game.state = 'vm_honecker' } function vm_inflationary_currency() { game.state = 'vm_inflationary_currency' } function vm_inflationary_currency_discard() { // This function starts with the player who is playing Inflationary Currency for the Event // Switch player and check the hand of their opponent to see if the have cards with ops > 3 to discard next_player() if (game.active === COM) { for (let card of game.communist_hand){ if (get_card_ops(card) >= 3) { game.valid_cards.push(card) } } } else { for (let card of game.democrat_hand){ if (get_card_ops(card) >= 3) { game.valid_cards.push(card) } } } game.state = 'vm_inflationary_currency_discard' } function vm_kiss_of_death() { game.state = 'vm_kiss_of_death' } function vm_klaus_and_komarek() { if (game.comInfl[29] > 0 ) {game.valid_spaces = [29]} vm_next() } function vm_kohl_proposes_reunification() { log('+2 VP') game.vp += 2 if (check_vp()) { return } if (game.persistent_events.includes(86)) { game.vm_event = 87 game.state = 'vm_common_european_home_play' } else { permanently_remove(87) vm_return() } } function vm_kremlin_coup() { log('-3 VP') game.vp -= 3 if (check_vp()) { return } game.support_check_modifier = 1 //countries = ['Poland', 'Hungary', 'East_Germany', 'Bulgaria', 'Czechoslovakia', 'Romania'] //revolutions: {'East_Germany': false, 'Poland': false, 'Czechoslovakia': false, 'Hungary': false, 'Romania': false, 'Bulgaria': false} game.temp = [] countries.forEach(country => { if (!game.revolutions[find_country_index(country)]) { game.temp.push(country) } }) console.log('game.temp', game.temp) game.state = 'vm_kremlin_coup_choose_country' } function vm_laszlo_tokes() { game.persistent_events.push(73) game.playable_cards.push(107) 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 i = 1; i < spaces.length; i++) { let space = spaces[i] if ((!check_com_control(i) && space.country === 'Czechoslovakia')) { game.valid_spaces.push(space.space_id); } } vm_next() } function vm_li_peng() { game.persistent_events.push(53) //game.table_cards.push(53) remove_from_discard(53) vm_next() } function vm_ligachev() { game.persistent_events.push(99) vm_next() } function vm_malta_summit() { game.state = 'vm_malta_summit' } function vm_massacre_in_timisoara() { game.persistent_events = game.persistent_events.filter(n => n !== 73) vm_next() } function vm_modrow() { game.playable_cards.push(15) game.state = 'vm_modrow' } function vm_nagy_reburied(){ if (game.comInfl[43] > 0) { game.valid_spaces.push(43) } vm_next() } function vm_national_salvation_front() { game.persistent_events.push(102) game.table_cards.push(102) remove_from_discard(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.demInfl[27] >0) {game.valid_spaces.push(27)} if (game.demInfl[29] > 0) {game.valid_spaces.push(29)} game.remove_opponent_infl = true vm_next() } function vm_peasant_parties_revolt() { game.persistent_events.push(72) log_msg_gap('C72 in effect') game.table_cards.push(72) remove_from_discard(72) vm_next() } function vm_perestroika() { game.persistent_events.push(25) log_msg_gap('C25 in effect') vm_next() } function vm_poszgay() { let valid_spaces = [] for (let space of spaces) { if (space && space.country === 'Hungary' && !check_dem_control(space.space_id)) { valid_spaces.push(space.space_id); } } game.valid_spaces = valid_spaces vm_next() } function vm_power_struggle() { console.log('in vm_power_struggle. game.vm_event', game.vm_event, 'game.active', game.active, 'game.view_opp_hand', game.view_opp_hand) game.is_pwr_struggle = true /* TO DELETE? //Check if Power Struggle is because of an event */ if (game.vm_event > 0) { console.log('vm_power_struggle, in game.vm_event check') game.pwr_struggle_in = countries[scoring_cards.indexOf(game.vm_event)] log_h2(`C${game.vm_event}`) } /* //Otherwise set Power Struggle country normally else { console.log('vm_power_struggle, country set normally') game.pwr_struggle_in = countries[scoring_cards.indexOf(game.played_card)] log_h2(`C${game.played_card}`) }*/ //Check for Securitate if (game.pwr_struggle_in === 'Romania' && game.persistent_events.includes(70)) { console.log('in Securitate subcheck') log('C70: Democrat reveals Power Struggle cards') game.view_opp_hand = true } log_h2('Deal Cards') game.state = 'draw_power_cards' console.log('game.state',game.state) } function vm_presidential_visit() { game.persistent_events.push(65) //game.table_cards.push(65) //remove_from_discard(65) log_msg_gap('C65 in effect') vm_next() } function vm_prudence() { if (!game.prudence) { game.prudence = {DEM: 0, COM: 0} } if (game.active === DEM) { game.prudence.COM -- log(`${game.prudence.COM} to Communist ops this turn`) } else { game.prudence.DEM -- log(`${game.prudence.DEM} to Democrat ops this turn`)} vm_next() } function vm_public_against_violence() { game.valid_spaces = [] if (game.comInfl[34] > 0 ) {game.valid_spaces.push(34)} vm_next() } function vm_reformer_rehabilitated () { permanently_remove(67) 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.push(17) game.table_cards.push(17) remove_from_discard(17) log_msg_gap('C17 in effect') vm_next() } function vm_sajudis_check() { if (!check_dem_control(56)) { game.valid_spaces.push(56) } if (!check_dem_control(70)) { game.valid_spaces.push(70) } vm_next() } function vm_sajudis() { game.playable_cards.push(81) game.stability++ log('+1 VP') game.vp++ if (check_vp()) { return } vm_next() } function vm_samizdat() { game.state = 'vm_samizdat' } function vm_securitate() { game.persistent_events.push(70) permanently_remove(70) //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.push(3) game.persistent_events.push(2) console.log('game.persistent_events', game.persistent_events) vm_next() } function vm_st_nicholas_church () { game.persistent_events.push(24) game.playable_cards.push(61) vm_next() } function vm_stasi() { log_msg_gap('C13 in effect') game.persistent_events.push(13) vm_next() } function vm_stand_fast() { game.persistent_events.push(100) if (game.active === DEM) { game.stand_fast = DEM } else {game.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++ game.dem_tst_attempted = 0 } else { game.com_tst_position++ game.com_tst_attempted = 0 } vm_next() } function vm_tear_gas () { game.persistent_events.push(30) game.table_cards.push(30) remove_from_discard(30) log_msg_gap('C30 in effect') vm_next() } function vm_the_baltic_way() { game.playable_cards.push(84) game.stability++ if (!check_dem_control(56) && game.systematization !== 56) {game.valid_spaces.push(56)} if (!check_dem_control(70) && game.systematization !== 70) {game.valid_spaces.push(70)} log('+3 VP') game.vp += 3 if (check_vp()) { return } console.log('game.state', game.state) vm_next() } function vm_the_chinese_solution() { game.state = 'vm_the_chinese_solution' } function vm_the_crowd_turns_against_ceausescu() { game.table_cards.push(54) remove_from_discard(54) game.playable_cards.push(97) vm_next() } function vm_the_monday_demonstrations() { if (!check_dem_control(6)) {game.valid_spaces.push(6)} if (!check_dem_control(9)) {game.valid_spaces.push(9)} vm_next() } function vm_the_sinatra_doctrine() { game.persistent_events.push(50) 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 i = 1; i < spaces.length; i++) { let space = spaces[i] if (game.demInfl[i] === 0 && space.country === 'Romania') { if (space.space_id === game.systematization) {continue} game.valid_spaces.push(space.space_id) } } console.log('game.vm_event', game.vm_event, 'game.played_card', game.played_card) game.state = 'vm_the_tyrant_is_gone' } function vm_the_tyrant_is_gone_prep() { game.table_cards.push(97) remove_from_discard(97) vm_next() } function vm_tyrant_block() { game.state = 'vm_tyrant_block' } function vm_the_wall () { game.persistent_events.push(9) //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 /*What does this do? */ game.state = 'vm_warsaw_pact_summit' } function vm_we_are_the_people() { if (game.demInfl[6] > 0) {game.valid_spaces = [6]} game.persistent_events.push(48) if (!game.vm_influence_added) { game.vm_influence_added = {}; } 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[find_country_index(country)] && game.comInfl[space.space_id] > 0 && space.socio === 4) { game.valid_spaces.push(space.space_id); } } } else { for (let space of spaces) { if (!space) continue let country = space.country if (game.revolutions[find_country_index(country)] && game.demInfl[space.space_id] > 0 && space.socio === 4) { game.valid_spaces.push(space.space_id); } } } game.state = 'vm_workers_revolt' } function vm_yakovlev_counsels_gorbachev() { game.persistent_events.push(62) log_msg_gap('C62 in effect') game.table_cards.push(62) remove_from_discard(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, is a card which should be removed, and which hasn't already been removed! if (game.vm_event !== 0 && cards[game.vm_event].remove === 1 && !game.strategy_removed.includes(game.vm_event)) { permanently_remove(game.vm_event) } if (cards[game.played_card].remove ===1 && !game.strategy_removed.includes(game.played_card)) { permanently_remove(game.played_card) } /*This means the card that called the event being played is also removed if relevant. Think this makes sense */ 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_1' } function vm_support_falters() { game.vm_available_ops = 2 game.return === game.active game.state = 'vm_support_falters' } function vm_kremlin_coup_elite() { game.valid_spaces=[] elite_spaces.forEach(space => { if (spaces[space].country === game.vm_active_country && !check_com_control(space)) { game.valid_spaces.push(space); } }) game.state = 'vm_kremlin_coup_take_control' } /* ================== VM STATES ============================== */ states.vm_end_event = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}.` }, prompt () { view.prompt = `${clean_name(cards[this_card()].name)}: done.` gen_action('done') }, done(){ vm_end_event() } } states.vm_take_control = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt () { console.log('game.vm_available_ops', game.vm_available_ops) if (game.vm_available_ops > 0 && game.valid_spaces.length === 0) { view.prompt = `${clean_name(cards[this_card()].name)}: all spaces controlled. Continue.` gen_action('done') } else if (game.vm_available_ops > 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}: take control of ${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Take control: done.` gen_action('done') } }, infl(space) { push_undo() vm_take_control(space) game.vm_available_ops-- }, done() { vm_next() } } states.vm_add_infl = { inactive: 'add Support Points.', prompt () { console.log('in vm add infl') if (game.vm_available_ops > 0 && game.valid_spaces.length === 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}. No available spaces remaining. Add SPs: done.` gen_action('done') } else if (game.vm_available_ops > 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}: add ${pluralize(game.vm_available_ops,'SP')}${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id) } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Add SPs: done.` gen_action('done') } }, infl(space) { vm_do_add_infl(space) if (game.vm_available_ops === 0) { game.valid_spaces = [] } }, done () { if (game.summary.length > 0) { pop_summary() log_br() } game.vm_event_done = true vm_next() } } states.vm_add_infl_free = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}: add SPs.` }, prompt () { if (game.vm_available_ops > 0 && game.valid_spaces.length === 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}. No available spaces remaining. Add SPs: done.` gen_action('done') } else if (game.vm_available_ops > 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}: add ${game.vm_available_ops} SPs to ${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Add SPs: done.` gen_action('done') } }, infl(space) { vm_do_add_infl_free(space) if (game.vm_available_ops === 0) { game.valid_spaces = [] } }, done () { game.valid_spaces = [] game.vm_event_done = true if (game.summary.length > 0) { pop_summary() log_br() } vm_next() } } states.vm_add_x_infl = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}: add Support Points.` }, // inactive: `resolve ${cards[this_card()].name}: add influence.`, prompt () { if (game.vm_available_ops > 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}: Add ${game.vm_available_ops} SPs to ${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id) } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Add SPs: done.` gen_action('done') } }, infl(space) { push_undo() vm_do_add_x_infl(space) if (game.vm_event === 105) { vm_next() } //game.vm_event_done = true //vm_next() }, done () { game.vm_event_done = true vm_next() } } states.vm_add_limited_infl = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}: add Support Points.` }, prompt () { if (game.vm_available_ops > 0 && game.valid_spaces.length > 0) { if (game.vm_max_infl === 1) { view.prompt = `${clean_name(cards[this_card()].name)}: add ${pluralize(game.vm_max_infl,'SP')} ${event_prompt()}.` } else { view.prompt = `${clean_name(cards[this_card()].name)}: add ${pluralize(game.vm_available_ops,'SP')} to ${event_prompt()}.` } for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Add SPs: done.` gen_action('done') } }, infl(space) { vm_do_add_limited_infl(space, game.vm_max_infl) if (game.vm_available_ops === 0) { game.valid_spaces = [] } }, done () { if (game.summary.length > 0) { pop_summary() log_br() } game.vm_event_done = true vm_next() } } states.vm_remove_infl = { inactive: 'remove Support Points.', prompt () { // Keep this so that there is an undo option in, e.g., Scare Tactics if (game.valid_spaces.length === 0 && game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no further SPs to remove.` gen_action('done') return } if (game.vm_available_ops === 0 ) { view.prompt = `${clean_name(cards[this_card()].name)}. Remove SPs: done.` gen_action('done') return } if (game.remove_opponent_infl) { view.prompt = `${clean_name(cards[this_card()].name)}: remove ${pluralize(game.vm_available_ops, 'opponent SP')}${event_prompt()}.` } else { view.prompt = `${clean_name(cards[this_card()].name)}: remove ${pluralize(game.vm_available_ops,'SP')}${event_prompt()}.` } for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } }, infl(space) { push_undo() vm_do_remove_infl(space) game.vm_active_country = spaces[space].country /*if (game.vm_available_ops === 0 || game.valid_spaces.length === 0) { vm_next() }*/ }, done() { if (game.summary.length > 0) { pop_summary() log_br() } vm_next() } } states.vm_remove_x_infl = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}: remove SP from ${event_prompt()}.` }, prompt () { if (game.valid_spaces.length === 0 && game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no SPs to remove.` gen_action('done') } else if (game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: remove ${pluralize(game.vm_available_ops,'SP')} from ${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Remove SPs: done.` gen_action('done') } }, infl(space) { vm_do_remove_x_infl(space) /*game.vm_event_done = true vm_next()*/ }, done () { game.vm_event_done = true vm_next() } } states.vm_remove_limited_infl = { inactive: 'remove SP.', prompt () { if (game.vm_available_ops > 0 && game.valid_spaces.length > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: remove ${pluralize(game.vm_available_ops,'SP')}${event_prompt()}, no more than ${game.vm_max_infl} per space.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else if (game.valid_spaces.length === 0 && game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no further SP to remove.` gen_action('done') } else { view.prompt = `${clean_name(cards[this_card()].name)}. Remove SPs: done.` gen_action('done') } }, infl(space) { vm_do_remove_limited_infl(space, game.vm_max_infl) /*if (game.vm_available_ops === 0) { game.vm_event_done = true } */ }, done () { game.vm_event_done = true if (game.summary.length > 0) { pop_summary() log_br() } vm_next() } } states.vm_remove_all_infl = { inactive: 'remove Support Points', prompt () { if (game.valid_spaces.length === 0 && game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no SPs to remove.` gen_action('done') } else if (game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: remove all SPs from ${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else { view.prompt = `${clean_name(cards[this_card()].name)}. Remove SPs: done.` gen_action('done') } }, infl(space) { vm_do_remove_all_infl(space) game.vm_active_country = spaces[space].country /*if (game.vm_available_ops === 0 || game.valid_spaces.length === 0) { vm_next() }*/ }, done() { vm_next() } } states.vm_support_check_prep = { inactive: 'do support checks.', prompt () { console.log('in states.vm_support_check_prep, game.vm_available_ops: ', game.vm_available_ops) if (game.vm_available_ops === 0) { view.prompt = `${clean_name(cards[this_card()].name)}. Support check: done.` gen_action('done') } else if (game.valid_spaces.length === 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no valid targets for support check.` gen_action('done') } else { if (game.vm_available_ops > 0) { view.prompt = `${clean_name(cards[this_card()].name)}: ${event_prompt()}. ${pluralize(game.vm_available_ops, 'support check')} remaining.` } for (let space_id of game.valid_spaces) { if (!space_id) continue gen_action_sc(space_id); } } }, sc(space) { push_undo() game.selected_space = space // Check for Austria-Hungary Border Reopened - check on first support check only //First check for Monday Demonstrations - support checks will always be in East Germany if (game.vm_event === 61 && game.persistent_events.includes(58)) { game.austria_hungary_border_reopened_tracker = true game.state = 'vm_do_support_check' return } //Then check Austria-Hungary Border Reopened normally //console.log('game.austria_hungary_border_reopened_checked', game.austria_hungary_border_reopened_checked) if (game.persistent_events.includes(58)) { if (game.active === DEM && game.vm_available_ops > 1) { if (spaces[game.selected_space].country === 'East_Germany' && game.persistent_events.includes(58) && game.active === DEM) { game.state = 'vm_austria_hungary_border_reopened_check' return } //game.state = 'do_support_check' } /*else { */ } game.state = 'vm_do_support_check' }, done () { game.vm_available_ops = 0 vm_next () } } states.vm_ceh_support_check_prep = { inactive: 'do support checks.', prompt () { if (game.vm_available_ops === 0) { view.prompt = 'Support checks: done.' gen_action('done') //return } 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) { gen_action_sc(space_id) } } }, sc(space) { push_undo() game.selected_space = space //Then check Austria-Hungary Border Reopened normally //console.log('game.austria_hungary_border_reopened_checked', game.austria_hungary_border_reopened_checked) if (game.persistent_events.includes(58)) { if (game.active === DEM && game.vm_available_ops > 1) { console.log('in ahb check, country, ', spaces[game.selected_space].country, 'ahb', game.persistent_events.includes(58)) if (spaces[game.selected_space].country === 'East_Germany' && game.persistent_events.includes(58) && game.active === DEM) { game.state = 'vm_austria_hungary_border_reopened_check' return } //game.state = 'do_support_check' } /*else { */ } game.state = 'vm_ceh_do_support_check' }, done () { vm_next () } } states.vm_ceh_do_support_check = { inactive: 'do support checks.', prompt () { view.prompt = `Support check: ${spaces[game.selected_space].name_unique}. Roll a die.` gen_action('roll') }, roll() { clear_undo() do_sc(game.selected_space) game.vm_available_ops-- if (game.vm_available_ops === 0) { game.valid_spaces = [] } game.state = 'vm_ceh_support_check_prep' return } } states.vm_austria_hungary_border_reopened_check = { inactive: 'decide Austria-Hungary Border Reopened', prompt() { view.prompt = 'Austria-Hungary Border Reopened: will all support checks be in East Germany?' gen_action('yes') gen_action('no') }, yes() { game.austria_hungary_border_reopened_tracker = true game.state = 'vm_do_support_check' }, no() { game.state = 'vm_do_support_check' } } states.vm_1_support_check_prep = { inactive: 'do support checks.', prompt () { if (game.vm_available_ops === 0) { view.prompt = `${clean_name(cards[this_card()].name)}. Support check: done.` gen_action('done') } else if (game.valid_spaces.length === 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no valid targets for support check.` gen_action('done') } else { view.prompt = `${clean_name(cards[this_card()].name)}: ${event_prompt()}.` for (let space_id of game.valid_spaces) { if (!space_id) continue gen_action_sc(space_id); } } }, sc(space) { push_undo() game.selected_space = 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 = `Support check: ${spaces[game.selected_space].name_unique}. Roll a die.` gen_action('roll') }, roll() { clear_undo() do_sc(game.selected_space) 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 ${clean_name(cards[88].name)}.` }, prompt() { view.prompt = 'Adamec: roll a die.' gen_action('roll') }, roll() { clear_undo() let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${roll}`) let worker_spaces = spaces.filter(space => space && space.country === 'Czechoslovakia' && space.socio === 4 && check_dem_control(space.space_id)).length if (worker_spaces > 0) { log(`-${worker_spaces} from Democrat controlled worker spaces`) roll -= worker_spaces } log(`Modified roll: ${roll}`) if (roll > 2) { log('Adamec succeeds') vm_next() return } log('Adamec fails: 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('pass') } else { view.prompt = 'Brought in for Questioning: you must discard a random card.' gen_action('discard') } }, discard() { game.vm_event = discard_card(game.democrat_hand) game.phase = 1 if (cards[game.vm_event].side === 'C' && (cards[game.vm_event].playable || game.playable_cards.includes(game.vm_event))) { //game.return = game.active if (!game.vm_infl_to_do) { if(game.round_player === DEM) { game.return = COM } else { game.return = DEM } } console.log('BIFQ discard: game.return', game.return) if (!auto_resolve_events.includes(game.vm_event) && !switch_events.includes(game.vm_event)) { next_player() } goto_vm(game.vm_event) } else { game.return = DEM } }, pass() { log('No cards to discard') vm_return() }, done() { vm_return() } } states.vm_central_committee_reshuffle = { get inactive() { return `resolve ${clean_name(cards[57].name)}.` }, prompt() { view.prompt = 'Central Committee Reshuffle: choose a country to add SPs.' if (!game.revolutions[0]) {gen_action('poland')} if (!game.revolutions[1]) {gen_action('hungary')} if (!game.revolutions[2]) {gen_action('east_germany')} if (!game.revolutions[3]) {gen_action('bulgaria')} if (!game.revolutions[4]) {gen_action('czechoslovakia')} if (!game.revolutions[5]) {gen_action('romania')} }, east_germany() { game.vm_active_country = "East_Germany" log(`Chose ${country_name(game.vm_active_country)}`) game.valid_spaces = [1,2,3,4,5,6,7,8,9,10,11,12] vm_next() }, poland() { game.vm_active_country = "Poland" log(`Chose ${country_name(game.vm_active_country)}`) game.valid_spaces = [13,14,15,16,17,18,19,20,21,22,23,24,25,26] vm_next() }, czechoslovakia() { game.vm_active_country = "Czechoslovakia" log(`Chose ${country_name(game.vm_active_country)}`) game.valid_spaces = [27,28,29,30,31,32,33,34,35,36,37] vm_next() }, hungary() { game.vm_active_country = "Hungary" log(`Chose ${country_name(game.vm_active_country)}`) game.valid_spaces = [38,39,40,41,42,43,44,45,46,47,48,49] vm_next() }, romania() { game.vm_active_country = "Romania" log(`Chose ${country_name(game.vm_active_country)}`) game.valid_spaces = [50,51,52,53,54,55,56,57,58,59,60,61,62,63] game.valid_spaces = game.valid_spaces.filter(space => space !== game.systematization) vm_next() }, bulgaria () { game.vm_active_country = "Bulgaria" log(`Chose ${country_name(game.vm_active_country)}`) game.valid_spaces = [64,65,66,67,68,69,70,71,72,73,74,75] vm_next() }, } states.vm_common_european_home_choose = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = `Common European Home: play an opponent's card, event does not occur.` for (let card of game.valid_cards) { gen_action_card(card) } }, card(card) { push_undo() log(`Played with C${cards[card].number}`) game.valid_cards = [] silent_discard(card) game.vm_event = card game.state = 'vm_common_european_home_play' } } states.vm_common_european_home_play = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}.` }, prompt() { view.prompt = `Play ${clean_name(cards[this_card()].name)} for:` gen_action('influence') gen_action('support_check') if (game.active === DEM && game.vm_event === 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') } }, influence(){ push_undo() game.vm_available_ops = cards[game.vm_event].ops valid_spaces_infl() // If ABHR - Set AHBR tracker to true if (game.persistent_events.includes(58)) { game.austria_hungary_border_reopened_tracker = true } game.state = 'vm_add_infl' }, support_check() { push_undo() game.vm_available_ops = 2 game.state = 'vm_ceh_support_check_prep' valid_spaces_sc() }, tst() { game.state = 'vm_tiananmen_square_attempt' } } states.vm_dash_for_the_west = { get inactive() { return `resolve ${clean_name(cards[36].name)}.` }, prompt() { /* if (game.phase === 1) {*/ view.prompt = 'Dash for the West: roll a die' gen_action('roll') /*} else { view.prompt = 'Dash for the West: roll a die. Done.' gen_action('done') }*/ }, roll() { clear_undo() let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${roll}`) let com_control = check_presence('East_Germany').com_spaces if (roll > com_control) { log(`Success. More than the ${com_control} Communist controlled spaces in East Germany`) log('+1 VP') game.vp++ if (check_vp()) { return } game.discard = true game.state = 'vm_play_event_from_discard' } else { log(`Fail: more than a ${com_control} required`) //game.phase++ vm_next() } },/* done() { vm_next() }*/ } states.vm_play_event_from_discard = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.valid_cards.length === 0) { view.prompt = `${clean_name(cards[this_card()].name)}: no valid cards in discard.` gen_action('pass') } else if (game.temp === 0) { view.prompt = `${event_prompt()}.` for (let card of game.valid_cards) { gen_action('pass') 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 Does turning this off cause problems? console.log('card:', card) if (switch_events.includes(card)) {next_player()} goto_vm(card) }, pass(){ push_undo() if (game.valid_cards.length === 0) { log('No valid cards to choose') } else{ log('Did not choose a card') } vm_next() }, done(){ game.discard = false vm_next() } } states.vm_deutsche_marks_prep = { inactive: 'choose a card.', prompt() { if (game.valid_cards.length === 0) { view.prompt = 'Deutsche Marks: no cards to give.' gen_action('pass') } else { view.prompt = 'Deutsche Marks: choose a card to give.' for (let card of game.valid_cards) { gen_action_card(card) } } }, card(card) { push_undo() log(`Gave C${cards[card].number}`) game.valid_cards = [] silent_discard(card) //next_player() game.state = 'vm_deutsche_marks_confirm' game.vm_event = card }, pass() { vm_next() } } states.vm_deutsche_marks_confirm = { inactive: 'choose a card.', prompt() { view.prompt = `Deutsche Marks: gave ${cards[game.vm_event].name}.` gen_action('done') }, done() { next_player() game.state = 'vm_deutsche_marks' } } states.vm_deutsche_marks = { get inactive() { return `resolve ${clean_name(cards[20].name)}.` }, prompt() { if(cards[game.vm_event].side === 'C' && (cards[game.vm_event].playable || game.playable_cards.includes(game.vm_event))) { view.prompt = `Deutsche Marks: you must play ${clean_name(cards[this_card()].name)} for the event.` gen_action('event') } else { view.prompt = `Deutsche Marks: play ${clean_name(cards[this_card()].name)} 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.vm_event].number} for the event`) console.log('game.active', game.active) if (!game.vm_infl_to_do) { game.return = game.active } console.log('DM Event played, game.return', game.return) goto_vm(game.vm_event) }, influence() { push_undo() log(`Played C${cards[game.vm_event].number} to place SPs`) game.vm_available_ops = get_card_ops(game.vm_event) /*cards[game.vm_event].ops if (game.persistent_events.includes(25)) {game.vm_available_ops++ } if (game.prudence.COM && game.prudence.COM < 0 ) { game.vm_available_ops += game.prudence.COM }*/ valid_spaces_infl() game.state = 'vm_add_infl' }, support_check() { push_undo() log_gap(`Played C${cards[game.vm_event].number} for support checks`) game.vm_available_ops = 2 game.state='vm_support_check_prep' valid_spaces_sc() }, tst() { push_undo() log_gap(`Played C${cards[game.vm_event].number} to the Tiananmen Square Track`) game.state='vm_tiananmen_square_attempt' } } states.vm_exit_visas = { get inactive() { return `resolve ${clean_name(cards[75].name)}.` }, prompt() { view.prompt = 'Exit Visas: you may discard cards from your hand and draw replacements.' for (let card of game.democrat_hand) { gen_action_card(card) } if (game.temp === 0) { gen_action('pass') } else { gen_action('done') } }, card(card){ push_undo() discard(card) game.temp++ }, pass() { push_undo() game.state = 'vm_exit_visas_finish' }, done() { push_undo() game.state = 'vm_exit_visas_finish' } } states.vm_exit_visas_finish = { get inactive() { return `resolve ${clean_name(cards[75].name)}.` }, prompt() { if (game.temp > 0 ) { view.prompt = 'Exit Visas: draw replacement cards.' gen_action('draw') } else { view.prompt = 'Exit Visas. Draw 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 ${clean_name(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() { push_undo() game.foreign_currency_debt_burden = 'East_Germany' log('Selected East Germany') vm_next() }, poland() { push_undo() game.foreign_currency_debt_burden = 'Poland' log('Selected Poland') vm_next() }, czechoslovakia() { push_undo() game.foreign_currency_debt_burden = 'Czechoslovakia' log('Selected Czechoslovakia') vm_next() }, hungary() { push_undo() game.foreign_currency_debt_burden = 'Hungary' log('Selected Hungary') vm_next() }, bulgaria() { push_undo() game.foreign_currency_debt_burden = 'Bulgaria' log('Selected Bulgaria') vm_next() } } states.vm_goodbye_lenin = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { console.log('in vm_goodbye lenin') 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) { push_undo() log(`Chose to play C${card} for the event`) let card_index = game.communist_hand.indexOf(card) game.communist_hand.splice(card_index, 1) game.vm_event = card game.view_opp_hand = false goto_vm(card) }, ops() { if (game.valid_cards.length === 0) { logi('No red events') } log('C46 played for operations') game.view_opp_hand = false game.state = 'vm_goodbye_lenin_ops' } } states.vm_goodbye_lenin_ops = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}.` }, prompt() { view.prompt = `Play ${clean_name(cards[this_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 = get_card_ops(this_card()) /*if (game.persistent_events.includes(50)) { log(`+1 from C50`) game.vm_available_ops++ }*/ console.log('goodbye lenin: influence selected') valid_spaces_infl() // If ABHR - Set AHBR tracker to true if (game.persistent_events.includes(58)) { game.austria_hungary_border_reopened_tracker = true } 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 ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.valid_cards.length === 0 && game.temp === 0) { view.prompt = 'Honecker: no valid cards to choose.' gen_action('done') } else if (game.temp === 0) {view.prompt = 'Honecker: choose a card to add to your hand.' for (let card of game.valid_cards) { gen_action_card(card) gen_action('pass') } } else { view.prompt = 'Honecker. 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) }, pass(){ log('Did not take a card') vm_next() }, done(){ if (game.temp === 0) { log('Did not take a card') } game.discard = false vm_next() } } states.vm_inflationary_currency = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { console.log('game.revolutions', game.revolutions, 'length', game.revolutions.length) if (game.revolutions.every(n => n === false)) { view.prompt = 'Inflationary Currency: no countries to choose.' gen_action('pass') } else { view.prompt = 'Inflationary Currency: choose a country where your opponent has power.' if (game.active === DEM) { if (!game.revolutions[0]) {gen_action('poland')} if (!game.revolutions[1]) {gen_action('hungary')} if (!game.revolutions[2]) {gen_action('east_germany')} if (!game.revolutions[3]) {gen_action('bulgaria')} if (!game.revolutions[4]) {gen_action('czechoslovakia')} if (!game.revolutions[5]) {gen_action('romania')} } else { if (game.revolutions[0]) {gen_action('poland')} if (game.revolutions[1]) {gen_action('hungary')} if (game.revolutions[2]) {gen_action('east_germany')} if (game.revolutions[3]) {gen_action('bulgaria')} if (game.revolutions[4]) {gen_action('czechoslovakia')} if (game.revolutions[5]) {gen_action('romania')} } } }, east_germany() { push_undo() game.vm_active_country = 'East_Germany' log(`Chose ${country_name(game.vm_active_country)}`) vm_next() }, poland() { push_undo() game.vm_active_country = 'Poland' log(`Chose ${country_name(game.vm_active_country)}`) vm_next() }, czechoslovakia() { push_undo() game.vm_active_country = 'Czechoslovakia' log(`Chose ${country_name(game.vm_active_country)}`) vm_next() }, hungary() { push_undo() game.vm_active_country = 'Hungary' log(`Chose ${country_name(game.vm_active_country)}`) vm_next() }, romania() { push_undo() game.vm_active_country = 'Romania' log(`Chose ${country_name(game.vm_active_country)}`) vm_next() }, bulgaria () { push_undo() game.vm_active_country = 'Bulgaria' log(`Chose ${country_name(game.vm_active_country)}`) vm_next() }, pass() { log('Passed') vm_return() } } states.vm_inflationary_currency_discard = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.valid_cards.length === 0 ) { view.prompt = 'Inflationary Currency: no valid cards to discard. You must pass.' gen_action('pass') } else if (game.temp === 0 ) { view.prompt = 'Inflationary Currency: 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) { push_undo() discard(card) game.temp = card }, pass() { log('Did not discard') next_player() game.vm_available_ops = 1 vm_next() //game.state = 'vm_support_check_prep' }, done() { if (!game.vm_infl_to_do) { if(game.round_player === DEM) { game.return = COM } else { game.return = DEM } } vm_next() } } states.vm_kiss_of_death = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.communist_hand.length === 0) { view.prompt = 'Kiss of Death. No cards to discard.' gen_action('pass') } else { view.prompt = 'Kiss of Death: 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' }, pass() { log('No card to discard') vm_next() } } states.vm_kiss_of_death_finish = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { console.log('game.vm_event', game.vm_event) if (game.vm_event > 0 && game.vm_event !== 21 && (cards[game.vm_event].side === 'D' || cards[game.vm_event].side === 'N')) { view.prompt = `Play ${clean_name(cards[game.vm_event].name)} for the event.` console.log('kiss of death before event button: game.stategy_discard', game.strategy_discard) gen_action('event') } else { view.prompt = 'Event does not occur.' gen_action('done') } }, event() { //game.return = game.active console.log('kiss of death event section, discard', game.strategy_discard) // Remove game.vm_event from the discard //game.strategy_discard = game.strategy_discard.filter(n => n !== game.vm_event) console.log('kiss of death event section 2, discard', game.strategy_discard) goto_vm(game.vm_event) }, done() { vm_next() } } states.vm_kremlin_coup_choose_country = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}.` }, prompt() { if (game.temp.length > 0) { view.prompt = 'Kremlin Coup! Select a country where the Communist retains power.' for (let country of countries) { console.log(`checking`, country) if (game.temp.includes(country)) { console.log('country in game.temp') gen_action(`${country.toLowerCase()}`) } } } else { view.prompt = 'Kremlin Coup! There are no countries where the Communist retains power.' gen_action('done') } }, east_germany() { push_undo() game.vm_active_country = 'East_Germany' game.temp = game.temp.filter(country => country !== game.vm_active_country) log(`${country_name(game.vm_active_country)}:`) vm_kremlin_coup_elite() }, poland() { push_undo() game.vm_active_country = 'Poland' log(`${country_name(game.vm_active_country)}:`) game.temp = game.temp.filter(country => country !== game.vm_active_country) vm_kremlin_coup_elite() }, czechoslovakia() { push_undo() game.vm_active_country = 'Czechoslovakia' log(`${country_name(game.vm_active_country)}:`) game.temp = game.temp.filter(country => country !== game.vm_active_country) vm_kremlin_coup_elite() }, hungary() { push_undo() game.vm_active_country = 'Hungary' log(`${country_name(game.vm_active_country)}:`) game.temp = game.temp.filter(country => country !== game.vm_active_country) vm_kremlin_coup_elite() }, romania() { push_undo() game.vm_active_country = 'Romania' log(`${country_name(game.vm_active_country)}:`) game.temp = game.temp.filter(country => country !== game.vm_active_country) vm_kremlin_coup_elite() }, bulgaria () { push_undo() game.vm_active_country = 'Bulgaria' log(`${country_name(game.vm_active_country)}:`) game.temp = game.temp.filter(country => country !== game.vm_active_country) vm_kremlin_coup_elite() }, done() { game.temp = 0 vm_next() } } states.vm_kremlin_coup_take_control = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.valid_spaces.includes(game.systematization)) { view.prompt = `Kremlin Coup! ${country_name(game.vm_active_country)}'s Elite space no longer exists.` gen_action('done') } else if (game.valid_spaces.length === 0){ view.prompt = `Kremlin Coup! ${country_name(game.vm_active_country)}'s Elite space is already controlled.` gen_action('done') } else { view.prompt = `Kremlin Coup! Take control of the Elite space in ${country_name(game.vm_active_country)}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } }, infl(space) { vm_take_control(space) if (game.vm_active_country === 'East_Germany') {game.selected_space = 3 } if (game.vm_active_country === 'Poland') {game.selected_space = 17} if (game.vm_active_country === 'Czechoslovakia') {game.selected_space = 29} if (game.vm_active_country === 'Hungary') {game.selected_space = 45} if (game.vm_active_country === 'Romania') {game.selected_space = 61} if (game.vm_active_country === 'Bulgaria') {game.selected_space = 68} game.state = 'vm_kremlin_coup_sc_prep' }, done() { if (game.vm_active_country === 'East_Germany') {game.selected_space = 3 } if (game.vm_active_country === 'Poland') {game.selected_space = 17} if (game.vm_active_country === 'Czechoslovakia') {game.selected_space = 29} if (game.vm_active_country === 'Hungary') {game.selected_space = 45} if (game.vm_active_country === 'Romania') {game.selected_space = 61} if (game.vm_active_country === 'Bulgaria') {game.selected_space = 68} game.state = 'vm_kremlin_coup_sc_prep' } } states.vm_kremlin_coup_sc_prep = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = `Kremlin Coup! Conduct a support check in ${country_name(game.vm_active_country)}'s Bureaucratic space.` gen_action_sc(game.selected_space); }, sc(space) { //game.selected_space = space game.state = 'vm_kremlin_coup_sc' } } states.vm_kremlin_coup_sc = { inactive: 'do support checks', prompt () { view.prompt = `Support check: ${spaces[game.selected_space].name_unique}. Roll a die.` gen_action('roll') }, roll() { clear_undo() do_sc(game.selected_space) if (game.temp.length > 0 ){ game.state = 'vm_kremlin_coup_choose_country' } else { game.state = 'vm_kremlin_coup_end' } } } states.vm_kremlin_coup_end = { get inactive() { return `resolve ${clean_name(cards[this_card()].name)}.` }, prompt() { view.prompt = `${clean_name(cards[this_card()].name)} Support checks: done.` gen_action('done') }, done() { vm_next() } } states.vm_laszlo_tokes = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = `Laszlo Tokes. Choose to:` gen_action('influence') gen_action('support_check') }, influence(){ push_undo() game.vm_available_ops = get_card_ops(73) valid_spaces_infl() game.valid_spaces = game.valid_spaces.filter(space_id => spaces[space_id].country === 'Romania') game.phase = 3 vm_next() //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') vm_next() } } states.vm_switch_infl = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.valid_spaces.length === 0) { view.prompt = `${clean_name(cards[this_card()].name)}: No SPs to remove.` gen_action('pass') } else { /*if (game.vm_available_ops > 0 ) {*/ view.prompt = `${clean_name(cards[game.played_card].name)}: ${event_prompt()}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } /*else { view.prompt = 'Influence replaced.' gen_action('done') }*/ }, infl(space) { push_undo() vm_switch_infl(space) if (game.vm_available_ops === 0) { game.valid_spaces = [] } vm_next() }, pass() { vm_next() } /*done() { vm_next() }*/ } states.vm_malta_summit = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { /*if (game.phase === 1) {*/ view.prompt = 'Malta Summit: 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(`Roll: D${roll}`) if (game.stability > 0) { log(`+${game.stability} from USSR Stability Track`) log(`Modified roll: ${roll + game.stability}`) } if (roll + game.stability > 3) { log('Summit successful') game.vp += 3 log('+3 VP') if (check_vp()) { return } if (game.comInfl[12] > 0 ) {game.valid_spaces.push(12)} if (game.comInfl[15] > 0 ) {game.valid_spaces.push(15)} if (game.comInfl[27] > 0 ) {game.valid_spaces.push(27)} if (game.comInfl[43] > 0 ) {game.valid_spaces.push(43)} if (game.comInfl[51] > 0 ) {game.valid_spaces.push(51)} if (game.comInfl[69] > 0 ) {game.valid_spaces.push(69)} //game.vm_available_ops = 5 game.remove_opponent_infl = true vm_next() } else { log('Summit failed. Required 4 or more') //game.phase++ vm_goto_step(vm_permanently_remove) } }, /*done() { vm_next() }*/ } states.vm_modrow = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = `Modrow: 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' && check_dem_control(space.space_id)).length if (roll > dem_spaces) { log(`Roll: D${roll}`) log(`Success. More than the ${dem_spaces} Democratically controlled spaces`) vm_next() } else { log(`Roll: D${roll}`) log(`Fail. More than ${dem_spaces} required`) permanently_remove(83) vm_return() } } } states.vm_nepotism = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { //if (game.phase === 1 ) { view.prompt = 'Nepotism: 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(`Roll: D${roll} adds 4 SPs`) game.vm_available_ops = 4} else if (roll < 5 ) { log(`Roll: D${roll} adds 3 SPs`) game.vm_available_ops = 3} else { log(`Roll: D${roll} adds 1 SP`) game.vm_available_ops = 1} //game.phase = 2 vm_next() }, /*done() { vm_next() }*/ } states.vm_new_years_eve_party = { get inactive() { return `resolve ${clean_name(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.push(104) log('Chooses to end the game. There will be no final scoring') let power = 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 } if (check_vp()) { return } //game.table_cards.push(104) permanently_remove(104) vm_next() }, continue() { log('Chooses to continue') permanently_remove(104) vm_next() } } states.vm_nomenklatura = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = 'Nomenklatura: choose to remove all Democratic SPs from Elite spaces or add 3 SPs to any Elite space(s).' gen_action('remove') gen_action('add') }, remove() { push_undo() game.valid_spaces = [] for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (space.socio === 1 && game.demInfl[i] > 0) { game.valid_spaces.push(space.space_id) } } game.vm_available_ops = game.valid_spaces.length game.remove_opponent_infl = true 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 ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.vm_available_ops === 0 || game.valid_spaces.length === 0 ) { view.prompt = 'Nomenklatura. Remove SPs: done.' gen_action('done') } else { view.prompt = 'Nomenklatura: remove all Democratic SPs from Elite spaces.' for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } }, infl(space) { push_undo() vm_do_remove_all_infl(space) /*if (game.vm_available_ops === 0) { vm_next() }*/ }, done() { vm_next() } } states.vm_nomenklatura_add = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.vm_available_ops === 0 || game.valid_spaces.length === 0 ) { view.prompt = 'Nomenklatura. Add SPs: done.' gen_action('done') } else { view.prompt = `Nomenklatura: add 3 SPs to any Elite space(s). ${pluralize(game.vm_available_ops, 'SP')} remaining.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } }, infl(space) { push_undo() vm_do_add_infl_free(space) if (game.vm_available_ops === 0 ) {game.valid_spaces = []} }, done() { if (game.summary.length > 0) { pop_summary() log_br() } vm_next() } } states.vm_samizdat = { get inactive() { return `resolve ${clean_name(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('pass') }, card(card) { push_undo() game.samizdat_card = card game.democrat_hand = game.democrat_hand.filter(c => c !== card) log('Set aside a card') game.state = 'vm_samizdat_finish' }, pass() { //if (game.samizdat_card > 0) {game.state = 'vm_samizdat_finish'} /*else { */ log('Did not set aside a card') vm_next() //} } } states.vm_samizdat_finish = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { /*if (game.phase ) { 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)) vm_next() //game.phase ++ }, /*done() { vm_next() }*/ } states.vm_shock_therapy = { get inactive() { return `resolve ${clean_name(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[0]) {gen_action('poland')} if (game.revolutions[1]) {gen_action('hungary')} if (game.revolutions[2]) {gen_action('east_germany')} if (game.revolutions[3]) {gen_action('bulgaria')} if (game.revolutions[4]) {gen_action('czechoslovakia')} if (game.revolutions[5]) {gen_action('romania')} } else if (game.phase === 2) { view.prompt = 'Shock Therapy: done.' gen_action('done') } else { view.prompt = 'Shock Therapy: roll a die.' gen_action('roll') } }, east_germany() { push_undo() game.vm_active_country = 'East_Germany' log(`Chose ${country_name(game.vm_active_country)}`) }, poland() { push_undo() game.vm_active_country = 'Poland' log(`Chose ${country_name(game.vm_active_country)}`) }, czechoslovakia() { push_undo() game.vm_active_country = 'Czechoslovakia' log(`Chose ${country_name(game.vm_active_country)}`) }, hungary() { push_undo() game.vm_active_country = 'Hungary' log(`Chose ${country_name(game.vm_active_country)}`) }, romania() { push_undo() game.vm_active_country = 'Romania' log(`Chose ${country_name(game.vm_active_country)}`) }, bulgaria () { push_undo() game.vm_active_country = 'Bulgaria' log(`Chose ${country_name(game.vm_active_country)}`) }, roll() { clear_undo() let roll = Math.floor(Math.random() * 6) + 1 let worker_farmer = 0 for (let space of spaces) { if (space && space.country === game.vm_active_country && check_com_control(space.space_id) && (space.socio === 3 || space.socio === 4)) { worker_farmer++ } } log(`Roll: D${roll}`) log(`-${worker_farmer} from Communist controlled Worker and Farmer spaces`) log(`Modified roll: ${roll - worker_farmer}`) if ((roll - worker_farmer) > 2) { log('C93 is successful. +3 VP') vm_next() } else { log('C93 is unsuccessful. Required 3 or more') game.phase++ } }, done() { permanently_remove(93) vm_return() } } states.vm_social_democratic_platform_adopted = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = 'Select a country where the Democrat holds Power.' if (game.revolutions[0]) {gen_action('poland')} if (game.revolutions[1]) {gen_action('hungary')} if (game.revolutions[2]) {gen_action('east_germany')} if (game.revolutions[3]) {gen_action('bulgaria')} if (game.revolutions[4]) {gen_action('czechoslovakia')} if (game.revolutions[5]) {gen_action('romania')} }, east_germany() { push_undo() game.vm_active_country = 'East_Germany' log(`Selected ${country_name(game.vm_active_country)}`) vm_next() }, poland() { push_undo() game.vm_active_country = 'Poland' log(`Selected ${country_name(game.vm_active_country)}`) vm_next()}, czechoslovakia() { push_undo() game.vm_active_country = 'Czechoslovakia' log(`Selected ${country_name(game.vm_active_country)}`) vm_next()}, hungary() { push_undo() game.vm_active_country = 'Hungary' log(`Selected ${country_name(game.vm_active_country)}`) vm_next() }, romania() { push_undo() game.vm_active_country = 'Romania' log(`Selected ${country_name(game.vm_active_country)}`) vm_next() }, bulgaria () { push_undo() game.vm_active_country = 'Bulgaria' log(`Selected ${country_name(game.vm_active_country)}`) vm_next()} } states.vm_systematization = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { /*if (game.systematization === 0) { */ view.prompt = 'Systematization: eliminate a space in Romania.' for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } /*} else { view.prompt = 'Systematization: done.' gen_action('done') }*/ }, infl(space) { push_undo() vm_eliminate(space) game.valid_spaces = [] game.systematization = space game.persistent_events.push(69) vm_next() }, /* done() { vm_next() } */ } states.vm_the_chinese_solution = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = 'The Chinese Solution: you may give up 3 VP to conduct support checks in a country where you hold power.' if (!game.revolutions[0]) {gen_action('poland')} if (!game.revolutions[1]) {gen_action('hungary')} if (!game.revolutions[2]) {gen_action('east_germany')} if (!game.revolutions[3]) {gen_action('bulgaria')} if (!game.revolutions[4]) {gen_action('czechoslovakia')} if (!game.revolutions[5]) {gen_action('romania')} gen_action('pass') }, east_germany() { push_undo() game.vm_active_country = 'East_Germany' log(`Chose ${country_name(game.vm_active_country)}`) log('+3 VP') game.vp += 3 if (check_vp()) { return } vm_next() }, poland() { push_undo() game.vm_active_country = 'Poland' log(`Chose ${country_name(game.vm_active_country)}`) log('+3 VP') game.vp += 3 if (check_vp()) { return } vm_next() }, czechoslovakia() { push_undo() game.vm_active_country = 'Czechoslovakia' log(`Chose ${country_name(game.vm_active_country)}`) log('+3 VP') game.vp += 3 if (check_vp()) { return } vm_next() }, hungary() { push_undo() game.vm_active_country = 'Hungary' log(`Chose ${country_name(game.vm_active_country)}`) log('+3 VP') game.vp += 3 if (check_vp()) { return } vm_next() }, romania() { push_undo() game.vm_active_country = 'Romania' log(`Chose ${country_name(game.vm_active_country)}`) log('+3 VP') game.vp += 3 if (check_vp()) { return } vm_next() }, bulgaria () { push_undo() game.vm_active_country = 'Bulgaria' log(`Chose ${country_name(game.vm_active_country)}`) log('+3 VP') game.vp += 3 if (check_vp()) { return } vm_next() }, pass() { permanently_remove(96) vm_return() } } states.vm_the_tyrant_is_gone = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (!game.the_tyrant_is_gone) { view.prompt = 'The Tyrant is Gone: Select a space in Romania for the Ceausescus to flee to.' for (let space_id of game.valid_spaces) { if (!space_id) continue gen_action_infl(space_id); } } else { view.prompt = 'Select a space: done.' gen_action('done') } }, infl(space) { push_undo() log(`The Ceausescus flee to %${space}`) game.the_tyrant_is_gone = space game.valid_spaces = [] game.persistent_events.push(97) }, done () { vm_next() } } states.vm_tyrant_block ={ get inactive() { return `resolve ${clean_name(cards[this_card()].name)}.` }, prompt() { view.prompt = `${clean_name(cards[this_card()].name)} has no effect after The Tyrant Has Gone.` gen_action('done') }, done() { push_undo() vm_next() } } states.vm_the_wall_must_go = { get inactive() { return `resolve ${clean_name(cards[this_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!" Rolls: done.' gen_action('done') } else { view.prompt = ('The Wall Must Go! Roll a die.') gen_action('roll') } }, roll() { clear_undo() let attempt = game.the_wall_must_go['dem_wins'] + game.the_wall_must_go['com_wins'] if (game.the_wall_must_go['dem_roll'] === 0 && game.the_wall_must_go['com_roll'] === 0) { log_h3(`Round ${attempt+1}`) } let roll = Math.floor(Math.random() * 6) + 1 log(`Roll: D${roll}`) if (game.active === DEM) { let controlled_spaces = spaces.filter(space => space && space.country === 'East_Germany' && check_dem_control(space.space_id)).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' && check_com_control(space.space_id)).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']++ } 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 C86') return } if (game.the_wall_must_go['com_wins'] === 2) { log('The Communist wins C86') return } if (game.the_wall_must_go['dem_roll'] === 0 || game.the_wall_must_go['com_roll'] === 0) { next_player() } else { game.the_wall_must_go['dem_roll'] = 0 game.the_wall_must_go['com_roll'] = 0 } }, done() { if (game.the_wall_must_go['dem_wins'] === 2) { game.persistent_events.push(86) log('+3 VP') game.vp += 3 if (check_vp()) { return } for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (space.country === 'East_Germany' && game.comInfl[i] > 0){ game.valid_spaces.push(space.space_id) } } if (!game.vm_infl_to_do) { if (game.round_player === DEM) { game.return = COM } else { game.return = DEM } } if (game.active === DEM) {next_player()} vm_next () } else { permanently_remove(86) delete game.the_wall_must_go vm_return() } } } states.vm_warsaw_pact_summit = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { view.prompt = 'Choose to play for support checks or place SPs.' gen_action('influence') gen_action('support_check') }, influence(){ push_undo() for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (game.demInfl[i] === 0) { game.valid_spaces.push(space.space_id); } } game.vm_available_ops = 4 game.phase = 3 //game.state = 'vm_add_infl' vm_next() }, support_check(){ push_undo() for (let i = 1; i < spaces.length; i++) { let space = spaces[i] if (game.demInfl[i] > 0 && (space.socio === 5 || space.socio === 6)) { game.valid_spaces.push(space.space_id) } } game.vm_available_ops = 2 //game.state = 'vm_support_check_prep' console.log('game.phase',game.phase) vm_next() } } states.vm_we_are_the_people_remove = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.demInfl[6] === 0 && game.vm_available_ops > 0) { view.prompt = '"We are the People!": no SPs to remove.' gen_action('done') } else if (game.vm_available_ops > 0 ) { view.prompt = '"We are the People!": remove up to 4 SPs from the Lutherian Church.' gen_action('done') for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } } else { view.prompt = '"We are the People!" Remove SPs: done.' gen_action('done') } }, infl(space) { vm_do_remove_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } if (!game.vm_influence_added[6]) { log('No SPs removed') 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 ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (!game.vm_influence_added[6]) { view.prompt = '"We are the People!" Add SPs: done.' gen_action('done') return } view.prompt = `"We are the People!": you must add the ${pluralize(game.vm_influence_added[6],'SP')} to spaces in Germany.` gen_action('done') for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } }, infl(space) { vm_do_add_infl_free(space) game.vm_influence_added[6]-- if (game.vm_influence_added[6] === 0 ) {game.valid_spaces = []} }, done() { if (game.summary.length > 0) { pop_summary() log_br() } vm_next() } } states.vm_workers_revolt = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.valid_spaces.length === 0 ) { view.prompt = 'Workers Revolt: no valid spaces to select.' gen_action('pass') return } view.prompt = 'Workers Revolt: select a Worker Space in a country your opponent has power.' for (let space_id of game.valid_spaces) { gen_action_infl(space_id) } }, pass() { push_undo() vm_next() }, infl(space) { game.selected_space = space log(`Chose %${game.selected_space}`) game.state = 'vm_workers_revolt_finish' } } states.vm_workers_revolt_finish = { get inactive() { return `resolve ${clean_name(cards[game.played_card].name)}.` }, prompt() { if (game.selected_space > 0) { view.prompt = `Target: ${spaces[game.selected_space].name_unique}. 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(`Roll: D${roll}`) let adj = count_adj(game.selected_space) 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 } log(`Modified roll: ${roll}`) if (roll >= 4) { log('Workers Revolt successful') vm_replace_all_infl(game.temp) } else {log('Workers Revolt fails. Required 4 or more')} game.selected_space = 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 SPs', prompt () { if (game.vm_available_ops === 0 || game.valid_spaces.length === 0) { view.prompt = 'Tiananmen Square Track award. Remove SPs: done.' gen_action('done') return } view.prompt = `Tiananmen Square Track award: remove ${pluralize(game.vm_available_ops,'SP')}.` for (let space_id of game.valid_spaces) { gen_action_infl(space_id); } }, infl(space) { vm_do_remove_infl(space) }, done() { if (game.summary.length > 0) { pop_summary() log_br() } 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 Ops support check.' for (let space_id of game.valid_spaces) { if (space_id) { gen_action_sc(space_id); } } } }, sc(space) { push_undo() game.selected_space = space if (game.active === DEM && game.persistent_events.includes(58) && spaces[space].country === "East_Germany") { game.austria_hungary_border_reopened_tracker = true } game.state = 'vm_tst_6_sc' }, done () { vm_next() } } states.vm_tst_6_sc = { inactive: 'do support check.', prompt () { view.prompt = `Support check: ${spaces[game.selected_space].name_unique}. Roll a die` gen_action('roll') }, roll() { clear_undo() do_sc(game.selected_space) game.vm_available_ops-- game.valid_spaces = [] 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() { push_undo() game.vm_event_to_do = false game.return_state = 'vm_tst_8' game.return = game.active game.vm_event = game.played_card goto_vm(game.vm_event) }, ops() { push_undo() 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 ${clean_name(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() // If ABHR - Set AHBR tracker to true if (game.persistent_events.includes(58)) { game.austria_hungary_border_reopened_tracker = true } 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_1 = { inactive: 'draw cards.', prompt() { view.prompt = 'Support Surges: draw a card.' gen_action('draw') }, draw() { if (game.active === DEM) { console.log('hand before', game.dem_pwr_hand) draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand.length+1, game.com_pwr_hand.length) game.temp = game.dem_pwr_hand[game.dem_pwr_hand.length-1] console.log('hand before', game.dem_pwr_hand, 'game.temp', game.temp) } 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+1) game.temp = game.dem_pwr_hand[game.dem_pwr_hand.length-1] } game.state = 'vm_support_surges_2' //game.phase = 0 //log('Drew 2 cards') //log('Surrenders initiative') //vm_next() } } states.vm_support_surges_2 = { inactive: 'draw cards.', prompt() { if (numberless_cards.includes(game.temp)) { view.prompt = `Support Surges: you drew a ${power_cards[game.temp].name}. Draw a second card.` } else { view.prompt = `Support Surges: you drew a ${power_cards[game.temp].name} ${power_cards[game.temp].value}. Draw a second card.` } gen_action('draw') }, draw() { if (game.active === DEM) { console.log('hand before', game.dem_pwr_hand) draw_cards(game.power_struggle_deck, game.dem_pwr_hand, game.com_pwr_hand, game.dem_pwr_hand.length+1, game.com_pwr_hand.length) game.temp = game.dem_pwr_hand[game.dem_pwr_hand.length - 1] console.log('hand before', game.dem_pwr_hand, 'game.temp', game.temp) } 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+1) game.temp = game.dem_pwr_hand[game.dem_pwr_hand.length - 1] } game.state = 'vm_support_surges_3' /*game.phase = 0 log('Drew 2 cards') log('Surrenders initiative') vm_next()*/ } } states.vm_support_surges_3 = { inactive: 'draw cards.', prompt() { if (numberless_cards.includes(game.temp)) { view.prompt = `Support Surges: you drew a ${power_cards[game.temp].name}. Done.` } else { view.prompt = `Support Surges: you drew a ${power_cards[game.temp].name} ${power_cards[game.temp].value}. Done.` } gen_action('done') }, done() { game.phase = 0 delete game.temp log('Drew 2 cards') log('Surrenders initiative') vm_next() } } states.vm_support_falters = { inactive: 'discard cards.', prompt() { if ((game.active === DEM && game.dem_pwr_hand.length === 0) || (game.active === COM && game.com_pwr_hand.length === 0)) { view.prompt = 'Support Falters: no remaining cards to discard.' gen_action('pass') } else if (game.vm_available_ops > 0) { view.prompt = 'Support Falters: discard a card.' gen_action('discard') } else { view.prompt = 'Support Falters: 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 -- }, pass() { log_msg_gap('Takes initiative') game.return = game.active vm_next() }, done() { log_msg_gap('Takes initiative') game.return = game.active vm_next() } } /* =================== EVENTS ================================ */ // #region GENERATED EVENT CODE const CODE = [] CODE[1] = [ // Legacy of Martial Law* [ vm_permanently_remove ], [ vm_valid_spaces_country_opp, 'Poland' ], [ vm_prompt, 'replace 1 Democratic SP in Poland with a Communist SP' ], [ vm_legacy_of_martial_law ], [ vm_valid_spaces_country_sc, 'Poland' ], [ vm_prompt, 'make a Support Check in Poland' ], [ vm_1_support_check ], [ vm_return ], ] CODE[2] = [ // Solidarity Legalised* [ vm_permanently_remove ], [ vm_solidarity_legalised ], [ vm_valid_spaces_solidarity_legalised ], [ vm_prompt, 'to every uncontrolled Worker and Farmer space in Poland' ], [ vm_add_limited_infl, 9, 1 ], [ vm_return ], ] CODE[3] = [ // Walesa [ vm_permanently_remove ], [ vm_valid_spaces_country, 'Poland' ], [ vm_prompt, 'any space(s) in Poland' ], [ vm_add_infl_free, 4 ], [ vm_valid_spaces_country_sc, 'Poland' ], [ vm_prompt, 'make Support Checks in Poland' ], [ vm_support_check, 2 ], [ vm_return ], ] CODE[4] = [ // Michnik [ vm_permanently_remove ], [ vm_valid_spaces, 26 ], [ vm_prompt, 'the Polish Intellectuals space' ], [ vm_add_x_infl, 3 ], [ 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_permanently_remove ], [ vm_valid_spaces_opponent ], [ vm_remove_limited_opp_infl, 4, 2 ], [ vm_return ], ] CODE[8] = [ // Prudence [ vm_prudence ], [ vm_return ], ] CODE[9] = [ // The Wall* [ vm_permanently_remove ], [ vm_the_wall ], [ vm_return ], ] CODE[10] = [ // Cult of Personality [ vm_permanently_remove ], [ vm_if, ()=>!game.the_tyrant_is_gone ], [ vm_valid_spaces_country_socio_2, 'Romania', 3, 4 ], [ vm_prompt, 'Worker or Farmer spaces in Romania, no more than 2 per space' ], [ vm_add_limited_infl, 4, 2 ], [ vm_else ], [ vm_tyrant_block ], [ vm_endif ], [ vm_return ], ] CODE[11] = [ // Dissident arrested [ vm_valid_spaces_opponent_socio, 5 ], [ vm_prompt, 'any Intellectuals space' ], [ vm_remove_x_opp_infl, 2 ], [ vm_return ], ] CODE[12] = [ // Apparatchicks [ vm_permanently_remove ], [ vm_valid_spaces_socio, 2 ], [ vm_prompt, ' to any Bureaucratic space(s)' ], [ vm_add_infl_free, 3 ], [ vm_return ], ] CODE[13] = [ // Stasi [ vm_permanently_remove ], [ vm_stasi ], [ vm_return ], ] CODE[14] = [ // Gorbachev Charms the West [ vm_valid_spaces_opponent ], [ vm_remove_opp_infl, 2 ], [ vm_valid_spaces_sc ], [ vm_prompt, 'select a space for the Support Check' ], [ vm_1_support_check ], [ vm_return ], ] CODE[15] = [ // Honecker [ vm_permanently_remove ], [ vm_honecker ], [ vm_return ], ] CODE[16] = [ // Nomenklatura* [ vm_permanently_remove ], [ vm_nomenklatura ], [ vm_return ], ] CODE[17] = [ // Roundtable talks [ vm_roundtable_talks ], [ vm_return ], ] CODE[18] = [ // Poszgay Defends the Revolution [ vm_permanently_remove ], [ vm_poszgay ], [ vm_prompt, 'to 4 spaces in Hungary not under Democratic control' ], [ vm_add_limited_infl, 4, 1 ], [ vm_return ], ] CODE[19] = [ // Papal vist [ vm_permanently_remove ], [ vm_valid_spaces, 20, 35, 38 ], [ vm_prompt, 'any Catholic Church space' ], [ vm_add_x_infl, 3 ], [ vm_return ], ] CODE[20] = [ // Deutsche Marks* [ vm_permanently_remove ], [ vm_deutsche_marks ], [ 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_permanently_remove ], [ vm_valid_spaces, 6 ], [ vm_prompt, 'the Lutheran Church' ], [ vm_take_control_prep, 1 ], [ vm_st_nicholas_church ], [ vm_return ], ] CODE[25] = [ // Perestroika [ vm_permanently_remove ], [ vm_perestroika ], [ vm_return ], ] CODE[26] = [ // Helsinki Final Act* [ vm_permanently_remove ], [ vm_helsinki_final_act ], [ vm_return ], ] CODE[27] = [ // Consumerism [ vm_valid_spaces_opponent_socio, 4 ], [ vm_prompt, ' from a Worker space' ], [ vm_remove_opp_infl, 1 ], [ vm_valid_spaces_opponent_socio, 4 ], [ vm_active_country ], [ vm_prompt, ()=>`make a support check in a Worker space in ${country_name(game.vm_active_country)}` ], [ vm_1_support_check ], [ vm_return ], ] CODE[28] = [ // Factory Party Cells [ vm_valid_spaces_opponent_socio, 4 ], [ vm_prompt, ' from Worker spaces' ], [ vm_remove_limited_opp_infl, 3, 2 ], [ vm_return ], ] CODE[29] = [ // Jan Palach Week* [ vm_permanently_remove ], [ vm_valid_spaces, 30 ], [ vm_prompt, 'the Charles University space' ], [ vm_add_x_infl, 6 ], [ vm_return ], ] CODE[30] = [ // Tear Gas [ vm_tear_gas ], [ vm_return ], ] CODE[31] = [ // Intelligentsia [ vm_valid_spaces, 4, 26, 31, 46, 55, 73 ], [ vm_prompt, 'Intellectual spaces, no more than 2 per space' ], [ vm_add_limited_infl, 4, 2 ], [ vm_return ], ] CODE[32] = [ // Peasant Parties* [ vm_permanently_remove ], [ vm_valid_spaces_socio, 3 ], [ vm_prompt, 'Farmer spaces, no more than 2 per space' ], [ vm_add_limited_infl, 4, 2 ], [ vm_return ], ] CODE[33] = [ // Sajudis* [ vm_permanently_remove ], [ vm_sajudis_check ], [ vm_prompt, 'any Minorities space' ], [ vm_take_control_prep, 1 ], [ vm_sajudis ], [ vm_return ], ] CODE[34] = [ // Fidesz* [ vm_permanently_remove ], [ vm_valid_spaces, 47 ], [ vm_prompt, 'the Hungary students space' ], [ vm_add_x_infl, 5 ], [ vm_return ], ] CODE[35] = [ // Heal our Bleeding Wounds* [ vm_permanently_remove ], [ vm_heal_our_bleeding_wounds ], [ vm_return ], ] CODE[36] = [ // Dash for the West* [ vm_permanently_remove ], [ vm_prompt, 'Dash for the West: select any Democratic event with an asterix(*) from the discard pile. Event occurs immediately' ], [ vm_dash_for_the_west ], [ vm_return ], ] CODE[37] = [ // Nagy Reburied* [ vm_permanently_remove ], [ vm_nagy_reburied ], [ vm_prompt, 'the Hungary Elite space' ], [ vm_remove_all_infl, 1 ], [ vm_valid_spaces_country, 'Hungary' ], [ vm_prompt, 'Hungary, no more than 2 per space' ], [ vm_add_limited_infl, 4, 2 ], [ vm_return ], ] CODE[38] = [ // July Concept [ vm_permanently_remove ], [ vm_valid_spaces_country, 'Bulgaria' ], [ vm_prompt, 'Bulgaria' ], [ vm_add_infl_free, 3 ], [ vm_return ], ] CODE[39] = [ // Eco-Glasnost* [ vm_permanently_remove ], [ vm_valid_spaces, 66 ], [ vm_prompt, 'Ruse' ], [ vm_add_x_infl, 4 ], [ vm_eco_glasnost ], [ vm_return ], ] CODE[40] = [ // Hungarian Democratic Forum [ vm_permanently_remove ], [ vm_valid_spaces_country, 'Hungary' ], [ vm_prompt, 'Hungary' ], [ vm_add_infl_free, 3 ], [ vm_valid_spaces_country_sc, 'Hungary' ], [ vm_prompt, 'make a Support Check in Hungary' ], [ vm_1_support_check ], [ vm_return ], ] CODE[41] = [ // Ceausescu* [ vm_permanently_remove ], [ vm_if, ()=>!game.the_tyrant_is_gone ], [ vm_valid_spaces_country_opp, 'Romania' ], [ vm_prompt, ' from Romania' ], [ vm_remove_opp_infl, 3 ], [ vm_valid_spaces_country_sc, 'Romania' ], [ vm_prompt, 'make a support check in Romania' ], [ vm_1_support_check ], [ vm_prompt, ' from Bucharesti' ], [ vm_ceausescu ], [ vm_else ], [ vm_tyrant_block ], [ vm_endif ], [ 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_permanently_remove ], [ vm_inflationary_currency ], [ vm_valid_spaces_country_opp ], [ vm_prompt, ()=>` from ${country_name(game.vm_active_country)}` ], [ vm_remove_opp_infl, 2 ], [ vm_inflationary_currency_discard ], [ vm_if, ()=>!discarded_card() ], [ vm_valid_spaces_country_sc ], [ vm_prompt, ()=>`make a Support Check in ${country_name(game.vm_active_country)}` ], [ vm_1_support_check ], [ vm_endif ], [ vm_return ], ] CODE[45] = [ // Soviet Troop Withdrawals* [ vm_permanently_remove ], [ vm_valid_spaces_region_opp, 'Eastern Europe' ], [ vm_prompt, ' from Eastern Europe' ], [ vm_remove_limited_opp_infl, 5, 2 ], [ vm_return ], ] CODE[46] = [ // Goodbye Lenin!* [ vm_permanently_remove ], [ vm_goodbye_lenin ], [ vm_return ], ] CODE[47] = [ // Bulgarian Turks Expelled* [ vm_permanently_remove ], [ vm_bulgarian_turks_expelled ], [ vm_prompt, 'Razgrad' ], [ vm_remove_all_infl, 1 ], [ vm_return ], ] CODE[48] = [ // We are the People!* [ vm_permanently_remove ], [ vm_we_are_the_people ], [ vm_return ], ] CODE[49] = [ // Foreign Currency Debt Burden* [ vm_permanently_remove ], [ vm_foreign_currency_debt_burden ], [ vm_return ], ] CODE[50] = [ // The Sinatra Doctrine* [ vm_permanently_remove ], [ vm_the_sinatra_doctrine ], [ vm_return ], ] CODE[51] = [ // 40th Anniversary Celebration* [ vm_permanently_remove ], [ vm_40th_anniversary_celebration ], [ vm_valid_spaces_country, 'East_Germany' ], [ vm_prompt, 'East Germany' ], [ vm_add_infl_free ], [ vm_40th_anniversary_celebration_vp ], [ vm_return ], ] CODE[52] = [ // Normalisation [ vm_permanently_remove ], [ vm_normalisation ], [ vm_prompt, 'the Czechoslovakia Elite and Bureaucrat Spaces' ], [ vm_remove_all_infl, 2 ], [ vm_return ], ] CODE[53] = [ // Li Peng* [ vm_permanently_remove ], [ 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_permanently_remove ], [ vm_foreign_television ], [ vm_remove_limited_opp_infl, 4, 2 ], [ vm_return ], ] CODE[57] = [ // Central Committee Reshuffle* [ vm_permanently_remove ], [ vm_central_committee_reshuffle ], [ vm_prompt, ()=>`${country_name(game.vm_active_country)}` ], [ vm_add_infl_free, 3 ], [ 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_permanently_remove ], [ vm_valid_spaces_socio, 4 ], [ vm_prompt, 'any Worker space(s)' ], [ vm_add_infl_free, 3 ], [ vm_return ], ] CODE[61] = [ // The Monday Demonstrations* [ vm_permanently_remove ], [ vm_the_monday_demonstrations ], [ vm_prompt, 'the Lutheran Church Space and Leipzig' ], [ vm_take_control_prep, 2 ], [ vm_valid_spaces_country_sc, 'East_Germany' ], [ vm_prompt, 'make 5 Support Checks in East Germany' ], [ vm_support_check, 5 ], [ 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_permanently_remove ], [ vm_legacy_of_1968 ], [ vm_prompt, 'all spaces in Czechoslovakia not controlled by the Communist Player' ], [ vm_add_limited_infl, 11, 1 ], [ vm_return ], ] CODE[65] = [ // Presidential Visit* [ vm_permanently_remove ], [ vm_presidential_visit ], [ vm_return ], ] CODE[66] = [ // New Forum [ vm_permanently_remove ], [ vm_valid_spaces_country, 'East_Germany' ], [ vm_prompt, '3 spaces in East Germany' ], [ vm_add_limited_infl, 3, 1 ], [ vm_return ], ] CODE[67] = [ // Reformer Rehabilitated* [ vm_prompt, 'Reformer Rehabilitated: chose any non-scoring card in the discard pile. Event takes place immediately' ], [ vm_reformer_rehabilitated ], [ vm_return ], ] CODE[68] = [ // Klaus and Komarek* [ vm_permanently_remove ], [ vm_klaus_and_komarek ], [ vm_prompt, 'Prague' ], [ vm_remove_x_opp_infl, 2 ], [ vm_valid_spaces, 29 ], [ vm_add_x_infl, 2 ], [ vm_return ], ] CODE[69] = [ // Systematization* [ vm_permanently_remove ], [ vm_valid_spaces_country, 'Romania' ], [ vm_systematization ], [ 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_permanently_remove ], [ vm_valid_spaces, 50, 56 ], [ vm_prompt, 'in Timisoara and Harghita/Covasna' ], [ vm_add_limited_infl, 2, 1 ], [ vm_laszlo_tokes ], [ vm_if, ()=>game.phase === 3 ], [ vm_prompt, ' in Romania' ], [ vm_add_infl ], [ vm_else ], [ vm_prompt, 'make 2 Support Checks in Romania' ], [ vm_support_check, 2 ], [ vm_endif ], [ vm_return ], ] CODE[74] = [ // FRG Embassies [ vm_frg_embassies ], [ vm_return ], ] CODE[75] = [ // Exit Visas* [ vm_permanently_remove ], [ vm_exit_visas ], [ vm_return ], ] CODE[76] = [ // Warsaw Pact Summit [ vm_permanently_remove ], [ vm_warsaw_pact_summit ], [ vm_if, ()=>game.phase === 3 ], [ vm_prompt, ' spaces with no Democratic SPs' ], [ vm_add_infl_free, 4 ], [ vm_else ], [ vm_prompt, 'Select a Student or Intellectual space' ], [ vm_valid_spaces_country_socio_2, 3,, 4 ], [ vm_support_check_modified, 2, 2 ], [ vm_endif ], [ vm_return ], ] CODE[77] = [ // Samizdat [ vm_permanently_remove ], [ vm_samizdat ], [ vm_return ], ] CODE[78] = [ // Workers Revolt [ vm_workers_revolt ], [ vm_return ], ] CODE[79] = [ // The Third Way* [ vm_permanently_remove ], [ vm_the_third_way ], [ vm_valid_spaces, 4 ], [ vm_prompt, 'the East German Writers space' ], [ vm_add_x_infl, 3 ], [ vm_return ], ] CODE[80] = [ // Nepotism* [ vm_permanently_remove ], [ vm_nepotism ], [ vm_valid_spaces_region_socio, 'Balkans', 4 ], [ vm_prompt, 'Worker spaces in the Balkans' ], [ vm_add_infl_free ], [ vm_return ], ] CODE[81] = [ // The Baltic Way* [ vm_permanently_remove ], [ vm_the_baltic_way ], [ vm_prompt, 'any Minorities space' ], [ vm_take_control_prep, 1 ], [ vm_return ], ] CODE[82] = [ // Spitzel* [ vm_permanently_remove ], [ vm_valid_spaces_country_opp, 'East_Germany' ], [ vm_prompt, ' from East Germany' ], [ vm_remove_opp_infl, 2 ], [ vm_return ], ] CODE[83] = [ // Modrow* [ vm_permanently_remove ], [ vm_modrow ], [ vm_valid_spaces_country, 'East_Germany' ], [ vm_prompt, 'East Germany' ], [ vm_add_limited_infl, 4, 2 ], [ vm_return ], ] CODE[84] = [ // Breakaway Baltic Republics* [ vm_permanently_remove ], [ vm_breakaway_baltic_republics ], [ vm_prompt, 'any Minorities space' ], [ vm_take_control_prep, 1 ], [ vm_valid_spaces_sc ], [ vm_prompt, 'select a space for the support check' ], [ vm_1_support_check ], [ vm_return ], ] CODE[85] = [ // Tank Column/Tank Man* [ vm_permanently_remove ], [ vm_tank_column ], [ vm_return ], ] CODE[86] = [ // The Wall Must Go!* [ vm_permanently_remove ], [ vm_the_wall_must_go ], [ vm_remove_infl, 3 ], [ vm_return ], ] CODE[87] = [ // Kohl Proposes Reunification* [ vm_permanently_remove ], [ vm_kohl_proposes_reunification ], [ vm_return ], ] CODE[88] = [ // Adamec* [ vm_permanently_remove ], [ vm_adamec ], [ vm_valid_spaces_country, 'Czechoslovakia' ], [ vm_prompt, 'Czechoslovakia' ], [ vm_add_limited_infl, 4, 2 ], [ vm_return ], ] CODE[89] = [ // Domino Theory* [ vm_prompt, 'Domino Theory: choose a Power Struggle card to play from the discard pile' ], [ vm_permanently_remove ], [ vm_domino_theory ], [ vm_return ], ] CODE[90] = [ // Civic Forum* [ vm_permanently_remove ], [ vm_valid_spaces_country, 'Czechoslovakia' ], [ vm_prompt, 'Czechoslovakia' ], [ vm_add_infl_free, 4 ], [ vm_civic_forum ], [ vm_valid_spaces_country_sc, 'Czechoslovakia' ], [ vm_prompt, 'Select a space in Czechoslovakia' ], [ vm_support_check, 2 ], [ vm_return ], ] CODE[91] = [ // My First Banana* [ vm_permanently_remove ], [ vm_valid_spaces_country_opp, 'East_Germany' ], [ vm_prompt, ' from East Germany' ], [ vm_remove_opp_infl, 2 ], [ vm_valid_spaces_country_sc, 'East_Germany' ], [ vm_prompt, 'select a space in East Germany' ], [ vm_support_check, 2 ], [ vm_return ], ] CODE[92] = [ // Betrayal [ vm_permanently_remove ], [ vm_prompt, 'choose any Orthodox Church space. Replace all Democratic SPs with Communist SPs' ], [ vm_betrayal ], [ vm_return ], ] CODE[93] = [ // Shock Therapy* [ vm_permanently_remove ], [ vm_shock_therapy ], [ vm_valid_spaces_country ], [ vm_prompt, ()=>` ${country_name(game.vm_active_country)}` ], [ vm_add_infl_free, 3 ], [ vm_return ], ] CODE[94] = [ // Union of Democratic Forces* [ vm_permanently_remove ], [ vm_valid_spaces_country_opp, 'Bulgaria' ], [ vm_prompt, ' from Bulgaria' ], [ vm_remove_opp_infl, 4 ], [ vm_valid_spaces_country_sc, 'Bulgaria' ], [ vm_prompt, 'Make 2 Support Checks in Bulgaria' ], [ vm_support_check, 2 ], [ vm_return ], ] CODE[95] = [ // Power Struggle - Romania [ vm_power_struggle ], [ vm_return ], ] CODE[96] = [ // The Chinese Solution* [ vm_permanently_remove ], [ vm_the_chinese_solution ], [ vm_valid_spaces_country_sc ], [ vm_prompt, ()=>`make 5 Support Checks in ${country_name(game.vm_active_country)}` ], [ vm_support_check_modified, 5, 3 ], [ vm_return ], ] CODE[97] = [ // The Tyrant is Gone* [ vm_if, ()=>game.persistent_events.includes(54) ], [ vm_valid_spaces, 51 ], [ vm_prompt, 'the Romanian Elite Space' ], [ vm_remove_x_opp_infl, 4 ], [ vm_the_tyrant_is_gone ], [ vm_permanently_remove ], [ vm_else ], [ vm_the_tyrant_is_gone_prep ], [ vm_endif ], [ vm_return ], ] CODE[98] = [ // Politburo Intrigue* [ vm_permanently_remove ], [ vm_valid_spaces_country_opp, 'Bulgaria' ], [ vm_prompt, ' from Bulgaria' ], [ vm_remove_limited_opp_infl, 3, 2 ], [ vm_valid_spaces_country_sc, 'Bulgaria' ], [ vm_prompt, 'make a support check in Bulgaria' ], [ vm_1_support_check ], [ vm_return ], ] CODE[99] = [ // Ligachev* [ vm_permanently_remove ], [ vm_ligachev ], [ vm_return ], ] CODE[100] = [ // Stand Fast* [ vm_permanently_remove ], [ vm_stand_fast ], [ vm_return ], ] CODE[101] = [ // Elena* [ vm_permanently_remove ], [ vm_if, ()=>!game.the_tyrant_is_gone ], [ vm_valid_spaces, 51 ], [ vm_prompt, 'the Romania Elite Space' ], [ vm_add_x_infl, 2 ], [ vm_elena ], [ vm_else ], [ vm_tyrant_block ], [ vm_endif ], [ vm_return ], ] CODE[102] = [ // National Salvation Front* [ vm_national_salvation_front ], [ vm_return ], ] CODE[103] = [ // Government Resigns* [ vm_government_resigns ], [ vm_prompt, 'any uncontrolled Elite space' ], [ 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_permanently_remove ], [ vm_valid_spaces, 36 ], [ vm_prompt, 'Kosice' ], [ vm_add_x_infl, 2 ], [ vm_valid_spaces, 37 ], [ vm_prompt, 'Presov' ], [ vm_add_x_infl, 2 ], [ vm_public_against_violence ], [ vm_prompt, 'Make a Support Check in Bratislava' ], [ vm_support_check_modified, 1, 2 ], [ vm_return ], ] CODE[106] = [ // Social Democratic Platform Adopted* [ vm_permanently_remove ], [ vm_social_democratic_platform_adopted ], [ vm_valid_spaces_country ], [ vm_prompt, ()=>`${country_name(game.vm_active_country)}` ], [ vm_add_infl_free, 2 ], [ vm_valid_spaces_country_sc ], [ vm_prompt, ()=>`make a Support Check in ${country_name(game.vm_active_country)}` ], [ vm_1_support_check ], [ vm_return ], ] CODE[107] = [ // Massacre in Timisoara* [ vm_permanently_remove ], [ vm_if, ()=>!game.the_tyrant_is_gone ], [ vm_massacre_in_timisoara ], [ vm_valid_spaces_country_sc, 'Romania' ], [ vm_prompt, 'Make Support Checks in Romania' ], [ vm_support_check_modified, 2, 2 ], [ vm_else ], [ vm_tyrant_block ], [ vm_endif ], [ vm_return ], ] CODE[108] = [ // Army Backs Revolution* [ vm_permanently_remove ], [ vm_army_backs_revolution ], [ vm_return ], ] CODE[109] = [ // Kremlin Coup* [ vm_permanently_remove ], [ vm_kremlin_coup ], [ vm_return ], ] CODE[110] = [ // Malta Summit* [ vm_permanently_remove ], [ vm_malta_summit ], [ vm_prompt, ' from Elite spaces' ], [ vm_remove_opp_infl, 5 ], [ vm_return ], ] // #endregion // ============= 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_opponent], [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_opp], [vm_prompt, ()=>` from ${country_name(game.vm_active_country)}`], [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] ]