mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Finish implementation of add/remove squadrons from AirWingConfigurationDialog
Users can now add and remove squadrons with specific buttons. this also allows new aircraft types to be added as well. - rebased existing PR to develop - reverted observable and changed to signals - changed the general concept so that changes only affect the ui data model and not the game directly. Game will only be updated on apply - removed unused code - adopt to review comments - allow user to choose a predefined squadron preset (also alow none value to use the random generator) - Reuse the squadron defs from the default assigner in the AirWing class - allow user to re-roll the squadron nickname (also added new ui icons for the button)
This commit is contained in:
@@ -5,10 +5,8 @@ from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from game.squadrons import Squadron
|
||||
from game.squadrons.squadrondef import SquadronDef
|
||||
from game.squadrons.squadrondefloader import SquadronDefLoader
|
||||
from ..ato.flighttype import FlightType
|
||||
from .campaignairwingconfig import CampaignAirWingConfig, SquadronConfig
|
||||
from .squadrondefgenerator import SquadronDefGenerator
|
||||
from ..dcs.aircrafttype import AircraftType
|
||||
from ..theater import ControlPoint
|
||||
|
||||
@@ -25,14 +23,6 @@ class DefaultSquadronAssigner:
|
||||
self.game = game
|
||||
self.coalition = coalition
|
||||
self.air_wing = coalition.air_wing
|
||||
self.squadron_defs = SquadronDefLoader(game, coalition).load()
|
||||
self.squadron_def_generator = SquadronDefGenerator(self.coalition)
|
||||
|
||||
def claim_squadron_def(self, squadron: SquadronDef) -> None:
|
||||
try:
|
||||
self.squadron_defs[squadron.aircraft].remove(squadron)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def assign(self) -> None:
|
||||
for control_point in self.game.theater.control_points_for(
|
||||
@@ -47,7 +37,6 @@ class DefaultSquadronAssigner:
|
||||
)
|
||||
continue
|
||||
|
||||
self.claim_squadron_def(squadron_def)
|
||||
squadron = Squadron.create_from(
|
||||
squadron_def, control_point, self.coalition, self.game
|
||||
)
|
||||
@@ -74,7 +63,7 @@ class DefaultSquadronAssigner:
|
||||
|
||||
# If we can't find any squadron matching the requirement, we should
|
||||
# create one.
|
||||
return self.squadron_def_generator.generate_for_task(
|
||||
return self.air_wing.squadron_def_generator.generate_for_task(
|
||||
config.primary, control_point
|
||||
)
|
||||
|
||||
@@ -105,7 +94,7 @@ class DefaultSquadronAssigner:
|
||||
|
||||
# No premade squadron available for this aircraft that meets the requirements,
|
||||
# so generate one if possible.
|
||||
return self.squadron_def_generator.generate_for_aircraft(aircraft)
|
||||
return self.air_wing.squadron_def_generator.generate_for_aircraft(aircraft)
|
||||
|
||||
@staticmethod
|
||||
def squadron_compatible_with(
|
||||
@@ -121,18 +110,24 @@ class DefaultSquadronAssigner:
|
||||
def find_squadron_for_airframe(
|
||||
self, aircraft: AircraftType, task: FlightType, control_point: ControlPoint
|
||||
) -> Optional[SquadronDef]:
|
||||
for squadron in self.squadron_defs[aircraft]:
|
||||
if self.squadron_compatible_with(squadron, task, control_point):
|
||||
for squadron in self.air_wing.squadron_defs[aircraft]:
|
||||
if not squadron.claimed and self.squadron_compatible_with(
|
||||
squadron, task, control_point
|
||||
):
|
||||
return squadron
|
||||
return None
|
||||
|
||||
def find_squadron_by_name(
|
||||
self, name: str, task: FlightType, control_point: ControlPoint
|
||||
) -> Optional[SquadronDef]:
|
||||
for squadrons in self.squadron_defs.values():
|
||||
for squadrons in self.air_wing.squadron_defs.values():
|
||||
for squadron in squadrons:
|
||||
if squadron.name == name and self.squadron_compatible_with(
|
||||
squadron, task, control_point, ignore_base_preference=True
|
||||
if (
|
||||
not squadron.claimed
|
||||
and squadron.name == name
|
||||
and self.squadron_compatible_with(
|
||||
squadron, task, control_point, ignore_base_preference=True
|
||||
)
|
||||
):
|
||||
return squadron
|
||||
return None
|
||||
@@ -140,8 +135,10 @@ class DefaultSquadronAssigner:
|
||||
def find_squadron_for_task(
|
||||
self, task: FlightType, control_point: ControlPoint
|
||||
) -> Optional[SquadronDef]:
|
||||
for squadrons in self.squadron_defs.values():
|
||||
for squadrons in self.air_wing.squadron_defs.values():
|
||||
for squadron in squadrons:
|
||||
if self.squadron_compatible_with(squadron, task, control_point):
|
||||
if not squadron.claimed and self.squadron_compatible_with(
|
||||
squadron, task, control_point
|
||||
):
|
||||
return squadron
|
||||
return None
|
||||
|
||||
@@ -12,12 +12,12 @@ from gen.flights.ai_flight_planner_db import aircraft_for_task, tasks_for_aircra
|
||||
from game.ato.flighttype import FlightType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.coalition import Coalition
|
||||
from game.factions.faction import Faction
|
||||
|
||||
|
||||
class SquadronDefGenerator:
|
||||
def __init__(self, coalition: Coalition) -> None:
|
||||
self.coalition = coalition
|
||||
def __init__(self, faction: Faction) -> None:
|
||||
self.faction = faction
|
||||
self.count = itertools.count(1)
|
||||
self.used_nicknames: set[str] = set()
|
||||
|
||||
@@ -26,7 +26,7 @@ class SquadronDefGenerator:
|
||||
) -> Optional[SquadronDef]:
|
||||
aircraft_choice: Optional[AircraftType] = None
|
||||
for aircraft in aircraft_for_task(task):
|
||||
if aircraft not in self.coalition.faction.aircrafts:
|
||||
if aircraft not in self.faction.aircrafts:
|
||||
continue
|
||||
if not control_point.can_operate(aircraft):
|
||||
continue
|
||||
@@ -44,7 +44,7 @@ class SquadronDefGenerator:
|
||||
return SquadronDef(
|
||||
name=f"Squadron {next(self.count):03}",
|
||||
nickname=self.random_nickname(),
|
||||
country=self.coalition.country_name,
|
||||
country=self.faction.country,
|
||||
role="Flying Squadron",
|
||||
aircraft=aircraft,
|
||||
livery=None,
|
||||
|
||||
@@ -40,7 +40,7 @@ class Coalition:
|
||||
self.procurement_requests: OrderedSet[AircraftProcurementRequest] = OrderedSet()
|
||||
self.bullseye = Bullseye(Point(0, 0))
|
||||
self.faker = Faker(self.faction.locales)
|
||||
self.air_wing = AirWing(player)
|
||||
self.air_wing = AirWing(player, game, self.faction)
|
||||
self.transfers = PendingTransfers(game, player)
|
||||
|
||||
# Late initialized because the two coalitions in the game are mutually
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
class Event(object):
|
||||
pass
|
||||
|
||||
|
||||
class Observable(object):
|
||||
def __init__(self) -> None:
|
||||
self.callbacks = []
|
||||
|
||||
def subscribe(self, callback) -> None:
|
||||
self.callbacks.append(callback)
|
||||
|
||||
def unsubscribe(self, callback) -> None:
|
||||
self.callbacks.remove(callback)
|
||||
|
||||
def fire(self, **attrs) -> None:
|
||||
e = Event()
|
||||
e.source = self
|
||||
for k, v in attrs.items():
|
||||
setattr(e, k, v)
|
||||
for fn in self.callbacks:
|
||||
fn(e)
|
||||
@@ -7,41 +7,34 @@ from typing import Sequence, Iterator, TYPE_CHECKING, Optional
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from gen.flights.ai_flight_planner_db import aircraft_for_task
|
||||
from gen.flights.closestairfields import ObjectiveDistanceCache
|
||||
from .squadrondef import SquadronDef
|
||||
from .squadrondefloader import SquadronDefLoader
|
||||
from ..campaignloader.squadrondefgenerator import SquadronDefGenerator
|
||||
from ..factions.faction import Faction
|
||||
from ..theater import ControlPoint, MissionTarget
|
||||
|
||||
from ..observer import Observable
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.game import Game
|
||||
from ..ato.flighttype import FlightType
|
||||
from .squadron import Squadron
|
||||
|
||||
|
||||
class AirWing(Observable):
|
||||
def __init__(self, player: bool) -> None:
|
||||
super().__init__()
|
||||
class AirWing:
|
||||
def __init__(self, player: bool, game: Game, faction: Faction) -> None:
|
||||
self.player = player
|
||||
self.squadrons: dict[AircraftType, list[Squadron]] = defaultdict(list)
|
||||
self.squadron_defs = SquadronDefLoader(game, faction).load()
|
||||
self.squadron_def_generator = SquadronDefGenerator(faction)
|
||||
|
||||
def unclaim_squadron_def(self, squadron: Squadron) -> None:
|
||||
if squadron.aircraft in self.squadron_defs:
|
||||
for squadron_def in self.squadron_defs[squadron.aircraft]:
|
||||
if squadron_def.claimed and squadron_def.name == squadron.name:
|
||||
squadron_def.claimed = False
|
||||
|
||||
def add_squadron(self, squadron: Squadron) -> None:
|
||||
new_aircraft_type = squadron.aircraft not in self.squadrons
|
||||
|
||||
self.squadrons[squadron.aircraft].append(squadron)
|
||||
|
||||
if new_aircraft_type:
|
||||
self.fire(type="add_aircraft_type", obj=squadron.aircraft)
|
||||
self.fire(type="add_squadron", obj=squadron)
|
||||
|
||||
def remove_squadron(self, toRemove: Squadron) -> None:
|
||||
if toRemove.aircraft in self.squadrons:
|
||||
self.squadrons[toRemove.aircraft].remove(toRemove)
|
||||
self.fire(type="remove_squadron", obj=toRemove)
|
||||
if len(self.squadrons[toRemove.aircraft]) == 0:
|
||||
self.remove_aircraft_type(toRemove.aircraft)
|
||||
|
||||
def remove_aircraft_type(self, toRemove: AircraftType) -> None:
|
||||
self.squadrons.pop(toRemove)
|
||||
self.fire(type="remove_aircraft_type", obj=toRemove)
|
||||
|
||||
def squadrons_for(self, aircraft: AircraftType) -> Sequence[Squadron]:
|
||||
return self.squadrons[aircraft]
|
||||
|
||||
|
||||
@@ -418,6 +418,7 @@ class Squadron:
|
||||
coalition: Coalition,
|
||||
game: Game,
|
||||
) -> Squadron:
|
||||
squadron_def.claimed = True
|
||||
return Squadron(
|
||||
squadron_def.name,
|
||||
squadron_def.nickname,
|
||||
|
||||
@@ -28,6 +28,7 @@ class SquadronDef:
|
||||
mission_types: tuple[FlightType, ...]
|
||||
operating_bases: OperatingBases
|
||||
pilot_pool: list[Pilot]
|
||||
claimed: bool = False
|
||||
|
||||
auto_assignable_mission_types: set[FlightType] = field(
|
||||
init=False, hash=False, compare=False
|
||||
|
||||
@@ -10,13 +10,13 @@ from .squadrondef import SquadronDef
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.coalition import Coalition
|
||||
from ..factions.faction import Faction
|
||||
|
||||
|
||||
class SquadronDefLoader:
|
||||
def __init__(self, game: Game, coalition: Coalition) -> None:
|
||||
def __init__(self, game: Game, faction: Faction) -> None:
|
||||
self.game = game
|
||||
self.coalition = coalition
|
||||
self.faction = faction
|
||||
|
||||
@staticmethod
|
||||
def squadron_directories() -> Iterator[Path]:
|
||||
@@ -27,8 +27,8 @@ class SquadronDefLoader:
|
||||
|
||||
def load(self) -> dict[AircraftType, list[SquadronDef]]:
|
||||
squadrons: dict[AircraftType, list[SquadronDef]] = defaultdict(list)
|
||||
country = self.coalition.country_name
|
||||
faction = self.coalition.faction
|
||||
country = self.faction.country
|
||||
faction = self.faction
|
||||
any_country = country.startswith("Combined Joint Task Forces ")
|
||||
for directory in self.squadron_directories():
|
||||
for path, squadron_def in self.load_squadrons_from(directory):
|
||||
|
||||
Reference in New Issue
Block a user