Ability to set callsigns

This commit is contained in:
Raffson 2023-11-18 23:05:01 +01:00
parent aaf23d52bc
commit ade81f4548
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
7 changed files with 180 additions and 6 deletions

View File

@ -24,6 +24,8 @@
* **[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
* **[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
* **[Mission Generation]** Anti-ship strikes should use "group attack" in their attack-task

View File

@ -14,7 +14,9 @@ from .flightmembers import FlightMembers
from .flightroster import FlightRoster
from .flightstate import FlightState, Navigating, Uninitialized
from .flightstate.killed import Killed
from .flighttype import FlightType
from .loadouts import Weapon
from ..radio.CallsignContainer import CallsignContainer
from ..radio.RadioFrequencyContainer import RadioFrequencyContainer
from ..radio.TacanContainer import TacanContainer
from ..radio.radios import RadioFrequency
@ -36,7 +38,6 @@ if TYPE_CHECKING:
from game.data.weapons import WeaponType
from .flightmember import FlightMember
from .flightplans.flightplan import FlightPlan
from .flighttype import FlightType
from .flightwaypoint import FlightWaypoint
from .package import Package
from .starttype import StartType
@ -44,7 +45,9 @@ if TYPE_CHECKING:
F18_TGP_PYLON: int = 4
class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
class Flight(
SidcDescribable, RadioFrequencyContainer, TacanContainer, CallsignContainer
):
def __init__(
self,
package: Package,
@ -58,7 +61,7 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
roster: Optional[FlightRoster] = None,
frequency: Optional[RadioFrequency] = None,
channel: Optional[TacanChannel] = None,
callsign: Optional[str] = None,
callsign_tcn: Optional[str] = None,
claim_inv: bool = True,
) -> None:
self.id = uuid.uuid4()
@ -81,7 +84,7 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
self.frequency = frequency
if self.unit_type.dcs_unit_type.tacan:
self.tacan = channel
self.tcn_name = callsign
self.tcn_name = callsign_tcn
self.initialize_fuel()
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
def flight_plan(self) -> FlightPlan[Any]:
return self._flight_plan_builder.get_or_build()

View File

@ -266,6 +266,8 @@ class FlightGroupSpawner:
start_type=self._start_type_at_airfield(airfield),
group_size=self.flight.count,
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(
@ -299,6 +301,8 @@ class FlightGroupSpawner:
speed=speed.kph,
maintask=None,
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
@ -315,6 +319,8 @@ class FlightGroupSpawner:
maintask=None,
start_type=self._start_type_at_group(at),
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(

View 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]:
...

View 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)

View 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)

View File

@ -2,13 +2,14 @@ from PySide6.QtWidgets import QGroupBox, QVBoxLayout
from game.ato import Flight, FlightType
from qt_ui.models import GameModel
from qt_ui.widgets.QCallsignWidget import QCallsignWidget
from qt_ui.widgets.QFrequencyWidget import QFrequencyWidget
from qt_ui.widgets.QTacanWidget import QTacanWidget
class QCommsEditor(QGroupBox):
def __init__(self, flight: Flight, game: GameModel):
title = "Intra-Flight Frequency"
title = "COMMs"
layout = QVBoxLayout()
@ -16,9 +17,9 @@ class QCommsEditor(QGroupBox):
has_tacan = flight.unit_type.dcs_unit_type.tacan
layout.addWidget(QFrequencyWidget(flight, game))
layout.addWidget(QCallsignWidget(flight, game))
if is_refuel and has_tacan:
layout.addWidget(QTacanWidget(flight, game))
title = title + " / TACAN"
super(QCommsEditor, self).__init__(title)
self.flight = flight