summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js239
1 files changed, 119 insertions, 120 deletions
diff --git a/rules.js b/rules.js
index 48d5a62..6e9d678 100644
--- a/rules.js
+++ b/rules.js
@@ -14,14 +14,8 @@
// TODO: BUILDUP
// TODO: setup scenario specials
-// TODO: clean up "can retreat" checks
// TODO: when is "fired" status cleared?
-// TODO: cache_valid, cache_axis, cache_allied (presence and disruption per hex)
-// instead of iterating units in is_axis_hex, etc.
-// invalidate when loading state
-// invalidate when disrupting, recovering, eliminating or moving units
-
// TODO: cache supply lines
// same as presence cache
@@ -41,33 +35,6 @@ var view = null
const { all_hexes, hex_exists, hex_road, side_road, side_limit, hex_name, units, regions } = require("./data")
-const first_axis_unit = 0
-const first_allied_unit = units.findIndex(item => item.nationality === 'allied')
-const last_axis_unit = first_allied_unit - 1
-const last_allied_unit = units.length - 1
-
-var first_friendly_unit, last_friendly_unit
-var first_enemy_unit, last_enemy_unit
-
-function update_aliases() {
- if (game.active === AXIS) {
- first_friendly_unit = first_axis_unit
- last_friendly_unit = last_axis_unit
- first_enemy_unit = first_allied_unit
- last_enemy_unit = last_allied_unit
- } else {
- first_friendly_unit = first_allied_unit
- last_friendly_unit = last_allied_unit
- first_enemy_unit = first_axis_unit
- last_enemy_unit = last_axis_unit
- }
-}
-
-function load_state(state) {
- game = state
- update_aliases()
-}
-
function debug_hexes3(n, list) {
console.log("--", n, "--")
list = list.map((x,i) => hex_exists[i] ? x : "")
@@ -89,26 +56,19 @@ function debug_hexes(n, list) {
console.log("".padStart(y," ") + list.slice(y*hexw, (y+1)*hexw).map(x=>String(x).padStart(2, ' ')).join(""))
}
-// Card deck has 42 cards, of which 28 are supply cards, and 14 are dummy cards.
-// Represent draw pile and hands as [ dummy_supply_count, real_supply_count ]
-const REAL_SUPPLY_COUNT = 28
-const DUMMY_SUPPLY_COUNT = 14
+const AXIS = 'Axis'
+const ALLIED = 'Allied'
const hexw = 25
const hexh = 9
-
const first_hex = 7
const last_hex = 215
-
const hexdeploy = hexw * hexh
const hexnext = [ 1, hexw, hexw-1, -1, -hexw, -(hexw-1) ]
-
const hexcount = last_hex + 1
const sidecount = hexcount * 3
-const AXIS = 'Axis'
-const ALLIED = 'Allied'
-
+const class_name = [ "armor", "infantry", "anti-tank", "artillery" ]
const firepower_name = [ "0", "1", "2", "3", "TF", "DF", "SF" ]
const speed_name = [ "zero", "leg", "motorized", "mechanized", "recon" ]
@@ -116,13 +76,17 @@ const SF = 6
const DF = 5
const TF = 4
-const class_name = [ "armor", "infantry", "anti-tank", "artillery" ]
-
const ARMOR = 0
const INFANTRY = 1
const ANTITANK = 2
const ARTILLERY = 3
+const TRAIL = 1
+const TRACK = 2
+const HIGHWAY = 4
+
+const SUPPLY_RANGE = [ 1, 2, 3, -1, 3 ]
+
const FIREPOWER_MATRIX = [
[ SF, DF, SF, TF ],
[ SF, SF, SF, TF ],
@@ -130,26 +94,26 @@ const FIREPOWER_MATRIX = [
[ SF, DF, DF, SF ],
]
-const CLEAR = 2
-const PASS = 1
-const ROUGH = 0
-
-const NO_ROAD = 0
-const TRAIL = 1
-const TRACK = 2
-const HIGHWAY = 4
-
-const SUPPLY_RANGE = [ 1, 2, 3, -1, 3 ]
-
const EL_AGHEILA = 151
const ALEXANDRIA = 74
const BENGHAZI = 54
const TOBRUK = 37
const BARDIA = 40
-const FT_CAPUZZO = 64
const MERSA_BREGA = 152
+const JALO_OASIS = 204
+const JARABUB_OASIS = 187
+const SIWA_OASIS = 213
+
const BARDIA_FT_CAPUZZO = 122
+const SS_NONE = 0
+const SS_EL_AGHEILA = 1
+const SS_ALEXANDRIA = 2
+const SS_BARDIA = 3
+const SS_BENGHAZI = 4
+const SS_TOBRUK = 5
+const SS_OASIS = 6
+
const hex_from_supply_source = [ 0, EL_AGHEILA, ALEXANDRIA, BARDIA, BENGHAZI, TOBRUK ]
function supply_source_from_hex(hex) {
@@ -164,8 +128,6 @@ function supply_source_from_hex(hex) {
}
const region_egypt = regions["Egypt"]
-const region_el_agheila = regions["El Agheila"]
-const region_tobruk = regions["Tobruk"]
const region_egypt_and_libya = regions["Libya"].concat(regions["Egypt"])
const region_libya_and_sidi_omar = regions["Libya"].concat(regions["Sidi Omar"])
const region_libya_and_sidi_omar_and_sollum = regions["Libya"].concat(regions["Sidi Omar"]).concat(regions["Sollum"])
@@ -227,6 +189,42 @@ function is_hex_or_adjacent_to(x, where) {
return false
}
+// === STATE CACHES ===
+
+const first_axis_unit = 0
+const first_allied_unit = units.findIndex(item => item.nationality === 'allied')
+const last_axis_unit = first_allied_unit - 1
+const last_allied_unit = units.length - 1
+
+var presence_invalid = true
+var presence_axis = new Array(hexcount).fill(0)
+var presence_allied = new Array(hexcount).fill(0)
+
+var first_friendly_unit, last_friendly_unit
+var first_enemy_unit, last_enemy_unit
+
+function update_aliases() {
+ if (game.active === AXIS) {
+ first_friendly_unit = first_axis_unit
+ last_friendly_unit = last_axis_unit
+ first_enemy_unit = first_allied_unit
+ last_enemy_unit = last_allied_unit
+ } else {
+ first_friendly_unit = first_allied_unit
+ last_friendly_unit = last_allied_unit
+ first_enemy_unit = first_axis_unit
+ last_enemy_unit = last_axis_unit
+ }
+}
+
+function load_state(state) {
+ if (game !== state) {
+ game = state
+ presence_invalid = true
+ update_aliases()
+ }
+}
+
// === UNIT STATE ===
// location (8 bits), supply source (3 bits), steps lost (2 bits), disrupted (1 bit)
@@ -261,10 +259,12 @@ function is_unit_disrupted(u) {
}
function set_unit_disrupted(u) {
+ presence_invalid = true
game.units[u] |= UNIT_DISRUPTED_MASK
}
function clear_unit_disrupted(u) {
+ presence_invalid = true
game.units[u] &= ~UNIT_DISRUPTED_MASK
}
@@ -273,6 +273,7 @@ function unit_hex(u) {
}
function set_unit_hex(u, x) {
+ presence_invalid = true
game.units[u] = (game.units[u] & ~UNIT_HEX_MASK) | (x << UNIT_HEX_SHIFT)
}
@@ -418,94 +419,93 @@ function is_axis_unit(u) {
// === MAP STATE ===
-function has_axis_unit(x) {
+function update_presence() {
+ console.log("UPDATE PRESENCE")
+ presence_invalid = false
+ presence_axis.fill(0)
for (let u = first_axis_unit; u <= last_axis_unit; ++u)
- if (unit_hex(u) === x)
- return true
- return false
+ if (is_unit_disrupted(u))
+ presence_axis[unit_hex(u)] |= 1
+ else
+ presence_axis[unit_hex(u)] |= 2
+ presence_allied.fill(0)
+ for (let u = first_allied_unit; u <= last_allied_unit; ++u)
+ if (is_unit_disrupted(u))
+ presence_allied[unit_hex(u)] |= 1
+ else
+ presence_allied[unit_hex(u)] |= 2
+}
+
+function has_axis_unit(x) {
+ if (presence_invalid)
+ update_presence()
+ return presence_axis[x] !== 0
}
function has_allied_unit(x) {
- for (let u = first_allied_unit; u <= last_allied_unit; ++u)
- if (unit_hex(u) === x)
- return true
- return false
+ if (presence_invalid)
+ update_presence()
+ return presence_allied[x] !== 0
}
function has_undisrupted_axis_unit(x) {
- for (let u = first_axis_unit; u <= last_axis_unit; ++u)
- if (!is_unit_disrupted(u) && unit_hex(u) === x)
- return true
- return false
+ if (presence_invalid)
+ update_presence()
+ return (presence_axis[x] & 2) !== 0
}
function has_disrupted_axis_unit(x) {
- for (let u = first_axis_unit; u <= last_axis_unit; ++u)
- if (is_unit_disrupted(u) && unit_hex(u) === x)
- return true
- return false
+ if (presence_invalid)
+ update_presence()
+ return (presence_axis[x] & 1) !== 0
}
function has_undisrupted_allied_unit(x) {
- for (let u = first_allied_unit; u <= last_allied_unit; ++u)
- if (!is_unit_disrupted(u) && unit_hex(u) === x)
- return true
- return false
+ if (presence_invalid)
+ update_presence()
+ return (presence_allied[x] & 2) !== 0
}
function has_disrupted_allied_unit(x) {
- for (let u = first_allied_unit; u <= last_allied_unit; ++u)
- if (is_unit_disrupted(u) && unit_hex(u) === x)
- return true
- return false
+ if (presence_invalid)
+ update_presence()
+ return (presence_allied[x] & 1) !== 0
}
function has_unshielded_disrupted_axis_unit(x) {
- let undisrupted = false
- let disrupted = false
- for (let u = first_axis_unit; u <= last_axis_unit; ++u)
- if (unit_hex(u) === x)
- if (is_unit_disrupted(u))
- disrupted = true
- else
- undisrupted = true
- return disrupted && !undisrupted
+ if (presence_invalid)
+ update_presence()
+ return presence_axis[x] === 1
}
function has_unshielded_disrupted_allied_unit(x) {
- let undisrupted = false
- let disrupted = false
- for (let u = first_allied_unit; u <= last_allied_unit; ++u)
- if (unit_hex(u) === x)
- if (is_unit_disrupted(u))
- disrupted = true
- else
- undisrupted = true
- return disrupted && !undisrupted
+ if (presence_invalid)
+ update_presence()
+ return presence_allied[x] === 1
}
function is_axis_hex(x) {
- let has_axis = has_axis_unit(x)
- let has_allied = has_allied_unit(x)
- return has_axis && !has_allied
+ if (presence_invalid)
+ update_presence()
+ return (presence_axis[x] !== 0) && (presence_allied[x] === 0)
}
function is_allied_hex(x) {
- let has_axis = has_axis_unit(x)
- let has_allied = has_allied_unit(x)
- return !has_axis && has_allied
+ if (presence_invalid)
+ update_presence()
+ return (presence_axis[x] === 0) && (presence_allied[x] !== 0)
}
function is_battle_hex(x) {
- let has_axis = has_axis_unit(x)
- let has_allied = has_allied_unit(x)
- return has_axis && has_allied
+ if (presence_invalid)
+ update_presence()
+ return (presence_axis[x] !== 0) && (presence_allied[x] !== 0)
}
function is_empty_hex(x) {
- let has_axis = has_axis_unit(x)
- let has_allied = has_allied_unit(x)
- return !has_axis && !has_allied
+ if (presence_invalid)
+ update_presence()
+ return (presence_axis[x] === 0) && (presence_allied[x] === 0)
}
function has_friendly_unit(x) {
@@ -2444,9 +2444,7 @@ function goto_rout(from, enemy, after) {
if (enemy)
set_enemy_player()
- game.pursuit = from
game.state = 'rout_attrition'
- game.flash = "Rout attrition!"
}
states.rout_attrition = {
@@ -3780,7 +3778,7 @@ exports.setup = function (seed, scenario, options) {
scenario: scenario,
month: 0,
- draw_pile: [ DUMMY_SUPPLY_COUNT, REAL_SUPPLY_COUNT ],
+ draw_pile: [ 14, 28 ], // 14 dummy supply + 28 real supply
axis_hand: [ 0, 0 ],
allied_hand: [ 0, 0 ],
@@ -4022,10 +4020,11 @@ function push_undo() {
function pop_undo() {
let save_log = game.log
let save_undo = game.undo
- game = save_undo.pop()
- save_log.length = game.log
- game.log = save_log
- game.undo = save_undo
+ let state = save_undo.pop()
+ save_log.length = state.log
+ state.log = save_log
+ state.undo = save_undo
+ load_state(state)
}
function clear_undo() {