From 8f5f3f54a610801a1d739636b49343a122f7113a Mon Sep 17 00:00:00 2001
From: Frans Bongers <fransbongers@macbookpro.home>
Date: Fri, 21 Mar 2025 21:34:05 +0100
Subject: momentum refactor

---
 rules.js | 94 +++++++++++++++++++++++++++++++---------------------------------
 1 file changed, 45 insertions(+), 49 deletions(-)

(limited to 'rules.js')

diff --git a/rules.js b/rules.js
index 2e1b0b9..29b676d 100644
--- a/rules.js
+++ b/rules.js
@@ -146,19 +146,18 @@ function setup_final_bid() {
     game.engine.push(create_function_node('setup_choose_card'));
     next();
 }
-function setup_player_turn() {
+function setup_player_turn(faction_id) {
     game.fascist = 0;
     game.card_played = 0;
     const next_faction = game.first_player === null
         ? get_player_order()[0]
-        : get_next_faction_in_player_order(get_active_faction());
+        : faction_id;
     if (game.first_player === null) {
         game.first_player = next_faction;
     }
     game.engine = [
         create_function_node('start_of_player_turn', { f: next_faction }),
         create_state_node('player_turn', next_faction),
-        create_function_node('end_of_player_turn', { f: next_faction }),
     ];
     next();
 }
@@ -172,7 +171,8 @@ function check_end_of_year_discard() {
 }
 function end_of_player_turn() {
     const { f: faction } = get_active_node_args();
-    if (get_next_faction_in_player_order(faction) === game.first_player) {
+    const next_faction = get_next_faction_in_player_order(faction);
+    if (next_faction === game.first_player) {
         game.engine = [
             create_state_node('change_active_player', game.initiative),
             create_function_node('resolve_fascist_test'),
@@ -180,7 +180,7 @@ function end_of_player_turn() {
         ];
     }
     else {
-        game.engine = [create_function_node('setup_player_turn')];
+        game.engine = [create_function_node('setup_player_turn', next_faction)];
     }
     next();
 }
@@ -443,6 +443,7 @@ function setup(seed, _scenario, options) {
         hero_points: [2, 2, 0, 14],
         initiative: data_1.MODERATES_ID,
         medallions: [[], [], [], []],
+        momentum: null,
         played_card: null,
         player_order: [data_1.MODERATE],
         selected_cards: [
@@ -972,7 +973,7 @@ states.play_card = {
     },
     card(c) {
         const faction = get_active_faction();
-        game.selected_cards[faction] = [c];
+        game.selected_cards[faction].push(c);
         game.card_played = 0;
         game.played_card = game.selected_cards[faction][0];
         resolve_active_and_proceed();
@@ -1047,26 +1048,14 @@ states.choose_final_bid = {
 };
 function setup_momentum() {
     const faction = get_active_faction();
-    if (game.faction_turn !== faction) {
-        insert_after_active_node(resolve_effect((0, data_1.create_effect)('play_card', faction, 1), 'momentum'));
+    game.momentum = faction;
+    const momentum_nodes = resolve_effect((0, data_1.create_effect)('play_card', faction, 1), data_1.MOMENTUM);
+    if (game.faction_turn !== null) {
+        game.engine.push(momentum_nodes);
         return;
     }
-    const node = get_nodes_for_state('player_turn')[0];
-    const player_needs_to_play_card = !game.card_played;
-    const { use_ap, use_morale_bonus, resolving_event } = node.a ?? {};
-    if (player_needs_to_play_card ||
-        use_ap ||
-        use_morale_bonus ||
-        resolving_event) {
-        node.a = {
-            ...(node.a || {}),
-            use_momentum: true,
-        };
-    }
     else {
-        insert_after_active_node(create_state_node('play_card', faction, {
-            src: 'momentum',
-        }));
+        insert_after_active_node(momentum_nodes);
     }
 }
 states.choose_medallion = {
@@ -1519,10 +1508,11 @@ states.player_turn = {
     prompt() {
         gen_spend_hero_points();
         const faction_id = get_active_faction();
-        let { use_ap, use_morale_bonus, use_momentum } = get_active_node_args();
+        let { use_ap, use_morale_bonus, src } = get_active_node_args();
         use_morale_bonus = use_morale_bonus && game.bonuses[data_1.MORALE_BONUS] === data_1.ON;
         const can_spend_hp = game.faction_turn === faction_id && game.hero_points[faction_id] > 0;
         const can_play_card = !game.card_played;
+        const use_momentum = game.momentum === faction_id && src !== data_1.MOMENTUM;
         if (use_momentum) {
             gen_action('use_momentum');
             if (use_ap || use_morale_bonus || can_play_card) {
@@ -1554,10 +1544,16 @@ states.player_turn = {
         resolve_spend_hp();
     },
     end_turn() {
-        if (game.faction_turn === get_active_faction()) {
+        const { src } = get_active_node_args();
+        const faction_id = get_active_faction();
+        if (game.faction_turn === faction_id) {
             game.faction_turn = null;
             game.played_card = null;
-            game.selected_cards[get_active_faction()] = [];
+            game.engine.push(create_function_node('end_of_player_turn', { f: faction_id }));
+        }
+        game.selected_cards[faction_id].pop();
+        if (src === data_1.MOMENTUM) {
+            game.momentum = null;
         }
         resolve_active_and_proceed(true);
     },
@@ -1599,18 +1595,10 @@ states.player_turn = {
         next();
     },
     use_momentum() {
-        log("Momentum:");
-        const faction = get_active_faction();
-        game.card_played = 0;
-        game.selected_cards[faction] = [];
-        update_active_node_args({
-            use_morale_bonus: false,
-            use_momentum: false,
-        });
-        insert_before_active_node(create_state_node('play_card', faction, {
-            src: 'momentum',
-        }));
-        next();
+        const faction_id = get_active_faction();
+        game.selected_cards[faction_id].pop();
+        game.momentum = null;
+        resolve_active_and_proceed();
     },
     use_morale_bonus() {
         log(`Morale Bonus:`);
@@ -1864,6 +1852,7 @@ states.swap_card_tableau_hand = {
         const selected_cards = game.selected_cards[faction];
         const hand = game.hands[faction];
         const tableau = game.tableaus[faction];
+        const { s: selected_at_start } = get_active_node_args();
         gen_action('skip');
         if (tableau.length === 0) {
             view.prompt = 'No card in your tableau to swap.';
@@ -1873,14 +1862,14 @@ states.swap_card_tableau_hand = {
             view.prompt = 'No card in your hand to swap.';
             return;
         }
-        if (selected_cards.length === 1) {
+        if (selected_cards.length === selected_at_start) {
             for (const c of hand) {
-                if (selected_cards[0] !== c) {
+                if (!selected_cards.includes(c)) {
                     gen_action_card(c);
                 }
             }
         }
-        if (selected_cards.length === 2) {
+        if (selected_cards.length === selected_at_start + 1) {
             for (const c of tableau) {
                 gen_action_card(c);
             }
@@ -1893,14 +1882,15 @@ states.swap_card_tableau_hand = {
         const faction = get_active_faction();
         const selected_cards = game.selected_cards[faction];
         selected_cards.push(c);
-        if (selected_cards.length === 3) {
+        const { s: selected_at_start } = get_active_node_args();
+        if (selected_cards.length === selected_at_start + 2) {
             const hand = game.hands[faction];
             const tableau = game.tableaus[faction];
-            array_remove_item(hand, selected_cards[1]);
-            array_remove_item(tableau, selected_cards[2]);
-            hand.push(selected_cards[2]);
-            tableau.push(selected_cards[1]);
-            game.selected_cards[faction].length = 1;
+            array_remove_item(hand, selected_cards[selected_at_start + 1]);
+            array_remove_item(tableau, selected_cards[selected_at_start + 2]);
+            hand.push(selected_cards[selected_at_start + 2]);
+            tableau.push(selected_cards[selected_at_start + 1]);
+            game.selected_cards[faction].length = selected_at_start;
             resolve_active_and_proceed();
         }
     },
@@ -2588,7 +2578,7 @@ function create_effects_node(effects, source) {
     return create_seq_node(nodes);
 }
 function get_faction_to_resolve_effect(effect) {
-    if (!effect.faction) {
+    if (effect.faction === undefined || effect.faction === null) {
         return get_active_faction();
     }
     if (effect.faction === data_1.INITIATIVE_PLAYER) {
@@ -2624,6 +2614,12 @@ function resolve_effect(effect, source) {
             src: source,
         });
     }
+    if (effect.type === 'swap_card_tableau_hand') {
+        return create_state_node('swap_card_tableau_hand', faction, {
+            ...args,
+            s: game.selected_cards[get_active_faction()].length
+        });
+    }
     let state = effect_type_state_map[effect.type];
     if (state !== undefined) {
         return create_state_node(state, faction, args);
@@ -2911,7 +2907,7 @@ function get_source_name(source) {
         case 'tr4': return tracks[4].name + ' Trigger';
         case 'track_icon':
             return 'Track Trigger';
-        case 'momentum':
+        case data_1.MOMENTUM:
             return 'Momentum';
     }
     return source;
-- 
cgit v1.2.3