diff options
author | Frans Bongers <fransbongers@franss-mbp.home> | 2024-12-15 21:38:52 +0100 |
---|---|---|
committer | Frans Bongers <fransbongers@franss-mbp.home> | 2024-12-15 21:38:52 +0100 |
commit | 72afc8e31c9dcef58b1308eddd4d1dde489e4670 (patch) | |
tree | 1e5ea6603d3144f9b45214c3d1466c4cd693dea9 /rules.ts | |
parent | 47b19b5e83850b5fac6e508468b227476d486025 (diff) | |
download | land-and-freedom-72afc8e31c9dcef58b1308eddd4d1dde489e4670.tar.gz |
victory and defeat on front and end game on defeat
Diffstat (limited to 'rules.ts')
-rw-r--r-- | rules.ts | 217 |
1 files changed, 152 insertions, 65 deletions
@@ -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<T>(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; } |