From fa18a313b5a57b106a8c41a542f08ba4697435ca Mon Sep 17 00:00:00 2001 From: Frans Bongers Date: Sun, 22 Dec 2024 14:45:51 +0100 Subject: Add final bid and determine winner --- rules.js | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 255 insertions(+), 15 deletions(-) (limited to 'rules.js') diff --git a/rules.js b/rules.js index cc93228..bd1f473 100644 --- a/rules.js +++ b/rules.js @@ -118,6 +118,14 @@ function setup_choose_card() { game.engine.push(create_function_node('setup_player_turn')); next(); } +function setup_final_bid() { + log_h1('Final Bid'); + const player_order = get_player_order(); + game.engine = player_order.map((faction_id) => create_leaf_node('choose_final_bid', faction_id)); + game.engine.push(create_function_node('resolve_final_bid')); + game.engine.push(create_function_node('setup_choose_card')); + next(); +} function setup_player_turn() { const player_order = get_player_order(); game.engine = player_order.map((faction_id) => create_seq_node([ @@ -139,12 +147,14 @@ function start_of_player_turn() { const engine_functions = { check_activate_icon, end_of_turn, - end_of_year, setup_bag_of_glory, setup_choose_card, + setup_final_bid, setup_player_turn, start_of_player_turn, + start_year, resolve_fascist_test, + resolve_final_bid, }; function get_active(engine) { for (let i of engine) { @@ -227,6 +237,7 @@ function game_view(state, player) { bag_of_glory: game.bag_of_glory, bonuses: game.bonuses, current_events: game.current_events, + final_bid: game.final_bid[faction_id], fronts: game.fronts, glory: game.glory, hand: game.hands[faction_id], @@ -272,6 +283,11 @@ function setup(seed, _scenario, _options) { f: [], }, engine: [], + final_bid: { + [data_1.ANARCHISTS_ID]: [], + [data_1.COMMUNISTS_ID]: [], + [data_1.MODERATES_ID]: [], + }, fronts: { a: { value: -2, @@ -333,24 +349,34 @@ function setup(seed, _scenario, _options) { triggered_track_effects: [[], [], [], [], []], log: [], undo: [], - turn: 1, - year: 1, + turn: 0, + year: 0, state_data: null, }; start_year(); return game; } function draw_hand_cards(faction_id, count) { + const deck = list_deck(faction_id); + if (deck.length < count) { + count = count - deck.length; + game.hands[faction_id] = game.hands[faction_id].concat(deck); + game.discard[faction_id] = []; + } + console.log('draw_hand_cards', count); const log = count === 1 ? `${get_player(faction_id)} draws 1 card` : `${get_player(faction_id)} draws ${count} cards`; logi(log); + console.log('deck', list_deck(faction_id)); for (let i = 0; i < count; i++) { const deck = list_deck(faction_id); game.hands[faction_id].push(draw_card(deck)); } } function start_year() { + game.year++; + game.turn = 1; game.current_events = []; role_ids.forEach((role) => { draw_hand_cards(role, 5); @@ -365,10 +391,12 @@ function start_turn() { log_h2('Fascist Event', 'fascist'); log(card.title); game.engine = card.effects.map((effect) => resolve_effect(effect, game.initiative)); - game.engine.push({ - t: 'f', - f: 'setup_choose_card', - }); + if (game.year === 3 && game.turn === 1) { + game.engine.push(create_function_node('setup_final_bid')); + } + else { + game.engine.push(create_function_node('setup_choose_card')); + } next(); } states.activate_icon = { @@ -514,6 +542,53 @@ states.attack_front = { resolve_active_and_proceed(); }, }; +states.break_tie_final_bid = { + inactive: 'break tie for Final Bid', + prompt() { + view.prompt = 'Choose the winner of the Final Bid'; + const { winners } = get_active_node_args(); + for (const f of winners) { + gen_action(faction_player_map[f]); + } + }, + Anarchist() { + win_final_bid(data_1.ANARCHISTS_ID); + resolve_active_and_proceed(); + }, + Communist() { + win_final_bid(data_1.COMMUNISTS_ID); + resolve_active_and_proceed(); + }, + Moderate() { + win_final_bid(data_1.MODERATES_ID); + resolve_active_and_proceed(); + }, +}; +states.break_tie_winner = { + inactive: 'break tie for winner of the game', + prompt() { + view.prompt = 'Choose the winner of the game'; + const { winners } = get_active_node_args(); + for (const f of winners) { + gen_action(faction_player_map[f]); + } + }, + Anarchist() { + const { glory } = get_active_node_args(); + win_game(data_1.ANARCHIST, glory); + resolve_active_and_proceed(); + }, + Communist() { + const { glory } = get_active_node_args(); + win_game(data_1.COMMUNIST, glory); + resolve_active_and_proceed(); + }, + Moderate() { + const { glory } = get_active_node_args(); + win_game(data_1.MODERATE, glory); + resolve_active_and_proceed(); + }, +}; states.choose_area_ap = { inactive: 'choose area to use Action Points', prompt() { @@ -598,6 +673,68 @@ states.choose_card = { resolve_active_and_proceed(); }, }; +states.choose_final_bid = { + inactive: 'choose Final Bid', + prompt() { + view.prompt = 'Choose a card to add to the Final Bid'; + const faction = get_active_faction(); + for (let c of game.hands[faction]) { + if (!game.final_bid[faction].includes(c)) { + gen_action_card(c); + } + } + gen_action('done'); + }, + card(c) { + const faction = get_active_faction(); + game.final_bid[faction].push(c); + if (game.final_bid[faction].length < 3) { + next(); + } + else { + resolve_active_and_proceed(); + } + }, + done() { + resolve_active_and_proceed(); + }, +}; +states.end_of_year_discard = { + inactive: 'discard cards from hand and tableau', + prompt() { + view.prompt = 'Discard a card'; + const faction_id = get_active_faction(); + const hand = game.hands[faction_id]; + if (hand.length > game.year) { + for (let c of hand) + gen_action_card(c); + } + const tableau = game.tableaus[faction_id]; + if (tableau.length > game.year) { + for (let c of tableau) + gen_action_card(c); + } + }, + card(c) { + const faction_id = get_active_faction(); + console.log('list deck', list_deck(faction_id)); + if (game.hands[faction_id].includes(c)) { + game.hands[faction_id] = game.hands[faction_id].filter((id) => id !== c); + } + else if (game.tableaus[faction_id].includes(c)) { + game.tableaus[faction_id] = game.tableaus[faction_id].filter((id) => id !== c); + } + game.discard[faction_id].push(c); + if (game.hands[faction_id].length > game.year || + game.tableaus[faction_id].length > game.year) { + next(); + } + else { + log(`${faction_player_map[faction_id]} discards cards`); + resolve_active_and_proceed(); + } + }, +}; states.gain_hero_points = { inactive: 'gain Hero Points', prompt() { @@ -639,12 +776,12 @@ states.lose_hero_points = { }, Communist() { const value = get_active_node_args().v; - lose_hero_point(data_1.ANARCHISTS_ID, value); + lose_hero_point(data_1.COMMUNISTS_ID, value); resolve_active_and_proceed(); }, Moderate() { const value = get_active_node_args().v; - lose_hero_point(data_1.ANARCHISTS_ID, value); + lose_hero_point(data_1.MODERATES_ID, value); resolve_active_and_proceed(); }, }; @@ -843,6 +980,46 @@ function check_initiative() { game.initiative = initiative; logi(`${faction_player_map[initiative]} claims the Initiative`); } +function war_is_won() { + let won_fronts = 0; + for (const f of data_1.FRONTS) { + if (game.fronts[f].value >= 1) { + won_fronts++; + } + } + return won_fronts >= 3; +} +function determine_winner() { + const glory = { + [data_1.ANARCHISTS_ID]: 0, + [data_1.COMMUNISTS_ID]: 0, + [data_1.MODERATES_ID]: 0, + }; + for (const g of game.glory) { + glory[g]++; + } + let highest_glory = 0; + let winners = []; + for (let f of role_ids) { + if (glory[f] === highest_glory) { + winners.push(f); + } + else if (glory[f] > highest_glory) { + highest_glory = glory[f]; + winners = [f]; + } + } + if (winners.length === 1) { + win_game(faction_player_map[winners[0]], highest_glory); + } + else { + insert_after_active_node(create_leaf_node('break_tie_winner', game.initiative, { + winners, + glory: highest_glory, + })); + } + resolve_active_and_proceed(); +} function end_of_turn() { Object.keys(game.fronts).forEach((front_id) => { game.fronts[front_id].contributions = []; @@ -856,14 +1033,39 @@ function end_of_turn() { } } function end_of_year() { - const gloryToDraw = [0, 1, 2, 5]; - for (let i = 0; i < gloryToDraw[game.year]; ++i) { + if (game.year === 3) { + log_h1('End of the game'); + const is_won = war_is_won(); + if (is_won) { + log('The war is won!'); + } + else { + game_over('None', 'The war is lost. All Players lose the game!'); + return; + } + } + const glory_to_draw = [0, 1, 2, 5]; + const glory_this_year = { + [data_1.ANARCHISTS_ID]: false, + [data_1.COMMUNISTS_ID]: false, + [data_1.MODERATES_ID]: false, + }; + for (let i = 0; i < glory_to_draw[game.year]; ++i) { const index = random(game.bag_of_glory.length); - game.glory.push(game.bag_of_glory[index]); + const faction = game.bag_of_glory[index]; + game.glory.push(faction); + glory_this_year[faction] = true; array_remove(game.bag_of_glory, index); } - game.year++; - start_year(); + if (game.year === 3) { + determine_winner(); + return; + } + const players_to_gain_hero_points = role_ids.filter((f) => !glory_this_year[f]); + gain_hero_points_in_player_order(players_to_gain_hero_points, game.year); + game.engine = get_player_order().map((f) => create_leaf_node('end_of_year_discard', f)); + game.engine.push(create_function_node('start_year')); + next(); } function gain_hero_points_in_player_order(factions, value) { for (const f of get_player_order()) { @@ -907,6 +1109,34 @@ function resolve_fascist_test() { } resolve_active_and_proceed(); } +function resolve_final_bid() { + let highest_bid = 0; + let winners = []; + for (const f of get_player_order()) { + let player_bid = 0; + for (const c of game.final_bid[f]) { + player_bid += cards[c].strength; + } + log(`${faction_player_map[f]} bids ${player_bid}`); + if (player_bid === highest_bid) { + winners.push(f); + } + else if (player_bid > highest_bid) { + highest_bid = player_bid; + winners = [f]; + } + game.hands[f] = game.hands[f].filter((c) => !game.final_bid[f].includes(c)); + game.discard[f].concat(game.final_bid[f]); + game.final_bid[f] = []; + } + if (winners.length === 1) { + win_final_bid(winners[0]); + } + else { + insert_after_active_node(create_leaf_node('break_tie_final_bid', game.initiative, { winners })); + } + resolve_active_and_proceed(); +} function get_fronts_to_add_to(target) { console.log('get_fronts_to_add_to', target); if (target === data_1.CLOSEST_TO_DEFEAT || target === data_1.CLOSEST_TO_VICTORY) { @@ -1075,6 +1305,14 @@ function resolve_effect(effect, faction = get_active_faction()) { } return state === undefined ? null : create_leaf_node(state, faction, args); } +function win_final_bid(faction_id) { + log_br(); + log(`${faction_player_map[faction_id]} wins the Final Bid`); + game.glory.push(faction_id); +} +function win_game(player, glory) { + game_over(player, `${player} wins the game with a total of ${glory} Glory!`); +} function draw_card(deck) { clear_undo(); let i = random(deck.length); @@ -1260,7 +1498,9 @@ function list_deck(id) { return; } else if (id !== 'fascist' && - (game.hands[id].includes(card) || game.discard[id].includes(card))) { + (game.hands[id].includes(card) || + game.discard[id].includes(card) || + game.tableaus[id].includes(card))) { return; } deck.push(card); -- cgit v1.2.3