mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
persistent time and weather between regular and quick missions; defense AA for frontline CAS
This commit is contained in:
parent
2323f481c5
commit
f8c1956614
@ -2,6 +2,7 @@ from dcs.unittype import UnitType
|
|||||||
|
|
||||||
from game import *
|
from game import *
|
||||||
from theater import *
|
from theater import *
|
||||||
|
from gen.environmentgen import EnvironmentSettings
|
||||||
|
|
||||||
from userdata.debriefing import Debriefing
|
from userdata.debriefing import Debriefing
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ class Event:
|
|||||||
operation = None # type: Operation
|
operation = None # type: Operation
|
||||||
difficulty = 1 # type: int
|
difficulty = 1 # type: int
|
||||||
game = None # type: Game
|
game = None # type: Game
|
||||||
|
environment_settings = None # type: EnvironmentSettings
|
||||||
BONUS_BASE = 3
|
BONUS_BASE = 3
|
||||||
|
|
||||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
||||||
@ -47,12 +49,16 @@ class Event:
|
|||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||||
|
|
||||||
self.operation.prepare(self.game.theater.terrain, is_quick=False)
|
self.operation.prepare(self.game.theater.terrain, is_quick=False)
|
||||||
self.operation.generate()
|
self.operation.generate()
|
||||||
self.operation.mission.save("build/nextturn.miz")
|
self.operation.mission.save("build/nextturn.miz")
|
||||||
|
self.environment_settings = self.operation.environment_settings
|
||||||
|
|
||||||
def generate_quick(self):
|
def generate_quick(self):
|
||||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||||
|
self.operation.environment_settings = self.environment_settings
|
||||||
|
|
||||||
self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
||||||
self.operation.generate()
|
self.operation.generate()
|
||||||
self.operation.mission.save('build/nextturn_quick.miz')
|
self.operation.mission.save('build/nextturn_quick.miz')
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import math
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
|
from dcs.vehicles import AirDefence
|
||||||
|
|
||||||
from game import *
|
from game import *
|
||||||
from game.event import *
|
from game.event import *
|
||||||
@ -57,6 +58,9 @@ class GroundInterceptEvent(Event):
|
|||||||
typecount = max(math.floor(self.difficulty * self.TARGET_AMOUNT_FACTOR), 1)
|
typecount = max(math.floor(self.difficulty * self.TARGET_AMOUNT_FACTOR), 1)
|
||||||
self.targets = {unittype: typecount for unittype in unittypes}
|
self.targets = {unittype: typecount for unittype in unittypes}
|
||||||
|
|
||||||
|
defense_aa_unit = random.choice(self.game.commision_unit_types(self.to_cp, AirDefence))
|
||||||
|
self.targets[defense_aa_unit] = 1
|
||||||
|
|
||||||
op = GroundInterceptOperation(game=self.game,
|
op = GroundInterceptOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
|
|||||||
19
game/game.py
19
game/game.py
@ -141,6 +141,14 @@ class Game:
|
|||||||
enemy_generated_types.append(event_class)
|
enemy_generated_types.append(event_class)
|
||||||
self.events.append(event_class(self.enemy, self.player, enemy_cp, player_cp, self))
|
self.events.append(event_class(self.enemy, self.player, enemy_cp, player_cp, self))
|
||||||
|
|
||||||
|
def commision_unit_types(self, cp: ControlPoint, for_task: Task) -> typing.Collection[UnitType]:
|
||||||
|
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
|
||||||
|
|
||||||
|
if for_task == AirDefence and not self.settings.sams:
|
||||||
|
return [x for x in db.find_unittype(AirDefence, self.enemy) if x not in db.SAM_BAN]
|
||||||
|
else:
|
||||||
|
return db.choose_units(for_task, importance_factor, COMMISION_UNIT_VARIETY, self.enemy)
|
||||||
|
|
||||||
def _commision_units(self, cp: ControlPoint):
|
def _commision_units(self, cp: ControlPoint):
|
||||||
for for_task in [PinpointStrike, CAS, CAP, AirDefence]:
|
for for_task in [PinpointStrike, CAS, CAP, AirDefence]:
|
||||||
limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_LIMITS_SCALE) * self.settings.multiplier
|
limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_LIMITS_SCALE) * self.settings.multiplier
|
||||||
@ -149,13 +157,7 @@ class Game:
|
|||||||
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE) * self.settings.multiplier
|
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE) * self.settings.multiplier
|
||||||
points_to_spend = cp.base.append_commision_points(for_task, awarded_points)
|
points_to_spend = cp.base.append_commision_points(for_task, awarded_points)
|
||||||
if points_to_spend > 0:
|
if points_to_spend > 0:
|
||||||
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
|
unittypes = self._commision_unit_types(cp, for_task)
|
||||||
|
|
||||||
if for_task == AirDefence and not self.settings.sams:
|
|
||||||
unittypes = [x for x in db.find_unittype(AirDefence, self.enemy) if x not in db.SAM_BAN]
|
|
||||||
else:
|
|
||||||
unittypes = db.choose_units(for_task, importance_factor, COMMISION_UNIT_VARIETY, self.enemy)
|
|
||||||
|
|
||||||
d = {random.choice(unittypes): points_to_spend}
|
d = {random.choice(unittypes): points_to_spend}
|
||||||
print("Commision {}: {}".format(cp, d))
|
print("Commision {}: {}".format(cp, d))
|
||||||
cp.base.commision_units(d)
|
cp.base.commision_units(d)
|
||||||
@ -208,7 +210,8 @@ class Game:
|
|||||||
|
|
||||||
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
event.skip()
|
if isinstance(event, UnitsDeliveryEvent):
|
||||||
|
event.skip()
|
||||||
|
|
||||||
if not no_action:
|
if not no_action:
|
||||||
self._budget_player()
|
self._budget_player()
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from gen.armor import *
|
|||||||
from gen.aircraft import *
|
from gen.aircraft import *
|
||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.settingsgen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.awacsgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from gen.armor import *
|
|||||||
from gen.aircraft import *
|
from gen.aircraft import *
|
||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.settingsgen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.awacsgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from gen.armor import *
|
|||||||
from gen.aircraft import *
|
from gen.aircraft import *
|
||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.settingsgen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.awacsgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from gen.armor import *
|
|||||||
from gen.aircraft import *
|
from gen.aircraft import *
|
||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.settingsgen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.awacsgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from gen.armor import *
|
|||||||
from gen.aircraft import *
|
from gen.aircraft import *
|
||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.settingsgen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.awacsgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|||||||
@ -16,10 +16,13 @@ class Operation:
|
|||||||
aagen = None # type: AAConflictGenerator
|
aagen = None # type: AAConflictGenerator
|
||||||
extra_aagen = None # type: ExtraAAConflictGenerator
|
extra_aagen = None # type: ExtraAAConflictGenerator
|
||||||
shipgen = None # type: ShipGenerator
|
shipgen = None # type: ShipGenerator
|
||||||
envgen = None # type: SettingsGenerator
|
triggersgen = None # type: TriggersGenerator
|
||||||
awacsgen = None # type: AWACSConflictGenerator
|
awacsgen = None # type: AWACSConflictGenerator
|
||||||
visualgen = None # type: VisualGenerator
|
visualgen = None # type: VisualGenerator
|
||||||
|
envgen = None # type: EnvironmentGenerator
|
||||||
|
|
||||||
|
environment_settings = None
|
||||||
|
is_quick = None
|
||||||
is_awacs_enabled = False
|
is_awacs_enabled = False
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
@ -48,8 +51,9 @@ class Operation:
|
|||||||
self.aagen = AAConflictGenerator(mission, conflict)
|
self.aagen = AAConflictGenerator(mission, conflict)
|
||||||
self.shipgen = ShipGenerator(mission, conflict)
|
self.shipgen = ShipGenerator(mission, conflict)
|
||||||
self.awacsgen = AWACSConflictGenerator(mission, conflict, self.game)
|
self.awacsgen = AWACSConflictGenerator(mission, conflict, self.game)
|
||||||
self.envgen = SettingsGenerator(mission, conflict, self.game)
|
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
|
||||||
self.visualgen = VisualGenerator(mission, conflict, self.game)
|
self.visualgen = VisualGenerator(mission, conflict, self.game)
|
||||||
|
self.envgen = EnviromentGenerator(mission, conflict, self.game)
|
||||||
|
|
||||||
player_name = self.from_cp.captured and self.attacker_name or self.defender_name
|
player_name = self.from_cp.captured and self.attacker_name or self.defender_name
|
||||||
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
|
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
|
||||||
@ -73,7 +77,12 @@ class Operation:
|
|||||||
self.awacsgen.generate()
|
self.awacsgen.generate()
|
||||||
|
|
||||||
self.extra_aagen.generate()
|
self.extra_aagen.generate()
|
||||||
self.envgen.generate(self.is_quick)
|
self.triggersgen.generate(self.is_quick)
|
||||||
|
|
||||||
|
if self.environment_settings is None:
|
||||||
|
self.environment_settings = self.envgen.generate()
|
||||||
|
else:
|
||||||
|
self.envgen.load(self.environment_settings)
|
||||||
|
|
||||||
for global_cp in self.game.theater.controlpoints:
|
for global_cp in self.game.theater.controlpoints:
|
||||||
if not global_cp.is_global:
|
if not global_cp.is_global:
|
||||||
|
|||||||
@ -5,7 +5,8 @@ from .awacsgen import *
|
|||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .shipgen import *
|
from .shipgen import *
|
||||||
from .visualgen import *
|
from .visualgen import *
|
||||||
from .settingsgen import *
|
from .triggergen import *
|
||||||
|
from .environmentgen import *
|
||||||
|
|
||||||
from . import naming
|
from . import naming
|
||||||
|
|
||||||
|
|||||||
106
gen/environmentgen.py
Normal file
106
gen/environmentgen.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import typing
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta, time
|
||||||
|
|
||||||
|
from dcs.mission import Mission
|
||||||
|
from dcs.triggers import *
|
||||||
|
from dcs.condition import *
|
||||||
|
from dcs.action import *
|
||||||
|
from dcs.unit import Skill
|
||||||
|
from dcs.point import MovingPoint, PointProperties
|
||||||
|
from dcs.action import *
|
||||||
|
|
||||||
|
from game import db
|
||||||
|
from theater import *
|
||||||
|
from gen import *
|
||||||
|
|
||||||
|
WEATHER_CLOUD_BASE = 2000, 3000
|
||||||
|
WEATHER_CLOUD_DENSITY = 1, 8
|
||||||
|
WEATHER_CLOUD_THICKNESS = 100, 400
|
||||||
|
WEATHER_CLOUD_BASE_MIN = 1200
|
||||||
|
|
||||||
|
RANDOM_TIME = {
|
||||||
|
"night": 5,
|
||||||
|
"dusk": 30,
|
||||||
|
"dawn": 30,
|
||||||
|
"day": 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
RANDOM_WEATHER = {
|
||||||
|
1: 5, # heavy rain
|
||||||
|
2: 20, # rain
|
||||||
|
3: 30, # dynamic
|
||||||
|
4: 50, # clear
|
||||||
|
5: 100, # random
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class EnvironmentSettings:
|
||||||
|
weather_dict = None
|
||||||
|
start_time = None
|
||||||
|
|
||||||
|
|
||||||
|
class EnviromentGenerator:
|
||||||
|
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||||
|
self.mission = mission
|
||||||
|
self.conflict = conflict
|
||||||
|
self.game = game
|
||||||
|
|
||||||
|
def _gen_random_time(self):
|
||||||
|
start_time = datetime.combine(datetime.today(), time())
|
||||||
|
time_range = None
|
||||||
|
for k, v in RANDOM_TIME.items():
|
||||||
|
if self.game.settings.night_disabled and k == "night":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if random.randint(0, 100) <= v:
|
||||||
|
time_range = self.game.theater.daytime_map[k]
|
||||||
|
break
|
||||||
|
|
||||||
|
start_time += timedelta(hours=random.randint(*time_range))
|
||||||
|
self.mission.start_time = start_time
|
||||||
|
|
||||||
|
def _gen_random_weather(self):
|
||||||
|
weather_type = None
|
||||||
|
for k, v in RANDOM_WEATHER.items():
|
||||||
|
if random.randint(0, 100) <= v:
|
||||||
|
weather_type = k
|
||||||
|
break
|
||||||
|
|
||||||
|
print("generated weather {}".format(weather_type))
|
||||||
|
if weather_type == 0:
|
||||||
|
self.mission.weather.random_thunderstorm()
|
||||||
|
elif weather_type == 1:
|
||||||
|
self.mission.weather.heavy_rain()
|
||||||
|
elif weather_type == 2:
|
||||||
|
self.mission.weather.heavy_rain()
|
||||||
|
self.mission.weather.enable_fog = False
|
||||||
|
elif weather_type == 3:
|
||||||
|
self.mission.weather.random(self.mission.start_time, self.conflict.theater.terrain)
|
||||||
|
elif weather_type == 4:
|
||||||
|
pass
|
||||||
|
elif weather_type == 5:
|
||||||
|
self.mission.weather.clouds_base = random.randint(*WEATHER_CLOUD_BASE)
|
||||||
|
self.mission.weather.clouds_density = random.randint(*WEATHER_CLOUD_DENSITY)
|
||||||
|
self.mission.weather.clouds_thickness = random.randint(*WEATHER_CLOUD_THICKNESS)
|
||||||
|
|
||||||
|
self.mission.weather.random(self.mission.start_time, self.conflict.theater.terrain)
|
||||||
|
|
||||||
|
if self.mission.weather.clouds_density > 0:
|
||||||
|
self.mission.weather.clouds_base = max(self.mission.weather.clouds_base, WEATHER_CLOUD_BASE_MIN)
|
||||||
|
|
||||||
|
self.mission.random_weather = False
|
||||||
|
|
||||||
|
def generate(self) -> EnvironmentSettings:
|
||||||
|
self._gen_random_time()
|
||||||
|
self._gen_random_weather()
|
||||||
|
|
||||||
|
settings = EnvironmentSettings()
|
||||||
|
settings.start_time = self.mission.start_time
|
||||||
|
settings.weather_dict = self.mission.weather.dict()
|
||||||
|
return settings
|
||||||
|
|
||||||
|
def load(self, settings: EnvironmentSettings):
|
||||||
|
self.mission.start_time = settings.start_time
|
||||||
|
self.mission.weather.load_from_dict(settings.weather_dict)
|
||||||
|
|
||||||
@ -22,67 +22,17 @@ PUSH_TRIGGER_SIZE = 3000
|
|||||||
REGROUP_ZONE_DISTANCE = 12000
|
REGROUP_ZONE_DISTANCE = 12000
|
||||||
REGROUP_ALT = 5000
|
REGROUP_ALT = 5000
|
||||||
|
|
||||||
CLOUDS_BASE_MIN = 4000
|
|
||||||
|
|
||||||
RANDOM_TIME = {
|
|
||||||
"night": 5,
|
|
||||||
"dusk": 30,
|
|
||||||
"dawn": 30,
|
|
||||||
"day": 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
RANDOM_WEATHER = {
|
|
||||||
1: 5, # heavy rain
|
|
||||||
2: 15, # rain
|
|
||||||
3: 100, # random dynamic
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Silence(Option):
|
class Silence(Option):
|
||||||
Key = 7
|
Key = 7
|
||||||
|
|
||||||
|
|
||||||
class SettingsGenerator:
|
class TriggersGenerator:
|
||||||
def __init__(self, mission: Mission, conflict: Conflict, game):
|
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||||
self.mission = mission
|
self.mission = mission
|
||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
self.game = game
|
self.game = game
|
||||||
|
|
||||||
def _gen_random_time(self):
|
|
||||||
start_time = datetime.combine(datetime.today(), time())
|
|
||||||
time_range = None
|
|
||||||
for k, v in RANDOM_TIME.items():
|
|
||||||
if self.game.settings.night_disabled and k == "night":
|
|
||||||
continue
|
|
||||||
|
|
||||||
if random.randint(0, 100) <= v:
|
|
||||||
time_range = self.game.theater.daytime_map[k]
|
|
||||||
break
|
|
||||||
|
|
||||||
start_time += timedelta(hours=random.randint(*time_range))
|
|
||||||
self.mission.start_time = start_time
|
|
||||||
|
|
||||||
def _gen_random_weather(self):
|
|
||||||
weather_type = None
|
|
||||||
for k, v in RANDOM_WEATHER.items():
|
|
||||||
if random.randint(0, 100) <= v:
|
|
||||||
weather_type = k
|
|
||||||
break
|
|
||||||
|
|
||||||
print("generated weather {}".format(weather_type))
|
|
||||||
if weather_type == 0:
|
|
||||||
self.mission.weather.random_thunderstorm()
|
|
||||||
elif weather_type == 1:
|
|
||||||
self.mission.weather.heavy_rain()
|
|
||||||
elif weather_type == 2:
|
|
||||||
self.mission.weather.heavy_rain()
|
|
||||||
self.mission.weather.enable_fog = False
|
|
||||||
elif weather_type == 3:
|
|
||||||
self.mission.weather.random(self.mission.start_time, self.conflict.theater.terrain)
|
|
||||||
|
|
||||||
if self.mission.weather.clouds_density > 0:
|
|
||||||
self.mission.weather.clouds_base = max(self.mission.weather.clouds_base, CLOUDS_BASE_MIN)
|
|
||||||
|
|
||||||
def _gen_activation_trigger(self, player_coalition: str, enemy_coalition: str):
|
def _gen_activation_trigger(self, player_coalition: str, enemy_coalition: str):
|
||||||
activate_by_trigger = []
|
activate_by_trigger = []
|
||||||
for coalition_name, coalition in self.mission.coalition.items():
|
for coalition_name, coalition in self.mission.coalition.items():
|
||||||
@ -178,8 +128,6 @@ class SettingsGenerator:
|
|||||||
self.mission.coalition[player_coalition].bullseye = {"x": self.conflict.position.x,
|
self.mission.coalition[player_coalition].bullseye = {"x": self.conflict.position.x,
|
||||||
"y": self.conflict.position.y}
|
"y": self.conflict.position.y}
|
||||||
|
|
||||||
self._gen_random_time()
|
|
||||||
self._gen_random_weather()
|
|
||||||
self._set_skill(player_coalition, enemy_coalition)
|
self._set_skill(player_coalition, enemy_coalition)
|
||||||
self._set_allegiances(player_coalition, enemy_coalition)
|
self._set_allegiances(player_coalition, enemy_coalition)
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user