From 72afc8e31c9dcef58b1308eddd4d1dde489e4670 Mon Sep 17 00:00:00 2001 From: Frans Bongers Date: Sun, 15 Dec 2024 21:38:52 +0100 Subject: victory and defeat on front and end game on defeat --- data.js | 9 ++- data.ts | 34 ++++++---- play.js | 2 +- play.ts | 3 +- rules.js | 131 ++++++++++++++++++++++++++++++------- rules.ts | 217 +++++++++++++++++++++++++++++++++++++++++++------------------ types.d.ts | 30 ++++----- 7 files changed, 305 insertions(+), 121 deletions(-) diff --git a/data.js b/data.js index 3de51ab..d4fb1b2 100644 --- a/data.js +++ b/data.js @@ -1,6 +1,7 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.TRASH = exports.TOWARDS_CENTER = exports.SELF = exports.PLAYER_WITH_MOST_HERO_POINTS = exports.OTHER_PLAYERS = exports.ON = exports.OFF = exports.TEAMWORK_BONUS = exports.MORALE_BONUS = exports.FOREIGN_AID = exports.SOVIET_SUPPORT = exports.GOVERNMENT = exports.COLLECTIVIZATION = exports.CLOSEST_TO_VICTORY = exports.CLOSEST_TO_DEFEAT = exports.LIBERTY = exports.ANY = exports.MODERATES_ID = exports.COMMUNISTS_ID = exports.ANARCHISTS_ID = exports.MODERATE = exports.COMMUNIST = exports.ANARCHIST = void 0; +exports.FRONTS = exports.DEFEAT = exports.VICTORY = exports.TRASH = exports.TOWARDS_CENTER = exports.SELF = exports.PLAYER_WITH_MOST_HERO_POINTS = exports.OTHER_PLAYERS = exports.ON = exports.OFF = exports.TEAMWORK_BONUS = exports.MORALE_BONUS = exports.FOREIGN_AID = exports.SOVIET_SUPPORT = exports.GOVERNMENT = exports.COLLECTIVIZATION = exports.CLOSEST_TO_VICTORY = exports.CLOSEST_TO_DEFEAT = exports.LIBERTY = exports.ANY = exports.MODERATES_ID = exports.COMMUNISTS_ID = exports.ANARCHISTS_ID = exports.MODERATE = exports.COMMUNIST = exports.ANARCHIST = void 0; +exports.create_effect = create_effect; const LIBERTY = 0; exports.LIBERTY = LIBERTY; const COLLECTIVIZATION = 1; @@ -31,6 +32,8 @@ const CLOSEST_TO_DEFEAT = 'd'; exports.CLOSEST_TO_DEFEAT = CLOSEST_TO_DEFEAT; const CLOSEST_TO_VICTORY = 'v'; exports.CLOSEST_TO_VICTORY = CLOSEST_TO_VICTORY; +const FRONTS = [ARAGON, MADRID, NORTHERN, SOUTHERN]; +exports.FRONTS = FRONTS; const TOWARDS_CENTER = 10; exports.TOWARDS_CENTER = TOWARDS_CENTER; const AWAY_FROM_CENTER = 11; @@ -54,6 +57,10 @@ const COMMUNIST = 'Communist'; exports.COMMUNIST = COMMUNIST; const MODERATE = 'Moderate'; exports.MODERATE = MODERATE; +const VICTORY = 'Victory'; +exports.VICTORY = VICTORY; +const DEFEAT = 'Defeat'; +exports.DEFEAT = DEFEAT; function create_effect(type, target, value) { return { type, diff --git a/data.ts b/data.ts index 1ab4a98..806c9b8 100644 --- a/data.ts +++ b/data.ts @@ -1,4 +1,4 @@ -import { Card, Effect, FactionId, Player, StaticData } from './types'; +import { Card, Effect, FactionId, FrontId, Player, StaticData } from './types'; const LIBERTY = 0; const COLLECTIVIZATION = 1; @@ -22,6 +22,7 @@ const NORTHERN = 'n'; const SOUTHERN = 's'; const CLOSEST_TO_DEFEAT = 'd'; const CLOSEST_TO_VICTORY = 'v'; +const FRONTS: FrontId[] = [ARAGON, MADRID, NORTHERN, SOUTHERN]; const TOWARDS_CENTER = 10; const AWAY_FROM_CENTER = 11; @@ -39,7 +40,23 @@ const ANARCHIST = 'Anarchist' as Player; const COMMUNIST = 'Communist' as Player; const MODERATE = 'Moderate' as Player; +const VICTORY = 'Victory'; +const DEFEAT = 'Defeat'; + +function create_effect( + type: Effect['type'], + target: Effect['target'], + value: Effect['value'] +): Effect { + return { + type, + target, + value, + }; +} + export { + create_effect, ANARCHIST, COMMUNIST, MODERATE, @@ -63,19 +80,12 @@ export { SELF, TOWARDS_CENTER, TRASH, + VICTORY, + DEFEAT, + FRONTS, }; -function create_effect( - type: Effect['type'], - target: Effect['target'], - value: Effect['value'] -): Effect { - return { - type, - target, - value, - }; -} + const data: StaticData = { cards: [ diff --git a/play.js b/play.js index 38d98dd..ffa817a 100644 --- a/play.js +++ b/play.js @@ -289,7 +289,7 @@ function on_update() { } for (let front_id of Object.keys(view.fronts)) { const front_data = view.fronts[front_id]; - ui.fronts[front_id].value.replaceChildren(front_data.value); + ui.fronts[front_id].value.replaceChildren(front_data.status !== null ? front_data.status : front_data.value); ui.fronts[front_id].contributions.replaceChildren(); for (let faction_id of front_data.contributions) { ui.fronts[front_id].contributions.appendChild(ui.tokens_on_front[front_id][faction_id]); diff --git a/play.ts b/play.ts index e192d6d..b97839b 100644 --- a/play.ts +++ b/play.ts @@ -381,7 +381,8 @@ function on_update() { for (let front_id of Object.keys(view.fronts)) { const front_data = view.fronts[front_id]; - ui.fronts[front_id].value.replaceChildren(front_data.value); + // ui.fronts[front_id].value.replaceChildren(front_data.value); + ui.fronts[front_id].value.replaceChildren(front_data.status !== null ? front_data.status : front_data.value); ui.fronts[front_id].contributions.replaceChildren(); for(let faction_id of front_data.contributions) { ui.fronts[front_id].contributions.appendChild(ui.tokens_on_front[front_id][faction_id]); diff --git a/rules.js b/rules.js index f9cd8e8..667c7a0 100644 --- a/rules.js +++ b/rules.js @@ -189,9 +189,7 @@ function insert_before_active_node(node, engine = game.engine) { insert_before_or_after_active_node(node, 'before', engine); } function next() { - console.log('next'); const node = get_active_node(game.engine); - console.log('node', node); if (node.t === function_node && engine_functions[node.f]) { const args = node.a; if (args) { @@ -241,7 +239,10 @@ function game_view(state, player) { triggered_track_effects: game.triggered_track_effects, year: game.year, }; - if (player !== game.active) { + if (game.state === 'game_over') { + view.prompt = game.victory; + } + else if (player !== game.active) { let inactive = states[game.state].inactive || game.state; view.prompt = `Waiting for ${game.active} to ${inactive}.`; } @@ -275,18 +276,22 @@ function setup(seed, _scenario, _options) { a: { value: -2, contributions: [], + status: null, }, m: { value: -2, contributions: [], + status: null, }, n: { value: -2, contributions: [], + status: null, }, s: { value: -2, contributions: [], + status: null, }, }, glory: [], @@ -470,13 +475,20 @@ states.attack_front = { const node = get_active_node(); const front = node.a.t; view.prompt = 'Attack ' + front_names[front]; + let targets = []; if (front === 'd' || front === 'v') { - const fronts = get_fronts_closest_to(front); - fronts.forEach((id) => gen_action('front', id)); + targets = get_fronts_closest_to(front); + } + else if (game.fronts[front].status === data_1.DEFEAT) { + targets = get_fronts_closest_to('d'); + } + else if (game.fronts[front].status === data_1.VICTORY) { + targets = get_fronts_to_add_to(data_1.ANY); } else { - gen_action_front(front); + targets.push(front); } + targets.forEach((id) => gen_action('front', id)); }, front(f) { const node = get_active_node(); @@ -579,13 +591,18 @@ states.gain_hero_points = { }, gain_hp() { const value = get_active_node_args().v; - if (game.hero_points.pool > value) { - game.hero_points.pool -= value; - game.hero_points[get_active_faction()] += value; - } + gain_hero_points(get_active_faction(), value); resolve_active_and_proceed(); }, }; +states.game_over = { + get inactive() { + return game.victory; + }, + prompt() { + view.prompt = game.victory; + }, +}; states.lose_hero_points = { inactive: 'choose a Player', prompt() { @@ -780,11 +797,35 @@ function end_of_year() { game.year++; start_year(); } +function gain_hero_points_in_player_order(factions, value) { + for (const f of get_player_order()) { + if (factions.includes(f)) { + gain_hero_points(f, value); + } + } +} +function gain_hero_points(faction_id, value) { + if (game.hero_points.pool === 0) { + return; + } + const gain = Math.min(game.hero_points.pool, value); + game.hero_points.pool -= gain; + game.hero_points[faction_id] += gain; + logi(`${get_player(faction_id)} +${gain} ${gain === 1 ? 'Hero Point' : 'Hero Points'}`); +} +function game_over(result, victory) { + insert_after_active_node(create_leaf_node('game_over', 'None')); + game.result = result; + game.victory = victory; + log_br(); + log(game.victory); +} function resolve_fascist_test() { - console.log('resolve fascist test'); log_h2('Fascist Test', 'fascist'); const test = get_current_event().test; - const test_passed = game.fronts[test.front].value >= test.value; + const status = game.fronts[test.front].status; + const test_passed = status === data_1.VICTORY || + (status !== data_1.DEFEAT && game.fronts[test.front].value >= test.value); if (test_passed) { log('The Test is passed'); } @@ -804,7 +845,7 @@ function get_fronts_to_add_to(target) { return get_fronts_closest_to(target); } else if (target === data_1.ANY) { - return ['a', 'm', 'n', 's']; + return data_1.FRONTS.filter((id) => game.fronts[id].status === null); } else { return [target]; @@ -842,21 +883,47 @@ function update_bonus(bonus_id, status) { game.bonuses[bonus_id] = status; logi(`${bonus_names[bonus_id]} ${status === data_1.ON ? 'on' : 'off'}`); } -function update_front(f, change, faction_id = null) { - const player_token_on_front = faction_id !== null && game.fronts[f].contributions.includes(faction_id); +function update_front(front_id, change, faction_id = null) { + const player_token_on_front = faction_id !== null && + game.fronts[front_id].contributions.includes(faction_id); if (game.bonuses[data_1.TEAMWORK_BONUS] === data_1.ON && change > 0 && faction_id !== null && !player_token_on_front && - game.fronts[f].contributions.length > 0) { + game.fronts[front_id].contributions.length > 0) { change += 1; } - game.fronts[f].value += change; - logi(`${front_names[f]}: ${change > 0 ? '+' : ''}${change}`); + game.fronts[front_id].value += change; + logi(`${front_names[front_id]}: ${change > 0 ? '+' : ''}${change}`); if (faction_id !== null && - !game.fronts[f].contributions.includes(faction_id)) { - game.fronts[f].contributions.push(faction_id); + !game.fronts[front_id].contributions.includes(faction_id)) { + game.fronts[front_id].contributions.push(faction_id); } + if (game.fronts[front_id].value >= 10) { + victory_on_a_front(front_id); + } + else if (game.fronts[front_id].value <= -10) { + defeat_on_a_front(front_id); + } +} +function defeat_on_a_front(front_id) { + game.fronts[front_id].status = data_1.DEFEAT; + log('Defeat on ' + get_front_name(front_id)); + if (front_id === 'm' || get_defeated_front_count() == 2) { + game_over('None', 'All players lose the game!'); + return; + } + insert_after_active_node(create_effects_node([ + (0, data_1.create_effect)('bonus', data_1.MORALE_BONUS, data_1.OFF), + (0, data_1.create_effect)('track', data_1.COLLECTIVIZATION, -1), + (0, data_1.create_effect)('track', data_1.SOVIET_SUPPORT, -1), + (0, data_1.create_effect)('track', data_1.FOREIGN_AID, -1), + ])); +} +function victory_on_a_front(front_id) { + game.fronts[front_id].status = data_1.VICTORY; + log('Victory on ' + get_front_name(front_id)); + gain_hero_points_in_player_order(game.fronts[front_id].contributions, 3); } function create_effects_node(effects) { const nodes = effects.reduce((accrued, current) => { @@ -923,7 +990,12 @@ function lose_hero_point(faction, value) { } } function get_fronts_closest_to(target) { - const values = Object.values(game.fronts).map((front) => front.value); + const values = Object.values(game.fronts).reduce((accrued, current) => { + if (current.status === null) { + accrued.push(current.value); + } + return accrued; + }, []); const targetValue = target === 'd' ? Math.min(...values) : Math.max(...values); return Object.keys(game.fronts).filter((frontId) => game.fronts[frontId].value === targetValue); } @@ -966,9 +1038,21 @@ function get_active_faction_id() { function get_faction_id(player) { return player_faction_map[player]; } +function get_front_name(id) { + return front_names[id]; +} function get_current_event() { return cards[game.current_events[game.current_events.length - 1]]; } +function get_defeated_front_count() { + let count = 0; + for (const front_id of data_1.FRONTS) { + if (game.fronts[front_id].status === data_1.DEFEAT) { + count++; + } + } + return count; +} function get_icon_count_in_tableau(icon, faction = get_active_faction_id()) { let count = 0; for (const c of game.tableaus[faction]) { @@ -1059,10 +1143,11 @@ function list_deck(id) { const deck = []; const card_list = id === 'fascist' ? fascist_decks[game.year] : faction_cards[id]; card_list.forEach((card) => { - if (id === 'fascist' && (game.discard.f.includes(card))) { + if (id === 'fascist' && game.discard.f.includes(card)) { return; } - else if (id !== 'fascist' && (game.hands[id].includes(card) || game.discard[id].includes(card))) { + else if (id !== 'fascist' && + (game.hands[id].includes(card) || game.discard[id].includes(card))) { return; } deck.push(card); diff --git a/rules.ts b/rules.ts index c6f01ab..2fea19e 100644 --- a/rules.ts +++ b/rules.ts @@ -6,6 +6,8 @@ import { EngineNode, EventCard, FactionId, + Front, + FrontId, FunctionNode, Game, Icon, @@ -46,6 +48,10 @@ import data, { TEAMWORK_BONUS, MORALE_BONUS, OFF, + VICTORY, + DEFEAT, + FRONTS, + create_effect, // StaticData, // PLAYER_WITH_MOST_HERO_POINTS, } from './data'; @@ -177,7 +183,7 @@ const resolved = 1; function create_leaf_node( state: string, - faction: FactionId, + faction: FactionId | 'None', args?: any ): LeafNode { return { @@ -272,41 +278,11 @@ function get_active( return null; } -// function get_active_node_parent(engine: EngineNode[]): EngineNode[] | null { -// for (let i of engine) { -// if ((i.t === leaf_node || i.t === function_node) && i.r !== resolved) { -// return engine; -// } -// if (i.t === seq_node) { -// const next_child = get_active_node_parent(i.c); -// if (next_child !== null) { -// return next_child; -// } -// } -// } -// return null; -// } - function get_active_node( engine: EngineNode[] = game.engine ): FunctionNode | LeafNode | null { const a = get_active(engine); return a === null ? null : a.node; - // for (let i of engine) { - // if ((i.t === leaf_node || i.t === function_node) && i.r !== resolved) { - // return i; - // } - // // if (i.t === function_node && i.r !== resolved) { - // // return i; - // // } - // if (i.t === seq_node) { - // const next_child = get_active_node(i.c); - // if (next_child !== null) { - // return next_child; - // } - // } - // } - // return null; } function get_active_node_args(): any { @@ -348,9 +324,7 @@ function insert_before_active_node( } function next() { - console.log('next'); const node = get_active_node(game.engine); - console.log('node', node); if (node.t === function_node && engine_functions[node.f]) { const args = node.a; if (args) { @@ -410,7 +384,9 @@ function game_view(state: Game, player: Player) { year: game.year, }; - if (player !== game.active) { + if (game.state === 'game_over') { + view.prompt = game.victory; + } else if (player !== game.active) { let inactive = states[game.state].inactive || game.state; view.prompt = `Waiting for ${game.active} to ${inactive}.`; } else { @@ -448,18 +424,22 @@ export function setup(seed: number, _scenario: string, _options: unknown) { a: { value: -2, contributions: [], + status: null, }, m: { value: -2, contributions: [], + status: null, }, n: { value: -2, contributions: [], + status: null, }, s: { value: -2, contributions: [], + status: null, }, }, glory: [], @@ -660,7 +640,7 @@ states.add_to_front = { gen_action_front(f); } }, - front(f: string) { + front(f: FrontId) { const value = get_active_node_args().v; update_front(f, value); resolve_active_and_proceed(); @@ -673,14 +653,20 @@ states.attack_front = { const node = get_active_node(); const front = node.a.t; view.prompt = 'Attack ' + front_names[front]; + let targets = []; + if (front === 'd' || front === 'v') { - const fronts = get_fronts_closest_to(front); - fronts.forEach((id) => gen_action('front', id)); + targets = get_fronts_closest_to(front); + } else if (game.fronts[front].status === DEFEAT) { + targets = get_fronts_closest_to('d') + } else if (game.fronts[front].status === VICTORY) { + targets = get_fronts_to_add_to(ANY); } else { - gen_action_front(front); + targets.push(front); } + targets.forEach((id) => gen_action('front', id)); }, - front(f: string) { + front(f: FrontId) { const node = get_active_node(); const value = node.a.v; update_front(f, value); @@ -710,7 +696,7 @@ states.choose_area_ap = { // TODO: insert action in case other bonus is OFF and AP left resolve_active_and_proceed(); }, - front(f: string) { + front(f: FrontId) { const s: number = get_active_node_args().strength; update_front(f, s, get_active_faction_id()); resolve_active_and_proceed(); @@ -786,14 +772,20 @@ states.gain_hero_points = { }, gain_hp() { const value = get_active_node_args().v; - if (game.hero_points.pool > value) { - game.hero_points.pool -= value; - game.hero_points[get_active_faction()] += value; - } + gain_hero_points(get_active_faction(), value); resolve_active_and_proceed(); }, }; +states.game_over = { + get inactive() { + return game.victory; + }, + prompt() { + view.prompt = game.victory; + }, +}; + states.lose_hero_points = { inactive: 'choose a Player', prompt() { @@ -865,7 +857,7 @@ states.move_track_up_or_down = { states.player_turn = { inactive: 'play their turn', prompt() { - const faction_id = get_faction_id(game.active); + const faction_id = get_faction_id(game.active as Player); const can_spend_hp = game.hero_points[faction_id] > 0; const can_play_card = game.hands[faction_id].includes( game.chosen_cards[faction_id] @@ -893,7 +885,7 @@ states.player_turn = { resolve_active_and_proceed(); }, play_for_ap() { - const faction_id = get_faction_id(game.active); + const faction_id = get_faction_id(game.active as Player); const card = game.chosen_cards[faction_id]; log_h3(`${game.active} plays ${cards[card].title} for the Action Points`); array_remove(game.hands[faction_id], game.hands[faction_id].indexOf(card)); @@ -909,7 +901,7 @@ states.player_turn = { next(); }, play_for_event() { - const faction_id = get_faction_id(game.active); + const faction_id = get_faction_id(game.active as Player); const card = game.chosen_cards[faction_id]; array_remove(game.hands[faction_id], game.hands[faction_id].indexOf(card)); game.trash[faction_id].push(card); @@ -922,7 +914,7 @@ states.player_turn = { spend_hp() { insert_before_active_node({ t: leaf_node, - p: get_faction_id(game.active), + p: get_faction_id(game.active as Player), s: 'spend_hero_points', }); // insert spend hero points node before current node @@ -1083,12 +1075,46 @@ function end_of_year() { start_year(); } +function gain_hero_points_in_player_order(factions: FactionId[], value) { + for (const f of get_player_order()) { + if (factions.includes(f)) { + gain_hero_points(f, value); + } + } +} + +function gain_hero_points(faction_id: FactionId, value: number) { + if (game.hero_points.pool === 0) { + return; + } + const gain = Math.min(game.hero_points.pool, value); + game.hero_points.pool -= gain; + game.hero_points[faction_id] += gain; + logi( + `${get_player(faction_id)} +${gain} ${ + gain === 1 ? 'Hero Point' : 'Hero Points' + }` + ); +} + +function game_over(result: Player | 'None', victory: string) { + insert_after_active_node(create_leaf_node('game_over', 'None')); + // game.state = 'game_over'; + // game.active = 'None'; + game.result = result; + game.victory = victory; + log_br(); + log(game.victory); +} + function resolve_fascist_test() { - console.log('resolve fascist test'); log_h2('Fascist Test', 'fascist'); const test = get_current_event().test; - const test_passed = game.fronts[test.front].value >= test.value; + const status = game.fronts[test.front].status; + const test_passed = + status === VICTORY || + (status !== DEFEAT && game.fronts[test.front].value >= test.value); if (test_passed) { log('The Test is passed'); } else { @@ -1110,7 +1136,7 @@ function get_fronts_to_add_to(target: string): string[] { if (target === CLOSEST_TO_DEFEAT || target === CLOSEST_TO_VICTORY) { return get_fronts_closest_to(target); } else if (target === ANY) { - return ['a', 'm', 'n', 's']; + return FRONTS.filter((id) => game.fronts[id].status === null); } else { return [target]; } @@ -1162,31 +1188,66 @@ function update_bonus(bonus_id: number, status: number) { // TODO: acccount for victory / defeat of front function update_front( - f: string, + // f: string, + front_id: FrontId, change: number, faction_id: FactionId | null = null ) { + // Check teamwork bonus const player_token_on_front = - faction_id !== null && game.fronts[f].contributions.includes(faction_id); + faction_id !== null && + game.fronts[front_id].contributions.includes(faction_id); if ( game.bonuses[TEAMWORK_BONUS] === ON && change > 0 && faction_id !== null && !player_token_on_front && - game.fronts[f].contributions.length > 0 + game.fronts[front_id].contributions.length > 0 ) { change += 1; } - game.fronts[f].value += change; - logi(`${front_names[f]}: ${change > 0 ? '+' : ''}${change}`); + + game.fronts[front_id].value += change; + logi(`${front_names[front_id]}: ${change > 0 ? '+' : ''}${change}`); + + // Add token to front if player contributed if ( faction_id !== null && - !game.fronts[f].contributions.includes(faction_id) + !game.fronts[front_id].contributions.includes(faction_id) ) { - game.fronts[f].contributions.push(faction_id); + game.fronts[front_id].contributions.push(faction_id); + } + + // Check victory / defeat on a front + if (game.fronts[front_id].value >= 10) { + victory_on_a_front(front_id); + } else if (game.fronts[front_id].value <= -10) { + defeat_on_a_front(front_id); } } +function defeat_on_a_front(front_id: FrontId) { + game.fronts[front_id].status = DEFEAT; + log('Defeat on ' + get_front_name(front_id)); + // Check game end + if (front_id === 'm' || get_defeated_front_count() == 2) { + game_over('None', 'All players lose the game!'); + return; + } + insert_after_active_node(create_effects_node([ + create_effect('bonus', MORALE_BONUS, OFF), + create_effect('track', COLLECTIVIZATION, -1), + create_effect('track', SOVIET_SUPPORT, -1), + create_effect('track', FOREIGN_AID, -1), + ])); +} + +function victory_on_a_front(front_id: FrontId) { + game.fronts[front_id].status = VICTORY; + log('Victory on ' + get_front_name(front_id)); + gain_hero_points_in_player_order(game.fronts[front_id].contributions, 3); +} + function create_effects_node(effects: Effect[]): EngineNode { const nodes = effects.reduce((accrued: EngineNode[], current: Effect) => { const node = resolve_effect(current); @@ -1359,7 +1420,15 @@ function lose_hero_point(faction: FactionId, value: number) { // #region FRONTS function get_fronts_closest_to(target: 'd' | 'v') { - const values = Object.values(game.fronts).map((front) => front.value); + const values = Object.values(game.fronts).reduce( + (accrued: number[], current: Front) => { + if (current.status === null) { + accrued.push(current.value); + } + return accrued; + }, + [] + ); const targetValue = target === 'd' ? Math.min(...values) : Math.max(...values); return Object.keys(game.fronts).filter( @@ -1453,12 +1522,26 @@ function get_faction_id(player: Player): FactionId { return player_faction_map[player]; } +function get_front_name(id: FrontId | 'd' | 'v') { + return front_names[id]; +} + function get_current_event(): EventCard { return cards[ game.current_events[game.current_events.length - 1] ] as EventCard; } +function get_defeated_front_count() { + let count = 0; + for (const front_id of FRONTS) { + if (game.fronts[front_id].status === DEFEAT) { + count++; + } + } + return count; +} + function get_icon_count_in_tableau( icon: Icon, faction: FactionId = get_active_faction_id() @@ -1560,15 +1643,19 @@ function set_delete(set: T[], item: T) { function list_deck(id: FactionId | 'fascist') { const deck = []; - const card_list = id === 'fascist' ? fascist_decks[game.year] : faction_cards[id]; + const card_list = + id === 'fascist' ? fascist_decks[game.year] : faction_cards[id]; card_list.forEach((card) => { - if (id === 'fascist' && (game.discard.f.includes(card))) { - return - } else if (id !== 'fascist' && (game.hands[id].includes(card) || game.discard[id].includes(card))) { + if (id === 'fascist' && game.discard.f.includes(card)) { + return; + } else if ( + id !== 'fascist' && + (game.hands[id].includes(card) || game.discard[id].includes(card)) + ) { return; } - deck.push(card) - }) + deck.push(card); + }); return deck; } diff --git a/types.d.ts b/types.d.ts index da8fe25..f0c4772 100644 --- a/types.d.ts +++ b/types.d.ts @@ -10,6 +10,12 @@ export type CardId = Brand; export type FactionId = Brand; export type FrontId = 'a' | 'm' | 'n' | 's'; +export interface Front { + value: number; + contributions: FactionId[]; + status: 'Victory' | 'Defeat' | null; +} + export interface Game { [index: number]: any; seed: number; @@ -17,7 +23,7 @@ export interface Game { undo: Game[]; turn: number; year: number; - active: Player | null; + active: Player | 'None' | null; state: string | null; bag_of_glory: FactionId[]; blank_markers: number[][]; @@ -27,22 +33,10 @@ export interface Game { discard: Record; engine: EngineNode[]; fronts: { - a: { - value: number; - contributions: FactionId[]; - }; - m: { - value: number; - contributions: FactionId[]; - }; - n: { - value: number; - contributions: FactionId[]; - }; - s: { - value: number; - contributions: FactionId[]; - }; + a: Front; + m: Front; + n: Front; + s: Front; }; glory: FactionId[]; hands: Record; @@ -112,7 +106,7 @@ export interface SeqNode { export interface LeafNode { t: 'l'; s: string; // State - p: FactionId; // Player + p: FactionId | 'None'; // Player a?: any; // args r?: 0 | 1; // 1 if resolved } -- cgit v1.2.3