From e2306ba0f367da9ceba573dd2efbcb60a251f352 Mon Sep 17 00:00:00 2001 From: Vasyl Horbachenko Date: Sat, 13 Oct 2018 22:28:30 +0300 Subject: [PATCH] new weather, strike objectives placement fixes & tarawa for av8b --- __init__.py | 2 +- game/db.py | 31 ++++++++++---- game/event/navalintercept.py | 2 +- game/operation/intercept.py | 11 +---- game/operation/navalintercept.py | 2 + game/operation/operation.py | 12 ++++++ game/operation/strike.py | 11 +---- game/settings.py | 1 + gen/airsupportgen.py | 4 +- gen/environmentgen.py | 71 ++++++++++++++++++++++---------- gen/shipgen.py | 12 +++++- theater/base.py | 4 +- theater/persiangulf.py | 2 +- theater/start_generator.py | 10 +++-- ui/configurationmenu.py | 4 ++ ui/newgamemenu.py | 3 -- 16 files changed, 119 insertions(+), 63 deletions(-) diff --git a/__init__.py b/__init__.py index 0d6339e2..e297774b 100755 --- a/__init__.py +++ b/__init__.py @@ -43,7 +43,7 @@ def is_version_compatible(save_version): if current_version_components == save_version_components: return True - if save_version in ["1.4_rc1", "1.4_rc2", "1.4_rc3", "1.4_rc4", "1.4_rc5"]: + if save_version in ["1.4_rc1", "1.4_rc2", "1.4_rc3", "1.4_rc4", "1.4_rc5", "1.4_rc6"]: return False if current_version_components[:2] == save_version_components[:2]: diff --git a/game/db.py b/game/db.py index de3cc37b..a7951994 100644 --- a/game/db.py +++ b/game/db.py @@ -76,7 +76,6 @@ PRICES = { S_3B_Tanker: 13, IL_78M: 13, KC_135: 13, - KC130: 13, A_50: 8, E_3A: 8, @@ -110,9 +109,10 @@ PRICES = { # ship CV_1143_5_Admiral_Kuznetsov: 100, CVN_74_John_C__Stennis: 100, + LHA_1_Tarawa: 50, - LHA_1_Tarawa: 30, Bulk_cargo_ship_Yakushev: 10, + Armed_speedboat: 10, Dry_cargo_ship_Ivanov: 10, Tanker_Elnya_160: 10, } @@ -166,14 +166,13 @@ UNIT_BY_TASK = { An_30M, Yak_40, - S_3B_Tanker, C_130, ], Refueling: [ IL_78M, KC_135, - KC130, + S_3B_Tanker, ], AWACS: [E_3A, A_50, ], @@ -198,8 +197,8 @@ UNIT_BY_TASK = { Nothing: [Infantry.Infantry_M4, Infantry.Soldier_AK, ], Embarking: [UH_1H, Mi_8MT, ], - Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ], - CargoTransportation: [Dry_cargo_ship_Ivanov, Bulk_cargo_ship_Yakushev, Tanker_Elnya_160, LHA_1_Tarawa], + Carriage: [CVN_74_John_C__Stennis, LHA_1_Tarawa, CV_1143_5_Admiral_Kuznetsov, ], + CargoTransportation: [Dry_cargo_ship_Ivanov, Bulk_cargo_ship_Yakushev, Tanker_Elnya_160, Armed_speedboat, ], } """ @@ -299,7 +298,6 @@ UNIT_BY_COUNTRY = { AV8BNA, KC_135, - KC130, S_3B_Tanker, C_130, E_3A, @@ -319,9 +317,18 @@ UNIT_BY_COUNTRY = { CVN_74_John_C__Stennis, LHA_1_Tarawa, + Armed_speedboat, ], } +CARRIER_TYPE_BY_PLANE = { + FA_18C_hornet: CVN_74_John_C__Stennis, + Ka_50: LHA_1_Tarawa, + UH_1H: LHA_1_Tarawa, + Mi_8MT: LHA_1_Tarawa, + AV8BNA: LHA_1_Tarawa, +} + """ Aircraft payload overrides. Usually default loadout for the task is loaded during the mission generation. Syntax goes as follows: @@ -341,6 +348,8 @@ Payload will be used for operation of following type, "*" category will be used PLANE_PAYLOAD_OVERRIDES = { FA_18C_hornet: { CAP: "AIM-120*4,AIM-9*2,AIM-7*2,Fuel", + PinpointStrike: "MK-82*8,AIM-9*2,AIM-7,FLIR Pod,Fuel", + AntishipStrike: "MK-82*8,AIM-9*2,AIM-7,FLIR Pod,Fuel", }, Su_25T: { @@ -460,6 +469,14 @@ def unitdict_append(unit_dict: UnitsDict, unit_type: UnitType, count: int): unit_dict[unit_type] = unit_dict.get(unit_type, 0) + 1 +def unitdict_merge(a: UnitsDict, b: UnitsDict) -> UnitsDict: + b = b.copy() + for k, v in a.items(): + b[k] = b.get(k, 0) + v + + return b + + def unitdict_split(unit_dict: UnitsDict, count: int): buffer_dict = {} for unit_type, unit_count in unit_dict.items(): diff --git a/game/event/navalintercept.py b/game/event/navalintercept.py index f1049a2d..df425415 100644 --- a/game/event/navalintercept.py +++ b/game/event/navalintercept.py @@ -11,7 +11,7 @@ class NavalInterceptEvent(Event): def _targets_count(self) -> int: from gen.conflictgen import IMPORTANCE_LOW - factor = (self.to_cp.importance - IMPORTANCE_LOW) * 10 + factor = (self.to_cp.importance - IMPORTANCE_LOW + 0.1) * 20 return max(int(factor), 1) def __str__(self) -> str: diff --git a/game/operation/intercept.py b/game/operation/intercept.py index 1d763113..27dabcda 100644 --- a/game/operation/intercept.py +++ b/game/operation/intercept.py @@ -39,16 +39,7 @@ class InterceptOperation(Operation): conflict=conflict) def generate(self): - for global_cp in self.game.theater.controlpoints: - if not global_cp.is_global: - continue - - ship = self.shipgen.generate_carrier(type=db.find_unittype(Carriage, self.game.player)[0], - country=self.game.player, - at=global_cp.at) - - if global_cp == self.from_cp and not self.is_quick: - self.attackers_starting_position = ship + self.prepare_carriers(self.interceptors.keys()) self.airgen.generate_transport(self.transport, self.to_cp.at) self.airgen.generate_defenders_escort(*assigned_units_split(self.escort), at=self.defenders_starting_position) diff --git a/game/operation/navalintercept.py b/game/operation/navalintercept.py index e782c759..fb373d23 100644 --- a/game/operation/navalintercept.py +++ b/game/operation/navalintercept.py @@ -33,6 +33,8 @@ class NavalInterceptionOperation(Operation): self.initialize(self.mission, conflict) def generate(self): + self.prepare_carriers(db.unitdict_from(self.strikegroup)) + target_groups = self.shipgen.generate_cargo(units=self.targets) self.airgen.generate_ship_strikegroup( diff --git a/game/operation/operation.py b/game/operation/operation.py index e04b40d9..19ff9611 100644 --- a/game/operation/operation.py +++ b/game/operation/operation.py @@ -83,6 +83,18 @@ class Operation: self.attackers_starting_position = self.from_cp.at self.defenders_starting_position = self.to_cp.at + def prepare_carriers(self, for_units: db.UnitsDict): + for global_cp in self.game.theater.controlpoints: + if not global_cp.is_global: + continue + + ship = self.shipgen.generate_carrier(for_units=for_units, + country=self.game.player, + at=global_cp.at) + + if global_cp == self.from_cp and not self.is_quick: + self.attackers_starting_position = ship + def generate(self): self.visualgen.generate() diff --git a/game/operation/strike.py b/game/operation/strike.py index eaf5ee4b..647434bd 100644 --- a/game/operation/strike.py +++ b/game/operation/strike.py @@ -35,16 +35,7 @@ class StrikeOperation(Operation): conflict=conflict) def generate(self): - for global_cp in self.game.theater.controlpoints: - if not global_cp.is_global: - continue - - ship = self.shipgen.generate_carrier(type=db.find_unittype(Carriage, self.game.player)[0], - country=self.game.player, - at=global_cp.at) - - if global_cp == self.from_cp and not self.is_quick: - self.attackers_starting_position = ship + self.prepare_carriers(db.unitdict_merge(db.unitdict_from(self.strikegroup), db.unitdict_from(self.escort))) targets = [] # type: typing.List[typing.Tuple[str, str, Point]] category_counters = {} # type: typing.Dict[str, int] diff --git a/game/settings.py b/game/settings.py index 2014d1f4..36edefd1 100644 --- a/game/settings.py +++ b/game/settings.py @@ -5,6 +5,7 @@ class Settings: enemy_vehicle_skill = "Average" only_player_takeoff = True night_disabled = False + multiplier = 1 sams = True cold_start = False diff --git a/gen/airsupportgen.py b/gen/airsupportgen.py index 68ee9af9..595e4fc7 100644 --- a/gen/airsupportgen.py +++ b/gen/airsupportgen.py @@ -9,11 +9,11 @@ from dcs.task import * from dcs.terrain.terrain import NoParkingSlotError TANKER_DISTANCE = 15000 -TANKER_ALT = 6000 +TANKER_ALT = 4572 TANKER_HEADING_OFFSET = 45 AWACS_DISTANCE = 150000 -AWACS_ALT = 15000 +AWACS_ALT = 13000 class AirSupportConflictGenerator: diff --git a/gen/environmentgen.py b/gen/environmentgen.py index 9deadb8d..abfc0cf0 100644 --- a/gen/environmentgen.py +++ b/gen/environmentgen.py @@ -21,6 +21,10 @@ WEATHER_CLOUD_DENSITY = 1, 8 WEATHER_CLOUD_THICKNESS = 100, 400 WEATHER_CLOUD_BASE_MIN = 1600 +WEATHER_FOG_CHANCE = 20 +WEATHER_FOG_VISIBILITY = 2500, 5000 +WEATHER_FOG_THICKNESS = 100, 500 + RANDOM_TIME = { "night": 5, "dusk": 30, @@ -29,11 +33,10 @@ RANDOM_TIME = { } RANDOM_WEATHER = { - 1: 0, # heavy rain - 2: 5, # rain - 3: 15, # dynamic - 4: 40, # clear - 5: 100, # random + 1: 0, # thunderstorm + 2: 20, # rain + 3: 80, # clouds + 4: 100, # clear } @@ -68,6 +71,29 @@ class EnviromentGenerator: self.mission.start_time = start_time + def _generate_wind(self, wind_speed, wind_direction=None): + # wind + if not wind_direction: + wind_direction = random.randint(0, 360) + + self.mission.weather.wind_at_ground = Wind(wind_direction, wind_speed) + self.mission.weather.wind_at_2000 = Wind(wind_direction, wind_speed * 2) + self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3) + + def _generate_base_weather(self): + # clouds + 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) + + # wind + self._generate_wind(random.randint(0, 4)) + + # fog + if random.randint(0, 100) < WEATHER_FOG_CHANCE: + self.mission.weather.fog_visibility = random.randint(*WEATHER_FOG_VISIBILITY) + self.mission.weather.fog_thickness = random.randint(*WEATHER_FOG_THICKNESS) + def _gen_random_weather(self): weather_type = None for k, v in RANDOM_WEATHER.items(): @@ -77,24 +103,25 @@ class EnviromentGenerator: logging.info("generated weather {}".format(weather_type)) if 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) + # thunderstorm + self._generate_base_weather() + self._generate_wind(random.randint(8, 12)) - wind_direction = random.randint(0, 360) - wind_speed = random.randint(0, 4) - self.mission.weather.wind_at_ground = Wind(wind_direction, wind_speed) - self.mission.weather.wind_at_2000 = Wind(wind_direction, wind_speed * 2) - self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3) + self.mission.weather.clouds_density = random.randint(9, 10) + self.mission.weather.clouds_iprecptns = Weather.Preceptions.Thunderstorm + elif weather_type == 2: + # rain + self._generate_base_weather() + self.mission.weather.clouds_density = random.randint(5, 8) + self.mission.weather.clouds_iprecptns = Weather.Preceptions.Rain + + self._generate_wind(random.randint(4, 8)) + elif weather_type == 3: + # clouds + self._generate_base_weather() + elif weather_type == 4: + # clear + pass if self.mission.weather.clouds_density > 0: # sometimes clouds are randomized way too low and need to be fixed diff --git a/gen/shipgen.py b/gen/shipgen.py index 5103d187..bdff7234 100644 --- a/gen/shipgen.py +++ b/gen/shipgen.py @@ -16,7 +16,17 @@ class ShipGenerator: self.m = mission self.conflict = conflict - def generate_carrier(self, type: ShipType, country: str, at: Point) -> ShipGroup: + def generate_carrier(self, for_units: db.UnitsDict, country: str, at: Point) -> ShipGroup: + type = db.find_unittype(Carriage, country)[0] + print(for_units) + for unit_type, unit_count in for_units.items(): + if unit_count == 0: + continue + + if unit_type in db.CARRIER_TYPE_BY_PLANE: + type = db.CARRIER_TYPE_BY_PLANE[unit_type] + break + group = self.m.ship_group( country=self.m.country(country), name=namegen.next_carrier_name(self.m.country(country)), diff --git a/theater/base.py b/theater/base.py index c9e020f9..c62c1474 100644 --- a/theater/base.py +++ b/theater/base.py @@ -10,9 +10,9 @@ from dcs.task import * from game import db STRENGTH_AA_ASSEMBLE_MIN = 0.2 -PLANES_SCRAMBLE_MIN_BASE = 4 +PLANES_SCRAMBLE_MIN_BASE = 2 PLANES_SCRAMBLE_MAX_BASE = 8 -PLANES_SCRAMBLE_FACTOR = 0.6 +PLANES_SCRAMBLE_FACTOR = 0.3 BASE_MAX_STRENGTH = 1 BASE_MIN_STRENGTH = 0 diff --git a/theater/persiangulf.py b/theater/persiangulf.py index e9a1caeb..ec55045f 100644 --- a/theater/persiangulf.py +++ b/theater/persiangulf.py @@ -72,8 +72,8 @@ class PersianGulfTheater(ConflictTheater): self.add_controlpoint(self.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas]) self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya]) - self.add_controlpoint(self.east_carrier) self.add_controlpoint(self.west_carrier) + self.add_controlpoint(self.east_carrier) self.west_carrier.captured = True self.east_carrier.captured = True diff --git a/theater/start_generator.py b/theater/start_generator.py index 6f598cec..2c4d9c87 100644 --- a/theater/start_generator.py +++ b/theater/start_generator.py @@ -2,6 +2,7 @@ import math import pickle import random import typing +import logging from theater.base import * from theater.conflicttheater import * @@ -72,8 +73,8 @@ def generate_groundobjects(theater: ConflictTheater): group_id = 0 for cp in theater.enemy_points(): - for _ in range(0, random.randrange(3, 6)): - available_categories = list(tpls) + ["aa", "aa", "aa"] + for _ in range(0, random.randrange(2, 4)): + available_categories = list(tpls) + ["aa", "aa"] tpl_category = random.choice(available_categories) tpl = random.choice(list(tpls[tpl_category].values())) @@ -84,14 +85,17 @@ def generate_groundobjects(theater: ConflictTheater): print("Couldn't find point for {}".format(cp)) continue - dist = point.distance_to_point(cp.position) + """ + dist = point.distance_to_point(cp.position) - 15000 for another_cp in theater.enemy_points(): if another_cp.position.distance_to_point(point) < dist: cp = another_cp + """ group_id += 1 object_id = 0 + logging.info("generated {} for {}".format(tpl_category, cp)) for object in tpl: object_id += 1 diff --git a/ui/configurationmenu.py b/ui/configurationmenu.py index f43fdc36..f32b00cf 100644 --- a/ui/configurationmenu.py +++ b/ui/configurationmenu.py @@ -79,10 +79,14 @@ class ConfigurationMenu(Menu): Label(body, text="Takeoff only for player group", **STYLES["widget"]).grid(row=row, column=0, sticky=W) Checkbutton(body, variable=self.takeoff_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E) row += 1 + Label(body, text="Only player group will start on the ground. AI units will be circling in the air until player takes off.", **STYLES["widget"]).grid(row=row, column=0, columnspan=2) + row += 1 Label(body, text="Disable night missions", **STYLES["widget"]).grid(row=row, column=0, sticky=W) Checkbutton(body, variable=self.night_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E) row += 1 + Label(body, text="No night missions. Dawns and dusks will still be present.", **STYLES["widget"]).grid(row=row, column=0, columnspan=2) + row += 1 Button(body, text="Display logs", command=self.display_logs, **STYLES["btn-primary"]).grid(row=row, column=1, sticky=E, pady=30) row += 1 diff --git a/ui/newgamemenu.py b/ui/newgamemenu.py index 4e229806..5688aae2 100644 --- a/ui/newgamemenu.py +++ b/ui/newgamemenu.py @@ -98,9 +98,6 @@ class NewGameMenu(Menu): Label(terrain, text="Persian Gulf", **STYLES["widget"]).grid(row=2, column=1, sticky=W) self.create_label_image(terrain, "terrain_pg.gif").grid(row=2, column=2, padx=5) - Label(terrain, text="Currently strike missions are only\navailable for a number of airports only in Caucasus", **STYLES["widget"]) \ - .grid(row=3, column=0, columnspan=3, sticky=W) - # Misc Options options = LabelFrame(body, text="Misc Options", **STYLES["label-frame"]) options.grid(row=0, column=2, sticky=NE, padx=5)