Add support for DCS 2.7 weather generation.

https://github.com/Khopa/dcs_liberation/issues/981
This commit is contained in:
Dan Albert 2021-04-15 19:42:33 -07:00
parent e63743f537
commit 38f632097e
4 changed files with 83 additions and 44 deletions

View File

@ -7,6 +7,7 @@ Saves from 2.4 are not compatible with 2.5.
* **[Flight Planner]** Added AEW&C missions. (by siKruger) * **[Flight Planner]** Added AEW&C missions. (by siKruger)
* **[Kneeboard]** Added dark kneeboard option (by GvonH) * **[Kneeboard]** Added dark kneeboard option (by GvonH)
* **[Campaigns]** Multiple EWR sites may now be generated, and EWR sites may be generated outside bases (by SnappyComebacks) * **[Campaigns]** Multiple EWR sites may now be generated, and EWR sites may be generated outside bases (by SnappyComebacks)
* **[Mission Generation]** Cloudy and rainy (but not thunderstorm) weather will use the cloud presets from DCS 2.7.
## Fixes ## Fixes

View File

@ -3,11 +3,12 @@ from __future__ import annotations
import datetime import datetime
import logging import logging
import random import random
from dataclasses import dataclass from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from dcs.weather import Weather as PydcsWeather, Wind from dcs.cloud_presets import Clouds as PydcsClouds
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
from game.settings import Settings from game.settings import Settings
from game.utils import Distance, meters from game.utils import Distance, meters
@ -36,6 +37,23 @@ class Clouds:
density: int density: int
thickness: int thickness: int
precipitation: PydcsWeather.Preceptions 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) @dataclass(frozen=True)
@ -101,12 +119,11 @@ class ClearSkies(Weather):
class Cloudy(Weather): class Cloudy(Weather):
def generate_clouds(self) -> Optional[Clouds]: def generate_clouds(self) -> Optional[Clouds]:
return Clouds( return Clouds.random_preset(rain=False)
base=self.random_cloud_base(),
density=random.randint(1, 8), def generate_fog(self) -> Optional[Fog]:
thickness=self.random_cloud_thickness(), # DCS 2.7 says to not use fog with the cloud presets.
precipitation=PydcsWeather.Preceptions.None_, return None
)
def generate_wind(self) -> WindConditions: def generate_wind(self) -> WindConditions:
return self.random_wind(0, 4) return self.random_wind(0, 4)
@ -114,12 +131,11 @@ class Cloudy(Weather):
class Raining(Weather): class Raining(Weather):
def generate_clouds(self) -> Optional[Clouds]: def generate_clouds(self) -> Optional[Clouds]:
return Clouds( return Clouds.random_preset(rain=True)
base=self.random_cloud_base(),
density=random.randint(5, 8), def generate_fog(self) -> Optional[Fog]:
thickness=self.random_cloud_thickness(), # DCS 2.7 says to not use fog with the cloud presets.
precipitation=PydcsWeather.Preceptions.Rain, return None
)
def generate_wind(self) -> WindConditions: def generate_wind(self) -> WindConditions:
return self.random_wind(0, 6) return self.random_wind(0, 6)

View File

@ -17,6 +17,7 @@ class EnvironmentGenerator:
self.mission.weather.clouds_thickness = clouds.thickness self.mission.weather.clouds_thickness = clouds.thickness
self.mission.weather.clouds_density = clouds.density self.mission.weather.clouds_density = clouds.density
self.mission.weather.clouds_iprecptns = clouds.precipitation self.mission.weather.clouds_iprecptns = clouds.precipitation
self.mission.weather.clouds_preset = clouds.preset
def set_fog(self, fog: Optional[Fog]) -> None: def set_fog(self, fog: Optional[Fog]) -> None:
if fog is None: if fog is None:

View File

@ -7,7 +7,7 @@ from PySide2.QtWidgets import (
QLabel, QLabel,
QVBoxLayout, QVBoxLayout,
) )
from dcs.weather import Weather as PydcsWeather from dcs.weather import CloudPreset, Weather as PydcsWeather
import qt_ui.uiconstants as CONST import qt_ui.uiconstants as CONST
from game.utils import mps from game.utils import mps
@ -162,7 +162,7 @@ class QWeatherWidget(QGroupBox):
self.turn = turn self.turn = turn
self.conditions = conditions self.conditions = conditions
self.updateForecast() self.update_forecast()
self.updateWinds() self.updateWinds()
def updateWinds(self): def updateWinds(self):
@ -186,55 +186,76 @@ class QWeatherWidget(QGroupBox):
self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts") self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts")
self.windFL26DirLabel.setText(f"{windFL26Dir}º") self.windFL26DirLabel.setText(f"{windFL26Dir}º")
def updateForecast(self): def update_forecast_from_preset(self, preset: CloudPreset) -> None:
self.forecastFog.setText("No fog")
if "Rain" in preset.name:
self.forecastRain.setText("Rain")
self.update_forecast_icons("rain")
else:
self.forecastRain.setText("No rain")
self.update_forecast_icons("partly-cloudy")
# We get a description like the following for the cloud preset.
#
# 09 ##Two Layer Broken/Scattered \nMETAR:BKN 7.5/10 SCT 20/22 FEW41
#
# The second line is probably interesting but doesn't fit into the widget
# currently, so for now just extract the first line.
self.forecastClouds.setText(preset.description.splitlines()[0].split("##")[1])
def update_forecast(self):
"""Updates the Forecast Text and icon with the current conditions wind info.""" """Updates the Forecast Text and icon with the current conditions wind info."""
icon = [] if (
self.conditions.weather.clouds
and self.conditions.weather.clouds.preset is not None
):
self.update_forecast_from_preset(self.conditions.weather.clouds.preset)
return
if self.conditions.weather.clouds is None: if self.conditions.weather.clouds is None:
cloudDensity = 0 cloud_density = 0
precipitation = None precipitation = None
else: else:
cloudDensity = self.conditions.weather.clouds.density cloud_density = self.conditions.weather.clouds.density
precipitation = self.conditions.weather.clouds.precipitation precipitation = self.conditions.weather.clouds.precipitation
fog = self.conditions.weather.fog or None if not cloud_density:
is_night = self.conditions.time_of_day == TimeOfDay.Night
time = "night" if is_night else "day"
if cloudDensity <= 0:
self.forecastClouds.setText("Sunny") self.forecastClouds.setText("Sunny")
icon = [time, "clear"] weather_type = "clear"
elif cloud_density < 3:
if cloudDensity > 0 and cloudDensity < 3:
self.forecastClouds.setText("Partly Cloudy") self.forecastClouds.setText("Partly Cloudy")
icon = [time, "partly-cloudy"] weather_type = "partly-cloudy"
elif cloud_density < 5:
if cloudDensity >= 3 and cloudDensity < 5:
self.forecastClouds.setText("Mostly Cloudy") self.forecastClouds.setText("Mostly Cloudy")
icon = [time, "partly-cloudy"] weather_type = "partly-cloudy"
else:
if cloudDensity >= 5:
self.forecastClouds.setText("Totally Cloudy") self.forecastClouds.setText("Totally Cloudy")
icon = [time, "partly-cloudy"] weather_type = "partly-cloudy"
if precipitation == PydcsWeather.Preceptions.Rain: if precipitation == PydcsWeather.Preceptions.Rain:
self.forecastRain.setText("Rain") self.forecastRain.setText("Rain")
icon = [time, "rain"] weather_type = "rain"
elif precipitation == PydcsWeather.Preceptions.Thunderstorm: elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
self.forecastRain.setText("Thunderstorm") self.forecastRain.setText("Thunderstorm")
icon = [time, "thunderstorm"] weather_type = "thunderstorm"
else: else:
self.forecastRain.setText("No Rain") self.forecastRain.setText("No rain")
if not fog: if not self.conditions.weather.fog is not None:
self.forecastFog.setText("No fog") self.forecastFog.setText("No fog")
else: else:
visibility = round(fog.visibility.nautical_miles, 1) visibility = round(self.conditions.weather.fog.visibility.nautical_miles, 1)
self.forecastFog.setText(f"Fog vis: {visibility}nm") self.forecastFog.setText(f"Fog vis: {visibility}nm")
icon = [time, ("cloudy" if cloudDensity > 1 else None), "fog"] if cloud_density > 1:
weather_type = "cloudy-fog"
else:
weather_type = "fog"
icon_key = "Weather_{}".format("-".join(filter(None.__ne__, icon))) self.update_forecast_icons(weather_type)
def update_forecast_icons(self, weather_type: str) -> None:
time = "night" if self.conditions.time_of_day == TimeOfDay.Night else "day"
icon_key = f"Weather_{time}-{weather_type}"
icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"] icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"]
self.weather_icon.setPixmap(icon) self.weather_icon.setPixmap(icon)