From cefc36a6a9e06eb718c5cb99697382564b050f00 Mon Sep 17 00:00:00 2001 From: bbirchnz Date: Sun, 9 Jan 2022 16:37:57 +1100 Subject: [PATCH] Add aircraft property for Zulu time preference. --- game/dcs/aircrafttype.py | 4 +++ game/missiongenerator/kneeboard.py | 16 +++++++--- game/theater/conflicttheater.py | 33 +++++++++++++++++++++ resources/units/aircraft/FA-18C_hornet.yaml | 1 + 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/game/dcs/aircrafttype.py b/game/dcs/aircrafttype.py index 383ff385..826f19de 100644 --- a/game/dcs/aircrafttype.py +++ b/game/dcs/aircrafttype.py @@ -157,6 +157,9 @@ class AircraftType(UnitType[Type[FlyingType]]): # If true, kneeboards will be generated in metric units metric_kneeboard: bool + # If true, kneeboards will display zulu times + utc_kneeboard: bool + max_group_size: int patrol_altitude: Optional[Distance] patrol_speed: Optional[Speed] @@ -399,4 +402,5 @@ class AircraftType(UnitType[Type[FlyingType]]): channel_allocator=radio_config.channel_allocator, channel_namer=radio_config.channel_namer, metric_kneeboard=data.get("metric_kneeboard", False), + utc_kneeboard=data.get("utc_kneeboard", False), ) diff --git a/game/missiongenerator/kneeboard.py b/game/missiongenerator/kneeboard.py index 6a1900fc..a745ff8d 100644 --- a/game/missiongenerator/kneeboard.py +++ b/game/missiongenerator/kneeboard.py @@ -266,7 +266,7 @@ class FlightPlanBuilder: if time is None: return "" local_time = self.start_time + time - return local_time.strftime(f"%H:%M:%S") + return f"{local_time.strftime('%H:%M:%S')}{'Z' if local_time.tzinfo is not None else ''}" def _format_alt(self, alt: Distance) -> str: if self.is_metric: @@ -584,7 +584,7 @@ class SupportPage(KneeboardPage): if time is None: return "" local_time = self.start_time + time - return local_time.strftime(f"%H:%M:%S") + return f"{local_time.strftime('%H:%M:%S')}{'Z' if local_time.tzinfo is not None else ''}" class SeadTaskPage(KneeboardPage): @@ -743,13 +743,21 @@ class KneeboardGenerator(MissionInfoGenerator): def generate_flight_kneeboard(self, flight: FlightData) -> List[KneeboardPage]: """Returns a list of kneeboard pages for the given flight.""" + + if flight.aircraft_type.utc_kneeboard: + zoned_time = self.game.conditions.start_time.replace( + tzinfo=self.game.theater.timezone + ).astimezone(datetime.timezone.utc) + else: + zoned_time = self.game.conditions.start_time + pages: List[KneeboardPage] = [ BriefingPage( flight, self.game.bullseye_for(flight.friendly), self.game.theater, self.game.conditions.weather, - self.game.conditions.start_time, + zoned_time, self.dark_kneeboard, ), SupportPage( @@ -758,7 +766,7 @@ class KneeboardGenerator(MissionInfoGenerator): self.awacs, self.tankers, self.jtacs, - self.game.conditions.start_time, + zoned_time, self.dark_kneeboard, ), ] diff --git a/game/theater/conflicttheater.py b/game/theater/conflicttheater.py index b2d4ed5d..271782ca 100644 --- a/game/theater/conflicttheater.py +++ b/game/theater/conflicttheater.py @@ -1,5 +1,6 @@ from __future__ import annotations +import datetime import math from dataclasses import dataclass from pathlib import Path @@ -244,6 +245,10 @@ class ConflictTheater: return cp raise KeyError(f"Cannot find ControlPoint named {name}") + @property + def timezone(self) -> datetime.timezone: + raise NotImplementedError + @property def seasonal_conditions(self) -> SeasonalConditions: raise NotImplementedError @@ -277,6 +282,10 @@ class CaucasusTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=4)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.caucasus import CONDITIONS @@ -305,6 +314,10 @@ class PersianGulfTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=4)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.persiangulf import CONDITIONS @@ -333,6 +346,10 @@ class NevadaTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=-8)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.nevada import CONDITIONS @@ -361,6 +378,10 @@ class NormandyTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=0)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.normandy import CONDITIONS @@ -389,6 +410,10 @@ class TheChannelTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=2)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.thechannel import CONDITIONS @@ -417,6 +442,10 @@ class SyriaTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=3)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.syria import CONDITIONS @@ -442,6 +471,10 @@ class MarianaIslandsTheater(ConflictTheater): "night": (0, 5), } + @property + def timezone(self) -> datetime.timezone: + return datetime.timezone(datetime.timedelta(hours=10)) + @property def seasonal_conditions(self) -> SeasonalConditions: from .seasonalconditions.marianaislands import CONDITIONS diff --git a/resources/units/aircraft/FA-18C_hornet.yaml b/resources/units/aircraft/FA-18C_hornet.yaml index 511a0b48..e2af4f01 100644 --- a/resources/units/aircraft/FA-18C_hornet.yaml +++ b/resources/units/aircraft/FA-18C_hornet.yaml @@ -46,3 +46,4 @@ radios: # we must use radio 1 for the intra-flight radio. intra_flight_radio_index: 1 inter_flight_radio_index: 2 +utc_kneeboard: true \ No newline at end of file