Example #1
0
    def __init__(self, game: Game, package: Package, parent=None) -> None:
        super().__init__(parent=parent)

        self.game = game
        self.package = package

        self.setWindowTitle("Create flight")
        self.setWindowIcon(EVENT_ICONS["strike"])

        layout = QVBoxLayout()

        self.task_selector = QFlightTypeComboBox(self.game.theater,
                                                 package.target)
        self.task_selector.setCurrentIndex(0)
        layout.addLayout(QLabeledWidget("Task:", self.task_selector))

        self.aircraft_selector = QAircraftTypeSelector(
            self.game.aircraft_inventory.available_types_for_player)
        self.aircraft_selector.setCurrentIndex(0)
        self.aircraft_selector.currentIndexChanged.connect(
            self.on_aircraft_changed)
        layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))

        self.departure = QOriginAirfieldSelector(
            self.game.aircraft_inventory,
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData())
        self.departure.availability_changed.connect(self.update_max_size)
        layout.addLayout(QLabeledWidget("Departure:", self.departure))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(), "Same as departure")
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(), "None")
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.flight_size_spinner = QFlightSizeSpinner()
        self.update_max_size(self.departure.available)
        layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))

        self.client_slots_spinner = QFlightSizeSpinner(
            min_size=0,
            max_size=self.flight_size_spinner.value(),
            default_size=0)
        self.flight_size_spinner.valueChanged.connect(
            lambda v: self.client_slots_spinner.setMaximum(v))
        layout.addLayout(
            QLabeledWidget("Client Slots:", self.client_slots_spinner))

        layout.addStretch()

        self.create_button = QPushButton("Create")
        self.create_button.clicked.connect(self.create_flight)
        layout.addWidget(self.create_button, alignment=Qt.AlignRight)

        self.setLayout(layout)
    def __init__(self, game: Game, package_model: PackageModel,
                 flight: Flight) -> None:
        super().__init__("Departure/Arrival")
        self.game = game
        self.package_model = package_model
        self.flight = flight

        layout = QVBoxLayout()

        self.departure_time = QLabel()
        layout.addLayout(
            QLabeledWidget(f"Departing from <b>{flight.from_cp.name}</b>",
                           self.departure_time))
        self.package_model.tot_changed.connect(self.update_departure_time)
        self.update_departure_time()

        layout.addWidget(
            QLabel("Determined based on the package TOT. Edit the "
                   "package to adjust the TOT."))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            flight.unit_type,
            "Same as departure",
        )
        self.arrival.currentIndexChanged.connect(self.set_arrival)
        if flight.arrival != flight.departure:
            self.arrival.setCurrentText(flight.arrival.name)
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            flight.unit_type,
            "None",
        )
        self.divert.currentIndexChanged.connect(self.set_divert)
        if flight.divert is not None:
            self.divert.setCurrentText(flight.divert.name)
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.setLayout(layout)
Example #3
0
    def __init__(self, game: Game, package: Package, parent=None) -> None:
        super().__init__(parent=parent)

        self.game = game
        self.package = package
        self.custom_name_text = None
        self.country = self.game.player_country

        self.setWindowTitle("Create flight")
        self.setWindowIcon(EVENT_ICONS["strike"])

        layout = QVBoxLayout()

        self.task_selector = QFlightTypeComboBox(self.game.theater, package.target)
        self.task_selector.setCurrentIndex(0)
        self.task_selector.currentIndexChanged.connect(self.on_task_changed)
        layout.addLayout(QLabeledWidget("Task:", self.task_selector))

        self.aircraft_selector = QAircraftTypeSelector(
            self.game.aircraft_inventory.available_types_for_player,
            self.game.player_country,
            self.task_selector.currentData(),
        )
        self.aircraft_selector.setCurrentIndex(0)
        self.aircraft_selector.currentIndexChanged.connect(self.on_aircraft_changed)
        layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))

        self.squadron_selector = SquadronSelector(
            self.game.air_wing_for(player=True),
            self.task_selector.currentData(),
            self.aircraft_selector.currentData(),
        )
        self.squadron_selector.setCurrentIndex(0)
        layout.addLayout(QLabeledWidget("Squadron:", self.squadron_selector))

        self.departure = QOriginAirfieldSelector(
            self.game.aircraft_inventory,
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(),
        )
        self.departure.availability_changed.connect(self.update_max_size)
        self.departure.currentIndexChanged.connect(self.on_departure_changed)
        layout.addLayout(QLabeledWidget("Departure:", self.departure))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(),
            "Same as departure",
        )
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(),
            "None",
        )
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.flight_size_spinner = QFlightSizeSpinner()
        self.update_max_size(self.departure.available)
        layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))

        squadron = self.squadron_selector.currentData()
        if squadron is None:
            roster = None
        else:
            roster = FlightRoster(
                squadron, initial_size=self.flight_size_spinner.value()
            )
        self.roster_editor = FlightRosterEditor(roster)
        self.flight_size_spinner.valueChanged.connect(self.resize_roster)
        self.squadron_selector.currentIndexChanged.connect(self.on_squadron_changed)
        roster_layout = QHBoxLayout()
        layout.addLayout(roster_layout)
        roster_layout.addWidget(QLabel("Assigned pilots:"))
        roster_layout.addLayout(self.roster_editor)

        # When an off-map spawn overrides the start type to in-flight, we save
        # the selected type into this value. If a non-off-map spawn is selected
        # we restore the previous choice.
        self.restore_start_type: Optional[str] = None
        self.start_type = QComboBox()
        self.start_type.addItems(["Cold", "Warm", "Runway", "In Flight"])
        self.start_type.setCurrentText(self.game.settings.default_start_type)
        layout.addLayout(
            QLabeledWidget(
                "Start type:",
                self.start_type,
                tooltip="Selects the start type for this flight.",
            )
        )
        layout.addWidget(
            QLabel(
                "Any option other than Cold will make this flight "
                + "non-targetable<br />by OCA/Aircraft missions. This will affect "
                + "game balance."
            )
        )

        self.custom_name = QLineEdit()
        self.custom_name.textChanged.connect(self.set_custom_name_text)
        layout.addLayout(
            QLabeledWidget("Custom Flight Name (Optional)", self.custom_name)
        )

        layout.addStretch()

        self.create_button = QPushButton("Create")
        self.create_button.clicked.connect(self.create_flight)
        layout.addWidget(self.create_button, alignment=Qt.AlignRight)

        self.setLayout(layout)

        self.on_departure_changed(self.departure.currentIndex())
Example #4
0
class QFlightCreator(QDialog):
    created = Signal(Flight)

    def __init__(self, game: Game, package: Package, parent=None) -> None:
        super().__init__(parent=parent)

        self.game = game
        self.package = package
        self.custom_name_text = None
        self.country = self.game.player_country

        self.setWindowTitle("Create flight")
        self.setWindowIcon(EVENT_ICONS["strike"])

        layout = QVBoxLayout()

        self.task_selector = QFlightTypeComboBox(self.game.theater, package.target)
        self.task_selector.setCurrentIndex(0)
        self.task_selector.currentIndexChanged.connect(self.on_task_changed)
        layout.addLayout(QLabeledWidget("Task:", self.task_selector))

        self.aircraft_selector = QAircraftTypeSelector(
            self.game.aircraft_inventory.available_types_for_player,
            self.game.player_country,
            self.task_selector.currentData(),
        )
        self.aircraft_selector.setCurrentIndex(0)
        self.aircraft_selector.currentIndexChanged.connect(self.on_aircraft_changed)
        layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))

        self.squadron_selector = SquadronSelector(
            self.game.air_wing_for(player=True),
            self.task_selector.currentData(),
            self.aircraft_selector.currentData(),
        )
        self.squadron_selector.setCurrentIndex(0)
        layout.addLayout(QLabeledWidget("Squadron:", self.squadron_selector))

        self.departure = QOriginAirfieldSelector(
            self.game.aircraft_inventory,
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(),
        )
        self.departure.availability_changed.connect(self.update_max_size)
        self.departure.currentIndexChanged.connect(self.on_departure_changed)
        layout.addLayout(QLabeledWidget("Departure:", self.departure))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(),
            "Same as departure",
        )
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(),
            "None",
        )
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.flight_size_spinner = QFlightSizeSpinner()
        self.update_max_size(self.departure.available)
        layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))

        squadron = self.squadron_selector.currentData()
        if squadron is None:
            roster = None
        else:
            roster = FlightRoster(
                squadron, initial_size=self.flight_size_spinner.value()
            )
        self.roster_editor = FlightRosterEditor(roster)
        self.flight_size_spinner.valueChanged.connect(self.resize_roster)
        self.squadron_selector.currentIndexChanged.connect(self.on_squadron_changed)
        roster_layout = QHBoxLayout()
        layout.addLayout(roster_layout)
        roster_layout.addWidget(QLabel("Assigned pilots:"))
        roster_layout.addLayout(self.roster_editor)

        # When an off-map spawn overrides the start type to in-flight, we save
        # the selected type into this value. If a non-off-map spawn is selected
        # we restore the previous choice.
        self.restore_start_type: Optional[str] = None
        self.start_type = QComboBox()
        self.start_type.addItems(["Cold", "Warm", "Runway", "In Flight"])
        self.start_type.setCurrentText(self.game.settings.default_start_type)
        layout.addLayout(
            QLabeledWidget(
                "Start type:",
                self.start_type,
                tooltip="Selects the start type for this flight.",
            )
        )
        layout.addWidget(
            QLabel(
                "Any option other than Cold will make this flight "
                + "non-targetable<br />by OCA/Aircraft missions. This will affect "
                + "game balance."
            )
        )

        self.custom_name = QLineEdit()
        self.custom_name.textChanged.connect(self.set_custom_name_text)
        layout.addLayout(
            QLabeledWidget("Custom Flight Name (Optional)", self.custom_name)
        )

        layout.addStretch()

        self.create_button = QPushButton("Create")
        self.create_button.clicked.connect(self.create_flight)
        layout.addWidget(self.create_button, alignment=Qt.AlignRight)

        self.setLayout(layout)

        self.on_departure_changed(self.departure.currentIndex())

    def reject(self) -> None:
        super().reject()
        # Clear the roster to return pilots to the pool.
        self.roster_editor.replace(None)

    def set_custom_name_text(self, text: str):
        self.custom_name_text = text

    def resize_roster(self, new_size: int) -> None:
        self.roster_editor.roster.resize(new_size)
        self.roster_editor.resize(new_size)

    def verify_form(self) -> Optional[str]:
        aircraft: Optional[Type[FlyingType]] = self.aircraft_selector.currentData()
        squadron: Optional[Squadron] = self.squadron_selector.currentData()
        origin: Optional[ControlPoint] = self.departure.currentData()
        arrival: Optional[ControlPoint] = self.arrival.currentData()
        divert: Optional[ControlPoint] = self.divert.currentData()
        size: int = self.flight_size_spinner.value()
        if aircraft is None:
            return "You must select an aircraft type."
        if squadron is None:
            return "You must select a squadron."
        if not origin.captured:
            return f"{origin.name} is not owned by your coalition."
        if arrival is not None and not arrival.captured:
            return f"{arrival.name} is not owned by your coalition."
        if divert is not None and not divert.captured:
            return f"{divert.name} is not owned by your coalition."
        available = origin.base.aircraft.get(aircraft, 0)
        if not available:
            return f"{origin.name} has no {aircraft.id} available."
        if size > available:
            return f"{origin.name} has only {available} {aircraft.id} available."
        if size <= 0:
            return f"Flight must have at least one aircraft."
        if self.custom_name_text and "|" in self.custom_name_text:
            return f"Cannot include | in flight name"
        return None

    def create_flight(self) -> None:
        error = self.verify_form()
        if error is not None:
            QMessageBox.critical(self, "Could not create flight", error, QMessageBox.Ok)
            return

        task = self.task_selector.currentData()
        squadron = self.squadron_selector.currentData()
        origin = self.departure.currentData()
        arrival = self.arrival.currentData()
        divert = self.divert.currentData()
        roster = self.roster_editor.roster

        if arrival is None:
            arrival = origin

        flight = Flight(
            self.package,
            self.country,
            squadron,
            # A bit of a hack to work around the old API. Not actually relevant because
            # the roster is passed explicitly. Needs a refactor.
            roster.max_size,
            task,
            self.start_type.currentText(),
            origin,
            arrival,
            divert,
            custom_name=self.custom_name_text,
            roster=roster,
        )

        # noinspection PyUnresolvedReferences
        self.created.emit(flight)
        self.accept()

    def on_aircraft_changed(self, index: int) -> None:
        new_aircraft = self.aircraft_selector.itemData(index)
        self.squadron_selector.update_items(
            self.task_selector.currentData(), new_aircraft
        )
        self.departure.change_aircraft(new_aircraft)
        self.arrival.change_aircraft(new_aircraft)
        self.divert.change_aircraft(new_aircraft)

    def on_departure_changed(self, index: int) -> None:
        departure = self.departure.itemData(index)
        if isinstance(departure, OffMapSpawn):
            previous_type = self.start_type.currentText()
            if previous_type != "In Flight":
                self.restore_start_type = previous_type
            self.start_type.setCurrentText("In Flight")
            self.start_type.setEnabled(False)
        else:
            self.start_type.setEnabled(True)
            if self.restore_start_type is not None:
                self.start_type.setCurrentText(self.restore_start_type)
                self.restore_start_type = None

    def on_task_changed(self, index: int) -> None:
        task = self.task_selector.itemData(index)
        self.aircraft_selector.update_items(
            task, self.game.aircraft_inventory.available_types_for_player
        )
        self.squadron_selector.update_items(task, self.aircraft_selector.currentData())

    def on_squadron_changed(self, index: int) -> None:
        squadron = self.squadron_selector.itemData(index)
        # Clear the roster first so we return the pilots to the pool. This way if we end
        # up repopulating from the same squadron we'll get the same pilots back.
        self.roster_editor.replace(None)
        if squadron is not None:
            self.roster_editor.replace(
                FlightRoster(squadron, self.flight_size_spinner.value())
            )

    def update_max_size(self, available: int) -> None:
        aircraft = self.aircraft_selector.currentData()
        if aircraft is None:
            self.flight_size_spinner.setMaximum(0)
            return

        self.flight_size_spinner.setMaximum(min(available, aircraft.max_group_size))

        if self.flight_size_spinner.maximum() >= 2:
            self.flight_size_spinner.setValue(2)
Example #5
0
class QFlightCreator(QDialog):
    created = Signal(Flight)

    def __init__(self, game: Game, package: Package, parent=None) -> None:
        super().__init__(parent=parent)

        self.game = game
        self.package = package
        self.custom_name_text = None
        self.country = self.game.player_country

        self.setWindowTitle("Create flight")
        self.setWindowIcon(EVENT_ICONS["strike"])

        layout = QVBoxLayout()

        self.task_selector = QFlightTypeComboBox(self.game.theater,
                                                 package.target)
        self.task_selector.setCurrentIndex(0)
        self.task_selector.currentTextChanged.connect(self.on_task_changed)
        layout.addLayout(QLabeledWidget("Task:", self.task_selector))

        self.aircraft_selector = QAircraftTypeSelector(
            self.game.aircraft_inventory.available_types_for_player,
            self.game.player_country, self.task_selector.currentData())
        self.aircraft_selector.setCurrentIndex(0)
        self.aircraft_selector.currentIndexChanged.connect(
            self.on_aircraft_changed)
        layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))

        self.departure = QOriginAirfieldSelector(
            self.game.aircraft_inventory,
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData())
        self.departure.availability_changed.connect(self.update_max_size)
        self.departure.currentIndexChanged.connect(self.on_departure_changed)
        layout.addLayout(QLabeledWidget("Departure:", self.departure))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(), "Same as departure")
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(), "None")
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.flight_size_spinner = QFlightSizeSpinner()
        self.update_max_size(self.departure.available)
        layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))

        self.client_slots_spinner = QFlightSizeSpinner(
            min_size=0,
            max_size=self.flight_size_spinner.value(),
            default_size=0)
        self.flight_size_spinner.valueChanged.connect(
            lambda v: self.client_slots_spinner.setMaximum(v))
        layout.addLayout(
            QLabeledWidget("Client Slots:", self.client_slots_spinner))

        # When an off-map spawn overrides the start type to in-flight, we save
        # the selected type into this value. If a non-off-map spawn is selected
        # we restore the previous choice.
        self.restore_start_type: Optional[str] = None
        self.start_type = QComboBox()
        self.start_type.addItems(["Cold", "Warm", "Runway", "In Flight"])
        self.start_type.setCurrentText(self.game.settings.default_start_type)
        layout.addLayout(
            QLabeledWidget("Start type:",
                           self.start_type,
                           tooltip="Selects the start type for this flight."))
        layout.addWidget(
            QLabel(
                "Any option other than Cold will make this flight " +
                "non-targetable<br />by OCA/Aircraft missions. This will affect "
                + "game balance."))

        self.custom_name = QLineEdit()
        self.custom_name.textChanged.connect(self.set_custom_name_text)
        layout.addLayout(
            QLabeledWidget("Custom Flight Name (Optional)", self.custom_name))

        layout.addStretch()

        self.create_button = QPushButton("Create")
        self.create_button.clicked.connect(self.create_flight)
        layout.addWidget(self.create_button, alignment=Qt.AlignRight)

        self.setLayout(layout)

        self.on_departure_changed(self.departure.currentIndex())

    def set_custom_name_text(self, text: str):
        self.custom_name_text = text

    def verify_form(self) -> Optional[str]:
        aircraft: PlaneType = self.aircraft_selector.currentData()
        origin: ControlPoint = self.departure.currentData()
        arrival: ControlPoint = self.arrival.currentData()
        divert: ControlPoint = self.divert.currentData()
        size: int = self.flight_size_spinner.value()
        if aircraft is None:
            return "You must select an aircraft type."
        if not origin.captured:
            return f"{origin.name} is not owned by your coalition."
        if arrival is not None and not arrival.captured:
            return f"{arrival.name} is not owned by your coalition."
        if divert is not None and not divert.captured:
            return f"{divert.name} is not owned by your coalition."
        available = origin.base.aircraft.get(aircraft, 0)
        if not available:
            return f"{origin.name} has no {aircraft.id} available."
        if size > available:
            return f"{origin.name} has only {available} {aircraft.id} available."
        if size <= 0:
            return f"Flight must have at least one aircraft."
        if self.custom_name_text and "|" in self.custom_name_text:
            return f"Cannot include | in flight name"
        return None

    def create_flight(self) -> None:
        error = self.verify_form()
        if error is not None:
            QMessageBox.critical(self, "Could not create flight", error,
                                 QMessageBox.Ok)
            return

        task = self.task_selector.currentData()
        aircraft = self.aircraft_selector.currentData()
        origin = self.departure.currentData()
        arrival = self.arrival.currentData()
        divert = self.divert.currentData()
        size = self.flight_size_spinner.value()

        if arrival is None:
            arrival = origin

        flight = Flight(self.package,
                        self.country,
                        aircraft,
                        size,
                        task,
                        self.start_type.currentText(),
                        origin,
                        arrival,
                        divert,
                        custom_name=self.custom_name_text)
        flight.client_count = self.client_slots_spinner.value()

        # noinspection PyUnresolvedReferences
        self.created.emit(flight)
        self.close()

    def on_aircraft_changed(self, index: int) -> None:
        new_aircraft = self.aircraft_selector.itemData(index)
        self.departure.change_aircraft(new_aircraft)
        self.arrival.change_aircraft(new_aircraft)
        self.divert.change_aircraft(new_aircraft)

    def on_departure_changed(self, index: int) -> None:
        departure = self.departure.itemData(index)
        if isinstance(departure, OffMapSpawn):
            previous_type = self.start_type.currentText()
            if previous_type != "In Flight":
                self.restore_start_type = previous_type
            self.start_type.setCurrentText("In Flight")
            self.start_type.setEnabled(False)
        else:
            self.start_type.setEnabled(True)
            if self.restore_start_type is not None:
                self.start_type.setCurrentText(self.restore_start_type)
                self.restore_start_type = None

    def on_task_changed(self) -> None:
        self.aircraft_selector.updateItems(
            self.task_selector.currentData(),
            self.game.aircraft_inventory.available_types_for_player)

    def update_max_size(self, available: int) -> None:
        self.flight_size_spinner.setMaximum(min(available, 4))
        if self.flight_size_spinner.maximum() >= 2:
            if self.flight_size_spinner.value() < 2:
                self.flight_size_spinner.setValue(2)
class FlightAirfieldDisplay(QGroupBox):
    def __init__(self, game: Game, package_model: PackageModel,
                 flight: Flight) -> None:
        super().__init__("Departure/Arrival")
        self.game = game
        self.package_model = package_model
        self.flight = flight

        layout = QVBoxLayout()

        self.departure_time = QLabel()
        layout.addLayout(
            QLabeledWidget(f"Departing from <b>{flight.from_cp.name}</b>",
                           self.departure_time))
        self.package_model.tot_changed.connect(self.update_departure_time)
        self.update_departure_time()

        layout.addWidget(
            QLabel("Determined based on the package TOT. Edit the "
                   "package to adjust the TOT."))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            flight.unit_type,
            "Same as departure",
        )
        self.arrival.currentIndexChanged.connect(self.set_arrival)
        if flight.arrival != flight.departure:
            self.arrival.setCurrentText(flight.arrival.name)
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            flight.unit_type,
            "None",
        )
        self.divert.currentIndexChanged.connect(self.set_divert)
        if flight.divert is not None:
            self.divert.setCurrentText(flight.divert.name)
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.setLayout(layout)

    def update_departure_time(self) -> None:
        estimator = TotEstimator(self.package_model.package)
        delay = estimator.mission_start_time(self.flight)
        self.departure_time.setText(f"At T+{delay}")

    def set_arrival(self, index: int) -> None:
        old_arrival = self.flight.arrival
        arrival = self.arrival.itemData(index)
        if arrival == old_arrival:
            return

        if arrival is None:
            arrival = self.flight.departure

        self.flight.arrival = arrival
        try:
            self.update_flight_plan()
        except PlanningError as ex:
            self.flight.arrival = old_arrival
            logging.exception("Could not change arrival airfield")
            QMessageBox.critical(self, "Could not update flight plan", str(ex),
                                 QMessageBox.Ok)

    def set_divert(self, index: int) -> None:
        old_divert = self.flight.divert
        divert = self.divert.itemData(index)
        if divert == old_divert:
            return

        self.flight.divert = divert
        try:
            self.update_flight_plan()
        except PlanningError as ex:
            self.flight.divert = old_divert
            logging.exception("Could not change divert airfield")
            QMessageBox.critical(self, "Could not update flight plan", str(ex),
                                 QMessageBox.Ok)

    def update_flight_plan(self) -> None:
        planner = FlightPlanBuilder(self.game,
                                    self.package_model.package,
                                    is_player=True)
        planner.populate_flight_plan(self.flight)
Example #7
0
class QFlightCreator(QDialog):
    created = Signal(Flight)

    def __init__(self, game: Game, package: Package, parent=None) -> None:
        super().__init__(parent=parent)

        self.game = game
        self.package = package

        self.setWindowTitle("Create flight")
        self.setWindowIcon(EVENT_ICONS["strike"])

        layout = QVBoxLayout()

        self.task_selector = QFlightTypeComboBox(self.game.theater,
                                                 package.target)
        self.task_selector.setCurrentIndex(0)
        layout.addLayout(QLabeledWidget("Task:", self.task_selector))

        self.aircraft_selector = QAircraftTypeSelector(
            self.game.aircraft_inventory.available_types_for_player)
        self.aircraft_selector.setCurrentIndex(0)
        self.aircraft_selector.currentIndexChanged.connect(
            self.on_aircraft_changed)
        layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))

        self.departure = QOriginAirfieldSelector(
            self.game.aircraft_inventory,
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData())
        self.departure.availability_changed.connect(self.update_max_size)
        layout.addLayout(QLabeledWidget("Departure:", self.departure))

        self.arrival = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(), "Same as departure")
        layout.addLayout(QLabeledWidget("Arrival:", self.arrival))

        self.divert = QArrivalAirfieldSelector(
            [cp for cp in game.theater.controlpoints if cp.captured],
            self.aircraft_selector.currentData(), "None")
        layout.addLayout(QLabeledWidget("Divert:", self.divert))

        self.flight_size_spinner = QFlightSizeSpinner()
        self.update_max_size(self.departure.available)
        layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))

        self.client_slots_spinner = QFlightSizeSpinner(
            min_size=0,
            max_size=self.flight_size_spinner.value(),
            default_size=0)
        self.flight_size_spinner.valueChanged.connect(
            lambda v: self.client_slots_spinner.setMaximum(v))
        layout.addLayout(
            QLabeledWidget("Client Slots:", self.client_slots_spinner))

        layout.addStretch()

        self.create_button = QPushButton("Create")
        self.create_button.clicked.connect(self.create_flight)
        layout.addWidget(self.create_button, alignment=Qt.AlignRight)

        self.setLayout(layout)

    def verify_form(self) -> Optional[str]:
        aircraft: PlaneType = self.aircraft_selector.currentData()
        origin: ControlPoint = self.departure.currentData()
        arrival: ControlPoint = self.arrival.currentData()
        divert: ControlPoint = self.divert.currentData()
        size: int = self.flight_size_spinner.value()
        if not origin.captured:
            return f"{origin.name} is not owned by your coalition."
        if arrival is not None and not arrival.captured:
            return f"{arrival.name} is not owned by your coalition."
        if divert is not None and not divert.captured:
            return f"{divert.name} is not owned by your coalition."
        available = origin.base.aircraft.get(aircraft, 0)
        if not available:
            return f"{origin.name} has no {aircraft.id} available."
        if size > available:
            return f"{origin.name} has only {available} {aircraft.id} available."
        if size <= 0:
            return f"Flight must have at least one aircraft."
        return None

    def create_flight(self) -> None:
        error = self.verify_form()
        if error is not None:
            QMessageBox.critical(self, "Could not create flight", error,
                                 QMessageBox.Ok)
            return

        task = self.task_selector.currentData()
        aircraft = self.aircraft_selector.currentData()
        origin = self.departure.currentData()
        arrival = self.arrival.currentData()
        divert = self.divert.currentData()
        size = self.flight_size_spinner.value()

        if arrival is None:
            arrival = origin

        if isinstance(origin, OffMapSpawn):
            start_type = "In Flight"
        elif self.game.settings.perf_ai_parking_start:
            start_type = "Cold"
        else:
            start_type = "Warm"
        flight = Flight(self.package, aircraft, size, task, start_type, origin,
                        arrival, divert)
        flight.client_count = self.client_slots_spinner.value()

        # noinspection PyUnresolvedReferences
        self.created.emit(flight)
        self.close()

    def on_aircraft_changed(self, index: int) -> None:
        new_aircraft = self.aircraft_selector.itemData(index)
        self.departure.change_aircraft(new_aircraft)
        self.arrival.change_aircraft(new_aircraft)
        self.divert.change_aircraft(new_aircraft)

    def update_max_size(self, available: int) -> None:
        self.flight_size_spinner.setMaximum(min(available, 4))
        if self.flight_size_spinner.maximum() >= 2:
            if self.flight_size_spinner.value() < 2:
                self.flight_size_spinner.setValue(2)