diff --git a/.github/actions/build-app/action.yaml b/.github/actions/build-app/action.yaml index 23273108..a1e68b79 100644 --- a/.github/actions/build-app/action.yaml +++ b/.github/actions/build-app/action.yaml @@ -1,5 +1,5 @@ -name: Build Liberation package -description: Assembles the full Liberation application. +name: Build Retribution package +description: Assembles the full Retribution application. runs: using: composite steps: diff --git a/.github/actions/setup-liberation-js/action.yaml b/.github/actions/setup-liberation-js/action.yaml index 1408e66c..ad5b7727 100644 --- a/.github/actions/setup-liberation-js/action.yaml +++ b/.github/actions/setup-liberation-js/action.yaml @@ -1,5 +1,5 @@ -name: Liberation JS set-up -description: Sets up the Liberation Javascript environment. +name: Retribution JS set-up +description: Sets up the Retribution Javascript environment. runs: using: composite steps: diff --git a/.github/actions/setup-liberation-python/action.yaml b/.github/actions/setup-liberation-python/action.yaml index 4d2d7877..b634b99c 100644 --- a/.github/actions/setup-liberation-python/action.yaml +++ b/.github/actions/setup-liberation-python/action.yaml @@ -1,5 +1,5 @@ -name: Liberation Python set-up -description: Sets up the Liberation Python environment. +name: Retribution Python set-up +description: Sets up the Retribution Python environment. runs: using: composite steps: diff --git a/changelog.md b/changelog.md index 15288afa..00094acd 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,8 @@ * **[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 * **[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 * **[UI/UX]** A-10A flights can be edited again. diff --git a/game/ato/flightroster.py b/game/ato/flightroster.py index 859b891c..5cff9fe5 100644 --- a/game/ato/flightroster.py +++ b/game/ato/flightroster.py @@ -22,6 +22,10 @@ class FlightRoster(IFlightRoster): def iter_pilots(self) -> Iterator[Pilot | None]: 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: return self.pilots[idx] diff --git a/game/ato/iflightroster.py b/game/ato/iflightroster.py index 62ea8c6b..685bfad7 100644 --- a/game/ato/iflightroster.py +++ b/game/ato/iflightroster.py @@ -26,6 +26,11 @@ class IFlightRoster(ABC): def max_size(self) -> int: ... + @property + @abstractmethod + def player_count(self) -> int: + ... + @abstractmethod def resize(self, new_size: int) -> None: ... diff --git a/game/commander/packagebuilder.py b/game/commander/packagebuilder.py index 6f1fafcd..dcc50770 100644 --- a/game/commander/packagebuilder.py +++ b/game/commander/packagebuilder.py @@ -76,6 +76,12 @@ class PackageBuilder: member.assign_tgp_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) return True diff --git a/game/debriefing.py b/game/debriefing.py index e21f8ba6..e5da2add 100644 --- a/game/debriefing.py +++ b/game/debriefing.py @@ -363,7 +363,7 @@ class Debriefing: seen = set() captures = [] 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("||") # Only the most recent capture event matters. diff --git a/game/missiongenerator/aircraft/flightgroupspawner.py b/game/missiongenerator/aircraft/flightgroupspawner.py index f1b11b7a..fa868138 100644 --- a/game/missiongenerator/aircraft/flightgroupspawner.py +++ b/game/missiongenerator/aircraft/flightgroupspawner.py @@ -20,7 +20,7 @@ from dcs.planes import ( from dcs.point import PointAction from dcs.ships import KUZNECOW 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 ( FlyingGroup, ShipGroup, @@ -132,6 +132,16 @@ class FlightGroupSpawner: for slot in cp.dcs_airport.free_parking_slots(ac_type) 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( name=namegen.next_aircraft_name(self.country, self.flight), airfield=cp, @@ -215,6 +225,20 @@ class FlightGroupSpawner: if slot.slot_name in [str(n) for n in range(55, 66)] ] 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: return self._generate_at_airfield(name, cp) else: @@ -237,6 +261,13 @@ class FlightGroupSpawner: nevatim_hack &= isinstance(cp.dcs_airport, Nevatim) 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]: assert isinstance(self.flight.state, InFlight) name = namegen.next_aircraft_name(self.country, self.flight) diff --git a/game/settings/settings.py b/game/settings/settings.py index 42a7374d..d08bb7b4 100644 --- a/game/settings/settings.py +++ b/game/settings/settings.py @@ -756,14 +756,22 @@ class Settings: "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( - "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, section=GAMEPLAY_SECTION, default=True, # TODO: set to False or remove this when DCS is fixed detail=( - "Air-starts forced for all aircraft at Nevatim except parking slots " - "55 till 65, since those are the only ones that work." + "Air-starts forced for all aircraft at Nevatim and Ramon Airbase except parking slots " + "which are known to work as of DCS World 2.9.4.53990." ), ) # Mission specific diff --git a/game/unitmap.py b/game/unitmap.py index 2744ca7f..088d49ce 100644 --- a/game/unitmap.py +++ b/game/unitmap.py @@ -1,4 +1,4 @@ -"""Maps generated units back to their Liberation types.""" +"""Maps generated units back to their Retribution types.""" from __future__ import annotations import itertools diff --git a/game/version.py b/game/version.py index 4c092f62..ee43eed0 100644 --- a/game/version.py +++ b/game/version.py @@ -30,7 +30,7 @@ def _build_version_string() -> str: return "-".join(components) -#: Current version of Liberation. +#: Current version of Retribution. VERSION = _build_version_string() #: The latest version of the campaign format. Increment this version whenever all diff --git a/qt_ui/windows/mission/flight/QFlightCreator.py b/qt_ui/windows/mission/flight/QFlightCreator.py index aeee0952..6759f036 100644 --- a/qt_ui/windows/mission/flight/QFlightCreator.py +++ b/qt_ui/windows/mission/flight/QFlightCreator.py @@ -89,8 +89,7 @@ class QFlightCreator(QDialog): roster = None else: roster = FlightRoster( - squadron, - initial_size=self.flight_size_spinner.value(), + squadron, initial_size=self.flight_size_spinner.value() ) self.roster_editor = FlightRosterEditor(squadron, roster) 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.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 # the selected type into this value. If a non-off-map spawn is selected # 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() for start_type in StartType: self.start_type.addItem(start_type.value, start_type) @@ -140,6 +141,8 @@ class QFlightCreator(QDialog): self.setLayout(layout) + self.roster_editor.pilots_changed.emit() + def reject(self) -> None: super().reject() # Clear the roster to return pilots to the pool. @@ -213,6 +216,8 @@ class QFlightCreator(QDialog): ) self.divert.change_aircraft(new_aircraft) + self.roster_editor.pilots_changed.emit() + def on_departure_changed(self, departure: ControlPoint) -> None: if isinstance(departure, OffMapSpawn): previous_type = self.start_type.currentData() @@ -245,6 +250,8 @@ class QFlightCreator(QDialog): ) self.on_departure_changed(squadron.location) + self.roster_editor.pilots_changed.emit() + def update_max_size(self, available: int) -> None: aircraft = self.aircraft_selector.currentData() if aircraft is None: @@ -255,3 +262,23 @@ class QFlightCreator(QDialog): default_size = max(2, available, aircraft.max_group_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) diff --git a/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py b/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py index bd7f4426..4a153780 100644 --- a/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py +++ b/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py @@ -96,11 +96,16 @@ class PilotControls(QHBoxLayout): player_toggled = Signal() def __init__( - self, squadron: Optional[Squadron], roster: Optional[FlightRoster], idx: int + self, + squadron: Optional[Squadron], + roster: Optional[FlightRoster], + idx: int, + pilots_changed: Signal, ) -> None: super().__init__() self.roster = roster self.pilot_index = idx + self.pilots_changed = pilots_changed self.selector = PilotSelector(squadron, roster, idx) self.selector.currentIndexChanged.connect(self.on_pilot_changed) @@ -131,6 +136,8 @@ class PilotControls(QHBoxLayout): pilot.player = checked self.player_toggled.emit() + self.pilots_changed.emit() + def on_pilot_changed(self, index: int) -> None: pilot = self.selector.itemData(index) self.player_checkbox.blockSignals(True) @@ -143,6 +150,10 @@ class PilotControls(QHBoxLayout): if self.roster is not None: self.player_checkbox.setEnabled(self.roster.squadron.aircraft.flyable) 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: self.selector.rebuild() @@ -174,9 +185,12 @@ class PilotControls(QHBoxLayout): class FlightRosterEditor(QVBoxLayout): MAX_PILOTS = 4 + pilots_changed = Signal() def __init__( - self, squadron: Optional[Squadron], roster: Optional[IFlightRoster] + self, + squadron: Optional[Squadron], + roster: Optional[IFlightRoster], ) -> None: super().__init__() self.roster = roster @@ -190,7 +204,7 @@ class FlightRosterEditor(QVBoxLayout): return callback - controls = PilotControls(squadron, roster, pilot_idx) + controls = PilotControls(squadron, roster, pilot_idx, self.pilots_changed) controls.selector.available_pilots_changed.connect( make_reset_callback(pilot_idx) ) @@ -226,7 +240,12 @@ class FlightRosterEditor(QVBoxLayout): class QFlightSlotEditor(QGroupBox): 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") self.package_model = package_model self.flight = flight diff --git a/qt_ui/windows/mission/flight/settings/QFlightStartType.py b/qt_ui/windows/mission/flight/settings/QFlightStartType.py index 82c73cf0..7f8351cd 100644 --- a/qt_ui/windows/mission/flight/settings/QFlightStartType.py +++ b/qt_ui/windows/mission/flight/settings/QFlightStartType.py @@ -43,6 +43,25 @@ class QFlightStartType(QGroupBox): ) 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): selected = self.start_type.currentData() self.flight.start_type = selected diff --git a/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py b/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py index 5d2484fa..a04ab9ab 100644 --- a/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py +++ b/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py @@ -38,6 +38,17 @@ class QGeneralFlightSettingsTab(QFrame): self.flight_slot_editor.flight_resized.connect(self.flight_size_changed) for pc in self.flight_slot_editor.roster_editor.pilot_controls: 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 = [ QFlightTypeTaskInfo(flight), @@ -46,7 +57,7 @@ class QGeneralFlightSettingsTab(QFrame): game.game, package_model, flight, flight_wpt_list ), self.flight_slot_editor, - QFlightStartType(package_model, flight), + start_type, QFlightCustomName(flight), ] layout = QGridLayout() diff --git a/qt_ui/windows/newgame/WizardPages/QGeneratorSettings.py b/qt_ui/windows/newgame/WizardPages/QGeneratorSettings.py index 6ae2e895..f48eaa86 100644 --- a/qt_ui/windows/newgame/WizardPages/QGeneratorSettings.py +++ b/qt_ui/windows/newgame/WizardPages/QGeneratorSettings.py @@ -154,34 +154,34 @@ class GeneratorOptions(QtWidgets.QWizardPage): modLayout_row = 1 mod_pairs = [ - ("F9F Panther (v2.8.7.101)", self.f9f_panther), ("A-4E Skyhawk (v2.2.0)", self.a4_skyhawk), ("A-6A Intruder (v2.7.5.01)", self.a6a_intruder), ("A-7E Corsair II", self.a7e_corsair2), - ("C-130J-30 Super Hercules", 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), + ("C-130J-30 Super Hercules (v6.8.2)", self.hercules), ("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-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), - ("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), ("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), - ("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)): diff --git a/qt_ui/windows/preferences/QLiberationPreferences.py b/qt_ui/windows/preferences/QLiberationPreferences.py index ed56f7af..1f5fefa6 100644 --- a/qt_ui/windows/preferences/QLiberationPreferences.py +++ b/qt_ui/windows/preferences/QLiberationPreferences.py @@ -148,7 +148,7 @@ class QLiberationPreferences(QFrame): "You set an empty DCS Installation directory! " "

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)." - "

You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.

" + "

You can find more information on how to manually change this file in the Retribution Wiki (Page: Dedicated Server Guide) on GitHub.

" "

Are you sure that you want to leave the installation directory empty?" "

This is only recommended for expert users!", 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" "

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)." - "

You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.

" + "

You can find more information on how to manually change this file in the Retribution Wiki (Page: Dedicated Server Guide) on GitHub.

" "

This is only recommended for expert users!", QMessageBox.StandardButton.Ignore, QMessageBox.StandardButton.Ok, diff --git a/resources/campaigns/mozdok_to_maykop.yaml b/resources/campaigns/mozdok_to_maykop.yaml index de1bbbb7..ab4ba5f9 100644 --- a/resources/campaigns/mozdok_to_maykop.yaml +++ b/resources/campaigns/mozdok_to_maykop.yaml @@ -3,7 +3,7 @@ theater: Caucasus authors: Khopa recommended_player_faction: Russia 2010 recommended_enemy_faction: USA 1990 -description:

A small theater in Russia, progress from Mozdok to Maykop.

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.

+description:

A small theater in Russia, progress from Mozdok to Maykop.

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.

miz: mozdok_to_maykop.miz performance: 0 version: 9.0 diff --git a/resources/customized_payloads/UH-60L.lua b/resources/customized_payloads/UH-60L.lua index 73228a4e..572b0a33 100644 --- a/resources/customized_payloads/UH-60L.lua +++ b/resources/customized_payloads/UH-60L.lua @@ -1,50 +1,95 @@ -local unitPayloads = -{ +local unitPayloads = { ["name"] = "UH-60L", - ["payloads"] = - { - [1] = - { - ["name"] = "Retribution Ferry", - ["pylons"] = - { + ["payloads"] = { + [1] = { + ["name"] = "Liberation Air Assault", + ["pylons"] = { [1] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", + ["CLSID"] = "", ["num"] = 7, }, [2] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", + ["CLSID"] = "", ["num"] = 1, }, [3] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", + ["CLSID"] = "", ["num"] = 2, }, [4] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", + ["CLSID"] = "", ["num"] = 6, }, [5] = { - ["CLSID"] = "{UH60_SEAT_GUNNER_L}", - ["num"] = 3, - }, - [6] = { ["CLSID"] = "{UH60_SEAT_CARGO_ALL}", ["num"] = 4, }, - [7] = { - ["CLSID"] = "{UH60_SEAT_GUNNER_R}", - ["num"] = 5, + }, + ["tasks"] = { + [1] = 35, + }, + }, + [2] = { + ["displayName"] = "Liberation Ferry", + ["name"] = "Liberation Ferry", + ["pylons"] = { + [1] = { + ["CLSID"] = "", + ["num"] = 7, + }, + [2] = { + ["CLSID"] = "", + ["num"] = 1, + }, + [3] = { + ["CLSID"] = "{UH60_SEAT_CARGO_ALL}", + ["num"] = 4, + }, + [4] = { + ["CLSID"] = "", + ["num"] = 6, + }, + [5] = { + ["CLSID"] = "", + ["num"] = 2, }, }, - ["tasks"] = - { + ["tasks"] = { + [1] = 35, + }, + }, + [3] = { + ["displayName"] = "Liberation Transport", + ["name"] = "Liberation Transport", + ["pylons"] = { + [1] = { + ["CLSID"] = "", + ["num"] = 7, + }, + [2] = { + ["CLSID"] = "", + ["num"] = 1, + }, + [3] = { + ["CLSID"] = "", + ["num"] = 2, + }, + [4] = { + ["CLSID"] = "", + ["num"] = 6, + }, + [5] = { + ["CLSID"] = "{UH60_SEAT_CARGO_ALL}", + ["num"] = 4, + }, + }, + ["tasks"] = { [1] = 35, - [2] = 17, }, }, }, - ["tasks"] = {}, + ["tasks"] = { + }, ["unitType"] = "UH-60L", } return unitPayloads diff --git a/resources/factions/blufor_late_coldwar.json b/resources/factions/blufor_late_coldwar.json index 4db3730c..e57f9324 100644 --- a/resources/factions/blufor_late_coldwar.json +++ b/resources/factions/blufor_late_coldwar.json @@ -12,8 +12,11 @@ "AJS-37 Viggen", "AV-8B Harrier II Night Attack", "B-52H Stratofortress", + "C-101CC Aviojet", "C-130", "C-130J-30 Super Hercules", + "CH-47D", + "CH-53E", "F-14A Tomcat (Block 135-GR Late)", "F-14B Tomcat", "F-15C Eagle", @@ -22,6 +25,7 @@ "F/A-18C Hornet (Lot 20)", "F-4E Phantom II", "F-5E Tiger II", + "Mi-8MTV2 Hip", "MiG-21bis Fishbed-N", "Mirage-F1B", "Mirage-F1BE", @@ -31,7 +35,9 @@ "S-3B Viking", "SA 342L Gazelle", "SA 342M Gazelle", - "UH-1H Iroquois" + "UH-1H Iroquois", + "UH-60A", + "UH-60L" ], "awacs": [ "E-2C Hawkeye", diff --git a/resources/factions/russia_1980.json b/resources/factions/russia_1980.json index c45e5699..4d3128a9 100644 --- a/resources/factions/russia_1980.json +++ b/resources/factions/russia_1980.json @@ -2,23 +2,27 @@ "country": "Russia", "name": "Russia 1980", "authors": "Starfire", - "description": "

Soviet army in the 1980s.

", + "description": "

Soviet military in the 1980s.

", "locales": [ "ru_RU" ], "aircrafts": [ + "IL-76MD", "Mi-24V Hind-E", "Mi-24P Hind-F", "Mi-8MTV2 Hip", "MiG-21bis Fishbed-N", "MiG-23MLD Flogger-K", "MiG-25PD Foxbat-E", + "MiG-27K Flogger-J2", "MiG-29A Fulcrum-A", + "MiG-31 Foxhound", "Su-17M4 Fitter-K", "Su-24M Fencer-D", "Su-25 Frogfoot", + "Su-27 Flanker-B", "Tu-142 Bear-F", - "Tu-22M3 Backfire-C", + "Tu-22M3 Backfire-C", "Tu-95MS Bear-H" ], "awacs": [ @@ -60,7 +64,9 @@ "KS-19/SON-9" ], "naval_units": [ - "Corvette 1241.1 Molniya" + "Corvette 1241.1 Molniya", + "Corvette 1124.4 Grish", + "SSK 877V Kilo" ], "air_defense_units": [ "SAM P19 \"Flat Face\" SR (SA-2/3)", @@ -81,4 +87,4 @@ "carrier_names": [], "has_jtac": false, "doctrine": "coldwar" -} \ No newline at end of file +} diff --git a/resources/plugins/ctld/plugin.json b/resources/plugins/ctld/plugin.json index d50c8e85..b32bb266 100644 --- a/resources/plugins/ctld/plugin.json +++ b/resources/plugins/ctld/plugin.json @@ -3,7 +3,7 @@ "defaultValue": true, "specificOptions": [ { - "nameInUI": "Tailor CTLD for the Liberation specific missions", + "nameInUI": "Tailor CTLD for the Retribution specific missions", "mnemonic": "tailorctld", "defaultValue": true }, diff --git a/resources/theaters/falklands/info.yaml b/resources/theaters/falklands/info.yaml index 3f9e42c0..e0b36f68 100644 --- a/resources/theaters/falklands/info.yaml +++ b/resources/theaters/falklands/info.yaml @@ -17,7 +17,7 @@ climate: day_night_temperature_difference: 11.0 seasons: # "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: average_pressure: 29.63 average_temperature: 21.0 diff --git a/resources/theaters/kola/icon.gif b/resources/theaters/kola/icon.gif new file mode 100644 index 00000000..9ee5c925 Binary files /dev/null and b/resources/theaters/kola/icon.gif differ