summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rules.js141
1 files changed, 114 insertions, 27 deletions
diff --git a/rules.js b/rules.js
index 6dae240..31fc20d 100644
--- a/rules.js
+++ b/rules.js
@@ -1,6 +1,6 @@
"use strict"
-// TODO: legal pass withdrawal moves (reduce supply net, withdraw from fortress attack)
+// TODO: valid pass withdrawal moves (reduce supply net, withdraw from fortress attack)
// TODO: fortress combat in pass turns (must withdraw)
// TODO: log summaries (deploy, rebuild, move, etc)
@@ -1455,6 +1455,17 @@ function unit_supply_line(who) {
return allied_supply_line()
}
+function unit_supply_network(who) {
+ switch (unit_supply(who)) {
+ case SS_BARDIA: return bardia_supply_network()
+ case SS_BENGHAZI: return benghazi_supply_network()
+ case SS_TOBRUK: return tobruk_supply_network()
+ }
+ if (is_axis_unit(who))
+ return axis_supply_network()
+ return allied_supply_network()
+}
+
function unit_supply_distance(who) {
switch (unit_supply(who)) {
case SS_BARDIA: return distance_to[BARDIA]
@@ -1466,6 +1477,17 @@ function unit_supply_distance(who) {
return distance_to[ALEXANDRIA]
}
+function unit_supply_source(who) {
+ switch (unit_supply(who)) {
+ case SS_BARDIA: return BARDIA
+ case SS_BENGHAZI: return BENGHAZI
+ case SS_TOBRUK: return TOBRUK
+ }
+ if (is_axis_unit(who))
+ return EL_AGHEILA
+ return ALEXANDRIA
+}
+
function friendly_supply_base() {
if (is_axis_player())
return EL_AGHEILA
@@ -1478,8 +1500,7 @@ function friendly_supply_network() {
return allied_supply_network()
}
-function query_friendly_supply_network(x, y) {
- // TODO: fortress supply
+function query_friendly_supply_network(src, x, y) {
let save_x
let save_y
if (is_axis_player()) {
@@ -1488,7 +1509,7 @@ function query_friendly_supply_network(x, y) {
if (y) save_y = presence_axis[y]
if (x) presence_axis[x] = 0
if (y) presence_axis[y] = 1
- trace_supply_network(EL_AGHEILA)
+ trace_supply_network(src)
if (x) presence_axis[x] = save_x
if (y) presence_axis[y] = save_y
} else {
@@ -1497,7 +1518,7 @@ function query_friendly_supply_network(x, y) {
if (y) save_y = presence_allied[y]
if (x) presence_allied[x] = 0
if (y) presence_allied[y] = 1
- trace_supply_network(ALEXANDRIA)
+ trace_supply_network(src)
if (x) presence_allied[x] = save_x
if (y) presence_allied[y] = save_y
}
@@ -1795,26 +1816,33 @@ function is_network_reduced(reference, candidate) {
return false
}
-function is_legal_withdrawal_from(x) {
+function is_valid_withdrawal_from(x) {
if (is_battle_hex(x)) {
// can retreat, will always reduce supply network
return can_all_units_disengage_and_withdraw(x);
} else {
// non-retreat withdrawal, check if network is reduced after we leave this hex
- let ref_net = friendly_supply_network()
- let new_net = query_friendly_supply_network(x, 0)
- if (is_network_reduced(ref_net, new_net))
- return true
+ // TODO: mixed supply source in hex (supplied and unsupplied)
+ if (can_all_units_withdraw(x)) {
+ let who = fastest_undisrupted_friendly_unit(x)
+ if (is_unit_supplied(who)) {
+ let ref_net = unit_supply_network(who)
+ let new_net = query_friendly_supply_network(unit_supply_source(who), x, 0)
+ if (is_network_reduced(ref_net, new_net))
+ return true
+ }
+ }
}
return false
}
-function is_legal_withdrawal_to(from, to) {
+function is_valid_withdrawal_group_move(who, from, to) {
+ // TODO: pass actual source instead of sample unit
if (is_battle_hex(from)) {
return true
} else {
- let ref_net = friendly_supply_network()
- let new_net = query_friendly_supply_network(from, to)
+ let ref_net = unit_supply_network(who)
+ let new_net = query_friendly_supply_network(unit_supply_source(who), from, to)
if (is_network_reduced(ref_net, new_net))
return true
}
@@ -2476,7 +2504,7 @@ states.group_move_from = {
}
if (!mandatory) {
for (let x of all_hexes)
- if (has_undisrupted_friendly_unit(x) && is_legal_withdrawal_from(x))
+ if (has_undisrupted_friendly_unit(x) && is_valid_withdrawal_from(x))
gen_action_hex(x)
}
}
@@ -2506,6 +2534,16 @@ states.group_move_from = {
game.state = 'select_moves'
else
goto_move()
+
+ if (game.turn_option === 'pass') {
+ // Precalculate valid withdrawal move destinations here
+ let rommel1 = (game.rommel === 1) ? 1 : 0
+ let who = fastest_undisrupted_friendly_unit(game.from1)
+ console.log("CALC WITHDRAWAL DESTINATIONS")
+ search_withdraw(who, 1 + rommel1)
+ game.withdraw = list_valid_withdrawal_group_moves(who, game.from1, unit_speed[who] + 1 + rommel1)
+ console.log("DONE")
+ }
},
}
@@ -2749,6 +2787,8 @@ states.move = {
push_undo() // XXX
clear_undo()
log_br()
+ if (game.turn_option === 'pass')
+ delete game.withdraw
end_movement()
}
}
@@ -2816,6 +2856,15 @@ function gen_move() {
}
}
+function list_valid_withdrawal_group_moves(who, from, speed) {
+ let result = []
+ for (let to of all_hexes)
+ if (to != from)
+ if (can_move_to(to, speed) && is_valid_withdrawal_group_move(who, game.from1, to))
+ result.push(to)
+ return result
+}
+
function gen_withdraw() {
let rommel1 = (game.rommel === 1) ? 1 : 0
let speed = unit_speed[game.selected]
@@ -2824,9 +2873,9 @@ function gen_withdraw() {
if (!game.to1 && game.from1 === from) {
for (let to of all_hexes) {
if (to != from) {
- if (can_move_to(to, speed + rommel1) && is_legal_withdrawal_to(game.from1, to))
+ if (can_move_to(to, speed + rommel1) && set_has(game.withdraw, to))
gen_action_hex(to)
- else if (can_move_to(to, speed + 1 + rommel1) && is_legal_withdrawal_to(game.from1, to))
+ else if (can_move_to(to, speed + 1 + rommel1) && set_has(game.withdraw, to))
gen_action_forced_march(to)
}
}
@@ -3263,16 +3312,18 @@ function is_enemy_hexside(side) {
}
function can_unit_disengage_and_withdraw(who) {
- let sline = unit_supply_line(who)
- let sdist = unit_supply_distance(who)
- let from = unit_hex(who)
let result = false
- for_each_adjacent_hex(from, to => {
- let side = to_side_id(from, to)
- if (is_friendly_hexside(side) && !has_enemy_unit(to))
- if (sline[side] && sdist[to] <= sdist[from])
- result = true
- })
+ if (is_unit_supplied(who)) {
+ let sline = unit_supply_line(who)
+ let sdist = unit_supply_distance(who)
+ let from = unit_hex(who)
+ for_each_adjacent_hex(from, to => {
+ let side = to_side_id(from, to)
+ if (is_friendly_hexside(side) && !has_enemy_unit(to))
+ if (sline[side] && sdist[to] <= sdist[from])
+ result = true
+ })
+ }
return result
}
@@ -3288,8 +3339,11 @@ function can_unit_disengage_and_move(who) {
}
function can_unit_disengage_and_withdraw_to(who, to, extra) {
- search_withdraw_retreat(who, extra)
- return can_move_to(to, unit_speed[who] + extra)
+ if (is_unit_supplied(who)) {
+ search_withdraw_retreat(who, extra)
+ return can_move_to(to, unit_speed[who] + extra)
+ }
+ return false
}
function can_unit_disengage_and_move_to(who, to, extra) {
@@ -3567,6 +3621,16 @@ function can_all_units_disengage_and_withdraw(from) {
return result
}
+function can_all_units_withdraw(from) {
+ let result = true
+ for_each_undisrupted_friendly_unit_in_hex(from, u => {
+ // No supply line to withdraw along!
+ if (!is_unit_supplied(u))
+ result = false
+ })
+ return result
+}
+
states.refuse_battle = {
inactive: "refuse battle",
prompt() {
@@ -4379,6 +4443,29 @@ function slowest_undisrupted_enemy_unit_speed(where) {
return r
}
+function slowest_undisrupted_friendly_unit_speed(where) {
+ let r = 4
+ for_each_undisrupted_friendly_unit_in_hex(where, u => {
+ let s = unit_speed[u]
+ if (s < r)
+ r = s
+ })
+ return r
+}
+
+function fastest_undisrupted_friendly_unit(where) {
+ let who = -1
+ let r = 0
+ for_each_undisrupted_friendly_unit_in_hex(where, u => {
+ let s = unit_speed[u]
+ if (s > r) {
+ who = u
+ r = s
+ }
+ })
+ return who
+}
+
function goto_rout_fire(where) {
set_enemy_player()
game.hits = 0