mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Ability to set callsigns
This commit is contained in:
parent
aaf23d52bc
commit
ade81f4548
@ -24,6 +24,8 @@
|
|||||||
* **[Options]** New options in Settings: Spawn ground power trucks at ground starts in airbases/roadbases
|
* **[Options]** New options in Settings: Spawn ground power trucks at ground starts in airbases/roadbases
|
||||||
* **[Options]** Option for hiding TGOs (with IADS roles) on MFD
|
* **[Options]** Option for hiding TGOs (with IADS roles) on MFD
|
||||||
* **[Plugins]** Splash Damage 2.1 with Clusters and Ship Radar effects.
|
* **[Plugins]** Splash Damage 2.1 with Clusters and Ship Radar effects.
|
||||||
|
* **[COMMs]** Aircraft-specific callsigns will now also be used.
|
||||||
|
* **[COMMs]** Ability to set a specific callsign to a flight.
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
* **[Mission Generation]** Anti-ship strikes should use "group attack" in their attack-task
|
* **[Mission Generation]** Anti-ship strikes should use "group attack" in their attack-task
|
||||||
|
|||||||
@ -14,7 +14,9 @@ from .flightmembers import FlightMembers
|
|||||||
from .flightroster import FlightRoster
|
from .flightroster import FlightRoster
|
||||||
from .flightstate import FlightState, Navigating, Uninitialized
|
from .flightstate import FlightState, Navigating, Uninitialized
|
||||||
from .flightstate.killed import Killed
|
from .flightstate.killed import Killed
|
||||||
|
from .flighttype import FlightType
|
||||||
from .loadouts import Weapon
|
from .loadouts import Weapon
|
||||||
|
from ..radio.CallsignContainer import CallsignContainer
|
||||||
from ..radio.RadioFrequencyContainer import RadioFrequencyContainer
|
from ..radio.RadioFrequencyContainer import RadioFrequencyContainer
|
||||||
from ..radio.TacanContainer import TacanContainer
|
from ..radio.TacanContainer import TacanContainer
|
||||||
from ..radio.radios import RadioFrequency
|
from ..radio.radios import RadioFrequency
|
||||||
@ -36,7 +38,6 @@ if TYPE_CHECKING:
|
|||||||
from game.data.weapons import WeaponType
|
from game.data.weapons import WeaponType
|
||||||
from .flightmember import FlightMember
|
from .flightmember import FlightMember
|
||||||
from .flightplans.flightplan import FlightPlan
|
from .flightplans.flightplan import FlightPlan
|
||||||
from .flighttype import FlightType
|
|
||||||
from .flightwaypoint import FlightWaypoint
|
from .flightwaypoint import FlightWaypoint
|
||||||
from .package import Package
|
from .package import Package
|
||||||
from .starttype import StartType
|
from .starttype import StartType
|
||||||
@ -44,7 +45,9 @@ if TYPE_CHECKING:
|
|||||||
F18_TGP_PYLON: int = 4
|
F18_TGP_PYLON: int = 4
|
||||||
|
|
||||||
|
|
||||||
class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
|
class Flight(
|
||||||
|
SidcDescribable, RadioFrequencyContainer, TacanContainer, CallsignContainer
|
||||||
|
):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
package: Package,
|
package: Package,
|
||||||
@ -58,7 +61,7 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
|
|||||||
roster: Optional[FlightRoster] = None,
|
roster: Optional[FlightRoster] = None,
|
||||||
frequency: Optional[RadioFrequency] = None,
|
frequency: Optional[RadioFrequency] = None,
|
||||||
channel: Optional[TacanChannel] = None,
|
channel: Optional[TacanChannel] = None,
|
||||||
callsign: Optional[str] = None,
|
callsign_tcn: Optional[str] = None,
|
||||||
claim_inv: bool = True,
|
claim_inv: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.id = uuid.uuid4()
|
self.id = uuid.uuid4()
|
||||||
@ -81,7 +84,7 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
|
|||||||
self.frequency = frequency
|
self.frequency = frequency
|
||||||
if self.unit_type.dcs_unit_type.tacan:
|
if self.unit_type.dcs_unit_type.tacan:
|
||||||
self.tacan = channel
|
self.tacan = channel
|
||||||
self.tcn_name = callsign
|
self.tcn_name = callsign_tcn
|
||||||
|
|
||||||
self.initialize_fuel()
|
self.initialize_fuel()
|
||||||
self.use_same_loadout_for_all_members = True
|
self.use_same_loadout_for_all_members = True
|
||||||
@ -120,6 +123,22 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available_callsigns(self) -> List[str]:
|
||||||
|
callsigns = set()
|
||||||
|
dcs_unit = self.squadron.aircraft.dcs_unit_type
|
||||||
|
category = dcs_unit.category
|
||||||
|
category = "Air" if category == "Interceptor" else category
|
||||||
|
for name in self.squadron.coalition.faction.country.callsign[category]:
|
||||||
|
callsigns.add(name)
|
||||||
|
if hasattr(dcs_unit, "callnames"):
|
||||||
|
country_name = self.squadron.coalition.faction.country.name
|
||||||
|
for c in dcs_unit.callnames:
|
||||||
|
if "Combined Joint Task Forces" in country_name or c == country_name:
|
||||||
|
for name in dcs_unit.callnames[c]:
|
||||||
|
callsigns.add(name)
|
||||||
|
return sorted(callsigns)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def flight_plan(self) -> FlightPlan[Any]:
|
def flight_plan(self) -> FlightPlan[Any]:
|
||||||
return self._flight_plan_builder.get_or_build()
|
return self._flight_plan_builder.get_or_build()
|
||||||
|
|||||||
@ -266,6 +266,8 @@ class FlightGroupSpawner:
|
|||||||
start_type=self._start_type_at_airfield(airfield),
|
start_type=self._start_type_at_airfield(airfield),
|
||||||
group_size=self.flight.count,
|
group_size=self.flight.count,
|
||||||
parking_slots=None,
|
parking_slots=None,
|
||||||
|
callsign_name=self.flight.callsign.name if self.flight.callsign else None,
|
||||||
|
callsign_nr=self.flight.callsign.nr if self.flight.callsign else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _generate_over_departure(
|
def _generate_over_departure(
|
||||||
@ -299,6 +301,8 @@ class FlightGroupSpawner:
|
|||||||
speed=speed.kph,
|
speed=speed.kph,
|
||||||
maintask=None,
|
maintask=None,
|
||||||
group_size=self.flight.count,
|
group_size=self.flight.count,
|
||||||
|
callsign_name=self.flight.callsign.name if self.flight.callsign else None,
|
||||||
|
callsign_nr=self.flight.callsign.nr if self.flight.callsign else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
group.points[0].alt_type = alt_type
|
group.points[0].alt_type = alt_type
|
||||||
@ -315,6 +319,8 @@ class FlightGroupSpawner:
|
|||||||
maintask=None,
|
maintask=None,
|
||||||
start_type=self._start_type_at_group(at),
|
start_type=self._start_type_at_group(at),
|
||||||
group_size=self.flight.count,
|
group_size=self.flight.count,
|
||||||
|
callsign_name=self.flight.callsign.name if self.flight.callsign else None,
|
||||||
|
callsign_nr=self.flight.callsign.nr if self.flight.callsign else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _generate_at_cp_helipad(
|
def _generate_at_cp_helipad(
|
||||||
|
|||||||
20
game/radio/CallsignContainer.py
Normal file
20
game/radio/CallsignContainer.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
|
||||||
|
class Callsign:
|
||||||
|
name: Optional[str] = None
|
||||||
|
nr: Optional[int] = None
|
||||||
|
|
||||||
|
def __init__(self, name: Optional[str], nr: int) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.nr = nr
|
||||||
|
|
||||||
|
|
||||||
|
class CallsignContainer:
|
||||||
|
callsign: Optional[Callsign] = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def available_callsigns(self) -> List[str]:
|
||||||
|
...
|
||||||
70
qt_ui/widgets/QCallsignWidget.py
Normal file
70
qt_ui/widgets/QCallsignWidget.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from PySide6.QtCore import Signal
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QPushButton,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from game.radio.CallsignContainer import CallsignContainer, Callsign
|
||||||
|
from qt_ui.models import GameModel
|
||||||
|
from qt_ui.windows.QCallsignDialog import QCallsignDialog
|
||||||
|
|
||||||
|
|
||||||
|
class QCallsignWidget(QWidget):
|
||||||
|
callsign_changed = Signal(QWidget)
|
||||||
|
|
||||||
|
def __init__(self, container: CallsignContainer, game_model: GameModel) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.ct = container
|
||||||
|
self.gm = game_model
|
||||||
|
|
||||||
|
columns = QHBoxLayout()
|
||||||
|
self.setLayout(columns)
|
||||||
|
|
||||||
|
self.callsign = QLabel(self._get_label_text())
|
||||||
|
columns.addWidget(self.callsign)
|
||||||
|
columns.addStretch()
|
||||||
|
|
||||||
|
self.set_callsign_btn = QPushButton("Set Callsign")
|
||||||
|
self.set_callsign_btn.setProperty("class", "comms")
|
||||||
|
self.set_callsign_btn.setFixedWidth(100)
|
||||||
|
columns.addWidget(self.set_callsign_btn)
|
||||||
|
self.set_callsign_btn.clicked.connect(self.open_callsign_dialog)
|
||||||
|
|
||||||
|
self.reset_callsign_btn = QPushButton("Reset Callsign")
|
||||||
|
self.reset_callsign_btn.setProperty("class", "btn-danger comms")
|
||||||
|
self.reset_callsign_btn.setFixedWidth(100)
|
||||||
|
columns.addWidget(self.reset_callsign_btn)
|
||||||
|
self.reset_callsign_btn.clicked.connect(self.reset_callsign)
|
||||||
|
|
||||||
|
def _get_label_text(self) -> str:
|
||||||
|
cs = (
|
||||||
|
"AUTO"
|
||||||
|
if self.ct.callsign is None
|
||||||
|
else f"{self.ct.callsign.name} {self.ct.callsign.nr}"
|
||||||
|
)
|
||||||
|
return f"<b>Callsign: {cs}</b>"
|
||||||
|
|
||||||
|
def open_callsign_dialog(self) -> None:
|
||||||
|
self.callsign_dialog = QCallsignDialog(self, self.ct)
|
||||||
|
self.callsign_dialog.accepted.connect(self.assign_callsign)
|
||||||
|
self.callsign_dialog.show()
|
||||||
|
|
||||||
|
def assign_callsign(self) -> None:
|
||||||
|
name = self.callsign_dialog.callsign_name_input.currentText()
|
||||||
|
nr = self.callsign_dialog.callsign_nr_input.value()
|
||||||
|
self.ct.callsign = Callsign(name, nr)
|
||||||
|
self.callsign.setText(self._get_label_text())
|
||||||
|
self.callsign_changed.emit(self)
|
||||||
|
|
||||||
|
def reset_callsign(self) -> None:
|
||||||
|
self.ct.callsign = None
|
||||||
|
self.callsign.setText(self._get_label_text())
|
||||||
|
self._reset_color_and_tooltip()
|
||||||
|
self.callsign_changed.emit(self)
|
||||||
|
|
||||||
|
def _reset_color_and_tooltip(self):
|
||||||
|
self.callsign.setStyleSheet("color: white")
|
||||||
|
self.callsign.setToolTip(None)
|
||||||
56
qt_ui/windows/QCallsignDialog.py
Normal file
56
qt_ui/windows/QCallsignDialog.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QDialog,
|
||||||
|
QPushButton,
|
||||||
|
QLabel,
|
||||||
|
QHBoxLayout,
|
||||||
|
QSpinBox,
|
||||||
|
QComboBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from game.radio.CallsignContainer import CallsignContainer
|
||||||
|
from qt_ui.uiconstants import EVENT_ICONS
|
||||||
|
|
||||||
|
|
||||||
|
class QCallsignDialog(QDialog):
|
||||||
|
def __init__(
|
||||||
|
self, parent=None, container: Optional[CallsignContainer] = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(parent=parent)
|
||||||
|
self.container = container
|
||||||
|
self.setMinimumWidth(400)
|
||||||
|
|
||||||
|
# Make dialog modal to prevent background windows to close unexpectedly.
|
||||||
|
self.setModal(True)
|
||||||
|
|
||||||
|
self.setWindowTitle("Assign Callsign")
|
||||||
|
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
|
||||||
|
self.callsign_label = QLabel("Callsign:")
|
||||||
|
self.callsign_name_input = QComboBox()
|
||||||
|
self.callsign_name_input.addItems(container.available_callsigns)
|
||||||
|
self.callsign_nr_input = QSpinBox()
|
||||||
|
self.callsign_nr_input.setRange(1, 9)
|
||||||
|
self.callsign_nr_input.setSingleStep(1)
|
||||||
|
self.callsign_nr_input.setMaximumWidth(50)
|
||||||
|
layout.addWidget(self.callsign_label)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(self.callsign_name_input)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(self.callsign_nr_input)
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
self.create_button = QPushButton("Save")
|
||||||
|
self.create_button.clicked.connect(self.accept)
|
||||||
|
layout.addWidget(self.create_button, alignment=Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
if container is not None:
|
||||||
|
if container.callsign is not None:
|
||||||
|
self.callsign_name_input.setCurrentText(container.callsign.name)
|
||||||
|
self.callsign_nr_input.setValue(container.callsign.nr)
|
||||||
@ -2,13 +2,14 @@ from PySide6.QtWidgets import QGroupBox, QVBoxLayout
|
|||||||
|
|
||||||
from game.ato import Flight, FlightType
|
from game.ato import Flight, FlightType
|
||||||
from qt_ui.models import GameModel
|
from qt_ui.models import GameModel
|
||||||
|
from qt_ui.widgets.QCallsignWidget import QCallsignWidget
|
||||||
from qt_ui.widgets.QFrequencyWidget import QFrequencyWidget
|
from qt_ui.widgets.QFrequencyWidget import QFrequencyWidget
|
||||||
from qt_ui.widgets.QTacanWidget import QTacanWidget
|
from qt_ui.widgets.QTacanWidget import QTacanWidget
|
||||||
|
|
||||||
|
|
||||||
class QCommsEditor(QGroupBox):
|
class QCommsEditor(QGroupBox):
|
||||||
def __init__(self, flight: Flight, game: GameModel):
|
def __init__(self, flight: Flight, game: GameModel):
|
||||||
title = "Intra-Flight Frequency"
|
title = "COMMs"
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
@ -16,9 +17,9 @@ class QCommsEditor(QGroupBox):
|
|||||||
has_tacan = flight.unit_type.dcs_unit_type.tacan
|
has_tacan = flight.unit_type.dcs_unit_type.tacan
|
||||||
|
|
||||||
layout.addWidget(QFrequencyWidget(flight, game))
|
layout.addWidget(QFrequencyWidget(flight, game))
|
||||||
|
layout.addWidget(QCallsignWidget(flight, game))
|
||||||
if is_refuel and has_tacan:
|
if is_refuel and has_tacan:
|
||||||
layout.addWidget(QTacanWidget(flight, game))
|
layout.addWidget(QTacanWidget(flight, game))
|
||||||
title = title + " / TACAN"
|
|
||||||
super(QCommsEditor, self).__init__(title)
|
super(QCommsEditor, self).__init__(title)
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user