mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add situational temperature and pressure variation.
Now varies by: * Season * Theater * Weather * Time of day
This commit is contained in:
parent
e5c0fc92ec
commit
04a346678c
@ -497,6 +497,17 @@ class ReferencePoint:
|
|||||||
image_coordinates: Point
|
image_coordinates: Point
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class SeasonalConditions:
|
||||||
|
# Units are inHg and degrees Celsius
|
||||||
|
# Future improvement: add clouds/precipitation
|
||||||
|
summer_avg_pressure: float
|
||||||
|
winter_avg_pressure: float
|
||||||
|
summer_avg_temperature: float
|
||||||
|
winter_avg_temperature: float
|
||||||
|
temperature_day_night_difference: float
|
||||||
|
|
||||||
|
|
||||||
class ConflictTheater:
|
class ConflictTheater:
|
||||||
terrain: Terrain
|
terrain: Terrain
|
||||||
|
|
||||||
@ -719,6 +730,10 @@ class ConflictTheater:
|
|||||||
MizCampaignLoader(directory / miz, t).populate_theater()
|
MizCampaignLoader(directory / miz, t).populate_theater()
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -748,6 +763,16 @@ class CaucasusTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=30.02, # TODO: More science
|
||||||
|
winter_avg_pressure=29.72, # TODO: More science
|
||||||
|
summer_avg_temperature=22.5,
|
||||||
|
winter_avg_temperature=3.0,
|
||||||
|
temperature_day_night_difference=6.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .caucasus import PARAMETERS
|
from .caucasus import PARAMETERS
|
||||||
@ -770,6 +795,16 @@ class PersianGulfTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=29.98, # TODO: More science
|
||||||
|
winter_avg_pressure=29.80, # TODO: More science
|
||||||
|
summer_avg_temperature=32.5,
|
||||||
|
winter_avg_temperature=15.0,
|
||||||
|
temperature_day_night_difference=2.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .persiangulf import PARAMETERS
|
from .persiangulf import PARAMETERS
|
||||||
@ -792,6 +827,16 @@ class NevadaTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=30.02, # TODO: More science
|
||||||
|
winter_avg_pressure=29.72, # TODO: More science
|
||||||
|
summer_avg_temperature=31.5,
|
||||||
|
winter_avg_temperature=5.0,
|
||||||
|
temperature_day_night_difference=6.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .nevada import PARAMETERS
|
from .nevada import PARAMETERS
|
||||||
@ -814,6 +859,16 @@ class NormandyTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=30.02, # TODO: More science
|
||||||
|
winter_avg_pressure=29.72, # TODO: More science
|
||||||
|
summer_avg_temperature=20.0,
|
||||||
|
winter_avg_temperature=0.0,
|
||||||
|
temperature_day_night_difference=5.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .normandy import PARAMETERS
|
from .normandy import PARAMETERS
|
||||||
@ -836,6 +891,16 @@ class TheChannelTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=30.02, # TODO: More science
|
||||||
|
winter_avg_pressure=29.72, # TODO: More science
|
||||||
|
summer_avg_temperature=20.0,
|
||||||
|
winter_avg_temperature=0.0,
|
||||||
|
temperature_day_night_difference=5.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .thechannel import PARAMETERS
|
from .thechannel import PARAMETERS
|
||||||
@ -858,6 +923,16 @@ class SyriaTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=29.98, # TODO: More science
|
||||||
|
winter_avg_pressure=29.86, # TODO: More science
|
||||||
|
summer_avg_temperature=28.5,
|
||||||
|
winter_avg_temperature=10.0,
|
||||||
|
temperature_day_night_difference=8.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .syria import PARAMETERS
|
from .syria import PARAMETERS
|
||||||
@ -877,6 +952,16 @@ class MarianaIslandsTheater(ConflictTheater):
|
|||||||
"night": (0, 5),
|
"night": (0, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer_avg_pressure=30.02, # TODO: More science
|
||||||
|
winter_avg_pressure=29.82, # TODO: More science
|
||||||
|
summer_avg_temperature=28.0,
|
||||||
|
winter_avg_temperature=27.0,
|
||||||
|
temperature_day_night_difference=1.0,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection_parameters(self) -> TransverseMercator:
|
def projection_parameters(self) -> TransverseMercator:
|
||||||
from .marianaislands import PARAMETERS
|
from .marianaislands import PARAMETERS
|
||||||
|
|||||||
@ -189,3 +189,15 @@ def pairwise(iterable: Iterable[Any]) -> Iterable[tuple[Any, Any]]:
|
|||||||
a, b = itertools.tee(iterable)
|
a, b = itertools.tee(iterable)
|
||||||
next(b, None)
|
next(b, None)
|
||||||
return zip(a, b)
|
return zip(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
def interpolate(value1: float, value2: float, factor: float, clamp: bool) -> float:
|
||||||
|
"""Inerpolate between two values, factor 0-1"""
|
||||||
|
interpolated = value1 + (value2 - value1) * factor
|
||||||
|
|
||||||
|
if clamp:
|
||||||
|
bigger_value = max(value1, value2)
|
||||||
|
smaller_value = min(value1, value2)
|
||||||
|
return min(bigger_value, max(smaller_value, interpolated))
|
||||||
|
else:
|
||||||
|
return interpolated
|
||||||
|
|||||||
124
game/weather.py
124
game/weather.py
@ -11,10 +11,11 @@ from dcs.cloud_presets import Clouds as PydcsClouds
|
|||||||
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
|
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, interpolate
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game.theater import ConflictTheater
|
from game.theater import ConflictTheater
|
||||||
|
from game.theater.conflicttheater import SeasonalConditions
|
||||||
|
|
||||||
|
|
||||||
class TimeOfDay(Enum):
|
class TimeOfDay(Enum):
|
||||||
@ -71,15 +72,56 @@ class Fog:
|
|||||||
|
|
||||||
|
|
||||||
class Weather:
|
class Weather:
|
||||||
def __init__(self) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
seasonal_conditions: SeasonalConditions,
|
||||||
|
day: datetime.date,
|
||||||
|
time_of_day: TimeOfDay,
|
||||||
|
) -> None:
|
||||||
# Future improvement: Use theater, day and time of day
|
# Future improvement: Use theater, day and time of day
|
||||||
# to get a more realistic conditions
|
# to get a more realistic conditions
|
||||||
self.atmospheric = self.generate_atmospheric()
|
self.atmospheric = self.generate_atmospheric(
|
||||||
|
seasonal_conditions, day, time_of_day
|
||||||
|
)
|
||||||
self.clouds = self.generate_clouds()
|
self.clouds = self.generate_clouds()
|
||||||
self.fog = self.generate_fog()
|
self.fog = self.generate_fog()
|
||||||
self.wind = self.generate_wind()
|
self.wind = self.generate_wind()
|
||||||
|
|
||||||
def generate_atmospheric(self) -> AtmosphericConditions:
|
def generate_atmospheric(
|
||||||
|
self,
|
||||||
|
seasonal_conditions: SeasonalConditions,
|
||||||
|
day: datetime.date,
|
||||||
|
time_of_day: TimeOfDay,
|
||||||
|
) -> AtmosphericConditions:
|
||||||
|
pressure = self.interpolate_summer_winter(
|
||||||
|
seasonal_conditions.summer_avg_pressure,
|
||||||
|
seasonal_conditions.winter_avg_pressure,
|
||||||
|
day,
|
||||||
|
)
|
||||||
|
temperature = self.interpolate_summer_winter(
|
||||||
|
seasonal_conditions.summer_avg_temperature,
|
||||||
|
seasonal_conditions.winter_avg_temperature,
|
||||||
|
day,
|
||||||
|
)
|
||||||
|
|
||||||
|
if time_of_day == TimeOfDay.Day:
|
||||||
|
temperature += seasonal_conditions.temperature_day_night_difference / 2
|
||||||
|
if time_of_day == TimeOfDay.Night:
|
||||||
|
temperature -= seasonal_conditions.temperature_day_night_difference / 2
|
||||||
|
pressure += self.pressure_adjustment
|
||||||
|
temperature += self.temperature_adjustment
|
||||||
|
conditions = AtmosphericConditions(
|
||||||
|
qnh_inches_mercury=self.random_pressure(pressure),
|
||||||
|
temperature_celsius=self.random_temperature(temperature),
|
||||||
|
)
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pressure_adjustment(self) -> float:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def temperature_adjustment(self) -> float:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def generate_clouds(self) -> Optional[Clouds]:
|
def generate_clouds(self) -> Optional[Clouds]:
|
||||||
@ -126,7 +168,7 @@ class Weather:
|
|||||||
SAFE_MIN = 28.4
|
SAFE_MIN = 28.4
|
||||||
SAFE_MAX = 30.9
|
SAFE_MAX = 30.9
|
||||||
# Use normalvariate to get normal distribution, more realistic than uniform
|
# Use normalvariate to get normal distribution, more realistic than uniform
|
||||||
pressure = random.normalvariate(average_pressure, 0.2)
|
pressure = random.normalvariate(average_pressure, 0.1)
|
||||||
return max(SAFE_MIN, min(SAFE_MAX, pressure))
|
return max(SAFE_MIN, min(SAFE_MAX, pressure))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -136,17 +178,29 @@ class Weather:
|
|||||||
SAFE_MIN = -12
|
SAFE_MIN = -12
|
||||||
SAFE_MAX = 49
|
SAFE_MAX = 49
|
||||||
# Use normalvariate to get normal distribution, more realistic than uniform
|
# Use normalvariate to get normal distribution, more realistic than uniform
|
||||||
temperature = random.normalvariate(average_temperature, 4)
|
temperature = random.normalvariate(average_temperature, 2)
|
||||||
temperature = round(temperature)
|
temperature = round(temperature)
|
||||||
return max(SAFE_MIN, min(SAFE_MAX, temperature))
|
return max(SAFE_MIN, min(SAFE_MAX, temperature))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def interpolate_summer_winter(
|
||||||
|
summer_value: float, winter_value: float, day: datetime.date
|
||||||
|
) -> float:
|
||||||
|
day_of_year = day.timetuple().tm_yday
|
||||||
|
day_of_year_peak_summer = 183
|
||||||
|
distance_from_peak_summer = abs(-day_of_year_peak_summer + day_of_year)
|
||||||
|
winter_factor = distance_from_peak_summer / day_of_year_peak_summer
|
||||||
|
return interpolate(summer_value, winter_value, winter_factor, clamp=True)
|
||||||
|
|
||||||
|
|
||||||
class ClearSkies(Weather):
|
class ClearSkies(Weather):
|
||||||
def generate_atmospheric(self) -> AtmosphericConditions:
|
@property
|
||||||
return AtmosphericConditions(
|
def pressure_adjustment(self) -> float:
|
||||||
qnh_inches_mercury=self.random_pressure(29.96),
|
return 0.22
|
||||||
temperature_celsius=self.random_temperature(22),
|
|
||||||
)
|
@property
|
||||||
|
def temperature_adjustment(self) -> float:
|
||||||
|
return 3.0
|
||||||
|
|
||||||
def generate_clouds(self) -> Optional[Clouds]:
|
def generate_clouds(self) -> Optional[Clouds]:
|
||||||
return None
|
return None
|
||||||
@ -159,11 +213,13 @@ class ClearSkies(Weather):
|
|||||||
|
|
||||||
|
|
||||||
class Cloudy(Weather):
|
class Cloudy(Weather):
|
||||||
def generate_atmospheric(self) -> AtmosphericConditions:
|
@property
|
||||||
return AtmosphericConditions(
|
def pressure_adjustment(self) -> float:
|
||||||
qnh_inches_mercury=self.random_pressure(29.90),
|
return 0.0
|
||||||
temperature_celsius=self.random_temperature(20),
|
|
||||||
)
|
@property
|
||||||
|
def temperature_adjustment(self) -> float:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
def generate_clouds(self) -> Optional[Clouds]:
|
def generate_clouds(self) -> Optional[Clouds]:
|
||||||
return Clouds.random_preset(rain=False)
|
return Clouds.random_preset(rain=False)
|
||||||
@ -177,11 +233,13 @@ class Cloudy(Weather):
|
|||||||
|
|
||||||
|
|
||||||
class Raining(Weather):
|
class Raining(Weather):
|
||||||
def generate_atmospheric(self) -> AtmosphericConditions:
|
@property
|
||||||
return AtmosphericConditions(
|
def pressure_adjustment(self) -> float:
|
||||||
qnh_inches_mercury=self.random_pressure(29.70),
|
return -0.22
|
||||||
temperature_celsius=self.random_temperature(16),
|
|
||||||
)
|
@property
|
||||||
|
def temperature_adjustment(self) -> float:
|
||||||
|
return -3.0
|
||||||
|
|
||||||
def generate_clouds(self) -> Optional[Clouds]:
|
def generate_clouds(self) -> Optional[Clouds]:
|
||||||
return Clouds.random_preset(rain=True)
|
return Clouds.random_preset(rain=True)
|
||||||
@ -195,11 +253,13 @@ class Raining(Weather):
|
|||||||
|
|
||||||
|
|
||||||
class Thunderstorm(Weather):
|
class Thunderstorm(Weather):
|
||||||
def generate_atmospheric(self) -> AtmosphericConditions:
|
@property
|
||||||
return AtmosphericConditions(
|
def pressure_adjustment(self) -> float:
|
||||||
qnh_inches_mercury=self.random_pressure(29.60),
|
return 0.1
|
||||||
temperature_celsius=self.random_temperature(15),
|
|
||||||
)
|
@property
|
||||||
|
def temperature_adjustment(self) -> float:
|
||||||
|
return -3.0
|
||||||
|
|
||||||
def generate_clouds(self) -> Optional[Clouds]:
|
def generate_clouds(self) -> Optional[Clouds]:
|
||||||
return Clouds(
|
return Clouds(
|
||||||
@ -233,7 +293,7 @@ class Conditions:
|
|||||||
return cls(
|
return cls(
|
||||||
time_of_day=time_of_day,
|
time_of_day=time_of_day,
|
||||||
start_time=_start_time,
|
start_time=_start_time,
|
||||||
weather=cls.generate_weather(),
|
weather=cls.generate_weather(theater.seasonal_conditions, day, time_of_day),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -259,7 +319,13 @@ class Conditions:
|
|||||||
return datetime.datetime.combine(day, time)
|
return datetime.datetime.combine(day, time)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_weather(cls) -> Weather:
|
def generate_weather(
|
||||||
|
cls,
|
||||||
|
seasonal_conditions: SeasonalConditions,
|
||||||
|
day: datetime.date,
|
||||||
|
time_of_day: TimeOfDay,
|
||||||
|
) -> Weather:
|
||||||
|
# Future improvement: use seasonal weights for theaters
|
||||||
chances = {
|
chances = {
|
||||||
Thunderstorm: 1,
|
Thunderstorm: 1,
|
||||||
Raining: 20,
|
Raining: 20,
|
||||||
@ -269,4 +335,4 @@ class Conditions:
|
|||||||
weather_type = random.choices(
|
weather_type = random.choices(
|
||||||
list(chances.keys()), weights=list(chances.values())
|
list(chances.keys()), weights=list(chances.values())
|
||||||
)[0]
|
)[0]
|
||||||
return weather_type()
|
return weather_type(seasonal_conditions, day, time_of_day)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user