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" + }] +}