summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-07-30 14:14:41 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-17 13:11:26 +0100
commite8ee549f0d30c5caa99b2d931734c5f18332d543 (patch)
treedb008ffc8b2779d5c44e8cda7c463f309241c79e
parentc3eaccd47742a41f79aa2aa05cee31c4b9848640 (diff)
downloadrommel-in-the-desert-e8ee549f0d30c5caa99b2d931734c5f18332d543.tar.gz
Fortress and Oasis supply.
-rw-r--r--play.js69
-rw-r--r--rules.js637
2 files changed, 504 insertions, 202 deletions
diff --git a/play.js b/play.js
index 685e280..4410ab9 100644
--- a/play.js
+++ b/play.js
@@ -1,7 +1,5 @@
"use strict"
-// TODO: intermediate regroup moves
-
// https://www.redblobgames.com/grids/hexagons/
const svgNS = "http://www.w3.org/2000/svg"
@@ -16,6 +14,13 @@ const hex_special = [ 48, 49, 102, 127, MALTA ]
const unit_count = 94
+const SS_NONE = 0
+const SS_BASE = 1
+const SS_BARDIA = 2
+const SS_BENGHAZI = 3
+const SS_TOBRUK = 4
+const SS_OASIS = 5
+
const ARMOR = 0
const INFANTRY = 1
const ANTITANK = 2
@@ -29,9 +34,9 @@ function is_allied_unit(u) { return (u >= 34 && u <= 93) }
function is_elite_unit(u) { return unit_elite[u] }
function is_armor_unit(u) { return unit_class[u] === ARMOR }
-function is_infantry_unit(u) { unit_class[u] === INFANTRY }
-function is_antitank_unit(u) { unit_class[u] === ANTITANK }
-function is_artillery_unit(u) { unit_class[u] === ARTILLERY }
+function is_infantry_unit(u) { return unit_class[u] === INFANTRY }
+function is_antitank_unit(u) { return unit_class[u] === ANTITANK }
+function is_artillery_unit(u) { return unit_class[u] === ARTILLERY }
function is_recon_unit(u) { return unit_speed[u] === 4 }
function is_mechanized_unit(u) { return unit_speed[u] === 3 }
@@ -103,6 +108,10 @@ let ui = {
const AXIS = 'Axis'
const ALLIED = 'Allied'
+function is_map_hex(x) {
+ return x < hex_exists.length && hex_exists[x] === 1
+}
+
// === UNIT STATE ===
const UNIT_DISRUPTED_SHIFT = 0
@@ -121,56 +130,32 @@ function is_unit_disrupted(u) {
return (view.units[u] & UNIT_DISRUPTED_MASK) === UNIT_DISRUPTED_MASK
}
-function set_unit_disrupted(u) {
- view.units[u] |= UNIT_DISRUPTED_MASK
-}
-
-function clear_unit_disrupted(u) {
- view.units[u] &= ~UNIT_DISRUPTED_MASK
-}
-
function unit_hex(u) {
return (view.units[u] & UNIT_HEX_MASK) >> UNIT_HEX_SHIFT
}
-function set_unit_hex(u, x) {
- view.units[u] = (view.units[u] & ~UNIT_HEX_MASK) | (x << UNIT_HEX_SHIFT)
-}
-
function is_unit_supplied(u) {
return ((view.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT) !== 0
}
function unit_supply(u) {
- let src = (view.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT
- return hex_from_supply_source[src]
+ return (view.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT
}
function is_unit_unsupplied(u) {
- return ((view.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT) === 0
-}
-
-function set_unit_supply(u, hex) {
- let src = supply_source_from_hex(hex)
- view.units[u] = (view.units[u] & ~UNIT_SUPPLY_MASK) | (src << UNIT_SUPPLY_SHIFT)
+ if (is_map_hex(unit_hex(u)))
+ return ((view.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT) === 0
+ return false
}
function unit_lost_steps(u) {
return (view.units[u] & UNIT_STEPS_MASK) >> UNIT_STEPS_SHIFT
}
-function set_unit_lost_steps(u, n) {
- view.units[u] = (view.units[u] & ~UNIT_STEPS_MASK) | (n << UNIT_STEPS_SHIFT)
-}
-
function unit_steps(u) {
return unit_start_steps[u] - unit_lost_steps(u)
}
-function set_unit_steps(u, n) {
- set_unit_lost_steps(u, unit_start_steps[u] - n)
-}
-
function is_unit_moved(u) {
return set_has(view.moved, u)
}
@@ -340,13 +325,23 @@ for (let u = 0; u <= 93; ++u) {
function on_focus_unit(evt) {
let u = evt.target.unit
- let t = "(" + u + ")"
- t += " " + unit_description[u]
- t += " \"" + unit_name[u] + "\""
+ let t = ""
+ if (is_unit_revealed(u)) {
+ t += " " + unit_description[u]
+ t += " \"" + unit_name[u] + "\""
+ } else {
+ t = is_allied_unit(u) ? "Allied unit" : "Axis unit"
+ }
if (is_unit_disrupted(u))
t += " - disrupted"
if (is_unit_unsupplied(u))
t += " - unsupplied"
+ else {
+ if (unit_supply(u) === SS_BARDIA) t += " - Bardia supply"
+ if (unit_supply(u) === SS_TOBRUK) t += " - Tobruk supply"
+ if (unit_supply(u) === SS_BENGHAZI) t += " - Benghazi supply"
+ if (unit_supply(u) === SS_OASIS) t += " - Oasis supply"
+ }
if (is_unit_moved(u))
t += " - moved"
if (is_unit_fired(u))
@@ -663,7 +658,7 @@ function update_map() {
e.classList.toggle("selected", !view.battle && is_unit_selected(u))
e.classList.toggle("disrupted", is_unit_disrupted(u))
e.classList.toggle("moved", is_unit_moved(u))
- // e.classList.toggle("unsupplied", is_unit_unsupplied(u))
+ e.classList.toggle("unsupplied", is_unit_unsupplied(u))
e.classList.toggle("revealed", is_unit_revealed(u))
}
diff --git a/rules.js b/rules.js
index e74e74c..141d56b 100644
--- a/rules.js
+++ b/rules.js
@@ -1,8 +1,5 @@
"use strict"
-// TODO: fortress supply
-// TODO: oasis supply
-
// TODO: RAIDERS
// TODO: MINEFIELDS
// TODO: legal pass withdrawal moves (reduce supply net, withdraw from fortress attack)
@@ -13,14 +10,19 @@
// TODO: log summaries (deploy, rebuild, move, etc)
// TODO: put initial deployment stack somewhere more accessible (spread out along the top?)
+// TODO: multi-select deployment
+
+// RULES: may units redeploying out of battle hex cross enemy controlled hexsides? (yes / doesn't matter)
+
+// RULES: can fortress supplied units be part of supply lines for non-fortress supplied units for withdrawals to base?
+// RULES: can non-fortress supplied units be part of supply lines for fortress supplied units for withdrawals?
// RULES: for sea redeployment, can bases be "besieged"? (yes)
// RULES: may units redeploying out of battle hex leave disrupted units behind to be routed? (no)
-// RULES: may units redeploying out of battle hex cross enemy controlled hexsides? (yes / doesn't matter)
// RULES: may units returning for refit enter enemy supply network? (no)
// RULES: if disrupted units are routed again during their "full enemy turn", can they still recover?
-// RULES: may oasis supplied units refuse battle or withdraw to base?
+// RULES: may oasis supplied units refuse battle or withdraw to base? (yes)
// RULES: when is "fired" status cleared?
// RULES: are minefields moved through (but not stopped at) revealed?
@@ -135,25 +137,11 @@ 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) {
- switch (hex) {
- case 0: return 0
- case EL_AGHEILA: return 1
- case ALEXANDRIA: return 2
- case BARDIA: return 3
- case BENGHAZI: return 4
- case TOBRUK: return 5
- }
-}
+const SS_BASE = 1
+const SS_BARDIA = 2
+const SS_BENGHAZI = 3
+const SS_TOBRUK = 4
+const SS_OASIS = 5
const region_egypt = regions["Egypt"]
const region_egypt_and_libya = regions["Libya"].concat(regions["Egypt"])
@@ -358,6 +346,7 @@ function is_unit_disrupted(u) {
}
function set_unit_disrupted(u) {
+ invalidate_caches()
game.units[u] |= UNIT_DISRUPTED_MASK
}
@@ -384,12 +373,10 @@ function is_unit_unsupplied(u) {
}
function unit_supply(u) {
- let src = (game.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT
- return hex_from_supply_source[src]
+ return (game.units[u] & UNIT_SUPPLY_MASK) >> UNIT_SUPPLY_SHIFT
}
-function set_unit_supply(u, hex) {
- let src = supply_source_from_hex(hex)
+function set_unit_supply(u, src) {
game.units[u] = (game.units[u] & ~UNIT_SUPPLY_MASK) | (src << UNIT_SUPPLY_SHIFT)
}
@@ -772,26 +759,38 @@ function capture_fortress(fortress, capacity) {
// === FORTRESSES ===
-const FORTRESS_BIT = {
- [BARDIA]: 1,
- [BENGHAZI]: 2,
- [TOBRUK]: 4,
+function fortress_bit(fortress) {
+ if (fortress === BARDIA) return 1
+ if (fortress === BENGHAZI) return 2
+ if (fortress === TOBRUK) return 4
+ return 0
+}
+
+function fortress_src(fortress) {
+ if (fortress === BARDIA) return SS_BARDIA
+ if (fortress === BENGHAZI) return SS_BENGHAZI
+ if (fortress === TOBRUK) return SS_TOBRUK
+ return SS_OASIS
+}
+
+function is_fortress_allied_controlled(fortress) {
+ return (game.fortress & fortress_bit(fortress)) === 1
}
function is_fortress_axis_controlled(fortress) {
- return (game.fortress & FORTRESS_BIT[fortress]) === 0
+ return (game.fortress & fortress_bit(fortress)) === 0
}
function set_fortress_axis_controlled(fortress) {
- game.fortress &= ~FORTRESS_BIT[fortress]
+ game.fortress &= ~fortress_bit(fortress)
}
function set_fortress_allied_controlled(fortress) {
- game.fortress |= FORTRESS_BIT[fortress]
+ game.fortress |= fortress_bit(fortress)
}
function set_fortress_captured(fortress) {
- let bit = FORTRESS_BIT[fortress] << 3
+ let bit = fortress_bit(fortress) << 3
if (game.fortress & bit)
return false
game.fortress |= bit
@@ -818,7 +817,7 @@ function set_fortress_friendly_controlled(fortress) {
function is_fortress_besieged(fortress) {
let result = false
- let besieged = is_fortress_axis_controlled() ? has_allied_unit : has_axis_unit
+ let besieged = is_fortress_axis_controlled(fortress) ? has_allied_unit : has_axis_unit
for_each_adjacent_hex(fortress, x => {
if (besieged(x))
result = true
@@ -1077,13 +1076,11 @@ function ind(d, msg, here, ...extra) {
//console.log(new Array(d).fill("-").join("") + msg, here, "("+hex_name[here]+")", extra.join(" "))
}
-var supply_defender, supply_defender_sides, supply_friendly, supply_enemy, supply_net, supply_line
+var supply_defender, supply_defender_sides, supply_friendly, supply_enemy, supply_net, supply_line, supply_fortress_enemy
var supply_visited = new Array(hexcount).fill(0)
var supply_src = new Array(hexcount).fill(0)
var trace_total
-var trace_highway
-var trace_chain
function is_supply_line_blocked(here, next, side) {
// impassable hexside
@@ -1102,6 +1099,11 @@ function is_supply_line_blocked(here, next, side) {
}
}
+ // enemy controlled fortresses block supply lines
+ if (next === BARDIA || next === BENGHAZI || next === TOBRUK)
+ if (supply_fortress_enemy(next))
+ return true
+
// cannot trace through enemy hexsides
if (supply_friendly[here] && supply_enemy[here])
if (!set_has(supply_defender_sides, side))
@@ -1243,7 +1245,7 @@ function trace_supply_chain(here, d, n, range) {
return has_supply
}
-function trace_supply_network(start) {
+function trace_supply_network(start, ss) {
supply_visited.fill(0)
supply_src.fill(0)
supply_net.fill(0)
@@ -1258,27 +1260,52 @@ function trace_supply_network(start) {
trace_supply_chain(x, 0, 0, 3)
console.log("SUPPLY VISITS", trace_total)
- //debug_hexes("SS", supply_src)
- //debug_hexes("SN", supply_net)
}
-// For repeated supplied hex checks during deployment and fortress assignment
-function init_trace_supply_to_base_or_fortress(net, line) {
+function trace_fortress_network(fortress, ss) {
+ supply_visited.fill(0)
+ supply_src.fill(0)
+ supply_net.fill(0)
+ supply_line.fill(0)
+
+ supply_src[fortress] = 1
+ supply_net[fortress] = 1
+
+ trace_total = 0
+ for (let u = 0; u < unit_count; ++u) {
+ let x = unit_hex(u)
+ if (is_map_hex(x) && unit_supply(u) === ss) {
+ if (!supply_visited[x])
+ trace_supply_chain(x, 0, 0, 3)
+ }
+ }
+
+ console.log("FORTRESS SUPPLY VISITS", trace_total)
+}
+
+function init_trace_supply(net, line, friendly) {
if (presence_invalid)
update_presence()
supply_net = net
supply_line = line
- if (is_axis_player()) {
+ if (friendly === AXIS) {
+ supply_fortress_enemy = is_fortress_allied_controlled
supply_defender = game.axis_hexes
supply_defender_sides = game.axis_sides
supply_friendly = presence_axis
supply_enemy = presence_allied
} else {
+ supply_fortress_enemy = is_fortress_axis_controlled
supply_defender = game.allied_hexes
supply_defender_sides = game.allied_sides
supply_friendly = presence_allied
supply_enemy = presence_axis
}
+}
+
+// For repeated supplied hex checks during deployment and fortress assignment
+function init_trace_supply_to_base_or_fortress() {
+ init_trace_supply(supply_temp_network, supply_temp_line, game.active)
supply_net.fill(0)
}
@@ -1291,39 +1318,32 @@ function can_trace_supply_to_base_or_fortress(base, from) {
function update_axis_supply() {
supply_axis_invalid = false
- if (presence_invalid)
- update_presence()
-
- supply_net = supply_axis_network
- supply_line = supply_axis_line
- supply_defender = game.axis_hexes
- supply_defender_sides = game.axis_sides
- supply_friendly = presence_axis
- supply_enemy = presence_allied
-
- trace_supply_network(EL_AGHEILA)
+ init_trace_supply(supply_axis_network, supply_axis_line, AXIS)
+ trace_supply_network(EL_AGHEILA, 0)
}
function update_allied_supply() {
supply_allied_invalid = false
- if (presence_invalid)
- update_presence()
+ init_trace_supply(supply_allied_network, supply_allied_line, ALLIED)
+ trace_supply_network(ALEXANDRIA, 0)
+}
- supply_net = supply_allied_network
- supply_line = supply_allied_line
- supply_defender = game.allied_hexes
- supply_defender_sides = game.allied_sides
- supply_friendly = presence_allied
- supply_enemy = presence_axis
+function update_bardia_supply() {
+ supply_bardia_invalid = false
+ init_trace_supply(supply_bardia_network, supply_bardia_line, is_fortress_axis_controlled(BARDIA) ? AXIS : ALLIED)
+ trace_fortress_network(BARDIA, SS_BARDIA)
+}
- trace_supply_network(ALEXANDRIA)
+function update_benghazi_supply() {
+ supply_benghazi_invalid = false
+ init_trace_supply(supply_benghazi_network, supply_benghazi_line, is_fortress_axis_controlled(BENGHAZI) ? AXIS : ALLIED)
+ trace_fortress_network(BENGHAZI, SS_BENGHAZI)
}
-function update_supply() {
- if (supply_axis_invalid)
- update_axis_supply()
- if (supply_allied_invalid)
- update_allied_supply()
+function update_tobruk_supply() {
+ supply_tobruk_invalid = false
+ init_trace_supply(supply_tobruk_network, supply_tobruk_line, is_fortress_axis_controlled(TOBRUK) ? AXIS : ALLIED)
+ trace_fortress_network(TOBRUK, SS_TOBRUK)
}
function axis_supply_line() {
@@ -1351,8 +1371,10 @@ function allied_supply_network() {
}
function bardia_supply_line() {
+ console.log("X")
if (supply_bardia_invalid)
update_bardia_supply()
+ debug_hexes("bardia-line", supply_bardia_line)
return supply_bardia_line
}
@@ -1387,14 +1409,24 @@ function tobruk_supply_network() {
}
function unit_supply_line(who) {
- // TODO: fortress supply
+ // TODO: allow oasis supplied units to trace to base?
+ switch (unit_supply(who)) {
+ case SS_BARDIA: return bardia_supply_line()
+ case SS_BENGHAZI: return benghazi_supply_line()
+ case SS_TOBRUK: return tobruk_supply_line()
+ }
if (is_axis_unit(who))
return axis_supply_line()
return allied_supply_line()
}
function unit_supply_distance(who) {
- // TODO: fortress supply
+ // TODO: allow oasis supplied units to trace to base?
+ switch (unit_supply(who)) {
+ case SS_BARDIA: return distance_to[BARDIA]
+ case SS_BENGHAZI: return distance_to[BENGHAZI]
+ case SS_TOBRUK: return distance_to[TOBRUK]
+ }
if (is_axis_unit(who))
return distance_to[EL_AGHEILA]
return distance_to[ALEXANDRIA]
@@ -1828,29 +1860,284 @@ function end_player_turn() {
goto_player_turn()
}
-// === INITIAL & FINAL SUPPLY CHECK ===
+// === FORTRESS SUPPLY ===
-function goto_initial_supply_check() {
- let snet = friendly_supply_network()
- let ssrc = friendly_supply_base()
+function union_fortress_network(result, fort) {
+ for (let i = first_hex; i <= last_hex; ++i)
+ result[i] |= fort[i]
+}
- // TODO: fortress supply
- // TODO: assign fortress supply
+function union_fortress_line(result, fort) {
+ for (let i = 0; i < sidecount; ++i)
+ result[i] |= fort[i]
+}
+function union_axis_network() {
+ let net = axis_supply_network().slice()
+ if (net[BARDIA] === 0 && is_fortress_axis_controlled(BARDIA))
+ union_fortress_network(net, bardia_supply_network())
+ if (net[BENGHAZI] === 0 && is_fortress_axis_controlled(BENGHAZI))
+ union_fortress_network(net, benghazi_supply_network())
+ if (net[TOBRUK] === 0 && is_fortress_axis_controlled(TOBRUK))
+ union_fortress_network(net, tobruk_supply_network())
+ return net
+}
+
+function union_allied_network() {
+ let net = allied_supply_network().slice()
+ if (net[BARDIA] === 0 && is_fortress_allied_controlled(BARDIA))
+ union_fortress_network(net, bardia_supply_network())
+ if (net[BENGHAZI] === 0 && is_fortress_allied_controlled(BENGHAZI))
+ union_fortress_network(net, benghazi_supply_network())
+ if (net[TOBRUK] === 0 && is_fortress_allied_controlled(TOBRUK))
+ union_fortress_network(net, tobruk_supply_network())
+ return net
+}
+
+function union_axis_line() {
+ let net = axis_supply_network()
+ let line = axis_supply_line().slice()
+ if (net[BARDIA] === 0 && is_fortress_axis_controlled(BARDIA))
+ union_fortress_line(line, bardia_supply_line())
+ if (net[BENGHAZI] === 0 && is_fortress_axis_controlled(BENGHAZI))
+ union_fortress_line(line, benghazi_supply_line())
+ if (net[TOBRUK] === 0 && is_fortress_axis_controlled(TOBRUK))
+ union_fortress_line(line, tobruk_supply_line())
+ return line
+}
+
+function union_allied_line() {
+ let net = allied_supply_network()
+ let line = allied_supply_line().slice()
+ console.log("Xa")
+ if (net[BARDIA] === 0 && is_fortress_allied_controlled(BARDIA))
+ union_fortress_line(line, bardia_supply_line())
+ if (net[BENGHAZI] === 0 && is_fortress_allied_controlled(BENGHAZI))
+ union_fortress_line(line, benghazi_supply_line())
+ if (net[TOBRUK] === 0 && is_fortress_allied_controlled(TOBRUK))
+ union_fortress_line(line, tobruk_supply_line())
+ return line
+}
+
+const FORTRESS_HEX_LIST = [ BARDIA, BENGHAZI, TOBRUK ]
+const FORTRESS_SRC_LIST = [ SS_BARDIA, SS_BENGHAZI, SS_TOBRUK ]
+
+function all_friendly_unsupplied_units() {
+ let unsupplied = []
for_each_friendly_unit_on_map(u => {
- let x = unit_hex(u)
- if (snet[x]) {
- set_unit_supply(u, ssrc)
- if (is_unit_disrupted(u) && set_has(game.recover, u) && !is_battle_hex(x)) {
- log(`Recovered at #${x}`)
- set_delete(game.recover, u)
- clear_unit_disrupted(u)
- }
+ if (is_unit_unsupplied(u))
+ unsupplied.push(u)
+ })
+ return unsupplied
+}
+
+function resume_fortress_supply() {
+ while (game.assign < 3) {
+ if (assign_fortress_supply())
+ return
+ game.assign++
+ }
+ end_fortress_supply()
+}
+
+function end_fortress_supply() {
+ game.assign = 0
+ if (game.state === 'initial_fortress_supply')
+ game.state = 'initial_oasis_supply'
+ if (game.state === 'final_fortress_supply')
+ game.state = 'final_oasis_supply'
+ if (game.state === 'buildup_fortress_supply')
+ game.state = 'buildup_oasis_supply'
+ resume_oasis_supply()
+}
+
+function list_fortress_supply_candidates(fortress) {
+ let dist = distance_to[fortress]
+ let list = []
+ init_trace_supply_to_base_or_fortress()
+ for_each_friendly_unit_on_map(u => {
+ if (is_unit_unsupplied(u))
+ if (can_trace_supply_to_base_or_fortress(fortress, unit_hex(u)))
+ list.push(u)
+ })
+ list.sort((a,b) => dist[unit_hex(a)] - dist[unit_hex(b)])
+ return list
+}
+
+function auto_assign_fortress_supply(list, fortress, ss, ix) {
+ let total = 0
+ let dist = distance_to[fortress]
+ while (list.length > 0 && game.capacity[ix] > 0) {
+ let d0 = dist[unit_hex(list[0])]
+ let n = 0
+ for (let u of list)
+ if (dist[unit_hex(u)] === d0)
+ ++n
+ if (n <= game.capacity[ix]) {
+ for (let u of list)
+ if (dist[unit_hex(u)] === d0)
+ set_unit_supply(u, ss)
+ game.capacity[ix] -= n
+ total += n
+ list = list.slice(n)
} else {
- set_unit_supply(u, 0)
+ return true
+ }
+ }
+ return false
+}
+
+function assign_fortress_supply() {
+ let ix = game.assign
+ let ss = FORTRESS_SRC_LIST[ix]
+ let fortress = FORTRESS_HEX_LIST[ix]
+ let base_net = friendly_supply_network()
+
+ // Isolated friendly fortress with capacity!
+ if (!base_net[fortress] && is_fortress_friendly_controlled(fortress) && game.capacity[ix] > 0) {
+ let dist = distance_to[fortress]
+ let list = list_fortress_supply_candidates(fortress)
+ if (auto_assign_fortress_supply(list, fortress, ss, ix)) {
+ return true
+ }
+ }
+
+ return false
+}
+
+const xxx_fortress_supply = {
+ prompt() {
+ let ix = game.assign
+ let ss = FORTRESS_SRC_LIST[ix]
+ let fortress = FORTRESS_HEX_LIST[ix]
+ view.prompt = `Supply Check: Assign fortress supply to ${hex_name[fortress]} (${game.capacity[ix]} capacity left).`
+ if (game.capacity[ix] > 0) {
+ let list = list_fortress_supply_candidates(fortress)
+ if (list.length > 0) {
+ let dist = distance_to[fortress]
+ let d0 = dist[unit_hex(list[0])]
+ for (let u of list)
+ if (dist[unit_hex(u)] === d0)
+ gen_action_unit(u)
+ }
+ }
+ gen_action_next()
+ },
+ unit(who) {
+ let ix = game.assign
+ let ss = FORTRESS_SRC_LIST[ix]
+ push_undo()
+ game.capacity[ix]--
+ set_unit_supply(who, ss)
+ },
+ next() {
+ push_undo()
+ game.assign++
+ resume_fortress_supply()
+ },
+}
+
+states.initial_fortress_supply = xxx_fortress_supply
+states.final_fortress_supply = xxx_fortress_supply
+states.buildup_fortress_supply = xxx_fortress_supply
+
+// === OASIS SUPPLY ===
+
+const OASIS_HEX_LIST = [ JALO_OASIS, JARABUB_OASIS, SIWA_OASIS ]
+
+function resume_oasis_supply() {
+ while (game.assign < 3) {
+ if (assign_oasis_supply())
+ return
+ game.assign++
+ }
+ end_oasis_supply()
+}
+
+function end_oasis_supply() {
+ if (game.state === 'initial_oasis_supply')
+ goto_initial_supply_check_recover()
+ if (game.state === 'final_oasis_supply')
+ goto_final_supply_check_disrupt()
+ if (game.state === 'buildup_oasis_supply')
+ end_buildup_supply_check()
+}
+
+function assign_oasis_supply() {
+ let ix = game.assign
+ if (game.oasis[ix] > 0) {
+ let oasis = OASIS_HEX_LIST[ix]
+ let enemy_battle = is_axis_player() ? game.allied_hexes : game.axis_hexes
+ if (has_friendly_unit(oasis)) {
+ if (!set_has(enemy_battle, oasis)) {
+ let n = count_friendly_units_in_hex(oasis)
+ if (n > 1)
+ return true
+ if (n === 1) {
+ for_each_friendly_unit_in_hex(oasis, u => {
+ game.oasis[ix] = 0
+ set_unit_supply(u, SS_OASIS)
+ })
+ }
+ }
}
+ }
+ return false
+}
+
+const xxx_oasis_supply = {
+ prompt() {
+ let ix = game.assign
+ let oasis = OASIS_HEX_LIST[ix]
+ view.prompt = `Supply Check: Assign oasis supply to ${hex_name[oasis]}.`
+ for_each_friendly_unit_in_hex(oasis, u => {
+ gen_action_unit(u)
+ })
+ },
+ unit(who) {
+ let ix = game.assign
+ push_undo()
+ game.oasis[ix] = 0
+ set_unit_supply(who, SS_OASIS)
+ game.assign++
+ resume_oasis_supply()
+ },
+}
+
+states.initial_oasis_supply = xxx_oasis_supply
+states.final_oasis_supply = xxx_oasis_supply
+states.buildup_oasis_supply = xxx_oasis_supply
+
+// === INITIAL SUPPLY CHECK ===
+
+function goto_initial_supply_check() {
+ let base_net = friendly_supply_network()
+ for_each_friendly_unit_on_map(u => {
+ if (base_net[unit_hex(u)])
+ set_unit_supply(u, SS_BASE)
+ else
+ set_unit_supply(u, SS_NONE)
})
+ if (is_axis_player())
+ game.capacity = [ 1, 1, 2 ]
+ else
+ game.capacity = [ 2, 2, 5 ]
+ game.oasis = [ 1, 1, 1 ]
+
+ game.state = 'initial_fortress_supply'
+ game.assign = 0
+ resume_fortress_supply()
+}
+
+function goto_initial_supply_check_recover() {
+ for (let u of game.recover) {
+ if (is_unit_disrupted(u) && is_unit_supplied(u) && !is_battle_hex(unit_hex(u))) {
+ log(`Recovered at #${unit_hex(u)}`)
+ clear_unit_disrupted(u)
+ }
+ }
+
set_clear(game.recover)
for_each_enemy_unit_on_map(u => {
if (is_unit_disrupted(u))
@@ -1888,6 +2175,8 @@ states.initial_supply_check_rout = {
}
}
+// === FINAL SUPPLY CHECK ===
+
function goto_final_supply_check() {
set_active_player()
@@ -1897,20 +2186,28 @@ function goto_final_supply_check() {
capture_fortress(BENGHAZI, 2)
capture_fortress(TOBRUK, 5)
- let snet = friendly_supply_network()
- let ssrc = friendly_supply_base()
+ game.disrupt = all_friendly_unsupplied_units()
- // TODO: fortress supply
- // TODO: assign unused fortress supply
+ // Now in supply!
+ let base_net = friendly_supply_network()
+ for (let u of game.disrupt) {
+ if (base_net[unit_hex(u)])
+ set_unit_supply(u, SS_BASE)
+ }
- for_each_friendly_unit_on_map(u => {
- let x = unit_hex(u)
- if (!snet[x] && !is_unit_disrupted(u) && !is_unit_supplied(u)) {
- log(`Disrupted at #${x}`)
+ game.state = 'final_fortress_supply'
+ game.assign = 0
+ resume_fortress_supply()
+}
+
+function goto_final_supply_check_disrupt() {
+ for (let u of game.disrupt) {
+ if (!is_unit_disrupted(u) && !is_unit_supplied(u)) {
+ log(`Disrupted at #${unit_hex(u)}`)
set_unit_disrupted(u)
}
- })
-
+ }
+ delete game.disrupt
goto_final_supply_check_rout()
}
@@ -2244,6 +2541,7 @@ states.move = {
}
},
end_move() {
+ push_undo() // XXX
clear_undo()
log_br()
end_movement()
@@ -2554,6 +2852,7 @@ states.forced_marches = {
gen_action_unit(who)
},
unit(who) {
+ push_undo() // XXX
let via = unit_hex(who)
let ix = game.forced.findIndex(item => who === item[0])
let to = game.forced[ix][1]
@@ -2958,7 +3257,6 @@ function end_retreat() {
function end_retreat_2() {
if (can_select_retreat_hex()) {
- console.log("can_select_retreat_hex")
game.state = 'retreat_from'
}
else
@@ -3968,7 +4266,7 @@ function end_rout_fire() {
goto_rout_move()
}
-// === BUILDUP ===
+// === BUILDUP - SUPPLY CHECK ===
function end_month() {
// Forget captured fortresses (for bonus cards)
@@ -3990,6 +4288,7 @@ function goto_buildup() {
}
function goto_buildup_discard() {
+ log_br()
game.state = 'buildup_discard'
let hand = player_hand()
if (hand[REAL] + hand[DUMMY] === 0)
@@ -4012,74 +4311,52 @@ states.buildup_discard = {
},
next() {
clear_undo()
- end_buildup_discard()
+ goto_buildup_supply_check()
},
}
-function end_buildup_discard() {
+function goto_buildup_supply_check() {
+ let base_net = friendly_supply_network()
+ for_each_friendly_unit_on_map(u => {
+ if (base_net[unit_hex(u)])
+ set_unit_supply(u, SS_BASE)
+ else
+ set_unit_supply(u, SS_NONE)
+ })
+
+ if (is_axis_player())
+ game.capacity = [ 1, 1, 2 ]
+ else
+ game.capacity = [ 2, 2, 5 ]
+ game.oasis = [ 1, 1, 1 ]
+
+ game.state = 'buildup_fortress_supply'
+ game.assign = 0
+ resume_fortress_supply()
+}
+
+function end_buildup_supply_check() {
if (is_axis_player()) {
set_enemy_player()
goto_buildup_discard()
} else {
- goto_buildup_supply_check()
- }
-}
-
-function init_buildup() {
- game.buildup = {
- // redeployment network
- axis_network: axis_supply_network().slice(),
- axis_line: axis_supply_line().slice(),
- allied_network: allied_supply_network().slice(),
- allied_line: allied_supply_line().slice(),
-
- // extra cards purchased
- axis_cards: 0,
- allied_cards: 0,
-
- // remaining port capacity for sea redeployment
- bardia: 2,
- benghazi: 2,
- tobruk: 5,
+ set_enemy_player()
+ goto_buildup_supply_check_recover()
}
}
-function goto_buildup_supply_check() {
- // TODO: fortress supply
- // TODO: assign fortress supply
-
- init_buildup()
-
- for_each_axis_unit_on_map(u => {
- let x = unit_hex(u)
- if (supply_axis_network[x])
- set_unit_supply(u, EL_AGHEILA)
- else
- set_unit_supply(u, 0)
- })
-
- for_each_allied_unit_on_map(u => {
- let x = unit_hex(u)
- if (supply_allied_network[x])
- set_unit_supply(u, ALEXANDRIA)
- else
- set_unit_supply(u, 0)
- })
-
- for_each_unit_on_map(u => {
+function goto_buildup_supply_check_recover() {
+ for_each_friendly_unit_on_map(u => {
if (is_unit_supplied(u) && is_unit_disrupted(u) && !is_battle_hex(unit_hex(u))) {
log(`Recovered at #${unit_hex(u)}.`)
clear_unit_disrupted(u)
}
})
-
- log_br()
-
- resume_buildup_eleminate_unsupplied()
+ resume_buildup_eliminate_unsupplied()
}
-function resume_buildup_eleminate_unsupplied() {
- game.state = 'buildup_eleminate_unsupplied'
+function resume_buildup_eliminate_unsupplied() {
+ game.state = 'buildup_eliminate_unsupplied'
let done = true
for_each_friendly_unit_on_map(u => {
if (is_unit_unsupplied(u))
@@ -4087,16 +4364,15 @@ function resume_buildup_eleminate_unsupplied() {
})
if (done) {
if (is_axis_player()) {
- log_br()
set_enemy_player()
- resume_buildup_eleminate_unsupplied()
+ goto_buildup_supply_check_recover()
} else {
goto_buildup_point_determination()
}
}
}
-states.buildup_eleminate_unsupplied = {
+states.buildup_eliminate_unsupplied = {
prompt() {
view.prompt = `Buildup: Eliminate unsupplied units.`
for_each_friendly_unit_on_map(u => {
@@ -4107,19 +4383,44 @@ states.buildup_eleminate_unsupplied = {
unit(u) {
log(`Eliminated at #${unit_hex(u)}`)
eliminate_unit(u)
- resume_buildup_eleminate_unsupplied()
+ resume_buildup_eliminate_unsupplied()
},
}
+// === BUILDUP - POINT DETERMINATION ===
+
+function init_buildup() {
+ game.buildup = {
+ // redeployment network
+ axis_network: union_axis_network(),
+ axis_line: union_axis_line(),
+ allied_network: union_allied_network(),
+ allied_line: union_allied_line(),
+
+ // extra cards purchased
+ axis_cards: 0,
+ allied_cards: 0,
+
+ // remaining port capacity for sea redeployment
+ bardia: 2,
+ benghazi: 2,
+ tobruk: 5,
+ }
+}
+
function goto_buildup_point_determination() {
let axis, allied
+ // take union of supply networks?
+
+ init_buildup()
+
log_br()
if (game.scenario === "1940") {
axis = roll_die()
allied = roll_die()
log(`Axis rolled ${axis}.`)
- log(`Allied rolled ${axis}.`)
+ log(`Allied rolled ${allied}.`)
} else {
let axis_a = roll_die()
let axis_b = roll_die()
@@ -4128,7 +4429,7 @@ function goto_buildup_point_determination() {
axis = axis_a + axis_b
allied = allied_a + allied_b
log(`Axis rolled ${axis_a} + ${axis_b}.`)
- log(`Allied rolled ${axis_a} + ${axis_b}.`)
+ log(`Allied rolled ${allied_a} + ${allied_b}.`)
}
log(`Receive ${axis + allied} BPs.`)
@@ -4148,7 +4449,7 @@ function have_scheduled_reinforcements() {
let refit = friendly_refit()
for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) {
let x = unit_hex(u)
- if (x === refit || x === game.month || x === game.month + 1)
+ if (x === refit || x === hexdeploy + game.month || x === hexdeploy + game.month + 1)
return true
}
}
@@ -4183,11 +4484,13 @@ function apply_reinforcements() {
for_each_friendly_unit_in_hex(friendly_refit(), u => {
set_unit_hex(u, base)
+ set_unit_supply(u, SS_BASE)
refitted++
})
for_each_friendly_unit_in_month(game.month, u => {
set_unit_hex(u, base)
+ set_unit_supply(u, SS_BASE)
scheduled++
})
@@ -4195,6 +4498,7 @@ function apply_reinforcements() {
for_each_friendly_unit_in_month(game.month + 1, u => {
if (roll_die() <= 2) {
set_unit_hex(u, base)
+ set_unit_supply(u, SS_BASE)
early++
}
})
@@ -4265,7 +4569,6 @@ function can_redeploy_from(from) {
function is_controlled_port(where) {
if (where === BARDIA || where === BENGHAZI || where === TOBRUK)
return is_fortress_friendly_controlled(where)
- console.log("not a porT", where)
return true
}
@@ -4627,7 +4930,7 @@ function goto_free_deployment() {
function is_valid_deployment_hex(base, x) {
// we've already seen this hex during a previous supplied hex check this go
- if (supply_net[from] > 0)
+ if (supply_temp_network[x] > 0)
return true
if (can_trace_supply_to_base_or_fortress(base, x))
return true
@@ -4688,6 +4991,7 @@ states.free_deployment = {
push_undo()
log(`Deployed at #${to}.`)
set_unit_hex(who, to)
+ set_unit_supply(who, SS_BASE)
},
next() {
clear_undo()
@@ -4724,6 +5028,7 @@ states.initial_supply_cards = {
gen_action('keep')
},
discard() {
+ push_undo() // XXX
if (is_axis_player()) {
log(`Axis discarded their hand.`)
game.axis_hand[REAL] = 0
@@ -4739,6 +5044,7 @@ states.initial_supply_cards = {
}
},
keep() {
+ push_undo() // XXX
if (is_axis_player())
set_enemy_player()
else
@@ -4769,7 +5075,6 @@ function begin_game() {
// No initiative first month
goto_player_turn()
- // goto_buildup()
}
// === SETUP ===
@@ -4812,6 +5117,7 @@ function setup_units(where, steps, list) {
set_unit_steps(u, unit_start_steps[u] + steps)
else if (steps > 0)
set_unit_steps(u, steps)
+ set_unit_supply(u, SS_BASE)
}
}
@@ -5270,6 +5576,7 @@ exports.setup = function (seed, scenario, options) {
fortress: 7,
axis_award: 0,
allied_award: 0,
+ assign: 0,
// battle hexes (defender)
axis_hexes: [],
@@ -5369,10 +5676,10 @@ exports.query = function (state, current, q) {
}
} else {
return {
- axis_supply: axis_supply_network(),
- axis_supply_line: axis_supply_line(),
- allied_supply: allied_supply_network(),
- allied_supply_line: allied_supply_line(),
+ axis_supply: union_axis_network(),
+ axis_supply_line: union_axis_line(),
+ allied_supply: union_allied_network(),
+ allied_supply_line: union_allied_line(),
}
}
}