From 23bd83c80d3e0a2d7dd18f76ae4039effd7ce448 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 22 Oct 2024 22:19:15 +0200 Subject: political shifts and troops+tcs --- rules.js | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 294 insertions(+), 33 deletions(-) (limited to 'rules.js') diff --git a/rules.js b/rules.js index 6a6d9d9..1450e9d 100644 --- a/rules.js +++ b/rules.js @@ -91,6 +91,7 @@ const F_ITALY_FRANCE = 4 const F_ITALY_AUSTRIA = 8 const F_SILESIA_ANNEXED = 16 const F_IMPERIAL_ELECTION = 32 // imperial election card revealed! +const F_WAR_OF_JENKINS_EAR = 64 const SPADES = 0 const CLUBS = 1 @@ -741,6 +742,21 @@ function tc_per_turn() { ++n } + // Jacobite Rising + if (game.power === P_PRAGMATIC) { + for (let p of all_power_generals[P_PRAGMATIC]) + if (game.pos[p] === ENGLAND) + --n + } + + // War of Jenkins' Ear + if (game.power === P_FRANCE) { + if (game.flags & F_WAR_OF_JENKINS_EAR) { + game.flags &= ~F_WAR_OF_JENKINS_EAR + --n + } + } + return n } @@ -2451,6 +2467,27 @@ states.recruit = { }, } +function enter_general_at(p, s) { + game.pos[p] = s + game.troops[p] = 1 + + // remove hussars + for (let p of all_hussars) { + if (game.pos[p] === s) { + log("P" + p + " removed.") + game.pos[p] = ELIMINATED + } + } + + // remove enemy supply trains + for (let p of all_enemy_trains(game.power)) { + if (game.pos[p] === s) { + log("P" + p + " eliminated.") + game.pos[p] = ELIMINATED + } + } +} + states.re_enter_general_where = { inactive: "recruit", prompt() { @@ -2462,26 +2499,32 @@ states.re_enter_general_where = { }, space(s) { let p = game.selected - game.pos[p] = s set_add(game.recruit.pieces, p) - if (is_general(p)) { - game.recruit.troops += 1 - game.troops[p] = 1 - } + enter_general_at(p, s) + game.recruit.troops += 1 game.selected = -1 game.state = "recruit" + }, +} - // remove hussars - for (let p of all_hussars) { - log("P" + p + " removed.") - game.pos[p] = ELIMINATED - } - - // remove enemy supply trains - for (let p of all_enemy_trains(game.power)) { - log("P" + p + " eliminated.") - game.pos[p] = ELIMINATED - } +states.re_enter_general_from_political_card = { + inactive: "execute political card", + prompt() { + prompt("Re-enter " + format_selected() + ".") + view.selected = game.selected + for (let s of all_home_country_major_fortresses[game.power]) + if (can_re_enter_general_at_city(s)) + gen_action_space(s) + }, + space(s) { + let p = game.selected + log("P" + p + " re-entered at S" + s + ".") + enter_general_at(p, s) + game.selected = -1 + if (--game.count > 0) + game.state = "political_troops_place" + else + next_execute_political_card() }, } @@ -3239,7 +3282,7 @@ const INFLUENCE_ORDER = [ function goto_politics() { game.political = [] - game.display = [ 0, 0, 0, 0 ] + game.placed = [ 0, 0, 0, 0 ] game.stage = 0 log("Reveal") @@ -3277,9 +3320,9 @@ states.determine_trump_suit = { view.actions.suit = [ 0, 1, 2, 3 ] }, suit(s) { + game.trump = s log(power_name[game.power] + " chose " + suit_name[game.trump] + " as trump.") log_br() - game.trump = s goto_place_tc_on_display() } } @@ -3301,7 +3344,7 @@ states.place_tc_on_display = { push_undo() log(power_name[game.power] + " placed a TC.") set_delete(game.hand[game.power], c) - game.display[game.power] = c + game.placed[game.power] = c game.state = "place_tc_on_display_done" }, pass() { @@ -3317,6 +3360,7 @@ states.place_tc_on_display_done = { view.actions.next = 1 }, next() { + clear_undo() end_place_tc_on_display() }, } @@ -3334,9 +3378,9 @@ function goto_determine_order_of_influence() { // Turn cards face-up and return bluff cards for (let pow of POWER_FROM_POLITICAL_STAGE) { - let c = game.display[pow] + let c = game.placed[pow] if (c > 0) { - if (to_suit(c) === game.trump) { + if (is_reserve(c) || to_suit(c) === game.trump) { log(">" + format_card(c) + " " + power_name[pow]) set_add(game.saved[pow], c) } else { @@ -3345,7 +3389,7 @@ function goto_determine_order_of_influence() { } } } - delete game.display + delete game.placed log_br() game.stage = 0 @@ -3404,7 +3448,10 @@ states.select_political_card = { political(pc) { push_undo() log(power_name[game.power] + " chose C" + pc + ".") - throw "TODO" + game.saved[game.power] = [] + game.pc = pc + game.pcx = -1 + next_execute_political_card() }, pass() { log(power_name[game.power] + " saved its TC.") @@ -3430,6 +3477,221 @@ function end_politics() { goto_place_hussars() } +/* POLITICAL CARDS */ + +const event_shift = { + "Italy +1": { track: "italy", amount: [ 1 ] }, + "Italy +2": { track: "italy", amount: [ 2 ] }, + "Italy -1 or +1": { track: "italy", amount: [ -1, 1 ] }, + "Italy -1 or +2": { track: "italy", amount: [ -1, 2 ] }, + "Italy -1": { track: "italy", amount: [ -1 ] }, + "Italy -2 or +1": { track: "italy", amount: [ -2, 1 ] }, + "Italy -2": { track: "italy", amount: [ -2 ] }, + "Russia +1": { track: "russia", amount: [ 1 ] }, + "Russia -1 or +1": { track: "russia", amount: [ -1, 1 ] }, + "Russia -1 or +2": { track: "russia", amount: [ -1, 2 ] }, + "Russia -1": { track: "russia", amount: [ -1 ] }, + "Russia -2": { track: "russia", amount: [ -2 ] }, + "Saxony +1": { track: "saxony", amount: [ 1 ] }, + "Saxony +4": { track: "saxony", amount: [ 4 ] }, + "Saxony -1 if allied with Prussia": { + track: "saxony", + amount: [ -1 ], + condition: () => is_saxony_allied_with_prussia(), + }, +} + +const event_troops = { + "Your major power +3 troops": + { tcs: 0, troops: 3, power: () => [ game.power ] }, + "France +1 TC and +3 troops": + { tcs: 1, troops: 3, power: () => [ P_FRANCE ] }, + "Pragmatic +1 TC and +3 troops": + { tcs: 1, troops: 3, power: () => [ P_PRAGMATIC ] }, + "Pragmatic or France +1 TC and +2 troops": + { tcs: 1, troops: 2, power: () => [ P_PRAGMATIC, P_FRANCE ] }, + "France or Bavaria +2 troops": + { tcs: 0, troops: 2, power: () => [ P_FRANCE, P_BAVARIA ] }, + "Saxony +2 troops": + { tcs: 0, troops: 2, power: () => [ P_SAXONY ] }, +} + +const event_misc = { + "Mannheim to French control": goto_mannheim_to_french_control, + "Pragmatic general to England": goto_pragmatic_general_to_england, + "France -1 TC this turn": goto_france_minus_tc_this_turn, +} + +function current_political_effect() { + return political_cards[game.pc].effects[game.pcx] +} + +function next_execute_political_card() { + if (++game.pcx === political_cards[game.pc].effects.length) { + game.state = "political_card_done" + return + } + let fx = current_political_effect() + if (fx in event_shift) + game.state = "political_shift" + else if (fx in event_troops) + game.state = "political_troop_power" + else if (fx in event_misc) + event_misc[fx]() +} + +states.political_card_done = { + inactive: "execute political card", + prompt() { + prompt("Political card done.") + view.actions.end_political_card = 1 + }, + end_political_card() { + end_execute_political_card() + }, +} + +function end_execute_political_card() { + clear_undo() + array_remove_item(game.political, game.pc) + delete game.pc + delete game.pcx + goto_adjust_political_tracks() +} + +const TRACK_NAME = { saxony: "Saxony marker", russia: "Russia marker", italy: "Italy marker" } +const TRACK_SIZE = { saxony: 5, russia: 9, italy: 9 } + +states.political_shift = { + inactive: "execute political card", + prompt() { + let info = event_shift[current_political_effect()] + prompt("Shift " + TRACK_NAME[info.track] + ".") + if (info.condition === undefined || info.condition()) + view.actions.shift = info.amount + view.actions.pass = 1 + view.pc = game.pc + }, + shift(n) { + push_undo() + let info = event_shift[current_political_effect()] + game[info.track] += n + game[info.track] = Math.max(1, Math.min(TRACK_SIZE[info.track], game[info.track])) + log("Shifted " + TRACK_NAME[info.track] + " to " + game[info.track] + ".") + next_execute_political_card() + }, + pass() { + push_undo() + next_execute_political_card() + }, +} + +states.political_troop_power = { + inactive: "execute political card", + prompt() { + let fx = current_political_effect() + let info = event_troops[fx] + prompt(fx) + view.pc = game.pc + view.actions.power = info.power() + view.actions.pass = 1 + }, + power(pow) { + clear_undo() + let info = event_troops[current_political_effect()] + set_active_to_power(pow) + if (info.tcs > 0) { + draw_tc(info.tcs) + game.state = "political_troops_draw" + } else { + game.state = "political_troops_place" + } + game.count = info.troops + }, + pass() { + push_undo() + next_execute_political_card() + }, +} + +states.political_troops_draw = { + inactive: "execute political card", + prompt() { + let info = event_troops[current_political_effect()] + prompt("Draw " + format_card_list_prompt(game.draw) + ".") + view.draw = game.draw + view.actions.next = 1 + }, + next() { + push_undo() + let info = event_troops[current_political_effect()] + if (info.tcs > 0) { + for (let c of game.draw) + set_add(game.hand[game.power], c) + delete game.draw + } + game.state = "political_troops_place" + }, +} + +states.political_troops_place = { + inactive: "execute political card", + prompt() { + let info = event_troops[current_political_effect()] + if (game.count > 1) + prompt("Add " + game.count + " troops.") + else if (game.count === 1) + prompt("Add 1 troop.") + + if (game.count > 0) { + for (let p of all_power_generals[game.power]) { + if (is_piece_on_map(p) && game.troops[p] < 8) + gen_action_piece(p) + if (is_piece_eliminated(p) && has_re_entry_space_for_general()) + gen_action_piece(p) + } + } + + view.actions.pass = 1 + }, + piece(p) { + push_undo() + if (game.pos[p] === ELIMINATED) { + game.selected = p + game.state = "re_enter_general_from_political_card" + } else { + game.troops[p] += 1 + if (--game.count === 0) + next_execute_political_card() + } + }, + pass() { + push_undo() + next_execute_political_card() + }, +} + +function goto_mannheim_to_french_control() { + throw "TODO" +} + +function goto_pragmatic_general_to_england() { + throw "TODO" +} + +function goto_france_minus_tc_this_turn() { + throw "TODO" +} + +/* POLITICAL TRACKS */ + +function goto_adjust_political_tracks() { + // TODO: handle expeditionary corps + // TODO: handle victory points (italy) + // TODO: handle saxony alliance + goto_select_political_card() +} + /* SETUP */ const POWER_FROM_SETUP_STAGE = [ @@ -3602,7 +3864,6 @@ exports.setup = function (seed, _scenario, _options) { deck: null, hand: [ [], [], [], [], [], [] ], saved: [ [], [], [], [] ], - display: [ [], [], [], [] ], pos: setup_piece_position.slice(), oos: 0, @@ -3780,17 +4041,17 @@ function mask_hand(player) { return view_hand } -function mask_display(player) { - let view_display = [] +function mask_placed(player) { + let view_placed = [] for (let pow of all_major_powers) { - if (game.display[pow] === 0) - view_display[pow] = -1 + if (game.placed[pow] === 0) + view_placed[pow] = -1 else if (player_from_power(pow) === player) - view_display[pow] = game.display[pow] + view_placed[pow] = game.placed[pow] else - view_display[pow] = game.display[pow] & ~127 + view_placed[pow] = game.placed[pow] & ~127 } - return view_display + return view_placed } function mask_saved(player) { @@ -3853,8 +4114,8 @@ exports.view = function (state, player) { if (game.political) view.political = game.political - if (game.display) - view.display = mask_display(player) + if (game.placed) + view.placed = mask_placed(player) if (game.state === "game_over") { view.prompt = game.victory -- cgit v1.2.3