Merge pull request #689 from walterroach/naming

Naming
This commit is contained in:
walterroach 2020-12-28 17:22:42 -06:00 committed by GitHub
commit 362caa6ac1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 137 additions and 58 deletions

View File

@ -26,12 +26,12 @@ from gen.environmentgen import EnvironmentGenerator
from gen.forcedoptionsgen import ForcedOptionsGenerator from gen.forcedoptionsgen import ForcedOptionsGenerator
from gen.groundobjectsgen import GroundObjectsGenerator from gen.groundobjectsgen import GroundObjectsGenerator
from gen.kneeboard import KneeboardGenerator from gen.kneeboard import KneeboardGenerator
from gen.naming import namegen
from gen.radios import RadioFrequency, RadioRegistry from gen.radios import RadioFrequency, RadioRegistry
from gen.tacan import TacanRegistry from gen.tacan import TacanRegistry
from gen.triggergen import TRIGGER_RADIUS_MEDIUM, TriggersGenerator from gen.triggergen import TRIGGER_RADIUS_MEDIUM, TriggersGenerator
from .. import db from .. import db
from ..debriefing import Debriefing
from ..theater import Airfield from ..theater import Airfield
from ..unitmap import UnitMap from ..unitmap import UnitMap
@ -86,7 +86,7 @@ class Operation:
cls.game.enemy_country, cls.game.enemy_country,
frontline.position frontline.position
) )
@classmethod @classmethod
def air_conflict(cls) -> Conflict: def air_conflict(cls) -> Conflict:
assert cls.game assert cls.game
@ -103,7 +103,7 @@ class Operation:
cls.game.enemy_name, cls.game.enemy_name,
cls.game.player_country, cls.game.player_country,
cls.game.enemy_country, cls.game.enemy_country,
mid_point mid_point
) )
@classmethod @classmethod
@ -295,7 +295,7 @@ class Operation:
heading=d["orientation"], heading=d["orientation"],
dead=True, dead=True,
) )
@classmethod @classmethod
def generate(cls) -> UnitMap: def generate(cls) -> UnitMap:
"""Build the final Mission to be exported""" """Build the final Mission to be exported"""
@ -349,7 +349,7 @@ class Operation:
cls.jtacs, cls.jtacs,
cls.airgen cls.airgen
) )
cls.reset_naming_ids()
return cls.unit_map return cls.unit_map
@classmethod @classmethod
@ -411,6 +411,15 @@ class Operation:
ground_conflict_gen.generate() ground_conflict_gen.generate()
cls.jtacs.extend(ground_conflict_gen.jtacs) cls.jtacs.extend(ground_conflict_gen.jtacs)
@classmethod
def reset_naming_ids(cls):
if not cls.game:
logging.warning("Game object not initialized before resetting IDs")
return
cls.game.current_group_id = 0
cls.game.current_unit_id = 0
namegen.reset_numbers()
@classmethod @classmethod
def generate_lua(cls, airgen: AircraftConflictGenerator, def generate_lua(cls, airgen: AircraftConflictGenerator,
airsupportgen: AirSupportConflictGenerator, airsupportgen: AirSupportConflictGenerator,

View File

@ -971,8 +971,8 @@ class AircraftConflictGenerator:
arrival=control_point, divert=None) arrival=control_point, divert=None)
group = self._generate_at_airport( group = self._generate_at_airport(
name=namegen.next_unit_name(country, control_point.id, name=namegen.next_aircraft_name(country, control_point.id,
aircraft), flight),
side=country, side=country,
unit_type=aircraft, unit_type=aircraft,
count=1, count=1,
@ -1036,17 +1036,18 @@ class AircraftConflictGenerator:
CoalitionHasAirdrome(coalition, flight.from_cp.id)) CoalitionHasAirdrome(coalition, flight.from_cp.id))
def generate_planned_flight(self, cp, country, flight:Flight): def generate_planned_flight(self, cp, country, flight:Flight):
name = namegen.next_aircraft_name(country, cp.id, flight)
try: try:
if flight.start_type == "In Flight": if flight.start_type == "In Flight":
group = self._generate_inflight( group = self._generate_inflight(
name=namegen.next_unit_name(country, cp.id, flight.unit_type), name=name,
side=country, side=country,
flight=flight, flight=flight,
origin=cp) origin=cp)
elif isinstance(cp, NavalControlPoint): elif isinstance(cp, NavalControlPoint):
group_name = cp.get_carrier_group_name() group_name = cp.get_carrier_group_name()
group = self._generate_at_group( group = self._generate_at_group(
name=namegen.next_unit_name(country, cp.id, flight.unit_type), name=name,
side=country, side=country,
unit_type=flight.unit_type, unit_type=flight.unit_type,
count=flight.count, count=flight.count,
@ -1057,8 +1058,7 @@ class AircraftConflictGenerator:
raise RuntimeError( raise RuntimeError(
f"Attempted to spawn at airfield for non-airfield {cp}") f"Attempted to spawn at airfield for non-airfield {cp}")
group = self._generate_at_airport( group = self._generate_at_airport(
name=namegen.next_unit_name(country, cp.id, name=name,
flight.unit_type),
side=country, side=country,
unit_type=flight.unit_type, unit_type=flight.unit_type,
count=flight.count, count=flight.count,
@ -1070,7 +1070,7 @@ class AircraftConflictGenerator:
logging.warning("No room on runway or parking slots. Starting from the air.") logging.warning("No room on runway or parking slots. Starting from the air.")
flight.start_type = "In Flight" flight.start_type = "In Flight"
group = self._generate_inflight( group = self._generate_inflight(
name=namegen.next_unit_name(country, cp.id, flight.unit_type), name=name,
side=country, side=country,
flight=flight, flight=flight,
origin=cp) origin=cp)

View File

@ -206,7 +206,7 @@ class GroundConflictGenerator:
u = random.choice(manpads) u = random.choice(manpads)
self.mission.vehicle_group( self.mission.vehicle_group(
side, side,
namegen.next_infantry_name(side, cp, u), u, namegen.next_infantry_name(side, cp.id, u), u,
position=infantry_position, position=infantry_position,
group_size=1, group_size=1,
heading=forward_heading, heading=forward_heading,
@ -220,7 +220,7 @@ class GroundConflictGenerator:
u = random.choice(possible_infantry_units) u = random.choice(possible_infantry_units)
self.mission.vehicle_group( self.mission.vehicle_group(
side, side,
namegen.next_infantry_name(side, cp, u), u, namegen.next_infantry_name(side, cp.id, u), u,
position=infantry_position, position=infantry_position,
group_size=1, group_size=1,
heading=forward_heading, heading=forward_heading,
@ -231,7 +231,7 @@ class GroundConflictGenerator:
position = infantry_position.random_point_within(55, 5) position = infantry_position.random_point_within(55, 5)
self.mission.vehicle_group( self.mission.vehicle_group(
side, side,
namegen.next_infantry_name(side, cp, u), u, namegen.next_infantry_name(side, cp.id, u), u,
position=position, position=position,
group_size=1, group_size=1,
heading=forward_heading, heading=forward_heading,

View File

@ -137,7 +137,8 @@ class Flight:
def __init__(self, package: Package, unit_type: Type[FlyingType], def __init__(self, package: Package, 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]) -> None: divert: Optional[ControlPoint],
custom_name: Optional[str] = None) -> None:
self.package = package self.package = package
self.unit_type = unit_type self.unit_type = unit_type
self.count = count self.count = count
@ -151,6 +152,7 @@ class Flight:
self.start_type = start_type self.start_type = start_type
self.use_custom_loadout = False self.use_custom_loadout = False
self.client_count = 0 self.client_count = 0
self.custom_name = custom_name
# Will be replaced with a more appropriate FlightPlan by # Will be replaced with a more appropriate FlightPlan by
# FlightPlanBuilder, but an empty flight plan the flight begins with an # FlightPlanBuilder, but an empty flight plan the flight begins with an
@ -172,4 +174,6 @@ class Flight:
def __repr__(self): def __repr__(self):
name = db.unit_type_name(self.unit_type) name = db.unit_type_name(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}" return f"[{self.flight_type}] {self.count} x {name}"

View File

@ -1,16 +1,19 @@
from game import db
import random import random
ALPHA_MILITARY = ["Alpha","Bravo","Charlie","Delta","Echo","Foxtrot", from dcs.country import Country
"Golf","Hotel","India","Juliet","Kilo","Lima","Mike", from dcs.unittype import UnitType
"November","Oscar","Papa","Quebec","Romeo","Sierra",
"Tango","Uniform","Victor","Whisky","XRay","Yankee",
"Zulu","Zero"]
class NameGenerator: from game import db
number = 0
ANIMALS = [ from gen.flights.flight import Flight
ALPHA_MILITARY = ["Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot",
"Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike",
"November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra",
"Tango", "Uniform", "Victor", "Whisky", "XRay", "Yankee",
"Zulu", "Zero"]
ANIMALS = [
"SHARK", "TORTOISE", "BAT", "PANGOLIN", "AARDWOLF", "SHARK", "TORTOISE", "BAT", "PANGOLIN", "AARDWOLF",
"MONKEY", "BUFFALO", "DOG", "BOBCAT", "LYNX", "PANTHER", "TIGER", "MONKEY", "BUFFALO", "DOG", "BOBCAT", "LYNX", "PANTHER", "TIGER",
"LION", "OWL", "BUTTERFLY", "BISON", "DUCK", "COBRA", "MAMBA", "LION", "OWL", "BUTTERFLY", "BISON", "DUCK", "COBRA", "MAMBA",
@ -38,47 +41,76 @@ class NameGenerator:
"ANACONDA" "ANACONDA"
] ]
def __init__(self): class NameGenerator:
self.number = 0 number = 0
self.ANIMALS = NameGenerator.ANIMALS.copy() infantry_number = 0
aircraft_number = 0
def reset(self): ANIMALS = ANIMALS
self.number = 0
self.ANIMALS = NameGenerator.ANIMALS.copy()
def next_unit_name(self, country, parent_base_id, unit_type): @classmethod
self.number += 1 def reset(cls):
return "unit|{}|{}|{}|{}|".format(country.id, self.number, parent_base_id, db.unit_type_name(unit_type)) cls.number = 0
cls.infantry_number = 0
cls.ANIMALS = ANIMALS
def next_infantry_name(self, country, parent_base_id, unit_type): @classmethod
self.number += 1 def reset_numbers(cls):
return "infantry|{}|{}|{}|{}|".format(country.id, self.number, parent_base_id, db.unit_type_name(unit_type)) cls.number = 0
cls.infantry_number = 0
cls.aircraft_number = 0
def next_basedefense_name(self): @classmethod
def next_aircraft_name(cls, country: Country, parent_base_id: int, flight: Flight):
cls.aircraft_number += 1
try:
if flight.custom_name:
name_str = flight.custom_name
else:
name_str = "{} {}".format(
flight.package.target.name, flight.flight_type)
except AttributeError: # Here to maintain save compatibility with 2.3
name_str = "{} {}".format(
flight.package.target.name, flight.flight_type)
return "{}|{}|{}|{}|{}|".format(name_str, country.id, cls.aircraft_number, parent_base_id, db.unit_type_name(flight.unit_type))
@classmethod
def next_unit_name(cls, country: Country, parent_base_id: int, unit_type: UnitType):
cls.number += 1
return "unit|{}|{}|{}|{}|".format(country.id, cls.number, parent_base_id, db.unit_type_name(unit_type))
@classmethod
def next_infantry_name(cls, country: Country, parent_base_id: int, unit_type: UnitType):
cls.infantry_number += 1
return "infantry|{}|{}|{}|{}|".format(country.id, cls.infantry_number, parent_base_id, db.unit_type_name(unit_type))
@staticmethod
def next_basedefense_name():
return "basedefense_aa|0|0|" return "basedefense_aa|0|0|"
def next_awacs_name(self, country): @classmethod
self.number += 1 def next_awacs_name(cls, country: Country):
return "awacs|{}|{}|0|".format(country.id, self.number) cls.number += 1
return "awacs|{}|{}|0|".format(country.id, cls.number)
def next_tanker_name(self, country, unit_type): @classmethod
self.number += 1 def next_tanker_name(cls, country: Country, unit_type: UnitType):
return "tanker|{}|{}|0|{}".format(country.id, self.number, db.unit_type_name(unit_type)) cls.number += 1
return "tanker|{}|{}|0|{}".format(country.id, cls.number, db.unit_type_name(unit_type))
def next_carrier_name(self, country): @classmethod
self.number += 1 def next_carrier_name(cls, country: Country):
return "carrier|{}|{}|0|".format(country.id, self.number) cls.number += 1
return "carrier|{}|{}|0|".format(country.id, cls.number)
def random_objective_name(self): @classmethod
if len(self.ANIMALS) == 0: def random_objective_name(cls):
if len(cls.ANIMALS) == 0:
return random.choice(ALPHA_MILITARY).upper() + "#" + str(random.randint(0, 100)) return random.choice(ALPHA_MILITARY).upper() + "#" + str(random.randint(0, 100))
else: else:
animal = random.choice(self.ANIMALS) animal = random.choice(cls.ANIMALS)
self.ANIMALS.remove(animal) cls.ANIMALS.remove(animal)
return animal return animal
namegen = NameGenerator() namegen = NameGenerator

View File

@ -65,7 +65,7 @@ class FlightDelegate(QStyledItemDelegate):
name = db.unit_type_name(flight.unit_type) name = db.unit_type_name(flight.unit_type)
estimator = TotEstimator(self.package) estimator = TotEstimator(self.package)
delay = estimator.mission_start_time(flight) delay = estimator.mission_start_time(flight)
return f"[{task}] {count} x {name} in {delay}" return f"{flight} in {delay}"
def second_row_text(self, index: QModelIndex) -> str: def second_row_text(self, index: QModelIndex) -> str:
flight = self.flight(index) flight = self.flight(index)

View File

@ -1,3 +1,4 @@
from re import L
from typing import Optional from typing import Optional
from PySide2.QtCore import Qt, Signal from PySide2.QtCore import Qt, Signal
@ -6,6 +7,7 @@ from PySide2.QtWidgets import (
QMessageBox, QMessageBox,
QPushButton, QPushButton,
QVBoxLayout, QVBoxLayout,
QLineEdit,
) )
from dcs.planes import PlaneType from dcs.planes import PlaneType
@ -31,6 +33,7 @@ class QFlightCreator(QDialog):
self.game = game self.game = game
self.package = package self.package = package
self.custom_name_text = None
self.setWindowTitle("Create flight") self.setWindowTitle("Create flight")
self.setWindowIcon(EVENT_ICONS["strike"]) self.setWindowIcon(EVENT_ICONS["strike"])
@ -88,6 +91,12 @@ class QFlightCreator(QDialog):
layout.addLayout( layout.addLayout(
QLabeledWidget("Client Slots:", self.client_slots_spinner)) QLabeledWidget("Client Slots:", self.client_slots_spinner))
self.custom_name = QLineEdit()
self.custom_name.textChanged.connect(self.set_custom_name_text)
layout.addLayout(
QLabeledWidget("Custom Flight Name (Optional)", self.custom_name)
)
layout.addStretch() layout.addStretch()
self.create_button = QPushButton("Create") self.create_button = QPushButton("Create")
@ -96,6 +105,9 @@ class QFlightCreator(QDialog):
self.setLayout(layout) self.setLayout(layout)
def set_custom_name_text(self, text: str):
self.custom_name_text = text
def verify_form(self) -> Optional[str]: def verify_form(self) -> Optional[str]:
aircraft: PlaneType = self.aircraft_selector.currentData() aircraft: PlaneType = self.aircraft_selector.currentData()
origin: ControlPoint = self.departure.currentData() origin: ControlPoint = self.departure.currentData()
@ -115,6 +127,8 @@ class QFlightCreator(QDialog):
return f"{origin.name} has only {available} {aircraft.id} available." return f"{origin.name} has only {available} {aircraft.id} available."
if size <= 0: if size <= 0:
return f"Flight must have at least one aircraft." return f"Flight must have at least one aircraft."
if self.custom_name_text and "|" in self.custom_name_text:
return f"Cannot include | in flight name"
return None return None
def create_flight(self) -> None: def create_flight(self) -> None:
@ -141,7 +155,7 @@ class QFlightCreator(QDialog):
else: else:
start_type = "Warm" start_type = "Warm"
flight = Flight(self.package, aircraft, size, task, start_type, origin, flight = Flight(self.package, aircraft, size, task, start_type, origin,
arrival, divert) arrival, divert, custom_name=self.custom_name_text)
flight.client_count = self.client_slots_spinner.value() flight.client_count = self.client_slots_spinner.value()
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences

View File

@ -0,0 +1,16 @@
from PySide2.QtWidgets import QGroupBox, QHBoxLayout, QLabel
from gen.flights.flight import Flight
class QFlightCustomName(QGroupBox):
def __init__(self, flight: Flight):
super(QFlightCustomName, self).__init__()
self.flight = flight
self.layout = QHBoxLayout()
self.custom_name_label = QLabel(f"Custom Name: {flight.custom_name}")
self.layout.addWidget(self.custom_name_label)
self.setLayout(self.layout)

View File

@ -1,5 +1,5 @@
from PySide2.QtCore import Signal from PySide2.QtCore import Signal
from PySide2.QtWidgets import QFrame, QGridLayout, QVBoxLayout from PySide2.QtWidgets import QFrame, QGridLayout, QVBoxLayout, QLabel
from game import Game from game import Game
from gen.ato import Package from gen.ato import Package
@ -12,6 +12,8 @@ from qt_ui.windows.mission.flight.settings.QFlightStartType import \
QFlightStartType QFlightStartType
from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import \ from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import \
QFlightTypeTaskInfo QFlightTypeTaskInfo
from qt_ui.windows.mission.flight.settings.QCustomName import \
QFlightCustomName
class QGeneralFlightSettingsTab(QFrame): class QGeneralFlightSettingsTab(QFrame):
@ -25,10 +27,12 @@ class QGeneralFlightSettingsTab(QFrame):
flight_departure = QFlightDepartureDisplay(package, flight) flight_departure = QFlightDepartureDisplay(package, flight)
flight_slots = QFlightSlotEditor(flight, game) flight_slots = QFlightSlotEditor(flight, game)
flight_start_type = QFlightStartType(flight) flight_start_type = QFlightStartType(flight)
flight_custom_name = QFlightCustomName(flight)
layout.addWidget(flight_info, 0, 0) layout.addWidget(flight_info, 0, 0)
layout.addWidget(flight_departure, 1, 0) layout.addWidget(flight_departure, 1, 0)
layout.addWidget(flight_slots, 2, 0) layout.addWidget(flight_slots, 2, 0)
layout.addWidget(flight_start_type, 3, 0) layout.addWidget(flight_start_type, 3, 0)
layout.addWidget(flight_custom_name, 4, 0)
vstretch = QVBoxLayout() vstretch = QVBoxLayout()
vstretch.addStretch() vstretch.addStretch()
layout.addLayout(vstretch, 3, 0) layout.addLayout(vstretch, 3, 0)