mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Store the owning coalition in ControlPoint.
This is needed fairly often, and we have a lot of Game being passed around to ControlPoint methods specifically to support this. Just store the owning Coalition directly in the ControlPoint to clean up. I haven't cleaned up *every* API here, but did that aircraft allocations as an example.
This commit is contained in:
parent
74577752e0
commit
4715773bba
@ -105,8 +105,7 @@ class MizCampaignLoader:
|
||||
|
||||
@staticmethod
|
||||
def control_point_from_airport(airport: Airport) -> ControlPoint:
|
||||
cp = Airfield(airport)
|
||||
cp.captured = airport.is_blue()
|
||||
cp = Airfield(airport, starts_blue=airport.is_blue())
|
||||
|
||||
# Use the unlimited aircraft option to determine if an airfield should
|
||||
# be owned by the player when the campaign is "inverted".
|
||||
@ -249,30 +248,38 @@ class MizCampaignLoader:
|
||||
for blue in (False, True):
|
||||
for group in self.off_map_spawns(blue):
|
||||
control_point = OffMapSpawn(
|
||||
next(self.control_point_id), str(group.name), group.position
|
||||
next(self.control_point_id),
|
||||
str(group.name),
|
||||
group.position,
|
||||
starts_blue=blue,
|
||||
)
|
||||
control_point.captured = blue
|
||||
control_point.captured_invert = group.late_activation
|
||||
control_points[control_point.id] = control_point
|
||||
for ship in self.carriers(blue):
|
||||
control_point = Carrier(
|
||||
ship.name, ship.position, next(self.control_point_id)
|
||||
ship.name,
|
||||
ship.position,
|
||||
next(self.control_point_id),
|
||||
starts_blue=blue,
|
||||
)
|
||||
control_point.captured = blue
|
||||
control_point.captured_invert = ship.late_activation
|
||||
control_points[control_point.id] = control_point
|
||||
for ship in self.lhas(blue):
|
||||
control_point = Lha(
|
||||
ship.name, ship.position, next(self.control_point_id)
|
||||
ship.name,
|
||||
ship.position,
|
||||
next(self.control_point_id),
|
||||
starts_blue=blue,
|
||||
)
|
||||
control_point.captured = blue
|
||||
control_point.captured_invert = ship.late_activation
|
||||
control_points[control_point.id] = control_point
|
||||
for fob in self.fobs(blue):
|
||||
control_point = Fob(
|
||||
str(fob.name), fob.position, next(self.control_point_id)
|
||||
str(fob.name),
|
||||
fob.position,
|
||||
next(self.control_point_id),
|
||||
starts_blue=blue,
|
||||
)
|
||||
control_point.captured = blue
|
||||
control_point.captured_invert = fob.late_activation
|
||||
control_points[control_point.id] = control_point
|
||||
|
||||
|
||||
@ -157,10 +157,7 @@ class ObjectiveFinder:
|
||||
for control_point in self.enemy_control_points():
|
||||
if not isinstance(control_point, Airfield):
|
||||
continue
|
||||
if (
|
||||
control_point.allocated_aircraft(self.game).total_present
|
||||
>= min_aircraft
|
||||
):
|
||||
if control_point.allocated_aircraft().total_present >= min_aircraft:
|
||||
airfields.append(control_point)
|
||||
return self._targets_by_range(airfields)
|
||||
|
||||
|
||||
@ -123,6 +123,9 @@ class Game:
|
||||
self.blue.set_opponent(self.red)
|
||||
self.red.set_opponent(self.blue)
|
||||
|
||||
for control_point in self.theater.controlpoints:
|
||||
control_point.finish_init(self)
|
||||
|
||||
self.blue.configure_default_air_wing(air_wing_config)
|
||||
self.red.configure_default_air_wing(air_wing_config)
|
||||
|
||||
|
||||
@ -74,7 +74,7 @@ class ProcurementAi:
|
||||
self.game.coalition_for(self.is_player).transfers
|
||||
)
|
||||
armor_investment += cp_ground_units.total_value
|
||||
cp_aircraft = cp.allocated_aircraft(self.game)
|
||||
cp_aircraft = cp.allocated_aircraft()
|
||||
aircraft_investment += cp_aircraft.total_value
|
||||
|
||||
total_investment = aircraft_investment + armor_investment
|
||||
@ -252,7 +252,7 @@ class ProcurementAi:
|
||||
for cp in distance_cache.operational_airfields:
|
||||
if not cp.is_friendly(self.is_player):
|
||||
continue
|
||||
if cp.unclaimed_parking(self.game) < request.number:
|
||||
if cp.unclaimed_parking() < request.number:
|
||||
continue
|
||||
if self.threat_zones.threatened(cp.position):
|
||||
threatened.append(cp)
|
||||
|
||||
@ -92,12 +92,9 @@ class PurchaseAdapter(Generic[ItemType]):
|
||||
|
||||
|
||||
class AircraftPurchaseAdapter(PurchaseAdapter[Squadron]):
|
||||
def __init__(
|
||||
self, control_point: ControlPoint, coalition: Coalition, game: Game
|
||||
) -> None:
|
||||
super().__init__(coalition)
|
||||
def __init__(self, control_point: ControlPoint) -> None:
|
||||
super().__init__(control_point.coalition)
|
||||
self.control_point = control_point
|
||||
self.game = game
|
||||
|
||||
def pending_delivery_quantity(self, item: Squadron) -> int:
|
||||
return item.pending_deliveries
|
||||
@ -106,10 +103,7 @@ class AircraftPurchaseAdapter(PurchaseAdapter[Squadron]):
|
||||
return item.owned_aircraft
|
||||
|
||||
def can_buy(self, item: Squadron) -> bool:
|
||||
return (
|
||||
super().can_buy(item)
|
||||
and self.control_point.unclaimed_parking(self.game) > 0
|
||||
)
|
||||
return super().can_buy(item) and self.control_point.unclaimed_parking() > 0
|
||||
|
||||
def can_sell(self, item: Squadron) -> bool:
|
||||
return item.untasked_aircraft > 0
|
||||
|
||||
@ -55,6 +55,7 @@ if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from gen.flights.flight import FlightType
|
||||
from game.squadrons.squadron import Squadron
|
||||
from ..coalition import Coalition
|
||||
from ..transfers import PendingTransfers
|
||||
|
||||
FREE_FRONTLINE_UNIT_SUPPLY: int = 15
|
||||
@ -280,7 +281,6 @@ class ControlPoint(MissionTarget, ABC):
|
||||
position = None # type: Point
|
||||
name = None # type: str
|
||||
|
||||
captured = False
|
||||
has_frontline = True
|
||||
|
||||
alt = 0
|
||||
@ -294,6 +294,7 @@ class ControlPoint(MissionTarget, ABC):
|
||||
name: str,
|
||||
position: Point,
|
||||
at: db.StartingPosition,
|
||||
starts_blue: bool,
|
||||
has_frontline: bool = True,
|
||||
cptype: ControlPointType = ControlPointType.AIRBASE,
|
||||
) -> None:
|
||||
@ -302,11 +303,12 @@ class ControlPoint(MissionTarget, ABC):
|
||||
self.id = cp_id
|
||||
self.full_name = name
|
||||
self.at = at
|
||||
self.starts_blue = starts_blue
|
||||
self.connected_objectives: List[TheaterGroundObject[Any]] = []
|
||||
self.preset_locations = PresetLocations()
|
||||
self.helipads: List[PointWithHeading] = []
|
||||
|
||||
self.captured = False
|
||||
self._coalition: Optional[Coalition] = None
|
||||
self.captured_invert = False
|
||||
# TODO: Should be Airbase specific.
|
||||
self.has_frontline = has_frontline
|
||||
@ -328,6 +330,20 @@ class ControlPoint(MissionTarget, ABC):
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.__class__}: {self.name}>"
|
||||
|
||||
@property
|
||||
def coalition(self) -> Coalition:
|
||||
if self._coalition is None:
|
||||
raise RuntimeError("ControlPoint not fully initialized: coalition not set")
|
||||
return self._coalition
|
||||
|
||||
def finish_init(self, game: Game) -> None:
|
||||
assert self._coalition is None
|
||||
self._coalition = game.coalition_for(self.starts_blue)
|
||||
|
||||
@property
|
||||
def captured(self) -> bool:
|
||||
return self.coalition.player
|
||||
|
||||
@property
|
||||
def ground_objects(self) -> List[TheaterGroundObject[Any]]:
|
||||
return list(self.connected_objectives)
|
||||
@ -561,7 +577,7 @@ class ControlPoint(MissionTarget, ABC):
|
||||
)
|
||||
|
||||
def aircraft_retreat_destination(
|
||||
self, game: Game, airframe: AircraftType
|
||||
self, airframe: AircraftType
|
||||
) -> Optional[ControlPoint]:
|
||||
closest = ObjectiveDistanceCache.get_closest_airfields(self)
|
||||
# TODO: Should be airframe dependent.
|
||||
@ -574,7 +590,7 @@ class ControlPoint(MissionTarget, ABC):
|
||||
continue
|
||||
if airbase.captured != self.captured:
|
||||
continue
|
||||
if airbase.unclaimed_parking(game) > 0:
|
||||
if airbase.unclaimed_parking() > 0:
|
||||
return airbase
|
||||
return None
|
||||
|
||||
@ -594,27 +610,23 @@ class ControlPoint(MissionTarget, ABC):
|
||||
|
||||
# TODO: Should be Airbase specific.
|
||||
def capture(self, game: Game, for_player: bool) -> None:
|
||||
coalition = game.coalition_for(for_player)
|
||||
self.ground_unit_orders.refund_all(coalition)
|
||||
new_coalition = game.coalition_for(for_player)
|
||||
self.ground_unit_orders.refund_all(self.coalition)
|
||||
for squadron in self.squadrons:
|
||||
squadron.refund_orders()
|
||||
self.retreat_ground_units(game)
|
||||
self.retreat_air_units(game)
|
||||
self.depopulate_uncapturable_tgos()
|
||||
|
||||
if for_player:
|
||||
self.captured = True
|
||||
else:
|
||||
self.captured = False
|
||||
|
||||
self._coalition = new_coalition
|
||||
self.base.set_strength_to_minimum()
|
||||
|
||||
@abstractmethod
|
||||
def can_operate(self, aircraft: AircraftType) -> bool:
|
||||
...
|
||||
|
||||
def unclaimed_parking(self, game: Game) -> int:
|
||||
return self.total_aircraft_parking - self.allocated_aircraft(game).total
|
||||
def unclaimed_parking(self) -> int:
|
||||
return self.total_aircraft_parking - self.allocated_aircraft().total
|
||||
|
||||
@abstractmethod
|
||||
def active_runway(
|
||||
@ -666,7 +678,7 @@ class ControlPoint(MissionTarget, ABC):
|
||||
u.position.x = u.position.x + delta.x
|
||||
u.position.y = u.position.y + delta.y
|
||||
|
||||
def allocated_aircraft(self, _game: Game) -> AircraftAllocations:
|
||||
def allocated_aircraft(self) -> AircraftAllocations:
|
||||
present: dict[AircraftType, int] = defaultdict(int)
|
||||
on_order: dict[AircraftType, int] = defaultdict(int)
|
||||
for squadron in self.squadrons:
|
||||
@ -771,13 +783,14 @@ class ControlPoint(MissionTarget, ABC):
|
||||
|
||||
|
||||
class Airfield(ControlPoint):
|
||||
def __init__(self, airport: Airport, has_frontline: bool = True) -> None:
|
||||
def __init__(self, airport: Airport, starts_blue: bool) -> None:
|
||||
super().__init__(
|
||||
airport.id,
|
||||
airport.name,
|
||||
airport.position,
|
||||
airport,
|
||||
has_frontline,
|
||||
starts_blue,
|
||||
has_frontline=True,
|
||||
cptype=ControlPointType.AIRBASE,
|
||||
)
|
||||
self.airport = airport
|
||||
@ -941,12 +954,13 @@ class NavalControlPoint(ControlPoint, ABC):
|
||||
|
||||
|
||||
class Carrier(NavalControlPoint):
|
||||
def __init__(self, name: str, at: Point, cp_id: int):
|
||||
def __init__(self, name: str, at: Point, cp_id: int, starts_blue: bool):
|
||||
super().__init__(
|
||||
cp_id,
|
||||
name,
|
||||
at,
|
||||
at,
|
||||
starts_blue,
|
||||
has_frontline=False,
|
||||
cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP,
|
||||
)
|
||||
@ -981,12 +995,13 @@ class Carrier(NavalControlPoint):
|
||||
|
||||
|
||||
class Lha(NavalControlPoint):
|
||||
def __init__(self, name: str, at: Point, cp_id: int):
|
||||
def __init__(self, name: str, at: Point, cp_id: int, starts_blue: bool):
|
||||
super().__init__(
|
||||
cp_id,
|
||||
name,
|
||||
at,
|
||||
at,
|
||||
starts_blue,
|
||||
has_frontline=False,
|
||||
cptype=ControlPointType.LHA_GROUP,
|
||||
)
|
||||
@ -1014,12 +1029,13 @@ class OffMapSpawn(ControlPoint):
|
||||
def runway_is_operational(self) -> bool:
|
||||
return True
|
||||
|
||||
def __init__(self, cp_id: int, name: str, position: Point):
|
||||
def __init__(self, cp_id: int, name: str, position: Point, starts_blue: bool):
|
||||
super().__init__(
|
||||
cp_id,
|
||||
name,
|
||||
position,
|
||||
at=position,
|
||||
position,
|
||||
starts_blue,
|
||||
has_frontline=False,
|
||||
cptype=ControlPointType.OFF_MAP,
|
||||
)
|
||||
@ -1067,12 +1083,13 @@ class OffMapSpawn(ControlPoint):
|
||||
|
||||
|
||||
class Fob(ControlPoint):
|
||||
def __init__(self, name: str, at: Point, cp_id: int):
|
||||
def __init__(self, name: str, at: Point, cp_id: int, starts_blue: bool):
|
||||
super().__init__(
|
||||
cp_id,
|
||||
name,
|
||||
at,
|
||||
at,
|
||||
starts_blue,
|
||||
has_frontline=True,
|
||||
cptype=ControlPointType.FOB,
|
||||
)
|
||||
|
||||
@ -8,8 +8,6 @@ from datetime import datetime
|
||||
from typing import Any, Dict, Iterable, List, Set
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.task import CAP, CAS, PinpointStrike
|
||||
from dcs.vehicles import AirDefence
|
||||
|
||||
from game import Game
|
||||
from game.factions.faction import Faction
|
||||
@ -30,7 +28,6 @@ from game.theater.theatergroundobject import (
|
||||
)
|
||||
from game.utils import Heading
|
||||
from game.version import VERSION
|
||||
from gen.naming import namegen
|
||||
from gen.coastal.coastal_group_generator import generate_coastal_group
|
||||
from gen.defenses.armor_group_generator import generate_armor_group
|
||||
from gen.fleet.ship_group_generator import (
|
||||
@ -39,6 +36,7 @@ from gen.fleet.ship_group_generator import (
|
||||
generate_ship_group,
|
||||
)
|
||||
from gen.missiles.missiles_group_generator import generate_missile_group
|
||||
from gen.naming import namegen
|
||||
from gen.sam.airdefensegroupgenerator import AirDefenseRange
|
||||
from gen.sam.ewr_group_generator import generate_ewr_group
|
||||
from gen.sam.sam_group_generator import generate_anti_air_group
|
||||
@ -61,7 +59,6 @@ class GeneratorSettings:
|
||||
start_date: datetime
|
||||
player_budget: int
|
||||
enemy_budget: int
|
||||
midgame: bool
|
||||
inverted: bool
|
||||
no_carrier: bool
|
||||
no_lha: bool
|
||||
@ -121,11 +118,6 @@ class GameGenerator:
|
||||
|
||||
def prepare_theater(self) -> None:
|
||||
to_remove: List[ControlPoint] = []
|
||||
# Auto-capture half the bases if midgame.
|
||||
if self.generator_settings.midgame:
|
||||
control_points = self.theater.controlpoints
|
||||
for control_point in control_points[: len(control_points) // 2]:
|
||||
control_point.captured = True
|
||||
|
||||
# Remove carrier and lha, invert situation if needed
|
||||
for cp in self.theater.controlpoints:
|
||||
@ -135,21 +127,12 @@ class GameGenerator:
|
||||
to_remove.append(cp)
|
||||
|
||||
if self.generator_settings.inverted:
|
||||
cp.captured = cp.captured_invert
|
||||
cp.starts_blue = cp.captured_invert
|
||||
|
||||
# do remove
|
||||
for cp in to_remove:
|
||||
self.theater.controlpoints.remove(cp)
|
||||
|
||||
# TODO: Fix this. This captures all bases for blue.
|
||||
# reapply midgame inverted if needed
|
||||
if self.generator_settings.midgame and self.generator_settings.inverted:
|
||||
for i, cp in enumerate(reversed(self.theater.controlpoints)):
|
||||
if i > len(self.theater.controlpoints):
|
||||
break
|
||||
else:
|
||||
cp.captured = True
|
||||
|
||||
|
||||
class ControlPointGroundObjectGenerator:
|
||||
def __init__(
|
||||
|
||||
@ -752,7 +752,7 @@ class PendingTransfers:
|
||||
)
|
||||
|
||||
def order_airlift_assets_at(self, control_point: ControlPoint) -> None:
|
||||
unclaimed_parking = control_point.unclaimed_parking(self.game)
|
||||
unclaimed_parking = control_point.unclaimed_parking()
|
||||
# Buy a maximum of unclaimed_parking only to prevent that aircraft procurement
|
||||
# take place at another base
|
||||
gap = min(
|
||||
|
||||
@ -252,7 +252,6 @@ def create_game(
|
||||
start_date=start_date,
|
||||
player_budget=DEFAULT_BUDGET,
|
||||
enemy_budget=DEFAULT_BUDGET,
|
||||
midgame=False,
|
||||
inverted=inverted,
|
||||
no_carrier=False,
|
||||
no_lha=False,
|
||||
|
||||
@ -190,7 +190,7 @@ class QBaseMenu2(QDialog):
|
||||
self.repair_button.setDisabled(True)
|
||||
|
||||
def update_intel_summary(self) -> None:
|
||||
aircraft = self.cp.allocated_aircraft(self.game_model.game).total_present
|
||||
aircraft = self.cp.allocated_aircraft().total_present
|
||||
parking = self.cp.total_aircraft_parking
|
||||
ground_unit_limit = self.cp.frontline_unit_count_limit
|
||||
deployable_unit_info = ""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from PySide2.QtWidgets import QTabWidget
|
||||
|
||||
from game.theater import ControlPoint, OffMapSpawn, Fob
|
||||
from game.theater import ControlPoint, Fob
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.DepartingConvoysMenu import DepartingConvoysMenu
|
||||
from qt_ui.windows.basemenu.airfield.QAirfieldCommand import QAirfieldCommand
|
||||
@ -13,7 +13,7 @@ class QBaseMenuTabs(QTabWidget):
|
||||
super(QBaseMenuTabs, self).__init__()
|
||||
|
||||
if not cp.captured:
|
||||
self.intel = QIntelInfo(cp, game_model.game)
|
||||
self.intel = QIntelInfo(cp)
|
||||
self.addTab(self.intel, "Intel")
|
||||
|
||||
self.departing_convoys = DepartingConvoysMenu(cp, game_model)
|
||||
|
||||
@ -21,12 +21,7 @@ from game.purchaseadapter import AircraftPurchaseAdapter
|
||||
|
||||
class QAircraftRecruitmentMenu(UnitTransactionFrame[Squadron]):
|
||||
def __init__(self, cp: ControlPoint, game_model: GameModel) -> None:
|
||||
super().__init__(
|
||||
game_model,
|
||||
AircraftPurchaseAdapter(
|
||||
cp, game_model.game.coalition_for(cp.captured), game_model.game
|
||||
),
|
||||
)
|
||||
super().__init__(game_model, AircraftPurchaseAdapter(cp))
|
||||
self.cp = cp
|
||||
self.game_model = game_model
|
||||
self.purchase_groups = {}
|
||||
@ -96,7 +91,7 @@ class QHangarStatus(QHBoxLayout):
|
||||
self.setAlignment(Qt.AlignLeft)
|
||||
|
||||
def update_label(self) -> None:
|
||||
next_turn = self.control_point.allocated_aircraft(self.game_model.game)
|
||||
next_turn = self.control_point.allocated_aircraft()
|
||||
max_amount = self.control_point.total_aircraft_parking
|
||||
|
||||
components = [f"{next_turn.total_present} present"]
|
||||
|
||||
@ -11,22 +11,20 @@ from PySide2.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game import Game
|
||||
from game.theater import ControlPoint
|
||||
|
||||
|
||||
class QIntelInfo(QFrame):
|
||||
def __init__(self, cp: ControlPoint, game: Game):
|
||||
def __init__(self, cp: ControlPoint):
|
||||
super(QIntelInfo, self).__init__()
|
||||
self.cp = cp
|
||||
self.game = game
|
||||
|
||||
layout = QVBoxLayout()
|
||||
scroll_content = QWidget()
|
||||
intel_layout = QVBoxLayout()
|
||||
|
||||
units_by_task: dict[str, dict[str, int]] = defaultdict(lambda: defaultdict(int))
|
||||
for unit_type, count in self.cp.allocated_aircraft(game).present.items():
|
||||
for unit_type, count in self.cp.allocated_aircraft().present.items():
|
||||
if count:
|
||||
task_type = unit_type.dcs_unit_type.task_default.name
|
||||
units_by_task[task_type][unit_type.name] += count
|
||||
|
||||
@ -77,7 +77,7 @@ class AircraftIntelLayout(IntelTableLayout):
|
||||
|
||||
total = 0
|
||||
for control_point in game.theater.control_points_for(player):
|
||||
allocation = control_point.allocated_aircraft(game)
|
||||
allocation = control_point.allocated_aircraft()
|
||||
base_total = allocation.total_present
|
||||
total += base_total
|
||||
if not base_total:
|
||||
|
||||
@ -94,7 +94,6 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
enemy_budget=int(self.field("enemy_starting_money")),
|
||||
# QSlider forces integers, so we use 1 to 50 and divide by 10 to
|
||||
# give 0.1 to 5.0.
|
||||
midgame=False,
|
||||
inverted=self.field("invertMap"),
|
||||
no_carrier=self.field("no_carrier"),
|
||||
no_lha=self.field("no_lha"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user