summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js387
1 files changed, 234 insertions, 153 deletions
diff --git a/rules.js b/rules.js
index e44b8e0..a3cdfb2 100644
--- a/rules.js
+++ b/rules.js
@@ -76,7 +76,7 @@ function gen_spend_hero_points() {
gen_action('spend_hp');
}
}
-const multiactive_states = ['choose_card', 'end_of_year_discard'];
+const multiactive_states = ['choose_card', 'end_of_year_discard', 'choose_final_bid'];
function action(state, player, action, arg) {
game = state;
if (action !== 'undo' && !multiactive_states.includes(game.state)) {
@@ -140,8 +140,7 @@ function setup_choose_card() {
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'));
@@ -207,7 +206,7 @@ const engine_functions = {
start_year,
resolve_fascist_test,
resolve_final_bid,
- log_trigger,
+ place_blank_marker,
card1_event2,
card3_event2,
card10_event2,
@@ -311,7 +310,7 @@ function next(checkpoint = false) {
const current_active = game.active;
const next_active = get_next_active(node.p);
if (next_active !== current_active && game.undo.length > 0) {
- insert_before_active_node(create_state_node('confirm_turn', get_active_faction()));
+ insert_before_active_node(create_state_node('confirm_turn', get_active_faction(), { f: next_active }));
game.state = 'confirm_turn';
return;
}
@@ -369,7 +368,8 @@ function game_view(state, current) {
}
else if (current !== game.active &&
!game.active.includes(current)) {
- 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}.`;
@@ -456,6 +456,7 @@ function setup(seed, _scenario, options) {
[],
],
triggered_track_effects: [],
+ untriggered_track_effects: [],
log: [],
undo: [],
used_medallions: [],
@@ -480,6 +481,7 @@ function setup(seed, _scenario, options) {
function draw_hand_cards(faction_id, count, indent = true) {
const deck = list_deck(faction_id);
if (game.medallions[faction_id].includes(data_1.INTELLIGENCE_MEDALLION_ID)) {
+ log(">M" + data_1.INTELLIGENCE_MEDALLION_ID);
count++;
}
let drawn_cards = 0;
@@ -549,7 +551,7 @@ const track_icon_to_track_id_map = {
d_soviet_support: data_1.SOVIET_SUPPORT,
};
states.activate_icon = {
- inactive: 'activate an icon',
+ inactive: 'activate a Morale Bonus icon',
prompt() {
gen_spend_hero_points();
const c = cards[game.played_card];
@@ -623,51 +625,19 @@ states.activate_icon = {
update_front(f, get_icon_count_in_tableau('add_to_front'), get_active_faction());
resolve_active_and_proceed();
},
- tr0(x) {
- if (can_use_medallion(data_1.ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(data_1.LIBERTY, x);
- }
- else {
- move_track_to(0, x);
- }
- resolve_active_and_proceed();
- },
- tr1(x) {
- if (can_use_medallion(data_1.ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(data_1.COLLECTIVIZATION, x);
- }
- else {
- move_track_to(1, x);
- }
- resolve_active_and_proceed();
- },
- tr2(x) {
- if (can_use_medallion(data_1.ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(data_1.GOVERNMENT, x);
- }
- else {
- move_track_to(2, x);
- }
- resolve_active_and_proceed();
- },
- tr3(x) {
+ trX(x, track) {
+ let old = game.tracks[track];
+ move_track_to(track, x);
if (can_use_medallion(data_1.ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(data_1.SOVIET_SUPPORT, x);
- }
- else {
- move_track_to(3, x);
- }
- resolve_active_and_proceed();
- },
- tr4(x) {
- if (can_use_medallion(data_1.ORGANIZATION_MEDALLION_ID)) {
- insert_use_organization_medallion_node(data_1.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) { this.trX(x, 0); },
+ tr1(x) { this.trX(x, 1); },
+ tr2(x) { this.trX(x, 2); },
+ tr3(x) { this.trX(x, 3); },
+ tr4(x) { this.trX(x, 4); },
draw_card() {
draw_hand_cards(get_active_faction(), get_icon_count_in_tableau('draw_card'));
resolve_active_and_proceed();
@@ -736,7 +706,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) {
@@ -769,7 +739,7 @@ states.attack_front = {
const possible_fronts = get_fronts_to_add_to(target, n);
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) {
@@ -795,7 +765,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]);
@@ -817,7 +787,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]);
@@ -849,7 +819,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[data_1.MORALE_BONUS] === data_1.ON;
@@ -947,7 +917,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();
@@ -955,7 +925,10 @@ states.change_bonus = {
game.bonuses[data_1.TEAMWORK_BONUS] === data_1.ON &&
game.bonuses[data_1.MORALE_BONUS] === data_1.ON) ||
(args.v === data_1.OFF && game.bonuses[args.t] === data_1.OFF)) {
- view.prompt = `${bonus_names[args.t]} is already ${args.v === data_1.OFF ? 'off' : 'on'}.`;
+ if (args.t === 'any')
+ view.prompt = `Both bonuses are already ${args.v === data_1.OFF ? 'off' : 'on'}.`;
+ else
+ view.prompt = `${bonus_names[args.t]} is already ${args.v === data_1.OFF ? 'off' : 'on'}.`;
gen_action('skip');
}
else if (args.t === data_1.ANY && args.v === data_1.ON) {
@@ -981,15 +954,15 @@ states.change_bonus = {
},
skip() {
const args = get_active_node_args();
- logi(`${bonus_names[args.t]} ${args.v === data_1.OFF ? 'off' : 'on'}`);
+ logi(`Bonus already ${args.v === data_1.OFF ? 'off' : 'on'}`);
resolve_active_and_proceed();
},
};
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();
const hand = game.hands[faction];
for (let c of hand) {
@@ -1011,7 +984,7 @@ states.play_card = {
game.played_card = game.selected_cards[faction][game.selected_cards[faction].length - 1];
const args = get_active_node_args();
if (args && args.src === 'momentum') {
- log_header("~ Momentum ~\nC" + game.played_card, faction);
+ log_header("~ M" + data_1.MOMENTUM_MEDALLION_ID + " ~\nC" + game.played_card, faction);
}
else {
log_header("~ Play Card ~\nC" + game.played_card, faction);
@@ -1024,10 +997,9 @@ states.play_card = {
},
};
states.choose_card = {
- inactive: 'choose a card',
+ inactive: 'play a card for this turn',
prompt(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];
if (game.selected_cards[faction].length === 0) {
view.actions.undo = 0;
@@ -1046,9 +1018,6 @@ states.choose_card = {
gen_action('skip');
}
},
- spend_hp() {
- resolve_spend_hp();
- },
card(c, player) {
const faction = player_faction_map[player];
game.selected_cards[faction] = [c];
@@ -1071,32 +1040,43 @@ 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) {
+ 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].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) {
- const faction = get_active_faction();
+ card(c, 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) {
+ const faction = player_faction_map[player];
+ game.selected_cards[faction].length--;
+ },
+ confirm(_, player) {
+ set_delete(game.active, player);
+ if (game.active.length === 0) {
resolve_active_and_proceed();
}
- else {
- next();
- }
- },
- done() {
- resolve_active_and_proceed(true);
},
};
function setup_momentum() {
@@ -1112,7 +1092,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.';
@@ -1164,9 +1144,21 @@ states.choose_medallion = {
},
};
states.confirm_turn = {
- inactive: 'confirm their turn',
+ inactive: 'confirm their move',
+ auto_resolve() {
+ 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() {
@@ -1174,7 +1166,7 @@ states.confirm_turn = {
},
};
states.confirm_fascist_turn = {
- inactive: 'confirm fascist turn',
+ inactive: 'end the Fascist turn',
prompt() {
view.prompt = "Done.";
gen_action('confirm');
@@ -1184,7 +1176,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') {
@@ -1217,18 +1209,15 @@ function draw_glory_from_bag() {
const index = random(game.bag_of_glory.length);
const faction = game.bag_of_glory[index];
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() {
+ if (get_active_faction() === game.initiative)
+ return false;
draw_glory_from_bag();
return true;
},
@@ -1260,14 +1249,12 @@ 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) {
@@ -1321,7 +1308,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') {
@@ -1341,14 +1328,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 {
@@ -1392,7 +1379,7 @@ function resolve_player_with_most_hero_points(faction) {
resolve_active_and_proceed();
}
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();
@@ -1456,6 +1443,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');
}
},
@@ -1483,6 +1471,14 @@ states.move_track = {
resolve_active_and_proceed();
},
skip() {
+ const node = get_active_node();
+ const track = node.a.t;
+ if (track === data_1.GOVERNMENT)
+ logi(`Government +0`);
+ else if (track === data_1.LIBERTY_OR_COLLECTIVIZATION)
+ logi("Liberty or Collectivization +0");
+ else
+ logi(`${get_track_name(track)} +0`);
resolve_active_and_proceed();
},
};
@@ -1514,7 +1510,7 @@ function can_move_track_down(track_id) {
return true;
}
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);
@@ -1570,7 +1566,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);
@@ -1580,6 +1576,7 @@ states.peek_fascist_cards = {
resolve_spend_hp();
},
card(c) {
+ 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) {
@@ -1605,12 +1602,12 @@ function set_player_turn_prompt({ can_play_card, use_ap, use_momentum, use_moral
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();
@@ -1699,11 +1696,17 @@ states.player_turn = {
next();
},
};
+function remove_blank_marker(b) {
+ 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);
}
@@ -1716,12 +1719,30 @@ states.remove_blank_marker = {
resolve_spend_hp();
},
blank_marker(b) {
+ 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) {
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" + data_1.ARCHIVES_MEDALLION_ID);
+ remove_blank_marker(b);
game.used_medallions.push(data_1.ARCHIVES_MEDALLION_ID);
resolve_active_and_proceed();
},
@@ -1751,7 +1772,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');
}
},
@@ -1844,13 +1865,13 @@ states.spend_hero_points = {
}
gen_action('draw_card');
if (can_use_medallion(data_1.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(data_1.VOLUNTEERS_MEDALLION_ID, faction)) {
- gen_action('add_to_front');
+ gen_action('volunteers');
}
if (hero_points < 2) {
return;
@@ -1872,10 +1893,12 @@ states.spend_hero_points = {
}
gen_spend_hero_points_move_track(data_1.GOVERNMENT, Math.floor(hero_points / 4));
},
- add_to_front() {
+ volunteers() {
const faction = get_active_faction();
+ log(">M" + data_1.VOLUNTEERS_MEDALLION_ID);
pay_hero_points(faction, 1);
insert_after_active_node(create_state_node('add_to_front', faction, {
+ src: 'volunteers',
t: data_1.ANY,
v: 1,
}));
@@ -1895,7 +1918,7 @@ 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(data_1.ARCHIVES_MEDALLION_ID);
@@ -1903,7 +1926,7 @@ states.spend_hero_points = {
else {
game.used_medallions = [data_1.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) {
@@ -1933,7 +1956,7 @@ states.spend_hero_points = {
},
};
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.';
@@ -2047,10 +2070,11 @@ function trash_card(faction) {
resolve_active_and_proceed();
}
states.use_organization_medallion = {
- inactive: 'use Organization Medallion',
+ inactive: 'choose to use Organization Medallion',
prompt() {
- gen_spend_hero_points();
- view.prompt = 'Use Organization Medallion?';
+ 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');
},
@@ -2062,33 +2086,36 @@ states.use_organization_medallion = {
pay_hero_points(faction, 1);
game.used_medallions.push(data_1.ORGANIZATION_MEDALLION_ID);
let { t, v } = get_active_node_args();
- if (v > game.tracks[t]) {
- v++;
- }
- else {
- v--;
- }
- move_track(t, v - game.tracks[t]);
+ log("M" + data_1.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?';
+ 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" + data_1.STRATEGY_MEDALLION_ID);
game.used_medallions.push(data_1.STRATEGY_MEDALLION_ID);
const { f } = get_active_node_args();
const faction = get_active_faction();
@@ -2299,10 +2326,9 @@ function end_of_year() {
false,
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'));
game.engine = engine;
@@ -2407,6 +2433,7 @@ function resolve_fascist_test() {
? 2
: 0;
if (can_use_medallion(data_1.PROPAGANDA_MEDALLION_ID, faction)) {
+ log(">M" + data_1.PROPAGANDA_MEDALLION_ID);
hero_points_gain += 2;
}
if (hero_points_gain > 0) {
@@ -2431,12 +2458,13 @@ function resolve_fascist_test() {
function resolve_final_bid() {
let highest_bid = 0;
let winners = [];
+ 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].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);
}
@@ -2553,15 +2581,16 @@ function move_track_to(track_id, new_value) {
: make_list(new_value, current_value - 1);
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))) {
- if (space_id !== 0) {
- game.triggered_track_effects.push(get_blank_marker_id(track_id, space_id));
- }
+ !game.triggered_track_effects.includes(blank) &&
+ !game.untriggered_track_effects.includes(blank)) {
+ 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]));
}
}
});
@@ -2581,11 +2610,20 @@ function can_use_medallion(medallion_id, faction) {
return can_use;
}
}
-function insert_use_organization_medallion_node(track_id, value) {
+function insert_use_organization_medallion_node(track_id, delta) {
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,
}));
}
function update_bonus(bonus_id, status) {
@@ -2800,7 +2838,8 @@ function resolve_effect(effect, source) {
}
function win_final_bid(faction_id) {
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);
}
function win_game(player, glory) {
@@ -2858,9 +2897,12 @@ function log_header(msg, prefix) {
log(`#${prefix} ${msg}`);
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();
}
function logi(msg) {
@@ -2996,12 +3038,34 @@ function get_source_name(source) {
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 data_1.MOMENTUM:
return 'Momentum';
}
return source;
}
+function get_source_inactive(source) {
+ 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 data_1.MOMENTUM:
+ return 'use Momentum';
+ }
+ return source;
+}
function get_factions_with_most_hero_poins() {
let most_hero_points = null;
let faction_ids = [];
@@ -3037,6 +3101,8 @@ function list_deck(id) {
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) ||
@@ -3136,6 +3202,21 @@ function array_insert(array, index, item) {
array[i] = array[i - 1];
array[index] = item;
}
+function set_add(set, item) {
+ 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(set, item) {
let a = 0;
let b = set.length - 1;