summaryrefslogtreecommitdiff
path: root/rules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'rules.ts')
-rw-r--r--rules.ts425
1 files changed, 241 insertions, 184 deletions
diff --git a/rules.ts b/rules.ts
index bb64184..17f8a46 100644
--- a/rules.ts
+++ b/rules.ts
@@ -168,7 +168,7 @@ function gen_spend_hero_points() {
}
}
-const multiactive_states = ['choose_card', 'end_of_year_discard'];
+const multiactive_states = ['choose_card', 'end_of_year_discard', 'choose_final_bid'];
export function action(
state: Game,
@@ -257,10 +257,8 @@ function setup_final_bid() {
game.fascist = 0;
log_header('Final Bid', 't');
- const player_order = get_player_order();
- game.engine = player_order.map((faction_id) =>
- create_state_node('choose_final_bid', faction_id)
- );
+
+ game.engine = [create_state_node('choose_final_bid', 'all')];
game.engine.push(create_function_node('checkpoint'));
game.engine.push(create_function_node('resolve_final_bid'));
game.engine.push(create_function_node('setup_choose_card'));
@@ -337,7 +335,7 @@ const engine_functions: Record<string, Function> = {
start_year,
resolve_fascist_test,
resolve_final_bid,
- log_trigger,
+ place_blank_marker,
// Unique card effects
card1_event2,
card3_event2,
@@ -484,7 +482,7 @@ function next(checkpoint = false) {
if (next_active !== current_active && game.undo.length > 0) {
insert_before_active_node(
- create_state_node('confirm_turn', get_active_faction())
+ create_state_node('confirm_turn', get_active_faction(), { f: next_active })
);
game.state = 'confirm_turn';
return;
@@ -561,7 +559,8 @@ function game_view(state: Game, current: Player | 'Observer') {
current !== game.active &&
!game.active.includes(current as Player)
) {
- let inactive = states[game.state].inactive || game.state;
+ let src = get_active_node_args()?.src;
+ let inactive = src ? get_source_inactive(src) : states[game.state].inactive || game.state;
view.prompt = Array.isArray(game.active)
? `Waiting for ${game.active.join(' and ')} to ${inactive}.`
: `Waiting for ${game.active} to ${inactive}.`;
@@ -653,6 +652,7 @@ export function setup(seed: number, _scenario: string, options: Record<string,bo
[],
],
triggered_track_effects: [],
+ untriggered_track_effects: [],
log: [],
undo: [],
used_medallions: [],
@@ -688,6 +688,7 @@ function draw_hand_cards(faction_id: FactionId, count: number, indent = true) {
const deck = list_deck(faction_id);
if (game.medallions[faction_id].includes(INTELLIGENCE_MEDALLION_ID)) {
+ log(">M" + INTELLIGENCE_MEDALLION_ID);
count++;
}
let drawn_cards = 0;
@@ -774,7 +775,7 @@ const track_icon_to_track_id_map = {
};
states.activate_icon = {
- inactive: 'activate an icon',
+ inactive: 'activate a Morale Bonus icon',
prompt() {
gen_spend_hero_points();
const c = cards[game.played_card] as PlayerCard;
@@ -867,46 +868,19 @@ states.activate_icon = {
);
resolve_active_and_proceed();
},
- tr0(x: number) {
- if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(LIBERTY, x);
- } else {
- move_track_to(0, x);
- }
- resolve_active_and_proceed();
- },
- tr1(x: number) {
- if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(COLLECTIVIZATION, x);
- } else {
- move_track_to(1, x);
- }
- resolve_active_and_proceed();
- },
- tr2(x: number) {
+ trX(x: number, track: number) {
+ let old = game.tracks[track]
+ move_track_to(track, x);
if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(GOVERNMENT, x);
- } else {
- move_track_to(2, x);
- }
- resolve_active_and_proceed();
- },
- tr3(x: number) {
- if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(SOVIET_SUPPORT, x);
- } else {
- move_track_to(3, x);
- }
- resolve_active_and_proceed();
- },
- tr4(x: number) {
- if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(FOREIGN_AID, x);
- } else {
- move_track_to(4, x);
+ insert_use_organization_medallion_node(track, game.tracks[track] - old);
}
resolve_active_and_proceed();
},
+ tr0(x: number) { this.trX(x, 0) },
+ tr1(x: number) { this.trX(x, 1) },
+ tr2(x: number) { this.trX(x, 2) },
+ tr3(x: number) { this.trX(x, 3) },
+ tr4(x: number) { this.trX(x, 4) },
draw_card() {
draw_hand_cards(
get_active_faction(),
@@ -981,7 +955,7 @@ states.add_to_front = {
const args = get_active_node_args();
const possible_fronts = get_fronts_to_add_to(args.t);
if (possible_fronts.length === 0) {
- view.prompt = 'No valid front to add strength to.'
+ view.prompt = 'Cannot support ' + front_names[args.t] + '.'
gen_action('skip');
} else if (possible_fronts.length === 4) {
view.prompt = `Support any Front.`;
@@ -1016,7 +990,7 @@ states.attack_front = {
const number_of_fronts = possible_fronts.length;
if (number_of_fronts === 0) {
- view.prompt = 'No valid front to attack.';
+ view.prompt = 'Cannot attack ' + front_names[target] + '.'
gen_action('skip');
} else if (possible_fronts.length === 4) {
view.prompt = `Attack any Front.`;
@@ -1042,7 +1016,7 @@ states.attack_front = {
states.break_tie_final_bid = {
inactive: 'break tie for Final Bid',
prompt() {
- view.prompt = 'Choose the winner of the Final Bid';
+ view.prompt = 'Choose the winner of the Final Bid.';
const { winners } = get_active_node_args();
for (const f of winners) {
gen_action(faction_player_map[f]);
@@ -1065,7 +1039,7 @@ states.break_tie_final_bid = {
states.break_tie_winner = {
inactive: 'break tie for winner of the game',
prompt() {
- view.prompt = 'Choose the winner of the game';
+ view.prompt = 'Choose the winner of the game.';
const { winners } = get_active_node_args();
for (const f of winners) {
gen_action(faction_player_map[f]);
@@ -1104,7 +1078,7 @@ states.change_active_player = {
};
states.choose_area_ap = {
- inactive: 'choose area to use Action Points',
+ inactive: 'use action points',
prompt() {
gen_spend_hero_points();
const use_morale_bonus = game.can_use_mb === 1 && game.bonuses[MORALE_BONUS] === ON;
@@ -1213,7 +1187,7 @@ states.choose_area_ap = {
};
states.change_bonus = {
- inactive: 'select Bonus',
+ inactive: 'toggle Bonus',
prompt() {
gen_spend_hero_points();
const args = get_active_node_args();
@@ -1223,7 +1197,10 @@ states.change_bonus = {
game.bonuses[MORALE_BONUS] === ON) ||
(args.v === OFF && game.bonuses[args.t] === OFF)
) {
- view.prompt = `${bonus_names[args.t]} is already ${args.v === OFF ? 'off' : 'on'}.`;
+ if (args.t === 'any')
+ view.prompt = `Both bonuses are already ${args.v === OFF ? 'off' : 'on'}.`;
+ else
+ view.prompt = `${bonus_names[args.t]} is already ${args.v === OFF ? 'off' : 'on'}.`;
gen_action('skip');
}
else if (args.t === ANY && args.v === ON) {
@@ -1248,18 +1225,18 @@ states.change_bonus = {
},
skip() {
const args = get_active_node_args();
- logi(`${bonus_names[args.t]} ${args.v === OFF ? 'off' : 'on'}`);
+ logi(`Bonus already ${args.v === OFF ? 'off' : 'on'}`);
resolve_active_and_proceed();
},
};
// Used for effects that allow play of an extra card
states.play_card = {
- inactive: 'play a card',
+ inactive: 'play another card',
prompt() {
gen_spend_hero_points();
- view.prompt = 'Play a card.';
+ view.prompt = 'Play another card.';
const faction = get_active_faction();
@@ -1286,7 +1263,7 @@ states.play_card = {
const args = get_active_node_args();
if (args && args.src === 'momentum') {
- log_header("~ Momentum ~\nC" + game.played_card, faction);
+ log_header("~ M" + MOMENTUM_MEDALLION_ID + " ~\nC" + game.played_card, faction);
} else {
log_header("~ Play Card ~\nC" + game.played_card, faction);
}
@@ -1302,10 +1279,9 @@ states.play_card = {
// Multiactive choose card state
states.choose_card = {
- inactive: 'choose a card',
+ inactive: 'play a card for this turn',
prompt(player: Player) {
- gen_spend_hero_points();
- view.prompt = 'Choose a card to play this turn.';
+ view.prompt = 'Play a card for this turn.';
const faction = player_faction_map[player];
@@ -1326,9 +1302,6 @@ states.choose_card = {
gen_action('skip');
}
},
- spend_hp() {
- resolve_spend_hp();
- },
card(c: CardId, player: Player) {
const faction = player_faction_map[player];
game.selected_cards[faction] = [c];
@@ -1352,35 +1325,47 @@ states.choose_card = {
};
states.choose_final_bid = {
- inactive: 'choose Final Bid',
- prompt() {
- view.prompt = 'Add a card to the Final Bid.';
- const faction = get_active_faction();
- for (let c of game.hands[faction]) {
- if (!game.selected_cards[faction].includes(c)) {
- gen_action_card(c);
+ inactive: 'add cards to the Final Bid',
+ prompt(player: Player) {
+ const faction = player_faction_map[player];
+
+ const number_selected = game.selected_cards[faction].length;
+ const number_hand = game.hands[faction].length;
+ if (number_selected < 3 && !(number_hand < 4 && number_selected === number_hand - 1)) {
+ for (let c of game.hands[faction]) {
+ if (!game.selected_cards[faction].includes(c)) {
+ gen_action_card(c);
+ }
}
}
- gen_action('done');
+
+ let n = 0
+ for (let c of game.selected_cards[faction]) {
+ n += (cards[c] as PlayerCard).strength
+ }
+ if (n > 0)
+ view.prompt = `Final Bid for Glory: Discard up to 3 cards. Your bid is ${n} strength.`
+ else
+ view.prompt = `Final Bid for Glory: Discard up to 3 cards for strength.`
+
+ gen_action('confirm');
+ if (game.selected_cards[faction].length > 0)
+ gen_action('undo');
},
- card(c: CardId) {
- const faction = get_active_faction();
+ card(c: CardId, player: Player) {
+ const faction = player_faction_map[player];
game.selected_cards[faction].push(c);
- const number_selected = game.selected_cards[faction].length;
-
- const number_hand = game.hands[faction].length;
- if (
- number_selected === 3 ||
- (number_hand < 4 && number_selected === number_hand - 1)
- ) {
+ },
+ undo(_, player: Player) {
+ const faction = player_faction_map[player];
+ game.selected_cards[faction].length--;
+ },
+ confirm(_, player: Player) {
+ set_delete(game.active as Player[], player);
+ if (game.active.length === 0) {
resolve_active_and_proceed();
- } else {
- next();
}
},
- done() {
- resolve_active_and_proceed(true);
- },
};
function setup_momentum() {
@@ -1401,7 +1386,7 @@ function setup_momentum() {
}
states.choose_medallion = {
- inactive: 'claim a medallion',
+ inactive: 'claim a Medallion',
prompt() {
gen_spend_hero_points();
view.prompt = 'Claim a Medallion.';
@@ -1457,9 +1442,21 @@ states.choose_medallion = {
};
states.confirm_turn = {
- inactive: 'confirm their turn',
+ inactive: 'confirm their move',
+ auto_resolve() {
+ // don't pause to confirm actions during fascist event
+ if (game.fascist === 1)
+ return true
+ return false
+ },
prompt() {
- view.prompt = 'You will not be able to undo this action.';
+ if (game.fascist === 2)
+ view.prompt = 'Fascist Test: Done.'
+ else if (game.fascist === 1) {
+ let f = get_active_node_args().f
+ view.prompt = `Fascist Event: ${f} needs to act.`
+ } else
+ view.prompt = 'You will not be able to undo this action.'
gen_action('confirm');
},
confirm() {
@@ -1468,7 +1465,7 @@ states.confirm_turn = {
};
states.confirm_fascist_turn = {
- inactive: 'confirm fascist turn',
+ inactive: 'end the Fascist turn',
prompt() {
view.prompt = "Done.";
gen_action('confirm');
@@ -1479,7 +1476,7 @@ states.confirm_fascist_turn = {
};
states.draw_card = {
- inactive: 'draw a card',
+ inactive: 'draw cards',
auto_resolve() {
const { src, v } = get_active_node_args();
if (src !== 'fascist_test') {
@@ -1515,22 +1512,19 @@ function draw_glory_from_bag() {
game.glory.push(faction);
- game.glory_current_year = game.glory_current_year = [
- false,
- false,
- false,
- ];
-
game.glory_current_year[faction] = true;
array_remove(game.bag_of_glory, index);
- logi(`Pulled T${faction} from the Bag`);
+ log(`Pulled T${faction} from the Bag.`);
}
states.draw_glory = {
inactive: 'draw from the Bag of Glory',
auto_resolve() {
+ // active player to trigger the draw
+ if (get_active_faction() === game.initiative)
+ return false;
draw_glory_from_bag();
return true;
},
@@ -1566,14 +1560,11 @@ states.end_of_year_discard = {
for (let c of tableau) gen_action_card(c);
}
- if (needs_to_discard_from_hand && needs_to_discard_from_tableau) {
- view.prompt = 'Discard a card from your hand or tableau';
- } else if (needs_to_discard_from_hand || needs_to_discard_from_tableau) {
- view.prompt = `Discard a card from your ${
- needs_to_discard_from_hand ? 'hand' : 'tableau'
- }`;
+ view.prompt = JSON.stringify({needs_to_discard_from_hand,needs_to_discard_from_tableau});
+ if (needs_to_discard_from_hand || needs_to_discard_from_tableau) {
+ view.prompt = 'End of Year: Discard cards from your hand and tableau.';
} else {
- view.prompt = 'Confirm discard';
+ view.prompt = 'End of Year: Done.';
view.actions.confirm = 1;
}
if (discarded[faction_id].h.length > 0 || discarded[faction_id].t.length > 0) {
@@ -1633,7 +1624,7 @@ states.end_of_year_discard = {
};
states.hero_points = {
- inactive: 'gain Hero points',
+ inactive: 'gain or lose Hero points',
auto_resolve() {
const { src, v } = get_active_node_args();
if (src !== 'fascist_test') {
@@ -1652,14 +1643,14 @@ states.hero_points = {
if (value < 0) {
view.prompt =
value < -1
- ? `Lose ${Math.abs(value)} Hero points`
- : 'Lose 1 Hero point';
+ ? `Lose ${Math.abs(value)} Hero points.`
+ : 'Lose a Hero point.';
gen_action('lose_hp');
return;
}
if (game.hero_points[POOL_ID] > 0) {
view.prompt =
- value > 1 ? `Gain ${value} Hero points.` : 'Gain 1 Hero point.';
+ value > 1 ? `Gain ${value} Hero points.` : 'Gain a Hero point.';
gen_action('gain_hp');
} else {
view.prompt = 'No Hero points available in pool.';
@@ -1704,7 +1695,7 @@ function resolve_player_with_most_hero_points(faction: FactionId) {
}
states.select_player_with_most_hero_points = {
- inactive: 'choose a Player',
+ inactive: 'choose who will gain or lose Hero points',
prompt() {
gen_spend_hero_points();
const { v } = get_active_node_args();
@@ -1774,6 +1765,7 @@ states.move_track = {
can_move_track = gen_move_track(track, game.tracks[track] + value) || can_move_track;
}
if (!can_move_track) {
+ view.prompt = view.prompt.replace("Move", "Cannot move")
gen_action('skip');
}
},
@@ -1801,6 +1793,14 @@ states.move_track = {
resolve_active_and_proceed();
},
skip() {
+ const node = get_active_node();
+ const track = node.a.t
+ if (track === GOVERNMENT)
+ logi(`Government +0`)
+ else if (track === LIBERTY_OR_COLLECTIVIZATION)
+ logi("Liberty or Collectivization +0")
+ else
+ logi(`${get_track_name(track)} +0`)
resolve_active_and_proceed();
},
};
@@ -1856,7 +1856,7 @@ function can_move_track_down(track_id): boolean {
// NOTE: we can probably remove this state. I don't think it's used anywhere anymore
states.move_track_up_or_down = {
- inactive: 'move a track',
+ inactive: 'move a Track',
auto_resolve() {
const { track_id, strength } = get_active_node_args();
const can_move_up = can_move_track_up(track_id);
@@ -1910,7 +1910,7 @@ states.peek_fascist_cards = {
inactive: 'peek at Fascist cards',
prompt() {
gen_spend_hero_points();
- view.prompt = 'Return one card to the top of the Fascist deck.';
+ view.prompt = 'Return one Fascist card to the top of the Fascist deck and discard the others.';
view.fascist_cards = game.fascist_cards;
for (const c of game.fascist_cards) {
gen_action_card(c);
@@ -1920,6 +1920,7 @@ states.peek_fascist_cards = {
resolve_spend_hp();
},
card(c: CardId) {
+ log(">Peeked at top three Fascist cards, returned one, and discarded the others")
game.top_of_events_deck = c;
for (const ec of game.fascist_cards) {
if (ec !== c) {
@@ -1956,13 +1957,13 @@ function set_player_turn_prompt({
else if (use_ap)
view.prompt = "Use Action Points."
else if (use_momentum)
- view.prompt = "Play a second card."
+ view.prompt = "Use Momentum Medallion."
else
- view.prompt = "Player Turn: Done."
+ view.prompt = "Player turn done."
}
states.player_turn = {
- inactive: 'play their turn',
+ inactive: 'play their card',
prompt() {
gen_spend_hero_points();
const faction_id = get_active_faction();
@@ -2070,11 +2071,18 @@ states.player_turn = {
},
};
+function remove_blank_marker(b: number) {
+ const track_id = Math.floor(b / 11);
+ const space_id = b % 11;
+ set_delete(game.triggered_track_effects, b);
+ logi(`Removed Blank from ${get_track_name(track_id)} ${space_id}`);
+}
+
states.remove_blank_marker = {
inactive: 'remove a Blank marker',
prompt() {
gen_spend_hero_points();
- view.prompt = 'Remove a Blank marker';
+ view.prompt = 'Remove a Blank marker.';
for (const b of game.triggered_track_effects) {
gen_action_blank_marker(b);
@@ -2088,15 +2096,31 @@ states.remove_blank_marker = {
resolve_spend_hp();
},
blank_marker(b: number) {
+ remove_blank_marker(b);
+ resolve_active_and_proceed();
+ },
+ skip() {
+ resolve_active_and_proceed();
+ },
+};
+
+states.remove_blank_marker_archives = {
+ inactive: 'remove a Blank marker',
+ prompt() {
+ view.prompt = 'Archives Medallion: Remove a Blank marker.';
+ for (const b of game.triggered_track_effects) {
+ gen_action_blank_marker(b);
+ }
+ if (game.triggered_track_effects.length === 0) {
+ view.prompt = 'No Blank marker to remove.';
+ gen_action('skip');
+ }
+ },
+ blank_marker(b: number) {
const faction = get_active_faction();
pay_hero_points(faction, 1);
-
- const track_id = Math.floor(b / 11);
- const space_id = b % 11;
- logp(`removed blank marker from ${get_track_name(track_id)} ${space_id}`);
- game.triggered_track_effects = game.triggered_track_effects.filter(
- (id) => id !== b
- );
+ log(">M" + ARCHIVES_MEDALLION_ID);
+ remove_blank_marker(b);
game.used_medallions.push(ARCHIVES_MEDALLION_ID);
resolve_active_and_proceed();
},
@@ -2134,7 +2158,7 @@ states.remove_attack_from_fronts = {
gen_action_front(id);
});
if (!is_front_with_attacks) {
- view.prompt = 'No valid Front to remove attacks from.';
+ view.prompt = 'No Front to remove attacks from.';
gen_action('skip');
}
},
@@ -2244,13 +2268,13 @@ states.spend_hero_points = {
gen_action('draw_card');
if (can_use_medallion(ARCHIVES_MEDALLION_ID, faction)) {
- gen_action('remove_blank_marker');
+ gen_action('archives');
if (game.triggered_track_effects.length === 0) {
- view.actions['remove_blank_marker'] = 0;
+ view.actions['archives'] = 0;
}
}
if (can_use_medallion(VOLUNTEERS_MEDALLION_ID, faction)) {
- gen_action('add_to_front');
+ gen_action('volunteers');
}
if (hero_points < 2) {
@@ -2285,11 +2309,13 @@ states.spend_hero_points = {
gen_spend_hero_points_move_track(GOVERNMENT, Math.floor(hero_points / 4));
},
- add_to_front() {
+ volunteers() {
const faction = get_active_faction();
+ log(">M" + VOLUNTEERS_MEDALLION_ID)
pay_hero_points(faction, 1);
insert_after_active_node(
create_state_node('add_to_front', faction, {
+ src: 'volunteers',
t: ANY,
v: 1,
})
@@ -2310,14 +2336,14 @@ states.spend_hero_points = {
draw_hand_cards(faction, 1);
resolve_active_and_proceed();
},
- remove_blank_marker() {
+ archives() {
const faction = get_active_faction();
if (game.used_medallions) {
game.used_medallions.push(ARCHIVES_MEDALLION_ID);
} else {
game.used_medallions = [ARCHIVES_MEDALLION_ID];
}
- insert_after_active_node(create_state_node('remove_blank_marker', faction));
+ insert_after_active_node(create_state_node('remove_blank_marker_archives', faction));
resolve_active_and_proceed();
},
tr0(x: number) {
@@ -2355,7 +2381,7 @@ states.spend_hero_points = {
Use the length of selected_cards[faction] to figure out where we are.
*/
states.swap_card_tableau_hand = {
- inactive: 'swap cards',
+ inactive: 'swap cards in their tableau and hand',
prompt() {
gen_spend_hero_points();
view.prompt = 'Swap a card in your tableau with a card in your hand.';
@@ -2476,11 +2502,12 @@ function trash_card(faction: FactionId) {
}
states.use_organization_medallion = {
- inactive: 'use Organization Medallion',
+ inactive: 'choose to use Organization Medallion',
prompt() {
- gen_spend_hero_points();
- view.prompt = 'Use Organization Medallion?';
-
+ // gen_spend_hero_points(); // confusing when available during this question
+ let { t, v } = get_active_node_args();
+ view.prompt = `Organization Medallion: Spend 1 Hero point to increase ${get_track_name(t)} movement?`;
+ gen_action(track_action_name[t], v)
gen_action('yes');
gen_action('no');
},
@@ -2491,42 +2518,39 @@ states.use_organization_medallion = {
const faction = get_active_faction();
pay_hero_points(faction, 1);
game.used_medallions.push(ORGANIZATION_MEDALLION_ID);
-
- // Value is the clicked location on the track
let { t, v } = get_active_node_args();
-
- // If player uses medallion we need to add or subtract
- // depending on direction of movement
- if (v > game.tracks[t]) {
- v++;
- } else {
- v--;
- }
-
- move_track(t, v - game.tracks[t]);
+ log("M" + ORGANIZATION_MEDALLION_ID + ":")
+ move_track_to(t, v);
resolve_active_and_proceed();
},
+ tr0() { this.yes() },
+ tr1() { this.yes() },
+ tr2() { this.yes() },
+ tr3() { this.yes() },
+ tr4() { this.yes() },
no() {
- const { t, v } = get_active_node_args();
-
- move_track(t, v);
resolve_active_and_proceed();
},
};
states.use_strategy_medallion = {
- inactive: 'use Strategy Medallion',
+ inactive: 'choose to use Strategy Medallion',
prompt() {
- gen_spend_hero_points();
- view.prompt = 'Use Strategy Medallion?';
-
+ // gen_spend_hero_points(); // confusing when available during this question
+ const { f } = get_active_node_args();
+ view.prompt = `Strategy Medallion: Add 1 strength to ${front_names[f]}?`;
+ gen_action_front(f)
gen_action('yes');
gen_action('no');
},
spend_hp() {
resolve_spend_hp();
},
+ front(_) {
+ this.yes()
+ },
yes() {
+ log(">M" + STRATEGY_MEDALLION_ID);
game.used_medallions.push(STRATEGY_MEDALLION_ID);
const { f } = get_active_node_args();
const faction = get_active_faction();
@@ -2803,12 +2827,10 @@ function end_of_year() {
false,
];
- const player_order = get_player_order();
-
const engine = [];
for (let i = 0; i < glory_to_draw[game.year]; ++i) {
- engine.push(create_state_node('draw_glory', player_order[i % 3]));
+ engine.push(create_state_node('draw_glory', game.initiative));
}
engine.push(create_function_node('end_of_year_cleanup'));
@@ -2960,6 +2982,7 @@ function resolve_fascist_test() {
? 2
: 0;
if (can_use_medallion(PROPAGANDA_MEDALLION_ID, faction)) {
+ log(">M" + PROPAGANDA_MEDALLION_ID);
hero_points_gain += 2;
}
if (hero_points_gain > 0) {
@@ -2991,12 +3014,13 @@ function resolve_fascist_test() {
function resolve_final_bid() {
let highest_bid = 0;
let winners: FactionId[] = [];
+ log("Final Bid for Glory:")
for (const f of get_player_order()) {
let player_bid = 0;
for (const c of game.selected_cards[f]) {
player_bid += (cards[c] as PlayerCard).strength;
}
- log(`${faction_player_map[f]} bid ${player_bid} cards`);
+ log(`>${faction_player_map[f]} ${player_bid} strength`);
if (player_bid === highest_bid) {
winners.push(f);
} else if (player_bid > highest_bid) {
@@ -3136,21 +3160,18 @@ function move_track_to(track_id: number, new_value: number) {
triggered_spaces.forEach((space_id) => {
const trigger = tracks[track_id].triggers[space_id];
+ const blank = get_blank_marker_id(track_id, space_id);
if (
trigger !== null &&
- !game.triggered_track_effects.includes(
- get_blank_marker_id(track_id, space_id)
- )
+ !game.triggered_track_effects.includes(blank) &&
+ !game.untriggered_track_effects.includes(blank)
) {
- if (space_id !== 0) {
- game.triggered_track_effects.push(
- get_blank_marker_id(track_id, space_id)
- );
- }
+ set_delete(game.triggered_track_effects, blank);
+ set_add(game.untriggered_track_effects, blank);
const node = resolve_effect(trigger, tracks[track_id].action);
if (node !== null) {
insert_after_active_node(node);
- insert_after_active_node(create_function_node('log_trigger', [track_id, space_id]));
+ insert_after_active_node(create_function_node('place_blank_marker', [track_id, space_id]));
}
}
});
@@ -3176,14 +3197,22 @@ function can_use_medallion(medallion_id: number, faction?: FactionId) {
function insert_use_organization_medallion_node(
track_id: number,
- value: number
+ delta: number
) {
const faction = get_active_faction();
-
+ if (delta > 0)
+ delta = 1
+ else if (delta < 0)
+ delta = -1
+ else
+ return;
+ let v = game.tracks[track_id] + delta
+ if (v < 0 || v > 10)
+ return;
insert_after_active_node(
create_state_node('use_organization_medallion', faction, {
t: track_id,
- v: value,
+ v: v,
})
);
}
@@ -3471,7 +3500,8 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
function win_final_bid(faction_id: FactionId) {
log_br();
- log(`${faction_player_map[faction_id]} won the Final Bid`);
+ log(`${faction_player_map[faction_id]} won the Final Bid:`);
+ logi("Placed T" + faction_id)
game.glory.push(faction_id);
}
@@ -3555,9 +3585,12 @@ function log_header(msg: string, prefix: string | number) {
log_br();
}
-function log_trigger(args) {
+function place_blank_marker(args) {
let [ track_id, space_id ] = args;
+ let blank = get_blank_marker_id(track_id, space_id);
log(`Trigger ${get_track_name(track_id)} ${space_id}:`);
+ set_delete(game.untriggered_track_effects, blank);
+ set_add(game.triggered_track_effects, blank);
resolve_active_and_proceed();
}
@@ -3729,13 +3762,36 @@ function get_source_name(source: EffectSource): string {
case 'tr3': return tracks[3].name + ' Trigger';
case 'tr4': return tracks[4].name + ' Trigger';
case 'track_icon':
- return 'Track Trigger';
+ throw "UNUSED"
+ case 'volunteers':
+ return 'Volunteers Medallion'
case MOMENTUM:
return 'Momentum';
}
return source;
}
+function get_source_inactive(source: EffectSource): string {
+ switch (source) {
+ case 'player_event':
+ return 'execute ' + cards[game.played_card].title;
+ case 'fascist_event':
+ return 'execute ' + cards[game.current_events[game.current_events.length - 1]].title;
+ case 'fascist_test':
+ return 'resolve Test';
+ case 'tr0': return 'trigger ' + tracks[0].name + ' icon';
+ case 'tr1': return 'trigger ' + tracks[1].name + ' icon';
+ case 'tr2': return 'trigger ' + tracks[2].name + ' icon';
+ case 'tr3': return 'trigger ' + tracks[3].name + ' icon';
+ case 'tr4': return 'trigger ' + tracks[4].name + ' icon';
+ case 'track_icon':
+ throw "UNUSED"
+ case MOMENTUM:
+ return 'use Momentum';
+ }
+ return source;
+}
+
function get_factions_with_most_hero_poins(): FactionId[] {
let most_hero_points = null;
let faction_ids = [];
@@ -3771,6 +3827,7 @@ function list_deck(id: FactionId | FascistId) {
if (id === FASCIST_ID) {
if (game.current_events.includes(card)) return;
if (game.discard[id].includes(card)) return;
+ if (game.fascist_cards && game.fascist_cards.includes(card)) return;
} else if (
game.hands[id].includes(card) ||
game.discard[id].includes(card) ||
@@ -3921,19 +3978,19 @@ function array_insert<T>(array: T[], index: number, item: T) {
// return false;
// }
-// function set_add<T>(set: T[], item: T) {
-// // eslint-disable-line @typescript-eslint/no-unused-vars
-// let a = 0;
-// let b = set.length - 1;
-// while (a <= b) {
-// const m = (a + b) >> 1;
-// const x = set[m];
-// if (item < x) b = m - 1;
-// else if (item > x) a = m + 1;
-// else return set;
-// }
-// return array_insert(set, a, item);
-// }
+function set_add<T>(set: T[], item: T) {
+ // eslint-disable-line @typescript-eslint/no-unused-vars
+ let a = 0;
+ let b = set.length - 1;
+ while (a <= b) {
+ const m = (a + b) >> 1;
+ const x = set[m];
+ if (item < x) b = m - 1;
+ else if (item > x) a = m + 1;
+ else return set;
+ }
+ return array_insert(set, a, item);
+}
// function set_delete<T>(set: T[], item: T) {
// let a = 0;