reworked the skynet group name generation

- added information about the role of the aa site
- moved handling of ground name from tgo to the sam generator to make the tgo cleaner
- adjusted the skynet-config lua to the changes
This commit is contained in:
RndName 2021-07-01 16:00:04 +02:00 committed by Dan Albert
parent 20839853b7
commit de443fa3f0
11 changed files with 97 additions and 35 deletions

View File

@ -13,13 +13,14 @@ Saves from 4.0.0 are compatible with 4.0.1.
## Features/Improvements ## Features/Improvements
* **[Plugins]** Increased time JTAC Autolase messages stay visible on the UI. * **[Plugins]** Increased time JTAC Autolase messages stay visible on the UI.
* **[Mission Generation]** Improvements for better support of the Skynet Plugin and long range SAMs are now acting as EWR
* **[UI]** Added ability to take notes and have those notes appear as a kneeboard page. * **[UI]** Added ability to take notes and have those notes appear as a kneeboard page.
* **[UI]** Hovering over the weather information now dispalys the cloud base (meters and feet). * **[UI]** Hovering over the weather information now dispalys the cloud base (meters and feet).
* **[UI]** Google search link added to unit information when there is no information provided. * **[UI]** Google search link added to unit information when there is no information provided.
## Fixes ## Fixes
* **[UI]** Statistics window tick marks are now always integers. * **[UI]** Statistics window tick marks are now always integers.
* **[Mission Generation]** The lua data for other plugins is now generated correctly
* **[Flight Planning]** Fixed potential issue with angles > 360° or < 0° being generated when summing two angles. * **[Flight Planning]** Fixed potential issue with angles > 360° or < 0° being generated when summing two angles.
# 4.0.0 # 4.0.0

View File

@ -483,7 +483,7 @@ class Game:
self.current_unit_id += 1 self.current_unit_id += 1
return self.current_unit_id return self.current_unit_id
def next_group_id(self): def next_group_id(self) -> int:
""" """
Next unit id for pre-generated units Next unit id for pre-generated units
""" """

View File

@ -460,9 +460,9 @@ class CoastalSiteGroundObject(TheaterGroundObject):
return False return False
# TODO: Differentiate types. # The SamGroundObject represents all type of AA
# This type gets used both for AA sites (SAM, AAA, or SHORAD). These should each # The TGO can have multiple types of units (AAA,SAM,Support...)
# be split into their own types. # Differentiation can be made during generation with the airdefensegroupgenerator
class SamGroundObject(TheaterGroundObject): class SamGroundObject(TheaterGroundObject):
def __init__( def __init__(
self, self,
@ -481,18 +481,6 @@ class SamGroundObject(TheaterGroundObject):
dcs_identifier="AA", dcs_identifier="AA",
sea_object=False, sea_object=False,
) )
# Set by the SAM unit generator if the generated group is compatible
# with Skynet.
self.skynet_capable = False
@property
def group_name(self) -> str:
if self.skynet_capable:
# Prefix the group names of SAM sites with the side color so Skynet
# can find them.
return f"{self.faction_color}|SAM|{self.group_id}"
else:
return super().group_name
def mission_types(self, for_player: bool) -> Iterator[FlightType]: def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType from gen.flights.flight import FlightType

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from enum import Enum from enum import Enum
from typing import Iterator, List from typing import Iterator, List
@ -9,11 +11,31 @@ from game.theater.theatergroundobject import SamGroundObject
from gen.sam.group_generator import GroupGenerator from gen.sam.group_generator import GroupGenerator
class SkynetRole(Enum):
#: A radar SAM that should be controlled by Skynet.
Sam = "Sam"
#: A radar SAM that should be controlled and used as an EWR by Skynet.
SamAsEwr = "SamAsEwr"
#: An air defense unit that should be used as point defense by Skynet.
PointDefense = "PD"
#: All other types of groups that might be present in a SAM TGO. This includes
#: SHORADS, AAA, supply trucks, etc. Anything that shouldn't be controlled by Skynet
#: should use this role.
NoSkynetBehavior = "NoSkynetBehavior"
class AirDefenseRange(Enum): class AirDefenseRange(Enum):
AAA = "AAA" AAA = ("AAA", SkynetRole.NoSkynetBehavior)
Short = "short" Short = ("short", SkynetRole.NoSkynetBehavior)
Medium = "medium" Medium = ("medium", SkynetRole.Sam)
Long = "long" Long = ("long", SkynetRole.SamAsEwr)
def __init__(self, description: str, default_role: SkynetRole) -> None:
self.range_name = description
self.default_role = default_role
class AirDefenseGroupGenerator(GroupGenerator, ABC): class AirDefenseGroupGenerator(GroupGenerator, ABC):
@ -24,18 +46,32 @@ class AirDefenseGroupGenerator(GroupGenerator, ABC):
price: int price: int
def __init__(self, game: Game, ground_object: SamGroundObject) -> None: def __init__(self, game: Game, ground_object: SamGroundObject) -> None:
ground_object.skynet_capable = True
super().__init__(game, ground_object) super().__init__(game, ground_object)
self.vg.name = self.group_name_for_role(self.vg.id, self.primary_group_role())
self.auxiliary_groups: List[VehicleGroup] = [] self.auxiliary_groups: List[VehicleGroup] = []
def add_auxiliary_group(self, name_suffix: str) -> VehicleGroup: def add_auxiliary_group(self, role: SkynetRole) -> VehicleGroup:
group = VehicleGroup( gid = self.game.next_group_id()
self.game.next_group_id(), "|".join([self.go.group_name, name_suffix]) group = VehicleGroup(gid, self.group_name_for_role(gid, role))
)
self.auxiliary_groups.append(group) self.auxiliary_groups.append(group)
return group return group
def group_name_for_role(self, gid: int, role: SkynetRole) -> str:
if role is SkynetRole.NoSkynetBehavior:
# No special naming needed for air defense groups that don't participate in
# Skynet.
return f"{self.go.group_name}|{gid}"
# For those that do, we need a prefix of `$COLOR|SAM| so our Skynet config picks
# the group up at all. To support PDs we need to append the ID of the TGO so
# that the PD will know which group it's protecting. We then append the role so
# our config knows what to do with the group, and finally the GID of *this*
# group to ensure no conflicts.
return "|".join(
[self.go.faction_color, "SAM", str(self.go.group_id), role.value, str(gid)]
)
def get_generated_group(self) -> VehicleGroup: def get_generated_group(self) -> VehicleGroup:
raise RuntimeError( raise RuntimeError(
"Deprecated call to AirDefenseGroupGenerator.get_generated_group " "Deprecated call to AirDefenseGroupGenerator.get_generated_group "
@ -52,3 +88,7 @@ class AirDefenseGroupGenerator(GroupGenerator, ABC):
@abstractmethod @abstractmethod
def range(cls) -> AirDefenseRange: def range(cls) -> AirDefenseRange:
... ...
@classmethod
def primary_group_role(cls) -> SkynetRole:
return cls.range().default_role

View File

@ -6,6 +6,7 @@ from dcs.vehicles import AirDefence
from gen.sam.airdefensegroupgenerator import ( from gen.sam.airdefensegroupgenerator import (
AirDefenseRange, AirDefenseRange,
AirDefenseGroupGenerator, AirDefenseGroupGenerator,
SkynetRole,
) )
@ -41,7 +42,7 @@ class HawkGenerator(AirDefenseGroupGenerator):
) )
# Triple A for close range defense # Triple A for close range defense
aa_group = self.add_auxiliary_group("AA") aa_group = self.add_auxiliary_group(SkynetRole.NoSkynetBehavior)
self.add_unit_to_group( self.add_unit_to_group(
aa_group, aa_group,
AirDefence.Vulcan, AirDefence.Vulcan,

View File

@ -6,6 +6,7 @@ from dcs.vehicles import AirDefence
from gen.sam.airdefensegroupgenerator import ( from gen.sam.airdefensegroupgenerator import (
AirDefenseRange, AirDefenseRange,
AirDefenseGroupGenerator, AirDefenseGroupGenerator,
SkynetRole,
) )
@ -34,7 +35,7 @@ class HQ7Generator(AirDefenseGroupGenerator):
) )
# Triple A for close range defense # Triple A for close range defense
aa_group = self.add_auxiliary_group("AA") aa_group = self.add_auxiliary_group(SkynetRole.NoSkynetBehavior)
self.add_unit_to_group( self.add_unit_to_group(
aa_group, aa_group,
AirDefence.Ural_375_ZU_23, AirDefence.Ural_375_ZU_23,

View File

@ -6,6 +6,7 @@ from dcs.vehicles import AirDefence
from gen.sam.airdefensegroupgenerator import ( from gen.sam.airdefensegroupgenerator import (
AirDefenseRange, AirDefenseRange,
AirDefenseGroupGenerator, AirDefenseGroupGenerator,
SkynetRole,
) )
@ -69,7 +70,7 @@ class PatriotGenerator(AirDefenseGroupGenerator):
) )
# Short range protection for high value site # Short range protection for high value site
aa_group = self.add_auxiliary_group("AA") aa_group = self.add_auxiliary_group(SkynetRole.NoSkynetBehavior)
num_launchers = random.randint(3, 4) num_launchers = random.randint(3, 4)
positions = self.get_circular_position( positions = self.get_circular_position(
num_launchers, launcher_distance=200, coverage=360 num_launchers, launcher_distance=200, coverage=360

View File

@ -5,6 +5,7 @@ from dcs.vehicles import AirDefence
from gen.sam.airdefensegroupgenerator import ( from gen.sam.airdefensegroupgenerator import (
AirDefenseRange, AirDefenseRange,
AirDefenseGroupGenerator, AirDefenseGroupGenerator,
SkynetRole,
) )
@ -49,3 +50,7 @@ class RapierGenerator(AirDefenseGroupGenerator):
@classmethod @classmethod
def range(cls) -> AirDefenseRange: def range(cls) -> AirDefenseRange:
return AirDefenseRange.Short return AirDefenseRange.Short
@classmethod
def primary_group_role(cls) -> SkynetRole:
return SkynetRole.Sam

View File

@ -3,6 +3,7 @@ from dcs.vehicles import AirDefence, Unarmed
from gen.sam.airdefensegroupgenerator import ( from gen.sam.airdefensegroupgenerator import (
AirDefenseRange, AirDefenseRange,
AirDefenseGroupGenerator, AirDefenseGroupGenerator,
SkynetRole,
) )
@ -40,3 +41,7 @@ class RolandGenerator(AirDefenseGroupGenerator):
@classmethod @classmethod
def range(cls) -> AirDefenseRange: def range(cls) -> AirDefenseRange:
return AirDefenseRange.Short return AirDefenseRange.Short
@classmethod
def primary_group_role(cls) -> SkynetRole:
return SkynetRole.Sam

View File

@ -8,6 +8,7 @@ from game.theater import SamGroundObject
from gen.sam.airdefensegroupgenerator import ( from gen.sam.airdefensegroupgenerator import (
AirDefenseRange, AirDefenseRange,
AirDefenseGroupGenerator, AirDefenseGroupGenerator,
SkynetRole,
) )
from pydcs_extensions.highdigitsams import highdigitsams from pydcs_extensions.highdigitsams import highdigitsams
@ -76,7 +77,7 @@ class SA10Generator(AirDefenseGroupGenerator):
def generate_defensive_groups(self) -> None: def generate_defensive_groups(self) -> None:
# AAA for defending against close targets. # AAA for defending against close targets.
aa_group = self.add_auxiliary_group("AA") aa_group = self.add_auxiliary_group(SkynetRole.NoSkynetBehavior)
num_launchers = random.randint(6, 8) num_launchers = random.randint(6, 8)
positions = self.get_circular_position( positions = self.get_circular_position(
num_launchers, launcher_distance=210, coverage=360 num_launchers, launcher_distance=210, coverage=360
@ -101,7 +102,7 @@ class Tier2SA10Generator(SA10Generator):
super().generate_defensive_groups() super().generate_defensive_groups()
# SA-15 for both shorter range targets and point defense. # SA-15 for both shorter range targets and point defense.
pd_group = self.add_auxiliary_group("PD") pd_group = self.add_auxiliary_group(SkynetRole.PointDefense)
num_launchers = random.randint(2, 4) num_launchers = random.randint(2, 4)
positions = self.get_circular_position( positions = self.get_circular_position(
num_launchers, launcher_distance=140, coverage=360 num_launchers, launcher_distance=140, coverage=360
@ -123,7 +124,7 @@ class Tier3SA10Generator(SA10Generator):
def generate_defensive_groups(self) -> None: def generate_defensive_groups(self) -> None:
# AAA for defending against close targets. # AAA for defending against close targets.
aa_group = self.add_auxiliary_group("AA") aa_group = self.add_auxiliary_group(SkynetRole.NoSkynetBehavior)
num_launchers = random.randint(6, 8) num_launchers = random.randint(6, 8)
positions = self.get_circular_position( positions = self.get_circular_position(
num_launchers, launcher_distance=210, coverage=360 num_launchers, launcher_distance=210, coverage=360
@ -138,7 +139,7 @@ class Tier3SA10Generator(SA10Generator):
) )
# SA-15 for both shorter range targets and point defense. # SA-15 for both shorter range targets and point defense.
pd_group = self.add_auxiliary_group("PD") pd_group = self.add_auxiliary_group(SkynetRole.PointDefense)
num_launchers = random.randint(2, 4) num_launchers = random.randint(2, 4)
positions = self.get_circular_position( positions = self.get_circular_position(
num_launchers, launcher_distance=140, coverage=360 num_launchers, launcher_distance=140, coverage=360

View File

@ -93,9 +93,28 @@ if dcsLiberation and SkynetIADS then
for i = 1, #sites do for i = 1, #sites do
local site = sites[i] local site = sites[i]
local name = site:getDCSName() local name = site:getDCSName()
if string.match(name, "|SamAsEwr|") then
env.info(string.format("DCSLiberation|Skynet-IADS plugin - %s now acting as EWR", name))
site:setActAsEW(true)
end
if not string.match(name, "|PD") then if not string.match(name, "|PD") then
env.info(string.format("DCSLiberation|Skynet-IADS plugin - Checking %s for PD", name)) -- Name is prefixed with `$color|SAM|$tgoid`. For pre-4.1 generated
local pds = iads:getSAMSitesByPrefix(name .. "|PD") -- campaigns that's the full name of the primary SAM and any PD are just
-- that name suffixed with |PD.
--
-- For 4.1+ generated campaigns the name will be
-- `$color|SAM|$tgoid|$role|$gid`, so we need to replace the content
-- beginning with the third pipe with `|PD` to find our PDs.
local first_pipe = string.find(name, "|")
local second_pipe = string.find(name, "|", first_pipe + 1)
local third_pipe = string.find(name, "|", second_pipe + 1)
local pd_prefix = name .. "|PD"
if third_pipe ~= nil then
pd_prefix = string.sub(name, 1, third_pipe) .. "PD"
end
local pds = iads:getSAMSitesByPrefix(pd_prefix)
for j = 1, #pds do for j = 1, #pds do
pd = pds[j] pd = pds[j]
env.info(string.format("DCSLiberation|Skynet-IADS plugin - Adding %s as PD for %s", pd:getDCSName(), name)) env.info(string.format("DCSLiberation|Skynet-IADS plugin - Adding %s as PD for %s", pd:getDCSName(), name))