mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge remote-tracking branch 'remotes/dcs-retribution/dcs-retribution/dev' into pretense-generator
This commit is contained in:
commit
48861c53da
4
.github/actions/build-app/action.yaml
vendored
4
.github/actions/build-app/action.yaml
vendored
@ -1,5 +1,5 @@
|
|||||||
name: Build Liberation package
|
name: Build Retribution package
|
||||||
description: Assembles the full Liberation application.
|
description: Assembles the full Retribution application.
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: Liberation JS set-up
|
name: Retribution JS set-up
|
||||||
description: Sets up the Liberation Javascript environment.
|
description: Sets up the Retribution Javascript environment.
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: Liberation Python set-up
|
name: Retribution Python set-up
|
||||||
description: Sets up the Liberation Python environment.
|
description: Sets up the Retribution Python environment.
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
* **[Campaign Setup]** Allow adjustments to naval TGOs (except carriers) on turn 0
|
* **[Campaign Setup]** Allow adjustments to naval TGOs (except carriers) on turn 0
|
||||||
* **[Campaign Design]** Ability to configure specific carrier names & types in campaign's yaml file
|
* **[Campaign Design]** Ability to configure specific carrier names & types in campaign's yaml file
|
||||||
* **[Mission Generation]** Ability to inject custom kneeboards
|
* **[Mission Generation]** Ability to inject custom kneeboards
|
||||||
|
* **[Options]** Extend option (so it can be disabled when fixed in DCS) to force air-starts (except for the slots that work) at Ramon Airbase, similar to the Nevatim fix in Retribution 1.3.0
|
||||||
|
* **[Options]** New option in Settings: Default start type for Player flights.
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
* **[UI/UX]** A-10A flights can be edited again.
|
* **[UI/UX]** A-10A flights can be edited again.
|
||||||
|
|||||||
@ -22,6 +22,10 @@ class FlightRoster(IFlightRoster):
|
|||||||
def iter_pilots(self) -> Iterator[Pilot | None]:
|
def iter_pilots(self) -> Iterator[Pilot | None]:
|
||||||
yield from self.pilots
|
yield from self.pilots
|
||||||
|
|
||||||
|
@property
|
||||||
|
def player_count(self) -> int:
|
||||||
|
return len([p for p in self.pilots if p is not None and p.player])
|
||||||
|
|
||||||
def pilot_at(self, idx: int) -> Pilot | None:
|
def pilot_at(self, idx: int) -> Pilot | None:
|
||||||
return self.pilots[idx]
|
return self.pilots[idx]
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,11 @@ class IFlightRoster(ABC):
|
|||||||
def max_size(self) -> int:
|
def max_size(self) -> int:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def player_count(self) -> int:
|
||||||
|
...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def resize(self, new_size: int) -> None:
|
def resize(self, new_size: int) -> None:
|
||||||
...
|
...
|
||||||
|
|||||||
@ -76,6 +76,12 @@ class PackageBuilder:
|
|||||||
member.assign_tgp_laser_code(
|
member.assign_tgp_laser_code(
|
||||||
self.laser_code_registry.alloc_laser_code()
|
self.laser_code_registry.alloc_laser_code()
|
||||||
)
|
)
|
||||||
|
# If this is a client flight, set the start_type again to match the configured default
|
||||||
|
# https://github.com/dcs-liberation/dcs_liberation/issues/1567
|
||||||
|
if flight.roster is not None and flight.roster.player_count > 0:
|
||||||
|
flight.start_type = (
|
||||||
|
squadron.coalition.game.settings.default_start_type_client
|
||||||
|
)
|
||||||
self.package.add_flight(flight)
|
self.package.add_flight(flight)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@ -363,7 +363,7 @@ class Debriefing:
|
|||||||
seen = set()
|
seen = set()
|
||||||
captures = []
|
captures = []
|
||||||
for capture in reversed(self.state_data.base_capture_events):
|
for capture in reversed(self.state_data.base_capture_events):
|
||||||
# The ID string in the JSON file will be the UUID generated from liberation
|
# The ID string in the JSON file will be the UUID generated from retribution
|
||||||
cp_id, new_owner_id_str, _name = capture.split("||")
|
cp_id, new_owner_id_str, _name = capture.split("||")
|
||||||
|
|
||||||
# Only the most recent capture event matters.
|
# Only the most recent capture event matters.
|
||||||
|
|||||||
@ -20,7 +20,7 @@ from dcs.planes import (
|
|||||||
from dcs.point import PointAction
|
from dcs.point import PointAction
|
||||||
from dcs.ships import KUZNECOW
|
from dcs.ships import KUZNECOW
|
||||||
from dcs.terrain import NoParkingSlotError, Sinai, ParkingSlot
|
from dcs.terrain import NoParkingSlotError, Sinai, ParkingSlot
|
||||||
from dcs.terrain.sinai.airports import Nevatim
|
from dcs.terrain.sinai.airports import Nevatim, Ramon_Airbase
|
||||||
from dcs.unitgroup import (
|
from dcs.unitgroup import (
|
||||||
FlyingGroup,
|
FlyingGroup,
|
||||||
ShipGroup,
|
ShipGroup,
|
||||||
@ -132,6 +132,16 @@ class FlightGroupSpawner:
|
|||||||
for slot in cp.dcs_airport.free_parking_slots(ac_type)
|
for slot in cp.dcs_airport.free_parking_slots(ac_type)
|
||||||
if slot.slot_name in [str(n) for n in range(55, 66)]
|
if slot.slot_name in [str(n) for n in range(55, 66)]
|
||||||
]
|
]
|
||||||
|
elif self._check_ramon_airbase_hack(cp):
|
||||||
|
ac_type = self.flight.unit_type.dcs_unit_type
|
||||||
|
slots = [
|
||||||
|
slot
|
||||||
|
for slot in cp.dcs_airport.free_parking_slots(ac_type)
|
||||||
|
if slot.slot_name
|
||||||
|
not in [
|
||||||
|
str(n) for n in [1, 2, 3, 4, 5, 6, 13, 14, 15, 16, 17, 18, 61]
|
||||||
|
]
|
||||||
|
]
|
||||||
group = self._generate_at_airfield(
|
group = self._generate_at_airfield(
|
||||||
name=namegen.next_aircraft_name(self.country, self.flight),
|
name=namegen.next_aircraft_name(self.country, self.flight),
|
||||||
airfield=cp,
|
airfield=cp,
|
||||||
@ -215,6 +225,20 @@ class FlightGroupSpawner:
|
|||||||
if slot.slot_name in [str(n) for n in range(55, 66)]
|
if slot.slot_name in [str(n) for n in range(55, 66)]
|
||||||
]
|
]
|
||||||
return self._generate_at_airfield(name, cp, slots)
|
return self._generate_at_airfield(name, cp, slots)
|
||||||
|
elif self._check_ramon_airbase_hack(cp):
|
||||||
|
# TODO: get rid of the ramon airbase hack once fixed in DCS...
|
||||||
|
slots = [
|
||||||
|
slot
|
||||||
|
for slot in cp.dcs_airport.free_parking_slots(
|
||||||
|
self.flight.squadron.aircraft.dcs_unit_type
|
||||||
|
)
|
||||||
|
if slot.slot_name
|
||||||
|
not in [
|
||||||
|
str(n)
|
||||||
|
for n in [1, 2, 3, 4, 5, 6, 13, 14, 15, 16, 17, 18, 61]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
return self._generate_at_airfield(name, cp, slots)
|
||||||
else:
|
else:
|
||||||
return self._generate_at_airfield(name, cp)
|
return self._generate_at_airfield(name, cp)
|
||||||
else:
|
else:
|
||||||
@ -237,6 +261,13 @@ class FlightGroupSpawner:
|
|||||||
nevatim_hack &= isinstance(cp.dcs_airport, Nevatim)
|
nevatim_hack &= isinstance(cp.dcs_airport, Nevatim)
|
||||||
return nevatim_hack
|
return nevatim_hack
|
||||||
|
|
||||||
|
def _check_ramon_airbase_hack(self, cp: ControlPoint) -> bool:
|
||||||
|
# TODO: get rid of the ramon airbase hack once fixed in DCS...
|
||||||
|
ramon_airbase_hack = self.flight.coalition.game.settings.nevatim_parking_fix
|
||||||
|
ramon_airbase_hack &= isinstance(self.mission.terrain, Sinai)
|
||||||
|
ramon_airbase_hack &= isinstance(cp.dcs_airport, Ramon_Airbase)
|
||||||
|
return ramon_airbase_hack
|
||||||
|
|
||||||
def generate_mid_mission(self) -> FlyingGroup[Any]:
|
def generate_mid_mission(self) -> FlyingGroup[Any]:
|
||||||
assert isinstance(self.flight.state, InFlight)
|
assert isinstance(self.flight.state, InFlight)
|
||||||
name = namegen.next_aircraft_name(self.country, self.flight)
|
name = namegen.next_aircraft_name(self.country, self.flight)
|
||||||
|
|||||||
@ -756,14 +756,22 @@ class Settings:
|
|||||||
"will not be included in automatically planned OCA packages."
|
"will not be included in automatically planned OCA packages."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
default_start_type_client: StartType = choices_option(
|
||||||
|
"Default start type for Player flights",
|
||||||
|
page=MISSION_GENERATOR_PAGE,
|
||||||
|
section=GAMEPLAY_SECTION,
|
||||||
|
choices={v.value: v for v in StartType},
|
||||||
|
default=StartType.COLD,
|
||||||
|
detail=("Default start type for flights containing Player/Client slots."),
|
||||||
|
)
|
||||||
nevatim_parking_fix: bool = boolean_option(
|
nevatim_parking_fix: bool = boolean_option(
|
||||||
"Force air-starts for all aircraft at Nevatim",
|
"Force air-starts for aircraft at Nevatim and Ramon Airbase inoperable parking slots",
|
||||||
page=MISSION_GENERATOR_PAGE,
|
page=MISSION_GENERATOR_PAGE,
|
||||||
section=GAMEPLAY_SECTION,
|
section=GAMEPLAY_SECTION,
|
||||||
default=True, # TODO: set to False or remove this when DCS is fixed
|
default=True, # TODO: set to False or remove this when DCS is fixed
|
||||||
detail=(
|
detail=(
|
||||||
"Air-starts forced for all aircraft at Nevatim except parking slots "
|
"Air-starts forced for all aircraft at Nevatim and Ramon Airbase except parking slots "
|
||||||
"55 till 65, since those are the only ones that work."
|
"which are known to work as of DCS World 2.9.4.53990."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
# Mission specific
|
# Mission specific
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
"""Maps generated units back to their Liberation types."""
|
"""Maps generated units back to their Retribution types."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|||||||
@ -30,7 +30,7 @@ def _build_version_string() -> str:
|
|||||||
return "-".join(components)
|
return "-".join(components)
|
||||||
|
|
||||||
|
|
||||||
#: Current version of Liberation.
|
#: Current version of Retribution.
|
||||||
VERSION = _build_version_string()
|
VERSION = _build_version_string()
|
||||||
|
|
||||||
#: The latest version of the campaign format. Increment this version whenever all
|
#: The latest version of the campaign format. Increment this version whenever all
|
||||||
|
|||||||
@ -89,8 +89,7 @@ class QFlightCreator(QDialog):
|
|||||||
roster = None
|
roster = None
|
||||||
else:
|
else:
|
||||||
roster = FlightRoster(
|
roster = FlightRoster(
|
||||||
squadron,
|
squadron, initial_size=self.flight_size_spinner.value()
|
||||||
initial_size=self.flight_size_spinner.value(),
|
|
||||||
)
|
)
|
||||||
self.roster_editor = FlightRosterEditor(squadron, roster)
|
self.roster_editor = FlightRosterEditor(squadron, roster)
|
||||||
self.flight_size_spinner.valueChanged.connect(self.roster_editor.resize)
|
self.flight_size_spinner.valueChanged.connect(self.roster_editor.resize)
|
||||||
@ -100,10 +99,12 @@ class QFlightCreator(QDialog):
|
|||||||
roster_layout.addWidget(QLabel("Assigned pilots:"))
|
roster_layout.addWidget(QLabel("Assigned pilots:"))
|
||||||
roster_layout.addLayout(self.roster_editor)
|
roster_layout.addLayout(self.roster_editor)
|
||||||
|
|
||||||
|
self.roster_editor.pilots_changed.connect(self.on_pilot_selected)
|
||||||
|
|
||||||
# When an off-map spawn overrides the start type to in-flight, we save
|
# 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
|
# the selected type into this value. If a non-off-map spawn is selected
|
||||||
# we restore the previous choice.
|
# we restore the previous choice.
|
||||||
self.restore_start_type = self.game.settings.default_start_type
|
self.restore_start_type: Optional[str] = None
|
||||||
self.start_type = QComboBox()
|
self.start_type = QComboBox()
|
||||||
for start_type in StartType:
|
for start_type in StartType:
|
||||||
self.start_type.addItem(start_type.value, start_type)
|
self.start_type.addItem(start_type.value, start_type)
|
||||||
@ -140,6 +141,8 @@ class QFlightCreator(QDialog):
|
|||||||
|
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
self.roster_editor.pilots_changed.emit()
|
||||||
|
|
||||||
def reject(self) -> None:
|
def reject(self) -> None:
|
||||||
super().reject()
|
super().reject()
|
||||||
# Clear the roster to return pilots to the pool.
|
# Clear the roster to return pilots to the pool.
|
||||||
@ -213,6 +216,8 @@ class QFlightCreator(QDialog):
|
|||||||
)
|
)
|
||||||
self.divert.change_aircraft(new_aircraft)
|
self.divert.change_aircraft(new_aircraft)
|
||||||
|
|
||||||
|
self.roster_editor.pilots_changed.emit()
|
||||||
|
|
||||||
def on_departure_changed(self, departure: ControlPoint) -> None:
|
def on_departure_changed(self, departure: ControlPoint) -> None:
|
||||||
if isinstance(departure, OffMapSpawn):
|
if isinstance(departure, OffMapSpawn):
|
||||||
previous_type = self.start_type.currentData()
|
previous_type = self.start_type.currentData()
|
||||||
@ -245,6 +250,8 @@ class QFlightCreator(QDialog):
|
|||||||
)
|
)
|
||||||
self.on_departure_changed(squadron.location)
|
self.on_departure_changed(squadron.location)
|
||||||
|
|
||||||
|
self.roster_editor.pilots_changed.emit()
|
||||||
|
|
||||||
def update_max_size(self, available: int) -> None:
|
def update_max_size(self, available: int) -> None:
|
||||||
aircraft = self.aircraft_selector.currentData()
|
aircraft = self.aircraft_selector.currentData()
|
||||||
if aircraft is None:
|
if aircraft is None:
|
||||||
@ -255,3 +262,23 @@ class QFlightCreator(QDialog):
|
|||||||
|
|
||||||
default_size = max(2, available, aircraft.max_group_size)
|
default_size = max(2, available, aircraft.max_group_size)
|
||||||
self.flight_size_spinner.setValue(default_size)
|
self.flight_size_spinner.setValue(default_size)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.roster_editor.pilots_changed.emit()
|
||||||
|
except AttributeError:
|
||||||
|
return
|
||||||
|
|
||||||
|
def on_pilot_selected(self):
|
||||||
|
# Pilot selection detected. If this is a player flight, set start_type
|
||||||
|
# as configured for players in the settings.
|
||||||
|
# Otherwise, set the start_type as configured for AI.
|
||||||
|
# https://github.com/dcs-liberation/dcs_liberation/issues/1567
|
||||||
|
|
||||||
|
roster = self.roster_editor.roster
|
||||||
|
|
||||||
|
if roster is not None and roster.player_count > 0:
|
||||||
|
start_type = self.game.settings.default_start_type_client
|
||||||
|
else:
|
||||||
|
start_type = self.game.settings.default_start_type
|
||||||
|
|
||||||
|
self.start_type.setCurrentText(start_type.value)
|
||||||
|
|||||||
@ -96,11 +96,16 @@ class PilotControls(QHBoxLayout):
|
|||||||
player_toggled = Signal()
|
player_toggled = Signal()
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, squadron: Optional[Squadron], roster: Optional[FlightRoster], idx: int
|
self,
|
||||||
|
squadron: Optional[Squadron],
|
||||||
|
roster: Optional[FlightRoster],
|
||||||
|
idx: int,
|
||||||
|
pilots_changed: Signal,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.roster = roster
|
self.roster = roster
|
||||||
self.pilot_index = idx
|
self.pilot_index = idx
|
||||||
|
self.pilots_changed = pilots_changed
|
||||||
|
|
||||||
self.selector = PilotSelector(squadron, roster, idx)
|
self.selector = PilotSelector(squadron, roster, idx)
|
||||||
self.selector.currentIndexChanged.connect(self.on_pilot_changed)
|
self.selector.currentIndexChanged.connect(self.on_pilot_changed)
|
||||||
@ -131,6 +136,8 @@ class PilotControls(QHBoxLayout):
|
|||||||
pilot.player = checked
|
pilot.player = checked
|
||||||
self.player_toggled.emit()
|
self.player_toggled.emit()
|
||||||
|
|
||||||
|
self.pilots_changed.emit()
|
||||||
|
|
||||||
def on_pilot_changed(self, index: int) -> None:
|
def on_pilot_changed(self, index: int) -> None:
|
||||||
pilot = self.selector.itemData(index)
|
pilot = self.selector.itemData(index)
|
||||||
self.player_checkbox.blockSignals(True)
|
self.player_checkbox.blockSignals(True)
|
||||||
@ -143,6 +150,10 @@ class PilotControls(QHBoxLayout):
|
|||||||
if self.roster is not None:
|
if self.roster is not None:
|
||||||
self.player_checkbox.setEnabled(self.roster.squadron.aircraft.flyable)
|
self.player_checkbox.setEnabled(self.roster.squadron.aircraft.flyable)
|
||||||
self.player_checkbox.blockSignals(False)
|
self.player_checkbox.blockSignals(False)
|
||||||
|
# on_pilot_changed should emit pilots_changed in its finally block,
|
||||||
|
# otherwise the start-type isn't updated if you have a single client
|
||||||
|
# pilot which you switch to a non-client pilot
|
||||||
|
self.pilots_changed.emit()
|
||||||
|
|
||||||
def update_available_pilots(self) -> None:
|
def update_available_pilots(self) -> None:
|
||||||
self.selector.rebuild()
|
self.selector.rebuild()
|
||||||
@ -174,9 +185,12 @@ class PilotControls(QHBoxLayout):
|
|||||||
|
|
||||||
class FlightRosterEditor(QVBoxLayout):
|
class FlightRosterEditor(QVBoxLayout):
|
||||||
MAX_PILOTS = 4
|
MAX_PILOTS = 4
|
||||||
|
pilots_changed = Signal()
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, squadron: Optional[Squadron], roster: Optional[IFlightRoster]
|
self,
|
||||||
|
squadron: Optional[Squadron],
|
||||||
|
roster: Optional[IFlightRoster],
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.roster = roster
|
self.roster = roster
|
||||||
@ -190,7 +204,7 @@ class FlightRosterEditor(QVBoxLayout):
|
|||||||
|
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
controls = PilotControls(squadron, roster, pilot_idx)
|
controls = PilotControls(squadron, roster, pilot_idx, self.pilots_changed)
|
||||||
controls.selector.available_pilots_changed.connect(
|
controls.selector.available_pilots_changed.connect(
|
||||||
make_reset_callback(pilot_idx)
|
make_reset_callback(pilot_idx)
|
||||||
)
|
)
|
||||||
@ -226,7 +240,12 @@ class FlightRosterEditor(QVBoxLayout):
|
|||||||
class QFlightSlotEditor(QGroupBox):
|
class QFlightSlotEditor(QGroupBox):
|
||||||
flight_resized = Signal(int)
|
flight_resized = Signal(int)
|
||||||
|
|
||||||
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
|
def __init__(
|
||||||
|
self,
|
||||||
|
package_model: PackageModel,
|
||||||
|
flight: Flight,
|
||||||
|
game: Game,
|
||||||
|
):
|
||||||
super().__init__("Slots")
|
super().__init__("Slots")
|
||||||
self.package_model = package_model
|
self.package_model = package_model
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
|
|||||||
@ -43,6 +43,25 @@ class QFlightStartType(QGroupBox):
|
|||||||
)
|
)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
def on_pilot_selected(self):
|
||||||
|
# Pilot selection detected. If this is a player flight, set start_type
|
||||||
|
# as configured for players in the settings.
|
||||||
|
# Otherwise, set the start_type as configured for AI.
|
||||||
|
# https://github.com/dcs-liberation/dcs_liberation/issues/1567
|
||||||
|
|
||||||
|
if self.flight.roster.player_count > 0:
|
||||||
|
self.flight.start_type = (
|
||||||
|
self.flight.coalition.game.settings.default_start_type_client
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.flight.start_type = (
|
||||||
|
self.flight.coalition.game.settings.default_start_type
|
||||||
|
)
|
||||||
|
|
||||||
|
self.start_type.setCurrentText(self.flight.start_type.value)
|
||||||
|
|
||||||
|
self.package_model.update_tot()
|
||||||
|
|
||||||
def _on_start_type_selected(self):
|
def _on_start_type_selected(self):
|
||||||
selected = self.start_type.currentData()
|
selected = self.start_type.currentData()
|
||||||
self.flight.start_type = selected
|
self.flight.start_type = selected
|
||||||
|
|||||||
@ -38,6 +38,17 @@ class QGeneralFlightSettingsTab(QFrame):
|
|||||||
self.flight_slot_editor.flight_resized.connect(self.flight_size_changed)
|
self.flight_slot_editor.flight_resized.connect(self.flight_size_changed)
|
||||||
for pc in self.flight_slot_editor.roster_editor.pilot_controls:
|
for pc in self.flight_slot_editor.roster_editor.pilot_controls:
|
||||||
pc.player_toggled.connect(self.on_player_toggle)
|
pc.player_toggled.connect(self.on_player_toggle)
|
||||||
|
pc.player_toggled.connect(
|
||||||
|
self.flight_slot_editor.roster_editor.pilots_changed
|
||||||
|
)
|
||||||
|
|
||||||
|
start_type = QFlightStartType(
|
||||||
|
package_model,
|
||||||
|
flight,
|
||||||
|
)
|
||||||
|
|
||||||
|
roster = self.flight_slot_editor.roster_editor
|
||||||
|
roster.pilots_changed.connect(start_type.on_pilot_selected)
|
||||||
|
|
||||||
widgets = [
|
widgets = [
|
||||||
QFlightTypeTaskInfo(flight),
|
QFlightTypeTaskInfo(flight),
|
||||||
@ -46,7 +57,7 @@ class QGeneralFlightSettingsTab(QFrame):
|
|||||||
game.game, package_model, flight, flight_wpt_list
|
game.game, package_model, flight, flight_wpt_list
|
||||||
),
|
),
|
||||||
self.flight_slot_editor,
|
self.flight_slot_editor,
|
||||||
QFlightStartType(package_model, flight),
|
start_type,
|
||||||
QFlightCustomName(flight),
|
QFlightCustomName(flight),
|
||||||
]
|
]
|
||||||
layout = QGridLayout()
|
layout = QGridLayout()
|
||||||
|
|||||||
@ -154,34 +154,34 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
|||||||
modLayout_row = 1
|
modLayout_row = 1
|
||||||
|
|
||||||
mod_pairs = [
|
mod_pairs = [
|
||||||
("F9F Panther (v2.8.7.101)", self.f9f_panther),
|
|
||||||
("A-4E Skyhawk (v2.2.0)", self.a4_skyhawk),
|
("A-4E Skyhawk (v2.2.0)", self.a4_skyhawk),
|
||||||
("A-6A Intruder (v2.7.5.01)", self.a6a_intruder),
|
("A-6A Intruder (v2.7.5.01)", self.a6a_intruder),
|
||||||
("A-7E Corsair II", self.a7e_corsair2),
|
("A-7E Corsair II", self.a7e_corsair2),
|
||||||
("C-130J-30 Super Hercules", self.hercules),
|
("C-130J-30 Super Hercules (v6.8.2)", self.hercules),
|
||||||
("F-4B/C Phantom II (2.8.7.204)", self.f4bc_phantom),
|
|
||||||
("F-15D Baz (v1.0)", self.f15d_baz),
|
|
||||||
("F-15I Ra'am (v1.0 by IDF Mods Project)", self.f_15_idf),
|
|
||||||
("F-16I Sufa & F-16D (v3.6 by IDF Mods Project)", self.f_16_idf),
|
|
||||||
("F/A-18E/F/G Super Hornet (version 2.2.5)", self.fa_18efg),
|
|
||||||
("F/A-18E/F Super Hornet AI Tanker (version 1.4)", self.fa18ef_tanker),
|
|
||||||
("F-22A Raptor", self.f22_raptor),
|
|
||||||
("F-84G Thunderjet (v2.5.7.01)", self.f84g_thunderjet),
|
|
||||||
("F-100 Super Sabre (v2.7.18.30765 patch 20.10.22)", self.f100_supersabre),
|
("F-100 Super Sabre (v2.7.18.30765 patch 20.10.22)", self.f100_supersabre),
|
||||||
("F-104 Starfighter (v2.7.11.222.01)", self.f104_starfighter),
|
("F-104 Starfighter (v2.7.11.222.01)", self.f104_starfighter),
|
||||||
("F-105 Thunderchief (v2.7.12.23x)", self.f105_thunderchief),
|
("F-105 Thunderchief (v2.7.12.23x)", self.f105_thunderchief),
|
||||||
("Frenchpack", self.frenchpack),
|
("F-15D Baz (v1.0)", self.f15d_baz),
|
||||||
|
("F-15I Ra'am (v1.0 by IDF Mods Project)", self.f_15_idf),
|
||||||
|
("F-16I Sufa & F-16D (v3.6 by IDF Mods Project)", self.f_16_idf),
|
||||||
|
("F-22A Raptor", self.f22_raptor),
|
||||||
|
("F-4B/C Phantom II (2.8.7.204)", self.f4bc_phantom),
|
||||||
|
("F-84G Thunderjet (v2.5.7.01)", self.f84g_thunderjet),
|
||||||
|
("F9F Panther (v2.8.7.101)", self.f9f_panther),
|
||||||
|
("F/A-18E/F Super Hornet AI Tanker (version 1.4)", self.fa18ef_tanker),
|
||||||
|
("F/A-18E/F/G Super Hornet (version 2.2.5)", self.fa_18efg),
|
||||||
|
("Frenchpack (v4.9.1)", self.frenchpack),
|
||||||
("High Digit SAMs", self.high_digit_sams),
|
("High Digit SAMs", self.high_digit_sams),
|
||||||
("Swedish Military Assets pack (1.10)", self.swedishmilitaryassetspack),
|
("IDF Assets Pack (v1.1 by IDF Mods Project)", self.irondome),
|
||||||
("JAS 39 Gripen (v1.8.5-beta)", self.jas39_gripen),
|
("JAS 39 Gripen (v1.8.5-beta)", self.jas39_gripen),
|
||||||
("OV-10A Bronco", self.ov10a_bronco),
|
("OV-10A Bronco", self.ov10a_bronco),
|
||||||
("Super Étendard (v2.5.5)", self.super_etendard),
|
|
||||||
("Su-30 Flanker-H (V2.7.3 beta)", self.su30_flanker_h),
|
|
||||||
("Su-57 Felon (build-04)", self.su57_felon),
|
|
||||||
("UH-60L Black Hawk (v1.3.1)", self.uh_60l),
|
|
||||||
("Star Wars Modpack 2.54+", self.SWPack),
|
|
||||||
("Spanish Naval Assets pack (desdemicabina 3.2.0)", self.spanishnavypack),
|
("Spanish Naval Assets pack (desdemicabina 3.2.0)", self.spanishnavypack),
|
||||||
("IDF Assets Pack (v1.1 by IDF Mods Project)", self.irondome),
|
("Star Wars Modpack 2.54+", self.SWPack),
|
||||||
|
("Su-30 Flanker-H (V2.7.3 beta)", self.su30_flanker_h),
|
||||||
|
("Su-57 Felon (build-04)", self.su57_felon),
|
||||||
|
("Super Étendard (v2.5.5)", self.super_etendard),
|
||||||
|
("Swedish Military Assets pack (1.10)", self.swedishmilitaryassetspack),
|
||||||
|
("UH-60L Black Hawk (v1.3.1)", self.uh_60l),
|
||||||
]
|
]
|
||||||
|
|
||||||
for i in range(len(mod_pairs)):
|
for i in range(len(mod_pairs)):
|
||||||
|
|||||||
@ -148,7 +148,7 @@ class QLiberationPreferences(QFrame):
|
|||||||
"You set an empty DCS Installation directory! "
|
"You set an empty DCS Installation directory! "
|
||||||
"<br/><br/>Without this directory, DCS Retribution can not replace the MissionScripting.lua for you and will not work properly. "
|
"<br/><br/>Without this directory, DCS Retribution can not replace the MissionScripting.lua for you and will not work properly. "
|
||||||
"In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)."
|
"In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)."
|
||||||
"<br/><br/>You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.</p>"
|
"<br/><br/>You can find more information on how to manually change this file in the Retribution Wiki (Page: Dedicated Server Guide) on GitHub.</p>"
|
||||||
"<br/><br/>Are you sure that you want to leave the installation directory empty?"
|
"<br/><br/>Are you sure that you want to leave the installation directory empty?"
|
||||||
"<br/><br/><strong>This is only recommended for expert users!</strong>",
|
"<br/><br/><strong>This is only recommended for expert users!</strong>",
|
||||||
QMessageBox.StandardButton.Yes,
|
QMessageBox.StandardButton.Yes,
|
||||||
@ -164,7 +164,7 @@ class QLiberationPreferences(QFrame):
|
|||||||
+ " is not a valid directory. DCS Retribution requires the installation directory to replace the MissionScripting.lua"
|
+ " is not a valid directory. DCS Retribution requires the installation directory to replace the MissionScripting.lua"
|
||||||
"<br/><br/>If you ignore this Error, DCS Retribution can not work properly and needs your attention. "
|
"<br/><br/>If you ignore this Error, DCS Retribution can not work properly and needs your attention. "
|
||||||
"In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)."
|
"In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)."
|
||||||
"<br/><br/>You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.</p>"
|
"<br/><br/>You can find more information on how to manually change this file in the Retribution Wiki (Page: Dedicated Server Guide) on GitHub.</p>"
|
||||||
"<br/><br/><strong>This is only recommended for expert users!</strong>",
|
"<br/><br/><strong>This is only recommended for expert users!</strong>",
|
||||||
QMessageBox.StandardButton.Ignore,
|
QMessageBox.StandardButton.Ignore,
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ theater: Caucasus
|
|||||||
authors: Khopa
|
authors: Khopa
|
||||||
recommended_player_faction: Russia 2010
|
recommended_player_faction: Russia 2010
|
||||||
recommended_enemy_faction: USA 1990
|
recommended_enemy_faction: USA 1990
|
||||||
description: <p>A small theater in Russia, progress from Mozdok to Maykop.</p><p>This scenario is pretty simple, and is ideal if you want to run a short campaign to try liberation. If your PC is not powerful, this is also the less performance heavy scenario.</p>
|
description: <p>A small theater in Russia, progress from Mozdok to Maykop.</p><p>This scenario is pretty simple, and is ideal if you want to run a short campaign to try Retribution. If your PC is not powerful, this is also the less performance heavy scenario.</p>
|
||||||
miz: mozdok_to_maykop.miz
|
miz: mozdok_to_maykop.miz
|
||||||
performance: 0
|
performance: 0
|
||||||
version: 9.0
|
version: 9.0
|
||||||
|
|||||||
@ -1,50 +1,95 @@
|
|||||||
local unitPayloads =
|
local unitPayloads = {
|
||||||
{
|
|
||||||
["name"] = "UH-60L",
|
["name"] = "UH-60L",
|
||||||
["payloads"] =
|
["payloads"] = {
|
||||||
{
|
[1] = {
|
||||||
[1] =
|
["name"] = "Liberation Air Assault",
|
||||||
{
|
["pylons"] = {
|
||||||
["name"] = "Retribution Ferry",
|
|
||||||
["pylons"] =
|
|
||||||
{
|
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{UH60_FUEL_TANK_230}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{UH60_FUEL_TANK_230}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{UH60_FUEL_TANK_230}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{UH60_FUEL_TANK_230}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 6,
|
["num"] = 6,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "{UH60_SEAT_GUNNER_L}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{UH60_SEAT_CARGO_ALL}",
|
["CLSID"] = "{UH60_SEAT_CARGO_ALL}",
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[7] = {
|
},
|
||||||
["CLSID"] = "{UH60_SEAT_GUNNER_R}",
|
["tasks"] = {
|
||||||
["num"] = 5,
|
[1] = 35,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["displayName"] = "Liberation Ferry",
|
||||||
|
["name"] = "Liberation Ferry",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{UH60_SEAT_CARGO_ALL}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] =
|
["tasks"] = {
|
||||||
{
|
[1] = 35,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["displayName"] = "Liberation Transport",
|
||||||
|
["name"] = "Liberation Transport",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{UH60_SEAT_CARGO_ALL}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
[1] = 35,
|
[1] = 35,
|
||||||
[2] = 17,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {},
|
["tasks"] = {
|
||||||
|
},
|
||||||
["unitType"] = "UH-60L",
|
["unitType"] = "UH-60L",
|
||||||
}
|
}
|
||||||
return unitPayloads
|
return unitPayloads
|
||||||
|
|||||||
@ -12,8 +12,11 @@
|
|||||||
"AJS-37 Viggen",
|
"AJS-37 Viggen",
|
||||||
"AV-8B Harrier II Night Attack",
|
"AV-8B Harrier II Night Attack",
|
||||||
"B-52H Stratofortress",
|
"B-52H Stratofortress",
|
||||||
|
"C-101CC Aviojet",
|
||||||
"C-130",
|
"C-130",
|
||||||
"C-130J-30 Super Hercules",
|
"C-130J-30 Super Hercules",
|
||||||
|
"CH-47D",
|
||||||
|
"CH-53E",
|
||||||
"F-14A Tomcat (Block 135-GR Late)",
|
"F-14A Tomcat (Block 135-GR Late)",
|
||||||
"F-14B Tomcat",
|
"F-14B Tomcat",
|
||||||
"F-15C Eagle",
|
"F-15C Eagle",
|
||||||
@ -22,6 +25,7 @@
|
|||||||
"F/A-18C Hornet (Lot 20)",
|
"F/A-18C Hornet (Lot 20)",
|
||||||
"F-4E Phantom II",
|
"F-4E Phantom II",
|
||||||
"F-5E Tiger II",
|
"F-5E Tiger II",
|
||||||
|
"Mi-8MTV2 Hip",
|
||||||
"MiG-21bis Fishbed-N",
|
"MiG-21bis Fishbed-N",
|
||||||
"Mirage-F1B",
|
"Mirage-F1B",
|
||||||
"Mirage-F1BE",
|
"Mirage-F1BE",
|
||||||
@ -31,7 +35,9 @@
|
|||||||
"S-3B Viking",
|
"S-3B Viking",
|
||||||
"SA 342L Gazelle",
|
"SA 342L Gazelle",
|
||||||
"SA 342M Gazelle",
|
"SA 342M Gazelle",
|
||||||
"UH-1H Iroquois"
|
"UH-1H Iroquois",
|
||||||
|
"UH-60A",
|
||||||
|
"UH-60L"
|
||||||
],
|
],
|
||||||
"awacs": [
|
"awacs": [
|
||||||
"E-2C Hawkeye",
|
"E-2C Hawkeye",
|
||||||
|
|||||||
@ -2,23 +2,27 @@
|
|||||||
"country": "Russia",
|
"country": "Russia",
|
||||||
"name": "Russia 1980",
|
"name": "Russia 1980",
|
||||||
"authors": "Starfire",
|
"authors": "Starfire",
|
||||||
"description": "<p>Soviet army in the 1980s.</p>",
|
"description": "<p>Soviet military in the 1980s.</p>",
|
||||||
"locales": [
|
"locales": [
|
||||||
"ru_RU"
|
"ru_RU"
|
||||||
],
|
],
|
||||||
"aircrafts": [
|
"aircrafts": [
|
||||||
|
"IL-76MD",
|
||||||
"Mi-24V Hind-E",
|
"Mi-24V Hind-E",
|
||||||
"Mi-24P Hind-F",
|
"Mi-24P Hind-F",
|
||||||
"Mi-8MTV2 Hip",
|
"Mi-8MTV2 Hip",
|
||||||
"MiG-21bis Fishbed-N",
|
"MiG-21bis Fishbed-N",
|
||||||
"MiG-23MLD Flogger-K",
|
"MiG-23MLD Flogger-K",
|
||||||
"MiG-25PD Foxbat-E",
|
"MiG-25PD Foxbat-E",
|
||||||
|
"MiG-27K Flogger-J2",
|
||||||
"MiG-29A Fulcrum-A",
|
"MiG-29A Fulcrum-A",
|
||||||
|
"MiG-31 Foxhound",
|
||||||
"Su-17M4 Fitter-K",
|
"Su-17M4 Fitter-K",
|
||||||
"Su-24M Fencer-D",
|
"Su-24M Fencer-D",
|
||||||
"Su-25 Frogfoot",
|
"Su-25 Frogfoot",
|
||||||
|
"Su-27 Flanker-B",
|
||||||
"Tu-142 Bear-F",
|
"Tu-142 Bear-F",
|
||||||
"Tu-22M3 Backfire-C",
|
"Tu-22M3 Backfire-C",
|
||||||
"Tu-95MS Bear-H"
|
"Tu-95MS Bear-H"
|
||||||
],
|
],
|
||||||
"awacs": [
|
"awacs": [
|
||||||
@ -60,7 +64,9 @@
|
|||||||
"KS-19/SON-9"
|
"KS-19/SON-9"
|
||||||
],
|
],
|
||||||
"naval_units": [
|
"naval_units": [
|
||||||
"Corvette 1241.1 Molniya"
|
"Corvette 1241.1 Molniya",
|
||||||
|
"Corvette 1124.4 Grish",
|
||||||
|
"SSK 877V Kilo"
|
||||||
],
|
],
|
||||||
"air_defense_units": [
|
"air_defense_units": [
|
||||||
"SAM P19 \"Flat Face\" SR (SA-2/3)",
|
"SAM P19 \"Flat Face\" SR (SA-2/3)",
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"defaultValue": true,
|
"defaultValue": true,
|
||||||
"specificOptions": [
|
"specificOptions": [
|
||||||
{
|
{
|
||||||
"nameInUI": "Tailor CTLD for the Liberation specific missions",
|
"nameInUI": "Tailor CTLD for the Retribution specific missions",
|
||||||
"mnemonic": "tailorctld",
|
"mnemonic": "tailorctld",
|
||||||
"defaultValue": true
|
"defaultValue": true
|
||||||
},
|
},
|
||||||
|
|||||||
@ -17,7 +17,7 @@ climate:
|
|||||||
day_night_temperature_difference: 11.0
|
day_night_temperature_difference: 11.0
|
||||||
seasons:
|
seasons:
|
||||||
# "winter" and "summer" are actually interpreted as northern hemisphere
|
# "winter" and "summer" are actually interpreted as northern hemisphere
|
||||||
# seasons in liberation, so these seasons are all inverted.
|
# seasons in Retribution, so these seasons are all inverted.
|
||||||
winter:
|
winter:
|
||||||
average_pressure: 29.63
|
average_pressure: 29.63
|
||||||
average_temperature: 21.0
|
average_temperature: 21.0
|
||||||
|
|||||||
BIN
resources/theaters/kola/icon.gif
Normal file
BIN
resources/theaters/kola/icon.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Loading…
x
Reference in New Issue
Block a user