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)