diff --git a/changelog.md b/changelog.md
index b1a7ec6c..5fc245cd 100644
--- a/changelog.md
+++ b/changelog.md
@@ -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]** 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]** 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 Poland 2010 faction.
* **[Factions]** Added Greece 2005 faction.
diff --git a/game/db.py b/game/db.py
index 3a331588..16c65e97 100644
--- a/game/db.py
+++ b/game/db.py
@@ -1,6 +1,8 @@
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Tuple, Type, Union
+import json
+from pathlib import Path
from dcs.countries import country_dict
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.su57.su57 import Su_57
+PRETTYNAMES_PATH = Path("./resources/units/pretty_unit_names.json")
+
plane_map["A-4E-C"] = A_4E_C
plane_map["MB-339PAN"] = MB_339PAN
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:
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]]:
if name in vehicle_map:
diff --git a/gen/aircraft.py b/gen/aircraft.py
index d9d35770..51c9dd03 100644
--- a/gen/aircraft.py
+++ b/gen/aircraft.py
@@ -262,6 +262,9 @@ class FlightData:
#: The package that the flight belongs to.
package: Package
+ #: The country that the flight belongs to.
+ country: str
+
flight_type: FlightType
#: All units in the flight.
@@ -299,7 +302,7 @@ class FlightData:
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,
departure_delay: timedelta, departure: RunwayData,
arrival: RunwayData, divert: Optional[RunwayData],
@@ -308,6 +311,7 @@ class FlightData:
bingo_fuel: Optional[int],
joker_fuel: Optional[int]) -> None:
self.package = package
+ self.country = country
self.flight_type = flight_type
self.units = units
self.size = size
@@ -778,6 +782,7 @@ class AircraftConflictGenerator:
self.flights.append(FlightData(
package=package,
+ country=faction.country,
flight_type=flight.flight_type,
units=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
# reuse the existing debriefing code.
# 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,
arrival=control_point, divert=None)
diff --git a/gen/flights/ai_flight_planner.py b/gen/flights/ai_flight_planner.py
index b40c7abe..45c9d1e6 100644
--- a/gen/flights/ai_flight_planner.py
+++ b/gen/flights/ai_flight_planner.py
@@ -173,9 +173,11 @@ class PackageBuilder:
closest_airfields: ClosestAirfields,
global_inventory: GlobalAircraftInventory,
is_player: bool,
+ package_country: str,
start_type: str) -> None:
self.closest_airfields = closest_airfields
self.is_player = is_player
+ self.package_country = package_country
self.package = Package(location)
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
is_player)
@@ -199,7 +201,7 @@ class PackageBuilder:
else:
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,
divert=self.find_divert_field(aircraft, airfield))
self.package.add_flight(flight)
@@ -629,11 +631,17 @@ class CoalitionMissionPlanner:
else:
start_type = "Warm"
+ if self.is_player:
+ package_country = self.game.player_country
+ else:
+ package_country = self.game.enemy_country
+
builder = PackageBuilder(
mission.location,
self.objective_finder.closest_airfields_to(mission.location),
self.game.aircraft_inventory,
self.is_player,
+ package_country,
start_type
)
diff --git a/gen/flights/flight.py b/gen/flights/flight.py
index 3125d6e1..1176bb62 100644
--- a/gen/flights/flight.py
+++ b/gen/flights/flight.py
@@ -136,12 +136,13 @@ class FlightWaypoint:
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,
departure: ControlPoint, arrival: ControlPoint,
divert: Optional[ControlPoint],
custom_name: Optional[str] = None) -> None:
self.package = package
+ self.country = country
self.unit_type = unit_type
self.count = count
self.departure = departure
@@ -179,3 +180,9 @@ class Flight:
if self.custom_name:
return f"{self.custom_name} {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}"
diff --git a/qt_ui/widgets/combos/QAircraftTypeSelector.py b/qt_ui/widgets/combos/QAircraftTypeSelector.py
index f31c611d..a12e57d4 100644
--- a/qt_ui/widgets/combos/QAircraftTypeSelector.py
+++ b/qt_ui/widgets/combos/QAircraftTypeSelector.py
@@ -5,12 +5,13 @@ from PySide2.QtWidgets import QComboBox
from dcs.unittype import FlyingType
+from game import Game, db
class QAircraftTypeSelector(QComboBox):
"""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__()
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)
diff --git a/qt_ui/windows/QDebriefingWindow.py b/qt_ui/windows/QDebriefingWindow.py
index a2d4c25c..f0552bce 100644
--- a/qt_ui/windows/QDebriefingWindow.py
+++ b/qt_ui/windows/QDebriefingWindow.py
@@ -52,7 +52,7 @@ class QDebriefingWindow(QDialog):
for unit_type, count in player_air_losses.items():
try:
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)
row += 1
except AttributeError:
@@ -94,7 +94,7 @@ class QDebriefingWindow(QDialog):
for unit_type, count in enemy_air_losses.items():
try:
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)
row += 1
except AttributeError:
diff --git a/qt_ui/windows/basemenu/QRecruitBehaviour.py b/qt_ui/windows/basemenu/QRecruitBehaviour.py
index 968d2b2a..7b6ad20b 100644
--- a/qt_ui/windows/basemenu/QRecruitBehaviour.py
+++ b/qt_ui/windows/basemenu/QRecruitBehaviour.py
@@ -58,7 +58,7 @@ class QRecruitBehaviour:
existing_units = self.cp.base.total_units_of_type(unit_type)
scheduled_units = self.pending_deliveries.units.get(unit_type, 0)
- unitName = QLabel("" + db.unit_type_name_2(unit_type) + "")
+ unitName = QLabel("" + db.unit_pretty_name(self.game_model.game.player_country, unit_type) + "")
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
existing_units = QLabel(str(existing_units))
diff --git a/qt_ui/windows/basemenu/intel/QIntelInfo.py b/qt_ui/windows/basemenu/intel/QIntelInfo.py
index e422ef3a..1f9a8f80 100644
--- a/qt_ui/windows/basemenu/intel/QIntelInfo.py
+++ b/qt_ui/windows/basemenu/intel/QIntelInfo.py
@@ -46,7 +46,7 @@ class QIntelInfo(QFrame):
existing_units = self.cp.base.total_units_of_type(unit_type)
if existing_units == 0:
continue
- groupLayout.addWidget(QLabel("" + db.unit_type_name(unit_type) + ""), row, 0)
+ groupLayout.addWidget(QLabel("" + db.unit_pretty_name(self.game.enemy_country, unit_type) + ""), row, 0)
groupLayout.addWidget(QLabel(str(existing_units)), row, 1)
row += 1
diff --git a/qt_ui/windows/intel.py b/qt_ui/windows/intel.py
index 497d65fb..eb7ee427 100644
--- a/qt_ui/windows/intel.py
+++ b/qt_ui/windows/intel.py
@@ -14,7 +14,7 @@ from PySide2.QtWidgets import (
QWidget,
)
-from game.game import Game
+from game.game import Game, db
from qt_ui.uiconstants import ICONS
from qt_ui.windows.finances.QFinancesMenu import FinancesLayout
@@ -81,7 +81,7 @@ class AircraftIntelLayout(IntelTableLayout):
for airframe, count in base.aircraft.items():
if not count:
continue
- self.add_row(airframe.id, count)
+ self.add_row(db.unit_pretty_name(game.enemy_country, airframe), count)
self.add_spacer()
self.add_row("Total", total)
diff --git a/qt_ui/windows/mission/flight/QFlightCreator.py b/qt_ui/windows/mission/flight/QFlightCreator.py
index 8066754f..f4eccb50 100644
--- a/qt_ui/windows/mission/flight/QFlightCreator.py
+++ b/qt_ui/windows/mission/flight/QFlightCreator.py
@@ -34,6 +34,7 @@ class QFlightCreator(QDialog):
self.game = game
self.package = package
self.custom_name_text = None
+ self.country = self.game.player_country
self.setWindowTitle("Create flight")
self.setWindowIcon(EVENT_ICONS["strike"])
@@ -47,7 +48,7 @@ class QFlightCreator(QDialog):
layout.addLayout(QLabeledWidget("Task:", self.task_selector))
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.currentIndexChanged.connect(
@@ -154,7 +155,7 @@ class QFlightCreator(QDialog):
start_type = "Cold"
else:
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)
flight.client_count = self.client_slots_spinner.value()
diff --git a/resources/units/pretty_unit_names.json b/resources/units/pretty_unit_names.json
new file mode 100644
index 00000000..14955f23
--- /dev/null
+++ b/resources/units/pretty_unit_names.json
@@ -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"
+ }]
+}