mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
* Updated Irondome support to IDF Assets Pack V1.1, which includes the David's Sling. * Added an Israel 2017 faction with the David's Sling. * IDF Assets Pack air defence presets and assets are now correctly removed from the faction when the mod is disabled. * Removed the Iron Dome mod rocket launchers: - "9M22U - 122mm Grad" - "9M27F - 229mm Uragan" - "9M55F - 300mm Smerch" These were added to the Iron Dome Mod V1.2 in order for the radar to recognize them and be able to intercept them (these are limitations of DCS), so new rockets were added. However, they don't exist in the IDF Assets Pack. * IronDome to IDF-Assets migration --------- Co-authored-by: Raffson <Raffson@users.noreply.github.com>
151 lines
5.4 KiB
Python
151 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from collections import defaultdict
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any, ClassVar, Iterator, Optional, Type
|
|
|
|
from dcs.unittype import VehicleType
|
|
from dcs.vehicles import vehicle_map
|
|
|
|
from game.data.units import UnitClass
|
|
from game.dcs.unittype import UnitType
|
|
|
|
|
|
@dataclass
|
|
class SkynetProperties:
|
|
can_engage_harm: Optional[str] = None
|
|
can_engage_air_weapon: Optional[str] = None
|
|
go_live_range_in_percent: Optional[str] = None
|
|
engagement_zone: Optional[str] = None
|
|
autonomous_behaviour: Optional[str] = None
|
|
harm_detection_chance: Optional[str] = None
|
|
|
|
@classmethod
|
|
def from_data(cls, data: dict[str, Any]) -> SkynetProperties:
|
|
props = SkynetProperties()
|
|
if "can_engage_harm" in data:
|
|
props.can_engage_harm = str(data["can_engage_harm"]).lower()
|
|
if "can_engage_air_weapon" in data:
|
|
props.can_engage_air_weapon = str(data["can_engage_air_weapon"]).lower()
|
|
if "go_live_range_in_percent" in data:
|
|
props.go_live_range_in_percent = str(data["go_live_range_in_percent"])
|
|
if "engagement_zone" in data:
|
|
props.engagement_zone = str(data["engagement_zone"])
|
|
if "autonomous_behaviour" in data:
|
|
props.autonomous_behaviour = str(data["autonomous_behaviour"])
|
|
if "harm_detection_chance" in data:
|
|
props.harm_detection_chance = str(data["harm_detection_chance"])
|
|
return props
|
|
|
|
def to_dict(self) -> dict[str, str]:
|
|
properties: dict[str, str] = {}
|
|
for key, value in self.__dict__.items():
|
|
if value is not None:
|
|
properties[key] = value
|
|
return properties
|
|
|
|
def __hash__(self) -> int:
|
|
return hash(id(self))
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GroundUnitType(UnitType[Type[VehicleType]]):
|
|
spawn_weight: int
|
|
skynet_properties: SkynetProperties
|
|
|
|
# Defines if we should place the ground unit with an inverted heading.
|
|
# Some units like few Launchers have to be placed backwards to be able to fire.
|
|
reversed_heading: bool = False
|
|
|
|
_by_name: ClassVar[dict[str, GroundUnitType]] = {}
|
|
_by_unit_type: ClassVar[
|
|
dict[type[VehicleType], list[GroundUnitType]]
|
|
] = defaultdict(list)
|
|
|
|
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
# Save compat: the `name` field has been renamed `variant_id`.
|
|
if "name" in state:
|
|
state["variant_id"] = state.pop("name")
|
|
|
|
# iron-dome migration to IDF assets
|
|
if state["variant_id"] in [
|
|
"(IDF Mods Project) BM-21 Grad 122mm",
|
|
"(IDF Mods Project) Urgan BM-27 220mm",
|
|
"(IDF Mods Project) 9A52 Smerch CM 300mm",
|
|
]:
|
|
state["variant_id"] = "M109A6 Paladin"
|
|
elif state["variant_id"] == "Iron Dome ELM-2048 MMR":
|
|
state["variant_id"] = "ELM-2084MMR AD Rotating Mode"
|
|
|
|
# Update any existing models with new data on load.
|
|
updated = GroundUnitType.named(state["variant_id"])
|
|
state.update(updated.__dict__)
|
|
self.__dict__.update(state)
|
|
|
|
@classmethod
|
|
def register(cls, unit_type: GroundUnitType) -> None:
|
|
cls._by_name[unit_type.variant_id] = unit_type
|
|
cls._by_unit_type[unit_type.dcs_unit_type].append(unit_type)
|
|
|
|
@classmethod
|
|
def named(cls, name: str) -> GroundUnitType:
|
|
if not cls._loaded:
|
|
cls._load_all()
|
|
return cls._by_name[name]
|
|
|
|
@classmethod
|
|
def for_dcs_type(cls, dcs_unit_type: Type[VehicleType]) -> Iterator[GroundUnitType]:
|
|
if not cls._loaded:
|
|
cls._load_all()
|
|
yield from cls._by_unit_type[dcs_unit_type]
|
|
|
|
@staticmethod
|
|
def each_dcs_type() -> Iterator[Type[VehicleType]]:
|
|
yield from vehicle_map.values()
|
|
|
|
@classmethod
|
|
def _data_directory(cls) -> Path:
|
|
return Path("resources/units/ground_units")
|
|
|
|
@classmethod
|
|
def _variant_from_dict(
|
|
cls, vehicle: Type[VehicleType], variant_id: str, data: dict[str, Any]
|
|
) -> GroundUnitType:
|
|
try:
|
|
introduction = data["introduced"]
|
|
if introduction is None:
|
|
introduction = "N/A"
|
|
except KeyError:
|
|
introduction = "No data."
|
|
|
|
class_name = data.get("class")
|
|
if class_name is None:
|
|
logging.warning(f"{vehicle.id} has no class")
|
|
unit_class = UnitClass.UNKNOWN
|
|
else:
|
|
unit_class = UnitClass(class_name)
|
|
|
|
display_name = data.get("display_name", variant_id)
|
|
return GroundUnitType(
|
|
dcs_unit_type=vehicle,
|
|
unit_class=unit_class,
|
|
spawn_weight=data.get("spawn_weight", 0),
|
|
variant_id=variant_id,
|
|
display_name=display_name,
|
|
description=data.get(
|
|
"description",
|
|
f"No data. <a href=\"https://google.com/search?q=DCS+{display_name.replace(' ', '+')}\"><span style=\"color:#FFFFFF\">Google {display_name}</span></a>",
|
|
),
|
|
year_introduced=introduction,
|
|
country_of_origin=data.get("origin", "No data."),
|
|
manufacturer=data.get("manufacturer", "No data."),
|
|
role=data.get("role", "No data."),
|
|
price=data.get("price", 1),
|
|
skynet_properties=SkynetProperties.from_data(
|
|
data.get("skynet_properties", {})
|
|
),
|
|
reversed_heading=data.get("reversed_heading", False),
|
|
)
|