summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrans Bongers <fransbongers@franss-mbp.home>2025-03-09 13:51:20 +0100
committerFrans Bongers <fransbongers@franss-mbp.home>2025-03-09 13:51:20 +0100
commit53ca3a6117265098a9ed1911b536962d97a4f4cf (patch)
tree642e34a64f728f5dfa6f6a5834730d1546a308ed
parentb42c19db211dfb9dce41afd39be576f0a8d80222 (diff)
downloadland-and-freedom-53ca3a6117265098a9ed1911b536962d97a4f4cf.tar.gz
move event card to trash after resolving action
-rw-r--r--play.js1
-rw-r--r--rules.js89
-rw-r--r--rules.ts144
3 files changed, 152 insertions, 82 deletions
diff --git a/play.js b/play.js
index 4f93687..2b439f9 100644
--- a/play.js
+++ b/play.js
@@ -542,6 +542,7 @@ function on_update() { // eslint-disable-line no-unused-vars
action_button("draw_glory", "Draw from Bag of Glory")
action_button("next", "Next")
action_button("remove_blank_marker", "Remove Blank marker")
+ action_button("trash_card", "Trash card")
action_button("confirm", "Confirm")
action_button("yes", "Yes")
action_button("no", "No")
diff --git a/rules.js b/rules.js
index abe0d7c..69c3e8c 100644
--- a/rules.js
+++ b/rules.js
@@ -361,7 +361,9 @@ function game_view(state, current) {
initiative: game.initiative,
medallions: game.medallions,
played_card: game.played_card,
- player_order: current === OBSERVER ? get_player_order() : get_player_order_in_game(faction),
+ player_order: current === OBSERVER
+ ? get_player_order()
+ : get_player_order_in_game(faction),
selected_cards: current === OBSERVER ? [] : game.selected_cards[faction],
tableaus: game.tableaus,
tracks: game.tracks,
@@ -377,7 +379,7 @@ function game_view(state, current) {
!game.active.includes(current)) {
let inactive = states[game.state].inactive || game.state;
view.prompt = Array.isArray(game.active)
- ? `Waiting for ${game.active.join(" and ")} to ${inactive}.`
+ ? `Waiting for ${game.active.join(' and ')} to ${inactive}.`
: `Waiting for ${game.active} to ${inactive}.`;
}
else {
@@ -1368,11 +1370,26 @@ states.move_track_up_or_down = {
spend_hp() {
resolve_spend_hp();
},
- tr0(x) { move_track_to(0, x); resolve_active_and_proceed(); },
- tr1(x) { move_track_to(1, x); resolve_active_and_proceed(); },
- tr2(x) { move_track_to(2, x); resolve_active_and_proceed(); },
- tr3(x) { move_track_to(3, x); resolve_active_and_proceed(); },
- tr4(x) { move_track_to(4, x); resolve_active_and_proceed(); },
+ tr0(x) {
+ move_track_to(0, x);
+ resolve_active_and_proceed();
+ },
+ tr1(x) {
+ move_track_to(1, x);
+ resolve_active_and_proceed();
+ },
+ tr2(x) {
+ move_track_to(2, x);
+ resolve_active_and_proceed();
+ },
+ tr3(x) {
+ move_track_to(3, x);
+ resolve_active_and_proceed();
+ },
+ tr4(x) {
+ move_track_to(4, x);
+ resolve_active_and_proceed();
+ },
};
states.peek_fascist_cards = {
inactive: 'peek at Fascist cards',
@@ -1498,6 +1515,7 @@ states.player_turn = {
resolving_event: true,
});
const node = create_effects_node(effects, 'player_event');
+ node.c.push(create_state_node('trash_card_played_for_event', faction));
node.c.push(create_function_node('end_resolving_event_effects'));
insert_before_active_node(node);
next();
@@ -1613,11 +1631,11 @@ states.remove_attack_from_fronts = {
},
};
states.return_card = {
- inactive: "return a card to their hand",
+ inactive: 'return a card to their hand',
prompt() {
const faction = get_active_faction();
gen_spend_hero_points();
- view.prompt = "Choose a card to return to your hand";
+ view.prompt = 'Choose a card to return to your hand';
view.trash = game.trash[faction];
let possible = false;
for (let c of game.trash[faction]) {
@@ -1627,8 +1645,8 @@ states.return_card = {
}
}
if (!possible) {
- view.prompt = "No card in trash to return. You must skip";
- gen_action("skip");
+ view.prompt = 'No card in trash to return. You must skip';
+ gen_action('skip');
}
},
spend_hp() {
@@ -1854,6 +1872,25 @@ states.take_hero_points = {
resolve_active_and_proceed();
},
};
+function trash_card() {
+ const faction = get_active_faction();
+ const index = game.selected_cards[faction].length - 1;
+ const card_id = game.selected_cards[faction][index];
+ array_remove(game.hands[faction], game.hands[faction].indexOf(card_id));
+ array_remove(game.selected_cards[faction], index);
+ game.trash[faction].push(card_id);
+}
+states.trash_card_played_for_event = {
+ inactive: 'trash their card',
+ prompt() {
+ view.prompt = 'Trash your card';
+ gen_action('trash_card');
+ },
+ trash_card() {
+ trash_card();
+ resolve_active_and_proceed();
+ },
+};
states.use_organization_medallion = {
inactive: 'use Organization Medallion',
prompt() {
@@ -2187,10 +2224,7 @@ function play_card_for_event(faction) {
const card_id = game.selected_cards[faction][index];
const card = cards[card_id];
game.played_card = card_id;
- array_remove(game.hands[faction], game.hands[faction].indexOf(card_id));
- array_remove(game.selected_cards[faction], index);
- log("Played for Event:");
- game.trash[faction].push(card_id);
+ log('Played for Event:');
return card;
}
function play_card_to_tableau(faction) {
@@ -2200,7 +2234,7 @@ function play_card_to_tableau(faction) {
game.played_card = card_id;
array_remove(game.hands[faction], game.hands[faction].indexOf(card_id));
array_remove(game.selected_cards[faction], index);
- log("Played to Tableau:");
+ log('Played to Tableau:');
game.tableaus[faction].push(card_id);
return card;
}
@@ -2323,13 +2357,7 @@ function get_government_track_direction(direction) {
return 1;
}
}
-const track_action_name = [
- "tr0",
- "tr1",
- "tr2",
- "tr3",
- "tr4"
-];
+const track_action_name = ['tr0', 'tr1', 'tr2', 'tr3', 'tr4'];
function gen_move_track(track_id, change) {
const current_value = game.tracks[track_id];
let new_value = current_value + change;
@@ -2741,11 +2769,16 @@ function get_player_order_in_game(first_player = game.initiative) {
}
function get_source_name(source) {
switch (source) {
- case 'player_event': return cards[game.played_card].title;
- case 'fascist_event': return cards[game.current_events[game.current_events.length - 1]].title;
- case 'fascist_test': return 'Fascist Test';
- case 'track_icon': return 'Track Trigger';
- case 'momentum': return 'Momentum';
+ case 'player_event':
+ return cards[game.played_card].title;
+ case 'fascist_event':
+ return cards[game.current_events[game.current_events.length - 1]].title;
+ case 'fascist_test':
+ return 'Fascist Test';
+ case 'track_icon':
+ return 'Track Trigger';
+ case 'momentum':
+ return 'Momentum';
}
return '???';
}
diff --git a/rules.ts b/rules.ts
index 852eb6f..8a6918b 100644
--- a/rules.ts
+++ b/rules.ts
@@ -541,7 +541,10 @@ function game_view(state: Game, current: Player | 'Observer') {
initiative: game.initiative,
medallions: game.medallions,
played_card: game.played_card,
- player_order: current === OBSERVER ? get_player_order() : get_player_order_in_game(faction),
+ player_order:
+ current === OBSERVER
+ ? get_player_order()
+ : get_player_order_in_game(faction),
selected_cards: current === OBSERVER ? [] : game.selected_cards[faction],
tableaus: game.tableaus,
tracks: game.tracks,
@@ -559,7 +562,7 @@ function game_view(state: Game, current: Player | 'Observer') {
) {
let inactive = states[game.state].inactive || game.state;
view.prompt = Array.isArray(game.active)
- ? `Waiting for ${game.active.join(" and ")} to ${inactive}.`
+ ? `Waiting for ${game.active.join(' and ')} to ${inactive}.`
: `Waiting for ${game.active} to ${inactive}.`;
} else {
view.actions = {};
@@ -1686,20 +1689,33 @@ states.move_track_up_or_down = {
const can_move_up = can_move_track_up(track_id);
const can_move_down = can_move_track_down(track_id);
const track_name = get_track_name(track_id);
- if (can_move_up)
- gen_move_track(track_id, strength);
- if (can_move_down)
- gen_move_track(track_id, -strength);
- view.prompt = `Move ${track_name}.`
+ if (can_move_up) gen_move_track(track_id, strength);
+ if (can_move_down) gen_move_track(track_id, -strength);
+ view.prompt = `Move ${track_name}.`;
},
spend_hp() {
resolve_spend_hp();
},
- tr0(x) { move_track_to(0, x); resolve_active_and_proceed(); },
- tr1(x) { move_track_to(1, x); resolve_active_and_proceed(); },
- tr2(x) { move_track_to(2, x); resolve_active_and_proceed(); },
- tr3(x) { move_track_to(3, x); resolve_active_and_proceed(); },
- tr4(x) { move_track_to(4, x); resolve_active_and_proceed(); },
+ tr0(x) {
+ move_track_to(0, x);
+ resolve_active_and_proceed();
+ },
+ tr1(x) {
+ move_track_to(1, x);
+ resolve_active_and_proceed();
+ },
+ tr2(x) {
+ move_track_to(2, x);
+ resolve_active_and_proceed();
+ },
+ tr3(x) {
+ move_track_to(3, x);
+ resolve_active_and_proceed();
+ },
+ tr4(x) {
+ move_track_to(4, x);
+ resolve_active_and_proceed();
+ },
};
states.peek_fascist_cards = {
@@ -1707,7 +1723,7 @@ states.peek_fascist_cards = {
prompt() {
gen_spend_hero_points();
view.prompt = 'Choose one card to return to the top of the deck';
- view.fascist_cards = game.fascist_cards
+ view.fascist_cards = game.fascist_cards;
for (const c of game.fascist_cards) {
gen_action_card(c);
}
@@ -1845,6 +1861,7 @@ states.player_turn = {
});
const node = create_effects_node(effects, 'player_event');
+ node.c.push(create_state_node('trash_card_played_for_event', faction));
node.c.push(create_function_node('end_resolving_event_effects'));
insert_before_active_node(node);
@@ -2000,12 +2017,12 @@ states.remove_attack_from_fronts = {
};
states.return_card = {
- inactive: "return a card to their hand",
+ inactive: 'return a card to their hand',
prompt() {
const faction = get_active_faction();
gen_spend_hero_points();
- view.prompt = "Choose a card to return to your hand";
- view.trash = game.trash[faction]
+ view.prompt = 'Choose a card to return to your hand';
+ view.trash = game.trash[faction];
let possible = false;
for (let c of game.trash[faction]) {
if (c !== game.played_card) {
@@ -2014,8 +2031,8 @@ states.return_card = {
}
}
if (!possible) {
- view.prompt = "No card in trash to return. You must skip";
- gen_action("skip");
+ view.prompt = 'No card in trash to return. You must skip';
+ gen_action('skip');
}
},
spend_hp() {
@@ -2031,7 +2048,7 @@ states.return_card = {
skip() {
resolve_active_and_proceed();
},
-}
+};
states.spend_hero_points = {
inactive: 'spend Hero points',
@@ -2281,6 +2298,33 @@ states.take_hero_points = {
},
};
+function trash_card() {
+ const faction = get_active_faction();
+ const index = game.selected_cards[faction].length - 1;
+ const card_id = game.selected_cards[faction][index];
+
+ array_remove(game.hands[faction], game.hands[faction].indexOf(card_id));
+ array_remove(game.selected_cards[faction], index);
+ game.trash[faction].push(card_id);
+}
+
+states.trash_card_played_for_event = {
+ inactive: 'trash their card',
+ prompt() {
+ view.prompt = 'Trash your card';
+ gen_action('trash_card');
+ },
+ // NOTE: uncomment this to autoresolve
+ // auto_resolve() {
+ // trash_card();
+ // return true;
+ // },
+ trash_card() {
+ trash_card();
+ resolve_active_and_proceed();
+ },
+};
+
states.use_organization_medallion = {
inactive: 'use Organization Medallion',
prompt() {
@@ -2448,7 +2492,7 @@ function card45_event2() {
}
function card46_event3() {
- game.fascist_cards = []
+ game.fascist_cards = [];
for (let i = 0; i < 3; ++i) {
game.fascist_cards.push(draw_fascist_card());
}
@@ -2718,26 +2762,18 @@ function get_hand_limit(faction: FactionId) {
return hand_limit;
}
-function play_card_for_event(
- faction: FactionId
-): PlayerCard {
+function play_card_for_event(faction: FactionId): PlayerCard {
const index = game.selected_cards[faction].length - 1;
const card_id = game.selected_cards[faction][index];
const card = cards[card_id];
game.played_card = card_id;
- array_remove(game.hands[faction], game.hands[faction].indexOf(card_id));
- // TODO: keep card selected during resolution
- array_remove(game.selected_cards[faction], index);
- log("Played for Event:")
- // TODO: trash card at end of event resolution!
- game.trash[faction].push(card_id);
+ log('Played for Event:');
+
return card as PlayerCard;
}
-function play_card_to_tableau(
- faction: FactionId
-): PlayerCard {
+function play_card_to_tableau(faction: FactionId): PlayerCard {
const index = game.selected_cards[faction].length - 1;
const card_id = game.selected_cards[faction][index];
const card = cards[card_id];
@@ -2746,13 +2782,13 @@ function play_card_to_tableau(
array_remove(game.hands[faction], game.hands[faction].indexOf(card_id));
// TODO: keep card selected during resolution
array_remove(game.selected_cards[faction], index);
- log("Played to Tableau:")
+ log('Played to Tableau:');
game.tableaus[faction].push(card_id);
return card as PlayerCard;
}
function resolve_fascist_test() {
- game.fascist = 1
+ game.fascist = 1;
log_h2('Fascist Test', 'fascist');
@@ -2893,20 +2929,14 @@ function get_government_track_direction(direction: 10 | 11): -1 | 1 {
}
}
-const track_action_name = [
- "tr0",
- "tr1",
- "tr2",
- "tr3",
- "tr4"
-]
+const track_action_name = ['tr0', 'tr1', 'tr2', 'tr3', 'tr4'];
function gen_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));
- gen_action(track_action_name[track_id], new_value)
+ gen_action(track_action_name[track_id], new_value);
}
function move_track(track_id: number, change: number) {
@@ -2914,7 +2944,7 @@ function move_track(track_id: number, change: number) {
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));
- move_track_to(track_id, new_value)
+ move_track_to(track_id, new_value);
}
function move_track_to(track_id: number, new_value: number) {
@@ -3074,7 +3104,10 @@ function victory_on_a_front(front_id: FrontId) {
gain_hero_points_in_player_order(game.fronts[front_id].contributions, 3);
}
-function create_effects_node(effects: Effect[], source?: EffectSource): SeqNode {
+function create_effects_node(
+ effects: Effect[],
+ source?: EffectSource
+): SeqNode {
const nodes = effects.reduce((accrued: EngineNode[], current: Effect) => {
const node = resolve_effect(current, source);
if (node !== null) {
@@ -3490,13 +3523,18 @@ function get_player_order_in_game(
function get_source_name(source: EffectSource): string {
switch (source) {
- case 'player_event': return cards[game.played_card].title;
- case 'fascist_event': return cards[game.current_events[game.current_events.length-1]].title;
- case 'fascist_test': return 'Fascist Test';
- case 'track_icon': return 'Track Trigger';
- case 'momentum': return 'Momentum';
+ case 'player_event':
+ return cards[game.played_card].title;
+ case 'fascist_event':
+ return cards[game.current_events[game.current_events.length - 1]].title;
+ case 'fascist_test':
+ return 'Fascist Test';
+ case 'track_icon':
+ return 'Track Trigger';
+ case 'momentum':
+ return 'Momentum';
}
- return '???'
+ return '???';
}
function get_factions_with_most_hero_poins(): FactionId[] {
@@ -3532,10 +3570,8 @@ function list_deck(id: FactionId | 'f') {
id === FASCIST_ID ? fascist_decks[game.year] : faction_cards[id];
card_list.forEach((card) => {
if (id === FASCIST_ID) {
- if (game.current_events.includes(card))
- return;
- if (game.discard[id].includes(card))
- return;
+ if (game.current_events.includes(card)) return;
+ if (game.discard[id].includes(card)) return;
} else if (
game.hands[id].includes(card) ||
game.discard[id].includes(card) ||