mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Differentiate required long and medium range SAMs.
To improve IADS design in campaigns, this differentiates required long and medium range SAMs. SAMs that must be long range SAMs are defined by SA-10 or Patriot launchers, while medium range SAMs are defined by SA-2, SA-3, or Hawk launchers. Long range SAMs positions will only be populated by long range SAMs (Patriots and SA-10s), and not all factions have those available. Medium range SAMs currently comprise all air defenses that are not long range SAMs, so if the faction includes flak guns in their `sams` property then flak guns may be spawned at medium range SAM locations. Base defenses and random SAM locations continue to use either type of SAM.
This commit is contained in:
@@ -7,7 +7,7 @@ from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from itertools import tee
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union, cast
|
||||
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union, cast
|
||||
|
||||
from dcs import Mission
|
||||
from dcs.countries import (
|
||||
@@ -96,17 +96,17 @@ class MizCampaignLoader:
|
||||
COASTAL_DEFENSE_UNIT_TYPE = MissilesSS.SS_N_2_Silkworm.id
|
||||
|
||||
# Multiple options for the required SAMs so campaign designers can more
|
||||
# easily see the coverage of their IADS. Designers focused on campaigns that
|
||||
# will primarily use SA-2s can place SA-2 launchers to ensure that they will
|
||||
# have adequate coverage, and designers focused on campaigns that will
|
||||
# primarily use SA-10s can do the same.
|
||||
REQUIRED_SAM_UNIT_TYPES = {
|
||||
AirDefence.SAM_Hawk_LN_M192,
|
||||
AirDefence.SAM_Patriot_LN_M901,
|
||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
|
||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85D,
|
||||
AirDefence.SAM_SA_2_LN_SM_90,
|
||||
AirDefence.SAM_SA_3_S_125_LN_5P73,
|
||||
# accurately see the coverage of their IADS for the expected type.
|
||||
REQUIRED_LONG_RANGE_SAM_UNIT_TYPES = {
|
||||
AirDefence.SAM_Patriot_LN_M901.id,
|
||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85C.id,
|
||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85D.id,
|
||||
}
|
||||
|
||||
REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES = {
|
||||
AirDefence.SAM_Hawk_LN_M192.id,
|
||||
AirDefence.SAM_SA_2_LN_SM_90.id,
|
||||
AirDefence.SAM_SA_3_S_125_LN_5P73.id,
|
||||
}
|
||||
|
||||
BASE_DEFENSE_RADIUS = nm_to_meter(2)
|
||||
@@ -221,9 +221,15 @@ class MizCampaignLoader:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def required_sams(self) -> Iterator[VehicleGroup]:
|
||||
def required_long_range_sams(self) -> Iterator[VehicleGroup]:
|
||||
for group in self.red.vehicle_group:
|
||||
if group.units[0].type == self.REQUIRED_SAM_UNIT_TYPES:
|
||||
if group.units[0].type in self.REQUIRED_LONG_RANGE_SAM_UNIT_TYPES:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def required_medium_range_sams(self) -> Iterator[VehicleGroup]:
|
||||
for group in self.red.vehicle_group:
|
||||
if group.units[0].type in self.REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES:
|
||||
yield group
|
||||
|
||||
@cached_property
|
||||
@@ -335,9 +341,17 @@ class MizCampaignLoader:
|
||||
closest, distance = self.objective_info(group)
|
||||
closest.preset_locations.coastal_defenses.append(group.position)
|
||||
|
||||
for group in self.required_sams:
|
||||
for group in self.required_long_range_sams:
|
||||
closest, distance = self.objective_info(group)
|
||||
closest.preset_locations.required_sams.append(group.position)
|
||||
closest.preset_locations.required_long_range_sams.append(
|
||||
group.position
|
||||
)
|
||||
|
||||
for group in self.required_medium_range_sams:
|
||||
closest, distance = self.objective_info(group)
|
||||
closest.preset_locations.required_medium_range_sams.append(
|
||||
group.position
|
||||
)
|
||||
|
||||
def populate_theater(self) -> None:
|
||||
for control_point in self.control_points.values():
|
||||
|
||||
@@ -95,8 +95,11 @@ class PresetLocations:
|
||||
#: Locations used by missile sites like scuds and V-2s.
|
||||
missile_sites: List[Point] = field(default_factory=list)
|
||||
|
||||
#: Locations of SAMs which should always be spawned.
|
||||
required_sams: List[Point] = field(default_factory=list)
|
||||
#: Locations of long range SAMs which should always be spawned.
|
||||
required_long_range_sams: List[Point] = field(default_factory=list)
|
||||
|
||||
#: Locations of medium range SAMs which should always be spawned.
|
||||
required_medium_range_sams: List[Point] = field(default_factory=list)
|
||||
|
||||
@staticmethod
|
||||
def _random_from(points: List[Point]) -> Optional[Point]:
|
||||
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
import math
|
||||
import pickle
|
||||
import random
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.task import CAP, CAS, PinpointStrike
|
||||
@@ -36,7 +36,7 @@ from gen.fleet.ship_group_generator import (
|
||||
from gen.locations.preset_location_finder import MizDataLocationFinder
|
||||
from gen.missiles.missiles_group_generator import generate_missile_group
|
||||
from gen.sam.sam_group_generator import (
|
||||
generate_anti_air_group,
|
||||
LONG_RANGE_SAMS, MEDIUM_RANGE_SAMS, generate_anti_air_group,
|
||||
generate_ewr_group, generate_shorad_group,
|
||||
)
|
||||
from . import (
|
||||
@@ -268,7 +268,6 @@ class LocationFinder:
|
||||
Find a valid ground object location
|
||||
:param on_ground: Whether it should be on ground or on sea (True = on
|
||||
ground)
|
||||
:param theater: Theater object
|
||||
:param min_range: Minimal range from point
|
||||
:param max_range: Max range from point
|
||||
:param is_base_defense: True if the location is for base defense.
|
||||
@@ -459,7 +458,7 @@ class BaseDefenseGenerator:
|
||||
g = EwrGroundObject(namegen.random_objective_name(), group_id,
|
||||
position, self.control_point)
|
||||
|
||||
group = generate_ewr_group(self.game, g, self.faction_name)
|
||||
group = generate_ewr_group(self.game, g, self.faction)
|
||||
if group is None:
|
||||
return
|
||||
|
||||
@@ -507,7 +506,7 @@ class BaseDefenseGenerator:
|
||||
g = SamGroundObject(namegen.random_objective_name(), group_id,
|
||||
position, self.control_point, for_airbase=True)
|
||||
|
||||
group = generate_anti_air_group(self.game, g, self.faction_name)
|
||||
group = generate_anti_air_group(self.game, g, self.faction)
|
||||
if group is not None:
|
||||
g.groups.append(group)
|
||||
self.control_point.base_defenses.append(g)
|
||||
@@ -523,7 +522,7 @@ class BaseDefenseGenerator:
|
||||
g = SamGroundObject(namegen.random_objective_name(), group_id,
|
||||
position, self.control_point, for_airbase=True)
|
||||
|
||||
group = generate_shorad_group(self.game, g, self.faction_name)
|
||||
group = generate_shorad_group(self.game, g, self.faction)
|
||||
if group is not None:
|
||||
g.groups.append(group)
|
||||
self.control_point.base_defenses.append(g)
|
||||
@@ -575,10 +574,13 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
Returns:
|
||||
The number of AA sites that were generated.
|
||||
"""
|
||||
sams = self.control_point.preset_locations.required_sams
|
||||
for position in sams:
|
||||
self.generate_aa_at(position)
|
||||
return len(sams)
|
||||
presets = self.control_point.preset_locations
|
||||
for position in presets.required_long_range_sams:
|
||||
self.generate_aa_at(position, filter_names=LONG_RANGE_SAMS)
|
||||
for position in presets.required_medium_range_sams:
|
||||
self.generate_aa_at(position, filter_names=MEDIUM_RANGE_SAMS)
|
||||
return (len(presets.required_long_range_sams) +
|
||||
len(presets.required_medium_range_sams))
|
||||
|
||||
def generate_ground_point(self) -> None:
|
||||
try:
|
||||
@@ -620,12 +622,14 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
return
|
||||
self.generate_aa_at(position)
|
||||
|
||||
def generate_aa_at(self, position: Point) -> None:
|
||||
def generate_aa_at(self, position: Point,
|
||||
filter_names: Optional[List[str]] = None) -> None:
|
||||
group_id = self.game.next_group_id()
|
||||
|
||||
g = SamGroundObject(namegen.random_objective_name(), group_id,
|
||||
position, self.control_point, for_airbase=False)
|
||||
group = generate_anti_air_group(self.game, g, self.faction_name)
|
||||
group = generate_anti_air_group(self.game, g, self.faction,
|
||||
filter_names)
|
||||
if group is not None:
|
||||
g.groups = [group]
|
||||
self.control_point.connected_objectives.append(g)
|
||||
|
||||
Reference in New Issue
Block a user