mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Compare commits
52 Commits
9.0.0
...
develop-10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce073c24bc | ||
|
|
8de053cc7d | ||
|
|
fe6e49b22b | ||
|
|
3653dc8cbd | ||
|
|
d2b5eea0de | ||
|
|
211ec86e2e | ||
|
|
03caddc1b4 | ||
|
|
3f7618d75d | ||
|
|
dcf23c655d | ||
|
|
ef69275f34 | ||
|
|
167cea08f6 | ||
|
|
48ae55bdc2 | ||
|
|
ff2bd3f815 | ||
|
|
ba5d0bed4d | ||
|
|
4a07b8a2d8 | ||
|
|
1efce862fb | ||
|
|
80cb440e7d | ||
|
|
e970c281e8 | ||
|
|
b863e2fb83 | ||
|
|
3007a96343 | ||
|
|
463981f4bf | ||
|
|
816d1cd787 | ||
|
|
4631ee0d74 | ||
|
|
a213215c3f | ||
|
|
b014f2e543 | ||
|
|
f3d3c5f43a | ||
|
|
5ee3afeddb | ||
|
|
88591fd18c | ||
|
|
f5573cfc19 | ||
|
|
f7141a9882 | ||
|
|
a599b503f8 | ||
|
|
6c4b8c81ee | ||
|
|
2447cc156d | ||
|
|
28954d05eb | ||
|
|
65eb10639b | ||
|
|
7bc35ef7f4 | ||
|
|
46766ecbd4 | ||
|
|
3469d08461 | ||
|
|
28d959bba0 | ||
|
|
b99eb49dcf | ||
|
|
c6f812238c | ||
|
|
cc5b5fa3bb | ||
|
|
5271b3d32c | ||
|
|
8f4192edc3 | ||
|
|
183d6df8bf | ||
|
|
a825651330 | ||
|
|
f3c02816fc | ||
|
|
c4e2e45650 | ||
|
|
6613642517 | ||
|
|
b73ca2c62e | ||
|
|
8abd3c7cf9 | ||
|
|
f8a72d8f22 |
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -31,7 +31,7 @@ body:
|
|||||||
If the bug was found in a development build, select "Development build"
|
If the bug was found in a development build, select "Development build"
|
||||||
and provide a link to the build in the field below.
|
and provide a link to the build in the field below.
|
||||||
options:
|
options:
|
||||||
- 8.1.0
|
- 9.0.0
|
||||||
- Development build
|
- Development build
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/new-game-bug.yml
vendored
2
.github/ISSUE_TEMPLATE/new-game-bug.yml
vendored
@@ -39,7 +39,7 @@ body:
|
|||||||
If the bug was found in a development build, select "Development build"
|
If the bug was found in a development build, select "Development build"
|
||||||
and provide a link to the build in the field below.
|
and provide a link to the build in the field below.
|
||||||
options:
|
options:
|
||||||
- 8.1.0
|
- 9.0.0
|
||||||
- Development build
|
- Development build
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v2
|
||||||
- uses: psf/black@stable
|
- uses: psf/black@stable
|
||||||
with:
|
with:
|
||||||
version: ~=22.12
|
version: ~=23.11
|
||||||
src: "."
|
src: "."
|
||||||
options: "--check"
|
options: "--check"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.12.0
|
rev: 23.11.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
language_version: python3
|
language_version: python3
|
||||||
17
changelog.md
17
changelog.md
@@ -1,3 +1,18 @@
|
|||||||
|
# 10.0.0
|
||||||
|
|
||||||
|
Saves from 9.x are not compatible with 10.0.0.
|
||||||
|
|
||||||
|
## Features/Improvements
|
||||||
|
|
||||||
|
* **[Engine]** Support for DCS 2.9.2.49629 Open Beta. (F-15E JDAM and JSOW, F-16 AIM-9P, updated Falklands and Normandy airfields).
|
||||||
|
* **[UI]** Improved the description of "runway" state for FARPs, FOBs, carriers, and off-map spawns.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* **[Flight Planning]** Aircraft from even numbered flights will no longer become inaccessible when canceling a draft package.
|
||||||
|
* **[UI]** Flight members in the loadout menu are now numbered starting from 1 instead of 0.
|
||||||
|
* **[UI]** Flight plan paths are now drawn behind all other map elements, fixing rare cases where they could prevent other UI elements from being clickable.
|
||||||
|
|
||||||
# 9.0.0
|
# 9.0.0
|
||||||
|
|
||||||
Saves from 8.x are not compatible with 9.0.0.
|
Saves from 8.x are not compatible with 9.0.0.
|
||||||
@@ -46,7 +61,7 @@ Saves from 8.x are not compatible with 9.0.0.
|
|||||||
* **[UI]** Fixed deleting waypoints in custom flight plans deleting the wrong waypoint.
|
* **[UI]** Fixed deleting waypoints in custom flight plans deleting the wrong waypoint.
|
||||||
* **[UI]** Fixed flight properties UI to support F-15E S4+ laser codes.
|
* **[UI]** Fixed flight properties UI to support F-15E S4+ laser codes.
|
||||||
* **[UI]** In unit transfer dialog, only list control points that are reachable from the control point units are being transferred from.
|
* **[UI]** In unit transfer dialog, only list control points that are reachable from the control point units are being transferred from.
|
||||||
* **[UI]** Fixed UI bug where altering an "ahead of package" TOT offset would change the offset back to a "behind pacakge" offset.
|
* **[UI]** Fixed UI bug where altering an "ahead of package" TOT offset would change the offset back to a "behind package" offset.
|
||||||
* **[UI]** Fixed bug where changing TOT offsets could result in flight startup times that are in the past.
|
* **[UI]** Fixed bug where changing TOT offsets could result in flight startup times that are in the past.
|
||||||
* **[UI]** Fixed odd spacing of the finance window when there were not enough items to fill the page.
|
* **[UI]** Fixed odd spacing of the finance window when there were not enough items to fill the page.
|
||||||
* **[UI]** Fixed regression where waypoint altitude changes in the waypoint list screen are applied to the wrong waypoint.
|
* **[UI]** Fixed regression where waypoint altitude changes in the waypoint list screen are applied to the wrong waypoint.
|
||||||
|
|||||||
12
client/package-lock.json
generated
12
client/package-lock.json
generated
@@ -50,9 +50,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@adobe/css-tools": {
|
"node_modules/@adobe/css-tools": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
|
||||||
"integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg=="
|
"integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw=="
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@@ -21339,9 +21339,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@adobe/css-tools": {
|
"@adobe/css-tools": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
|
||||||
"integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg=="
|
"integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw=="
|
||||||
},
|
},
|
||||||
"@ampproject/remapping": {
|
"@ampproject/remapping": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Flight } from "../../api/liberationApi";
|
import { Flight } from "../../api/liberationApi";
|
||||||
import { useGetCommitBoundaryForFlightQuery } from "../../api/liberationApi";
|
import { useGetCommitBoundaryForFlightQuery } from "../../api/liberationApi";
|
||||||
import WaypointMarker from "../waypointmarker";
|
import WaypointMarker from "../waypointmarker";
|
||||||
import { ReactElement } from "react";
|
import { Polyline as LPolyline } from "leaflet";
|
||||||
|
import { ReactElement, useEffect, useRef } from "react";
|
||||||
import { Polyline } from "react-leaflet";
|
import { Polyline } from "react-leaflet";
|
||||||
|
|
||||||
const BLUE_PATH = "#0084ff";
|
const BLUE_PATH = "#0084ff";
|
||||||
@@ -27,16 +28,41 @@ const pathColor = (props: FlightPlanProps) => {
|
|||||||
function FlightPlanPath(props: FlightPlanProps) {
|
function FlightPlanPath(props: FlightPlanProps) {
|
||||||
const color = pathColor(props);
|
const color = pathColor(props);
|
||||||
const waypoints = props.flight.waypoints;
|
const waypoints = props.flight.waypoints;
|
||||||
|
|
||||||
|
const polylineRef = useRef<LPolyline | null>(null);
|
||||||
|
|
||||||
|
// Flight paths should be drawn under everything else. There seems to be an
|
||||||
|
// issue where `interactive: false` doesn't do as its told (there's nuance,
|
||||||
|
// see the bug for details). It looks better if we draw the other elements on
|
||||||
|
// top of the flight plans anyway, so just push the flight plan to the back.
|
||||||
|
//
|
||||||
|
// https://github.com/dcs-liberation/dcs_liberation/issues/3295
|
||||||
|
//
|
||||||
|
// It's not possible to z-index a polyline (and leaflet says it never will be,
|
||||||
|
// because this is a limitation of SVG, not leaflet:
|
||||||
|
// https://github.com/Leaflet/Leaflet/issues/185), so we need to use
|
||||||
|
// bringToBack() to push the flight paths to the back of the drawing once
|
||||||
|
// they've been added to the map. They'll still draw on top of the map, but
|
||||||
|
// behind everything than was added before them. Anything added after always
|
||||||
|
// goes on top.
|
||||||
|
useEffect(() => {
|
||||||
|
if (!props.selected) {
|
||||||
|
polylineRef.current?.bringToBack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (waypoints == null) {
|
if (waypoints == null) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
const points = waypoints
|
const points = waypoints
|
||||||
.filter((waypoint) => waypoint.include_in_path)
|
.filter((waypoint) => waypoint.include_in_path)
|
||||||
.map((waypoint) => waypoint.position);
|
.map((waypoint) => waypoint.position);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Polyline
|
<Polyline
|
||||||
positions={points}
|
positions={points}
|
||||||
pathOptions={{ color: color, interactive: false }}
|
pathOptions={{ color: color, interactive: false }}
|
||||||
|
ref={polylineRef}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,8 +95,12 @@ describe("FlightPlansLayer", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(mockPolyline).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockLayerGroup).toBeCalledTimes(1);
|
// For some reason passing ref to PolyLine causes it and its group to be
|
||||||
|
// redrawn, so these numbers don't match what you'd expect from the test.
|
||||||
|
// It probably needs to be rewritten without mocks.
|
||||||
|
expect(mockPolyline).toHaveBeenCalledTimes(3);
|
||||||
|
expect(mockLayerGroup).toBeCalledTimes(2);
|
||||||
});
|
});
|
||||||
it("are not drawn if wrong coalition", () => {
|
it("are not drawn if wrong coalition", () => {
|
||||||
renderWithProviders(<FlightPlansLayer blue={true} />, {
|
renderWithProviders(<FlightPlansLayer blue={true} />, {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
project = "DCS Liberation"
|
project = "DCS Liberation"
|
||||||
copyright = "2023, DCS Liberation Team"
|
copyright = "2023, DCS Liberation Team"
|
||||||
author = "DCS Liberation Team"
|
author = "DCS Liberation Team"
|
||||||
release = "9.0.0"
|
release = "10.0.0"
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]):
|
|||||||
|
|
||||||
class Builder(IBuilder[RecoveryTankerFlightPlan, RecoveryTankerLayout]):
|
class Builder(IBuilder[RecoveryTankerFlightPlan, RecoveryTankerLayout]):
|
||||||
def layout(self) -> RecoveryTankerLayout:
|
def layout(self) -> RecoveryTankerLayout:
|
||||||
|
|
||||||
builder = WaypointBuilder(self.flight, self.coalition)
|
builder = WaypointBuilder(self.flight, self.coalition)
|
||||||
|
|
||||||
# TODO: Propagate the ship position to the Tanker's TOT,
|
# TODO: Propagate the ship position to the Tanker's TOT,
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ class GroundSpeed:
|
|||||||
# on fuel, but mission speed will be fast enough to keep the flight
|
# on fuel, but mission speed will be fast enough to keep the flight
|
||||||
# safer.
|
# safer.
|
||||||
|
|
||||||
|
if flight.squadron.aircraft.cruise_speed is not None:
|
||||||
|
return mach(flight.squadron.aircraft.cruise_speed.mach(), altitude)
|
||||||
|
|
||||||
# DCS's max speed is in kph at 0 MSL.
|
# DCS's max speed is in kph at 0 MSL.
|
||||||
max_speed = flight.unit_type.max_speed
|
max_speed = flight.unit_type.max_speed
|
||||||
if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL:
|
if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL:
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ class DefaultSquadronAssigner:
|
|||||||
self.coalition.player
|
self.coalition.player
|
||||||
):
|
):
|
||||||
for squadron_config in self.config.by_location[control_point]:
|
for squadron_config in self.config.by_location[control_point]:
|
||||||
|
|
||||||
squadron_def = self.override_squadron_defaults(
|
squadron_def = self.override_squadron_defaults(
|
||||||
self.find_squadron_for(squadron_config, control_point),
|
self.find_squadron_for(squadron_config, control_point),
|
||||||
squadron_config,
|
squadron_config,
|
||||||
@@ -162,7 +161,6 @@ class DefaultSquadronAssigner:
|
|||||||
def override_squadron_defaults(
|
def override_squadron_defaults(
|
||||||
squadron_def: Optional[SquadronDef], config: SquadronConfig
|
squadron_def: Optional[SquadronDef], config: SquadronConfig
|
||||||
) -> Optional[SquadronDef]:
|
) -> Optional[SquadronDef]:
|
||||||
|
|
||||||
if squadron_def is None:
|
if squadron_def is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from game.utils import meters, nautical_miles
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
from game.transfers import CargoShip, Convoy
|
from game.transfers import CargoShip, Convoy
|
||||||
|
from game.threatzones import ThreatZones
|
||||||
|
|
||||||
MissionTargetType = TypeVar("MissionTargetType", bound=MissionTarget)
|
MissionTargetType = TypeVar("MissionTargetType", bound=MissionTarget)
|
||||||
|
|
||||||
@@ -193,17 +194,36 @@ class ObjectiveFinder:
|
|||||||
|
|
||||||
def farthest_friendly_control_point(self) -> ControlPoint:
|
def farthest_friendly_control_point(self) -> ControlPoint:
|
||||||
"""Finds the friendly control point that is farthest from any threats."""
|
"""Finds the friendly control point that is farthest from any threats."""
|
||||||
|
|
||||||
|
def find_farthest(
|
||||||
|
control_points: Iterator[ControlPoint],
|
||||||
|
threat_zones: ThreatZones,
|
||||||
|
consider_off_map_spawn: bool,
|
||||||
|
) -> ControlPoint | None:
|
||||||
|
farthest = None
|
||||||
|
max_distance = meters(0)
|
||||||
|
for cp in control_points:
|
||||||
|
if isinstance(cp, OffMapSpawn) and not consider_off_map_spawn:
|
||||||
|
continue
|
||||||
|
distance = threat_zones.distance_to_threat(cp.position)
|
||||||
|
if distance > max_distance:
|
||||||
|
farthest = cp
|
||||||
|
max_distance = distance
|
||||||
|
return farthest
|
||||||
|
|
||||||
threat_zones = self.game.threat_zone_for(not self.is_player)
|
threat_zones = self.game.threat_zone_for(not self.is_player)
|
||||||
|
|
||||||
farthest = None
|
farthest = find_farthest(
|
||||||
max_distance = meters(0)
|
self.friendly_control_points(), threat_zones, consider_off_map_spawn=False
|
||||||
for cp in self.friendly_control_points():
|
)
|
||||||
if isinstance(cp, OffMapSpawn):
|
|
||||||
continue
|
# If there are only off-map spawn control points, fall back to the farthest amongst off map spawn points
|
||||||
distance = threat_zones.distance_to_threat(cp.position)
|
if farthest is None:
|
||||||
if distance > max_distance:
|
farthest = find_farthest(
|
||||||
farthest = cp
|
self.friendly_control_points(),
|
||||||
max_distance = distance
|
threat_zones,
|
||||||
|
consider_off_map_spawn=True,
|
||||||
|
)
|
||||||
|
|
||||||
if farthest is None:
|
if farthest is None:
|
||||||
raise RuntimeError("Found no friendly control points. You probably lost.")
|
raise RuntimeError("Found no friendly control points. You probably lost.")
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import yaml
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
@@ -15,6 +21,16 @@ class GroundUnitProcurementRatios:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data: dict[str, float]) -> GroundUnitProcurementRatios:
|
||||||
|
unit_class_enum_from_name = {unit.value: unit for unit in UnitClass}
|
||||||
|
r = {}
|
||||||
|
for unit_class in data:
|
||||||
|
if unit_class not in unit_class_enum_from_name:
|
||||||
|
raise ValueError(f"Could not find unit type {unit_class}")
|
||||||
|
r[unit_class_enum_from_name[unit_class]] = float(data[unit_class])
|
||||||
|
return GroundUnitProcurementRatios(r)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Doctrine:
|
class Doctrine:
|
||||||
@@ -79,122 +95,78 @@ class Doctrine:
|
|||||||
|
|
||||||
ground_unit_procurement_ratios: GroundUnitProcurementRatios
|
ground_unit_procurement_ratios: GroundUnitProcurementRatios
|
||||||
|
|
||||||
|
_by_name: ClassVar[dict[str, Doctrine]] = {}
|
||||||
|
_loaded: ClassVar[bool] = False
|
||||||
|
|
||||||
MODERN_DOCTRINE = Doctrine(
|
@classmethod
|
||||||
"modern",
|
def register(cls, doctrine: Doctrine) -> None:
|
||||||
cap=True,
|
if doctrine.name in cls._by_name:
|
||||||
cas=True,
|
duplicate = cls._by_name[doctrine.name]
|
||||||
sead=True,
|
raise ValueError(f"Doctrine {doctrine.name} is already loaded")
|
||||||
strike=True,
|
cls._by_name[doctrine.name] = doctrine
|
||||||
antiship=True,
|
|
||||||
rendezvous_altitude=feet(25000),
|
|
||||||
hold_distance=nautical_miles(25),
|
|
||||||
push_distance=nautical_miles(20),
|
|
||||||
join_distance=nautical_miles(20),
|
|
||||||
max_ingress_distance=nautical_miles(45),
|
|
||||||
min_ingress_distance=nautical_miles(10),
|
|
||||||
ingress_altitude=feet(20000),
|
|
||||||
min_patrol_altitude=feet(15000),
|
|
||||||
max_patrol_altitude=feet(33000),
|
|
||||||
pattern_altitude=feet(5000),
|
|
||||||
cap_duration=timedelta(minutes=30),
|
|
||||||
cap_min_track_length=nautical_miles(15),
|
|
||||||
cap_max_track_length=nautical_miles(40),
|
|
||||||
cap_min_distance_from_cp=nautical_miles(10),
|
|
||||||
cap_max_distance_from_cp=nautical_miles(40),
|
|
||||||
cap_engagement_range=nautical_miles(50),
|
|
||||||
cas_duration=timedelta(minutes=30),
|
|
||||||
sweep_distance=nautical_miles(60),
|
|
||||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios(
|
|
||||||
{
|
|
||||||
UnitClass.TANK: 3,
|
|
||||||
UnitClass.ATGM: 2,
|
|
||||||
UnitClass.APC: 2,
|
|
||||||
UnitClass.IFV: 3,
|
|
||||||
UnitClass.ARTILLERY: 1,
|
|
||||||
UnitClass.SHORAD: 2,
|
|
||||||
UnitClass.RECON: 1,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
COLDWAR_DOCTRINE = Doctrine(
|
@classmethod
|
||||||
name="coldwar",
|
def named(cls, name: str) -> Doctrine:
|
||||||
cap=True,
|
if not cls._loaded:
|
||||||
cas=True,
|
cls.load_all()
|
||||||
sead=True,
|
return cls._by_name[name]
|
||||||
strike=True,
|
|
||||||
antiship=True,
|
|
||||||
rendezvous_altitude=feet(22000),
|
|
||||||
hold_distance=nautical_miles(15),
|
|
||||||
push_distance=nautical_miles(10),
|
|
||||||
join_distance=nautical_miles(10),
|
|
||||||
max_ingress_distance=nautical_miles(30),
|
|
||||||
min_ingress_distance=nautical_miles(10),
|
|
||||||
ingress_altitude=feet(18000),
|
|
||||||
min_patrol_altitude=feet(10000),
|
|
||||||
max_patrol_altitude=feet(24000),
|
|
||||||
pattern_altitude=feet(5000),
|
|
||||||
cap_duration=timedelta(minutes=30),
|
|
||||||
cap_min_track_length=nautical_miles(12),
|
|
||||||
cap_max_track_length=nautical_miles(24),
|
|
||||||
cap_min_distance_from_cp=nautical_miles(8),
|
|
||||||
cap_max_distance_from_cp=nautical_miles(25),
|
|
||||||
cap_engagement_range=nautical_miles(35),
|
|
||||||
cas_duration=timedelta(minutes=30),
|
|
||||||
sweep_distance=nautical_miles(40),
|
|
||||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios(
|
|
||||||
{
|
|
||||||
UnitClass.TANK: 4,
|
|
||||||
UnitClass.ATGM: 2,
|
|
||||||
UnitClass.APC: 3,
|
|
||||||
UnitClass.IFV: 2,
|
|
||||||
UnitClass.ARTILLERY: 1,
|
|
||||||
UnitClass.SHORAD: 2,
|
|
||||||
UnitClass.RECON: 1,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
WWII_DOCTRINE = Doctrine(
|
@classmethod
|
||||||
name="ww2",
|
def all_doctrines(cls) -> list[Doctrine]:
|
||||||
cap=True,
|
if not cls._loaded:
|
||||||
cas=True,
|
cls.load_all()
|
||||||
sead=False,
|
return list(cls._by_name.values())
|
||||||
strike=True,
|
|
||||||
antiship=True,
|
|
||||||
hold_distance=nautical_miles(10),
|
|
||||||
push_distance=nautical_miles(5),
|
|
||||||
join_distance=nautical_miles(5),
|
|
||||||
rendezvous_altitude=feet(10000),
|
|
||||||
max_ingress_distance=nautical_miles(7),
|
|
||||||
min_ingress_distance=nautical_miles(5),
|
|
||||||
ingress_altitude=feet(8000),
|
|
||||||
min_patrol_altitude=feet(4000),
|
|
||||||
max_patrol_altitude=feet(15000),
|
|
||||||
pattern_altitude=feet(5000),
|
|
||||||
cap_duration=timedelta(minutes=30),
|
|
||||||
cap_min_track_length=nautical_miles(8),
|
|
||||||
cap_max_track_length=nautical_miles(18),
|
|
||||||
cap_min_distance_from_cp=nautical_miles(0),
|
|
||||||
cap_max_distance_from_cp=nautical_miles(5),
|
|
||||||
cap_engagement_range=nautical_miles(20),
|
|
||||||
cas_duration=timedelta(minutes=30),
|
|
||||||
sweep_distance=nautical_miles(10),
|
|
||||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios(
|
|
||||||
{
|
|
||||||
UnitClass.TANK: 3,
|
|
||||||
UnitClass.ATGM: 3,
|
|
||||||
UnitClass.APC: 3,
|
|
||||||
UnitClass.ARTILLERY: 1,
|
|
||||||
UnitClass.SHORAD: 3,
|
|
||||||
UnitClass.RECON: 1,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
ALL_DOCTRINES = [
|
@classmethod
|
||||||
COLDWAR_DOCTRINE,
|
def load_all(cls) -> None:
|
||||||
MODERN_DOCTRINE,
|
if cls._loaded:
|
||||||
WWII_DOCTRINE,
|
return
|
||||||
]
|
for doctrine_file_path in Path("resources/doctrines").glob("**/*.yaml"):
|
||||||
|
with doctrine_file_path.open(encoding="utf8") as doctrine_file:
|
||||||
|
data = yaml.safe_load(doctrine_file)
|
||||||
|
cls.register(
|
||||||
|
Doctrine(
|
||||||
|
name=data["name"],
|
||||||
|
cap=data["cap"],
|
||||||
|
cas=data["cas"],
|
||||||
|
sead=data["sead"],
|
||||||
|
strike=data["strike"],
|
||||||
|
antiship=data["antiship"],
|
||||||
|
rendezvous_altitude=feet(data["rendezvous_altitude_ft_msl"]),
|
||||||
|
hold_distance=nautical_miles(data["hold_distance_nm"]),
|
||||||
|
push_distance=nautical_miles(data["push_distance_nm"]),
|
||||||
|
join_distance=nautical_miles(data["join_distance_nm"]),
|
||||||
|
max_ingress_distance=nautical_miles(
|
||||||
|
data["max_ingress_distance_nm"]
|
||||||
|
),
|
||||||
|
min_ingress_distance=nautical_miles(
|
||||||
|
data["min_ingress_distance_nm"]
|
||||||
|
),
|
||||||
|
ingress_altitude=feet(data["ingress_altitude_ft_msl"]),
|
||||||
|
min_patrol_altitude=feet(data["min_patrol_altitude_ft_msl"]),
|
||||||
|
max_patrol_altitude=feet(data["max_patrol_altitude_ft_msl"]),
|
||||||
|
pattern_altitude=feet(data["pattern_altitude_ft_msl"]),
|
||||||
|
cap_duration=timedelta(minutes=data["cap_duration_minutes"]),
|
||||||
|
cap_min_track_length=nautical_miles(
|
||||||
|
data["cap_min_track_length_nm"]
|
||||||
|
),
|
||||||
|
cap_max_track_length=nautical_miles(
|
||||||
|
data["cap_max_track_length_nm"]
|
||||||
|
),
|
||||||
|
cap_min_distance_from_cp=nautical_miles(
|
||||||
|
data["cap_min_distance_from_cp_nm"]
|
||||||
|
),
|
||||||
|
cap_max_distance_from_cp=nautical_miles(
|
||||||
|
data["cap_max_distance_from_cp_nm"]
|
||||||
|
),
|
||||||
|
cap_engagement_range=nautical_miles(
|
||||||
|
data["cap_engagement_range_nm"]
|
||||||
|
),
|
||||||
|
cas_duration=timedelta(minutes=data["cas_duration_minutes"]),
|
||||||
|
sweep_distance=nautical_miles(data["sweep_distance_nm"]),
|
||||||
|
ground_unit_procurement_ratios=GroundUnitProcurementRatios.from_dict(
|
||||||
|
data["ground_unit_procurement_ratios"]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cls._loaded = True
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, replace as dataclasses_replace
|
||||||
from functools import cache, cached_property
|
from functools import cache, cached_property
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, ClassVar, Dict, Iterator, Optional, TYPE_CHECKING, Type
|
from typing import Any, ClassVar, Dict, Iterator, Optional, TYPE_CHECKING, Type
|
||||||
@@ -182,6 +182,9 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
|||||||
#: planner will consider this aircraft usable for a mission.
|
#: planner will consider this aircraft usable for a mission.
|
||||||
max_mission_range: Distance
|
max_mission_range: Distance
|
||||||
|
|
||||||
|
#: Speed used for TOT calculations
|
||||||
|
cruise_speed: Optional[Speed]
|
||||||
|
|
||||||
fuel_consumption: Optional[FuelConsumption]
|
fuel_consumption: Optional[FuelConsumption]
|
||||||
|
|
||||||
default_livery: Optional[str]
|
default_livery: Optional[str]
|
||||||
@@ -400,6 +403,12 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
|||||||
for k in config:
|
for k in config:
|
||||||
if k in aircraft.property_defaults:
|
if k in aircraft.property_defaults:
|
||||||
aircraft.property_defaults[k] = config[k]
|
aircraft.property_defaults[k] = config[k]
|
||||||
|
# In addition to setting the property_defaults, we have to set the "default" property in the
|
||||||
|
# value of aircraft.properties for the key, as this is used in parts of the codebase to get
|
||||||
|
# the default value.
|
||||||
|
aircraft.properties[k] = dataclasses_replace(
|
||||||
|
aircraft.properties[k], default=config[k]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"'{aircraft.id}' attempted to set default prop '{k}' that does not exist"
|
f"'{aircraft.id}' attempted to set default prop '{k}' that does not exist"
|
||||||
@@ -489,6 +498,9 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
|||||||
patrol_altitude=patrol_config.altitude,
|
patrol_altitude=patrol_config.altitude,
|
||||||
patrol_speed=patrol_config.speed,
|
patrol_speed=patrol_config.speed,
|
||||||
max_mission_range=mission_range,
|
max_mission_range=mission_range,
|
||||||
|
cruise_speed=knots(data["cruise_speed_kt_indicated"])
|
||||||
|
if "cruise_speed_kt_indicated" in data
|
||||||
|
else None,
|
||||||
fuel_consumption=fuel_consumption,
|
fuel_consumption=fuel_consumption,
|
||||||
default_livery=data.get("default_livery"),
|
default_livery=data.get("default_livery"),
|
||||||
intra_flight_radio=radio_config.intra_flight,
|
intra_flight_radio=radio_config.intra_flight,
|
||||||
|
|||||||
@@ -19,12 +19,7 @@ from game.data.building_data import (
|
|||||||
WW2_FREE,
|
WW2_FREE,
|
||||||
WW2_GERMANY_BUILDINGS,
|
WW2_GERMANY_BUILDINGS,
|
||||||
)
|
)
|
||||||
from game.data.doctrine import (
|
from game.data.doctrine import Doctrine
|
||||||
COLDWAR_DOCTRINE,
|
|
||||||
Doctrine,
|
|
||||||
MODERN_DOCTRINE,
|
|
||||||
WWII_DOCTRINE,
|
|
||||||
)
|
|
||||||
from game.data.groups import GroupRole
|
from game.data.groups import GroupRole
|
||||||
from game.data.units import UnitClass
|
from game.data.units import UnitClass
|
||||||
from game.dcs.aircrafttype import AircraftType
|
from game.dcs.aircrafttype import AircraftType
|
||||||
@@ -106,7 +101,7 @@ class Faction:
|
|||||||
jtac_unit: Optional[AircraftType] = field(default=None)
|
jtac_unit: Optional[AircraftType] = field(default=None)
|
||||||
|
|
||||||
# doctrine
|
# doctrine
|
||||||
doctrine: Doctrine = field(default=MODERN_DOCTRINE)
|
doctrine: Doctrine = field(default=Doctrine.named("modern"))
|
||||||
|
|
||||||
# List of available building layouts for this faction
|
# List of available building layouts for this faction
|
||||||
building_set: List[str] = field(default_factory=list)
|
building_set: List[str] = field(default_factory=list)
|
||||||
@@ -238,14 +233,7 @@ class Faction:
|
|||||||
|
|
||||||
# Load doctrine
|
# Load doctrine
|
||||||
doctrine = json.get("doctrine", "modern")
|
doctrine = json.get("doctrine", "modern")
|
||||||
if doctrine == "modern":
|
faction.doctrine = Doctrine.named(doctrine)
|
||||||
faction.doctrine = MODERN_DOCTRINE
|
|
||||||
elif doctrine == "coldwar":
|
|
||||||
faction.doctrine = COLDWAR_DOCTRINE
|
|
||||||
elif doctrine == "ww2":
|
|
||||||
faction.doctrine = WWII_DOCTRINE
|
|
||||||
else:
|
|
||||||
faction.doctrine = MODERN_DOCTRINE
|
|
||||||
|
|
||||||
# Load the building set
|
# Load the building set
|
||||||
faction.building_set = []
|
faction.building_set = []
|
||||||
|
|||||||
@@ -11,17 +11,14 @@ from shapely import transform
|
|||||||
from shapely.geometry import shape
|
from shapely.geometry import shape
|
||||||
from shapely.geometry.base import BaseGeometry
|
from shapely.geometry.base import BaseGeometry
|
||||||
|
|
||||||
from game.data.doctrine import Doctrine, ALL_DOCTRINES
|
from game.data.doctrine import Doctrine
|
||||||
from .ipsolver import IpSolver
|
from .ipsolver import IpSolver
|
||||||
from .waypointsolver import WaypointSolver
|
from .waypointsolver import WaypointSolver
|
||||||
from ..theater.theaterloader import TERRAINS_BY_NAME
|
from ..theater.theaterloader import TERRAINS_BY_NAME
|
||||||
|
|
||||||
|
|
||||||
def doctrine_from_name(name: str) -> Doctrine:
|
def doctrine_from_name(name: str) -> Doctrine:
|
||||||
for doctrine in ALL_DOCTRINES:
|
return Doctrine.named(name)
|
||||||
if doctrine.name == name:
|
|
||||||
return doctrine
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
|
|
||||||
def geometry_ll_to_xy(geometry: BaseGeometry, terrain: Terrain) -> BaseGeometry:
|
def geometry_ll_to_xy(geometry: BaseGeometry, terrain: Terrain) -> BaseGeometry:
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ class RequirementBuilder:
|
|||||||
def maximum_turn_to(
|
def maximum_turn_to(
|
||||||
self, turn_point: Point, next_point: Point, turn_limit: Heading
|
self, turn_point: Point, next_point: Point, turn_limit: Heading
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
large_distance = nautical_miles(400)
|
large_distance = nautical_miles(400)
|
||||||
next_heading = Heading.from_degrees(
|
next_heading = Heading.from_degrees(
|
||||||
angle_between_points(next_point, turn_point)
|
angle_between_points(next_point, turn_point)
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ class GroundPlanner:
|
|||||||
self.reserve: List[CombatGroup] = []
|
self.reserve: List[CombatGroup] = []
|
||||||
|
|
||||||
def plan_groundwar(self) -> None:
|
def plan_groundwar(self) -> None:
|
||||||
|
|
||||||
ground_unit_limit = self.cp.frontline_unit_count_limit
|
ground_unit_limit = self.cp.frontline_unit_count_limit
|
||||||
|
|
||||||
remaining_available_frontline_units = ground_unit_limit
|
remaining_available_frontline_units = ground_unit_limit
|
||||||
@@ -139,7 +138,6 @@ class GroundPlanner:
|
|||||||
remaining_available_frontline_units -= available
|
remaining_available_frontline_units -= available
|
||||||
|
|
||||||
while available > 0:
|
while available > 0:
|
||||||
|
|
||||||
if role == CombatGroupRole.SHORAD:
|
if role == CombatGroupRole.SHORAD:
|
||||||
count = 1
|
count = 1
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -241,7 +241,6 @@ class AntiAirLayout(TgoLayout):
|
|||||||
location: PresetLocation,
|
location: PresetLocation,
|
||||||
control_point: ControlPoint,
|
control_point: ControlPoint,
|
||||||
) -> IadsGroundObject:
|
) -> IadsGroundObject:
|
||||||
|
|
||||||
if GroupTask.EARLY_WARNING_RADAR in self.tasks:
|
if GroupTask.EARLY_WARNING_RADAR in self.tasks:
|
||||||
return EwrGroundObject(name, location, control_point)
|
return EwrGroundObject(name, location, control_point)
|
||||||
elif any(tasking in self.tasks for tasking in GroupRole.AIR_DEFENSE.tasks):
|
elif any(tasking in self.tasks for tasking in GroupRole.AIR_DEFENSE.tasks):
|
||||||
|
|||||||
@@ -132,7 +132,6 @@ class LayoutLoader:
|
|||||||
temp_mis.country(country.name).ship_group,
|
temp_mis.country(country.name).ship_group,
|
||||||
temp_mis.country(country.name).static_group,
|
temp_mis.country(country.name).static_group,
|
||||||
):
|
):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
g_id, u_id, group_name, group_mapping = mapping.group_for_name(
|
g_id, u_id, group_name, group_mapping = mapping.group_for_name(
|
||||||
dcs_group.name
|
dcs_group.name
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
|
|||||||
|
|
||||||
class RecoveryTankerBuilder(PydcsWaypointBuilder):
|
class RecoveryTankerBuilder(PydcsWaypointBuilder):
|
||||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||||
|
|
||||||
assert self.flight.flight_type == FlightType.REFUELING
|
assert self.flight.flight_type == FlightType.REFUELING
|
||||||
|
|
||||||
# Tanker task required in conjunction with RecoveryTanker task.
|
# Tanker task required in conjunction with RecoveryTanker task.
|
||||||
@@ -48,7 +47,6 @@ class RecoveryTankerBuilder(PydcsWaypointBuilder):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def configure_tanker_tacan(self, waypoint: MovingPoint) -> None:
|
def configure_tanker_tacan(self, waypoint: MovingPoint) -> None:
|
||||||
|
|
||||||
if self.flight.unit_type.dcs_unit_type.tacan:
|
if self.flight.unit_type.dcs_unit_type.tacan:
|
||||||
tanker_info = self.mission_data.tankers[-1]
|
tanker_info = self.mission_data.tankers[-1]
|
||||||
tacan = tanker_info.tacan
|
tacan = tanker_info.tacan
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
|
|||||||
|
|
||||||
class SplitPointBuilder(PydcsWaypointBuilder):
|
class SplitPointBuilder(PydcsWaypointBuilder):
|
||||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||||
|
|
||||||
if not self.flight.flight_type.is_air_to_air:
|
if not self.flight.flight_type.is_air_to_air:
|
||||||
# Capture any non A/A type to avoid issues with SPJs that use the primary radar such as the F/A-18C.
|
# Capture any non A/A type to avoid issues with SPJs that use the primary radar such as the F/A-18C.
|
||||||
# You can bully them with STT to not be able to fire radar guided missiles at you,
|
# You can bully them with STT to not be able to fire radar guided missiles at you,
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ class DrawingsGenerator:
|
|||||||
if destination in seen:
|
if destination in seen:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Determine path color
|
# Determine path color
|
||||||
if cp.captured and destination.captured:
|
if cp.captured and destination.captured:
|
||||||
color = BLUE_PATH_COLOR
|
color = BLUE_PATH_COLOR
|
||||||
|
|||||||
@@ -191,7 +191,6 @@ class FlotGenerator:
|
|||||||
side: Country,
|
side: Country,
|
||||||
forward_heading: Heading,
|
forward_heading: Heading,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
infantry_position = self.conflict.find_ground_position(
|
infantry_position = self.conflict.find_ground_position(
|
||||||
group.points[0].position.random_point_within(250, 50),
|
group.points[0].position.random_point_within(250, 50),
|
||||||
500,
|
500,
|
||||||
@@ -304,7 +303,6 @@ class FlotGenerator:
|
|||||||
|
|
||||||
# Artillery will fall back when under attack
|
# Artillery will fall back when under attack
|
||||||
if stance != CombatStance.RETREAT:
|
if stance != CombatStance.RETREAT:
|
||||||
|
|
||||||
# Hold position
|
# Hold position
|
||||||
dcs_group.points[1].tasks.append(Hold())
|
dcs_group.points[1].tasks.append(Hold())
|
||||||
retreat = self.find_retreat_point(
|
retreat = self.find_retreat_point(
|
||||||
@@ -476,7 +474,6 @@ class FlotGenerator:
|
|||||||
from_cp: ControlPoint,
|
from_cp: ControlPoint,
|
||||||
to_cp: ControlPoint,
|
to_cp: ControlPoint,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
if not self.game.settings.perf_moving_units:
|
if not self.game.settings.perf_moving_units:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ class NumberedWaypoint:
|
|||||||
|
|
||||||
|
|
||||||
class FlightPlanBuilder:
|
class FlightPlanBuilder:
|
||||||
|
|
||||||
WAYPOINT_DESC_MAX_LEN = 25
|
WAYPOINT_DESC_MAX_LEN = 25
|
||||||
|
|
||||||
def __init__(self, start_time: datetime.datetime, units: UnitSystem) -> None:
|
def __init__(self, start_time: datetime.datetime, units: UnitSystem) -> None:
|
||||||
@@ -503,7 +502,6 @@ class SupportPage(KneeboardPage):
|
|||||||
aewc_ladder = []
|
aewc_ladder = []
|
||||||
|
|
||||||
for single_aewc in self.awacs:
|
for single_aewc in self.awacs:
|
||||||
|
|
||||||
if single_aewc.depature_location is None:
|
if single_aewc.depature_location is None:
|
||||||
dep = "-"
|
dep = "-"
|
||||||
arr = "-"
|
arr = "-"
|
||||||
|
|||||||
@@ -402,7 +402,6 @@ class GenericCarrierGenerator(GroundObjectGenerator):
|
|||||||
self.mission_data = mission_data
|
self.mission_data = mission_data
|
||||||
|
|
||||||
def generate(self) -> None:
|
def generate(self) -> None:
|
||||||
|
|
||||||
# This can also be refactored as the general generation was updated
|
# This can also be refactored as the general generation was updated
|
||||||
atc = self.radio_registry.alloc_uhf()
|
atc = self.radio_registry.alloc_uhf()
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ class ProcurementAi:
|
|||||||
manage_front_line: bool,
|
manage_front_line: bool,
|
||||||
manage_aircraft: bool,
|
manage_aircraft: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self.game = game
|
self.game = game
|
||||||
self.is_player = for_player
|
self.is_player = for_player
|
||||||
self.air_wing = game.air_wing_for(for_player)
|
self.air_wing = game.air_wing_for(for_player)
|
||||||
|
|||||||
@@ -33,15 +33,19 @@ class FrozenCombatJs(BaseModel):
|
|||||||
if isinstance(combat, AtIp):
|
if isinstance(combat, AtIp):
|
||||||
return FrozenCombatJs(
|
return FrozenCombatJs(
|
||||||
id=combat.id,
|
id=combat.id,
|
||||||
flight_position=combat.flight.position().latlng(),
|
flight_position=LeafletPoint.from_pydcs(combat.flight.position()),
|
||||||
target_positions=[combat.flight.package.target.position.latlng()],
|
target_positions=[
|
||||||
|
LeafletPoint.from_pydcs(combat.flight.package.target.position)
|
||||||
|
],
|
||||||
footprint=None,
|
footprint=None,
|
||||||
)
|
)
|
||||||
if isinstance(combat, DefendingSam):
|
if isinstance(combat, DefendingSam):
|
||||||
return FrozenCombatJs(
|
return FrozenCombatJs(
|
||||||
id=combat.id,
|
id=combat.id,
|
||||||
flight_position=combat.flight.position().latlng(),
|
flight_position=LeafletPoint.from_pydcs(combat.flight.position()),
|
||||||
target_positions=[sam.position.latlng() for sam in combat.air_defenses],
|
target_positions=[
|
||||||
|
LeafletPoint.from_pydcs(sam.position) for sam in combat.air_defenses
|
||||||
|
],
|
||||||
footprint=None,
|
footprint=None,
|
||||||
)
|
)
|
||||||
raise NotImplementedError(f"Unhandled FrozenCombat type: {combat.__class__}")
|
raise NotImplementedError(f"Unhandled FrozenCombat type: {combat.__class__}")
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ class ControlPointJs(BaseModel):
|
|||||||
def for_control_point(control_point: ControlPoint) -> ControlPointJs:
|
def for_control_point(control_point: ControlPoint) -> ControlPointJs:
|
||||||
destination = None
|
destination = None
|
||||||
if control_point.target_position is not None:
|
if control_point.target_position is not None:
|
||||||
destination = control_point.target_position.latlng()
|
destination = LeafletPoint.from_pydcs(control_point.target_position)
|
||||||
return ControlPointJs(
|
return ControlPointJs(
|
||||||
id=control_point.id,
|
id=control_point.id,
|
||||||
name=control_point.name,
|
name=control_point.name,
|
||||||
blue=control_point.captured,
|
blue=control_point.captured,
|
||||||
position=control_point.position.latlng(),
|
position=LeafletPoint.from_pydcs(control_point.position),
|
||||||
mobile=control_point.moveable and control_point.captured,
|
mobile=control_point.moveable and control_point.captured,
|
||||||
destination=destination,
|
destination=destination,
|
||||||
sidc=str(control_point.sidc()),
|
sidc=str(control_point.sidc()),
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ class GameUpdateEventsJs(BaseModel):
|
|||||||
def from_events(
|
def from_events(
|
||||||
cls, events: GameUpdateEvents, game: Game | None
|
cls, events: GameUpdateEvents, game: Game | None
|
||||||
) -> GameUpdateEventsJs:
|
) -> GameUpdateEventsJs:
|
||||||
|
|
||||||
# We still need to be able to send update events when there is no game loaded
|
# We still need to be able to send update events when there is no game loaded
|
||||||
# because we need to send the unload event.
|
# because we need to send the unload event.
|
||||||
new_combats = []
|
new_combats = []
|
||||||
@@ -81,9 +80,13 @@ class GameUpdateEventsJs(BaseModel):
|
|||||||
for f in events.updated_front_lines
|
for f in events.updated_front_lines
|
||||||
]
|
]
|
||||||
|
|
||||||
|
reset_on_map_center: LeafletPoint | None = None
|
||||||
|
if events.reset_on_map_center is not None:
|
||||||
|
reset_on_map_center = LeafletPoint.from_pydcs(events.reset_on_map_center)
|
||||||
return GameUpdateEventsJs(
|
return GameUpdateEventsJs(
|
||||||
updated_flight_positions={
|
updated_flight_positions={
|
||||||
f[0].id: f[1].latlng() for f in events.updated_flight_positions
|
f[0].id: LeafletPoint.from_pydcs(f[1])
|
||||||
|
for f in events.updated_flight_positions
|
||||||
},
|
},
|
||||||
new_combats=new_combats,
|
new_combats=new_combats,
|
||||||
updated_combats=updated_combats,
|
updated_combats=updated_combats,
|
||||||
@@ -110,7 +113,7 @@ class GameUpdateEventsJs(BaseModel):
|
|||||||
],
|
],
|
||||||
updated_iads=updated_iads,
|
updated_iads=updated_iads,
|
||||||
deleted_iads=events.deleted_iads_connections,
|
deleted_iads=events.deleted_iads_connections,
|
||||||
reset_on_map_center=events.reset_on_map_center,
|
reset_on_map_center=reset_on_map_center,
|
||||||
game_unloaded=events.game_unloaded,
|
game_unloaded=events.game_unloaded,
|
||||||
new_turn=events.new_turn,
|
new_turn=events.new_turn,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from asyncio import wait
|
from asyncio import wait, Future
|
||||||
|
|
||||||
from fastapi import APIRouter, WebSocket
|
from fastapi import APIRouter, WebSocket
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
@@ -16,9 +16,9 @@ class ConnectionManager:
|
|||||||
self.active_connections: list[WebSocket] = []
|
self.active_connections: list[WebSocket] = []
|
||||||
|
|
||||||
async def shutdown(self) -> None:
|
async def shutdown(self) -> None:
|
||||||
futures = []
|
futures: list[Future[None]] = []
|
||||||
for connection in self.active_connections:
|
for connection in self.active_connections:
|
||||||
futures.append(connection.close())
|
futures.append(asyncio.create_task(connection.close()))
|
||||||
await wait(futures)
|
await wait(futures)
|
||||||
|
|
||||||
async def connect(self, websocket: WebSocket) -> None:
|
async def connect(self, websocket: WebSocket) -> None:
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class FlightJs(BaseModel):
|
|||||||
# lost.
|
# lost.
|
||||||
position = None
|
position = None
|
||||||
if isinstance(flight.state, InFlight) or isinstance(flight.state, Killed):
|
if isinstance(flight.state, InFlight) or isinstance(flight.state, Killed):
|
||||||
position = flight.position().latlng()
|
position = LeafletPoint.from_pydcs(flight.position())
|
||||||
waypoints = None
|
waypoints = None
|
||||||
if with_waypoints:
|
if with_waypoints:
|
||||||
waypoints = waypoints_for_flight(flight)
|
waypoints = waypoints_for_flight(flight)
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ class FrontLineJs(BaseModel):
|
|||||||
bounds = FrontLineConflictDescription.frontline_bounds(front_line, theater)
|
bounds = FrontLineConflictDescription.frontline_bounds(front_line, theater)
|
||||||
return FrontLineJs(
|
return FrontLineJs(
|
||||||
id=front_line.id,
|
id=front_line.id,
|
||||||
extents=[bounds.left_position.latlng(), bounds.right_position.latlng()],
|
extents=[
|
||||||
|
LeafletPoint.from_pydcs(bounds.left_position),
|
||||||
|
LeafletPoint.from_pydcs(bounds.right_position),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ from pydantic import BaseModel
|
|||||||
from game.server.controlpoints.models import ControlPointJs
|
from game.server.controlpoints.models import ControlPointJs
|
||||||
from game.server.flights.models import FlightJs
|
from game.server.flights.models import FlightJs
|
||||||
from game.server.frontlines.models import FrontLineJs
|
from game.server.frontlines.models import FrontLineJs
|
||||||
|
from game.server.iadsnetwork.models import IadsNetworkJs
|
||||||
from game.server.leaflet import LeafletPoint
|
from game.server.leaflet import LeafletPoint
|
||||||
from game.server.mapzones.models import ThreatZoneContainerJs, UnculledZoneJs
|
from game.server.mapzones.models import ThreatZoneContainerJs, UnculledZoneJs
|
||||||
from game.server.navmesh.models import NavMeshesJs
|
from game.server.navmesh.models import NavMeshesJs
|
||||||
from game.server.supplyroutes.models import SupplyRouteJs
|
from game.server.supplyroutes.models import SupplyRouteJs
|
||||||
from game.server.tgos.models import TgoJs
|
from game.server.tgos.models import TgoJs
|
||||||
from game.server.iadsnetwork.models import IadsConnectionJs, IadsNetworkJs
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
@@ -44,6 +44,8 @@ class GameJs(BaseModel):
|
|||||||
iads_network=IadsNetworkJs.from_network(game.theater.iads_network),
|
iads_network=IadsNetworkJs.from_network(game.theater.iads_network),
|
||||||
threat_zones=ThreatZoneContainerJs.for_game(game),
|
threat_zones=ThreatZoneContainerJs.for_game(game),
|
||||||
navmeshes=NavMeshesJs.from_game(game),
|
navmeshes=NavMeshesJs.from_game(game),
|
||||||
map_center=game.theater.terrain.map_view_default.position.latlng(),
|
map_center=LeafletPoint.from_pydcs(
|
||||||
|
game.theater.terrain.map_view_default.position
|
||||||
|
),
|
||||||
unculled_zones=UnculledZoneJs.from_game(game),
|
unculled_zones=UnculledZoneJs.from_game(game),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from game.server.leaflet import LeafletPoint
|
from game.server.leaflet import LeafletPoint
|
||||||
from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode, IadsNetwork
|
from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode, IadsNetwork
|
||||||
from game.theater.theatergroundobject import TheaterGroundObject
|
|
||||||
|
|
||||||
|
|
||||||
class IadsConnectionJs(BaseModel):
|
class IadsConnectionJs(BaseModel):
|
||||||
@@ -45,8 +45,8 @@ class IadsConnectionJs(BaseModel):
|
|||||||
IadsConnectionJs(
|
IadsConnectionJs(
|
||||||
id=id,
|
id=id,
|
||||||
points=[
|
points=[
|
||||||
tgo.position.latlng(),
|
LeafletPoint.from_pydcs(tgo.position),
|
||||||
connection.ground_object.position.latlng(),
|
LeafletPoint.from_pydcs(connection.ground_object.position),
|
||||||
],
|
],
|
||||||
node=tgo.id,
|
node=tgo.id,
|
||||||
connected=connection.ground_object.id,
|
connected=connection.ground_object.id,
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ class LeafletPoint(BaseModel):
|
|||||||
|
|
||||||
title = "LatLng"
|
title = "LatLng"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_pydcs(point: Point) -> LeafletPoint:
|
||||||
|
latlng = point.latlng()
|
||||||
|
return LeafletPoint(lat=latlng.lat, lng=latlng.lng)
|
||||||
|
|
||||||
|
|
||||||
LeafletLine = list[LeafletPoint]
|
LeafletLine = list[LeafletPoint]
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class UnculledZoneJs(BaseModel):
|
|||||||
def from_game(game: Game) -> list[UnculledZoneJs]:
|
def from_game(game: Game) -> list[UnculledZoneJs]:
|
||||||
return [
|
return [
|
||||||
UnculledZoneJs(
|
UnculledZoneJs(
|
||||||
position=zone.latlng(),
|
position=LeafletPoint.from_pydcs(zone),
|
||||||
radius=game.settings.perf_culling_distance * 1000,
|
radius=game.settings.perf_culling_distance * 1000,
|
||||||
)
|
)
|
||||||
for zone in game.get_culling_zones()
|
for zone in game.get_culling_zones()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
|
||||||
from pydantic import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
class ServerSettings(BaseSettings):
|
class ServerSettings(BaseSettings):
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class SupplyRouteJs(BaseModel):
|
|||||||
# https://reactjs.org/docs/lists-and-keys.html#keys
|
# https://reactjs.org/docs/lists-and-keys.html#keys
|
||||||
# https://github.com/dcs-liberation/dcs_liberation/issues/2167
|
# https://github.com/dcs-liberation/dcs_liberation/issues/2167
|
||||||
id=uuid.uuid4(),
|
id=uuid.uuid4(),
|
||||||
points=[p.latlng() for p in points],
|
points=[LeafletPoint.from_pydcs(p) for p in points],
|
||||||
front_active=not sea and a.front_is_active(b),
|
front_active=not sea and a.front_is_active(b),
|
||||||
is_sea=sea,
|
is_sea=sea,
|
||||||
blue=a.captured,
|
blue=a.captured,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class TgoJs(BaseModel):
|
|||||||
control_point_name=tgo.control_point.name,
|
control_point_name=tgo.control_point.name,
|
||||||
category=tgo.category,
|
category=tgo.category,
|
||||||
blue=tgo.control_point.captured,
|
blue=tgo.control_point.captured,
|
||||||
position=tgo.position.latlng(),
|
position=LeafletPoint.from_pydcs(tgo.position),
|
||||||
units=[unit.display_name for unit in tgo.units],
|
units=[unit.display_name for unit in tgo.units],
|
||||||
threat_ranges=threat_ranges,
|
threat_ranges=threat_ranges,
|
||||||
detection_ranges=detection_ranges,
|
detection_ranges=detection_ranges,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class FlightWaypointJs(BaseModel):
|
|||||||
|
|
||||||
return FlightWaypointJs(
|
return FlightWaypointJs(
|
||||||
name=waypoint.name,
|
name=waypoint.name,
|
||||||
position=waypoint.position.latlng(),
|
position=LeafletPoint.from_pydcs(waypoint.position),
|
||||||
altitude_ft=waypoint.alt.feet,
|
altitude_ft=waypoint.alt.feet,
|
||||||
altitude_reference=waypoint.alt_type,
|
altitude_reference=waypoint.alt_type,
|
||||||
is_movable=is_movable,
|
is_movable=is_movable,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING
|
|||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from dcs import Point
|
from dcs import Point
|
||||||
from dcs.mapping import LatLng
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
@@ -38,7 +37,7 @@ class GameUpdateEvents:
|
|||||||
updated_control_points: set[ControlPoint] = field(default_factory=set)
|
updated_control_points: set[ControlPoint] = field(default_factory=set)
|
||||||
updated_iads: set[IadsNetworkNode] = field(default_factory=set)
|
updated_iads: set[IadsNetworkNode] = field(default_factory=set)
|
||||||
deleted_iads_connections: set[UUID] = field(default_factory=set)
|
deleted_iads_connections: set[UUID] = field(default_factory=set)
|
||||||
reset_on_map_center: LatLng | None = None
|
reset_on_map_center: Point | None = None
|
||||||
game_unloaded: bool = False
|
game_unloaded: bool = False
|
||||||
new_turn: bool = False
|
new_turn: bool = False
|
||||||
shutting_down: bool = False
|
shutting_down: bool = False
|
||||||
@@ -140,9 +139,7 @@ class GameUpdateEvents:
|
|||||||
self.game_unloaded = True
|
self.game_unloaded = True
|
||||||
self.reset_on_map_center = None
|
self.reset_on_map_center = None
|
||||||
else:
|
else:
|
||||||
self.reset_on_map_center = (
|
self.reset_on_map_center = game.theater.terrain.map_view_default.position
|
||||||
game.theater.terrain.map_view_default.position.latlng()
|
|
||||||
)
|
|
||||||
self.game_unloaded = False
|
self.game_unloaded = False
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,6 @@ class MissionResultsProcessor:
|
|||||||
delta = DEFEAT_INFLUENCE
|
delta = DEFEAT_INFLUENCE
|
||||||
status_msg = f"Enemy casualties outnumber allied casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces claim a victory."
|
status_msg = f"Enemy casualties outnumber allied casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces claim a victory."
|
||||||
elif ally_casualties > enemy_casualties:
|
elif ally_casualties > enemy_casualties:
|
||||||
|
|
||||||
if (
|
if (
|
||||||
ally_units_alive > 2 * enemy_units_alive
|
ally_units_alive > 2 * enemy_units_alive
|
||||||
and player_aggresive
|
and player_aggresive
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ class SquadronDef:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_yaml(cls, path: Path) -> SquadronDef:
|
def from_yaml(cls, path: Path) -> SquadronDef:
|
||||||
|
|
||||||
with path.open(encoding="utf8") as squadron_file:
|
with path.open(encoding="utf8") as squadron_file:
|
||||||
data = yaml.safe_load(squadron_file)
|
data = yaml.safe_load(squadron_file)
|
||||||
|
|
||||||
|
|||||||
@@ -271,15 +271,15 @@ class RunwayStatus:
|
|||||||
def needs_repair(self) -> bool:
|
def needs_repair(self) -> bool:
|
||||||
return self.damaged and self.repair_turns_remaining is None
|
return self.damaged and self.repair_turns_remaining is None
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def describe(self) -> str:
|
||||||
if not self.damaged:
|
if not self.damaged:
|
||||||
return "Runway operational"
|
return "operational"
|
||||||
|
|
||||||
turns_remaining = self.repair_turns_remaining
|
turns_remaining = self.repair_turns_remaining
|
||||||
if turns_remaining is None:
|
if turns_remaining is None:
|
||||||
return "Runway damaged"
|
return "damaged"
|
||||||
|
|
||||||
return f"Runway repairing, {turns_remaining} turns remaining"
|
return f"repairing, {turns_remaining} turns remaining"
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
@@ -915,6 +915,10 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
|||||||
def runway_status(self) -> RunwayStatus:
|
def runway_status(self) -> RunwayStatus:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def describe_runway_status(self) -> str | None:
|
||||||
|
"""Description of the runway status suitable for UI use."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def runway_can_be_repaired(self) -> bool:
|
def runway_can_be_repaired(self) -> bool:
|
||||||
return self.runway_status.needs_repair
|
return self.runway_status.needs_repair
|
||||||
@@ -1157,6 +1161,9 @@ class Airfield(ControlPoint):
|
|||||||
def runway_status(self) -> RunwayStatus:
|
def runway_status(self) -> RunwayStatus:
|
||||||
return self._runway_status
|
return self._runway_status
|
||||||
|
|
||||||
|
def describe_runway_status(self) -> str:
|
||||||
|
return f"Runway {self.runway_status.describe()}"
|
||||||
|
|
||||||
def damage_runway(self) -> None:
|
def damage_runway(self) -> None:
|
||||||
self.runway_status.damage()
|
self.runway_status.damage()
|
||||||
|
|
||||||
@@ -1275,6 +1282,9 @@ class NavalControlPoint(ControlPoint, ABC):
|
|||||||
def runway_status(self) -> RunwayStatus:
|
def runway_status(self) -> RunwayStatus:
|
||||||
return RunwayStatus(damaged=not self.runway_is_operational())
|
return RunwayStatus(damaged=not self.runway_is_operational())
|
||||||
|
|
||||||
|
def describe_runway_status(self) -> str:
|
||||||
|
return f"Flight deck {self.runway_status.describe()}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def runway_can_be_repaired(self) -> bool:
|
def runway_can_be_repaired(self) -> bool:
|
||||||
return False
|
return False
|
||||||
@@ -1428,6 +1438,9 @@ class OffMapSpawn(ControlPoint):
|
|||||||
def runway_status(self) -> RunwayStatus:
|
def runway_status(self) -> RunwayStatus:
|
||||||
return RunwayStatus()
|
return RunwayStatus()
|
||||||
|
|
||||||
|
def describe_runway_status(self) -> str:
|
||||||
|
return f"Off-map airport {self.runway_status.describe()}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def can_deploy_ground_units(self) -> bool:
|
def can_deploy_ground_units(self) -> bool:
|
||||||
return False
|
return False
|
||||||
@@ -1474,6 +1487,11 @@ class Fob(ControlPoint):
|
|||||||
def runway_status(self) -> RunwayStatus:
|
def runway_status(self) -> RunwayStatus:
|
||||||
return RunwayStatus()
|
return RunwayStatus()
|
||||||
|
|
||||||
|
def describe_runway_status(self) -> str | None:
|
||||||
|
if not self.has_helipads:
|
||||||
|
return None
|
||||||
|
return f"FARP {self.runway_status.describe()}"
|
||||||
|
|
||||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||||
from game.ato import FlightType
|
from game.ato import FlightType
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ class TheaterGroup:
|
|||||||
|
|
||||||
def max_threat_range(self, radar_only: bool = False) -> Distance:
|
def max_threat_range(self, radar_only: bool = False) -> Distance:
|
||||||
"""Calculate the maximum threat range of the TheaterGroup.
|
"""Calculate the maximum threat range of the TheaterGroup.
|
||||||
This also checks for Launcher and Tracker Pairs and if they are functioning or not. Allows to also use only radar emitting units for the calculation with the parameter."""
|
This also checks for Launcher and Tracker Pairs and if they are functioning or not. Allows to also use only radar emitting units for the calculation with the parameter.
|
||||||
|
"""
|
||||||
max_non_radar = meters(0)
|
max_non_radar = meters(0)
|
||||||
max_telar_range = meters(0)
|
max_telar_range = meters(0)
|
||||||
max_tel_range = meters(0)
|
max_tel_range = meters(0)
|
||||||
|
|||||||
@@ -718,7 +718,6 @@ class PendingTransfers:
|
|||||||
self.order_airlift_assets_at(control_point)
|
self.order_airlift_assets_at(control_point)
|
||||||
|
|
||||||
def desired_airlift_capacity(self, control_point: ControlPoint) -> int:
|
def desired_airlift_capacity(self, control_point: ControlPoint) -> int:
|
||||||
|
|
||||||
if control_point.has_factory:
|
if control_point.has_factory:
|
||||||
is_major_hub = control_point.total_aircraft_parking > 0
|
is_major_hub = control_point.total_aircraft_parking > 0
|
||||||
# Check if there is a CP which is only reachable via Airlift
|
# Check if there is a CP which is only reachable via Airlift
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
MAJOR_VERSION = 9
|
MAJOR_VERSION = 10
|
||||||
MINOR_VERSION = 0
|
MINOR_VERSION = 0
|
||||||
MICRO_VERSION = 0
|
MICRO_VERSION = 0
|
||||||
VERSION_NUMBER = ".".join(str(v) for v in (MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION))
|
VERSION_NUMBER = ".".join(str(v) for v in (MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION))
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ class Weather(ABC):
|
|||||||
def interpolate_solar_activity(
|
def interpolate_solar_activity(
|
||||||
time_of_day: TimeOfDay, high: float, low: float
|
time_of_day: TimeOfDay, high: float, low: float
|
||||||
) -> float:
|
) -> float:
|
||||||
|
|
||||||
scale: float = 0
|
scale: float = 0
|
||||||
|
|
||||||
match time_of_day:
|
match time_of_day:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def init():
|
|||||||
|
|
||||||
if os.path.isfile(THEME_PREFERENCES_FILE_PATH):
|
if os.path.isfile(THEME_PREFERENCES_FILE_PATH):
|
||||||
try:
|
try:
|
||||||
with (open(THEME_PREFERENCES_FILE_PATH)) as prefs:
|
with open(THEME_PREFERENCES_FILE_PATH) as prefs:
|
||||||
pref_data = json.loads(prefs.read())
|
pref_data = json.loads(prefs.read())
|
||||||
__theme_index = pref_data["theme_index"]
|
__theme_index = pref_data["theme_index"]
|
||||||
set_theme_index(__theme_index)
|
set_theme_index(__theme_index)
|
||||||
@@ -83,5 +83,5 @@ def get_theme_css_file():
|
|||||||
# save current theme index to json file
|
# save current theme index to json file
|
||||||
def save_theme_config():
|
def save_theme_config():
|
||||||
pref_data = {"theme_index": get_theme_index()}
|
pref_data = {"theme_index": get_theme_index()}
|
||||||
with (open(THEME_PREFERENCES_FILE_PATH, "w")) as prefs:
|
with open(THEME_PREFERENCES_FILE_PATH, "w") as prefs:
|
||||||
prefs.write(json.dumps(pref_data))
|
prefs.write(json.dumps(pref_data))
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
from collections.abc import Iterator
|
||||||
|
|
||||||
LogHook = typing.Callable[[str], None]
|
LogHook = typing.Callable[[str], None]
|
||||||
|
|
||||||
@@ -15,6 +18,16 @@ class HookableInMemoryHandler(logging.Handler):
|
|||||||
self._log = ""
|
self._log = ""
|
||||||
self._hook = None
|
self._hook = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def iter_registered_handlers(
|
||||||
|
logger: logging.Logger | None = None,
|
||||||
|
) -> Iterator[HookableInMemoryHandler]:
|
||||||
|
if logger is None:
|
||||||
|
logger = logging.getLogger()
|
||||||
|
for handler in logger.handlers:
|
||||||
|
if isinstance(handler, HookableInMemoryHandler):
|
||||||
|
yield handler
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def log(self) -> str:
|
def log(self) -> str:
|
||||||
return self._log
|
return self._log
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ class AtoModel(QAbstractListModel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
package_model = self.find_matching_package_model(package)
|
package_model = self.find_matching_package_model(package)
|
||||||
for flight in package.flights:
|
for flight in list(package.flights):
|
||||||
if flight.state.cancelable:
|
if flight.state.cancelable:
|
||||||
package_model.delete_flight(flight)
|
package_model.delete_flight(flight)
|
||||||
events.delete_flight(flight)
|
events.delete_flight(flight)
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
|
|||||||
return waypoints
|
return waypoints
|
||||||
|
|
||||||
def find_possible_waypoints(self):
|
def find_possible_waypoints(self):
|
||||||
|
|
||||||
self.wpts = []
|
self.wpts = []
|
||||||
model = QStandardItemModel()
|
model = QStandardItemModel()
|
||||||
i = 0
|
i = 0
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from game.debriefing import Debriefing
|
|||||||
|
|
||||||
|
|
||||||
class GameUpdateSignal(QObject):
|
class GameUpdateSignal(QObject):
|
||||||
|
|
||||||
instance = None
|
instance = None
|
||||||
gameupdated = Signal(Game)
|
gameupdated = Signal(Game)
|
||||||
budgetupdated = Signal(Game)
|
budgetupdated = Signal(Game)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ from game.theater import ControlPoint, MissionTarget, TheaterGroundObject
|
|||||||
from game.turnstate import TurnState
|
from game.turnstate import TurnState
|
||||||
from qt_ui import liberation_install
|
from qt_ui import liberation_install
|
||||||
from qt_ui.dialogs import Dialog
|
from qt_ui.dialogs import Dialog
|
||||||
|
from qt_ui.logging_handler import HookableInMemoryHandler
|
||||||
from qt_ui.models import GameModel
|
from qt_ui.models import GameModel
|
||||||
from qt_ui.simcontroller import SimController
|
from qt_ui.simcontroller import SimController
|
||||||
from qt_ui.uiflags import UiFlags
|
from qt_ui.uiflags import UiFlags
|
||||||
@@ -576,6 +577,10 @@ class QLiberationWindow(QMainWindow):
|
|||||||
self._cp_dialog = QBaseMenu2(None, cp, self.game_model)
|
self._cp_dialog = QBaseMenu2(None, cp, self.game_model)
|
||||||
self._cp_dialog.show()
|
self._cp_dialog.show()
|
||||||
|
|
||||||
|
def _disconnect_log_signals(self) -> None:
|
||||||
|
for handler in HookableInMemoryHandler.iter_registered_handlers():
|
||||||
|
handler.clearHook()
|
||||||
|
|
||||||
def _qsettings(self) -> QSettings:
|
def _qsettings(self) -> QSettings:
|
||||||
return QSettings("DCS Liberation", "Qt UI")
|
return QSettings("DCS Liberation", "Qt UI")
|
||||||
|
|
||||||
@@ -597,6 +602,7 @@ class QLiberationWindow(QMainWindow):
|
|||||||
QMessageBox.Yes | QMessageBox.No,
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
)
|
)
|
||||||
if result == QMessageBox.Yes:
|
if result == QMessageBox.Yes:
|
||||||
|
self._disconnect_log_signals()
|
||||||
self._save_window_geometry()
|
self._save_window_geometry()
|
||||||
super().closeEvent(event)
|
super().closeEvent(event)
|
||||||
self.dialog = None
|
self.dialog = None
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
|||||||
|
|
||||||
|
|
||||||
class DebriefingFileWrittenSignal(QObject):
|
class DebriefingFileWrittenSignal(QObject):
|
||||||
|
|
||||||
instance = None
|
instance = None
|
||||||
debriefingReceived = Signal(Debriefing)
|
debriefingReceived = Signal(Debriefing)
|
||||||
|
|
||||||
|
|||||||
@@ -254,19 +254,22 @@ class QBaseMenu2(QDialog):
|
|||||||
f" (Up to {ground_unit_limit} deployable, {unit_overage} reserve)"
|
f" (Up to {ground_unit_limit} deployable, {unit_overage} reserve)"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.intel_summary.setText(
|
intel_lines = [
|
||||||
"\n".join(
|
f"{aircraft}/{parking} aircraft",
|
||||||
[
|
f"{self.cp.base.total_armor} ground units" + deployable_unit_info,
|
||||||
f"{aircraft}/{parking} aircraft",
|
f"{allocated.total_transferring} more ground units en route, {allocated.total_ordered} ordered",
|
||||||
f"{self.cp.base.total_armor} ground units" + deployable_unit_info,
|
]
|
||||||
f"{allocated.total_transferring} more ground units en route, {allocated.total_ordered} ordered",
|
if (runway_description := self.cp.describe_runway_status()) is not None:
|
||||||
str(self.cp.runway_status),
|
intel_lines.append(runway_description)
|
||||||
f"{self.cp.active_ammo_depots_count}/{self.cp.total_ammo_depots_count} ammo depots",
|
intel_lines.extend(
|
||||||
f"{'Factory can produce units' if self.cp.has_factory else 'Does not have a factory'}",
|
[
|
||||||
]
|
f"{self.cp.active_ammo_depots_count}/{self.cp.total_ammo_depots_count} ammo depots",
|
||||||
)
|
f"{'Factory can produce units' if self.cp.has_factory else 'Does not have a factory'}",
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.intel_summary.setText("\n".join(intel_lines))
|
||||||
|
|
||||||
def generate_intel_tooltip(self) -> str:
|
def generate_intel_tooltip(self) -> str:
|
||||||
tooltip = (
|
tooltip = (
|
||||||
f"Deployable unit limit ({self.cp.frontline_unit_count_limit}) = {FREE_FRONTLINE_UNIT_SUPPLY} (base) + "
|
f"Deployable unit limit ({self.cp.frontline_unit_count_limit}) = {FREE_FRONTLINE_UNIT_SUPPLY} (base) + "
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ class QGroundObjectMenu(QDialog):
|
|||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
|
|
||||||
self.mainLayout = QVBoxLayout()
|
self.mainLayout = QVBoxLayout()
|
||||||
self.budget = QBudgetBox(self.game)
|
self.budget = QBudgetBox(self.game)
|
||||||
self.budget.setGame(self.game)
|
self.budget.setGame(self.game)
|
||||||
@@ -105,7 +104,6 @@ class QGroundObjectMenu(QDialog):
|
|||||||
self.setLayout(self.mainLayout)
|
self.setLayout(self.mainLayout)
|
||||||
|
|
||||||
def doLayout(self):
|
def doLayout(self):
|
||||||
|
|
||||||
self.update_total_value()
|
self.update_total_value()
|
||||||
self.intelBox = QGroupBox("Units :")
|
self.intelBox = QGroupBox("Units :")
|
||||||
self.intelLayout = QGridLayout()
|
self.intelLayout = QGridLayout()
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ class IntelWindow(QDialog):
|
|||||||
self.refresh_layout()
|
self.refresh_layout()
|
||||||
|
|
||||||
def refresh_layout(self) -> None:
|
def refresh_layout(self) -> None:
|
||||||
|
|
||||||
# Clear the existing layout
|
# Clear the existing layout
|
||||||
if self.layout():
|
if self.layout():
|
||||||
idx = 0
|
idx = 0
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import logging
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from PySide6.QtCore import Signal
|
from PySide6.QtCore import Signal
|
||||||
|
from PySide6.QtGui import QTextCursor, QIcon
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QDialog,
|
QDialog,
|
||||||
QPlainTextEdit,
|
QPlainTextEdit,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QPushButton,
|
QPushButton,
|
||||||
)
|
)
|
||||||
from PySide6.QtGui import QTextCursor, QIcon
|
|
||||||
|
|
||||||
from qt_ui.logging_handler import HookableInMemoryHandler
|
from qt_ui.logging_handler import HookableInMemoryHandler
|
||||||
|
|
||||||
@@ -50,12 +49,17 @@ class QLogsWindow(QDialog):
|
|||||||
|
|
||||||
self.appendLogSignal.connect(self.appendLog)
|
self.appendLogSignal.connect(self.appendLog)
|
||||||
|
|
||||||
self._logging_handler = None
|
try:
|
||||||
logger = logging.getLogger()
|
# This assumes that there's never more than one in memory handler. We don't
|
||||||
for handler in logger.handlers:
|
# configure more than one by default, but logging is customizable with
|
||||||
if isinstance(handler, HookableInMemoryHandler):
|
# resources/logging.yaml. If someone adds a second in-memory handler, only
|
||||||
self._logging_handler = handler
|
# the first one (in arbitrary order) will be shown.
|
||||||
break
|
self._logging_handler = next(
|
||||||
|
HookableInMemoryHandler.iter_registered_handlers()
|
||||||
|
)
|
||||||
|
except StopIteration:
|
||||||
|
self._logging_handler = None
|
||||||
|
|
||||||
if self._logging_handler is not None:
|
if self._logging_handler is not None:
|
||||||
self.textbox.setPlainText(self._logging_handler.log)
|
self.textbox.setPlainText(self._logging_handler.log)
|
||||||
self.textbox.moveCursor(QTextCursor.End)
|
self.textbox.moveCursor(QTextCursor.End)
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ class QNewPackageDialog(QPackageDialog):
|
|||||||
|
|
||||||
def on_cancel(self) -> None:
|
def on_cancel(self) -> None:
|
||||||
super().on_cancel()
|
super().on_cancel()
|
||||||
for flight in self.package_model.package.flights:
|
for flight in list(self.package_model.package.flights):
|
||||||
self.package_model.cancel_or_abort_flight(flight)
|
self.package_model.cancel_or_abort_flight(flight)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ class FlightMemberSelector(QSpinBox):
|
|||||||
def __init__(self, flight: Flight, parent: QWidget | None = None) -> None:
|
def __init__(self, flight: Flight, parent: QWidget | None = None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
self.setMinimum(0)
|
self.setMinimum(1)
|
||||||
self.setMaximum(flight.count - 1)
|
self.setMaximum(flight.count)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_member(self) -> FlightMember:
|
def selected_member(self) -> FlightMember:
|
||||||
return self.flight.roster.members[self.value()]
|
return self.flight.roster.members[self.value() - 1]
|
||||||
|
|
||||||
|
|
||||||
class QFlightPayloadTab(QFrame):
|
class QFlightPayloadTab(QFrame):
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ class QFlightWaypointInfoBox(QGroupBox):
|
|||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
def init_ui(self) -> None:
|
def init_ui(self) -> None:
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
x_pos_layout = QHBoxLayout()
|
x_pos_layout = QHBoxLayout()
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ class QFlightWaypointTab(QFrame):
|
|||||||
|
|
||||||
self.recreate_buttons.clear()
|
self.recreate_buttons.clear()
|
||||||
for task in self.package.target.mission_types(for_player=True):
|
for task in self.package.target.mission_types(for_player=True):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
task == FlightType.AIR_ASSAULT
|
task == FlightType.AIR_ASSAULT
|
||||||
and not self.game.lua_plugin_manager.is_plugin_enabled("ctld")
|
and not self.game.lua_plugin_manager.is_plugin_enabled("ctld")
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ PREDEFINED_WAYPOINT_CATEGORIES = [
|
|||||||
|
|
||||||
|
|
||||||
class QPredefinedWaypointSelectionWindow(QDialog):
|
class QPredefinedWaypointSelectionWindow(QDialog):
|
||||||
|
|
||||||
# List of FlightWaypoint
|
# List of FlightWaypoint
|
||||||
waypoints_added = Signal(list)
|
waypoints_added = Signal(list)
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ class QLiberationPreferences(QFrame):
|
|||||||
self.edit_dcs_install_dir.setText(install_dir)
|
self.edit_dcs_install_dir.setText(install_dir)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
|
|
||||||
print("Applying changes")
|
print("Applying changes")
|
||||||
self.saved_game_dir = self.edit_saved_game_dir.text()
|
self.saved_game_dir = self.edit_saved_game_dir.text()
|
||||||
self.dcs_install_dir = self.edit_dcs_install_dir.text()
|
self.dcs_install_dir = self.edit_dcs_install_dir.text()
|
||||||
|
|||||||
@@ -345,7 +345,6 @@ class QSettingsWindow(QDialog):
|
|||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
def initCheatLayout(self):
|
def initCheatLayout(self):
|
||||||
|
|
||||||
self.cheatPage = QWidget()
|
self.cheatPage = QWidget()
|
||||||
self.cheatLayout = QVBoxLayout()
|
self.cheatLayout = QVBoxLayout()
|
||||||
self.cheatPage.setLayout(self.cheatLayout)
|
self.cheatPage.setLayout(self.cheatLayout)
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ class QAircraftChart(QFrame):
|
|||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
def generateUnitCharts(self):
|
def generateUnitCharts(self):
|
||||||
|
|
||||||
self.alliedAircraft = [
|
self.alliedAircraft = [
|
||||||
d.allied_units.aircraft_count for d in self.game.game_stats.data_per_turn
|
d.allied_units.aircraft_count for d in self.game.game_stats.data_per_turn
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ class QArmorChart(QFrame):
|
|||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
def generateUnitCharts(self):
|
def generateUnitCharts(self):
|
||||||
|
|
||||||
self.alliedArmor = [
|
self.alliedArmor = [
|
||||||
d.allied_units.vehicles_count for d in self.game.game_stats.data_per_turn
|
d.allied_units.vehicles_count for d in self.game.game_stats.data_per_turn
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,53 +1,56 @@
|
|||||||
altgraph==0.17.3
|
altgraph==0.17.4
|
||||||
anyio==3.6.2
|
annotated-types==0.6.0
|
||||||
asgiref==3.6.0
|
anyio==3.7.1
|
||||||
attrs==22.2.0
|
asgiref==3.7.2
|
||||||
black==22.12.0
|
attrs==23.1.0
|
||||||
certifi==2023.7.22
|
black==23.11.0
|
||||||
cfgv==3.3.1
|
certifi==2023.11.17
|
||||||
click==8.1.3
|
cfgv==3.4.0
|
||||||
|
click==8.1.7
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
coverage==7.0.5
|
coverage==7.3.2
|
||||||
distlib==0.3.6
|
distlib==0.3.7
|
||||||
exceptiongroup==1.1.0
|
exceptiongroup==1.2.0
|
||||||
Faker==15.3.4
|
Faker==20.1.0
|
||||||
fastapi==0.95.2
|
fastapi==0.104.1
|
||||||
filelock==3.9.0
|
filelock==3.13.1
|
||||||
future==0.18.3
|
future==0.18.3
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
httptools==0.5.0
|
httptools==0.6.1
|
||||||
identify==2.5.11
|
identify==2.5.32
|
||||||
idna==3.4
|
idna==3.6
|
||||||
iniconfig==1.1.1
|
iniconfig==2.0.0
|
||||||
Jinja2==3.1.2
|
Jinja2==3.1.2
|
||||||
MarkupSafe==2.1.1
|
MarkupSafe==2.1.3
|
||||||
mypy==1.2.0
|
mypy==1.7.1
|
||||||
mypy-extensions==1.0.0
|
mypy-extensions==1.0.0
|
||||||
nodeenv==1.7.0
|
nodeenv==1.8.0
|
||||||
numpy==1.25.1
|
numpy==1.26.2
|
||||||
packaging==22.0
|
packaging==23.2
|
||||||
pathspec==0.10.3
|
pathspec==0.11.2
|
||||||
pefile==2022.5.30
|
pefile==2023.2.7
|
||||||
Pillow==10.0.1
|
Pillow==10.0.1
|
||||||
platformdirs==2.6.2
|
platformdirs==4.0.0
|
||||||
pluggy==1.0.0
|
pluggy==1.3.0
|
||||||
pre-commit==2.21.0
|
pre-commit==3.5.0
|
||||||
pydantic==1.10.7
|
pydantic==2.5.2
|
||||||
git+https://github.com/pydcs/dcs@f8232606a21eaef82af7ba78c2013403da4a86f5#egg=pydcs
|
pydantic-settings==2.1.0
|
||||||
pyinstaller==5.13.0
|
pydantic_core==2.14.5
|
||||||
|
pydcs @ git+https://github.com/pydcs/dcs@1092fc419d3f879e8e7951b25e15d8b7c9938627
|
||||||
|
pyinstaller==5.13.1
|
||||||
pyinstaller-hooks-contrib==2023.6
|
pyinstaller-hooks-contrib==2023.6
|
||||||
pyproj==3.4.1
|
pyproj==3.6.1
|
||||||
PySide6==6.4.1
|
PySide6==6.4.1
|
||||||
PySide6-Addons==6.4.1
|
PySide6-Addons==6.4.1
|
||||||
PySide6-Essentials==6.4.1
|
PySide6-Essentials==6.4.1
|
||||||
pytest==7.2.0
|
pytest==7.4.3
|
||||||
pytest-cov==4.0.0
|
pytest-cov==4.1.0
|
||||||
pytest-mock==3.10.0
|
pytest-mock==3.12.0
|
||||||
python-dateutil==2.8.2
|
python-dateutil==2.8.2
|
||||||
python-dotenv==0.21.0
|
python-dotenv==1.0.0
|
||||||
pywin32-ctypes==0.2.2
|
pywin32-ctypes==0.2.2
|
||||||
PyYAML==6.0
|
PyYAML==6.0.1
|
||||||
shapely==2.0.1
|
shapely==2.0.2
|
||||||
shiboken6==6.4.1
|
shiboken6==6.4.1
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
sniffio==1.3.0
|
sniffio==1.3.0
|
||||||
@@ -57,10 +60,10 @@ tomli==2.0.1
|
|||||||
types-Jinja2==2.11.9
|
types-Jinja2==2.11.9
|
||||||
types-MarkupSafe==1.1.10
|
types-MarkupSafe==1.1.10
|
||||||
types-Pillow==9.3.0.4
|
types-Pillow==9.3.0.4
|
||||||
types-PyYAML==6.0.12.2
|
types-PyYAML==6.0.12.12
|
||||||
types-tabulate==0.9.0.0
|
types-tabulate==0.9.0.3
|
||||||
typing_extensions==4.4.0
|
typing_extensions==4.8.0
|
||||||
uvicorn==0.20.0
|
uvicorn==0.24.0.post1
|
||||||
virtualenv==20.17.1
|
virtualenv==20.24.7
|
||||||
watchfiles==0.18.1
|
watchfiles==0.21.0
|
||||||
websockets==10.4
|
websockets==12.0
|
||||||
|
|||||||
Binary file not shown.
@@ -1,14 +1,18 @@
|
|||||||
---
|
---
|
||||||
name: Syria - The Falcon went over the mountain
|
name: Syria - The Falcon went over the mountain
|
||||||
theater: Syria
|
theater: Syria
|
||||||
authors: Sith1144
|
authors: Sith1144, updated by Astro
|
||||||
description: <p>Campaign about a task force attacking northern Syria from Incirlik. Culling recommended. Do you love SEAD? Know no greater joy in than showing SAMs who truly rules the skies? this is the campaign for you!</p>
|
description: <p>Campaign about a task force attacking northern Syria from Incirlik. Culling recommended. Do you love SEAD? Know no greater joy in than showing SAMs who truly rules the skies? this is the campaign for you!</p>
|
||||||
recommended_player_faction: USA 2005
|
recommended_player_faction: USA 2005
|
||||||
recommended_enemy_faction: Syria 2012'ish
|
recommended_enemy_faction: Syria 2012'ish
|
||||||
recommended_start_date: 2012-06-01
|
recommended_start_date: 2012-06-01
|
||||||
|
recommended_player_money: 400
|
||||||
|
recommended_enemy_money: 400
|
||||||
|
recommended_player_income_multiplier: 1.0
|
||||||
|
recommended_enemy_income_multiplier: 1.0
|
||||||
miz: TheFalconWentOverTheMountain.miz
|
miz: TheFalconWentOverTheMountain.miz
|
||||||
performance: 2
|
performance: 2
|
||||||
version: "10.4"
|
version: "11.0"
|
||||||
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers
|
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers
|
||||||
#IADS: EWR and C2 get power generators. batteries have their own generators.
|
#IADS: EWR and C2 get power generators. batteries have their own generators.
|
||||||
iads_config:
|
iads_config:
|
||||||
@@ -43,7 +47,7 @@ iads_config:
|
|||||||
- YellowEWRS: #mountainrange (center)
|
- YellowEWRS: #mountainrange (center)
|
||||||
- YellowPPW
|
- YellowPPW
|
||||||
- YellowControlW
|
- YellowControlW
|
||||||
- YellowEWRC: # internal
|
- YellowEWRC: #internal
|
||||||
- HamidiyeControl
|
- HamidiyeControl
|
||||||
- GaziantepControl
|
- GaziantepControl
|
||||||
- GaziantepPP
|
- GaziantepPP
|
||||||
@@ -243,94 +247,201 @@ iads_config:
|
|||||||
- Aleppo Control
|
- Aleppo Control
|
||||||
- Aleppo Control:
|
- Aleppo Control:
|
||||||
- Aleppo Power
|
- Aleppo Power
|
||||||
|
control_points:
|
||||||
|
From Reserves:
|
||||||
|
ferry_only: true
|
||||||
squadrons:
|
squadrons:
|
||||||
#Incirlik
|
#Incirlik (120)
|
||||||
16:
|
16:
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
|
secondary: air-to-air
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15C Eagle
|
- F-15C Eagle
|
||||||
|
size: 12
|
||||||
- primary: SEAD
|
- primary: SEAD
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-16CM Fighting Falcon (Block 50)
|
- F-16CM Fighting Falcon (Block 50)
|
||||||
- primary: DEAD
|
size: 12
|
||||||
|
- primary: Strike
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle
|
- F-15E Strike Eagle (Suite 4+)
|
||||||
- primary: BARCAP
|
size: 8
|
||||||
aircraft:
|
|
||||||
- F-16CM Fighting Falcon (Block 50)
|
|
||||||
- primary: CAS
|
|
||||||
aircraft:
|
|
||||||
- A-10C Thunderbolt II (Suite 3)
|
|
||||||
- primary: CAS
|
- primary: CAS
|
||||||
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- A-10C Thunderbolt II (Suite 7)
|
- A-10C Thunderbolt II (Suite 7)
|
||||||
|
size: 8
|
||||||
- primary: CAS
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- AH-64D Apache Longbow
|
- AH-64D Apache Longbow
|
||||||
|
size: 8
|
||||||
- primary: Strike
|
- primary: Strike
|
||||||
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-117A Nighthawk
|
- F-117A Nighthawk
|
||||||
|
size: 4
|
||||||
- primary: Strike
|
- primary: Strike
|
||||||
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- B-1B Lancer
|
- B-1B Lancer
|
||||||
|
size: 2
|
||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
|
secondary: any
|
||||||
|
size: 1
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- KC-135 Stratotanker MPRS
|
- KC-135 Stratotanker MPRS
|
||||||
|
size: 1
|
||||||
#carrier
|
#carrier
|
||||||
Blue Carrier:
|
Blue Carrier:
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
|
secondary: air-to-air
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-14B Tomcat
|
- F-14B Tomcat
|
||||||
|
size: 12
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
aircraft:
|
|
||||||
- F-14B Tomcat
|
|
||||||
- primary: Strike
|
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F/A-18C Hornet (Lot 20)
|
- F/A-18C Hornet (Lot 20)
|
||||||
- primary: Strike
|
size: 12
|
||||||
|
- primary: AEW&C
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
size: 1
|
||||||
- F/A-18C Hornet (Lot 20)
|
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
|
secondary: any
|
||||||
|
size: 2
|
||||||
#LHA
|
#LHA
|
||||||
Blue LHA:
|
Blue LHA:
|
||||||
- primary: CAS
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- AV-8B Harrier II Night Attack
|
- AV-8B Harrier II Night Attack
|
||||||
#Abu Al-Duhur
|
size: 8
|
||||||
1:
|
#Ferry-only
|
||||||
- primary: BARCAP
|
From Reserves:
|
||||||
aircraft:
|
- primary: SEAD
|
||||||
- MiG-29S Fulcrum-C
|
secondary: any
|
||||||
- primary: BAI
|
aircraft:
|
||||||
aircraft:
|
- F-16CM Fighting Falcon (Block 50)
|
||||||
- Su-24M Fencer-D
|
size: 12
|
||||||
- primary: BARCAP
|
- primary: CAS
|
||||||
aircraft:
|
secondary: air-to-ground
|
||||||
- Su-30 Flanker-C
|
aircraft:
|
||||||
#Hatay
|
- A-10C Thunderbolt II (Suite 3)
|
||||||
|
size: 12
|
||||||
|
# REDFOR squadrons
|
||||||
|
# Smaller number of modern fighters in forward airfields (Hatay, Minakh and Gaziantep)
|
||||||
|
# Larger number of older fighters in the rear (Aleppo, Abu Al-Duhur and Jirah)
|
||||||
|
# CAS aircraft distributed over all airfields, helos more forward
|
||||||
|
# Aleppo is main airfield for AWACS, Refueling and Transport, for protection it has some modern fighters
|
||||||
|
#Hatay (10)
|
||||||
15:
|
15:
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
aircraft:
|
secondary: any
|
||||||
- MiG-23MLD Flogger-K
|
aircraft:
|
||||||
#Aleppo
|
- MiG-29S Fulcrum-C
|
||||||
27:
|
size: 4
|
||||||
- primary: AEW&C
|
|
||||||
- primary: Refueling
|
|
||||||
- primary: CAS
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-25 Frogfoot
|
||||||
|
size: 4
|
||||||
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- Mi-24P Hind-F
|
- Mi-24P Hind-F
|
||||||
- primary: Transport
|
size: 2
|
||||||
#Jirah
|
#Minakh (20)
|
||||||
17:
|
26:
|
||||||
|
- primary: BARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-30 Flanker-C
|
||||||
|
size: 8
|
||||||
- primary: SEAD
|
- primary: SEAD
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- Su-34 Fullback
|
- Su-34 Fullback
|
||||||
|
size: 4
|
||||||
- primary: Strike
|
- primary: Strike
|
||||||
#Gaziantep
|
secondary: any
|
||||||
11:
|
size: 4
|
||||||
- primary: CAS
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- Su-25 Frogfoot
|
- Su-25 Frogfoot
|
||||||
|
size: 4
|
||||||
|
#Gaziantep (12)
|
||||||
|
11:
|
||||||
|
- primary: BARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-29S Fulcrum-C
|
||||||
|
size: 4
|
||||||
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-25 Frogfoot
|
||||||
|
size: 4
|
||||||
|
- primary: Strike
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-24M Fencer-D
|
||||||
|
size: 4
|
||||||
|
#Aleppo (14)
|
||||||
|
27:
|
||||||
|
- primary: BARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-29S Fulcrum-C
|
||||||
|
size: 4
|
||||||
|
- primary: BARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-23MLD Flogger-K
|
||||||
|
size: 4
|
||||||
|
- primary: AEW&C
|
||||||
|
secondary: any
|
||||||
|
size: 1
|
||||||
|
- primary: Refueling
|
||||||
|
secondary: any
|
||||||
|
size: 1
|
||||||
|
- primary: Transport
|
||||||
|
secondary: any
|
||||||
|
size: 2
|
||||||
|
#Abu Al-Duhur (36)
|
||||||
|
1:
|
||||||
|
- primary: BARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-23MLD Flogger-K
|
||||||
|
size: 12
|
||||||
|
- primary: SEAD
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-34 Fullback
|
||||||
|
size: 8
|
||||||
|
- primary: Strike
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-24M Fencer-D
|
||||||
|
size: 8
|
||||||
|
#Kuweires (37) ID: 31
|
||||||
|
#Jirah (28)
|
||||||
|
17:
|
||||||
|
- primary: BARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-23MLD Flogger-K
|
||||||
|
size: 12
|
||||||
|
- primary: BAI
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Su-24M Fencer-D
|
||||||
|
size: 8
|
||||||
|
#
|
||||||
|
# air-to-air: Barcap, Tarcap, Escort, and Fighter Sweep
|
||||||
BIN
resources/campaigns/battle_for_no_mans_land.miz
Normal file
BIN
resources/campaigns/battle_for_no_mans_land.miz
Normal file
Binary file not shown.
69
resources/campaigns/battle_for_no_mans_land.yaml
Normal file
69
resources/campaigns/battle_for_no_mans_land.yaml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
name: Falklands - Battle for No Man's Land
|
||||||
|
theater: Falklands
|
||||||
|
authors: Starfire
|
||||||
|
recommended_player_faction: USA 2005
|
||||||
|
recommended_enemy_faction: Private Military Company - Russian (Hard)
|
||||||
|
description:
|
||||||
|
<p><strong>Note:</strong> This campaign was designed for helicopters.</p><p>
|
||||||
|
Set against the rugged and windswept backdrop of the Falkland Islands,
|
||||||
|
this fictional campaign scenario unfolds with a dramatic dawn sneak attack
|
||||||
|
on RAF Mount Pleasant Airbase. Orchestrated by a Russia-backed private
|
||||||
|
military company, the deadly offensive with helicopter gunships and ground troops
|
||||||
|
has left the airbase's runways in ruins and its defences obliterated. This brutal
|
||||||
|
incursion resulted in significant casualties among the RAF personnel, with many
|
||||||
|
killed or wounded in the unexpected onslaught. The carrier HMS Queen Elizabeth and
|
||||||
|
its task force are on their way to evacuate the survivors and retake Mount Pleasant.
|
||||||
|
However, they are eight days away at full steam.</p><p>
|
||||||
|
Amidst this chaos, a beacon of hope emerges in the heart of the Falklands. At Port
|
||||||
|
Stanley, a small detachment of US military personnel, including helicopter pilots
|
||||||
|
and armor units, find themselves inadvertently thrust into the fray. Originally at
|
||||||
|
Port Stanley for some R&R following a training exercise, these soldiers now face
|
||||||
|
an unexpected and urgent call to action. Their mission is daunting but clear - to
|
||||||
|
prevent the capture of Port Stanley and liberate East Falkland from the clutches
|
||||||
|
of the PMC forces.</p><p>
|
||||||
|
This small group must strategically push the PMC forces back through the treacherous
|
||||||
|
valley lying between Wickham Heights and the Onion Ranges, an area ominously known
|
||||||
|
as No Man's Land. Their plan involves a daring assault to destroy the enemy's
|
||||||
|
helicopter gunships stationed at San Carlos FOB. Following this, they aim to force
|
||||||
|
the PMC ground forces into a strategic retreat southward, along the 1.6 mile wide
|
||||||
|
isthmus into Lafonia. This calculated offensive is designed to create a defensible
|
||||||
|
position at Goose Green on the narrow isthmus, which can be held against a numerically
|
||||||
|
superior force until the arrival of Big Lizzie.</p>
|
||||||
|
miz: battle_for_no_mans_land.miz
|
||||||
|
performance: 1
|
||||||
|
recommended_start_date: 2001-11-10
|
||||||
|
version: "11.0"
|
||||||
|
squadrons:
|
||||||
|
#Port Stanley
|
||||||
|
1:
|
||||||
|
- primary: DEAD
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- AH-64D Apache Longbow
|
||||||
|
size: 6
|
||||||
|
- primary: BAI
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- AH-64D Apache Longbow
|
||||||
|
size: 6
|
||||||
|
- primary: Air Assault
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- UH-60L
|
||||||
|
- UH-60A
|
||||||
|
size: 4
|
||||||
|
#San Carlos FOB
|
||||||
|
3:
|
||||||
|
- primary: BAI
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- Mi-24P Hind-F
|
||||||
|
size: 6
|
||||||
|
#Goose Green
|
||||||
|
24:
|
||||||
|
- primary: DEAD
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- Ka-50 Hokum (Blackshark 3)
|
||||||
|
size: 6
|
||||||
@@ -27,7 +27,7 @@ squadrons:
|
|||||||
size: 24
|
size: 24
|
||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
aircraft:
|
aircraft:
|
||||||
- E-2C Hawkeye
|
- E-2D Advanced Hawkeye
|
||||||
size: 2
|
size: 2
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
@@ -55,12 +55,7 @@ squadrons:
|
|||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle (Suite 4+)
|
- F-15E Strike Eagle (Suite 4+)
|
||||||
size: 8
|
size: 16
|
||||||
- primary: Strike
|
|
||||||
secondary: any
|
|
||||||
aircraft:
|
|
||||||
- F-15E Strike Eagle
|
|
||||||
size: 8
|
|
||||||
- primary: DEAD
|
- primary: DEAD
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
|
|||||||
Binary file not shown.
@@ -17,17 +17,29 @@ performance: 1
|
|||||||
recommended_start_date: 2011-02-24
|
recommended_start_date: 2011-02-24
|
||||||
version: "11.0"
|
version: "11.0"
|
||||||
squadrons:
|
squadrons:
|
||||||
|
Bombers from Minot AFB:
|
||||||
|
- primary: Strike
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- B-52H Stratofortress
|
||||||
|
size: 4
|
||||||
|
Bombers from Ellsworth AFB:
|
||||||
|
- primary: OCA/Runway
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- B-1B Lancer
|
||||||
|
size: 4
|
||||||
# Tonopah Airport
|
# Tonopah Airport
|
||||||
17:
|
17:
|
||||||
- primary: TARCAP
|
- primary: TARCAP
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle (Suite 4+)
|
- F-15C Eagle
|
||||||
size: 12
|
size: 12
|
||||||
- primary: Strike
|
- primary: Strike
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle
|
- F-15E Strike Eagle (Suite 4+)
|
||||||
size: 12
|
size: 12
|
||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
aircraft:
|
aircraft:
|
||||||
@@ -58,7 +70,8 @@ squadrons:
|
|||||||
- primary: Air Assault
|
- primary: Air Assault
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- UH-1H Iroquois
|
- UH-60L
|
||||||
|
- UH-60A
|
||||||
size: 2
|
size: 2
|
||||||
# Groom Lake
|
# Groom Lake
|
||||||
2:
|
2:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ recommended_player_faction:
|
|||||||
- F-14B Tomcat
|
- F-14B Tomcat
|
||||||
- F/A-18C Hornet (Lot 20)
|
- F/A-18C Hornet (Lot 20)
|
||||||
- S-3B Viking
|
- S-3B Viking
|
||||||
|
- UH-60L
|
||||||
- UH-60A
|
- UH-60A
|
||||||
awacs:
|
awacs:
|
||||||
- E-2C Hawkeye
|
- E-2C Hawkeye
|
||||||
@@ -107,8 +108,9 @@ squadrons:
|
|||||||
- primary: Air Assault
|
- primary: Air Assault
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
|
- UH-60L
|
||||||
- UH-60A
|
- UH-60A
|
||||||
size: 4
|
size: 6
|
||||||
#Stoney Cross (39)
|
#Stoney Cross (39)
|
||||||
58:
|
58:
|
||||||
- primary: OCA/Runway
|
- primary: OCA/Runway
|
||||||
|
|||||||
Binary file not shown.
@@ -35,11 +35,6 @@ squadrons:
|
|||||||
aircraft:
|
aircraft:
|
||||||
- F-15C Eagle
|
- F-15C Eagle
|
||||||
size: 8
|
size: 8
|
||||||
- primary: BAI
|
|
||||||
secondary: air-to-ground
|
|
||||||
aircraft:
|
|
||||||
- F-15E Strike Eagle
|
|
||||||
size: 8
|
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
- KC-135 Stratotanker
|
- KC-135 Stratotanker
|
||||||
@@ -90,12 +85,12 @@ squadrons:
|
|||||||
- AV-8B Harrier II Night Attack
|
- AV-8B Harrier II Night Attack
|
||||||
size: 18
|
size: 18
|
||||||
- primary: Air Assault
|
- primary: Air Assault
|
||||||
secondary: air-to-ground
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- UH-1H Iroquois
|
- UH-1H Iroquois
|
||||||
size: 2
|
size: 2
|
||||||
Bombers from Edwards AFB:
|
Bombers from Edwards AFB:
|
||||||
- primary: DEAD
|
- primary: Strike
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- B-52H Stratofortress
|
- B-52H Stratofortress
|
||||||
|
|||||||
BIN
resources/campaigns/operation_aegean_aegis.miz
Normal file
BIN
resources/campaigns/operation_aegean_aegis.miz
Normal file
Binary file not shown.
100
resources/campaigns/operation_aegean_aegis.yaml
Normal file
100
resources/campaigns/operation_aegean_aegis.yaml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
name: Syria - Operation Aegean Aegis
|
||||||
|
theater: Syria
|
||||||
|
authors: Starfire
|
||||||
|
recommended_player_faction: USA 2005
|
||||||
|
recommended_enemy_faction: Turkey 2005
|
||||||
|
description:
|
||||||
|
<p><strong>Note:</strong> This fictional campaign was designed for the Apache
|
||||||
|
and Harrier. It requires manual flight planning. While enemy aircraft are present
|
||||||
|
at airfields, there will be no enemy flights as their aircraft are grounded.</p>
|
||||||
|
<p>
|
||||||
|
In a sudden and alarming escalation of tensions in Cyprus, the Anatolian Order,
|
||||||
|
a North Cypriot insurgent faction, has carried out a bold night-time assault on
|
||||||
|
three crucial airfields in the Republic of Cyprus; Paphos, Akrotiri, and Larnaca.
|
||||||
|
The insurgents, equipped with stolen surplus Turkish military hardware, used
|
||||||
|
chemical weapons in their attack, forcing the evacuation of all three airfields.
|
||||||
|
Notably, the capture of Akrotiri, a British Overseas Territory hosting a Royal
|
||||||
|
Air Force base, has drawn significant international attention and concern.</p>
|
||||||
|
<p>
|
||||||
|
The EU has strongly condemned this unprovoked attack against one of its member
|
||||||
|
states. Turkey, despite its historical connections with North Cyprus, has also
|
||||||
|
denounced the Anatolian Order's actions and is investigating how its aircraft,
|
||||||
|
ground vehicles, and weaponry held in storage ended up in insurgent hands.</p>
|
||||||
|
<p>
|
||||||
|
Amidst the crisis, a lone US Navy LHA, strategically positioned in the Aegean Sea,
|
||||||
|
is preparing a response to the crisis. Its mission is to deploy Apache helicopters
|
||||||
|
to neutralise the hastily erected air defenses around the captured airfields, before
|
||||||
|
Harrier jumpjets neutralise the Anatolian Order's aircraft. These aircraft, a
|
||||||
|
selection of mothballed Turkish F-4s and helicopters, are currently grounded due to
|
||||||
|
lack of suitable fuel and spare parts. It is imperative that they are dealt with
|
||||||
|
swiftly before ground troops are air-lifted in to reclaim the airfields.</p>
|
||||||
|
<p>
|
||||||
|
The operation's final phase involves targeting North Cyprus's only airport at Ercan.
|
||||||
|
The plan is to bomb its runway, preventing any further airborne reinforcements by the
|
||||||
|
insurgents. However, due to the air defenses established along the northern edge of
|
||||||
|
the Green Line (the UN-patrolled demilitarised zone) there are strict advisories against
|
||||||
|
overflying North Cyprus unless absolutely necessary, to minimise the risk of losses.
|
||||||
|
</p>
|
||||||
|
miz: operation_aegean_aegis.miz
|
||||||
|
performance: 1
|
||||||
|
recommended_start_date: 2017-04-20
|
||||||
|
recommended_player_money: 1000
|
||||||
|
recommended_enemy_money: 0
|
||||||
|
recommended_player_income_multiplier: 1.0
|
||||||
|
recommended_enemy_income_multiplier: 0.0
|
||||||
|
version: "11.0"
|
||||||
|
squadrons:
|
||||||
|
#Tarawa Class LHA
|
||||||
|
Blue-LHA:
|
||||||
|
- primary: DEAD
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- AH-64D Apache Longbow
|
||||||
|
size: 12
|
||||||
|
- primary: DEAD
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- AV-8B Harrier II Night Attack
|
||||||
|
size: 6
|
||||||
|
- primary: Air Assault
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- UH-1H Iroquois
|
||||||
|
size: 2
|
||||||
|
#Paphos
|
||||||
|
46:
|
||||||
|
- primary: DEAD
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- F-4E Phantom II
|
||||||
|
size: 12
|
||||||
|
#Akrotiri
|
||||||
|
44:
|
||||||
|
- primary: BAI
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- AH-1W SuperCobra
|
||||||
|
size: 4
|
||||||
|
- primary: CAS
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- OH-58D Kiowa Warrior
|
||||||
|
size: 4
|
||||||
|
- primary: Air Assault
|
||||||
|
secondary: air-to-ground
|
||||||
|
aircraft:
|
||||||
|
- UH-60A
|
||||||
|
size: 4
|
||||||
|
#Larnaca
|
||||||
|
47:
|
||||||
|
- primary: Transport
|
||||||
|
aircraft:
|
||||||
|
- C-130
|
||||||
|
size: 6
|
||||||
|
#Ercan
|
||||||
|
49:
|
||||||
|
- primary: Transport
|
||||||
|
aircraft:
|
||||||
|
- CH-47D
|
||||||
|
size: 6
|
||||||
@@ -40,7 +40,7 @@ squadrons:
|
|||||||
size: 40
|
size: 40
|
||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
aircraft:
|
aircraft:
|
||||||
- E-2C Hawkeye
|
- E-2D Advanced Hawkeye
|
||||||
size: 2
|
size: 2
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
@@ -49,7 +49,8 @@ squadrons:
|
|||||||
- primary: Air Assault
|
- primary: Air Assault
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- SH-60B Seahawk
|
- UH-60L
|
||||||
|
- UH-60A
|
||||||
size: 4
|
size: 4
|
||||||
#Al Minhad AFB (61)
|
#Al Minhad AFB (61)
|
||||||
12:
|
12:
|
||||||
@@ -78,12 +79,12 @@ squadrons:
|
|||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle (Suite 4+)
|
- F-15E Strike Eagle (Suite 4+)
|
||||||
size: 8
|
size: 20
|
||||||
- primary: BAI
|
- primary: DEAD
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle
|
- AV-8B Harrier II Night Attack
|
||||||
size: 12
|
size: 20
|
||||||
#Bandar Abbas Intl (51)
|
#Bandar Abbas Intl (51)
|
||||||
2:
|
2:
|
||||||
- primary: SEAD
|
- primary: SEAD
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ squadrons:
|
|||||||
size: 20
|
size: 20
|
||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
aircraft:
|
aircraft:
|
||||||
- E-2C Hawkeye
|
- E-2D Advanced Hawkeye
|
||||||
size: 4
|
size: 4
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
@@ -55,12 +55,7 @@ squadrons:
|
|||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle (Suite 4+)
|
- F-15E Strike Eagle (Suite 4+)
|
||||||
size: 4
|
size: 12
|
||||||
- primary: OCA/Aircraft
|
|
||||||
secondary: any
|
|
||||||
aircraft:
|
|
||||||
- F-15E Strike Eagle
|
|
||||||
size: 8
|
|
||||||
- primary: TARCAP
|
- primary: TARCAP
|
||||||
secondary: air-to-air
|
secondary: air-to-air
|
||||||
aircraft:
|
aircraft:
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ squadrons:
|
|||||||
- primary: Air Assault
|
- primary: Air Assault
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
|
- UH-60L
|
||||||
- UH-60A
|
- UH-60A
|
||||||
size: 2
|
size: 2
|
||||||
Blue LHA:
|
Blue LHA:
|
||||||
@@ -83,31 +84,11 @@ squadrons:
|
|||||||
aircraft:
|
aircraft:
|
||||||
- F-16CM Fighting Falcon (Block 50)
|
- F-16CM Fighting Falcon (Block 50)
|
||||||
size: 16
|
size: 16
|
||||||
- primary: DEAD
|
|
||||||
secondary: any
|
|
||||||
aircraft:
|
|
||||||
- F-16CM Fighting Falcon (Block 50)
|
|
||||||
size: 16
|
|
||||||
- primary: BAI
|
- primary: BAI
|
||||||
secondary: any
|
secondary: any
|
||||||
aircraft:
|
aircraft:
|
||||||
- F-15E Strike Eagle (Suite 4+)
|
- F-15E Strike Eagle (Suite 4+)
|
||||||
size: 8
|
size: 8
|
||||||
- primary: BAI
|
|
||||||
secondary: air-to-ground
|
|
||||||
aircraft:
|
|
||||||
- F-15E Strike Eagle
|
|
||||||
size: 8
|
|
||||||
- primary: Strike
|
|
||||||
secondary: air-to-ground
|
|
||||||
aircraft:
|
|
||||||
- B-1B Lancer
|
|
||||||
size: 4
|
|
||||||
- primary: Strike
|
|
||||||
secondary: air-to-ground
|
|
||||||
aircraft:
|
|
||||||
- B-52H Stratofortress
|
|
||||||
size: 4
|
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
- KC-135 Stratotanker
|
- KC-135 Stratotanker
|
||||||
|
|||||||
BIN
resources/campaigns/operation_velvet_thunder.miz
Normal file
BIN
resources/campaigns/operation_velvet_thunder.miz
Normal file
Binary file not shown.
94
resources/campaigns/operation_velvet_thunder.yaml
Normal file
94
resources/campaigns/operation_velvet_thunder.yaml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
---
|
||||||
|
name: Marianas - Operation Velvet Thunder
|
||||||
|
theater: MarianaIslands
|
||||||
|
authors: Starfire
|
||||||
|
recommended_player_faction: USA 1970
|
||||||
|
recommended_enemy_faction: NVA 1970
|
||||||
|
description:
|
||||||
|
<p>Operation Velvet Thunder is a high-intensity training exercise designed to
|
||||||
|
prepare fresh troops for the challenges they will face in Vietnam. The dense
|
||||||
|
jungle and rugged terrain of the Mariana Islands will provide a realistic
|
||||||
|
backdrop, allowing our forces to hone essential skills in jungle warfare,
|
||||||
|
unconventional tactics, and counterinsurgency operations. There are multiple
|
||||||
|
checkpoints scattered across the area of operations that will have to be
|
||||||
|
captured by Air Assault. Due to the limited size and availability of LZs, it
|
||||||
|
is vital to pay close attention to where you designate troop drop off zones.
|
||||||
|
</p><p><strong>Note:</strong> This campaign is intended to be played with the
|
||||||
|
A-4 Skyhawk and OV-10a aircraft mods active. The C-101CC has also been included
|
||||||
|
as a stand-in for the Cessna A-37 Dragonfly in order to provide a CAS platform
|
||||||
|
of roughly equivalent combat capability. This campaign will be updated to use
|
||||||
|
Heatblur's F-4 Phantom II once it is in early access.</p>
|
||||||
|
miz: operation_velvet_thunder.miz
|
||||||
|
performance: 1
|
||||||
|
recommended_start_date: 1970-11-29
|
||||||
|
version: "11.0"
|
||||||
|
squadrons:
|
||||||
|
#Andersen AFB
|
||||||
|
6:
|
||||||
|
- primary: Escort
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- F-5E Tiger II
|
||||||
|
size: 8
|
||||||
|
- primary: BAI
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- C-101CC Aviojet
|
||||||
|
size: 8
|
||||||
|
- primary: CAS
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- OV-10A Bronco
|
||||||
|
size: 8
|
||||||
|
- primary: SEAD
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- F-4E Phantom II
|
||||||
|
size: 16
|
||||||
|
- primary: Strike
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- B-52H Stratofortress
|
||||||
|
size: 4
|
||||||
|
- primary: Air Assault
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- UH-1H Iroquois
|
||||||
|
size: 4
|
||||||
|
- primary: Transport
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- CH-47D
|
||||||
|
size: 4
|
||||||
|
#Blue CV
|
||||||
|
Blue-CV:
|
||||||
|
- primary: DEAD
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- A-4E Skyhawk
|
||||||
|
size: 16
|
||||||
|
- primary: AEW&C
|
||||||
|
aircraft:
|
||||||
|
- E-2C Hawkeye
|
||||||
|
size: 2
|
||||||
|
#Rota Intl
|
||||||
|
1:
|
||||||
|
- primary: TARCAP
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-19P Farmer-B
|
||||||
|
size: 8
|
||||||
|
#Tinian Intl
|
||||||
|
3:
|
||||||
|
- primary: Air Assault
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- Mi-8MTV2 Hip
|
||||||
|
size: 4
|
||||||
|
#Saipan Intl
|
||||||
|
2:
|
||||||
|
- primary: BAI
|
||||||
|
secondary: any
|
||||||
|
aircraft:
|
||||||
|
- MiG-21bis Fishbed-N
|
||||||
|
size: 8
|
||||||
@@ -9,7 +9,7 @@ local unitPayloads = {
|
|||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
|
["CLSID"] = "{M299_4xAGM_114L}",
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
@@ -17,7 +17,7 @@ local unitPayloads = {
|
|||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
|
["CLSID"] = "{M299_4xAGM_114L}",
|
||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -51,6 +51,31 @@ local unitPayloads = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
|
["displayName"] = "Liberation DEAD",
|
||||||
|
["name"] = "Liberation DEAD",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{M299_4xAGM_114L}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{M299_4xAGM_114L}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{M299_4xAGM_114L}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{M299_4xAGM_114L}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
["name"] = "Liberation OCA/Aircraft",
|
["name"] = "Liberation OCA/Aircraft",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
|
|||||||
@@ -2,27 +2,36 @@ local unitPayloads = {
|
|||||||
["name"] = "AV8BNA",
|
["name"] = "AV8BNA",
|
||||||
["payloads"] = {
|
["payloads"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["name"] = "INTERCEPT",
|
["displayName"] = "Liberation CAS",
|
||||||
|
["name"] = "Liberation CAS",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
["num"] = 8,
|
["num"] = 5,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
["num"] = 1,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
|
["CLSID"] = "{BRU-70A_3*GBU-54}",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
|
["CLSID"] = "{BRU-70A_3*GBU-54}",
|
||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "{GAU_12_Equalizer}",
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
["num"] = 4,
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
@@ -30,7 +39,8 @@ local unitPayloads = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["name"] = "SEAD",
|
["displayName"] = "Liberation SEAD",
|
||||||
|
["name"] = "Liberation SEAD",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{AGM_122_SIDEARM}",
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
@@ -41,32 +51,25 @@ local unitPayloads = {
|
|||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
["CLSID"] = "{LAU_7_AGM_122_SIDEARM}",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
["CLSID"] = "{LAU_7_AGM_122_SIDEARM}",
|
||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "{ALQ_164_RF_Jammer}",
|
["CLSID"] = "{ALQ_164_RF_Jammer}",
|
||||||
["num"] = 5,
|
["num"] = 5,
|
||||||
},
|
},
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 31,
|
[1] = 31,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["name"] = "CAS",
|
["displayName"] = "Liberation OCA/Runway",
|
||||||
|
["name"] = "Liberation OCA/Runway",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
@@ -77,36 +80,144 @@ local unitPayloads = {
|
|||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
|
||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[5] = {
|
[4] = {
|
||||||
["CLSID"] = "{GAU_12_Equalizer}",
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
["num"] = 4,
|
["num"] = 6,
|
||||||
},
|
},
|
||||||
[6] = {
|
[5] = {
|
||||||
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
["num"] = 5,
|
["num"] = 5,
|
||||||
},
|
},
|
||||||
[7] = {
|
[6] = {
|
||||||
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
|
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 31,
|
[1] = 31,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["name"] = "ANTISHIP",
|
["displayName"] = "Liberation BAI",
|
||||||
|
["name"] = "Liberation BAI",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{BRU-70A_3*GBU-54}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{BRU-70A_2*GBU-54_RIGHT}",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{BRU-70A_2*GBU-54_LEFT}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{BRU-70A_3*GBU-54}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["displayName"] = "Liberation DEAD",
|
||||||
|
["name"] = "Liberation DEAD",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["displayName"] = "Liberation Strike",
|
||||||
|
["name"] = "Liberation Strike",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{BRU-42_2*GBU-38_LEFT}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{BRU-42_3*GBU-38}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{BRU-42_2*GBU-38_RIGHT}",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{BRU-42_3*GBU-38}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["displayName"] = "Liberation Anti-ship",
|
||||||
|
["name"] = "Liberation Anti-ship",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
@@ -116,6 +227,43 @@ local unitPayloads = {
|
|||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
["displayName"] = "Liberation SEAD Escort",
|
||||||
|
["name"] = "Liberation SEAD Escort",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{AGM_122_SIDEARM}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "LAU_117_AGM_65F",
|
["CLSID"] = "LAU_117_AGM_65F",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
@@ -141,28 +289,9 @@ local unitPayloads = {
|
|||||||
[1] = 31,
|
[1] = 31,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[5] = {
|
[9] = {
|
||||||
["name"] = "STRIKE",
|
["displayName"] = "Liberation OCA/Aircraft",
|
||||||
["pylons"] = {
|
["name"] = "Liberation OCA/Aircraft",
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{BRU-42_2*GBU-38_LEFT}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{BRU-42_2*GBU-38_RIGHT}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 31,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["name"] = "CAP",
|
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
@@ -173,16 +302,24 @@ local unitPayloads = {
|
|||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
|
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
|
||||||
["num"] = 2,
|
["num"] = 5,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "{GAU_12_Equalizer}",
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
["num"] = 4,
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{GBU_32_V_2B}",
|
||||||
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
|
|||||||
@@ -2,109 +2,8 @@ local unitPayloads = {
|
|||||||
["name"] = "F-15ESE",
|
["name"] = "F-15ESE",
|
||||||
["payloads"] = {
|
["payloads"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["displayName"] = "Liberation Strike",
|
["displayName"] = "Liberation Escort",
|
||||||
["name"] = "Liberation Strike",
|
["name"] = "Liberation Escort",
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 15,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 13,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{CFT_R_MK84LD_x_2}",
|
|
||||||
["num"] = 12,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
|
|
||||||
["num"] = 8,
|
|
||||||
["settings"] = {
|
|
||||||
["GUI_fuze_type"] = 1,
|
|
||||||
["arm_delay_ctrl_FMU139CB_LD"] = 1,
|
|
||||||
["function_delay_ctrl_FMU139CB_LD"] = 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{CFT_L_MK84LD_x_2}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 14,
|
|
||||||
},
|
|
||||||
[11] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 32,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["name"] = "Liberation BAI",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{CFT_L_CBU_97_x_6}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{CFT_R_CBU_97_x_6}",
|
|
||||||
["num"] = 12,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 13,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 32,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["name"] = "Liberation BARCAP",
|
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
@@ -131,7 +30,7 @@ local unitPayloads = {
|
|||||||
["num"] = 9,
|
["num"] = 9,
|
||||||
},
|
},
|
||||||
[7] = {
|
[7] = {
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 8,
|
["num"] = 8,
|
||||||
},
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
@@ -163,9 +62,114 @@ local unitPayloads = {
|
|||||||
[1] = 32,
|
[1] = 32,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
[2] = {
|
||||||
|
["displayName"] = "Liberation OCA/Aircraft",
|
||||||
|
["name"] = "Liberation OCA/Aircraft",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 15,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 13,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
||||||
|
["num"] = 9,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
|
["num"] = 14,
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
[10] = {
|
||||||
|
["CLSID"] = "{CFT_R_GBU_31V3B_x_2}",
|
||||||
|
["num"] = 12,
|
||||||
|
},
|
||||||
|
[11] = {
|
||||||
|
["CLSID"] = "{CFT_L_GBU_31V3B_x_2}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["name"] = "Liberation BAI",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
||||||
|
["num"] = 9,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{CFT_L_GBU_31V3B_x_2}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{CFT_R_GBU_31V3B_x_2}",
|
||||||
|
["num"] = 12,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 15,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 13,
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[10] = {
|
||||||
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
|
["num"] = 14,
|
||||||
|
},
|
||||||
|
[11] = {
|
||||||
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["displayName"] = "Liberation Escort",
|
["displayName"] = "Liberation Fighter Sweep",
|
||||||
["name"] = "Liberation Escort",
|
["name"] = "Liberation Fighter Sweep",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
@@ -192,7 +196,7 @@ local unitPayloads = {
|
|||||||
["num"] = 9,
|
["num"] = 9,
|
||||||
},
|
},
|
||||||
[7] = {
|
[7] = {
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 8,
|
["num"] = 8,
|
||||||
},
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
@@ -225,8 +229,8 @@ local unitPayloads = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["displayName"] = "Liberation OCA/Runway",
|
["displayName"] = "Liberation Strike",
|
||||||
["name"] = "Liberation OCA/Runway",
|
["name"] = "Liberation Strike",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
@@ -245,32 +249,32 @@ local unitPayloads = {
|
|||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "{CFT_R_BLU107_x_6}",
|
|
||||||
["num"] = 12,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
||||||
["num"] = 9,
|
["num"] = 9,
|
||||||
},
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
[7] = {
|
[7] = {
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
["CLSID"] = "{CFT_L_GBU_31V3B_x_2}",
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{CFT_L_BLU107_x_6}",
|
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
|
[9] = {
|
||||||
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
[10] = {
|
[10] = {
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
["num"] = 14,
|
["num"] = 14,
|
||||||
},
|
},
|
||||||
[11] = {
|
[11] = {
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
["CLSID"] = "{CFT_R_GBU_31V3B_x_2}",
|
||||||
["num"] = 2,
|
["num"] = 12,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
@@ -278,66 +282,7 @@ local unitPayloads = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
[6] = {
|
[6] = {
|
||||||
["displayName"] = "Liberation OCA/Aircraft",
|
["name"] = "Liberation BARCAP",
|
||||||
["name"] = "Liberation OCA/Aircraft",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 15,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 13,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{CFT_R_MK82LD_x_6}",
|
|
||||||
["num"] = 12,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
|
||||||
["num"] = 8,
|
|
||||||
["settings"] = {
|
|
||||||
["GUI_fuze_type"] = 1,
|
|
||||||
["arm_delay_ctrl_FMU139CB_LD"] = 1,
|
|
||||||
["function_delay_ctrl_FMU139CB_LD"] = 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{CFT_L_MK82LD_x_6}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 14,
|
|
||||||
},
|
|
||||||
[11] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 32,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["displayName"] = "Liberation Fighter Sweep",
|
|
||||||
["name"] = "Liberation Fighter Sweep",
|
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
@@ -364,7 +309,7 @@ local unitPayloads = {
|
|||||||
["num"] = 9,
|
["num"] = 9,
|
||||||
},
|
},
|
||||||
[7] = {
|
[7] = {
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
["CLSID"] = "<CLEAN>",
|
||||||
["num"] = 8,
|
["num"] = 8,
|
||||||
},
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
@@ -396,7 +341,121 @@ local unitPayloads = {
|
|||||||
[1] = 32,
|
[1] = 32,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
[7] = {
|
||||||
|
["displayName"] = "Liberation CAS",
|
||||||
|
["name"] = "Liberation CAS",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 15,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 13,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
||||||
|
["num"] = 9,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
["CLSID"] = "{CFT_L_GBU_38_x_3}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
|
["CLSID"] = "{GBU-38}",
|
||||||
|
["num"] = 14,
|
||||||
|
},
|
||||||
|
[10] = {
|
||||||
|
["CLSID"] = "{CFT_R_GBU_38_x_3}",
|
||||||
|
["num"] = 12,
|
||||||
|
},
|
||||||
|
[11] = {
|
||||||
|
["CLSID"] = "{GBU-38}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
|
["displayName"] = "Liberation TARCAP",
|
||||||
|
["name"] = "Liberation TARCAP",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 15,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
|
["num"] = 14,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 13,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 11,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 10,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
||||||
|
["num"] = 9,
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
["CLSID"] = "<CLEAN>",
|
||||||
|
["num"] = 8,
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[10] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
[11] = {
|
||||||
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[12] = {
|
||||||
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
[13] = {
|
||||||
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
["displayName"] = "Liberation DEAD",
|
["displayName"] = "Liberation DEAD",
|
||||||
["name"] = "Liberation DEAD",
|
["name"] = "Liberation DEAD",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
@@ -429,118 +488,65 @@ local unitPayloads = {
|
|||||||
["num"] = 7,
|
["num"] = 7,
|
||||||
},
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
["CLSID"] = "{CFT_L_CBU_97_x_6}",
|
["CLSID"] = "{CFT_L_GBU_31V3B_x_2}",
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[9] = {
|
[9] = {
|
||||||
["CLSID"] = "{CFT_R_CBU_97_x_6}",
|
["CLSID"] = "{CFT_R_GBU_31V3B_x_2}",
|
||||||
["num"] = 12,
|
["num"] = 12,
|
||||||
},
|
},
|
||||||
},
|
[10] = {
|
||||||
["tasks"] = {
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
[1] = 32,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["displayName"] = "Liberation TARCAP",
|
|
||||||
["name"] = "Liberation TARCAP",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 15,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 14,
|
["num"] = 14,
|
||||||
},
|
},
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
|
||||||
["num"] = 13,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 11,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
[11] = {
|
[11] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{GBU-31V3B}",
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[12] = {
|
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
[13] = {
|
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 32,
|
[1] = 32,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[10] = {
|
[10] = {
|
||||||
["displayName"] = "Liberation CAS",
|
["displayName"] = "Liberation OCA/Runway",
|
||||||
["name"] = "Liberation CAS",
|
["name"] = "Liberation OCA/Runway",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
["num"] = 15,
|
["num"] = 15,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
["num"] = 13,
|
["num"] = 13,
|
||||||
},
|
},
|
||||||
[4] = {
|
[3] = {
|
||||||
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
["CLSID"] = "{CFT_R_BLU107_x_6}",
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{CFT_R_CBU_97_x_6}",
|
|
||||||
["num"] = 12,
|
["num"] = 12,
|
||||||
},
|
},
|
||||||
[6] = {
|
[4] = {
|
||||||
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
|
||||||
["num"] = 9,
|
["num"] = 9,
|
||||||
},
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
||||||
|
["num"] = 7,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "{CFT_L_BLU107_x_6}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
[7] = {
|
[7] = {
|
||||||
["CLSID"] = "{F15E_EXTTANK}",
|
["CLSID"] = "{F15E_EXTTANK}",
|
||||||
["num"] = 8,
|
["num"] = 8,
|
||||||
},
|
},
|
||||||
[8] = {
|
[8] = {
|
||||||
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
|
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
|
||||||
["num"] = 7,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[9] = {
|
[9] = {
|
||||||
["CLSID"] = "{CFT_L_CBU_97_x_6}",
|
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
|
||||||
["num"] = 4,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
|
|||||||
@@ -2,133 +2,102 @@ local unitPayloads = {
|
|||||||
["name"] = "Ka-50",
|
["name"] = "Ka-50",
|
||||||
["payloads"] = {
|
["payloads"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["name"] = "CAS",
|
["name"] = "Liberation CAS",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
||||||
["num"] = 1,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
||||||
["num"] = 2,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
["num"] = 4,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 31,
|
[1] = 31,
|
||||||
[2] = 32,
|
|
||||||
[3] = 18,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["name"] = "CAP",
|
["displayName"] = "Liberation BAI",
|
||||||
|
["name"] = "Liberation BAI",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||||
["num"] = 1,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||||
["num"] = 2,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
["num"] = 4,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 31,
|
[1] = 31,
|
||||||
[2] = 32,
|
|
||||||
[3] = 18,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["name"] = "SEAD",
|
["displayName"] = "Liberation OCA/Aircraft",
|
||||||
|
["name"] = "Liberation OCA/Aircraft",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
||||||
["num"] = 1,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
||||||
["num"] = 2,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
||||||
["num"] = 4,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 31,
|
[1] = 31,
|
||||||
[2] = 32,
|
|
||||||
[3] = 18,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["name"] = "ANTISHIP",
|
["displayName"] = "Liberation DEAD",
|
||||||
|
["name"] = "Liberation DEAD",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 31,
|
|
||||||
[2] = 32,
|
|
||||||
[3] = 18,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["name"] = "STRIKE",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[2] = {
|
[2] = {
|
||||||
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
|
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||||
["num"] = 2,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
|
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
|
||||||
["num"] = 4,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 31,
|
[1] = 31,
|
||||||
[2] = 32,
|
|
||||||
[3] = 18,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ local unitPayloads = {
|
|||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[6] = {
|
[6] = {
|
||||||
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -36,6 +36,39 @@ local unitPayloads = {
|
|||||||
[2] = {
|
[2] = {
|
||||||
["displayName"] = "Liberation BAI",
|
["displayName"] = "Liberation BAI",
|
||||||
["name"] = "Liberation BAI",
|
["name"] = "Liberation BAI",
|
||||||
|
["pylons"] = {
|
||||||
|
[1] = {
|
||||||
|
["CLSID"] = "{9S846_2xIGLA}",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
["CLSID"] = "{9S846_2xIGLA}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||||
|
["num"] = 4,
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||||
|
["num"] = 1,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
|
["num"] = 3,
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
["CLSID"] = "B_8V20A_OFP2",
|
||||||
|
["num"] = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
["displayName"] = "Liberation DEAD",
|
||||||
|
["name"] = "Liberation DEAD",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{9S846_2xIGLA}",
|
["CLSID"] = "{9S846_2xIGLA}",
|
||||||
@@ -66,7 +99,7 @@ local unitPayloads = {
|
|||||||
[1] = 31,
|
[1] = 31,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[3] = {
|
[4] = {
|
||||||
["displayName"] = "Liberation OCA/Aircraft",
|
["displayName"] = "Liberation OCA/Aircraft",
|
||||||
["name"] = "Liberation OCA/Aircraft",
|
["name"] = "Liberation OCA/Aircraft",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
@@ -79,19 +112,19 @@ local unitPayloads = {
|
|||||||
["num"] = 5,
|
["num"] = 5,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
["CLSID"] = "B_8V20A_OFP2",
|
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
[4] = {
|
[4] = {
|
||||||
["CLSID"] = "B_8V20A_OFP2",
|
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
|
||||||
["num"] = 1,
|
["num"] = 1,
|
||||||
},
|
},
|
||||||
[5] = {
|
[5] = {
|
||||||
["CLSID"] = "B_8V20A_OFP2",
|
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[6] = {
|
[6] = {
|
||||||
["CLSID"] = "B_8V20A_OFP2",
|
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
32
resources/doctrines/coldwar.yaml
Normal file
32
resources/doctrines/coldwar.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: coldwar
|
||||||
|
cap: true
|
||||||
|
cas: true
|
||||||
|
sead: true
|
||||||
|
strike: true
|
||||||
|
antiship: true
|
||||||
|
rendezvous_altitude_ft_msl: 22000
|
||||||
|
hold_distance_nm: 15
|
||||||
|
push_distance_nm: 10
|
||||||
|
join_distance_nm: 10
|
||||||
|
max_ingress_distance_nm: 30
|
||||||
|
min_ingress_distance_nm: 10
|
||||||
|
ingress_altitude_ft_msl: 18000
|
||||||
|
min_patrol_altitude_ft_msl: 10000
|
||||||
|
max_patrol_altitude_ft_msl: 24000
|
||||||
|
pattern_altitude_ft_msl: 5000
|
||||||
|
cap_duration_minutes: 30
|
||||||
|
cap_min_track_length_nm: 12
|
||||||
|
cap_max_track_length_nm: 24
|
||||||
|
cap_min_distance_from_cp_nm: 8
|
||||||
|
cap_max_distance_from_cp_nm: 25
|
||||||
|
cap_engagement_range_nm: 35
|
||||||
|
cas_duration_minutes: 30
|
||||||
|
sweep_distance_nm: 40
|
||||||
|
ground_unit_procurement_ratios:
|
||||||
|
Tank: 4
|
||||||
|
ATGM: 2
|
||||||
|
APC: 3
|
||||||
|
IFV: 2
|
||||||
|
Artillery: 1
|
||||||
|
SHORAD: 2
|
||||||
|
Recon: 1
|
||||||
32
resources/doctrines/modern.yaml
Normal file
32
resources/doctrines/modern.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: modern
|
||||||
|
cap: true
|
||||||
|
cas: true
|
||||||
|
sead: true
|
||||||
|
strike: true
|
||||||
|
antiship: true
|
||||||
|
rendezvous_altitude_ft_msl: 25000
|
||||||
|
hold_distance_nm: 25
|
||||||
|
push_distance_nm: 20
|
||||||
|
join_distance_nm: 20
|
||||||
|
max_ingress_distance_nm: 45
|
||||||
|
min_ingress_distance_nm: 10
|
||||||
|
ingress_altitude_ft_msl: 20000
|
||||||
|
min_patrol_altitude_ft_msl: 15000
|
||||||
|
max_patrol_altitude_ft_msl: 33000
|
||||||
|
pattern_altitude_ft_msl: 5000
|
||||||
|
cap_duration_minutes: 30
|
||||||
|
cap_min_track_length_nm: 15
|
||||||
|
cap_max_track_length_nm: 40
|
||||||
|
cap_min_distance_from_cp_nm: 10
|
||||||
|
cap_max_distance_from_cp_nm: 40
|
||||||
|
cap_engagement_range_nm: 50
|
||||||
|
cas_duration_minutes: 30
|
||||||
|
sweep_distance_nm: 60
|
||||||
|
ground_unit_procurement_ratios:
|
||||||
|
Tank: 3
|
||||||
|
ATGM: 2
|
||||||
|
APC: 2
|
||||||
|
IFV: 3
|
||||||
|
Artillery: 1
|
||||||
|
SHORAD: 2
|
||||||
|
Recon: 1
|
||||||
31
resources/doctrines/ww2.yaml
Normal file
31
resources/doctrines/ww2.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: ww2
|
||||||
|
cap: true
|
||||||
|
cas: true
|
||||||
|
sead: false
|
||||||
|
strike: true
|
||||||
|
antiship: true
|
||||||
|
hold_distance_nm: 10
|
||||||
|
push_distance_nm: 5
|
||||||
|
join_distance_nm: 5
|
||||||
|
rendezvous_altitude_ft_msl: 10000
|
||||||
|
max_ingress_distance_nm: 7
|
||||||
|
min_ingress_distance_nm: 5
|
||||||
|
ingress_altitude_ft_msl: 8000
|
||||||
|
min_patrol_altitude_ft_msl: 4000
|
||||||
|
max_patrol_altitude_ft_msl: 15000
|
||||||
|
pattern_altitude_ft_msl: 5000
|
||||||
|
cap_duration_minutes: 30
|
||||||
|
cap_min_track_length_nm: 8
|
||||||
|
cap_max_track_length_nm: 18
|
||||||
|
cap_min_distance_from_cp_nm: 0
|
||||||
|
cap_max_distance_from_cp_nm: 5
|
||||||
|
cap_engagement_range_nm: 20
|
||||||
|
cas_duration_minutes: 30
|
||||||
|
sweep_distance_nm: 10
|
||||||
|
ground_unit_procurement_ratios:
|
||||||
|
Tank: 3
|
||||||
|
ATGM: 3
|
||||||
|
APC: 3
|
||||||
|
Artillery: 1
|
||||||
|
SHORAD: 3
|
||||||
|
Recon: 1
|
||||||
46
resources/factions/nva_1970.yaml
Normal file
46
resources/factions/nva_1970.yaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
country: Vietnam
|
||||||
|
name: NVA 1970
|
||||||
|
authors: Starfire
|
||||||
|
description: <p>North Vietnamese Army during the Vietnam War from 1965 to 1975</p>
|
||||||
|
locales:
|
||||||
|
- vi_Vn
|
||||||
|
aircrafts:
|
||||||
|
- Mi-8MTV2 Hip
|
||||||
|
- MiG-19P Farmer-B
|
||||||
|
- MiG-21bis Fishbed-N
|
||||||
|
awacs: []
|
||||||
|
tankers: []
|
||||||
|
frontline_units:
|
||||||
|
- T-55A
|
||||||
|
- PT-76
|
||||||
|
- M2A1 Half-Track
|
||||||
|
- Grad MRL FDDM (FC)
|
||||||
|
artillery_units:
|
||||||
|
- BM-21 Grad
|
||||||
|
logistics_units:
|
||||||
|
- LUV UAZ-469 Jeep
|
||||||
|
- Truck Ural-375
|
||||||
|
infantry_units:
|
||||||
|
- Infantry AK-74 Rus
|
||||||
|
- Infantry RPG
|
||||||
|
missiles: []
|
||||||
|
preset_groups:
|
||||||
|
- SA-2/S-75
|
||||||
|
- SA-3/S-125
|
||||||
|
- KS-19
|
||||||
|
- Cold-War-Flak
|
||||||
|
naval_units:
|
||||||
|
- Boat Armed Hi-speed
|
||||||
|
- Boat Schnellboot type S130
|
||||||
|
air_defense_units:
|
||||||
|
- SAM P19 "Flat Face" SR (SA-2/3)
|
||||||
|
- S-60 57mm
|
||||||
|
- 8.8 cm Flak 18
|
||||||
|
- ZSU-57-2 'Sparka'
|
||||||
|
- AAA ZU-23 Emplacement
|
||||||
|
- ZU-23 on Ural-375
|
||||||
|
- ZSU-23-4 Shilka
|
||||||
|
|
||||||
|
requirements: {}
|
||||||
|
doctrine: coldwar
|
||||||
45
resources/factions/pmc_russian_hard.yaml
Normal file
45
resources/factions/pmc_russian_hard.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
country: Russia
|
||||||
|
name: Private Military Company - Russian (Hard)
|
||||||
|
authors: Starfire
|
||||||
|
description: <p>A well-equipped private military company using a mix of modern and older Russian hardware.</p>
|
||||||
|
locales:
|
||||||
|
- ru_RU
|
||||||
|
aircrafts:
|
||||||
|
- Ka-50 Hokum
|
||||||
|
- Ka-50 Hokum (Blackshark 3)
|
||||||
|
- L-39ZA Albatros
|
||||||
|
- Mi-24V Hind-E
|
||||||
|
- Mi-24P Hind-F
|
||||||
|
- Mi-8MTV2 Hip
|
||||||
|
frontline_units:
|
||||||
|
- BMP-1
|
||||||
|
- BRDM-2
|
||||||
|
- BTR-80
|
||||||
|
- BTR-D
|
||||||
|
- Cobra
|
||||||
|
- MT-LB
|
||||||
|
- PT-76
|
||||||
|
- T-55A
|
||||||
|
- ZSU-57-2 'Sparka'
|
||||||
|
artillery_units:
|
||||||
|
- 2S1 Gvozdika
|
||||||
|
- 2S19 Msta-S
|
||||||
|
- BM-27 Uragan
|
||||||
|
logistics_units:
|
||||||
|
- LUV UAZ-469 Jeep
|
||||||
|
- Truck Ural-375
|
||||||
|
infantry_units:
|
||||||
|
- Infantry AK-74 Rus
|
||||||
|
- MANPADS SA-18 Igla-S "Grouse"
|
||||||
|
- Mortar 2B11 120mm
|
||||||
|
- Paratrooper AKS
|
||||||
|
- Paratrooper RPG-16
|
||||||
|
air_defense_units:
|
||||||
|
- SA-9 Strela
|
||||||
|
- SA-13 Gopher (9K35 Strela-10M3)
|
||||||
|
- ZSU-57-2 'Sparka'
|
||||||
|
- ZSU-23-4 Shilka
|
||||||
|
preset_groups: []
|
||||||
|
naval_units: []
|
||||||
|
missiles: []
|
||||||
58
resources/factions/usa_1970.yaml
Normal file
58
resources/factions/usa_1970.yaml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
country: USA
|
||||||
|
name: USA 1970
|
||||||
|
authors: Starfire
|
||||||
|
description: <p>US military during the Vietnam War from 1965 to 1975</p>
|
||||||
|
locales:
|
||||||
|
- en_US
|
||||||
|
aircrafts:
|
||||||
|
- F-14A Tomcat (Block 135-GR Late)
|
||||||
|
- F-4C Phantom II
|
||||||
|
- F-4B Phantom II
|
||||||
|
- F-4E Phantom II
|
||||||
|
- F-5E Tiger II
|
||||||
|
- A-4E Skyhawk
|
||||||
|
- OV-10A Bronco
|
||||||
|
- C-101CC Aviojet
|
||||||
|
- B-52H Stratofortress
|
||||||
|
- C-47 Skytrain
|
||||||
|
- C-130
|
||||||
|
- UH-1H Iroquois
|
||||||
|
- AH-1W SuperCobra
|
||||||
|
- OH-58D Kiowa Warrior
|
||||||
|
- CH-47D
|
||||||
|
- CH-53E
|
||||||
|
awacs:
|
||||||
|
- E-2C Hawkeye
|
||||||
|
tankers:
|
||||||
|
- KC-130
|
||||||
|
- KC-135 Stratotanker
|
||||||
|
frontline_units:
|
||||||
|
- M113
|
||||||
|
- M163 Vulcan Air Defense System
|
||||||
|
- M60A3 "Patton"
|
||||||
|
artillery_units:
|
||||||
|
- M109A6 Paladin
|
||||||
|
logistics_units:
|
||||||
|
- Truck M818 6x6
|
||||||
|
- LARC-V
|
||||||
|
infantry_units:
|
||||||
|
- Infantry M249
|
||||||
|
- Infantry M4
|
||||||
|
missiles: []
|
||||||
|
preset_groups:
|
||||||
|
- Hawk
|
||||||
|
naval_units:
|
||||||
|
- FFG Oliver Hazard Perry
|
||||||
|
- CV-59 Forrestal
|
||||||
|
air_defense_units:
|
||||||
|
- SAM Hawk SR (AN/MPQ-50)
|
||||||
|
- M163 Vulcan Air Defense System
|
||||||
|
- M48 Chaparral
|
||||||
|
carrier_names:
|
||||||
|
- CV-59 Forrestal
|
||||||
|
- CV-60 Saratoga
|
||||||
|
- CV-61 Ranger
|
||||||
|
- CV-62 Independence
|
||||||
|
requirements: {}
|
||||||
|
doctrine: coldwar
|
||||||
@@ -30,10 +30,8 @@
|
|||||||
<h2>Launching the mission:</h2>
|
<h2>Launching the mission:</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Launch the <code>liberation_nextturn</code> mission as you normally would for single-
|
Launch the <code>liberation_nextturn</code> mission as you normally would for
|
||||||
or multi-player. Note that even for single-player, running the mission with the
|
single- or multi-player.
|
||||||
dedicated server, <em>even on the same machine</em>, can significantly improve frame
|
|
||||||
rates, but may cause AI wingmen to behave strangely during taxi.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user