summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorFrans Bongers <fransbongers@franss-mbp.home>2024-12-22 14:45:51 +0100
committerFrans Bongers <fransbongers@franss-mbp.home>2024-12-22 14:45:51 +0100
commitfa18a313b5a57b106a8c41a542f08ba4697435ca (patch)
tree2146925d47aaf3107c8007bd513f4f99c4682c41 /rules.js
parentb80ba3e739ed5dd1fa2796e3683bbe98659d865a (diff)
downloadland-and-freedom-fa18a313b5a57b106a8c41a542f08ba4697435ca.tar.gz
Add final bid and determine winner
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js270
1 files changed, 255 insertions, 15 deletions
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);