Compare commits

...

52 Commits

Author SHA1 Message Date
Astro-739
ce073c24bc Update of Campaign Falcon Went over the Mountain.
Added secondary mission types to all air-to-air squadrons for more
flexibility.
2023-12-30 20:33:03 +00:00
Starfire13
8de053cc7d Add Operation Aegean Aegis.
Adds a new Apache and Harrier campaign to the Syria map.
2023-12-28 20:01:34 -08:00
Astro-739
fe6e49b22b Update of Campaign Falcon Went over the Mountain.
Campaign update of Falcon Went over the Mountain (Syria map) to v11.0

1. Added squadron sizes
2. Rebalanced scenario
3. Added (non zero) heading to all SAM and EWR sites
2023-12-28 23:03:46 +00:00
Starfire13
3653dc8cbd Campaign inversion support for Battle for No Man's Land. 2023-12-27 14:06:46 -08:00
Starfire13
d2b5eea0de Update Harrier loadout (#3316)
I had a look and the default Harrier loadouts were very outdated and
quite sub-optimal. So I fixed it up.
2023-12-27 14:05:43 -08:00
zhexu14
211ec86e2e Apache speed fix (#3315)
This PR 1) introduces a cruise_speed parameter to the AircraftType class
and uses it as an override for default TOT/Ground Speed calculations and
2) sets this for the AH64.

The reason for this change is that air starts with the Apache at a speed
>130kt seems to completely break the FCR, even if you subsequently slow
down. In the development branch, Liberation sets the Apache to travel at
168kt, so any player air starting won't be able to use their FCR and it
wouldn't be readily apparent as to why.

In the longer run this parameter may also be useful for other aircraft
e.g. to override the cruise speed to the most efficient etc.
2023-12-27 14:04:16 -08:00
Starfire13
03caddc1b4 Update F-15E Suite 4+ loadouts to add the fixed GBU31v3 (#3314) 2023-12-21 22:15:16 -08:00
Dan Albert
3f7618d75d Update pydcs.
Has the __eq__ implementation for Task which fixes inconsistent save
loading issues.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3288.
2023-12-21 21:48:17 -08:00
Dan Albert
dcf23c655d Describe non-airport "runways" better.
Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3290.
2023-12-21 16:46:06 -08:00
Dan Albert
ef69275f34 Don't send the selected flight plan to the back.
We want the selected flight plan to show on top of all the other flight
plans, and because we can't properly z-order with the other elements of
the map (see the code comment), this is probably the best we can do.

This means that the selected flight will be drawn on top of the front
line again, and will in some cases intercept mouse clicks meant for the
front line, but it's much less of a problem than when all the paths were
drawn on top.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3305.
2023-12-21 15:43:12 -08:00
Dan Albert
167cea08f6 Update pydcs.
Normandy terrain update.
2023-12-21 15:34:47 -08:00
zhexu14
48ae55bdc2 Default overrides fix (#3307)
This PR makes sure that the Payload tab of the Edit Flight window shows
the correct property values (with `default_overrides` applied in the
aircraft YAML). It looks like the issue only affects an obscure
parameter on F14s (INS reference alignment stored) so may not have been
noticed until now.
2023-12-21 02:51:34 -08:00
zhexu14
ff2bd3f815 Enable AH-64 FCR by default. 2023-12-20 21:42:18 -08:00
Starfire13
ba5d0bed4d Add Battle for No Man's Land campaign. 2023-12-20 18:40:31 -08:00
Dan Albert
4a07b8a2d8 Update pydcs. 2023-12-20 18:01:39 -08:00
Dan Albert
1efce862fb Send flight plan paths to the back of the map.
This fixes the unusual case where the `interactive: false` property had
no effect, which would make it impossible to plan missions against UI
elements that were overflown by many flights (such as the front line).

As an added bonus, it looks a bit nicer.

This impacts the test in an odd way, but the cure for that is probably
rewriting the test to not use a mock now that we've figured out how to
do that.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3295.
2023-12-18 20:16:08 -08:00
Starfire13
80cb440e7d Adds Private Military Company - Russian (Hard) faction.
This is a new faction that expands on the current PMC Russian faction by
adding in a substantial number of new units for additional variety and
challenge. It'll be the default faction for my helicopter campaign (I'll
open a PR for that tomorrow. It's all done apart from the campaign
description).
2023-12-18 17:49:12 -08:00
Starfire13
e970c281e8 Add DEAD loadouts to AH-64D, KA-50, and KA-50 BS3 (#3301) 2023-12-18 17:41:19 -08:00
dependabot[bot]
b863e2fb83 Bump pyinstaller from 5.13.0 to 5.13.1
Bumps [pyinstaller](https://github.com/pyinstaller/pyinstaller) from 5.13.0 to 5.13.1.
- [Release notes](https://github.com/pyinstaller/pyinstaller/releases)
- [Changelog](https://github.com/pyinstaller/pyinstaller/blob/develop/doc/CHANGES.rst)
- [Commits](https://github.com/pyinstaller/pyinstaller/compare/v5.13.0...v5.13.1)

---
updated-dependencies:
- dependency-name: pyinstaller
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-17 18:45:43 -08:00
Starfire13
3007a96343 Add DEAD capability to AH-64D Blk II 2023-12-17 18:43:16 -08:00
Starfire13
463981f4bf Add DEAD mission capability to Blackshark 3 2023-12-17 18:43:05 -08:00
Starfire13
816d1cd787 Add DEAD mission capability to KA-50 2023-12-17 18:42:54 -08:00
zhexu14
4631ee0d74 Doctrine load from YAML (#3291)
This PR refactors the Doctrine class to load from YAML files in the
resources folder instead of being hardcoded as a step towards making
doctrines moddable (Issue #829).

I haven't added anything to the changelog as a couple of things should
get cleaned up first:
- As far as I can tell, the flags in the Doctrine class (cap, cas, sead
etc.) aren't used anywhere. Need to test further, and if they're truly
not used, will remove them.
- Probably need to update the Wiki
2023-12-17 18:42:31 -08:00
zhexu14
a213215c3f Fix exception when campaign has only off map CPs.
This PR fixes an exception in custom campaigns that only contain off map
spawns.
2023-12-15 14:25:11 -08:00
Starfire13
b014f2e543 Improve F-15E S4+ loadouts (#3286)
I've come to realise that two external tanks is overkill for pretty much
all A2G mission types. The AI no longer have a problem with fuel, and
player flights will essentially never run out of fuel with the 2 CFTs
and a single external tank. I have done 700+ mile trips at mil power the
whole way with fuel to spare. I have therefore switched all A2G mission
loadouts to a single tank. A2A loadouts still carry 2 tanks, as players
may require the extra fuel if they make very extensive use of
afterburner in air combat.

It turns out the GBU31v3 JDAMs are bugged in more than one way. We've
known that they vanish if carried in pairs on the CFT pylons, but now it
turns out their penetration doesn't actually work. This means they are
no better in any way than the GBU31v1s, which are not bugged on CFT
pylons.

I have therefore removed the penetrator JDAMs from all loadouts,
replacing them with regular JDAMs.
2023-12-06 16:46:16 -08:00
Nosajthedevil
f3d3c5f43a Aim-9 Updates (#3287)
Adds the Aim-9P3 between the Aim-9P5 and the Aim-9P. Also adds fallback
support for sidewinder versions for the VSN 104 mod, the JAS39 mod, and
the AJS-37.
2023-12-06 16:45:38 -08:00
Dan Albert
5ee3afeddb Disconnect log signals on exit.
If we don't do this, the uvicorn server may log its shutdown after the
Qt application has closed, and the signal this attempts to emit may not
be valid. Disconnect the log signals when the application exits to
prevent that.

There's actually another solution that I thought would be better, but I
couldn't get it to work:
https://www.pyinstaller.org/en/stable/feature-notes.html#automatic-hiding-and-minimization-of-console-window-under-windows
describes a way to have pyinstaller hide or minimize the console rather
than disabling it entirely. I was never really fond of getting rid of
the console window in the first place, but it did bother some users. If
we could get the hide or minimize option working, that'd probably avoid
bothering users, but also make the logs much easier to find, get us out
of the trouble of maintaining our own log viewer, and fix the problem
mentioned in the comment I add here (the log window only works if
there's only one in memory log handler).

Another option would be ditching our log window and instead just having
that menu item open the log file or directory in whatever program the OS
defaults to (probably notepad). It would still have the quirk of maybe
needing to open more than one location, since logging is use
configurable.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3278.
2023-12-02 15:59:00 -08:00
Dan Albert
88591fd18c Downgrade Qt.
Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3276.
2023-12-02 15:01:07 -08:00
Dan Albert
f5573cfc19 Revert "Update to Python 3.12."
Might fix https://github.com/dcs-liberation/dcs_liberation/issues/3276.
If not, we need to revert the Qt upgrade too, and if we downgrade Qt we
can't use Python 3.12 anyway.

This reverts commit 65eb10639b.
2023-12-02 15:01:07 -08:00
Dan Albert
f7141a9882 Fix a few more Pydantic conversions.
One of the newer versions got a lot more strict. It now only expects
dicts that match the model, or objects of the model. Previously it also
accepted objects which had the same properties as the model. Convert a
few more LatLngs to LeafletPoints.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3279.
2023-12-02 12:25:01 -08:00
dependabot[bot]
a599b503f8 Bump @adobe/css-tools from 4.3.1 to 4.3.2 in /client
Bumps [@adobe/css-tools](https://github.com/adobe/css-tools) from 4.3.1 to 4.3.2.
- [Changelog](https://github.com/adobe/css-tools/blob/main/History.md)
- [Commits](https://github.com/adobe/css-tools/commits)

---
updated-dependencies:
- dependency-name: "@adobe/css-tools"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 16:15:04 -08:00
Dan Albert
6c4b8c81ee Update mypy.
Needed so mypy can recognize the new Python 3.12 generic syntax.
2023-12-01 16:14:54 -08:00
Dan Albert
2447cc156d Update black.
Required for the new syntax in Python 3.12.
2023-11-30 21:10:14 -08:00
Dan Albert
28954d05eb Downgrade pyinstaller.
I forgot to test the pyinstaller binary when I upgraded all the other
dependencies, and there's a breaking change in 6.0.0:

https://pyinstaller.org/en/latest/CHANGES.html#incompatible-changes

> All of onedir build's contents except for the executable are now moved
> into a sub-directory (called _internal by default). sys._MEIPASS is
> adjusted to point to this _internal directory. The breaking
> implications for this are:
>
> * Assumptions that os.path.dirname(sys.executable) == sys._MEIPASS
>   will break. Code locating application resources using
>   os.path.dirname(sys.executable) should be adjusted to use __file__
>   or sys._MEIPASS and any code locating the original executable using
>   sys._MEIPASS should use sys.executable directly.
> * Any custom post processing steps (either in the .spec file or
>   externally) which modify the bundle will likely need adjusting to
>   accommodate the new directory.

This is actually great because it declutters the top level directory to
just `dcs_liberation.exe` and a directory named `_internal` that has all
the guts, but the CWD is no longer the directory that has `resources/`
in it, so we can't find any of our resources. There are a few options
for fixing that (cd into that directory probably being the easiest, or
we could stop relying on CWD relative paths), but for now just downgrade
to unbreak the build.
2023-11-30 21:01:13 -08:00
Dan Albert
65eb10639b Update to Python 3.12. 2023-11-30 20:45:19 -08:00
Dan Albert
7bc35ef7f4 Update most Python dependencies.
A lot of the dependency versions we have pinned don't have wheels for
Python 3.12. Update almost all of them so we can upgrade Python.

The few that weren't upgraded here are black and mypy, since those will
be a bit invasive, and Pillow, which has an API change I don't want to
deal with right now (I've got a commit on another machine that has
already done the migration, so I'll do it later).
2023-11-30 20:24:28 -08:00
Starfire13
46766ecbd4 Remove AI F-15E from Starfire's campaigns.
Now that the F-15E Suite 4+ has JDAMs and the bug preventing AI from
using LGBs has been fixed, I have removed the AI-only F-15Es from my
campaigns. Also minor tweaks to a couple of squadron types/sizes based
on play-testing results.
2023-11-30 19:12:45 -08:00
Dan Albert
3469d08461 Remove recommendation to dedicated server.
DCS multithreading made this unnecessary.
2023-11-30 19:10:26 -08:00
Dan Albert
28d959bba0 Fix disappearing aircraft when deleting packages.
There are a few different code paths for deleting packages depending on
the state of the package, and two of them were deleting items from a
list they were iterating over without first making a copy, causing each
iteration of the loop to skip over a flight, making it still used since
the flight was never deleted, but unreachable since the package that
owned it was deleted.

This only happened when the package was canceled in its draft state
(the user clicked the X without ever saving the package), or if the user
canceled a package mid fast forward (the controls for which aren't even
visible to users) while only a portion of the package was active. In
both cases, only even numbered flights were lost.

There's a better fix lurking in here somewhere but the interaction with
the Qt model complicates it. Fortunately that mess would be cleaned up
automatically by moving this dialog into React, which we'll do some day.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3257.
Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3258.
2023-11-30 19:00:58 -08:00
Dan Albert
b99eb49dcf Renumber flight members for meatbags.
Puny humans count wrong, but we ought to match DCS.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3244.
2023-11-30 18:47:43 -08:00
Starfire13
c6f812238c Update Exercise Vegas Nerve.
Updated Exercise Vegas Nerve with off map spawns for B-52 and B-1.
2023-12-01 02:02:21 +00:00
Starfire13
cc5b5fa3bb Add new Mariana Islands campaign - Operation Velvet Thunder.
Vietnam War era campaign for the Mariana Islands map, utilising the two
new Vietnam War factions.
2023-12-01 01:57:50 +00:00
Starfire13
5271b3d32c Switch F-15E S4+ loadouts from LGBs to JDAMs (AI still won't use LGBs) (#3259)
It appears the AI is still incapable of using LGBs (and laser JDAMs),
even though Razbam had said the issues was fixed. I have switched
loadouts to JDAMs because the AI will use those.
2023-11-30 17:56:34 -08:00
Starfire13
8f4192edc3 Fix Operation Grabthar's Hammer map object strike target.
This fixes a map object strike target (yes, just one. Fortunately!) that
was broken by the latest DCS open beta update that removed the buildings
the strike target was using.
2023-11-30 17:51:55 -08:00
Starfire13
183d6df8bf Add guided bombs to F-15E Suite 4+ loadouts.
GBUs have been added to the F-15E Suite 4+ loadouts

Also switched CAP loadouts to 2 external tanks instead of 3 to improve
aircraft performance, as 2 tanks is plenty for players and the AI has
infinite fuel now.
2023-11-18 18:51:42 -08:00
Dan Albert
a825651330 Update pydcs.
Terrain updates for Normandy and South Atlantic.
2023-11-18 15:00:21 -08:00
Dan Albert
f3c02816fc Update pydcs.
Includes F-15E JDAM support.
2023-11-18 14:54:14 -08:00
Starfire13
c4e2e45650 Add Vietnam War factions for USA and NVA.
This adds factions for Vietnam War for both the US and North Vietnamese
Army.
2023-11-18 14:20:14 -08:00
Starfire13
6613642517 Add LARC-V and Speedboat.
This adds LARC-V to Liberation (required by USA 1970)
Also adds Speedboat to Liberation (required by NVA 1970)

Both units are available via pydcs but have not been added to Liberation
thus far as no factions used them (until now).
2023-11-18 22:12:40 +00:00
Dan Albert
b73ca2c62e Update bug templates. 2023-11-11 13:32:10 -08:00
Dan Albert
8abd3c7cf9 Fix typo in changelog. 2023-11-11 13:28:57 -08:00
Dan Albert
f8a72d8f22 Bump version to 10.0.0. 2023-11-10 19:15:41 -08:00
120 changed files with 1713 additions and 804 deletions

View File

@@ -31,7 +31,7 @@ body:
If the bug was found in a development build, select "Development build"
and provide a link to the build in the field below.
options:
- 8.1.0
- 9.0.0
- Development build
- type: textarea
attributes:

View File

@@ -39,7 +39,7 @@ body:
If the bug was found in a development build, select "Development build"
and provide a link to the build in the field below.
options:
- 8.1.0
- 9.0.0
- Development build
- type: textarea
attributes:

View File

@@ -11,7 +11,7 @@ jobs:
- uses: actions/setup-python@v2
- uses: psf/black@stable
with:
version: ~=22.12
version: ~=23.11
src: "."
options: "--check"

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/psf/black
rev: 22.12.0
rev: 23.11.0
hooks:
- id: black
language_version: python3

View File

@@ -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
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 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]** 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 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.

View File

@@ -50,9 +50,9 @@
}
},
"node_modules/@adobe/css-tools": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz",
"integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg=="
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
"integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw=="
},
"node_modules/@ampproject/remapping": {
"version": "2.1.2",
@@ -21339,9 +21339,9 @@
},
"dependencies": {
"@adobe/css-tools": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz",
"integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg=="
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
"integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw=="
},
"@ampproject/remapping": {
"version": "2.1.2",

View File

@@ -1,7 +1,8 @@
import { Flight } from "../../api/liberationApi";
import { useGetCommitBoundaryForFlightQuery } from "../../api/liberationApi";
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";
const BLUE_PATH = "#0084ff";
@@ -27,16 +28,41 @@ const pathColor = (props: FlightPlanProps) => {
function FlightPlanPath(props: FlightPlanProps) {
const color = pathColor(props);
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) {
return <></>;
}
const points = waypoints
.filter((waypoint) => waypoint.include_in_path)
.map((waypoint) => waypoint.position);
return (
<Polyline
positions={points}
pathOptions={{ color: color, interactive: false }}
ref={polylineRef}
/>
);
}

View File

@@ -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", () => {
renderWithProviders(<FlightPlansLayer blue={true} />, {

View File

@@ -9,7 +9,7 @@
project = "DCS Liberation"
copyright = "2023, DCS Liberation Team"
author = "DCS Liberation Team"
release = "9.0.0"
release = "10.0.0"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

View File

@@ -65,7 +65,6 @@ class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]):
class Builder(IBuilder[RecoveryTankerFlightPlan, RecoveryTankerLayout]):
def layout(self) -> RecoveryTankerLayout:
builder = WaypointBuilder(self.flight, self.coalition)
# TODO: Propagate the ship position to the Tanker's TOT,

View File

@@ -18,6 +18,9 @@ class GroundSpeed:
# on fuel, but mission speed will be fast enough to keep the flight
# 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.
max_speed = flight.unit_type.max_speed
if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL:

View File

@@ -29,7 +29,6 @@ class DefaultSquadronAssigner:
self.coalition.player
):
for squadron_config in self.config.by_location[control_point]:
squadron_def = self.override_squadron_defaults(
self.find_squadron_for(squadron_config, control_point),
squadron_config,
@@ -162,7 +161,6 @@ class DefaultSquadronAssigner:
def override_squadron_defaults(
squadron_def: Optional[SquadronDef], config: SquadronConfig
) -> Optional[SquadronDef]:
if squadron_def is None:
return None

View File

@@ -25,6 +25,7 @@ from game.utils import meters, nautical_miles
if TYPE_CHECKING:
from game import Game
from game.transfers import CargoShip, Convoy
from game.threatzones import ThreatZones
MissionTargetType = TypeVar("MissionTargetType", bound=MissionTarget)
@@ -193,17 +194,36 @@ class ObjectiveFinder:
def farthest_friendly_control_point(self) -> ControlPoint:
"""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)
farthest = None
max_distance = meters(0)
for cp in self.friendly_control_points():
if isinstance(cp, OffMapSpawn):
continue
distance = threat_zones.distance_to_threat(cp.position)
if distance > max_distance:
farthest = cp
max_distance = distance
farthest = find_farthest(
self.friendly_control_points(), threat_zones, consider_off_map_spawn=False
)
# If there are only off-map spawn control points, fall back to the farthest amongst off map spawn points
if farthest is None:
farthest = find_farthest(
self.friendly_control_points(),
threat_zones,
consider_off_map_spawn=True,
)
if farthest is None:
raise RuntimeError("Found no friendly control points. You probably lost.")

View File

@@ -1,3 +1,9 @@
from __future__ import annotations
from pathlib import Path
import yaml
from typing import ClassVar
from dataclasses import dataclass
from datetime import timedelta
@@ -15,6 +21,16 @@ class GroundUnitProcurementRatios:
except KeyError:
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)
class Doctrine:
@@ -79,122 +95,78 @@ class Doctrine:
ground_unit_procurement_ratios: GroundUnitProcurementRatios
_by_name: ClassVar[dict[str, Doctrine]] = {}
_loaded: ClassVar[bool] = False
MODERN_DOCTRINE = Doctrine(
"modern",
cap=True,
cas=True,
sead=True,
strike=True,
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,
}
),
)
@classmethod
def register(cls, doctrine: Doctrine) -> None:
if doctrine.name in cls._by_name:
duplicate = cls._by_name[doctrine.name]
raise ValueError(f"Doctrine {doctrine.name} is already loaded")
cls._by_name[doctrine.name] = doctrine
COLDWAR_DOCTRINE = Doctrine(
name="coldwar",
cap=True,
cas=True,
sead=True,
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,
}
),
)
@classmethod
def named(cls, name: str) -> Doctrine:
if not cls._loaded:
cls.load_all()
return cls._by_name[name]
WWII_DOCTRINE = Doctrine(
name="ww2",
cap=True,
cas=True,
sead=False,
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,
}
),
)
@classmethod
def all_doctrines(cls) -> list[Doctrine]:
if not cls._loaded:
cls.load_all()
return list(cls._by_name.values())
ALL_DOCTRINES = [
COLDWAR_DOCTRINE,
MODERN_DOCTRINE,
WWII_DOCTRINE,
]
@classmethod
def load_all(cls) -> None:
if cls._loaded:
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

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections import defaultdict
from dataclasses import dataclass
from dataclasses import dataclass, replace as dataclasses_replace
from functools import cache, cached_property
from pathlib import Path
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.
max_mission_range: Distance
#: Speed used for TOT calculations
cruise_speed: Optional[Speed]
fuel_consumption: Optional[FuelConsumption]
default_livery: Optional[str]
@@ -400,6 +403,12 @@ class AircraftType(UnitType[Type[FlyingType]]):
for k in config:
if k in aircraft.property_defaults:
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:
logging.warning(
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_speed=patrol_config.speed,
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,
default_livery=data.get("default_livery"),
intra_flight_radio=radio_config.intra_flight,

View File

@@ -19,12 +19,7 @@ from game.data.building_data import (
WW2_FREE,
WW2_GERMANY_BUILDINGS,
)
from game.data.doctrine import (
COLDWAR_DOCTRINE,
Doctrine,
MODERN_DOCTRINE,
WWII_DOCTRINE,
)
from game.data.doctrine import Doctrine
from game.data.groups import GroupRole
from game.data.units import UnitClass
from game.dcs.aircrafttype import AircraftType
@@ -106,7 +101,7 @@ class Faction:
jtac_unit: Optional[AircraftType] = field(default=None)
# doctrine
doctrine: Doctrine = field(default=MODERN_DOCTRINE)
doctrine: Doctrine = field(default=Doctrine.named("modern"))
# List of available building layouts for this faction
building_set: List[str] = field(default_factory=list)
@@ -238,14 +233,7 @@ class Faction:
# Load doctrine
doctrine = json.get("doctrine", "modern")
if doctrine == "modern":
faction.doctrine = MODERN_DOCTRINE
elif doctrine == "coldwar":
faction.doctrine = COLDWAR_DOCTRINE
elif doctrine == "ww2":
faction.doctrine = WWII_DOCTRINE
else:
faction.doctrine = MODERN_DOCTRINE
faction.doctrine = Doctrine.named(doctrine)
# Load the building set
faction.building_set = []

View File

@@ -11,17 +11,14 @@ from shapely import transform
from shapely.geometry import shape
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 .waypointsolver import WaypointSolver
from ..theater.theaterloader import TERRAINS_BY_NAME
def doctrine_from_name(name: str) -> Doctrine:
for doctrine in ALL_DOCTRINES:
if doctrine.name == name:
return doctrine
raise KeyError
return Doctrine.named(name)
def geometry_ll_to_xy(geometry: BaseGeometry, terrain: Terrain) -> BaseGeometry:

View File

@@ -119,7 +119,6 @@ class RequirementBuilder:
def maximum_turn_to(
self, turn_point: Point, next_point: Point, turn_limit: Heading
) -> None:
large_distance = nautical_miles(400)
next_heading = Heading.from_degrees(
angle_between_points(next_point, turn_point)

View File

@@ -89,7 +89,6 @@ class GroundPlanner:
self.reserve: List[CombatGroup] = []
def plan_groundwar(self) -> None:
ground_unit_limit = self.cp.frontline_unit_count_limit
remaining_available_frontline_units = ground_unit_limit
@@ -139,7 +138,6 @@ class GroundPlanner:
remaining_available_frontline_units -= available
while available > 0:
if role == CombatGroupRole.SHORAD:
count = 1
else:

View File

@@ -241,7 +241,6 @@ class AntiAirLayout(TgoLayout):
location: PresetLocation,
control_point: ControlPoint,
) -> IadsGroundObject:
if GroupTask.EARLY_WARNING_RADAR in self.tasks:
return EwrGroundObject(name, location, control_point)
elif any(tasking in self.tasks for tasking in GroupRole.AIR_DEFENSE.tasks):

View File

@@ -132,7 +132,6 @@ class LayoutLoader:
temp_mis.country(country.name).ship_group,
temp_mis.country(country.name).static_group,
):
try:
g_id, u_id, group_name, group_mapping = mapping.group_for_name(
dcs_group.name

View File

@@ -8,7 +8,6 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
class RecoveryTankerBuilder(PydcsWaypointBuilder):
def add_tasks(self, waypoint: MovingPoint) -> None:
assert self.flight.flight_type == FlightType.REFUELING
# Tanker task required in conjunction with RecoveryTanker task.
@@ -48,7 +47,6 @@ class RecoveryTankerBuilder(PydcsWaypointBuilder):
)
def configure_tanker_tacan(self, waypoint: MovingPoint) -> None:
if self.flight.unit_type.dcs_unit_type.tacan:
tanker_info = self.mission_data.tankers[-1]
tacan = tanker_info.tacan

View File

@@ -6,7 +6,6 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
class SplitPointBuilder(PydcsWaypointBuilder):
def add_tasks(self, waypoint: MovingPoint) -> None:
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.
# You can bully them with STT to not be able to fire radar guided missiles at you,

View File

@@ -59,7 +59,6 @@ class DrawingsGenerator:
if destination in seen:
continue
else:
# Determine path color
if cp.captured and destination.captured:
color = BLUE_PATH_COLOR

View File

@@ -191,7 +191,6 @@ class FlotGenerator:
side: Country,
forward_heading: Heading,
) -> None:
infantry_position = self.conflict.find_ground_position(
group.points[0].position.random_point_within(250, 50),
500,
@@ -304,7 +303,6 @@ class FlotGenerator:
# Artillery will fall back when under attack
if stance != CombatStance.RETREAT:
# Hold position
dcs_group.points[1].tasks.append(Hold())
retreat = self.find_retreat_point(
@@ -476,7 +474,6 @@ class FlotGenerator:
from_cp: ControlPoint,
to_cp: ControlPoint,
) -> None:
if not self.game.settings.perf_moving_units:
return

View File

@@ -185,7 +185,6 @@ class NumberedWaypoint:
class FlightPlanBuilder:
WAYPOINT_DESC_MAX_LEN = 25
def __init__(self, start_time: datetime.datetime, units: UnitSystem) -> None:
@@ -503,7 +502,6 @@ class SupportPage(KneeboardPage):
aewc_ladder = []
for single_aewc in self.awacs:
if single_aewc.depature_location is None:
dep = "-"
arr = "-"

View File

@@ -402,7 +402,6 @@ class GenericCarrierGenerator(GroundObjectGenerator):
self.mission_data = mission_data
def generate(self) -> None:
# This can also be refactored as the general generation was updated
atc = self.radio_registry.alloc_uhf()

View File

@@ -41,7 +41,6 @@ class ProcurementAi:
manage_front_line: bool,
manage_aircraft: bool,
) -> None:
self.game = game
self.is_player = for_player
self.air_wing = game.air_wing_for(for_player)

View File

@@ -33,15 +33,19 @@ class FrozenCombatJs(BaseModel):
if isinstance(combat, AtIp):
return FrozenCombatJs(
id=combat.id,
flight_position=combat.flight.position().latlng(),
target_positions=[combat.flight.package.target.position.latlng()],
flight_position=LeafletPoint.from_pydcs(combat.flight.position()),
target_positions=[
LeafletPoint.from_pydcs(combat.flight.package.target.position)
],
footprint=None,
)
if isinstance(combat, DefendingSam):
return FrozenCombatJs(
id=combat.id,
flight_position=combat.flight.position().latlng(),
target_positions=[sam.position.latlng() for sam in combat.air_defenses],
flight_position=LeafletPoint.from_pydcs(combat.flight.position()),
target_positions=[
LeafletPoint.from_pydcs(sam.position) for sam in combat.air_defenses
],
footprint=None,
)
raise NotImplementedError(f"Unhandled FrozenCombat type: {combat.__class__}")

View File

@@ -28,12 +28,12 @@ class ControlPointJs(BaseModel):
def for_control_point(control_point: ControlPoint) -> ControlPointJs:
destination = 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(
id=control_point.id,
name=control_point.name,
blue=control_point.captured,
position=control_point.position.latlng(),
position=LeafletPoint.from_pydcs(control_point.position),
mobile=control_point.moveable and control_point.captured,
destination=destination,
sidc=str(control_point.sidc()),

View File

@@ -47,7 +47,6 @@ class GameUpdateEventsJs(BaseModel):
def from_events(
cls, events: GameUpdateEvents, game: Game | None
) -> GameUpdateEventsJs:
# We still need to be able to send update events when there is no game loaded
# because we need to send the unload event.
new_combats = []
@@ -81,9 +80,13 @@ class GameUpdateEventsJs(BaseModel):
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(
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,
updated_combats=updated_combats,
@@ -110,7 +113,7 @@ class GameUpdateEventsJs(BaseModel):
],
updated_iads=updated_iads,
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,
new_turn=events.new_turn,
)

View File

@@ -1,5 +1,5 @@
import asyncio
from asyncio import wait
from asyncio import wait, Future
from fastapi import APIRouter, WebSocket
from fastapi.encoders import jsonable_encoder
@@ -16,9 +16,9 @@ class ConnectionManager:
self.active_connections: list[WebSocket] = []
async def shutdown(self) -> None:
futures = []
futures: list[Future[None]] = []
for connection in self.active_connections:
futures.append(connection.close())
futures.append(asyncio.create_task(connection.close()))
await wait(futures)
async def connect(self, websocket: WebSocket) -> None:

View File

@@ -37,7 +37,7 @@ class FlightJs(BaseModel):
# lost.
position = None
if isinstance(flight.state, InFlight) or isinstance(flight.state, Killed):
position = flight.position().latlng()
position = LeafletPoint.from_pydcs(flight.position())
waypoints = None
if with_waypoints:
waypoints = waypoints_for_flight(flight)

View File

@@ -27,7 +27,10 @@ class FrontLineJs(BaseModel):
bounds = FrontLineConflictDescription.frontline_bounds(front_line, theater)
return FrontLineJs(
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

View File

@@ -7,12 +7,12 @@ from pydantic import BaseModel
from game.server.controlpoints.models import ControlPointJs
from game.server.flights.models import FlightJs
from game.server.frontlines.models import FrontLineJs
from game.server.iadsnetwork.models import IadsNetworkJs
from game.server.leaflet import LeafletPoint
from game.server.mapzones.models import ThreatZoneContainerJs, UnculledZoneJs
from game.server.navmesh.models import NavMeshesJs
from game.server.supplyroutes.models import SupplyRouteJs
from game.server.tgos.models import TgoJs
from game.server.iadsnetwork.models import IadsConnectionJs, IadsNetworkJs
if TYPE_CHECKING:
from game import Game
@@ -44,6 +44,8 @@ class GameJs(BaseModel):
iads_network=IadsNetworkJs.from_network(game.theater.iads_network),
threat_zones=ThreatZoneContainerJs.for_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),
)

View File

@@ -1,11 +1,11 @@
from __future__ import annotations
from uuid import UUID
from pydantic import BaseModel
from game.server.leaflet import LeafletPoint
from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode, IadsNetwork
from game.theater.theatergroundobject import TheaterGroundObject
class IadsConnectionJs(BaseModel):
@@ -45,8 +45,8 @@ class IadsConnectionJs(BaseModel):
IadsConnectionJs(
id=id,
points=[
tgo.position.latlng(),
connection.ground_object.position.latlng(),
LeafletPoint.from_pydcs(tgo.position),
LeafletPoint.from_pydcs(connection.ground_object.position),
],
node=tgo.id,
connected=connection.ground_object.id,

View File

@@ -19,6 +19,11 @@ class LeafletPoint(BaseModel):
title = "LatLng"
@staticmethod
def from_pydcs(point: Point) -> LeafletPoint:
latlng = point.latlng()
return LeafletPoint(lat=latlng.lat, lng=latlng.lng)
LeafletLine = list[LeafletPoint]

View File

@@ -36,7 +36,7 @@ class UnculledZoneJs(BaseModel):
def from_game(game: Game) -> list[UnculledZoneJs]:
return [
UnculledZoneJs(
position=zone.latlng(),
position=LeafletPoint.from_pydcs(zone),
radius=game.settings.perf_culling_distance * 1000,
)
for zone in game.get_culling_zones()

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
from functools import lru_cache
from pydantic import BaseSettings
from pydantic_settings import BaseSettings
class ServerSettings(BaseSettings):

View File

@@ -92,7 +92,7 @@ class SupplyRouteJs(BaseModel):
# https://reactjs.org/docs/lists-and-keys.html#keys
# https://github.com/dcs-liberation/dcs_liberation/issues/2167
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),
is_sea=sea,
blue=a.captured,

View File

@@ -38,7 +38,7 @@ class TgoJs(BaseModel):
control_point_name=tgo.control_point.name,
category=tgo.category,
blue=tgo.control_point.captured,
position=tgo.position.latlng(),
position=LeafletPoint.from_pydcs(tgo.position),
units=[unit.display_name for unit in tgo.units],
threat_ranges=threat_ranges,
detection_ranges=detection_ranges,

View File

@@ -82,7 +82,7 @@ class FlightWaypointJs(BaseModel):
return FlightWaypointJs(
name=waypoint.name,
position=waypoint.position.latlng(),
position=LeafletPoint.from_pydcs(waypoint.position),
altitude_ft=waypoint.alt.feet,
altitude_reference=waypoint.alt_type,
is_movable=is_movable,

View File

@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING
from uuid import UUID
from dcs import Point
from dcs.mapping import LatLng
if TYPE_CHECKING:
from game import Game
@@ -38,7 +37,7 @@ class GameUpdateEvents:
updated_control_points: set[ControlPoint] = field(default_factory=set)
updated_iads: set[IadsNetworkNode] = 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
new_turn: bool = False
shutting_down: bool = False
@@ -140,9 +139,7 @@ class GameUpdateEvents:
self.game_unloaded = True
self.reset_on_map_center = None
else:
self.reset_on_map_center = (
game.theater.terrain.map_view_default.position.latlng()
)
self.reset_on_map_center = game.theater.terrain.map_view_default.position
self.game_unloaded = False
return self

View File

@@ -245,7 +245,6 @@ class MissionResultsProcessor:
delta = DEFEAT_INFLUENCE
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:
if (
ally_units_alive > 2 * enemy_units_alive
and player_aggresive

View File

@@ -54,7 +54,6 @@ class SquadronDef:
@classmethod
def from_yaml(cls, path: Path) -> SquadronDef:
with path.open(encoding="utf8") as squadron_file:
data = yaml.safe_load(squadron_file)

View File

@@ -271,15 +271,15 @@ class RunwayStatus:
def needs_repair(self) -> bool:
return self.damaged and self.repair_turns_remaining is None
def __str__(self) -> str:
def describe(self) -> str:
if not self.damaged:
return "Runway operational"
return "operational"
turns_remaining = self.repair_turns_remaining
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
@@ -915,6 +915,10 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
def runway_status(self) -> RunwayStatus:
...
@abstractmethod
def describe_runway_status(self) -> str | None:
"""Description of the runway status suitable for UI use."""
@property
def runway_can_be_repaired(self) -> bool:
return self.runway_status.needs_repair
@@ -1157,6 +1161,9 @@ class Airfield(ControlPoint):
def runway_status(self) -> RunwayStatus:
return self._runway_status
def describe_runway_status(self) -> str:
return f"Runway {self.runway_status.describe()}"
def damage_runway(self) -> None:
self.runway_status.damage()
@@ -1275,6 +1282,9 @@ class NavalControlPoint(ControlPoint, ABC):
def runway_status(self) -> RunwayStatus:
return RunwayStatus(damaged=not self.runway_is_operational())
def describe_runway_status(self) -> str:
return f"Flight deck {self.runway_status.describe()}"
@property
def runway_can_be_repaired(self) -> bool:
return False
@@ -1428,6 +1438,9 @@ class OffMapSpawn(ControlPoint):
def runway_status(self) -> RunwayStatus:
return RunwayStatus()
def describe_runway_status(self) -> str:
return f"Off-map airport {self.runway_status.describe()}"
@property
def can_deploy_ground_units(self) -> bool:
return False
@@ -1474,6 +1487,11 @@ class Fob(ControlPoint):
def runway_status(self) -> 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]:
from game.ato import FlightType

View File

@@ -196,7 +196,8 @@ class TheaterGroup:
def max_threat_range(self, radar_only: bool = False) -> Distance:
"""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_telar_range = meters(0)
max_tel_range = meters(0)

View File

@@ -718,7 +718,6 @@ class PendingTransfers:
self.order_airlift_assets_at(control_point)
def desired_airlift_capacity(self, control_point: ControlPoint) -> int:
if control_point.has_factory:
is_major_hub = control_point.total_aircraft_parking > 0
# Check if there is a CP which is only reachable via Airlift

View File

@@ -1,7 +1,7 @@
from pathlib import Path
MAJOR_VERSION = 9
MAJOR_VERSION = 10
MINOR_VERSION = 0
MICRO_VERSION = 0
VERSION_NUMBER = ".".join(str(v) for v in (MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION))

View File

@@ -190,7 +190,6 @@ class Weather(ABC):
def interpolate_solar_activity(
time_of_day: TimeOfDay, high: float, low: float
) -> float:
scale: float = 0
match time_of_day:

View File

@@ -32,7 +32,7 @@ def init():
if os.path.isfile(THEME_PREFERENCES_FILE_PATH):
try:
with (open(THEME_PREFERENCES_FILE_PATH)) as prefs:
with open(THEME_PREFERENCES_FILE_PATH) as prefs:
pref_data = json.loads(prefs.read())
__theme_index = pref_data["theme_index"]
set_theme_index(__theme_index)
@@ -83,5 +83,5 @@ def get_theme_css_file():
# save current theme index to json file
def save_theme_config():
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))

View File

@@ -1,5 +1,8 @@
from __future__ import annotations
import logging
import typing
from collections.abc import Iterator
LogHook = typing.Callable[[str], None]
@@ -15,6 +18,16 @@ class HookableInMemoryHandler(logging.Handler):
self._log = ""
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
def log(self) -> str:
return self._log

View File

@@ -288,7 +288,7 @@ class AtoModel(QAbstractListModel):
return
package_model = self.find_matching_package_model(package)
for flight in package.flights:
for flight in list(package.flights):
if flight.state.cancelable:
package_model.delete_flight(flight)
events.delete_flight(flight)

View File

@@ -54,7 +54,6 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
return waypoints
def find_possible_waypoints(self):
self.wpts = []
model = QStandardItemModel()
i = 0

View File

@@ -9,7 +9,6 @@ from game.debriefing import Debriefing
class GameUpdateSignal(QObject):
instance = None
gameupdated = Signal(Game)
budgetupdated = Signal(Game)

View File

@@ -27,6 +27,7 @@ from game.theater import ControlPoint, MissionTarget, TheaterGroundObject
from game.turnstate import TurnState
from qt_ui import liberation_install
from qt_ui.dialogs import Dialog
from qt_ui.logging_handler import HookableInMemoryHandler
from qt_ui.models import GameModel
from qt_ui.simcontroller import SimController
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.show()
def _disconnect_log_signals(self) -> None:
for handler in HookableInMemoryHandler.iter_registered_handlers():
handler.clearHook()
def _qsettings(self) -> QSettings:
return QSettings("DCS Liberation", "Qt UI")
@@ -597,6 +602,7 @@ class QLiberationWindow(QMainWindow):
QMessageBox.Yes | QMessageBox.No,
)
if result == QMessageBox.Yes:
self._disconnect_log_signals()
self._save_window_geometry()
super().closeEvent(event)
self.dialog = None

View File

@@ -28,7 +28,6 @@ from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
class DebriefingFileWrittenSignal(QObject):
instance = None
debriefingReceived = Signal(Debriefing)

View File

@@ -254,19 +254,22 @@ class QBaseMenu2(QDialog):
f" (Up to {ground_unit_limit} deployable, {unit_overage} reserve)"
)
self.intel_summary.setText(
"\n".join(
[
f"{aircraft}/{parking} aircraft",
f"{self.cp.base.total_armor} ground units" + deployable_unit_info,
f"{allocated.total_transferring} more ground units en route, {allocated.total_ordered} ordered",
str(self.cp.runway_status),
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'}",
]
)
intel_lines = [
f"{aircraft}/{parking} aircraft",
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:
intel_lines.append(runway_description)
intel_lines.extend(
[
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:
tooltip = (
f"Deployable unit limit ({self.cp.frontline_unit_count_limit}) = {FREE_FRONTLINE_UNIT_SUPPLY} (base) + "

View File

@@ -70,7 +70,6 @@ class QGroundObjectMenu(QDialog):
self.init_ui()
def init_ui(self):
self.mainLayout = QVBoxLayout()
self.budget = QBudgetBox(self.game)
self.budget.setGame(self.game)
@@ -105,7 +104,6 @@ class QGroundObjectMenu(QDialog):
self.setLayout(self.mainLayout)
def doLayout(self):
self.update_total_value()
self.intelBox = QGroupBox("Units :")
self.intelLayout = QGridLayout()

View File

@@ -160,7 +160,6 @@ class IntelWindow(QDialog):
self.refresh_layout()
def refresh_layout(self) -> None:
# Clear the existing layout
if self.layout():
idx = 0

View File

@@ -1,14 +1,13 @@
import logging
import typing
from PySide6.QtCore import Signal
from PySide6.QtGui import QTextCursor, QIcon
from PySide6.QtWidgets import (
QDialog,
QPlainTextEdit,
QVBoxLayout,
QPushButton,
)
from PySide6.QtGui import QTextCursor, QIcon
from qt_ui.logging_handler import HookableInMemoryHandler
@@ -50,12 +49,17 @@ class QLogsWindow(QDialog):
self.appendLogSignal.connect(self.appendLog)
self._logging_handler = None
logger = logging.getLogger()
for handler in logger.handlers:
if isinstance(handler, HookableInMemoryHandler):
self._logging_handler = handler
break
try:
# This assumes that there's never more than one in memory handler. We don't
# configure more than one by default, but logging is customizable with
# resources/logging.yaml. If someone adds a second in-memory handler, only
# the first one (in arbitrary order) will be shown.
self._logging_handler = next(
HookableInMemoryHandler.iter_registered_handlers()
)
except StopIteration:
self._logging_handler = None
if self._logging_handler is not None:
self.textbox.setPlainText(self._logging_handler.log)
self.textbox.moveCursor(QTextCursor.End)

View File

@@ -261,7 +261,7 @@ class QNewPackageDialog(QPackageDialog):
def on_cancel(self) -> None:
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)

View File

@@ -38,12 +38,12 @@ class FlightMemberSelector(QSpinBox):
def __init__(self, flight: Flight, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.flight = flight
self.setMinimum(0)
self.setMaximum(flight.count - 1)
self.setMinimum(1)
self.setMaximum(flight.count)
@property
def selected_member(self) -> FlightMember:
return self.flight.roster.members[self.value()]
return self.flight.roster.members[self.value() - 1]
class QFlightPayloadTab(QFrame):

View File

@@ -14,7 +14,6 @@ class QFlightWaypointInfoBox(QGroupBox):
self.init_ui()
def init_ui(self) -> None:
layout = QVBoxLayout()
x_pos_layout = QHBoxLayout()

View File

@@ -60,7 +60,6 @@ class QFlightWaypointTab(QFrame):
self.recreate_buttons.clear()
for task in self.package.target.mission_types(for_player=True):
if (
task == FlightType.AIR_ASSAULT
and not self.game.lua_plugin_manager.is_plugin_enabled("ctld")

View File

@@ -27,7 +27,6 @@ PREDEFINED_WAYPOINT_CATEGORIES = [
class QPredefinedWaypointSelectionWindow(QDialog):
# List of FlightWaypoint
waypoints_added = Signal(list)

View File

@@ -87,7 +87,6 @@ class QLiberationPreferences(QFrame):
self.edit_dcs_install_dir.setText(install_dir)
def apply(self):
print("Applying changes")
self.saved_game_dir = self.edit_saved_game_dir.text()
self.dcs_install_dir = self.edit_dcs_install_dir.text()

View File

@@ -345,7 +345,6 @@ class QSettingsWindow(QDialog):
self.setLayout(self.layout)
def initCheatLayout(self):
self.cheatPage = QWidget()
self.cheatLayout = QVBoxLayout()
self.cheatPage.setLayout(self.cheatLayout)

View File

@@ -18,7 +18,6 @@ class QAircraftChart(QFrame):
self.setLayout(self.layout)
def generateUnitCharts(self):
self.alliedAircraft = [
d.allied_units.aircraft_count for d in self.game.game_stats.data_per_turn
]

View File

@@ -18,7 +18,6 @@ class QArmorChart(QFrame):
self.setLayout(self.layout)
def generateUnitCharts(self):
self.alliedArmor = [
d.allied_units.vehicles_count for d in self.game.game_stats.data_per_turn
]

View File

@@ -1,53 +1,56 @@
altgraph==0.17.3
anyio==3.6.2
asgiref==3.6.0
attrs==22.2.0
black==22.12.0
certifi==2023.7.22
cfgv==3.3.1
click==8.1.3
altgraph==0.17.4
annotated-types==0.6.0
anyio==3.7.1
asgiref==3.7.2
attrs==23.1.0
black==23.11.0
certifi==2023.11.17
cfgv==3.4.0
click==8.1.7
colorama==0.4.6
coverage==7.0.5
distlib==0.3.6
exceptiongroup==1.1.0
Faker==15.3.4
fastapi==0.95.2
filelock==3.9.0
coverage==7.3.2
distlib==0.3.7
exceptiongroup==1.2.0
Faker==20.1.0
fastapi==0.104.1
filelock==3.13.1
future==0.18.3
h11==0.14.0
httptools==0.5.0
identify==2.5.11
idna==3.4
iniconfig==1.1.1
httptools==0.6.1
identify==2.5.32
idna==3.6
iniconfig==2.0.0
Jinja2==3.1.2
MarkupSafe==2.1.1
mypy==1.2.0
MarkupSafe==2.1.3
mypy==1.7.1
mypy-extensions==1.0.0
nodeenv==1.7.0
numpy==1.25.1
packaging==22.0
pathspec==0.10.3
pefile==2022.5.30
nodeenv==1.8.0
numpy==1.26.2
packaging==23.2
pathspec==0.11.2
pefile==2023.2.7
Pillow==10.0.1
platformdirs==2.6.2
pluggy==1.0.0
pre-commit==2.21.0
pydantic==1.10.7
git+https://github.com/pydcs/dcs@f8232606a21eaef82af7ba78c2013403da4a86f5#egg=pydcs
pyinstaller==5.13.0
platformdirs==4.0.0
pluggy==1.3.0
pre-commit==3.5.0
pydantic==2.5.2
pydantic-settings==2.1.0
pydantic_core==2.14.5
pydcs @ git+https://github.com/pydcs/dcs@1092fc419d3f879e8e7951b25e15d8b7c9938627
pyinstaller==5.13.1
pyinstaller-hooks-contrib==2023.6
pyproj==3.4.1
pyproj==3.6.1
PySide6==6.4.1
PySide6-Addons==6.4.1
PySide6-Essentials==6.4.1
pytest==7.2.0
pytest-cov==4.0.0
pytest-mock==3.10.0
pytest==7.4.3
pytest-cov==4.1.0
pytest-mock==3.12.0
python-dateutil==2.8.2
python-dotenv==0.21.0
python-dotenv==1.0.0
pywin32-ctypes==0.2.2
PyYAML==6.0
shapely==2.0.1
PyYAML==6.0.1
shapely==2.0.2
shiboken6==6.4.1
six==1.16.0
sniffio==1.3.0
@@ -57,10 +60,10 @@ tomli==2.0.1
types-Jinja2==2.11.9
types-MarkupSafe==1.1.10
types-Pillow==9.3.0.4
types-PyYAML==6.0.12.2
types-tabulate==0.9.0.0
typing_extensions==4.4.0
uvicorn==0.20.0
virtualenv==20.17.1
watchfiles==0.18.1
websockets==10.4
types-PyYAML==6.0.12.12
types-tabulate==0.9.0.3
typing_extensions==4.8.0
uvicorn==0.24.0.post1
virtualenv==20.24.7
watchfiles==0.21.0
websockets==12.0

View File

@@ -1,14 +1,18 @@
---
name: Syria - The Falcon went over the mountain
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>
recommended_player_faction: USA 2005
recommended_enemy_faction: Syria 2012'ish
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
performance: 2
version: "10.4"
version: "11.0"
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers
#IADS: EWR and C2 get power generators. batteries have their own generators.
iads_config:
@@ -43,7 +47,7 @@ iads_config:
- YellowEWRS: #mountainrange (center)
- YellowPPW
- YellowControlW
- YellowEWRC: # internal
- YellowEWRC: #internal
- HamidiyeControl
- GaziantepControl
- GaziantepPP
@@ -243,94 +247,201 @@ iads_config:
- Aleppo Control
- Aleppo Control:
- Aleppo Power
control_points:
From Reserves:
ferry_only: true
squadrons:
#Incirlik
#Incirlik (120)
16:
- primary: BARCAP
secondary: air-to-air
aircraft:
- F-15C Eagle
size: 12
- primary: SEAD
secondary: any
aircraft:
- F-16CM Fighting Falcon (Block 50)
- primary: DEAD
size: 12
- primary: Strike
secondary: any
aircraft:
- F-15E Strike Eagle
- primary: BARCAP
aircraft:
- F-16CM Fighting Falcon (Block 50)
- primary: CAS
aircraft:
- A-10C Thunderbolt II (Suite 3)
- F-15E Strike Eagle (Suite 4+)
size: 8
- primary: CAS
secondary: air-to-ground
aircraft:
- A-10C Thunderbolt II (Suite 7)
size: 8
- primary: CAS
secondary: any
aircraft:
- AH-64D Apache Longbow
size: 8
- primary: Strike
secondary: air-to-ground
aircraft:
- F-117A Nighthawk
size: 4
- primary: Strike
secondary: air-to-ground
aircraft:
- B-1B Lancer
size: 2
- primary: AEW&C
secondary: any
size: 1
- primary: Refueling
secondary: any
aircraft:
- KC-135 Stratotanker MPRS
size: 1
#carrier
Blue Carrier:
- primary: BARCAP
secondary: air-to-air
aircraft:
- F-14B Tomcat
size: 12
- primary: BARCAP
aircraft:
- F-14B Tomcat
- primary: Strike
secondary: any
aircraft:
- F/A-18C Hornet (Lot 20)
- primary: Strike
size: 12
- primary: AEW&C
secondary: any
aircraft:
- F/A-18C Hornet (Lot 20)
size: 1
- primary: Refueling
secondary: any
size: 2
#LHA
Blue LHA:
- primary: CAS
secondary: any
aircraft:
- AV-8B Harrier II Night Attack
#Abu Al-Duhur
1:
- primary: BARCAP
aircraft:
- MiG-29S Fulcrum-C
- primary: BAI
aircraft:
- Su-24M Fencer-D
- primary: BARCAP
aircraft:
- Su-30 Flanker-C
#Hatay
size: 8
#Ferry-only
From Reserves:
- primary: SEAD
secondary: any
aircraft:
- F-16CM Fighting Falcon (Block 50)
size: 12
- primary: CAS
secondary: air-to-ground
aircraft:
- 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:
- primary: BARCAP
aircraft:
- MiG-23MLD Flogger-K
#Aleppo
27:
- primary: AEW&C
- primary: Refueling
secondary: any
aircraft:
- MiG-29S Fulcrum-C
size: 4
- primary: CAS
secondary: any
aircraft:
- Su-25 Frogfoot
size: 4
- primary: CAS
secondary: any
aircraft:
- Mi-24P Hind-F
- primary: Transport
#Jirah
17:
size: 2
#Minakh (20)
26:
- primary: BARCAP
secondary: any
aircraft:
- Su-30 Flanker-C
size: 8
- primary: SEAD
secondary: any
aircraft:
- Su-34 Fullback
size: 4
- primary: Strike
#Gaziantep
11:
secondary: any
size: 4
- primary: CAS
secondary: any
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

Binary file not shown.

View 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

View File

@@ -27,7 +27,7 @@ squadrons:
size: 24
- primary: AEW&C
aircraft:
- E-2C Hawkeye
- E-2D Advanced Hawkeye
size: 2
- primary: Refueling
aircraft:
@@ -55,12 +55,7 @@ squadrons:
secondary: any
aircraft:
- F-15E Strike Eagle (Suite 4+)
size: 8
- primary: Strike
secondary: any
aircraft:
- F-15E Strike Eagle
size: 8
size: 16
- primary: DEAD
secondary: any
aircraft:

View File

@@ -17,17 +17,29 @@ performance: 1
recommended_start_date: 2011-02-24
version: "11.0"
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
17:
- primary: TARCAP
secondary: any
aircraft:
- F-15E Strike Eagle (Suite 4+)
- F-15C Eagle
size: 12
- primary: Strike
secondary: air-to-ground
aircraft:
- F-15E Strike Eagle
- F-15E Strike Eagle (Suite 4+)
size: 12
- primary: AEW&C
aircraft:
@@ -58,7 +70,8 @@ squadrons:
- primary: Air Assault
secondary: air-to-ground
aircraft:
- UH-1H Iroquois
- UH-60L
- UH-60A
size: 2
# Groom Lake
2:

View File

@@ -19,6 +19,7 @@ recommended_player_faction:
- F-14B Tomcat
- F/A-18C Hornet (Lot 20)
- S-3B Viking
- UH-60L
- UH-60A
awacs:
- E-2C Hawkeye
@@ -107,8 +108,9 @@ squadrons:
- primary: Air Assault
secondary: any
aircraft:
- UH-60L
- UH-60A
size: 4
size: 6
#Stoney Cross (39)
58:
- primary: OCA/Runway

View File

@@ -35,11 +35,6 @@ squadrons:
aircraft:
- F-15C Eagle
size: 8
- primary: BAI
secondary: air-to-ground
aircraft:
- F-15E Strike Eagle
size: 8
- primary: Refueling
aircraft:
- KC-135 Stratotanker
@@ -90,12 +85,12 @@ squadrons:
- AV-8B Harrier II Night Attack
size: 18
- primary: Air Assault
secondary: air-to-ground
secondary: any
aircraft:
- UH-1H Iroquois
size: 2
Bombers from Edwards AFB:
- primary: DEAD
- primary: Strike
secondary: air-to-ground
aircraft:
- B-52H Stratofortress

Binary file not shown.

View 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

View File

@@ -40,7 +40,7 @@ squadrons:
size: 40
- primary: AEW&C
aircraft:
- E-2C Hawkeye
- E-2D Advanced Hawkeye
size: 2
- primary: Refueling
aircraft:
@@ -49,7 +49,8 @@ squadrons:
- primary: Air Assault
secondary: any
aircraft:
- SH-60B Seahawk
- UH-60L
- UH-60A
size: 4
#Al Minhad AFB (61)
12:
@@ -78,12 +79,12 @@ squadrons:
secondary: any
aircraft:
- F-15E Strike Eagle (Suite 4+)
size: 8
- primary: BAI
size: 20
- primary: DEAD
secondary: air-to-ground
aircraft:
- F-15E Strike Eagle
size: 12
- AV-8B Harrier II Night Attack
size: 20
#Bandar Abbas Intl (51)
2:
- primary: SEAD

View File

@@ -32,7 +32,7 @@ squadrons:
size: 20
- primary: AEW&C
aircraft:
- E-2C Hawkeye
- E-2D Advanced Hawkeye
size: 4
- primary: Refueling
aircraft:
@@ -55,12 +55,7 @@ squadrons:
secondary: any
aircraft:
- F-15E Strike Eagle (Suite 4+)
size: 4
- primary: OCA/Aircraft
secondary: any
aircraft:
- F-15E Strike Eagle
size: 8
size: 12
- primary: TARCAP
secondary: air-to-air
aircraft:

View File

@@ -59,6 +59,7 @@ squadrons:
- primary: Air Assault
secondary: any
aircraft:
- UH-60L
- UH-60A
size: 2
Blue LHA:
@@ -83,31 +84,11 @@ squadrons:
aircraft:
- F-16CM Fighting Falcon (Block 50)
size: 16
- primary: DEAD
secondary: any
aircraft:
- F-16CM Fighting Falcon (Block 50)
size: 16
- primary: BAI
secondary: any
aircraft:
- F-15E Strike Eagle (Suite 4+)
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
aircraft:
- KC-135 Stratotanker

Binary file not shown.

View 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

View File

@@ -9,7 +9,7 @@ local unitPayloads = {
["num"] = 3,
},
[2] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 4,
},
[3] = {
@@ -17,7 +17,7 @@ local unitPayloads = {
["num"] = 2,
},
[4] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 1,
},
},
@@ -51,6 +51,31 @@ local unitPayloads = {
},
},
[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",
["pylons"] = {
[1] = {

View File

@@ -2,27 +2,36 @@ local unitPayloads = {
["name"] = "AV8BNA",
["payloads"] = {
[1] = {
["name"] = "INTERCEPT",
["displayName"] = "Liberation CAS",
["name"] = "Liberation CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 8,
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 5,
},
[2] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 1,
["CLSID"] = "LAU_117_AGM_65F",
["num"] = 3,
},
[3] = {
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
["CLSID"] = "{BRU-70A_3*GBU-54}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
["CLSID"] = "{BRU-70A_3*GBU-54}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{GAU_12_Equalizer}",
["num"] = 4,
["CLSID"] = "LAU_117_AGM_65F",
["num"] = 6,
},
[6] = {
["CLSID"] = "{AGM_122_SIDEARM}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{AGM_122_SIDEARM}",
["num"] = 1,
},
},
["tasks"] = {
@@ -30,7 +39,8 @@ local unitPayloads = {
},
},
[2] = {
["name"] = "SEAD",
["displayName"] = "Liberation SEAD",
["name"] = "Liberation SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{AGM_122_SIDEARM}",
@@ -41,32 +51,25 @@ local unitPayloads = {
["num"] = 1,
},
[3] = {
["CLSID"] = "LAU_117_AGM_65F",
["CLSID"] = "{LAU_7_AGM_122_SIDEARM}",
["num"] = 2,
},
[4] = {
["CLSID"] = "LAU_117_AGM_65F",
["CLSID"] = "{LAU_7_AGM_122_SIDEARM}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{ALQ_164_RF_Jammer}",
["num"] = 5,
},
[6] = {
["CLSID"] = "LAU_117_AGM_65F",
["num"] = 6,
},
[7] = {
["CLSID"] = "LAU_117_AGM_65F",
["num"] = 3,
},
},
["tasks"] = {
[1] = 31,
},
},
[3] = {
["name"] = "CAS",
["displayName"] = "Liberation OCA/Runway",
["name"] = "Liberation OCA/Runway",
["pylons"] = {
[1] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
@@ -77,36 +80,144 @@ local unitPayloads = {
["num"] = 1,
},
[3] = {
["CLSID"] = "LAU_117_AGM_65F",
["num"] = 2,
},
[4] = {
["CLSID"] = "LAU_117_AGM_65F",
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{GAU_12_Equalizer}",
["num"] = 4,
[4] = {
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 6,
},
[6] = {
[5] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 5,
},
[7] = {
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
["num"] = 6,
},
[8] = {
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
[6] = {
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 3,
},
[7] = {
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
},
},
[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"] = {
[1] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
@@ -116,6 +227,43 @@ local unitPayloads = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["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] = {
["CLSID"] = "LAU_117_AGM_65F",
["num"] = 2,
@@ -141,28 +289,9 @@ local unitPayloads = {
[1] = 31,
},
},
[5] = {
["name"] = "STRIKE",
["pylons"] = {
[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",
[9] = {
["displayName"] = "Liberation OCA/Aircraft",
["name"] = "Liberation OCA/Aircraft",
["pylons"] = {
[1] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
@@ -173,16 +302,24 @@ local unitPayloads = {
["num"] = 1,
},
[3] = {
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
["num"] = 2,
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 5,
},
[4] = {
["CLSID"] = "{AIM-9M-ON-ADAPTER}",
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{GAU_12_Equalizer}",
["num"] = 4,
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 6,
},
[6] = {
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 3,
},
[7] = {
["CLSID"] = "{GBU_32_V_2B}",
["num"] = 2,
},
},
["tasks"] = {

View File

@@ -2,109 +2,8 @@ local unitPayloads = {
["name"] = "F-15ESE",
["payloads"] = {
[1] = {
["displayName"] = "Liberation Strike",
["name"] = "Liberation Strike",
["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",
["displayName"] = "Liberation Escort",
["name"] = "Liberation Escort",
["pylons"] = {
[1] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
@@ -131,7 +30,7 @@ local unitPayloads = {
["num"] = 9,
},
[7] = {
["CLSID"] = "{F15E_EXTTANK}",
["CLSID"] = "<CLEAN>",
["num"] = 8,
},
[8] = {
@@ -163,9 +62,114 @@ local unitPayloads = {
[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] = {
["displayName"] = "Liberation Escort",
["name"] = "Liberation Escort",
["displayName"] = "Liberation Fighter Sweep",
["name"] = "Liberation Fighter Sweep",
["pylons"] = {
[1] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
@@ -192,7 +196,7 @@ local unitPayloads = {
["num"] = 9,
},
[7] = {
["CLSID"] = "{F15E_EXTTANK}",
["CLSID"] = "<CLEAN>",
["num"] = 8,
},
[8] = {
@@ -225,8 +229,8 @@ local unitPayloads = {
},
},
[5] = {
["displayName"] = "Liberation OCA/Runway",
["name"] = "Liberation OCA/Runway",
["displayName"] = "Liberation Strike",
["name"] = "Liberation Strike",
["pylons"] = {
[1] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
@@ -245,32 +249,32 @@ local unitPayloads = {
["num"] = 3,
},
[5] = {
["CLSID"] = "{CFT_R_BLU107_x_6}",
["num"] = 12,
},
[6] = {
["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"] = "{F-15E_AAQ-14_LANTIRN}",
["num"] = 7,
},
[9] = {
["CLSID"] = "{CFT_L_BLU107_x_6}",
["CLSID"] = "{CFT_L_GBU_31V3B_x_2}",
["num"] = 4,
},
[9] = {
["CLSID"] = "{GBU-31V3B}",
["num"] = 2,
},
[10] = {
["CLSID"] = "{F15E_EXTTANK}",
["CLSID"] = "{GBU-31V3B}",
["num"] = 14,
},
[11] = {
["CLSID"] = "{F15E_EXTTANK}",
["num"] = 2,
["CLSID"] = "{CFT_R_GBU_31V3B_x_2}",
["num"] = 12,
},
},
["tasks"] = {
@@ -278,66 +282,7 @@ local unitPayloads = {
},
},
[6] = {
["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"] = "{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",
["name"] = "Liberation BARCAP",
["pylons"] = {
[1] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
@@ -364,7 +309,7 @@ local unitPayloads = {
["num"] = 9,
},
[7] = {
["CLSID"] = "{F15E_EXTTANK}",
["CLSID"] = "<CLEAN>",
["num"] = 8,
},
[8] = {
@@ -396,7 +341,121 @@ local unitPayloads = {
[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] = {
["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",
["name"] = "Liberation DEAD",
["pylons"] = {
@@ -429,118 +488,65 @@ local unitPayloads = {
["num"] = 7,
},
[8] = {
["CLSID"] = "{CFT_L_CBU_97_x_6}",
["CLSID"] = "{CFT_L_GBU_31V3B_x_2}",
["num"] = 4,
},
[9] = {
["CLSID"] = "{CFT_R_CBU_97_x_6}",
["CLSID"] = "{CFT_R_GBU_31V3B_x_2}",
["num"] = 12,
},
},
["tasks"] = {
[1] = 32,
},
},
[9] = {
["displayName"] = "Liberation TARCAP",
["name"] = "Liberation TARCAP",
["pylons"] = {
[1] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 15,
},
[2] = {
["CLSID"] = "{F15E_EXTTANK}",
[10] = {
["CLSID"] = "{GBU-31V3B}",
["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] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
[12] = {
["CLSID"] = "{F15E_EXTTANK}",
["CLSID"] = "{GBU-31V3B}",
["num"] = 2,
},
[13] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 32,
},
},
[10] = {
["displayName"] = "Liberation CAS",
["name"] = "Liberation CAS",
["displayName"] = "Liberation OCA/Runway",
["name"] = "Liberation OCA/Runway",
["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_CBU_97_x_6}",
[3] = {
["CLSID"] = "{CFT_R_BLU107_x_6}",
["num"] = 12,
},
[6] = {
[4] = {
["CLSID"] = "{F-15E_AAQ-13_LANTIRN}",
["num"] = 9,
},
[5] = {
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{CFT_L_BLU107_x_6}",
["num"] = 4,
},
[7] = {
["CLSID"] = "{F15E_EXTTANK}",
["num"] = 8,
},
[8] = {
["CLSID"] = "{F-15E_AAQ-14_LANTIRN}",
["num"] = 7,
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 1,
},
[9] = {
["CLSID"] = "{CFT_L_CBU_97_x_6}",
["num"] = 4,
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
},
["tasks"] = {

View File

@@ -2,133 +2,102 @@ local unitPayloads = {
["name"] = "Ka-50",
["payloads"] = {
[1] = {
["name"] = "CAS",
["name"] = "Liberation CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
["num"] = 4,
},
[2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["CLSID"] = "B_8V20A_OFP2",
["num"] = 3,
},
[4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 4,
["CLSID"] = "B_8V20A_OFP2",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[2] = {
["name"] = "CAP",
["displayName"] = "Liberation BAI",
["name"] = "Liberation BAI",
["pylons"] = {
[1] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 4,
},
[2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["CLSID"] = "B_8V20A_OFP2",
["num"] = 3,
},
[4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 4,
["CLSID"] = "B_8V20A_OFP2",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[3] = {
["name"] = "SEAD",
["displayName"] = "Liberation OCA/Aircraft",
["name"] = "Liberation OCA/Aircraft",
["pylons"] = {
[1] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 4,
},
[2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 4,
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[4] = {
["name"] = "ANTISHIP",
["displayName"] = "Liberation DEAD",
["name"] = "Liberation DEAD",
["pylons"] = {
[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}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[5] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 2,
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 4,
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
},

View File

@@ -21,11 +21,11 @@ local unitPayloads = {
["num"] = 1,
},
[5] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["CLSID"] = "B_8V20A_OFP2",
["num"] = 3,
},
[6] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["CLSID"] = "B_8V20A_OFP2",
["num"] = 2,
},
},
@@ -36,6 +36,39 @@ local unitPayloads = {
[2] = {
["displayName"] = "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"] = {
[1] = {
["CLSID"] = "{9S846_2xIGLA}",
@@ -66,7 +99,7 @@ local unitPayloads = {
[1] = 31,
},
},
[3] = {
[4] = {
["displayName"] = "Liberation OCA/Aircraft",
["name"] = "Liberation OCA/Aircraft",
["pylons"] = {
@@ -79,19 +112,19 @@ local unitPayloads = {
["num"] = 5,
},
[3] = {
["CLSID"] = "B_8V20A_OFP2",
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 4,
},
[4] = {
["CLSID"] = "B_8V20A_OFP2",
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
},
[5] = {
["CLSID"] = "B_8V20A_OFP2",
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 3,
},
[6] = {
["CLSID"] = "B_8V20A_OFP2",
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
},
},

View 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

View 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

View 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

View 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

View 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: []

View 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

View File

@@ -30,10 +30,8 @@
<h2>Launching the mission:</h2>
<p>
Launch the <code>liberation_nextturn</code> mission as you normally would for single-
or multi-player. Note that even for single-player, running the mission with the
dedicated server, <em>even on the same machine</em>, can significantly improve frame
rates, but may cause AI wingmen to behave strangely during taxi.
Launch the <code>liberation_nextturn</code> mission as you normally would for
single- or multi-player.
</p>
<p>

Some files were not shown because too many files have changed in this diff Show More