new weather, strike objectives placement fixes & tarawa for av8b

This commit is contained in:
Vasyl Horbachenko 2018-10-13 22:28:30 +03:00
parent 6d0f488672
commit e2306ba0f3
16 changed files with 119 additions and 63 deletions

View File

@ -43,7 +43,7 @@ def is_version_compatible(save_version):
if current_version_components == save_version_components: if current_version_components == save_version_components:
return True 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 return False
if current_version_components[:2] == save_version_components[:2]: if current_version_components[:2] == save_version_components[:2]:

View File

@ -76,7 +76,6 @@ PRICES = {
S_3B_Tanker: 13, S_3B_Tanker: 13,
IL_78M: 13, IL_78M: 13,
KC_135: 13, KC_135: 13,
KC130: 13,
A_50: 8, A_50: 8,
E_3A: 8, E_3A: 8,
@ -110,9 +109,10 @@ PRICES = {
# ship # ship
CV_1143_5_Admiral_Kuznetsov: 100, CV_1143_5_Admiral_Kuznetsov: 100,
CVN_74_John_C__Stennis: 100, CVN_74_John_C__Stennis: 100,
LHA_1_Tarawa: 50,
LHA_1_Tarawa: 30,
Bulk_cargo_ship_Yakushev: 10, Bulk_cargo_ship_Yakushev: 10,
Armed_speedboat: 10,
Dry_cargo_ship_Ivanov: 10, Dry_cargo_ship_Ivanov: 10,
Tanker_Elnya_160: 10, Tanker_Elnya_160: 10,
} }
@ -166,14 +166,13 @@ UNIT_BY_TASK = {
An_30M, An_30M,
Yak_40, Yak_40,
S_3B_Tanker,
C_130, C_130,
], ],
Refueling: [ Refueling: [
IL_78M, IL_78M,
KC_135, KC_135,
KC130, S_3B_Tanker,
], ],
AWACS: [E_3A, A_50, ], AWACS: [E_3A, A_50, ],
@ -198,8 +197,8 @@ UNIT_BY_TASK = {
Nothing: [Infantry.Infantry_M4, Infantry.Soldier_AK, ], Nothing: [Infantry.Infantry_M4, Infantry.Soldier_AK, ],
Embarking: [UH_1H, Mi_8MT, ], Embarking: [UH_1H, Mi_8MT, ],
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ], 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, LHA_1_Tarawa], CargoTransportation: [Dry_cargo_ship_Ivanov, Bulk_cargo_ship_Yakushev, Tanker_Elnya_160, Armed_speedboat, ],
} }
""" """
@ -299,7 +298,6 @@ UNIT_BY_COUNTRY = {
AV8BNA, AV8BNA,
KC_135, KC_135,
KC130,
S_3B_Tanker, S_3B_Tanker,
C_130, C_130,
E_3A, E_3A,
@ -319,9 +317,18 @@ UNIT_BY_COUNTRY = {
CVN_74_John_C__Stennis, CVN_74_John_C__Stennis,
LHA_1_Tarawa, 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. Aircraft payload overrides. Usually default loadout for the task is loaded during the mission generation.
Syntax goes as follows: Syntax goes as follows:
@ -341,6 +348,8 @@ Payload will be used for operation of following type, "*" category will be used
PLANE_PAYLOAD_OVERRIDES = { PLANE_PAYLOAD_OVERRIDES = {
FA_18C_hornet: { FA_18C_hornet: {
CAP: "AIM-120*4,AIM-9*2,AIM-7*2,Fuel", 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: { 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 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): def unitdict_split(unit_dict: UnitsDict, count: int):
buffer_dict = {} buffer_dict = {}
for unit_type, unit_count in unit_dict.items(): for unit_type, unit_count in unit_dict.items():

View File

@ -11,7 +11,7 @@ class NavalInterceptEvent(Event):
def _targets_count(self) -> int: def _targets_count(self) -> int:
from gen.conflictgen import IMPORTANCE_LOW 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) return max(int(factor), 1)
def __str__(self) -> str: def __str__(self) -> str:

View File

@ -39,16 +39,7 @@ class InterceptOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): def generate(self):
for global_cp in self.game.theater.controlpoints: self.prepare_carriers(self.interceptors.keys())
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.airgen.generate_transport(self.transport, self.to_cp.at) 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) self.airgen.generate_defenders_escort(*assigned_units_split(self.escort), at=self.defenders_starting_position)

View File

@ -33,6 +33,8 @@ class NavalInterceptionOperation(Operation):
self.initialize(self.mission, conflict) self.initialize(self.mission, conflict)
def generate(self): def generate(self):
self.prepare_carriers(db.unitdict_from(self.strikegroup))
target_groups = self.shipgen.generate_cargo(units=self.targets) target_groups = self.shipgen.generate_cargo(units=self.targets)
self.airgen.generate_ship_strikegroup( self.airgen.generate_ship_strikegroup(

View File

@ -83,6 +83,18 @@ class Operation:
self.attackers_starting_position = self.from_cp.at self.attackers_starting_position = self.from_cp.at
self.defenders_starting_position = self.to_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): def generate(self):
self.visualgen.generate() self.visualgen.generate()

View File

@ -35,16 +35,7 @@ class StrikeOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): def generate(self):
for global_cp in self.game.theater.controlpoints: self.prepare_carriers(db.unitdict_merge(db.unitdict_from(self.strikegroup), db.unitdict_from(self.escort)))
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
targets = [] # type: typing.List[typing.Tuple[str, str, Point]] targets = [] # type: typing.List[typing.Tuple[str, str, Point]]
category_counters = {} # type: typing.Dict[str, int] category_counters = {} # type: typing.Dict[str, int]

View File

@ -5,6 +5,7 @@ class Settings:
enemy_vehicle_skill = "Average" enemy_vehicle_skill = "Average"
only_player_takeoff = True only_player_takeoff = True
night_disabled = False night_disabled = False
multiplier = 1 multiplier = 1
sams = True sams = True
cold_start = False cold_start = False

View File

@ -9,11 +9,11 @@ from dcs.task import *
from dcs.terrain.terrain import NoParkingSlotError from dcs.terrain.terrain import NoParkingSlotError
TANKER_DISTANCE = 15000 TANKER_DISTANCE = 15000
TANKER_ALT = 6000 TANKER_ALT = 4572
TANKER_HEADING_OFFSET = 45 TANKER_HEADING_OFFSET = 45
AWACS_DISTANCE = 150000 AWACS_DISTANCE = 150000
AWACS_ALT = 15000 AWACS_ALT = 13000
class AirSupportConflictGenerator: class AirSupportConflictGenerator:

View File

@ -21,6 +21,10 @@ WEATHER_CLOUD_DENSITY = 1, 8
WEATHER_CLOUD_THICKNESS = 100, 400 WEATHER_CLOUD_THICKNESS = 100, 400
WEATHER_CLOUD_BASE_MIN = 1600 WEATHER_CLOUD_BASE_MIN = 1600
WEATHER_FOG_CHANCE = 20
WEATHER_FOG_VISIBILITY = 2500, 5000
WEATHER_FOG_THICKNESS = 100, 500
RANDOM_TIME = { RANDOM_TIME = {
"night": 5, "night": 5,
"dusk": 30, "dusk": 30,
@ -29,11 +33,10 @@ RANDOM_TIME = {
} }
RANDOM_WEATHER = { RANDOM_WEATHER = {
1: 0, # heavy rain 1: 0, # thunderstorm
2: 5, # rain 2: 20, # rain
3: 15, # dynamic 3: 80, # clouds
4: 40, # clear 4: 100, # clear
5: 100, # random
} }
@ -68,6 +71,29 @@ class EnviromentGenerator:
self.mission.start_time = start_time 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): def _gen_random_weather(self):
weather_type = None weather_type = None
for k, v in RANDOM_WEATHER.items(): for k, v in RANDOM_WEATHER.items():
@ -77,24 +103,25 @@ class EnviromentGenerator:
logging.info("generated weather {}".format(weather_type)) logging.info("generated weather {}".format(weather_type))
if weather_type == 1: if weather_type == 1:
self.mission.weather.heavy_rain() # thunderstorm
elif weather_type == 2: self._generate_base_weather()
self.mission.weather.heavy_rain() self._generate_wind(random.randint(8, 12))
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)
wind_direction = random.randint(0, 360) self.mission.weather.clouds_density = random.randint(9, 10)
wind_speed = random.randint(0, 4) self.mission.weather.clouds_iprecptns = Weather.Preceptions.Thunderstorm
self.mission.weather.wind_at_ground = Wind(wind_direction, wind_speed) elif weather_type == 2:
self.mission.weather.wind_at_2000 = Wind(wind_direction, wind_speed * 2) # rain
self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3) 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: if self.mission.weather.clouds_density > 0:
# sometimes clouds are randomized way too low and need to be fixed # sometimes clouds are randomized way too low and need to be fixed

View File

@ -16,7 +16,17 @@ class ShipGenerator:
self.m = mission self.m = mission
self.conflict = conflict 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( group = self.m.ship_group(
country=self.m.country(country), country=self.m.country(country),
name=namegen.next_carrier_name(self.m.country(country)), name=namegen.next_carrier_name(self.m.country(country)),

View File

@ -10,9 +10,9 @@ from dcs.task import *
from game import db from game import db
STRENGTH_AA_ASSEMBLE_MIN = 0.2 STRENGTH_AA_ASSEMBLE_MIN = 0.2
PLANES_SCRAMBLE_MIN_BASE = 4 PLANES_SCRAMBLE_MIN_BASE = 2
PLANES_SCRAMBLE_MAX_BASE = 8 PLANES_SCRAMBLE_MAX_BASE = 8
PLANES_SCRAMBLE_FACTOR = 0.6 PLANES_SCRAMBLE_FACTOR = 0.3
BASE_MAX_STRENGTH = 1 BASE_MAX_STRENGTH = 1
BASE_MIN_STRENGTH = 0 BASE_MIN_STRENGTH = 0

View File

@ -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.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas])
self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya]) 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.west_carrier)
self.add_controlpoint(self.east_carrier)
self.west_carrier.captured = True self.west_carrier.captured = True
self.east_carrier.captured = True self.east_carrier.captured = True

View File

@ -2,6 +2,7 @@ import math
import pickle import pickle
import random import random
import typing import typing
import logging
from theater.base import * from theater.base import *
from theater.conflicttheater import * from theater.conflicttheater import *
@ -72,8 +73,8 @@ def generate_groundobjects(theater: ConflictTheater):
group_id = 0 group_id = 0
for cp in theater.enemy_points(): for cp in theater.enemy_points():
for _ in range(0, random.randrange(3, 6)): for _ in range(0, random.randrange(2, 4)):
available_categories = list(tpls) + ["aa", "aa", "aa"] available_categories = list(tpls) + ["aa", "aa"]
tpl_category = random.choice(available_categories) tpl_category = random.choice(available_categories)
tpl = random.choice(list(tpls[tpl_category].values())) 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)) print("Couldn't find point for {}".format(cp))
continue continue
dist = point.distance_to_point(cp.position) """
dist = point.distance_to_point(cp.position) - 15000
for another_cp in theater.enemy_points(): for another_cp in theater.enemy_points():
if another_cp.position.distance_to_point(point) < dist: if another_cp.position.distance_to_point(point) < dist:
cp = another_cp cp = another_cp
"""
group_id += 1 group_id += 1
object_id = 0 object_id = 0
logging.info("generated {} for {}".format(tpl_category, cp))
for object in tpl: for object in tpl:
object_id += 1 object_id += 1

View File

@ -79,10 +79,14 @@ class ConfigurationMenu(Menu):
Label(body, text="Takeoff only for player group", **STYLES["widget"]).grid(row=row, column=0, sticky=W) 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) Checkbutton(body, variable=self.takeoff_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E)
row += 1 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) 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) Checkbutton(body, variable=self.night_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E)
row += 1 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) Button(body, text="Display logs", command=self.display_logs, **STYLES["btn-primary"]).grid(row=row, column=1, sticky=E, pady=30)
row += 1 row += 1

View File

@ -98,9 +98,6 @@ class NewGameMenu(Menu):
Label(terrain, text="Persian Gulf", **STYLES["widget"]).grid(row=2, column=1, sticky=W) 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) 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 # Misc Options
options = LabelFrame(body, text="Misc Options", **STYLES["label-frame"]) options = LabelFrame(body, text="Misc Options", **STYLES["label-frame"])
options.grid(row=0, column=2, sticky=NE, padx=5) options.grid(row=0, column=2, sticky=NE, padx=5)