summaryrefslogtreecommitdiff
path: root/rules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'rules.ts')
-rw-r--r--rules.ts495
1 files changed, 401 insertions, 94 deletions
diff --git a/rules.ts b/rules.ts
index dc3700a..3f0a2cf 100644
--- a/rules.ts
+++ b/rules.ts
@@ -39,6 +39,7 @@ import data, {
CLOSEST_TO_VICTORY,
COLLECTIVIZATION,
GOVERNMENT,
+ INITIATIVE_PLAYER,
SOVIET_SUPPORT,
FOREIGN_AID,
ON,
@@ -54,6 +55,13 @@ import data, {
create_effect,
AWAY_FROM_CENTER,
TOWARDS_CENTER,
+ ARCHIVES_MEDALLION_ID,
+ INTELLIGENCE_MEDALLION_ID,
+ // VOLUNTEERS_MEDALLION_ID,
+ ORGANIZATION_MEDALLION_ID,
+ STRATEGY_MEDALLION_ID,
+ PROPAGANDA_MEDALLION_ID,
+ VOLUNTEERS_MEDALLION_ID,
// StaticData,
// PLAYER_WITH_MOST_HERO_POINTS,
} from './data';
@@ -98,6 +106,7 @@ const bonus_names: string[] = ['Morale Bonus', 'Teamwork Bonus'];
const {
cards,
+ medallions,
// fronts,
tracks,
} = data;
@@ -110,10 +119,6 @@ const faction_cards = {
[MODERATES_ID]: make_list(1, 18) as CardId[],
};
-const medaillons = make_list(0, 8) as number[];
-
-console.log('medaillons', medaillons);
-
const fascist_decks = {
1: make_list(55, 72),
2: make_list(73, 90),
@@ -133,6 +138,10 @@ function gen_action(action: string, argument?: number | string) {
}
}
+function gen_action_blank_marker(marker_id: number) {
+ gen_action('blank_marker', marker_id);
+}
+
function gen_action_bonus(bonus_id: number) {
gen_action('bonus', bonus_id);
}
@@ -145,6 +154,10 @@ function gen_action_front(front_id: string) {
gen_action('front', front_id);
}
+function gen_action_medallion(medallion_id: number) {
+ gen_action('medallion', medallion_id);
+}
+
function gen_action_standee(track_id: number) {
gen_action('standee', track_id);
}
@@ -256,8 +269,6 @@ function setup_player_turn() {
function start_of_player_turn() {
const args = get_active_node_args();
- console.log('args', args);
- console.log('args');
const player = faction_player_map[args.f];
log_h2(player, player);
resolve_active_and_proceed();
@@ -319,7 +330,6 @@ function insert_before_or_after_active_node(
return;
}
const i = a.parent.indexOf(a.node);
- console.log('insert_before_active_node', i);
if (i >= 0) {
array_insert(a.parent, i + (position == 'after' ? 1 : 0), node);
}
@@ -356,7 +366,6 @@ function next() {
function resolve_active_node() {
const next_node = get_active_node(game.engine);
- console.log('resolve_active_node', next_node);
if (next_node !== null) {
next_node.r = resolved;
}
@@ -393,11 +402,12 @@ function game_view(state: Game, player: Player) {
hand: game.hands[faction_id],
hero_points: game.hero_points,
initiative: game.initiative,
- medaillons: game.medaillons,
+ medallions: game.medallions,
selected_card: game.chosen_cards[faction_id],
tableaus: game.tableaus,
tracks: game.tracks,
triggered_track_effects: game.triggered_track_effects,
+ used_medallions: game.used_medallions,
year: game.year,
};
@@ -482,13 +492,12 @@ export function setup(seed: number, _scenario: string, _options: unknown) {
[MODERATES_ID]: null,
},
initiative: MODERATES_ID,
- medaillons: [
- draw_item(medaillons),
- draw_item(medaillons),
- draw_item(medaillons),
- draw_item(medaillons),
- draw_item(medaillons),
- ],
+ medallions: {
+ [ANARCHISTS_ID]: [],
+ [COMMUNISTS_ID]: [],
+ [MODERATES_ID]: [],
+ pool: [],
+ },
tableaus: {
[ANARCHISTS_ID]: [],
[COMMUNISTS_ID]: [],
@@ -500,14 +509,17 @@ export function setup(seed: number, _scenario: string, _options: unknown) {
[COMMUNISTS_ID]: [],
[MODERATES_ID]: [],
},
- triggered_track_effects: [[], [], [], [], []],
+ triggered_track_effects: [],
log: [],
undo: [],
+ used_medallions: [],
turn: 0,
year: 0,
state_data: null,
};
+ draw_medallions();
+
start_year();
return game;
}
@@ -515,6 +527,11 @@ export function setup(seed: number, _scenario: string, _options: unknown) {
function draw_hand_cards(faction_id: FactionId, count: number) {
const deck = list_deck(faction_id);
+ if (game.medallions[faction_id].includes(INTELLIGENCE_MEDALLION_ID)) {
+ count++;
+ }
+ const drawn_cards = count;
+
// Draw all remaining cards
if (deck.length < count) {
count = count - deck.length;
@@ -522,13 +539,12 @@ function draw_hand_cards(faction_id: FactionId, count: number) {
game.discard[faction_id] = [];
}
- console.log('draw_hand_cards', count);
const log =
- count === 1
+ drawn_cards === 1
? `${get_player(faction_id)} draws 1 card`
- : `${get_player(faction_id)} draws ${count} cards`;
+ : `${get_player(faction_id)} draws ${drawn_cards} cards`;
logi(log);
- console.log('deck', list_deck(faction_id));
+
for (let i = 0; i < count; i++) {
const deck = list_deck(faction_id);
game.hands[faction_id].push(draw_card(deck));
@@ -557,9 +573,7 @@ function start_turn() {
log_h2('Fascist Event', 'fascist');
log(card.title);
- game.engine = card.effects.map((effect) =>
- resolve_effect(effect, game.initiative)
- );
+ game.engine = card.effects.map((effect) => resolve_effect(effect));
if (game.year === 3 && game.turn === 1) {
game.engine.push(create_function_node('setup_final_bid'));
} else {
@@ -594,33 +608,57 @@ states.activate_icon = {
resolve_active_and_proceed();
},
collectivization() {
- move_track(COLLECTIVIZATION, get_icon_count_in_tableau('collectivization'));
+ const count = get_icon_count_in_tableau('collectivization');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(COLLECTIVIZATION, count);
+ } else {
+ move_track(COLLECTIVIZATION, count);
+ }
resolve_active_and_proceed();
},
d_collectivization() {
- move_track(
- COLLECTIVIZATION,
- -1 * get_icon_count_in_tableau('d_collectivization')
- );
+ const count = -1 * get_icon_count_in_tableau('d_collectivization');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(COLLECTIVIZATION, count);
+ } else {
+ move_track(COLLECTIVIZATION, count);
+ }
resolve_active_and_proceed();
},
d_foreign_aid() {
- move_track(FOREIGN_AID, -1 * get_icon_count_in_tableau('d_foreign_aid'));
+ const count = -1 * get_icon_count_in_tableau('d_foreign_aid');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(FOREIGN_AID, count);
+ } else {
+ move_track(FOREIGN_AID, count);
+ }
resolve_active_and_proceed();
},
d_government() {
- move_track(GOVERNMENT, -1 * get_icon_count_in_tableau('d_government'));
+ const count = -1 * get_icon_count_in_tableau('d_government');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(GOVERNMENT, count);
+ } else {
+ move_track(GOVERNMENT, count);
+ }
resolve_active_and_proceed();
},
d_liberty() {
- move_track(LIBERTY, -1 * get_icon_count_in_tableau('d_liberty'));
+ const count = -1 * get_icon_count_in_tableau('d_liberty');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(LIBERTY, count);
+ } else {
+ move_track(LIBERTY, count);
+ }
resolve_active_and_proceed();
},
d_soviet_support() {
- move_track(
- SOVIET_SUPPORT,
- -1 * get_icon_count_in_tableau('d_soviet_support')
- );
+ const count = -1 * get_icon_count_in_tableau('d_soviet_support');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(SOVIET_SUPPORT, count);
+ } else {
+ move_track(SOVIET_SUPPORT, count);
+ }
resolve_active_and_proceed();
},
draw_card() {
@@ -631,12 +669,22 @@ states.activate_icon = {
resolve_active_and_proceed();
},
foreign_aid() {
- move_track(FOREIGN_AID, get_icon_count_in_tableau('foreign_aid'));
+ const count = get_icon_count_in_tableau('foreign_aid');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(FOREIGN_AID, count);
+ } else {
+ move_track(FOREIGN_AID, count);
+ }
resolve_active_and_proceed();
},
government() {
const direction = game.active === COMMUNIST ? -1 : 1;
- move_track(GOVERNMENT, direction * get_icon_count_in_tableau('government'));
+ const count = direction * get_icon_count_in_tableau('government');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(GOVERNMENT, count);
+ } else {
+ move_track(GOVERNMENT, count);
+ }
resolve_active_and_proceed();
},
government_to_center() {
@@ -648,11 +696,21 @@ states.activate_icon = {
resolve_active_and_proceed();
},
liberty() {
- move_track(LIBERTY, get_icon_count_in_tableau('liberty'));
+ const count = get_icon_count_in_tableau('liberty');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(LIBERTY, count);
+ } else {
+ move_track(LIBERTY, count);
+ }
resolve_active_and_proceed();
},
soviet_support() {
- move_track(SOVIET_SUPPORT, get_icon_count_in_tableau('soviet_support'));
+ const count = get_icon_count_in_tableau('soviet_support');
+ if (can_use_medallion(ORGANIZATION_MEDALLION_ID)) {
+ insert_use_organization_medallion_node(SOVIET_SUPPORT, count);
+ } else {
+ move_track(SOVIET_SUPPORT, count);
+ }
resolve_active_and_proceed();
},
teamwork_on() {
@@ -668,17 +726,11 @@ states.add_glory = {
gen_action('add_glory');
},
add_glory() {
- console.log('add_glory');
let number = 1;
if (game.turn === 4) {
number++;
}
- game.bag_of_glory.push(get_active_faction());
- if (number === 1) {
- log_h3(`${game.active} adds 1 token to the Bag of Glory`);
- } else {
- log_h3(`${game.active} adds ${number} tokens to the Bag of Glory`);
- }
+ add_glory(get_active_faction(), number);
resolve_active_and_proceed();
},
};
@@ -898,13 +950,54 @@ states.choose_final_bid = {
},
};
+states.choose_medallion = {
+ inactive: 'choose a medallion',
+ prompt() {
+ view.prompt = 'Choose a medallion';
+ for (let m of game.medallions.pool) {
+ gen_action_medallion(m);
+ }
+ if (!game.medallions.pool.some((m) => m !== null)) {
+ gen_action('skip');
+ }
+ },
+ medallion(m: number) {
+ const faction = get_active_faction();
+ const medallion = medallions[m];
+
+ logi(`${faction_player_map[faction]} earns ${medallion.name}`);
+
+ const index = game.medallions.pool.indexOf(m);
+
+ game.medallions.pool[index] = null;
+
+ switch (m) {
+ case 0:
+ add_glory(faction, 1, true);
+ break;
+ case 1:
+ gain_hero_points(faction, 7);
+ break;
+ case 2:
+ // insert play another card action
+ break;
+ default:
+ game.medallions[faction].push(m);
+ }
+ resolve_active_and_proceed();
+ },
+ skip() {
+ resolve_active_and_proceed();
+ },
+};
+
states.end_of_year_discard = {
inactive: 'discard cards from hand and tableau',
prompt() {
view.prompt = 'Discard a card';
const faction_id = get_active_faction();
const hand = game.hands[faction_id];
- if (hand.length > game.year) {
+ if (hand.length > get_hand_limit(faction_id)) {
for (let c of hand) gen_action_card(c);
}
const tableau = game.tableaus[faction_id];
@@ -914,7 +1007,6 @@ states.end_of_year_discard = {
},
card(c: CardId) {
const faction_id = get_active_faction();
- console.log('list deck', list_deck(faction_id));
if (game.hands[faction_id].includes(c)) {
game.hands[faction_id] = game.hands[faction_id].filter((id) => id !== c);
} else if (game.tableaus[faction_id].includes(c)) {
@@ -924,7 +1016,7 @@ states.end_of_year_discard = {
}
game.discard[faction_id].push(c);
if (
- game.hands[faction_id].length > game.year ||
+ game.hands[faction_id].length > get_hand_limit(faction_id) ||
game.tableaus[faction_id].length > game.year
) {
// More cards to discard so resolve same state again
@@ -966,7 +1058,6 @@ states.lose_hero_points = {
view.prompt = 'Choose player to lose Hero Points';
if (args.t === PLAYER_WITH_MOST_HERO_POINTS) {
const factions = get_factions_with_most_hero_poins();
- console.log('faction', factions);
for (let faction_id of factions) {
gen_action(faction_player_map[faction_id]);
}
@@ -1014,7 +1105,9 @@ states.move_track = {
s === GOVERNMENT &&
(value === TOWARDS_CENTER || value === AWAY_FROM_CENTER)
) {
- value = get_government_track_direction(value);
+ const direction = get_government_track_direction(value);
+ // Value equals direction because away / towards always moves 1 step
+ value = direction;
}
move_track(s, value);
@@ -1095,9 +1188,9 @@ states.player_turn = {
game.trash[faction_id].push(card);
log_h3(`${game.active} plays ${cards[card].title} for the Event`);
- insert_after_active_node(create_effects_node(cards[card].effects));
+ insert_before_active_node(create_effects_node(cards[card].effects));
- resolve_active_and_proceed();
+ next();
},
spend_hp() {
// insert spend hero points node before current node
@@ -1111,18 +1204,55 @@ states.player_turn = {
},
};
+states.remove_blank_marker = {
+ inactive: 'remove a Blank marker',
+ prompt() {
+ view.prompt = 'Remove a Blank marker';
+
+ for (const b of game.triggered_track_effects) {
+ gen_action_blank_marker(b);
+ }
+ },
+ 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;
+
+ logi(
+ `${
+ faction_player_map[faction]
+ } removes a Blank marker from space ${space_id} of ${get_track_name(
+ track_id
+ )}`
+ );
+ game.triggered_track_effects = game.triggered_track_effects.filter(
+ (id) => id !== b
+ );
+ game.used_medallions.push(ARCHIVES_MEDALLION_ID);
+ resolve_active_and_proceed();
+ },
+};
+
states.spend_hero_points = {
inactive: 'spend Hero points',
prompt() {
view.prompt = 'Spend your Hero points';
gen_action('done');
+ const faction = get_active_faction();
const hero_points = game.hero_points[get_active_faction()];
if (hero_points === 0) {
return;
}
gen_action('draw_card');
-
+ if (can_use_medallion(ARCHIVES_MEDALLION_ID, faction)) {
+ gen_action('remove_blank_marker');
+ }
+ if (can_use_medallion(VOLUNTEERS_MEDALLION_ID, faction)) {
+ gen_action('add_to_front');
+ }
if (hero_points < 2) {
return;
}
@@ -1145,6 +1275,20 @@ states.spend_hero_points = {
}
gen_action_standee(GOVERNMENT);
},
+ add_to_front() {
+ const faction = get_active_faction();
+ pay_hero_points(faction, 1);
+ insert_after_active_node(
+ create_seq_node([
+ create_leaf_node('add_to_front', faction, {
+ t: ANY,
+ v: 1,
+ }),
+ create_leaf_node('spend_hero_points', faction),
+ ])
+ );
+ resolve_active_and_proceed();
+ },
done() {
resolve_active_and_proceed();
},
@@ -1157,6 +1301,21 @@ states.spend_hero_points = {
pay_hero_points(faction, 1);
draw_hand_cards(faction, 1);
},
+ remove_blank_marker() {
+ 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_seq_node([
+ create_leaf_node('remove_blank_marker', faction),
+ create_leaf_node('spend_hero_points', faction),
+ ])
+ );
+ resolve_active_and_proceed();
+ },
standee(track_id: number) {
let amount = 2;
if (track_id === LIBERTY || track_id === COLLECTIVIZATION) {
@@ -1179,21 +1338,59 @@ states.spend_hero_points = {
},
};
-// states.move_to = {
-// inactive: 'move',
-// prompt() {
-// view.prompt = 'Move the piece to a space.';
-// for (let s = 0; s < 64; ++s) gen_action_space(s);
-// },
-// // space(to) {
-// // game.location[game.selected] = to
-// // game.state = "move"
-// // if (game.active === PLAYER1)
-// // game.active = PLAYER2
-// // else
-// // game.active = PLAYER1
-// // },
-// };
+states.use_organization_medallion = {
+ inactive: 'use Organization Medallion',
+ prompt() {
+ view.prompt = 'Use Organization Medallion?';
+
+ gen_action('yes');
+ gen_action('no');
+ },
+ yes() {
+ const faction = get_active_faction();
+ pay_hero_points(faction, 1);
+ game.used_medallions.push(ORGANIZATION_MEDALLION_ID);
+
+ let { t, v } = get_active_node_args();
+
+ if (v > 0) {
+ v++;
+ } else {
+ v--;
+ }
+
+ move_track(t, v);
+ resolve_active_and_proceed();
+ },
+ no() {
+ const { t, v } = get_active_node_args();
+
+ move_track(t, v);
+ resolve_active_and_proceed();
+ },
+};
+
+states.use_strategy_medallion = {
+ inactive: 'use Strategy Medallion',
+ prompt() {
+ view.prompt = 'Use Strategy Medallion?';
+
+ gen_action('yes');
+ gen_action('no');
+ },
+ yes() {
+ game.used_medallions.push(STRATEGY_MEDALLION_ID);
+ const { f } = get_active_node_args();
+ const faction = get_active_faction();
+
+ update_front(f, 1, faction);
+
+ resolve_active_and_proceed();
+ },
+ no() {
+ resolve_active_and_proceed();
+ },
+};
// #endrregion
@@ -1208,6 +1405,27 @@ function pop_undo() {
// #region GAME FUNCTIONS
+function add_glory(
+ faction: FactionId,
+ amount: number,
+ indent: boolean = false
+) {
+ for (let i = 0; i < amount; ++i) {
+ game.bag_of_glory.push(get_active_faction());
+ }
+
+ let text =
+ amount === 1
+ ? `${faction_player_map[faction]} adds 1 token to the Bag of Glory`
+ : `${faction_player_map[faction]} adds ${amount} tokens to the Bag of Glory`;
+
+ if (indent) {
+ logi(text);
+ } else {
+ log_h3(text);
+ }
+}
+
// Check if Morale bonus is on so player can activate icon
function check_activate_icon() {
if (game.bonuses[MORALE_BONUS] === ON) {
@@ -1281,6 +1499,7 @@ function end_of_turn() {
Object.keys(game.fronts).forEach((front_id) => {
game.fronts[front_id].contributions = [];
});
+ game.used_medallions = [];
if (game.turn === 4) {
end_of_year();
} else {
@@ -1365,6 +1584,14 @@ function game_over(result: Player | 'None', victory: string) {
log(game.victory);
}
+function get_hand_limit(faction: FactionId) {
+ let hand_limit = game.year;
+ if (game.medallions[faction].includes(INTELLIGENCE_MEDALLION_ID)) {
+ hand_limit++;
+ }
+ return hand_limit;
+}
+
function resolve_fascist_test() {
log_h2('Fascist Test', 'fascist');
@@ -1375,9 +1602,23 @@ function resolve_fascist_test() {
(status !== DEFEAT && game.fronts[test.front].value >= test.value);
if (test_passed) {
log('The Test is passed');
+ for (const faction of get_player_order()) {
+ let hero_points_gain = game.fronts[test.front].contributions.includes(
+ faction
+ )
+ ? 2
+ : 0;
+ if (can_use_medallion(PROPAGANDA_MEDALLION_ID, faction)) {
+ hero_points_gain += 2;
+ }
+ if (hero_points_gain > 0) {
+ gain_hero_points(faction, hero_points_gain);
+ }
+ }
} else {
log('The Test is failed');
}
+
const effect = test_passed ? test.pass : test.fail;
const node = resolve_effect(effect);
@@ -1421,7 +1662,6 @@ function resolve_final_bid() {
// TODO: check for defeated / won fronts
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) {
@@ -1434,9 +1674,11 @@ function get_fronts_to_add_to(target: string): FrontId[] {
function get_max_value_for_track(track_id: number) {
switch (track_id) {
case LIBERTY:
- return game.tracks[COLLECTIVIZATION] >= 8 ? 10 : 7;
+ const max_lib = game.tracks[COLLECTIVIZATION] >= 8 ? 10 : 7;
+ return Math.max(max_lib, game.tracks[LIBERTY]);
case GOVERNMENT:
- return game.tracks[FOREIGN_AID] >= 8 ? 10 : 7;
+ const max_gov = game.tracks[FOREIGN_AID] >= 8 ? 10 : 7;
+ return Math.max(max_gov, game.tracks[GOVERNMENT]);
case COLLECTIVIZATION:
case SOVIET_SUPPORT:
case FOREIGN_AID:
@@ -1448,7 +1690,8 @@ function get_max_value_for_track(track_id: number) {
function get_min_value_for_track(track_id: number) {
switch (track_id) {
case GOVERNMENT:
- return game.tracks[SOVIET_SUPPORT] >= 8 ? 4 : 1;
+ const min_gov = game.tracks[SOVIET_SUPPORT] >= 8 ? 4 : 1;
+ return Math.min(min_gov, game.tracks[GOVERNMENT]);
case LIBERTY:
case COLLECTIVIZATION:
case SOVIET_SUPPORT:
@@ -1476,8 +1719,8 @@ function move_track(track_id: number, change: number) {
const current_value = game.tracks[track_id];
let new_value = current_value + change;
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}`);
@@ -1492,10 +1735,14 @@ function move_track(track_id: number, change: number) {
const trigger = tracks[track_id].triggers[space_id];
if (
trigger !== null &&
- !game.triggered_track_effects[track_id].includes(space_id)
+ !game.triggered_track_effects.includes(
+ get_blank_marker_id(track_id, space_id)
+ )
) {
if (space_id !== 0) {
- game.triggered_track_effects[track_id].push(space_id);
+ game.triggered_track_effects.push(
+ get_blank_marker_id(track_id, space_id)
+ );
}
const node = resolve_effect(trigger);
if (node !== null) {
@@ -1510,6 +1757,33 @@ function pay_hero_points(faction: FactionId, amount: number) {
game.hero_points.pool += amount;
}
+function can_use_medallion(medallion_id: number, faction?: FactionId) {
+ faction = faction === undefined ? get_active_faction() : faction;
+ const can_use =
+ game.medallions[faction].includes(medallion_id) &&
+ !game.used_medallions.includes(medallion_id);
+
+ if (medallion_id === ORGANIZATION_MEDALLION_ID) {
+ return can_use && game.hero_points[faction] > 0;
+ } else {
+ return can_use;
+ }
+}
+
+function insert_use_organization_medallion_node(
+ track_id: number,
+ value: number
+) {
+ const faction = get_active_faction();
+
+ insert_after_active_node(
+ create_leaf_node('use_organization_medallion', faction, {
+ t: track_id,
+ v: value,
+ })
+ );
+}
+
function update_bonus(bonus_id: number, status: number) {
if (game.bonuses[bonus_id] === status) {
return;
@@ -1557,6 +1831,19 @@ function update_front(
game.fronts[front_id].contributions.push(faction_id);
}
+ if (
+ change > 0 &&
+ faction_id !== undefined &&
+ game.fronts[front_id].value < 10 &&
+ can_use_medallion(STRATEGY_MEDALLION_ID)
+ ) {
+ insert_after_active_node(
+ create_leaf_node('use_strategy_medallion', get_active_faction(), {
+ f: front_id,
+ })
+ );
+ }
+
// Check victory / defeat on a front
if (game.fronts[front_id].value >= 10) {
victory_on_a_front(front_id);
@@ -1597,33 +1884,45 @@ function create_effects_node(effects: Effect[]): EngineNode {
}
return accrued;
}, []);
- return {
- t: seq_node,
- c: nodes,
- };
+ return create_seq_node(nodes);
+}
+
+function get_faction_to_resolve_effect(effect: Effect): FactionId {
+ if (!effect.faction) {
+ return get_active_faction();
+ }
+ if (effect.faction === INITIATIVE_PLAYER) {
+ return game.initiative;
+ }
+ return effect.faction;
}
const effect_type_state_map: Record<string, string> = {
attack: 'attack_front',
bonus: 'change_bonus',
front: 'add_to_front',
+ medallion: 'choose_medallion',
track: 'move_track',
};
function resolve_effect(
- effect: Effect,
- faction: FactionId = get_active_faction()
+ effect: Effect
+ // faction: FactionId = get_active_faction() //
): EngineNode | null {
const args = {
t: effect.target,
v: effect.value,
};
- let state = effect_type_state_map[effect.type];
+ const faction = get_faction_to_resolve_effect(effect);
+
+ // Default cases where effect type is mapped to a state
+ let state = effect_type_state_map[effect.type];
if (state !== undefined) {
return create_leaf_node(state, faction, args);
}
+ // Specific mapping based on target
if (
effect.type === 'hero_points' &&
effect.target === PLAYER_WITH_MOST_HERO_POINTS
@@ -1666,13 +1965,6 @@ function draw_card(deck: CardId[]): CardId {
return c;
}
-function draw_item(ids: number[]): number {
- let i = random(ids.length);
- let r = ids[i] as CardId;
- set_delete(ids, r);
- return r;
-}
-
function lose_hero_point(faction: FactionId, value: number) {
const points_lost = Math.min(game.hero_points[faction], Math.abs(value));
game.hero_points.pool += points_lost;
@@ -1749,8 +2041,6 @@ function log_h2(msg: string, player?: Player | 'fascist') {
log_br();
}
-log;
-
// function log_h2_active(msg: string) {
// log_br();
// log('.h2 ' + msg);
@@ -1790,6 +2080,10 @@ function get_active_faction_id(): FactionId {
return player_faction_map[game.active];
}
+function get_blank_marker_id(track_id: number, space_id: number) {
+ return track_id * 11 + space_id;
+}
+
function get_faction_id(player: Player): FactionId {
return player_faction_map[player];
}
@@ -1918,7 +2212,10 @@ function list_deck(id: FactionId | 'fascist') {
const card_list =
id === 'fascist' ? fascist_decks[game.year] : faction_cards[id];
card_list.forEach((card) => {
- if (id === 'fascist' && game.discard.f.includes(card)) {
+ if (
+ id === 'fascist' &&
+ (game.discard.f.includes(card) || game.current_events.includes(card))
+ ) {
return;
} else if (
id !== 'fascist' &&
@@ -1933,6 +2230,16 @@ function list_deck(id: FactionId | 'fascist') {
return deck;
}
+function draw_medallions() {
+ const medallion_ids = make_list(0, 8) as number[];
+ for (let m = 0; m < 5; ++m) {
+ let i = random(medallion_ids.length);
+ let r = medallion_ids[i] as CardId;
+ set_delete(medallion_ids, r);
+ game.medallions.pool.push(r);
+ }
+}
+
// #endregion
// #region ARRAY