diff options
-rw-r--r-- | rules.js | 160 |
1 files changed, 138 insertions, 22 deletions
@@ -1,8 +1,25 @@ "use strict" +// TODO: fortress battles mandatory combat! +// TODO: claim fortress control + +// TODO: FORCED MARCHES +// TODO: BLITZ TURN +// TODO: FINAL SUPPLY CHECK +// TODO: SUPPLY CARDS (playing and revealing and choosing turn option) +// TODO: BUILDUP + // TODO: first_friendly_unit / for_each_friendly_unit -// TODO: be smart about caching update_supply_networks calls +// 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 // 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) @@ -573,7 +590,7 @@ function is_new_battle_hex(a) { } function claim_hexside_control(side) { - if (game.active === AXIS) { + if (is_axis_player()) { set_add(game.axis_sides, side) set_delete(game.allied_sides, side) } else { @@ -598,7 +615,7 @@ function release_hex_control(a) { function claim_hex_control_for_defender(a) { // a new battle hex: claim hex and hexsides for defender - if (game.active === AXIS) + if (is_axis_player()) set_add(game.allied_hexes, a) else set_add(game.axis_hexes, a) @@ -606,7 +623,7 @@ function claim_hex_control_for_defender(a) { for_each_adjacent_hex(a, b => { let side = to_side_id(a, b) if (side_limit[side] > 0) { - if (game.active === AXIS) { + if (is_axis_player()) { if (!set_has(game.axis_sides, side)) set_add(game.allied_sides, side) } else { @@ -617,6 +634,27 @@ function claim_hex_control_for_defender(a) { }) } +function capture_fortress(fortress, capacity, control_prop, captured_prop) { + if (game[control_prop] !== game.active) { + if (has_undisrupted_friendly_unit(fortress) && !has_enemy_unit(fortress)) { + log(`Captured #${fortress}!`) + game[control_prop] = game.active + if (!game[captured_prop]) { + game[captured_prop] = 1 + if (is_axis_player()) { + let award = capacity + log(`Awarded ${award} supply cards.`) + deal_axis_supply_cards(award) + } else { + let award = Math.floor(capacity / 2) + log(`Awarded ${award} supply cards.`) + deal_allied_supply_cards(award) + } + } + } + } +} + // === ITERATORS === function for_each_adjacent_hex(here, fn) { @@ -1124,8 +1162,8 @@ function search_move_retreat(start, speed) { function search_withdraw(start, speed) { update_supply_networks() - let sline = game.active === AXIS ? game.axis_supply_line : game.allied_supply_line - let sdist = game.active === AXIS ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] + let sline = is_axis_player() ? game.axis_supply_line : game.allied_supply_line + let sdist = is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] search_init() search_move_bfs(path_from[0], path_cost[0], start, 0, speed, false, sline, sdist) @@ -1136,8 +1174,8 @@ function search_withdraw(start, speed) { function search_withdraw_retreat(start, speed) { update_supply_networks() - let sline = game.active === AXIS ? game.axis_supply_line : game.allied_supply_line - let sdist = game.active === AXIS ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] + let sline = is_axis_player() ? game.axis_supply_line : game.allied_supply_line + let sdist = is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] search_init() search_move_bfs(path_from[0], path_cost[0], start, 0, speed, true, sline, sdist) @@ -1162,7 +1200,7 @@ function search_init() { // Breadth First Search function search_move_bfs(from, cost, start, road, max_cost, retreat, sline, sdist) { - let friendly_sides = (game.active === AXIS) ? game.axis_sides : game.allied_sides + let friendly_sides = (is_axis_player()) ? game.axis_sides : game.allied_sides from.fill(0) cost.fill(15) @@ -1325,6 +1363,22 @@ function set_active_player() { game.active = game.phasing } +function is_active_player() { + return game.active === game.phasing +} + +function is_passive_player() { + return game.active !== game.phasing +} + +function is_axis_player() { + return game.active === AXIS +} + +function is_allied_player() { + return game.active === ALLIED +} + function set_passive_player() { if (game.phasing === AXIS) game.active = ALLIED @@ -1372,6 +1426,9 @@ function goto_initial_supply_check() { let snet = game.phasing === AXIS ? game.axis_supply : game.allied_supply let ssrc = game.phasing === AXIS ? EL_AGHEILA : ALEXANDRIA + // TODO: fortress supply + // TODO: assign fortress supply + for_each_friendly_unit(u => { let x = unit_hex(u) if (snet[x]) { @@ -1390,9 +1447,40 @@ function goto_initial_supply_check() { set_add(game.recover, u) }) + // TODO: check for enemy routs + goto_turn_option() } +function goto_final_supply_check() { + set_active_player() + + capture_fortress(BARDIA, 2, "bardia", "bardia_captured") + capture_fortress(BENGHAZI, 2, "benghazi", "benghazi_captured") + capture_fortress(TOBRUK, 5, "tobruk", "tobruk_captured") + + update_supply_networks() + let snet = game.phasing === AXIS ? game.axis_supply : game.allied_supply + let ssrc = game.phasing === AXIS ? EL_AGHEILA : ALEXANDRIA + + // TODO: fortress supply + // TODO: assign unused fortress supply + + for_each_friendly_unit(u => { + let x = unit_hex(u) + if (!snet[x]) { + if (!is_unit_disrupted(u) && !is_unit_supplied(u)) { + log(`Disrupted at #${x}`) + set_unit_disrupted(u) + } + } + }) + + // TODO: rout friendly units + + end_player_turn() +} + function goto_turn_option() { game.state = 'turn_option' } @@ -1472,7 +1560,7 @@ states.select_moves = { }, end_turn() { clear_undo() - end_player_turn() + goto_final_supply_check() } } @@ -1951,8 +2039,8 @@ states.retreat_from = { view.prompt = `Retreat: Select hex to retreat from.` update_supply_networks() - let sline = game.active === AXIS ? game.axis_supply_line : game.allied_supply_line - let sdist = game.active === AXIS ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] + let sline = is_axis_player() ? game.axis_supply_line : game.allied_supply_line + let sdist = is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] if (!game.to1 && game.from1) { if (can_retreat_with_group_move(game.from1, sline, sdist)) @@ -2173,8 +2261,8 @@ states.refuse_battle = { view.prompt = `You may Refuse Battle.` update_supply_networks() - let sline = game.active === AXIS ? game.axis_supply_line : game.allied_supply_line - let sdist = game.active === AXIS ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] + let sline = is_axis_player() ? game.axis_supply_line : game.allied_supply_line + let sdist = is_axis_player() ? distance_to[EL_AGHEILA] : distance_to[ALEXANDRIA] for (let x of game.active_battles) if (can_disengage_and_withdraw(x, sline, sdist)) @@ -2459,9 +2547,7 @@ states.select_battle = { function end_combat_phase() { // TODO: blitz - // TODO: final supply check - // TODO: supply cards revealed - end_player_turn() + goto_final_supply_check() } // === BATTLES === @@ -2478,9 +2564,32 @@ function is_unit_retreating(u) { return false } +function is_assault_battle() { + return set_has(game.assault_battles, game.battle) +} + +function is_fortress_defender() { + if ((game.state === 'battle_fire' && is_passive_player()) || (game.state === 'probe_fire' && is_active_player())) { + if (game.battle === BENGHAZI) + return game.benghazi === game.active + if (game.battle === TOBRUK) + return game.tobruk === game.active + if (game.battle === BARDIA) + return game.tobruk === game.active + } + return false +} + function roll_battle_fire(who, tc) { let fc = unit_class(who) let cv = unit_cv(who) + + // Double dice during assault! + if (is_assault_battle()) + cv += cv + else if (fc !== ARMOR && is_fortress_defender()) + cv += cv + console.log("FIRE", unit_name(who), cv) let fp = FIREPOWER_MATRIX[fc][tc] let result = [] @@ -3010,6 +3119,14 @@ function end_rout_fire() { goto_rout_move() } +// === BUILD-UP === + +function end_month() { + delete game.bardia_captured + delete game.benghazi_captured + delete game.tobruk_captured +} + // === DEPLOYMENT === states.free_deployment = { @@ -3053,8 +3170,8 @@ states.free_deployment = { }, next() { clear_undo() - if (game.active === AXIS) { - game.active = ALLIED + if (is_axis_player()) { + set_enemy_player() log_h2("Allied Deployment") } else { end_free_deployment() @@ -3063,8 +3180,8 @@ states.free_deployment = { } function end_free_deployment() { - game.phasing = game.first_player_turn - game.active = game.phasing + game.phasing = AXIS + set_active_player() let scenario = SCENARIOS[game.scenario] deal_axis_supply_cards(scenario.axis_initial_supply) @@ -3546,7 +3663,6 @@ exports.setup = function (seed, scenario, options) { scenario: scenario, month: 0, - first_player_turn: AXIS, draw_pile: [ DUMMY_SUPPLY_COUNT, REAL_SUPPLY_COUNT ], axis_hand: [ 0, 0 ], |