diff --git a/changelog.md b/changelog.md index 0c92026f..5af0e59e 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,8 @@ Saves from 11.x are not compatible with 12.0.0. ## Fixes * **[Campaign]** Fixed double counting of parked aircraft kills when DCS reports multiple kill events. +* **[Campaign]** Fixed error where frontline units are not re-deployed when multiple control points were captured in one turn or when control points are captured "out of order" using air-assault missions. +* **[Cheat Menu]** Re-deploy frontline units when using cheats to capture control points, so that cheats behave the same way as capturing a control point in-mission. * **[UI]** Naval control points (carriers, LHAs) can no longer be moved onto land. diff --git a/game/sim/missionresultsprocessor.py b/game/sim/missionresultsprocessor.py index 54c0a6f7..71a0fd24 100644 --- a/game/sim/missionresultsprocessor.py +++ b/game/sim/missionresultsprocessor.py @@ -320,38 +320,40 @@ class MissionResultsProcessor: """ " Auto redeploy units to newly captured base """ + # Find the set of friendly CPs that can either contribute or receive frontline units + all_ally_connected_cps = cp.transitive_connected_friendly_points() + [cp] - ally_connected_cps = [ - ocp for ocp in cp.connected_points if cp.captured == ocp.captured - ] - enemy_connected_cps = [ - ocp for ocp in cp.connected_points if cp.captured != ocp.captured - ] + # Split into frontline CPs that are connected to enemy CPs and should receive units + # vs. non-frontline CPs that are not connected to enemy CPs and should send units. + frontline_cps = [] + non_frontline_cps = [] + for cp in all_ally_connected_cps: + is_frontline = False + for ocp in cp.connected_points: + if not ocp.captured: + is_frontline = True + break + if is_frontline: + frontline_cps.append(cp) + else: + non_frontline_cps.append(cp) - # If the newly captured cp does not have enemy connected cp, - # then it is not necessary to redeploy frontline units there. - if len(enemy_connected_cps) == 0: + # If there are no frontline CPs, then nothing to do. + if len(frontline_cps) == 0: return - # From each ally cp, send reinforcements - for ally_cp in ally_connected_cps: - self.redeploy_between(cp, ally_cp) + # Equally split between all frontline CPs + move_factor = 1.0 / len(frontline_cps) + for non_frontline_cp in non_frontline_cps: + for frontline_cp in frontline_cps: + self.redeploy_between(frontline_cp, non_frontline_cp, move_factor) - def redeploy_between(self, destination: ControlPoint, source: ControlPoint) -> None: + def redeploy_between( + self, destination: ControlPoint, source: ControlPoint, move_factor: float + ) -> None: total_units_redeployed = 0 moved_units = {} - if source.has_active_frontline or not destination.captured: - # If there are still active front lines to defend at the - # transferring CP we should not transfer all units. - # - # Opfor also does not transfer all of their units. - # TODO: Balance the CPs rather than moving half from everywhere. - move_factor = 0.5 - else: - # Otherwise we can move everything. - move_factor = 1 - for frontline_unit, count in source.base.armor.items(): moved_units[frontline_unit] = int(count * move_factor) total_units_redeployed = total_units_redeployed + int(count * move_factor) diff --git a/qt_ui/windows/basemenu/QBaseMenu2.py b/qt_ui/windows/basemenu/QBaseMenu2.py index f93d33a1..a4a24982 100644 --- a/qt_ui/windows/basemenu/QBaseMenu2.py +++ b/qt_ui/windows/basemenu/QBaseMenu2.py @@ -16,6 +16,7 @@ from game import Game from game.ato.flighttype import FlightType from game.config import RUNWAY_REPAIR_COST from game.server import EventStream +from game.sim.missionresultsprocessor import MissionResultsProcessor from game.theater import ( AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION, ControlPoint, @@ -156,6 +157,9 @@ class QBaseMenu2(QDialog): self.cp.capture( self.game_model.game, events, for_player=not self.cp.captured ) + # Redeploy frontline units, as if the CP capture was done in mission. + results_processor = MissionResultsProcessor(self.game_model.game) + results_processor.redeploy_units(self.cp) self.close() @property