summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js233
1 files changed, 56 insertions, 177 deletions
diff --git a/rules.js b/rules.js
index d20f049..1eec59c 100644
--- a/rules.js
+++ b/rules.js
@@ -221,50 +221,41 @@ const LORD_VLADISLAV = find_lord("Vladislav")
const LEGATE_INDISPOSED = -2
const LEGATE_ARRIVED = -1
-const LOC_REVAL = find_locale("Reval")
-const LOC_WESENBERG = find_locale("Wesenberg")
-const LOC_DORPAT = find_locale("Dorpat")
-const LOC_LEAL = find_locale("Leal")
-const LOC_RIGA = find_locale("Riga")
const LOC_ADSEL = find_locale("Adsel")
+const LOC_DORPAT = find_locale("Dorpat")
+const LOC_DUBROVNO = find_locale("Dubrovno")
const LOC_FELLIN = find_locale("Fellin")
-const LOC_ODENPAH = find_locale("Odenpäh")
-const LOC_WENDEN = find_locale("Wenden")
-const LOC_NOVGOROD = find_locale("Novgorod")
+const LOC_IZBORSK = find_locale("Izborsk")
+const LOC_KAIBOLOVO = find_locale("Kaibolovo")
+const LOC_KOPORYE = find_locale("Koporye")
const LOC_LADOGA = find_locale("Ladoga")
-const LOC_PSKOV = find_locale("Pskov")
-const LOC_RUSA = find_locale("Rusa")
+const LOC_LEAL = find_locale("Leal")
+const LOC_LETTGALLIA = find_locale("Lettgallia")
const LOC_LOVAT = find_locale("Lovat")
const LOC_LUGA = find_locale("Luga")
const LOC_NEVA = find_locale("Neva")
-const LOC_VOLKHOV = find_locale("Volkhov")
-const LOC_IZBORSK = find_locale("Izborsk")
-const LOC_KAIBOLOVO = find_locale("Kaibolovo")
-const LOC_KOPORYE = find_locale("Koporye")
+const LOC_NOVGOROD = find_locale("Novgorod")
+const LOC_ODENPAH = find_locale("Odenpäh")
+const LOC_OSTROV = find_locale("Ostrov")
const LOC_PORKHOV = find_locale("Porkhov")
-const LOC_VELIKIYE_LUKI = find_locale("Velikiye Luki")
-
-const LOC_DUBROVNO = find_locale("Dubrovno")
-const LOC_VOD = find_locale("Vod")
-const LOC_ZHELTSY = find_locale("Zheltsy")
-const LOC_TESOVO = find_locale("Tesovo")
+const LOC_PSKOV = find_locale("Pskov")
+const LOC_REVAL = find_locale("Reval")
+const LOC_RIGA = find_locale("Riga")
+const LOC_ROSITTEN = find_locale("Rositten")
+const LOC_RUSA = find_locale("Rusa")
const LOC_SABLIA = find_locale("Sablia")
-
-const LOC_OSTROV = find_locale("Ostrov")
-const LOC_UZMEN = find_locale("Uzmen")
const LOC_SOROT_RIVER = find_locale("Sorot River")
+const LOC_TESOVO = find_locale("Tesovo")
+const LOC_TOLOWA = find_locale("Tolowa")
+const LOC_UZMEN = find_locale("Uzmen")
const LOC_VELIKAYA_RIVER = find_locale("Velikaya River")
+const LOC_VELIKIYE_LUKI = find_locale("Velikiye Luki")
+const LOC_VOD = find_locale("Vod")
+const LOC_VOLKHOV = find_locale("Volkhov")
+const LOC_WENDEN = find_locale("Wenden")
+const LOC_WESENBERG = find_locale("Wesenberg")
const LOC_ZHELCHA_RIVER = find_locale("Zhelcha River")
-
-const LOC_ROSITTEN = find_locale("Rositten")
-const LOC_LETTGALLIA = find_locale("Lettgallia")
-const LOC_TOLOWA = find_locale("Tolowa")
-
-
-// Misc tracking flags
-const FLAG_FIRST_ACTION = 1 << 0
-const FLAG_FIRST_MARCH = 1 << 1
-const FLAG_TEUTONIC_RAIDERS = 1 << 2
+const LOC_ZHELTSY = find_locale("Zheltsy")
const AOW_TEUTONIC_TREATY_OF_STENSBY = T1
const AOW_TEUTONIC_RAIDERS = T2
@@ -391,13 +382,6 @@ const TURN_NAME = [
null,
]
-const USABLE_TRANSPORT = [
- [ CART, BOAT, SHIP ],
- [ SLED ],
- [ SLED ],
- [ BOAT, SHIP ]
-]
-
const COMMANDERIES = [
LOC_ADSEL,
LOC_FELLIN,
@@ -406,17 +390,14 @@ const COMMANDERIES = [
]
function is_in_rus(loc) {
- return loc >= 0 && loc < last_locale && data.locales[loc].region === "Novgorodan Rus"
+ return loc >= first_p2_locale && loc <= last_p2_locale
}
function is_in_livonia(loc) {
+ // FIXME actual numbers
return loc >= 0 && loc <= last_locale && data.locales[loc].region === "Crusader Livonia"
}
-function is_in_estonia(loc) {
- return loc >= 0 && loc <= last_locale && data.locales[loc].region === "Danish Estonia"
-}
-
function is_commandery(loc) {
return (
loc === LOC_ADSEL ||
@@ -507,7 +488,7 @@ function push_state(next) {
}
function pop_state() {
- ;[ game.state, game.who, game.count ] = game.stack.pop()
+ [ game.state, game.who, game.count ] = game.stack.pop()
}
function set_active(new_active) {
@@ -544,7 +525,7 @@ function has_any_spoils() {
)
}
-function get_spoils(type, n) {
+function get_spoils(type) {
if (game.spoils)
return game.spoils[type]
return 0
@@ -922,7 +903,7 @@ function list_deck() {
let last_card = (game.active === P1) ? last_p1_card : last_p2_card
let no = (game.active === P1) ? game.no1 : game.no2
for (let c = first_card; c <= last_card; ++c)
- if (!is_card_in_play(c))
+ if (!is_card_in_use(c))
deck.push(c)
for (let c = last_card + 1; c <= last_card + no; ++c)
deck.push(c)
@@ -992,10 +973,6 @@ function is_special_vassal_available(vassal) {
return true
}
-function is_vassal_unavailable(vassal) {
- return game.pieces.vassals[vassal] === VASSAL_UNAVAILABLE
-}
-
function is_vassal_ready(vassal) {
return game.pieces.vassals[vassal] === VASSAL_READY
}
@@ -1016,10 +993,6 @@ function is_friendly_lord(lord) {
return lord >= first_friendly_lord && lord <= last_friendly_lord
}
-function is_enemy_lord(lord) {
- return lord >= first_enemy_lord && lord <= last_enemy_lord
-}
-
function is_lord_at_friendly_locale(lord) {
let loc = get_lord_locale(lord)
return is_friendly_locale(loc)
@@ -1213,14 +1186,6 @@ function add_siege_marker(loc) {
map_set(game.pieces.sieges, loc, map_get(game.pieces.sieges, loc, 0) + 1)
}
-function remove_siege_marker(loc) {
- let n = map_get(game.pieces.sieges, loc, 0)
- if (n > 1)
- map_set(game.pieces.sieges, loc, n - 1)
- else
- map_delete(game.pieces.sieges, loc)
-}
-
function remove_all_but_one_siege_markers(loc) {
map_set(game.pieces.sieges, loc, 1)
}
@@ -1243,7 +1208,7 @@ function conquer_trade_route(loc) {
}
}
-function count_castles(loc) {
+function count_castles() {
return game.pieces.castles1.length + game.pieces.castles2.length
}
@@ -1281,10 +1246,6 @@ function flip_castle(loc) {
}
}
-function has_conquered_stronghold(loc) {
- return is_stronghold(loc) && has_conquered_marker(loc)
-}
-
function is_friendly_stronghold_locale(loc) {
if (is_stronghold(loc) || has_friendly_castle(loc))
return is_friendly_locale(loc)
@@ -1327,10 +1288,6 @@ function is_besieged_enemy_stronghold(loc) {
return is_enemy_stronghold(loc) && has_siege_marker(loc)
}
-function is_besieged_friendly_stronghold(loc) {
- return is_friendly_stronghold(loc) && has_siege_marker(loc)
-}
-
function is_friendly_locale(loc) {
if (loc !== NOWHERE && loc < CALENDAR) {
if (has_enemy_lord(loc))
@@ -1351,15 +1308,10 @@ function is_friendly_locale(loc) {
return false
}
-function is_not_friendly_locale(loc) {
- return !is_friendly_locale(loc)
-}
-
function can_add_transport(who, what) {
return get_lord_assets(who, what) < 8
}
-
function count_lord_transport(lord, type) {
let season = current_season()
let n = 0
@@ -1402,10 +1354,6 @@ function list_ways(from, to) {
return null
}
-function has_two_ways(from, to) {
- return list_ways(from, to).length > 2
-}
-
function is_upper_lord(lord) {
return map_has(game.pieces.lieutenants, lord)
}
@@ -1417,13 +1365,6 @@ function is_lower_lord(lord) {
return false
}
-function get_upper_lord(lower) {
- for (let i = 0; i < game.pieces.lieutenants.length; i += 2)
- if (game.pieces.lieutenants[i+1] === lower)
- return i
- return NOBODY
-}
-
function get_lower_lord(upper) {
return map_get(game.pieces.lieutenants, upper, NOBODY)
}
@@ -1588,7 +1529,7 @@ function disband_vassal(vassal) {
add_lord_forces(lord, MILITIA, -(info.forces.militia | 0))
add_lord_forces(lord, SERFS, -(info.forces.serfs | 0))
- game.pieces.vassals[v] = VASSAL_READY
+ game.pieces.vassals[vassal] = VASSAL_READY
}
function muster_vassal(lord, vassal) {
@@ -2156,10 +2097,10 @@ function goto_teutonic_event_torzhok() {
}
}
-function torzhok_action(lord, asset) {
+function action_torzhok(lord, asset) {
push_undo()
- logi(`Removed ${ASSET_TYPE_NAME[type]} from L${lord}.`)
- add_lord_assets(lord, type, -1)
+ logi(`Removed ${ASSET_TYPE_NAME[asset]} from L${lord}.`)
+ add_lord_assets(lord, asset, -1)
game.count--
}
@@ -2378,7 +2319,7 @@ states.prussian_revolt = {
gen_action_locale(LOC_RIGA)
}
},
- locale(loc) {
+ locale(_) {
logi(`Placed L${game.who} at %${LOC_RIGA}.`)
set_lord_locale(game.who, LOC_RIGA)
game.who = NOBODY
@@ -2813,7 +2754,7 @@ states.heinrich_sees_the_curia = {
view.prompt = "Heinrich Sees the Curia: Disband Heinrich to add 4 Assets each to 2 Lords."
gen_action_lord(LORD_HEINRICH)
},
- lord(lord) {
+ lord(_) {
disband_lord(LORD_HEINRICH)
game.state = "heinrich_sees_the_curia_1"
game.who = NOBODY
@@ -3260,7 +3201,6 @@ states.levy_muster_lord = {
prompt_held_event_lordship()
if (game.count > 0) {
- let season = current_season()
view.prompt += ` ${game.count} lordship left.`
// Roll to muster Ready Lord at Seat
@@ -3268,7 +3208,7 @@ states.levy_muster_lord = {
if (lord === LORD_ALEKSANDR)
continue
- // NOTE: 2E change, ANDREY may be mustered normally
+ // NOTE: ANDREY may be mustered normally in 2nd edition
// if (lord === LORD_ANDREY && game.who !== LORD_ALEKSANDR) continue
if (no_muster_of_or_by_lord(lord))
@@ -3496,7 +3436,7 @@ function add_lord_capability(lord, c) {
}
function discard_lord_capability_n(lord, n) {
- set_lord_capability(lord, 0, NOTHING)
+ set_lord_capability(lord, n, NOTHING)
}
function discard_lord_capability(lord, c) {
@@ -4792,7 +4732,7 @@ states.avoid_battle_laden = {
push_undo()
spoil_loot(lord)
},
- locale(to) {
+ locale(_) {
avoid_battle_2()
},
avoid() {
@@ -4801,7 +4741,6 @@ states.avoid_battle_laden = {
}
function avoid_battle_2() {
- let from = game.march.to
let to = game.march.avoid_to
let way = game.march.avoid_way
@@ -4935,7 +4874,6 @@ function take_spoils(type) {
function take_spoils_prov() { take_spoils(PROV) }
function take_spoils_loot() { take_spoils(LOOT) }
function take_spoils_coin() { take_spoils(COIN) }
-function take_spoils_ship() { take_spoils(SHIP) }
function take_spoils_boat() { take_spoils(BOAT) }
function take_spoils_cart() { take_spoils(CART) }
function take_spoils_sled() { take_spoils(SLED) }
@@ -5559,7 +5497,7 @@ function restore_mustered_forces(lord) {
muster_lord_forces(lord)
for (let v of data.lords[lord].vassals)
if (is_vassal_mustered(v))
- muster_vassal_forces(lord, v)
+ restore_vassal_forces(lord, v)
}
function can_action_tax() {
@@ -5632,7 +5570,6 @@ function can_action_sail() {
return false
// during Rasputitsa or Summer
- let season = current_season()
if (is_winter())
return false
@@ -6023,10 +5960,6 @@ function start_storm() {
// NOTE: sallying attackers are flagged as besieged
-function is_lord_arrayed(lord) {
- return game.battle.array.includes(lord)
-}
-
function goto_relief_sally() {
set_active_attacker()
if (has_besieged_friendly_lord(game.battle.where)) {
@@ -6600,9 +6533,9 @@ function goto_reposition_battle() {
slide_array(SA2, A2)
slide_array(SA3, A3)
// then D back to reserve
- send_to_reserv(D1)
- send_to_reserv(D2)
- send_to_reserv(D3)
+ send_to_reserve(D1)
+ send_to_reserve(D2)
+ send_to_reserve(D3)
// then RD to D
slide_array(RD1, D1)
slide_array(RD2, D2)
@@ -6812,9 +6745,6 @@ states.reposition_storm = {
const battle_defending_positions = [ D1, D2, D3, RD1, RD2, RD3 ]
const battle_attacking_positions = [ A1, A2, A3, SA1, SA2, SA3 ]
-const storm_defending_positions = [ D2 ]
-const storm_attacking_positions = [ A2 ]
-
const battle_steps = [
{ name: "Defending Archery", hits: count_archery_hits, xhits: count_archery_xhits, archery: 1 },
{ name: "Attacking Archery", hits: count_archery_hits, xhits: count_archery_xhits, archery: 1 },
@@ -6831,7 +6761,7 @@ const storm_steps = [
{ name: "Attacking Melee", hits: count_melee_hits, xhits: count_zero_hits, archery: 0 },
]
-function count_zero_hits(lord) {
+function count_zero_hits(_) {
return 0
}
@@ -7099,9 +7029,6 @@ function unpack_group(g, offset) {
return list
}
-function round_hits(hits, xhits) {
-}
-
function create_battle_group(list, targets) {
let strikers = []
let hits = 0
@@ -7397,7 +7324,7 @@ function goto_select_strike_group() {
states.select_strike_group = {
prompt() {
view.prompt = `${format_strike_step()}: Select Striking Lord or Group.`
- for (let [strikers, targets] of game.battle.groups) {
+ for (let [strikers] of game.battle.groups) {
for (let p of strikers)
gen_action_lord(game.battle.array[p])
}
@@ -7412,7 +7339,7 @@ states.select_strike_group = {
}
function select_strike_group(i) {
- ;[ game.battle.strikers, game.battle.targets, game.battle.hits, game.battle.xhits ] = game.battle.groups[i]
+ [ game.battle.strikers, game.battle.targets, game.battle.hits, game.battle.xhits ] = game.battle.groups[i]
array_remove(game.battle.groups, i)
goto_assign_hits()
}
@@ -8109,7 +8036,7 @@ function can_retreat() {
return true
} else {
// Battle after Sally
- for (let [to, way] of data.locales[game.battle.where].ways)
+ for (let to of data.locales[game.battle.where].adjacent)
if (can_retreat_to(to))
return true
}
@@ -8149,9 +8076,9 @@ states.retreat = {
}
} else {
// after Sally
- for (let [to, way] of data.locales[game.battle.where].ways)
- if (can_retreat_to(to))
- gen_action_locale(to)
+ for (let to of data.locales[game.battle.where].adjacent)
+ if (can_retreat_to(to))
+ gen_action_locale(to)
}
},
locale(to) {
@@ -8254,7 +8181,7 @@ states.retreat_laden = {
loot(lord) {
spoil_loot(lord)
},
- locale(to) {
+ locale(_) {
retreat_2()
},
retreat() {
@@ -8263,7 +8190,6 @@ states.retreat_laden = {
}
function retreat_2() {
- let from = game.battle.where
let to = game.battle.retreat_to
let way = game.battle.retreat_way
@@ -9166,8 +9092,7 @@ function goto_end_campaign() {
function count_vp1() {
let vp = 0
- for (let loc of game.pieces.castles1)
- vp += 2
+ vp += game.pieces.castles1.length << 1
for (let loc of game.pieces.conquered)
if (is_p2_locale(loc))
vp += data.locales[loc].vp << 1
@@ -9178,9 +9103,9 @@ function count_vp1() {
}
function count_vp2() {
- let vp = game.pieces.veche_vp * 2
- for (let loc of game.pieces.castles2)
- vp += 2
+ let vp = 0
+ vp += game.pieces.veche_vp << 1
+ vp += game.pieces.castles2.length << 1
for (let loc of game.pieces.conquered)
if (is_p1_locale(loc))
vp += data.locales[loc].vp << 1
@@ -9233,16 +9158,14 @@ function flip_and_discard_half(lord, from_type, to_type) {
states.plow_and_reap = {
prompt() {
- let from_type, to_type
+ let from_type
let turn = current_turn()
if (turn === 2 || turn === 10) {
view.prompt = "Plow and Reap: Flip Carts to Sleds and discard half."
from_type = CART
- to_type = SLED
} else {
view.prompt = "Plow and Reap: Flip Sleds to Carts and discard half."
from_type = SLED
- to_type = CART
}
let done = true
for (let lord = first_friendly_lord; lord <= last_friendly_lord; ++lord) {
@@ -9401,9 +9324,6 @@ function end_wastage() {
// === END CAMPAIGN: RESET (DISCARD ARTS OF WAR) ===
-function reset_serfs() {
-}
-
function goto_reset() {
game.state = "reset"
@@ -9787,11 +9707,6 @@ exports.action = function (state, current, action, arg) {
// === COMMON TEMPLATE ===
-function random(range) {
- // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf
- return (game.seed = (game.seed * 200105) % 34359738337) % range
-}
-
// Packed array of small numbers in one word
function pack1_get(word, n) {
@@ -9867,34 +9782,6 @@ function random(range) {
return (game.seed = (game.seed * 200105) % 34359738337) % range
}
-function random_bigint(range) {
- // Largest MLCG that will fit its state in a double.
- // Uses BigInt for arithmetic, so is an order of magnitude slower.
- // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf
- // m = 2**53 - 111
- return (game.seed = Number((BigInt(game.seed) * 5667072534355537n) % 9007199254740881n)) % range
-}
-
-function shuffle(list) {
- // Fisher-Yates shuffle
- for (let i = list.length - 1; i > 0; --i) {
- let j = random(i + 1)
- let tmp = list[j]
- list[j] = list[i]
- list[i] = tmp
- }
-}
-
-function shuffle_bigint(list) {
- // Fisher-Yates shuffle
- for (let i = list.length - 1; i > 0; --i) {
- let j = random_bigint(i + 1)
- let tmp = list[j]
- list[j] = list[i]
- list[i] = tmp
- }
-}
-
// Fast deep copy for objects without cycles
function object_copy(original) {
if (Array.isArray(original)) {
@@ -9961,10 +9848,6 @@ function array_insert_pair(array, index, key, value) {
// Set as plain sorted array
-function set_clear(set) {
- set.length = 0
-}
-
function set_has(set, item) {
let a = 0
let b = set.length - 1
@@ -10034,10 +9917,6 @@ function set_toggle(set, item) {
// Map as plain sorted array of key/value pairs
-function map_clear(map) {
- map.length = 0
-}
-
function map_has(map, key) {
let a = 0
let b = (map.length >> 1) - 1