Add logic for specification of ground_units in campaign yaml file

Resolves #22
This commit is contained in:
Raffson 2023-02-12 21:24:21 +01:00
parent 34b9d8c334
commit d9967bda8f
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
7 changed files with 65 additions and 3 deletions

View File

@ -23,6 +23,7 @@
* **[UI]** Configurable LINK4 for Carriers.
* **[Kneeboard]** Show package information in Support page
* **[Campaign Design]** Ability to define designated CTLD zones for Control Points (Airbases & FOBs/FARPs)
* **[Campaign Design]** Ability to define preset groups for specific TGOs, given the preset group is accessible for the faction and the task matches.
## Fixes
* **[UI]** Removed deprecated options

View File

@ -19,6 +19,7 @@ from game.theater.iadsnetwork.iadsnetwork import IadsNetwork
from game.theater.theaterloader import TheaterLoader
from game.version import CAMPAIGN_FORMAT_VERSION
from .campaignairwingconfig import CampaignAirWingConfig
from .campaigngroundconfig import TgoConfig
from .mizcampaignloader import MizCampaignLoader
PERF_FRIENDLY = 0
@ -137,6 +138,13 @@ class Campaign:
return CampaignAirWingConfig({})
return CampaignAirWingConfig.from_campaign_data(squadron_data, theater)
def load_ground_forces_config(self) -> TgoConfig:
ground_forces = self.data.get("ground_forces", {})
if not ground_forces:
logging.warning(f"Campaign {self.name} does not define any squadrons")
return TgoConfig({})
return TgoConfig.from_campaign_data(ground_forces)
@property
def is_out_of_date(self) -> bool:
"""Returns True if this campaign is not up to date with the latest format.

View File

@ -0,0 +1,25 @@
from __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass
from typing import Iterator, Optional
from game.armedforces.forcegroup import ForceGroup
@dataclass(frozen=True)
class TgoConfig:
by_original_name: dict[str, ForceGroup]
def __iter__(self) -> Iterator[str]:
return self.by_original_name.__iter__()
def __getitem__(self, name: str) -> Optional[ForceGroup]:
return self.by_original_name.get(name)
@classmethod
def from_campaign_data(cls, data: dict[str, str]) -> TgoConfig:
by_original_name: dict[str, ForceGroup] = defaultdict()
for tgo_name, force_group in data.items():
by_original_name[tgo_name] = ForceGroup.from_preset_group(force_group)
return TgoConfig(by_original_name)

View File

@ -4,7 +4,7 @@ import logging
import random
from dataclasses import dataclass
from datetime import datetime, time
from typing import List
from typing import List, Optional
import dcs.statics
@ -30,6 +30,7 @@ from .theatergroup import IadsGroundGroup, IadsRole, SceneryUnit, TheaterGroup
from ..armedforces.armedforces import ArmedForces
from ..armedforces.forcegroup import ForceGroup
from ..campaignloader.campaignairwingconfig import CampaignAirWingConfig
from ..campaignloader.campaigngroundconfig import TgoConfig
from ..data.groups import GroupTask
from ..profiling import logged_duration
from ..settings import Settings
@ -47,6 +48,7 @@ class GeneratorSettings:
no_lha: bool
no_player_navy: bool
no_enemy_navy: bool
tgo_config: TgoConfig
@dataclass
@ -295,9 +297,31 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
self.generate_missile_sites()
self.generate_coastal_sites()
def get_unit_group_for_task(
self, position: PresetLocation, task: GroupTask
) -> Optional[ForceGroup]:
tgo_config = self.generator_settings.tgo_config
fg = tgo_config[position.original_name]
valid_fg = (
fg
and task in fg.tasks
and all([u in self.faction.accessible_units for u in fg.units])
)
if valid_fg:
unit_group = fg
assert fg
self.armed_forces.add_or_update_force_group(fg)
else:
if fg and not valid_fg:
logging.warning(
f"Override in ground_forces failed for {fg} at {position.original_name}"
)
unit_group = self.armed_forces.random_group_for_task(task)
return unit_group
def generate_armor_groups(self) -> None:
for position in self.control_point.preset_locations.armor_groups:
unit_group = self.armed_forces.random_group_for_task(GroupTask.BASE_DEFENSE)
unit_group = self.get_unit_group_for_task(position, GroupTask.BASE_DEFENSE)
if not unit_group:
logging.error(f"{self.faction_name} has no ForceGroup for Armor")
return
@ -351,7 +375,7 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
def generate_aa_at(self, location: PresetLocation, tasks: list[GroupTask]) -> None:
for task in tasks:
unit_group = self.armed_forces.random_group_for_task(task)
unit_group = self.get_unit_group_for_task(location, task)
if unit_group:
# Only take next (smaller) aa_range when no template available for the
# most requested range. Otherwise break the loop and continue

View File

@ -176,5 +176,7 @@ VERSION = _build_version_string()
#:
#: Version 10.6
#: * Designated CTLD zones for ControlPoints (Airbases & FOBs/FARPs)
#: * 'ground_forces' in yaml file to specify preset groups for TGOs,
#: given the group is available for the faction and the task matches
CAMPAIGN_FORMAT_VERSION = (10, 6)

View File

@ -318,6 +318,7 @@ def create_game(
no_lha=False,
no_player_navy=False,
no_enemy_navy=False,
tgo_config=campaign.load_ground_forces_config(),
),
ModSettings(
a4_skyhawk=False,

View File

@ -172,6 +172,7 @@ class NewGameWizard(QtWidgets.QWizard):
no_lha=self.field("no_lha"),
no_player_navy=self.field("no_player_navy"),
no_enemy_navy=self.field("no_enemy_navy"),
tgo_config=campaign.load_ground_forces_config(),
)
mod_settings = ModSettings(
a4_skyhawk=self.field("a4_skyhawk"),