Skip to content

Commit

Permalink
Merge branch 'develop' into dependabot/npm_and_yarn/client/multi-7d5e…
Browse files Browse the repository at this point in the history
…57b41f
  • Loading branch information
zhexu14 authored Nov 11, 2024
2 parents ae51166 + fa41b00 commit f611620
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 18 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Saves from 11.x are not compatible with 12.0.0.
* **[Engine]** Support for DCS 2.9.9.2280.
* **[Campaign]** Flights are assigned different callsigns appropriate to the faction.
* **[Campaign]** Removed deprecated settings for generating persistent and invulnerable AWACs and tankers.
* **[Data]** Added ability to restrict weapons usage for a faction to a different year from the nominal weapon introduction year. Updated faction data to restrict more advanced missiles from Soviet client states during the cold war. Updated Egypt 2000 faction to restrict AIM-120 usage.
* **[Mission Generation]** Added option to skip combat when fast forwarding, which progresses fast forward as if the combat did not occur. Simplified fast forward settings by consolidating "Fast forward mission to first contact" and "Player missions interrupt fast forward" into a single setting and expanding options for "Auto-resolve combat during fast-forward (WIP)".
* **[Mods]** F/A-18 E/F/G Super Hornet mod version updated to 2.3.

Expand Down
19 changes: 12 additions & 7 deletions game/ato/loadouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from game.data.weapons import Pylon, Weapon, WeaponType
from game.dcs.aircrafttype import AircraftType
from game.factions.faction import Faction

from .flighttype import FlightType

if TYPE_CHECKING:
Expand Down Expand Up @@ -52,21 +54,24 @@ def _fallback_for(
weapon: Weapon,
pylon: Pylon,
date: datetime.date,
faction: Faction,
skip_types: Optional[Iterable[WeaponType]] = None,
) -> Optional[Weapon]:
if skip_types is None:
skip_types = set()
for fallback in weapon.fallbacks:
if not pylon.can_equip(fallback):
continue
if not fallback.available_on(date):
if not fallback.available_on(date, faction):
continue
if fallback.weapon_group.type in skip_types:
continue
return fallback
return None

def degrade_for_date(self, unit_type: AircraftType, date: datetime.date) -> Loadout:
def degrade_for_date(
self, unit_type: AircraftType, date: datetime.date, faction: Faction
) -> Loadout:
if self.date is not None and self.date <= date:
return Loadout(self.name, self.pylons, self.date, self.is_custom)

Expand All @@ -75,9 +80,9 @@ def degrade_for_date(self, unit_type: AircraftType, date: datetime.date) -> Load
if weapon is None:
del new_pylons[pylon_number]
continue
if not weapon.available_on(date):
if not weapon.available_on(date, faction):
pylon = Pylon.for_aircraft(unit_type, pylon_number)
fallback = self._fallback_for(weapon, pylon, date)
fallback = self._fallback_for(weapon, pylon, date, faction)
if fallback is None:
del new_pylons[pylon_number]
else:
Expand All @@ -89,11 +94,11 @@ def degrade_for_date(self, unit_type: AircraftType, date: datetime.date) -> Load
# If the loadout was chosen explicitly by the user, assume they know what
# they're doing. They may be coordinating buddy-lase.
if not loadout.is_custom:
loadout.replace_lgbs_if_no_tgp(unit_type, date)
loadout.replace_lgbs_if_no_tgp(unit_type, date, faction)
return loadout

def replace_lgbs_if_no_tgp(
self, unit_type: AircraftType, date: datetime.date
self, unit_type: AircraftType, date: datetime.date, faction: Faction
) -> None:
if self.has_weapon_of_type(WeaponType.TGP):
return
Expand All @@ -106,7 +111,7 @@ def replace_lgbs_if_no_tgp(
if weapon is not None and weapon.weapon_group.type is WeaponType.LGB:
pylon = Pylon.for_aircraft(unit_type, pylon_number)
fallback = self._fallback_for(
weapon, pylon, date, skip_types={WeaponType.LGB}
weapon, pylon, date, faction, skip_types={WeaponType.LGB}
)
if fallback is None:
del new_pylons[pylon_number]
Expand Down
2 changes: 2 additions & 0 deletions game/commander/packagebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,6 @@ def release_planned_aircraft(self) -> None:
"""Returns any planned flights to the inventory."""
flights = list(self.package.flights)
for flight in flights:
if flight.callsign is not None:
self.callsign_generator.release_callsign(flight.callsign)
self.package.remove_flight(flight)
30 changes: 28 additions & 2 deletions game/data/doctrine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

from pathlib import Path
import yaml
from typing import Any, ClassVar
from typing import Any, ClassVar, Optional

from dataclasses import dataclass
from datetime import timedelta

from dcs.task import OptAAMissileAttackRange
from game.data.units import UnitClass
from game.utils import Distance, feet, nautical_miles

Expand Down Expand Up @@ -115,6 +115,28 @@ def from_dict(data: dict[str, Any]) -> Cap:
)


@dataclass(frozen=True)
class Tactics:
#: Aircraft use countermeasures (chaff, flares)
use_countermeasures: bool

#: Air-to-air missile attack range options
air_to_air_missile_attack_range: Optional[OptAAMissileAttackRange.Values]

#: Air defence units evade ARMs
air_defence_evades_anti_radiation_missiles: bool

@staticmethod
def from_dict(data: dict[str, Any]) -> Tactics:
return Tactics(
use_countermeasures=data.get("use_countermeasures", True),
air_to_air_missile_attack_range=None,
air_defence_evades_anti_radiation_missiles=data.get(
"air_defence_evades_anti_radiation_missiles", False
),
)


@dataclass(frozen=True)
class Doctrine:
#: Name of the doctrine, used to assign a doctrine in a faction.
Expand Down Expand Up @@ -159,6 +181,9 @@ class Doctrine:
#: Doctrine for Fighter Sweep missions.
sweep: Sweep

#: Tactics options
tactics: Tactics

_by_name: ClassVar[dict[str, Doctrine]] = {}
_loaded: ClassVar[bool] = False

Expand Down Expand Up @@ -219,6 +244,7 @@ def load_all(cls) -> None:
cas=Cas.from_dict(data["cas"]),
cap=Cap.from_dict(data["cap"]),
sweep=Sweep.from_dict(data["sweep"]),
tactics=Tactics.from_dict(data.get("tactics", {})),
)
)
cls._loaded = True
12 changes: 9 additions & 3 deletions game/data/weapons.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from dcs.weapons_data import weapon_ids

from game.dcs.aircrafttype import AircraftType
from game.factions.faction import Faction


PydcsWeapon = Any
PydcsWeaponAssignment = tuple[int, PydcsWeapon]
Expand Down Expand Up @@ -77,8 +79,12 @@ def _load_all(cls) -> None:
WeaponGroup.load_all()
cls._loaded = True

def available_on(self, date: datetime.date) -> bool:
def available_on(self, date: datetime.date, faction: Faction) -> bool:
introduction_year = self.weapon_group.introduction_year
if self.weapon_group.name in faction.weapons_introduction_year_overrides:
introduction_year = faction.weapons_introduction_year_overrides[
self.weapon_group.name
]
if introduction_year is None:
return True
return date >= datetime.date(introduction_year, 1, 1)
Expand Down Expand Up @@ -243,9 +249,9 @@ def equip(self, unit: FlyingUnit, weapon: Weapon) -> None:
def make_pydcs_assignment(self, weapon: Weapon) -> PydcsWeaponAssignment:
return self.number, weapon.pydcs_data

def available_on(self, date: datetime.date) -> Iterator[Weapon]:
def available_on(self, date: datetime.date, faction: Faction) -> Iterator[Weapon]:
for weapon in self.allowed:
if weapon.available_on(date):
if weapon.available_on(date, faction):
yield weapon

@classmethod
Expand Down
9 changes: 9 additions & 0 deletions game/factions/faction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import itertools
import logging
from dataclasses import dataclass, field
import datetime
from functools import cached_property
from typing import Any, Dict, Iterator, List, Optional, TYPE_CHECKING, Type

Expand Down Expand Up @@ -118,6 +119,10 @@ class Faction:
#: both will use it.
unrestricted_satnav: bool = False

#: Overrides default weapons introduction years for faction. Maps names of
#: weapons groups to their introduction years.
weapons_introduction_year_overrides: Dict[str, int] = field(default_factory=dict)

def has_access_to_dcs_type(self, unit_type: Type[DcsUnitType]) -> bool:
# Vehicle and Ship Units
if any(unit_type == u.dcs_unit_type for u in self.accessible_units):
Expand Down Expand Up @@ -262,6 +267,10 @@ def from_dict(cls: Type[Faction], json: Dict[str, Any]) -> Faction:

faction.unrestricted_satnav = json.get("unrestricted_satnav", False)

faction.weapons_introduction_year_overrides = json.get(
"weapons_introduction_year_overrides", {}
)

return faction

@property
Expand Down
6 changes: 5 additions & 1 deletion game/missiongenerator/aircraft/flightgroupconfigurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,11 @@ def setup_payload(self, unit: FlyingUnit, member: FlightMember) -> None:

loadout = member.loadout
if self.game.settings.restrict_weapons_by_date:
loadout = loadout.degrade_for_date(self.flight.unit_type, self.game.date)
loadout = loadout.degrade_for_date(
self.flight.unit_type,
self.game.date,
self.flight.squadron.coalition.faction,
)

for pylon_number, weapon in loadout.pylons.items():
if weapon is None:
Expand Down
10 changes: 8 additions & 2 deletions qt_ui/windows/mission/flight/payload/QPylonEditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ def __init__(

self.addItem("None", None)
if self.game.settings.restrict_weapons_by_date:
weapons = pylon.available_on(self.game.date)
weapons = pylon.available_on(
self.game.date, flight.squadron.coalition.faction
)
else:
weapons = pylon.allowed
allowed = sorted(weapons, key=operator.attrgetter("name"))
Expand Down Expand Up @@ -68,7 +70,11 @@ def weapon_from_loadout(self, loadout: Loadout) -> Optional[Weapon]:

def matching_weapon_name(self, loadout: Loadout) -> str:
if self.game.settings.restrict_weapons_by_date:
loadout = loadout.degrade_for_date(self.flight.unit_type, self.game.date)
loadout = loadout.degrade_for_date(
self.flight.unit_type,
self.game.date,
self.flight.squadron.coalition.faction,
)
weapon = self.weapon_from_loadout(loadout)
if weapon is None:
return "None"
Expand Down
5 changes: 4 additions & 1 deletion resources/doctrines/coldwar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ helicopter:
combat_altitude_ft_agl: 200
rendezvous_altitude_ft_agl: 1500
air_assault_nav_altitude_ft_agl: 1500

tactics:
use_countermeasures: true
air_defence_evades_anti_radiation_missiles: false
air_to_air_missile_attack_range: ~
4 changes: 4 additions & 0 deletions resources/doctrines/modern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ helicopter:
combat_altitude_ft_agl: 200
rendezvous_altitude_ft_agl: 1500
air_assault_nav_altitude_ft_agl: 1500
tactics:
use_countermeasures: true
air_defence_evades_anti_radiation_missiles: false
air_to_air_missile_attack_range: ~
4 changes: 4 additions & 0 deletions resources/doctrines/ww2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ helicopter:
combat_altitude_ft_agl: 200
rendezvous_altitude_ft_agl: 1500
air_assault_nav_altitude_ft_agl: 1500
tactics:
use_countermeasures: true
air_defence_evades_anti_radiation_missiles: false
air_to_air_missile_attack_range: ~
4 changes: 4 additions & 0 deletions resources/factions/egypt_1973.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ air_defense_units:
- ZSU-57-2 'Sparka'
has_jtac: false
doctrine: coldwar
weapons_introduction_year_overrides:
R-3R - AAM, radar guided: 1980
R-60 x 2: 1980
R-60: 1980
5 changes: 5 additions & 0 deletions resources/factions/egypt_2000.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,8 @@ air_defense_units:
- ZSU-57-2 'Sparka'
has_jtac: true
jtac_unit: MQ-9 Reaper
weapons_introduction_year_overrides:
AIM-120B: 2050
2xAIM-120B: 2050
AIM-120C: 2050
2xAIM-120C: 2050
6 changes: 5 additions & 1 deletion resources/factions/nva_1970.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ air_defense_units:
- ZU-23 on Ural-375
- ZSU-23-4 Shilka
has_jtac: "false"
doctrine: "coldwar"
doctrine: "coldwar"
weapons_introduction_year_overrides:
R-3R - AAM, radar guided: 1980
R-60 x 2: 1980
R-60: 1980
4 changes: 4 additions & 0 deletions resources/factions/syria_1967.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,7 @@ helicopter_carrier_names: []
requirements: {}
carrier_names: []
doctrine: coldwar
weapons_introduction_year_overrides:
R-3R - AAM, radar guided: 1980
R-60 x 2: 1980
R-60: 1980
4 changes: 4 additions & 0 deletions resources/factions/syria_1967_with_ww2_weapons.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ carrier_names: []
requirements:
WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/
doctrine: coldwar
weapons_introduction_year_overrides:
R-3R - AAM, radar guided: 1980
R-60 x 2: 1980
R-60: 1980
4 changes: 4 additions & 0 deletions resources/factions/syria_1973.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@ helicopter_carrier_names: []
requirements: {}
carrier_names: []
doctrine: coldwar
weapons_introduction_year_overrides:
R-3R - AAM, radar guided: 1980
R-60 x 2: 1980
R-60: 1980
1 change: 1 addition & 0 deletions resources/weapons/a2a-missiles/AIM-7E.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ clsids:
- "{LAU-115 - AIM-7E}"
- "{SHOULDER AIM-7E}"
- "{BELLY AIM-7E}"
- "{HB_F4E_AIM-7E}"
2 changes: 1 addition & 1 deletion resources/weapons/a2a-missiles/AIM-7F.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: AIM-7F
year: 1976
fallback: AIM-7E
fallback: AIM-7E-2
clsids:
- "{SHOULDER AIM-7F}"
- "{BELLY AIM-7F}"
Expand Down

0 comments on commit f611620

Please sign in to comment.