diff options
Diffstat (limited to 'rules.ts')
-rw-r--r-- | rules.ts | 333 |
1 files changed, 157 insertions, 176 deletions
@@ -86,7 +86,7 @@ const player_faction_map: Record<Player, FactionId> = { const front_names: Record<string, string> = { a: 'Aragon Front', m: 'Madrid Front', - n: 'Nothern Front', + n: 'Northern Front', s: 'Southern Front', d: 'the Front closest to Defeat', v: 'the Front closest to Victory', @@ -490,13 +490,16 @@ export function setup(seed: number, _scenario: string, _options: unknown) { return game; } -function draw_hand_cards() { - role_ids.forEach((role) => { - const deck = list_deck(role); - for (let i = 0; i < 5; i++) { - game.hands[role].push(draw_card(deck)); - } - }); +function draw_hand_cards(faction_id: FactionId, count: number) { + const log = + count === 1 + ? `${get_player(faction_id)} draws 1 card` + : `${get_player(faction_id)} draws ${count} cards`; + logi(log); + for (let i = 0; i < count; i++) { + const deck = list_deck(faction_id); + game.hands[faction_id].push(draw_card(deck)); + } } // #endregion @@ -504,7 +507,9 @@ function draw_hand_cards() { function start_year() { // log_h1('Year ' + game.year); game.current_events = []; - draw_hand_cards(); + role_ids.forEach((role) => { + draw_hand_cards(role, 5); + }); start_turn(); } @@ -545,7 +550,12 @@ states.activate_icon = { } }, add_to_front() { - // insert state to select front + insert_after_active_node( + create_leaf_node('add_to_front', get_active_faction(), { + t: ANY, + v: get_icon_count_in_tableau('add_to_front'), + }) + ); resolve_active_and_proceed(); }, collectivization() { @@ -579,7 +589,10 @@ states.activate_icon = { resolve_active_and_proceed(); }, draw_card() { - // TODO: draw cards + draw_hand_cards( + get_active_faction(), + get_icon_count_in_tableau('draw_card') + ); resolve_active_and_proceed(); }, foreign_aid() { @@ -587,10 +600,18 @@ states.activate_icon = { resolve_active_and_proceed(); }, government() { - move_track(GOVERNMENT, get_icon_count_in_tableau('government')); + const direction = game.active === COMMUNIST ? -1 : 1; + move_track(GOVERNMENT, direction * get_icon_count_in_tableau('government')); + resolve_active_and_proceed(); + }, + government_to_center() { + const direction = game.tracks[GOVERNMENT] >= 6 ? -1 : 1; + move_track( + GOVERNMENT, + direction * get_icon_count_in_tableau('government_to_center') + ); resolve_active_and_proceed(); }, - government_to_center() {}, liberty() { move_track(LIBERTY, get_icon_count_in_tableau('liberty')); resolve_active_and_proceed(); @@ -642,7 +663,7 @@ states.add_to_front = { }, front(f: FrontId) { const value = get_active_node_args().v; - update_front(f, value); + update_front(f, value, get_active_faction()); resolve_active_and_proceed(); }, }; @@ -652,18 +673,23 @@ states.attack_front = { prompt() { const node = get_active_node(); const front = node.a.t; - view.prompt = 'Attack ' + front_names[front]; - let targets = []; - + + let targets: Array<FrontId> = []; + if (front === 'd' || front === 'v') { targets = get_fronts_closest_to(front); } else if (game.fronts[front].status === DEFEAT) { - targets = get_fronts_closest_to('d') + targets = get_fronts_closest_to('d'); } else if (game.fronts[front].status === VICTORY) { targets = get_fronts_to_add_to(ANY); } else { targets.push(front); } + view.prompt = + targets.length === 1 + ? `Attack ${front_names[targets[0]]}` + : 'Attack a front'; + targets.forEach((id) => gen_action('front', id)); }, front(f: FrontId) { @@ -702,7 +728,6 @@ states.choose_area_ap = { resolve_active_and_proceed(); }, standee(track_id: number) { - console.log('standee', track_id); insert_after_active_node({ t: leaf_node, p: get_active_faction_id(), @@ -912,85 +937,82 @@ states.player_turn = { resolve_active_and_proceed(); }, spend_hp() { - insert_before_active_node({ - t: leaf_node, - p: get_faction_id(game.active as Player), - s: 'spend_hero_points', - }); // insert spend hero points node before current node + // so it will return to current node after resolving + insert_before_active_node( + create_leaf_node('spend_hero_points', get_active_faction()) + ); + log('Spends Hero Points'); + next(); }, - // card(c: CardId) { - // const faction = get_active_faction(); - // log_h3(`${game.active} plays ${cards[c].title} to their tableau`); - // if (!game.tableaus) { - // game.tableaus = { - // [ANARCHISTS_ID]: [], - // [COMMUNISTS_ID]: [], - // [MODERATES_ID]: [], - // }; - // } - // game.chosen_cards[faction] = null; - // game.tableaus[faction].push(c); - // array_remove(game.hands[faction], game.hands[faction].indexOf(c)); - // resolve_active_and_proceed(); - // }, }; -// states.resolve_event = { -// inactive: 'resolve Fascist Event', -// prompt() { -// const card = get_current_event(); -// const node = get_active_node(game.engine) as LeafNode; -// const effect: Effect = card.effects[node.a]; -// view.prompt = get_event_prompt(effect); - -// if (effect.type === 'track') { -// gen_action('standee', effect.target); -// } else if ( -// effect.type === 'hero_points' && -// effect.target === PLAYER_WITH_MOST_HERO_POINTS -// ) { -// const factions = get_factions_with_most_hero_poins(); -// for (let faction_id of factions) { -// gen_action(get_player(faction_id)); -// } -// } -// // for (let p = 0; p < 5; ++p) gen_action('standee', p); -// }, - -// Anarchist() { -// lose_hero_point(ANARCHISTS_ID, 1); -// resolve_active_and_proceed(); -// }, -// Communist() { -// lose_hero_point(ANARCHISTS_ID, 1); -// resolve_active_and_proceed(); -// }, -// Moderate() { -// lose_hero_point(ANARCHISTS_ID, 1); -// resolve_active_and_proceed(); -// }, -// }; - states.spend_hero_points = { inactive: 'spend Hero points', prompt() { view.prompt = 'Spend your Hero points'; gen_action('done'); + const hero_points = game.hero_points[get_active_faction()]; + if (hero_points === 0) { + return; + } gen_action('draw_card'); + + if (hero_points < 2) { + return; + } + gen_action_standee(FOREIGN_AID); + gen_action_standee(SOVIET_SUPPORT); + for (const bonus of bonuses) { + if (game.bonuses[bonus] === OFF) { + gen_action_bonus(bonus); + } + } + + if (hero_points < 3) { + return; + } + gen_action_standee(COLLECTIVIZATION); + gen_action_standee(LIBERTY); + + if (hero_points < 4) { + return; + } + gen_action_standee(GOVERNMENT); }, done() { resolve_active_and_proceed(); }, + bonus(b: number) { + update_bonus(b, ON); + pay_hero_points(get_active_faction(), 2); + }, draw_card() { - game.hero_points[get_active_faction_id()]--; - log(`${game.active} draws a card`); - // TODO: Draw card - if (game.hero_points[get_active_faction_id()] === 0) { - resolve_active_and_proceed(); + const faction = get_active_faction(); + pay_hero_points(faction, 1); + draw_hand_cards(faction, 1); + }, + standee(track_id: number) { + let amount = 2; + if (track_id === LIBERTY || track_id === COLLECTIVIZATION) { + amount = 3; + } else if (track_id === GOVERNMENT) { + amount = 4; } + const faction = get_active_faction(); + pay_hero_points(faction, amount); + insert_after_active_node( + create_seq_node([ + create_leaf_node('move_track_up_or_down', faction, { + track_id, + strength: 1, + }), + create_leaf_node('spend_hero_points', faction), + ]) + ); + resolve_active_and_proceed(); }, }; @@ -1131,26 +1153,50 @@ function resolve_fascist_test() { } // TODO: check for defeated / won fronts -function get_fronts_to_add_to(target: string): string[] { +function get_fronts_to_add_to(target: string): FrontId[] { console.log('get_fronts_to_add_to', target); if (target === CLOSEST_TO_DEFEAT || target === CLOSEST_TO_VICTORY) { return get_fronts_closest_to(target); } else if (target === ANY) { return FRONTS.filter((id) => game.fronts[id].status === null); } else { - return [target]; + return [target as FrontId]; + } +} + +function get_max_value_for_track(track_id: number) { + switch (track_id) { + case LIBERTY: + return game.tracks[COLLECTIVIZATION] >= 8 ? 10 : 7; + case GOVERNMENT: + return game.tracks[FOREIGN_AID] >= 8 ? 10 : 7; + case COLLECTIVIZATION: + case SOVIET_SUPPORT: + case FOREIGN_AID: + default: + return 10; + } +} + +function get_min_value_for_track(track_id: number) { + switch (track_id) { + case GOVERNMENT: + return game.tracks[SOVIET_SUPPORT] >= 8 ? 4 : 1; + case LIBERTY: + case COLLECTIVIZATION: + case SOVIET_SUPPORT: + case FOREIGN_AID: + default: + return 0; } } function move_track(track_id: number, change: number) { - // Check if track can be moved - // Updata values - // Check all triggers - // Add states for triggers const current_value = game.tracks[track_id]; let new_value = current_value + change; - new_value = Math.max(new_value, track_id === GOVERNMENT ? 1 : 0); - new_value = Math.min(new_value, 10); + new_value = Math.max(new_value, get_min_value_for_track(track_id)); + + new_value = Math.min(new_value, get_max_value_for_track(track_id)); game.tracks[track_id] = new_value; logi(`${get_track_name(track_id)} to ${new_value}`); @@ -1178,6 +1224,11 @@ function move_track(track_id: number, change: number) { }); } +function pay_hero_points(faction: FactionId, amount: number) { + game.hero_points[faction] -= amount; + game.hero_points.pool += amount; +} + function update_bonus(bonus_id: number, status: number) { if (game.bonuses[bonus_id] === status) { return; @@ -1206,9 +1257,16 @@ function update_front( ) { change += 1; } - + const value_before = game.fronts[front_id].value; game.fronts[front_id].value += change; logi(`${front_names[front_id]}: ${change > 0 ? '+' : ''}${change}`); + if ( + faction_id !== null && + value_before <= 0 && + game.fronts[front_id].value > 0 + ) { + gain_hero_points(faction_id, 1); + } // Add token to front if player contributed if ( @@ -1234,12 +1292,14 @@ function defeat_on_a_front(front_id: FrontId) { 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), - ])); + 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) { @@ -1338,88 +1398,9 @@ function lose_hero_point(faction: FactionId, value: number) { // #endregion -// #region EVENTS - -// function get_current_event(): EventCard { -// return cards[ -// game.current_events[game.current_events.length - 1] -// ] as EventCard; -// } - -// function get_front_name(frontId: string) { -// switch (frontId) { -// case 'a': -// return 'the Aragon Front'; -// case 'm': -// return 'the Madrid Front'; -// case 'n': -// return 'the Nothern Front'; -// case 's': -// return 'the Southern Front'; -// case 'd': -// return 'the Front closest to Defeat'; -// case 'v': -// return 'the Front closest to Victory'; -// default: -// return ''; -// } -// } - -// function get_event_prompt(effect: Effect) { -// let prompt = ''; -// switch (effect.type) { -// case 'attack': -// return 'Attack ' + front_names[effect.target as string]; -// case 'bonus': -// break; -// case 'hero_points': -// return 'Select player with most Hero points'; -// case 'track': -// return 'Decrease ' + tracks[effect.target].name; -// } -// return prompt; -// } - -// function resolve_event_attack(target: string | number, value: number) { -// switch (target) { -// case 'v': -// break; -// case 'd': -// break; -// default: -// game.fronts[target] += value; -// } -// } - -// function fascist_event() { -// // log_h1('Year ' + game.year); -// const deck = fascist_decks[game.year]; -// const cardId = draw_card(deck); -// game.current_events.push(cardId); - -// const card = cards[cardId] as EventCard; - -// card.effects.forEach((effect) => { -// switch (effect.type) { -// case 'attack': -// resolve_event_attack(effect.target, effect.value); -// break; -// case 'bonus': -// break; -// case 'hero_points': -// break; -// case 'track': -// game.tracks[effect.target] += effect.value; -// break; -// } -// }); -// } - -// #endregion - // #region FRONTS -function get_fronts_closest_to(target: 'd' | 'v') { +function get_fronts_closest_to(target: 'd' | 'v'): FrontId[] { const values = Object.values(game.fronts).reduce( (accrued: number[], current: Front) => { if (current.status === null) { @@ -1433,7 +1414,7 @@ function get_fronts_closest_to(target: 'd' | 'v') { target === 'd' ? Math.min(...values) : Math.max(...values); return Object.keys(game.fronts).filter( (frontId) => game.fronts[frontId].value === targetValue - ); + ) as FrontId[]; } // #endregion |