summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.js127
-rw-r--r--rules.js293
2 files changed, 237 insertions, 183 deletions
diff --git a/play.js b/play.js
index 3e63b57..89880e6 100644
--- a/play.js
+++ b/play.js
@@ -22,19 +22,8 @@ function toggle_shift() {
document.body.classList.toggle("shift")
}
-/* DATA */
-
-const P_FRANCE = 0
-const P_BAVARIA = 1
-const P_PRUSSIA = 2
-const P_SAXONY = 3
-const P_PRAGMATIC = 4
-const P_AUSTRIA = 5
-
const last_city = data.cities.name.length - 1
-const ELIMINATED = data.cities.name.length
-const REMOVED = ELIMINATED + 1
const ELIMINATED_TRAIN_X = 340
const ELIMINATED_TRAIN_Y = 160
const ELIMINATED_TRAIN_DX = 33
@@ -45,8 +34,35 @@ const ELIMINATED_GENERAL_DX = 50
const HUSSAR_X = 2190
const HUSSAR_Y = 1630
+/* DATA (SHARED) */
+
+const deck_name = [ "red", "green", "blue", "yellow" ]
+const suit_name = [ "\u2660", "\u2663", "\u2665", "\u2666", "R" ]
+const suit_class = [ "spades", "clubs", "hearts", "diamonds", "reserve" ]
+const suit_letter = [ "S", "C", "H", "D", "R" ]
+
+const P_FRANCE = 0
+const P_BAVARIA = 1
+const P_PRUSSIA = 2
+const P_SAXONY = 3
+const P_PRAGMATIC = 4
+const P_AUSTRIA = 5
+
+const power_name = [ "France", "Bavaria", "Prussia", "Saxony", "Pragmatic Army", "Austria" ]
const power_class = [ "france", "bavaria", "prussia", "saxony", "pragmatic", "austria" ]
-const power_name = [ "France", "Bavaria", "Prussia", "Saxony", "Pragmatic", "Austria" ]
+
+const is_major_power = [ 1, 0, 1, 0, 1, 1 ]
+const is_minor_power = [ 0, 1, 0, 1, 0, 0 ]
+
+const SPADES = 0
+const CLUBS = 1
+const HEARTS = 2
+const DIAMONDS = 3
+const RESERVE = 4
+
+const IMPERIAL_ELECTION = 25
+
+const ELIMINATED = data.cities.name.length
const all_powers = [ 0, 1, 2, 3, 4, 5 ]
@@ -68,6 +84,10 @@ const all_power_trains = [
[ 27, 28, 29 ],
]
+const last_piece = 29
+
+const all_hussars = [ 30, 31 ]
+
const piece_power = [
P_FRANCE, P_FRANCE, P_FRANCE, P_FRANCE, P_FRANCE,
P_BAVARIA,
@@ -123,6 +143,36 @@ const piece_name = [
"Batthyány",
"Neipperg",
"Arenberg",
+ "supply train", "supply train",
+ "supply train",
+ "supply train", "supply train",
+ "supply train",
+ "supply train",
+ "supply train", "supply train", "supply train",
+ "hussar", "hussar",
+]
+
+const piece_log_name = [
+ "Moritz",
+ "Belle-Isle",
+ "Broglie",
+ "Maillebois",
+ "Noailles",
+ "Törring",
+ "Friedrich",
+ "Schwerin",
+ "Leopold",
+ "Dessauer",
+ "Rutowski",
+ "George II",
+ "Cumberland",
+ "Earl of Stair",
+ "Karl",
+ "Traun",
+ "Khevenhüller",
+ "Batthyány",
+ "Neipperg",
+ "Arenberg",
"French ST", "French ST",
"Bavarian ST",
"Prussian ST", "Prussian ST",
@@ -132,8 +182,11 @@ const piece_name = [
"Hussars", "Hussars",
]
-let suit_class = [ "spades", "clubs", "hearts", "diamonds", "reserve" ]
-let suit_letter = [ "S", "C", "H", "D", "R" ]
+
+const all_pieces = [ ...all_power_generals.flat(), ...all_power_trains.flat() ]
+const all_trains = [ ...all_power_trains.flat() ]
+const all_generals = [ ...all_power_generals.flat() ]
+const all_generals_by_rank = all_generals.slice().sort((a,b)=>piece_rank[a]-piece_rank[b])
function to_deck(c) {
return c >> 7
@@ -144,7 +197,7 @@ function to_suit(c) {
}
function to_value(c) {
- if (to_suit(c) === 4)
+ if (to_suit(c) === RESERVE)
return 8
return c & 15
}
@@ -442,16 +495,6 @@ function make_political_card(fc) {
return e
}
-function has_removed_all_pieces(pow) {
- for (let p of all_power_generals[pow])
- if (view.pos[p] !== REMOVED)
- return false
- for (let p of all_power_trains[pow])
- if (view.pos[p] !== REMOVED)
- return false
- return true
-}
-
function on_init() {
ui.pieces = [
create_piece("piece", 0, "piece cylinder france france_1"),
@@ -533,12 +576,13 @@ function on_init() {
]
ui.tc_hand = [
- make_tc_deck_pile("deck_1"),
- make_tc_deck_pile("deck_1"),
- make_tc_deck_pile("deck_1"),
- make_tc_deck_pile("deck_1"),
- make_tc_deck_pile("deck_1"),
- make_tc_deck_pile("deck_1"),
+ // TODO: or make_tc_deck_pile ???
+ make_tc_deck_hand("deck_1"),
+ make_tc_deck_hand("deck_1"),
+ make_tc_deck_hand("deck_1"),
+ make_tc_deck_hand("deck_1"),
+ make_tc_deck_hand("deck_1"),
+ make_tc_deck_hand("deck_1"),
]
ui.tc_discard = [
@@ -675,9 +719,9 @@ function on_blur_city() {
function on_focus_piece(evt) {
let p = evt.target.my_id
if (p < 20 && view.troops[p] > 0)
- ui.status.textContent = piece_name[evt.target.my_id] + " (" + view.troops[p] + " troops)"
+ ui.status.textContent = piece_log_name[evt.target.my_id] + " (" + view.troops[p] + " troops)"
else
- ui.status.textContent = piece_name[evt.target.my_id]
+ ui.status.textContent = piece_log_name[evt.target.my_id]
}
function on_blur_piece() {
@@ -751,14 +795,6 @@ function layout_hussar(id, s) {
function layout_general(id, s) {
let x, y, n
- if (s === REMOVED) {
- if (ui.pieces[id].parentElement === ui.pieces_element)
- e.remove()
- if (ui.troops[id].parentElement === ui.pieces_element)
- e.remove()
- return
- }
-
if (s === ELIMINATED) {
n = layout_general_offset_elim(id)
x = ELIMINATED_GENERAL_X + ELIMINATED_GENERAL_DX * get_cylinder_power(id)
@@ -794,11 +830,6 @@ function layout_train(id, s) {
let n = layout_train_offset(id, s)
let x, y
- if (s === REMOVED) {
- if (e.parentElement === ui.pieces_element)
- e.remove()
- return
- }
if (e.parentElement !== ui.pieces_element)
ui.pieces_element.appendChild(e)
@@ -1067,7 +1098,7 @@ function on_update() {
function sub_piece(match, p1) {
let x = p1 | 0
- let n = piece_name[x]
+ let n = piece_log_name[x]
let p = power_class[piece_power[x]]
return `<span class="piece_tip ${p}" onclick="on_click_piece_tip(${x})" onmouseenter="on_focus_piece_tip(${x})" onmouseleave="on_blur_piece_tip(${x})">${n}</span>`
}
@@ -1082,7 +1113,7 @@ function sub_path(pieces_and_spaces) {
let ps = pieces_and_spaces[0].split(",")
let ss = pieces_and_spaces[1].split(",")
let x = ss[ss.length-1]
- let ps_name = ps.map(p => piece_name[p]).join(" and ")
+ let ps_name = ps.map(p => piece_log_name[p]).join(" and ")
let ss_name = data.cities.name[x]
return `<span onclick="on_click_city_tip(${x})" onmouseenter="on_focus_path_tip([${ps.join(",")}],[${ss.join(",")}])" onmouseleave="on_blur_path_tip()">${ps_name} to ${ss_name}.</span>`
}
diff --git a/rules.js b/rules.js
index bfafa26..1cbe2a4 100644
--- a/rules.js
+++ b/rules.js
@@ -46,64 +46,26 @@ const R_LOUIS_XV = "Louis XV"
const R_FREDERICK = "Frederick"
const R_MARIA_THERESA = "Maria Theresa"
-exports.roles = [ R_LOUIS_XV, R_FREDERICK, R_MARIA_THERESA ]
+exports.roles = [
+ R_MARIA_THERESA,
+ R_FREDERICK,
+ R_LOUIS_XV
+]
exports.scenarios = [ "Advanced" ]
-/* DATA */
+const data = require("./data")
var game
var view
var states = {}
-const data = require("./data")
-
-function is_bohemia_space(s) {
- return s >= 0 && s <= 401
-}
-
-function is_flanders_space(s) {
- return s >= 402 && s <= 618
-}
-
-function is_map_space(s) {
- return s >= 0 && s <= 618
-}
-
-function is_piece_on_map(p) {
- return is_map_space(game.pos[p])
-}
-
-function is_piece_on_map_or_eliminated(p) {
- let s = game.pos[p]
- return is_map_space(s) || s === ELIMINATED
-}
-
-function find_city(city) {
- let n = data.cities.name.length
- let x = -1
- for (let c = 0; c < n; ++c) {
- if (data.cities.name[c] === city) {
- if (x < 0)
- x = c
- else
- throw "TWO CITIES: " + city
- }
- }
- if (x < 0)
- throw "CITY NOT FOUND: " + city
- return x
-}
-
-function find_city_list(names) {
- let list = []
- for (let n of names)
- set_add(list, find_city(n))
- return list
-}
+/* DATA (SHARED) */
const deck_name = [ "red", "green", "blue", "yellow" ]
const suit_name = [ "\u2660", "\u2663", "\u2665", "\u2666", "R" ]
+const suit_class = [ "spades", "clubs", "hearts", "diamonds", "reserve" ]
+const suit_letter = [ "S", "C", "H", "D", "R" ]
const P_FRANCE = 0
const P_BAVARIA = 1
@@ -112,7 +74,8 @@ const P_SAXONY = 3
const P_PRAGMATIC = 4
const P_AUSTRIA = 5
-const POWER_NAME = [ "France", "Bavaria", "Prussia", "Saxony", "Pragmatic Army", "Austria" ]
+const power_name = [ "France", "Bavaria", "Prussia", "Saxony", "Pragmatic Army", "Austria" ]
+const power_class = [ "france", "bavaria", "prussia", "saxony", "pragmatic", "austria" ]
const is_major_power = [ 1, 0, 1, 0, 1, 1 ]
const is_minor_power = [ 0, 1, 0, 1, 0, 0 ]
@@ -127,24 +90,6 @@ const IMPERIAL_ELECTION = 25
const ELIMINATED = data.cities.name.length
-const TRIER = find_city("Trier")
-const MAINZ = find_city("Mainz")
-const KOLN = find_city("Köln")
-const MANNHEIM = find_city("Mannheim")
-
-const LIEGNITZ = find_city("Liegnitz")
-const GLOGAU = find_city("Glogau")
-const BRESLAU = find_city("Breslau")
-const BRIEG = find_city("Brieg")
-const GLATZ = find_city("Glatz")
-const NEISSE = find_city("Neisse")
-const COSEL = find_city("Cosel")
-
-const MUNCHEN = find_city("München")
-const DRESDEN = find_city("Dresden")
-
-const ENGLAND = find_city("England")
-
const all_powers = [ 0, 1, 2, 3, 4, 5 ]
const all_power_generals = [
@@ -194,6 +139,15 @@ const piece_rank = [
1, 2, 3, 4, 5, 6,
]
+const piece_abbr = [
+ "F1", "F2", "F3", "F4", "F5",
+ "B1",
+ "P1", "P2", "P3", "P4",
+ "S1",
+ "PA1", "PA2", "PA3",
+ "A1", "A2", "A3", "A4", "A5", "A6",
+]
+
const piece_name = [
"Moritz",
"Belle-Isle",
@@ -224,11 +178,117 @@ const piece_name = [
"hussar", "hussar",
]
+const piece_log_name = [
+ "Moritz",
+ "Belle-Isle",
+ "Broglie",
+ "Maillebois",
+ "Noailles",
+ "Törring",
+ "Friedrich",
+ "Schwerin",
+ "Leopold",
+ "Dessauer",
+ "Rutowski",
+ "George II",
+ "Cumberland",
+ "Earl of Stair",
+ "Karl",
+ "Traun",
+ "Khevenhüller",
+ "Batthyány",
+ "Neipperg",
+ "Arenberg",
+ "French ST", "French ST",
+ "Bavarian ST",
+ "Prussian ST", "Prussian ST",
+ "Saxon ST",
+ "Pragmatic Army ST",
+ "Austrian ST", "Austrian ST", "Austrian ST",
+ "Hussars", "Hussars",
+]
+
+
const all_pieces = [ ...all_power_generals.flat(), ...all_power_trains.flat() ]
const all_trains = [ ...all_power_trains.flat() ]
const all_generals = [ ...all_power_generals.flat() ]
const all_generals_by_rank = all_generals.slice().sort((a,b)=>piece_rank[a]-piece_rank[b])
+function to_deck(c) {
+ return c >> 7
+}
+
+function to_suit(c) {
+ return (c >> 4) & 7
+}
+
+function to_value(c) {
+ if (to_suit(c) === RESERVE)
+ return 8
+ return c & 15
+}
+
+/* DATA */
+
+function is_bohemia_space(s) {
+ return s >= 0 && s <= 401
+}
+
+function is_flanders_space(s) {
+ return s >= 402 && s <= 618
+}
+
+function is_map_space(s) {
+ return s >= 0 && s <= 618
+}
+
+function is_piece_on_map(p) {
+ return is_map_space(game.pos[p])
+}
+
+function is_piece_eliminated(p) {
+ return game.pos[p] === ELIMINATED
+}
+
+function is_piece_on_map_or_eliminated(p) {
+ let s = game.pos[p]
+ return is_map_space(s) || s === ELIMINATED
+}
+
+function find_city(city) {
+ let n = data.cities.name.length
+ let x = -1
+ for (let c = 0; c < n; ++c) {
+ if (data.cities.name[c] === city) {
+ if (x < 0)
+ x = c
+ else
+ throw "TWO CITIES: " + city
+ }
+ }
+ if (x < 0)
+ throw "CITY NOT FOUND: " + city
+ return x
+}
+
+const TRIER = find_city("Trier")
+const MAINZ = find_city("Mainz")
+const KOLN = find_city("Köln")
+const MANNHEIM = find_city("Mannheim")
+
+const LIEGNITZ = find_city("Liegnitz")
+const GLOGAU = find_city("Glogau")
+const BRESLAU = find_city("Breslau")
+const BRIEG = find_city("Brieg")
+const GLATZ = find_city("Glatz")
+const NEISSE = find_city("Neisse")
+const COSEL = find_city("Cosel")
+
+const MUNCHEN = find_city("München")
+const DRESDEN = find_city("Dresden")
+
+const ENGLAND = find_city("England")
+
const all_france_bavaria_generals = [
...all_power_generals[P_FRANCE],
...all_power_generals[P_BAVARIA],
@@ -490,20 +550,6 @@ function is_hussar(p) {
return p >= 30 && p < 32
}
-function to_deck(c) {
- return c >> 7
-}
-
-function to_suit(c) {
- return (c >> 4) & 7
-}
-
-function to_value(c) {
- if (to_suit(c) === RESERVE)
- return 8
- return c & 15
-}
-
function format_card_prompt(c) {
if (is_reserve(c))
return "8R"
@@ -583,10 +629,6 @@ function make_protect_range(result, start, here, range) {
}
}
-function is_fortress(s) {
- return set_has(all_fortresses, s)
-}
-
function is_home_country(s) {
// TODO: Silesia
switch (game.power) {
@@ -690,18 +732,20 @@ function tc_per_turn() {
return n
}
-const player_from_power_table = [
- R_LOUIS_XV,
- R_LOUIS_XV,
- R_FREDERICK,
- R_FREDERICK,
- R_FREDERICK,
- R_MARIA_THERESA,
-]
-
function player_from_power(pow) {
- // TOOD: saxony allies with austria
- return player_from_power_table[pow]
+ switch (pow) {
+ case P_FRANCE:
+ case P_BAVARIA:
+ return R_LOUIS_XV
+ case P_PRUSSIA:
+ return R_FREDERICK
+ case P_SAXONY:
+ return R_FREDERICK
+ case P_PRAGMATIC:
+ return R_FREDERICK
+ case P_AUSTRIA:
+ return R_MARIA_THERESA
+ }
}
function set_active_to_power(power) {
@@ -783,20 +827,6 @@ function has_friendly_supply_train(to) {
return false
}
-function has_enemy_supply_train(to) {
- for (let p of all_enemy_trains(game.power))
- if (game.pos[p] === to)
- return true
- return false
-}
-
-function has_enemy_general(to) {
- for (let p of all_enemy_generals(game.power))
- if (game.pos[p] === to)
- return true
- return false
-}
-
function has_enemy_piece(to) {
for (let p of all_enemy_generals(game.power))
if (game.pos[p] === to)
@@ -815,13 +845,6 @@ function has_non_cooperative_general(to) {
return false
}
-function has_own_general(to) {
- for (let p of all_power_generals[game.power])
- if (game.pos[p] === to)
- return true
- return false
-}
-
function count_generals(to) {
let n = 0
for (let p of all_generals)
@@ -877,8 +900,8 @@ const TURN_NAME = [
const POWER_FROM_ACTION_STAGE = [
P_FRANCE, // and bavaria
P_PRUSSIA, // and saxony
- P_AUSTRIA, // and pragmatic army -- interleave with pragmatic moves on flanders map
P_PRAGMATIC, // interleave with austria moves on flanders map
+ P_AUSTRIA, // and pragmatic army -- interleave with pragmatic moves on flanders map
]
const title_from_action_stage = [
@@ -1122,7 +1145,7 @@ function draw_tc(n) {
while (n > 0) {
if (game.deck.length === 0) {
if (k > 0)
- log(POWER_NAME[game.power] + " " + k + " TC.")
+ log(power_name[game.power] + " " + k + " TC.")
k = 0
next_tactics_deck()
if (game.deck.length === 0) {
@@ -1136,7 +1159,7 @@ function draw_tc(n) {
}
if (k > 0)
- log(POWER_NAME[game.power] + " " + k + " TC.")
+ log(power_name[game.power] + " " + k + " TC.")
}
function goto_tactical_cards() {
@@ -1358,7 +1381,7 @@ function resume_supply() {
goto_supply_suffer()
else
end_supply()
- // TODO: pause
+ // TODO: pause
// game.state = "supply_done"
}
@@ -2102,7 +2125,7 @@ function goto_re_enter_train() {
function can_train_re_enter(p) {
return (
- (is_piece_on_map(p) || game.pos[p] === ELIMINATED) &&
+ (is_piece_on_map_or_eliminated(p)) &&
!set_has(game.moved, p) &&
has_re_entry_space_for_supply_train(piece_power[p])
)
@@ -2238,7 +2261,7 @@ states.re_enter_train_where = {
function end_re_enter_train() {
if (game.recruit.used.length > 0) {
log_br()
- log(POWER_NAME[game.power] + " spent " + game.recruit.used.map(format_card).join(", ") + ".")
+ log(power_name[game.power] + " spent " + game.recruit.used.map(format_card).join(", ") + ".")
map_for_each(game.recruit.pieces, (p, s) => {
if (s !== ELIMINATED)
log("Re-entered P" + p + " from S" + s + " at S" + game.pos[p] + ".")
@@ -2311,7 +2334,7 @@ function has_re_entry_space_for_general() {
return false
}
-function can_re_enter_general_at_city(from, to) {
+function can_re_enter_general_at_city(to) {
if (is_enemy_controlled_fortress(to))
return false
if (has_friendly_supply_train(to))
@@ -2326,7 +2349,7 @@ function can_re_enter_general_at_city(from, to) {
function can_recruit_anything() {
for (let p of all_power_generals[game.power]) {
// can re-enter generals
- if (game.pos[p] === ELIMINATED && has_re_entry_space_for_general())
+ if (is_piece_eliminated(p) && has_re_entry_space_for_general())
return true
// can recruit troops?
if (is_piece_on_map(p) && game.troops[p] < 8)
@@ -2343,7 +2366,7 @@ states.recruit = {
for (let p of all_power_generals[game.power]) {
if (is_piece_on_map(p))
av_troops += 8 - game.troops[p]
- else if (game.pos[p] === ELIMINATED && has_re_entry_space_for_general()) {
+ else if (is_piece_eliminated(p) && has_re_entry_space_for_general()) {
av_general += 1
av_troops += 8
}
@@ -2379,7 +2402,7 @@ states.recruit = {
for (let p of all_power_generals[game.power]) {
if (game.troops[p] > 0 && game.troops[p] < 8)
gen_action_piece(p)
- else if (game.pos[p] === ELIMINATED && has_re_entry_space_for_general())
+ else if (is_piece_eliminated(p) && has_re_entry_space_for_general())
gen_action_piece(p)
}
}
@@ -2398,7 +2421,7 @@ states.recruit = {
spend_card_value(game.recruit.pool, game.recruit.used, 4)
- if (game.pos[p] === ELIMINATED) {
+ if (is_piece_eliminated(p)) {
game.selected = p
game.state = "re_enter_general_where"
} else {
@@ -2627,7 +2650,7 @@ function format_combat(value) {
let a = format_combat_stack(game.attacker)
let d = format_combat_stack(game.defender)
let s = signed_number(value)
- let p = POWER_NAME[game.power]
+ let p = power_name[game.power]
return `${a} vs ${d}. ${p} is at ${s}.`
}
@@ -2699,7 +2722,7 @@ function gen_play_reserve() {
}
function play_card(c, sign) {
- let prefix = (sign < 0 ? ">>" : ">") + POWER_NAME[game.power]
+ let prefix = (sign < 0 ? ">>" : ">") + power_name[game.power]
if (sign < 0)
game.count -= to_value(c)
else
@@ -2711,7 +2734,7 @@ function play_card(c, sign) {
function play_reserve(v, sign) {
let c = game.reserve
delete game.reserve
- let prefix = (sign < 0 ? ">>" : ">") + POWER_NAME[game.power]
+ let prefix = (sign < 0 ? ">>" : ">") + power_name[game.power]
if (sign < 0)
game.count -= v
else
@@ -2867,7 +2890,7 @@ function goto_retreat() {
for (let pow of all_powers)
if (lost[pow] > 0)
- log(POWER_NAME[pow] + " lost " + (lost[pow]) + " troops.")
+ log(power_name[pow] + " lost " + (lost[pow]) + " troops.")
resume_retreat()
}
@@ -3100,7 +3123,7 @@ const setup_max_troops = [
8, 8, 8, 8, 8,
5,
8, 8, 8, 6,
- 8,
+ 5,
8, 8, 8,
8, 8, 8, 8, 8, 8,
]
@@ -3270,7 +3293,7 @@ states.setup = {
} else {
let n_stacks = 0
for (let p of all_power_generals[game.power]) {
- if (game.pos[p] !== ELIMINATED && !set_has(game.moved, p)) {
+ if (!set_has(game.moved, p)) {
gen_action_piece(p)
n_stacks ++
}
@@ -3432,7 +3455,7 @@ exports.view = function (state, player) {
if (typeof inactive === "function")
view.prompt = inactive()
else
- view.prompt = `Waiting for ${POWER_NAME[game.power]} to ${inactive}.`
+ view.prompt = `Waiting for ${power_name[game.power]} to ${inactive}.`
} else {
view.actions = {}
if (states[game.state])
@@ -3463,7 +3486,7 @@ function goto_game_over(result, victory) {
}
function prompt(str) {
- view.prompt = POWER_NAME[game.power] + ": " + str
+ view.prompt = power_name[game.power] + ": " + str
}
exports.action = function (state, _player, action, arg) {