mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
184 lines
5.0 KiB
Python
184 lines
5.0 KiB
Python
from __future__ import annotations
|
|
|
|
import datetime
|
|
import logging
|
|
import random
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
from typing import Optional
|
|
|
|
from dcs.weather import Weather as PydcsWeather, Wind
|
|
|
|
from game.settings import Settings
|
|
from theater import ConflictTheater
|
|
|
|
|
|
class TimeOfDay(Enum):
|
|
Dawn = "dawn"
|
|
Day = "day"
|
|
Dusk = "dusk"
|
|
Night = "night"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class WindConditions:
|
|
at_0m: Wind
|
|
at_2000m: Wind
|
|
at_8000m: Wind
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Clouds:
|
|
base: int
|
|
density: int
|
|
thickness: int
|
|
precipitation: PydcsWeather.Preceptions
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Fog:
|
|
visibility: int
|
|
thickness: int
|
|
|
|
|
|
class Weather:
|
|
def __init__(self) -> None:
|
|
self.clouds = self.generate_clouds()
|
|
self.fog = self.generate_fog()
|
|
self.wind = self.generate_wind()
|
|
|
|
def generate_clouds(self) -> Optional[Clouds]:
|
|
raise NotImplementedError
|
|
|
|
def generate_fog(self) -> Optional[Fog]:
|
|
if random.randrange(5) != 0:
|
|
return None
|
|
return Fog(
|
|
visibility=random.randint(2500, 5000),
|
|
thickness=random.randint(100, 500)
|
|
)
|
|
|
|
def generate_wind(self) -> WindConditions:
|
|
raise NotImplementedError
|
|
|
|
@staticmethod
|
|
def random_wind(minimum: int, maximum) -> WindConditions:
|
|
wind_direction = random.randint(0, 360)
|
|
at_0m_factor = 1
|
|
at_2000m_factor = 2
|
|
at_8000m_factor = 3
|
|
base_wind = random.randint(minimum, maximum)
|
|
|
|
return WindConditions(
|
|
# Always some wind to make the smoke move a bit.
|
|
at_0m=Wind(wind_direction, max(1, base_wind * at_0m_factor)),
|
|
at_2000m=Wind(wind_direction, base_wind * at_2000m_factor),
|
|
at_8000m=Wind(wind_direction, base_wind * at_8000m_factor)
|
|
)
|
|
|
|
@staticmethod
|
|
def random_cloud_base() -> int:
|
|
return random.randint(2000, 3000)
|
|
|
|
@staticmethod
|
|
def random_cloud_thickness() -> int:
|
|
return random.randint(100, 400)
|
|
|
|
|
|
class ClearSkies(Weather):
|
|
def generate_clouds(self) -> Optional[Clouds]:
|
|
return None
|
|
|
|
def generate_fog(self) -> Optional[Fog]:
|
|
return None
|
|
|
|
def generate_wind(self) -> WindConditions:
|
|
return self.random_wind(0, 0)
|
|
|
|
|
|
class Cloudy(Weather):
|
|
def generate_clouds(self) -> Optional[Clouds]:
|
|
return Clouds(
|
|
base=self.random_cloud_base(),
|
|
density=random.randint(1, 8),
|
|
thickness=self.random_cloud_thickness(),
|
|
precipitation=PydcsWeather.Preceptions.None_
|
|
)
|
|
|
|
def generate_wind(self) -> WindConditions:
|
|
return self.random_wind(0, 4)
|
|
|
|
|
|
class Raining(Weather):
|
|
def generate_clouds(self) -> Optional[Clouds]:
|
|
return Clouds(
|
|
base=self.random_cloud_base(),
|
|
density=random.randint(5, 8),
|
|
thickness=self.random_cloud_thickness(),
|
|
precipitation=PydcsWeather.Preceptions.Rain
|
|
)
|
|
|
|
def generate_wind(self) -> WindConditions:
|
|
return self.random_wind(0, 6)
|
|
|
|
|
|
class Thunderstorm(Weather):
|
|
def generate_clouds(self) -> Optional[Clouds]:
|
|
return Clouds(
|
|
base=self.random_cloud_base(),
|
|
density=random.randint(9, 10),
|
|
thickness=self.random_cloud_thickness(),
|
|
precipitation=PydcsWeather.Preceptions.Thunderstorm
|
|
)
|
|
|
|
def generate_wind(self) -> WindConditions:
|
|
return self.random_wind(0, 8)
|
|
|
|
|
|
@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) -> Conditions:
|
|
return cls(
|
|
time_of_day=time_of_day,
|
|
start_time=cls.generate_start_time(
|
|
theater, day, time_of_day, settings.night_disabled
|
|
),
|
|
weather=cls.generate_weather()
|
|
)
|
|
|
|
@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 = {
|
|
TimeOfDay.Dawn: (8, 9),
|
|
TimeOfDay.Day: (10, 12),
|
|
TimeOfDay.Dusk: (12, 14),
|
|
TimeOfDay.Night: (14, 17),
|
|
}[time_of_day]
|
|
else:
|
|
time_range = theater.daytime_map[time_of_day.value]
|
|
|
|
time = datetime.time(hour=random.randint(*time_range))
|
|
return datetime.datetime.combine(day, time)
|
|
|
|
@classmethod
|
|
def generate_weather(cls) -> Weather:
|
|
chances = {
|
|
Thunderstorm: 1,
|
|
Raining: 20,
|
|
Cloudy: 60,
|
|
ClearSkies: 20,
|
|
}
|
|
weather_type = random.choices(list(chances.keys()),
|
|
weights=list(chances.values()))[0]
|
|
return weather_type()
|