mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge remote-tracking branch 'khopa/develop' into develop
This commit is contained in:
commit
1843d23203
@ -20,6 +20,7 @@ Saves from 2.3 are not compatible with 2.4.
|
|||||||
* **[Economy]** Carriers and off-map spawns generate no income (previously $20M like airbases).
|
* **[Economy]** Carriers and off-map spawns generate no income (previously $20M like airbases).
|
||||||
* **[Economy]** Sales of aircraft and ground vehicles can now be cancelled before the next turn begins.
|
* **[Economy]** Sales of aircraft and ground vehicles can now be cancelled before the next turn begins.
|
||||||
* **[UI]** Multi-SAM objectives now show threat and detection rings per group.
|
* **[UI]** Multi-SAM objectives now show threat and detection rings per group.
|
||||||
|
* **[UI]** Unit names are now prettier and more accurate, and can now be set per-country for added historical flavour.
|
||||||
* **[Factions]** Added option for date-based loadout restriction. Active radar homing missiles are handled, patches welcome for the other thousand weapons.
|
* **[Factions]** Added option for date-based loadout restriction. Active radar homing missiles are handled, patches welcome for the other thousand weapons.
|
||||||
* **[Factions]** Added Poland 2010 faction.
|
* **[Factions]** Added Poland 2010 faction.
|
||||||
* **[Factions]** Added Greece 2005 faction.
|
* **[Factions]** Added Greece 2005 faction.
|
||||||
|
|||||||
23
game/db.py
23
game/db.py
@ -1,6 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Dict, List, Optional, Tuple, Type, Union
|
from typing import Dict, List, Optional, Tuple, Type, Union
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from dcs.countries import country_dict
|
from dcs.countries import country_dict
|
||||||
from dcs.helicopters import (
|
from dcs.helicopters import (
|
||||||
@ -169,6 +171,8 @@ from pydcs_extensions.mb339.mb339 import MB_339PAN
|
|||||||
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
|
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
|
||||||
from pydcs_extensions.su57.su57 import Su_57
|
from pydcs_extensions.su57.su57 import Su_57
|
||||||
|
|
||||||
|
PRETTYNAMES_PATH = Path("./resources/units/pretty_unit_names.json")
|
||||||
|
|
||||||
plane_map["A-4E-C"] = A_4E_C
|
plane_map["A-4E-C"] = A_4E_C
|
||||||
plane_map["MB-339PAN"] = MB_339PAN
|
plane_map["MB-339PAN"] = MB_339PAN
|
||||||
plane_map["Rafale_M"] = Rafale_M
|
plane_map["Rafale_M"] = Rafale_M
|
||||||
@ -1321,6 +1325,25 @@ def unit_type_name(unit_type) -> str:
|
|||||||
def unit_type_name_2(unit_type) -> str:
|
def unit_type_name_2(unit_type) -> str:
|
||||||
return unit_type.name and unit_type.name or unit_type.id
|
return unit_type.name and unit_type.name or unit_type.id
|
||||||
|
|
||||||
|
def unit_pretty_name(country_name: str, unit_type) -> str:
|
||||||
|
original_name = unit_type.name and unit_type.name or unit_type.id
|
||||||
|
default_name = None
|
||||||
|
faction_name = None
|
||||||
|
with PRETTYNAMES_PATH.open("r", encoding="utf-8") as fdata:
|
||||||
|
data = json.load(fdata, encoding="utf-8")
|
||||||
|
type_exists = data.get(original_name)
|
||||||
|
if type_exists is None:
|
||||||
|
return original_name
|
||||||
|
for faction in type_exists:
|
||||||
|
if default_name is None:
|
||||||
|
default_name = faction.get("default")
|
||||||
|
if faction_name is None:
|
||||||
|
faction_name = faction.get(country_name)
|
||||||
|
if default_name is None:
|
||||||
|
return original_name
|
||||||
|
if faction_name is None:
|
||||||
|
return default_name
|
||||||
|
return faction_name
|
||||||
|
|
||||||
def unit_type_from_name(name: str) -> Optional[Type[UnitType]]:
|
def unit_type_from_name(name: str) -> Optional[Type[UnitType]]:
|
||||||
if name in vehicle_map:
|
if name in vehicle_map:
|
||||||
|
|||||||
@ -262,6 +262,9 @@ class FlightData:
|
|||||||
#: The package that the flight belongs to.
|
#: The package that the flight belongs to.
|
||||||
package: Package
|
package: Package
|
||||||
|
|
||||||
|
#: The country that the flight belongs to.
|
||||||
|
country: str
|
||||||
|
|
||||||
flight_type: FlightType
|
flight_type: FlightType
|
||||||
|
|
||||||
#: All units in the flight.
|
#: All units in the flight.
|
||||||
@ -299,7 +302,7 @@ class FlightData:
|
|||||||
|
|
||||||
joker_fuel: Optional[int]
|
joker_fuel: Optional[int]
|
||||||
|
|
||||||
def __init__(self, package: Package, flight_type: FlightType,
|
def __init__(self, package: Package, country: str, flight_type: FlightType,
|
||||||
units: List[FlyingUnit], size: int, friendly: bool,
|
units: List[FlyingUnit], size: int, friendly: bool,
|
||||||
departure_delay: timedelta, departure: RunwayData,
|
departure_delay: timedelta, departure: RunwayData,
|
||||||
arrival: RunwayData, divert: Optional[RunwayData],
|
arrival: RunwayData, divert: Optional[RunwayData],
|
||||||
@ -308,6 +311,7 @@ class FlightData:
|
|||||||
bingo_fuel: Optional[int],
|
bingo_fuel: Optional[int],
|
||||||
joker_fuel: Optional[int]) -> None:
|
joker_fuel: Optional[int]) -> None:
|
||||||
self.package = package
|
self.package = package
|
||||||
|
self.country = country
|
||||||
self.flight_type = flight_type
|
self.flight_type = flight_type
|
||||||
self.units = units
|
self.units = units
|
||||||
self.size = size
|
self.size = size
|
||||||
@ -778,6 +782,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
self.flights.append(FlightData(
|
self.flights.append(FlightData(
|
||||||
package=package,
|
package=package,
|
||||||
|
country=faction.country,
|
||||||
flight_type=flight.flight_type,
|
flight_type=flight.flight_type,
|
||||||
units=group.units,
|
units=group.units,
|
||||||
size=len(group.units),
|
size=len(group.units),
|
||||||
@ -984,7 +989,7 @@ class AircraftConflictGenerator:
|
|||||||
# Creating a flight even those this isn't a fragged mission lets us
|
# Creating a flight even those this isn't a fragged mission lets us
|
||||||
# reuse the existing debriefing code.
|
# reuse the existing debriefing code.
|
||||||
# TODO: Special flight type?
|
# TODO: Special flight type?
|
||||||
flight = Flight(Package(control_point), aircraft, 1,
|
flight = Flight(Package(control_point), faction.country, aircraft, 1,
|
||||||
FlightType.BARCAP, "Cold", departure=control_point,
|
FlightType.BARCAP, "Cold", departure=control_point,
|
||||||
arrival=control_point, divert=None)
|
arrival=control_point, divert=None)
|
||||||
|
|
||||||
|
|||||||
@ -173,9 +173,11 @@ class PackageBuilder:
|
|||||||
closest_airfields: ClosestAirfields,
|
closest_airfields: ClosestAirfields,
|
||||||
global_inventory: GlobalAircraftInventory,
|
global_inventory: GlobalAircraftInventory,
|
||||||
is_player: bool,
|
is_player: bool,
|
||||||
|
package_country: str,
|
||||||
start_type: str) -> None:
|
start_type: str) -> None:
|
||||||
self.closest_airfields = closest_airfields
|
self.closest_airfields = closest_airfields
|
||||||
self.is_player = is_player
|
self.is_player = is_player
|
||||||
|
self.package_country = package_country
|
||||||
self.package = Package(location)
|
self.package = Package(location)
|
||||||
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
|
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
|
||||||
is_player)
|
is_player)
|
||||||
@ -199,7 +201,7 @@ class PackageBuilder:
|
|||||||
else:
|
else:
|
||||||
start_type = self.start_type
|
start_type = self.start_type
|
||||||
|
|
||||||
flight = Flight(self.package, aircraft, plan.num_aircraft, plan.task,
|
flight = Flight(self.package, self.package_country, aircraft, plan.num_aircraft, plan.task,
|
||||||
start_type, departure=airfield, arrival=airfield,
|
start_type, departure=airfield, arrival=airfield,
|
||||||
divert=self.find_divert_field(aircraft, airfield))
|
divert=self.find_divert_field(aircraft, airfield))
|
||||||
self.package.add_flight(flight)
|
self.package.add_flight(flight)
|
||||||
@ -629,11 +631,17 @@ class CoalitionMissionPlanner:
|
|||||||
else:
|
else:
|
||||||
start_type = "Warm"
|
start_type = "Warm"
|
||||||
|
|
||||||
|
if self.is_player:
|
||||||
|
package_country = self.game.player_country
|
||||||
|
else:
|
||||||
|
package_country = self.game.enemy_country
|
||||||
|
|
||||||
builder = PackageBuilder(
|
builder = PackageBuilder(
|
||||||
mission.location,
|
mission.location,
|
||||||
self.objective_finder.closest_airfields_to(mission.location),
|
self.objective_finder.closest_airfields_to(mission.location),
|
||||||
self.game.aircraft_inventory,
|
self.game.aircraft_inventory,
|
||||||
self.is_player,
|
self.is_player,
|
||||||
|
package_country,
|
||||||
start_type
|
start_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -136,12 +136,13 @@ class FlightWaypoint:
|
|||||||
|
|
||||||
class Flight:
|
class Flight:
|
||||||
|
|
||||||
def __init__(self, package: Package, unit_type: Type[FlyingType],
|
def __init__(self, package: Package, country: str, unit_type: Type[FlyingType],
|
||||||
count: int, flight_type: FlightType, start_type: str,
|
count: int, flight_type: FlightType, start_type: str,
|
||||||
departure: ControlPoint, arrival: ControlPoint,
|
departure: ControlPoint, arrival: ControlPoint,
|
||||||
divert: Optional[ControlPoint],
|
divert: Optional[ControlPoint],
|
||||||
custom_name: Optional[str] = None) -> None:
|
custom_name: Optional[str] = None) -> None:
|
||||||
self.package = package
|
self.package = package
|
||||||
|
self.country = country
|
||||||
self.unit_type = unit_type
|
self.unit_type = unit_type
|
||||||
self.count = count
|
self.count = count
|
||||||
self.departure = departure
|
self.departure = departure
|
||||||
@ -179,3 +180,9 @@ class Flight:
|
|||||||
if self.custom_name:
|
if self.custom_name:
|
||||||
return f"{self.custom_name} {self.count} x {name}"
|
return f"{self.custom_name} {self.count} x {name}"
|
||||||
return f"[{self.flight_type}] {self.count} x {name}"
|
return f"[{self.flight_type}] {self.count} x {name}"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
name = db.unit_pretty_name(self.country, self.unit_type)
|
||||||
|
if self.custom_name:
|
||||||
|
return f"{self.custom_name} {self.count} x {name}"
|
||||||
|
return f"[{self.flight_type}] {self.count} x {name}"
|
||||||
|
|||||||
@ -5,12 +5,13 @@ from PySide2.QtWidgets import QComboBox
|
|||||||
|
|
||||||
from dcs.unittype import FlyingType
|
from dcs.unittype import FlyingType
|
||||||
|
|
||||||
|
from game import Game, db
|
||||||
|
|
||||||
class QAircraftTypeSelector(QComboBox):
|
class QAircraftTypeSelector(QComboBox):
|
||||||
"""Combo box for selecting among the given aircraft types."""
|
"""Combo box for selecting among the given aircraft types."""
|
||||||
|
|
||||||
def __init__(self, aircraft_types: Iterable[Type[FlyingType]]) -> None:
|
def __init__(self, aircraft_types: Iterable[Type[FlyingType]], country: str) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
for aircraft in aircraft_types:
|
for aircraft in aircraft_types:
|
||||||
self.addItem(f"{aircraft.id}", userData=aircraft)
|
self.addItem(f"{db.unit_pretty_name(country, aircraft)}", userData=aircraft)
|
||||||
self.model().sort(0)
|
self.model().sort(0)
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class QDebriefingWindow(QDialog):
|
|||||||
for unit_type, count in player_air_losses.items():
|
for unit_type, count in player_air_losses.items():
|
||||||
try:
|
try:
|
||||||
lostUnitsLayout.addWidget(
|
lostUnitsLayout.addWidget(
|
||||||
QLabel(db.unit_type_name(unit_type)), row, 0)
|
QLabel(db.unit_pretty_name(self.debriefing.player_country, unit_type)), row, 0)
|
||||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||||
row += 1
|
row += 1
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -94,7 +94,7 @@ class QDebriefingWindow(QDialog):
|
|||||||
for unit_type, count in enemy_air_losses.items():
|
for unit_type, count in enemy_air_losses.items():
|
||||||
try:
|
try:
|
||||||
enemylostUnitsLayout.addWidget(
|
enemylostUnitsLayout.addWidget(
|
||||||
QLabel(db.unit_type_name(unit_type)), row, 0)
|
QLabel(db.unit_pretty_name(self.debriefing.enemy_country, unit_type)), row, 0)
|
||||||
enemylostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
enemylostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||||
row += 1
|
row += 1
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|||||||
@ -58,7 +58,7 @@ class QRecruitBehaviour:
|
|||||||
existing_units = self.cp.base.total_units_of_type(unit_type)
|
existing_units = self.cp.base.total_units_of_type(unit_type)
|
||||||
scheduled_units = self.pending_deliveries.units.get(unit_type, 0)
|
scheduled_units = self.pending_deliveries.units.get(unit_type, 0)
|
||||||
|
|
||||||
unitName = QLabel("<b>" + db.unit_type_name_2(unit_type) + "</b>")
|
unitName = QLabel("<b>" + db.unit_pretty_name(self.game_model.game.player_country, unit_type) + "</b>")
|
||||||
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||||
|
|
||||||
existing_units = QLabel(str(existing_units))
|
existing_units = QLabel(str(existing_units))
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class QIntelInfo(QFrame):
|
|||||||
existing_units = self.cp.base.total_units_of_type(unit_type)
|
existing_units = self.cp.base.total_units_of_type(unit_type)
|
||||||
if existing_units == 0:
|
if existing_units == 0:
|
||||||
continue
|
continue
|
||||||
groupLayout.addWidget(QLabel("<b>" + db.unit_type_name(unit_type) + "</b>"), row, 0)
|
groupLayout.addWidget(QLabel("<b>" + db.unit_pretty_name(self.game.enemy_country, unit_type) + "</b>"), row, 0)
|
||||||
groupLayout.addWidget(QLabel(str(existing_units)), row, 1)
|
groupLayout.addWidget(QLabel(str(existing_units)), row, 1)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ from PySide2.QtWidgets import (
|
|||||||
QWidget,
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
from game.game import Game
|
from game.game import Game, db
|
||||||
from qt_ui.uiconstants import ICONS
|
from qt_ui.uiconstants import ICONS
|
||||||
from qt_ui.windows.finances.QFinancesMenu import FinancesLayout
|
from qt_ui.windows.finances.QFinancesMenu import FinancesLayout
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class AircraftIntelLayout(IntelTableLayout):
|
|||||||
for airframe, count in base.aircraft.items():
|
for airframe, count in base.aircraft.items():
|
||||||
if not count:
|
if not count:
|
||||||
continue
|
continue
|
||||||
self.add_row(airframe.id, count)
|
self.add_row(db.unit_pretty_name(game.enemy_country, airframe), count)
|
||||||
|
|
||||||
self.add_spacer()
|
self.add_spacer()
|
||||||
self.add_row("<b>Total</b>", total)
|
self.add_row("<b>Total</b>", total)
|
||||||
|
|||||||
@ -34,6 +34,7 @@ class QFlightCreator(QDialog):
|
|||||||
self.game = game
|
self.game = game
|
||||||
self.package = package
|
self.package = package
|
||||||
self.custom_name_text = None
|
self.custom_name_text = None
|
||||||
|
self.country = self.game.player_country
|
||||||
|
|
||||||
self.setWindowTitle("Create flight")
|
self.setWindowTitle("Create flight")
|
||||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||||
@ -47,7 +48,7 @@ class QFlightCreator(QDialog):
|
|||||||
layout.addLayout(QLabeledWidget("Task:", self.task_selector))
|
layout.addLayout(QLabeledWidget("Task:", self.task_selector))
|
||||||
|
|
||||||
self.aircraft_selector = QAircraftTypeSelector(
|
self.aircraft_selector = QAircraftTypeSelector(
|
||||||
self.game.aircraft_inventory.available_types_for_player
|
self.game.aircraft_inventory.available_types_for_player, self.game.player_country
|
||||||
)
|
)
|
||||||
self.aircraft_selector.setCurrentIndex(0)
|
self.aircraft_selector.setCurrentIndex(0)
|
||||||
self.aircraft_selector.currentIndexChanged.connect(
|
self.aircraft_selector.currentIndexChanged.connect(
|
||||||
@ -154,7 +155,7 @@ class QFlightCreator(QDialog):
|
|||||||
start_type = "Cold"
|
start_type = "Cold"
|
||||||
else:
|
else:
|
||||||
start_type = "Warm"
|
start_type = "Warm"
|
||||||
flight = Flight(self.package, aircraft, size, task, start_type, origin,
|
flight = Flight(self.package, self.country, aircraft, size, task, start_type, origin,
|
||||||
arrival, divert, custom_name=self.custom_name_text)
|
arrival, divert, custom_name=self.custom_name_text)
|
||||||
flight.client_count = self.client_slots_spinner.value()
|
flight.client_count = self.client_slots_spinner.value()
|
||||||
|
|
||||||
|
|||||||
271
resources/units/pretty_unit_names.json
Normal file
271
resources/units/pretty_unit_names.json
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
{
|
||||||
|
"A-10A": [{
|
||||||
|
"default": "A-10A Thunderbolt II"
|
||||||
|
}],
|
||||||
|
"A-10C": [{
|
||||||
|
"default": "A-10C Thunderbolt II (Suite 3)"
|
||||||
|
}],
|
||||||
|
"A-10C_2": [{
|
||||||
|
"default": "A-10C Thunderbolt II (Suite 7)"
|
||||||
|
}],
|
||||||
|
"A-20G": [{
|
||||||
|
"default": "A-20G Havoc",
|
||||||
|
"UK": "Boston Mk.III"
|
||||||
|
}],
|
||||||
|
"A-4E-C": [{
|
||||||
|
"default": "A-4E Skyhawk"
|
||||||
|
}],
|
||||||
|
"AH_1W": [{
|
||||||
|
"default": "AH-1W SuperCobra"
|
||||||
|
}],
|
||||||
|
"AH-64A": [{
|
||||||
|
"default": "AH-64A Apache"
|
||||||
|
}],
|
||||||
|
"AH-64D": [{
|
||||||
|
"default": "AH-64D Apache Longbow"
|
||||||
|
}],
|
||||||
|
"AJS37": [{
|
||||||
|
"default": "AJS-37 Viggen"
|
||||||
|
}],
|
||||||
|
"AV8BNA": [{
|
||||||
|
"default": "AV-8B Harrier II Night Attack"
|
||||||
|
}],
|
||||||
|
"B-1B": [{
|
||||||
|
"default": "B-1B Lancer"
|
||||||
|
}],
|
||||||
|
"B-17G": [{
|
||||||
|
"default": "B-17G Flying Fortress",
|
||||||
|
"UK": "Fortress Mk.III"
|
||||||
|
}],
|
||||||
|
"B-52H": [{
|
||||||
|
"default": "B-52H Stratofortress"
|
||||||
|
}],
|
||||||
|
"Bf-109K-4": [{
|
||||||
|
"default": "Bf 109 K-4 Kurfürst"
|
||||||
|
}],
|
||||||
|
"C-101CC": [{
|
||||||
|
"default": "C-101CC Aviojet"
|
||||||
|
}],
|
||||||
|
"C-101EB": [{
|
||||||
|
"default": "C-101EB Aviojet"
|
||||||
|
}],
|
||||||
|
"F-4E": [{
|
||||||
|
"default": "F-4E Phantom II",
|
||||||
|
"Germany": "F-4F Phantom II",
|
||||||
|
"Japan": "F-4EJ Kai Phantom II",
|
||||||
|
"UK": "Phantom F.3"
|
||||||
|
}],
|
||||||
|
"F-5E-3": [{
|
||||||
|
"default": "F-5E Tiger II"
|
||||||
|
}],
|
||||||
|
"F-14A-135-GR": [{
|
||||||
|
"default": "F-14A Tomcat (Block 135-GR Late)"
|
||||||
|
}],
|
||||||
|
"F-14B": [{
|
||||||
|
"default": "F-14B Tomcat"
|
||||||
|
}],
|
||||||
|
"F-15C": [{
|
||||||
|
"default": "F-15C Eagle",
|
||||||
|
"Japan": "F-15J Eagle"
|
||||||
|
}],
|
||||||
|
"F-15E": [{
|
||||||
|
"default": "F-15E Strike Eagle"
|
||||||
|
}],
|
||||||
|
"F-16C_50": [{
|
||||||
|
"default": "F-16CM Fighting Falcon (Block 50)",
|
||||||
|
"Japan": "F-2A"
|
||||||
|
}],
|
||||||
|
"F-22A":[{
|
||||||
|
"default": "F-22A Raptor"
|
||||||
|
}],
|
||||||
|
"F-86F Sabre": [{
|
||||||
|
"default": "F-86F Sabre"
|
||||||
|
}],
|
||||||
|
"F-111F": [{
|
||||||
|
"default": "F-111F Aardvark"
|
||||||
|
}],
|
||||||
|
"F-117A": [{
|
||||||
|
"default": "F-117A Nighthawk"
|
||||||
|
}],
|
||||||
|
"FA-18C_hornet": [{
|
||||||
|
"default": "F/A-18C Hornet (Lot 20)",
|
||||||
|
"Canada": "CF-188 Hornet",
|
||||||
|
"Spain": "EF-18A+ Hornet"
|
||||||
|
}],
|
||||||
|
"FW-190A8": [{
|
||||||
|
"default": "Fw 190 A-8 Anton"
|
||||||
|
}],
|
||||||
|
"FW-190D9": [{
|
||||||
|
"default": "Fw 190 D-9 Dora"
|
||||||
|
}],
|
||||||
|
"Hercules": [{
|
||||||
|
"default": "C-130J-30 Super Hercules"
|
||||||
|
}],
|
||||||
|
"I-16": [{
|
||||||
|
"default": "I-16 Ishak"
|
||||||
|
}],
|
||||||
|
"J-11A": [{
|
||||||
|
"default": "J-11A Flanker-L"
|
||||||
|
}],
|
||||||
|
"JF-17": [{
|
||||||
|
"default": "JF-17 Thunder",
|
||||||
|
"China": "FC-1 Fierce Dragon"
|
||||||
|
}],
|
||||||
|
"Ju-88A4": [{
|
||||||
|
"default": "Ju 88 A-4"
|
||||||
|
}],
|
||||||
|
"Ka-50": [{
|
||||||
|
"default": "Ka-50 Hokum"
|
||||||
|
}],
|
||||||
|
"L-39ZA": [{
|
||||||
|
"default": "L-39ZA Albatross"
|
||||||
|
}],
|
||||||
|
"M-2000C": [{
|
||||||
|
"default": "Mirage 2000C"
|
||||||
|
}],
|
||||||
|
"MB-339PAN":[{
|
||||||
|
"default": "MB-339PAN"
|
||||||
|
}],
|
||||||
|
"Mirage 2000-5": [{
|
||||||
|
"default": "Mirage 2000-5"
|
||||||
|
}],
|
||||||
|
"Mi-24V": [{
|
||||||
|
"default": "Mi-24V Hind-E"
|
||||||
|
}],
|
||||||
|
"Mi-28N": [{
|
||||||
|
"default": "Mi-28N Havoc"
|
||||||
|
}],
|
||||||
|
"Mi-8MT": [{
|
||||||
|
"default": "Mi-8MTV2 Hip"
|
||||||
|
}],
|
||||||
|
"MiG-15bis": [{
|
||||||
|
"default": "MiG-15bis Fagot"
|
||||||
|
}],
|
||||||
|
"MiG-19P": [{
|
||||||
|
"default": "MiG-19P Farmer-B",
|
||||||
|
"China": "J-6A"
|
||||||
|
}],
|
||||||
|
"MiG-21Bis": [{
|
||||||
|
"default": "MiG-21bis Fishbed-N",
|
||||||
|
"China": "J-7B"
|
||||||
|
}],
|
||||||
|
"MiG-23MLD": [{
|
||||||
|
"default": "MiG-23MLD Flogger-K"
|
||||||
|
}],
|
||||||
|
"MiG-25PD": [{
|
||||||
|
"default": "MiG-25PD Foxbat-E"
|
||||||
|
}],
|
||||||
|
"MiG-25RBT": [{
|
||||||
|
"default": "MiG-25RBT Foxbat-B"
|
||||||
|
}],
|
||||||
|
"MiG_27K": [{
|
||||||
|
"default": "MiG-27K Flogger-J2"
|
||||||
|
}],
|
||||||
|
"MiG-29A": [{
|
||||||
|
"default": "MiG-29A Fulcrum-A"
|
||||||
|
}],
|
||||||
|
"MiG-29G": [{
|
||||||
|
"default": "MiG-29G Fulcrum-A"
|
||||||
|
}],
|
||||||
|
"MiG-29S": [{
|
||||||
|
"default": "MiG-29S Fulcrum-C"
|
||||||
|
}],
|
||||||
|
"MiG-31": [{
|
||||||
|
"default": "MiG-31 Foxhound"
|
||||||
|
}],
|
||||||
|
"P-47D-30": [{
|
||||||
|
"default": "P-47D-30 Thunderbolt (Late)",
|
||||||
|
"UK": "Thunderbolt Mk.II (Mid)"
|
||||||
|
}],
|
||||||
|
"P-47D-30bl1": [{
|
||||||
|
"default": "P-47D-30 Thunderbolt (Early)",
|
||||||
|
"UK": "Thunderbolt Mk.II (Early)"
|
||||||
|
}],
|
||||||
|
"P-47D-40": [{
|
||||||
|
"default": "P-47D-40 Thunderbolt",
|
||||||
|
"UK": "Thunderbolt Mk.II (Late)"
|
||||||
|
}],
|
||||||
|
"P-51D": [{
|
||||||
|
"default": "P-51D-25-NA Mustang",
|
||||||
|
"UK": "Mustang Mk.IV (Early)"
|
||||||
|
}],
|
||||||
|
"P-51D-30-NA": [{
|
||||||
|
"default": "P-51D-30-NA Mustang",
|
||||||
|
"UK": "Mustang Mk.IV (Late)"
|
||||||
|
}],
|
||||||
|
"Rafale_A_S": [{
|
||||||
|
"default": "Rafale M (Air-to-Ground)"
|
||||||
|
}],
|
||||||
|
"Rafale_B": [{
|
||||||
|
"default": "Rafale B"
|
||||||
|
}],
|
||||||
|
"Rafale_M": [{
|
||||||
|
"default": "Rafale M (Air-to-Air)"
|
||||||
|
}],
|
||||||
|
"S-3B": [{
|
||||||
|
"default": "S-3B Viking"
|
||||||
|
}],
|
||||||
|
"SA342L": [{
|
||||||
|
"default": "SA 342L Gazelle"
|
||||||
|
}],
|
||||||
|
"SA342M": [{
|
||||||
|
"default": "SA 342M Gazelle",
|
||||||
|
"UK": "Gazelle AH.1"
|
||||||
|
}],
|
||||||
|
"SA342Mistral": [{
|
||||||
|
"default": "SA 342M Gazelle Mistral"
|
||||||
|
}],
|
||||||
|
"SpitfireLFMkIX": [{
|
||||||
|
"default": "Spitfire LF Mk IX"
|
||||||
|
}],
|
||||||
|
"SpitfireLFMkIXCW": [{
|
||||||
|
"default": "Spitfire LF Mk IX (Clipped Wings)"
|
||||||
|
}],
|
||||||
|
"Su-17M4": [{
|
||||||
|
"default": "Su-17M4 Fitter-K",
|
||||||
|
"Poland": "Su-22M4 Fitter-K"
|
||||||
|
}],
|
||||||
|
"Su-24M": [{
|
||||||
|
"default": "Su-24M Fencer-D"
|
||||||
|
}],
|
||||||
|
"Su-25": [{
|
||||||
|
"default": "Su-25 Frogfoot"
|
||||||
|
}],
|
||||||
|
"Su-25T": [{
|
||||||
|
"default": "Su-25T Frogfoot"
|
||||||
|
}],
|
||||||
|
"Su-27": [{
|
||||||
|
"default": "Su-27 Flanker-B"
|
||||||
|
}],
|
||||||
|
"Su-30": [{
|
||||||
|
"default": "Su-30 Flanker-C"
|
||||||
|
}],
|
||||||
|
"Su-33": [{
|
||||||
|
"default": "Su-33 Flanker-D"
|
||||||
|
}],
|
||||||
|
"Su-34": [{
|
||||||
|
"default": "Su-34 Fullback"
|
||||||
|
}],
|
||||||
|
"Su-57": [{
|
||||||
|
"default": "Su-57 Felon"
|
||||||
|
}],
|
||||||
|
"Tornado GR4": [{
|
||||||
|
"default": "Tornado GR4"
|
||||||
|
}],
|
||||||
|
"Tornado IDS": [{
|
||||||
|
"default": "Tornado IDS"
|
||||||
|
}],
|
||||||
|
"Tu-22M3": [{
|
||||||
|
"default": "Tu-22M3 Backfire-C"
|
||||||
|
}],
|
||||||
|
"Tu-95MS": [{
|
||||||
|
"default": "Tu-95MS Bear-H"
|
||||||
|
}],
|
||||||
|
"Tu-160": [{
|
||||||
|
"default": "Tu-160 Blackjack"
|
||||||
|
}],
|
||||||
|
"UH-1H": [{
|
||||||
|
"default": "UH-1H Iroquois",
|
||||||
|
"Germany": "UH-1D Iroquois"
|
||||||
|
}]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user