summaryrefslogtreecommitdiff
path: root/rules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'rules.ts')
-rw-r--r--rules.ts145
1 files changed, 89 insertions, 56 deletions
diff --git a/rules.ts b/rules.ts
index db25c1b..e47abe9 100644
--- a/rules.ts
+++ b/rules.ts
@@ -224,7 +224,7 @@ const resolved = 1;
function create_leaf_node<T = any>(
state: string,
- faction: FactionId | 'None',
+ faction: FactionId | 'None' | 'all' | FactionId[],
args?: T
): LeafNode {
return {
@@ -272,13 +272,15 @@ function setup_bag_of_glory() {
}
function setup_choose_card() {
- const player_order = get_player_order();
- game.engine = player_order.map((faction_id) =>
- create_leaf_node('choose_card', faction_id)
- );
+ game.engine = [create_leaf_node('choose_card', 'all')];
+
+ // const player_order = get_player_order();
+ // game.engine = player_order.map((faction_id) =>
+ // create_leaf_node('choose_card', faction_id)
+ // );
// Add extra confirm, otherwise first players card will be revealed
// before confirm
- game.engine.push(create_leaf_node('confirm_turn', player_order[2]));
+ // game.engine.push(create_leaf_node('confirm_turn', player_order[2]));
game.engine.push(create_function_node('setup_player_turn'));
next();
}
@@ -474,6 +476,20 @@ function insert_before_active_node(
insert_before_or_after_active_node(node, 'before', engine);
}
+function get_next_active(p: LeafNode['p']): Player | Player[] | 'None' {
+ if (Array.isArray(p)) {
+ return p.map((faction) => faction_player_map[faction]);
+ }
+ if (p === 'all') {
+ return roles;
+ }
+ if (p === 'None') {
+ return 'None';
+ } else {
+ return faction_player_map[p];
+ }
+}
+
function next(checkpoint = false) {
if (checkpoint) {
clear_undo();
@@ -492,7 +508,9 @@ function next(checkpoint = false) {
// Control switches to another player and player can undo
// so ask to confirm turn
const current_active = game.active;
- const next_active = faction_player_map[node.p];
+
+ const next_active = get_next_active(node.p);
+
if (next_active !== current_active && game.undo.length > 0) {
insert_before_active_node(
create_leaf_node('confirm_turn', get_active_faction())
@@ -532,6 +550,7 @@ function game_view(state: Game, current: Player | 'Observer') {
current === OBSERVER ? null : player_faction_map[current];
view = {
+ active: game.active,
engine: game.engine, // TODO: remove
log: game.log,
prompt: null,
@@ -694,25 +713,28 @@ function draw_hand_cards(faction_id: FactionId, count: number) {
if (game.medallions[faction_id].includes(INTELLIGENCE_MEDALLION_ID)) {
count++;
}
- const drawn_cards = count;
+ let drawn_cards = 0;
// Draw all remaining cards
if (deck.length < count) {
count = count - deck.length;
+ drawn_cards += deck.length;
game.hands[faction_id] = game.hands[faction_id].concat(deck);
game.discard[faction_id] = [];
}
+ for (let i = 0; i < count; i++) {
+ const deck = list_deck(faction_id);
+ if (deck.length > 0) {
+ game.hands[faction_id].push(draw_card(deck));
+ drawn_cards++;
+ }
+ }
const log =
drawn_cards === 1
? `${get_player(faction_id)} draws 1 card`
: `${get_player(faction_id)} draws ${drawn_cards} cards`;
logi(log);
-
- for (let i = 0; i < count; i++) {
- const deck = list_deck(faction_id);
- game.hands[faction_id].push(draw_card(deck));
- }
}
// #endregion
@@ -956,10 +978,18 @@ states.add_to_front = {
gen_spend_hero_points();
const args = get_active_node_args();
const possible_fronts = get_fronts_to_add_to(args.t);
- view.prompt =
- possible_fronts.length === 1
- ? `Add strength to ${front_names[possible_fronts[0]]}`
- : 'Add strength to a Front';
+
+ const number_of_fronts = possible_fronts.length;
+
+ if (number_of_fronts === 0) {
+ view.prompt = 'No valid front to target. You must skip';
+ gen_action('skip');
+ } else if (number_of_fronts === 1) {
+ view.prompt = `Add strength to ${front_names[possible_fronts[0]]}`;
+ } else {
+ view.prompt = 'Add strength to a Front';
+ }
+
for (let f of possible_fronts) {
gen_action_front(f);
}
@@ -975,6 +1005,9 @@ states.add_to_front = {
update_front(f, value, get_active_faction());
resolve_active_and_proceed();
},
+ skip() {
+ resolve_active_and_proceed();
+ },
};
states.attack_front = {
@@ -983,47 +1016,35 @@ states.attack_front = {
gen_spend_hero_points();
const { t: target, n, src } = get_active_node_args();
- let fronts: Array<FrontId> = [];
+ const possible_fronts = get_fronts_to_add_to(target, n);
+ const number_of_fronts = possible_fronts.length;
- if (target === ANY) {
- fronts = get_fronts_to_add_to(ANY, n);
- } else if (target === 'd' || target === 'v') {
- fronts = get_fronts_closest_to(target);
- } else if (game.fronts[target].status === DEFEAT) {
- fronts = get_fronts_closest_to('d');
- } else if (game.fronts[target].status === VICTORY) {
- fronts = get_fronts_to_add_to(ANY);
+ if (number_of_fronts === 0) {
+ view.prompt = 'No valid front to target. You must skip';
+ gen_action('skip');
+ } else if (number_of_fronts === 1) {
+ view.prompt = `Attack ${front_names[possible_fronts[0]]}`;
} else {
- fronts.push(target);
+ view.prompt = 'Attack a Front';
}
- view.prompt =
- fronts.length === 1
- ? `Attack ${front_names[fronts[0]]}`
- : 'Attack a front';
- let prefix = '';
if (src) {
- prefix = `${get_source_name(src)}: `;
- }
- if (fronts.length === 1) {
- view.prompt = prefix
- ? `${prefix}attack ${front_names[fronts[0]]}`
- : `Attack ${front_names[fronts[0]]}`;
- } else {
- view.prompt = prefix ? `${prefix}attack a front` : `Attack a front`;
+ view.prompt = add_prompt_prefix(view.prompt, get_source_name(src));
}
- fronts.forEach((id) => gen_action('front', id));
+ possible_fronts.forEach((id) => gen_action('front', id));
},
spend_hp() {
resolve_spend_hp();
},
front(f: FrontId) {
- const node = get_active_node();
- const value = node.a.v;
+ const value = get_active_node_args().v;
update_front(f, value);
resolve_active_and_proceed();
},
+ skip() {
+ resolve_active_and_proceed();
+ },
};
states.break_tie_final_bid = {
@@ -1076,7 +1097,7 @@ states.break_tie_winner = {
};
/**
- * Change does not do anything, but it will change
+ * Change does not do anything, but it will change
* active player and trigger a confirm for the previous
* state
*/
@@ -1087,8 +1108,8 @@ states.change_active_player = {
},
prompt() {
view.prompt = '';
- }
-}
+ },
+};
states.choose_area_ap = {
inactive: 'choose area to use Action Points',
@@ -1186,7 +1207,8 @@ states.change_bonus = {
states.choose_card = {
inactive: 'choose a card',
- prompt() {
+ prompt(player: Player) {
+ console.log('player', player);
gen_spend_hero_points();
const { src } = get_active_node_args<ChooseCardArgs>();
view.prompt = 'Choose a card to play this turn';
@@ -1194,7 +1216,7 @@ states.choose_card = {
view.prompt = 'Choose a card to play';
}
- const faction = get_active_faction();
+ const faction = player_faction_map[player];
const hand = game.hands[faction];
for (let c of hand) {
if (!game.selected_cards[faction].includes(c)) {
@@ -1205,14 +1227,14 @@ states.choose_card = {
spend_hp() {
resolve_spend_hp();
},
- 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 { src } = get_active_node_args<ChooseCardArgs>();
if (src === 'momentum') {
game.played_card = game.selected_cards[faction][0];
}
- resolve_active_and_proceed();
+ // resolve_active_and_proceed();
},
};
@@ -1362,12 +1384,12 @@ states.draw_card = {
draw_card() {
const { v } = get_active_node_args();
draw_hand_cards(get_active_faction(), v);
- resolve_active_and_proceed();
+ resolve_active_and_proceed(true);
},
draw_cards() {
const { v } = get_active_node_args();
draw_hand_cards(get_active_faction(), v);
- resolve_active_and_proceed();
+ resolve_active_and_proceed(true);
},
};
@@ -1384,7 +1406,7 @@ states.draw_glory = {
game.glory.push(faction);
- // TODO: remove if statement, just here atm to not break
+ // TODO: remove if statement, just here atm to not break
// running games
if (!game.glory_current_year) {
game.glory_current_year = game.glory_current_year = {
@@ -1397,7 +1419,11 @@ states.draw_glory = {
array_remove(game.bag_of_glory, index);
- log(`${get_player(get_active_faction())} draws <ft${faction}> from the Bag of Glory`)
+ log(
+ `${get_player(
+ get_active_faction()
+ )} draws <ft${faction}> from the Bag of Glory`
+ );
resolve_active_and_proceed(true);
},
};
@@ -3299,6 +3325,13 @@ function get_fronts_closest_to(target: 'd' | 'v'): FrontId[] {
},
[]
);
+
+ // Possible if all fronts have either been
+ // defeated or are victorious
+ if (values.length === 0) {
+ return [];
+ }
+
const targetValue =
target === 'd' ? Math.min(...values) : Math.max(...values);
return Object.keys(game.fronts).filter(
@@ -3382,7 +3415,7 @@ function add_prompt_prefix(prompt: string, prefix: string) {
}
function get_active_faction(): FactionId {
- return player_faction_map[game.active];
+ return player_faction_map[game.active as Player];
}
function get_blank_marker_id(track_id: number, space_id: number) {