From e901d1f538397353bf97d45797020d670ab16c82 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Sat, 22 Jul 2023 16:32:11 -0700 Subject: [PATCH] Add UI for selecting weapon laser codes. This makes it possible to have the right laser code set for hot start aircraft that (typically) do not allow changing laser codes when the engine is on. --- changelog.md | 1 + game/ato/flightmember.py | 5 ++ .../aircraft/flightgroupconfigurator.py | 6 ++- .../flight/payload/QFlightPayloadTab.py | 20 ++++++++ .../flight/payload/weaponlasercodeselector.py | 51 +++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py diff --git a/changelog.md b/changelog.md index 1cb04ec6..1882a324 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ Saves from 8.x are not compatible with 9.0.0. * **[Flight Planning]** Improved IP selection for targets that are near the center of a threat zone. * **[Flight Planning]** Loadouts and aircraft properties can now be set per-flight member. Warning: AI flights should not use mixed loadouts. +* **[Flight Planning]** Laser codes that are pre-assigned to weapons at mission start can now be chosen from a list in the loadout UI. This does not affect the aircraft's TGP, just the weapons. Currently only implemented for the F-15E S4+. * **[Modding]** Factions can now specify the ship type to be used for cargo shipping. The Handy Wind will be used by default, but WW2 factions can pick something more appropriate. * **[UI]** An error will be displayed when invalid fast-forward options are selected rather than beginning a never ending simulation. * **[UI]** Added cheats for instantly repairing and destroying runways. diff --git a/game/ato/flightmember.py b/game/ato/flightmember.py index ddb2cca4..1a853af9 100644 --- a/game/ato/flightmember.py +++ b/game/ato/flightmember.py @@ -16,12 +16,15 @@ class FlightMember: self.loadout = loadout self.use_custom_loadout = False self.tgp_laser_code: LaserCode | None = None + self.weapon_laser_code: LaserCode | None = None self.properties: dict[str, bool | float | int] = {} @has_save_compat_for(9) def __setstate__(self, state: dict[str, Any]) -> None: if "tgp_laser_code" not in state: state["tgp_laser_code"] = None + if "weapon_laser_code" not in state: + state["weapon_laser_code"] = None self.__dict__.update(state) def assign_tgp_laser_code(self, code: LaserCode) -> None: @@ -36,6 +39,8 @@ class FlightMember: if self.tgp_laser_code is None: raise RuntimeError(f"{self.pilot} has no assigned laser code") + if self.weapon_laser_code == self.tgp_laser_code: + self.weapon_laser_code = None self.tgp_laser_code.release() self.tgp_laser_code = None diff --git a/game/missiongenerator/aircraft/flightgroupconfigurator.py b/game/missiongenerator/aircraft/flightgroupconfigurator.py index 96bae31f..8c266286 100644 --- a/game/missiongenerator/aircraft/flightgroupconfigurator.py +++ b/game/missiongenerator/aircraft/flightgroupconfigurator.py @@ -213,7 +213,11 @@ class FlightGroupConfigurator: def setup_props(self) -> None: for unit, member in zip(self.group.units, self.flight.iter_members()): - for prop_id, value in member.properties.items(): + props = dict(member.properties) + if (code := member.weapon_laser_code) is not None: + for laser_code_config in self.flight.unit_type.laser_code_configs: + props.update(laser_code_config.property_dict_for_code(code.code)) + for prop_id, value in props.items(): unit.set_property(prop_id, value) def setup_payloads(self) -> None: diff --git a/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py b/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py index ef55736f..9fbd1baf 100644 --- a/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py +++ b/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py @@ -18,6 +18,7 @@ from qt_ui.widgets.QLabeledWidget import QLabeledWidget from .QLoadoutEditor import QLoadoutEditor from .ownlasercodeinfo import OwnLaserCodeInfo from .propertyeditor import PropertyEditor +from .weaponlasercodeselector import WeaponLaserCodeSelector class DcsLoadoutSelector(QComboBox): @@ -95,6 +96,24 @@ class QFlightPayloadTab(QFrame): ) scrolling_layout.addLayout(self.own_laser_code_info) + self.weapon_laser_code_selector = WeaponLaserCodeSelector( + game, self.member_selector.selected_member, self + ) + self.own_laser_code_info.assigned_laser_code_changed.connect( + self.weapon_laser_code_selector.rebuild + ) + scrolling_layout.addLayout( + QLabeledWidget( + "Preset laser code for weapons:", self.weapon_laser_code_selector + ) + ) + scrolling_layout.addWidget( + QLabel( + "Equipped weapons will be pre-configured to the selected laser code at " + "mission start." + ) + ) + self.property_editor = PropertyEditor( self.flight, self.member_selector.selected_member ) @@ -123,6 +142,7 @@ class QFlightPayloadTab(QFrame): self.loadout_selector.setCurrentText(member.loadout.name) self.loadout_selector.setDisabled(member.loadout.is_custom) self.payload_editor.set_flight_member(member) + self.weapon_laser_code_selector.set_flight_member(member) self.own_laser_code_info.set_flight_member(member) if self.member_selector.value() != 0: self.loadout_selector.setDisabled( diff --git a/qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py b/qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py new file mode 100644 index 00000000..6b3b3f59 --- /dev/null +++ b/qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py @@ -0,0 +1,51 @@ +from PySide6.QtWidgets import QComboBox, QWidget + +from game import Game +from game.ato.flightmember import FlightMember +from qt_ui.blocksignals import block_signals + + +class WeaponLaserCodeSelector(QComboBox): + def __init__( + self, game: Game, flight_member: FlightMember, parent: QWidget | None = None + ) -> None: + super().__init__(parent) + self.game = game + self.flight_member = flight_member + self.currentIndexChanged.connect(self.on_index_changed) + + self.rebuild() + + def set_flight_member(self, flight_member: FlightMember) -> None: + self.flight_member = flight_member + self.rebuild() + + def on_index_changed(self) -> None: + self.flight_member.weapon_laser_code = self.currentData() + + def rebuild(self) -> None: + with block_signals(self): + self.clear() + if not self.flight_member.is_player: + self.setDisabled(True) + self.addItem("AI does not use laser codes", None) + + self.setEnabled(True) + + self.addItem("Default (1688)", None) + selected_index: int | None = None + idx = 1 + if (own := self.flight_member.tgp_laser_code) is not None: + self.addItem(f"Use own code ({own})", own) + if own == self.flight_member.weapon_laser_code: + selected_index = idx + idx += 1 + for idx, front in enumerate(self.game.theater.conflicts(), idx): + self.addItem( + f"JTAC {front.name} ({front.laser_code})", front.laser_code + ) + if front.laser_code == self.flight_member.weapon_laser_code: + selected_index = idx + + if selected_index is not None: + self.setCurrentIndex(selected_index)