Compare commits

...

135 Commits

Author SHA1 Message Date
C. Perreau
de2e5f861b Merge pull request #1007 from Khopa/develop_2_5_x
Release 2.5.0
2021-04-22 00:08:42 +02:00
Khopa
b27a7fc71b Fixed Lint issue 2021-04-21 22:54:48 +02:00
Khopa
5861ce6146 Fixed error with Ramat David frequency (typo) 2021-04-21 22:38:08 +02:00
Khopa
c732ed556f Fixed airfields frequency on Persian Gulf 2021-04-21 22:30:08 +02:00
Khopa
be1a75e520 Fixed airfields frequency on Syria 2021-04-21 22:14:18 +02:00
Khopa
c41d10c581 Pydcs update to latest version 2021-04-21 12:57:19 +02:00
Dan Albert
157a59e3c4 Fix UI crash when unchecking default loadout.
This was throwing because it was being called with the wrong number of
arguments, preventing the UI from actually updating back to the default.
2021-04-18 13:05:22 -07:00
Khopa
d24c65c3aa Fixed airfield data airport name for Persian Gulf map 2021-04-18 20:10:52 +02:00
Khopa
d4d441ff9b Fixed some factions errors that weren't caught yet. 2021-04-18 18:11:00 +02:00
Khopa
f43fb1223f Fix : Fixed duplicate units on cold war flak site. 2021-04-18 15:16:17 +02:00
Khopa
3db275414d Allow 0 income multiplier in game settings windows (this was already possible in new game wizard) 2021-04-18 01:20:32 +02:00
Khopa
6e0ff6c805 pydcs update 2021-04-18 01:13:50 +02:00
Dan Albert
9c359efbff Note Litening -> ATFLIR change. 2021-04-17 16:03:56 -07:00
Dan Albert
c5cc1ea8e8 Make the F/A-18C strike loadout less silly.
Instead of 4xMk83 and 4xGBU-38, 2 bags and 2 GBU-31. ATFLIR added for
TOO/BDA.
2021-04-17 15:51:46 -07:00
Dan Albert
afb6a33131 Replace Litening II with ATFLIR in Honet loadouts.
https://github.com/pydcs/dcs/pull/120
2021-04-17 15:43:49 -07:00
Khopa
539a11f54d Added icons for new units 2021-04-18 00:15:10 +02:00
Khopa
9324e549e6 Updated changelog 2021-04-18 00:13:43 +02:00
Khopa
c8f6b6df87 Fixed lint issue 2021-04-18 00:11:06 +02:00
Dan Albert
38f632097e Add support for DCS 2.7 weather generation.
https://github.com/Khopa/dcs_liberation/issues/981
2021-04-17 15:06:17 -07:00
Khopa
e63743f537 Improved FOB support : new custom banner for FOB menu and do not display aircrafts menu on first page. 2021-04-17 23:49:49 +02:00
Khopa
ce13295cf0 pydcs repo now pointing on temporary branch 2-7-temp on https://github.com/Khopa/dcs for new weather development 2021-04-17 23:06:48 +02:00
Khopa
23c02a3510 Updated airfields data for the Channel map 2021-04-17 17:50:41 +02:00
Khopa
01ea7b9ee1 Updated airfields metadata for Syria 2021-04-17 17:37:15 +02:00
Khopa
6fed1284a1 Updated airfields metadata for Syria 2021-04-17 17:35:40 +02:00
Khopa
5574d849bd Unit support : S-60 added to Syria faction 2021-04-17 13:11:58 +02:00
Khopa
c2ce3a6992 Fixed Lint issue 2021-04-17 13:11:26 +02:00
Khopa
b61d15fdf4 Unit support : Added support for the PLZ-05, new artillery unit from the Chinese Asset Pack 2021-04-17 11:28:36 +02:00
Khopa
ad5cc83fb3 Unit support : now using the new unit S-60 57mm AA Gun units. 2021-04-17 11:23:00 +02:00
Ronny Röhricht
2f53edd775 Add plugin for exporting RED and BLUE threat circles to LotATC.
Implemented as a plugin because LotATC needs actual lat/lon, and the only APIs for those are in lua.

Fixes https://github.com/Khopa/dcs_liberation/issues/956.
2021-04-17 00:55:06 -07:00
Khopa
923459c88b Pydcs update to the good commit reference 2021-04-17 02:35:34 +02:00
Khopa
1192d26448 Fixed lint issue 2021-04-17 02:27:42 +02:00
Khopa
2d5e827417 Pydcs update to master repo 2021-04-17 02:26:31 +02:00
Khopa
a30d9276b8 Merge remote-tracking branch 'khopa/develop' into develop 2021-04-17 02:22:56 +02:00
Khopa
b963c2272f More naming fixes 2021-04-17 02:21:19 +02:00
Khopa
221cb8709b Ran black formatter 2021-04-17 02:15:49 +02:00
Khopa
648857fc44 Removed deprecated faction 2021-04-17 02:15:02 +02:00
Khopa
8091051bb4 Fixed weapons names in pdcs extensions, removed deprecated rafale mod, fixed many other compilation issues with pydcs 2.7+ 2021-04-17 02:13:52 +02:00
Khopa
1e468cd3e0 Fixed weapons fallback db names with new pydcs version 2021-04-17 01:23:08 +02:00
Khopa
15d2a5bb2b Updated units name in liberation 2021-04-16 23:33:22 +02:00
Khopa
5c76229ee5 Referencing pydcs new version 2021-04-16 23:31:03 +02:00
Dan Albert
0cd088122e Remove WIP status of AEW&C missions. 2021-04-15 21:35:25 -07:00
Dan Albert
b6f3467a89 Update changelog. 2021-04-15 21:34:31 -07:00
SnappyComebacks
52ce1a5959 Add support for additional EWR sites in campaigns.
* A Bluefor EWR 55GS in the campaign miz defines an optional EWR site. There is no distinction between how close or far it is to a base, so it's possible that there will be many EWRs within an airbase.
* A Redfor EWR 1L13 in the campaign miz defines a required EWR site.

It would be a good future idea to limit the amount of EWRs within a certain distance from an airbase. That way there's no chance of 5 EWRs all at the same airbase. Even better if there were something preventing any two EWRs from being right next to each other.

No campaigns take advantage of this yet.

Fixes https://github.com/Khopa/dcs_liberation/issues/524
2021-04-15 21:23:27 -07:00
Khopa
7ce05762f5 Possible to add additional helipad to any control point in campaign file. (WIP) 2021-04-14 00:00:25 +02:00
Dan Albert
cce736bc16 Note the font crash fix in the changelog. 2021-04-11 13:27:39 -07:00
Hanninho
2a1127e637 Force the basic layout engine when generating the kneeboard.
The libraqm backed layout engine causes crashes on some machines.

Fixes #531.
2021-04-11 13:24:31 -07:00
Dan Albert
8ca68b3d7a Set win/loss status for functioning airfields.
"Fixes" https://github.com/Khopa/dcs_liberation/issues/833. The crash is
still present, but we're at least telling the player that the game is
over so they shouldn't try to play. The UX for this sucks
(https://github.com/Khopa/dcs_liberation/issues/978), but it's the same
as other end-game states.
2021-04-10 15:44:57 -07:00
Dan Albert
0f76d893b8 Note date fix in the changelog. 2021-04-10 15:22:27 -07:00
Dan Albert
ab746b5195 Fix date given to the conditions generator.
`Game.date` is actually the start date, not the current date. Not renaming to
avoid breaking save compat.

This fix won't have any effect on existing saves until they pass the turn
because this is encoded into the conditions generated at the start of the turn,
but it will fix on the next turn.

Fixes https://github.com/Khopa/dcs_liberation/issues/973
2021-04-10 15:20:54 -07:00
Khopa
828c87df39 Game settings / new game wizard : Allowed a 0% income multiplier. 2021-04-07 19:33:23 +02:00
C. Perreau
888aeb621d Merge pull request #955 from Hornet2041/Integrate-splash-damage-script-plugin
Integrate splash damage plugin script
2021-04-05 20:33:17 +02:00
Khopa
ac2fddf87e Changelog update 2021-03-31 00:28:52 +02:00
Khopa
614304cc81 Added F86 Sabre loadout by Starfire. 2021-03-31 00:20:19 +02:00
Khopa
f363d66aac F_86F Sabre payloads can now be customized. 2021-03-31 00:17:21 +02:00
Khopa
1706c42695 Fix : Added Mig-19P to CAS capable aircraft list 2021-03-31 00:00:44 +02:00
Khopa
2b44b2fc0b Ran formatter to fix lint issue 2021-03-29 23:53:09 +02:00
C. Perreau
25986aa15c Merge pull request #928 from Mustang-25/patch-1
Add GAR-8 restriction date and fallback info
2021-03-29 23:51:21 +02:00
C. Perreau
264eb01afc Merge pull request #947 from SnappyComebacks/add-e2c-to-more-factions
Add E-2C to more factions
2021-03-29 23:49:27 +02:00
Khopa
6db3c3f9f1 Updated changelog 2021-03-29 23:46:44 +02:00
SnappyComebacks
714992bdcb ARMADILLLO to ARMADILLO. 2021-03-27 13:02:16 -07:00
SnappyComebacks
ca7a86b6d7 Merge branch 'develop' into add-e2c-to-more-factions 2021-03-27 11:04:13 -06:00
GvonH
49e729e9ec Add dark kneeboard option for night missions (#951) 2021-03-22 19:41:54 -07:00
Hornet2041
7f0a690c7b Add files via upload
referencing the original upload in Discord here: https://discord.com/channels/595702951800995872/768226890158702654/809571449979142174

and wheelyjoe's github repository here: https://github.com/wheelyjoe/DCS-Scripts

"Improves splash damage modelling by pulling weapon warhead info (where available) and using this to create explosions (only way to apply damage) to units in more sensible range." Makes using non-precision weaponry actually viable for ground targets.
2021-03-22 09:43:42 -04:00
C. Perreau
d07afc603b Merge pull request #950 from Khopa/dependabot/pip/pillow-8.1.1
Bump pillow from 7.2.0 to 8.1.1
2021-03-21 19:09:21 +01:00
Khopa
5bd4c00257 Merge branch 'develop_2_4_x' into develop
# Conflicts:
#	changelog.md
#	game/db.py
#	game/navmesh.py
#	game/operation/operation.py
#	game/theater/conflicttheater.py
#	game/theater/controlpoint.py
#	game/theater/start_generator.py
#	game/theater/theatergroundobject.py
#	game/threatzones.py
#	game/version.py
#	gen/aircraft.py
#	gen/airsupportgen.py
#	gen/fleet/carrier_group.py
#	gen/flights/ai_flight_planner.py
#	gen/flights/ai_flight_planner_db.py
#	gen/flights/flightplan.py
#	gen/flights/waypointbuilder.py
#	gen/groundobjectsgen.py
#	gen/kneeboard.py
#	pydcs
#	pydcs_extensions/f22a/f22a.py
#	qt_ui/uiconstants.py
#	qt_ui/widgets/combos/QAircraftTypeSelector.py
#	qt_ui/widgets/map/QLiberationMap.py
#	qt_ui/windows/QUnitInfoWindow.py
#	qt_ui/windows/mission/flight/payload/QPylonEditor.py
#	qt_ui/windows/settings/QSettingsWindow.py
2021-03-21 18:50:50 +01:00
dependabot[bot]
13272aa280 Bump pillow from 7.2.0 to 8.1.1
Bumps [pillow](https://github.com/python-pillow/Pillow) from 7.2.0 to 8.1.1.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/7.2.0...8.1.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-19 15:06:06 +00:00
Simon Krüger
260358c5fb AEW&C kneeboard + actually do AEW&C (#922)
* AEW&C will now do AEW&C
* AEW&C gets a frequency
* AEW&C is added to kneeboard (Frequency, Depature, Depature Time, Arrival Time)
2021-03-13 14:07:19 -08:00
Dan Albert
0f07b2c095 Increase size of navmesh to avoid planning issues.
The tradeoff is that any flights that might have previously routed
_around_ a threat near the edge of the map may no longer do so as the
zones at the edge are significantly larger now.

Fixes https://github.com/Khopa/dcs_liberation/issues/903
2021-03-13 13:41:57 -08:00
Dan Albert
b2fafc22dd Fix flight path debugging. 2021-03-13 13:34:49 -08:00
Dan Albert
6200ec8e0e Don't plan BAI targets at dead subgroups.
Fixes https://github.com/Khopa/dcs_liberation/issues/900
2021-03-13 13:16:10 -08:00
Dan Albert
831516c5f5 Ask for state.json in the bug template. 2021-03-13 12:56:33 -08:00
Dan Albert
fb49d9e6ae Project threat zone from front lines.
Fixes https://github.com/Khopa/dcs_liberation/issues/940
2021-03-13 12:53:10 -08:00
SnappyComebacks
e660726828 Added E-2C elements for UI. 2021-03-12 14:19:50 -07:00
SnappyComebacks
4519f47b19 Added US Aggressors. 2021-03-12 11:16:27 -07:00
SnappyComebacks
47174bbb4d Added E-2C to USA, France, Bluefor. 2021-03-12 11:12:29 -07:00
Mustang-25
de18ce3e7b Add GAR-8 restriction date and fallback info 2021-02-27 15:22:26 -08:00
Dan Albert
b5934633fa Improve wording of "never delay players" option. 2021-02-27 14:16:41 -08:00
Dan Albert
4ec8994c38 Avoid warning in GitHub workflow. 2021-02-25 17:32:33 -08:00
Simon Krüger
49d6cece50 Merge pull request #896 from siKruger/aewc_no_threat_zone
if aewc is in threat zone move it further away
2021-02-24 22:14:22 +01:00
sikruger
03251d5bd5 some improvements 2021-02-24 22:06:42 +01:00
BenBenBeartrax
a6e03184bc fictional Korea factions 2021-02-22 16:52:53 -08:00
Khopa
688a20c312 Changelog update 2021-02-21 23:01:05 +01:00
Khopa
4c1b34461e Merge remote-tracking branch 'khopa/develop' into develop 2021-02-21 22:57:32 +01:00
Khopa
c6939e7194 Added possibility to set up custom date in new game wizard. 2021-02-21 22:57:21 +01:00
BenBenBeartrax
cd9432e395 kneeboard: custom flight name in title (#911)
If a flight has a custom flight name set it gets appended to the title in the kneeboard.
Partially addresses #862 .
2021-02-21 13:29:31 -08:00
Khopa
7d5244a5bc black 2021-02-21 17:47:51 +01:00
Khopa
1aa5d4f7de Updated Hercules cargo script to latest version. 2021-02-21 17:33:34 +01:00
Khopa
ad74204fe4 Updated C130J Hercules pydcs data 2021-02-21 17:31:58 +01:00
Khopa
5cb1a47ed3 Updated credits in about dialog. 2021-02-21 17:24:15 +01:00
Khopa
fff22d3cd1 F-22 default loadout replaced weapons in internal bay by their "no-drag" versions 2021-02-21 17:20:51 +01:00
Khopa
665cd7b996 Merge remote-tracking branch 'khopa/develop' into develop 2021-02-21 17:15:54 +01:00
Khopa
61173196d2 Updated F22 mod 2021-02-21 17:15:29 +01:00
Dan Albert
03e98ba562 Increase file log level to debug.
Fixes https://github.com/Khopa/dcs_liberation/issues/907
2021-02-20 15:38:52 -08:00
BenBenBeartrax
6195290adf customized_payloads: M-2000C add Eclair counter meassures pod to all loadouts 2021-02-20 12:49:08 -08:00
sikruger
4f1b0055e1 new point generation 2021-02-19 20:40:58 +01:00
sikruger
dd9fe87ff4 new point generation 2021-02-18 16:08:23 +01:00
sikruger
5bda4abfce if aewc is in threat zone move it further away 2021-02-17 16:47:24 +01:00
Dan Albert
f8ae1e9076 Merge pull request #885 from DanAlbert/black
Set up black.
2021-02-12 20:21:41 -08:00
Dan Albert
16b0dcad71 Add black workflow. 2021-02-12 20:13:47 -08:00
Dan Albert
9c1265d50d Add pre-commit configuration for black.
To set up, run `pre-commit install`.
2021-02-12 20:11:41 -08:00
Dan Albert
8c0e781c94 Ignore reformating in blame. 2021-02-12 20:11:36 -08:00
Dan Albert
a47bef1f13 Blacken. 2021-02-12 20:10:45 -08:00
Dan Albert
053663bd76 Merge branch 'develop_2_4_x' into develop 2021-02-12 19:23:13 -08:00
Dan Albert
2ffe3bf722 Undo unintentional change.
Not sure how the extra whitespace got there, but this gets overwritten
on every launch.
2021-02-12 18:59:48 -08:00
Dan Albert
f7889b785d Mention new start dates in the changelog. 2021-02-12 16:16:13 -08:00
Mustang-25
27829a024a Add a mid-90s campaign date option
1995 is a good date to pick if you want to date restrict all GPS weapons but still have all the laser guided options.
2021-02-12 16:15:20 -08:00
Mustang-25
a0fda2552f Adjust HARM Weapon Restriction Date
Official Navy docs have the 88A's IOC date in 1983. Also left a note on the B and C IOC dates if DCS ever adds the older models.
2021-02-12 16:14:54 -08:00
Simon Krüger
65c185ebd2 Add an option for disabling the legacy AEW&C aircraft.
Using the legacy AEW&C aircraft is still the default until
https://github.com/Khopa/dcs_liberation/issues/844 is fixed.
2021-02-12 14:20:26 -08:00
Dan Albert
5792eb354c Fix rounding of budget in recruitment menu.
Fixes https://github.com/Khopa/dcs_liberation/issues/861.
2021-02-12 14:00:58 -08:00
Dan Albert
dce7d91511 Mention weapon data in changelog. 2021-02-12 13:54:30 -08:00
Dan Albert
3d1afa74d4 Move 2.4.2 fix to the correct section. 2021-02-12 13:47:14 -08:00
Dan Albert
d8c94f5ece Transfer pending purchases forward along capture.
Fixes https://github.com/Khopa/dcs_liberation/issues/828.
2021-02-12 13:45:01 -08:00
Brandon Danyluk
61f1e11a48 Add weapon era restrictions for USA/Russia/UK/France (#860) 2021-02-10 22:30:56 -08:00
Simon Krüger
98249b1aca Bugfix: Blue AEW&C above Red CV (#872) 2021-02-10 11:49:49 -08:00
Simon Krüger
8e51b7fc1d Carrier strike group (#863)
Generate a Carrier Group which comes close the the real Carrier Strike Group 8.

Under carrier_names in the faction simply add "Carrier Strike Group 8" as the first and only entry and enable super carrier.

* TRU as TACAN name
* Harry S. Truman CV
* 4x Arleigh Burke
* 1x Ticonderoga
* CV in the middle, Ticonderoga in a radius of 2 miles, Arleigh Burkes forming a rectangle
2021-02-09 14:17:46 -08:00
Simon Krüger
71914b8a8b Aew&c ai planning.
AI will generate AWE&C

* Only one flight per turn
* Takes the airfield farthest away from the frontline
* Prefers CV over any airfield
2021-02-09 12:35:47 -08:00
Khopa
7a077a0d21 Merge remote-tracking branch 'khopa/develop' into develop 2021-02-07 21:16:04 +01:00
Khopa
d23e4665e7 Fixed possible cheat by selling SA-10 SAMs site for more money than what they were bought for.
+ Fixed SA-10 sites having the same name in game UI.
2021-02-07 21:15:48 +01:00
C. Perreau
df12b54856 Merge pull request #858 from benedikt-wegmann/develop_kneeboard_briefing_cleanup
kneeboard: slight cleanup in Jinja
2021-02-07 18:48:47 +01:00
Khopa
ae12053d74 Pydcs update 2021-02-07 18:34:48 +01:00
Khopa
0e7695f2d6 pydcs update repo 2021-02-07 17:49:01 +01:00
BenBenBeartrax
38cee87ee9 kneeboard: slight cleanup in Jinja by not rendering sections that are empty anyway (JTAC, Carriers, AWACS etc.) 2021-02-07 16:44:41 +01:00
Simon Clark
c64a6083e2 Merge branch 'develop' of https://github.com/Khopa/dcs_liberation into develop 2021-02-07 11:41:04 +00:00
Simon Krüger
e0501e46e3 Initial implementation of AEW&C missions.
Still a work in progress (the missions don't actually perform their task, just orbit). Currently:

* AEW&C aircraft can be bought.
* AEW&C missions can be planned at any control point and at front lines.
* AEW&C will return after 4H or Bingo.
2021-02-07 11:39:22 +00:00
Khopa
4a0ccc4c2f Fixed error detected by mypy 2021-02-07 11:39:21 +00:00
Khopa
c92b7240eb Increased number of launchers on Silkworms sites 2021-02-07 11:39:21 +00:00
Khopa
6a74c3faeb Added coastal defenses sites generator for Iran and China. 2021-02-07 11:39:21 +00:00
BenBenBeartrax
c5ae872787 waypointbuilder: low altitude AGL for helos 2021-02-07 11:39:21 +00:00
Dan Albert
2e9ab0a9d7 Move develop to 2.5. 2021-02-07 11:39:20 +00:00
Simon Krüger
a004f62fe8 Initial implementation of AEW&C missions.
Still a work in progress (the missions don't actually perform their task, just orbit). Currently:

* AEW&C aircraft can be bought.
* AEW&C missions can be planned at any control point and at front lines.
* AEW&C will return after 4H or Bingo.
2021-02-05 17:18:50 -08:00
Khopa
07ce20fd29 Fixed error detected by mypy 2021-02-05 00:48:35 +01:00
Khopa
df74f7c6c7 Increased number of launchers on Silkworms sites 2021-02-05 00:25:42 +01:00
Khopa
2a6e2d470d Added coastal defenses sites generator for Iran and China. 2021-02-05 00:15:06 +01:00
BenBenBeartrax
643dd65113 waypointbuilder: low altitude AGL for helos 2021-02-02 14:30:28 -08:00
Dan Albert
cee0532b85 Move develop to 2.5. 2021-01-31 15:42:13 -08:00
229 changed files with 6056 additions and 5764 deletions

2
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,2 @@
# Black
a47bef1f1336fd264d0b175f4421758339a30acb

View File

@@ -28,7 +28,8 @@ We will usually need more information for debugging. Include as much of the foll
- DCS Liberation save file (the `.liberation` file you save from the DCS Liberation window). By default these are located in your DCS saved games directory (`%USERPROFILE%/Saved Games/DCS`).
- The generated mission file (the `.miz` file that you load in DCS to play the turn). By default these are located in your missions directory (`%USERPROFILE%/Saved Games/DCS/Missions`).
- A tacview track file, especially when demonstrating an issue with AI behavior. By default these are locaed in your Tacview tracks directory (`%USERPROFILE%/Documents/Tacview`).
- A tacview track file, especially when demonstrating an issue with AI behavior. By default these are located in your Tacview tracks directory (`%USERPROFILE%/Documents/Tacview`).
- The state.json file from the finished mission when the problem is related to results processing. By default these are located in your Liberation install directory.
**Version information (please complete the following information):**
- DCS Liberation [e.g. 2.3.1]:

13
.github/workflows/black.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: psf/black@stable
with:
args: ". --check"

6
.pre-commit-config.yaml Normal file
View File

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

View File

@@ -1,3 +1,38 @@
# 2.5.0
Saves from 2.4 are not compatible with 2.5.
## Features/Improvements
* **[Engine]** DCS 2.7 Support
* **[UI]** Improved FOB menu, added a custom banner, and do not display aircraft recruitment menu
* **[Flight Planner]** Added AEW&C missions. (by siKruger)
* **[Kneeboard]** Added dark kneeboard option (by GvonH)
* **[Campaigns]** Multiple EWR sites may now be generated, and EWR sites may be generated outside bases (by SnappyComebacks)
* **[Mission Generation]** Cloudy and rainy (but not thunderstorm) weather will use the cloud presets from DCS 2.7.
* **[Plugins]** Added LotATC export plugin (by drsoran)
* **[Plugins]** Added Splash Damage Plugin (by Wheelijoe)
* **[Loadouts]** Replaced Litening with ATFLIR for all default F/A-18C loadouts.
## Fixes
* **[Flight Planner]** Front lines now project threat zones, so TARCAP/escorts will not be pruned for flights near the front. Packages may also route around the front line when practical.
* **[Flight Planner]** Fixed error when planning BAI at SAMs with dead subgroups.
* **[Flight Planner]** Mig-19 was not allowed for CAS roles fixed
* **[Flight Planner]** Increased size of navigation planning area to avoid plannign failures with distant waypoints.
* **[Flight Planner]** Fixed UI refresh when unchecking the "default loadout" box in the loadout editor.
* **[Objective names]** Fixed typos in objective name : ARMADILLLO -> ARMADILLO (by SnappyComebacks)
* **[Payloads]** F-86 Sabre was missing a custom payload
* **[Payloads]** Added GAR-8 period restrictions (by Mustang-25)
* **[Campaign]** Date now progresses.
* **[Campaign]** Added game over message when a coalition runs out of functioning airbases.
* **[Mission Generation]** Fixed "invalid face handle" error in kneeboard generation that occurred on some machines.
## Regressions
* **[Mod Support]** Stopped support for 2.5.5 Rafale Mode, and removed factions that were using it
* **[Mod Support]** Su-57 mod support might be out of date
# 2.4.3
## Features/Improvements
@@ -8,7 +43,6 @@
* **[Mods]** Updated C-130J mod data to version 6.4
* **[Mods]** Updated F-22A mod to latest version
* **[Payload]** Mirage-2000C : Added Eclair counter measures pod to all default loadouts
# 2.4.2

View File

@@ -2,20 +2,21 @@ from dcs.vehicles import AirDefence
AAA_UNITS = [
AirDefence.SPAAA_Gepard,
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.AAA_Vulcan_M163,
AirDefence.AAA_ZU_23_Closed,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
AirDefence.SPAAA_Vulcan_M163,
AirDefence.AAA_ZU_23_Closed_Emplacement,
AirDefence.AAA_ZU_23_Emplacement,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_Insurgent_Closed,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
AirDefence.AAA_ZU_23_Closed_Emplacement_Insurgent,
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375,
AirDefence.AAA_ZU_23_Insurgent,
AirDefence.AAA_8_8cm_Flak_18,
AirDefence.AAA_Flak_38,
AirDefence.AAA_Flak_38_20mm,
AirDefence.AAA_8_8cm_Flak_36,
AirDefence.AAA_8_8cm_Flak_37,
AirDefence.AAA_Flak_Vierling_38,
AirDefence.AAA_Kdo_G_40,
AirDefence.AAA_Flak_Vierling_38_Quad_20mm,
AirDefence.AAA_SP_Kdo_G_40,
AirDefence.AAA_8_8cm_Flak_41,
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_40mm_Bofors,
AirDefence.AAA_S_60_57mm,
]

View File

@@ -1,6 +1,6 @@
from dcs.ships import (
CGN_1144_2_Pyotr_Velikiy,
CG_1164_Moskva,
Battlecruiser_1144_2_Pyotr_Velikiy,
Cruiser_1164_Moskva,
CVN_70_Carl_Vinson,
CVN_71_Theodore_Roosevelt,
CVN_72_Abraham_Lincoln,
@@ -8,63 +8,63 @@ from dcs.ships import (
CVN_74_John_C__Stennis,
CV_1143_5_Admiral_Kuznetsov,
CV_1143_5_Admiral_Kuznetsov_2017,
FFG_11540_Neustrashimy,
FFL_1124_4_Grisha,
FF_1135M_Rezky,
FSG_1241_1MP_Molniya,
Frigate_11540_Neustrashimy,
Corvette_1124_4_Grisha,
Frigate_1135M_Rezky,
Corvette_1241_1_Molniya,
LHA_1_Tarawa,
Oliver_Hazzard_Perry_class,
Ticonderoga_class,
FFG_Oliver_Hazzard_Perry,
CG_Ticonderoga,
Type_052B_Destroyer,
Type_052C_Destroyer,
Type_054A_Frigate,
USS_Arleigh_Burke_IIa,
DDG_Arleigh_Burke_IIa,
)
from dcs.vehicles import AirDefence
UNITS_WITH_RADAR = [
# Radars
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_11_Buk_CC_9S470M1,
AirDefence.SAM_Patriot_AMG_AN_MRC_137,
AirDefence.SAM_Patriot_ECS_AN_MSQ_104,
AirDefence.SAM_SA_15_Tor_Gauntlet,
AirDefence.SAM_SA_11_Buk_Gadfly_C2,
AirDefence.SAM_Patriot_CR__AMG_AN_MRC_137,
AirDefence.SAM_Patriot_ECS,
AirDefence.SPAAA_Gepard,
AirDefence.AAA_Vulcan_M163,
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SPAAA_Vulcan_M163,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
AirDefence.EWR_1L13,
AirDefence.SAM_SA_6_Kub_STR_9S91,
AirDefence.SAM_SA_10_S_300PS_TR_30N6,
AirDefence.SAM_SA_10_S_300PS_SR_5N66M,
AirDefence.SAM_SA_6_Kub_Long_Track_STR,
AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR,
AirDefence.SAM_SA_10_S_300_Grumble_Clam_Shell_SR,
AirDefence.EWR_55G6,
AirDefence.SAM_SA_10_S_300PS_SR_64H6E,
AirDefence.SAM_SA_11_Buk_SR_9S18M1,
AirDefence.CP_9S80M1_Sborka,
AirDefence.SAM_Hawk_TR_AN_MPQ_46,
AirDefence.SAM_Hawk_SR_AN_MPQ_50,
AirDefence.SAM_Patriot_STR_AN_MPQ_53,
AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR,
AirDefence.SAM_SA_11_Buk_Gadfly_Snow_Drift_SR,
AirDefence.MCC_SR_Sborka_Dog_Ear_SR,
AirDefence.SAM_Hawk_TR__AN_MPQ_46,
AirDefence.SAM_Hawk_SR__AN_MPQ_50,
AirDefence.SAM_Patriot_STR,
AirDefence.SAM_Hawk_CWAR_AN_MPQ_55,
AirDefence.SAM_SR_P_19,
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3,
AirDefence.SAM_Roland_EWR,
AirDefence.SAM_SA_3_S_125_TR_SNR,
AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song,
AirDefence.SAM_SA_3_S_125_Low_Blow_TR,
AirDefence.SAM_SA_2_S_75_Fan_Song_TR,
AirDefence.HQ_7_Self_Propelled_STR,
# Ships
CVN_70_Carl_Vinson,
Oliver_Hazzard_Perry_class,
Ticonderoga_class,
FFL_1124_4_Grisha,
FFG_Oliver_Hazzard_Perry,
CG_Ticonderoga,
Corvette_1124_4_Grisha,
CV_1143_5_Admiral_Kuznetsov,
FSG_1241_1MP_Molniya,
CG_1164_Moskva,
FFG_11540_Neustrashimy,
CGN_1144_2_Pyotr_Velikiy,
FF_1135M_Rezky,
Corvette_1241_1_Molniya,
Cruiser_1164_Moskva,
Frigate_11540_Neustrashimy,
Battlecruiser_1144_2_Pyotr_Velikiy,
Frigate_1135M_Rezky,
CV_1143_5_Admiral_Kuznetsov_2017,
CVN_74_John_C__Stennis,
CVN_71_Theodore_Roosevelt,
CVN_72_Abraham_Lincoln,
CVN_73_George_Washington,
USS_Arleigh_Burke_IIa,
DDG_Arleigh_Burke_IIa,
LHA_1_Tarawa,
Type_052B_Destroyer,
Type_054A_Frigate,

File diff suppressed because it is too large Load Diff

View File

@@ -51,7 +51,6 @@ from dcs.planes import (
F_117A,
F_14A_135_GR,
F_14B,
F_111F,
F_15C,
F_15E,
F_16A,
@@ -116,8 +115,8 @@ from dcs.planes import (
I_16,
)
from dcs.ships import (
Armed_speedboat,
Bulk_cargo_ship_Yakushev,
Boat_Armed_Hi_speed,
Bulker_Yakushev,
CVN_71_Theodore_Roosevelt,
CVN_72_Abraham_Lincoln,
CVN_73_George_Washington,
@@ -125,7 +124,7 @@ from dcs.ships import (
CVN_75_Harry_S__Truman,
CV_1143_5_Admiral_Kuznetsov,
CV_1143_5_Admiral_Kuznetsov_2017,
Dry_cargo_ship_Ivanov,
Cargo_Ivanov,
LHA_1_Tarawa,
Tanker_Elnya_160,
ship_map,
@@ -174,7 +173,6 @@ from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
from pydcs_extensions.su57.su57 import Su_57
UNITINFOTEXT_PATH = Path("./resources/units/unit_info_text.json")
@@ -182,9 +180,6 @@ UNITINFOTEXT_PATH = Path("./resources/units/unit_info_text.json")
plane_map["A-4E-C"] = A_4E_C
plane_map["F-22A"] = F_22A
plane_map["MB-339PAN"] = MB_339PAN
plane_map["Rafale_M"] = Rafale_M
plane_map["Rafale_A_S"] = Rafale_A_S
plane_map["Rafale_B"] = Rafale_B
plane_map["Su-57"] = Su_57
plane_map["Hercules"] = Hercules
@@ -360,7 +355,7 @@ x_map = {
}
from this example `Identifier` should be used (which may or may not include category of the unit and dot + underscore characters).
For example, player accessible Hornet is called `FA_18C_hornet`, and MANPAD Igla is called `AirDefence.SAM_SA_18_Igla_S_MANPADS`
For example, player accessible Hornet is called `FA_18C_hornet`, and MANPAD Igla is called `AirDefence.MANPADS_SA_18_Igla_S_Grouse`
"""
# This should probably be much higher, but the AI doesn't rollover their budget
@@ -453,7 +448,6 @@ PRICES = {
Tu_160: 50,
Tu_22M3: 40,
Tu_95MS: 35,
F_111F: 21,
# special
IL_76MD: 30,
An_26B: 25,
@@ -481,15 +475,11 @@ PRICES = {
MQ_9_Reaper: 12,
RQ_1A_Predator: 6,
WingLoong_I: 6,
# Modded
Rafale_M: 26,
Rafale_A_S: 26,
Rafale_B: 26,
# armor
Armor.APC_MTLB: 4,
Armor.FDDM_Grad: 4,
Armor.ARV_BRDM_2: 6,
Armor.ARV_BTR_RD: 6,
Artillery.Grad_MRL_FDDM__FC: 4,
Armor.IFV_BRDM_2: 6,
Armor.APC_BTR_RD: 6,
Armor.APC_BTR_80: 8,
Armor.APC_BTR_82A: 10,
Armor.MBT_T_55: 18,
@@ -503,147 +493,149 @@ PRICES = {
Armor.IFV_BMP_3: 18,
Armor.ZBD_04A: 12,
Armor.ZTZ_96B: 30,
Armor.APC_Cobra: 4,
Armor.APC_Cobra__Scout: 4,
Armor.APC_M113: 6,
Armor.APC_M1043_HMMWV_Armament: 2,
Armor.ATGM_M1045_HMMWV_TOW: 8,
Armor.APC_HMMWV__Scout: 2,
Armor.ATGM_HMMWV: 8,
Armor.IFV_M2A2_Bradley: 12,
Armor.APC_M1126_Stryker_ICV: 10,
Armor.SPG_M1128_Stryker_MGS: 14,
Armor.ATGM_M1134_Stryker: 12,
Armor.IFV_M1126_Stryker_ICV: 10,
Armor.SPG_Stryker_MGS: 14,
Armor.ATGM_Stryker: 12,
Armor.MBT_M60A3_Patton: 16,
Armor.MBT_M1A2_Abrams: 25,
Armor.MBT_Leclerc: 25,
Armor.MBT_Leopard_1A3: 20,
Armor.MBT_Leopard_2: 25,
Armor.MBT_Merkava_Mk__4: 25,
Armor.TPz_Fuchs: 5,
Armor.MBT_Merkava_IV: 25,
Armor.APC_TPz_Fuchs: 5,
Armor.MBT_Challenger_II: 25,
Armor.IFV_Marder: 10,
Armor.IFV_MCV_80: 10,
Armor.IFV_Warrior: 10,
Armor.IFV_LAV_25: 7,
Artillery.MLRS_M270: 55,
Artillery.SPH_M109_Paladin: 25,
Artillery.SPH_2S9_Nona: 12,
Artillery.SPH_2S1_Gvozdika: 18,
Artillery.SPH_2S3_Akatsia: 24,
Artillery.SPH_2S19_Msta: 30,
Artillery.MLRS_BM_21_Grad: 15,
Artillery.MLRS_9K57_Uragan_BM_27: 50,
Artillery.MLRS_9A52_Smerch: 40,
Artillery._2B11_mortar: 4,
Artillery.SpGH_Dana: 26,
Unarmed.Transport_UAZ_469: 3,
Unarmed.Transport_Ural_375: 3,
Artillery.MLRS_M270_227mm: 55,
Artillery.SPH_M109_Paladin_155mm: 25,
Artillery.SPH_2S9_Nona_120mm_M: 12,
Artillery.SPH_2S1_Gvozdika_122mm: 18,
Artillery.SPH_2S3_Akatsia_152mm: 24,
Artillery.SPH_2S19_Msta_152mm: 30,
Artillery.MLRS_BM_21_Grad_122mm: 15,
Artillery.MLRS_BM_27_Uragan_220mm: 50,
Artillery.MLRS_9A52_Smerch_HE_300mm: 40,
Artillery.Mortar_2B11_120mm: 4,
Artillery.SPH_Dana_vz77_152mm: 26,
Artillery.PLZ_05: 25,
Unarmed.LUV_UAZ_469_Jeep: 3,
Unarmed.Truck_Ural_375: 3,
Infantry.Infantry_M4: 1,
Infantry.Soldier_AK: 1,
Unarmed.Transport_M818: 3,
Infantry.Infantry_AK_74: 1,
Unarmed.Truck_M818_6x6: 3,
# WW2
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G: 24,
Armor.MT_Pz_Kpfw_IV_Ausf_H: 16,
Armor.MT_PzIV_H: 16,
Armor.HT_Pz_Kpfw_VI_Tiger_I: 24,
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II: 26,
Armor.TD_Jagdpanther_G1: 18,
Armor.TD_Jagdpanzer_IV: 11,
Armor.Sd_Kfz_184_Elefant: 18,
Armor.APC_Sd_Kfz_251: 4,
Armor.AC_Sd_Kfz_234_2_Puma: 8,
Armor.SPG_Jagdpanther_G1: 18,
Armor.SPG_Jagdpanzer_IV: 11,
Armor.SPG_Sd_Kfz_184_Elefant: 18,
Armor.APC_Sd_Kfz_251_Halftrack: 4,
Armor.IFV_Sd_Kfz_234_2_Puma: 8,
Armor.MT_M4_Sherman: 12,
Armor.MT_M4A4_Sherman_Firefly: 16,
Armor.CT_Cromwell_IV: 12,
Armor.M30_Cargo_Carrier: 2,
Armor.APC_M2A1: 4,
Unarmed.Carrier_M30_Cargo: 2,
Armor.APC_M2A1_Halftrack: 4,
Armor.CT_Centaur_IV: 10,
Armor.HIT_Churchill_VII: 16,
Armor.LAC_M8_Greyhound: 8,
Armor.TD_M10_GMC: 14,
Armor.StuG_III_Ausf__G: 12,
Armor.StuG_IV: 14,
Artillery.M12_GMC: 10,
Artillery.Sturmpanzer_IV_Brummbär: 10,
Armor.Daimler_Armoured_Car: 8,
Armor.Car_M8_Greyhound_Armored: 8,
Armor.SPG_M10_GMC: 14,
Armor.SPG_StuG_III_Ausf__G: 12,
Armor.SPG_StuG_IV: 14,
Artillery.SPG_M12_GMC_155mm: 10,
Artillery.SPG_Sturmpanzer_IV_Brummbar: 10,
Armor.Car_Daimler_Armored: 8,
Armor.LT_Mk_VII_Tetrarch: 8,
Armor.M4_Tractor: 2,
Unarmed.Tractor_M4_Hi_Speed: 2,
# ship
CV_1143_5_Admiral_Kuznetsov: 100,
CVN_74_John_C__Stennis: 100,
LHA_1_Tarawa: 50,
Bulk_cargo_ship_Yakushev: 10,
Armed_speedboat: 10,
Dry_cargo_ship_Ivanov: 10,
Bulker_Yakushev: 10,
Boat_Armed_Hi_speed: 10,
Cargo_Ivanov: 10,
Tanker_Elnya_160: 10,
# Air Defence units
AirDefence.SAM_SA_19_Tunguska_2S6: 30,
AirDefence.SAM_SA_6_Kub_LN_2P25: 20,
AirDefence.SAM_SA_3_S_125_LN_5P73: 6,
AirDefence.SAM_SA_11_Buk_LN_9A310M1: 30,
AirDefence.SAM_SA_11_Buk_CC_9S470M1: 25,
AirDefence.SAM_SA_11_Buk_SR_9S18M1: 28,
AirDefence.SAM_SA_8_Osa_9A33: 28,
AirDefence.SAM_SA_15_Tor_9A331: 40,
AirDefence.SAM_SA_13_Strela_10M3_9A35M3: 16,
AirDefence.SAM_SA_9_Strela_1_9P31: 12,
AirDefence.SAM_SA_19_Tunguska_Grison: 30,
AirDefence.SAM_SA_6_Kub_Gainful_TEL: 20,
AirDefence.SAM_SA_3_S_125_Goa_LN: 6,
AirDefence.SAM_SA_11_Buk_Gadfly_Fire_Dome_TEL: 30,
AirDefence.SAM_SA_11_Buk_Gadfly_C2: 25,
AirDefence.SAM_SA_11_Buk_Gadfly_Snow_Drift_SR: 28,
AirDefence.SAM_SA_8_Osa_Gecko_TEL: 28,
AirDefence.SAM_SA_15_Tor_Gauntlet: 40,
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL: 16,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL: 12,
AirDefence.SAM_SA_8_Osa_LD_9T217: 22,
AirDefence.SAM_Patriot_AMG_AN_MRC_137: 35,
AirDefence.SAM_Patriot_ECS_AN_MSQ_104: 30,
AirDefence.SAM_Patriot_CR__AMG_AN_MRC_137: 35,
AirDefence.SAM_Patriot_ECS: 30,
AirDefence.SPAAA_Gepard: 24,
AirDefence.SAM_Hawk_PCP: 14,
AirDefence.AAA_Vulcan_M163: 10,
AirDefence.SAM_Hawk_Generator__PCP: 14,
AirDefence.SPAAA_Vulcan_M163: 10,
AirDefence.SAM_Hawk_LN_M192: 8,
AirDefence.SAM_Chaparral_M48: 16,
AirDefence.SAM_Linebacker_M6: 18,
AirDefence.SAM_Patriot_LN_M901: 15,
AirDefence.SAM_Avenger_M1097: 20,
AirDefence.SAM_Linebacker___Bradley_M6: 18,
AirDefence.SAM_Patriot_LN: 15,
AirDefence.SAM_Avenger__Stinger: 20,
AirDefence.SAM_Patriot_EPP_III: 15,
AirDefence.SAM_Patriot_ICC: 18,
AirDefence.SAM_Patriot_C2_ICC: 18,
AirDefence.SAM_Roland_ADS: 12,
AirDefence.Stinger_MANPADS: 6,
AirDefence.SAM_Stinger_comm_dsr: 4,
AirDefence.SAM_Stinger_comm: 4,
AirDefence.SPAAA_ZSU_23_4_Shilka: 10,
AirDefence.AAA_ZSU_57_2: 12,
AirDefence.AAA_ZU_23_Closed: 6,
AirDefence.MANPADS_Stinger: 6,
AirDefence.MANPADS_Stinger_C2_Desert: 4,
AirDefence.MANPADS_Stinger_C2: 4,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish: 10,
AirDefence.SPAAA_ZSU_57_2: 12,
AirDefence.AAA_ZU_23_Closed_Emplacement: 6,
AirDefence.AAA_ZU_23_Emplacement: 6,
AirDefence.AAA_ZU_23_on_Ural_375: 7,
AirDefence.AAA_ZU_23_Insurgent_Closed: 6,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375: 7,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375: 7,
AirDefence.AAA_ZU_23_Closed_Emplacement_Insurgent: 6,
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375: 7,
AirDefence.AAA_ZU_23_Insurgent: 6,
AirDefence.SAM_SA_18_Igla_MANPADS: 10,
AirDefence.SAM_SA_18_Igla_comm: 8,
AirDefence.SAM_SA_18_Igla_S_MANPADS: 12,
AirDefence.SAM_SA_18_Igla_S_comm: 8,
AirDefence.MANPADS_SA_18_Igla_Grouse: 10,
AirDefence.MANPADS_SA_18_Igla_Grouse_C2: 8,
AirDefence.MANPADS_SA_18_Igla_S_Grouse: 12,
AirDefence.MANPADS_SA_18_Igla_S_Grouse_C2: 8,
AirDefence.EWR_1L13: 30,
AirDefence.SAM_SA_6_Kub_STR_9S91: 22,
AirDefence.SAM_SA_6_Kub_Long_Track_STR: 22,
AirDefence.EWR_55G6: 30,
AirDefence.CP_9S80M1_Sborka: 10,
AirDefence.SAM_Hawk_TR_AN_MPQ_46: 14,
AirDefence.SAM_Hawk_SR_AN_MPQ_50: 18,
AirDefence.SAM_Patriot_STR_AN_MPQ_53: 22,
AirDefence.MCC_SR_Sborka_Dog_Ear_SR: 10,
AirDefence.SAM_Hawk_TR__AN_MPQ_46: 14,
AirDefence.SAM_Hawk_SR__AN_MPQ_50: 18,
AirDefence.SAM_Patriot_STR: 22,
AirDefence.SAM_Hawk_CWAR_AN_MPQ_55: 20,
AirDefence.SAM_SR_P_19: 14,
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3: 14,
AirDefence.SAM_Roland_EWR: 16,
AirDefence.SAM_SA_3_S_125_TR_SNR: 14,
AirDefence.SAM_SA_2_LN_SM_90: 8,
AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song: 12,
AirDefence.Rapier_FSA_Launcher: 6,
AirDefence.Rapier_FSA_Optical_Tracker: 6,
AirDefence.Rapier_FSA_Blindfire_Tracker: 8,
AirDefence.SAM_SA_3_S_125_Low_Blow_TR: 14,
AirDefence.SAM_SA_2_S_75_Guideline_LN: 8,
AirDefence.SAM_SA_2_S_75_Fan_Song_TR: 12,
AirDefence.SAM_Rapier_LN: 6,
AirDefence.SAM_Rapier_Tracker: 6,
AirDefence.SAM_Rapier_Blindfire_TR: 8,
AirDefence.HQ_7_Self_Propelled_LN: 20,
AirDefence.HQ_7_Self_Propelled_STR: 24,
AirDefence.AAA_8_8cm_Flak_18: 6,
AirDefence.AAA_Flak_38: 6,
AirDefence.AAA_Flak_38_20mm: 6,
AirDefence.AAA_8_8cm_Flak_36: 8,
AirDefence.AAA_8_8cm_Flak_37: 9,
AirDefence.AAA_Flak_Vierling_38: 5,
AirDefence.AAA_Kdo_G_40: 8,
AirDefence.Flak_Searchlight_37: 4,
AirDefence.Maschinensatz_33: 10,
AirDefence.AAA_Flak_Vierling_38_Quad_20mm: 5,
AirDefence.AAA_SP_Kdo_G_40: 8,
AirDefence.SL_Flakscheinwerfer_37: 4,
AirDefence.PU_Maschinensatz_33: 10,
AirDefence.AAA_8_8cm_Flak_41: 10,
AirDefence.EWR_FuMG_401_Freya_LZ: 25,
AirDefence.AAA_Bofors_40mm: 8,
AirDefence.AAA_40mm_Bofors: 8,
AirDefence.AAA_S_60_57mm: 8,
AirDefence.AAA_M1_37mm: 7,
AirDefence.AAA_M45_Quadmount: 4,
AirDefence.AA_gun_QF_3_7: 10,
AirDefence.AAA_M45_Quadmount_HB_12_7mm: 4,
AirDefence.AAA_QF_3_7: 10,
# FRENCH PACK MOD
frenchpack.AMX_10RCR: 10,
frenchpack.AMX_10RCR_SEPAR: 12,
@@ -674,12 +666,12 @@ PRICES = {
frenchpack.DIM__TOYOTA_DESERT: 2,
frenchpack.DIM__KAMIKAZE: 6,
# SA-10
AirDefence.SAM_SA_10_S_300PS_CP_54K6: 18,
AirDefence.SAM_SA_10_S_300PS_TR_30N6: 24,
AirDefence.SAM_SA_10_S_300PS_SR_5N66M: 30,
AirDefence.SAM_SA_10_S_300PS_SR_64H6E: 30,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 22,
AirDefence.SAM_SA_10_S_300PS_LN_5P85D: 22,
AirDefence.SAM_SA_10_S_300_Grumble_C2: 18,
AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR: 24,
AirDefence.SAM_SA_10_S_300_Grumble_Clam_Shell_SR: 30,
AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR: 30,
AirDefence.SAM_SA_10_S_300_Grumble_TEL_C: 22,
AirDefence.SAM_SA_10_S_300_Grumble_TEL_D: 22,
# High digit sams mod
highdigitsams.AAA_SON_9_Fire_Can: 8,
highdigitsams.AAA_100mm_KS_19: 10,
@@ -772,7 +764,6 @@ UNIT_BY_TASK = {
SpitfireLFMkIXCW,
SpitfireLFMkIX,
A_4E_C,
Rafale_M,
SA342Mistral,
],
CAS: [
@@ -786,7 +777,6 @@ UNIT_BY_TASK = {
A_10C_2,
A_20G,
B_17G,
F_111F,
B_1B,
B_52H,
F_117A,
@@ -807,8 +797,6 @@ UNIT_BY_TASK = {
P_47D_30bl1,
P_47D_40,
RQ_1A_Predator,
Rafale_A_S,
Rafale_B,
S_3B,
SA342L,
SA342M,
@@ -844,18 +832,18 @@ UNIT_BY_TASK = {
Armor.APC_MTLB,
Armor.APC_MTLB,
Armor.APC_MTLB,
Armor.FDDM_Grad,
Armor.FDDM_Grad,
Armor.FDDM_Grad,
Armor.FDDM_Grad,
Armor.FDDM_Grad,
Armor.ARV_BRDM_2,
Armor.ARV_BRDM_2,
Armor.ARV_BRDM_2,
Armor.ARV_BTR_RD,
Armor.ARV_BTR_RD,
Armor.ARV_BTR_RD,
Armor.ARV_BTR_RD,
Artillery.Grad_MRL_FDDM__FC,
Artillery.Grad_MRL_FDDM__FC,
Artillery.Grad_MRL_FDDM__FC,
Artillery.Grad_MRL_FDDM__FC,
Artillery.Grad_MRL_FDDM__FC,
Armor.IFV_BRDM_2,
Armor.IFV_BRDM_2,
Armor.IFV_BRDM_2,
Armor.APC_BTR_RD,
Armor.APC_BTR_RD,
Armor.APC_BTR_RD,
Armor.APC_BTR_RD,
Armor.APC_BTR_80,
Armor.APC_BTR_80,
Armor.APC_BTR_80,
@@ -885,33 +873,33 @@ UNIT_BY_TASK = {
Armor.MBT_T_80U,
Armor.MBT_T_90,
Armor.ZTZ_96B,
Armor.APC_Cobra,
Armor.APC_Cobra,
Armor.APC_Cobra,
Armor.APC_Cobra,
Armor.APC_Cobra__Scout,
Armor.APC_Cobra__Scout,
Armor.APC_Cobra__Scout,
Armor.APC_Cobra__Scout,
Armor.APC_M113,
Armor.APC_M113,
Armor.APC_M113,
Armor.APC_M113,
Armor.TPz_Fuchs,
Armor.TPz_Fuchs,
Armor.TPz_Fuchs,
Armor.TPz_Fuchs,
Armor.ATGM_M1045_HMMWV_TOW,
Armor.ATGM_M1045_HMMWV_TOW,
Armor.APC_M1043_HMMWV_Armament,
Armor.APC_M1043_HMMWV_Armament,
Armor.APC_TPz_Fuchs,
Armor.APC_TPz_Fuchs,
Armor.APC_TPz_Fuchs,
Armor.APC_TPz_Fuchs,
Armor.ATGM_HMMWV,
Armor.ATGM_HMMWV,
Armor.APC_HMMWV__Scout,
Armor.APC_HMMWV__Scout,
Armor.IFV_M2A2_Bradley,
Armor.IFV_M2A2_Bradley,
Armor.ATGM_M1134_Stryker,
Armor.ATGM_M1134_Stryker,
Armor.APC_M1126_Stryker_ICV,
Armor.APC_M1126_Stryker_ICV,
Armor.APC_M1126_Stryker_ICV,
Armor.SPG_M1128_Stryker_MGS,
Armor.IFV_MCV_80,
Armor.IFV_MCV_80,
Armor.IFV_MCV_80,
Armor.ATGM_Stryker,
Armor.ATGM_Stryker,
Armor.IFV_M1126_Stryker_ICV,
Armor.IFV_M1126_Stryker_ICV,
Armor.IFV_M1126_Stryker_ICV,
Armor.SPG_Stryker_MGS,
Armor.IFV_Warrior,
Armor.IFV_Warrior,
Armor.IFV_Warrior,
Armor.IFV_LAV_25,
Armor.IFV_LAV_25,
Armor.IFV_Marder,
@@ -927,92 +915,94 @@ UNIT_BY_TASK = {
Armor.MBT_Leclerc,
Armor.MBT_Leopard_2,
Armor.MBT_Challenger_II,
Armor.MBT_Merkava_Mk__4,
Armor.MBT_Merkava_IV,
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
Armor.MT_Pz_Kpfw_IV_Ausf_H,
Armor.MT_PzIV_H,
Armor.HT_Pz_Kpfw_VI_Tiger_I,
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II,
Armor.APC_Sd_Kfz_251,
Armor.APC_Sd_Kfz_251,
Armor.APC_Sd_Kfz_251,
Armor.APC_Sd_Kfz_251,
Armor.AC_Sd_Kfz_234_2_Puma,
Armor.AC_Sd_Kfz_234_2_Puma,
Armor.APC_Sd_Kfz_251_Halftrack,
Armor.APC_Sd_Kfz_251_Halftrack,
Armor.APC_Sd_Kfz_251_Halftrack,
Armor.APC_Sd_Kfz_251_Halftrack,
Armor.IFV_Sd_Kfz_234_2_Puma,
Armor.IFV_Sd_Kfz_234_2_Puma,
Armor.MT_M4_Sherman,
Armor.MT_M4A4_Sherman_Firefly,
Armor.CT_Cromwell_IV,
Armor.M30_Cargo_Carrier,
Armor.M30_Cargo_Carrier,
Armor.APC_M2A1,
Armor.APC_M2A1,
Armor.APC_M2A1,
Armor.APC_M2A1,
Unarmed.Carrier_M30_Cargo,
Unarmed.Carrier_M30_Cargo,
Armor.APC_M2A1_Halftrack,
Armor.APC_M2A1_Halftrack,
Armor.APC_M2A1_Halftrack,
Armor.APC_M2A1_Halftrack,
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
Armor.MT_Pz_Kpfw_IV_Ausf_H,
Armor.MT_PzIV_H,
Armor.HT_Pz_Kpfw_VI_Tiger_I,
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II,
Armor.TD_Jagdpanther_G1,
Armor.TD_Jagdpanzer_IV,
Armor.Sd_Kfz_184_Elefant,
Armor.APC_Sd_Kfz_251,
Armor.AC_Sd_Kfz_234_2_Puma,
Armor.SPG_Jagdpanther_G1,
Armor.SPG_Jagdpanzer_IV,
Armor.SPG_Sd_Kfz_184_Elefant,
Armor.APC_Sd_Kfz_251_Halftrack,
Armor.IFV_Sd_Kfz_234_2_Puma,
Armor.MT_M4_Sherman,
Armor.MT_M4A4_Sherman_Firefly,
Armor.CT_Cromwell_IV,
Armor.M30_Cargo_Carrier,
Armor.M30_Cargo_Carrier,
Armor.M30_Cargo_Carrier,
Armor.APC_M2A1,
Armor.APC_M2A1,
Unarmed.Carrier_M30_Cargo,
Unarmed.Carrier_M30_Cargo,
Unarmed.Carrier_M30_Cargo,
Armor.APC_M2A1_Halftrack,
Armor.APC_M2A1_Halftrack,
Armor.CT_Centaur_IV,
Armor.CT_Centaur_IV,
Armor.HIT_Churchill_VII,
Armor.LAC_M8_Greyhound,
Armor.LAC_M8_Greyhound,
Armor.TD_M10_GMC,
Armor.TD_M10_GMC,
Armor.StuG_III_Ausf__G,
Armor.StuG_IV,
Artillery.M12_GMC,
Artillery.Sturmpanzer_IV_Brummbär,
Armor.Daimler_Armoured_Car,
Armor.Car_M8_Greyhound_Armored,
Armor.Car_M8_Greyhound_Armored,
Armor.SPG_M10_GMC,
Armor.SPG_M10_GMC,
Armor.SPG_StuG_III_Ausf__G,
Armor.SPG_StuG_IV,
Artillery.SPG_M12_GMC_155mm,
Artillery.SPG_Sturmpanzer_IV_Brummbar,
Armor.Car_Daimler_Armored,
Armor.LT_Mk_VII_Tetrarch,
Artillery.MLRS_M270,
Artillery.SPH_M109_Paladin,
Artillery.SPH_2S9_Nona,
Artillery.SPH_2S1_Gvozdika,
Artillery.SPH_2S3_Akatsia,
Artillery.SPH_2S19_Msta,
Artillery.MLRS_BM_21_Grad,
Artillery.MLRS_BM_21_Grad,
Artillery.MLRS_9K57_Uragan_BM_27,
Artillery.MLRS_9A52_Smerch,
Artillery.SpGH_Dana,
Artillery.M12_GMC,
Artillery.Sturmpanzer_IV_Brummbär,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
AirDefence.AAA_ZSU_57_2,
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_13_Strela_10M3_9A35M3,
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_19_Tunguska_2S6,
Artillery.MLRS_M270_227mm,
Artillery.SPH_M109_Paladin_155mm,
Artillery.SPH_2S9_Nona_120mm_M,
Artillery.SPH_2S1_Gvozdika_122mm,
Artillery.SPH_2S3_Akatsia_152mm,
Artillery.SPH_2S19_Msta_152mm,
Artillery.MLRS_BM_21_Grad_122mm,
Artillery.MLRS_BM_21_Grad_122mm,
Artillery.MLRS_BM_27_Uragan_220mm,
Artillery.MLRS_9A52_Smerch_HE_300mm,
Artillery.SPH_Dana_vz77_152mm,
Artillery.PLZ_05,
Artillery.SPG_M12_GMC_155mm,
Artillery.SPG_Sturmpanzer_IV_Brummbar,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375,
AirDefence.SPAAA_ZSU_57_2,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
AirDefence.SAM_SA_8_Osa_Gecko_TEL,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL,
AirDefence.SAM_SA_15_Tor_Gauntlet,
AirDefence.SAM_SA_19_Tunguska_Grison,
AirDefence.SPAAA_Gepard,
AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Linebacker_M6,
AirDefence.SPAAA_Vulcan_M163,
AirDefence.SAM_Linebacker___Bradley_M6,
AirDefence.SAM_Chaparral_M48,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger__Stinger,
AirDefence.SAM_Roland_ADS,
AirDefence.HQ_7_Self_Propelled_LN,
AirDefence.AAA_8_8cm_Flak_18,
AirDefence.AAA_8_8cm_Flak_36,
AirDefence.AAA_8_8cm_Flak_37,
AirDefence.AAA_8_8cm_Flak_41,
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_40mm_Bofors,
AirDefence.AAA_S_60_57mm,
AirDefence.AAA_M1_37mm,
AirDefence.AA_gun_QF_3_7,
AirDefence.AAA_QF_3_7,
frenchpack.DIM__TOYOTA_BLUE,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__TOYOTA_GREEN,
@@ -1037,13 +1027,13 @@ UNIT_BY_TASK = {
],
AirDefence: [],
Reconnaissance: [
Unarmed.Transport_M818,
Unarmed.Transport_Ural_375,
Unarmed.Transport_UAZ_469,
Unarmed.Truck_M818_6x6,
Unarmed.Truck_Ural_375,
Unarmed.LUV_UAZ_469_Jeep,
],
Nothing: [
Infantry.Infantry_M4,
Infantry.Soldier_AK,
Infantry.Infantry_AK_74,
],
Embarking: [],
Carriage: [
@@ -1052,10 +1042,10 @@ UNIT_BY_TASK = {
CV_1143_5_Admiral_Kuznetsov,
],
CargoTransportation: [
Dry_cargo_ship_Ivanov,
Bulk_cargo_ship_Yakushev,
Cargo_Ivanov,
Bulker_Yakushev,
Tanker_Elnya_160,
Armed_speedboat,
Boat_Armed_Hi_speed,
],
}
@@ -1063,41 +1053,41 @@ UNIT_BY_TASK = {
Units from AirDefense category of UNIT_BY_TASK that will be removed from use if "No SAM" option is checked at the start of the game
"""
SAM_BAN = [
AirDefence.SAM_Linebacker_M6,
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_6_Kub_LN_2P25,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_3_S_125_LN_5P73,
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_SA_2_LN_SM_90,
AirDefence.SAM_SA_11_Buk_LN_9A310M1,
AirDefence.SAM_Linebacker___Bradley_M6,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
AirDefence.SAM_SA_8_Osa_Gecko_TEL,
AirDefence.SAM_SA_19_Tunguska_Grison,
AirDefence.SAM_SA_6_Kub_Gainful_TEL,
AirDefence.SAM_SA_8_Osa_Gecko_TEL,
AirDefence.SAM_SA_3_S_125_Goa_LN,
AirDefence.SAM_Hawk_Generator__PCP,
AirDefence.SAM_SA_2_S_75_Guideline_LN,
AirDefence.SAM_SA_11_Buk_Gadfly_Fire_Dome_TEL,
]
"""
Used to convert SAM site parts to the corresponding site
"""
SAM_CONVERT = {
AirDefence.SAM_SR_P_19: AirDefence.SAM_SA_3_S_125_LN_5P73,
AirDefence.SAM_SA_3_S_125_TR_SNR: AirDefence.SAM_SA_3_S_125_LN_5P73,
AirDefence.SAM_SA_3_S_125_LN_5P73: AirDefence.SAM_SA_3_S_125_LN_5P73,
AirDefence.SAM_SA_6_Kub_LN_2P25: AirDefence.SAM_SA_6_Kub_LN_2P25,
AirDefence.SAM_SA_6_Kub_STR_9S91: AirDefence.SAM_SA_6_Kub_LN_2P25,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C: AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
AirDefence.SAM_SA_10_S_300PS_SR_5N66M: AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
AirDefence.SAM_SA_10_S_300PS_TR_30N6: AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
AirDefence.SAM_SA_10_S_300PS_CP_54K6: AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
AirDefence.SAM_SA_10_S_300PS_SR_64H6E: AirDefence.SAM_SA_10_S_300PS_CP_54K6,
AirDefence.SAM_Hawk_TR_AN_MPQ_46: AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Hawk_SR_AN_MPQ_50: AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Hawk_LN_M192: AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3: AirDefence.SAM_SA_3_S_125_Goa_LN,
AirDefence.SAM_SA_3_S_125_Low_Blow_TR: AirDefence.SAM_SA_3_S_125_Goa_LN,
AirDefence.SAM_SA_3_S_125_Goa_LN: AirDefence.SAM_SA_3_S_125_Goa_LN,
AirDefence.SAM_SA_6_Kub_Gainful_TEL: AirDefence.SAM_SA_6_Kub_Gainful_TEL,
AirDefence.SAM_SA_6_Kub_Long_Track_STR: AirDefence.SAM_SA_6_Kub_Gainful_TEL,
AirDefence.SAM_SA_10_S_300_Grumble_TEL_C: AirDefence.SAM_SA_10_S_300_Grumble_TEL_C,
AirDefence.SAM_SA_10_S_300_Grumble_Clam_Shell_SR: AirDefence.SAM_SA_10_S_300_Grumble_TEL_C,
AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR: AirDefence.SAM_SA_10_S_300_Grumble_TEL_C,
AirDefence.SAM_SA_10_S_300_Grumble_C2: AirDefence.SAM_SA_10_S_300_Grumble_TEL_C,
AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR: AirDefence.SAM_SA_10_S_300_Grumble_C2,
AirDefence.SAM_Hawk_TR__AN_MPQ_46: AirDefence.SAM_Hawk_Generator__PCP,
AirDefence.SAM_Hawk_SR__AN_MPQ_50: AirDefence.SAM_Hawk_Generator__PCP,
AirDefence.SAM_Hawk_LN_M192: AirDefence.SAM_Hawk_Generator__PCP,
"except": {
# this radar is shared between the two S300's. if we attempt to find a SAM site at a base and can't find one
# model, we can safely assume the other was deployed
# well, perhaps not safely, but we'll make the assumption anyway :p
AirDefence.SAM_SA_10_S_300PS_TR_30N6: AirDefence.SAM_SA_10_S_300PS_CP_54K6,
AirDefence.SAM_SR_P_19: AirDefence.SAM_SA_2_LN_SM_90,
AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR: AirDefence.SAM_SA_10_S_300_Grumble_C2,
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3: AirDefence.SAM_SA_2_S_75_Guideline_LN,
},
}
@@ -1158,6 +1148,7 @@ COMMON_OVERRIDE = {
Escort: "CAP",
RunwayAttack: "RUNWAY_ATTACK",
FighterSweep: "CAP",
AWACS: "AEW&C",
}
"""
@@ -1226,7 +1217,6 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
F_14A_135_GR: COMMON_OVERRIDE,
F_14B: COMMON_OVERRIDE,
F_15C: COMMON_OVERRIDE,
F_111F: COMMON_OVERRIDE,
F_22A: COMMON_OVERRIDE,
F_16C_50: COMMON_OVERRIDE,
JF_17: COMMON_OVERRIDE,
@@ -1279,9 +1269,6 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
A_20G: COMMON_OVERRIDE,
A_4E_C: COMMON_OVERRIDE,
MB_339PAN: COMMON_OVERRIDE,
Rafale_M: COMMON_OVERRIDE,
Rafale_A_S: COMMON_OVERRIDE,
Rafale_B: COMMON_OVERRIDE,
OH_58D: COMMON_OVERRIDE,
F_16A: COMMON_OVERRIDE,
MQ_9_Reaper: COMMON_OVERRIDE,
@@ -1292,6 +1279,7 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
AH_64A: COMMON_OVERRIDE,
SH_60B: COMMON_OVERRIDE,
Hercules: COMMON_OVERRIDE,
F_86F_Sabre: COMMON_OVERRIDE,
Su_25TM: {
SEAD: "Kh-31P*2_Kh-25ML*4_R-73*2_L-081_MPS410",
},
@@ -1375,8 +1363,8 @@ CARRIER_CAPABLE = [
AV8BNA,
Su_33,
A_4E_C,
Rafale_M,
S_3B,
E_2C,
UH_1H,
Mi_8MT,
Ka_50,
@@ -1432,6 +1420,8 @@ def upgrade_to_supercarrier(unit, name: str):
return CVN_73_George_Washington
elif name == "CVN-75 Harry S. Truman":
return CVN_75_Harry_S__Truman
elif name == "Carrier Strike Group 8":
return CVN_75_Harry_S__Truman
else:
return CVN_71_Theodore_Roosevelt
elif unit == CV_1143_5_Admiral_Kuznetsov:
@@ -1457,9 +1447,9 @@ def find_unittype(for_task: Task, country_name: str) -> List[Type[UnitType]]:
MANPADS: List[VehicleType] = [
AirDefence.SAM_SA_18_Igla_MANPADS,
AirDefence.SAM_SA_18_Igla_S_MANPADS,
AirDefence.Stinger_MANPADS,
AirDefence.MANPADS_SA_18_Igla_Grouse,
AirDefence.MANPADS_SA_18_Igla_S_Grouse,
AirDefence.MANPADS_Stinger,
]
INFANTRY: List[VehicleType] = [
@@ -1468,28 +1458,28 @@ INFANTRY: List[VehicleType] = [
Infantry.Paratrooper_AKS,
Infantry.Paratrooper_AKS,
Infantry.Paratrooper_AKS,
Infantry.Soldier_RPG,
Infantry.Infantry_RPG,
Infantry.Infantry_M4,
Infantry.Infantry_M4,
Infantry.Infantry_M4,
Infantry.Infantry_M4,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
Artillery._2B11_mortar,
Infantry.Soldier_AK,
Infantry.Soldier_AK,
Infantry.Soldier_AK,
Infantry.Soldier_AK,
Infantry.Soldier_AK,
Infantry.Infantry_M249,
Artillery.Mortar_2B11_120mm,
Infantry.Infantry_AK_74,
Infantry.Infantry_AK_74,
Infantry.Infantry_AK_74,
Infantry.Infantry_AK_74,
Infantry.Infantry_AK_74,
Infantry.Paratrooper_RPG_16,
Infantry.Georgian_soldier_with_M4,
Infantry.Georgian_soldier_with_M4,
Infantry.Georgian_soldier_with_M4,
Infantry.Georgian_soldier_with_M4,
Infantry.Infantry_Soldier_Rus,
Infantry.Infantry_Soldier_Rus,
Infantry.Infantry_Soldier_Rus,
Infantry.Infantry_Soldier_Rus,
Infantry.Infantry_M4_Georgia,
Infantry.Infantry_M4_Georgia,
Infantry.Infantry_M4_Georgia,
Infantry.Infantry_M4_Georgia,
Infantry.Infantry_AK_74_Rus,
Infantry.Infantry_AK_74_Rus,
Infantry.Infantry_AK_74_Rus,
Infantry.Infantry_AK_74_Rus,
Infantry.Infantry_SMLE_No_4_Mk_1,
Infantry.Infantry_SMLE_No_4_Mk_1,
Infantry.Infantry_SMLE_No_4_Mk_1,
@@ -1500,9 +1490,9 @@ INFANTRY: List[VehicleType] = [
Infantry.Infantry_M1_Garand,
Infantry.Infantry_M1_Garand,
Infantry.Infantry_M1_Garand,
Infantry.Infantry_Soldier_Insurgents,
Infantry.Infantry_Soldier_Insurgents,
Infantry.Infantry_Soldier_Insurgents,
Infantry.Insurgent_AK_74,
Infantry.Insurgent_AK_74,
Infantry.Insurgent_AK_74,
]

View File

@@ -70,6 +70,9 @@ class Faction:
# Possible Missile site generators for this faction
missiles: List[str] = field(default_factory=list)
# Possible costal site generators for this faction
coastal_defenses: List[str] = field(default_factory=list)
# Required mods or asset packs
requirements: Dict[str, str] = field(default_factory=dict)
@@ -100,6 +103,9 @@ class Faction:
# How many missiles group should we try to generate per CP on startup for this faction
missiles_group_count: int = field(default=1)
# How many coastal group should we try to generate per CP on startup for this faction
coastal_group_count: int = field(default=1)
# Whether this faction has JTAC access
has_jtac: bool = field(default=False)
@@ -162,6 +168,7 @@ class Faction:
faction.air_defenses.extend(json.get("shorads", []))
faction.missiles = json.get("missiles", [])
faction.coastal_defenses = json.get("coastal_defenses", [])
faction.requirements = json.get("requirements", {})
faction.carrier_names = json.get("carrier_names", [])
@@ -179,6 +186,7 @@ class Faction:
faction.jtac_unit = None
faction.navy_group_count = int(json.get("navy_group_count", 1))
faction.missiles_group_count = int(json.get("missiles_group_count", 0))
faction.coastal_group_count = int(json.get("coastal_group_count", 0))
# Load doctrine
doctrine = json.get("doctrine", "modern")

View File

@@ -96,6 +96,7 @@ class Game:
self.enemy_name = enemy_name
self.enemy_country = db.FACTIONS[enemy_name].country
self.turn = 0
# NB: This is the *start* date. It is never updated.
self.date = date(start_date.year, start_date.month, start_date.day)
self.game_stats = GameStats()
self.game_stats.update(self)
@@ -152,7 +153,7 @@ class Game:
def generate_conditions(self) -> Conditions:
return Conditions.generate(
self.theater, self.date, self.current_turn_time_of_day, self.settings
self.theater, self.current_day, self.current_turn_time_of_day, self.settings
)
def sanitize_sides(self):
@@ -283,11 +284,18 @@ class Game:
persistency.autosave(self)
def check_win_loss(self):
captured_states = {i.captured for i in self.theater.controlpoints}
if True not in captured_states:
player_airbases = {
cp for cp in self.theater.player_points() if cp.runway_is_operational()
}
if not player_airbases:
return TurnState.LOSS
if False not in captured_states:
enemy_airbases = {
cp for cp in self.theater.enemy_points() if cp.runway_is_operational()
}
if not enemy_airbases:
return TurnState.WIN
return TurnState.CONTINUE
def initialize_turn(self) -> None:

View File

@@ -21,6 +21,10 @@ from game.threatzones import ThreatZones
from game.utils import nautical_miles
class NavMeshError(RuntimeError):
pass
class NavMeshPoly:
def __init__(self, ident: int, poly: Polygon, threatened: bool) -> None:
self.ident = ident
@@ -125,7 +129,7 @@ class NavMesh:
path.append(current.world_point)
previous = came_from[current]
if previous is None:
raise RuntimeError(
raise NavMeshError(
f"Could not reconstruct path to {destination} from {origin}"
)
current = previous
@@ -140,10 +144,12 @@ class NavMesh:
def shortest_path(self, origin: Point, destination: Point) -> List[Point]:
origin_poly = self.localize(origin)
if origin_poly is None:
raise ValueError(f"Origin point {origin} is outside the navmesh")
raise NavMeshError(f"Origin point {origin} is outside the navmesh")
destination_poly = self.localize(destination)
if destination_poly is None:
raise ValueError(f"Origin point {destination} is outside the navmesh")
raise NavMeshError(
f"Destination point {destination} is outside the navmesh"
)
return self._shortest_path(
NavPoint(self.dcs_to_shapely_point(origin), origin_poly),
@@ -203,7 +209,7 @@ class NavMesh:
# threatened airbases at the map edges have room to retreat from the
# threat without running off the navmesh.
return box(*LineString(points).bounds).buffer(
nautical_miles(100).meters, resolution=1
nautical_miles(200).meters, resolution=1
)
@staticmethod

View File

@@ -166,6 +166,7 @@ class Operation:
airgen: AircraftConflictGenerator,
):
"""Generates subscribed MissionInfoGenerator objects (currently kneeboards and briefings)"""
gens: List[MissionInfoGenerator] = [
KneeboardGenerator(cls.current_mission, cls.game),
BriefingGenerator(cls.current_mission, cls.game),
@@ -177,9 +178,8 @@ class Operation:
for tanker in airsupportgen.air_support.tankers:
gen.add_tanker(tanker)
if cls.player_awacs_enabled:
for awacs in airsupportgen.air_support.awacs:
gen.add_awacs(awacs)
for aewc in airsupportgen.air_support.awacs:
gen.add_awacs(aewc)
for jtac in jtacs:
gen.add_jtac(jtac)
@@ -378,7 +378,9 @@ class Operation:
cls.game,
cls.radio_registry,
cls.unit_map,
air_support=cls.airsupportgen.air_support,
)
cls.airgen.clear_parking_slots()
cls.airgen.generate_flights(
@@ -444,6 +446,8 @@ class Operation:
"AWACs": {},
"JTACs": {},
"TargetPoints": {},
"RedAA": {},
"BlueAA": {},
} # type: ignore
for tanker in airsupportgen.air_support.tankers:
@@ -501,6 +505,26 @@ class Operation:
},
}
for cp in cls.game.theater.controlpoints:
for ground_object in cp.ground_objects:
if ground_object.might_have_aa and not ground_object.is_dead:
for g in ground_object.groups:
threat_range = ground_object.threat_range(g)
if not threat_range:
continue
faction = "BlueAA" if cp.captured else "RedAA"
luaData[faction][g.name] = {
"name": ground_object.name,
"range": threat_range.meters,
"position": {
"x": ground_object.position.x,
"y": ground_object.position.y,
},
}
# set a LUA table with data from Liberation that we want to set
# at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function
# later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts
@@ -593,7 +617,33 @@ class Operation:
-- list the aircraft carriers generated by Liberation
-- dcsLiberation.Carriers = {}
-- later, we'll add more data to the table
-- list the Red AA generated by Liberation
dcsLiberation.RedAA = {
"""
for key in luaData["RedAA"]:
data = luaData["RedAA"][key]
name = data["name"]
radius = data["range"]
positionX = data["position"]["x"]
positionY = data["position"]["y"]
lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n"
lua += "}"
lua += """
-- list the Blue AA generated by Liberation
dcsLiberation.BlueAA = {
"""
for key in luaData["BlueAA"]:
data = luaData["BlueAA"][key]
name = data["name"]
radius = data["range"]
positionX = data["position"]["x"]
positionY = data["position"]["y"]
lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n"
lua += "}"
lua += """
"""

View File

@@ -0,0 +1,15 @@
from dcs import Point
class PointWithHeading(Point):
def __init__(self):
super(PointWithHeading, self).__init__(0, 0)
self.heading = 0
@staticmethod
def from_point(point: Point, heading: int):
p = PointWithHeading()
p.x = point.x
p.y = point.y
p.heading = heading
return p

View File

@@ -30,6 +30,8 @@ class Settings:
automate_front_line_reinforcements: bool = False
automate_aircraft_reinforcements: bool = False
restrict_weapons_by_date: bool = False
disable_legacy_aewc: bool = False
generate_dark_kneeboard: bool = False
# Performance oriented
perf_red_alert_state: bool = True

View File

@@ -4,7 +4,7 @@ import math
import typing
from typing import Dict, Type
from dcs.task import CAP, CAS, Embarking, PinpointStrike, Task
from dcs.task import AWACS, CAP, CAS, Embarking, PinpointStrike, Task
from dcs.unittype import FlyingType, UnitType, VehicleType
from dcs.vehicles import AirDefence, Armor
@@ -147,7 +147,12 @@ class Base:
for_task = db.unit_task(unit_type)
target_dict = None
if for_task == CAS or for_task == CAP or for_task == Embarking:
if (
for_task == AWACS
or for_task == CAS
or for_task == CAP
or for_task == Embarking
):
target_dict = self.aircraft
elif for_task == PinpointStrike:
target_dict = self.armor

View File

@@ -23,7 +23,7 @@ from dcs.planes import F_15C
from dcs.ships import (
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
USS_Arleigh_Burke_IIa,
DDG_Arleigh_Burke_IIa,
)
from dcs.statics import Fortification
from dcs.terrain import (
@@ -55,6 +55,7 @@ from .controlpoint import (
Fob,
)
from .landmap import Landmap, load_landmap, poly_contains
from ..point_with_heading import PointWithHeading
from ..utils import Distance, meters, nautical_miles
Numeric = Union[int, float]
@@ -92,30 +93,33 @@ class MizCampaignLoader:
LHA_UNIT_TYPE = LHA_1_Tarawa.id
FRONT_LINE_UNIT_TYPE = Armor.APC_M113.id
FOB_UNIT_TYPE = Unarmed.CP_SKP_11_ATC_Mobile_Command_Post.id
FOB_UNIT_TYPE = Unarmed.Truck_SKP_11_Mobile_ATC.id
FARP_HELIPAD = "SINGLE_HELIPAD"
EWR_UNIT_TYPE = AirDefence.EWR_55G6.id
SAM_UNIT_TYPE = AirDefence.SAM_SA_10_S_300PS_SR_64H6E.id
GARRISON_UNIT_TYPE = AirDefence.SAM_SA_19_Tunguska_2S6.id
SAM_UNIT_TYPE = AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR.id
GARRISON_UNIT_TYPE = AirDefence.SAM_SA_19_Tunguska_Grison.id
OFFSHORE_STRIKE_TARGET_UNIT_TYPE = Fortification.Oil_platform.id
SHIP_UNIT_TYPE = USS_Arleigh_Burke_IIa.id
MISSILE_SITE_UNIT_TYPE = MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M.id
COASTAL_DEFENSE_UNIT_TYPE = MissilesSS.SS_N_2_Silkworm.id
SHIP_UNIT_TYPE = DDG_Arleigh_Burke_IIa.id
MISSILE_SITE_UNIT_TYPE = MissilesSS.SSM_SS_1C_Scud_B.id
COASTAL_DEFENSE_UNIT_TYPE = MissilesSS.AShM_SS_N_2_Silkworm.id
# Multiple options for the required SAMs so campaign designers can more
# accurately see the coverage of their IADS for the expected type.
REQUIRED_LONG_RANGE_SAM_UNIT_TYPES = {
AirDefence.SAM_Patriot_LN_M901.id,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C.id,
AirDefence.SAM_SA_10_S_300PS_LN_5P85D.id,
AirDefence.SAM_Patriot_LN.id,
AirDefence.SAM_SA_10_S_300_Grumble_TEL_C.id,
AirDefence.SAM_SA_10_S_300_Grumble_TEL_D.id,
}
REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES = {
AirDefence.SAM_Hawk_LN_M192.id,
AirDefence.SAM_SA_2_LN_SM_90.id,
AirDefence.SAM_SA_3_S_125_LN_5P73.id,
AirDefence.SAM_SA_2_S_75_Guideline_LN.id,
AirDefence.SAM_SA_3_S_125_Goa_LN.id,
}
REQUIRED_EWR_UNIT_TYPE = AirDefence.EWR_1L13.id
BASE_DEFENSE_RADIUS = nautical_miles(2)
def __init__(self, miz: Path, theater: ConflictTheater) -> None:
@@ -245,6 +249,18 @@ class MizCampaignLoader:
if group.units[0].type in self.REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES:
yield group
@property
def required_ewrs(self) -> Iterator[VehicleGroup]:
for group in self.red.vehicle_group:
if group.units[0].type in self.REQUIRED_EWR_UNIT_TYPE:
yield group
@property
def helipads(self) -> Iterator[StaticGroup]:
for group in self.blue.static_group:
if group.units[0].type == self.FARP_HELIPAD:
yield group
@cached_property
def control_points(self) -> Dict[int, ControlPoint]:
control_points = {}
@@ -270,7 +286,7 @@ class MizCampaignLoader:
control_point.captured_invert = group.late_activation
control_points[control_point.id] = control_point
for group in self.lhas(blue):
# TODO: Name the LHA.
# TODO: Name the LHA.db
control_point = Lha("lha", group.position, next(self.control_point_id))
control_point.captured = blue
control_point.captured_invert = group.late_activation
@@ -329,44 +345,81 @@ class MizCampaignLoader:
for group in self.garrisons:
closest, distance = self.objective_info(group)
if distance < self.BASE_DEFENSE_RADIUS:
closest.preset_locations.base_garrisons.append(group.position)
closest.preset_locations.base_garrisons.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
else:
logging.warning(f"Found garrison unit too far from base: {group.name}")
for group in self.sams:
closest, distance = self.objective_info(group)
if distance < self.BASE_DEFENSE_RADIUS:
closest.preset_locations.base_air_defense.append(group.position)
closest.preset_locations.base_air_defense.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
else:
closest.preset_locations.strike_locations.append(group.position)
closest.preset_locations.strike_locations.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.ewrs:
closest, distance = self.objective_info(group)
closest.preset_locations.ewrs.append(group.position)
if distance < self.BASE_DEFENSE_RADIUS:
closest.preset_locations.ewrs.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
else:
closest.preset_locations.ewrs.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.offshore_strike_targets:
closest, distance = self.objective_info(group)
closest.preset_locations.offshore_strike_locations.append(group.position)
closest.preset_locations.offshore_strike_locations.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.ships:
closest, distance = self.objective_info(group)
closest.preset_locations.ships.append(group.position)
closest.preset_locations.ships.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.missile_sites:
closest, distance = self.objective_info(group)
closest.preset_locations.missile_sites.append(group.position)
closest.preset_locations.missile_sites.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.coastal_defenses:
closest, distance = self.objective_info(group)
closest.preset_locations.coastal_defenses.append(group.position)
closest.preset_locations.coastal_defenses.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.required_long_range_sams:
closest, distance = self.objective_info(group)
closest.preset_locations.required_long_range_sams.append(group.position)
closest.preset_locations.required_long_range_sams.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.required_medium_range_sams:
closest, distance = self.objective_info(group)
closest.preset_locations.required_medium_range_sams.append(group.position)
closest.preset_locations.required_medium_range_sams.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.required_ewrs:
closest, distance = self.objective_info(group)
closest.preset_locations.required_ewrs.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.helipads:
closest, distance = self.objective_info(group)
closest.helipads.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
def populate_theater(self) -> None:
for control_point in self.control_points.values():
@@ -677,8 +730,8 @@ class PersianGulfTheater(ConflictTheater):
terrain = persiangulf.PersianGulf()
overview_image = "persiangulf.gif"
reference_points = (
ReferencePoint(persiangulf.Jiroft_Airport.position, Point(1692, 1343)),
ReferencePoint(persiangulf.Liwa_Airbase.position, Point(358, 3238)),
ReferencePoint(persiangulf.Jiroft.position, Point(1692, 1343)),
ReferencePoint(persiangulf.Liwa_AFB.position, Point(358, 3238)),
)
landmap = load_landmap("resources\\gulflandmap.p")
daytime_map = {
@@ -811,6 +864,7 @@ class FrontLine(MissionTarget):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
yield from [
FlightType.CAS,
FlightType.AEWC,
# TODO: FlightType.TROOP_TRANSPORT
# TODO: FlightType.EVAC
]

View File

@@ -4,7 +4,6 @@ import heapq
import itertools
import logging
import random
import re
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
@@ -28,6 +27,7 @@ from gen.ground_forces.combat_stance import CombatStance
from gen.runways import RunwayAssigner, RunwayData
from .base import Base
from .missiontarget import MissionTarget
from game.point_with_heading import PointWithHeading
from .theatergroundobject import (
BaseDefenseGroundObject,
EwrGroundObject,
@@ -77,38 +77,41 @@ class PresetLocations:
"""Defines the preset locations loaded from the campaign mission file."""
#: Locations used for spawning ground defenses for bases.
base_garrisons: List[Point] = field(default_factory=list)
base_garrisons: List[PointWithHeading] = field(default_factory=list)
#: Locations used for spawning air defenses for bases. Used by SAMs, AAA,
#: and SHORADs.
base_air_defense: List[Point] = field(default_factory=list)
base_air_defense: List[PointWithHeading] = field(default_factory=list)
#: Locations used by EWRs.
ewrs: List[Point] = field(default_factory=list)
ewrs: List[PointWithHeading] = field(default_factory=list)
#: Locations used by non-carrier ships. Carriers and LHAs are not random.
ships: List[Point] = field(default_factory=list)
ships: List[PointWithHeading] = field(default_factory=list)
#: Locations used by coastal defenses.
coastal_defenses: List[Point] = field(default_factory=list)
coastal_defenses: List[PointWithHeading] = field(default_factory=list)
#: Locations used by ground based strike objectives.
strike_locations: List[Point] = field(default_factory=list)
strike_locations: List[PointWithHeading] = field(default_factory=list)
#: Locations used by offshore strike objectives.
offshore_strike_locations: List[Point] = field(default_factory=list)
offshore_strike_locations: List[PointWithHeading] = field(default_factory=list)
#: Locations used by missile sites like scuds and V-2s.
missile_sites: List[Point] = field(default_factory=list)
missile_sites: List[PointWithHeading] = field(default_factory=list)
#: Locations of long range SAMs which should always be spawned.
required_long_range_sams: List[Point] = field(default_factory=list)
required_long_range_sams: List[PointWithHeading] = field(default_factory=list)
#: Locations of medium range SAMs which should always be spawned.
required_medium_range_sams: List[Point] = field(default_factory=list)
required_medium_range_sams: List[PointWithHeading] = field(default_factory=list)
#: Locations of EWRs which should always be spawned.
required_ewrs: List[PointWithHeading] = field(default_factory=list)
@staticmethod
def _random_from(points: List[Point]) -> Optional[Point]:
def _random_from(points: List[PointWithHeading]) -> Optional[PointWithHeading]:
"""Finds, removes, and returns a random position from the given list."""
if not points:
return None
@@ -116,7 +119,7 @@ class PresetLocations:
points.remove(point)
return point
def random_for(self, location_type: LocationType) -> Optional[Point]:
def random_for(self, location_type: LocationType) -> Optional[PointWithHeading]:
"""Returns a position suitable for the given location type.
The location, if found, will be claimed by the caller and not available
@@ -250,6 +253,7 @@ class ControlPoint(MissionTarget, ABC):
self.connected_objectives: List[TheaterGroundObject] = []
self.base_defenses: List[BaseDefenseGroundObject] = []
self.preset_locations = PresetLocations()
self.helipads: List[PointWithHeading] = []
# TODO: Should be Airbase specific.
self.size = size
@@ -386,18 +390,19 @@ class ControlPoint(MissionTarget, ABC):
# TODO: Should be Airbase specific.
def clear_base_defenses(self) -> None:
for base_defense in self.base_defenses:
p = PointWithHeading.from_point(base_defense.position, base_defense.heading)
if isinstance(base_defense, EwrGroundObject):
self.preset_locations.ewrs.append(base_defense.position)
self.preset_locations.ewrs.append(p)
elif isinstance(base_defense, SamGroundObject):
self.preset_locations.base_air_defense.append(base_defense.position)
self.preset_locations.base_air_defense.append(p)
elif isinstance(base_defense, VehicleGroupGroundObject):
self.preset_locations.base_garrisons.append(base_defense.position)
self.preset_locations.base_garrisons.append(p)
else:
logging.error(
"Could not determine preset location type for "
f"{base_defense}. Assuming garrison type."
)
self.preset_locations.base_garrisons.append(base_defense.position)
self.preset_locations.base_garrisons.append(p)
self.base_defenses = []
def capture_equipment(self, game: Game) -> None:
@@ -633,6 +638,15 @@ class ControlPoint(MissionTarget, ABC):
def income_per_turn(self) -> int:
return 0
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
if self.is_friendly(for_player):
yield from [
FlightType.AEWC,
]
yield from super().mission_types(for_player)
@property
def has_active_frontline(self) -> bool:
return any(not c.is_friendly(self.captured) for c in self.connected_points)

View File

@@ -13,7 +13,7 @@ from dcs.vehicles import AirDefence
from game import Game, db
from game.factions.faction import Faction
from game.theater import Carrier, Lha, LocationType
from game.theater import Carrier, Lha, LocationType, PointWithHeading
from game.theater.theatergroundobject import (
BuildingGroundObject,
CarrierGroundObject,
@@ -23,9 +23,11 @@ from game.theater.theatergroundobject import (
SamGroundObject,
ShipGroundObject,
VehicleGroupGroundObject,
CoastalSiteGroundObject,
)
from game.version import VERSION
from gen import namegen
from gen.coastal.coastal_group_generator import generate_coastal_group
from gen.defenses.armor_group_generator import generate_armor_group
from gen.fleet.ship_group_generator import (
generate_carrier_group,
@@ -35,10 +37,8 @@ from gen.fleet.ship_group_generator import (
from gen.locations.preset_location_finder import MizDataLocationFinder
from gen.missiles.missiles_group_generator import generate_missile_group
from gen.sam.airdefensegroupgenerator import AirDefenseRange
from gen.sam.sam_group_generator import (
generate_anti_air_group,
generate_ewr_group,
)
from gen.sam.sam_group_generator import generate_anti_air_group
from gen.sam.ewr_group_generator import generate_ewr_group
from . import (
ConflictTheater,
ControlPoint,
@@ -148,13 +148,13 @@ class LocationFinder:
game.theater.terrain.name, control_point.full_name
)
def location_for(self, location_type: LocationType) -> Optional[Point]:
def location_for(self, location_type: LocationType) -> Optional[PointWithHeading]:
position = self.control_point.preset_locations.random_for(location_type)
if position is not None:
return position
logging.warning(
f"No campaign location for %s at %s",
f"No campaign location for %s Mat %s",
location_type.value,
self.control_point,
)
@@ -178,7 +178,7 @@ class LocationFinder:
)
return None
def random_from_miz_data(self, offshore: bool) -> Optional[Point]:
def random_from_miz_data(self, offshore: bool) -> Optional[PointWithHeading]:
if offshore:
locations = self.miz_data.offshore_locations
else:
@@ -186,11 +186,18 @@ class LocationFinder:
if self.miz_data.offshore_locations:
preset = random.choice(locations)
locations.remove(preset)
return preset.position
return PointWithHeading.from_point(preset.position, preset.heading)
return None
def random_position(self, location_type: LocationType) -> Optional[Point]:
def random_position(
self, location_type: LocationType
) -> Optional[PointWithHeading]:
# TODO: Flesh out preset locations so we never hit this case.
if location_type == LocationType.Coastal:
# No coastal locations generated randomly
return None
logging.warning(
"Falling back to random location for %s at %s",
location_type.value,
@@ -250,7 +257,7 @@ class LocationFinder:
on_ground: bool,
is_base_defense: bool,
avoid_others: bool,
) -> Optional[Point]:
) -> Optional[PointWithHeading]:
"""
Find a valid ground object location
:param on_ground: Whether it should be on ground or on sea (True = on
@@ -263,7 +270,7 @@ class LocationFinder:
near = self.control_point.position
others = self.control_point.ground_objects
def is_valid(point: Optional[Point]) -> bool:
def is_valid(point: Optional[PointWithHeading]) -> bool:
if point is None:
return False
@@ -294,7 +301,9 @@ class LocationFinder:
for _ in range(300):
# Check if on land or sea
p = near.random_point_within(max_range, min_range)
p = PointWithHeading.from_point(
near.random_point_within(max_range, min_range), random.randint(0, 360)
)
if is_valid(p):
return p
return None
@@ -453,7 +462,11 @@ class BaseDefenseGenerator:
group_id = self.game.next_group_id()
g = EwrGroundObject(
namegen.random_objective_name(), group_id, position, self.control_point
namegen.random_objective_name(),
group_id,
position,
self.control_point,
True,
)
group = generate_ewr_group(self.game, g, self.faction)
@@ -590,11 +603,15 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
if self.faction.missiles:
self.generate_missile_sites()
if self.faction.coastal_defenses:
self.generate_coastal_sites()
return True
def generate_ground_points(self) -> None:
"""Generate ground objects and AA sites for the control point."""
skip_sams = self.generate_required_aa()
skip_ewrs = self.generate_required_ewr()
if self.control_point.is_global:
return
@@ -611,6 +628,12 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
skip_sams -= 1
else:
self.generate_aa_site()
# 1 in 4 additional objectives are EWR.
elif random.randint(0, 3) == 0:
if skip_ewrs > 0:
skip_ewrs -= 1
else:
self.generate_ewr_site()
else:
self.generate_ground_point()
@@ -642,6 +665,17 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
presets.required_medium_range_sams
)
def generate_required_ewr(self) -> int:
"""Generates the EWR sites that are required by the campaign.
Returns:
The number of EWR sites that were generated.
"""
presets = self.control_point.preset_locations
for position in presets.required_ewrs:
self.generate_ewr_at(position)
return len(presets.required_ewrs)
def generate_ground_point(self) -> None:
try:
category = random.choice(self.faction.building_set)
@@ -719,6 +753,33 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
g.groups = groups
self.control_point.connected_objectives.append(g)
def generate_ewr_site(self) -> None:
position = self.location_finder.location_for(LocationType.Ewr)
if position is None:
return
self.generate_ewr_at(position)
def generate_ewr_at(self, position: Point) -> None:
group_id = self.game.next_group_id()
g = EwrGroundObject(
namegen.random_objective_name(),
group_id,
position,
self.control_point,
for_airbase=False,
)
group = generate_ewr_group(self.game, g, self.faction)
if group is None:
logging.error(
"Could not generate ewr group for %s at %s",
g.name,
self.control_point,
)
return
g.groups = [group]
self.control_point.connected_objectives.append(g)
def generate_missile_sites(self) -> None:
for i in range(self.faction.missiles_group_count):
self.generate_missile_site()
@@ -740,6 +801,31 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
self.control_point.connected_objectives.append(g)
return
def generate_coastal_sites(self) -> None:
for i in range(self.faction.coastal_group_count):
self.generate_coastal_site()
def generate_coastal_site(self) -> None:
position = self.location_finder.location_for(LocationType.Coastal)
if position is None:
return
group_id = self.game.next_group_id()
g = CoastalSiteGroundObject(
namegen.random_objective_name(),
group_id,
position,
self.control_point,
position.heading,
)
group = generate_coastal_group(self.game, g, self.faction_name)
g.groups = []
if group is not None:
g.groups.append(group)
self.control_point.connected_objectives.append(g)
return
class FobGroundObjectGenerator(AirbaseGroundObjectGenerator):
def generate(self) -> bool:

View File

@@ -344,6 +344,28 @@ class MissileSiteGroundObject(TheaterGroundObject):
)
class CoastalSiteGroundObject(TheaterGroundObject):
def __init__(
self,
name: str,
group_id: int,
position: Point,
control_point: ControlPoint,
heading,
) -> None:
super().__init__(
name=name,
category="aa",
group_id=group_id,
position=position,
heading=heading,
control_point=control_point,
dcs_identifier="AA",
airbase_group=False,
sea_object=False,
)
class BaseDefenseGroundObject(TheaterGroundObject):
"""Base type for all base defenses."""
@@ -420,7 +442,12 @@ class VehicleGroupGroundObject(BaseDefenseGroundObject):
class EwrGroundObject(BaseDefenseGroundObject):
def __init__(
self, name: str, group_id: int, position: Point, control_point: ControlPoint
self,
name: str,
group_id: int,
position: Point,
control_point: ControlPoint,
for_airbase: bool,
) -> None:
super().__init__(
name=name,
@@ -430,7 +457,7 @@ class EwrGroundObject(BaseDefenseGroundObject):
heading=0,
control_point=control_point,
dcs_identifier="EWR",
airbase_group=True,
airbase_group=for_airbase,
sea_object=False,
)

View File

@@ -15,6 +15,7 @@ from shapely.ops import nearest_points, unary_union
from game.theater import ControlPoint
from game.utils import Distance, meters, nautical_miles
from gen import Conflict
from gen.flights.closestairfields import ObjectiveDistanceCache
from gen.flights.flight import Flight
@@ -131,7 +132,7 @@ class ThreatZones:
zone belongs to the player, it is the zone that will be avoided by
the enemy and vice versa.
"""
airbases = []
air_threats = []
air_defenses = []
for control_point in game.theater.controlpoints:
if control_point.captured != player:
@@ -139,7 +140,7 @@ class ThreatZones:
if control_point.runway_is_operational():
point = ShapelyPoint(control_point.position.x, control_point.position.y)
cap_threat_range = cls.barcap_threat_range(game, control_point)
airbases.append(point.buffer(cap_threat_range.meters))
air_threats.append(point.buffer(cap_threat_range.meters))
for tgo in control_point.ground_objects:
for group in tgo.groups:
@@ -151,8 +152,25 @@ class ThreatZones:
threat_zone = point.buffer(threat_range.meters)
air_defenses.append(threat_zone)
for front_line in game.theater.conflicts(player):
vector = Conflict.frontline_vector(
front_line.control_point_a, front_line.control_point_b, game.theater
)
start = vector[0]
end = vector[0].point_from_heading(vector[1], vector[2])
line = LineString(
[
ShapelyPoint(start.x, start.y),
ShapelyPoint(end.x, end.y),
]
)
doctrine = game.faction_for(player).doctrine
air_threats.append(line.buffer(doctrine.cap_engagement_range.meters))
return cls(
airbases=unary_union(airbases), air_defenses=unary_union(air_defenses)
airbases=unary_union(air_threats), air_defenses=unary_union(air_defenses)
)
@staticmethod

View File

@@ -2,7 +2,7 @@ from pathlib import Path
def _build_version_string() -> str:
components = ["2.4.4"]
components = ["2.5"]
build_number_path = Path("resources/buildnumber")
if build_number_path.exists():
with build_number_path.open("r") as build_number_file:

View File

@@ -3,11 +3,12 @@ from __future__ import annotations
import datetime
import logging
import random
from dataclasses import dataclass
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, TYPE_CHECKING
from dcs.weather import Weather as PydcsWeather, Wind
from dcs.cloud_presets import Clouds as PydcsClouds
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
from game.settings import Settings
from game.utils import Distance, meters
@@ -36,6 +37,23 @@ class Clouds:
density: int
thickness: int
precipitation: PydcsWeather.Preceptions
preset: Optional[CloudPreset] = field(default=None)
@classmethod
def random_preset(cls, rain: bool) -> Clouds:
clouds = (p.value for p in PydcsClouds)
if rain:
presets = [p for p in clouds if "Rain" in p.name]
else:
presets = [p for p in clouds if "Rain" not in p.name]
preset = random.choice(presets)
return Clouds(
base=random.randint(preset.min_base, preset.max_base),
density=0,
thickness=0,
precipitation=PydcsWeather.Preceptions.None_,
preset=preset,
)
@dataclass(frozen=True)
@@ -101,12 +119,11 @@ class ClearSkies(Weather):
class Cloudy(Weather):
def generate_clouds(self) -> Optional[Clouds]:
return Clouds(
base=self.random_cloud_base(),
density=random.randint(1, 8),
thickness=self.random_cloud_thickness(),
precipitation=PydcsWeather.Preceptions.None_,
)
return Clouds.random_preset(rain=False)
def generate_fog(self) -> Optional[Fog]:
# DCS 2.7 says to not use fog with the cloud presets.
return None
def generate_wind(self) -> WindConditions:
return self.random_wind(0, 4)
@@ -114,12 +131,11 @@ class Cloudy(Weather):
class Raining(Weather):
def generate_clouds(self) -> Optional[Clouds]:
return Clouds(
base=self.random_cloud_base(),
density=random.randint(5, 8),
thickness=self.random_cloud_thickness(),
precipitation=PydcsWeather.Preceptions.Rain,
)
return Clouds.random_preset(rain=True)
def generate_fog(self) -> Optional[Fog]:
# DCS 2.7 says to not use fog with the cloud presets.
return None
def generate_wind(self) -> WindConditions:
return self.random_wind(0, 6)

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
import random
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import timedelta
from functools import cached_property
from typing import Dict, List, Optional, TYPE_CHECKING, Type, Union
@@ -41,6 +41,7 @@ from dcs.planes import (
)
from dcs.point import MovingPoint, PointAction
from dcs.task import (
AWACS,
AntishipStrike,
AttackGroup,
Bombing,
@@ -66,6 +67,8 @@ from dcs.task import (
Targets,
Task,
WeaponType,
AWACSTaskAction,
SetFrequencyCommand,
)
from dcs.terrain.terrain import Airport, NoParkingSlotError
from dcs.triggers import Event, TriggerOnce, TriggerRule
@@ -87,10 +90,8 @@ from game.theater.controlpoint import (
from game.theater.theatergroundobject import TheaterGroundObject
from game.unitmap import UnitMap
from game.utils import Distance, meters, nautical_miles
from gen.airsupportgen import AirSupport
from gen.ato import AirTaskingOrder, Package
from gen.callsigns import create_group_callsign_from_unit
from gen.conflictgen import FRONTLINE_LENGTH
from gen.flights.flight import (
Flight,
FlightType,
@@ -104,9 +105,12 @@ from .flights.flightplan import (
LoiterFlightPlan,
PatrollingFlightPlan,
SweepFlightPlan,
AwacsFlightPlan,
)
from .flights.traveltime import GroundSpeed, TotEstimator
from .naming import namegen
from .airsupportgen import AirSupport, AwacsInfo
from .callsigns import callsign_for_support_unit
if TYPE_CHECKING:
from game import Game
@@ -134,6 +138,7 @@ TARGET_WAYPOINTS = (
FlightWaypointType.TARGET_SHIP,
)
# TODO: Get radio information for all the special cases.
def get_fallback_channel(unit_type: UnitType) -> RadioFrequency:
if unit_type in helicopter_map.values() and unit_type != UH_1H:
@@ -318,6 +323,7 @@ class FlightData:
intra_flight_channel: RadioFrequency,
bingo_fuel: Optional[int],
joker_fuel: Optional[int],
custom_name: Optional[str],
) -> None:
self.package = package
self.country = country
@@ -335,6 +341,7 @@ class FlightData:
self.bingo_fuel = bingo_fuel
self.joker_fuel = joker_fuel
self.callsign = create_group_callsign_from_unit(self.units[0])
self.custom_name = custom_name
@property
def client_units(self) -> List[FlyingUnit]:
@@ -669,6 +676,7 @@ class AircraftConflictGenerator:
game: Game,
radio_registry: RadioRegistry,
unit_map: UnitMap,
air_support: AirSupport,
) -> None:
self.m = mission
self.game = game
@@ -676,6 +684,7 @@ class AircraftConflictGenerator:
self.radio_registry = radio_registry
self.unit_map = unit_map
self.flights: List[FlightData] = []
self.air_support = air_support
@cached_property
def use_client(self) -> bool:
@@ -790,7 +799,10 @@ class AircraftConflictGenerator:
OptReactOnThreat(OptReactOnThreat.Values.EvadeFire)
)
channel = self.get_intra_flight_channel(unit_type)
if flight.flight_type == FlightType.AEWC:
channel = self.radio_registry.alloc_uhf()
else:
channel = self.get_intra_flight_channel(unit_type)
group.set_frequency(channel.mhz)
divert = None
@@ -819,6 +831,7 @@ class AircraftConflictGenerator:
intra_flight_channel=channel,
bingo_fuel=flight.flight_plan.bingo_fuel,
joker_fuel=flight.flight_plan.joker_fuel,
custom_name=flight.custom_name,
)
)
@@ -826,6 +839,20 @@ class AircraftConflictGenerator:
if unit_type in [Su_33, C_101EB, C_101CC]:
self.set_reduced_fuel(flight, group, unit_type)
if isinstance(flight.flight_plan, AwacsFlightPlan):
callsign = callsign_for_support_unit(group)
self.air_support.awacs.append(
AwacsInfo(
dcsGroupName=str(group.name),
callsign=callsign,
freq=channel,
depature_location=flight.departure.name,
end_time=flight.flight_plan.mission_departure_time,
start_time=flight.flight_plan.mission_start_time,
)
)
def _generate_at_airport(
self,
name: str,
@@ -1350,6 +1377,33 @@ class AircraftConflictGenerator:
restrict_jettison=True,
)
def configure_awacs(
self,
group: FlyingGroup,
package: Package,
flight: Flight,
dynamic_runways: Dict[str, RunwayData],
) -> None:
group.task = AWACS.name
if not isinstance(flight.flight_plan, AwacsFlightPlan):
logging.error(
f"Cannot configure AEW&C tasks for {flight} because it does not have an AEW&C flight plan."
)
return
self._setup_group(group, AWACS, package, flight, dynamic_runways)
# Awacs task action
self.configure_behavior(
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.WeaponHold,
restrict_jettison=True,
)
group.points[0].tasks.append(AWACSTaskAction())
def configure_escort(
self,
group: FlyingGroup,
@@ -1386,6 +1440,8 @@ class AircraftConflictGenerator:
self.configure_cap(group, package, flight, dynamic_runways)
elif flight_type == FlightType.SWEEP:
self.configure_sweep(group, package, flight, dynamic_runways)
elif flight_type == FlightType.AEWC:
self.configure_awacs(group, package, flight, dynamic_runways)
elif flight_type in [FlightType.CAS, FlightType.BAI]:
self.configure_cas(group, package, flight, dynamic_runways)
elif flight_type == FlightType.DEAD:

View File

@@ -383,8 +383,8 @@ AIRFIELD_DATA = {
"31": ("IVZ", MHz(108, 750)),
},
),
# TODO : PERSIAN GULF MAP
"Liwa Airbase": AirfieldData(
# PERSIAN GULF MAP
"Liwa AFB": AirfieldData(
theater="Persian Gulf",
icao="OMLW",
elevation=400,
@@ -394,7 +394,7 @@ AIRFIELD_DATA = {
vor=("OMLW", MHz(117, 400)),
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(119, 300), MHz(250, 950)),
),
"Al Dhafra AB": AirfieldData(
"Al Dhafra AFB": AirfieldData(
theater="Persian Gulf",
icao="OMAM",
elevation=52,
@@ -402,50 +402,50 @@ AIRFIELD_DATA = {
tacan=TacanChannel(96, TacanBand.X),
tacan_callsign="MA",
vor=("MA", MHz(114, 900)),
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(126, 500), MHz(251, 000)),
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(126, 500), MHz(251, 100)),
ils={
"13": ("MMA", MHz(111, 100)),
"31": ("IMA", MHz(109, 100)),
},
),
"Al-Bateen Airport": AirfieldData(
"Al-Bateen": AirfieldData(
theater="Persian Gulf",
icao="OMAD",
elevation=11,
runway_length=6808,
vor=("ALB", MHz(114, 0)),
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(119, 900), MHz(250, 550)),
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 900), MHz(250, 600)),
),
"Sas Al Nakheel Airport": AirfieldData(
"Sas Al Nakheel": AirfieldData(
theater="Persian Gulf",
icao="OMNK",
elevation=9,
runway_length=5387,
vor=("SAS", MHz(128, 930)),
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(128, 900), MHz(250, 450)),
atc=AtcData(MHz(4, 0), MHz(38, 900), MHz(128, 900), MHz(250, 450)),
),
"Abu Dhabi International Airport": AirfieldData(
"Abu Dhabi Intl": AirfieldData(
theater="Persian Gulf",
icao="OMAA",
elevation=91,
runway_length=12817,
vor=("ADV", MHz(114, 250)),
atc=AtcData(MHz(4, 000), MHz(38, 900), MHz(119, 200), MHz(250, 500)),
atc=AtcData(MHz(4, 50), MHz(39, 0), MHz(119, 200), MHz(250, 550)),
),
"Al Ain International Airport": AirfieldData(
"Al Ain Intl": AirfieldData(
theater="Persian Gulf",
icao="OMAL",
elevation=813,
runway_length=11267,
vor=("ALN", MHz(112, 600)),
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 850), MHz(250, 650)),
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(119, 850), MHz(250, 700)),
),
"Al Maktoum Intl": AirfieldData(
theater="Persian Gulf",
icao="OMDW",
elevation=123,
runway_length=11500,
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(118, 650), MHz(251, 100)),
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(118, 600), MHz(251, 200)),
ils={
"30": ("IJWA", MHz(109, 750)),
"12": ("IMA", MHz(111, 750)),
@@ -458,7 +458,7 @@ AIRFIELD_DATA = {
runway_length=11865,
tacan=TacanChannel(99, TacanBand.X),
tacan_callsign="MIN",
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(121, 800), MHz(250, 100)),
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(118, 550), MHz(250, 100)),
ils={
"27": ("IMNR", MHz(110, 750)),
"9": ("IMNW", MHz(110, 700)),
@@ -469,7 +469,7 @@ AIRFIELD_DATA = {
icao="OMDB",
elevation=16,
runway_length=11018,
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(118, 750), MHz(251, 50)),
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(118, 750), MHz(251, 150)),
ils={
"30": ("IDBL", MHz(110, 900)),
"12": ("IDBR", MHz(110, 100)),
@@ -480,7 +480,7 @@ AIRFIELD_DATA = {
icao="OMSJ",
elevation=98,
runway_length=10535,
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(118, 600), MHz(252, 200)),
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(118, 600), MHz(250, 200)),
ils={
"30": ("ISHW", MHz(111, 950)),
"12": ("ISRE", MHz(108, 550)),
@@ -492,18 +492,18 @@ AIRFIELD_DATA = {
elevation=60,
runway_length=9437,
vor=("FJV", MHz(113, 800)),
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(124, 600), MHz(251, 150)),
atc=AtcData(MHz(4, 375), MHz(39, 650), MHz(124, 600), MHz(251, 250)),
ils={
"29": ("IFJR", MHz(111, 500)),
},
),
"Ras AL Khaimah": AirfieldData(
"Ras Al Khaimah Intl": AirfieldData(
theater="Persian Gulf",
icao="OMRK",
elevation=70,
runway_length=8406,
vor=("OMRK", MHz(113, 600)),
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(121, 600), MHz(250, 800)),
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(121, 600), MHz(250, 900)),
),
"Khasab": AirfieldData(
theater="Persian Gulf",
@@ -516,7 +516,11 @@ AIRFIELD_DATA = {
},
),
"Sir Abu Nuayr": AirfieldData(
theater="Persian Gulf", icao="OMSN", elevation=25, runway_length=2229
theater="Persian Gulf",
icao="OMSN",
elevation=25,
runway_length=2229,
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(118, 0), MHz(250, 800)),
),
"Sirri Island": AirfieldData(
theater="Persian Gulf",
@@ -526,7 +530,7 @@ AIRFIELD_DATA = {
vor=("SIR", MHz(113, 750)),
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(135, 50), MHz(250, 250)),
),
"Abu Musa Island Airport": AirfieldData(
"Abu Musa Island": AirfieldData(
theater="Persian Gulf",
icao="OIBA",
elevation=16,
@@ -555,13 +559,13 @@ AIRFIELD_DATA = {
vor=("KHM", MHz(117, 100)),
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(118, 50), MHz(250, 150)),
),
"Bandar-e-Jask airfield": AirfieldData(
"Bandar-e-Jask": AirfieldData(
theater="Persian Gulf",
icao="OIZJ",
elevation=26,
runway_length=6842,
vor=("KHM", MHz(116, 300)),
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(118, 50), MHz(250, 150)),
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(118, 150), MHz(250, 500)),
),
"Bandar Lengeh": AirfieldData(
theater="Persian Gulf",
@@ -569,26 +573,26 @@ AIRFIELD_DATA = {
elevation=80,
runway_length=7625,
vor=("LEN", MHz(114, 800)),
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 700), MHz(250, 950)),
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(121, 700), MHz(251, 50)),
),
"Kish International Airport": AirfieldData(
"Kish Intl": AirfieldData(
theater="Persian Gulf",
icao="OIBK",
elevation=114,
runway_length=10617,
tacan=TacanChannel(112, TacanBand.X),
tacan_callsign="KIH",
atc=AtcData(MHz(4, 50), MHz(39, 000), MHz(121, 650), MHz(250, 600)),
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(121, 650), MHz(250, 650)),
),
"Lavan Island Airport": AirfieldData(
"Lavan Island": AirfieldData(
theater="Persian Gulf",
icao="OIBV",
elevation=75,
runway_length=8234,
vor=("LVA", MHz(116, 850)),
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(128, 550), MHz(250, 700)),
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(128, 550), MHz(250, 750)),
),
"Lar Airbase": AirfieldData(
"Lar": AirfieldData(
theater="Persian Gulf",
icao="OISL",
elevation=2635,
@@ -603,7 +607,7 @@ AIRFIELD_DATA = {
runway_length=7300,
tacan=TacanChannel(47, TacanBand.X),
tacan_callsign="HDR",
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(123, 150), MHz(251, 200)),
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(123, 150), MHz(251, 300)),
ils={
"8": ("IBHD", MHz(108, 900)),
},
@@ -616,19 +620,19 @@ AIRFIELD_DATA = {
tacan=TacanChannel(78, TacanBand.X),
tacan_callsign="BND",
vor=("BND", MHz(117, 200)),
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(118, 100), MHz(250, 900)),
atc=AtcData(MHz(4, 250), MHz(39, 401), MHz(118, 100), MHz(251, 0)),
ils={
"21": ("IBND", MHz(333, 800)),
},
),
"Jiroft Airport": AirfieldData(
"Jiroft": AirfieldData(
theater="Persian Gulf",
icao="OIKJ",
elevation=2664,
runway_length=9160,
atc=AtcData(MHz(4, 125), MHz(39, 120), MHz(136, 0), MHz(250, 750)),
),
"Kerman Airport": AirfieldData(
"Kerman": AirfieldData(
theater="Persian Gulf",
icao="OIKK",
elevation=5746,
@@ -636,9 +640,9 @@ AIRFIELD_DATA = {
tacan=TacanChannel(97, TacanBand.X),
tacan_callsign="KER",
vor=("KER", MHz(112, 0)),
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(118, 250), MHz(250, 300)),
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 250), MHz(250, 300)),
),
"Shiraz International Airport": AirfieldData(
"Shiraz Intl": AirfieldData(
theater="Persian Gulf",
icao="OISS",
elevation=4878,
@@ -646,7 +650,7 @@ AIRFIELD_DATA = {
tacan=TacanChannel(94, TacanBand.X),
tacan_callsign="SYZ1",
vor=("SYZ", MHz(112, 0)),
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(121, 900), MHz(250, 350)),
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(121, 900), MHz(250, 350)),
),
# Syria Map
"Adana Sakirpasa": AirfieldData(
@@ -655,7 +659,7 @@ AIRFIELD_DATA = {
elevation=55,
runway_length=8115,
vor=("ADA", MHz(112, 700)),
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 100), MHz(250, 900)),
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(121, 100), MHz(251, 0)),
ils={
"05": ("IADA", MHz(108, 700)),
},
@@ -668,7 +672,7 @@ AIRFIELD_DATA = {
tacan=TacanChannel(21, TacanBand.X),
tacan_callsign="DAN",
vor=("DAN", MHz(108, 400)),
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(129, 400), MHz(360, 100)),
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(122, 100), MHz(360, 100)),
ils={
"50": ("IDAN", MHz(109, 300)),
"23": ("DANM", MHz(111, 700)),
@@ -679,7 +683,7 @@ AIRFIELD_DATA = {
icao="OS71",
elevation=1614,
runway_length=4648,
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(120, 600), MHz(250, 700)),
atc=AtcData(MHz(4, 175), MHz(39, 250), MHz(120, 600), MHz(250, 800)),
),
"Hatay": AirfieldData(
theater="Syria",
@@ -687,7 +691,7 @@ AIRFIELD_DATA = {
elevation=253,
runway_length=9052,
vor=("HTY", MHz(112, 500)),
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(128, 500), MHz(250, 150)),
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(128, 500), MHz(250, 250)),
ils={
"22": ("IHTY", MHz(108, 150)),
"04": ("IHAT", MHz(108, 900)),
@@ -698,25 +702,21 @@ AIRFIELD_DATA = {
icao="OS66",
elevation=1200,
runway_length=6662,
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(120, 500), MHz(251)),
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(120, 500), MHz(251, 100)),
),
"Aleppo": AirfieldData(
theater="Syria",
icao="OSAP",
elevation=1253,
runway_length=8332,
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(119, 100), MHz(250, 750)),
ils={
"50": ("IDAN", MHz(109, 300)),
"23": ("DANM", MHz(111, 700)),
},
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(119, 100), MHz(250, 850)),
),
"Jirah": AirfieldData(
theater="Syria",
icao="OS62",
elevation=1170,
runway_length=9090,
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(118, 100), MHz(250, 200)),
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 100), MHz(250, 300)),
),
"Taftanaz": AirfieldData(
theater="Syria",
@@ -729,14 +729,14 @@ AIRFIELD_DATA = {
icao="OS59",
elevation=1083,
runway_length=9036,
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(118, 500), MHz(251, 150)),
atc=AtcData(MHz(4, 500), MHz(39, 900), MHz(122, 800), MHz(251, 450)),
),
"Abu al-Dahur": AirfieldData(
theater="Syria",
icao="OS57",
elevation=820,
runway_length=8728,
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(122, 200), MHz(250, 350)),
atc=AtcData(MHz(4, 0), MHz(38, 900), MHz(122, 200), MHz(250, 450)),
),
"Bassel Al-Assad": AirfieldData(
theater="Syria",
@@ -744,7 +744,7 @@ AIRFIELD_DATA = {
elevation=93,
runway_length=7305,
vor=("LTK", MHz(114, 800)),
atc=AtcData(MHz(4), MHz(38, 900), MHz(118, 100), MHz(250, 450)),
atc=AtcData(MHz(4, 50), MHz(39, 0), MHz(118, 100), MHz(250, 550)),
ils={
"17": ("IBA", MHz(109, 100)),
},
@@ -754,28 +754,28 @@ AIRFIELD_DATA = {
icao="OS58",
elevation=983,
runway_length=7957,
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(118, 50), MHz(250, 100)),
atc=AtcData(MHz(3, 850), MHz(38, 600), MHz(118, 50), MHz(250, 200)),
),
"Rene Mouawad": AirfieldData(
theater="Syria",
icao="OLKA",
elevation=14,
runway_length=8614,
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(129, 500), MHz(251, 100)),
atc=AtcData(MHz(4, 375), MHz(39, 650), MHz(121, 0), MHz(251, 200)),
),
"Al Quasayr": AirfieldData(
theater="Syria",
icao="OS70",
elevation=1729,
runway_length=8585,
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(119, 200), MHz(251, 250)),
atc=AtcData(MHz(4, 550), MHz(40, 0), MHz(119, 200), MHz(251, 550)),
),
"Palmyra": AirfieldData(
theater="Syria",
icao="OSPR",
elevation=1267,
runway_length=8704,
atc=AtcData(MHz(4, 175), MHz(39, 250), MHz(121, 900), MHz(250, 800)),
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 900), MHz(250, 900)),
),
"Wujah Al Hajar": AirfieldData(
theater="Syria",
@@ -783,14 +783,14 @@ AIRFIELD_DATA = {
elevation=619,
runway_length=4717,
vor=("CAK", MHz(116, 200)),
atc=AtcData(MHz(4, 425), MHz(39, 750), MHz(121, 500), MHz(251, 300)),
atc=AtcData(MHz(4, 575), MHz(40, 50), MHz(121, 500), MHz(251, 600)),
),
"An Nasiriyah": AirfieldData(
theater="Syria",
icao="OS64",
elevation=2746,
runway_length=8172,
atc=AtcData(MHz(4, 450), MHz(39, 800), MHz(122, 300), MHz(251, 350)),
atc=AtcData(MHz(4, 600), MHz(40, 100), MHz(122, 300), MHz(251, 650)),
),
"Rayak": AirfieldData(
theater="Syria",
@@ -798,7 +798,7 @@ AIRFIELD_DATA = {
elevation=2934,
runway_length=8699,
vor=("HTY", MHz(124, 400)),
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(124, 400), MHz(251, 50)),
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(124, 400), MHz(251, 150)),
),
"Beirut-Rafic Hariri": AirfieldData(
theater="Syria",
@@ -806,7 +806,7 @@ AIRFIELD_DATA = {
elevation=39,
runway_length=9463,
vor=("KAD", MHz(112, 600)),
atc=AtcData(MHz(4, 475), MHz(39, 850), MHz(118, 900), MHz(251, 400)),
atc=AtcData(MHz(4, 675), MHz(40, 250), MHz(118, 900), MHz(251, 800)),
ils={
"17": ("BIL", MHz(109, 500)),
},
@@ -816,32 +816,32 @@ AIRFIELD_DATA = {
icao="OS61",
elevation=2066,
runway_length=8902,
atc=AtcData(MHz(4, 550), MHz(40), MHz(120, 300), MHz(251, 550)),
atc=AtcData(MHz(4, 750), MHz(40, 400), MHz(120, 300), MHz(251, 950)),
),
"Marj as Sultan North": AirfieldData(
theater="Syria",
elevation=2007,
runway_length=268,
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(122, 700), MHz(250, 500)),
atc=AtcData(MHz(4, 75), MHz(38, 50), MHz(122, 700), MHz(250, 600)),
),
"Marj as Sultan South": AirfieldData(
theater="Syria",
elevation=2007,
runway_length=166,
atc=AtcData(MHz(4, 525), MHz(39, 950), MHz(122, 900), MHz(251, 500)),
atc=AtcData(MHz(4, 725), MHz(40, 350), MHz(122, 900), MHz(251, 900)),
),
"Mezzeh": AirfieldData(
theater="Syria",
icao="OS67",
elevation=2355,
runway_length=7522,
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(120, 700), MHz(250, 650)),
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(120, 700), MHz(250, 750)),
),
"Qabr as Sitt": AirfieldData(
theater="Syria",
elevation=2134,
runway_length=489,
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(122, 600), MHz(250, 850)),
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(122, 600), MHz(250, 950)),
),
"Damascus": AirfieldData(
theater="Syria",
@@ -849,7 +849,7 @@ AIRFIELD_DATA = {
elevation=2007,
runway_length=11423,
vor=("DAM", MHz(116)),
atc=AtcData(MHz(4, 500), MHz(39, 900), MHz(118, 500), MHz(251, 450)),
atc=AtcData(MHz(4, 700), MHz(40, 300), MHz(118, 500), MHz(251, 850)),
ils={
"24": ("IDA", MHz(109, 900)),
},
@@ -859,42 +859,42 @@ AIRFIELD_DATA = {
icao="OS63",
elevation=2160,
runway_length=7576,
atc=AtcData(MHz(4, 50), MHz(39), MHz(120, 800), MHz(250, 550)),
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(120, 800), MHz(250, 6550)),
),
"Kiryat Shmona": AirfieldData(
theater="Syria",
icao="LLKS",
elevation=328,
runway_length=3258,
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(118, 400), MHz(250, 400)),
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(118, 400), MHz(250, 500)),
),
"Khalkhalah": AirfieldData(
theater="Syria",
icao="OS69",
elevation=2337,
runway_length=8248,
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(122, 500), MHz(250, 250)),
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(122, 500), MHz(250, 350)),
),
"Haifa": AirfieldData(
theater="Syria",
icao="LLHA",
elevation=19,
runway_length=3253,
atc=AtcData(MHz(3, 775), MHz(38, 450), MHz(127, 800), MHz(250, 50)),
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(127, 800), MHz(250, 150)),
),
"Ramat David": AirfieldData(
theater="Syria",
icao="LLRD",
elevation=105,
runway_length=7037,
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(118, 600), MHz(250, 950)),
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(118, 600), MHz(251, 50)),
),
"Megiddo": AirfieldData(
theater="Syria",
icao="LLMG",
elevation=180,
runway_length=6098,
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 900), MHz(250, 600)),
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(119, 900), MHz(250, 700)),
),
"Eyn Shemer": AirfieldData(
theater="Syria",
@@ -908,7 +908,66 @@ AIRFIELD_DATA = {
icao="OJMF",
elevation=2204,
runway_length=8595,
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 300), MHz(250, 300)),
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(118, 300), MHz(250, 400)),
),
"Tha'lah": AirfieldData(
theater="Syria",
icao="OS60",
elevation=2381,
runway_length=8025,
atc=AtcData(MHz(4, 650), MHz(40, 200), MHz(122, 400), MHz(251, 750)),
),
"Shayrat": AirfieldData(
theater="Syria",
icao="OS60",
elevation=2637,
runway_length=8553,
atc=AtcData(MHz(4, 450), MHz(39, 800), MHz(122, 200), MHz(251, 350)),
),
"Tiyas": AirfieldData(
theater="Syria",
icao="OS72",
elevation=1797,
runway_length=9420,
atc=AtcData(MHz(4, 525), MHz(39, 950), MHz(120, 500), MHz(251, 500)),
),
"Rosh Pina": AirfieldData(
theater="Syria",
icao="LLIB",
elevation=865,
runway_length=2711,
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(118, 450), MHz(251, 250)),
),
"Sayqal": AirfieldData(
theater="Syria",
icao="OS68",
elevation=2273,
runway_length=8536,
atc=AtcData(MHz(4, 425), MHz(39, 750), MHz(120, 400), MHz(251, 300)),
),
"H4": AirfieldData(
theater="Syria",
icao="OJHR",
elevation=2257,
runway_length=7179,
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(120, 400), MHz(250, 100)),
),
"Naqoura": AirfieldData(
theater="Syria",
icao="",
elevation=378,
runway_length=0,
atc=AtcData(MHz(4, 625), MHz(40, 150), MHz(122, 000), MHz(251, 700)),
),
"Gaziantep": AirfieldData(
theater="Syria",
icao="LTAJ",
elevation=2287,
runway_length=8871,
atc=AtcData(MHz(3, 775), MHz(38, 450), MHz(120, 100), MHz(250, 50)),
ils={
"28": ("IGNP", MHz(109, 10)),
},
),
# NTTR
"Mina Airport 3Q0": AirfieldData(
@@ -1304,55 +1363,73 @@ AIRFIELD_DATA = {
"Detling": AirfieldData(
theater="Channel",
elevation=623,
runway_length=2557,
atc=AtcData(MHz(3, 950), MHz(118, 400), MHz(38, 800), MHz(250, 400)),
runway_length=3482,
atc=AtcData(MHz(4, 50), MHz(118, 600), MHz(39, 0), MHz(250, 600)),
),
"High Halden": AirfieldData(
theater="Channel",
elevation=104,
runway_length=3296,
atc=AtcData(MHz(3, 750), MHz(118, 800), MHz(38, 400), MHz(250, 0)),
atc=AtcData(MHz(3, 800), MHz(118, 100), MHz(38, 500), MHz(250, 100)),
),
"Lympne": AirfieldData(
theater="Channel",
elevation=351,
runway_length=2548,
atc=AtcData(MHz(3, 925), MHz(118, 350), MHz(38, 750), MHz(250, 350)),
runway_length=3054,
atc=AtcData(MHz(4, 25), MHz(118, 550), MHz(38, 950), MHz(250, 550)),
),
"Hawkinge": AirfieldData(
theater="Channel",
elevation=524,
runway_length=3013,
atc=AtcData(MHz(3, 900), MHz(118, 300), MHz(38, 700), MHz(250, 300)),
atc=AtcData(MHz(4, 0), MHz(118, 500), MHz(38, 900), MHz(250, 500)),
),
"Manston": AirfieldData(
theater="Channel",
elevation=160,
runway_length=8626,
atc=AtcData(MHz(3, 875), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
atc=AtcData(MHz(3, 975), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
),
"Dunkirk Mardyck": AirfieldData(
theater="Channel",
elevation=16,
runway_length=1737,
atc=AtcData(MHz(3, 850), MHz(118, 200), MHz(38, 600), MHz(250, 200)),
atc=AtcData(MHz(3, 950), MHz(118, 450), MHz(38, 850), MHz(250, 450)),
),
"Saint Omer Longuenesse": AirfieldData(
theater="Channel",
elevation=219,
runway_length=1929,
atc=AtcData(MHz(3, 825), MHz(118, 150), MHz(38, 550), MHz(250, 150)),
atc=AtcData(MHz(3, 925), MHz(118, 350), MHz(38, 750), MHz(250, 350)),
),
"Merville Calonne": AirfieldData(
theater="Channel",
elevation=52,
runway_length=7580,
atc=AtcData(MHz(3, 800), MHz(118, 100), MHz(38, 500), MHz(250, 100)),
atc=AtcData(MHz(3, 900), MHz(118, 300), MHz(38, 700), MHz(250, 300)),
),
"Abbeville Drucat": AirfieldData(
theater="Channel",
elevation=183,
runway_length=4726,
atc=AtcData(MHz(3, 875), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
),
"Eastchurch": AirfieldData(
theater="Channel",
elevation=30,
runway_length=2983,
atc=AtcData(MHz(3, 775), MHz(118, 50), MHz(38, 450), MHz(250, 50)),
),
"Headcorn": AirfieldData(
theater="Channel",
elevation=114,
runway_length=3680,
atc=AtcData(MHz(3, 825), MHz(118, 150), MHz(38, 550), MHz(250, 150)),
),
"Biggin Hill": AirfieldData(
theater="Channel",
elevation=552,
runway_length=3953,
atc=AtcData(MHz(3, 850), MHz(118, 200), MHz(38, 600), MHz(250, 200)),
),
}

View File

@@ -1,6 +1,7 @@
import logging
from dataclasses import dataclass, field
from typing import List, Type, Tuple
from datetime import timedelta
from typing import List, Type, Tuple, Optional
from dcs.mission import Mission, StartType
from dcs.planes import IL_78M, KC130, KC135MPRS, KC_135
@@ -21,6 +22,7 @@ from .conflictgen import Conflict
from .radios import RadioFrequency, RadioRegistry
from .tacan import TacanBand, TacanChannel, TacanRegistry
TANKER_DISTANCE = 15000
TANKER_ALT = 4572
TANKER_HEADING_OFFSET = 45
@@ -36,6 +38,9 @@ class AwacsInfo:
dcsGroupName: str
callsign: str
freq: RadioFrequency
depature_location: Optional[str]
start_time: Optional[timedelta]
end_time: Optional[timedelta]
@dataclass
@@ -163,37 +168,41 @@ class AirSupportConflictGenerator:
TankerInfo(str(tanker_group.name), callsign, variant, freq, tacan)
)
possible_awacs = db.find_unittype(AWACS, self.conflict.attackers_side)
if not self.game.settings.disable_legacy_aewc:
possible_awacs = db.find_unittype(AWACS, self.conflict.attackers_side)
if len(possible_awacs) > 0:
awacs_unit = possible_awacs[0]
freq = self.radio_registry.alloc_uhf()
if len(possible_awacs) > 0:
awacs_unit = possible_awacs[0]
freq = self.radio_registry.alloc_uhf()
awacs_flight = self.mission.awacs_flight(
country=self.mission.country(self.game.player_country),
name=namegen.next_awacs_name(
self.mission.country(self.game.player_country)
),
plane_type=awacs_unit,
altitude=AWACS_ALT,
airport=None,
position=self.conflict.position.random_point_within(
AWACS_DISTANCE, AWACS_DISTANCE
),
frequency=freq.mhz,
start_type=StartType.Warm,
)
awacs_flight.set_frequency(freq.mhz)
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))
awacs_flight.points[0].tasks.append(SetImmortalCommand(True))
self.air_support.awacs.append(
AwacsInfo(
str(awacs_flight.name),
callsign_for_support_unit(awacs_flight),
freq,
awacs_flight = self.mission.awacs_flight(
country=self.mission.country(self.game.player_country),
name=namegen.next_awacs_name(
self.mission.country(self.game.player_country)
),
plane_type=awacs_unit,
altitude=AWACS_ALT,
airport=None,
position=self.conflict.position.random_point_within(
AWACS_DISTANCE, AWACS_DISTANCE
),
frequency=freq.mhz,
start_type=StartType.Warm,
)
)
else:
logging.warning("No AWACS for faction")
awacs_flight.set_frequency(freq.mhz)
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))
awacs_flight.points[0].tasks.append(SetImmortalCommand(True))
self.air_support.awacs.append(
AwacsInfo(
dcsGroupName=str(awacs_flight.name),
callsign=callsign_for_support_unit(awacs_flight),
freq=freq,
depature_location=None,
start_time=None,
end_time=None,
)
)
else:
logging.warning("No AWACS for faction")

View File

@@ -175,6 +175,7 @@ class Package:
FlightType.SEAD,
FlightType.TARCAP,
FlightType.BARCAP,
FlightType.AEWC,
FlightType.SWEEP,
FlightType.ESCORT,
]

View File

@@ -20,6 +20,7 @@ from .ground_forces.combat_stance import CombatStance
from .radios import RadioFrequency
from .runways import RunwayData
if TYPE_CHECKING:
from game import Game

View File

@@ -0,0 +1,31 @@
import logging
import random
from game import db
from gen.coastal.silkworm import SilkwormGenerator
COASTAL_MAP = {
"SilkwormGenerator": SilkwormGenerator,
}
def generate_coastal_group(game, ground_object, faction_name: str):
"""
This generate a coastal defenses group
:return: Nothing, but put the group reference inside the ground object
"""
faction = db.FACTIONS[faction_name]
if len(faction.coastal_defenses) > 0:
generators = faction.coastal_defenses
if len(generators) > 0:
gen = random.choice(generators)
if gen in COASTAL_MAP.keys():
generator = COASTAL_MAP[gen](game, ground_object, faction)
generator.generate()
return generator.get_generated_group()
else:
logging.info(
"Unable to generate missile group, generator : "
+ str(gen)
+ "does not exists"
)
return None

58
gen/coastal/silkworm.py Normal file
View File

@@ -0,0 +1,58 @@
from dcs.vehicles import MissilesSS, Unarmed, AirDefence
from gen.sam.group_generator import GroupGenerator
class SilkwormGenerator(GroupGenerator):
def __init__(self, game, ground_object, faction):
super(SilkwormGenerator, self).__init__(game, ground_object)
self.faction = faction
def generate(self):
positions = self.get_circular_position(5, launcher_distance=120, coverage=180)
self.add_unit(
MissilesSS.AShM_Silkworm_SR,
"SR#0",
self.position.x,
self.position.y,
self.heading,
)
# Launchers
for i, p in enumerate(positions):
self.add_unit(
MissilesSS.AShM_SS_N_2_Silkworm,
"Missile#" + str(i),
p[0],
p[1],
self.heading,
)
# Commander
self.add_unit(
Unarmed.Truck_KAMAZ_43101,
"KAMAZ#0",
self.position.x - 35,
self.position.y - 20,
self.heading,
)
# Shorad
self.add_unit(
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
"SHILKA#0",
self.position.x - 55,
self.position.y - 38,
self.heading,
)
# Shorad 2
self.add_unit(
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
"STRELA#0",
self.position.x + 200,
self.position.y + 15,
90,
)

View File

@@ -17,6 +17,7 @@ class EnvironmentGenerator:
self.mission.weather.clouds_thickness = clouds.thickness
self.mission.weather.clouds_density = clouds.density
self.mission.weather.clouds_iprecptns = clouds.precipitation
self.mission.weather.clouds_preset = clouds.preset
def set_fog(self, fog: Optional[Fog]) -> None:
if fog is None:

View File

@@ -2,50 +2,122 @@ import random
from gen.sam.group_generator import ShipGroupGenerator
from dcs.ships import DDG_Arleigh_Burke_IIa, CG_Ticonderoga
class CarrierGroupGenerator(ShipGroupGenerator):
def generate(self):
# Add carrier
if len(self.faction.aircraft_carrier) > 0:
# Carrier Strike Group 8
if self.faction.carrier_names[0] == "Carrier Strike Group 8":
carrier_type = random.choice(self.faction.aircraft_carrier)
self.add_unit(
carrier_type, "Carrier", self.position.x, self.position.y, self.heading
carrier_type,
"CVN-75 Harry S. Truman",
self.position.x,
self.position.y,
self.heading,
)
# Add Arleigh Burke escort
self.add_unit(
DDG_Arleigh_Burke_IIa,
"USS Ramage",
self.position.x + 6482,
self.position.y + 6667,
self.heading,
)
self.add_unit(
DDG_Arleigh_Burke_IIa,
"USS Mitscher",
self.position.x - 7963,
self.position.y + 7037,
self.heading,
)
self.add_unit(
DDG_Arleigh_Burke_IIa,
"USS Forrest Sherman",
self.position.x - 7408,
self.position.y - 7408,
self.heading,
)
self.add_unit(
DDG_Arleigh_Burke_IIa,
"USS Lassen",
self.position.x + 8704,
self.position.y - 6296,
self.heading,
)
# Add Ticonderoga escort
if self.heading >= 180:
self.add_unit(
CG_Ticonderoga,
"USS Hué City",
self.position.x + 2222,
self.position.y - 3333,
self.heading,
)
else:
self.add_unit(
CG_Ticonderoga,
"USS Hué City",
self.position.x - 3333,
self.position.y + 2222,
self.heading,
)
self.get_generated_group().points[0].speed = 20
##################################################################################################
# Add carrier for normal generation
else:
return
if len(self.faction.aircraft_carrier) > 0:
carrier_type = random.choice(self.faction.aircraft_carrier)
self.add_unit(
carrier_type,
"Carrier",
self.position.x,
self.position.y,
self.heading,
)
else:
return
# Add destroyers escort
if len(self.faction.destroyers) > 0:
dd_type = random.choice(self.faction.destroyers)
self.add_unit(
dd_type,
"DD1",
self.position.x + 2500,
self.position.y + 4500,
self.heading,
)
self.add_unit(
dd_type,
"DD2",
self.position.x + 2500,
self.position.y - 4500,
self.heading,
)
# Add destroyers escort
if len(self.faction.destroyers) > 0:
dd_type = random.choice(self.faction.destroyers)
self.add_unit(
dd_type,
"DD1",
self.position.x + 2500,
self.position.y + 4500,
self.heading,
)
self.add_unit(
dd_type,
"DD2",
self.position.x + 2500,
self.position.y - 4500,
self.heading,
)
self.add_unit(
dd_type,
"DD3",
self.position.x + 4500,
self.position.y + 8500,
self.heading,
)
self.add_unit(
dd_type,
"DD4",
self.position.x + 4500,
self.position.y - 8500,
self.heading,
)
self.add_unit(
dd_type,
"DD3",
self.position.x + 4500,
self.position.y + 8500,
self.heading,
)
self.add_unit(
dd_type,
"DD4",
self.position.x + 4500,
self.position.y - 8500,
self.heading,
)
self.get_generated_group().points[0].speed = 20
self.get_generated_group().points[0].speed = 20

View File

@@ -6,7 +6,7 @@ from game.theater.theatergroundobject import TheaterGroundObject
from gen.sam.group_generator import ShipGroupGenerator
from dcs.unittype import ShipType
from dcs.ships import Oliver_Hazzard_Perry_class, USS_Arleigh_Burke_IIa
from dcs.ships import FFG_Oliver_Hazzard_Perry, DDG_Arleigh_Burke_IIa
if TYPE_CHECKING:
from game.game import Game
@@ -46,7 +46,7 @@ class OliverHazardPerryGroupGenerator(DDGroupGenerator):
self, game: Game, ground_object: TheaterGroundObject, faction: Faction
):
super(OliverHazardPerryGroupGenerator, self).__init__(
game, ground_object, faction, Oliver_Hazzard_Perry_class
game, ground_object, faction, FFG_Oliver_Hazzard_Perry
)
@@ -55,5 +55,5 @@ class ArleighBurkeGroupGenerator(DDGroupGenerator):
self, game: Game, ground_object: TheaterGroundObject, faction: Faction
):
super(ArleighBurkeGroupGenerator, self).__init__(
game, ground_object, faction, USS_Arleigh_Burke_IIa
game, ground_object, faction, DDG_Arleigh_Burke_IIa
)

View File

@@ -3,13 +3,13 @@ import random
from typing import TYPE_CHECKING
from dcs.ships import (
FFL_1124_4_Grisha,
FSG_1241_1MP_Molniya,
FFG_11540_Neustrashimy,
FF_1135M_Rezky,
CG_1164_Moskva,
SSK_877,
SSK_641B,
Corvette_1124_4_Grisha,
Corvette_1241_1_Molniya,
Frigate_11540_Neustrashimy,
Frigate_1135M_Rezky,
Cruiser_1164_Moskva,
SSK_877V_Kilo,
SSK_641B_Tango,
)
from gen.fleet.dd_group import DDGroupGenerator
@@ -37,7 +37,9 @@ class RussianNavyGroupGenerator(ShipGroupGenerator):
include_frigate = True
if include_frigate:
frigate_type = random.choice([FFL_1124_4_Grisha, FSG_1241_1MP_Molniya])
frigate_type = random.choice(
[Corvette_1124_4_Grisha, Corvette_1241_1_Molniya]
)
self.add_unit(
frigate_type,
"FF1",
@@ -54,7 +56,7 @@ class RussianNavyGroupGenerator(ShipGroupGenerator):
)
if include_dd:
dd_type = random.choice([FFG_11540_Neustrashimy, FF_1135M_Rezky])
dd_type = random.choice([Frigate_11540_Neustrashimy, Frigate_1135M_Rezky])
self.add_unit(
dd_type,
"DD1",
@@ -74,7 +76,11 @@ class RussianNavyGroupGenerator(ShipGroupGenerator):
# Only include the Moskva for now, the Pyotry Velikiy is an unkillable monster.
# See https://github.com/Khopa/dcs_liberation/issues/567
self.add_unit(
CG_1164_Moskva, "CC1", self.position.x, self.position.y, self.heading
Cruiser_1164_Moskva,
"CC1",
self.position.x,
self.position.y,
self.heading,
)
self.get_generated_group().points[0].speed = 20
@@ -85,7 +91,7 @@ class GrishaGroupGenerator(DDGroupGenerator):
self, game: Game, ground_object: TheaterGroundObject, faction: Faction
):
super(GrishaGroupGenerator, self).__init__(
game, ground_object, faction, FFL_1124_4_Grisha
game, ground_object, faction, Corvette_1124_4_Grisha
)
@@ -94,7 +100,7 @@ class MolniyaGroupGenerator(DDGroupGenerator):
self, game: Game, ground_object: TheaterGroundObject, faction: Faction
):
super(MolniyaGroupGenerator, self).__init__(
game, ground_object, faction, FSG_1241_1MP_Molniya
game, ground_object, faction, Corvette_1241_1_Molniya
)
@@ -103,7 +109,7 @@ class KiloSubGroupGenerator(DDGroupGenerator):
self, game: Game, ground_object: TheaterGroundObject, faction: Faction
):
super(KiloSubGroupGenerator, self).__init__(
game, ground_object, faction, SSK_877
game, ground_object, faction, SSK_877V_Kilo
)
@@ -112,5 +118,5 @@ class TangoSubGroupGenerator(DDGroupGenerator):
self, game: Game, ground_object: TheaterGroundObject, faction: Faction
):
super(TangoSubGroupGenerator, self).__init__(
game, ground_object, faction, SSK_641B
game, ground_object, faction, SSK_641B_Tango
)

View File

@@ -1,6 +1,6 @@
import random
from dcs.ships import Schnellboot_type_S130
from dcs.ships import Boat_Schnellboot_type_S130
from gen.sam.group_generator import ShipGroupGenerator
@@ -10,7 +10,7 @@ class SchnellbootGroupGenerator(ShipGroupGenerator):
for i in range(random.randint(2, 4)):
self.add_unit(
Schnellboot_type_S130,
Boat_Schnellboot_type_S130,
"Schnellboot" + str(i),
self.position.x + i * random.randint(100, 250),
self.position.y + (random.randint(100, 200) - 100),

View File

@@ -47,6 +47,7 @@ def generate_ship_group(game, ground_object, faction_name: str):
gen = random.choice(faction.navy_generators)
if gen in SHIP_MAP.keys():
generator = SHIP_MAP[gen](game, ground_object, faction)
print(generator.position)
generator.generate()
return generator.get_generated_group()
else:

View File

@@ -1,6 +1,6 @@
import random
from dcs.ships import Uboat_VIIC_U_flak
from dcs.ships import U_boat_VIIC_U_flak
from gen.sam.group_generator import ShipGroupGenerator
@@ -10,7 +10,7 @@ class UBoatGroupGenerator(ShipGroupGenerator):
for i in range(random.randint(1, 4)):
self.add_unit(
Uboat_VIIC_U_flak,
U_boat_VIIC_U_flak,
"Uboat" + str(i),
self.position.x + i * random.randint(100, 250),
self.position.y + (random.randint(100, 200) - 100),

View File

@@ -450,6 +450,22 @@ class ObjectiveFinder:
c for c in self.game.theater.controlpoints if c.is_friendly(self.is_player)
)
def farthest_friendly_control_point(self) -> ControlPoint:
"""
Iterates over all friendly control points and find the one farthest away from the frontline
BUT! prefer Cvs. Everybody likes CVs!
"""
from_frontline = 0
for c in self.game.theater.controlpoints:
if c.is_carrier and c.is_friendly(self.is_player):
return c
if c.is_friendly(self.is_player) and c.has_frontline:
if c.distance_to(self.front_lines().__next__()) > from_frontline:
from_frontline = c.distance_to(self.front_lines().__next__())
cp = c
return cp
def enemy_control_points(self) -> Iterator[ControlPoint]:
"""Iterates over all enemy control points."""
return (
@@ -507,6 +523,7 @@ class CoalitionMissionPlanner:
MAX_OCA_RANGE = nautical_miles(150)
MAX_SEAD_RANGE = nautical_miles(150)
MAX_STRIKE_RANGE = nautical_miles(150)
MAX_AWEC_RANGE = nautical_miles(200)
def __init__(self, game: Game, is_player: bool) -> None:
self.game = game
@@ -526,6 +543,13 @@ class CoalitionMissionPlanner:
ensure that they can be planned again next turn even if all aircraft are
eliminated this turn.
"""
# Find farthest, friendly CP for AEWC
cp = self.objective_finder.farthest_friendly_control_point()
yield ProposedMission(
cp, [ProposedFlight(FlightType.AEWC, 1, self.MAX_AWEC_RANGE)]
)
# Find friendly CPs within 100 nmi from an enemy airfield, plan CAP.
for cp in self.objective_finder.vulnerable_control_points():
# Plan three rounds of CAP to give ~90 minutes coverage. Spacing

View File

@@ -12,8 +12,8 @@ from dcs.helicopters import (
OH_58D,
SA342L,
SA342M,
UH_1H,
SH_60B,
UH_1H,
)
from dcs.planes import (
AJS37,
@@ -22,11 +22,14 @@ from dcs.planes import (
A_10C,
A_10C_2,
A_20G,
A_50,
B_17G,
B_1B,
B_52H,
Bf_109K_4,
C_101CC,
E_2C,
E_3A,
FA_18C_hornet,
FW_190A8,
FW_190D9,
@@ -40,9 +43,11 @@ from dcs.planes import (
F_4E,
F_5E_3,
F_86F_Sabre,
I_16,
JF_17,
J_11A,
Ju_88A4,
KJ_2000,
L_39ZA,
MQ_9_Reaper,
M_2000C,
@@ -54,7 +59,6 @@ from dcs.planes import (
MiG_27K,
MiG_29A,
MiG_29G,
MiG_29K,
MiG_29S,
MiG_31,
Mirage_2000_5,
@@ -88,13 +92,11 @@ from dcs.planes import (
from dcs.unittype import FlyingType
from gen.flights.flight import FlightType
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
from pydcs_extensions.su57.su57 import Su_57
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.su57.su57 import Su_57
# All aircraft lists are in priority order. Aircraft higher in the list will be
# preferred over those lower in the list.
@@ -111,14 +113,12 @@ CAP_CAPABLE = [
F_14B,
F_14A_135_GR,
MiG_25PD,
Rafale_M,
Su_33,
Su_30,
Su_27,
J_11A,
F_15C,
MiG_29S,
MiG_29K,
MiG_29G,
MiG_29A,
F_16C_50,
@@ -155,8 +155,8 @@ CAP_CAPABLE = [
# Used for CAS (Close air support) and BAI (Battlefield Interdiction)
CAS_CAPABLE = [
A_10C_2,
A_10C,
B_1B,
A_10C,
F_14B,
F_14A_135_GR,
Su_25TM,
@@ -165,8 +165,6 @@ CAS_CAPABLE = [
F_15E,
F_16C_50,
FA_18C_hornet,
Rafale_A_S,
Rafale_B,
Tornado_GR4,
Tornado_IDS,
JF_17,
@@ -180,6 +178,7 @@ CAS_CAPABLE = [
S_3B,
Su_34,
Su_30,
MiG_19P,
MiG_29S,
MiG_27K,
MiG_29A,
@@ -227,8 +226,6 @@ SEAD_CAPABLE = [
Tornado_IDS,
Su_25T,
Su_25TM,
Rafale_A_S,
Rafale_B,
F_4E,
A_4E_C,
AV8BNA,
@@ -276,8 +273,6 @@ STRIKE_CAPABLE = [
Tu_22M3,
F_15E,
AJS37,
Rafale_A_S,
Rafale_B,
Tornado_GR4,
F_16C_50,
FA_18C_hornet,
@@ -296,7 +291,6 @@ STRIKE_CAPABLE = [
Su_30,
Su_27,
MiG_29S,
MiG_29K,
MiG_29G,
MiG_29A,
JF_17,
@@ -333,8 +327,6 @@ ANTISHIP_CAPABLE = [
AJS37,
Tu_22M3,
FA_18C_hornet,
Rafale_A_S,
Rafale_B,
Su_24M,
Su_17M4,
JF_17,
@@ -369,6 +361,13 @@ TRANSPORT_CAPABLE = [
DRONES = [MQ_9_Reaper, RQ_1A_Predator, WingLoong_I]
AEWC_CAPABLE = [
E_3A,
E_2C,
A_50,
KJ_2000,
]
def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
cap_missions = (FlightType.BARCAP, FlightType.TARCAP)
@@ -392,6 +391,8 @@ def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
return STRIKE_CAPABLE
elif task == FlightType.ESCORT:
return CAP_CAPABLE
elif task == FlightType.AEWC:
return AEWC_CAPABLE
else:
logging.error(f"Unplannable flight type: {task}")
return []

View File

@@ -20,6 +20,15 @@ if TYPE_CHECKING:
class FlightType(Enum):
"""Enumeration of mission types.
The value of each enumeration is the name that will be shown in the UI.
These values are persisted to the save game as well since they are a part of
each flight and thus a part of the ATO, so changing these values will break
save compat.
"""
TARCAP = "TARCAP"
BARCAP = "BARCAP"
CAS = "CAS"
@@ -33,6 +42,7 @@ class FlightType(Enum):
SWEEP = "Fighter sweep"
OCA_RUNWAY = "OCA/Runway"
OCA_AIRCRAFT = "OCA/Aircraft"
AEWC = "AEW&C"
def __str__(self) -> str:
return self.value

View File

@@ -15,6 +15,8 @@ from datetime import timedelta
from functools import cached_property
from typing import Iterator, List, Optional, Set, TYPE_CHECKING, Tuple
from dcs.planes import E_3A, E_2C, A_50, KJ_2000
from dcs.mapping import Point
from dcs.unit import Unit
from shapely.geometry import Point as ShapelyPoint
@@ -29,7 +31,7 @@ from game.theater import (
TheaterGroundObject,
)
from game.theater.theatergroundobject import EwrGroundObject
from game.utils import Distance, Speed, meters, nautical_miles
from game.utils import Distance, Speed, feet, meters, nautical_miles
from .closestairfields import ObjectiveDistanceCache
from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
from .traveltime import GroundSpeed, TravelTime
@@ -278,11 +280,11 @@ class LoiterFlightPlan(FlightPlan):
travel_time = super().travel_time_between_waypoints(a, b)
if a != self.hold:
return travel_time
try:
return travel_time + self.hold_duration
except AttributeError:
# Save compat for 2.3.
return travel_time + timedelta(minutes=5)
return travel_time + self.hold_duration
@property
def mission_departure_time(self) -> timedelta:
raise NotImplementedError
@dataclass(frozen=True)
@@ -694,6 +696,45 @@ class SweepFlightPlan(LoiterFlightPlan):
return self.sweep_end_time
@dataclass(frozen=True)
class AwacsFlightPlan(LoiterFlightPlan):
takeoff: FlightWaypoint
nav_to: List[FlightWaypoint]
nav_from: List[FlightWaypoint]
land: FlightWaypoint
divert: Optional[FlightWaypoint]
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.takeoff
yield from self.nav_to
yield self.hold
yield from self.nav_from
yield self.land
if self.divert is not None:
yield self.divert
@property
def mission_start_time(self) -> Optional[timedelta]:
return self.takeoff_time()
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
if waypoint == self.hold:
return self.package.time_over_target
return None
@property
def tot_waypoint(self) -> Optional[FlightWaypoint]:
return self.hold
@property
def push_time(self) -> timedelta:
return self.package.time_over_target + self.hold_duration
@property
def mission_departure_time(self) -> timedelta:
return self.push_time
@dataclass(frozen=True)
class CustomFlightPlan(FlightPlan):
custom_waypoints: List[FlightWaypoint]
@@ -759,7 +800,17 @@ class FlightPlanBuilder:
raise RuntimeError("Flight must be a part of the package")
if self.package.waypoints is None:
self.regenerate_package_waypoints()
flight.flight_plan = self.generate_flight_plan(flight, custom_targets)
from game.navmesh import NavMeshError
try:
flight.flight_plan = self.generate_flight_plan(flight, custom_targets)
except NavMeshError as ex:
color = "blue" if self.is_player else "red"
raise PlanningError(
f"Could not plan {color} {flight.flight_type.value} from "
f"{flight.departure} to {flight.package.target}"
) from ex
def generate_flight_plan(
self, flight: Flight, custom_targets: Optional[List[Unit]]
@@ -790,6 +841,8 @@ class FlightPlanBuilder:
return self.generate_sweep(flight)
elif task == FlightType.TARCAP:
return self.generate_tarcap(flight)
elif task == FlightType.AEWC:
return self.generate_aewc(flight)
raise PlanningError(f"{task} flight plan generation not implemented")
def regenerate_package_waypoints(self) -> None:
@@ -920,6 +973,47 @@ class FlightPlanBuilder:
flight, location, FlightWaypointType.INGRESS_STRIKE, targets
)
def generate_aewc(self, flight: Flight) -> AwacsFlightPlan:
"""Generate a AWACS flight at a given location.
Args:
flight: The flight to generate the flight plan for.
"""
location = self.package.target
start = self.aewc_orbit(location)
# As high as possible to maximize detection and on-station time.
if flight.unit_type == E_2C:
patrol_alt = feet(30000)
elif flight.unit_type == E_3A:
patrol_alt = feet(35000)
elif flight.unit_type == A_50:
patrol_alt = feet(33000)
elif flight.unit_type == KJ_2000:
patrol_alt = feet(40000)
else:
patrol_alt = feet(25000)
builder = WaypointBuilder(flight, self.game, self.is_player)
start = builder.orbit(start, patrol_alt)
return AwacsFlightPlan(
package=self.package,
flight=flight,
takeoff=builder.takeoff(flight.departure),
nav_to=builder.nav_path(
flight.departure.position, start.position, patrol_alt
),
nav_from=builder.nav_path(
start.position, flight.arrival.position, patrol_alt
),
land=builder.land(flight.arrival),
divert=builder.divert(flight.divert),
hold=start,
hold_duration=timedelta(hours=4),
)
def generate_bai(self, flight: Flight) -> StrikeFlightPlan:
"""Generates a BAI flight plan.
@@ -933,7 +1027,8 @@ class FlightPlanBuilder:
targets: List[StrikeTarget] = []
for group in location.groups:
targets.append(StrikeTarget(f"{group.name} at {location.name}", group))
if group.units:
targets.append(StrikeTarget(f"{group.name} at {location.name}", group))
return self.strike_flightplan(
flight, location, FlightWaypointType.INGRESS_BAI, targets
@@ -1102,6 +1197,22 @@ class FlightPlanBuilder:
start = end.point_from_heading(heading - 180, diameter)
return start, end
def aewc_orbit(self, location: MissionTarget) -> Point:
# in threat zone
if self.threat_zones.threatened(location.position):
# Borderpoint
closest_boundary = self.threat_zones.closest_boundary(location.position)
# Heading + Distance to border point
heading = location.position.heading_between_point(closest_boundary)
distance = location.position.distance_to_point(closest_boundary)
return location.position.point_from_heading(heading, distance)
# this Part is fine. No threat zone, just use our point
else:
return location.position
def racetrack_for_frontline(
self, origin: Point, front_line: FrontLine
) -> Tuple[Point, Point]:

View File

@@ -14,7 +14,7 @@ from typing import (
from dcs.mapping import Point
from dcs.unit import Unit
from dcs.unitgroup import VehicleGroup
from dcs.unitgroup import Group, VehicleGroup
if TYPE_CHECKING:
from game import Game
@@ -32,7 +32,7 @@ from .flight import Flight, FlightWaypoint, FlightWaypointType
@dataclass(frozen=True)
class StrikeTarget:
name: str
target: Union[VehicleGroup, TheaterGroundObject, Unit]
target: Union[VehicleGroup, TheaterGroundObject, Unit, Group]
class WaypointBuilder:
@@ -161,8 +161,10 @@ class WaypointBuilder:
FlightWaypointType.JOIN,
position.x,
position.y,
meters(500) if self.is_helo else self.doctrine.ingress_altitude,
meters(80) if self.is_helo else self.doctrine.ingress_altitude,
)
if self.is_helo:
waypoint.alt_type = "RADIO"
waypoint.pretty_name = "Join"
waypoint.description = "Rendezvous with package"
waypoint.name = "JOIN"
@@ -173,8 +175,10 @@ class WaypointBuilder:
FlightWaypointType.SPLIT,
position.x,
position.y,
meters(500) if self.is_helo else self.doctrine.ingress_altitude,
meters(80) if self.is_helo else self.doctrine.ingress_altitude,
)
if self.is_helo:
waypoint.alt_type = "RADIO"
waypoint.pretty_name = "Split"
waypoint.description = "Depart from package"
waypoint.name = "SPLIT"
@@ -190,8 +194,10 @@ class WaypointBuilder:
ingress_type,
position.x,
position.y,
meters(500) if self.is_helo else self.doctrine.ingress_altitude,
meters(50) if self.is_helo else self.doctrine.ingress_altitude,
)
if self.is_helo:
waypoint.alt_type = "RADIO"
waypoint.pretty_name = "INGRESS on " + objective.name
waypoint.description = "INGRESS on " + objective.name
waypoint.name = "INGRESS"
@@ -204,8 +210,10 @@ class WaypointBuilder:
FlightWaypointType.EGRESS,
position.x,
position.y,
meters(500) if self.is_helo else self.doctrine.ingress_altitude,
meters(50) if self.is_helo else self.doctrine.ingress_altitude,
)
if self.is_helo:
waypoint.alt_type = "RADIO"
waypoint.pretty_name = "EGRESS from " + target.name
waypoint.description = "EGRESS from " + target.name
waypoint.name = "EGRESS"
@@ -286,7 +294,7 @@ class WaypointBuilder:
FlightWaypointType.CAS,
position.x,
position.y,
meters(500) if self.is_helo else meters(1000),
meters(50) if self.is_helo else meters(1000),
)
waypoint.alt_type = "RADIO"
waypoint.description = "Provide CAS"
@@ -341,6 +349,21 @@ class WaypointBuilder:
self.race_track_end(end, altitude),
)
@staticmethod
def orbit(start: Point, altitude: Distance) -> FlightWaypoint:
"""Creates an circular orbit point.
Args:
start: Position of the waypoint.
altitude: Altitude of the racetrack.
"""
waypoint = FlightWaypoint(FlightWaypointType.LOITER, start.x, start.y, altitude)
waypoint.name = "ORBIT"
waypoint.description = "Anchor and hold at this point"
waypoint.pretty_name = "Orbit"
return waypoint
@staticmethod
def sweep_start(position: Point, altitude: Distance) -> FlightWaypoint:
"""Creates a sweep start waypoint.
@@ -407,8 +430,10 @@ class WaypointBuilder:
FlightWaypointType.TARGET_GROUP_LOC,
target.position.x,
target.position.y,
meters(500) if self.is_helo else self.doctrine.ingress_altitude,
meters(50) if self.is_helo else self.doctrine.ingress_altitude,
)
if self.is_helo:
waypoint.alt_type = "RADIO"
waypoint.name = "TARGET"
waypoint.description = "Escort the package"
waypoint.pretty_name = "Target area"

View File

@@ -14,16 +14,16 @@ TYPE_TANKS = [
Armor.MBT_Challenger_II,
Armor.MBT_M1A2_Abrams,
Armor.MBT_M60A3_Patton,
Armor.MBT_Merkava_Mk__4,
Armor.MBT_Merkava_IV,
Armor.ZTZ_96B,
# WW2
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
Armor.MT_Pz_Kpfw_IV_Ausf_H,
Armor.MT_PzIV_H,
Armor.HT_Pz_Kpfw_VI_Tiger_I,
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II,
Armor.MT_M4_Sherman,
Armor.MT_M4A4_Sherman_Firefly,
Armor.StuG_IV,
Armor.SPG_StuG_IV,
Armor.CT_Centaur_IV,
Armor.CT_Cromwell_IV,
Armor.HIT_Churchill_VII,
@@ -40,14 +40,14 @@ TYPE_TANKS = [
]
TYPE_ATGM = [
Armor.ATGM_M1045_HMMWV_TOW,
Armor.ATGM_M1134_Stryker,
Armor.ATGM_HMMWV,
Armor.ATGM_Stryker,
Armor.IFV_BMP_2,
# WW2 (Tank Destroyers)
Armor.M30_Cargo_Carrier,
Armor.TD_Jagdpanzer_IV,
Armor.TD_Jagdpanther_G1,
Armor.TD_M10_GMC,
Unarmed.Carrier_M30_Cargo,
Armor.SPG_Jagdpanzer_IV,
Armor.SPG_Jagdpanther_G1,
Armor.SPG_M10_GMC,
# Mods
frenchpack.VBAE_CRAB_MMP,
frenchpack.VAB_MEPHISTO,
@@ -59,17 +59,17 @@ TYPE_IFV = [
Armor.IFV_BMP_2,
Armor.IFV_BMP_1,
Armor.IFV_Marder,
Armor.IFV_MCV_80,
Armor.IFV_Warrior,
Armor.IFV_LAV_25,
Armor.SPG_M1128_Stryker_MGS,
Armor.AC_Sd_Kfz_234_2_Puma,
Armor.SPG_Stryker_MGS,
Armor.IFV_Sd_Kfz_234_2_Puma,
Armor.IFV_M2A2_Bradley,
Armor.IFV_BMD_1,
Armor.ZBD_04A,
# WW2
Armor.AC_Sd_Kfz_234_2_Puma,
Armor.LAC_M8_Greyhound,
Armor.Daimler_Armoured_Car,
Armor.IFV_Sd_Kfz_234_2_Puma,
Armor.Car_M8_Greyhound_Armored,
Armor.Car_Daimler_Armored,
# Mods
frenchpack.ERC_90,
frenchpack.VBAE_CRAB,
@@ -77,23 +77,23 @@ TYPE_IFV = [
]
TYPE_APC = [
Armor.APC_M1043_HMMWV_Armament,
Armor.APC_M1126_Stryker_ICV,
Armor.APC_HMMWV__Scout,
Armor.IFV_M1126_Stryker_ICV,
Armor.APC_M113,
Armor.APC_BTR_80,
Armor.APC_BTR_82A,
Armor.APC_MTLB,
Armor.APC_M2A1,
Armor.APC_Cobra,
Armor.APC_Sd_Kfz_251,
Armor.APC_AAV_7,
Armor.TPz_Fuchs,
Armor.ARV_BRDM_2,
Armor.ARV_BTR_RD,
Armor.FDDM_Grad,
Armor.APC_M2A1_Halftrack,
Armor.APC_Cobra__Scout,
Armor.APC_Sd_Kfz_251_Halftrack,
Armor.APC_AAV_7_Amphibious,
Armor.APC_TPz_Fuchs,
Armor.IFV_BRDM_2,
Armor.APC_BTR_RD,
Artillery.Grad_MRL_FDDM__FC,
# WW2
Armor.APC_M2A1,
Armor.APC_Sd_Kfz_251,
Armor.APC_M2A1_Halftrack,
Armor.APC_Sd_Kfz_251_Halftrack,
# Mods
frenchpack.VAB__50,
frenchpack.VBL__50,
@@ -101,80 +101,82 @@ TYPE_APC = [
]
TYPE_ARTILLERY = [
Artillery.MLRS_9A52_Smerch,
Artillery.SPH_2S1_Gvozdika,
Artillery.SPH_2S3_Akatsia,
Artillery.MLRS_BM_21_Grad,
Artillery.MLRS_9K57_Uragan_BM_27,
Artillery.SPH_M109_Paladin,
Artillery.MLRS_M270,
Artillery.SPH_2S9_Nona,
Artillery.SpGH_Dana,
Artillery.SPH_2S19_Msta,
Artillery.MLRS_FDDM,
Artillery.MLRS_9A52_Smerch_HE_300mm,
Artillery.SPH_2S1_Gvozdika_122mm,
Artillery.SPH_2S3_Akatsia_152mm,
Artillery.MLRS_BM_21_Grad_122mm,
Artillery.MLRS_BM_27_Uragan_220mm,
Artillery.SPH_M109_Paladin_155mm,
Artillery.MLRS_M270_227mm,
Artillery.SPH_2S9_Nona_120mm_M,
Artillery.SPH_Dana_vz77_152mm,
Artillery.PLZ_05,
Artillery.SPH_2S19_Msta_152mm,
Artillery.MLRS_9A52_Smerch_CM_300mm,
# WW2
Artillery.Sturmpanzer_IV_Brummbär,
Artillery.M12_GMC,
Artillery.SPG_Sturmpanzer_IV_Brummbar,
Artillery.SPG_M12_GMC_155mm,
]
TYPE_LOGI = [
Unarmed.Transport_M818,
Unarmed.Transport_KAMAZ_43101,
Unarmed.Transport_Ural_375,
Unarmed.Transport_GAZ_66,
Unarmed.Transport_GAZ_3307,
Unarmed.Transport_GAZ_3308,
Unarmed.Transport_Ural_4320_31_Armored,
Unarmed.Transport_Ural_4320T,
Unarmed.Blitz_3_6_6700A,
Unarmed.belwagen_82,
Unarmed.Sd_Kfz_7,
Unarmed.Sd_Kfz_2,
Unarmed.Willys_MB,
Unarmed.Land_Rover_109_S3,
Unarmed.Land_Rover_101_FC,
Unarmed.Truck_M818_6x6,
Unarmed.Truck_KAMAZ_43101,
Unarmed.Truck_Ural_375,
Unarmed.Truck_GAZ_66,
Unarmed.Truck_GAZ_3307,
Unarmed.Truck_GAZ_3308,
Unarmed.Truck_Ural_4320_31_Arm_d,
Unarmed.Truck_Ural_4320T,
Unarmed.Truck_Opel_Blitz,
Unarmed.LUV_Kubelwagen_82,
Unarmed.Carrier_Sd_Kfz_7_Tractor,
Unarmed.LUV_Kettenrad,
Unarmed.Car_Willys_Jeep,
Unarmed.LUV_Land_Rover_109,
Unarmed.Truck_Land_Rover_101_FC,
# Mods
frenchpack.VBL,
frenchpack.VAB,
]
TYPE_INFANTRY = [
Infantry.Infantry_Soldier_Insurgents,
Infantry.Soldier_AK,
Infantry.Insurgent_AK_74,
Infantry.Infantry_AK_74,
Infantry.Infantry_M1_Garand,
Infantry.Infantry_Mauser_98,
Infantry.Infantry_SMLE_No_4_Mk_1,
Infantry.Georgian_soldier_with_M4,
Infantry.Infantry_Soldier_Rus,
Infantry.Infantry_M4_Georgia,
Infantry.Infantry_AK_74_Rus,
Infantry.Paratrooper_AKS,
Infantry.Paratrooper_RPG_16,
Infantry.Soldier_M249,
Infantry.Infantry_M249,
Infantry.Infantry_M4,
Infantry.Soldier_RPG,
Infantry.Infantry_RPG,
]
TYPE_SHORAD = [
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
AirDefence.AAA_ZSU_57_2,
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_13_Strela_10M3_9A35M3,
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375,
AirDefence.SPAAA_ZSU_57_2,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
AirDefence.SAM_SA_8_Osa_Gecko_TEL,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL,
AirDefence.SAM_SA_15_Tor_Gauntlet,
AirDefence.SAM_SA_19_Tunguska_Grison,
AirDefence.SPAAA_Gepard,
AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Linebacker_M6,
AirDefence.SPAAA_Vulcan_M163,
AirDefence.SAM_Linebacker___Bradley_M6,
AirDefence.SAM_Chaparral_M48,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger__Stinger,
AirDefence.SAM_Roland_ADS,
AirDefence.HQ_7_Self_Propelled_LN,
AirDefence.AAA_8_8cm_Flak_18,
AirDefence.AAA_8_8cm_Flak_36,
AirDefence.AAA_8_8cm_Flak_37,
AirDefence.AAA_8_8cm_Flak_41,
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_40mm_Bofors,
AirDefence.AAA_S_60_57mm,
AirDefence.AAA_M1_37mm,
AirDefence.AA_gun_QF_3_7,
AirDefence.AAA_QF_3_7,
]

View File

@@ -11,9 +11,10 @@ import logging
import random
from typing import Dict, Iterator, Optional, TYPE_CHECKING, Type, List
from dcs import Mission, Point
from dcs import Mission, Point, unitgroup
from dcs.country import Country
from dcs.statics import fortification_map, warehouse_map
from dcs.point import StaticPoint
from dcs.statics import fortification_map, warehouse_map, Warehouse
from dcs.task import (
ActivateBeaconCommand,
ActivateICLSCommand,
@@ -21,7 +22,7 @@ from dcs.task import (
OptAlarmState,
FireAtPoint,
)
from dcs.unit import Ship, Unit, Vehicle
from dcs.unit import Ship, Unit, Vehicle, SingleHeliPad, Static
from dcs.unitgroup import Group, ShipGroup, StaticGroup, VehicleGroup
from dcs.unittype import StaticType, UnitType
from dcs.vehicles import vehicle_map
@@ -47,7 +48,6 @@ from .tacan import TacanBand, TacanChannel, TacanRegistry
if TYPE_CHECKING:
from game import Game
FARP_FRONTLINE_DISTANCE = 10000
AA_CP_MIN_DISTANCE = 40000
@@ -402,20 +402,23 @@ class CarrierGenerator(GenericCarrierGenerator):
def tacan_callsign(self) -> str:
# TODO: Assign these properly.
return random.choice(
[
"STE",
"CVN",
"CVH",
"CCV",
"ACC",
"ARC",
"GER",
"ABR",
"LIN",
"TRU",
]
)
if self.control_point.name == "Carrier Strike Group 8":
return "TRU"
else:
return random.choice(
[
"STE",
"CVN",
"CVH",
"CCV",
"ACC",
"ARC",
"GER",
"ABR",
"LIN",
"TRU",
]
)
class LhaGenerator(GenericCarrierGenerator):
@@ -474,6 +477,48 @@ class ShipObjectGenerator(GenericGroundObjectGenerator):
self._register_unit_group(group_def, group)
class HelipadGenerator:
"""
Generates helipads for given control point
"""
def __init__(
self,
mission: Mission,
cp: ControlPoint,
game: Game,
radio_registry: RadioRegistry,
tacan_registry: TacanRegistry,
):
self.m = mission
self.cp = cp
self.game = game
self.radio_registry = radio_registry
self.tacan_registry = tacan_registry
def generate(self) -> None:
if self.cp.captured:
country_name = self.game.player_country
else:
country_name = self.game.enemy_country
country = self.m.country(country_name)
for i, helipad in enumerate(self.cp.helipads):
name = self.cp.name + "_helipad_" + str(i)
logging.info("Generating helipad : " + name)
pad = SingleHeliPad(name=self.m.string(name + "_unit"))
pad.position = Point(helipad.x, helipad.y)
pad.heading = helipad.heading
# pad.heliport_frequency = self.radio_registry.alloc_uhf() TODO : alloc radio & callsign
sg = unitgroup.StaticGroup(self.m.next_group_id(), self.m.string(name))
sg.add_unit(pad)
sp = StaticPoint()
sp.position = pad.position
sg.add_point(sp)
country.add_static_group(sg)
class GroundObjectsGenerator:
"""Creates DCS groups and statics for the theater during mission generation.
@@ -507,6 +552,10 @@ class GroundObjectsGenerator:
country_name = self.game.enemy_country
country = self.m.country(country_name)
HelipadGenerator(
self.m, cp, self.game, self.radio_registry, self.tacan_registry
).generate()
for ground_object in cp.ground_objects:
if isinstance(ground_object, BuildingGroundObject):
generator = BuildingSiteGenerator(

View File

@@ -41,6 +41,7 @@ from .flights.flight import FlightWaypoint, FlightWaypointType
from .radios import RadioFrequency
from .runways import RunwayData
if TYPE_CHECKING:
from game import Game
@@ -48,17 +49,33 @@ if TYPE_CHECKING:
class KneeboardPageWriter:
"""Creates kneeboard images."""
def __init__(self, page_margin: int = 24, line_spacing: int = 12) -> None:
self.image = Image.new("RGB", (768, 1024), (0xFF, 0xFF, 0xFF))
def __init__(
self, page_margin: int = 24, line_spacing: int = 12, dark_theme: bool = False
) -> None:
if dark_theme:
self.foreground_fill = (215, 200, 200)
self.background_fill = (10, 5, 5)
else:
self.foreground_fill = (15, 15, 15)
self.background_fill = (255, 252, 252)
self.image = Image.new("RGB", (768, 1024), self.background_fill)
# These font sizes create a relatively full page for current sorties. If
# we start generating more complicated flight plans, or start including
# more information in the comm ladder (the latter of which we should
# probably do), we'll need to split some of this information off into a
# second page.
self.title_font = ImageFont.truetype("arial.ttf", 32)
self.heading_font = ImageFont.truetype("arial.ttf", 24)
self.content_font = ImageFont.truetype("arial.ttf", 20)
self.table_font = ImageFont.truetype("resources/fonts/Inconsolata.otf", 20)
self.title_font = ImageFont.truetype(
"arial.ttf", 32, layout_engine=ImageFont.LAYOUT_BASIC
)
self.heading_font = ImageFont.truetype(
"arial.ttf", 24, layout_engine=ImageFont.LAYOUT_BASIC
)
self.content_font = ImageFont.truetype(
"arial.ttf", 20, layout_engine=ImageFont.LAYOUT_BASIC
)
self.table_font = ImageFont.truetype(
"resources/fonts/Inconsolata.otf", 20, layout_engine=ImageFont.LAYOUT_BASIC
)
self.draw = ImageDraw.Draw(self.image)
self.x = page_margin
self.y = page_margin
@@ -79,10 +96,10 @@ class KneeboardPageWriter:
self.y += height + self.line_spacing
def title(self, title: str) -> None:
self.text(title, font=self.title_font)
self.text(title, font=self.title_font, fill=self.foreground_fill)
def heading(self, text: str) -> None:
self.text(text, font=self.heading_font)
self.text(text, font=self.heading_font, fill=self.foreground_fill)
def table(
self, cells: List[List[str]], headers: Optional[List[str]] = None
@@ -90,7 +107,7 @@ class KneeboardPageWriter:
if headers is None:
headers = []
table = tabulate(cells, headers=headers, numalign="right")
self.text(table, font=self.table_font)
self.text(table, font=self.table_font, fill=self.foreground_fill)
def write(self, path: Path) -> None:
self.image.save(path)
@@ -237,6 +254,7 @@ class BriefingPage(KneeboardPage):
tankers: List[TankerInfo],
jtacs: List[JtacInfo],
start_time: datetime.datetime,
dark_kneeboard: bool,
) -> None:
self.flight = flight
self.comms = list(comms)
@@ -244,11 +262,16 @@ class BriefingPage(KneeboardPage):
self.tankers = tankers
self.jtacs = jtacs
self.start_time = start_time
self.dark_kneeboard = dark_kneeboard
self.comms.append(CommInfo("Flight", self.flight.intra_flight_channel))
def write(self, path: Path) -> None:
writer = KneeboardPageWriter()
writer.title(f"{self.flight.callsign} Mission Info")
writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard)
if self.flight.custom_name is not None:
custom_name_title = ' ("{}")'.format(self.flight.custom_name)
else:
custom_name_title = ""
writer.title(f"{self.flight.callsign} Mission Info{custom_name_title}")
# TODO: Handle carriers.
writer.heading("Airfield Info")
@@ -281,6 +304,34 @@ class BriefingPage(KneeboardPage):
["Bingo", "Joker"],
)
# AEW&C
writer.heading("AEW&C")
aewc_ladder = []
for single_aewc in self.awacs:
if single_aewc.depature_location is None:
dep = "-"
arr = "-"
else:
dep = self._format_time(single_aewc.start_time)
arr = self._format_time(single_aewc.end_time)
aewc_ladder.append(
[
str(single_aewc.callsign),
str(single_aewc.freq),
str(single_aewc.depature_location),
str(dep),
str(arr),
]
)
writer.table(
aewc_ladder,
headers=["Callsign", "FREQ", "Depature", "ETD", "ETA"],
)
# Package Section
writer.heading("Comm ladder")
comm_ladder = []
@@ -289,10 +340,6 @@ class BriefingPage(KneeboardPage):
[comm.name, "", "", "", self.format_frequency(comm.freq)]
)
for a in self.awacs:
comm_ladder.append(
[a.callsign, "AWACS", "", "", self.format_frequency(a.freq)]
)
for tanker in self.tankers:
comm_ladder.append(
[
@@ -361,12 +408,21 @@ class BriefingPage(KneeboardPage):
channel_name = namer.channel_name(channel.radio_id, channel.channel)
return f"{channel_name} {frequency}"
def _format_time(self, time: Optional[datetime.timedelta]) -> str:
if time is None:
return ""
local_time = self.start_time + time
return local_time.strftime(f"%H:%M:%S")
class KneeboardGenerator(MissionInfoGenerator):
"""Creates kneeboard pages for each client flight in the mission."""
def __init__(self, mission: Mission, game: "Game") -> None:
super().__init__(mission, game)
self.dark_kneeboard = self.game.settings.generate_dark_kneeboard and (
self.mission.start_time.hour > 19 or self.mission.start_time.hour < 7
)
def generate(self) -> None:
"""Generates a kneeboard per client flight."""
@@ -410,5 +466,6 @@ class KneeboardGenerator(MissionInfoGenerator):
self.tankers,
self.jtacs,
self.mission.start_time,
self.dark_kneeboard,
),
]

View File

@@ -9,7 +9,7 @@ from gen.locations.preset_locations import PresetLocation
class PresetControlPointLocations:
"""A repository of preset locations for a given control point"""
# List of possible ashore locations to generate objects (Represented in miz file by an APC_AAV_7)
# List of possible ashore locations to generate objects (Represented in miz file by an APC_AAV_7_Amphibious)
ashore_locations: List[PresetLocation] = field(default_factory=list)
# List of possible offshore locations to generate ship groups (Represented in miz file by an Oliver Hazard Perry)

View File

@@ -44,7 +44,7 @@ class MizDataLocationFinder:
for ship_group in m.country("USA").ship_group:
if (
len(ship_group.units) > 0
and ship_group.units[0].type == ships.Oliver_Hazzard_Perry_class.id
and ship_group.units[0].type == ships.FFG_Oliver_Hazzard_Perry.id
):
offshore_locations.append(
PresetLocation(
@@ -68,7 +68,8 @@ class MizDataLocationFinder:
for vehicle_group in m.country("Iran").vehicle_group:
if (
len(vehicle_group.units) > 0
and vehicle_group.units[0].type == MissilesSS.SS_N_2_Silkworm.id
and vehicle_group.units[0].type
== MissilesSS.AShM_SS_N_2_Silkworm.id
):
antiship_locations.append(
PresetLocation(

View File

@@ -9,7 +9,7 @@ MISSILES_MAP = {"V1GroupGenerator": V1GroupGenerator, "ScudGenerator": ScudGener
def generate_missile_group(game, ground_object, faction_name: str):
"""
This generate a ship group
This generate a missiles group
:return: Nothing, but put the group reference inside the ground object
"""
faction = db.FACTIONS[faction_name]

View File

@@ -14,21 +14,21 @@ class ScudGenerator(GroupGenerator):
# Scuds
self.add_unit(
MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M,
MissilesSS.SSM_SS_1C_Scud_B,
"V1#0",
self.position.x,
self.position.y + random.randint(1, 8),
self.heading,
)
self.add_unit(
MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M,
MissilesSS.SSM_SS_1C_Scud_B,
"V1#1",
self.position.x + 50,
self.position.y + random.randint(1, 8),
self.heading,
)
self.add_unit(
MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M,
MissilesSS.SSM_SS_1C_Scud_B,
"V1#2",
self.position.x + 100,
self.position.y + random.randint(1, 8),
@@ -37,7 +37,7 @@ class ScudGenerator(GroupGenerator):
# Commander
self.add_unit(
Unarmed.Transport_UAZ_469,
Unarmed.LUV_UAZ_469_Jeep,
"Kubel#0",
self.position.x - 35,
self.position.y - 20,
@@ -46,7 +46,7 @@ class ScudGenerator(GroupGenerator):
# Shorad
self.add_unit(
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
"SHILKA#0",
self.position.x - 55,
self.position.y - 38,
@@ -54,7 +54,7 @@ class ScudGenerator(GroupGenerator):
)
self.add_unit(
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
"STRELA#0",
self.position.x + 200,
self.position.y + 15,

View File

@@ -14,21 +14,21 @@ class V1GroupGenerator(GroupGenerator):
# Ramps
self.add_unit(
MissilesSS.V_1_ramp,
MissilesSS.SSM_V_1_Launcher,
"V1#0",
self.position.x,
self.position.y + random.randint(1, 8),
self.heading,
)
self.add_unit(
MissilesSS.V_1_ramp,
MissilesSS.SSM_V_1_Launcher,
"V1#1",
self.position.x + 50,
self.position.y + random.randint(1, 8),
self.heading,
)
self.add_unit(
MissilesSS.V_1_ramp,
MissilesSS.SSM_V_1_Launcher,
"V1#2",
self.position.x + 100,
self.position.y + random.randint(1, 8),
@@ -37,7 +37,7 @@ class V1GroupGenerator(GroupGenerator):
# Commander
self.add_unit(
Unarmed.belwagen_82,
Unarmed.LUV_Kubelwagen_82,
"Kubel#0",
self.position.x - 35,
self.position.y - 20,
@@ -46,7 +46,7 @@ class V1GroupGenerator(GroupGenerator):
# Self defense flak
flak_unit = random.choice(
[AirDefence.AAA_Flak_Vierling_38, AirDefence.AAA_Flak_38]
[AirDefence.AAA_Flak_Vierling_38_Quad_20mm, AirDefence.AAA_Flak_38_20mm]
)
self.add_unit(
@@ -58,7 +58,7 @@ class V1GroupGenerator(GroupGenerator):
)
self.add_unit(
Unarmed.Blitz_3_6_6700A,
Unarmed.Truck_Opel_Blitz,
"Blitz#0",
self.position.x + 200,
self.position.y + 15,

View File

@@ -61,7 +61,7 @@ ANIMALS = [
"MAMBA",
"DOLPHIN",
"PHEASANT",
"ARMADILLLO",
"ARMADILLO",
"RACOON",
"ZEBRA",
"COW",

View File

@@ -27,7 +27,7 @@ class BoforsGenerator(AirDefenseGroupGenerator):
for j in range(grid_y):
index = index + 1
self.add_unit(
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_40mm_Bofors,
"AAA#" + str(index),
self.position.x + spacing * i,
self.position.y + spacing * j,

View File

@@ -8,12 +8,12 @@ from gen.sam.airdefensegroupgenerator import (
)
GFLAK = [
AirDefence.AAA_Flak_Vierling_38,
AirDefence.AAA_Flak_Vierling_38_Quad_20mm,
AirDefence.AAA_8_8cm_Flak_18,
AirDefence.AAA_8_8cm_Flak_36,
AirDefence.AAA_8_8cm_Flak_37,
AirDefence.AAA_8_8cm_Flak_41,
AirDefence.AAA_Flak_38,
AirDefence.AAA_Flak_38_20mm,
]
@@ -53,7 +53,7 @@ class FlakGenerator(AirDefenseGroupGenerator):
search_pos = self.get_circular_position(random.randint(2, 3), 80)
for index, pos in enumerate(search_pos):
self.add_unit(
AirDefence.Flak_Searchlight_37,
AirDefence.SL_Flakscheinwerfer_37,
"SearchLight#" + str(index),
pos[0],
pos[1],
@@ -62,14 +62,14 @@ class FlakGenerator(AirDefenseGroupGenerator):
# Support
self.add_unit(
AirDefence.Maschinensatz_33,
AirDefence.PU_Maschinensatz_33,
"MC33#",
self.position.x - 20,
self.position.y - 20,
self.heading,
)
self.add_unit(
AirDefence.AAA_Kdo_G_40,
AirDefence.AAA_SP_Kdo_G_40,
"KDO#",
self.position.x - 25,
self.position.y - 20,
@@ -78,7 +78,7 @@ class FlakGenerator(AirDefenseGroupGenerator):
# Commander
self.add_unit(
Unarmed.belwagen_82,
Unarmed.LUV_Kubelwagen_82,
"Kubel#",
self.position.x - 35,
self.position.y - 20,
@@ -89,7 +89,7 @@ class FlakGenerator(AirDefenseGroupGenerator):
for i in range(int(max(1, grid_x / 2))):
for j in range(int(max(1, grid_x / 2))):
self.add_unit(
Unarmed.Blitz_3_6_6700A,
Unarmed.Truck_Opel_Blitz,
"BLITZ#" + str(index),
self.position.x + 125 + 15 * i + random.randint(1, 5),
self.position.y + 15 * j + random.randint(1, 5),

View File

@@ -34,7 +34,7 @@ class Flak18Generator(AirDefenseGroupGenerator):
# Add a commander truck
self.add_unit(
Unarmed.Blitz_3_6_6700A,
Unarmed.Truck_Opel_Blitz,
"Blitz#",
self.position.x - 35,
self.position.y - 20,

View File

@@ -21,7 +21,7 @@ class AllyWW2FlakGenerator(AirDefenseGroupGenerator):
positions = self.get_circular_position(4, launcher_distance=30, coverage=360)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.AA_gun_QF_3_7,
AirDefence.AAA_QF_3_7,
"AA#" + str(i),
position[0],
position[1],
@@ -41,7 +41,7 @@ class AllyWW2FlakGenerator(AirDefenseGroupGenerator):
positions = self.get_circular_position(8, launcher_distance=90, coverage=360)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.AAA_M45_Quadmount,
AirDefence.AAA_M45_Quadmount_HB_12_7mm,
"AA#" + str(12 + i),
position[0],
position[1],
@@ -50,28 +50,28 @@ class AllyWW2FlakGenerator(AirDefenseGroupGenerator):
# Add a commander truck
self.add_unit(
Unarmed.Willys_MB,
Unarmed.Car_Willys_Jeep,
"CMD#1",
self.position.x,
self.position.y - 20,
random.randint(0, 360),
)
self.add_unit(
Armor.M30_Cargo_Carrier,
Unarmed.Carrier_M30_Cargo,
"LOG#1",
self.position.x,
self.position.y + 20,
random.randint(0, 360),
)
self.add_unit(
Armor.M4_Tractor,
Unarmed.Tractor_M4_Hi_Speed,
"LOG#2",
self.position.x + 20,
self.position.y,
random.randint(0, 360),
)
self.add_unit(
Unarmed.Bedford_MWD,
Unarmed.Truck_Bedford,
"LOG#3",
self.position.x - 20,
self.position.y,

View File

@@ -21,7 +21,7 @@ class ZSU57Generator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.AAA_ZSU_57_2,
AirDefence.SPAAA_ZSU_57_2,
"SPAA#" + str(i),
position[0],
position[1],

View File

@@ -27,7 +27,7 @@ class ZU23InsurgentGenerator(AirDefenseGroupGenerator):
for j in range(grid_y):
index = index + 1
self.add_unit(
AirDefence.AAA_ZU_23_Insurgent_Closed,
AirDefence.AAA_ZU_23_Closed_Emplacement_Insurgent,
"AAA#" + str(index),
self.position.x + spacing * i,
self.position.y + spacing * j,

View File

@@ -12,13 +12,13 @@ from gen.sam.group_generator import GroupGenerator
class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
"""
This generator attempt to mimic an early cold-war era flak AAA site.
The Flak 18 88mm is used as the main long range gun and 2 Bofors 40mm guns provide short range protection.
The Flak 18 88mm is used as the main long range gun, S-60 is used as a mid range gun and 2 Bofors 40mm guns provide short range protection.
This does not include search lights and telemeter computer (Kdo.G 40) because these are paid units only available in WW2 asset pack
"""
name = "Early Cold War Flak Site"
price = 58
price = 74
def generate(self):
@@ -37,25 +37,41 @@ class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
self.heading,
)
# Short range guns
# Medium range guns
self.add_unit(
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_S_60_57mm,
"SHO#1",
self.position.x - 40,
self.position.y - 40,
self.heading + 180,
),
self.add_unit(
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_S_60_57mm,
"SHO#2",
self.position.x + spacing * 2 + 40,
self.position.y + spacing + 40,
self.heading,
),
# Short range guns
self.add_unit(
AirDefence.AAA_ZU_23_Closed_Emplacement,
"SHO#3",
self.position.x - 80,
self.position.y - 40,
self.heading + 180,
),
self.add_unit(
AirDefence.AAA_ZU_23_Closed_Emplacement,
"SHO#4",
self.position.x + spacing * 2 + 80,
self.position.y + spacing + 40,
self.heading,
),
# Add a truck
self.add_unit(
Unarmed.Transport_KAMAZ_43101,
Unarmed.Truck_KAMAZ_43101,
"Truck#",
self.position.x - 60,
self.position.y - 20,
@@ -70,7 +86,7 @@ class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
class ColdWarFlakGenerator(AirDefenseGroupGenerator):
"""
This generator attempt to mimic a cold-war era flak AAA site.
The Flak 18 88mm is used as the main long range gun while 2 Zu-23 guns provide short range protection.
The Flak 18 88mm is used as the main long range gun, 2 S-60 57mm gun improve mid range firepower, while 2 Zu-23 guns even provide short range protection.
The site is also fitted with a P-19 radar for early detection.
"""
@@ -94,25 +110,41 @@ class ColdWarFlakGenerator(AirDefenseGroupGenerator):
self.heading,
)
# Short range guns
# Medium range guns
self.add_unit(
AirDefence.AAA_ZU_23_Closed,
AirDefence.AAA_S_60_57mm,
"SHO#1",
self.position.x - 40,
self.position.y - 40,
self.heading + 180,
),
self.add_unit(
AirDefence.AAA_ZU_23_Closed,
AirDefence.AAA_S_60_57mm,
"SHO#2",
self.position.x + spacing * 2 + 40,
self.position.y + spacing + 40,
self.heading,
),
# Short range guns
self.add_unit(
AirDefence.AAA_ZU_23_Closed_Emplacement,
"SHO#3",
self.position.x - 80,
self.position.y - 40,
self.heading + 180,
),
self.add_unit(
AirDefence.AAA_ZU_23_Closed_Emplacement,
"SHO#4",
self.position.x + spacing * 2 + 80,
self.position.y + spacing + 40,
self.heading,
),
# Add a P19 Radar for EWR
self.add_unit(
AirDefence.SAM_SR_P_19,
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3,
"SR#0",
self.position.x - 60,
self.position.y - 20,

View File

@@ -0,0 +1,63 @@
import random
from typing import List, Optional, Type
from dcs.unitgroup import VehicleGroup
from game import Game
from game.factions.faction import Faction
from game.theater.theatergroundobject import EwrGroundObject
from gen.sam.ewrs import (
BigBirdGenerator,
BoxSpringGenerator,
DogEarGenerator,
FlatFaceGenerator,
HawkEwrGenerator,
PatriotEwrGenerator,
RolandEwrGenerator,
SnowDriftGenerator,
StraightFlushGenerator,
TallRackGenerator,
)
from gen.sam.group_generator import GroupGenerator
EWR_MAP = {
"BoxSpringGenerator": BoxSpringGenerator,
"TallRackGenerator": TallRackGenerator,
"DogEarGenerator": DogEarGenerator,
"RolandEwrGenerator": RolandEwrGenerator,
"FlatFaceGenerator": FlatFaceGenerator,
"PatriotEwrGenerator": PatriotEwrGenerator,
"BigBirdGenerator": BigBirdGenerator,
"SnowDriftGenerator": SnowDriftGenerator,
"StraightFlushGenerator": StraightFlushGenerator,
"HawkEwrGenerator": HawkEwrGenerator,
}
def get_faction_possible_ewrs_generator(
faction: Faction,
) -> List[Type[GroupGenerator]]:
"""
Return the list of possible EWR generators for the given faction
:param faction: Faction name to search units for
"""
return [EWR_MAP[s] for s in faction.ewrs]
def generate_ewr_group(
game: Game, ground_object: EwrGroundObject, faction: Faction
) -> Optional[VehicleGroup]:
"""Generates an early warning radar group.
:param game: The Game.
:param ground_object: The ground object which will own the EWR group.
:param faction: Owner faction.
:return: The generated group, or None if one could not be generated.
"""
generators = get_faction_possible_ewrs_generator(faction)
if len(generators) > 0:
generator_class = random.choice(generators)
generator = generator_class(game, ground_object)
generator.generate()
return generator.get_generated_group()
return None

View File

@@ -33,7 +33,7 @@ class DogEarGenerator(EwrGenerator):
This is the SA-8 search radar, but used as an early warning radar.
"""
unit_type = AirDefence.CP_9S80M1_Sborka
unit_type = AirDefence.MCC_SR_Sborka_Dog_Ear_SR
class RolandEwrGenerator(EwrGenerator):
@@ -51,7 +51,7 @@ class FlatFaceGenerator(EwrGenerator):
This is the SA-3 search radar, but used as an early warning radar.
"""
unit_type = AirDefence.SAM_SR_P_19
unit_type = AirDefence.SAM_P19_Flat_Face_SR__SA_2_3
class PatriotEwrGenerator(EwrGenerator):
@@ -60,7 +60,7 @@ class PatriotEwrGenerator(EwrGenerator):
This is the Patriot search/track radar, but used as an early warning radar.
"""
unit_type = AirDefence.SAM_Patriot_STR_AN_MPQ_53
unit_type = AirDefence.SAM_Patriot_STR
class BigBirdGenerator(EwrGenerator):
@@ -69,7 +69,7 @@ class BigBirdGenerator(EwrGenerator):
This is the SA-10 track radar, but used as an early warning radar.
"""
unit_type = AirDefence.SAM_SA_10_S_300PS_SR_64H6E
unit_type = AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR
class SnowDriftGenerator(EwrGenerator):
@@ -78,7 +78,7 @@ class SnowDriftGenerator(EwrGenerator):
This is the SA-11 search radar, but used as an early warning radar.
"""
unit_type = AirDefence.SAM_SA_11_Buk_SR_9S18M1
unit_type = AirDefence.SAM_SA_11_Buk_Gadfly_Snow_Drift_SR
class StraightFlushGenerator(EwrGenerator):
@@ -87,7 +87,7 @@ class StraightFlushGenerator(EwrGenerator):
This is the SA-6 search/track radar, but used as an early warning radar.
"""
unit_type = AirDefence.SAM_SA_6_Kub_STR_9S91
unit_type = AirDefence.SAM_SA_6_Kub_Long_Track_STR
class HawkEwrGenerator(EwrGenerator):
@@ -96,4 +96,4 @@ class HawkEwrGenerator(EwrGenerator):
This is the Hawk search radar, but used as an early warning radar.
"""
unit_type = AirDefence.SAM_Hawk_SR_AN_MPQ_50
unit_type = AirDefence.SAM_Hawk_SR__AN_MPQ_50

View File

@@ -28,7 +28,7 @@ class FreyaGenerator(AirDefenseGroupGenerator):
positions = self.get_circular_position(4, launcher_distance=50, coverage=360)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.AAA_Flak_Vierling_38,
AirDefence.AAA_Flak_Vierling_38_Quad_20mm,
"AA#" + str(i),
position[0],
position[1],
@@ -47,37 +47,37 @@ class FreyaGenerator(AirDefenseGroupGenerator):
# Command/Logi
self.add_unit(
Unarmed.belwagen_82,
Unarmed.LUV_Kubelwagen_82,
"Kubel#1",
self.position.x - 20,
self.position.y - 20,
self.heading,
)
self.add_unit(
Unarmed.Sd_Kfz_7,
Unarmed.Carrier_Sd_Kfz_7_Tractor,
"Sdkfz#1",
self.position.x + 20,
self.position.y + 22,
self.heading,
)
self.add_unit(
Unarmed.Sd_Kfz_2,
Unarmed.LUV_Kettenrad,
"Sdkfz#2",
self.position.x - 22,
self.position.y + 20,
self.heading,
)
# Maschinensatz_33 and Kdo.g 40 Telemeter
# PU_Maschinensatz_33 and Kdo.g 40 Telemeter
self.add_unit(
AirDefence.Maschinensatz_33,
AirDefence.PU_Maschinensatz_33,
"Energy#1",
self.position.x + 20,
self.position.y - 20,
self.heading,
)
self.add_unit(
AirDefence.AAA_Kdo_G_40,
AirDefence.AAA_SP_Kdo_G_40,
"Telemeter#1",
self.position.x + 20,
self.position.y - 10,

View File

@@ -20,7 +20,7 @@ class AvengerGenerator(AirDefenseGroupGenerator):
num_launchers = random.randint(2, 3)
self.add_unit(
Unarmed.Transport_M818,
Unarmed.Truck_M818_6x6,
"TRUCK",
self.position.x,
self.position.y,
@@ -31,7 +31,7 @@ class AvengerGenerator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger__Stinger,
"SPAA#" + str(i),
position[0],
position[1],

View File

@@ -20,7 +20,7 @@ class ChaparralGenerator(AirDefenseGroupGenerator):
num_launchers = random.randint(2, 4)
self.add_unit(
Unarmed.Transport_M818,
Unarmed.Truck_M818_6x6,
"TRUCK",
self.position.x,
self.position.y,

View File

@@ -33,7 +33,7 @@ class GepardGenerator(AirDefenseGroupGenerator):
self.heading,
)
self.add_unit(
Unarmed.Transport_M818,
Unarmed.Truck_M818_6x6,
"TRUCK",
self.position.x + 80,
self.position.y,

View File

@@ -6,7 +6,6 @@ from dcs.vehicles import AirDefence
from game import Game
from game.factions.faction import Faction
from game.theater import TheaterGroundObject
from game.theater.theatergroundobject import SamGroundObject
from gen.sam.aaa_bofors import BoforsGenerator
from gen.sam.aaa_flak import FlakGenerator
@@ -23,20 +22,7 @@ from gen.sam.cold_war_flak import (
ColdWarFlakGenerator,
EarlyColdWarFlakGenerator,
)
from gen.sam.ewrs import (
BigBirdGenerator,
BoxSpringGenerator,
DogEarGenerator,
FlatFaceGenerator,
HawkEwrGenerator,
PatriotEwrGenerator,
RolandEwrGenerator,
SnowDriftGenerator,
StraightFlushGenerator,
TallRackGenerator,
)
from gen.sam.freya_ewr import FreyaGenerator
from gen.sam.group_generator import GroupGenerator
from gen.sam.sam_avenger import AvengerGenerator
from gen.sam.sam_chaparral import ChaparralGenerator
from gen.sam.sam_gepard import GepardGenerator
@@ -119,52 +105,39 @@ SAM_MAP: Dict[str, Type[AirDefenseGroupGenerator]] = {
SAM_PRICES = {
AirDefence.SAM_Hawk_PCP: 35,
AirDefence.SAM_Hawk_Generator__PCP: 35,
AirDefence.AAA_ZU_23_Emplacement: 10,
AirDefence.AAA_ZU_23_Closed: 10,
AirDefence.AAA_ZU_23_on_Ural_375: 10,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375: 10,
AirDefence.AAA_ZU_23_Insurgent_Closed: 10,
AirDefence.AAA_ZU_23_Closed_Emplacement: 10,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375: 10,
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375: 10,
AirDefence.AAA_ZU_23_Closed_Emplacement_Insurgent: 10,
AirDefence.AAA_ZU_23_Insurgent: 10,
AirDefence.SPAAA_ZSU_23_4_Shilka: 10,
AirDefence.AAA_Vulcan_M163: 15,
AirDefence.SAM_Linebacker_M6: 20,
AirDefence.Rapier_FSA_Launcher: 20,
AirDefence.SAM_Avenger_M1097: 22,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish: 10,
AirDefence.SPAAA_Vulcan_M163: 15,
AirDefence.SAM_Linebacker___Bradley_M6: 20,
AirDefence.SAM_Rapier_LN: 20,
AirDefence.SAM_Avenger__Stinger: 22,
AirDefence.SPAAA_Gepard: 24,
AirDefence.SAM_Roland_ADS: 40,
AirDefence.SAM_Patriot_LN_M901: 85,
AirDefence.SAM_Patriot_LN: 85,
AirDefence.SAM_Patriot_EPP_III: 85,
AirDefence.SAM_Chaparral_M48: 25,
AirDefence.AAA_Bofors_40mm: 15,
AirDefence.AAA_40mm_Bofors: 15,
AirDefence.AAA_8_8cm_Flak_36: 15,
AirDefence.SAM_SA_2_LN_SM_90: 30,
AirDefence.SAM_SA_3_S_125_LN_5P73: 35,
AirDefence.SAM_SA_6_Kub_LN_2P25: 45,
AirDefence.SAM_SA_8_Osa_9A33: 30,
AirDefence.SAM_SA_9_Strela_1_9P31: 25,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 80,
AirDefence.SAM_SA_10_S_300PS_CP_54K6: 80,
AirDefence.SAM_SA_11_Buk_LN_9A310M1: 60,
AirDefence.SAM_SA_13_Strela_10M3_9A35M3: 30,
AirDefence.SAM_SA_15_Tor_9A331: 40,
AirDefence.SAM_SA_19_Tunguska_2S6: 35,
AirDefence.SAM_SA_2_S_75_Guideline_LN: 30,
AirDefence.SAM_SA_3_S_125_Goa_LN: 35,
AirDefence.SAM_SA_6_Kub_Gainful_TEL: 45,
AirDefence.SAM_SA_8_Osa_Gecko_TEL: 30,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL: 25,
AirDefence.SAM_SA_10_S_300_Grumble_TEL_C: 80,
AirDefence.SAM_SA_10_S_300_Grumble_C2: 80,
AirDefence.SAM_SA_11_Buk_Gadfly_Fire_Dome_TEL: 60,
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL: 30,
AirDefence.SAM_SA_15_Tor_Gauntlet: 40,
AirDefence.SAM_SA_19_Tunguska_Grison: 35,
AirDefence.HQ_7_Self_Propelled_LN: 35,
}
EWR_MAP = {
"BoxSpringGenerator": BoxSpringGenerator,
"TallRackGenerator": TallRackGenerator,
"DogEarGenerator": DogEarGenerator,
"RolandEwrGenerator": RolandEwrGenerator,
"FlatFaceGenerator": FlatFaceGenerator,
"PatriotEwrGenerator": PatriotEwrGenerator,
"BigBirdGenerator": BigBirdGenerator,
"SnowDriftGenerator": SnowDriftGenerator,
"StraightFlushGenerator": StraightFlushGenerator,
"HawkEwrGenerator": HawkEwrGenerator,
}
def get_faction_possible_sams_generator(
faction: Faction,
@@ -176,14 +149,6 @@ def get_faction_possible_sams_generator(
return [SAM_MAP[s] for s in faction.air_defenses]
def get_faction_possible_ewrs_generator(faction: Faction) -> List[Type[GroupGenerator]]:
"""
Return the list of possible SAM generator for the given faction
:param faction: Faction name to search units for
"""
return [EWR_MAP[s] for s in faction.ewrs]
def _generate_anti_air_from(
generators: Sequence[Type[AirDefenseGroupGenerator]],
game: Game,
@@ -236,22 +201,3 @@ def generate_anti_air_group(
if groups:
return groups
return []
def generate_ewr_group(
game: Game, ground_object: TheaterGroundObject, faction: Faction
) -> Optional[VehicleGroup]:
"""Generates an early warning radar group.
:param game: The Game.
:param ground_object: The ground object which will own the EWR group.
:param faction: Owner faction.
:return: The generated group, or None if one could not be generated.
"""
generators = get_faction_possible_ewrs_generator(faction)
if len(generators) > 0:
generator_class = random.choice(generators)
generator = generator_class(game, ground_object)
generator.generate()
return generator.get_generated_group()
return None

View File

@@ -19,21 +19,21 @@ class HawkGenerator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_Hawk_SR_AN_MPQ_50,
AirDefence.SAM_Hawk_SR__AN_MPQ_50,
"SR",
self.position.x + 20,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Hawk_Generator__PCP,
"PCP",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_Hawk_TR_AN_MPQ_46,
AirDefence.SAM_Hawk_TR__AN_MPQ_46,
"TR",
self.position.x + 40,
self.position.y,
@@ -44,7 +44,7 @@ class HawkGenerator(AirDefenseGroupGenerator):
aa_group = self.add_auxiliary_group("AA")
self.add_unit_to_group(
aa_group,
AirDefence.AAA_Vulcan_M163,
AirDefence.SPAAA_Vulcan_M163,
"AAA",
self.position + Point(20, 30),
self.heading,

View File

@@ -37,14 +37,14 @@ class HQ7Generator(AirDefenseGroupGenerator):
aa_group = self.add_auxiliary_group("AA")
self.add_unit_to_group(
aa_group,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
"AAA1",
self.position + Point(20, 30),
self.heading,
)
self.add_unit_to_group(
aa_group,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
"AAA2",
self.position - Point(20, 30),
self.heading,

View File

@@ -20,7 +20,7 @@ class LinebackerGenerator(AirDefenseGroupGenerator):
num_launchers = random.randint(2, 4)
self.add_unit(
Unarmed.Transport_M818,
Unarmed.Truck_M818_6x6,
"TRUCK",
self.position.x,
self.position.y,
@@ -31,7 +31,7 @@ class LinebackerGenerator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_Linebacker_M6,
AirDefence.SAM_Linebacker___Bradley_M6,
"M6#" + str(i),
position[0],
position[1],

View File

@@ -20,28 +20,28 @@ class PatriotGenerator(AirDefenseGroupGenerator):
def generate(self):
# Command Post
self.add_unit(
AirDefence.SAM_Patriot_STR_AN_MPQ_53,
AirDefence.SAM_Patriot_STR,
"STR",
self.position.x + 30,
self.position.y + 30,
self.heading,
)
self.add_unit(
AirDefence.SAM_Patriot_AMG_AN_MRC_137,
AirDefence.SAM_Patriot_CR__AMG_AN_MRC_137,
"MRC",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_Patriot_ECS_AN_MSQ_104,
AirDefence.SAM_Patriot_ECS,
"MSQ",
self.position.x + 30,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_Patriot_ICC,
AirDefence.SAM_Patriot_C2_ICC,
"ICC",
self.position.x + 60,
self.position.y,
@@ -61,7 +61,7 @@ class PatriotGenerator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_Patriot_LN_M901,
AirDefence.SAM_Patriot_LN,
"LN#" + str(i),
position[0],
position[1],
@@ -76,7 +76,11 @@ class PatriotGenerator(AirDefenseGroupGenerator):
)
for i, (x, y, heading) in enumerate(positions):
self.add_unit_to_group(
aa_group, AirDefence.AAA_Vulcan_M163, f"SPAAA#{i}", Point(x, y), heading
aa_group,
AirDefence.SPAAA_Vulcan_M163,
f"SPAAA#{i}",
Point(x, y),
heading,
)
@classmethod

View File

@@ -18,14 +18,14 @@ class RapierGenerator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.Rapier_FSA_Blindfire_Tracker,
AirDefence.SAM_Rapier_Blindfire_TR,
"BT",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.Rapier_FSA_Optical_Tracker,
AirDefence.SAM_Rapier_Tracker,
"OT",
self.position.x + 20,
self.position.y,
@@ -39,7 +39,7 @@ class RapierGenerator(AirDefenseGroupGenerator):
for i, position in enumerate(positions):
self.add_unit(
AirDefence.Rapier_FSA_Launcher,
AirDefence.SAM_Rapier_LN,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -30,7 +30,7 @@ class RolandGenerator(AirDefenseGroupGenerator):
self.heading,
)
self.add_unit(
Unarmed.Transport_M818,
Unarmed.Truck_M818_6x6,
"TRUCK",
self.position.x + 80,
self.position.y,

View File

@@ -1,7 +1,6 @@
import random
from dcs.mapping import Point
from dcs.unittype import VehicleType
from dcs.vehicles import AirDefence
from game import Game
@@ -18,18 +17,18 @@ class SA10Generator(AirDefenseGroupGenerator):
This generate a SA-10 group
"""
name = "SA-10/S-300PS Battery"
name = "SA-10/S-300PS Battery - With ZSU-23"
price = 550
def __init__(self, game: Game, ground_object: SamGroundObject):
super().__init__(game, ground_object)
self.sr1 = AirDefence.SAM_SA_10_S_300PS_SR_5N66M
self.sr2 = AirDefence.SAM_SA_10_S_300PS_SR_64H6E
self.cp = AirDefence.SAM_SA_10_S_300PS_CP_54K6
self.tr1 = AirDefence.SAM_SA_10_S_300PS_TR_30N6
self.tr2 = AirDefence.SAM_SA_10_S_300PS_TR_30N6
self.ln1 = AirDefence.SAM_SA_10_S_300PS_LN_5P85C
self.ln2 = AirDefence.SAM_SA_10_S_300PS_LN_5P85D
self.sr1 = AirDefence.SAM_SA_10_S_300_Grumble_Clam_Shell_SR
self.sr2 = AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR
self.cp = AirDefence.SAM_SA_10_S_300_Grumble_C2
self.tr1 = AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR
self.tr2 = AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR
self.ln1 = AirDefence.SAM_SA_10_S_300_Grumble_TEL_C
self.ln2 = AirDefence.SAM_SA_10_S_300_Grumble_TEL_D
def generate(self):
# Search Radar
@@ -85,7 +84,7 @@ class SA10Generator(AirDefenseGroupGenerator):
for i, (x, y, heading) in enumerate(positions):
self.add_unit_to_group(
aa_group,
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
f"AA#{i}",
Point(x, y),
heading,
@@ -93,6 +92,10 @@ class SA10Generator(AirDefenseGroupGenerator):
class Tier2SA10Generator(SA10Generator):
name = "SA-10/S-300PS Battery - With SA-15 PD"
price = 650
def generate_defensive_groups(self) -> None:
# Create AAA the way the main group does.
super().generate_defensive_groups()
@@ -106,7 +109,7 @@ class Tier2SA10Generator(SA10Generator):
for i, (x, y, heading) in enumerate(positions):
self.add_unit_to_group(
pd_group,
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_15_Tor_Gauntlet,
f"PD#{i}",
Point(x, y),
heading,
@@ -114,6 +117,10 @@ class Tier2SA10Generator(SA10Generator):
class Tier3SA10Generator(SA10Generator):
name = "SA-10/S-300PS Battery - With SA-15 PD & SA-19 SHORAD"
price = 750
def generate_defensive_groups(self) -> None:
# AAA for defending against close targets.
aa_group = self.add_auxiliary_group("AA")
@@ -124,7 +131,7 @@ class Tier3SA10Generator(SA10Generator):
for i, (x, y, heading) in enumerate(positions):
self.add_unit_to_group(
aa_group,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_19_Tunguska_Grison,
f"AA#{i}",
Point(x, y),
heading,
@@ -139,7 +146,7 @@ class Tier3SA10Generator(SA10Generator):
for i, (x, y, heading) in enumerate(positions):
self.add_unit_to_group(
pd_group,
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_15_Tor_Gauntlet,
f"PD#{i}",
Point(x, y),
heading,

View File

@@ -18,14 +18,14 @@ class SA11Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SA_11_Buk_SR_9S18M1,
AirDefence.SAM_SA_11_Buk_Gadfly_Snow_Drift_SR,
"SR",
self.position.x + 20,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_SA_11_Buk_CC_9S470M1,
AirDefence.SAM_SA_11_Buk_Gadfly_C2,
"CC",
self.position.x,
self.position.y,
@@ -39,7 +39,7 @@ class SA11Generator(AirDefenseGroupGenerator):
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_11_Buk_LN_9A310M1,
AirDefence.SAM_SA_11_Buk_Gadfly_Fire_Dome_TEL,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -18,14 +18,14 @@ class SA13Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
Unarmed.Transport_UAZ_469,
Unarmed.LUV_UAZ_469_Jeep,
"UAZ",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
Unarmed.Transport_KAMAZ_43101,
Unarmed.Truck_KAMAZ_43101,
"TRUCK",
self.position.x + 40,
self.position.y,
@@ -38,7 +38,7 @@ class SA13Generator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_13_Strela_10M3_9A35M3,
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -16,21 +16,21 @@ class SA15Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_15_Tor_Gauntlet,
"ADS",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
Unarmed.Transport_UAZ_469,
Unarmed.LUV_UAZ_469_Jeep,
"EWR",
self.position.x + 40,
self.position.y,
self.heading,
)
self.add_unit(
Unarmed.Transport_KAMAZ_43101,
Unarmed.Truck_KAMAZ_43101,
"TRUCK",
self.position.x + 80,
self.position.y,

View File

@@ -17,14 +17,14 @@ class SA17Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SA_11_Buk_SR_9S18M1,
AirDefence.SAM_SA_11_Buk_Gadfly_Snow_Drift_SR,
"SR",
self.position.x + 20,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_SA_11_Buk_CC_9S470M1,
AirDefence.SAM_SA_11_Buk_Gadfly_C2,
"CC",
self.position.x,
self.position.y,

View File

@@ -21,7 +21,7 @@ class SA19Generator(AirDefenseGroupGenerator):
if num_launchers == 1:
self.add_unit(
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_19_Tunguska_Grison,
"LN#0",
self.position.x,
self.position.y,
@@ -33,7 +33,7 @@ class SA19Generator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_19_Tunguska_Grison,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -18,10 +18,14 @@ class SA2Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SR_P_19, "SR", self.position.x, self.position.y, self.heading
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3,
"SR",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song,
AirDefence.SAM_SA_2_S_75_Fan_Song_TR,
"TR",
self.position.x + 20,
self.position.y,
@@ -35,7 +39,7 @@ class SA2Generator(AirDefenseGroupGenerator):
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_2_LN_SM_90,
AirDefence.SAM_SA_2_S_75_Guideline_LN,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -18,10 +18,14 @@ class SA3Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SR_P_19, "SR", self.position.x, self.position.y, self.heading
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3,
"SR",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
AirDefence.SAM_SA_3_S_125_TR_SNR,
AirDefence.SAM_SA_3_S_125_Low_Blow_TR,
"TR",
self.position.x + 20,
self.position.y,
@@ -35,7 +39,7 @@ class SA3Generator(AirDefenseGroupGenerator):
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_3_S_125_LN_5P73,
AirDefence.SAM_SA_3_S_125_Goa_LN,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -18,7 +18,7 @@ class SA6Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SA_6_Kub_STR_9S91,
AirDefence.SAM_SA_6_Kub_Long_Track_STR,
"STR",
self.position.x,
self.position.y,
@@ -32,7 +32,7 @@ class SA6Generator(AirDefenseGroupGenerator):
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_6_Kub_LN_2P25,
AirDefence.SAM_SA_6_Kub_Gainful_TEL,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -16,7 +16,7 @@ class SA8Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_8_Osa_Gecko_TEL,
"OSA",
self.position.x,
self.position.y,

View File

@@ -18,14 +18,14 @@ class SA9Generator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
Unarmed.Transport_UAZ_469,
Unarmed.LUV_UAZ_469_Jeep,
"UAZ",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
Unarmed.Transport_KAMAZ_43101,
Unarmed.Truck_KAMAZ_43101,
"TRUCK",
self.position.x + 40,
self.position.y,
@@ -38,7 +38,7 @@ class SA9Generator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
"LN#" + str(i),
position[0],
position[1],

View File

@@ -18,7 +18,7 @@ class VulcanGenerator(AirDefenseGroupGenerator):
def generate(self):
self.add_unit(
AirDefence.AAA_Vulcan_M163,
AirDefence.SPAAA_Vulcan_M163,
"SPAAA",
self.position.x,
self.position.y,
@@ -26,14 +26,14 @@ class VulcanGenerator(AirDefenseGroupGenerator):
)
if random.randint(0, 1) == 1:
self.add_unit(
AirDefence.AAA_Vulcan_M163,
AirDefence.SPAAA_Vulcan_M163,
"SPAAA2",
self.position.x,
self.position.y,
self.heading,
)
self.add_unit(
Unarmed.Transport_M818,
Unarmed.Truck_M818_6x6,
"TRUCK",
self.position.x + 80,
self.position.y,

View File

@@ -24,7 +24,7 @@ class ZSU23Generator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
"SPAA#" + str(i),
position[0],
position[1],

View File

@@ -27,7 +27,7 @@ class ZU23Generator(AirDefenseGroupGenerator):
for j in range(grid_y):
index = index + 1
self.add_unit(
AirDefence.AAA_ZU_23_Closed,
AirDefence.AAA_ZU_23_Closed_Emplacement,
"AAA#" + str(index),
self.position.x + spacing * i,
self.position.y + spacing * j,

View File

@@ -24,7 +24,7 @@ class ZU23UralGenerator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
"SPAA#" + str(i),
position[0],
position[1],

View File

@@ -24,7 +24,7 @@ class ZU23UralInsurgentGenerator(AirDefenseGroupGenerator):
)
for i, position in enumerate(positions):
self.add_unit(
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375,
"SPAA#" + str(i),
position[0],
position[1],

2
pydcs

Submodule pydcs updated: 42de2ec352...cd14f0a049

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@ class F_22A(PlaneType):
chaff_charge_size = 1
flare_charge_size = 2
eplrs = True
category = "Interceptor" #{78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
radio_frequency = 127.5
property_defaults = {
@@ -36,7 +36,6 @@ class F_22A(PlaneType):
id = "BAY_DOOR_OPTION"
class Liveries:
class USSR(Enum):
default = "default"
_154_wg = "154 wg"
@@ -1767,15 +1766,15 @@ class F_22A(PlaneType):
Fuel_tank_610_gal = (2, Weapons.Fuel_tank_610_gal)
class Pylon3:
AIM_120C = (3, Weapons.AIM_120C)
AIM_120C = (3, Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM)
AIM_120D = (3, F22AWeapons.AIM_120D)
class Pylon4:
AIM_120C = (4, Weapons.AIM_120C)
AIM_120C = (4, Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM)
AIM_120D = (4, F22AWeapons.AIM_120D)
class Pylon5:
AIM_120C = (5, Weapons.AIM_120C)
AIM_120C = (5, Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM)
AIM_120D = (5, F22AWeapons.AIM_120D)
class Pylon6:
@@ -1786,15 +1785,15 @@ class F_22A(PlaneType):
Smokewinder___yellow = (6, Weapons.Smokewinder___yellow)
class Pylon7:
AIM_120C = (7, Weapons.AIM_120C)
AIM_120C = (7, Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM)
AIM_120D = (7, F22AWeapons.AIM_120D)
class Pylon8:
AIM_120C = (8, Weapons.AIM_120C)
AIM_120C = (8, Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM)
AIM_120D = (8, F22AWeapons.AIM_120D)
class Pylon9:
AIM_120C = (9, Weapons.AIM_120C)
AIM_120C = (9, Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM)
AIM_120D = (9, F22AWeapons.AIM_120D)
class Pylon10:
@@ -1806,5 +1805,11 @@ class F_22A(PlaneType):
pylons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
tasks = [task.CAP, task.Escort, task.FighterSweep, task.Intercept, task.Reconnaissance]
tasks = [
task.CAP,
task.Escort,
task.FighterSweep,
task.Intercept,
task.Reconnaissance,
]
task_default = task.CAP

View File

@@ -3,6 +3,7 @@
#
from dcs import unittype
class AMX_10RCR(unittype.VehicleType):
id = "AMX10RCR"
name = "AMX-10RCR"
@@ -150,8 +151,10 @@ class DIM__KAMIKAZE(unittype.VehicleType):
air_weapon_dist = 50
eplrs = True
## FORTIFICATION
class _FIELD_HIDE(unittype.VehicleType):
id = "FieldHL"
name = "*FIELD HIDE"
@@ -159,6 +162,7 @@ class _FIELD_HIDE(unittype.VehicleType):
threat_range = 0
air_weapon_dist = 0
class _FIELD_HIDE_SMALL(unittype.VehicleType):
id = "HARRIERH"
name = "*FIELD HIDE SMALL"
@@ -166,6 +170,7 @@ class _FIELD_HIDE_SMALL(unittype.VehicleType):
threat_range = 0
air_weapon_dist = 0
class SmokeD1(unittype.VehicleType):
id = "SmokeD1"
name = "SmokeD1"
@@ -173,6 +178,7 @@ class SmokeD1(unittype.VehicleType):
threat_range = 0
air_weapon_dist = 0
class SmokeD3(unittype.VehicleType):
id = "SmokeD3"
name = "SmokeD3"
@@ -189,6 +195,7 @@ class TRM_2000(unittype.VehicleType):
air_weapon_dist = 0
eplrs = True
class TRM_2000_Fuel(unittype.VehicleType):
id = "TRM2000_Citerne"
name = "TRM-2000 Fuel"
@@ -197,6 +204,7 @@ class TRM_2000_Fuel(unittype.VehicleType):
air_weapon_dist = 0
eplrs = True
class VAB_MEDICAL(unittype.VehicleType):
id = "VABH"
name = "VAB MEDICAL"
@@ -205,6 +213,7 @@ class VAB_MEDICAL(unittype.VehicleType):
air_weapon_dist = 0
eplrs = True
class VAB(unittype.VehicleType):
id = "VAB_RADIO"
name = "VAB"
@@ -213,6 +222,7 @@ class VAB(unittype.VehicleType):
air_weapon_dist = 0
eplrs = True
class VBL(unittype.VehicleType):
id = "VBL-Radio"
name = "VBL"
@@ -221,6 +231,7 @@ class VBL(unittype.VehicleType):
air_weapon_dist = 0
eplrs = True
class Tracma_TD_1500(unittype.VehicleType):
id = "Tracma"
name = "Tracma TD 1500"
@@ -228,8 +239,10 @@ class Tracma_TD_1500(unittype.VehicleType):
threat_range = 0
air_weapon_dist = 0
## AIRDEFENCE
class SMOKE_SAM_IR(unittype.VehicleType):
id = "SMOKESAM"
name = "SMOKE SAM IR"
@@ -238,6 +251,7 @@ class SMOKE_SAM_IR(unittype.VehicleType):
air_weapon_dist = 20000
eplrs = True
class _53T2(unittype.VehicleType):
id = "AA20"
name = "53T2"
@@ -245,6 +259,7 @@ class _53T2(unittype.VehicleType):
threat_range = 2000
air_weapon_dist = 2000
class TRM_2000_53T2(unittype.VehicleType):
id = "TRM2000_AA20"
name = "TRM-2000 53T2"
@@ -253,6 +268,7 @@ class TRM_2000_53T2(unittype.VehicleType):
air_weapon_dist = 2000
eplrs = True
class TRM_2000_PAMELA(unittype.VehicleType):
id = "TRMMISTRAL"
name = "TRM-2000 PAMELA"
@@ -261,8 +277,10 @@ class TRM_2000_PAMELA(unittype.VehicleType):
air_weapon_dist = 10000
eplrs = True
## INFANTRY
class Infantry_Soldier_JTAC(unittype.VehicleType):
id = "JTACFP"
name = "Infantry Soldier JTAC"
@@ -270,8 +288,10 @@ class Infantry_Soldier_JTAC(unittype.VehicleType):
threat_range = 500
air_weapon_dist = 500
## ARTILERY
class MO_120_RT(unittype.VehicleType):
id = "M120"
name = "MO 120 RT"
@@ -279,10 +299,11 @@ class MO_120_RT(unittype.VehicleType):
threat_range = 15000
air_weapon_dist = 15000
class VAB_MORTIER(unittype.VehicleType):
id = "VAB_MORTIER"
name = "VAB MORTIER"
detection_range = 0
threat_range = 15000
air_weapon_dist = 15000
eplrs = True
eplrs = True

View File

@@ -1056,7 +1056,7 @@ class Hercules(PlaneType):
class Pylon2:
LAU_68___7_2_75__rockets_M257__Parachute_illumination_ = (
2,
Weapons.LAU_68___7_2_75__rockets_M257__Parachute_illumination_,
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
)
Smokewinder___red = (2, Weapons.Smokewinder___red)
Smokewinder___green = (2, Weapons.Smokewinder___green)
@@ -1064,13 +1064,13 @@ class Hercules(PlaneType):
Smokewinder___white = (2, Weapons.Smokewinder___white)
Smokewinder___yellow = (2, Weapons.Smokewinder___yellow)
Smokewinder___orange = (2, Weapons.Smokewinder___orange)
MER_6_Mk_82 = (2, Weapons.MER_6_Mk_82)
MER_6_Mk_82 = (2, Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD)
Herc_Ext_Fuel_Tank = (2, HerculesWeapons.Herc_Ext_Fuel_Tank)
class Pylon3:
LAU_68___7_2_75__rockets_M257__Parachute_illumination_ = (
3,
Weapons.LAU_68___7_2_75__rockets_M257__Parachute_illumination_,
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
)
Smokewinder___red = (3, Weapons.Smokewinder___red)
Smokewinder___green = (3, Weapons.Smokewinder___green)
@@ -1078,13 +1078,13 @@ class Hercules(PlaneType):
Smokewinder___white = (3, Weapons.Smokewinder___white)
Smokewinder___yellow = (3, Weapons.Smokewinder___yellow)
Smokewinder___orange = (3, Weapons.Smokewinder___orange)
MER_6_Mk_82 = (3, Weapons.MER_6_Mk_82)
MER_6_Mk_82 = (3, Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD)
Herc_Ext_Fuel_Tank = (3, HerculesWeapons.Herc_Ext_Fuel_Tank)
class Pylon4:
LAU_68___7_2_75__rockets_M257__Parachute_illumination_ = (
4,
Weapons.LAU_68___7_2_75__rockets_M257__Parachute_illumination_,
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
)
Smokewinder___red = (4, Weapons.Smokewinder___red)
Smokewinder___green = (4, Weapons.Smokewinder___green)
@@ -1092,13 +1092,13 @@ class Hercules(PlaneType):
Smokewinder___white = (4, Weapons.Smokewinder___white)
Smokewinder___yellow = (4, Weapons.Smokewinder___yellow)
Smokewinder___orange = (4, Weapons.Smokewinder___orange)
MER_6_Mk_82 = (4, Weapons.MER_6_Mk_82)
MER_6_Mk_82 = (4, Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD)
Herc_Ext_Fuel_Tank = (4, HerculesWeapons.Herc_Ext_Fuel_Tank)
class Pylon5:
LAU_68___7_2_75__rockets_M257__Parachute_illumination_ = (
5,
Weapons.LAU_68___7_2_75__rockets_M257__Parachute_illumination_,
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
)
Smokewinder___red = (5, Weapons.Smokewinder___red)
Smokewinder___green = (5, Weapons.Smokewinder___green)
@@ -1106,7 +1106,7 @@ class Hercules(PlaneType):
Smokewinder___white = (5, Weapons.Smokewinder___white)
Smokewinder___yellow = (5, Weapons.Smokewinder___yellow)
Smokewinder___orange = (5, Weapons.Smokewinder___orange)
MER_6_Mk_82 = (5, Weapons.MER_6_Mk_82)
MER_6_Mk_82 = (5, Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD)
Herc_Ext_Fuel_Tank = (5, HerculesWeapons.Herc_Ext_Fuel_Tank)
class Pylon6:

View File

@@ -335,4 +335,3 @@ class _34Ya6E_Gazetchik_E_decoy(unittype.VehicleType):
detection_range = 20000
threat_range = 0
air_weapon_dist = 0

View File

@@ -7,32 +7,104 @@ from dcs.weapons_data import Weapons
class MB_339PAN_Weapons:
ARF8M3_TP = {"clsid": "{ARF8M3_TP}", "name": "ARF8M3 TP", "weight": None}
BRD_4_250_4_MK_76_2_ARF_8M3TP_ = {"clsid": "{BRD-4-250}", "name": "BRD-4-250(4*MK.76+2*ARF-8M3TP)", "weight": 137.6}
BRD_4_250_4_MK_76_2_ARF_8M3TP_ = {
"clsid": "{BRD-4-250}",
"name": "BRD-4-250(4*MK.76+2*ARF-8M3TP)",
"weight": 137.6,
}
Color_Oil_Tank = {"clsid": "{COLOR-TANK}", "name": "Color Oil Tank", "weight": 183}
Empty_Pylon = {"clsid": "{VOID-PYLON-MB339A}", "name": "Empty Pylon", "weight": 20}
Fuel_Tank_330lt = {"clsid": "{FUEL-SUBAL_TANK-330}", "name": "Fuel Tank 330lt", "weight": 315}
Fuel_Tank_330lt = {
"clsid": "{FUEL-SUBAL_TANK-330}",
"name": "Fuel Tank 330lt",
"weight": 315,
}
GunPod_AN_M3 = {"clsid": "{MB339-AN-M3_L}", "name": "GunPod AN/M3", "weight": 75}
GunPod_AN_M3_ = {"clsid": "{MB339-AN-M3_R}", "name": "GunPod AN/M3", "weight": 75}
GunPod_DEFA553 = {"clsid": "{MB339-DEFA553_L}", "name": "GunPod DEFA553", "weight": 190}
GunPod_DEFA553_ = {"clsid": "{MB339-DEFA553_R}", "name": "GunPod DEFA553", "weight": 190}
LAU_10___4_ZUNI_MK_71___ = {"clsid": "{LAU-10}", "name": "LAU-10 - 4 ZUNI MK 71", "weight": 308}
LR_25___25_ARF_8M3_API_ = {"clsid": "{LR-25API}", "name": "LR-25 - 25 ARF/8M3(API)", "weight": 141}
LR_25___25_ARF_8M3_HEI_ = {"clsid": "{LR-25HEI}", "name": "LR-25 - 25 ARF/8M3(HEI)", "weight": 161}
GunPod_DEFA553 = {
"clsid": "{MB339-DEFA553_L}",
"name": "GunPod DEFA553",
"weight": 190,
}
GunPod_DEFA553_ = {
"clsid": "{MB339-DEFA553_R}",
"name": "GunPod DEFA553",
"weight": 190,
}
LAU_10___4_ZUNI_MK_71___ = {
"clsid": "{LAU-10}",
"name": "LAU-10 - 4 ZUNI MK 71",
"weight": 308,
}
LR_25___25_ARF_8M3_API_ = {
"clsid": "{LR-25API}",
"name": "LR-25 - 25 ARF/8M3(API)",
"weight": 141,
}
LR_25___25_ARF_8M3_HEI_ = {
"clsid": "{LR-25HEI}",
"name": "LR-25 - 25 ARF/8M3(HEI)",
"weight": 161,
}
MAK79_2_MK_20 = {"clsid": "{MAK79_MK20 2L}", "name": "MAK79 2 MK-20", "weight": 464}
MAK79_2_MK_20_ = {"clsid": "{MAK79_MK20 2R}", "name": "MAK79 2 MK-20", "weight": 464}
MAK79_2_MK_20_ = {
"clsid": "{MAK79_MK20 2R}",
"name": "MAK79 2 MK-20",
"weight": 464,
}
MAK79_MK_20 = {"clsid": "{MAK79_MK20 1R}", "name": "MAK79 MK-20", "weight": 232}
MAK79_MK_20_ = {"clsid": "{MAK79_MK20 1L}", "name": "MAK79 MK-20", "weight": 232}
MB339_Black_Smoke = {"clsid": "{SMOKE-BLACK-MB339}", "name": "MB339 Black Smoke", "weight": 1}
MB339_Green_Smoke = {"clsid": "{SMOKE-GREEN-MB339}", "name": "MB339 Green Smoke", "weight": 1}
MB339_ORANGE_Smoke = {"clsid": "{SMOKE-ORANGE-MB339}", "name": "MB339 ORANGE Smoke", "weight": 1}
MB339_Red_Smoke = {"clsid": "{SMOKE-RED-MB339}", "name": "MB339 Red Smoke", "weight": 1}
MB339_White_Smoke = {"clsid": "{SMOKE-WHITE-MB339}", "name": "MB339 White Smoke", "weight": 1}
MB339_YELLOW_Smoke = {"clsid": "{SMOKE-YELLOW-MB339}", "name": "MB339 YELLOW Smoke", "weight": 1}
MB339_Black_Smoke = {
"clsid": "{SMOKE-BLACK-MB339}",
"name": "MB339 Black Smoke",
"weight": 1,
}
MB339_Green_Smoke = {
"clsid": "{SMOKE-GREEN-MB339}",
"name": "MB339 Green Smoke",
"weight": 1,
}
MB339_ORANGE_Smoke = {
"clsid": "{SMOKE-ORANGE-MB339}",
"name": "MB339 ORANGE Smoke",
"weight": 1,
}
MB339_Red_Smoke = {
"clsid": "{SMOKE-RED-MB339}",
"name": "MB339 Red Smoke",
"weight": 1,
}
MB339_White_Smoke = {
"clsid": "{SMOKE-WHITE-MB339}",
"name": "MB339 White Smoke",
"weight": 1,
}
MB339_YELLOW_Smoke = {
"clsid": "{SMOKE-YELLOW-MB339}",
"name": "MB339 YELLOW Smoke",
"weight": 1,
}
MK76 = {"clsid": "{MK76}", "name": "MK76", "weight": 11.3}
Tip_Fuel_Tank_500lt = {"clsid": "{FUEL-TIP-TANK-500-L}", "name": "Tip Fuel Tank 500lt", "weight": 471}
Tip_Fuel_Tank_500lt_ = {"clsid": "{FUEL-TIP-TANK-500-R}", "name": "Tip Fuel Tank 500lt", "weight": 471}
Tip_Fuel_Tank_Ellittici_320lt = {"clsid": "{FUEL-TIP-ELLITTIC-L}", "name": "Tip Fuel Tank Ellittici 320lt", "weight": 314.2}
Tip_Fuel_Tank_Ellittici_320lt_ = {"clsid": "{FUEL-TIP-ELLITTIC-R}", "name": "Tip Fuel Tank Ellittici 320lt", "weight": 314.2}
Tip_Fuel_Tank_500lt = {
"clsid": "{FUEL-TIP-TANK-500-L}",
"name": "Tip Fuel Tank 500lt",
"weight": 471,
}
Tip_Fuel_Tank_500lt_ = {
"clsid": "{FUEL-TIP-TANK-500-R}",
"name": "Tip Fuel Tank 500lt",
"weight": 471,
}
Tip_Fuel_Tank_Ellittici_320lt = {
"clsid": "{FUEL-TIP-ELLITTIC-L}",
"name": "Tip Fuel Tank Ellittici 320lt",
"weight": 314.2,
}
Tip_Fuel_Tank_Ellittici_320lt_ = {
"clsid": "{FUEL-TIP-ELLITTIC-R}",
"name": "Tip Fuel Tank Ellittici 320lt",
"weight": 314.2,
}
class MB_339PAN(PlaneType):
@@ -43,7 +115,7 @@ class MB_339PAN(PlaneType):
length = 12.13
fuel_max = 626
max_speed = 763.2
category = "Interceptor" #{78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
radio_frequency = 124
panel_radio = {
@@ -68,7 +140,7 @@ class MB_339PAN(PlaneType):
7: 262,
14: 266,
19: 268,
15: 265
15: 265,
},
},
2: {
@@ -102,7 +174,7 @@ class MB_339PAN(PlaneType):
28: 257,
23: 260,
29: 253,
15: 265
15: 265,
},
},
}
@@ -113,7 +185,6 @@ class MB_339PAN(PlaneType):
}
class Properties:
class SoloFlight:
id = "SoloFlight"
@@ -127,7 +198,6 @@ class MB_339PAN(PlaneType):
Equally_Responsible = -2
class Liveries:
class Georgia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
@@ -370,7 +440,10 @@ class MB_339PAN(PlaneType):
class Pylon1:
Tip_Fuel_Tank_500lt = (1, MB_339PAN_Weapons.Tip_Fuel_Tank_500lt)
Tip_Fuel_Tank_Ellittici_320lt = (1, MB_339PAN_Weapons.Tip_Fuel_Tank_Ellittici_320lt)
Tip_Fuel_Tank_Ellittici_320lt = (
1,
MB_339PAN_Weapons.Tip_Fuel_Tank_Ellittici_320lt,
)
class Pylon2:
Empty_Pylon = (2, MB_339PAN_Weapons.Empty_Pylon)
@@ -386,7 +459,10 @@ class MB_339PAN(PlaneType):
LR_25___25_ARF_8M3_API_ = (3, MB_339PAN_Weapons.LR_25___25_ARF_8M3_API_)
Mk_82 = (3, Weapons.Mk_82)
LAU_10___4_ZUNI_MK_71___ = (3, MB_339PAN_Weapons.LAU_10___4_ZUNI_MK_71___)
BRD_4_250_4_MK_76_2_ARF_8M3TP_ = (3, MB_339PAN_Weapons.BRD_4_250_4_MK_76_2_ARF_8M3TP_)
BRD_4_250_4_MK_76_2_ARF_8M3TP_ = (
3,
MB_339PAN_Weapons.BRD_4_250_4_MK_76_2_ARF_8M3TP_,
)
Matra_Type_155_Rocket_Pod = (3, Weapons.Matra_Type_155_Rocket_Pod)
class Pylon4:
@@ -427,7 +503,10 @@ class MB_339PAN(PlaneType):
Mk_82 = (8, Weapons.Mk_82)
LAU_10___4_ZUNI_MK_71___ = (8, MB_339PAN_Weapons.LAU_10___4_ZUNI_MK_71___)
Matra_Type_155_Rocket_Pod = (8, Weapons.Matra_Type_155_Rocket_Pod)
BRD_4_250_4_MK_76_2_ARF_8M3TP_ = (8, MB_339PAN_Weapons.BRD_4_250_4_MK_76_2_ARF_8M3TP_)
BRD_4_250_4_MK_76_2_ARF_8M3TP_ = (
8,
MB_339PAN_Weapons.BRD_4_250_4_MK_76_2_ARF_8M3TP_,
)
class Pylon9:
Empty_Pylon = (9, MB_339PAN_Weapons.Empty_Pylon)
@@ -438,9 +517,18 @@ class MB_339PAN(PlaneType):
class Pylon10:
Tip_Fuel_Tank_500lt_ = (10, MB_339PAN_Weapons.Tip_Fuel_Tank_500lt_)
Tip_Fuel_Tank_Ellittici_320lt_ = (10, MB_339PAN_Weapons.Tip_Fuel_Tank_Ellittici_320lt_)
Tip_Fuel_Tank_Ellittici_320lt_ = (
10,
MB_339PAN_Weapons.Tip_Fuel_Tank_Ellittici_320lt_,
)
pylons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
tasks = [task.GroundAttack, task.RunwayAttack, task.CAS, task.AntishipStrike, task.Reconnaissance]
task_default = task.Nothing
tasks = [
task.GroundAttack,
task.RunwayAttack,
task.CAS,
task.AntishipStrike,
task.Reconnaissance,
]
task_default = task.Nothing

View File

@@ -3,11 +3,16 @@ from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.highdigitsams import highdigitsams
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_M, Rafale_A_S, Rafale_B
from pydcs_extensions.su57.su57 import Su_57
import pydcs_extensions.frenchpack.frenchpack as frenchpack
MODDED_AIRPLANES = [A_4E_C, MB_339PAN, Rafale_A_S, Rafale_M, Rafale_B, Su_57, F_22A, Hercules]
MODDED_AIRPLANES = [
A_4E_C,
MB_339PAN,
Su_57,
F_22A,
Hercules,
]
MODDED_VEHICLES = [
frenchpack._FIELD_HIDE,
frenchpack._FIELD_HIDE_SMALL,
@@ -84,5 +89,5 @@ MODDED_VEHICLES = [
highdigitsams.SAM_SA_24_Igla_S_manpad,
highdigitsams.SAM_SA_14_Strela_3_manpad,
highdigitsams.Polyana_D4M1_C2_node,
highdigitsams._34Ya6E_Gazetchik_E_decoy
]
highdigitsams._34Ya6E_Gazetchik_E_decoy,
]

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,11 @@ class Su57Weapons:
RVV_BD = {"clsid": "{RVV-BD}", "name": "RVV-BD", "weight": 600}
RVV_L = {"clsid": "{RVV-L}", "name": "RVV-L", "weight": 748}
RVV_M = {"clsid": "{RVV-M}", "name": "RVV-M", "weight": 190}
Su_57_Fuel_Tank = {"clsid": "{SU_57Tank}", "name": "Su-57 Fuel Tank", "weight": 1561.421}
Su_57_Fuel_Tank = {
"clsid": "{SU_57Tank}",
"name": "Su-57 Fuel Tank",
"weight": 1561.421,
}
class Su_57(PlaneType):
@@ -27,10 +31,9 @@ class Su_57(PlaneType):
charge_total = 200
chaff_charge_size = 1
flare_charge_size = 1
category = "Interceptor" #{78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
class Liveries:
class USSR(Enum):
_22 = "22"
_20 = "20"
@@ -1508,7 +1511,7 @@ class Su_57(PlaneType):
_15 = "15"
class Pylon1:
R_73 = (1, Weapons.R_73)
R_73__AA_11_Archer____Infra_Red = (1, Weapons.R_73__AA_11_Archer____Infra_Red)
RVV_AE = (1, Su57Weapons.RVV_AE)
RVV_M = (1, Su57Weapons.RVV_M)
Smoke_Generator___red = (1, Weapons.Smoke_Generator___red)
@@ -1519,33 +1522,26 @@ class Su_57(PlaneType):
Smoke_Generator___orange = (1, Weapons.Smoke_Generator___orange)
class Pylon2:
R_27R = (2, Weapons.R_27R)
R_27ER = (2, Weapons.R_27ER)
R_27T = (2, Weapons.R_27T)
R_27ET = (2, Weapons.R_27ET)
R_77 = (2, Weapons.R_77)
R_73 = (2, Weapons.R_73)
Kh_31P = (2, Weapons.Kh_31P)
Kh_31A = (2, Weapons.Kh_31A)
Kh_29L = (2, Weapons.Kh_29L)
Kh_29T = (2, Weapons.Kh_29T)
Kh_59M = (2, Weapons.Kh_59M)
MER_6_FAB_100 = (2, Weapons.MER_6_FAB_100)
B_8M1___20_S_8KOM = (2, Weapons.B_8M1___20_S_8KOM)
B_13L___5_S_13_OF = (2, Weapons.B_13L___5_S_13_OF)
S_25_OFM = (2, Weapons.S_25_OFM)
BetAB_500 = (2, Weapons.BetAB_500)
KMGU_2___96_AO_2_5RT = (2, Weapons.KMGU_2___96_AO_2_5RT)
KMGU_2___96_PTAB_2_5KO = (2, Weapons.KMGU_2___96_PTAB_2_5KO)
FAB_250 = (2, Weapons.FAB_250)
RBK_250_PTAB_2_5M = (2, Weapons.RBK_250_PTAB_2_5M)
FAB_500_M62 = (2, Weapons.FAB_500_M62)
RBK_500_255_PTAB_10_5 = (2, Weapons.RBK_500_255_PTAB_10_5)
KAB_500L = (2, Weapons.KAB_500L)
KAB_500kr = (2, Weapons.KAB_500kr)
FAB_1500_M54 = (2, Weapons.FAB_1500_M54)
KAB_1500L = (2, Weapons.KAB_1500L)
MER_6_FAB_250 = (2, Weapons.MER_6_FAB_250)
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
2,
Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr,
)
R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = (
2,
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
)
R_27T = (2, Weapons.R_27T__AA_10_Alamo_B____Infra_Red)
R_27ET__AA_10_Alamo_D____IR_Extended_Range = (
2,
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
)
R_77__AA_12_Adder____Active_Rdr = (2, Weapons.R_77__AA_12_Adder____Active_Rdr)
R_73__AA_11_Archer____Infra_Red = (2, Weapons.R_73__AA_11_Archer____Infra_Red)
Kh_31P = (2, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_31A = (2, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_29L = (2, Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser)
Kh_29T = (2, Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided)
Kh_59M = (2, Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN)
RVV_BD = (2, Su57Weapons.RVV_BD)
RVV_AE = (2, Su57Weapons.RVV_AE)
RVV_M = (2, Su57Weapons.RVV_M)
@@ -1562,7 +1558,7 @@ class Su_57(PlaneType):
Smoke_Generator___orange = (2, Weapons.Smoke_Generator___orange)
class Pylon3:
R_73 = (3, Weapons.R_73)
R_73__AA_11_Archer____Infra_Red = (3, Weapons.R_73__AA_11_Archer____Infra_Red)
Smoke_Generator___red = (3, Weapons.Smoke_Generator___red)
Smoke_Generator___green = (3, Weapons.Smoke_Generator___green)
Smoke_Generator___blue = (3, Weapons.Smoke_Generator___blue)
@@ -1571,33 +1567,29 @@ class Su_57(PlaneType):
Smoke_Generator___orange = (3, Weapons.Smoke_Generator___orange)
class Pylon4:
R_27R = (4, Weapons.R_27R)
R_27ER = (4, Weapons.R_27ER)
R_27T = (4, Weapons.R_27T)
R_27ET = (4, Weapons.R_27ET)
R_77 = (4, Weapons.R_77)
R_73 = (4, Weapons.R_73)
Kh_31P = (4, Weapons.Kh_31P)
Kh_31A = (4, Weapons.Kh_31A)
Kh_29L = (4, Weapons.Kh_29L)
Kh_29T = (4, Weapons.Kh_29T)
Kh_59M = (4, Weapons.Kh_59M)
MER_6_FAB_100 = (4, Weapons.MER_6_FAB_100)
B_8M1___20_S_8KOM = (4, Weapons.B_8M1___20_S_8KOM)
B_13L___5_S_13_OF = (4, Weapons.B_13L___5_S_13_OF)
S_25_OFM = (4, Weapons.S_25_OFM)
BetAB_500 = (4, Weapons.BetAB_500)
KMGU_2___96_AO_2_5RT = (4, Weapons.KMGU_2___96_AO_2_5RT)
KMGU_2___96_PTAB_2_5KO = (4, Weapons.KMGU_2___96_PTAB_2_5KO)
FAB_250 = (4, Weapons.FAB_250)
RBK_250_PTAB_2_5M = (4, Weapons.RBK_250_PTAB_2_5M)
FAB_500_M62 = (4, Weapons.FAB_500_M62)
RBK_500_255_PTAB_10_5 = (4, Weapons.RBK_500_255_PTAB_10_5)
KAB_500L = (4, Weapons.KAB_500L)
KAB_500kr = (4, Weapons.KAB_500kr)
FAB_1500_M54 = (4, Weapons.FAB_1500_M54)
KAB_1500L = (4, Weapons.KAB_1500L)
MER_6_FAB_250 = (4, Weapons.MER_6_FAB_250)
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
4,
Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr,
)
R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = (
4,
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
)
R_27T__AA_10_Alamo_B____Infra_Red = (
4,
Weapons.R_27T__AA_10_Alamo_B____Infra_Red,
)
R_27ET__AA_10_Alamo_D____IR_Extended_Range = (
4,
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
)
R_77__AA_12_Adder____Active_Rdr = (4, Weapons.R_77__AA_12_Adder____Active_Rdr)
R_73__AA_11_Archer____Infra_Red = (4, Weapons.R_73__AA_11_Archer____Infra_Red)
Kh_31P = (4, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_31A = (4, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_29L = (4, Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser)
Kh_29T = (4, Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided)
Kh_59M = (4, Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN)
RVV_BD = (4, Su57Weapons.RVV_BD)
RVV_AE = (4, Su57Weapons.RVV_AE)
RVV_M = (4, Su57Weapons.RVV_M)
@@ -1607,57 +1599,50 @@ class Su_57(PlaneType):
Kh_59MK2 = (4, Su57Weapons.Kh_59MK2)
class Pylon5:
R_77 = (5, Weapons.R_77)
R_77__AA_12_Adder____Active_Rdr = (5, Weapons.R_77__AA_12_Adder____Active_Rdr)
RVV_AE = (5, Su57Weapons.RVV_AE)
RVV_M = (5, Su57Weapons.RVV_M)
Kh_59MK2 = (5, Su57Weapons.Kh_59MK2)
class Pylon6:
R_77 = (6, Weapons.R_77)
R_77__AA_12_Adder____Active_Rdr = (6, Weapons.R_77__AA_12_Adder____Active_Rdr)
RVV_AE = (6, Su57Weapons.RVV_AE)
RVV_M = (6, Su57Weapons.RVV_M)
Kh_59MK2 = (6, Su57Weapons.Kh_59MK2)
class Pylon7:
R_77 = (7, Weapons.R_77)
R_77__AA_12_Adder____Active_Rdr = (7, Weapons.R_77__AA_12_Adder____Active_Rdr)
RVV_AE = (7, Su57Weapons.RVV_AE)
RVV_M = (7, Su57Weapons.RVV_M)
Kh_59MK2 = (7, Su57Weapons.Kh_59MK2)
class Pylon8:
R_77 = (8, Weapons.R_77)
R_77__AA_12_Adder____Active_Rdr = (8, Weapons.R_77__AA_12_Adder____Active_Rdr)
RVV_AE = (8, Su57Weapons.RVV_AE)
RVV_M = (8, Su57Weapons.RVV_M)
Kh_59MK2 = (8, Su57Weapons.Kh_59MK2)
class Pylon9:
R_27R = (9, Weapons.R_27R)
R_27ER = (9, Weapons.R_27ER)
R_27T = (9, Weapons.R_27T)
R_27ET = (9, Weapons.R_27ET)
R_77 = (9, Weapons.R_77)
R_73 = (9, Weapons.R_73)
Kh_31P = (9, Weapons.Kh_31P)
Kh_31A = (9, Weapons.Kh_31A)
Kh_29L = (9, Weapons.Kh_29L)
Kh_29T = (9, Weapons.Kh_29T)
Kh_59M = (9, Weapons.Kh_59M)
MER_6_FAB_100 = (9, Weapons.MER_6_FAB_100)
B_8M1___20_S_8KOM = (9, Weapons.B_8M1___20_S_8KOM)
B_13L___5_S_13_OF = (9, Weapons.B_13L___5_S_13_OF)
S_25_OFM = (9, Weapons.S_25_OFM)
BetAB_500 = (9, Weapons.BetAB_500)
KMGU_2___96_AO_2_5RT = (9, Weapons.KMGU_2___96_AO_2_5RT)
KMGU_2___96_PTAB_2_5KO = (9, Weapons.KMGU_2___96_PTAB_2_5KO)
FAB_250 = (9, Weapons.FAB_250)
RBK_250_PTAB_2_5M = (9, Weapons.RBK_250_PTAB_2_5M)
FAB_500_M62 = (9, Weapons.FAB_500_M62)
RBK_500_255_PTAB_10_5 = (9, Weapons.RBK_500_255_PTAB_10_5)
KAB_500L = (9, Weapons.KAB_500L)
KAB_500kr = (9, Weapons.KAB_500kr)
FAB_1500_M54 = (9, Weapons.FAB_1500_M54)
KAB_1500L = (9, Weapons.KAB_1500L)
MER_6_FAB_250 = (9, Weapons.MER_6_FAB_250)
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
9,
Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr,
)
R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = (
9,
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
)
R_27T = (9, Weapons.R_27T__AA_10_Alamo_B____Infra_Red)
R_27ET__AA_10_Alamo_D____IR_Extended_Range = (
9,
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
)
R_77__AA_12_Adder____Active_Rdr = (9, Weapons.R_77__AA_12_Adder____Active_Rdr)
R_73__AA_11_Archer____Infra_Red = (9, Weapons.R_73__AA_11_Archer____Infra_Red)
Kh_31P = (9, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_31A = (9, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_29L = (9, Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser)
Kh_29T = (9, Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided)
Kh_59M = (9, Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN)
RVV_BD = (9, Su57Weapons.RVV_BD)
RVV_AE = (9, Su57Weapons.RVV_AE)
RVV_M = (9, Su57Weapons.RVV_M)
@@ -1667,7 +1652,7 @@ class Su_57(PlaneType):
Kh_59MK2 = (9, Su57Weapons.Kh_59MK2)
class Pylon10:
R_73 = (10, Weapons.R_73)
R_73__AA_11_Archer____Infra_Red = (10, Weapons.R_73__AA_11_Archer____Infra_Red)
Smoke_Generator___red = (10, Weapons.Smoke_Generator___red)
Smoke_Generator___green = (10, Weapons.Smoke_Generator___green)
Smoke_Generator___blue = (10, Weapons.Smoke_Generator___blue)
@@ -1676,35 +1661,28 @@ class Su_57(PlaneType):
Smoke_Generator___orange = (10, Weapons.Smoke_Generator___orange)
class Pylon11:
R_27R = (11, Weapons.R_27R)
R_27ER = (11, Weapons.R_27ER)
R_27T = (11, Weapons.R_27T)
R_27ET = (11, Weapons.R_27ET)
R_77 = (11, Weapons.R_77)
R_73 = (11, Weapons.R_73)
Kh_31P = (11, Weapons.Kh_31P)
Kh_31A = (11, Weapons.Kh_31A)
Kh_29L = (11, Weapons.Kh_29L)
Kh_29T = (11, Weapons.Kh_29T)
Kh_59M = (11, Weapons.Kh_59M)
MER_6_FAB_100 = (11, Weapons.MER_6_FAB_100)
B_8M1___20_S_8KOM = (11, Weapons.B_8M1___20_S_8KOM)
B_13L___5_S_13_OF = (11, Weapons.B_13L___5_S_13_OF)
S_25_OFM = (11, Weapons.S_25_OFM)
BetAB_500 = (11, Weapons.BetAB_500)
KMGU_2___96_AO_2_5RT = (11, Weapons.KMGU_2___96_AO_2_5RT)
KMGU_2___96_PTAB_2_5KO = (11, Weapons.KMGU_2___96_PTAB_2_5KO)
FAB_250 = (11, Weapons.FAB_250)
RBK_250_PTAB_2_5M = (11, Weapons.RBK_250_PTAB_2_5M)
FAB_500_M62 = (11, Weapons.FAB_500_M62)
RBK_500_255_PTAB_10_5 = (11, Weapons.RBK_500_255_PTAB_10_5)
KAB_500L = (11, Weapons.KAB_500L)
KAB_500kr = (11, Weapons.KAB_500kr)
FAB_1500_M54 = (11, Weapons.FAB_1500_M54)
KAB_1500L = (11, Weapons.KAB_1500L)
MER_6_FAB_250 = (11, Weapons.MER_6_FAB_250)
#ERRR {R-33}
RVV_BD = (11,Su57Weapons.RVV_BD)
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
11,
Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr,
)
R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = (
11,
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
)
R_27T = (11, Weapons.R_27T__AA_10_Alamo_B____Infra_Red)
R_27ET__AA_10_Alamo_D____IR_Extended_Range = (
11,
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
)
R_77__AA_12_Adder____Active_Rdr = (11, Weapons.R_77__AA_12_Adder____Active_Rdr)
R_73__AA_11_Archer____Infra_Red = (11, Weapons.R_73__AA_11_Archer____Infra_Red)
Kh_31P = (11, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_31A = (11, Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr)
Kh_29L = (11, Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser)
Kh_29T = (11, Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided)
Kh_59M = (11, Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN)
# ERRR {R-33}
RVV_BD = (11, Su57Weapons.RVV_BD)
RVV_AE = (11, Su57Weapons.RVV_AE)
RVV_M = (11, Su57Weapons.RVV_M)
RVV_L = (11, Su57Weapons.RVV_L)
@@ -1720,7 +1698,7 @@ class Su_57(PlaneType):
Kh_59MK2 = (11, Su57Weapons.Kh_59MK2)
class Pylon12:
R_73 = (12, Weapons.R_73)
R_73__AA_11_Archer____Infra_Red = (12, Weapons.R_73__AA_11_Archer____Infra_Red)
RVV_AE = (12, Su57Weapons.RVV_AE)
RVV_M = (12, Su57Weapons.RVV_M)
Smoke_Generator___red = (12, Weapons.Smoke_Generator___red)
@@ -1732,5 +1710,15 @@ class Su_57(PlaneType):
pylons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
tasks = [task.CAP, task.Intercept, task.Escort, task.FighterSweep, task.AFAC, task.GroundAttack, task.RunwayAttack, task.AntishipStrike, task.CAS]
tasks = [
task.CAP,
task.Intercept,
task.Escort,
task.FighterSweep,
task.AFAC,
task.GroundAttack,
task.RunwayAttack,
task.AntishipStrike,
task.CAS,
]
task_default = task.CAP

View File

@@ -147,12 +147,16 @@ def load_icons():
"./resources/ui/ground_assets/" + category + "_blue.png"
)
ICONS["destroyed"] = QPixmap("./resources/ui/ground_assets/destroyed.png")
ICONS["EWR"] = QPixmap("./resources/ui/ground_assets/ewr.png")
ICONS["EWR_blue"] = QPixmap("./resources/ui/ground_assets/ewr_blue.png")
ICONS["ship"] = QPixmap("./resources/ui/ground_assets/ship.png")
ICONS["ship_blue"] = QPixmap("./resources/ui/ground_assets/ship_blue.png")
ICONS["missile"] = QPixmap("./resources/ui/ground_assets/missile.png")
ICONS["missile_blue"] = QPixmap("./resources/ui/ground_assets/missile_blue.png")
ICONS["nothreat"] = QPixmap("./resources/ui/ground_assets/nothreat.png")
ICONS["nothreat_blue"] = QPixmap("./resources/ui/ground_assets/nothreat_blue.png")
ICONS["coastal"] = QPixmap("./resources/ui/ground_assets/coastal.png")
ICONS["coastal_blue"] = QPixmap("./resources/ui/ground_assets/coastal_blue.png")
ICONS["Generator"] = QPixmap(
"./resources/ui/misc/" + get_theme_icons() + "/generator.png"

View File

@@ -7,7 +7,7 @@ from PySide2.QtWidgets import (
QLabel,
QVBoxLayout,
)
from dcs.weather import Weather as PydcsWeather
from dcs.weather import CloudPreset, Weather as PydcsWeather
import qt_ui.uiconstants as CONST
from game.utils import mps
@@ -162,7 +162,7 @@ class QWeatherWidget(QGroupBox):
self.turn = turn
self.conditions = conditions
self.updateForecast()
self.update_forecast()
self.updateWinds()
def updateWinds(self):
@@ -186,55 +186,76 @@ class QWeatherWidget(QGroupBox):
self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts")
self.windFL26DirLabel.setText(f"{windFL26Dir}º")
def updateForecast(self):
def update_forecast_from_preset(self, preset: CloudPreset) -> None:
self.forecastFog.setText("No fog")
if "Rain" in preset.name:
self.forecastRain.setText("Rain")
self.update_forecast_icons("rain")
else:
self.forecastRain.setText("No rain")
self.update_forecast_icons("partly-cloudy")
# We get a description like the following for the cloud preset.
#
# 09 ##Two Layer Broken/Scattered \nMETAR:BKN 7.5/10 SCT 20/22 FEW41
#
# The second line is probably interesting but doesn't fit into the widget
# currently, so for now just extract the first line.
self.forecastClouds.setText(preset.description.splitlines()[0].split("##")[1])
def update_forecast(self):
"""Updates the Forecast Text and icon with the current conditions wind info."""
icon = []
if (
self.conditions.weather.clouds
and self.conditions.weather.clouds.preset is not None
):
self.update_forecast_from_preset(self.conditions.weather.clouds.preset)
return
if self.conditions.weather.clouds is None:
cloudDensity = 0
cloud_density = 0
precipitation = None
else:
cloudDensity = self.conditions.weather.clouds.density
cloud_density = self.conditions.weather.clouds.density
precipitation = self.conditions.weather.clouds.precipitation
fog = self.conditions.weather.fog or None
is_night = self.conditions.time_of_day == TimeOfDay.Night
time = "night" if is_night else "day"
if cloudDensity <= 0:
if not cloud_density:
self.forecastClouds.setText("Sunny")
icon = [time, "clear"]
if cloudDensity > 0 and cloudDensity < 3:
weather_type = "clear"
elif cloud_density < 3:
self.forecastClouds.setText("Partly Cloudy")
icon = [time, "partly-cloudy"]
if cloudDensity >= 3 and cloudDensity < 5:
weather_type = "partly-cloudy"
elif cloud_density < 5:
self.forecastClouds.setText("Mostly Cloudy")
icon = [time, "partly-cloudy"]
if cloudDensity >= 5:
weather_type = "partly-cloudy"
else:
self.forecastClouds.setText("Totally Cloudy")
icon = [time, "partly-cloudy"]
weather_type = "partly-cloudy"
if precipitation == PydcsWeather.Preceptions.Rain:
self.forecastRain.setText("Rain")
icon = [time, "rain"]
weather_type = "rain"
elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
self.forecastRain.setText("Thunderstorm")
icon = [time, "thunderstorm"]
weather_type = "thunderstorm"
else:
self.forecastRain.setText("No Rain")
self.forecastRain.setText("No rain")
if not fog:
if not self.conditions.weather.fog is not None:
self.forecastFog.setText("No fog")
else:
visibility = round(fog.visibility.nautical_miles, 1)
visibility = round(self.conditions.weather.fog.visibility.nautical_miles, 1)
self.forecastFog.setText(f"Fog vis: {visibility}nm")
icon = [time, ("cloudy" if cloudDensity > 1 else None), "fog"]
if cloud_density > 1:
weather_type = "cloudy-fog"
else:
weather_type = "fog"
icon_key = "Weather_{}".format("-".join(filter(None.__ne__, icon)))
self.update_forecast_icons(weather_type)
def update_forecast_icons(self, weather_type: str) -> None:
time = "night" if self.conditions.time_of_day == TimeOfDay.Night else "day"
icon_key = f"Weather_{time}-{weather_type}"
icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"]
self.weather_icon.setPixmap(icon)

View File

@@ -90,6 +90,12 @@ class QAircraftTypeSelector(QComboBox):
f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
userData=aircraft,
)
elif mission_type in [FlightType.AEWC]:
if aircraft in gen.flights.ai_flight_planner_db.AEWC_CAPABLE:
self.addItem(
f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
userData=aircraft,
)
current_aircraft_index = self.findData(current_aircraft)
if current_aircraft_index != -1:
self.setCurrentIndex(current_aircraft_index)

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