mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Fall back to lower range SAMs when needed.
Mostly fixes https://github.com/Khopa/dcs_liberation/issues/473. The last part of the fix is to migrate the `shorads` property of the faction to just be in `sams` and just use the property to decide its use. Currently factions like USA 2005 that have long range SAMs and SHORADs only will still not spawn anything at medium sites because they have no other SAMs declared.
This commit is contained in:
parent
fcdb22db5b
commit
e8aa9839b0
@ -4,7 +4,7 @@ import logging
|
||||
import math
|
||||
import pickle
|
||||
import random
|
||||
from typing import Any, Dict, Iterable, Optional
|
||||
from typing import Any, Dict, Iterable, Optional, Set
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.task import CAP, CAS, PinpointStrike
|
||||
@ -35,9 +35,11 @@ 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.airdefensegroupgenerator import AirDefenseRange
|
||||
from gen.sam.sam_group_generator import (
|
||||
LONG_RANGE_SAMS, MEDIUM_RANGE_SAMS, generate_anti_air_group,
|
||||
generate_ewr_group, generate_shorad_group,
|
||||
generate_anti_air_group,
|
||||
generate_ewr_group,
|
||||
generate_shorad_group,
|
||||
)
|
||||
from . import (
|
||||
ConflictTheater,
|
||||
@ -585,9 +587,16 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
"""
|
||||
presets = self.control_point.preset_locations
|
||||
for position in presets.required_long_range_sams:
|
||||
self.generate_aa_at(position, filter_names=LONG_RANGE_SAMS)
|
||||
self.generate_aa_at(position, ranges=[
|
||||
{AirDefenseRange.Long},
|
||||
{AirDefenseRange.Medium},
|
||||
{AirDefenseRange.Short},
|
||||
])
|
||||
for position in presets.required_medium_range_sams:
|
||||
self.generate_aa_at(position, filter_names=MEDIUM_RANGE_SAMS)
|
||||
self.generate_aa_at(position, ranges=[
|
||||
{AirDefenseRange.Medium},
|
||||
{AirDefenseRange.Short},
|
||||
])
|
||||
return (len(presets.required_long_range_sams) +
|
||||
len(presets.required_medium_range_sams))
|
||||
|
||||
@ -629,25 +638,23 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
position = self.location_finder.location_for(LocationType.Sam)
|
||||
if position is None:
|
||||
return
|
||||
self.generate_aa_at(position)
|
||||
self.generate_aa_at(position, ranges=[
|
||||
# Prefer to use proper SAMs, but fall back to SHORADs if needed.
|
||||
{AirDefenseRange.Long, AirDefenseRange.Medium},
|
||||
{AirDefenseRange.Short},
|
||||
])
|
||||
|
||||
def generate_aa_at(self, position: Point,
|
||||
filter_names: Optional[Iterable[str]] = None) -> None:
|
||||
def generate_aa_at(
|
||||
self, position: Point,
|
||||
ranges: Iterable[Set[AirDefenseRange]]) -> 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,
|
||||
filter_names)
|
||||
group = generate_anti_air_group(self.game, g, self.faction, ranges)
|
||||
if group is None:
|
||||
location = f"{g.name} at {self.control_point}"
|
||||
if filter_names is not None:
|
||||
logging.warning(
|
||||
"Could not generate SAM group for %s from types: %s",
|
||||
location, ", ".join(filter_names)
|
||||
)
|
||||
else:
|
||||
logging.error("Could not generate SAM group for %s", location)
|
||||
logging.error("Could not generate air defense group for %s at %s",
|
||||
g.name, self.control_point)
|
||||
return
|
||||
g.groups = [group]
|
||||
self.control_point.connected_objectives.append(g)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import random
|
||||
from typing import Dict, Iterable, List, Optional, Type
|
||||
from typing import Dict, Iterable, List, Optional, Sequence, Set, Type
|
||||
|
||||
from dcs.unitgroup import VehicleGroup
|
||||
from dcs.vehicles import AirDefence
|
||||
@ -13,6 +13,10 @@ from gen.sam.aaa_flak import FlakGenerator
|
||||
from gen.sam.aaa_flak18 import Flak18Generator
|
||||
from gen.sam.aaa_ww2_ally_flak import AllyWW2FlakGenerator
|
||||
from gen.sam.aaa_zu23_insurgent import ZU23InsurgentGenerator
|
||||
from gen.sam.airdefensegroupgenerator import (
|
||||
AirDefenseGroupGenerator,
|
||||
AirDefenseRange,
|
||||
)
|
||||
from gen.sam.cold_war_flak import (
|
||||
ColdWarFlakGenerator,
|
||||
EarlyColdWarFlakGenerator,
|
||||
@ -30,7 +34,6 @@ from gen.sam.ewrs import (
|
||||
TallRackGenerator,
|
||||
)
|
||||
from gen.sam.freya_ewr import FreyaGenerator
|
||||
from gen.sam.airdefensegroupgenerator import AirDefenseGroupGenerator
|
||||
from gen.sam.group_generator import GroupGenerator
|
||||
from gen.sam.sam_avenger import AvengerGenerator
|
||||
from gen.sam.sam_chaparral import ChaparralGenerator
|
||||
@ -98,17 +101,6 @@ SAM_MAP: Dict[str, Type[AirDefenseGroupGenerator]] = {
|
||||
"AllyWW2FlakGenerator": AllyWW2FlakGenerator
|
||||
}
|
||||
|
||||
#: Used to fill the long-range required SAM locations in the campaign.
|
||||
LONG_RANGE_SAMS = {
|
||||
"SA10Generator",
|
||||
"PatriotGenerator",
|
||||
"Tier2SA10Generator",
|
||||
"Tier3SA10Generator",
|
||||
}
|
||||
|
||||
#: Used to fill the medium-range required SAM location in the campaign.
|
||||
MEDIUM_RANGE_SAMS = SAM_MAP.keys() - LONG_RANGE_SAMS
|
||||
|
||||
|
||||
SAM_PRICES = {
|
||||
AirDefence.SAM_Hawk_PCP: 35,
|
||||
@ -159,16 +151,12 @@ EWR_MAP = {
|
||||
|
||||
|
||||
def get_faction_possible_sams_generator(
|
||||
faction: Faction,
|
||||
filter_names: Optional[Iterable[str]] = None
|
||||
) -> List[Type[GroupGenerator]]:
|
||||
faction: Faction) -> List[Type[AirDefenseGroupGenerator]]:
|
||||
"""
|
||||
Return the list of possible SAM generator for the given faction
|
||||
:param faction: Faction name to search units for
|
||||
:param filter_names: Optional list of names to filter allowed SAMs by.
|
||||
"""
|
||||
return [SAM_MAP[s] for s in faction.sams if
|
||||
filter_names is None or s in filter_names]
|
||||
return [SAM_MAP[s] for s in faction.sams]
|
||||
|
||||
|
||||
def get_faction_possible_ewrs_generator(faction: Faction) -> List[Type[GroupGenerator]]:
|
||||
@ -179,23 +167,53 @@ def get_faction_possible_ewrs_generator(faction: Faction) -> List[Type[GroupGene
|
||||
return [EWR_MAP[s] for s in faction.ewrs]
|
||||
|
||||
|
||||
def _generate_anti_air_from(
|
||||
generators: Sequence[Type[AirDefenseGroupGenerator]], game: Game,
|
||||
ground_object: SamGroundObject) -> Optional[VehicleGroup]:
|
||||
if not generators:
|
||||
return None
|
||||
sam_generator_class = random.choice(generators)
|
||||
generator = sam_generator_class(game, ground_object)
|
||||
generator.generate()
|
||||
return generator.get_generated_group()
|
||||
|
||||
|
||||
def generate_anti_air_group(
|
||||
game: Game, ground_object: TheaterGroundObject, faction: Faction,
|
||||
filter_names: Optional[Iterable[str]] = None) -> Optional[VehicleGroup]:
|
||||
game: Game, ground_object: SamGroundObject, faction: Faction,
|
||||
ranges: Optional[Iterable[Set[AirDefenseRange]]] = None
|
||||
) -> Optional[VehicleGroup]:
|
||||
"""
|
||||
This generate a SAM group
|
||||
:param game: The Game.
|
||||
:param ground_object: The ground object which will own the sam group.
|
||||
:param faction: Owner faction.
|
||||
:param filter_names: Optional list of names to filter allowed SAMs by.
|
||||
:param ranges: Optional list of preferred ranges of the air defense to
|
||||
create. If None, any generator may be used. Otherwise generators
|
||||
matching the given ranges will be used in order of preference. For
|
||||
example, when given `[{Long, Medium}, {Short}]`, long and medium range
|
||||
air defenses will be tried first with no bias, and short range air
|
||||
defenses will be used if no long or medium range generators are
|
||||
available to the faction. If instead `[{Long}, {Medium}, {Short}]` had
|
||||
been used, long range systems would take precedence over medium range
|
||||
systems. If instead `[{Long, Medium, Short}]` had been used, all types
|
||||
would be considered with equal preference.
|
||||
:return: The generated group, or None if one could not be generated.
|
||||
"""
|
||||
generators = get_faction_possible_sams_generator(faction, filter_names)
|
||||
if len(generators) > 0:
|
||||
sam_generator_class = random.choice(generators)
|
||||
generator = sam_generator_class(game, ground_object)
|
||||
generator.generate()
|
||||
return generator.get_generated_group()
|
||||
generators = get_faction_possible_sams_generator(faction)
|
||||
if ranges is None:
|
||||
ranges = [{
|
||||
AirDefenseRange.Long,
|
||||
AirDefenseRange.Medium,
|
||||
AirDefenseRange.Short,
|
||||
}]
|
||||
|
||||
for range_options in ranges:
|
||||
generators_for_range = [g for g in generators if
|
||||
g.range() in range_options]
|
||||
group = _generate_anti_air_from(generators_for_range, game,
|
||||
ground_object)
|
||||
if group is not None:
|
||||
return group
|
||||
return None
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user