diff options
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 183 |
1 files changed, 149 insertions, 34 deletions
@@ -1445,7 +1445,6 @@ function tobruk_supply_network() { } function unit_supply_line(who) { - // 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() @@ -1457,7 +1456,6 @@ function unit_supply_line(who) { } function unit_supply_distance(who) { - // 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] @@ -1480,6 +1478,32 @@ function friendly_supply_network() { return allied_supply_network() } +function query_friendly_supply_network(x, y) { + // TODO: fortress supply + let save_x + let save_y + if (is_axis_player()) { + init_trace_supply(supply_temp_network, supply_temp_line, AXIS) + if (x) save_x = presence_axis[x] + if (y) save_y = presence_axis[y] + if (x) presence_axis[x] = 0 + if (y) presence_axis[y] = 1 + trace_supply_network(EL_AGHEILA) + if (x) presence_axis[x] = save_x + if (y) presence_axis[y] = save_y + } else { + init_trace_supply(supply_temp_network, supply_temp_line, ALLIED) + if (x) save_x = presence_allied[x] + if (y) save_y = presence_allied[y] + if (x) presence_allied[x] = 0 + if (y) presence_allied[y] = 1 + trace_supply_network(ALEXANDRIA) + if (x) presence_allied[x] = save_x + if (y) presence_allied[y] = save_y + } + return supply_temp_network +} + // === PATHING === const path_from = [ new Array(hexcount), new Array(hexcount), new Array(hexcount), null, new Array(hexcount) ] @@ -1762,6 +1786,41 @@ function find_valid_regroup_destinations(from, rommel) { } } +// === WITHDRAWAL CHECKS === + +function is_network_reduced(reference, candidate) { + for (let x = first_hex; x <= last_hex; ++x) + if (reference[x] - candidate[x] === 1) + return true + return false +} + +function is_legal_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 + } + return false +} + +function is_legal_withdrawal_to(from, to) { + if (is_battle_hex(from)) { + return true + } else { + let ref_net = friendly_supply_network() + let new_net = query_friendly_supply_network(from, to) + if (is_network_reduced(ref_net, new_net)) + return true + } + return false +} + // === MINEFIELDS === function visit_hex(x) { @@ -2359,8 +2418,7 @@ states.select_moves = { view.prompt = `Designate ${game.turn_option} move.` } gen_action('group') - if (game.turn_option !== 'pass') - gen_action('regroup') // TODO: needs work... + gen_action('regroup') if (game.turn_option === 'pass') gen_action('end_turn') }, @@ -2376,6 +2434,9 @@ states.select_moves = { clear_undo() reveal_visited_minefields() goto_final_supply_check() + }, + confirm_end_turn() { + this.end_turn() } } @@ -2389,15 +2450,36 @@ states.group_move_from = { prompt() { view.prompt = `Group Move: Select hex to move from.` gen_rommel_move() - for (let x of all_hexes) { - if (x === game.from1 && !game.to1) - continue - if (has_undisrupted_friendly_unit(x)) - gen_action_hex(x) - } - if (game.turn_option !== 'pass') + if (game.turn_option !== 'pass') { + for (let x of all_hexes) { + if (x === game.from1 && !game.to1) + continue + if (has_undisrupted_friendly_unit(x)) + gen_action_hex(x) + } if (has_friendly_unit_in_raw_hex(friendly_queue())) gen_action_hex(friendly_queue()) + } else { + // Withdrawal group move + let mandatory = false + if (is_mandatory_combat(BARDIA)) { + gen_action_hex(BARDIA) + mandatory = true + } + if (is_mandatory_combat(BENGHAZI)) { + gen_action_hex(BENGHAZI) + mandatory = true + } + if (is_mandatory_combat(TOBRUK)) { + gen_action_hex(TOBRUK) + mandatory = true + } + if (!mandatory) { + for (let x of all_hexes) + if (has_undisrupted_friendly_unit(x) && is_legal_withdrawal_from(x)) + gen_action_hex(x) + } + } }, rommel() { push_undo() @@ -2432,13 +2514,18 @@ states.regroup_move_command_point = { prompt() { view.prompt = `Regroup Move: Designate the command point hex.` gen_rommel_move() - for (let x of all_hexes) { - if (!is_enemy_hex(x)) { - let n = count_hex_or_adjacent_has_undisrupted_and_unmoved_friendly_unit(x) - // TODO: allow one-hex regroup moves? (failed forced march abuse) - if (n >= 2) - gen_action_hex(x) + if (game.turn_option !== 'pass') { + for (let x of all_hexes) { + if (!is_enemy_hex(x)) { + let n = count_hex_or_adjacent_has_undisrupted_and_unmoved_friendly_unit(x) + // TODO: allow one-hex regroup moves? (failed forced march abuse) + if (n >= 2) + gen_action_hex(x) + } } + } else { + // TODO: Withdrawal regroup moves + view.prompt = "TODO" } }, rommel() { @@ -2604,8 +2691,14 @@ states.move = { if (has_overrun_hex) gen_action('overrun') - else - gen_action('end_move') + else { + if (game.turn_option !== 'pass') { + gen_action('end_move') + } else { + if (!game.to1 && !has_friendly_unit(game.from1)) + gen_action('end_move') + } + } } else { view.prompt = `Move: Select hex to move to.` @@ -2613,12 +2706,13 @@ states.move = { gen_action_unit(game.selected) // Move - if (game.turn_option === 'pass') - search_withdraw(game.selected, 1 + (rommel1 | rommel2)) - else + if (game.turn_option !== 'pass') { search_move(unit_hex(game.selected), unit_speed[game.selected] + 1 + (rommel1 | rommel2)) - - gen_move() + gen_move() + } else { + search_withdraw(game.selected, 1 + rommel1) + gen_withdraw() + } } }, unit(who) { @@ -2722,6 +2816,30 @@ function gen_move() { } } +function gen_withdraw() { + let rommel1 = (game.rommel === 1) ? 1 : 0 + let speed = unit_speed[game.selected] + let from = unit_hex(game.selected) + + 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)) + gen_action_hex(to) + else if (can_move_to(to, speed + 1 + rommel1) && is_legal_withdrawal_to(game.from1, to)) + gen_action_forced_march(to) + } + } + } + + if (game.to1 && is_hex_or_adjacent_to(from, game.from1)) { + if (can_move_to(game.to1, speed + rommel1)) + gen_action_hex(game.to1) + else if (can_move_to(game.to1, speed + 1 + rommel1)) + gen_action_forced_march(game.to1) + } +} + function apply_move(to) { let rommel1 = (game.rommel === 1) ? 1 : 0 let rommel2 = (game.rommel === 2) ? 1 : 0 @@ -3426,7 +3544,7 @@ function end_retreat_2() { function can_select_refuse_battle_hex() { for (let x of game.active_battles) - if (can_all_refuse_battle(x)) + if (can_all_units_disengage_and_withdraw(x)) return true return false } @@ -3440,25 +3558,21 @@ function goto_refuse_battle() { } } -function can_all_refuse_battle(from) { +function can_all_units_disengage_and_withdraw(from) { let result = true for_each_undisrupted_friendly_unit_in_hex(from, u => { - if (result === true && !can_unit_refuse_battle(u)) + if (result === true && !can_unit_disengage_and_withdraw(u)) result = false }) return result } -function can_unit_refuse_battle(who) { - return can_unit_disengage_and_withdraw(who) -} - states.refuse_battle = { inactive: "refuse battle", prompt() { view.prompt = `You may Refuse Battle.` for (let x of game.active_battles) - if (can_all_refuse_battle(x)) + if (can_all_units_disengage_and_withdraw(x)) gen_action_hex(x) gen_action('pass') }, @@ -3538,7 +3652,8 @@ function end_refuse_battle_move_2() { // withdraw by group move // eliminated if cannot -function can_rout_from_hex(from) { +function can_disengage_from(from) { + // TODO: check supply lines too... let n = 0 for_each_adjacent_hex(from, to => { let side = to_side_id(from, to) @@ -3575,7 +3690,7 @@ function goto_rout(from, enemy, after) { set_delete(game.recover, u) }) - if (can_rout_from_hex(from)) + if (can_all_units_disengage_and_withdraw(from)) game.state = 'rout_attrition' else game.state = 'rout_elimination' |