diff --git a/changelog.md b/changelog.md index bc6c15fa..f0358c0f 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,7 @@ Saves from 2.5 are not compatible with 3.0. * **[Campaign]** Ground units must now be recruited at a base with a factory and transferred to their destination. When buying units in the UI, the purchase will automatically be fulfilled at the closest factory, and a transfer will be created on the next turn. * **[Campaign]** Non-control point FOBs will no longer spawn. * **[Campaign]** Added squadrons and pilots. See https://github.com/dcs-liberation/dcs_liberation/wiki/Squadrons-and-pilots for more information. +* **[Campaign]** Capturing a base now depopulates all of its attached objectives with units: air defenses, EWRs, ships, armor groups, etc. Buildings are captured. * **[Campaign AI]** AI now considers Ju-88s for CAS, strike, and DEAD missions. * **[Campaign AI]** AI planned AEW&C missions will now be scheduled ASAP. * **[Campaign AI]** AI now considers the range to the SAM's threat zone rather than the range to the SAM itself when determining target priorities. diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py index adedb330..999f4968 100644 --- a/game/theater/controlpoint.py +++ b/game/theater/controlpoint.py @@ -554,11 +554,17 @@ class ControlPoint(MissionTarget, ABC): airframe, count = self.base.aircraft.popitem() self._retreat_air_units(game, airframe, count) + def depopulate_uncapturable_tgos(self) -> None: + for tgo in self.connected_objectives: + if not tgo.capturable: + tgo.clear() + # TODO: Should be Airbase specific. def capture(self, game: Game, for_player: bool) -> None: self.pending_unit_deliveries.refund_all(game) self.retreat_ground_units(game) self.retreat_air_units(game) + self.depopulate_uncapturable_tgos() if for_player: self.captured = True diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py index 27c9d202..99d4a9cf 100644 --- a/game/theater/theatergroundobject.py +++ b/game/theater/theatergroundobject.py @@ -190,6 +190,13 @@ class TheaterGroundObject(MissionTarget): def strike_targets(self) -> List[Union[MissionTarget, Unit]]: return self.units + def clear(self) -> None: + self.groups = [] + + @property + def capturable(self) -> bool: + raise NotImplementedError + class BuildingGroundObject(TheaterGroundObject): def __init__( @@ -251,6 +258,10 @@ class BuildingGroundObject(TheaterGroundObject): def is_control_point(self) -> bool: return self.is_fob_structure + @property + def capturable(self) -> bool: + return True + class SceneryGroundObject(BuildingGroundObject): def __init__( @@ -322,6 +333,10 @@ class NavalGroundObject(TheaterGroundObject): def might_have_aa(self) -> bool: return True + @property + def capturable(self) -> bool: + return False + class GenericCarrierGroundObject(NavalGroundObject): @property @@ -386,6 +401,10 @@ class MissileSiteGroundObject(TheaterGroundObject): sea_object=False, ) + @property + def capturable(self) -> bool: + return False + class CoastalSiteGroundObject(TheaterGroundObject): def __init__( @@ -407,6 +426,10 @@ class CoastalSiteGroundObject(TheaterGroundObject): sea_object=False, ) + @property + def capturable(self) -> bool: + return False + # TODO: Differentiate types. # This type gets used both for AA sites (SAM, AAA, or SHORAD). These should each @@ -486,6 +509,10 @@ class SamGroundObject(TheaterGroundObject): else: return max(max_tel_range, max_telar_range, max_non_radar) + @property + def capturable(self) -> bool: + return False + class VehicleGroupGroundObject(TheaterGroundObject): def __init__( @@ -506,6 +533,10 @@ class VehicleGroupGroundObject(TheaterGroundObject): sea_object=False, ) + @property + def capturable(self) -> bool: + return False + class EwrGroundObject(TheaterGroundObject): def __init__( @@ -542,6 +573,10 @@ class EwrGroundObject(TheaterGroundObject): def might_have_aa(self) -> bool: return True + @property + def capturable(self) -> bool: + return False + class ShipGroundObject(NavalGroundObject): def __init__(