mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Move and split up weather.py.
This is getting out of hand, and I'm about to make it worse.
This commit is contained in:
parent
080d346517
commit
8ed843a9cf
@ -39,7 +39,7 @@ from .theater.theatergroundobject import (
|
|||||||
)
|
)
|
||||||
from .theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
|
from .theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
|
||||||
from .timeofday import TimeOfDay
|
from .timeofday import TimeOfDay
|
||||||
from .weather import Conditions
|
from .weather.conditions import Conditions
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .ato.airtaaskingorder import AirTaskingOrder
|
from .ato.airtaaskingorder import AirTaskingOrder
|
||||||
|
|||||||
@ -3,7 +3,11 @@ from typing import Optional
|
|||||||
|
|
||||||
from dcs.mission import Mission
|
from dcs.mission import Mission
|
||||||
|
|
||||||
from game.weather import Clouds, Fog, Conditions, WindConditions, AtmosphericConditions
|
from game.weather.atmosphericconditions import AtmosphericConditions
|
||||||
|
from game.weather.clouds import Clouds
|
||||||
|
from game.weather.conditions import Conditions
|
||||||
|
from game.weather.fog import Fog
|
||||||
|
from game.weather.wind import WindConditions
|
||||||
|
|
||||||
|
|
||||||
class EnvironmentGenerator:
|
class EnvironmentGenerator:
|
||||||
|
|||||||
@ -43,8 +43,8 @@ from game.radio.radios import RadioFrequency
|
|||||||
from game.runways import RunwayData
|
from game.runways import RunwayData
|
||||||
from game.theater import TheaterGroundObject, TheaterUnit
|
from game.theater import TheaterGroundObject, TheaterUnit
|
||||||
from game.theater.bullseye import Bullseye
|
from game.theater.bullseye import Bullseye
|
||||||
from game.utils import Distance, UnitSystem, meters, mps, pounds, knots, feet
|
from game.utils import Distance, UnitSystem, meters, mps, pounds
|
||||||
from game.weather import Weather
|
from game.weather.weather import Weather
|
||||||
from .aircraft.flightdata import FlightData
|
from .aircraft.flightdata import FlightData
|
||||||
from .missiondata import AwacsInfo, TankerInfo
|
from .missiondata import AwacsInfo, TankerInfo
|
||||||
from .briefinggenerator import CommInfo, JtacInfo, MissionInfoGenerator
|
from .briefinggenerator import CommInfo, JtacInfo, MissionInfoGenerator
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from game.dcs.beacons import BeaconType, Beacons
|
|||||||
from game.radio.radios import RadioFrequency
|
from game.radio.radios import RadioFrequency
|
||||||
from game.radio.tacan import TacanChannel
|
from game.radio.tacan import TacanChannel
|
||||||
from game.utils import Heading
|
from game.utils import Heading
|
||||||
from game.weather import Conditions
|
from game.weather.conditions import Conditions
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game.theater import ConflictTheater
|
from game.theater import ConflictTheater
|
||||||
|
|||||||
@ -81,7 +81,7 @@ from ..radio.Link4Container import Link4Container
|
|||||||
from ..radio.RadioFrequencyContainer import RadioFrequencyContainer
|
from ..radio.RadioFrequencyContainer import RadioFrequencyContainer
|
||||||
from ..radio.TacanContainer import TacanContainer
|
from ..radio.TacanContainer import TacanContainer
|
||||||
from ..utils import nautical_miles
|
from ..utils import nautical_miles
|
||||||
from ..weather import Conditions
|
from ..weather.conditions import Conditions
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
|
|||||||
0
game/weather/__init__.py
Normal file
0
game/weather/__init__.py
Normal file
17
game/weather/atmosphericconditions.py
Normal file
17
game/weather/atmosphericconditions.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from game.utils import Pressure
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class AtmosphericConditions:
|
||||||
|
#: Pressure at sea level.
|
||||||
|
qnh: Pressure
|
||||||
|
|
||||||
|
#: Temperature at sea level in Celcius.
|
||||||
|
temperature_celsius: float
|
||||||
|
|
||||||
|
#: Turbulence per 10 cm.
|
||||||
|
turbulence_per_10cm: float
|
||||||
33
game/weather/clouds.py
Normal file
33
game/weather/clouds.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import random
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from dcs.cloud_presets import Clouds as PydcsClouds
|
||||||
|
from dcs.weather import Weather as PydcsWeather, CloudPreset
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Clouds:
|
||||||
|
base: int
|
||||||
|
density: int
|
||||||
|
thickness: int
|
||||||
|
precipitation: PydcsWeather.Preceptions
|
||||||
|
preset: Optional[CloudPreset] = field(default=None)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def random_preset(cls, rain: bool) -> Clouds:
|
||||||
|
clouds = (p.value for p in PydcsClouds)
|
||||||
|
if rain:
|
||||||
|
presets = [p for p in clouds if "Rain" in p.name]
|
||||||
|
else:
|
||||||
|
presets = [p for p in clouds if "Rain" not in p.name]
|
||||||
|
preset = random.choice(presets)
|
||||||
|
return Clouds(
|
||||||
|
base=random.randint(preset.min_base, preset.max_base),
|
||||||
|
density=0,
|
||||||
|
thickness=0,
|
||||||
|
precipitation=PydcsWeather.Preceptions.None_,
|
||||||
|
preset=preset,
|
||||||
|
)
|
||||||
93
game/weather/conditions.py
Normal file
93
game/weather/conditions.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import random
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from game.settings import Settings
|
||||||
|
from game.theater import ConflictTheater, DaytimeMap, SeasonalConditions
|
||||||
|
from game.theater.seasonalconditions import determine_season
|
||||||
|
from game.timeofday import TimeOfDay
|
||||||
|
from game.weather.weather import Weather, Thunderstorm, Raining, Cloudy, ClearSkies
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Conditions:
|
||||||
|
time_of_day: TimeOfDay
|
||||||
|
start_time: datetime.datetime
|
||||||
|
weather: Weather
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate(
|
||||||
|
cls,
|
||||||
|
theater: ConflictTheater,
|
||||||
|
day: datetime.date,
|
||||||
|
time_of_day: TimeOfDay,
|
||||||
|
settings: Settings,
|
||||||
|
forced_time: datetime.time | None = None,
|
||||||
|
) -> Conditions:
|
||||||
|
# The time might be forced by the campaign for the first turn.
|
||||||
|
if forced_time is not None:
|
||||||
|
_start_time = datetime.datetime.combine(day, forced_time)
|
||||||
|
else:
|
||||||
|
_start_time = cls.generate_start_time(
|
||||||
|
theater, day, time_of_day, settings.night_disabled
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
time_of_day=time_of_day,
|
||||||
|
start_time=_start_time,
|
||||||
|
weather=cls.generate_weather(theater.seasonal_conditions, day, time_of_day),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_start_time(
|
||||||
|
cls,
|
||||||
|
theater: ConflictTheater,
|
||||||
|
day: datetime.date,
|
||||||
|
time_of_day: TimeOfDay,
|
||||||
|
night_disabled: bool,
|
||||||
|
) -> datetime.datetime:
|
||||||
|
if night_disabled:
|
||||||
|
logging.info("Skip Night mission due to user settings")
|
||||||
|
time_range = DaytimeMap(
|
||||||
|
dawn=(datetime.time(hour=8), datetime.time(hour=9)),
|
||||||
|
day=(datetime.time(hour=10), datetime.time(hour=12)),
|
||||||
|
dusk=(datetime.time(hour=12), datetime.time(hour=14)),
|
||||||
|
night=(datetime.time(hour=14), datetime.time(hour=17)),
|
||||||
|
).range_of(time_of_day)
|
||||||
|
else:
|
||||||
|
time_range = theater.daytime_map.range_of(time_of_day)
|
||||||
|
|
||||||
|
# Starting missions on the hour is a nice gameplay property, so keep the random
|
||||||
|
# time constrained to that. DaytimeMap enforces that we have only whole hour
|
||||||
|
# ranges for now, so we don't need to worry about accidentally changing the time
|
||||||
|
# of day by truncating sub-hours.
|
||||||
|
time = datetime.time(
|
||||||
|
hour=random.randint(time_range[0].hour, time_range[1].hour)
|
||||||
|
)
|
||||||
|
return datetime.datetime.combine(day, time)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_weather(
|
||||||
|
cls,
|
||||||
|
seasonal_conditions: SeasonalConditions,
|
||||||
|
day: datetime.date,
|
||||||
|
time_of_day: TimeOfDay,
|
||||||
|
) -> Weather:
|
||||||
|
season = determine_season(day)
|
||||||
|
logging.debug("Weather: Season {}".format(season))
|
||||||
|
weather_chances = seasonal_conditions.weather_type_chances[season]
|
||||||
|
chances = {
|
||||||
|
Thunderstorm: weather_chances.thunderstorm,
|
||||||
|
Raining: weather_chances.raining,
|
||||||
|
Cloudy: weather_chances.cloudy,
|
||||||
|
ClearSkies: weather_chances.clear_skies,
|
||||||
|
}
|
||||||
|
logging.debug("Weather: Chances {}".format(weather_chances))
|
||||||
|
weather_type = random.choices(
|
||||||
|
list(chances.keys()), weights=list(chances.values())
|
||||||
|
)[0]
|
||||||
|
logging.debug("Weather: Type {}".format(weather_type))
|
||||||
|
return weather_type(seasonal_conditions, day, time_of_day)
|
||||||
11
game/weather/fog.py
Normal file
11
game/weather/fog.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from game.utils import Distance
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Fog:
|
||||||
|
visibility: Distance
|
||||||
|
thickness: int
|
||||||
@ -4,17 +4,14 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from dcs.cloud_presets import Clouds as PydcsClouds
|
from dcs.weather import Weather as PydcsWeather, Wind
|
||||||
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
|
|
||||||
|
|
||||||
from game.theater.seasonalconditions import determine_season
|
|
||||||
from game.timeofday import TimeOfDay
|
from game.timeofday import TimeOfDay
|
||||||
from game.utils import (
|
from game.utils import (
|
||||||
Distance,
|
|
||||||
Heading,
|
Heading,
|
||||||
Pressure,
|
Pressure,
|
||||||
inches_hg,
|
inches_hg,
|
||||||
@ -23,10 +20,12 @@ from game.utils import (
|
|||||||
meters,
|
meters,
|
||||||
Speed,
|
Speed,
|
||||||
)
|
)
|
||||||
|
from game.weather.atmosphericconditions import AtmosphericConditions
|
||||||
|
from game.weather.clouds import Clouds
|
||||||
|
from game.weather.fog import Fog
|
||||||
|
from game.weather.wind import WindConditions
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game.settings import Settings
|
|
||||||
from game.theater import ConflictTheater
|
|
||||||
from game.theater.seasonalconditions import SeasonalConditions
|
from game.theater.seasonalconditions import SeasonalConditions
|
||||||
|
|
||||||
|
|
||||||
@ -36,62 +35,12 @@ class NightMissions(Enum):
|
|||||||
OnlyNight = "nightmissions_onlynight"
|
OnlyNight = "nightmissions_onlynight"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class AtmosphericConditions:
|
|
||||||
#: Pressure at sea level.
|
|
||||||
qnh: Pressure
|
|
||||||
|
|
||||||
#: Temperature at sea level in Celcius.
|
|
||||||
temperature_celsius: float
|
|
||||||
|
|
||||||
#: Turbulence per 10 cm.
|
|
||||||
turbulence_per_10cm: float
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class WindConditions:
|
|
||||||
at_0m: Wind
|
|
||||||
at_2000m: Wind
|
|
||||||
at_8000m: Wind
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class WeibullWindSpeedParameters:
|
class WeibullWindSpeedParameters:
|
||||||
shape: float
|
shape: float
|
||||||
scale: Speed
|
scale: Speed
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Clouds:
|
|
||||||
base: int
|
|
||||||
density: int
|
|
||||||
thickness: int
|
|
||||||
precipitation: PydcsWeather.Preceptions
|
|
||||||
preset: Optional[CloudPreset] = field(default=None)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def random_preset(cls, rain: bool) -> Clouds:
|
|
||||||
clouds = (p.value for p in PydcsClouds)
|
|
||||||
if rain:
|
|
||||||
presets = [p for p in clouds if "Rain" in p.name]
|
|
||||||
else:
|
|
||||||
presets = [p for p in clouds if "Rain" not in p.name]
|
|
||||||
preset = random.choice(presets)
|
|
||||||
return Clouds(
|
|
||||||
base=random.randint(preset.min_base, preset.max_base),
|
|
||||||
density=0,
|
|
||||||
thickness=0,
|
|
||||||
precipitation=PydcsWeather.Preceptions.None_,
|
|
||||||
preset=preset,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Fog:
|
|
||||||
visibility: Distance
|
|
||||||
thickness: int
|
|
||||||
|
|
||||||
|
|
||||||
class Weather:
|
class Weather:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -417,94 +366,3 @@ class Thunderstorm(Weather):
|
|||||||
WeibullWindSpeedParameters(6.2, knots(20)),
|
WeibullWindSpeedParameters(6.2, knots(20)),
|
||||||
WeibullWindSpeedParameters(6.4, knots(20)),
|
WeibullWindSpeedParameters(6.4, knots(20)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Conditions:
|
|
||||||
time_of_day: TimeOfDay
|
|
||||||
start_time: datetime.datetime
|
|
||||||
weather: Weather
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def generate(
|
|
||||||
cls,
|
|
||||||
theater: ConflictTheater,
|
|
||||||
day: datetime.date,
|
|
||||||
time_of_day: TimeOfDay,
|
|
||||||
settings: Settings,
|
|
||||||
forced_time: datetime.time | None = None,
|
|
||||||
) -> Conditions:
|
|
||||||
# The time might be forced by the campaign for the first turn.
|
|
||||||
if forced_time is not None:
|
|
||||||
_start_time = datetime.datetime.combine(day, forced_time)
|
|
||||||
else:
|
|
||||||
_start_time = cls.generate_start_time(
|
|
||||||
theater, day, time_of_day, settings.night_day_missions
|
|
||||||
)
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
time_of_day=time_of_day,
|
|
||||||
start_time=_start_time,
|
|
||||||
weather=cls.generate_weather(theater.seasonal_conditions, day, time_of_day),
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def generate_start_time(
|
|
||||||
cls,
|
|
||||||
theater: ConflictTheater,
|
|
||||||
day: datetime.date,
|
|
||||||
time_of_day: TimeOfDay,
|
|
||||||
night_day_missions: NightMissions,
|
|
||||||
) -> datetime.datetime:
|
|
||||||
from game.theater import DaytimeMap
|
|
||||||
|
|
||||||
if night_day_missions == NightMissions.OnlyDay:
|
|
||||||
logging.info("Skip Night mission due to user settings")
|
|
||||||
time_range = DaytimeMap(
|
|
||||||
dawn=(datetime.time(hour=8), datetime.time(hour=9)),
|
|
||||||
day=(datetime.time(hour=10), datetime.time(hour=12)),
|
|
||||||
dusk=(datetime.time(hour=12), datetime.time(hour=14)),
|
|
||||||
night=(datetime.time(hour=14), datetime.time(hour=17)),
|
|
||||||
).range_of(time_of_day)
|
|
||||||
elif night_day_missions == NightMissions.OnlyNight:
|
|
||||||
logging.info("Skip Day mission due to user settings")
|
|
||||||
time_range = DaytimeMap(
|
|
||||||
dawn=(datetime.time(hour=0), datetime.time(hour=3)),
|
|
||||||
day=(datetime.time(hour=3), datetime.time(hour=6)),
|
|
||||||
dusk=(datetime.time(hour=21), datetime.time(hour=22)),
|
|
||||||
night=(datetime.time(hour=22), datetime.time(hour=23)),
|
|
||||||
).range_of(time_of_day)
|
|
||||||
else:
|
|
||||||
time_range = theater.daytime_map.range_of(time_of_day)
|
|
||||||
|
|
||||||
# Starting missions on the hour is a nice gameplay property, so keep the random
|
|
||||||
# time constrained to that. DaytimeMap enforces that we have only whole hour
|
|
||||||
# ranges for now, so we don't need to worry about accidentally changing the time
|
|
||||||
# of day by truncating sub-hours.
|
|
||||||
time = datetime.time(
|
|
||||||
hour=random.randint(time_range[0].hour, time_range[1].hour)
|
|
||||||
)
|
|
||||||
return datetime.datetime.combine(day, time)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def generate_weather(
|
|
||||||
cls,
|
|
||||||
seasonal_conditions: SeasonalConditions,
|
|
||||||
day: datetime.date,
|
|
||||||
time_of_day: TimeOfDay,
|
|
||||||
) -> Weather:
|
|
||||||
season = determine_season(day)
|
|
||||||
logging.debug("Weather: Season {}".format(season))
|
|
||||||
weather_chances = seasonal_conditions.weather_type_chances[season]
|
|
||||||
chances = {
|
|
||||||
Thunderstorm: weather_chances.thunderstorm,
|
|
||||||
Raining: weather_chances.raining,
|
|
||||||
Cloudy: weather_chances.cloudy,
|
|
||||||
ClearSkies: weather_chances.clear_skies,
|
|
||||||
}
|
|
||||||
logging.debug("Weather: Chances {}".format(weather_chances))
|
|
||||||
weather_type = random.choices(
|
|
||||||
list(chances.keys()), weights=list(chances.values())
|
|
||||||
)[0]
|
|
||||||
logging.debug("Weather: Type {}".format(weather_type))
|
|
||||||
return weather_type(seasonal_conditions, day, time_of_day)
|
|
||||||
12
game/weather/wind.py
Normal file
12
game/weather/wind.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from dcs.weather import Wind
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class WindConditions:
|
||||||
|
at_0m: Wind
|
||||||
|
at_2000m: Wind
|
||||||
|
at_8000m: Wind
|
||||||
@ -15,7 +15,7 @@ import qt_ui.uiconstants as CONST
|
|||||||
from game.sim.gameupdateevents import GameUpdateEvents
|
from game.sim.gameupdateevents import GameUpdateEvents
|
||||||
from game.timeofday import TimeOfDay
|
from game.timeofday import TimeOfDay
|
||||||
from game.utils import mps
|
from game.utils import mps
|
||||||
from game.weather import Conditions
|
from game.weather.conditions import Conditions
|
||||||
from qt_ui.simcontroller import SimController
|
from qt_ui.simcontroller import SimController
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user