summaryrefslogtreecommitdiff
path: root/rules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'rules.ts')
-rw-r--r--rules.ts190
1 files changed, 68 insertions, 122 deletions
diff --git a/rules.ts b/rules.ts
index 929b4ca..98b10b9 100644
--- a/rules.ts
+++ b/rules.ts
@@ -12,7 +12,7 @@ import {
FunctionNode,
Game,
Icon,
- LeafNode,
+ StateNode,
PlayCardArgs,
Player,
PlayerCard,
@@ -29,14 +29,6 @@ import data, {
ANARCHISTS_ID,
COMMUNISTS_ID,
MODERATES_ID,
- // LIBERTY,
- // COLLECTIVIZATION,
- // GOVERNMENT,
- // SOVIET_SUPPORT,
- // FOREIGN_AID,
- // MORALE_BONUS,
- // TEAMWORK_BONUS,
- // OFF,
LIBERTY,
CLOSEST_TO_DEFEAT,
CLOSEST_TO_VICTORY,
@@ -60,7 +52,6 @@ import data, {
TOWARDS_CENTER,
ARCHIVES_MEDALLION_ID,
INTELLIGENCE_MEDALLION_ID,
- // VOLUNTEERS_MEDALLION_ID,
ORGANIZATION_MEDALLION_ID,
STRATEGY_MEDALLION_ID,
PROPAGANDA_MEDALLION_ID,
@@ -75,24 +66,14 @@ import data, {
ARAGON,
FASCIST_ID,
NORTHERN,
- // StaticData,
- // PLAYER_WITH_MOST_HERO_POINTS,
} from './data';
-// interface State {
-// inactive: string;
-// prompt: () => void;
-// }
const OBSERVER = 'Observer';
const states = {} as States;
let game = {} as Game; // = null
var view = {} as View; // = null
-// export const ANARCHIST = 'Anarchist' as Player;
-// export const COMMUNIST = 'Communist' as Player;
-// export const MODERATE = 'Moderate' as Player;
-
const role_ids: FactionId[] = [ANARCHISTS_ID, COMMUNISTS_ID, MODERATES_ID];
const faction_player_map: Record<FactionId, Player> = {
@@ -185,18 +166,6 @@ function gen_spend_hero_points() {
}
}
-// function gen_action_space(space) {
-// gen_action('space', space);
-// }
-
-// function gen_action_piece(piece) {
-// gen_action('piece', piece);
-// }
-
-// function gen_action_card(card) {
-// gen_action('card', card);
-// }
-
export function action(
state: Game,
player: Player,
@@ -217,18 +186,18 @@ export function action(
// #region ENGINE
-const leaf_node = 'l';
+const state_node = 'l';
const seq_node = 's';
const function_node = 'f';
const resolved = 1;
-function create_leaf_node<T = any>(
+function create_state_node<T = any>(
state: string,
faction: FactionId | 'None' | 'all' | FactionId[],
args?: T
-): LeafNode {
+): StateNode {
return {
- t: leaf_node,
+ t: state_node,
s: state,
p: faction,
a: args,
@@ -256,7 +225,7 @@ function create_seq_node(children: EngineNode[]): SeqNode {
function checkpoint() {
if (game.undo.length > 0) {
insert_after_active_node(
- create_leaf_node('confirm_turn', get_active_faction())
+ create_state_node('confirm_turn', get_active_faction())
);
}
resolve_active_and_proceed();
@@ -265,22 +234,15 @@ function checkpoint() {
function setup_bag_of_glory() {
log_h1('Bag of Glory');
game.engine = [
- create_leaf_node('add_glory', game.initiative),
+ create_state_node('add_glory', game.initiative),
create_function_node('end_of_turn'),
];
next();
}
function setup_choose_card() {
- 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 = [create_state_node('choose_card', 'all')];
+
game.engine.push(create_function_node('setup_player_turn'));
next();
}
@@ -289,7 +251,7 @@ function setup_final_bid() {
log_h1('Final Bid');
const player_order = get_player_order();
game.engine = player_order.map((faction_id) =>
- create_leaf_node('choose_final_bid', faction_id)
+ create_state_node('choose_final_bid', faction_id)
);
game.engine.push(create_function_node('checkpoint'));
game.engine.push(create_function_node('resolve_final_bid'));
@@ -309,14 +271,14 @@ function setup_player_turn() {
game.engine = [
create_function_node('start_of_player_turn', { f: next_faction }),
- create_leaf_node('player_turn', next_faction),
+ create_state_node('player_turn', next_faction),
create_function_node('end_of_player_turn', { f: next_faction }),
];
next();
}
-// Check if player needs to discard cards. If so inserts leaf node
+// Check if player needs to discard cards. If so inserts state node
function check_end_of_year_discard() {
const { f: faction } = get_active_node_args();
@@ -324,7 +286,7 @@ function check_end_of_year_discard() {
game.hands[faction].length > get_hand_limit(faction) ||
game.tableaus[faction].length > game.year
) {
- insert_after_active_node(create_leaf_node('end_of_year_discard', faction));
+ insert_after_active_node(create_state_node('end_of_year_discard', faction));
}
resolve_active_and_proceed();
@@ -334,7 +296,7 @@ function end_of_player_turn() {
const { f: faction } = get_active_node_args();
if (get_next_faction_in_player_order(faction) === game.first_player) {
game.engine = [
- create_leaf_node('change_active_player', game.initiative),
+ create_state_node('change_active_player', game.initiative),
create_function_node('resolve_fascist_test'),
create_function_node('setup_bag_of_glory'),
];
@@ -391,9 +353,9 @@ const engine_functions: Record<string, Function> = {
function get_active(
engine: EngineNode[]
-): { parent: EngineNode[]; node: FunctionNode | LeafNode } | null {
+): { parent: EngineNode[]; node: FunctionNode | StateNode } | null {
for (let i of engine) {
- if ((i.t === leaf_node || i.t === function_node) && i.r !== resolved) {
+ if ((i.t === state_node || i.t === function_node) && i.r !== resolved) {
return { parent: engine, node: i };
}
if (i.t === seq_node) {
@@ -408,7 +370,7 @@ function get_active(
function get_active_node(
engine: EngineNode[] = game.engine
-): FunctionNode | LeafNode | null {
+): FunctionNode | StateNode | null {
const a = get_active(engine);
return a === null ? null : a.node;
}
@@ -416,10 +378,10 @@ function get_active_node(
function get_nodes_for_state(
state: string,
engine: EngineNode[] = game.engine
-): LeafNode[] {
+): StateNode[] {
let nodes = [];
for (let i of engine) {
- if (i.t === leaf_node && i.s === state) {
+ if (i.t === state_node && i.s === state) {
nodes.push(i);
}
if (i.t === seq_node) {
@@ -431,7 +393,7 @@ function get_nodes_for_state(
function get_active_node_args<T = any>(): T {
const node = get_active_node(game.engine);
- if (node.t === leaf_node || node.t === function_node) {
+ if (node.t === state_node || node.t === function_node) {
return node.a ?? {};
}
return null;
@@ -439,7 +401,7 @@ function get_active_node_args<T = any>(): T {
function update_active_node_args<T = any>(args: Partial<T>) {
const node = get_active_node(game.engine);
- if (node.t === leaf_node || node.t === function_node) {
+ if (node.t === state_node || node.t === function_node) {
node.a = {
...node.a,
...args,
@@ -476,7 +438,7 @@ function insert_before_active_node(
insert_before_or_after_active_node(node, 'before', engine);
}
-function get_next_active(p: LeafNode['p']): Player | Player[] | 'None' {
+function get_next_active(p: StateNode['p']): Player | Player[] | 'None' {
if (Array.isArray(p)) {
return p.map((faction) => faction_player_map[faction]);
}
@@ -513,7 +475,7 @@ function next(checkpoint = false) {
if (next_active !== current_active && game.undo.length > 0) {
insert_before_active_node(
- create_leaf_node('confirm_turn', get_active_faction())
+ create_state_node('confirm_turn', get_active_faction())
);
game.state = 'confirm_turn';
return;
@@ -592,7 +554,9 @@ function game_view(state: Game, current: Player | 'Observer') {
!game.active.includes(current as Player)
) {
let inactive = states[game.state].inactive || game.state;
- view.prompt = Array.isArray(game.active) ? `Waiting for other players to ${inactive}.` : `Waiting for ${game.active} to ${inactive}.`;
+ view.prompt = Array.isArray(game.active)
+ ? `Waiting for other players to ${inactive}.`
+ : `Waiting for ${game.active} to ${inactive}.`;
} else {
view.actions = {};
if (game.undo && game.undo.length > 0) view.actions.undo = 1;
@@ -771,11 +735,6 @@ function start_turn() {
game.engine.push(create_function_node('setup_choose_card'));
}
next();
- // game.state = 'resolve_event';
- // game.active = faction_player_map[game.initiative];
- // game.state_data = {
- // current_effect: 0,
- // };
}
// region STATES
@@ -805,7 +764,7 @@ states.activate_icon = {
},
add_to_front() {
insert_after_active_node(
- create_leaf_node('add_to_front', get_active_faction(), {
+ create_state_node('add_to_front', get_active_faction(), {
t: ANY,
v: get_icon_count_in_tableau('add_to_front'),
})
@@ -1155,15 +1114,12 @@ states.choose_area_ap = {
resolve_active_and_proceed();
},
standee(track_id: number) {
- insert_after_active_node({
- t: leaf_node,
- p: get_active_faction(),
- s: 'move_track_up_or_down',
- a: {
+ insert_after_active_node(
+ create_state_node('move_track_up_or_down', get_active_faction(), {
track_id,
strength: get_active_node()?.a.strength,
- },
- });
+ })
+ );
resolve_active_and_proceed();
},
};
@@ -1328,7 +1284,7 @@ function setup_momentum() {
// right away or not. Depends on whether card for this turn has been fully resolved or not
// Get player turn node
- const node: LeafNode<PlayerTurnArgs> = get_nodes_for_state('player_turn')[0];
+ const node: StateNode<PlayerTurnArgs> = get_nodes_for_state('player_turn')[0];
const player_needs_to_play_card = game.selected_cards[faction].length > 0;
const { use_ap, use_morale_bonus, resolving_event } =
@@ -1348,7 +1304,7 @@ function setup_momentum() {
} else {
// Player can resolve choosing a new card
insert_after_active_node(
- create_leaf_node<PlayCardArgs>('play_card', faction, {
+ create_state_node<PlayCardArgs>('play_card', faction, {
src: 'momentum',
})
);
@@ -1785,7 +1741,7 @@ function resolve_spend_hp() {
// insert spend hero points node before current node
// so it will return to current node after resolving
insert_before_active_node(
- create_leaf_node('spend_hero_points', get_active_faction())
+ create_state_node('spend_hero_points', get_active_faction())
);
log('Spends Hero Points');
@@ -1911,7 +1867,7 @@ states.player_turn = {
use_ap: false,
});
insert_before_active_node(
- create_leaf_node('choose_area_ap', faction, {
+ create_state_node('choose_area_ap', faction, {
strength,
})
);
@@ -1935,7 +1891,7 @@ states.player_turn = {
use_morale_bonus: false,
});
insert_before_active_node(
- create_leaf_node('activate_icon', get_active_faction())
+ create_state_node('activate_icon', get_active_faction())
);
next();
},
@@ -2029,7 +1985,7 @@ states.remove_attack_from_fronts = {
resolve_active_and_proceed();
} else if (card_id === 39 || card_id === 16) {
insert_after_active_node(
- create_leaf_node('attack_front', get_active_faction(), {
+ create_state_node('attack_front', get_active_faction(), {
t: ANY,
v: card_id === 39 ? -2 : -1 * removed_value,
n: card_id === 16 ? id : undefined,
@@ -2043,7 +1999,7 @@ states.remove_attack_from_fronts = {
const values: number[] = Object.values(f ?? {});
if (card_id === 39 && values.length > 0) {
insert_after_active_node(
- create_leaf_node('attack_front', get_active_faction(), {
+ create_state_node('attack_front', get_active_faction(), {
t: ANY,
v: -2,
})
@@ -2161,11 +2117,11 @@ states.spend_hero_points = {
pay_hero_points(faction, 1);
insert_after_active_node(
create_seq_node([
- create_leaf_node('add_to_front', faction, {
+ create_state_node('add_to_front', faction, {
t: ANY,
v: 1,
}),
- create_leaf_node('spend_hero_points', faction),
+ create_state_node('spend_hero_points', faction),
])
);
resolve_active_and_proceed();
@@ -2202,8 +2158,8 @@ states.spend_hero_points = {
}
insert_after_active_node(
create_seq_node([
- create_leaf_node('remove_blank_marker', faction),
- create_leaf_node('spend_hero_points', faction),
+ create_state_node('remove_blank_marker', faction),
+ create_state_node('spend_hero_points', faction),
])
);
resolve_active_and_proceed();
@@ -2222,11 +2178,11 @@ states.spend_hero_points = {
pay_hero_points(faction, amount);
insert_after_active_node(
create_seq_node([
- create_leaf_node('move_track_up_or_down', faction, {
+ create_state_node('move_track_up_or_down', faction, {
track_id,
strength: 1,
}),
- create_leaf_node('spend_hero_points', faction),
+ create_state_node('spend_hero_points', faction),
])
);
resolve_active_and_proceed();
@@ -2637,7 +2593,7 @@ function determine_winner() {
win_game(faction_player_map[winners[0]], highest_glory);
} else {
insert_after_active_node(
- create_leaf_node('break_tie_winner', game.initiative, {
+ create_state_node('break_tie_winner', game.initiative, {
winners,
glory: highest_glory,
})
@@ -2689,7 +2645,7 @@ function end_of_year() {
const engine = [];
for (let i = 0; i < glory_to_draw[game.year]; ++i) {
- engine.push(create_leaf_node('draw_glory', player_order[i % 3]));
+ engine.push(create_state_node('draw_glory', player_order[i % 3]));
}
engine.push(create_function_node('end_of_year_cleanup'));
@@ -2726,7 +2682,7 @@ function end_of_year_cleanup() {
function end_resolving_event_effects() {
// Get player turn node
- const node: LeafNode<PlayerTurnArgs> = get_nodes_for_state('player_turn')[0];
+ const node: StateNode<PlayerTurnArgs> = get_nodes_for_state('player_turn')[0];
// Update args
node.a = {
@@ -2784,9 +2740,7 @@ function gain_hero_points(
}
function game_over(result: Player | 'None', victory: string) {
- insert_after_active_node(create_leaf_node('game_over', 'None'));
- // game.state = 'game_over';
- // game.active = 'None';
+ insert_after_active_node(create_state_node('game_over', 'None'));
game.result = result;
game.victory = victory;
game.undo = [];
@@ -2896,7 +2850,7 @@ function resolve_final_bid() {
win_final_bid(winners[0]);
} else {
insert_after_active_node(
- create_leaf_node('break_tie_final_bid', game.initiative, { winners })
+ create_state_node('break_tie_final_bid', game.initiative, { winners })
);
}
@@ -3025,7 +2979,7 @@ function insert_use_organization_medallion_node(
const faction = get_active_faction();
insert_after_active_node(
- create_leaf_node('use_organization_medallion', faction, {
+ create_state_node('use_organization_medallion', faction, {
t: track_id,
v: value,
})
@@ -3085,7 +3039,7 @@ function update_front(
can_use_medallion(STRATEGY_MEDALLION_ID)
) {
insert_after_active_node(
- create_leaf_node('use_strategy_medallion', get_active_faction(), {
+ create_state_node('use_strategy_medallion', get_active_faction(), {
f: front_id,
})
);
@@ -3170,7 +3124,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
return create_function_node(effect.target as string);
}
if (effect.type === 'state') {
- return create_leaf_node(effect.target as string, faction, {
+ return create_state_node(effect.target as string, faction, {
v: effect.value,
src: source,
});
@@ -3178,7 +3132,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
// 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);
+ return create_state_node(state, faction, args);
}
// Specific mapping based on target
@@ -3188,7 +3142,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
effect.type === 'hero_points' &&
effect.target === PLAYER_WITH_MOST_HERO_POINTS,
resolve: () => {
- return create_leaf_node(
+ return create_state_node(
'select_player_with_most_hero_points',
faction,
args
@@ -3200,7 +3154,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
resolve: () => {
return create_seq_node(
get_player_order().map((faction) =>
- create_leaf_node('hero_points', faction, args)
+ create_state_node('hero_points', faction, args)
)
);
},
@@ -3208,7 +3162,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
{
condition: effect.type === 'hero_points' && effect.target === SELF,
resolve: () => {
- return create_leaf_node('hero_points', faction, args);
+ return create_state_node('hero_points', faction, args);
},
},
{
@@ -3216,7 +3170,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
effect.type === 'hero_points' &&
role_ids.includes(effect.target as FactionId),
resolve: () => {
- return create_leaf_node(
+ return create_state_node(
'hero_points',
effect.target as FactionId,
args
@@ -3227,20 +3181,20 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
condition:
effect.type === 'hero_points' && effect.target === INITIATIVE_PLAYER,
resolve: () => {
- return create_leaf_node('hero_points', game.initiative, args);
+ return create_state_node('hero_points', game.initiative, args);
},
},
{
condition: effect.type === 'draw_card' && effect.target === SELF,
resolve: () => {
- return create_leaf_node('draw_card', faction, args);
+ return create_state_node('draw_card', faction, args);
},
},
{
condition:
effect.type === 'draw_card' && effect.target === INITIATIVE_PLAYER,
resolve: () => {
- return create_leaf_node('draw_card', game.initiative, args);
+ return create_state_node('draw_card', game.initiative, args);
},
},
{
@@ -3248,7 +3202,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
effect.type === 'draw_card' &&
role_ids.includes(effect.target as FactionId),
resolve: () => {
- return create_leaf_node('draw_card', effect.target as FactionId, args);
+ return create_state_node('draw_card', effect.target as FactionId, args);
},
},
{
@@ -3256,7 +3210,7 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
resolve: () => {
return create_seq_node(
get_player_order(get_active_faction()).map((faction) =>
- create_leaf_node('draw_card', faction, args)
+ create_state_node('draw_card', faction, args)
)
);
},
@@ -3264,19 +3218,19 @@ function resolve_effect(effect: Effect, source?: EffectSource): EngineNode {
{
condition: effect.type === 'draw_card' && effect.target === OTHER_PLAYERS,
resolve: () => {
- const leaf_nodes = get_player_order(get_active_faction()).map(
- (faction) => create_leaf_node('draw_card', faction, args)
+ const state_nodes = get_player_order(get_active_faction()).map(
+ (faction) => create_state_node('draw_card', faction, args)
);
- array_remove(leaf_nodes, 0); // Remove current player
- return create_seq_node(leaf_nodes);
+ array_remove(state_nodes, 0); // Remove current player
+ return create_seq_node(state_nodes);
},
},
{
condition: effect.type === 'play_card',
resolve: () => {
return create_seq_node([
- create_leaf_node('play_card', faction, { src: source }),
- create_leaf_node('player_turn', faction, { src: source }),
+ create_state_node('play_card', faction, { src: source }),
+ create_state_node('player_turn', faction, { src: source }),
]);
},
},
@@ -3305,14 +3259,6 @@ function win_game(player: Player, glory: number) {
// #endregion
// #region CARDS
-// function draw_faction_card(faction: Player): CardId {
-// return draw_faction_cards(faction, 1)[0];
-// }
-
-// function draw_faction_cards(faction: Player, count: number = 1): CardId[] {
-// const drawnCards = [];
-
-// }
function draw_card(deck: CardId[]): CardId {
clear_undo();