summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-10-30 00:45:54 +0100
committerTor Andersson <tor@ccxvii.net>2024-10-30 00:53:56 +0100
commitb9aced407fd405cdc46df7d5dde9968909724b3d (patch)
tree5af03727f193510b3f02cc0bbfe5821670b3ff0f
parentb81278195d8184e77fe778c325a74aa865562792 (diff)
downloadmaria-b9aced407fd405cdc46df7d5dde9968909724b3d.tar.gz
Introductory game.
-rw-r--r--play.js164
-rw-r--r--rules.js160
2 files changed, 238 insertions, 86 deletions
diff --git a/play.js b/play.js
index 6ffb8df..cef2bdd 100644
--- a/play.js
+++ b/play.js
@@ -1168,7 +1168,9 @@ function player_from_power(pow) {
case P_PRUSSIA:
return R_FREDERICK
case P_PRAGMATIC:
- return R_FREDERICK
+ if (view.pol_deck)
+ return R_FREDERICK
+ return "NONE"
case P_AUSTRIA:
return R_MARIA_THERESA
case P_SAXONY:
@@ -1233,6 +1235,36 @@ function show_tc(c) {
return ui.tc[c]
}
+function update_political() {
+ ui.pol_tracks.replaceChildren()
+ layout_political_marker(ui.saxony, view.saxony, 0)
+ layout_political_marker(ui.russia, view.russia, 1)
+ layout_political_marker(ui.italy, view.italy, 2)
+
+ ui.pc_deck.replaceChildren()
+ for (let e of ui.political_back[view.pol_deck])
+ ui.pc_deck.appendChild(e)
+ if (view.flags & F_IMPERIAL_ELECTION)
+ ui.pc_deck.appendChild(ui.political[24])
+
+ for (let pc = 0; pc < 25; ++pc)
+ ui.political[pc].classList.toggle("selected", pc === view.pc)
+
+ for (let pow of all_major_powers) {
+ ui.pc_placed[pow].replaceChildren()
+ for (let tc of view.face_up[pow])
+ ui.pc_placed[pow].appendChild(show_tc(tc))
+ for (let tc of view.face_down[pow])
+ ui.pc_placed[pow].appendChild(show_tc(tc))
+ }
+
+ ui.pc_show.replaceChildren()
+ if (view.political) {
+ for (let pc of view.political)
+ ui.pc_show.appendChild(ui.political[pc])
+ }
+}
+
function on_update() {
ui.header.classList.toggle("france", view.power === P_FRANCE)
ui.header.classList.toggle("bavaria", view.power === P_BAVARIA)
@@ -1252,6 +1284,10 @@ function on_update() {
back.fill(0)
sort_power_panel(true)
+ if (!view.pol_deck) {
+ ui.power_panel[P_PRAGMATIC].style.display = "none"
+ ui.power_panel[6].style.display = "none"
+ }
for (let p = 0; p < 20; ++p)
layout_general(p, view.pos[p])
@@ -1292,33 +1328,8 @@ function on_update() {
ui.hand[view.power].appendChild(ui.tc[c])
}
- ui.pol_tracks.replaceChildren()
- layout_political_marker(ui.saxony, view.saxony, 0)
- layout_political_marker(ui.russia, view.russia, 1)
- layout_political_marker(ui.italy, view.italy, 2)
-
- ui.pc_deck.replaceChildren()
- for (let e of ui.political_back[view.pol_deck])
- ui.pc_deck.appendChild(e)
- if (view.flags & F_IMPERIAL_ELECTION)
- ui.pc_deck.appendChild(ui.political[24])
-
- for (let pc = 0; pc < 25; ++pc)
- ui.political[pc].classList.toggle("selected", pc === view.pc)
-
- for (let pow of all_major_powers) {
- ui.pc_placed[pow].replaceChildren()
- for (let tc of view.face_up[pow])
- ui.pc_placed[pow].appendChild(show_tc(tc))
- for (let tc of view.face_down[pow])
- ui.pc_placed[pow].appendChild(show_tc(tc))
- }
-
- ui.pc_show.replaceChildren()
- if (view.political) {
- for (let pc of view.political)
- ui.pc_show.appendChild(ui.political[pc])
- }
+ if (view.pol_deck)
+ update_political()
for (let deck = 0; deck < 4; ++deck) {
ui.discard[deck].replaceChildren()
@@ -1330,58 +1341,61 @@ function on_update() {
for (let i = 0; i < view.victory.length; i += 2)
layout_victory(view.victory[i], view.victory[i+1])
- for (let i = 0; i < view.elector.length; i += 2)
- layout_elector(view.elector[i], view.elector[i+1])
for (let i = 0; i < view.retro.length; i += 2)
layout_retro(view.retro[i], view.retro[i+1])
- layout_electoral_college(0, P_PRAGMATIC)
- for (let i = 0; i < all_electoral_colleges.length; ++i) {
- for (let pow of all_powers)
- if (is_power_controlled_fortress(pow, all_electoral_colleges[i]))
- layout_electoral_college(i+1, pow)
- }
+ if (view.pol_deck) {
+ for (let i = 0; i < view.elector.length; i += 2)
+ layout_elector(view.elector[i], view.elector[i+1])
- layout_victory_pool(P_FRANCE, 11, 83, 1560)
- layout_victory_pool(P_AUSTRIA, 8, 2334, 1561)
- layout_victory_pool(P_PRUSSIA, 13, 1927, 76)
- layout_victory_pool(P_PRAGMATIC, 8, 797, 98)
-
- // battle vp
- if (view.vp[P_PRUSSIA] > 0) layout_victory_box(P_PRUSSIA, 0, 0)
- if (view.vp[P_PRUSSIA] > 1) layout_victory_box(P_PRUSSIA, 0, 1)
- if (view.vp[P_PRAGMATIC] > 0) layout_victory_box(P_PRAGMATIC, 1, 0)
- if (view.vp[P_PRAGMATIC] > 1) layout_victory_box(P_PRAGMATIC, 1, 1)
- if (view.vp[P_FRANCE] > 0) layout_victory_box(P_FRANCE, 2, 0)
- if (view.vp[P_FRANCE] > 1) layout_victory_box(P_FRANCE, 2, 1)
- if (view.vp[P_AUSTRIA] > 0) layout_victory_box(P_AUSTRIA, 3, 0)
- if (view.vp[P_AUSTRIA] > 1) layout_victory_box(P_AUSTRIA, 3, 1)
-
- if (view.flags & F_SILESIA_ANNEXED)
- layout_victory_box(P_PRUSSIA, 0, 2)
-
- let elector_france = 0
- let elector_pragmatic = 0
- for (let i = 0; i < 8; i += 2) {
- if (view.elector[i+1] === P_FRANCE)
- elector_france ++
- else
- elector_pragmatic ++
+ layout_electoral_college(0, P_PRAGMATIC)
+ for (let i = 0; i < all_electoral_colleges.length; ++i) {
+ for (let pow of all_powers)
+ if (is_power_controlled_fortress(pow, all_electoral_colleges[i]))
+ layout_electoral_college(i+1, pow)
+ }
+
+ layout_victory_pool(P_FRANCE, 11, 83, 1560)
+ layout_victory_pool(P_AUSTRIA, 8, 2334, 1561)
+ layout_victory_pool(P_PRUSSIA, 13, 1927, 76)
+ layout_victory_pool(P_PRAGMATIC, 8, 797, 98)
+
+ // battle vp
+ if (view.vp[P_PRUSSIA] > 0) layout_victory_box(P_PRUSSIA, 0, 0)
+ if (view.vp[P_PRUSSIA] > 1) layout_victory_box(P_PRUSSIA, 0, 1)
+ if (view.vp[P_PRAGMATIC] > 0) layout_victory_box(P_PRAGMATIC, 1, 0)
+ if (view.vp[P_PRAGMATIC] > 1) layout_victory_box(P_PRAGMATIC, 1, 1)
+ if (view.vp[P_FRANCE] > 0) layout_victory_box(P_FRANCE, 2, 0)
+ if (view.vp[P_FRANCE] > 1) layout_victory_box(P_FRANCE, 2, 1)
+ if (view.vp[P_AUSTRIA] > 0) layout_victory_box(P_AUSTRIA, 3, 0)
+ if (view.vp[P_AUSTRIA] > 1) layout_victory_box(P_AUSTRIA, 3, 1)
+
+ if (view.flags & F_SILESIA_ANNEXED)
+ layout_victory_box(P_PRUSSIA, 0, 2)
+
+ let elector_france = 0
+ let elector_pragmatic = 0
+ for (let i = 0; i < 8; i += 2) {
+ if (view.elector[i+1] === P_FRANCE)
+ elector_france ++
+ else
+ elector_pragmatic ++
+ }
+ if (elector_france >= 3)
+ layout_victory_box(P_FRANCE, 1, 2)
+ if (elector_pragmatic >= 3)
+ layout_victory_box(P_PRAGMATIC, 1, 2)
+
+ if (view.flags & F_ITALY_FRANCE)
+ layout_victory_box(P_FRANCE, 2, 2)
+ if (view.flags & F_ITALY_AUSTRIA)
+ layout_victory_box(P_AUSTRIA, 2, 2)
+
+ if (view.flags & F_EMPEROR_FRANCE)
+ layout_victory_box(P_FRANCE, 3, 2)
+ if (view.flags & F_EMPEROR_AUSTRIA)
+ layout_victory_box(P_AUSTRIA, 3, 2)
}
- if (elector_france >= 3)
- layout_victory_box(P_FRANCE, 1, 2)
- if (elector_pragmatic >= 3)
- layout_victory_box(P_PRAGMATIC, 1, 2)
-
- if (view.flags & F_ITALY_FRANCE)
- layout_victory_box(P_FRANCE, 2, 2)
- if (view.flags & F_ITALY_AUSTRIA)
- layout_victory_box(P_AUSTRIA, 2, 2)
-
- if (view.flags & F_EMPEROR_FRANCE)
- layout_victory_box(P_FRANCE, 3, 2)
- if (view.flags & F_EMPEROR_AUSTRIA)
- layout_victory_box(P_AUSTRIA, 3, 2)
layout_turn_marker()
diff --git a/rules.js b/rules.js
index 1d57af3..9a1395b 100644
--- a/rules.js
+++ b/rules.js
@@ -17,13 +17,24 @@ const R_LOUIS_XV = "Louis XV"
const R_FREDERICK = "Frederick"
const R_MARIA_THERESA = "Maria Theresa"
+const R_PLAYER_A = "Player A"
+const R_PLAYER_B = "Player B"
+
exports.roles = [
R_MARIA_THERESA,
R_FREDERICK,
R_LOUIS_XV
]
-exports.scenarios = [ "Advanced" ]
+const SCENARIO_INDEX = {
+ "Advanced": 0,
+ "Introductory": 1,
+}
+
+exports.scenarios = [
+ "Advanced",
+ "Introductory",
+]
const data = require("./data.js")
const political_cards = require("./cards.js")
@@ -855,11 +866,22 @@ function is_protected_from_conquest(s) {
/* STATE */
+function is_intro() {
+ return game.scenario & 1
+}
+
+function is_two_player() {
+ return game.scenario & 2
+}
+
const tc_per_turn_table = [ 5, 3, 3, 5, 1, 1 ]
function tc_per_turn() {
let n = tc_per_turn_table[game.power]
+ if (game.power === P_FRANCE && is_intro())
+ n = 3
+
// Saxony track
if (game.power === P_SAXONY) {
if (game.saxony > 4)
@@ -1095,7 +1117,10 @@ function goto_start_turn() {
if (game.turn % 4 === 0) {
goto_winter_turn()
} else {
- goto_politics()
+ if (is_intro())
+ start_sequence_of_play()
+ else
+ goto_politics()
}
}
@@ -1107,7 +1132,7 @@ function goto_end_turn() {
goto_start_turn()
}
-const sequence_of_play = [
+const advanced_sequence_of_play = [
{ power: P_AUSTRIA, action: goto_place_hussars },
{ power: P_FRANCE, action: start_action_stage },
@@ -1177,12 +1202,66 @@ const sequence_of_play = [
{ power: P_FRANCE, action: goto_end_turn },
]
+const intro_sequence_of_play = [
+ { power: P_AUSTRIA, action: goto_place_hussars },
+
+ { power: P_FRANCE, action: start_action_stage },
+ { power: P_FRANCE, action: goto_tactical_cards },
+ { power: P_BAVARIA, action: goto_tactical_cards },
+ { power: P_FRANCE, action: goto_supply },
+ { power: P_FRANCE, action: init_movement },
+ { power: P_FRANCE, action: goto_movement_global },
+ { power: P_FRANCE, action: end_movement },
+ { power: P_FRANCE, action: goto_combat },
+ { power: P_FRANCE, action: end_action_stage },
+
+ { power: P_PRUSSIA, action: start_action_stage },
+ { power: P_PRUSSIA, action: goto_tactical_cards },
+ {
+ power: P_SAXONY,
+ action() {
+ if (is_saxony_prussian())
+ goto_tactical_cards()
+ else
+ next_sequence_of_play()
+ },
+ },
+ { power: P_PRUSSIA, action: goto_supply },
+ { power: P_PRUSSIA, action: init_movement },
+ { power: P_PRUSSIA, action: goto_movement_global },
+ { power: P_PRUSSIA, action: end_movement },
+ { power: P_PRUSSIA, action: goto_combat },
+ { power: P_PRUSSIA, action: end_action_stage },
+
+ { power: P_AUSTRIA, action: start_action_stage },
+ { power: P_AUSTRIA, action: goto_tactical_cards },
+ {
+ power: P_SAXONY,
+ action() {
+ if (is_saxony_prussian())
+ next_sequence_of_play()
+ else
+ goto_tactical_cards()
+ },
+ },
+ { power: P_AUSTRIA, action: goto_supply },
+ { power: P_AUSTRIA, action: init_movement },
+ { power: P_AUSTRIA, action: goto_movement_global },
+ { power: P_AUSTRIA, action: end_movement },
+ { power: P_AUSTRIA, action: goto_combat },
+ { power: P_AUSTRIA, action: end_action_stage },
+
+ { power: P_FRANCE, action: goto_end_turn },
+]
+
function start_sequence_of_play() {
game.stage = -1
next_sequence_of_play()
}
function current_sequence_of_play() {
+ if (is_intro())
+ return intro_sequence_of_play[game.stage]
return sequence_of_play[game.stage]
}
@@ -1913,6 +1992,12 @@ function give_troops(total) {
function init_movement() {
set_clear(game.moved)
+ if (is_intro()) {
+ for (let p of all_pieces)
+ if (is_flanders_space(game.pos[p]))
+ set_add(game.moved, p)
+ }
+
log_br()
game.move_re_entered = 0
@@ -2207,6 +2292,8 @@ function can_move_train_to(p, from, to) {
}
function is_illegal_cross_map_move(from, to) {
+ if (is_intro() && is_flanders_space(to))
+ return true
return (
game.power !== P_FRANCE && game.power !== P_AUSTRIA && (
(is_flanders_space(from) && is_bohemia_space(to)) ||
@@ -2959,6 +3046,11 @@ function goto_winter_turn() {
function goto_winter_stage() {
set_active_to_current_winter_stage()
+ if (is_intro() && game.power === P_PRAGMATIC) {
+ end_winter_stage()
+ return
+ }
+
log(title_from_winter_stage[game.stage])
goto_recruit()
@@ -3032,6 +3124,8 @@ states.recruit = {
let av_general = 0
let av_troops = 0
for (let p of all_power_generals[game.power]) {
+ if (is_intro() && is_flanders_space(game.pos[p]))
+ continue
if (is_piece_on_map(p))
av_troops += 8 - game.troops[p]
else if (is_piece_eliminated(p) && has_re_entry_space_for_general(p)) {
@@ -3066,6 +3160,8 @@ states.recruit = {
if (paid >= 4) {
for (let p of all_power_generals[game.power]) {
+ if (is_intro() && is_flanders_space(game.pos[p]))
+ continue
if (game.troops[p] > 0 && game.troops[p] < 8)
gen_action_piece(p)
else if (is_piece_eliminated(p) && has_re_entry_space_for_general(p))
@@ -3811,6 +3907,13 @@ function lose_vp(pow, n) {
}
function finish_combat() {
+ if (is_intro()) {
+ delete game.lost_generals
+ delete game.lost_troops
+ next_combat()
+ return
+ }
+
let n = game.lost_troops / 3 | 0
if (n === 0 && game.lost_generals > 0)
n = 1
@@ -5454,8 +5557,16 @@ const POWER_FROM_SETUP_STAGE = [
P_AUSTRIA,
]
+const INTRO_POWER_FROM_SETUP_STAGE = [
+ P_PRUSSIA,
+ P_AUSTRIA,
+]
+
function set_active_setup_power() {
- set_active_to_power(POWER_FROM_SETUP_STAGE[game.stage])
+ if (is_intro())
+ set_active_to_power(INTRO_POWER_FROM_SETUP_STAGE[game.stage])
+ else
+ set_active_to_power(POWER_FROM_SETUP_STAGE[game.stage])
}
const setup_initial_tcs = [ 2, 9, 3, 5, 5, 3 ]
@@ -5595,9 +5706,10 @@ function make_tactics_discard(n) {
})
}
-exports.setup = function (seed, _scenario, _options) {
+exports.setup = function (seed, scenario, _options) {
game = {
seed: seed,
+ scenario: SCENARIO_INDEX[scenario],
undo: [],
log: [],
@@ -5620,7 +5732,6 @@ exports.setup = function (seed, _scenario, _options) {
loser_power: -1,
trump: SPADES,
- pol_deck: null,
deck: null,
hand1: [ [], [], [], [], [], [] ],
hand2: [ [], [], [], [], [], [] ],
@@ -5651,7 +5762,20 @@ exports.setup = function (seed, _scenario, _options) {
count: 0,
}
- game.pol_deck = make_political_deck()
+ if (is_intro()) {
+ log("Introductory")
+
+ game.troops[ARENBERG] = 4
+ game.troops[0] = 3
+ game.troops[1] = 8
+ game.troops[2] = 8
+ game.troops[3] = 3
+ game.troops[4] = 4
+ }
+
+ if (!is_intro())
+ game.pol_deck = make_political_deck()
+
game.deck = make_tactics_deck(0)
shuffle_bigint(game.deck)
@@ -5670,12 +5794,17 @@ exports.setup = function (seed, _scenario, _options) {
map_set(game.victory, COSEL, P_AUSTRIA)
// Deal initial cards
- for (let pow of all_powers)
+ for (let pow of all_powers) {
+ if (is_intro() && pow === P_PRAGMATIC)
+ continue
for (let i = 0; i < setup_initial_tcs[pow]; ++i)
set_add(game.hand1[pow], game.deck.pop())
+ }
log("# 1741")
+ goto_setup()
+
return game
}
@@ -5759,8 +5888,15 @@ states.setup_general = {
},
}
+function goto_setup() {
+ game.stage = 0
+ set_active_setup_power()
+ game.state = "setup"
+}
+
function end_setup() {
- if (++game.stage === 4) {
+ let end = is_intro() ? 2 : 4
+ if (++game.stage === end) {
goto_start_turn()
} else {
set_active_setup_power()
@@ -5865,7 +6001,6 @@ exports.view = function (state, player) {
discard: total_discard_list(),
contracts: game.contracts,
- pol_deck: mask_pol_deck(),
face_up: game.face_up,
face_down: mask_face_down(),
@@ -5878,6 +6013,9 @@ exports.view = function (state, player) {
view.defender = game.defender
}
+ if (!is_intro())
+ view.pol_deck = mask_pol_deck()
+
if (game.political)
view.political = game.political
@@ -5906,7 +6044,7 @@ exports.view = function (state, player) {
}
// subsidy contracts actions for active player
- if (!game.proposal) {
+ if (!game.proposal && !is_intro()) {
if (may_cancel_subsidy())
view.actions.cancel_subsidy = 1
view.actions.propose_subsidy = 1