summaryrefslogtreecommitdiff
path: root/rules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'rules.ts')
-rw-r--r--rules.ts122
1 files changed, 50 insertions, 72 deletions
diff --git a/rules.ts b/rules.ts
index 8fdf1b9..7c6075d 100644
--- a/rules.ts
+++ b/rules.ts
@@ -68,6 +68,7 @@ import data, {
ARAGON,
FASCIST_ID,
NORTHERN,
+ MOMENTUM,
} from './data';
const OBSERVER = 'Observer';
@@ -263,14 +264,14 @@ function setup_final_bid() {
next();
}
-function setup_player_turn() {
+function setup_player_turn(faction_id: FactionId) {
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;
@@ -279,7 +280,6 @@ function setup_player_turn() {
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();
@@ -301,14 +301,15 @@ 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'),
create_function_node('setup_bag_of_glory'),
];
} else {
- game.engine = [create_function_node('setup_player_turn')];
+ game.engine = [create_function_node('setup_player_turn', next_faction)];
}
next();
}
@@ -629,6 +630,7 @@ export function setup(seed: number, _scenario: string, options: Record<string,bo
hero_points: [2, 2, 0, 14],
initiative: MODERATES_ID,
medallions: [[],[],[],[]],
+ momentum: null,
played_card: null,
player_order: [MODERATE],
selected_cards: [
@@ -1228,7 +1230,7 @@ states.play_card = {
},
card(c: CardId) {
const faction = get_active_faction();
- game.selected_cards[faction] = [c];
+ game.selected_cards[faction].push(c);
game.card_played = 0;
// NOTE: I don't think we are using game.played_card in the UI at the moment?
@@ -1314,43 +1316,17 @@ states.choose_final_bid = {
function setup_momentum() {
const faction = get_active_faction();
- // Player received medallion outside of their normal turn
- // and must be resolved
- if (game.faction_turn !== faction) {
- insert_after_active_node(
- resolve_effect(create_effect('play_card', faction, 1), 'momentum')
- );
- return;
- }
-
- // Player gets medallion during their turn. Need to check if it can be player
- // right away or not. Depends on whether card for this turn has been fully resolved or not
-
- // Get player turn node
- const node: StateNode<PlayerTurnArgs> = 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 ?? ({} as PlayerTurnArgs);
+ game.momentum = faction;
- if (
- player_needs_to_play_card ||
- use_ap ||
- use_morale_bonus ||
- resolving_event
- ) {
- // Player hasn't fully resolved this turns card. Update args to enable button
- node.a = {
- ...(node.a || {}),
- use_momentum: true,
- };
+ const momentum_nodes = resolve_effect(create_effect('play_card', faction, 1), MOMENTUM);
+ if (game.faction_turn !== null) {
+ // Player received medallion during a player turn, either their own or another players.
+ // Push to end of the engine so it's resolved after current turn ends
+ game.engine.push(momentum_nodes);
+ return;
} else {
- // Player can resolve choosing a new card
- insert_after_active_node(
- create_state_node<PlayCardArgs>('play_card', faction, {
- src: 'momentum',
- })
- );
+ // Insert right after current node
+ insert_after_active_node(momentum_nodes)
}
}
@@ -1863,7 +1839,7 @@ states.player_turn = {
prompt() {
gen_spend_hero_points();
const faction_id = get_active_faction();
- let { use_ap, use_morale_bonus, use_momentum } =
+ let { use_ap, use_morale_bonus, src } =
get_active_node_args<PlayerTurnArgs>();
use_morale_bonus = use_morale_bonus && game.bonuses[MORALE_BONUS] === ON;
@@ -1872,6 +1848,7 @@ states.player_turn = {
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 !== MOMENTUM;
if (use_momentum) {
gen_action('use_momentum');
if (use_ap || use_morale_bonus || can_play_card) {
@@ -1905,10 +1882,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 === MOMENTUM) {
+ game.momentum = null;
}
resolve_active_and_proceed(true);
},
@@ -1954,23 +1937,10 @@ states.player_turn = {
next();
},
use_momentum() {
- log("Momentum:");
- const faction = get_active_faction();
- // We need to update since there can be a case where
- // morale bonus hasn't been used yet but is still set to true
- // due to bonus being turned off.
- game.card_played = 0;
- game.selected_cards[faction] = [];
- update_active_node_args<PlayerTurnArgs>({
- use_morale_bonus: false,
- use_momentum: false,
- });
- insert_before_active_node(
- create_state_node<PlayCardArgs>('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:`)
@@ -2280,6 +2250,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.';
@@ -2290,15 +2261,15 @@ 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) {
// do not swap currently executing card!
- 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);
}
@@ -2311,14 +2282,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();
}
},
@@ -3223,7 +3195,7 @@ function create_effects_node(
}
function get_faction_to_resolve_effect(effect: Effect): FactionId {
- if (!effect.faction) {
+ if (effect.faction === undefined || effect.faction === null) {
return get_active_faction();
}
if (effect.faction === INITIATIVE_PLAYER) {
@@ -3263,6 +3235,12 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
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
+ });
+ }
// Default cases where effect type is mapped to a state
let state = effect_type_state_map[effect.type];
@@ -3641,7 +3619,7 @@ function get_source_name(source: EffectSource): string {
case 'tr4': return tracks[4].name + ' Trigger';
case 'track_icon':
return 'Track Trigger';
- case 'momentum':
+ case MOMENTUM:
return 'Momentum';
}
return source;