diff --git a/changelog.md b/changelog.md index 00094acd..25b053ff 100644 --- a/changelog.md +++ b/changelog.md @@ -12,12 +12,16 @@ * **[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. +* **[AirWing]** Expose OPFOR Squadrons, giving the ability to change liveries, auto-assignable mission types & an easy way to retrieve debug information. +* **[ATO]** Allow planning as OPFOR +* **[Campaign Design]** Support for Kola map by Orbx +* **[UI]** Zoom level retained when switching campaigns ## Fixes -* **[UI/UX]** A-10A flights can be edited again. +* **[UI/UX]** A-10A flights can be edited again * **[Mission Generation]** IADS bug sometimes triggering "no skynet usable units" error during mission generation * **[New Game Wizard]** Campaign errors show a dialog again and avoid CTDs - +* **[UI]** Landmap wasn't updating when switching to a different theater # Retribution v1.3.1 #### Note: Re-save your missions in DCS' Mission Editor to avoid possible crashes due to datalink (usually the case when F-16C blk50s are used) when hosting missions on a dedicated server. diff --git a/client/src/api/_liberationApi.ts b/client/src/api/_liberationApi.ts index 8f527a49..3f33a591 100644 --- a/client/src/api/_liberationApi.ts +++ b/client/src/api/_liberationApi.ts @@ -466,6 +466,7 @@ export type Game = { navmeshes: NavMeshes; map_center?: LatLng; unculled_zones: UnculledZone[]; + map_zones: MapZones; }; export type MapZones = { inclusion: LatLng[][][]; diff --git a/client/src/api/mapZonesSlice.ts b/client/src/api/mapZonesSlice.ts new file mode 100644 index 00000000..979d778d --- /dev/null +++ b/client/src/api/mapZonesSlice.ts @@ -0,0 +1,34 @@ +import { RootState } from "../app/store"; +import { gameLoaded, gameUnloaded } from "./actions"; +import { createSlice } from "@reduxjs/toolkit"; +import { MapZones } from "./_liberationApi"; + +interface MapZonesState { + mapZones: MapZones; +} + +const initialState: MapZonesState = { + mapZones: { inclusion: [], exclusion: [], sea: [] }, +}; + +const mapZonesSlice = createSlice({ + name: "map", + initialState: initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(gameLoaded, (state, action) => { + if (action.payload != null) { + state.mapZones.exclusion = action.payload.map_zones.exclusion; + state.mapZones.inclusion = action.payload.map_zones.inclusion; + state.mapZones.sea = action.payload.map_zones.sea; + } + }); + builder.addCase(gameUnloaded, (state) => { + state.mapZones = initialState.mapZones; + }); + }, +}); + +export const selectMapZones = (state: RootState) => state.mapZones; + +export default mapZonesSlice.reducer; diff --git a/client/src/app/store.ts b/client/src/app/store.ts index bbb6eb83..1000c5fa 100644 --- a/client/src/app/store.ts +++ b/client/src/app/store.ts @@ -10,6 +10,7 @@ import supplyRoutesReducer from "../api/supplyRoutesSlice"; import tgosReducer from "../api/tgosSlice"; import threatZonesReducer from "../api/threatZonesSlice"; import unculledZonesReducer from "../api/unculledZonesSlice"; +import mapZonesReducer from "../api/mapZonesSlice"; import { Action, PreloadedState, @@ -31,6 +32,7 @@ const rootReducer = combineReducers({ threatZones: threatZonesReducer, [baseApi.reducerPath]: baseApi.reducer, unculledZones: unculledZonesReducer, + mapZones: mapZonesReducer, }); export function setupStore(preloadedState?: PreloadedState) { diff --git a/client/src/components/liberationmap/LiberationMap.tsx b/client/src/components/liberationmap/LiberationMap.tsx index 24253f73..97cfe342 100644 --- a/client/src/components/liberationmap/LiberationMap.tsx +++ b/client/src/components/liberationmap/LiberationMap.tsx @@ -25,10 +25,10 @@ export default function LiberationMap() { const map = useRef(null); const mapCenter = useAppSelector(selectMapCenter); useEffect(() => { - map.current?.setView(mapCenter, 8, { animate: true, duration: 1 }); + map.current?.setView(mapCenter, map.current?.getZoom() ?? 8, { animate: true, duration: 1 }); }); return ( - + diff --git a/client/src/components/terrainzones/TerrainZonesLayers.tsx b/client/src/components/terrainzones/TerrainZonesLayers.tsx index 5d5bb2c3..3ebbce6c 100644 --- a/client/src/components/terrainzones/TerrainZonesLayers.tsx +++ b/client/src/components/terrainzones/TerrainZonesLayers.tsx @@ -1,6 +1,7 @@ -import { useGetTerrainZonesQuery } from "../../api/liberationApi"; +import { useAppSelector } from "../../app/hooks"; import { LatLngLiteral } from "leaflet"; import { LayerGroup, LayersControl, Polygon } from "react-leaflet"; +import { selectMapZones } from "../../api/mapZonesSlice"; interface TerrainZoneLayerProps { zones: LatLngLiteral[][][]; @@ -28,33 +29,28 @@ function TerrainZoneLayer(props: TerrainZoneLayerProps) { } export default function TerrainZonesLayers() { - const { data, error, isLoading } = useGetTerrainZonesQuery(); + const zones = useAppSelector(selectMapZones).mapZones; var exclusion = <>; var inclusion = <>; var sea = <>; - if (error) { - console.error("Error while loading terrain zones", error); - } else if (isLoading) { - } else if (!data) { - console.log("Empty response when loading terrain zones"); - } else { + if (zones) { exclusion = ( ); inclusion = ( ); sea = ( - + ); } return ( diff --git a/game/server/game/models.py b/game/server/game/models.py index 610f2ae1..9454e1a3 100644 --- a/game/server/game/models.py +++ b/game/server/game/models.py @@ -9,7 +9,11 @@ from game.server.flights.models import FlightJs from game.server.frontlines.models import FrontLineJs from game.server.iadsnetwork.models import IadsNetworkJs from game.server.leaflet import LeafletPoint -from game.server.mapzones.models import ThreatZoneContainerJs, UnculledZoneJs +from game.server.mapzones.models import ( + ThreatZoneContainerJs, + UnculledZoneJs, + MapZonesJs, +) from game.server.navmesh.models import NavMeshesJs from game.server.supplyroutes.models import SupplyRouteJs from game.server.tgos.models import TgoJs @@ -29,6 +33,7 @@ class GameJs(BaseModel): navmeshes: NavMeshesJs map_center: LeafletPoint | None unculled_zones: list[UnculledZoneJs] + map_zones: MapZonesJs class Config: title = "Game" @@ -46,4 +51,5 @@ class GameJs(BaseModel): navmeshes=NavMeshesJs.from_game(game), map_center=game.theater.terrain.map_view_default.position.latlng(), unculled_zones=UnculledZoneJs.from_game(game), + map_zones=MapZonesJs.from_game(game), ) diff --git a/game/server/mapzones/models.py b/game/server/mapzones/models.py index f83f43e0..33eb6ba6 100644 --- a/game/server/mapzones/models.py +++ b/game/server/mapzones/models.py @@ -24,6 +24,18 @@ class MapZonesJs(BaseModel): def empty(cls) -> MapZonesJs: return MapZonesJs(inclusion=[], exclusion=[], sea=[]) + @classmethod + def from_game(cls, game: Game) -> MapZonesJs: + zones = game.theater.landmap + if zones is None: + return cls.empty() + + return MapZonesJs( + inclusion=ShapelyUtil.polys_to_leaflet(zones.inclusion_zones, game.theater), + exclusion=ShapelyUtil.polys_to_leaflet(zones.exclusion_zones, game.theater), + sea=ShapelyUtil.polys_to_leaflet(zones.sea_zones, game.theater), + ) + class UnculledZoneJs(BaseModel): position: LeafletPoint diff --git a/game/settings/settings.py b/game/settings/settings.py index d08bb7b4..e2745948 100644 --- a/game/settings/settings.py +++ b/game/settings/settings.py @@ -1198,7 +1198,6 @@ class Settings: # Cheating. Not using auto settings because the same page also has buttons which do # not alter settings. - show_red_ato: bool = False enable_frontline_cheats: bool = False enable_base_capture_cheat: bool = False enable_transfer_cheat: bool = False diff --git a/game/theater/theaterloader.py b/game/theater/theaterloader.py index f88096fd..b57b6306 100644 --- a/game/theater/theaterloader.py +++ b/game/theater/theaterloader.py @@ -17,6 +17,7 @@ from dcs.terrain import ( Syria, TheChannel, Sinai, + Kola, ) from .conflicttheater import ConflictTheater @@ -34,6 +35,7 @@ ALL_TERRAINS = [ TheChannel(), Syria(), Sinai(), + Kola(), ] TERRAINS_BY_NAME = {t.name: t for t in ALL_TERRAINS} diff --git a/qt_ui/dialogs.py b/qt_ui/dialogs.py index 92064768..8b13b954 100644 --- a/qt_ui/dialogs.py +++ b/qt_ui/dialogs.py @@ -37,7 +37,7 @@ class Dialog: def open_new_package_dialog(cls, mission_target: MissionTarget, parent=None): """Opens the dialog to create a new package with the given target.""" cls.new_package_dialog = QNewPackageDialog( - cls.game_model, cls.game_model.ato_model, mission_target, parent=parent + cls.game_model, mission_target, parent=parent ) cls.new_package_dialog.show() diff --git a/qt_ui/models.py b/qt_ui/models.py index ca93111a..eaa24a01 100644 --- a/qt_ui/models.py +++ b/qt_ui/models.py @@ -540,12 +540,14 @@ class GameModel: self.sim_controller = sim_controller self.transfer_model = TransferModel(self) self.blue_air_wing_model = AirWingModel(self, player=True) + self.red_air_wing_model = AirWingModel(self, player=False) if self.game is None: self.ato_model = AtoModel(self, AirTaskingOrder()) self.red_ato_model = AtoModel(self, AirTaskingOrder()) else: self.ato_model = AtoModel(self, self.game.blue.ato) self.red_ato_model = AtoModel(self, self.game.red.ato) + self.is_ownfor = True # For UI purposes self.allocated_freqs: list[RadioFrequency] = list() diff --git a/qt_ui/widgets/ato.py b/qt_ui/widgets/ato.py index 620ff659..48a6c07b 100644 --- a/qt_ui/widgets/ato.py +++ b/qt_ui/widgets/ato.py @@ -23,12 +23,14 @@ from PySide6.QtWidgets import ( QSplitter, QVBoxLayout, QMessageBox, + QCheckBox, ) from game.ato.flight import Flight from game.ato.package import Package from game.server import EventStream from game.sim import GameUpdateEvents +from .QLabeledWidget import QLabeledWidget from ..delegates import TwoColumnRowDelegate from ..models import AtoModel, GameModel, NullListModel, PackageModel @@ -484,8 +486,20 @@ class QAirTaskingOrderPanel(QSplitter): def __init__(self, game_model: GameModel) -> None: super().__init__(Qt.Orientation.Vertical) + self.game_model = game_model self.ato_model = game_model.ato_model + # ATO + self.red_ato_checkbox = QCheckBox() + self.red_ato_checkbox.toggled.connect(self.on_ato_changed) + self.red_ato_labeled = QLabeledWidget( + "Show/Plan OPFOR's ATO: ", self.red_ato_checkbox + ) + + self.ato_group_box = QGroupBox("ATO") + self.ato_group_box.setLayout(self.red_ato_labeled) + self.addWidget(self.ato_group_box) + self.package_panel = QPackagePanel(game_model, self.ato_model) self.package_panel.current_changed.connect(self.on_package_change) self.addWidget(self.package_panel) @@ -500,3 +514,17 @@ class QAirTaskingOrderPanel(QSplitter): self.flight_panel.set_package(self.ato_model.get_package_model(index)) else: self.flight_panel.set_package(None) + + def on_ato_changed(self) -> None: + opfor = self.red_ato_checkbox.isChecked() + ato_model = ( + self.game_model.red_ato_model if opfor else self.game_model.ato_model + ) + ato_model.layoutChanged.connect(self.package_panel.on_current_changed) + self.ato_model = ato_model + self.package_panel.ato_model = ato_model + self.package_panel.package_list.ato_model = ato_model + self.package_panel.package_list.setModel(ato_model) + self.package_panel.current_changed.connect(self.on_package_change) + self.flight_panel.flight_list.set_package(None) + self.game_model.is_ownfor = not opfor diff --git a/qt_ui/widgets/combos/QFlightTypeComboBox.py b/qt_ui/widgets/combos/QFlightTypeComboBox.py index f6f7e28a..b2ee30dd 100644 --- a/qt_ui/widgets/combos/QFlightTypeComboBox.py +++ b/qt_ui/widgets/combos/QFlightTypeComboBox.py @@ -11,12 +11,16 @@ class QFlightTypeComboBox(QComboBox): """Combo box for selecting a flight task type.""" def __init__( - self, theater: ConflictTheater, target: MissionTarget, settings: Settings + self, + theater: ConflictTheater, + target: MissionTarget, + settings: Settings, + is_ownfor: bool, ) -> None: super().__init__() self.theater = theater self.target = target - for mission_type in self.target.mission_types(for_player=True): + for mission_type in self.target.mission_types(for_player=is_ownfor): if mission_type == FlightType.AIR_ASSAULT and not settings.plugin_option( "ctld" ): diff --git a/qt_ui/windows/AirWingDialog.py b/qt_ui/windows/AirWingDialog.py index 87f902f3..ef2a9c80 100644 --- a/qt_ui/windows/AirWingDialog.py +++ b/qt_ui/windows/AirWingDialog.py @@ -245,7 +245,16 @@ class AirWingTabs(QTabWidget): game_model.game.theater, game_model.sim_controller, ), - "Squadrons", + "Squadrons OWNFOR", + ) + self.addTab( + SquadronList( + game_model.red_ato_model, + game_model.red_air_wing_model, + game_model.game.theater, + game_model.sim_controller, + ), + "Squadrons OPFOR", ) self.addTab(AirInventoryView(game_model), "Inventory") diff --git a/qt_ui/windows/GameUpdateSignal.py b/qt_ui/windows/GameUpdateSignal.py index daeb0725..f5739dc1 100644 --- a/qt_ui/windows/GameUpdateSignal.py +++ b/qt_ui/windows/GameUpdateSignal.py @@ -15,6 +15,7 @@ class GameUpdateSignal(QObject): budgetupdated = Signal(Game) game_state_changed = Signal(TurnState) debriefingReceived = Signal(Debriefing) + ato_changed = Signal() game_loaded = Signal(Game) @@ -41,6 +42,9 @@ class GameUpdateSignal(QObject): # noinspection PyUnresolvedReferences self.game_state_changed.emit(state) + def atoChanged(self) -> None: + self.ato_changed.emit() + @staticmethod def get_instance() -> GameUpdateSignal: return GameUpdateSignal.instance diff --git a/qt_ui/windows/mission/QAutoCreateDialog.py b/qt_ui/windows/mission/QAutoCreateDialog.py index 95fcb7dd..3792c6c4 100644 --- a/qt_ui/windows/mission/QAutoCreateDialog.py +++ b/qt_ui/windows/mission/QAutoCreateDialog.py @@ -31,11 +31,14 @@ def _spinbox_template() -> QSpinBox: class QAutoCreateDialog(QDialog): - def __init__(self, game: Game, model: PackageModel, parent=None) -> None: + def __init__( + self, game: Game, model: PackageModel, is_ownfor: bool, parent=None + ) -> None: super().__init__(parent) self.game = game self.package_model = model self.package = model.package + self.is_ownfor = is_ownfor self.setMinimumSize(300, 400) self.setWindowTitle( @@ -159,7 +162,7 @@ class QAutoCreateDialog(QDialog): FlightType.BAI, FlightType.CAS, } - for mt in self.package.target.mission_types(True): + for mt in self.package.target.mission_types(self.is_ownfor): if mt in primary_tasks: self.primary_combobox.addItem(mt.value, mt) self.primary_combobox.setCurrentIndex(0) @@ -172,15 +175,16 @@ class QAutoCreateDialog(QDialog): return cb def _create_type_selector(self, flight_type: FlightType) -> QComboBox: - airwing = self.game.blue.air_wing + air_wing = self.game.blue.air_wing if self.is_ownfor else self.game.red.air_wing cb = QComboBox() - for ac in airwing.best_available_aircrafts_for(flight_type): + for ac in air_wing.best_available_aircrafts_for(flight_type): cb.addItem(ac.variant_id, ac) return cb def _load_aircraft_types(self): self.primary_type.clear() - for ac in self.game.blue.air_wing.best_available_aircrafts_for( + air_wing = self.game.blue.air_wing if self.is_ownfor else self.game.red.air_wing + for ac in air_wing.best_available_aircrafts_for( self.primary_combobox.currentData() ): self.primary_type.addItem(ac.variant_id, ac) @@ -217,7 +221,7 @@ class QAutoCreateDialog(QDialog): with tracer.trace(f"Auto-plan package"): pm = ProposedMission(self.package.target, pf, asap=True) pff = PackageFulfiller( - self.game.coalition_for(True), + self.game.coalition_for(self.is_ownfor), self.game.theater, self.game.db.flights, self.game.settings, diff --git a/qt_ui/windows/mission/QPackageDialog.py b/qt_ui/windows/mission/QPackageDialog.py index 75412f92..30d430a8 100644 --- a/qt_ui/windows/mission/QPackageDialog.py +++ b/qt_ui/windows/mission/QPackageDialog.py @@ -198,7 +198,10 @@ class QPackageDialog(QDialog): def on_add_flight(self) -> None: """Opens the new flight dialog.""" self.add_flight_dialog = QFlightCreator( - self.game, self.package_model.package, parent=self.window() + self.game, + self.package_model.package, + is_ownfor=self.game_model.is_ownfor, + parent=self.window(), ) self.add_flight_dialog.created.connect(self.add_flight) self.add_flight_dialog.show() @@ -235,7 +238,10 @@ class QPackageDialog(QDialog): def on_auto_create(self) -> None: """Opens the new flight dialog.""" auto_create_dialog = QAutoCreateDialog( - self.game, self.package_model, parent=self.window() + self.game, + self.package_model, + self.game_model.is_ownfor, + parent=self.window(), ) if auto_create_dialog.exec_() == QDialog.DialogCode.Accepted: for f in self.package_model.package.flights: @@ -275,7 +281,7 @@ class QNewPackageDialog(QPackageDialog): """ def __init__( - self, game_model: GameModel, model: AtoModel, target: MissionTarget, parent=None + self, game_model: GameModel, target: MissionTarget, parent=None ) -> None: super().__init__( game_model, @@ -284,7 +290,9 @@ class QNewPackageDialog(QPackageDialog): ), parent=parent, ) - self.ato_model = model + self.ato_model = ( + game_model.ato_model if game_model.is_ownfor else game_model.red_ato_model + ) # In the *new* package dialog, a package has been created and may have aircraft # assigned to it, but it is not a part of the ATO until the user saves it. diff --git a/qt_ui/windows/mission/flight/QFlightCreator.py b/qt_ui/windows/mission/flight/QFlightCreator.py index 6759f036..6143c868 100644 --- a/qt_ui/windows/mission/flight/QFlightCreator.py +++ b/qt_ui/windows/mission/flight/QFlightCreator.py @@ -33,7 +33,9 @@ from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import FlightRoster class QFlightCreator(QDialog): created = Signal(Flight) - def __init__(self, game: Game, package: Package, parent=None) -> None: + def __init__( + self, game: Game, package: Package, is_ownfor: bool, parent=None + ) -> None: super().__init__(parent=parent) self.setMinimumWidth(400) @@ -50,23 +52,22 @@ class QFlightCreator(QDialog): layout = QVBoxLayout() self.task_selector = QFlightTypeComboBox( - self.game.theater, package.target, self.game.settings + self.game.theater, package.target, self.game.settings, is_ownfor ) self.task_selector.setCurrentIndex(0) self.task_selector.currentIndexChanged.connect(self.on_task_changed) layout.addLayout(QLabeledWidget("Task:", self.task_selector)) + self.air_wing = self.game.blue.air_wing if is_ownfor else self.game.red.air_wing self.aircraft_selector = QAircraftTypeSelector( - self.game.blue.air_wing.best_available_aircrafts_for( - self.task_selector.currentData() - ) + self.air_wing.best_available_aircrafts_for(self.task_selector.currentData()) ) self.aircraft_selector.setCurrentIndex(0) self.aircraft_selector.currentIndexChanged.connect(self.on_aircraft_changed) layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector)) self.squadron_selector = SquadronSelector( - self.game.air_wing_for(player=True), + self.air_wing, self.task_selector.currentData(), self.aircraft_selector.currentData(), ) @@ -74,7 +75,7 @@ class QFlightCreator(QDialog): layout.addLayout(QLabeledWidget("Squadron:", self.squadron_selector)) self.divert = QArrivalAirfieldSelector( - [cp for cp in game.theater.controlpoints if cp.captured], + [cp for cp in game.theater.controlpoints if cp.captured == is_ownfor], self.aircraft_selector.currentData(), "None", ) @@ -84,10 +85,12 @@ class QFlightCreator(QDialog): self.update_max_size(self.squadron_selector.aircraft_available) layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner)) + required_start_type = None squadron = self.squadron_selector.currentData() if squadron is None: roster = None else: + required_start_type = squadron.location.required_aircraft_start_type roster = FlightRoster( squadron, initial_size=self.flight_size_spinner.value() ) @@ -107,7 +110,7 @@ class QFlightCreator(QDialog): 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) + self.start_type.addItem(start_type.value, userData=start_type) self.start_type.setCurrentText(self.game.settings.default_start_type.value) layout.addLayout( QLabeledWidget( @@ -116,8 +119,7 @@ class QFlightCreator(QDialog): tooltip="Selects the start type for this flight.", ) ) - if squadron is not None and isinstance(squadron.location, OffMapSpawn): - self.start_type.setCurrentText(StartType.IN_FLIGHT.value) + if squadron is not None and required_start_type: self.start_type.setEnabled(False) layout.addWidget( QLabel( @@ -234,7 +236,7 @@ class QFlightCreator(QDialog): def on_task_changed(self, index: int) -> None: task = self.task_selector.itemData(index) self.aircraft_selector.update_items( - self.game.blue.air_wing.best_available_aircrafts_for(task) + self.air_wing.best_available_aircrafts_for(task) ) self.squadron_selector.update_items(task, self.aircraft_selector.currentData()) @@ -275,8 +277,14 @@ class QFlightCreator(QDialog): # https://github.com/dcs-liberation/dcs_liberation/issues/1567 roster = self.roster_editor.roster + required_start_type = None + squadron = self.squadron_selector.currentData() + if squadron: + required_start_type = squadron.location.required_aircraft_start_type - if roster is not None and roster.player_count > 0: + if required_start_type: + start_type = required_start_type + elif 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 diff --git a/qt_ui/windows/settings/QSettingsWindow.py b/qt_ui/windows/settings/QSettingsWindow.py index 8e44f809..6d4525b2 100644 --- a/qt_ui/windows/settings/QSettingsWindow.py +++ b/qt_ui/windows/settings/QSettingsWindow.py @@ -54,13 +54,6 @@ class CheatSettingsBox(QGroupBox): self.main_layout = QVBoxLayout() self.setLayout(self.main_layout) - # ATO - self.red_ato_checkbox = QCheckBox() - self.red_ato_checkbox.setChecked(sc.settings.show_red_ato) - self.red_ato_checkbox.toggled.connect(apply_settings) - self.red_ato = QLabeledWidget("Show Red ATO:", self.red_ato_checkbox) - self.main_layout.addLayout(self.red_ato) - # Frontline self.frontline_cheat_checkbox = QCheckBox() self.frontline_cheat_checkbox.setChecked(sc.settings.enable_frontline_cheats) @@ -122,10 +115,6 @@ class CheatSettingsBox(QGroupBox): ) self.main_layout.addLayout(self.redfor_buysell_cheat) - @property - def show_red_ato(self) -> bool: - return self.red_ato_checkbox.isChecked() - @property def show_frontline_cheat(self) -> bool: return self.frontline_cheat_checkbox.isChecked() @@ -496,7 +485,6 @@ class QSettingsWidget(QtWidgets.QWizardPage, SettingsContainer): def applySettings(self): if self.updating_ui: return - self.settings.show_red_ato = self.cheat_options.show_red_ato self.settings.enable_frontline_cheats = self.cheat_options.show_frontline_cheat self.settings.enable_base_capture_cheat = ( self.cheat_options.show_base_capture_cheat @@ -525,7 +513,6 @@ class QSettingsWidget(QtWidgets.QWizardPage, SettingsContainer): for p in self.pages.values(): p.update_from_settings() - self.cheat_options.red_ato_checkbox.setChecked(self.settings.show_red_ato) self.cheat_options.base_capture_cheat_checkbox.setChecked( self.settings.enable_base_capture_cheat ) diff --git a/requirements.txt b/requirements.txt index 10e0ba0d..268346e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,7 +32,7 @@ pluggy==1.5.0 pre-commit==3.7.0 pydantic==2.7.1 pydantic-settings==2.2.1 -pydcs @ git+https://github.com/dcs-retribution/pydcs@ab2f274c0882f13918ca6f4be3c6c8bdc71818e0 +pydcs @ git+https://github.com/dcs-retribution/pydcs@961b5e1109c416f1a168d10db52c34bede6306af pyinstaller==5.13.2 pyinstaller-hooks-contrib==2024.0 pyparsing==3.1.2 diff --git a/resources/campaigns/exercise_able_archer.miz b/resources/campaigns/exercise_able_archer.miz new file mode 100644 index 00000000..bcebb59c Binary files /dev/null and b/resources/campaigns/exercise_able_archer.miz differ diff --git a/resources/campaigns/exercise_able_archer.yaml b/resources/campaigns/exercise_able_archer.yaml new file mode 100644 index 00000000..41e114c1 --- /dev/null +++ b/resources/campaigns/exercise_able_archer.yaml @@ -0,0 +1,240 @@ +--- +name: Kola Peninsula - Able Archer 83 +theater: Kola +authors: Starfire +recommended_player_faction: Blufor Late Cold War (80s) +recommended_enemy_faction: Russia 1980 +description: +

In 1983 during the height of the Cold War, tensions escalate to a breaking point as the Soviet Union, misinterpreting NATO's Able Archer 83 exercise as a genuine mobilisation for a surprise nuclear attack, decides to launch a pre-emptive conventional strike. On the 9th of November, Soviet forces commence a sudden and overwhelming invasion of Finland and Norway, aiming to secure strategic territories and disrupt NATO's northern flank before it can organize an effective response.

+miz: exercise_able_archer.miz +performance: 1 +recommended_start_date: 1983-11-09 +version: "10.7" +settings: + restrict_weapons_by_date: true + hercules: true +squadrons: + #Bodo + 7: + - primary: CAS + secondary: any + aircraft: + - A-10A Thunderbolt II + size: 8 + - primary: BARCAP + secondary: any + aircraft: + - F-5E Tiger II + size: 12 + - primary: TARCAP + secondary: any + aircraft: + - F-15C Eagle + size: 16 + - primary: Escort + secondary: any + aircraft: + - Mirage F1CE + size: 12 + - primary: BAI + secondary: any + aircraft: + - F-4E Phantom II + size: 12 + - primary: Refueling + aircraft: + - KC-135 Stratotanker + size: 1 + - primary: Air Assault + secondary: any + aircraft: + - C-130J-30 Super Hercules + - C-130 + size: 4 + - primary: Transport + secondary: any + aircraft: + - CH-47D + size: 2 + #Lakselv + 1: + - primary: SEAD + secondary: any + aircraft: + - F-16CM Fighting Falcon (Block 50) + size: 16 + - primary: CAS + secondary: any + aircraft: + - SA 342L Gazelle + size: 2 + - primary: Refueling + aircraft: + - KC-130 + size: 1 + - primary: Air Assault + secondary: any + aircraft: + - C-130J-30 Super Hercules + - C-130 + size: 2 + #Rovaniemi + 2: + - primary: BARCAP + secondary: any + aircraft: + - MiG-21bis Fishbed-N + size: 12 + - primary: Air Assault + secondary: any + aircraft: + - Mi-8MTV2 Hip + size: 4 + #Kemi Tornio + 3: + - primary: Transport + secondary: any + aircraft: + - C-47 Dakota + size: 3 + #Kiruna (14) + 5: + - primary: DEAD + secondary: air-to-ground + aircraft: + - AJS-37 Viggen + size: 10 + #Blue Carrier + Blue-CV: + - primary: TARCAP + secondary: any + aircraft: + - F-14A Tomcat + size: 24 + - primary: AEW&C + aircraft: + - E-2C Hawkeye + size: 4 + - primary: BAI + secondary: air-to-ground + aircraft: + - S-3B Viking + size: 12 + - primary: Air Assault + secondary: any + aircraft: + - UH-60L + - UH-60A + size: 4 + #Blue LHA + Blue-LHA: + - primary: DEAD + secondary: air-to-ground + aircraft: + - AV-8B Harrier II Night Attack + size: 12 + - primary: Air Assault + secondary: any + aircraft: + - UH-1H Iroquois + size: 4 + - primary: Escort + secondary: any + aircraft: + - AH-1J SeaCobra + size: 4 + #RAF Fairfield + Bombers from RAF Fairford: + - primary: Strike + secondary: any + aircraft: + - B-52H Stratofortress + size: 8 + #Bas 100 + 4: + - primary: CAS + secondary: air-to-ground + aircraft: + - Su-25 Frogfoot + size: 4 + - primary: DEAD + secondary: air-to-ground + aircraft: + - Su-17M4 Fitter-K + size: 6 + #Severomorsk1 + 8: + - primary: BARCAP + secondary: any + aircraft: + - MiG-31 Foxhound + size: 4 + - primary: Escort + secondary: any + aircraft: + - MiG-23ML Flogger-G + size: 8 + - primary: SEAD + secondary: any + aircraft: + - MiG-27K Flogger-J2 + size: 16 + #Severomorsk3 + 6: + - primary: AEW&C + aircraft: + - A-50 + size: 1 + - primary: Refueling + aircraft: + - IL-78M + size: 1 + - primary: DEAD + secondary: any + aircraft: + - Su-24M Fencer-D + size: 20 + - primary: TARCAP + secondary: any + aircraft: + - Su-27 Flanker-B + size: 8 + - primary: Air Assault + secondary: any + aircraft: + - Mi-8MTV2 Hip + size: 4 + #Olenegorsk + 9: + - primary: Strike + secondary: any + aircraft: + - Tu-95MS Bear-H + size: 16 + - primary: Strike + secondary: any + aircraft: + - Tu-22M3 Backfire-C + size: 16 + - primary: Transport + secondary: any + aircraft: + - IL-76MD + size: 2 + #Monchegorsk + 10: + - primary: BARCAP + secondary: any + aircraft: + - MiG-25PD Foxbat-E + size: 4 + - primary: Escort + secondary: any + aircraft: + - MiG-29A Fulcrum-A + size: 8 + - primary: BAI + secondary: any + aircraft: + - MiG-21bis Fishbed-N + size: 16 \ No newline at end of file diff --git a/resources/campaigns/exercise_bright_star.miz b/resources/campaigns/exercise_bright_star.miz index 045f63a8..577cc290 100644 Binary files a/resources/campaigns/exercise_bright_star.miz and b/resources/campaigns/exercise_bright_star.miz differ diff --git a/resources/campaigns/exercise_bright_star.yaml b/resources/campaigns/exercise_bright_star.yaml index 23fc787d..13229e69 100644 --- a/resources/campaigns/exercise_bright_star.yaml +++ b/resources/campaigns/exercise_bright_star.yaml @@ -86,21 +86,16 @@ squadrons: size: 12 # Ramon Airbase 9: - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 20 - primary: BARCAP secondary: any aircraft: - Mirage 2000C size: 12 - - primary: Transport + - primary: DEAD secondary: any aircraft: - - CH-47D - size: 12 + - F-16CM Fighting Falcon (Block 50) + size: 20 - primary: BAI secondary: any aircraft: diff --git a/resources/campaigns/operation_allied_sword.yaml b/resources/campaigns/operation_allied_sword.yaml index ae78eea7..2d32f7ba 100644 --- a/resources/campaigns/operation_allied_sword.yaml +++ b/resources/campaigns/operation_allied_sword.yaml @@ -2,8 +2,171 @@ name: Syria - Operation Allied Sword theater: Syria authors: Fuzzle -recommended_player_faction: Israel-USN 2005 (Allied Sword) -recommended_enemy_faction: Syria-Lebanon 2005 (Allied Sword) +recommended_player_faction: + country: Combined Joint Task Forces Blue + name: Israel-USN 2005 + authors: Fuzzle + description: +

A joint US Navy/Israeli modern faction for use with the Operation Allied + Sword scenario.

+ locales: + - en_US + aircrafts: + - F-4E Phantom II + - F-15C Eagle + - F-15E Strike Eagle + - F-15E Strike Eagle (Suite 4+) + - F-16CM Fighting Falcon (Block 50) + - F-14B Tomcat + - F/A-18C Hornet (Lot 20) + - AV-8B Harrier II Night Attack + - AH-1W SuperCobra + - AH-64D Apache Longbow + - AH-64D Apache Longbow (AI) + - S-3B Viking + - SH-60B Seahawk + - UH-1H Iroquois + - UH-60L + awacs: + - E-2C Hawkeye + tankers: + - KC-130 + - S-3B Tanker + frontline_units: + - M113 + - M1043 HMMWV (M2 HMG) + - M1045 HMMWV (BGM-71 TOW) + - Merkava Mk IV + - M163 Vulcan Air Defense System + artillery_units: + - M109A6 Paladin + - M270 Multiple Launch Rocket System + logistics_units: + - Truck M818 6x6 + infantry_units: + - Infantry M4 + - Infantry M249 + - MANPADS Stinger + preset_groups: + - Hawk + - Patriot + naval_units: + - FFG Oliver Hazard Perry + - DDG Arleigh Burke IIa + - CG Ticonderoga + - LHA-1 Tarawa + - CVN-74 John C. Stennis + missiles: [] + air_defense_units: + - SAM Hawk SR (AN/MPQ-50) + - M163 Vulcan Air Defense System + - M48 Chaparral + requirements: {} + carrier_names: + - CVN-71 Theodore Roosevelt + - CVN-72 Abraham Lincoln + - CVN-73 George Washington + - CVN-74 John C. Stennis + - CVN-75 Harry S. Truman + helicopter_carrier_names: + - LHA-1 Tarawa + - LHA-2 Saipan + - LHA-3 Belleau Wood + - LHA-4 Nassau + - LHA-5 Peleliu + has_jtac: true + jtac_unit: MQ-9 Reaper + doctrine: modern + liveries_overrides: + F-14B Tomcat: + - VF-142 Ghostriders + F/A-18C Hornet (Lot 20): + - VMFA-251 high visibility + AV-8B Harrier II Night Attack: + - VMAT-542 + AH-1W SuperCobra: + - Marines + UH-1H Iroquois: + - US NAVY + UH-60L: + - Israeli Air Force + unrestricted_satnav: true +recommended_enemy_faction: + country: Combined Joint Task Forces Red + name: Syria-Lebanon 2005 (Allied Sword) + authors: Fuzzle + description: +

Syria-Lebanon alliance in a modern setting with several imported Russian + assets. Designed for use with the Allied Sword scenario.

+ aircrafts: + - MiG-23ML Flogger-G + - MiG-29A Fulcrum-A + - Su-17M4 Fitter-K + - Su-24M Fencer-D + - Su-30 Flanker-C + - Su-34 Fullback + - L-39ZA Albatros + - Tu-22M3 Backfire-C + - Mi-24V Hind-E + - Mi-8MTV2 Hip + - SA 342L Gazelle + - IL-76MD + awacs: + - A-50 + tankers: + - IL-78M + frontline_units: + - BMP-1 + - BMP-2 + - BTR-80 + - BRDM-2 + - MT-LB + - T-55A + - T-72B with Kontakt-1 ERA + - T-90A + - ZSU-57-2 'Sparka' + artillery_units: + - BM-21 Grad + - 2S1 Gvozdika + logistics_units: + - Truck Ural-375 + - LUV UAZ-469 Jeep + infantry_units: + - Paratrooper AKS + - Infantry AK-74 Rus + - Paratrooper RPG-16 + - MANPADS SA-18 Igla-S "Grouse" + preset_groups: + - SA-2/S-75 + - SA-3/S-125 + - SA-6 + - SA-11 + - SA-10/S-300PS + - Silkworm + - Cold-War-Flak + - Russian Navy + naval_units: + - Corvette 1124.4 Grish + - Corvette 1241.1 Molniya + - FAC La Combattante IIa + - Frigate 1135M Rezky + air_defense_units: + - SAM P19 "Flat Face" SR (SA-2/3) + - EWR 1L13 + - EWR 55G6 + - SAM SA-8 Osa "Gecko" TEL + - SA-9 Strela + - SA-13 Gopher (9K35 Strela-10M3) + - SA-19 Grison (2K22 Tunguska) + - ZSU-57-2 'Sparka' + - AAA ZU-23 Closed Emplacement + - ZU-23 on Ural-375 + - ZSU-23-4 Shilka + missiles: + - SSM SS-1C Scud-B + helicopter_carrier_names: [] + requirements: {} + carrier_names: [] description:

In this fictional scenario, a US/Israeli coalition must push north from the Israeli border, through Syria and Lebanon to @@ -13,7 +176,6 @@ description: counterattack. The US Navy will handle the Beirut region's coastal arena, while the IAF will push through Damascus and the inland mountain ranges.

version: "10.7" -advanced_iads: true miz: operation_allied_sword.miz performance: 2 recommended_start_date: 2004-07-17 @@ -89,7 +251,7 @@ squadrons: - primary: CAS secondary: air-to-ground aircraft: - - AH-64D Apache Longbow + - 113th Squadron #Ramat David 30: - primary: BARCAP @@ -108,12 +270,12 @@ squadrons: secondary: any aircraft: - 69th Squadron - size: 8 + size: 12 - primary: BAI secondary: any aircraft: - 110th Squadron - size: 8 + size: 16 # Damascus 7: - primary: TARCAP @@ -151,14 +313,14 @@ squadrons: - primary: CAS secondary: air-to-ground aircraft: - - SA 342M Gazelle + - SA 342L Gazelle size: 6 # OPFOR Second inland FOB FOB Homs: - primary: CAS secondary: air-to-ground aircraft: - - SA 342M Gazelle + - SA 342L Gazelle size: 6 # Palmyra 28: @@ -201,7 +363,7 @@ squadrons: - primary: CAS secondary: air-to-ground aircraft: - - SA 342M Gazelle + - SA 342L Gazelle # OPFOR Second inland FOB FOB Ithriyah: - primary: CAS diff --git a/resources/campaigns/operation_noisy_cricket.yaml b/resources/campaigns/operation_noisy_cricket.yaml index 54511b7e..d4954a0e 100644 --- a/resources/campaigns/operation_noisy_cricket.yaml +++ b/resources/campaigns/operation_noisy_cricket.yaml @@ -30,6 +30,8 @@ recommended_player_money: 0 recommended_enemy_money: 0 recommended_player_income_multiplier: 0.2 recommended_enemy_income_multiplier: 0.2 +settings: + hercules: true version: "10.7" squadrons: Blue CV-1: diff --git a/resources/dcs/beacons/kola.json b/resources/dcs/beacons/kola.json new file mode 100644 index 00000000..5c1d349d --- /dev/null +++ b/resources/dcs/beacons/kola.json @@ -0,0 +1,226 @@ +{ + "world_0": { + "name": "SPO", + "callsign": "SPO", + "beacon_type": 2, + "hertz": 115900000, + "channel": 106 + }, + "world_1": { + "name": "IL", + "callsign": "IL", + "beacon_type": 8, + "hertz": 320000, + "channel": null + }, + "world_2": { + "name": "KM", + "callsign": "KMV", + "beacon_type": 8, + "hertz": 445000, + "channel": null + }, + "world_3": { + "name": "I", + "callsign": "I", + "beacon_type": 12, + "hertz": 595000, + "channel": null + }, + "world_4": { + "name": "IO", + "callsign": "IO", + "beacon_type": 11, + "hertz": 1210000, + "channel": null + }, + "world_5": { + "name": "TG", + "callsign": "TG", + "beacon_type": 8, + "hertz": 346000, + "channel": null + }, + "world_6": { + "name": "OG", + "callsign": "OG", + "beacon_type": 11, + "hertz": 325000, + "channel": null + }, + "world_7": { + "name": "NAT", + "callsign": "NAT", + "beacon_type": 3, + "hertz": 113000000, + "channel": 77 + }, + "airfield3_0": { + "name": "kemi", + "callsign": "ke", + "beacon_type": 14, + "hertz": 110900000, + "channel": null + }, + "airfield3_1": { + "name": "kemi", + "callsign": "ke", + "beacon_type": 13, + "hertz": 110900000, + "channel": null + }, + "airfield2_0": { + "name": "ROVANIEMI", + "callsign": "ro", + "beacon_type": 13, + "hertz": 111700000, + "channel": null + }, + "airfield2_1": { + "name": "rovaniemi", + "callsign": "roi", + "beacon_type": 3, + "hertz": 117700000, + "channel": 124 + }, + "airfield2_2": { + "name": "ROVANIEMI", + "callsign": "RO", + "beacon_type": 14, + "hertz": 111700000, + "channel": null + }, + "airfield7_0": { + "name": "BODO", + "callsign": "BO", + "beacon_type": 14, + "hertz": 110300000, + "channel": null + }, + "airfield7_1": { + "name": "BODO", + "callsign": "BDO", + "beacon_type": 3, + "hertz": 117550000, + "channel": 122 + }, + "airfield7_2": { + "name": "BODO", + "callsign": "BO", + "beacon_type": 13, + "hertz": 110300000, + "channel": null + }, + "airfield7_3": { + "name": "BODO", + "callsign": "BD", + "beacon_type": 13, + "hertz": 108700000, + "channel": null + }, + "airfield7_4": { + "name": "BODO-ILSTAD", + "callsign": "BD", + "beacon_type": 14, + "hertz": 108700000, + "channel": null + }, + "airfield7_5": { + "name": "bodo", + "callsign": "boo", + "beacon_type": 4, + "hertz": 110800000, + "channel": 45 + }, + "airfield1_0": { + "name": "banak", + "callsign": "ba", + "beacon_type": 14, + "hertz": 108300000, + "channel": 20 + }, + "airfield1_1": { + "name": "banak", + "callsign": "ba", + "beacon_type": 14, + "hertz": 108300000, + "channel": null + }, + "airfield1_2": { + "name": "BANAK", + "callsign": "BNA", + "beacon_type": 3, + "hertz": 114400000, + "channel": 91 + }, + "airfield1_3": { + "name": "ENNA", + "callsign": "BNK", + "beacon_type": 4, + "hertz": 111000000, + "channel": 47 + }, + "airfield1_4": { + "name": "banak", + "callsign": "ba", + "beacon_type": 13, + "hertz": 108300000, + "channel": null + }, + "airfield5_0": { + "name": "kiruna", + "callsign": "KRA", + "beacon_type": 3, + "hertz": 115200000, + "channel": 99 + }, + "airfield5_1": { + "name": "kiruna", + "callsign": "nq", + "beacon_type": 14, + "hertz": 110300000, + "channel": 0 + }, + "airfield5_2": { + "name": "OP", + "callsign": "OP", + "beacon_type": 8, + "hertz": 360000, + "channel": null + }, + "airfield5_3": { + "name": "kiruna", + "callsign": "nq", + "beacon_type": 13, + "hertz": 110300000, + "channel": 0 + }, + "airfield12_0": { + "name": "IRD", + "callsign": "ird", + "beacon_type": 13, + "hertz": 108500000, + "channel": null + }, + "airfield12_1": { + "name": "IPF", + "callsign": "ipf", + "beacon_type": 13, + "hertz": 110300000, + "channel": null + }, + "airfield12_2": { + "name": "IRD", + "callsign": "ird", + "beacon_type": 14, + "hertz": 108500000, + "channel": null + }, + "airfield12_3": { + "name": "IPF", + "callsign": "ipf", + "beacon_type": 14, + "hertz": 110300000, + "channel": null + } +} \ No newline at end of file diff --git a/resources/factions/Israel-USN_2005_Allied_Sword.json b/resources/factions/Israel-USN_2005_Allied_Sword.json deleted file mode 100644 index 0a3b5378..00000000 --- a/resources/factions/Israel-USN_2005_Allied_Sword.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "country": "Combined Joint Task Forces Blue", - "name": "Israel-USN 2005 (Allied Sword)", - "authors": "Fuzzle", - "description": "

A joint US Navy/Israeli modern faction for use with the Operation Allied Sword scenario.

", - "locales": [ - "en_US" - ], - "aircrafts": [ - "F-4E Phantom II", - "F-15C Eagle", - "F-15D Baz", - "F-15E Strike Eagle (AI)", - "F-15E Strike Eagle (Suite 4+)", - "F-16CM Fighting Falcon (Block 50)", - "F-16D Barak (Block 30)", - "F-16D Barak (Block 40)", - "F-16I Sufa", - "F-14B Tomcat", - "F/A-18C Hornet (Lot 20)", - "F/A-18E Super Hornet", - "F/A-18F Super Hornet", - "EA-18G Growler", - "AV-8B Harrier II Night Attack", - "AH-1W SuperCobra", - "AH-64D Apache Longbow", - "AH-64D Apache Longbow (AI)", - "S-3B Viking", - "SH-60B Seahawk", - "UH-1H Iroquois", - "UH-60L" - ], - "awacs": [ - "E-2C Hawkeye" - ], - "tankers": [ - "KC-130", - "S-3B Tanker" - ], - "frontline_units": [ - "M113", - "M1043 HMMWV (M2 HMG)", - "M1045 HMMWV (BGM-71 TOW)", - "Merkava Mk IV", - "M163 Vulcan Air Defense System" - ], - "artillery_units": [ - "M109A6 Paladin", - "M270 Multiple Launch Rocket System" - ], - "logistics_units": [ - "Truck M818 6x6" - ], - "infantry_units": [ - "Infantry M4", - "Infantry M249", - "MANPADS Stinger" - ], - "preset_groups": [ - "Hawk", - "Patriot" - ], - "naval_units": [ - "FFG Oliver Hazard Perry", - "DDG Arleigh Burke IIa", - "CG Ticonderoga", - "LHA-1 Tarawa", - "CVN-74 John C. Stennis" - ], - "missiles": [], - "air_defense_units": [ - "SAM Hawk SR (AN/MPQ-50)", - "M163 Vulcan Air Defense System", - "M48 Chaparral" - ], - "requirements": {}, - "carrier_names": [ - "CVN-71 Theodore Roosevelt", - "CVN-72 Abraham Lincoln", - "CVN-73 George Washington", - "CVN-74 John C. Stennis", - "CVN-75 Harry S. Truman" - ], - "helicopter_carrier_names": [ - "LHA-1 Tarawa", - "LHA-2 Saipan", - "LHA-3 Belleau Wood", - "LHA-4 Nassau", - "LHA-5 Peleliu" - ], - "has_jtac": true, - "jtac_unit": "MQ-9 Reaper", - "doctrine": "modern", - "liveries_overrides": { - "F-14B Tomcat": [ - "VF-142 Ghostriders" - ], - "F/A-18C Hornet (Lot 20)": [ - "VMFA-251 high visibility" - ], - "AV-8B Harrier II Night Attack": [ - "VMAT-542" - ], - "AH-1W SuperCobra": [ - "Marines" - ], - "UH-1H Iroquois": [ - "US NAVY" - ], - "UH-60L": [ - "Israeli Air Force" - ] - }, - "unrestricted_satnav": true -} \ No newline at end of file diff --git a/resources/factions/NATO_Desert_Storm.json b/resources/factions/NATO_Desert_Storm.json index 171835a2..942cf542 100644 --- a/resources/factions/NATO_Desert_Storm.json +++ b/resources/factions/NATO_Desert_Storm.json @@ -20,10 +20,10 @@ "F-15E Strike Eagle (Suite 4+)", "F-16A MLU", "F-16CM Fighting Falcon (Block 50)", - "F-16D Fighting Falcon (Block 52+)", - "F-16D Fighting Falcon (Block 52)", - "F-16D Fighting Falcon (Block 50+)", - "F-16D Fighting Falcon (Block 50)", + "F-16D Fighting Falcon (Block 52+)", + "F-16D Fighting Falcon (Block 52)", + "F-16D Fighting Falcon (Block 50+)", + "F-16D Fighting Falcon (Block 50)", "F-4E Phantom II", "F/A-18C Hornet (Lot 20)", "Mirage 2000C", @@ -42,6 +42,7 @@ "tankers": [ "KC-130", "KC-135 Stratotanker", + "KC-135 Stratotanker MPRS", "S-3B Tanker" ], "frontline_units": [ diff --git a/resources/factions/NATO_OIF.json b/resources/factions/NATO_OIF.json index 0498472f..3a44d35a 100644 --- a/resources/factions/NATO_OIF.json +++ b/resources/factions/NATO_OIF.json @@ -5,6 +5,7 @@ "description": "

A more modern NATO mixed faction reflecting the units involved in Operation Iraqi Freedom.

", "aircrafts": [ "A-10C Thunderbolt II (Suite 3)", + "A-10C Thunderbolt II (Suite 7)", "AH-64D Apache Longbow", "AH-64D Apache Longbow (AI)", "AV-8B Harrier II Night Attack", @@ -22,10 +23,10 @@ "F-15E Strike Eagle (Suite 4+)", "F-16A MLU", "F-16CM Fighting Falcon (Block 50)", - "F-16D Fighting Falcon (Block 52+)", - "F-16D Fighting Falcon (Block 52)", - "F-16D Fighting Falcon (Block 50+)", - "F-16D Fighting Falcon (Block 50)", + "F-16D Fighting Falcon (Block 52+)", + "F-16D Fighting Falcon (Block 52)", + "F-16D Fighting Falcon (Block 50+)", + "F-16D Fighting Falcon (Block 50)", "F-22A Raptor", "F/A-18C Hornet (Lot 20)", "Mirage 2000C", @@ -46,6 +47,7 @@ "tankers": [ "KC-130", "KC-130J", + "KC-135 Stratotanker MPRS", "KC-135 Stratotanker", "S-3B Tanker" ], diff --git a/resources/factions/Syria-Lebanon_2005_Allied_Sword.json b/resources/factions/Syria-Lebanon_2005_Allied_Sword.json deleted file mode 100644 index 2104e0ba..00000000 --- a/resources/factions/Syria-Lebanon_2005_Allied_Sword.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "country": "Combined Joint Task Forces Red", - "name": "Syria-Lebanon 2005 (Allied Sword)", - "authors": "Fuzzle", - "description": "

Syria-Lebanon alliance in a modern setting with several imported Russian assets. Designed for use with the Allied Sword scenario.

", - "aircrafts": [ - "MiG-23ML Flogger-G", - "MiG-25RBT Foxbat-B", - "MiG-29A Fulcrum-A", - "Su-17M4 Fitter-K", - "Su-24M Fencer-D", - "Su-30 Flanker-C", - "Su-34 Fullback", - "L-39ZA Albatros", - "Tu-22M3 Backfire-C", - "Mi-24V Hind-E", - "Mi-8MTV2 Hip", - "SA 342M Gazelle", - "SA 342L Gazelle", - "IL-76MD" - ], - "awacs": [ - "A-50" - ], - "tankers": [ - "IL-78M" - ], - "frontline_units": [ - "BMP-1", - "BMP-2", - "BTR-80", - "BRDM-2", - "MT-LB", - "T-55A", - "T-72B with Kontakt-1 ERA", - "T-90A", - "ZSU-57-2 'Sparka'" - ], - "artillery_units": [ - "BM-21 Grad", - "2S1 Gvozdika" - ], - "logistics_units": [ - "Truck Ural-375", - "LUV UAZ-469 Jeep" - ], - "infantry_units": [ - "Paratrooper AKS", - "Infantry AK-74 Rus", - "Paratrooper RPG-16", - "MANPADS SA-18 Igla-S \"Grouse\"" - ], - "preset_groups": [ - "SA-2/S-75", - "SA-3/S-125", - "SA-6", - "SA-11", - "SA-10/S-300PS", - "Silkworm", - "Cold-War-Flak", - "Russian Navy", - "KS-19/SON-9" - ], - "naval_units": [ - "Corvette 1124.4 Grish", - "Corvette 1241.1 Molniya", - "FAC La Combattante IIa", - "Frigate 1135M Rezky" - ], - "air_defense_units": [ - "SAM P19 \"Flat Face\" SR (SA-2/3)", - "EWR 1L13", - "EWR 55G6", - "SAM SA-8 Osa \"Gecko\" TEL", - "SA-9 Strela", - "SA-13 Gopher (9K35 Strela-10M3)", - "SA-19 Grison (2K22 Tunguska)", - "ZSU-57-2 'Sparka'", - "AAA ZU-23 Closed Emplacement", - "ZU-23 on Ural-375", - "ZSU-23-4 Shilka" - ], - "missiles": [ - "SSM SS-1C Scud-B" - ], - "helicopter_carrier_names": [], - "requirements": {}, - "carrier_names": [] -} \ No newline at end of file diff --git a/resources/factions/blufor_late_coldwar.json b/resources/factions/blufor_late_coldwar.json index e57f9324..f0f8da8d 100644 --- a/resources/factions/blufor_late_coldwar.json +++ b/resources/factions/blufor_late_coldwar.json @@ -11,10 +11,12 @@ "AH-1W SuperCobra", "AJS-37 Viggen", "AV-8B Harrier II Night Attack", + "B-1B Lancer", "B-52H Stratofortress", "C-101CC Aviojet", "C-130", "C-130J-30 Super Hercules", + "C-47 Dakota", "CH-47D", "CH-53E", "F-14A Tomcat (Block 135-GR Late)", @@ -35,6 +37,7 @@ "S-3B Viking", "SA 342L Gazelle", "SA 342M Gazelle", + "SH-60B Seahawk", "UH-1H Iroquois", "UH-60A", "UH-60L" @@ -51,10 +54,16 @@ "M113", "M163 Vulcan Air Defense System", "M48 Chaparral", - "M60A3 \"Patton\"" + "M60A3 \"Patton\"", + "Leopard 2", + "M1A2 Abrams", + "M2A2 Bradley", + "Marder 1A3", + "VAB Mephisto" ], "artillery_units": [ - "M109A6 Paladin" + "M109A6 Paladin", + "M270 Multiple Launch Rocket System" ], "logistics_units": [ "Truck M818 6x6" @@ -66,7 +75,8 @@ "missiles": [], "preset_groups": [ "Hawk", - "Cold-War-Flak" + "Patriot", + "Rapier" ], "naval_units": [ "FFG Oliver Hazard Perry", @@ -77,7 +87,9 @@ "air_defense_units": [ "SAM Hawk SR (AN/MPQ-50)", "M163 Vulcan Air Defense System", - "M48 Chaparral" + "M48 Chaparral", + "Flakpanzer Gepard", + "Roland 2 (Marder Chassis)" ], "carrier_names": [ "CVN-59 Forrestal", @@ -94,4 +106,4 @@ ], "has_jtac": false, "doctrine": "coldwar" -} +} \ No newline at end of file diff --git a/resources/factions/russia_1980.json b/resources/factions/russia_1980.json index 4d3128a9..17e86f4b 100644 --- a/resources/factions/russia_1980.json +++ b/resources/factions/russia_1980.json @@ -7,7 +7,6 @@ "ru_RU" ], "aircrafts": [ - "IL-76MD", "Mi-24V Hind-E", "Mi-24P Hind-F", "Mi-8MTV2 Hip", @@ -37,8 +36,8 @@ "BRDM-2", "BTR-80", "PT-76", - "SAM SA-8 Osa \"Gecko\" TEL", - "T-55A" + "T-55A", + "T-72B with Kontakt-1 ERA" ], "artillery_units": [ "2S1 Gvozdika", @@ -59,14 +58,13 @@ "SA-2/S-75 V-759/5V23", "SA-3/S-125", "SA-3/S-125 V-601P/5V27", + "SA-5/S-200", "SA-6", - "Cold-War-Flak", "KS-19/SON-9" ], "naval_units": [ "Corvette 1241.1 Molniya", - "Corvette 1124.4 Grish", - "SSK 877V Kilo" + "Corvette 1124.4 Grish" ], "air_defense_units": [ "SAM P19 \"Flat Face\" SR (SA-2/3)", @@ -87,4 +85,4 @@ "carrier_names": [], "has_jtac": false, "doctrine": "coldwar" -} +} \ No newline at end of file diff --git a/resources/factions/russia_1990.json b/resources/factions/russia_1990.json index 027d9703..4480fa26 100644 --- a/resources/factions/russia_1990.json +++ b/resources/factions/russia_1990.json @@ -9,6 +9,7 @@ "aircrafts": [ "IL-76MD", "Ka-50 Hokum", + "Ka-50 Hokum III", "Mi-24V Hind-E", "Mi-24P Hind-F", "Mi-8MTV2 Hip", diff --git a/resources/theaters/kola/info.yaml b/resources/theaters/kola/info.yaml new file mode 100644 index 00000000..01ef2796 --- /dev/null +++ b/resources/theaters/kola/info.yaml @@ -0,0 +1,44 @@ +--- +name: Kola +timezone: +3 +daytime: + dawn: [3, 9] + day: [9, 18] + dusk: [18, 22] + night: [23, 2] +climate: + day_night_temperature_difference: 10.0 + seasons: + winter: + average_pressure: 29.79 + average_temperature: -16 + weather: + thunderstorm: 1 + raining: 20 + cloudy: 60 + clear: 20 + spring: + weather: + thunderstorm: 1 + raining: 20 + cloudy: 40 + clear: 40 + summer: + average_pressure: 29.85 + average_temperature: 15.0 + weather: + thunderstorm: 1 + raining: 10 + cloudy: 35 + clear: 55 + fall: + weather: + thunderstorm: 1 + raining: 30 + cloudy: 50 + clear: 20 + turbulence: + high_avg_yearly_turbulence_per_10cm: 9 + low_avg_yearly_turbulence_per_10cm: 3.5 + solar_noon_turbulence_per_10cm: 3.5 + midnight_turbulence_per_10cm: -3 \ No newline at end of file diff --git a/resources/theaters/kola/landmap.p b/resources/theaters/kola/landmap.p new file mode 100644 index 00000000..52009b66 Binary files /dev/null and b/resources/theaters/kola/landmap.p differ diff --git a/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.cpg b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.cpg new file mode 100644 index 00000000..3ad133c0 --- /dev/null +++ b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.dbf b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.dbf new file mode 100644 index 00000000..518188c4 Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.dbf differ diff --git a/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.prj b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.prj new file mode 100644 index 00000000..c1e15790 --- /dev/null +++ b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.prj @@ -0,0 +1 @@ +PROJCS["WGS_1984_UTM_Zone_34N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",21.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.shp b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.shp new file mode 100644 index 00000000..a3a81395 Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.shp differ diff --git a/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.shx b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.shx new file mode 100644 index 00000000..573a723b Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/exclusion/exclusion_zones.shx differ diff --git a/unshipped_data/arcgis_maps/kola/land/land_zones.cpg b/unshipped_data/arcgis_maps/kola/land/land_zones.cpg new file mode 100644 index 00000000..3ad133c0 --- /dev/null +++ b/unshipped_data/arcgis_maps/kola/land/land_zones.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/kola/land/land_zones.dbf b/unshipped_data/arcgis_maps/kola/land/land_zones.dbf new file mode 100644 index 00000000..504c6a8f Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/land/land_zones.dbf differ diff --git a/unshipped_data/arcgis_maps/kola/land/land_zones.prj b/unshipped_data/arcgis_maps/kola/land/land_zones.prj new file mode 100644 index 00000000..f45cbadf --- /dev/null +++ b/unshipped_data/arcgis_maps/kola/land/land_zones.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/kola/land/land_zones.shp b/unshipped_data/arcgis_maps/kola/land/land_zones.shp new file mode 100644 index 00000000..665ab491 Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/land/land_zones.shp differ diff --git a/unshipped_data/arcgis_maps/kola/land/land_zones.shx b/unshipped_data/arcgis_maps/kola/land/land_zones.shx new file mode 100644 index 00000000..e24258d3 Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/land/land_zones.shx differ diff --git a/unshipped_data/arcgis_maps/kola/sea/sea_zones.cpg b/unshipped_data/arcgis_maps/kola/sea/sea_zones.cpg new file mode 100644 index 00000000..3ad133c0 --- /dev/null +++ b/unshipped_data/arcgis_maps/kola/sea/sea_zones.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/kola/sea/sea_zones.dbf b/unshipped_data/arcgis_maps/kola/sea/sea_zones.dbf new file mode 100644 index 00000000..2182596f Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/sea/sea_zones.dbf differ diff --git a/unshipped_data/arcgis_maps/kola/sea/sea_zones.prj b/unshipped_data/arcgis_maps/kola/sea/sea_zones.prj new file mode 100644 index 00000000..c1e15790 --- /dev/null +++ b/unshipped_data/arcgis_maps/kola/sea/sea_zones.prj @@ -0,0 +1 @@ +PROJCS["WGS_1984_UTM_Zone_34N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",21.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/kola/sea/sea_zones.shp b/unshipped_data/arcgis_maps/kola/sea/sea_zones.shp new file mode 100644 index 00000000..fc18a57c Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/sea/sea_zones.shp differ diff --git a/unshipped_data/arcgis_maps/kola/sea/sea_zones.shx b/unshipped_data/arcgis_maps/kola/sea/sea_zones.shx new file mode 100644 index 00000000..f8fff1f4 Binary files /dev/null and b/unshipped_data/arcgis_maps/kola/sea/sea_zones.shx differ