mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Compare commits
36 Commits
pydcs-2-7-
...
2.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de2e5f861b | ||
|
|
b27a7fc71b | ||
|
|
5861ce6146 | ||
|
|
c732ed556f | ||
|
|
be1a75e520 | ||
|
|
c41d10c581 | ||
|
|
157a59e3c4 | ||
|
|
d24c65c3aa | ||
|
|
d4d441ff9b | ||
|
|
f43fb1223f | ||
|
|
3db275414d | ||
|
|
6e0ff6c805 | ||
|
|
9c359efbff | ||
|
|
c5cc1ea8e8 | ||
|
|
afb6a33131 | ||
|
|
539a11f54d | ||
|
|
9324e549e6 | ||
|
|
c8f6b6df87 | ||
|
|
38f632097e | ||
|
|
e63743f537 | ||
|
|
ce13295cf0 | ||
|
|
23c02a3510 | ||
|
|
01ea7b9ee1 | ||
|
|
6fed1284a1 | ||
|
|
5574d849bd | ||
|
|
c2ce3a6992 | ||
|
|
b61d15fdf4 | ||
|
|
ad5cc83fb3 | ||
|
|
2f53edd775 | ||
|
|
923459c88b | ||
|
|
1192d26448 | ||
|
|
2d5e827417 | ||
|
|
a30d9276b8 | ||
|
|
0cd088122e | ||
|
|
b6f3467a89 | ||
|
|
52ce1a5959 |
24
changelog.md
24
changelog.md
@@ -4,25 +4,35 @@ Saves from 2.4 are not compatible with 2.5.
|
||||
|
||||
## Features/Improvements
|
||||
|
||||
* **[Flight Planner]** (WIP) Added AEW&C missions. (by siKruger)
|
||||
* **[Kneeboard]** Added dark kneeboard option (by GvonH)
|
||||
* **[Engine]** DCS 2.7 Support
|
||||
* **[UI]** Improved FOB menu, added a custom banner, and do not display aircraft recruitment menu
|
||||
* **[Flight Planner]** Added AEW&C missions. (by siKruger)
|
||||
* **[Kneeboard]** Added dark kneeboard option (by GvonH)
|
||||
* **[Campaigns]** Multiple EWR sites may now be generated, and EWR sites may be generated outside bases (by SnappyComebacks)
|
||||
* **[Mission Generation]** Cloudy and rainy (but not thunderstorm) weather will use the cloud presets from DCS 2.7.
|
||||
* **[Plugins]** Added LotATC export plugin (by drsoran)
|
||||
* **[Plugins]** Added Splash Damage Plugin (by Wheelijoe)
|
||||
* **[Loadouts]** Replaced Litening with ATFLIR for all default F/A-18C loadouts.
|
||||
|
||||
## Fixes
|
||||
|
||||
* **[Flight Planner]** Front lines now project threat zones, so TARCAP/escorts will not be pruned for flights near the front. Packages may also route around the front line when practical.
|
||||
* **[Flight Planner]** Fixed error when planning BAI at SAMs with dead subgroups.
|
||||
* **[Flight Planner]** Mig-19 was not allowed for CAS roles fixed
|
||||
* **[Flight Planner]** Increased size of navigation planning area to avoid plannign failures with distant waypoints.
|
||||
* **[Flight Planner]** Fixed UI refresh when unchecking the "default loadout" box in the loadout editor.
|
||||
* **[Objective names]** Fixed typos in objective name : ARMADILLLO -> ARMADILLO (by SnappyComebacks)
|
||||
* **[Payloads]** F-86 Sabre was missing a custom payload
|
||||
* **[Payloads]** Added GAR-8 period restrictions (by Mustang-25)
|
||||
* **[Campaign]** Date now progresses.
|
||||
|
||||
# 2.4.4
|
||||
|
||||
## Fixes
|
||||
|
||||
* **[Campaign]** Added game over message when a coalition runs out of functioning airbases.
|
||||
* **[Mission Generation]** Fixed "invalid face handle" error in kneeboard generation that occurred on some machines.
|
||||
|
||||
## Regressions
|
||||
|
||||
* **[Mod Support]** Stopped support for 2.5.5 Rafale Mode, and removed factions that were using it
|
||||
* **[Mod Support]** Su-57 mod support might be out of date
|
||||
|
||||
# 2.4.3
|
||||
|
||||
## Features/Improvements
|
||||
|
||||
@@ -18,4 +18,5 @@ AAA_UNITS = [
|
||||
AirDefence.AAA_SP_Kdo_G_40,
|
||||
AirDefence.AAA_8_8cm_Flak_41,
|
||||
AirDefence.AAA_40mm_Bofors,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
]
|
||||
|
||||
@@ -523,6 +523,7 @@ PRICES = {
|
||||
Artillery.MLRS_9A52_Smerch_HE_300mm: 40,
|
||||
Artillery.Mortar_2B11_120mm: 4,
|
||||
Artillery.SPH_Dana_vz77_152mm: 26,
|
||||
Artillery.PLZ_05: 25,
|
||||
Unarmed.LUV_UAZ_469_Jeep: 3,
|
||||
Unarmed.Truck_Ural_375: 3,
|
||||
Infantry.Infantry_M4: 1,
|
||||
@@ -631,6 +632,7 @@ PRICES = {
|
||||
AirDefence.AAA_8_8cm_Flak_41: 10,
|
||||
AirDefence.EWR_FuMG_401_Freya_LZ: 25,
|
||||
AirDefence.AAA_40mm_Bofors: 8,
|
||||
AirDefence.AAA_S_60_57mm: 8,
|
||||
AirDefence.AAA_M1_37mm: 7,
|
||||
AirDefence.AAA_M45_Quadmount_HB_12_7mm: 4,
|
||||
AirDefence.AAA_QF_3_7: 10,
|
||||
@@ -974,6 +976,7 @@ UNIT_BY_TASK = {
|
||||
Artillery.MLRS_BM_27_Uragan_220mm,
|
||||
Artillery.MLRS_9A52_Smerch_HE_300mm,
|
||||
Artillery.SPH_Dana_vz77_152mm,
|
||||
Artillery.PLZ_05,
|
||||
Artillery.SPG_M12_GMC_155mm,
|
||||
Artillery.SPG_Sturmpanzer_IV_Brummbar,
|
||||
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
|
||||
@@ -997,6 +1000,7 @@ UNIT_BY_TASK = {
|
||||
AirDefence.AAA_8_8cm_Flak_37,
|
||||
AirDefence.AAA_8_8cm_Flak_41,
|
||||
AirDefence.AAA_40mm_Bofors,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
AirDefence.AAA_M1_37mm,
|
||||
AirDefence.AAA_QF_3_7,
|
||||
frenchpack.DIM__TOYOTA_BLUE,
|
||||
|
||||
@@ -446,6 +446,8 @@ class Operation:
|
||||
"AWACs": {},
|
||||
"JTACs": {},
|
||||
"TargetPoints": {},
|
||||
"RedAA": {},
|
||||
"BlueAA": {},
|
||||
} # type: ignore
|
||||
|
||||
for tanker in airsupportgen.air_support.tankers:
|
||||
@@ -503,6 +505,26 @@ class Operation:
|
||||
},
|
||||
}
|
||||
|
||||
for cp in cls.game.theater.controlpoints:
|
||||
for ground_object in cp.ground_objects:
|
||||
if ground_object.might_have_aa and not ground_object.is_dead:
|
||||
for g in ground_object.groups:
|
||||
threat_range = ground_object.threat_range(g)
|
||||
|
||||
if not threat_range:
|
||||
continue
|
||||
|
||||
faction = "BlueAA" if cp.captured else "RedAA"
|
||||
|
||||
luaData[faction][g.name] = {
|
||||
"name": ground_object.name,
|
||||
"range": threat_range.meters,
|
||||
"position": {
|
||||
"x": ground_object.position.x,
|
||||
"y": ground_object.position.y,
|
||||
},
|
||||
}
|
||||
|
||||
# set a LUA table with data from Liberation that we want to set
|
||||
# at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function
|
||||
# later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts
|
||||
@@ -595,7 +617,33 @@ class Operation:
|
||||
-- list the aircraft carriers generated by Liberation
|
||||
-- dcsLiberation.Carriers = {}
|
||||
|
||||
-- later, we'll add more data to the table
|
||||
-- list the Red AA generated by Liberation
|
||||
dcsLiberation.RedAA = {
|
||||
"""
|
||||
for key in luaData["RedAA"]:
|
||||
data = luaData["RedAA"][key]
|
||||
name = data["name"]
|
||||
radius = data["range"]
|
||||
positionX = data["position"]["x"]
|
||||
positionY = data["position"]["y"]
|
||||
lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n"
|
||||
lua += "}"
|
||||
|
||||
lua += """
|
||||
|
||||
-- list the Blue AA generated by Liberation
|
||||
dcsLiberation.BlueAA = {
|
||||
"""
|
||||
for key in luaData["BlueAA"]:
|
||||
data = luaData["BlueAA"][key]
|
||||
name = data["name"]
|
||||
radius = data["range"]
|
||||
positionX = data["position"]["x"]
|
||||
positionY = data["position"]["y"]
|
||||
lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n"
|
||||
lua += "}"
|
||||
|
||||
lua += """
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -118,6 +118,8 @@ class MizCampaignLoader:
|
||||
AirDefence.SAM_SA_3_S_125_Goa_LN.id,
|
||||
}
|
||||
|
||||
REQUIRED_EWR_UNIT_TYPE = AirDefence.EWR_1L13.id
|
||||
|
||||
BASE_DEFENSE_RADIUS = nautical_miles(2)
|
||||
|
||||
def __init__(self, miz: Path, theater: ConflictTheater) -> None:
|
||||
@@ -247,6 +249,12 @@ class MizCampaignLoader:
|
||||
if group.units[0].type in self.REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def required_ewrs(self) -> Iterator[VehicleGroup]:
|
||||
for group in self.red.vehicle_group:
|
||||
if group.units[0].type in self.REQUIRED_EWR_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def helipads(self) -> Iterator[StaticGroup]:
|
||||
for group in self.blue.static_group:
|
||||
@@ -356,9 +364,14 @@ class MizCampaignLoader:
|
||||
|
||||
for group in self.ewrs:
|
||||
closest, distance = self.objective_info(group)
|
||||
closest.preset_locations.ewrs.append(
|
||||
PointWithHeading.from_point(group.position, group.units[0].heading)
|
||||
)
|
||||
if distance < self.BASE_DEFENSE_RADIUS:
|
||||
closest.preset_locations.ewrs.append(
|
||||
PointWithHeading.from_point(group.position, group.units[0].heading)
|
||||
)
|
||||
else:
|
||||
closest.preset_locations.ewrs.append(
|
||||
PointWithHeading.from_point(group.position, group.units[0].heading)
|
||||
)
|
||||
|
||||
for group in self.offshore_strike_targets:
|
||||
closest, distance = self.objective_info(group)
|
||||
@@ -396,6 +409,12 @@ class MizCampaignLoader:
|
||||
PointWithHeading.from_point(group.position, group.units[0].heading)
|
||||
)
|
||||
|
||||
for group in self.required_ewrs:
|
||||
closest, distance = self.objective_info(group)
|
||||
closest.preset_locations.required_ewrs.append(
|
||||
PointWithHeading.from_point(group.position, group.units[0].heading)
|
||||
)
|
||||
|
||||
for group in self.helipads:
|
||||
closest, distance = self.objective_info(group)
|
||||
closest.helipads.append(
|
||||
|
||||
@@ -107,6 +107,9 @@ class PresetLocations:
|
||||
#: Locations of medium range SAMs which should always be spawned.
|
||||
required_medium_range_sams: List[PointWithHeading] = field(default_factory=list)
|
||||
|
||||
#: Locations of EWRs which should always be spawned.
|
||||
required_ewrs: List[PointWithHeading] = field(default_factory=list)
|
||||
|
||||
@staticmethod
|
||||
def _random_from(points: List[PointWithHeading]) -> Optional[PointWithHeading]:
|
||||
"""Finds, removes, and returns a random position from the given list."""
|
||||
|
||||
@@ -37,10 +37,8 @@ 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 (
|
||||
generate_anti_air_group,
|
||||
generate_ewr_group,
|
||||
)
|
||||
from gen.sam.sam_group_generator import generate_anti_air_group
|
||||
from gen.sam.ewr_group_generator import generate_ewr_group
|
||||
from . import (
|
||||
ConflictTheater,
|
||||
ControlPoint,
|
||||
@@ -464,7 +462,11 @@ class BaseDefenseGenerator:
|
||||
group_id = self.game.next_group_id()
|
||||
|
||||
g = EwrGroundObject(
|
||||
namegen.random_objective_name(), group_id, position, self.control_point
|
||||
namegen.random_objective_name(),
|
||||
group_id,
|
||||
position,
|
||||
self.control_point,
|
||||
True,
|
||||
)
|
||||
|
||||
group = generate_ewr_group(self.game, g, self.faction)
|
||||
@@ -609,6 +611,7 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
def generate_ground_points(self) -> None:
|
||||
"""Generate ground objects and AA sites for the control point."""
|
||||
skip_sams = self.generate_required_aa()
|
||||
skip_ewrs = self.generate_required_ewr()
|
||||
|
||||
if self.control_point.is_global:
|
||||
return
|
||||
@@ -625,6 +628,12 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
skip_sams -= 1
|
||||
else:
|
||||
self.generate_aa_site()
|
||||
# 1 in 4 additional objectives are EWR.
|
||||
elif random.randint(0, 3) == 0:
|
||||
if skip_ewrs > 0:
|
||||
skip_ewrs -= 1
|
||||
else:
|
||||
self.generate_ewr_site()
|
||||
else:
|
||||
self.generate_ground_point()
|
||||
|
||||
@@ -656,6 +665,17 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
presets.required_medium_range_sams
|
||||
)
|
||||
|
||||
def generate_required_ewr(self) -> int:
|
||||
"""Generates the EWR sites that are required by the campaign.
|
||||
|
||||
Returns:
|
||||
The number of EWR sites that were generated.
|
||||
"""
|
||||
presets = self.control_point.preset_locations
|
||||
for position in presets.required_ewrs:
|
||||
self.generate_ewr_at(position)
|
||||
return len(presets.required_ewrs)
|
||||
|
||||
def generate_ground_point(self) -> None:
|
||||
try:
|
||||
category = random.choice(self.faction.building_set)
|
||||
@@ -733,6 +753,33 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
g.groups = groups
|
||||
self.control_point.connected_objectives.append(g)
|
||||
|
||||
def generate_ewr_site(self) -> None:
|
||||
position = self.location_finder.location_for(LocationType.Ewr)
|
||||
if position is None:
|
||||
return
|
||||
self.generate_ewr_at(position)
|
||||
|
||||
def generate_ewr_at(self, position: Point) -> None:
|
||||
group_id = self.game.next_group_id()
|
||||
|
||||
g = EwrGroundObject(
|
||||
namegen.random_objective_name(),
|
||||
group_id,
|
||||
position,
|
||||
self.control_point,
|
||||
for_airbase=False,
|
||||
)
|
||||
group = generate_ewr_group(self.game, g, self.faction)
|
||||
if group is None:
|
||||
logging.error(
|
||||
"Could not generate ewr group for %s at %s",
|
||||
g.name,
|
||||
self.control_point,
|
||||
)
|
||||
return
|
||||
g.groups = [group]
|
||||
self.control_point.connected_objectives.append(g)
|
||||
|
||||
def generate_missile_sites(self) -> None:
|
||||
for i in range(self.faction.missiles_group_count):
|
||||
self.generate_missile_site()
|
||||
|
||||
@@ -442,7 +442,12 @@ class VehicleGroupGroundObject(BaseDefenseGroundObject):
|
||||
|
||||
class EwrGroundObject(BaseDefenseGroundObject):
|
||||
def __init__(
|
||||
self, name: str, group_id: int, position: Point, control_point: ControlPoint
|
||||
self,
|
||||
name: str,
|
||||
group_id: int,
|
||||
position: Point,
|
||||
control_point: ControlPoint,
|
||||
for_airbase: bool,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
name=name,
|
||||
@@ -452,7 +457,7 @@ class EwrGroundObject(BaseDefenseGroundObject):
|
||||
heading=0,
|
||||
control_point=control_point,
|
||||
dcs_identifier="EWR",
|
||||
airbase_group=True,
|
||||
airbase_group=for_airbase,
|
||||
sea_object=False,
|
||||
)
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ from __future__ import annotations
|
||||
import datetime
|
||||
import logging
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from dcs.weather import Weather as PydcsWeather, Wind
|
||||
from dcs.cloud_presets import Clouds as PydcsClouds
|
||||
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
|
||||
|
||||
from game.settings import Settings
|
||||
from game.utils import Distance, meters
|
||||
@@ -36,6 +37,23 @@ class Clouds:
|
||||
density: int
|
||||
thickness: int
|
||||
precipitation: PydcsWeather.Preceptions
|
||||
preset: Optional[CloudPreset] = field(default=None)
|
||||
|
||||
@classmethod
|
||||
def random_preset(cls, rain: bool) -> Clouds:
|
||||
clouds = (p.value for p in PydcsClouds)
|
||||
if rain:
|
||||
presets = [p for p in clouds if "Rain" in p.name]
|
||||
else:
|
||||
presets = [p for p in clouds if "Rain" not in p.name]
|
||||
preset = random.choice(presets)
|
||||
return Clouds(
|
||||
base=random.randint(preset.min_base, preset.max_base),
|
||||
density=0,
|
||||
thickness=0,
|
||||
precipitation=PydcsWeather.Preceptions.None_,
|
||||
preset=preset,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -101,12 +119,11 @@ class ClearSkies(Weather):
|
||||
|
||||
class Cloudy(Weather):
|
||||
def generate_clouds(self) -> Optional[Clouds]:
|
||||
return Clouds(
|
||||
base=self.random_cloud_base(),
|
||||
density=random.randint(1, 8),
|
||||
thickness=self.random_cloud_thickness(),
|
||||
precipitation=PydcsWeather.Preceptions.None_,
|
||||
)
|
||||
return Clouds.random_preset(rain=False)
|
||||
|
||||
def generate_fog(self) -> Optional[Fog]:
|
||||
# DCS 2.7 says to not use fog with the cloud presets.
|
||||
return None
|
||||
|
||||
def generate_wind(self) -> WindConditions:
|
||||
return self.random_wind(0, 4)
|
||||
@@ -114,12 +131,11 @@ class Cloudy(Weather):
|
||||
|
||||
class Raining(Weather):
|
||||
def generate_clouds(self) -> Optional[Clouds]:
|
||||
return Clouds(
|
||||
base=self.random_cloud_base(),
|
||||
density=random.randint(5, 8),
|
||||
thickness=self.random_cloud_thickness(),
|
||||
precipitation=PydcsWeather.Preceptions.Rain,
|
||||
)
|
||||
return Clouds.random_preset(rain=True)
|
||||
|
||||
def generate_fog(self) -> Optional[Fog]:
|
||||
# DCS 2.7 says to not use fog with the cloud presets.
|
||||
return None
|
||||
|
||||
def generate_wind(self) -> WindConditions:
|
||||
return self.random_wind(0, 6)
|
||||
|
||||
239
gen/airfields.py
239
gen/airfields.py
@@ -383,8 +383,8 @@ AIRFIELD_DATA = {
|
||||
"31": ("IVZ", MHz(108, 750)),
|
||||
},
|
||||
),
|
||||
# TODO : PERSIAN GULF MAP
|
||||
"Liwa Airbase": AirfieldData(
|
||||
# PERSIAN GULF MAP
|
||||
"Liwa AFB": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMLW",
|
||||
elevation=400,
|
||||
@@ -394,7 +394,7 @@ AIRFIELD_DATA = {
|
||||
vor=("OMLW", MHz(117, 400)),
|
||||
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(119, 300), MHz(250, 950)),
|
||||
),
|
||||
"Al Dhafra AB": AirfieldData(
|
||||
"Al Dhafra AFB": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMAM",
|
||||
elevation=52,
|
||||
@@ -402,50 +402,50 @@ AIRFIELD_DATA = {
|
||||
tacan=TacanChannel(96, TacanBand.X),
|
||||
tacan_callsign="MA",
|
||||
vor=("MA", MHz(114, 900)),
|
||||
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(126, 500), MHz(251, 000)),
|
||||
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(126, 500), MHz(251, 100)),
|
||||
ils={
|
||||
"13": ("MMA", MHz(111, 100)),
|
||||
"31": ("IMA", MHz(109, 100)),
|
||||
},
|
||||
),
|
||||
"Al-Bateen Airport": AirfieldData(
|
||||
"Al-Bateen": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMAD",
|
||||
elevation=11,
|
||||
runway_length=6808,
|
||||
vor=("ALB", MHz(114, 0)),
|
||||
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(119, 900), MHz(250, 550)),
|
||||
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 900), MHz(250, 600)),
|
||||
),
|
||||
"Sas Al Nakheel Airport": AirfieldData(
|
||||
"Sas Al Nakheel": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMNK",
|
||||
elevation=9,
|
||||
runway_length=5387,
|
||||
vor=("SAS", MHz(128, 930)),
|
||||
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(128, 900), MHz(250, 450)),
|
||||
atc=AtcData(MHz(4, 0), MHz(38, 900), MHz(128, 900), MHz(250, 450)),
|
||||
),
|
||||
"Abu Dhabi International Airport": AirfieldData(
|
||||
"Abu Dhabi Intl": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMAA",
|
||||
elevation=91,
|
||||
runway_length=12817,
|
||||
vor=("ADV", MHz(114, 250)),
|
||||
atc=AtcData(MHz(4, 000), MHz(38, 900), MHz(119, 200), MHz(250, 500)),
|
||||
atc=AtcData(MHz(4, 50), MHz(39, 0), MHz(119, 200), MHz(250, 550)),
|
||||
),
|
||||
"Al Ain International Airport": AirfieldData(
|
||||
"Al Ain Intl": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMAL",
|
||||
elevation=813,
|
||||
runway_length=11267,
|
||||
vor=("ALN", MHz(112, 600)),
|
||||
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 850), MHz(250, 650)),
|
||||
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(119, 850), MHz(250, 700)),
|
||||
),
|
||||
"Al Maktoum Intl": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMDW",
|
||||
elevation=123,
|
||||
runway_length=11500,
|
||||
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(118, 650), MHz(251, 100)),
|
||||
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(118, 600), MHz(251, 200)),
|
||||
ils={
|
||||
"30": ("IJWA", MHz(109, 750)),
|
||||
"12": ("IMA", MHz(111, 750)),
|
||||
@@ -458,7 +458,7 @@ AIRFIELD_DATA = {
|
||||
runway_length=11865,
|
||||
tacan=TacanChannel(99, TacanBand.X),
|
||||
tacan_callsign="MIN",
|
||||
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(121, 800), MHz(250, 100)),
|
||||
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(118, 550), MHz(250, 100)),
|
||||
ils={
|
||||
"27": ("IMNR", MHz(110, 750)),
|
||||
"9": ("IMNW", MHz(110, 700)),
|
||||
@@ -469,7 +469,7 @@ AIRFIELD_DATA = {
|
||||
icao="OMDB",
|
||||
elevation=16,
|
||||
runway_length=11018,
|
||||
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(118, 750), MHz(251, 50)),
|
||||
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(118, 750), MHz(251, 150)),
|
||||
ils={
|
||||
"30": ("IDBL", MHz(110, 900)),
|
||||
"12": ("IDBR", MHz(110, 100)),
|
||||
@@ -480,7 +480,7 @@ AIRFIELD_DATA = {
|
||||
icao="OMSJ",
|
||||
elevation=98,
|
||||
runway_length=10535,
|
||||
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(118, 600), MHz(252, 200)),
|
||||
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(118, 600), MHz(250, 200)),
|
||||
ils={
|
||||
"30": ("ISHW", MHz(111, 950)),
|
||||
"12": ("ISRE", MHz(108, 550)),
|
||||
@@ -492,18 +492,18 @@ AIRFIELD_DATA = {
|
||||
elevation=60,
|
||||
runway_length=9437,
|
||||
vor=("FJV", MHz(113, 800)),
|
||||
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(124, 600), MHz(251, 150)),
|
||||
atc=AtcData(MHz(4, 375), MHz(39, 650), MHz(124, 600), MHz(251, 250)),
|
||||
ils={
|
||||
"29": ("IFJR", MHz(111, 500)),
|
||||
},
|
||||
),
|
||||
"Ras AL Khaimah": AirfieldData(
|
||||
"Ras Al Khaimah Intl": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OMRK",
|
||||
elevation=70,
|
||||
runway_length=8406,
|
||||
vor=("OMRK", MHz(113, 600)),
|
||||
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(121, 600), MHz(250, 800)),
|
||||
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(121, 600), MHz(250, 900)),
|
||||
),
|
||||
"Khasab": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
@@ -516,7 +516,11 @@ AIRFIELD_DATA = {
|
||||
},
|
||||
),
|
||||
"Sir Abu Nuayr": AirfieldData(
|
||||
theater="Persian Gulf", icao="OMSN", elevation=25, runway_length=2229
|
||||
theater="Persian Gulf",
|
||||
icao="OMSN",
|
||||
elevation=25,
|
||||
runway_length=2229,
|
||||
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(118, 0), MHz(250, 800)),
|
||||
),
|
||||
"Sirri Island": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
@@ -526,7 +530,7 @@ AIRFIELD_DATA = {
|
||||
vor=("SIR", MHz(113, 750)),
|
||||
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(135, 50), MHz(250, 250)),
|
||||
),
|
||||
"Abu Musa Island Airport": AirfieldData(
|
||||
"Abu Musa Island": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OIBA",
|
||||
elevation=16,
|
||||
@@ -555,13 +559,13 @@ AIRFIELD_DATA = {
|
||||
vor=("KHM", MHz(117, 100)),
|
||||
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(118, 50), MHz(250, 150)),
|
||||
),
|
||||
"Bandar-e-Jask airfield": AirfieldData(
|
||||
"Bandar-e-Jask": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OIZJ",
|
||||
elevation=26,
|
||||
runway_length=6842,
|
||||
vor=("KHM", MHz(116, 300)),
|
||||
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(118, 50), MHz(250, 150)),
|
||||
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(118, 150), MHz(250, 500)),
|
||||
),
|
||||
"Bandar Lengeh": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
@@ -569,26 +573,26 @@ AIRFIELD_DATA = {
|
||||
elevation=80,
|
||||
runway_length=7625,
|
||||
vor=("LEN", MHz(114, 800)),
|
||||
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 700), MHz(250, 950)),
|
||||
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(121, 700), MHz(251, 50)),
|
||||
),
|
||||
"Kish International Airport": AirfieldData(
|
||||
"Kish Intl": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OIBK",
|
||||
elevation=114,
|
||||
runway_length=10617,
|
||||
tacan=TacanChannel(112, TacanBand.X),
|
||||
tacan_callsign="KIH",
|
||||
atc=AtcData(MHz(4, 50), MHz(39, 000), MHz(121, 650), MHz(250, 600)),
|
||||
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(121, 650), MHz(250, 650)),
|
||||
),
|
||||
"Lavan Island Airport": AirfieldData(
|
||||
"Lavan Island": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OIBV",
|
||||
elevation=75,
|
||||
runway_length=8234,
|
||||
vor=("LVA", MHz(116, 850)),
|
||||
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(128, 550), MHz(250, 700)),
|
||||
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(128, 550), MHz(250, 750)),
|
||||
),
|
||||
"Lar Airbase": AirfieldData(
|
||||
"Lar": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OISL",
|
||||
elevation=2635,
|
||||
@@ -603,7 +607,7 @@ AIRFIELD_DATA = {
|
||||
runway_length=7300,
|
||||
tacan=TacanChannel(47, TacanBand.X),
|
||||
tacan_callsign="HDR",
|
||||
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(123, 150), MHz(251, 200)),
|
||||
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(123, 150), MHz(251, 300)),
|
||||
ils={
|
||||
"8": ("IBHD", MHz(108, 900)),
|
||||
},
|
||||
@@ -616,19 +620,19 @@ AIRFIELD_DATA = {
|
||||
tacan=TacanChannel(78, TacanBand.X),
|
||||
tacan_callsign="BND",
|
||||
vor=("BND", MHz(117, 200)),
|
||||
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(118, 100), MHz(250, 900)),
|
||||
atc=AtcData(MHz(4, 250), MHz(39, 401), MHz(118, 100), MHz(251, 0)),
|
||||
ils={
|
||||
"21": ("IBND", MHz(333, 800)),
|
||||
},
|
||||
),
|
||||
"Jiroft Airport": AirfieldData(
|
||||
"Jiroft": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OIKJ",
|
||||
elevation=2664,
|
||||
runway_length=9160,
|
||||
atc=AtcData(MHz(4, 125), MHz(39, 120), MHz(136, 0), MHz(250, 750)),
|
||||
),
|
||||
"Kerman Airport": AirfieldData(
|
||||
"Kerman": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OIKK",
|
||||
elevation=5746,
|
||||
@@ -636,9 +640,9 @@ AIRFIELD_DATA = {
|
||||
tacan=TacanChannel(97, TacanBand.X),
|
||||
tacan_callsign="KER",
|
||||
vor=("KER", MHz(112, 0)),
|
||||
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(118, 250), MHz(250, 300)),
|
||||
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 250), MHz(250, 300)),
|
||||
),
|
||||
"Shiraz International Airport": AirfieldData(
|
||||
"Shiraz Intl": AirfieldData(
|
||||
theater="Persian Gulf",
|
||||
icao="OISS",
|
||||
elevation=4878,
|
||||
@@ -646,7 +650,7 @@ AIRFIELD_DATA = {
|
||||
tacan=TacanChannel(94, TacanBand.X),
|
||||
tacan_callsign="SYZ1",
|
||||
vor=("SYZ", MHz(112, 0)),
|
||||
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(121, 900), MHz(250, 350)),
|
||||
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(121, 900), MHz(250, 350)),
|
||||
),
|
||||
# Syria Map
|
||||
"Adana Sakirpasa": AirfieldData(
|
||||
@@ -655,7 +659,7 @@ AIRFIELD_DATA = {
|
||||
elevation=55,
|
||||
runway_length=8115,
|
||||
vor=("ADA", MHz(112, 700)),
|
||||
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 100), MHz(250, 900)),
|
||||
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(121, 100), MHz(251, 0)),
|
||||
ils={
|
||||
"05": ("IADA", MHz(108, 700)),
|
||||
},
|
||||
@@ -668,7 +672,7 @@ AIRFIELD_DATA = {
|
||||
tacan=TacanChannel(21, TacanBand.X),
|
||||
tacan_callsign="DAN",
|
||||
vor=("DAN", MHz(108, 400)),
|
||||
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(129, 400), MHz(360, 100)),
|
||||
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(122, 100), MHz(360, 100)),
|
||||
ils={
|
||||
"50": ("IDAN", MHz(109, 300)),
|
||||
"23": ("DANM", MHz(111, 700)),
|
||||
@@ -679,7 +683,7 @@ AIRFIELD_DATA = {
|
||||
icao="OS71",
|
||||
elevation=1614,
|
||||
runway_length=4648,
|
||||
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(120, 600), MHz(250, 700)),
|
||||
atc=AtcData(MHz(4, 175), MHz(39, 250), MHz(120, 600), MHz(250, 800)),
|
||||
),
|
||||
"Hatay": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -687,7 +691,7 @@ AIRFIELD_DATA = {
|
||||
elevation=253,
|
||||
runway_length=9052,
|
||||
vor=("HTY", MHz(112, 500)),
|
||||
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(128, 500), MHz(250, 150)),
|
||||
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(128, 500), MHz(250, 250)),
|
||||
ils={
|
||||
"22": ("IHTY", MHz(108, 150)),
|
||||
"04": ("IHAT", MHz(108, 900)),
|
||||
@@ -698,25 +702,21 @@ AIRFIELD_DATA = {
|
||||
icao="OS66",
|
||||
elevation=1200,
|
||||
runway_length=6662,
|
||||
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(120, 500), MHz(251)),
|
||||
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(120, 500), MHz(251, 100)),
|
||||
),
|
||||
"Aleppo": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OSAP",
|
||||
elevation=1253,
|
||||
runway_length=8332,
|
||||
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(119, 100), MHz(250, 750)),
|
||||
ils={
|
||||
"50": ("IDAN", MHz(109, 300)),
|
||||
"23": ("DANM", MHz(111, 700)),
|
||||
},
|
||||
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(119, 100), MHz(250, 850)),
|
||||
),
|
||||
"Jirah": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS62",
|
||||
elevation=1170,
|
||||
runway_length=9090,
|
||||
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(118, 100), MHz(250, 200)),
|
||||
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 100), MHz(250, 300)),
|
||||
),
|
||||
"Taftanaz": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -729,14 +729,14 @@ AIRFIELD_DATA = {
|
||||
icao="OS59",
|
||||
elevation=1083,
|
||||
runway_length=9036,
|
||||
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(118, 500), MHz(251, 150)),
|
||||
atc=AtcData(MHz(4, 500), MHz(39, 900), MHz(122, 800), MHz(251, 450)),
|
||||
),
|
||||
"Abu al-Dahur": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS57",
|
||||
elevation=820,
|
||||
runway_length=8728,
|
||||
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(122, 200), MHz(250, 350)),
|
||||
atc=AtcData(MHz(4, 0), MHz(38, 900), MHz(122, 200), MHz(250, 450)),
|
||||
),
|
||||
"Bassel Al-Assad": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -744,7 +744,7 @@ AIRFIELD_DATA = {
|
||||
elevation=93,
|
||||
runway_length=7305,
|
||||
vor=("LTK", MHz(114, 800)),
|
||||
atc=AtcData(MHz(4), MHz(38, 900), MHz(118, 100), MHz(250, 450)),
|
||||
atc=AtcData(MHz(4, 50), MHz(39, 0), MHz(118, 100), MHz(250, 550)),
|
||||
ils={
|
||||
"17": ("IBA", MHz(109, 100)),
|
||||
},
|
||||
@@ -754,28 +754,28 @@ AIRFIELD_DATA = {
|
||||
icao="OS58",
|
||||
elevation=983,
|
||||
runway_length=7957,
|
||||
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(118, 50), MHz(250, 100)),
|
||||
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(118, 50), MHz(250, 200)),
|
||||
),
|
||||
"Rene Mouawad": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OLKA",
|
||||
elevation=14,
|
||||
runway_length=8614,
|
||||
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(129, 500), MHz(251, 100)),
|
||||
atc=AtcData(MHz(4, 375), MHz(39, 650), MHz(121, 0), MHz(251, 200)),
|
||||
),
|
||||
"Al Quasayr": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS70",
|
||||
elevation=1729,
|
||||
runway_length=8585,
|
||||
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(119, 200), MHz(251, 250)),
|
||||
atc=AtcData(MHz(4, 550), MHz(40, 0), MHz(119, 200), MHz(251, 550)),
|
||||
),
|
||||
"Palmyra": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OSPR",
|
||||
elevation=1267,
|
||||
runway_length=8704,
|
||||
atc=AtcData(MHz(4, 175), MHz(39, 250), MHz(121, 900), MHz(250, 800)),
|
||||
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 900), MHz(250, 900)),
|
||||
),
|
||||
"Wujah Al Hajar": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -783,14 +783,14 @@ AIRFIELD_DATA = {
|
||||
elevation=619,
|
||||
runway_length=4717,
|
||||
vor=("CAK", MHz(116, 200)),
|
||||
atc=AtcData(MHz(4, 425), MHz(39, 750), MHz(121, 500), MHz(251, 300)),
|
||||
atc=AtcData(MHz(4, 575), MHz(40, 50), MHz(121, 500), MHz(251, 600)),
|
||||
),
|
||||
"An Nasiriyah": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS64",
|
||||
elevation=2746,
|
||||
runway_length=8172,
|
||||
atc=AtcData(MHz(4, 450), MHz(39, 800), MHz(122, 300), MHz(251, 350)),
|
||||
atc=AtcData(MHz(4, 600), MHz(40, 100), MHz(122, 300), MHz(251, 650)),
|
||||
),
|
||||
"Rayak": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -798,7 +798,7 @@ AIRFIELD_DATA = {
|
||||
elevation=2934,
|
||||
runway_length=8699,
|
||||
vor=("HTY", MHz(124, 400)),
|
||||
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(124, 400), MHz(251, 50)),
|
||||
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(124, 400), MHz(251, 150)),
|
||||
),
|
||||
"Beirut-Rafic Hariri": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -806,7 +806,7 @@ AIRFIELD_DATA = {
|
||||
elevation=39,
|
||||
runway_length=9463,
|
||||
vor=("KAD", MHz(112, 600)),
|
||||
atc=AtcData(MHz(4, 475), MHz(39, 850), MHz(118, 900), MHz(251, 400)),
|
||||
atc=AtcData(MHz(4, 675), MHz(40, 250), MHz(118, 900), MHz(251, 800)),
|
||||
ils={
|
||||
"17": ("BIL", MHz(109, 500)),
|
||||
},
|
||||
@@ -816,32 +816,32 @@ AIRFIELD_DATA = {
|
||||
icao="OS61",
|
||||
elevation=2066,
|
||||
runway_length=8902,
|
||||
atc=AtcData(MHz(4, 550), MHz(40), MHz(120, 300), MHz(251, 550)),
|
||||
atc=AtcData(MHz(4, 750), MHz(40, 400), MHz(120, 300), MHz(251, 950)),
|
||||
),
|
||||
"Marj as Sultan North": AirfieldData(
|
||||
theater="Syria",
|
||||
elevation=2007,
|
||||
runway_length=268,
|
||||
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(122, 700), MHz(250, 500)),
|
||||
atc=AtcData(MHz(4, 75), MHz(38, 50), MHz(122, 700), MHz(250, 600)),
|
||||
),
|
||||
"Marj as Sultan South": AirfieldData(
|
||||
theater="Syria",
|
||||
elevation=2007,
|
||||
runway_length=166,
|
||||
atc=AtcData(MHz(4, 525), MHz(39, 950), MHz(122, 900), MHz(251, 500)),
|
||||
atc=AtcData(MHz(4, 725), MHz(40, 350), MHz(122, 900), MHz(251, 900)),
|
||||
),
|
||||
"Mezzeh": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS67",
|
||||
elevation=2355,
|
||||
runway_length=7522,
|
||||
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(120, 700), MHz(250, 650)),
|
||||
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(120, 700), MHz(250, 750)),
|
||||
),
|
||||
"Qabr as Sitt": AirfieldData(
|
||||
theater="Syria",
|
||||
elevation=2134,
|
||||
runway_length=489,
|
||||
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(122, 600), MHz(250, 850)),
|
||||
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(122, 600), MHz(250, 950)),
|
||||
),
|
||||
"Damascus": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -849,7 +849,7 @@ AIRFIELD_DATA = {
|
||||
elevation=2007,
|
||||
runway_length=11423,
|
||||
vor=("DAM", MHz(116)),
|
||||
atc=AtcData(MHz(4, 500), MHz(39, 900), MHz(118, 500), MHz(251, 450)),
|
||||
atc=AtcData(MHz(4, 700), MHz(40, 300), MHz(118, 500), MHz(251, 850)),
|
||||
ils={
|
||||
"24": ("IDA", MHz(109, 900)),
|
||||
},
|
||||
@@ -859,42 +859,42 @@ AIRFIELD_DATA = {
|
||||
icao="OS63",
|
||||
elevation=2160,
|
||||
runway_length=7576,
|
||||
atc=AtcData(MHz(4, 50), MHz(39), MHz(120, 800), MHz(250, 550)),
|
||||
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(120, 800), MHz(250, 6550)),
|
||||
),
|
||||
"Kiryat Shmona": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="LLKS",
|
||||
elevation=328,
|
||||
runway_length=3258,
|
||||
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(118, 400), MHz(250, 400)),
|
||||
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(118, 400), MHz(250, 500)),
|
||||
),
|
||||
"Khalkhalah": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS69",
|
||||
elevation=2337,
|
||||
runway_length=8248,
|
||||
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(122, 500), MHz(250, 250)),
|
||||
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(122, 500), MHz(250, 350)),
|
||||
),
|
||||
"Haifa": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="LLHA",
|
||||
elevation=19,
|
||||
runway_length=3253,
|
||||
atc=AtcData(MHz(3, 775), MHz(38, 450), MHz(127, 800), MHz(250, 50)),
|
||||
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(127, 800), MHz(250, 150)),
|
||||
),
|
||||
"Ramat David": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="LLRD",
|
||||
elevation=105,
|
||||
runway_length=7037,
|
||||
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(118, 600), MHz(250, 950)),
|
||||
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(118, 600), MHz(251, 50)),
|
||||
),
|
||||
"Megiddo": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="LLMG",
|
||||
elevation=180,
|
||||
runway_length=6098,
|
||||
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 900), MHz(250, 600)),
|
||||
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(119, 900), MHz(250, 700)),
|
||||
),
|
||||
"Eyn Shemer": AirfieldData(
|
||||
theater="Syria",
|
||||
@@ -908,7 +908,66 @@ AIRFIELD_DATA = {
|
||||
icao="OJMF",
|
||||
elevation=2204,
|
||||
runway_length=8595,
|
||||
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 300), MHz(250, 300)),
|
||||
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(118, 300), MHz(250, 400)),
|
||||
),
|
||||
"Tha'lah": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS60",
|
||||
elevation=2381,
|
||||
runway_length=8025,
|
||||
atc=AtcData(MHz(4, 650), MHz(40, 200), MHz(122, 400), MHz(251, 750)),
|
||||
),
|
||||
"Shayrat": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS60",
|
||||
elevation=2637,
|
||||
runway_length=8553,
|
||||
atc=AtcData(MHz(4, 450), MHz(39, 800), MHz(122, 200), MHz(251, 350)),
|
||||
),
|
||||
"Tiyas": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS72",
|
||||
elevation=1797,
|
||||
runway_length=9420,
|
||||
atc=AtcData(MHz(4, 525), MHz(39, 950), MHz(120, 500), MHz(251, 500)),
|
||||
),
|
||||
"Rosh Pina": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="LLIB",
|
||||
elevation=865,
|
||||
runway_length=2711,
|
||||
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(118, 450), MHz(251, 250)),
|
||||
),
|
||||
"Sayqal": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OS68",
|
||||
elevation=2273,
|
||||
runway_length=8536,
|
||||
atc=AtcData(MHz(4, 425), MHz(39, 750), MHz(120, 400), MHz(251, 300)),
|
||||
),
|
||||
"H4": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="OJHR",
|
||||
elevation=2257,
|
||||
runway_length=7179,
|
||||
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(120, 400), MHz(250, 100)),
|
||||
),
|
||||
"Naqoura": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="",
|
||||
elevation=378,
|
||||
runway_length=0,
|
||||
atc=AtcData(MHz(4, 625), MHz(40, 150), MHz(122, 000), MHz(251, 700)),
|
||||
),
|
||||
"Gaziantep": AirfieldData(
|
||||
theater="Syria",
|
||||
icao="LTAJ",
|
||||
elevation=2287,
|
||||
runway_length=8871,
|
||||
atc=AtcData(MHz(3, 775), MHz(38, 450), MHz(120, 100), MHz(250, 50)),
|
||||
ils={
|
||||
"28": ("IGNP", MHz(109, 10)),
|
||||
},
|
||||
),
|
||||
# NTTR
|
||||
"Mina Airport 3Q0": AirfieldData(
|
||||
@@ -1304,55 +1363,73 @@ AIRFIELD_DATA = {
|
||||
"Detling": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=623,
|
||||
runway_length=2557,
|
||||
atc=AtcData(MHz(3, 950), MHz(118, 400), MHz(38, 800), MHz(250, 400)),
|
||||
runway_length=3482,
|
||||
atc=AtcData(MHz(4, 50), MHz(118, 600), MHz(39, 0), MHz(250, 600)),
|
||||
),
|
||||
"High Halden": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=104,
|
||||
runway_length=3296,
|
||||
atc=AtcData(MHz(3, 750), MHz(118, 800), MHz(38, 400), MHz(250, 0)),
|
||||
atc=AtcData(MHz(3, 800), MHz(118, 100), MHz(38, 500), MHz(250, 100)),
|
||||
),
|
||||
"Lympne": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=351,
|
||||
runway_length=2548,
|
||||
atc=AtcData(MHz(3, 925), MHz(118, 350), MHz(38, 750), MHz(250, 350)),
|
||||
runway_length=3054,
|
||||
atc=AtcData(MHz(4, 25), MHz(118, 550), MHz(38, 950), MHz(250, 550)),
|
||||
),
|
||||
"Hawkinge": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=524,
|
||||
runway_length=3013,
|
||||
atc=AtcData(MHz(3, 900), MHz(118, 300), MHz(38, 700), MHz(250, 300)),
|
||||
atc=AtcData(MHz(4, 0), MHz(118, 500), MHz(38, 900), MHz(250, 500)),
|
||||
),
|
||||
"Manston": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=160,
|
||||
runway_length=8626,
|
||||
atc=AtcData(MHz(3, 875), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
|
||||
atc=AtcData(MHz(3, 975), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
|
||||
),
|
||||
"Dunkirk Mardyck": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=16,
|
||||
runway_length=1737,
|
||||
atc=AtcData(MHz(3, 850), MHz(118, 200), MHz(38, 600), MHz(250, 200)),
|
||||
atc=AtcData(MHz(3, 950), MHz(118, 450), MHz(38, 850), MHz(250, 450)),
|
||||
),
|
||||
"Saint Omer Longuenesse": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=219,
|
||||
runway_length=1929,
|
||||
atc=AtcData(MHz(3, 825), MHz(118, 150), MHz(38, 550), MHz(250, 150)),
|
||||
atc=AtcData(MHz(3, 925), MHz(118, 350), MHz(38, 750), MHz(250, 350)),
|
||||
),
|
||||
"Merville Calonne": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=52,
|
||||
runway_length=7580,
|
||||
atc=AtcData(MHz(3, 800), MHz(118, 100), MHz(38, 500), MHz(250, 100)),
|
||||
atc=AtcData(MHz(3, 900), MHz(118, 300), MHz(38, 700), MHz(250, 300)),
|
||||
),
|
||||
"Abbeville Drucat": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=183,
|
||||
runway_length=4726,
|
||||
atc=AtcData(MHz(3, 875), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
|
||||
),
|
||||
"Eastchurch": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=30,
|
||||
runway_length=2983,
|
||||
atc=AtcData(MHz(3, 775), MHz(118, 50), MHz(38, 450), MHz(250, 50)),
|
||||
),
|
||||
"Headcorn": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=114,
|
||||
runway_length=3680,
|
||||
atc=AtcData(MHz(3, 825), MHz(118, 150), MHz(38, 550), MHz(250, 150)),
|
||||
),
|
||||
"Biggin Hill": AirfieldData(
|
||||
theater="Channel",
|
||||
elevation=552,
|
||||
runway_length=3953,
|
||||
atc=AtcData(MHz(3, 850), MHz(118, 200), MHz(38, 600), MHz(250, 200)),
|
||||
),
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ class EnvironmentGenerator:
|
||||
self.mission.weather.clouds_thickness = clouds.thickness
|
||||
self.mission.weather.clouds_density = clouds.density
|
||||
self.mission.weather.clouds_iprecptns = clouds.precipitation
|
||||
self.mission.weather.clouds_preset = clouds.preset
|
||||
|
||||
def set_fog(self, fog: Optional[Fog]) -> None:
|
||||
if fog is None:
|
||||
|
||||
@@ -110,6 +110,7 @@ TYPE_ARTILLERY = [
|
||||
Artillery.MLRS_M270_227mm,
|
||||
Artillery.SPH_2S9_Nona_120mm_M,
|
||||
Artillery.SPH_Dana_vz77_152mm,
|
||||
Artillery.PLZ_05,
|
||||
Artillery.SPH_2S19_Msta_152mm,
|
||||
Artillery.MLRS_9A52_Smerch_CM_300mm,
|
||||
# WW2
|
||||
@@ -175,6 +176,7 @@ TYPE_SHORAD = [
|
||||
AirDefence.AAA_8_8cm_Flak_37,
|
||||
AirDefence.AAA_8_8cm_Flak_41,
|
||||
AirDefence.AAA_40mm_Bofors,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
AirDefence.AAA_M1_37mm,
|
||||
AirDefence.AAA_QF_3_7,
|
||||
]
|
||||
|
||||
@@ -68,7 +68,8 @@ class MizDataLocationFinder:
|
||||
for vehicle_group in m.country("Iran").vehicle_group:
|
||||
if (
|
||||
len(vehicle_group.units) > 0
|
||||
and vehicle_group.units[0].type == MissilesSS.AShM_SS_N_2_Silkworm.id
|
||||
and vehicle_group.units[0].type
|
||||
== MissilesSS.AShM_SS_N_2_Silkworm.id
|
||||
):
|
||||
antiship_locations.append(
|
||||
PresetLocation(
|
||||
|
||||
@@ -12,13 +12,13 @@ from gen.sam.group_generator import GroupGenerator
|
||||
class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
|
||||
"""
|
||||
This generator attempt to mimic an early cold-war era flak AAA site.
|
||||
The Flak 18 88mm is used as the main long range gun and 2 Bofors 40mm guns provide short range protection.
|
||||
The Flak 18 88mm is used as the main long range gun, S-60 is used as a mid range gun and 2 Bofors 40mm guns provide short range protection.
|
||||
|
||||
This does not include search lights and telemeter computer (Kdo.G 40) because these are paid units only available in WW2 asset pack
|
||||
"""
|
||||
|
||||
name = "Early Cold War Flak Site"
|
||||
price = 58
|
||||
price = 74
|
||||
|
||||
def generate(self):
|
||||
|
||||
@@ -37,22 +37,38 @@ class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
|
||||
self.heading,
|
||||
)
|
||||
|
||||
# Short range guns
|
||||
# Medium range guns
|
||||
self.add_unit(
|
||||
AirDefence.AAA_40mm_Bofors,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
"SHO#1",
|
||||
self.position.x - 40,
|
||||
self.position.y - 40,
|
||||
self.heading + 180,
|
||||
),
|
||||
self.add_unit(
|
||||
AirDefence.AAA_40mm_Bofors,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
"SHO#2",
|
||||
self.position.x + spacing * 2 + 40,
|
||||
self.position.y + spacing + 40,
|
||||
self.heading,
|
||||
),
|
||||
|
||||
# Short range guns
|
||||
self.add_unit(
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement,
|
||||
"SHO#3",
|
||||
self.position.x - 80,
|
||||
self.position.y - 40,
|
||||
self.heading + 180,
|
||||
),
|
||||
self.add_unit(
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement,
|
||||
"SHO#4",
|
||||
self.position.x + spacing * 2 + 80,
|
||||
self.position.y + spacing + 40,
|
||||
self.heading,
|
||||
),
|
||||
|
||||
# Add a truck
|
||||
self.add_unit(
|
||||
Unarmed.Truck_KAMAZ_43101,
|
||||
@@ -70,7 +86,7 @@ class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
|
||||
class ColdWarFlakGenerator(AirDefenseGroupGenerator):
|
||||
"""
|
||||
This generator attempt to mimic a cold-war era flak AAA site.
|
||||
The Flak 18 88mm is used as the main long range gun while 2 Zu-23 guns provide short range protection.
|
||||
The Flak 18 88mm is used as the main long range gun, 2 S-60 57mm gun improve mid range firepower, while 2 Zu-23 guns even provide short range protection.
|
||||
The site is also fitted with a P-19 radar for early detection.
|
||||
"""
|
||||
|
||||
@@ -94,22 +110,38 @@ class ColdWarFlakGenerator(AirDefenseGroupGenerator):
|
||||
self.heading,
|
||||
)
|
||||
|
||||
# Short range guns
|
||||
# Medium range guns
|
||||
self.add_unit(
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
"SHO#1",
|
||||
self.position.x - 40,
|
||||
self.position.y - 40,
|
||||
self.heading + 180,
|
||||
),
|
||||
self.add_unit(
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
"SHO#2",
|
||||
self.position.x + spacing * 2 + 40,
|
||||
self.position.y + spacing + 40,
|
||||
self.heading,
|
||||
),
|
||||
|
||||
# Short range guns
|
||||
self.add_unit(
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement,
|
||||
"SHO#3",
|
||||
self.position.x - 80,
|
||||
self.position.y - 40,
|
||||
self.heading + 180,
|
||||
),
|
||||
self.add_unit(
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement,
|
||||
"SHO#4",
|
||||
self.position.x + spacing * 2 + 80,
|
||||
self.position.y + spacing + 40,
|
||||
self.heading,
|
||||
),
|
||||
|
||||
# Add a P19 Radar for EWR
|
||||
self.add_unit(
|
||||
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3,
|
||||
|
||||
63
gen/sam/ewr_group_generator.py
Normal file
63
gen/sam/ewr_group_generator.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import random
|
||||
from typing import List, Optional, Type
|
||||
|
||||
from dcs.unitgroup import VehicleGroup
|
||||
|
||||
from game import Game
|
||||
from game.factions.faction import Faction
|
||||
from game.theater.theatergroundobject import EwrGroundObject
|
||||
from gen.sam.ewrs import (
|
||||
BigBirdGenerator,
|
||||
BoxSpringGenerator,
|
||||
DogEarGenerator,
|
||||
FlatFaceGenerator,
|
||||
HawkEwrGenerator,
|
||||
PatriotEwrGenerator,
|
||||
RolandEwrGenerator,
|
||||
SnowDriftGenerator,
|
||||
StraightFlushGenerator,
|
||||
TallRackGenerator,
|
||||
)
|
||||
from gen.sam.group_generator import GroupGenerator
|
||||
|
||||
EWR_MAP = {
|
||||
"BoxSpringGenerator": BoxSpringGenerator,
|
||||
"TallRackGenerator": TallRackGenerator,
|
||||
"DogEarGenerator": DogEarGenerator,
|
||||
"RolandEwrGenerator": RolandEwrGenerator,
|
||||
"FlatFaceGenerator": FlatFaceGenerator,
|
||||
"PatriotEwrGenerator": PatriotEwrGenerator,
|
||||
"BigBirdGenerator": BigBirdGenerator,
|
||||
"SnowDriftGenerator": SnowDriftGenerator,
|
||||
"StraightFlushGenerator": StraightFlushGenerator,
|
||||
"HawkEwrGenerator": HawkEwrGenerator,
|
||||
}
|
||||
|
||||
|
||||
def get_faction_possible_ewrs_generator(
|
||||
faction: Faction,
|
||||
) -> List[Type[GroupGenerator]]:
|
||||
"""
|
||||
Return the list of possible EWR generators for the given faction
|
||||
:param faction: Faction name to search units for
|
||||
"""
|
||||
return [EWR_MAP[s] for s in faction.ewrs]
|
||||
|
||||
|
||||
def generate_ewr_group(
|
||||
game: Game, ground_object: EwrGroundObject, faction: Faction
|
||||
) -> Optional[VehicleGroup]:
|
||||
"""Generates an early warning radar group.
|
||||
|
||||
:param game: The Game.
|
||||
:param ground_object: The ground object which will own the EWR group.
|
||||
:param faction: Owner faction.
|
||||
:return: The generated group, or None if one could not be generated.
|
||||
"""
|
||||
generators = get_faction_possible_ewrs_generator(faction)
|
||||
if len(generators) > 0:
|
||||
generator_class = random.choice(generators)
|
||||
generator = generator_class(game, ground_object)
|
||||
generator.generate()
|
||||
return generator.get_generated_group()
|
||||
return None
|
||||
@@ -6,7 +6,6 @@ from dcs.vehicles import AirDefence
|
||||
|
||||
from game import Game
|
||||
from game.factions.faction import Faction
|
||||
from game.theater import TheaterGroundObject
|
||||
from game.theater.theatergroundobject import SamGroundObject
|
||||
from gen.sam.aaa_bofors import BoforsGenerator
|
||||
from gen.sam.aaa_flak import FlakGenerator
|
||||
@@ -23,20 +22,7 @@ from gen.sam.cold_war_flak import (
|
||||
ColdWarFlakGenerator,
|
||||
EarlyColdWarFlakGenerator,
|
||||
)
|
||||
from gen.sam.ewrs import (
|
||||
BigBirdGenerator,
|
||||
BoxSpringGenerator,
|
||||
DogEarGenerator,
|
||||
FlatFaceGenerator,
|
||||
HawkEwrGenerator,
|
||||
PatriotEwrGenerator,
|
||||
RolandEwrGenerator,
|
||||
SnowDriftGenerator,
|
||||
StraightFlushGenerator,
|
||||
TallRackGenerator,
|
||||
)
|
||||
from gen.sam.freya_ewr import FreyaGenerator
|
||||
from gen.sam.group_generator import GroupGenerator
|
||||
from gen.sam.sam_avenger import AvengerGenerator
|
||||
from gen.sam.sam_chaparral import ChaparralGenerator
|
||||
from gen.sam.sam_gepard import GepardGenerator
|
||||
@@ -152,19 +138,6 @@ SAM_PRICES = {
|
||||
AirDefence.HQ_7_Self_Propelled_LN: 35,
|
||||
}
|
||||
|
||||
EWR_MAP = {
|
||||
"BoxSpringGenerator": BoxSpringGenerator,
|
||||
"TallRackGenerator": TallRackGenerator,
|
||||
"DogEarGenerator": DogEarGenerator,
|
||||
"RolandEwrGenerator": RolandEwrGenerator,
|
||||
"FlatFaceGenerator": FlatFaceGenerator,
|
||||
"PatriotEwrGenerator": PatriotEwrGenerator,
|
||||
"BigBirdGenerator": BigBirdGenerator,
|
||||
"SnowDriftGenerator": SnowDriftGenerator,
|
||||
"StraightFlushGenerator": StraightFlushGenerator,
|
||||
"HawkEwrGenerator": HawkEwrGenerator,
|
||||
}
|
||||
|
||||
|
||||
def get_faction_possible_sams_generator(
|
||||
faction: Faction,
|
||||
@@ -176,14 +149,6 @@ def get_faction_possible_sams_generator(
|
||||
return [SAM_MAP[s] for s in faction.air_defenses]
|
||||
|
||||
|
||||
def get_faction_possible_ewrs_generator(faction: Faction) -> List[Type[GroupGenerator]]:
|
||||
"""
|
||||
Return the list of possible SAM generator for the given faction
|
||||
:param faction: Faction name to search units for
|
||||
"""
|
||||
return [EWR_MAP[s] for s in faction.ewrs]
|
||||
|
||||
|
||||
def _generate_anti_air_from(
|
||||
generators: Sequence[Type[AirDefenseGroupGenerator]],
|
||||
game: Game,
|
||||
@@ -236,22 +201,3 @@ def generate_anti_air_group(
|
||||
if groups:
|
||||
return groups
|
||||
return []
|
||||
|
||||
|
||||
def generate_ewr_group(
|
||||
game: Game, ground_object: TheaterGroundObject, faction: Faction
|
||||
) -> Optional[VehicleGroup]:
|
||||
"""Generates an early warning radar group.
|
||||
|
||||
:param game: The Game.
|
||||
:param ground_object: The ground object which will own the EWR group.
|
||||
:param faction: Owner faction.
|
||||
:return: The generated group, or None if one could not be generated.
|
||||
"""
|
||||
generators = get_faction_possible_ewrs_generator(faction)
|
||||
if len(generators) > 0:
|
||||
generator_class = random.choice(generators)
|
||||
generator = generator_class(game, ground_object)
|
||||
generator.generate()
|
||||
return generator.get_generated_group()
|
||||
return None
|
||||
|
||||
2
pydcs
2
pydcs
Submodule pydcs updated: d899985e28...cd14f0a049
@@ -147,6 +147,8 @@ def load_icons():
|
||||
"./resources/ui/ground_assets/" + category + "_blue.png"
|
||||
)
|
||||
ICONS["destroyed"] = QPixmap("./resources/ui/ground_assets/destroyed.png")
|
||||
ICONS["EWR"] = QPixmap("./resources/ui/ground_assets/ewr.png")
|
||||
ICONS["EWR_blue"] = QPixmap("./resources/ui/ground_assets/ewr_blue.png")
|
||||
ICONS["ship"] = QPixmap("./resources/ui/ground_assets/ship.png")
|
||||
ICONS["ship_blue"] = QPixmap("./resources/ui/ground_assets/ship_blue.png")
|
||||
ICONS["missile"] = QPixmap("./resources/ui/ground_assets/missile.png")
|
||||
|
||||
@@ -7,7 +7,7 @@ from PySide2.QtWidgets import (
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
)
|
||||
from dcs.weather import Weather as PydcsWeather
|
||||
from dcs.weather import CloudPreset, Weather as PydcsWeather
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.utils import mps
|
||||
@@ -162,7 +162,7 @@ class QWeatherWidget(QGroupBox):
|
||||
self.turn = turn
|
||||
self.conditions = conditions
|
||||
|
||||
self.updateForecast()
|
||||
self.update_forecast()
|
||||
self.updateWinds()
|
||||
|
||||
def updateWinds(self):
|
||||
@@ -186,55 +186,76 @@ class QWeatherWidget(QGroupBox):
|
||||
self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts")
|
||||
self.windFL26DirLabel.setText(f"{windFL26Dir}º")
|
||||
|
||||
def updateForecast(self):
|
||||
def update_forecast_from_preset(self, preset: CloudPreset) -> None:
|
||||
self.forecastFog.setText("No fog")
|
||||
if "Rain" in preset.name:
|
||||
self.forecastRain.setText("Rain")
|
||||
self.update_forecast_icons("rain")
|
||||
else:
|
||||
self.forecastRain.setText("No rain")
|
||||
self.update_forecast_icons("partly-cloudy")
|
||||
|
||||
# We get a description like the following for the cloud preset.
|
||||
#
|
||||
# 09 ##Two Layer Broken/Scattered \nMETAR:BKN 7.5/10 SCT 20/22 FEW41
|
||||
#
|
||||
# The second line is probably interesting but doesn't fit into the widget
|
||||
# currently, so for now just extract the first line.
|
||||
self.forecastClouds.setText(preset.description.splitlines()[0].split("##")[1])
|
||||
|
||||
def update_forecast(self):
|
||||
"""Updates the Forecast Text and icon with the current conditions wind info."""
|
||||
icon = []
|
||||
if (
|
||||
self.conditions.weather.clouds
|
||||
and self.conditions.weather.clouds.preset is not None
|
||||
):
|
||||
self.update_forecast_from_preset(self.conditions.weather.clouds.preset)
|
||||
return
|
||||
|
||||
if self.conditions.weather.clouds is None:
|
||||
cloudDensity = 0
|
||||
cloud_density = 0
|
||||
precipitation = None
|
||||
else:
|
||||
cloudDensity = self.conditions.weather.clouds.density
|
||||
cloud_density = self.conditions.weather.clouds.density
|
||||
precipitation = self.conditions.weather.clouds.precipitation
|
||||
|
||||
fog = self.conditions.weather.fog or None
|
||||
is_night = self.conditions.time_of_day == TimeOfDay.Night
|
||||
time = "night" if is_night else "day"
|
||||
|
||||
if cloudDensity <= 0:
|
||||
if not cloud_density:
|
||||
self.forecastClouds.setText("Sunny")
|
||||
icon = [time, "clear"]
|
||||
|
||||
if cloudDensity > 0 and cloudDensity < 3:
|
||||
weather_type = "clear"
|
||||
elif cloud_density < 3:
|
||||
self.forecastClouds.setText("Partly Cloudy")
|
||||
icon = [time, "partly-cloudy"]
|
||||
|
||||
if cloudDensity >= 3 and cloudDensity < 5:
|
||||
weather_type = "partly-cloudy"
|
||||
elif cloud_density < 5:
|
||||
self.forecastClouds.setText("Mostly Cloudy")
|
||||
icon = [time, "partly-cloudy"]
|
||||
|
||||
if cloudDensity >= 5:
|
||||
weather_type = "partly-cloudy"
|
||||
else:
|
||||
self.forecastClouds.setText("Totally Cloudy")
|
||||
icon = [time, "partly-cloudy"]
|
||||
weather_type = "partly-cloudy"
|
||||
|
||||
if precipitation == PydcsWeather.Preceptions.Rain:
|
||||
self.forecastRain.setText("Rain")
|
||||
icon = [time, "rain"]
|
||||
|
||||
weather_type = "rain"
|
||||
elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
|
||||
self.forecastRain.setText("Thunderstorm")
|
||||
icon = [time, "thunderstorm"]
|
||||
|
||||
weather_type = "thunderstorm"
|
||||
else:
|
||||
self.forecastRain.setText("No Rain")
|
||||
self.forecastRain.setText("No rain")
|
||||
|
||||
if not fog:
|
||||
if not self.conditions.weather.fog is not None:
|
||||
self.forecastFog.setText("No fog")
|
||||
else:
|
||||
visibility = round(fog.visibility.nautical_miles, 1)
|
||||
visibility = round(self.conditions.weather.fog.visibility.nautical_miles, 1)
|
||||
self.forecastFog.setText(f"Fog vis: {visibility}nm")
|
||||
icon = [time, ("cloudy" if cloudDensity > 1 else None), "fog"]
|
||||
if cloud_density > 1:
|
||||
weather_type = "cloudy-fog"
|
||||
else:
|
||||
weather_type = "fog"
|
||||
|
||||
icon_key = "Weather_{}".format("-".join(filter(None.__ne__, icon)))
|
||||
self.update_forecast_icons(weather_type)
|
||||
|
||||
def update_forecast_icons(self, weather_type: str) -> None:
|
||||
time = "night" if self.conditions.time_of_day == TimeOfDay.Night else "day"
|
||||
icon_key = f"Weather_{time}-{weather_type}"
|
||||
icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"]
|
||||
self.weather_icon.setPixmap(icon)
|
||||
|
||||
|
||||
@@ -172,6 +172,8 @@ class QBaseMenu2(QDialog):
|
||||
return "./resources/ui/carrier.png"
|
||||
elif self.cp.cptype == ControlPointType.LHA_GROUP:
|
||||
return "./resources/ui/lha.png"
|
||||
elif self.cp.cptype == ControlPointType.FOB:
|
||||
return "./resources/ui/fob.png"
|
||||
else:
|
||||
return "./resources/ui/airbase.png"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from PySide2.QtWidgets import QTabWidget
|
||||
|
||||
from game.theater import ControlPoint, OffMapSpawn
|
||||
from game.theater import ControlPoint, OffMapSpawn, Fob
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.airfield.QAirfieldCommand import QAirfieldCommand
|
||||
from qt_ui.windows.basemenu.base_defenses.QBaseDefensesHQ import QBaseDefensesHQ
|
||||
@@ -19,14 +19,26 @@ class QBaseMenuTabs(QTabWidget):
|
||||
self.intel = QIntelInfo(cp, game_model.game)
|
||||
self.addTab(self.intel, "Intel")
|
||||
else:
|
||||
self.airfield_command = QAirfieldCommand(cp, game_model)
|
||||
self.addTab(self.airfield_command, "Airfield Command")
|
||||
|
||||
if cp.is_carrier:
|
||||
self.base_defenses_hq = QBaseDefensesHQ(cp, game_model.game)
|
||||
self.addTab(self.base_defenses_hq, "Fleet")
|
||||
elif not isinstance(cp, OffMapSpawn):
|
||||
self.ground_forces_hq = QGroundForcesHQ(cp, game_model)
|
||||
self.addTab(self.ground_forces_hq, "Ground Forces HQ")
|
||||
self.base_defenses_hq = QBaseDefensesHQ(cp, game_model.game)
|
||||
self.addTab(self.base_defenses_hq, "Base Defenses")
|
||||
if cp:
|
||||
if isinstance(cp, Fob):
|
||||
self.ground_forces_hq = QGroundForcesHQ(cp, game_model)
|
||||
self.addTab(self.ground_forces_hq, "Ground Forces HQ")
|
||||
if cp.helipads:
|
||||
self.airfield_command = QAirfieldCommand(cp, game_model)
|
||||
self.addTab(self.airfield_command, "Heliport")
|
||||
self.base_defenses_hq = QBaseDefensesHQ(cp, game_model.game)
|
||||
self.addTab(self.base_defenses_hq, "Base Defenses")
|
||||
else:
|
||||
|
||||
self.airfield_command = QAirfieldCommand(cp, game_model)
|
||||
self.addTab(self.airfield_command, "Airfield Command")
|
||||
|
||||
if cp.is_carrier:
|
||||
self.base_defenses_hq = QBaseDefensesHQ(cp, game_model.game)
|
||||
self.addTab(self.base_defenses_hq, "Fleet")
|
||||
elif not isinstance(cp, OffMapSpawn):
|
||||
self.ground_forces_hq = QGroundForcesHQ(cp, game_model)
|
||||
self.addTab(self.ground_forces_hq, "Ground Forces HQ")
|
||||
self.base_defenses_hq = QBaseDefensesHQ(cp, game_model.game)
|
||||
self.addTab(self.base_defenses_hq, "Base Defenses")
|
||||
|
||||
@@ -12,11 +12,12 @@ from PySide2.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from dcs.helicopters import helicopter_map
|
||||
from dcs.task import CAP, CAS, AWACS
|
||||
from dcs.unittype import FlyingType, UnitType
|
||||
|
||||
from game import db
|
||||
from game.theater import ControlPoint
|
||||
from game.theater import ControlPoint, ControlPointType
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.uiconstants import ICONS
|
||||
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
|
||||
@@ -63,6 +64,11 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
continue
|
||||
if self.cp.is_lha and unit not in db.LHA_CAPABLE:
|
||||
continue
|
||||
if (
|
||||
self.cp.cptype in [ControlPointType.FOB, ControlPointType.FARP]
|
||||
and unit not in helicopter_map.values()
|
||||
):
|
||||
continue
|
||||
unit_types.add(unit)
|
||||
|
||||
sorted_units = sorted(
|
||||
|
||||
@@ -43,4 +43,4 @@ class QLoadoutEditor(QGroupBox):
|
||||
self.flight.use_custom_loadout = self.isChecked()
|
||||
if not self.isChecked():
|
||||
for i in self.findChildren(QPylonEditor):
|
||||
i.default_loadout(i.pylon.number)
|
||||
i.default_loadout()
|
||||
|
||||
@@ -213,14 +213,14 @@ class QSettingsWindow(QDialog):
|
||||
|
||||
self.player_income = TenthsSpinSlider(
|
||||
"Player income multiplier",
|
||||
1,
|
||||
0,
|
||||
50,
|
||||
int(self.game.settings.player_income_multiplier * 10),
|
||||
)
|
||||
self.player_income.spinner.valueChanged.connect(self.applySettings)
|
||||
self.enemy_income = TenthsSpinSlider(
|
||||
"Enemy income multiplier",
|
||||
1,
|
||||
0,
|
||||
50,
|
||||
int(self.game.settings.enemy_income_multiplier * 10),
|
||||
)
|
||||
|
||||
Binary file not shown.
@@ -17,26 +17,22 @@ local unitPayloads = {
|
||||
["num"] = 6,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
["CLSID"] = "{AN_ASQ_228}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "LAU_117_AGM_65F",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
[6] = {
|
||||
["CLSID"] = "LAU_117_AGM_65F",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
[7] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[9] = {
|
||||
[8] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 9,
|
||||
},
|
||||
@@ -61,26 +57,22 @@ local unitPayloads = {
|
||||
["num"] = 6,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
["CLSID"] = "{AN_ASQ_228}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
[6] = {
|
||||
["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
[7] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[9] = {
|
||||
[8] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 9,
|
||||
},
|
||||
@@ -137,38 +129,34 @@ local unitPayloads = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{BRU55_2*GBU-38}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{BRU33_2X_MK-83}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{FPU_8A_FUEL_TANK}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{BRU55_2*GBU-38}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{BRU33_2X_MK-83}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[9] = {
|
||||
[2] = {
|
||||
["CLSID"] = "{GBU_31_V_2B}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{FPU_8A_FUEL_TANK}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN_ASQ_228}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{FPU_8A_FUEL_TANK}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{GBU_31_V_2B}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 9,
|
||||
},
|
||||
@@ -189,30 +177,26 @@ local unitPayloads = {
|
||||
["num"] = 7,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||
[4] = {
|
||||
["CLSID"] = "{AN_ASQ_228}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
[5] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[7] = {
|
||||
[6] = {
|
||||
["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[8] = {
|
||||
[7] = {
|
||||
["CLSID"] = "{AGM_84D}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[9] = {
|
||||
[8] = {
|
||||
["CLSID"] = "{AGM_84D}",
|
||||
["num"] = 2,
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
],
|
||||
"logistics_units": [
|
||||
"Truck_Bedford",
|
||||
"CCKW_353"
|
||||
"Truck_GMC_Jimmy_6x6_Truck"
|
||||
],
|
||||
"infantry_units": [
|
||||
"Infantry_SMLE_No_4_Mk_1",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_9A52_Smerch_HE_300mm",
|
||||
"PLZ_05",
|
||||
"SPH_2S9_Nona_120mm_M"
|
||||
],
|
||||
"logistics_units": [
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"MBT_M60A3_Patton",
|
||||
"IFV_BMP_1",
|
||||
"SPAAA_ZSU_23_4_Shilka_Gun_Dish",
|
||||
"SPAAA_ZSU_57_2"
|
||||
"SPAAA_ZSU_57_2",
|
||||
"SPAAA_ZU_23_2_Mounted_Ural_375"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm",
|
||||
@@ -45,7 +46,7 @@
|
||||
"ZSU57Generator",
|
||||
"ZSU23Generator",
|
||||
"ZU23Generator",
|
||||
"ZU23UralGenerator"
|
||||
"ColdWarFlakGenerator"
|
||||
],
|
||||
"ewrs": [
|
||||
"TallRackGenerator"
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"APC_MTLB",
|
||||
"MBT_T_55",
|
||||
"SPAAA_ZU_23_2_Mounted_Ural_375",
|
||||
"AAA_8_8cm_Flak_18"
|
||||
"AAA_8_8cm_Flak_18",
|
||||
"AAA_S_60_57mm"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm"
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
"IFV_BMP_1",
|
||||
"MBT_T_55",
|
||||
"SPAAA_ZU_23_2_Mounted_Ural_375",
|
||||
"SPAAA_ZSU_57_2"
|
||||
"SPAAA_ZSU_57_2",
|
||||
"AAA_S_60_57mm"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
],
|
||||
"logistics_units": [
|
||||
"Truck_Bedford",
|
||||
"CCKW_353"
|
||||
"Truck_GMC_Jimmy_6x6_Truck"
|
||||
],
|
||||
"infantry_units": [
|
||||
"Infantry_SMLE_No_4_Mk_1"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"frontline_units": [
|
||||
"IFV_Sd_Kfz_234_2_Puma",
|
||||
"APC_Sd_Kfz_251_Halftrack_Halftrack",
|
||||
"APC_Sd_Kfz_251_Halftrack",
|
||||
"MT_PzIV_H",
|
||||
"MT_M4_Sherman",
|
||||
"AAA_40mm_Bofors"
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"MT_PzIV_H",
|
||||
"MBT_T_55",
|
||||
"SPAAA_ZU_23_2_Mounted_Ural_375",
|
||||
"SPAAA_ZSU_57_2"
|
||||
"SPAAA_ZSU_57_2",
|
||||
"AAA_S_60_57mm"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm"
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"MT_PzIV_H",
|
||||
"SPG_StuG_III_Ausf__G",
|
||||
"SPG_Jagdpanzer_IV",
|
||||
"SPAAA_ZSU_57_2"
|
||||
"SPAAA_ZSU_57_2",
|
||||
"AAA_S_60_57mm"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm"
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"APC_MTLB",
|
||||
"MBT_T_55",
|
||||
"SPAAA_ZU_23_2_Mounted_Ural_375",
|
||||
"SPAAA_ZSU_57_2"
|
||||
"SPAAA_ZSU_57_2",
|
||||
"AAA_S_60_57mm"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm"
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"MBT_T_55",
|
||||
"MBT_T_72B",
|
||||
"SPAAA_ZU_23_2_Mounted_Ural_375",
|
||||
"SPAAA_ZSU_57_2"
|
||||
"SPAAA_ZSU_57_2",
|
||||
"AAA_S_60_57mm"
|
||||
],
|
||||
"artillery_units": [
|
||||
"MLRS_BM_21_Grad_122mm"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
],
|
||||
"logistics_units": [
|
||||
"Truck_Bedford",
|
||||
"CCKW_353"
|
||||
"Truck_GMC_Jimmy_6x6_Truck"
|
||||
],
|
||||
"infantry_units": [
|
||||
"Infantry_SMLE_No_4_Mk_1"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"SPG_M12_GMC_155mm"
|
||||
],
|
||||
"logistics_units": [
|
||||
"CCKW_353"
|
||||
"Truck_GMC_Jimmy_6x6_Truck"
|
||||
],
|
||||
"infantry_units": [
|
||||
"Infantry_M1_Garand"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"frontline_units": [
|
||||
"MBT_M60A3_Patton",
|
||||
"APC_M113",
|
||||
"APC_M1025_HMMWV",
|
||||
"APC_HMMWV__Scout",
|
||||
"SPAAA_Vulcan_M163"
|
||||
],
|
||||
"artillery_units": [
|
||||
|
||||
58
resources/plugins/lotatc/LotAtcExport-config.lua
Normal file
58
resources/plugins/lotatc/LotAtcExport-config.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- configuration file for the LotATC Export script
|
||||
--
|
||||
-- This configuration is tailored for a mission generated by DCS Liberation
|
||||
-- see https://github.com/Khopa/dcs_liberation
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- LotATC Export plugin - configuration
|
||||
logger:info("DCSLiberation|LotATC Export plugin - configuration")
|
||||
|
||||
local function discoverLotAtcDrawingsPath()
|
||||
-- establish a search pattern into the following modes
|
||||
-- 1. Environment variable LOTATC_DRAWINGS_DIR, to support server exporting with auto load from LotATC
|
||||
-- 2. DCS saved games folder as configured in DCS Liberation
|
||||
|
||||
local drawingEnvDir = os.getenv("LOTATC_DRAWINGS_DIR")
|
||||
if drawingEnvDir then
|
||||
return drawingEnvDir
|
||||
else
|
||||
return lfs.writedir()..[[\Mods\services\LotAtc\userdb\drawings\]]
|
||||
end
|
||||
end
|
||||
|
||||
if dcsLiberation then
|
||||
logger:info("DCSLiberation|LotATC Export plugin - configuration dcsLiberation")
|
||||
|
||||
local exportRedAA = true
|
||||
local exportBlueAA = false
|
||||
local exportSymbols = true
|
||||
|
||||
-- retrieve specific options values
|
||||
if dcsLiberation.plugins then
|
||||
logger:info("DCSLiberation|LotATC Export plugin - configuration dcsLiberation.plugins")
|
||||
|
||||
if dcsLiberation.plugins.lotatc then
|
||||
logger:info("DCSLiberation|LotATC Export plugin - dcsLiberation.plugins.lotatcExport")
|
||||
|
||||
exportRedAA = dcsLiberation.plugins.lotatc.exportRedAA
|
||||
logger:info(string.format("DCSLiberation|LotATC Export plugin - exportRedAA = %s",tostring(exportRedAA)))
|
||||
|
||||
exportBlueAA = dcsLiberation.plugins.lotatc.exportBlueAA
|
||||
logger:info(string.format("DCSLiberation|LotATC Export plugin - exportBlueAA = %s",tostring(exportBlueAA)))
|
||||
|
||||
exportBlueAA = dcsLiberation.plugins.lotatc.exportSymbols
|
||||
logger:info(string.format("DCSLiberation|LotATC Export plugin - exportSymbols = %s",tostring(exportSymbols)))
|
||||
end
|
||||
end
|
||||
|
||||
-- actual configuration code
|
||||
if LotAtcExportConfig then
|
||||
LotAtcExportConfig.exportRedAA = exportRedAA
|
||||
LotAtcExportConfig.exportBlueAA = exportBlueAA
|
||||
LotAtcExportConfig.exportSymbols = exportSymbols
|
||||
LotAtcExportConfig.drawingBasePath = discoverLotAtcDrawingsPath()
|
||||
|
||||
LotatcExport()
|
||||
end
|
||||
end
|
||||
253
resources/plugins/lotatc/LotAtcExport.lua
Normal file
253
resources/plugins/lotatc/LotAtcExport.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
--[[
|
||||
Export script for LotATC drawings
|
||||
|
||||
Allows to export certain DCS Liberation objects as predefined drawing in LotATC.
|
||||
|
||||
This script runs at mission startup and generates a drawing JSON file to be imported
|
||||
in LotATC.
|
||||
]]
|
||||
|
||||
LotAtcExportConfig = {
|
||||
["exportRedAA"] = false,
|
||||
["exportBlueAA"] = false,
|
||||
["exportSymbols"] = false,
|
||||
["exportVersion"] = "2.2.0",
|
||||
["drawingBasePath"] = nil,
|
||||
["redColor"] = "#7FE32000",
|
||||
["blueColor"] = "#7F0084FF"
|
||||
}
|
||||
|
||||
local function factionName(isFriend)
|
||||
if isFriend then
|
||||
return "BLUE"
|
||||
else
|
||||
return "RED"
|
||||
end
|
||||
end
|
||||
|
||||
local function uuid()
|
||||
local random = math.random
|
||||
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||
return string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
|
||||
return string.format('%x', v)
|
||||
end)
|
||||
end
|
||||
|
||||
local function ends_with(str, ending)
|
||||
return ending == "" or str:sub(-#ending) == ending
|
||||
end
|
||||
|
||||
local function combine(path1, path2)
|
||||
if not ends_with(path1, "\\") then
|
||||
path1 = path1 .. "\\"
|
||||
end
|
||||
|
||||
return path1 .. path2
|
||||
end
|
||||
|
||||
local function lotatcExport_get_aa_nato_name(unit, isFriend)
|
||||
if not redIADS or not blueIADS then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- logger:info(string.format("DCSLiberation|LotATC Export plugin - try get NATO name for unit %s", unit.dcsGroupName))
|
||||
|
||||
local iads = redIADS
|
||||
if isFriend then
|
||||
iads = blueIADS
|
||||
end
|
||||
|
||||
local samSite = iads:getSAMSiteByGroupName(unit.dcsGroupName)
|
||||
if samSite and samSite.natoName then
|
||||
-- logger:info(string.format("DCSLiberation|LotATC Export plugin - NATO name is %s", samSite.natoName))
|
||||
return samSite.natoName
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function lotatcExport_get_name(unit, isFriend)
|
||||
local classification = "SAM"
|
||||
|
||||
if string.find(unit.dcsGroupName, "|EWR|", 1, true) then
|
||||
classification = "EWR"
|
||||
elseif string.find(unit.dcsGroupName, "|AA", 1, true) then
|
||||
classification = "AAA"
|
||||
end
|
||||
|
||||
local natoName = lotatcExport_get_aa_nato_name(unit, isFriend)
|
||||
|
||||
local name = nil
|
||||
if not natoName then
|
||||
name = string.format("%s|%s", unit.name, classification)
|
||||
else
|
||||
name = string.format("%s|%s|%s", unit.name, classification, natoName)
|
||||
end
|
||||
|
||||
return name, classification
|
||||
end
|
||||
|
||||
local function lotatc_write_json(filename, json)
|
||||
logger:info(string.format("DCSLiberation|LotATC Export plugin - writing %s", filename))
|
||||
|
||||
local function Write()
|
||||
local fp = io.open(filename, 'w')
|
||||
if fp then
|
||||
fp:write(json)
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
|
||||
if pcall(Write) then
|
||||
else
|
||||
logger:error("Unable to write LotATC export file to %s", filename)
|
||||
end
|
||||
end
|
||||
|
||||
local function lotatcExport_threat_circles_for_faction(faction, color, isFriend)
|
||||
local drawings = {}
|
||||
|
||||
for _,aa in pairs(faction) do
|
||||
logger:info(string.format("DCSLiberation|LotATC Export plugin - exporting threat circle for %s", aa.dcsGroupName))
|
||||
|
||||
local convLat, convLon = coord.LOtoLL({x = aa.positionX, y = 0, z = aa.positionY})
|
||||
|
||||
local name = lotatcExport_get_name(aa, isFriend)
|
||||
|
||||
table.insert(drawings,
|
||||
{
|
||||
["author"] = "DCSLiberation",
|
||||
["brushStyle"] = 1,
|
||||
["color"] = color,
|
||||
["colorBg"] = "#00000000",
|
||||
["id"] = string.format("{%s}", uuid()),
|
||||
["longitude"] = convLon,
|
||||
["latitude"] = convLat,
|
||||
["radius"] = tonumber(aa.range),
|
||||
["lineWidth"] = 2,
|
||||
["name"] = name,
|
||||
["shared"] = true,
|
||||
["timestamp"] = "",
|
||||
["type"] = "circle",
|
||||
["text"] = name,
|
||||
["font"] = {
|
||||
["color"] = color,
|
||||
["font"] = "Lato"
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
local lotatcData = {
|
||||
["name"] = "Threat Circles " .. factionName(isFriend),
|
||||
["enable"] = "true",
|
||||
["version"] = LotAtcExportConfig.exportVersion,
|
||||
["drawings"] = drawings
|
||||
}
|
||||
|
||||
local drawings_json = json:encode(lotatcData)
|
||||
return drawings_json
|
||||
end
|
||||
|
||||
local function lotatcExport_symbols_for_faction(faction, color, isFriend)
|
||||
local drawings = {}
|
||||
|
||||
for _,aa in pairs(faction) do
|
||||
logger:info(string.format("DCSLiberation|LotATC Export plugin - exporting AA symbol for %s", aa.dcsGroupName))
|
||||
|
||||
local convLat, convLon = coord.LOtoLL({x = aa.positionX, y = 0, z = aa.positionY})
|
||||
|
||||
local name = lotatcExport_get_name(aa, isFriend)
|
||||
|
||||
local classification = "hostile"
|
||||
if isFriend then
|
||||
classification = "friend"
|
||||
end
|
||||
|
||||
local sub_dimension = "none"
|
||||
|
||||
if string.find(aa.dcsGroupName, "|EWR|", 1, true) then
|
||||
sub_dimension = "ew"
|
||||
end
|
||||
|
||||
table.insert(drawings,
|
||||
{
|
||||
["author"] = "DCSLiberation",
|
||||
["brushStyle"] = 1,
|
||||
["classification"] = {
|
||||
["classification"] = classification,
|
||||
["dimension"] = "land_unit",
|
||||
["sub_dimension"] = sub_dimension
|
||||
},
|
||||
["color"] = color,
|
||||
["colorBg"] = "#33FF0000",
|
||||
["font"] = {
|
||||
["color"] = color,
|
||||
["font"] = "Lato"
|
||||
},
|
||||
["id"] = string.format("{%s}", uuid()),
|
||||
["longitude"] = convLon,
|
||||
["latitude"] = convLat,
|
||||
["lineWidth"] = 2,
|
||||
["name"] = name,
|
||||
["shared"] = true,
|
||||
["timestamp"] = "",
|
||||
["type"] = "symbol",
|
||||
["text"] = name
|
||||
})
|
||||
end
|
||||
|
||||
local lotatcData = {
|
||||
["name"] = "Threat Symbols " .. factionName(isFriend),
|
||||
["enable"] = "true",
|
||||
["version"] = LotAtcExportConfig.exportVersion,
|
||||
["drawings"] = drawings,
|
||||
}
|
||||
|
||||
local drawings_json = json:encode(lotatcData)
|
||||
return drawings_json
|
||||
end
|
||||
|
||||
local function lotatc_export_faction(faction, color, factionPath, isFriend)
|
||||
local exportBasePathFaction = combine(LotAtcExportConfig.drawingBasePath, factionPath)
|
||||
lfs.mkdir(exportBasePathFaction)
|
||||
|
||||
local exportFileName = combine(exportBasePathFaction, "threatZones.json")
|
||||
local json = lotatcExport_threat_circles_for_faction(faction, color, isFriend)
|
||||
lotatc_write_json(exportFileName, json)
|
||||
|
||||
if LotAtcExportConfig.exportSymbols then
|
||||
exportFileName = combine(exportBasePathFaction, "threatSymbols.json")
|
||||
json = lotatcExport_symbols_for_faction(faction, color, isFriend);
|
||||
lotatc_write_json(exportFileName, json)
|
||||
end
|
||||
end
|
||||
|
||||
function LotatcExport()
|
||||
|
||||
if not json then
|
||||
local message = "Unable to export LotATC drawings, JSON library is not loaded!"
|
||||
logger:error(message)
|
||||
return
|
||||
end
|
||||
|
||||
if not LotAtcExportConfig.drawingBasePath then
|
||||
local message = "No writable export path for LotATC drawings. Set environment variable LOTATC_DRAWINGS_DIR pointing to your export path."
|
||||
logger:error(message)
|
||||
return
|
||||
end
|
||||
|
||||
local message = "Export LotATC drawings to "..LotAtcExportConfig.drawingBasePath
|
||||
logger:info(message)
|
||||
|
||||
-- The RED AA is exported to the blue folder and vice versa. If a BLUE GCI connects he/she
|
||||
-- wants to see the RED AA.
|
||||
|
||||
if LotAtcExportConfig.exportRedAA then
|
||||
lotatc_export_faction(dcsLiberation.RedAA, LotAtcExportConfig.redColor, [[blue\]], false)
|
||||
end
|
||||
|
||||
if LotAtcExportConfig.exportBlueAA then
|
||||
lotatc_export_faction(dcsLiberation.BlueAA, LotAtcExportConfig.blueColor, [[red\]], true)
|
||||
end
|
||||
end
|
||||
33
resources/plugins/lotatc/plugin.json
Normal file
33
resources/plugins/lotatc/plugin.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"nameInUI": "LotATC Export",
|
||||
"defaultValue": false,
|
||||
"specificOptions": [
|
||||
{
|
||||
"nameInUI": "Export RED AA",
|
||||
"mnemonic": "exportRedAA",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"nameInUI": "Export BLUE AA",
|
||||
"mnemonic": "exportBlueAA",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"nameInUI": "Export AA Symbols",
|
||||
"mnemonic": "exportSymbols",
|
||||
"defaultValue": true
|
||||
}
|
||||
],
|
||||
"scriptsWorkOrders": [
|
||||
{
|
||||
"file": "LotAtcExport.lua",
|
||||
"mnemonic": "LotAtcExport-script"
|
||||
}
|
||||
],
|
||||
"configurationWorkOrders": [
|
||||
{
|
||||
"file": "LotAtcExport-config.lua",
|
||||
"mnemonic": "LotAtcExport-config"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
[
|
||||
"base",
|
||||
"jtacautolase",
|
||||
"skynetiads",
|
||||
"ewrs",
|
||||
"herculescargo",
|
||||
"splashdamage"
|
||||
]
|
||||
[
|
||||
"base",
|
||||
"jtacautolase",
|
||||
"skynetiads",
|
||||
"ewrs",
|
||||
"herculescargo",
|
||||
"splashdamage",
|
||||
"lotatc"
|
||||
]
|
||||
|
||||
BIN
resources/ui/fob.png
Normal file
BIN
resources/ui/fob.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 258 KiB |
BIN
resources/ui/ground_assets/ewr.png
Normal file
BIN
resources/ui/ground_assets/ewr.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
resources/ui/ground_assets/ewr_blue.png
Normal file
BIN
resources/ui/ground_assets/ewr_blue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 881 B |
BIN
resources/ui/units/vehicles/icons/PLZ-05_24.jpg
Normal file
BIN
resources/ui/units/vehicles/icons/PLZ-05_24.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
resources/ui/units/vehicles/icons/S-60_24.jpg
Normal file
BIN
resources/ui/units/vehicles/icons/S-60_24.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1011 B |
Reference in New Issue
Block a user