Adds prettier user-facing aircraft names. (#726)

This makes the names of the aircraft displayed to the player in the UI more verbose and readable.

It allows allows specific countries to display an aircraft's name differently. An example of this would be the JF-17 Thunder, which is known in China as the FC-1 Fierce Dragon - this now displays correctly in the Liberation UI.
This commit is contained in:
Simon Clark 2021-01-05 21:21:38 +00:00 committed by GitHub
parent c3401d478b
commit c740c8304b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 331 additions and 14 deletions

View File

@ -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.

View File

@ -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:

View File

@ -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)

View File

@ -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
)

View File

@ -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}"

View File

@ -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)

View File

@ -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:

View File

@ -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("<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))
existing_units = QLabel(str(existing_units))

View File

@ -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("<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)
row += 1

View File

@ -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("<b>Total</b>", total)

View File

@ -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()

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