diff options
-rw-r--r-- | rules.js | 189 |
1 files changed, 77 insertions, 112 deletions
@@ -1,16 +1,17 @@ "use strict" -// TODO: BLITZ TURN - // TODO: fortress supply // TODO: fortress battles mandatory combat! +// TODO: legal pass withdrawal moves +// TODO: raiders +// TODO: MINEFIELDS // TODO: FORCED MARCHES -// TODO: SUPPLY CARDS (playing and revealing and choosing turn option) +// TODO: SUPPLY COMMITMENT // TODO: BUILDUP +// TODO: setup scenario specials -// TODO: first_friendly_unit / for_each_friendly_unit - +// TODO: clean up "can retreat" checks // TODO: when is "fired" status cleared? // TODO: cache_valid, cache_axis, cache_allied (presence and disruption per hex) @@ -24,51 +25,6 @@ // RULES: disrupted units routed again in second enemy turn, will they still recover? // assume yes, easy to change (remove from game.recover set if routed) -// TODO: check that full retreat of all units is possible for pass regroup moves! -// TODO: pass withdrawal moves must reduce supply net - -// TODO: forced marches (force march at first move, remember where to for later, or separate step) -// TODO: raider - -// unit state: location (8 bits), supply source (3 bits), steps (2 bits), disrupted (1 bit) - -// SEQUENCE -// -------- -// Supply check -// Turn option -// Movement -// declare moves -// normal moves -// rout -// retreats -// declare full/partial retreats -// probe combat -// pursuit fire -// withdraw -// rout -// pursuit fire -// withdraw -// forced marches -// refuse battle -// pursuit fire -// withdraw -// rout -// pursuit fire -// withdraw -// Combat -// declare active -// declare assault -// resolve -// defensive fire -// rout -// offensive fire -// rout -// Blitz Movement -// Blitz Combat -// Final supply check -// rout -// Reveal supply cards -> next player - const max = Math.max const min = Math.min const abs = Math.abs @@ -78,13 +34,35 @@ var after_rout = {} var game = null var view = null -let { all_hexes, hex_exists, hex_road, side_road, side_limit, hex_name, units, regions } = require("./data") +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_friendly_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 : "") @@ -246,6 +224,8 @@ function is_hex_or_adjacent_to(x, where) { // === UNIT STATE === +// location (8 bits), supply source (3 bits), steps lost (2 bits), disrupted (1 bit) + function apply_select(u) { if (game.selected === u) game.selected = -1 @@ -411,18 +391,6 @@ function unit_hp(u) { return unit_steps(u) * unit_hp_per_step(u) } -function is_friendly_unit(u) { - if (game.active === AXIS) - return is_axis_unit(u) - return is_allied_unit(u) -} - -function is_enemy_unit(u) { - if (game.active === ALLIED) - return is_axis_unit(u) - return is_allied_unit(u) -} - function is_friendly_hex(x) { if (game.active === AXIS) return is_axis_hex(x) @@ -571,6 +539,12 @@ function has_unshielded_disrupted_enemy_unit(x) { return has_unshielded_disrupted_allied_unit(x) } +function has_unshielded_disrupted_friendly_unit(x) { + if (game.active === ALLIED) + return has_unshielded_disrupted_allied_unit(x) + return has_unshielded_disrupted_axis_unit(x) +} + function is_overrun_hex(x) { return has_undisrupted_friendly_unit(x) && has_unshielded_disrupted_enemy_unit(x) } @@ -685,66 +659,55 @@ function for_each_allied_unit(fn) { } function for_each_friendly_unit(fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_friendly_unit(u)) - fn(u) + for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) + fn(u) } function for_each_enemy_unit(fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_enemy_unit(u)) - fn(u) + for (let u = first_enemy_unit; u <= last_enemy_unit; ++u) + fn(u) } function for_each_friendly_unit_in_hex(x, fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_friendly_unit(u) && unit_hex(u) === x) + for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) + if (unit_hex(u) === x) fn(u) } function for_each_undisrupted_friendly_unit_in_hex(x, fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_friendly_unit(u) && !is_unit_disrupted(u) && unit_hex(u) === x) + for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) + if (!is_unit_disrupted(u) && unit_hex(u) === x) fn(u) } function for_each_undisrupted_and_unmoved_friendly_unit_in_hex(x, fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_friendly_unit(u) && !is_unit_disrupted(u) && unit_hex(u) === x && !is_unit_moved(u)) + for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) + if (!is_unit_disrupted(u) && unit_hex(u) === x && !is_unit_moved(u)) fn(u) } function has_undisrupted_and_moved_friendly_unit_in_hex(x) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_friendly_unit(u) && !is_unit_disrupted(u) && unit_hex(u) === x && is_unit_moved(u)) + for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) + if (!is_unit_disrupted(u) && unit_hex(u) === x && is_unit_moved(u)) return true } function for_each_undisrupted_friendly_unit_in_hex_or_adjacent(x, fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_friendly_unit(u) && !is_unit_disrupted(u) && is_hex_or_adjacent_to(unit_hex(u), x)) + for (let u = first_friendly_unit; u <= last_friendly_unit; ++u) + if (!is_unit_disrupted(u) && is_hex_or_adjacent_to(unit_hex(u), x)) fn(u) } function for_each_enemy_unit_in_hex(x, fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_enemy_unit(u) && unit_hex(u) === x) + for (let u = first_enemy_unit; u <= last_enemy_unit; ++u) + if (unit_hex(u) === x) fn(u) } function for_each_undisrupted_enemy_unit_in_hex(x, fn) { - // TODO: first/last_enemy_unit - for (let u = 0; u < units.length; ++u) - if (is_enemy_unit(u) && !is_unit_disrupted(u) && unit_hex(u) === x) + for (let u = first_enemy_unit; u <= last_enemy_unit; ++u) + if (!is_unit_disrupted(u) && unit_hex(u) === x) fn(u) } @@ -1361,6 +1324,22 @@ function find_valid_regroup_destinations(from, rommel) { function set_active_player() { game.active = game.phasing + update_aliases() +} + +function set_passive_player() { + if (game.phasing === AXIS) + game.active = ALLIED + else + game.active = AXIS + update_aliases() +} + +function set_enemy_player() { + if (is_active_player()) + set_passive_player() + else + set_active_player() } function is_active_player() { @@ -1379,20 +1358,6 @@ function is_allied_player() { return game.active === ALLIED } -function set_passive_player() { - if (game.phasing === AXIS) - game.active = ALLIED - else - game.active = AXIS -} - -function set_enemy_player() { - if (game.active === AXIS) - game.active = ALLIED - else - game.active = AXIS -} - function end_player_turn() { set_clear(game.partial_retreats) @@ -1740,7 +1705,6 @@ states.regroup_move_destination = { function end_move_phase() { game.side_limit = {} - game.rommel = 0 game.from1 = game.from2 = game.to1 = game.to2 = 0 // TODO: forced marches goto_refuse_battle() @@ -3716,7 +3680,8 @@ function setup(name) { game.tobruk = setup_fortress(scenario, TOBRUK) log_h2("Axis Deployment") - game.active = 'Axis' + game.phasing = AXIS + set_active_player() game.state = 'free_deployment' game.selected = -1 } @@ -3807,7 +3772,7 @@ exports.setup = function (seed, scenario, options) { } exports.view = function(state, current) { - game = state + load_state(state) view = { month: game.month, @@ -3841,7 +3806,7 @@ exports.view = function(state, current) { exports.query = function (state, current, q) { if (q === 'supply') { - game = state + load_state(state) update_supply_networks() return { axis_supply: game.axis_supply, @@ -4051,7 +4016,7 @@ states.game_over = { } exports.resign = function (state, current) { - game = state + load_state(state) if (game.state !== 'game_over') { for (let opponent of exports.roles) { if (opponent !== current) { @@ -4064,7 +4029,7 @@ exports.resign = function (state, current) { } exports.action = function (state, current, action, arg) { - game = state + load_state(state) // Object.seal(game) // XXX: don't allow adding properties let S = states[game.state] if (S && action in S) { |