summaryrefslogtreecommitdiff
path: root/rules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'rules.ts')
-rw-r--r--rules.ts333
1 files changed, 157 insertions, 176 deletions
diff --git a/rules.ts b/rules.ts
index 2fea19e..796f887 100644
--- a/rules.ts
+++ b/rules.ts
@@ -86,7 +86,7 @@ const player_faction_map: Record<Player, FactionId> = {
const front_names: Record<string, string> = {
a: 'Aragon Front',
m: 'Madrid Front',
- n: 'Nothern Front',
+ n: 'Northern Front',
s: 'Southern Front',
d: 'the Front closest to Defeat',
v: 'the Front closest to Victory',
@@ -490,13 +490,16 @@ export function setup(seed: number, _scenario: string, _options: unknown) {
return game;
}
-function draw_hand_cards() {
- role_ids.forEach((role) => {
- const deck = list_deck(role);
- for (let i = 0; i < 5; i++) {
- game.hands[role].push(draw_card(deck));
- }
- });
+function draw_hand_cards(faction_id: FactionId, count: number) {
+ const log =
+ count === 1
+ ? `${get_player(faction_id)} draws 1 card`
+ : `${get_player(faction_id)} draws ${count} 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
@@ -504,7 +507,9 @@ function draw_hand_cards() {
function start_year() {
// log_h1('Year ' + game.year);
game.current_events = [];
- draw_hand_cards();
+ role_ids.forEach((role) => {
+ draw_hand_cards(role, 5);
+ });
start_turn();
}
@@ -545,7 +550,12 @@ states.activate_icon = {
}
},
add_to_front() {
- // insert state to select front
+ insert_after_active_node(
+ create_leaf_node('add_to_front', get_active_faction(), {
+ t: ANY,
+ v: get_icon_count_in_tableau('add_to_front'),
+ })
+ );
resolve_active_and_proceed();
},
collectivization() {
@@ -579,7 +589,10 @@ states.activate_icon = {
resolve_active_and_proceed();
},
draw_card() {
- // TODO: draw cards
+ draw_hand_cards(
+ get_active_faction(),
+ get_icon_count_in_tableau('draw_card')
+ );
resolve_active_and_proceed();
},
foreign_aid() {
@@ -587,10 +600,18 @@ states.activate_icon = {
resolve_active_and_proceed();
},
government() {
- move_track(GOVERNMENT, get_icon_count_in_tableau('government'));
+ const direction = game.active === COMMUNIST ? -1 : 1;
+ move_track(GOVERNMENT, direction * get_icon_count_in_tableau('government'));
+ resolve_active_and_proceed();
+ },
+ government_to_center() {
+ const direction = game.tracks[GOVERNMENT] >= 6 ? -1 : 1;
+ move_track(
+ GOVERNMENT,
+ direction * get_icon_count_in_tableau('government_to_center')
+ );
resolve_active_and_proceed();
},
- government_to_center() {},
liberty() {
move_track(LIBERTY, get_icon_count_in_tableau('liberty'));
resolve_active_and_proceed();
@@ -642,7 +663,7 @@ states.add_to_front = {
},
front(f: FrontId) {
const value = get_active_node_args().v;
- update_front(f, value);
+ update_front(f, value, get_active_faction());
resolve_active_and_proceed();
},
};
@@ -652,18 +673,23 @@ states.attack_front = {
prompt() {
const node = get_active_node();
const front = node.a.t;
- view.prompt = 'Attack ' + front_names[front];
- let targets = [];
-
+
+ let targets: Array<FrontId> = [];
+
if (front === 'd' || front === 'v') {
targets = get_fronts_closest_to(front);
} else if (game.fronts[front].status === DEFEAT) {
- targets = get_fronts_closest_to('d')
+ targets = get_fronts_closest_to('d');
} else if (game.fronts[front].status === VICTORY) {
targets = get_fronts_to_add_to(ANY);
} else {
targets.push(front);
}
+ view.prompt =
+ targets.length === 1
+ ? `Attack ${front_names[targets[0]]}`
+ : 'Attack a front';
+
targets.forEach((id) => gen_action('front', id));
},
front(f: FrontId) {
@@ -702,7 +728,6 @@ states.choose_area_ap = {
resolve_active_and_proceed();
},
standee(track_id: number) {
- console.log('standee', track_id);
insert_after_active_node({
t: leaf_node,
p: get_active_faction_id(),
@@ -912,85 +937,82 @@ states.player_turn = {
resolve_active_and_proceed();
},
spend_hp() {
- insert_before_active_node({
- t: leaf_node,
- p: get_faction_id(game.active as Player),
- s: 'spend_hero_points',
- });
// 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())
+ );
+ log('Spends Hero Points');
+
next();
},
- // card(c: CardId) {
- // const faction = get_active_faction();
- // log_h3(`${game.active} plays ${cards[c].title} to their tableau`);
- // if (!game.tableaus) {
- // game.tableaus = {
- // [ANARCHISTS_ID]: [],
- // [COMMUNISTS_ID]: [],
- // [MODERATES_ID]: [],
- // };
- // }
- // game.chosen_cards[faction] = null;
- // game.tableaus[faction].push(c);
- // array_remove(game.hands[faction], game.hands[faction].indexOf(c));
- // resolve_active_and_proceed();
- // },
};
-// states.resolve_event = {
-// inactive: 'resolve Fascist Event',
-// prompt() {
-// const card = get_current_event();
-// const node = get_active_node(game.engine) as LeafNode;
-// const effect: Effect = card.effects[node.a];
-// view.prompt = get_event_prompt(effect);
-
-// if (effect.type === 'track') {
-// gen_action('standee', effect.target);
-// } else if (
-// effect.type === 'hero_points' &&
-// effect.target === PLAYER_WITH_MOST_HERO_POINTS
-// ) {
-// const factions = get_factions_with_most_hero_poins();
-// for (let faction_id of factions) {
-// gen_action(get_player(faction_id));
-// }
-// }
-// // for (let p = 0; p < 5; ++p) gen_action('standee', p);
-// },
-
-// Anarchist() {
-// lose_hero_point(ANARCHISTS_ID, 1);
-// resolve_active_and_proceed();
-// },
-// Communist() {
-// lose_hero_point(ANARCHISTS_ID, 1);
-// resolve_active_and_proceed();
-// },
-// Moderate() {
-// lose_hero_point(ANARCHISTS_ID, 1);
-// resolve_active_and_proceed();
-// },
-// };
-
states.spend_hero_points = {
inactive: 'spend Hero points',
prompt() {
view.prompt = 'Spend your Hero points';
gen_action('done');
+ const hero_points = game.hero_points[get_active_faction()];
+ if (hero_points === 0) {
+ return;
+ }
gen_action('draw_card');
+
+ if (hero_points < 2) {
+ return;
+ }
+ gen_action_standee(FOREIGN_AID);
+ gen_action_standee(SOVIET_SUPPORT);
+ for (const bonus of bonuses) {
+ if (game.bonuses[bonus] === OFF) {
+ gen_action_bonus(bonus);
+ }
+ }
+
+ if (hero_points < 3) {
+ return;
+ }
+ gen_action_standee(COLLECTIVIZATION);
+ gen_action_standee(LIBERTY);
+
+ if (hero_points < 4) {
+ return;
+ }
+ gen_action_standee(GOVERNMENT);
},
done() {
resolve_active_and_proceed();
},
+ bonus(b: number) {
+ update_bonus(b, ON);
+ pay_hero_points(get_active_faction(), 2);
+ },
draw_card() {
- game.hero_points[get_active_faction_id()]--;
- log(`${game.active} draws a card`);
- // TODO: Draw card
- if (game.hero_points[get_active_faction_id()] === 0) {
- resolve_active_and_proceed();
+ const faction = get_active_faction();
+ pay_hero_points(faction, 1);
+ draw_hand_cards(faction, 1);
+ },
+ standee(track_id: number) {
+ let amount = 2;
+ if (track_id === LIBERTY || track_id === COLLECTIVIZATION) {
+ amount = 3;
+ } else if (track_id === GOVERNMENT) {
+ amount = 4;
}
+ const faction = get_active_faction();
+ pay_hero_points(faction, amount);
+ insert_after_active_node(
+ create_seq_node([
+ create_leaf_node('move_track_up_or_down', faction, {
+ track_id,
+ strength: 1,
+ }),
+ create_leaf_node('spend_hero_points', faction),
+ ])
+ );
+ resolve_active_and_proceed();
},
};
@@ -1131,26 +1153,50 @@ function resolve_fascist_test() {
}
// TODO: check for defeated / won fronts
-function get_fronts_to_add_to(target: string): string[] {
+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) {
return FRONTS.filter((id) => game.fronts[id].status === null);
} else {
- return [target];
+ return [target as FrontId];
+ }
+}
+
+function get_max_value_for_track(track_id: number) {
+ switch (track_id) {
+ case LIBERTY:
+ return game.tracks[COLLECTIVIZATION] >= 8 ? 10 : 7;
+ case GOVERNMENT:
+ return game.tracks[FOREIGN_AID] >= 8 ? 10 : 7;
+ case COLLECTIVIZATION:
+ case SOVIET_SUPPORT:
+ case FOREIGN_AID:
+ default:
+ return 10;
+ }
+}
+
+function get_min_value_for_track(track_id: number) {
+ switch (track_id) {
+ case GOVERNMENT:
+ return game.tracks[SOVIET_SUPPORT] >= 8 ? 4 : 1;
+ case LIBERTY:
+ case COLLECTIVIZATION:
+ case SOVIET_SUPPORT:
+ case FOREIGN_AID:
+ default:
+ return 0;
}
}
function move_track(track_id: number, change: number) {
- // Check if track can be moved
- // Updata values
- // Check all triggers
- // Add states for triggers
const current_value = game.tracks[track_id];
let new_value = current_value + change;
- new_value = Math.max(new_value, track_id === GOVERNMENT ? 1 : 0);
- new_value = Math.min(new_value, 10);
+ 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}`);
@@ -1178,6 +1224,11 @@ function move_track(track_id: number, change: number) {
});
}
+function pay_hero_points(faction: FactionId, amount: number) {
+ game.hero_points[faction] -= amount;
+ game.hero_points.pool += amount;
+}
+
function update_bonus(bonus_id: number, status: number) {
if (game.bonuses[bonus_id] === status) {
return;
@@ -1206,9 +1257,16 @@ function update_front(
) {
change += 1;
}
-
+ const value_before = game.fronts[front_id].value;
game.fronts[front_id].value += change;
logi(`${front_names[front_id]}: ${change > 0 ? '+' : ''}${change}`);
+ if (
+ faction_id !== null &&
+ value_before <= 0 &&
+ game.fronts[front_id].value > 0
+ ) {
+ gain_hero_points(faction_id, 1);
+ }
// Add token to front if player contributed
if (
@@ -1234,12 +1292,14 @@ function defeat_on_a_front(front_id: FrontId) {
game_over('None', 'All players lose the game!');
return;
}
- insert_after_active_node(create_effects_node([
- create_effect('bonus', MORALE_BONUS, OFF),
- create_effect('track', COLLECTIVIZATION, -1),
- create_effect('track', SOVIET_SUPPORT, -1),
- create_effect('track', FOREIGN_AID, -1),
- ]));
+ insert_after_active_node(
+ create_effects_node([
+ create_effect('bonus', MORALE_BONUS, OFF),
+ create_effect('track', COLLECTIVIZATION, -1),
+ create_effect('track', SOVIET_SUPPORT, -1),
+ create_effect('track', FOREIGN_AID, -1),
+ ])
+ );
}
function victory_on_a_front(front_id: FrontId) {
@@ -1338,88 +1398,9 @@ function lose_hero_point(faction: FactionId, value: number) {
// #endregion
-// #region EVENTS
-
-// function get_current_event(): EventCard {
-// return cards[
-// game.current_events[game.current_events.length - 1]
-// ] as EventCard;
-// }
-
-// function get_front_name(frontId: string) {
-// switch (frontId) {
-// case 'a':
-// return 'the Aragon Front';
-// case 'm':
-// return 'the Madrid Front';
-// case 'n':
-// return 'the Nothern Front';
-// case 's':
-// return 'the Southern Front';
-// case 'd':
-// return 'the Front closest to Defeat';
-// case 'v':
-// return 'the Front closest to Victory';
-// default:
-// return '';
-// }
-// }
-
-// function get_event_prompt(effect: Effect) {
-// let prompt = '';
-// switch (effect.type) {
-// case 'attack':
-// return 'Attack ' + front_names[effect.target as string];
-// case 'bonus':
-// break;
-// case 'hero_points':
-// return 'Select player with most Hero points';
-// case 'track':
-// return 'Decrease ' + tracks[effect.target].name;
-// }
-// return prompt;
-// }
-
-// function resolve_event_attack(target: string | number, value: number) {
-// switch (target) {
-// case 'v':
-// break;
-// case 'd':
-// break;
-// default:
-// game.fronts[target] += value;
-// }
-// }
-
-// function fascist_event() {
-// // log_h1('Year ' + game.year);
-// const deck = fascist_decks[game.year];
-// const cardId = draw_card(deck);
-// game.current_events.push(cardId);
-
-// const card = cards[cardId] as EventCard;
-
-// card.effects.forEach((effect) => {
-// switch (effect.type) {
-// case 'attack':
-// resolve_event_attack(effect.target, effect.value);
-// break;
-// case 'bonus':
-// break;
-// case 'hero_points':
-// break;
-// case 'track':
-// game.tracks[effect.target] += effect.value;
-// break;
-// }
-// });
-// }
-
-// #endregion
-
// #region FRONTS
-function get_fronts_closest_to(target: 'd' | 'v') {
+function get_fronts_closest_to(target: 'd' | 'v'): FrontId[] {
const values = Object.values(game.fronts).reduce(
(accrued: number[], current: Front) => {
if (current.status === null) {
@@ -1433,7 +1414,7 @@ function get_fronts_closest_to(target: 'd' | 'v') {
target === 'd' ? Math.min(...values) : Math.max(...values);
return Object.keys(game.fronts).filter(
(frontId) => game.fronts[frontId].value === targetValue
- );
+ ) as FrontId[];
}
// #endregion