From ad4cc37be3e14fdf8f631c64d99ab595a2524b24 Mon Sep 17 00:00:00 2001 From: Frans Bongers Date: Sun, 23 Mar 2025 11:43:03 +0100 Subject: multiactive end of year discard --- rules.js | 81 +++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 26 deletions(-) (limited to 'rules.js') diff --git a/rules.js b/rules.js index aaaa0b3..72b3966 100644 --- a/rules.js +++ b/rules.js @@ -76,9 +76,10 @@ function gen_spend_hero_points() { gen_action('spend_hp'); } } +const multiactive_states = ['choose_card', 'end_of_year_discard']; function action(state, player, action, arg) { game = state; - if (action !== 'undo' && game.state !== 'choose_card') { + if (action !== 'undo' && !multiactive_states.includes(game.state)) { push_undo(); } let S = states[game.state]; @@ -171,14 +172,6 @@ function setup_player_turn(faction_id) { next(); } } -function check_end_of_year_discard() { - const { f: faction } = get_active_node_args(); - if (game.hands[faction].length > get_hand_limit(faction) || - game.tableaus[faction].length > game.year) { - insert_after_active_node(create_state_node('end_of_year_discard', faction)); - } - resolve_active_and_proceed(); -} function end_of_player_turn() { const { f: faction } = get_active_node_args(); const next_faction = get_next_faction_in_player_order(faction); @@ -202,7 +195,6 @@ function start_of_player_turn() { resolve_active_and_proceed(); } const engine_functions = { - check_end_of_year_discard, checkpoint, end_of_player_turn, end_of_turn, @@ -604,9 +596,10 @@ states.activate_icon = { gen_action_bonus(data_1.TEAMWORK_BONUS); can_activate_icon = true; } - else { - can_activate_icon = false; - } + break; + case 'draw_card': + gen_action('draw_card'); + can_activate_icon = true; break; default: gen_action(i); @@ -614,9 +607,9 @@ states.activate_icon = { if (!player_can_resolve_icon(i)) { view.actions[i] = 0; } - if (!can_activate_icon) { - gen_action('skip'); - } + } + if (!can_activate_icon) { + gen_action('skip'); } }, spend_hp() { @@ -1234,8 +1227,9 @@ states.draw_glory = { }; states.end_of_year_discard = { inactive: 'discard cards from hand and tableau', - prompt() { - const faction_id = get_active_faction(); + prompt(player) { + const faction_id = player_faction_map[player]; + const { d: discarded } = get_active_node_args(); const hand = game.hands[faction_id]; const hand_limit = get_hand_limit(faction_id); const needs_to_discard_from_hand = hand.length > hand_limit; @@ -1252,25 +1246,50 @@ states.end_of_year_discard = { if (needs_to_discard_from_hand && needs_to_discard_from_tableau) { view.prompt = 'Discard a card from your hand or tableau'; } - else { + else if (needs_to_discard_from_hand || needs_to_discard_from_tableau) { view.prompt = `Discard a card from your ${needs_to_discard_from_hand ? 'hand' : 'tableau'}`; } + else { + view.prompt = 'Confirm discard'; + view.actions.confirm = 1; + } + if (discarded[faction_id].h.length > 0 || discarded[faction_id].t.length > 0) { + view.actions.undo = 1; + } }, - card(c) { - const faction_id = get_active_faction(); + card(c, player) { + const faction_id = player_faction_map[player]; + const { d: discarded } = get_active_node_args(); if (game.hands[faction_id].includes(c)) { game.hands[faction_id] = game.hands[faction_id].filter((id) => id !== c); + discarded[faction_id].h.push(c); } else if (game.tableaus[faction_id].includes(c)) { game.tableaus[faction_id] = game.tableaus[faction_id].filter((id) => id !== c); + discarded[faction_id].t.push(c); } game.discard[faction_id].push(c); - if (game.hands[faction_id].length > get_hand_limit(faction_id) || - game.tableaus[faction_id].length > game.year) { - next(); + if (game.hands[faction_id].length <= get_hand_limit(faction_id) && + game.tableaus[faction_id].length <= game.year) { + log(`${player} discarded cards.`); + } + }, + undo(_, player) { + const faction_id = player_faction_map[player]; + const last_discarded = game.discard[faction_id].pop(); + const { d: discarded } = get_active_node_args(); + if (discarded[faction_id].h.includes(last_discarded)) { + game.hands[faction_id].push(last_discarded); + discarded[faction_id].h.pop(); } else { - log(`${game.active} discarded cards.`); + game.tableaus[faction_id].push(last_discarded); + discarded[faction_id].t.pop(); + } + }, + confirm(_, player) { + set_delete(game.active, player); + if (game.active.length === 0) { resolve_active_and_proceed(); } }, @@ -2269,7 +2288,17 @@ function end_of_year_cleanup() { } const players_to_gain_hero_points = role_ids.filter((f) => !game.glory_current_year?.[f]); gain_hero_points_in_player_order(players_to_gain_hero_points, game.year); - game.engine = get_player_order().map((f) => create_function_node('check_end_of_year_discard', { f })); + game.engine = []; + const factions_that_must_discard = []; + role_ids.forEach((factionId) => { + if (game.hands[factionId].length > get_hand_limit(factionId) || + game.tableaus[factionId].length > game.year) { + factions_that_must_discard.push(factionId); + } + }); + if (factions_that_must_discard.length > 0) { + game.engine.push(create_state_node('end_of_year_discard', factions_that_must_discard, { d: [{ h: [], t: [] }, { h: [], t: [] }, { h: [], t: [] }] })); + } game.engine.push(create_function_node('checkpoint')); game.engine.push(create_function_node('start_year')); game.top_of_events_deck = null; -- cgit v1.2.3