Assign laser codes to players with TGPs.

This doesn't configure the bombs in the mission or anything yet; it only
pre-assigns a laser code for the player to use if they choose to.
This commit is contained in:
Dan Albert 2021-07-31 16:49:58 -07:00
parent fc45c3b98c
commit 73ba7933da
4 changed files with 44 additions and 44 deletions

View File

@ -294,8 +294,10 @@ class Operation:
cls._generate_ground_units() cls._generate_ground_units()
cls._generate_transports() cls._generate_transports()
cls._generate_destroyed_units() cls._generate_destroyed_units()
cls._generate_air_units() # Generate ground conflicts first so the JTACs get the first laser code (1688)
# rather than the first player flight with a TGP.
cls._generate_ground_conflicts() cls._generate_ground_conflicts()
cls._generate_air_units()
cls.assign_channels_to_flights( cls.assign_channels_to_flights(
cls.airgen.flights, cls.airsupportgen.air_support cls.airgen.flights, cls.airsupportgen.air_support
) )
@ -357,6 +359,7 @@ class Operation:
cls.game, cls.game,
cls.radio_registry, cls.radio_registry,
cls.tacan_registry, cls.tacan_registry,
cls.laser_code_registry,
cls.unit_map, cls.unit_map,
air_support=cls.airsupportgen.air_support, air_support=cls.airsupportgen.air_support,
) )

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import itertools import itertools
import logging import logging
import random import random
from dataclasses import dataclass from dataclasses import dataclass, field
from datetime import timedelta from datetime import timedelta
from functools import cached_property from functools import cached_property
from typing import Dict, List, Optional, TYPE_CHECKING, Type, Union, Iterable, Any from typing import Dict, List, Optional, TYPE_CHECKING, Type, Union, Iterable, Any
@ -65,7 +65,7 @@ from dcs.unitgroup import FlyingGroup, ShipGroup, StaticGroup
from dcs.unittype import FlyingType from dcs.unittype import FlyingType
from game import db from game import db
from game.data.weapons import Pylon from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from game.factions.faction import Faction from game.factions.faction import Faction
from game.settings import Settings from game.settings import Settings
@ -90,6 +90,7 @@ from gen.flights.flight import (
FlightWaypoint, FlightWaypoint,
FlightWaypointType, FlightWaypointType,
) )
from gen.lasercoderegistry import LaserCodeRegistry
from gen.radios import RadioFrequency, RadioRegistry from gen.radios import RadioFrequency, RadioRegistry
from gen.runways import RunwayData from gen.runways import RunwayData
from gen.tacan import TacanBand, TacanRegistry from gen.tacan import TacanBand, TacanRegistry
@ -138,6 +139,8 @@ class FlightData:
flight_type: FlightType flight_type: FlightType
aircraft_type: AircraftType
#: All units in the flight. #: All units in the flight.
units: List[FlyingUnit] units: List[FlyingUnit]
@ -165,49 +168,24 @@ class FlightData:
#: Radio frequency for intra-flight communications. #: Radio frequency for intra-flight communications.
intra_flight_channel: RadioFrequency intra_flight_channel: RadioFrequency
#: Map of radio frequencies to their assigned radio and channel, if any.
frequency_to_channel_map: Dict[RadioFrequency, ChannelAssignment]
#: Bingo fuel value in lbs. #: Bingo fuel value in lbs.
bingo_fuel: Optional[int] bingo_fuel: Optional[int]
joker_fuel: Optional[int] joker_fuel: Optional[int]
def __init__( laser_codes: list[Optional[int]]
self,
package: Package, custom_name: Optional[str]
aircraft_type: AircraftType,
flight_type: FlightType, callsign: str = field(init=False)
units: List[FlyingUnit],
size: int, #: Map of radio frequencies to their assigned radio and channel, if any.
friendly: bool, frequency_to_channel_map: Dict[RadioFrequency, ChannelAssignment] = field(
departure_delay: timedelta, init=False, default_factory=dict
departure: RunwayData, )
arrival: RunwayData,
divert: Optional[RunwayData], def __post_init__(self) -> None:
waypoints: List[FlightWaypoint],
intra_flight_channel: RadioFrequency,
bingo_fuel: Optional[int],
joker_fuel: Optional[int],
custom_name: Optional[str],
) -> None:
self.package = package
self.aircraft_type = aircraft_type
self.flight_type = flight_type
self.units = units
self.size = size
self.friendly = friendly
self.departure_delay = departure_delay
self.departure = departure
self.arrival = arrival
self.divert = divert
self.waypoints = waypoints
self.intra_flight_channel = intra_flight_channel
self.frequency_to_channel_map = {}
self.bingo_fuel = bingo_fuel
self.joker_fuel = joker_fuel
self.callsign = create_group_callsign_from_unit(self.units[0]) self.callsign = create_group_callsign_from_unit(self.units[0])
self.custom_name = custom_name
@property @property
def client_units(self) -> List[FlyingUnit]: def client_units(self) -> List[FlyingUnit]:
@ -247,6 +225,7 @@ class AircraftConflictGenerator:
game: Game, game: Game,
radio_registry: RadioRegistry, radio_registry: RadioRegistry,
tacan_registry: TacanRegistry, tacan_registry: TacanRegistry,
laser_code_registry: LaserCodeRegistry,
unit_map: UnitMap, unit_map: UnitMap,
air_support: AirSupport, air_support: AirSupport,
) -> None: ) -> None:
@ -255,6 +234,7 @@ class AircraftConflictGenerator:
self.settings = settings self.settings = settings
self.radio_registry = radio_registry self.radio_registry = radio_registry
self.tacan_registy = tacan_registry self.tacan_registy = tacan_registry
self.laser_code_registry = laser_code_registry
self.unit_map = unit_map self.unit_map = unit_map
self.flights: List[FlightData] = [] self.flights: List[FlightData] = []
self.air_support = air_support self.air_support = air_support
@ -361,6 +341,7 @@ class AircraftConflictGenerator:
self._setup_payload(flight, group) self._setup_payload(flight, group)
self._setup_livery(flight, group) self._setup_livery(flight, group)
laser_codes = []
for unit, pilot in zip(group.units, flight.roster.pilots): for unit, pilot in zip(group.units, flight.roster.pilots):
player = pilot is not None and pilot.player player = pilot is not None and pilot.player
self.set_skill(unit, pilot, blue=flight.departure.captured) self.set_skill(unit, pilot, blue=flight.departure.captured)
@ -368,6 +349,11 @@ class AircraftConflictGenerator:
if player and group.late_activation: if player and group.late_activation:
group.late_activation = False group.late_activation = False
code: Optional[int] = None
if flight.loadout.has_weapon_of_type(WeaponTypeEnum.TGP) and player:
code = self.laser_code_registry.get_next_laser_code()
laser_codes.append(code)
# Set up F-14 Client to have pre-stored alignment # Set up F-14 Client to have pre-stored alignment
if unit_type is F_14B: if unit_type is F_14B:
unit.set_property(F_14B.Properties.INSAlignmentStored.id, True) unit.set_property(F_14B.Properties.INSAlignmentStored.id, True)
@ -423,6 +409,7 @@ class AircraftConflictGenerator:
bingo_fuel=flight.flight_plan.bingo_fuel, bingo_fuel=flight.flight_plan.bingo_fuel,
joker_fuel=flight.flight_plan.joker_fuel, joker_fuel=flight.flight_plan.joker_fuel,
custom_name=flight.custom_name, custom_name=flight.custom_name,
laser_codes=laser_codes,
) )
) )

View File

@ -31,6 +31,12 @@ class Loadout:
def derive_custom(self, name: str) -> Loadout: def derive_custom(self, name: str) -> Loadout:
return Loadout(name, self.pylons, self.date, is_custom=True) return Loadout(name, self.pylons, self.date, is_custom=True)
def has_weapon_of_type(self, weapon_type: WeaponType) -> bool:
for weapon in self.pylons.values():
if weapon is not None and weapon.weapon_group.type is weapon_type:
return True
return False
@staticmethod @staticmethod
def _fallback_for( def _fallback_for(
weapon: Weapon, weapon: Weapon,
@ -79,10 +85,8 @@ class Loadout:
def replace_lgbs_if_no_tgp( def replace_lgbs_if_no_tgp(
self, unit_type: AircraftType, date: datetime.date self, unit_type: AircraftType, date: datetime.date
) -> None: ) -> None:
for weapon in self.pylons.values(): if self.has_weapon_of_type(WeaponType.TGP):
if weapon is not None and weapon.weapon_group.type is WeaponType.TGP: return
# Have a TGP. Nothing to do.
return
new_pylons = dict(self.pylons) new_pylons = dict(self.pylons)
for pylon_number, weapon in self.pylons.items(): for pylon_number, weapon in self.pylons.items():

View File

@ -354,6 +354,12 @@ class BriefingPage(KneeboardPage):
["Bingo", "Joker"], ["Bingo", "Joker"],
) )
if any(self.flight.laser_codes):
codes: list[list[str]] = []
for idx, code in enumerate(self.flight.laser_codes, start=1):
codes.append([str(idx), "" if code is None else str(code)])
writer.table(codes, ["#", "Laser Code"])
writer.write(path) writer.write(path)
def airfield_info_row( def airfield_info_row(