Allow selection of auto-assigned mission types.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1176
This commit is contained in:
Dan Albert 2021-06-04 17:50:21 -07:00
parent 8bb1b1da7c
commit a0833e8943
6 changed files with 64 additions and 10 deletions

View File

@ -193,7 +193,7 @@ class ProcurementAi:
continue continue
for squadron in self.air_wing.squadrons_for(unit): for squadron in self.air_wing.squadrons_for(unit):
if task in squadron.mission_types: if task in squadron.auto_assignable_mission_types:
break break
else: else:
continue continue

View File

@ -10,7 +10,6 @@ from pathlib import Path
from typing import ( from typing import (
Type, Type,
Tuple, Tuple,
List,
TYPE_CHECKING, TYPE_CHECKING,
Optional, Optional,
Iterator, Iterator,
@ -82,9 +81,12 @@ class Squadron:
role: str role: str
aircraft: Type[FlyingType] aircraft: Type[FlyingType]
livery: Optional[str] livery: Optional[str]
mission_types: Tuple[FlightType, ...] mission_types: tuple[FlightType, ...]
pilots: List[Pilot] pilots: list[Pilot]
available_pilots: List[Pilot] = field(init=False, hash=False, compare=False) available_pilots: list[Pilot] = field(init=False, hash=False, compare=False)
auto_assignable_mission_types: set[FlightType] = field(
init=False, hash=False, compare=False
)
# We need a reference to the Game so that we can access the Faker without needing to # We need a reference to the Game so that we can access the Faker without needing to
# persist it to the save game, or having to reconstruct it (it's not cheap) each # persist it to the save game, or having to reconstruct it (it's not cheap) each
@ -94,6 +96,7 @@ class Squadron:
def __post_init__(self) -> None: def __post_init__(self) -> None:
self.available_pilots = list(self.active_pilots) self.available_pilots = list(self.active_pilots)
self.auto_assignable_mission_types = set(self.mission_types)
def __str__(self) -> str: def __str__(self) -> str:
return f'{self.name} "{self.nickname}"' return f'{self.name} "{self.nickname}"'
@ -223,6 +226,12 @@ class Squadron:
player=player, player=player,
) )
def __setstate__(self, state) -> None:
# TODO: Remove save compat.
if "auto_assignable_mission_types" not in state:
state["auto_assignable_mission_types"] = set(state["mission_types"])
self.__dict__.update(state)
class SquadronLoader: class SquadronLoader:
def __init__(self, game: Game, player: bool) -> None: def __init__(self, game: Game, player: bool) -> None:

View File

@ -238,7 +238,7 @@ class AirliftPlanner:
for s in self.game.air_wing_for(self.for_player).squadrons_for( for s in self.game.air_wing_for(self.for_player).squadrons_for(
unit_type unit_type
) )
if FlightType.TRANSPORT in s.mission_types if FlightType.TRANSPORT in s.auto_assignable_mission_types
] ]
if not squadrons: if not squadrons:
continue continue

View File

@ -180,7 +180,7 @@ class AircraftAllocator:
# Valid location with enough aircraft available. Find a squadron to fit # Valid location with enough aircraft available. Find a squadron to fit
# the role. # the role.
for squadron in self.air_wing.squadrons_for(aircraft): for squadron in self.air_wing.squadrons_for(aircraft):
if task not in squadron.mission_types: if task not in squadron.auto_assignable_mission_types:
continue continue
if len(squadron.available_pilots) >= flight.num_aircraft: if len(squadron.available_pilots) >= flight.num_aircraft:
inventory.remove_aircraft(aircraft, flight.num_aircraft) inventory.remove_aircraft(aircraft, flight.num_aircraft)
@ -604,7 +604,7 @@ class CoalitionMissionPlanner:
for squadron in self.game.air_wing_for(self.is_player).iter_squadrons(): for squadron in self.game.air_wing_for(self.is_player).iter_squadrons():
if ( if (
squadron.aircraft in all_compatible squadron.aircraft in all_compatible
and mission_type in squadron.mission_types and mission_type in squadron.auto_assignable_mission_types
): ):
return True return True
return False return False

View File

@ -18,7 +18,7 @@ from game.squadrons import Squadron, Pilot
from game.theater.missiontarget import MissionTarget from game.theater.missiontarget import MissionTarget
from game.transfers import TransferOrder from game.transfers import TransferOrder
from gen.ato import AirTaskingOrder, Package from gen.ato import AirTaskingOrder, Package
from gen.flights.flight import Flight from gen.flights.flight import Flight, FlightType
from gen.flights.traveltime import TotEstimator from gen.flights.traveltime import TotEstimator
from qt_ui.uiconstants import AIRCRAFT_ICONS from qt_ui.uiconstants import AIRCRAFT_ICONS
@ -467,6 +467,15 @@ class SquadronModel(QAbstractListModel):
pilot.send_on_leave() pilot.send_on_leave()
self.endResetModel() self.endResetModel()
def is_auto_assignable(self, task: FlightType) -> bool:
return task in self.squadron.auto_assignable_mission_types
def set_auto_assignable(self, task: FlightType, auto_assignable: bool) -> None:
if auto_assignable:
self.squadron.auto_assignable_mission_types.add(task)
else:
self.squadron.auto_assignable_mission_types.remove(task)
class GameModel: class GameModel:
"""A model for the Game object. """A model for the Game object.

View File

@ -1,4 +1,5 @@
import logging import logging
from typing import Callable
from PySide2.QtCore import ( from PySide2.QtCore import (
QItemSelectionModel, QItemSelectionModel,
@ -13,9 +14,13 @@ from PySide2.QtWidgets import (
QVBoxLayout, QVBoxLayout,
QPushButton, QPushButton,
QHBoxLayout, QHBoxLayout,
QGridLayout,
QLabel,
QCheckBox,
) )
from game.squadrons import Pilot from game.squadrons import Pilot
from gen.flights.flight import FlightType
from qt_ui.delegates import TwoColumnRowDelegate from qt_ui.delegates import TwoColumnRowDelegate
from qt_ui.models import SquadronModel from qt_ui.models import SquadronModel
@ -61,6 +66,31 @@ class PilotList(QListView):
self.setSelectionBehavior(QAbstractItemView.SelectItems) self.setSelectionBehavior(QAbstractItemView.SelectItems)
class AutoAssignedTaskControls(QVBoxLayout):
def __init__(self, squadron_model: SquadronModel) -> None:
super().__init__()
self.squadron_model = squadron_model
self.addWidget(QLabel("Auto-assignable mission types"))
def make_callback(toggled_task: FlightType) -> Callable[[bool], None]:
def callback(checked: bool) -> None:
self.on_toggled(toggled_task, checked)
return callback
for task in squadron_model.squadron.mission_types:
checkbox = QCheckBox(text=task.value)
checkbox.setChecked(squadron_model.is_auto_assignable(task))
checkbox.toggled.connect(make_callback(task))
self.addWidget(checkbox)
self.addStretch()
def on_toggled(self, task: FlightType, checked: bool) -> None:
self.squadron_model.set_auto_assignable(task, checked)
class SquadronDialog(QDialog): class SquadronDialog(QDialog):
"""Dialog window showing a squadron.""" """Dialog window showing a squadron."""
@ -75,11 +105,17 @@ class SquadronDialog(QDialog):
layout = QVBoxLayout() layout = QVBoxLayout()
self.setLayout(layout) self.setLayout(layout)
columns = QHBoxLayout()
layout.addLayout(columns)
auto_assigned_tasks = AutoAssignedTaskControls(squadron_model)
columns.addLayout(auto_assigned_tasks)
self.pilot_list = PilotList(squadron_model) self.pilot_list = PilotList(squadron_model)
self.pilot_list.selectionModel().selectionChanged.connect( self.pilot_list.selectionModel().selectionChanged.connect(
self.on_selection_changed self.on_selection_changed
) )
layout.addWidget(self.pilot_list) columns.addWidget(self.pilot_list)
button_panel = QHBoxLayout() button_panel = QHBoxLayout()
button_panel.addStretch() button_panel.addStretch()