Compare commits

...

157 Commits

Author SHA1 Message Date
C. Perreau
3dac0af6c4 Merge pull request #61 from Khopa/develop
2.0.11
2020-08-16 15:27:25 +02:00
Khopa
f9ce6966bb Changelog update 2020-08-16 15:26:20 +02:00
C. Perreau
f61e23153b Merge pull request #60 from Khopa/develop
Develop
2020-08-16 15:22:10 +02:00
Khopa
ff4f008a63 Merge branches 'develop' and 'master' of https://github.com/khopa/dcs_liberation into develop 2020-08-16 15:21:22 +02:00
C. Perreau
cbcf8a0a90 Merge pull request #59 from bwRavencl/fix_uk_typo
Fixed typo "United Kingdown" -> "United Kingdom"
2020-08-16 15:20:59 +02:00
Khopa
647e62059f Changelog update 2020-08-16 15:10:55 +02:00
Khopa
6e3ef24e3a Changelog update 2020-08-16 15:09:44 +02:00
Khopa
2559b27a6f Restrict afterburner for AI units. 2020-08-16 15:08:27 +02:00
Khopa
421e2508d4 JTAC invisble and immortal commands update. 2020-08-16 15:01:34 +02:00
Matteo Hausner
c9f8a93813 Fixed typo "United Kingdown" -> "United Kingdom" 2020-08-16 14:07:37 +02:00
Khopa
126849cf9a JTAC message will be displayed for 25 seconds instead of just 10. 2020-08-16 13:52:42 +02:00
Khopa
c08768f648 Cleaned up dead code 2020-08-16 13:31:12 +02:00
Khopa
2c07257bf6 Small update to nevada exclusion polygons around nellis AFB. 2020-08-16 13:30:36 +02:00
Khopa
f797bbb97f Fixed JTAC using code above than 1688 that cannot be used in game. 2020-08-16 13:11:28 +02:00
Khopa
a7f3b6e0dc F-15E added for USA 2005 and USA 1990 factions. 2020-08-16 13:09:31 +02:00
Khopa
60732c33c0 Libya mispell issue 2020-08-16 12:53:40 +02:00
Khopa
65b77e241f Changelog update 2020-08-16 02:41:56 +02:00
Khopa
a167b95cec Destroyed units will not remain on airfields. 2020-08-16 02:25:42 +02:00
Khopa
283cfd1ce9 Removed some dead code. 2020-08-16 02:19:52 +02:00
Khopa
e16db60d0f Fix error with JTAC compatibility with old saves 2020-08-16 02:18:30 +02:00
Khopa
6a3b5bbe1d Empty neutral airports from supply 2020-08-16 02:17:43 +02:00
Khopa
339c3f506c changelog update 2020-08-16 01:02:12 +02:00
Khopa
9fade70092 Fixed Tankers TACAN being the same and being different from the one in briefing. 2020-08-16 01:01:01 +02:00
Khopa
e18d84ae5e Fixed issues with libya 2011 faction. 2020-08-15 01:10:30 +02:00
Khopa
fa76e31640 JTAC smoke markers can be disabled 2020-08-14 22:59:45 +02:00
Khopa
2fd4fa25f7 Added JTAC smoke parameter. 2020-08-14 22:39:45 +02:00
Khopa
c27d8e3b16 Updated readme.md file. 2020-08-14 19:45:02 +02:00
Khopa
0841c52a75 Readme update link 2020-08-14 19:28:46 +02:00
Khopa
669bff13c7 Updated Github readme. 2020-08-14 19:24:35 +02:00
Khopa
01ea4fa7a6 Fixed big performance issues in release executable. 2020-08-13 16:53:56 +02:00
Khopa
ef024b5118 Removed unused part of release script 2020-08-13 16:10:37 +02:00
Khopa
a96a107ef9 Added Mi24, Mi28, Mig31, Su30 to Russia. 2020-08-13 14:51:30 +02:00
Khopa
8d3ab2be5d Payloads for Mi-24V && Mi-28 2020-08-13 14:50:36 +02:00
Khopa
6ed407f656 Fixed OH-58D not being used by AI 2020-08-13 14:47:59 +02:00
Khopa
6b3625f0ea Forgot to put jtac in changelog. 2020-08-13 00:36:28 +02:00
C. Perreau
db8e7f0474 Merge pull request #46 from Khopa/develop
Merge develop 2.0.10
2020-08-13 00:02:21 +02:00
Khopa
d6398630df Version number 2020-08-12 23:58:23 +02:00
Khopa
464bfccfb6 C-101 picture fix.
Removed UH60 from PMCs.
2020-08-12 23:57:25 +02:00
Khopa
aa16da837d Fixed error 2020-08-12 22:59:00 +02:00
Khopa
ce4478803a Added new factions, and OH-58D payloads. 2020-08-12 22:57:50 +02:00
Khopa
114239fe8e Default size for info panel & map changed 2020-08-12 18:27:13 +02:00
Khopa
67d96061da Fixed JTAC infos in briefing 2020-08-12 18:26:49 +02:00
Khopa
2d5ad16399 More WW2 factions 2020-08-12 18:26:26 +02:00
Khopa
4c7f79c6f8 Fix bug in mission result window. 2020-08-12 03:31:56 +02:00
Khopa
2a50768db1 JTAC support 2020-08-12 03:13:51 +02:00
Khopa
bff33e6992 Added LHA to Caucasus campaigns. 2020-08-10 18:41:41 +02:00
Khopa
448057a0b9 Disabled interceptors for upcoming release 2020-08-10 18:17:00 +02:00
Khopa
0a47669b14 Possible fix for debriefing updates. 2020-08-10 18:10:10 +02:00
Khopa
b5893ce521 Fix potential error in mission waiting for results window. 2020-08-10 17:56:30 +02:00
Khopa
23537211b0 Fallback point is further away 2020-08-10 17:55:32 +02:00
Khopa
39f25db439 Replaced Sa342L by SA342M in uk 90 factions. (L version doesn't want to attack ennemy.) 2020-08-10 17:49:22 +02:00
Khopa
a551067c72 Restrict Jettison for CAS aircrafts 2020-08-10 17:04:46 +02:00
Khopa
23f4df766c Now possible to open and save game under different names. 2020-08-09 17:31:53 +02:00
Khopa
7354a34f1a Misc UI changes to new game wizard and mission result window. 2020-08-09 16:37:10 +02:00
Khopa
2de48b3918 Fix no lha for some factions 2020-08-09 16:36:21 +02:00
Khopa
e823a7a7b0 Replaced new game wizard picture by my own screenshoots (not sure of the source for the previous ones) 2020-08-09 16:36:00 +02:00
Khopa
ffc1f9d48e New harrier payload, tarawa compatible. 2020-08-09 14:43:53 +02:00
Khopa
bb19bfb925 Improved special case for Su-33 carrier takeoff payload 2020-08-07 23:06:54 +02:00
Khopa
b3a2464249 Fixed issue with IL-78M tanker 2020-08-07 23:03:15 +02:00
Khopa
09718e73a3 Changed campaign names in new game window 2020-08-06 00:37:39 +02:00
Khopa
d5f20377ea Remove weapons fired from debriefing window (not computed anymore) 2020-08-06 00:36:49 +02:00
Khopa
f703d620c2 Changed the Nevada campaign setup 2020-08-06 00:35:55 +02:00
Khopa
5ac680b37d Slight change to base defense position calculations 2020-08-06 00:35:24 +02:00
Khopa
9bf57e99fb Removed Mig-29 from Strike mission 2020-08-06 00:34:13 +02:00
Khopa
b787f7cb11 RTB rules for CAS aircraft changed. Added PP M points for AJS 37 2020-08-06 00:33:37 +02:00
Khopa
7b35965dbf Fix : Awacs frequency in briefing 2020-08-06 00:32:47 +02:00
Khopa
1618c1e677 Awacs use 233Mhz instead of 133Mhz 2020-08-06 00:32:17 +02:00
Khopa
0a5ce108b7 Added preplanned point to briefing 2020-08-06 00:31:50 +02:00
Khopa
99c180441d Updated terrain data for all maps. 2020-08-05 22:01:32 +02:00
Khopa
79a7b0557c Improved Caucasus landmap collision data, added exclusions zones for airports. 2020-08-05 20:13:42 +02:00
Khopa
91cf192d2e Fixed AI aircraft do not start datalink. 2020-08-05 01:04:44 +02:00
Khopa
66d7435ed6 Minor balances changes 2020-08-05 00:58:14 +02:00
Khopa
19ea75b281 Fixed all aircraft spawning in the air after a few missions have been played without restarting DCS Liberation. 2020-08-05 00:58:02 +02:00
Khopa
f0350b7045 New Caucasus campaign in Russia 2020-08-04 01:17:26 +02:00
Khopa
9d4d3d0523 Avoid duplicate groups id. 2020-08-04 01:08:27 +02:00
Khopa
a76962e206 Added new campaign generation settings. Added Helicopter Carrier to China faction. 2020-08-04 00:14:42 +02:00
Khopa
4060039440 Changed tanker frequency range to avoid overlap with Persian Gulf TACAN frequencies. 2020-08-03 21:47:22 +02:00
Khopa
c3a3a428a4 Fix tanker speed, tacan and increased race track length. 2020-08-03 20:34:28 +02:00
Khopa
171e23bd09 Fixed S-300 (SA-10) sites missing a tracking radar. 2020-08-03 19:47:08 +02:00
Khopa
6f4b7e0f1a WIP 2020-08-03 19:43:12 +02:00
Khopa
ccf2cd3425 Factions small changes 2020-08-03 19:42:09 +02:00
Khopa
6ee444efd7 Aircraft should RTB when Bingo.
CAP should RTB when winchester.
2020-08-02 13:59:55 +02:00
Khopa
3e5be909a2 Lua script injected in mission will not listen to weapon fired event anymore. 2020-08-02 02:46:00 +02:00
Khopa
dac78f8f09 changelog update 2020-08-02 02:45:19 +02:00
Khopa
6b91e1b03c Fixed FW-190A8 spawning with bomb rack even when configured for CAP 2020-08-02 02:31:40 +02:00
Khopa
772295fc04 Avoid having Su-33 crashing when taking off from their carrier with a too big payload by removing some fuel. 2020-08-01 18:07:49 +02:00
Khopa
a4e93276b8 Possible to mix factions side. Player will always be blue. 2020-08-01 14:21:34 +02:00
Khopa
456a82acaa Multiple factions fixes 2020-08-01 14:20:37 +02:00
Khopa
f2fb2cb363 Fixed label in strike mission generator 2020-08-01 14:19:46 +02:00
C. Perreau
2a7e5eecd7 Merge pull request #30 from DeusEx010101/add-usa-aggressors-faction
Added USA aggressors aircraft.
2020-07-31 20:35:18 +02:00
Khopa
79502f56a0 Added Australia / Canada 2020-07-31 20:34:27 +02:00
Khopa
12dacfe2d2 Fixed A-20G payloads. 2020-07-30 19:31:38 +02:00
Donnie
d46337d694 Added USA aggressors. TODO. Decide on final aggressors unit list. 2020-07-26 11:27:18 -04:00
Khopa
f897cf745f Multiple WIP changes on UI / Submit manually debriefing. 2020-07-26 12:59:16 +02:00
Khopa
cfa4f7da2e Take off alt waypoint was editable in flight waypoint table. 2020-07-26 00:57:45 +02:00
Khopa
b21272cfab Made waypoint altitude column not editable 2020-07-25 23:07:23 +02:00
Khopa
8ce0520101 QSettings Windows can edit new performance setting to disable destroyed units 2020-07-25 23:05:13 +02:00
Khopa
4c17e1fd33 Possible to disable destroyed units. 2020-07-25 23:04:00 +02:00
Khopa
d5fb1f62f5 Previously destroyed units are added to the mission. 2020-07-25 18:46:10 +02:00
Khopa
b34ede3795 LHA carrier group ships are more spread out. 2020-07-25 16:21:03 +02:00
Khopa
4989d84693 Carrier group ships are more spread out. 2020-07-25 16:18:13 +02:00
Khopa
2f210ab59f Fixed error in carrier group generator if faction has no destroyers 2020-07-25 16:17:40 +02:00
Khopa
3ffea901f1 Added japan_2005 faction. 2020-07-25 16:15:23 +02:00
Khopa
5e2e6520ce Fixed issues with coldwar factions. 2020-07-25 16:14:53 +02:00
Khopa
a8679c8eef Fixed strike mission generator window was named "sead mission generator" 2020-07-25 15:14:48 +02:00
Khopa
469e842e96 Fixed wrong radio frequency for german WW2 warbirds. 2020-07-24 01:37:33 +02:00
Khopa
cd945c625f Base defense units can be controlled with CA. 2020-07-24 00:23:11 +02:00
Khopa
1346192b75 Fix : Carrier on Persian Gulf full map were sharing the same id. 2020-07-24 00:11:55 +02:00
Khopa
45bebdd94e Updated pydcs version in requirements.txt 2020-07-24 00:02:13 +02:00
Khopa
d0bbb025d3 Added carrier frequency to briefing. 2020-07-23 21:30:50 +02:00
Khopa
8d0c53ef69 Remove Oliver Hazard Perry from Cold War factions. 2020-07-23 21:12:46 +02:00
Khopa
a59c2dfb10 Changed F-15C default payload. Replaced AIM-9P by AIM-9M. Replaced AIM-120B by AIM-120C. 2020-07-22 23:59:25 +02:00
Khopa
9c7689f9b5 Increased offset for attack points. 2020-07-20 21:32:49 +02:00
Khopa
c580979fee Open base menu by single mouse click. 2020-07-20 20:36:57 +02:00
Khopa
e8e7bc95ea Culling is a bit less aggresive. 2020-07-20 00:29:37 +02:00
Khopa
839e3e0833 Removed JF-17 from usa 2005 faction. 2020-07-19 17:11:34 +02:00
Khopa
4f451fab2f Show required mods in new gam wizard 2020-07-19 17:11:05 +02:00
Khopa
7d0413f41d Remove Type 93 from radar db and cc fleet gen 2020-07-17 01:45:46 +02:00
Khopa
bbac78195d Credits 2020-07-17 01:08:47 +02:00
Khopa
20fef86b84 Fixed aircraft carrier cold start 2020-07-17 01:02:21 +02:00
Khopa
9581a8f1f4 Support for frenchpack mod & Rafale Mod 2020-07-09 00:39:33 +02:00
Khopa
58b4c36b6c MB-339PAN payload fix. 2020-07-05 18:10:54 +02:00
Khopa
15aaa5d9a1 MB-339PAN support. 2020-07-05 17:15:43 +02:00
Khopa
b38332d061 Requirements update, new pydcs version 2020-07-04 16:43:01 +02:00
Khopa
4cfbbb6756 A-4E-C is now considered carrier capable; 2020-07-04 15:59:50 +02:00
Khopa
dec7db9e69 Cleaning up dead code 2020-07-04 15:59:23 +02:00
Khopa
274be3bcfc Fix : Carrier sail into the wind. Not in the same direction. 2020-07-04 15:59:00 +02:00
Khopa
d8a668ce60 Fix : Channel map, removed town names 2020-07-04 02:04:53 +02:00
Khopa
a845ed1998 Fix : Code that should be commented for custom ref point. 2020-07-04 01:37:04 +02:00
Khopa
53bd147de2 Community A-4E-C support 2020-07-04 01:35:48 +02:00
Khopa
4248b518a2 Merge branch 'develop' of https://github.com/khopa/dcs_liberation 2020-07-03 02:55:50 +02:00
Khopa
8f65a88d8b New satelitte background for all maps. 2020-07-03 02:54:58 +02:00
C. Perreau
4d4a640f34 Merge pull request #11 from DeusEx010101/UI-fixes-new-themes
UI Update!
2020-07-01 15:39:31 +02:00
Donnie
af9ead5937 lots of UI enhancements for better feedback and state 2020-06-30 22:19:45 -04:00
Donnie
ae3518f450 Map cp lines and flight paths are now the color of your coalition (red or blue) 2020-06-30 16:44:04 -04:00
Donnie
04e77a97f2 Fix: map icons now match player side color (red or blue) 2020-06-29 17:32:29 -04:00
Donnie
0ff3ce98e0 new map graphic test 2020-06-29 17:31:47 -04:00
Donnie
df2659787c adjust map colors 2020-06-29 17:31:35 -04:00
Donnie
d994673e91 blurred map background to soften edges 2020-06-29 10:00:12 -04:00
Donnie
dce781ef0e New splash screen 2020-06-29 09:59:20 -04:00
Donnie
b0e2c73024 Made SAM range circles easier to see 2020-06-28 22:56:48 -04:00
Donnie
bda28f81cc Added disable button style 2020-06-28 22:45:30 -04:00
Donnie
d8dc3d48b1 made dcs theme default 2020-06-28 01:12:47 -04:00
Donnie
5fdfa6339d front line thinner 2020-06-28 01:10:38 -04:00
Donnie
9a799190ef Map ui design updated 2020-06-28 01:06:02 -04:00
Donnie
8d32ba5b8e Map red icons darker 2020-06-28 01:05:37 -04:00
Donnie
85a7f89ba9 Css updates to dcs theme 2020-06-27 23:55:56 -04:00
Donnie
17f5378326 Modified recruit button layout 2020-06-27 23:54:27 -04:00
Donnie
9d67741310 made font references constants 2020-06-27 23:53:56 -04:00
Donnie
ac6a106c6a Merge branch 'master' into DCS-UI-Theme 2020-06-26 16:18:01 -04:00
Donnie
d775b8baa0 Some clean up and refactoring 2020-06-26 11:39:28 -04:00
Donnie
2dc1b3ec43 Icons change based on theme. wip 2020-06-26 00:57:00 -04:00
Donnie
d3d5160861 UI Theme switcher working 2020-06-26 00:39:04 -04:00
Donnie
cdf8c3b6e5 menu bar and info panel spacing 2020-06-24 22:09:31 -04:00
Donnie
29b1bbab9d combobox styles. what a pain. WIP 2020-06-24 18:13:20 -04:00
Donnie
b994878465 checkboxes 2020-06-24 17:33:36 -04:00
Donnie
7890fd5cc7 Base theme applied. WIP. 2020-06-24 16:40:19 -04:00
227 changed files with 8046 additions and 1554 deletions

View File

@@ -1,9 +1,22 @@
![Logo](https://i.imgur.com/c2k18E1.png)
[DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player semi dynamic campaign.
[![Download](https://img.shields.io/github/downloads/khopa/dcs_liberation/total?label=Download)](https://github.com/Khopa/dcs_liberation/releases)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/paypalme/KhopaDCSL)
[![Discord](https://img.shields.io/discord/595702951800995872?label=Discord&logo=discord)](https://discord.gg/bKrtrkJ)
DCS Liberation uses [pydcs](http://github.com/pydcs/dcs) for mission generation
and [Mist](https://github.com/mrSkortch/MissionScriptingTools) for mission scripting
[![GitHub pull requests](https://img.shields.io/github/issues-pr/khopa/dcs_liberation)](https://github.com/Khopa/dcs_liberation)
[![GitHub issues](https://img.shields.io/github/issues/khopa/dcs_liberation)](https://github.com/Khopa/dcs_liberation/issues)
![GitHub stars](https://img.shields.io/github/stars/khopa/dcs_liberation?style=social)
## About DCS Liberation
DCS Liberation is a [DCS World](https://www.digitalcombatsimulator.com/en/products/world/) turn based single-player semi dynamic campaign.
It is an external program that generates full and complex DCS missions and manage a persistent combat environment.
![Logo](https://imgur.com/B6tvlBJ.png)
## Downloads
Latest release is available here : https://github.com/Khopa/dcs_liberation/releases
## Resources
@@ -11,15 +24,16 @@ and [Mist](https://github.com/mrSkortch/MissionScriptingTools) for mission scrip
* [Tutorials](https://github.com/Khopa/dcs_liberation/wiki/Tutorial-01-:-UI)
## Development Guide (WIP)
* [Developer/Contributor Guide]()(TODO)
Develop is the main development branch which is updated regularly.
Master branch will be updated less regularly and on release on new version.
* [Hosting DCS Liberation generated missions on a dedicated server]()(TODO)
Other branch might be used for feature development.
**Note :**
If you have errors with pydcs object not being defined, please check that you have the latest version installed. Sometimes the dev branch will use an even more recent version of pydcs that has not been published yet, so you might want to download pydcs directly from the pydcs repository, and copy it in your Python (or virtual env) ./Libs/site-package directory.
## Special Thanks
First, a big thanks to shdwp, for starting the original DCS Liberation project.
Then, DCS Liberation uses [pydcs](http://github.com/pydcs/dcs) for mission generation, and nothing would be possible without this.
It also uses the popular [Mist](https://github.com/mrSkortch/MissionScriptingTools) lua framework for mission scripting.
And for the JTAC feature, DCS Liberation embed Ciribob's JTAC Autolase [script](https://github.com/ciribob/DCS-JTACAutoLaze).
Please also show some support to these projects !

View File

@@ -1,3 +1,78 @@
# 2.0.11
## Features/Improvements :
* **[Units/Factions]** Added Mig-31, Su-30, Mi-24V, Mi-28N to Russia 2010 faction.
* **[Units/Factions]** Added F-15E to USA 2005 and USA 1990 factions.
* **[Mission Generator]** Added a parameter to choose whether the JTACs should use smoke markers or not
## Fixed issues :
* **[Units/Factions]** Fixed big performance issue in new release UI that occurred only when running the .exe
* **[Units/Factions]** Fixed mission generation not working with Libya faction
* **[Units/Factions]** Fixed OH-58D not being used by AI
* **[Units/Factions]** Typo in UK 1990 name (fixed by bwRavencl)
* **[Units/Factions]** Fixed Tanker Tacan channel not being the same as the briefing one. (Sorry)
* **[Mission Generator]** Neutral airbases services will now be disabled. (Not possible to refuel or re-arm there)
* **[Mission Generator]** AI will be configured to limit afterburner usage
* **[Mission Generator]** JTAC will not use laser codes above 1688 anymore
* **[Mission Generator]** JTAC units were misconfigured and would not be invisible/immortal.
* **[Mission Generator]** Increased JTAC status message duration to 25s, so you have more time to enter coordinates;
* **[Mission Generator]** Destroyed units carcass will not appear on airfields to avoid having a destroyed vehicle blocking a runway or taxiway.
# 2.0.10
## Features/Improvements :
* **[Misc]** Now possible to save game in a different file, and to open DCS Liberation savegame files. (You are not restricted to a single save file anymore)
* **[UI/UX]** New dark UI Theme and default theme improvement by Deus
* **[UI/UX]** New "satellite" map backgrounds
* **[UX]** Base menu is opened with a single mouse click
* **[Units/Factions/Mods]** Added Community A-4E-C support for faction Bluefor Cold War
* **[Units/Factions/Mods]** Added MB-339PAN support for faction Bluefor Cold War
* **[Units/Factions/Mods]** Added Rafale AI mod support
* **[Units/Factions/Mods]** Added faction "France Modded" with units from frenchpack v3.5 mod
* **[Units/Factions/Mods]** Added faction "Insurgent modded" with Insurgent units from frenchpack v3.5 mod (Toyota truck)
* **[Units/Factions/Mods]** Added factions Canada 2005, Australia 2005, Japan 2005, USA Aggressors, PMC
* **[New Game Wizard]** Added the list of required mods for modded factions.
* **[New Game Wizard]** No more RED vs BLUE opposing faction restrictions.
* **[New Game Wizard]** New campaign generation settings added : No aircraft carrier, no lha, no navy, invert map starting positions.
* **[Mission Generator]** Artillery units will start firing mission after a random delay. It should reduces lag spikes induced by artillery strikes by spreading them out.
* **[Mission Generator]** Ground units will retreat after taking too much casualties. Artillery units will retreat if engaged.
* **[Mission Generator]** The briefing will now contain the carrier ATC frequency
* **[Mission Generator]** The briefing contains a small situation update.
* **[Mission Generator]** Previously destroyed units are visible in the mission. (And added a performance settings to disable this behaviour)
* **[Mission Generator]** Basic JTAC on Frontlines
* **[Campaign Generator]** Added Tarawa in caucasus campaigns
* **[Campaign Generator]** Tuned the various existing campaign parameters
* **[Campaign Generator]** Added small campaign : "Russia" on Caucasus Theater
## Fixed issues :
* **[Mission Generator]** Carrier will sail into the wind, not in the same direction
* **[Mission Generator]** Carrier cold start was not working (flight was starting warm even when cold was selected)
* **[Mission Generator]** Carrier group ships are more spread out
* **[Mission Generator]** Fixed wrong radio frequency for german WW2 warbirds
* **[Mission Generator]** Fixed FW-190A8 spawning with bomb rack for CAP missions
* **[Mission Generator]** Fixed A-20G spawning with no payload
* **[Mission Generator]** Fixed Su-33 spawning too heavy to take off from carrier
* **[Mission Generator]** Fixed Harrier AV-8B spawning too heavy to take off from tarawa
* **[Mission Generator]** Base defense units were not controllable with Combined Arms
* **[Mission Generator]** Tanker speed was too low
* **[Mission Generator]** Tanker TACAN settings were wrong
* **[Mission Generator]** AI aircraft should start datalink ON (EPLRS)
* **[Mission Generator]** Base defense units should not spawn on runway and or taxyway. (The chance for this to happen should now be really really low)
* **[Mission Generator]** Fixed all flights starting "In flight" after playing a few missions (parking slot reset issue)
* **[Mission Script/Performance]** Mission lua script will not listen to weapons fired event anymore and register every fired weapons. This should improve performance especially in WW2 scenarios or when rocket artillery is firing.
* **[Campaign Generator]** Carrier name will now not appear for faction who do not have carriers
* **[Campaign Generator]** SA-10 sites will now have a tracking radar.
* **[Units/Factions]** Remove JF-17 from USA 2005 faction
* **[Units/Factions]** Remove AJS-37 from Russia 2010
* **[Units/Factions]** Removed Oliver Hazard Perry from cold war factions (too powerful sam system for the era)
* **[Bug]** On the persian gulf full map campaign, the two carriers were sharing the same id, this was causing a lot of bugs
* **[Performance]** Tuned the culling setting so that you cannot run into situation where no friendly or enemy AI flights are generated
* **[Other]** Application doesn't gracefully exit.
* **[Other]** Other minor fixes, and multiples factions small changes
# 2.0 RC 9
## Features/Improvements :

View File

@@ -0,0 +1,33 @@
from dcs.planes import *
from pydcs_extensions.a4ec.a4ec import A_4E_C
"""
This list contains the aircraft that do not use the guns as the last resort weapons, but as a main weapon
They'll RTB when they don't have gun ammo left
"""
GUNFIGHTERS = [
# Cold War
MiG_15bis,
MiG_19P,
MiG_21Bis,
F_86F_Sabre,
A_4E_C,
F_5E_3,
# Trainers
C_101CC,
L_39ZA,
# WW2
P_51D_30_NA,
P_51D,
P_47D_30,
SpitfireLFMkIXCW,
SpitfireLFMkIX,
Bf_109K_4,
FW_190D9,
FW_190A8,
I_16,
]

View File

@@ -49,6 +49,5 @@ UNITS_WITH_RADAR = [
LHA_1_Tarawa,
Type_052B_Destroyer,
Type_054A_Frigate,
Type_052C_Destroyer,
Type_093,
Type_052C_Destroyer
]

View File

@@ -13,20 +13,29 @@ from dcs.unit import *
from dcs.unittype import *
from dcs.unitgroup import *
from game.factions.australia_2005 import Australia_2005
from game.factions.bluefor_coldwar import BLUEFOR_COLDWAR
from game.factions.china_2000 import China_2000
from game.factions.bluefor_coldwar_a4 import BLUEFOR_COLDWAR_A4
from game.factions.bluefor_coldwar_mods import BLUEFOR_COLDWAR_MODS
from game.factions.canada_2005 import Canada_2005
from game.factions.china_2010 import China_2010
from game.factions.france_1995 import France_1995
from game.factions.france_2005 import France_2005
from game.factions.france_modded import France_2005_Modded
from game.factions.germany_1944_easy import Germany_1944_Easy
from game.factions.germany_1990 import Germany_1990
from game.factions.insurgent import Insurgent
from game.factions.insurgent_modded import Insurgent_modded
from game.factions.iran_2015 import Iran_2015
from game.factions.israel_2000 import Israel_2000
from game.factions.italy_1990 import Italy_1990
from game.factions.libya_2011 import Lybia_2011
from game.factions.italy_1990_mb339 import Italy_1990_MB339
from game.factions.japan_2005 import Japan_2005
from game.factions.libya_2011 import Libya_2011
from game.factions.netherlands_1990 import Netherlands_1990
from game.factions.north_korea_2000 import NorthKorea_2000
from game.factions.pakistan_2015 import Pakistan_2015
from game.factions.private_miltary_companies import PMC_WESTERN_B, PMC_RUSSIAN, PMC_WESTERN_A
from game.factions.russia_1975 import Russia_1975
from game.factions.germany_1944 import Germany_1944
from game.factions.india_2010 import India_2010
@@ -38,9 +47,11 @@ from game.factions.spain_1990 import Spain_1990
from game.factions.sweden_1990 import Sweden_1990
from game.factions.turkey_2005 import Turkey_2005
from game.factions.uae_2005 import UAE_2005
from game.factions.uk_1944 import UK_1944
from game.factions.uk_1990 import UnitedKingdom_1990
from game.factions.ukraine_2010 import Ukraine_2010
from game.factions.usa_1944 import USA_1944
from game.factions.us_aggressors import US_Aggressors
from game.factions.usa_1944 import USA_1944, ALLIES_1944
from game.factions.usa_1955 import USA_1955
from game.factions.usa_1960 import USA_1960
from game.factions.usa_1965 import USA_1965
@@ -48,6 +59,53 @@ from game.factions.usa_1990 import USA_1990
from game.factions.usa_2005 import USA_2005
from game.factions.bluefor_modern import BLUEFOR_MODERN
# PATCH pydcs data with MODS
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.mb339.mb339 import MB_339PAN
import pydcs_extensions.frenchpack.frenchpack as frenchpack
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M
plane_map["A-4E-C"] = A_4E_C
plane_map["MB-339PAN"] = MB_339PAN
plane_map["Rafale_M"] = Rafale_M
plane_map["Rafale_A_S"] = Rafale_A_S
vehicle_map["FieldHL"] = frenchpack._FIELD_HIDE
vehicle_map["HARRIERH"] = frenchpack._FIELD_HIDE_SMALL
vehicle_map["SMOKESAM"] = frenchpack.SMOKE_SAM_IR
vehicle_map["SmokeD1"] = frenchpack.SmokeD1
vehicle_map["SmokeD3"] = frenchpack.SmokeD3
vehicle_map["AMX10RCR"] = frenchpack.AMX_10RCR
vehicle_map["SEPAR"] = frenchpack.AMX_10RCR_SEPAR
vehicle_map["ERC"] = frenchpack.ERC_90
vehicle_map["M120"] = frenchpack.MO_120_RT
vehicle_map["AA20"] = frenchpack._53T2
vehicle_map["TRM2000"] = frenchpack.TRM_2000
vehicle_map["TRM2000_Citerne"] = frenchpack.TRM_2000_Fuel
vehicle_map["TRM2000_AA20"] = frenchpack.TRM_2000_53T2
vehicle_map["TRMMISTRAL"] = frenchpack.TRM_2000_PAMELA
vehicle_map["VABH"] = frenchpack.VAB_MEDICAL
vehicle_map["VAB_RADIO"] = frenchpack.VAB
vehicle_map["VAB_50"] = frenchpack.VAB__50
vehicle_map["VIB_VBR"] = frenchpack.VAB_T20_13
vehicle_map["VAB_HOT"] = frenchpack.VAB_MEPHISTO
vehicle_map["VAB_MORTIER"] = frenchpack.VAB_MORTIER
vehicle_map["VBL50"] = frenchpack.VBL__50
vehicle_map["VBLANF1"] = frenchpack.VBL_AANF1
vehicle_map["VBL-radio"] = frenchpack.VBL
vehicle_map["VBAE"] = frenchpack.VBAE_CRAB
vehicle_map["VBAE_MMP"] = frenchpack.VBAE_CRAB_MMP
vehicle_map["AMX-30B2"] = frenchpack.AMX_30B2
vehicle_map["Tracma"] = frenchpack.Tracma_TD_1500
vehicle_map["JTACFP"] = frenchpack.Infantry_Soldier_JTAC
vehicle_map["SHERIDAN"] = frenchpack.Char_M551_Sheridan
vehicle_map["Leclerc_XXI"] = frenchpack.Leclerc_Serie_XXI
vehicle_map["Toyota_bleu"] = frenchpack.DIM__TOYOTA_BLUE
vehicle_map["Toyota_vert"] = frenchpack.DIM__TOYOTA_GREEN
vehicle_map["Toyota_desert"] = frenchpack.DIM__TOYOTA_DESERT
vehicle_map["Kamikaze"] = frenchpack.DIM__KAMIKAZE
"""
---------- BEGINNING OF CONFIGURATION SECTION
"""
@@ -103,16 +161,19 @@ PRICES = {
F_4E: 10,
AJS37: 12,
C_101CC: 6,
A_4E_C: 8,
MB_339PAN: 6,
AV8BNA: 14,
M_2000C: 16,
Mirage_2000_5: 22,
FA_18C_hornet: 24,
F_15C: 26,
Mirage_2000_5: 20,
FA_18C_hornet: 22,
F_15C: 22,
F_15E: 24,
F_16C_50: 20,
F_14B: 22,
Tornado_IDS: 24,
Tornado_GR4: 24,
F_14B: 24,
Tornado_IDS: 20,
Tornado_GR4: 20,
# bomber
Su_17M4: 10,
@@ -131,13 +192,15 @@ PRICES = {
Ka_50: 13,
SA342M: 8,
SA342L: 5,
SA342Minigun: 4,
SA342Mistral: 8,
UH_1H: 4,
Mi_8MT: 5,
Mi_24V: 12,
Mi_28N: 16,
AH_1W: 10,
AH_64A: 12,
AH_64D: 16,
Mi_24V: 18,
Mi_28N: 24,
AH_1W: 20,
AH_64A: 24,
AH_64D: 30,
OH_58D: 6,
# Bombers
@@ -164,6 +227,10 @@ PRICES = {
P_47D_30: 18,
B_17G: 30,
# Modded
Rafale_M: 26,
Rafale_A_S: 26,
# armor
Armor.APC_MTLB: 4,
Armor.FDDM_Grad: 5,
@@ -171,15 +238,15 @@ PRICES = {
Armor.ARV_BTR_RD: 8,
Armor.APC_BTR_80: 8,
Armor.MBT_T_55: 18,
Armor.MBT_T_72B: 25,
Armor.MBT_T_80U: 30,
Armor.MBT_T_90: 35,
Armor.MBT_T_72B: 22,
Armor.MBT_T_80U: 25,
Armor.MBT_T_90: 30,
Armor.IFV_BMD_1: 8,
Armor.IFV_BMP_1: 14,
Armor.IFV_BMP_2: 16,
Armor.IFV_BMP_3: 18,
Armor.ZBD_04A: 12,
Armor.ZTZ_96B: 35,
Armor.ZTZ_96B: 30,
Armor.APC_Cobra: 4,
Armor.APC_M113: 6,
@@ -188,14 +255,14 @@ PRICES = {
Armor.IFV_M2A2_Bradley: 12,
Armor.APC_M1126_Stryker_ICV: 10,
Armor.ATGM_M1134_Stryker: 12,
Armor.MBT_M60A3_Patton: 18,
Armor.MBT_M1A2_Abrams: 35,
Armor.MBT_Leclerc: 35,
Armor.MBT_Leopard_1A3: 24,
Armor.MBT_Leopard_2: 35,
Armor.MBT_Merkava_Mk__4: 35,
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_Challenger_II: 30,
Armor.MBT_Challenger_II: 25,
Armor.IFV_Marder: 10,
Armor.IFV_MCV_80: 10,
Armor.IFV_LAV_25: 7,
@@ -208,7 +275,7 @@ PRICES = {
Artillery.SPH_2S3_Akatsia: 24,
Artillery.SPH_2S19_Msta: 30,
Artillery.MLRS_BM_21_Grad: 15,
Artillery.MLRS_9K57_Uragan_BM_27: 40,
Artillery.MLRS_9K57_Uragan_BM_27: 50,
Artillery.MLRS_9A52_Smerch: 40,
Unarmed.Transport_UAZ_469: 3,
@@ -270,6 +337,38 @@ PRICES = {
Armed_speedboat: 10,
Dry_cargo_ship_Ivanov: 10,
Tanker_Elnya_160: 10,
# FRENCH PACK MOD
frenchpack.AMX_10RCR: 10,
frenchpack.AMX_10RCR_SEPAR: 12,
frenchpack.ERC_90: 12,
frenchpack.MO_120_RT: 10,
frenchpack._53T2: 4,
frenchpack.TRM_2000: 4,
frenchpack.TRM_2000_Fuel: 4,
frenchpack.TRM_2000_53T2: 8,
frenchpack.TRM_2000_PAMELA: 14,
frenchpack.VAB_MEDICAL: 8,
frenchpack.VAB: 6,
frenchpack.VAB__50: 4,
frenchpack.VAB_T20_13: 6,
frenchpack.VAB_MEPHISTO: 8,
frenchpack.VAB_MORTIER: 10,
frenchpack.VBL__50: 4,
frenchpack.VBL_AANF1: 2,
frenchpack.VBL: 1,
frenchpack.VBAE_CRAB: 8,
frenchpack.VBAE_CRAB_MMP: 12,
frenchpack.AMX_30B2: 18,
frenchpack.Tracma_TD_1500: 2,
frenchpack.Infantry_Soldier_JTAC: 1,
frenchpack.Leclerc_Serie_XXI: 35,
frenchpack.DIM__TOYOTA_BLUE: 2,
frenchpack.DIM__TOYOTA_GREEN: 2,
frenchpack.DIM__TOYOTA_DESERT: 2,
frenchpack.DIM__KAMIKAZE: 6,
}
"""
@@ -298,6 +397,7 @@ UNIT_BY_TASK = {
MiG_21Bis,
MiG_29A,
MiG_29S,
MiG_31,
FA_18C_hornet,
F_15C,
F_14B,
@@ -317,8 +417,12 @@ UNIT_BY_TASK = {
FW_190A8,
SpitfireLFMkIXCW,
SpitfireLFMkIX,
A_4E_C,
Rafale_M,
SA342Mistral
],
CAS: [
F_15E,
F_86F_Sabre,
MiG_15bis,
L_39ZA,
@@ -333,6 +437,7 @@ UNIT_BY_TASK = {
Ka_50,
SA342M,
SA342L,
SA342Minigun,
Su_24M,
Su_24MR,
AH_64A,
@@ -350,7 +455,9 @@ UNIT_BY_TASK = {
A_20G,
P_47D_30,
Ju_88A4,
B_17G
B_17G,
MB_339PAN,
Rafale_A_S
],
Transport: [
IL_76MD,
@@ -513,6 +620,29 @@ UNIT_BY_TASK = {
Artillery.M12_GMC,
Artillery.Sturmpanzer_IV_Brummbär,
frenchpack.DIM__TOYOTA_BLUE,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__TOYOTA_GREEN,
frenchpack.DIM__KAMIKAZE,
frenchpack.AMX_10RCR,
frenchpack.AMX_10RCR_SEPAR,
frenchpack.ERC_90,
frenchpack.TRM_2000_PAMELA,
frenchpack.VAB__50,
frenchpack.VAB_MEPHISTO,
frenchpack.VAB_T20_13,
frenchpack.VBL__50,
frenchpack.VBL_AANF1,
frenchpack.VBAE_CRAB,
frenchpack.VBAE_CRAB_MMP,
frenchpack.AMX_30B2,
frenchpack.Leclerc_Serie_XXI,
frenchpack.DIM__TOYOTA_BLUE,
frenchpack.DIM__TOYOTA_GREEN,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__KAMIKAZE,
],
AirDefence: [
@@ -602,46 +732,83 @@ Units separated by country.
country : DCS Country name
"""
FACTIONS = {
"Bluefor Modern": BLUEFOR_MODERN,
"Bluefor Cold War 1970s": BLUEFOR_COLDWAR,
"Bluefor Cold War (with A-4)": BLUEFOR_COLDWAR_A4,
"Bluefor Cold War (with A-4 and MB339)": BLUEFOR_COLDWAR_MODS,
"USA 1955 (WW2 Pack)": USA_1955,
"USA 1960": USA_1960,
"USA 1965": USA_1965,
"USA 1990": USA_1990,
"USA 2005": USA_2005,
"USA Aggressors 2005": US_Aggressors,
"Russia 1955": Russia_1955,
"Russia 1965": Russia_1965,
"Russia 1975": Russia_1975,
"Russia 1990": Russia_1990,
"Russia 2010": Russia_2010,
"France 1995": France_1995,
"France 2005": France_2005,
"France 2005 (Modded)": France_2005_Modded,
"Germany 1990": Germany_1990,
"Netherlands 1990": Netherlands_1990,
"United Kingdom 1990": UnitedKingdom_1990,
"Spain 1990": Spain_1990,
"Italy 1990": Italy_1990,
"Italy 1990 (With MB339)": Italy_1990_MB339,
"Israel 2000": Israel_2000,
"China 2010": China_2010,
"Sweden 1990": Sweden_1990,
"Australia 2005": Australia_2005,
"Canada 2005": Canada_2005,
"Japan 2005": Japan_2005,
"Turkey 2005": Turkey_2005,
"United Arab Emirates 2005": UAE_2005,
"Ukraine 2010": Ukraine_2010,
"India 2010": India_2010,
"Libya 2011": Libya_2011,
"Pakistan 2015": Pakistan_2015,
"Iran 2015": Iran_2015,
"Lybia 2011": Lybia_2011,
"China 2000": China_2000,
"North Korea 2000": NorthKorea_2000,
"Insurgent": Insurgent,
"Insurgent (Modded)": Insurgent_modded,
"PMC (American)": PMC_WESTERN_A,
"PMC (American) - MB339": PMC_WESTERN_B,
"PMC (Russian)": PMC_RUSSIAN,
"Allies 1944 (WW2 Pack)": USA_1944,
"USA 1944 (WW2 Pack)": ALLIES_1944,
"UK 1944 (WW2 Pack)": UK_1944,
"Germany 1944 (WW2 Pack)": Germany_1944,
"Germany 1944 Easy (WW2 Pack)": Germany_1944_Easy,
"Bluefor Modern": BLUEFOR_MODERN,
"Bluefor Cold War 1970s": BLUEFOR_COLDWAR,
"USA 2005": USA_2005,
"USA 1990": USA_1990,
"USA 1965": USA_1965,
"USA 1960": USA_1960,
"USA 1955 (WW2 Pack)": USA_1955,
"Allies 1944 (WW2 Pack)": USA_1944,
"France 2005": France_2005,
"France 1995": France_1995,
"Germany 1990": Germany_1990,
"Netherlands 1990": Netherlands_1990,
"United Kingdown 1990": UnitedKingdom_1990,
"Spain 1990": Spain_1990,
"Italy 1990": Italy_1990,
"Sweden 1990": Sweden_1990,
"Ukraine 2010": Ukraine_2010,
"India 2010": India_2010,
"Pakistan 2015": Pakistan_2015,
"Israel 2000": Israel_2000,
"Turkey 2005": Turkey_2005,
"United Arab Emirates 2005": UAE_2005,
}
BLUEFOR_FACTIONS = [FACTIONS[f]["country"] for f in FACTIONS if FACTIONS[f]["side"] == "blue"]
print(BLUEFOR_FACTIONS)
CARRIER_TYPE_BY_PLANE = {
@@ -708,6 +875,7 @@ PLANE_PAYLOAD_OVERRIDES = {
F_5E_3: COMMON_OVERRIDE,
F_14B: COMMON_OVERRIDE,
F_15C: COMMON_OVERRIDE,
F_15E: COMMON_OVERRIDE,
F_16C_50: COMMON_OVERRIDE,
JF_17: COMMON_OVERRIDE,
M_2000C: COMMON_OVERRIDE,
@@ -735,6 +903,8 @@ PLANE_PAYLOAD_OVERRIDES = {
SA342L:COMMON_OVERRIDE,
SA342Mistral:COMMON_OVERRIDE,
Mi_8MT:COMMON_OVERRIDE,
Mi_24V:COMMON_OVERRIDE,
Mi_28N:COMMON_OVERRIDE,
Ka_50:COMMON_OVERRIDE,
L_39ZA:COMMON_OVERRIDE,
L_39C:COMMON_OVERRIDE,
@@ -749,6 +919,12 @@ PLANE_PAYLOAD_OVERRIDES = {
Bf_109K_4: COMMON_OVERRIDE,
SpitfireLFMkIXCW: COMMON_OVERRIDE,
SpitfireLFMkIX: COMMON_OVERRIDE,
A_20G: COMMON_OVERRIDE,
A_4E_C: COMMON_OVERRIDE,
MB_339PAN: COMMON_OVERRIDE,
Rafale_M: COMMON_OVERRIDE,
Rafale_A_S: COMMON_OVERRIDE,
OH_58D: COMMON_OVERRIDE,
AH_64D:{
CAS: "AGM-114K*16"
@@ -772,8 +948,6 @@ PLANE_LIVERY_OVERRIDES = {
FA_18C_hornet: "VFA-34", # default livery for the hornet is blue angels one
}
"""
Possible time periods for new games
@@ -825,12 +999,14 @@ CARRIER_CAPABLE = [
F_14B,
AV8BNA,
Su_33,
A_4E_C,
UH_1H,
Mi_8MT,
Ka_50,
AH_1W,
OH_58D,
UH_60A,
SA342L,
SA342M,
@@ -846,6 +1022,7 @@ LHA_CAPABLE = [
Ka_50,
AH_1W,
OH_58D,
UH_60A,
SA342L,
SA342M,
@@ -919,6 +1096,8 @@ def find_infantry(country_name: str) -> typing.List[UnitType]:
def unit_type_name(unit_type) -> str:
return unit_type.id and unit_type.id or unit_type.name
def unit_type_name_2(unit_type) -> str:
return unit_type.name and unit_type.name or unit_type.id
def unit_type_from_name(name: str) -> UnitType:
if name in vehicle_map:

View File

@@ -65,25 +65,10 @@ class Event:
else:
return self.departure_cp
@property
def threat_description(self) -> str:
return ""
def flight_name(self, for_task: typing.Type[typing.Type[Task]]) -> str:
return "Flight"
@property
def tasks(self) -> typing.Collection[typing.Type[Task]]:
return []
@property
def ai_banned_tasks(self) -> typing.Collection[typing.Type[Task]]:
return []
@property
def player_banned_tasks(self) -> typing.Collection[typing.Type[Task]]:
return []
@property
def global_cp_available(self) -> bool:
return False
@@ -206,10 +191,10 @@ class Event:
# ------------------------------
# Captured bases
if self.game.player_country in db.BLUEFOR_FACTIONS:
coalition = 2 # Value in DCS mission event for BLUE
else:
coalition = 1 # Value in DCS mission event for RED
#if self.game.player_country in db.BLUEFOR_FACTIONS:
coalition = 2 # Value in DCS mission event for BLUE
#else:
# coalition = 1 # Value in DCS mission event for RED
for captured in debriefing.base_capture_events:
try:
@@ -253,6 +238,11 @@ class Event:
except Exception as e:
print(e)
# Destroyed units carcass
# -------------------------
for destroyed_unit in debriefing.destroyed_units:
self.game.add_destroyed_units(destroyed_unit)
# -----------------------------------
# Compute damage to bases
for cp in self.game.theater.player_points():

View File

@@ -4,16 +4,6 @@ from userdata.debriefing import Debriefing
class FrontlineAttackEvent(Event):
TARGET_VARIETY = 2
TARGET_AMOUNT_FACTOR = 0.5
ATTACKER_AMOUNT_FACTOR = 0.4
ATTACKER_DEFENDER_FACTOR = 0.7
STRENGTH_INFLUENCE = 0.3
SUCCESS_FACTOR = 1.5
@property
def threat_description(self):
return "{} vehicles".format(self.to_cp.base.assemble_count())
@property
def tasks(self) -> typing.Collection[typing.Type[Task]]:
@@ -26,32 +16,11 @@ class FrontlineAttackEvent(Event):
def global_cp_available(self) -> bool:
return True
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAS:
return "CAS flight"
elif for_task == CAP:
return "CAP flight"
elif for_task == PinpointStrike:
return "Ground attack"
def __str__(self):
return "Frontline attack"
def is_successfull(self, debriefing: Debriefing):
if self.game.player_name == self.attacker_name:
attacker_country = self.game.player_country
defender_country = self.game.enemy_country
else:
attacker_country = self.game.enemy_country
defender_country = self.game.player_country
# TODO : Rework
#alive_attackers = sum([v for k, v in debriefing.alive_units.get(attacker_country, {}).items() if db.unit_task(k) == PinpointStrike])
#alive_defenders = sum([v for k, v in debriefing.alive_units.get(defender_country, {}).items() if db.unit_task(k) == PinpointStrike])
#attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) > self.SUCCESS_FACTOR
attackers_success = True
if self.from_cp.captured:
return attackers_success
else:
@@ -65,46 +34,20 @@ class FrontlineAttackEvent(Event):
self.to_cp.base.affect_strength(-0.1)
def player_attacking(self, flights: db.TaskForceDict):
# assert CAS in flights and CAP in flights and len(flights) == 2, "Invalid flights"
op = FrontlineAttackOperation(game=self.game,
attacker_name=self.attacker_name,
defender_name=self.defender_name,
from_cp=self.from_cp,
departure_cp=self.departure_cp,
to_cp=self.to_cp)
defenders = self.to_cp.base.assemble_attack()
max_attackers = int(math.ceil(sum(defenders.values()) * self.ATTACKER_DEFENDER_FACTOR))
attackers = db.unitdict_restrict_count(self.from_cp.base.assemble_attack(), max_attackers)
op.setup(defenders=defenders,
attackers=attackers,
strikegroup=flights[CAS],
escort=flights[CAP],
interceptors=assigned_units_from(self.to_cp.base.scramble_interceptors(1)))
self.operation = op
def player_defending(self, flights: db.TaskForceDict):
# assert CAP in flights and len(flights) == 1, "Invalid flights"
op = FrontlineAttackOperation(game=self.game,
attacker_name=self.attacker_name,
defender_name=self.defender_name,
from_cp=self.from_cp,
departure_cp=self.departure_cp,
to_cp=self.to_cp)
defenders = self.to_cp.base.assemble_attack()
max_attackers = int(math.ceil(sum(defenders.values())))
attackers = db.unitdict_restrict_count(self.from_cp.base.assemble_attack(), max_attackers)
op.setup(defenders=defenders,
attackers=attackers,
strikegroup=assigned_units_from(self.from_cp.base.scramble_cas(1)),
escort=assigned_units_from(self.from_cp.base.scramble_sweep(1)),
interceptors=flights[CAP])
self.operation = op

View File

@@ -0,0 +1,50 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
Australia_2005 = {
"country": "Australia",
"side": "blue",
"units": [
FA_18C_hornet,
KC_135,
KC130,
C_130,
E_3A,
Armor.MBT_M1A2_Abrams,
Armor.MBT_Leopard_1A3,
Armor.APC_M113,
Armor.IFV_LAV_25,
Armor.IFV_MCV_80,
UH_1H,
AH_1W, # Standing as EC Tiger
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Hawk_PCP,
AirDefence.Rapier_FSA_Launcher,
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad": [
AirDefence.Rapier_FSA_Launcher,
], "helicopter_carrier": [
LHA_1_Tarawa,
], "destroyer": [
USS_Arleigh_Burke_IIa,
], "cruiser": [
Ticonderoga_class,
], "lhanames": [
"HMAS Canberra",
"HMAS Adelaide"
], "boat":[
"ArleighBurkeGroupGenerator"
], "has_jtac": True
}

View File

@@ -42,10 +42,6 @@ BLUEFOR_COLDWAR = {
CVN_74_John_C__Stennis,
], "helicopter_carrier": [
LHA_1_Tarawa,
], "destroyer": [
Oliver_Hazzard_Perry_class,
], "cruiser": [
Ticonderoga_class,
], "carrier_names": [
"CVN-71 Theodore Roosevelt",
"CVN-72 Abraham Lincoln",
@@ -57,7 +53,6 @@ BLUEFOR_COLDWAR = {
"LHA-3 Belleau Wood",
"LHA-4 Nassau",
"LHA-5 Peleliu"
], "boat":[
"OliverHazardPerryGroupGenerator"
]
], "boat": [
], "has_jtac": True
}

View File

@@ -0,0 +1,65 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
from pydcs_extensions.a4ec.a4ec import A_4E_C
BLUEFOR_COLDWAR_A4 = {
"country": "USA",
"side": "blue",
"units": [
F_14B,
F_4E,
F_5E_3,
A_10A,
AJS37,
A_4E_C,
KC_135,
KC130,
C_130,
E_3A,
UH_1H,
SA342M,
SA342L,
Armor.MBT_M60A3_Patton,
Armor.APC_M113,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Chaparral_M48,
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad": [
AirDefence.AAA_Vulcan_M163,
], "aircraft_carrier": [
CVN_74_John_C__Stennis,
], "helicopter_carrier": [
LHA_1_Tarawa,
], "cruiser": [
Ticonderoga_class,
], "carrier_names": [
"CVN-71 Theodore Roosevelt",
"CVN-72 Abraham Lincoln",
"CVN-73 George Washington",
"CVN-74 John C. Stennis",
], "lhanames": [
"LHA-1 Tarawa",
"LHA-2 Saipan",
"LHA-3 Belleau Wood",
"LHA-4 Nassau",
"LHA-5 Peleliu"
], "boat": [
], "requirements": {
"Community A-4E": "https://heclak.github.io/community-a4e-c/",
}, "has_jtac": True
}

View File

@@ -0,0 +1,68 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.mb339.mb339 import MB_339PAN
BLUEFOR_COLDWAR_MODS = {
"country": "USA",
"side": "blue",
"units": [
F_14B,
F_4E,
F_5E_3,
A_10A,
AJS37,
A_4E_C,
MB_339PAN,
KC_135,
KC130,
C_130,
E_3A,
UH_1H,
SA342M,
SA342L,
Armor.MBT_M60A3_Patton,
Armor.APC_M113,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Chaparral_M48,
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad": [
AirDefence.AAA_Vulcan_M163,
], "aircraft_carrier": [
CVN_74_John_C__Stennis,
], "helicopter_carrier": [
LHA_1_Tarawa,
], "cruiser": [
Ticonderoga_class,
], "carrier_names": [
"CVN-71 Theodore Roosevelt",
"CVN-72 Abraham Lincoln",
"CVN-73 George Washington",
"CVN-74 John C. Stennis",
], "lhanames": [
"LHA-1 Tarawa",
"LHA-2 Saipan",
"LHA-3 Belleau Wood",
"LHA-4 Nassau",
"LHA-5 Peleliu"
], "boat": [
], "requirements": {
"MB-339A": "http://www.freccetricolorivirtuali.net/",
"Community A-4E": "https://heclak.github.io/community-a4e-c/",
}, "has_jtac": True
}

View File

@@ -78,5 +78,5 @@ BLUEFOR_MODERN = {
"LHA-5 Peleliu"
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -0,0 +1,43 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
Canada_2005 = {
"country": "Canada",
"side": "blue",
"units": [
FA_18C_hornet,
KC_135,
KC130,
C_130,
E_3A,
Armor.MBT_Leopard_1A3,
Armor.MBT_Leopard_2,
Armor.IFV_LAV_25,
Armor.APC_M113,
Armor.IFV_MCV_80,
UH_1H,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Avenger_M1097,
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad": [
AirDefence.SAM_Avenger_M1097,
], "destroyer": [
USS_Arleigh_Burke_IIa,
], "cruiser": [
Ticonderoga_class,
], "boat":[
"ArleighBurkeGroupGenerator"
], "has_jtac": True
}

View File

@@ -3,7 +3,7 @@ from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
China_2000 = {
China_2010 = {
"country": "China",
"side": "red",
"units": [
@@ -37,7 +37,9 @@ China_2000 = {
Unarmed.Transport_Ural_375,
Unarmed.Transport_UAZ_469,
Infantry.Soldier_AK,
Infantry.Paratrooper_AKS,
Infantry.Infantry_Soldier_Rus,
Infantry.Paratrooper_RPG_16,
CV_1143_5_Admiral_Kuznetsov,
@@ -56,10 +58,20 @@ China_2000 = {
Type_052C_Destroyer
], "cruiser": [
Type_054A_Frigate,
], "helicopter_carrier": [
Type_071_Amphibious_Transport_Dock,
], "lhanames": [
"Kunlun Shan",
"Jinggang Shan",
"Changbai Shan",
"Yimeng Shan",
"Longhu Shan",
"Wuzhi Shan",
"Wudang Shan"
], "carrier_names": [
"001 Liaoning",
"002 Shandong",
], "boat":[
"ChineseNavyGroupGenerator", "Type54GroupGenerator"
]
"Type54GroupGenerator"
], "has_jtac": True
}

View File

@@ -17,6 +17,7 @@ France_1995 = {
SA342M,
SA342L,
SA342Mistral,
Armor.MBT_Leclerc,
Armor.TPz_Fuchs, # Standing as VAB
@@ -42,5 +43,5 @@ France_1995 = {
AirDefence.SAM_Roland_ADS
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -18,6 +18,7 @@ France_2005 = {
SA342M,
SA342L,
SA342Mistral,
Armor.MBT_Leclerc,
Armor.TPz_Fuchs, # Standing as VAB
@@ -50,12 +51,12 @@ France_2005 = {
], "cruiser": [
Ticonderoga_class,
], "carrier_names": [
"R91 Charles de Gaulle",
"PA Charles de Gaulle",
], "lhanames": [
"L9013 Mistral",
"L9014 Tonerre",
"L9015 Dixmude"
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -0,0 +1,80 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
import pydcs_extensions.frenchpack.frenchpack as frenchpack
from pydcs_extensions.rafale.rafale import Rafale_M, Rafale_A_S
France_2005_Modded = {
"country": "France",
"side": "blue",
"units": [
M_2000C,
Mirage_2000_5,
Rafale_M,
Rafale_A_S,
KC_135,
KC130,
C_130,
E_3A,
SA342M,
SA342L,
SA342Mistral,
Armor.MBT_Leclerc,
Artillery.SPH_M109_Paladin, # Standing as AMX30 AuF1
Artillery.MLRS_M270,
frenchpack.AMX_10RCR,
frenchpack.AMX_10RCR_SEPAR,
frenchpack.ERC_90,
frenchpack.TRM_2000_PAMELA,
frenchpack.VAB__50,
frenchpack.VAB_MEPHISTO,
frenchpack.VAB_T20_13,
frenchpack.VBL__50,
frenchpack.VBL_AANF1,
frenchpack.VBAE_CRAB,
frenchpack.VBAE_CRAB_MMP,
frenchpack.AMX_30B2,
frenchpack.Leclerc_Serie_XXI,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Roland_ADS,
AirDefence.SAM_Hawk_PCP,
AirDefence.HQ_7_Self_Propelled_LN, # Standing as Crotale
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad": [
AirDefence.HQ_7_Self_Propelled_LN,
AirDefence.SAM_Roland_ADS
], "aircraft_carrier": [
CVN_74_John_C__Stennis, # Standing as CDG Aircraft Carrier
], "helicopter_carrier": [
LHA_1_Tarawa, # Standing as Mistral Class
], "destroyer": [
Oliver_Hazzard_Perry_class,
], "cruiser": [
Ticonderoga_class,
], "carrier_names": [
"PA Charles de Gaulle",
], "lhanames": [
"L9013 Mistral",
"L9014 Tonerre",
"L9015 Dixmude"
], "boat": [
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
], "requirements": {
"frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974",
"RAFALE 2.5.5": "https://www.digitalcombatsimulator.com/fr/files/3307478/",
}, "has_jtac": True
}

View File

@@ -39,7 +39,7 @@ Germany_1944 = {
"objects": WW2_GERMANY_BUILDINGS,
"doctrine": WWII_DOCTRINE,
"boat": ["UBoatGroupGenerator", "SchnellbootGroupGenerator"],
"boat_count": 4,
"boat_count": 2,
"missiles": ["V1GroupGenerator"],
"missiles_count": 1
}

View File

@@ -32,7 +32,7 @@ Germany_1944_Easy = {
"objects": WW2_GERMANY_BUILDINGS,
"doctrine": WWII_DOCTRINE,
"boat": ["UBoatGroupGenerator", "SchnellbootGroupGenerator"],
"boat_count": 4,
"boat_count": 1,
"missiles": ["V1GroupGenerator"],
"missiles_count": 1
}

View File

@@ -51,5 +51,5 @@ India_2010 = {
"INS Vikramaditya"
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator", "MolniyaGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -0,0 +1,33 @@
from dcs.ships import *
from dcs.vehicles import *
from pydcs_extensions.frenchpack.frenchpack import DIM__TOYOTA_BLUE, DIM__TOYOTA_DESERT, DIM__TOYOTA_GREEN, \
DIM__KAMIKAZE
Insurgent_modded = {
"country": "Insurgents",
"side": "red",
"units": [
AirDefence.AAA_ZU_23_Insurgent_Closed,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
DIM__TOYOTA_BLUE,
DIM__TOYOTA_DESERT,
DIM__TOYOTA_GREEN,
DIM__KAMIKAZE,
Armor.ARV_BRDM_2,
Armor.APC_Cobra,
Unarmed.Transport_Ural_375,
Unarmed.Transport_UAZ_469,
Infantry.Soldier_AK,
Infantry.Infantry_Soldier_Insurgents,
Bulk_cargo_ship_Yakushev,
Dry_cargo_ship_Ivanov,
Tanker_Elnya_160
], "requirements": {
"frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974",
}
}

View File

@@ -35,5 +35,5 @@ Israel_2000 = {
AirDefence.SAM_Avenger_M1097
], "boat": [
"ArleighBurkeGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -39,10 +39,10 @@ Italy_1990 = {
Oliver_Hazzard_Perry_class,
], "cruiser": [
Ticonderoga_class,
], "lha_names": [
], "lhanames": [
"Giuseppe Garibaldi",
"Cavour",
], "boat":[
"OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -0,0 +1,52 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
from pydcs_extensions.mb339.mb339 import MB_339PAN
Italy_1990_MB339 = {
"country": "Italy",
"side": "blue",
"units": [
Tornado_IDS,
AV8BNA,
MB_339PAN,
KC_135,
S_3B_Tanker,
C_130,
E_3A,
AH_1W,
UH_1H,
Armor.MBT_Leopard_1A3, # OF-40 MBT
Armor.APC_M113,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Avenger_M1097,
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad":[
AirDefence.SAM_Avenger_M1097,
], "helicopter_carrier": [
LHA_1_Tarawa,
], "destroyer": [
Oliver_Hazzard_Perry_class,
], "cruiser": [
Ticonderoga_class,
], "lhanames": [
"Giuseppe Garibaldi",
"Cavour",
], "boat": [
"OliverHazardPerryGroupGenerator"
], "requirements": {
"MB-339A": "http://www.freccetricolorivirtuali.net/",
}, "has_jtac": True
}

View File

@@ -0,0 +1,54 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
Japan_2005 = {
"country": "Japan",
"side": "blue",
"units": [
F_15C, # F-15J/DJ
F_16C_50, # F-2A/B
F_4E, # F-4EJ
KC_135,
KC130,
C_130,
E_3A,
AH_1W,
AH_64D,
Armor.MBT_Merkava_Mk__4, # Standing as Type 10 MBT
Armor.MBT_M1A2_Abrams, # Standing as Type 90 MBT
Armor.IFV_Marder, # Standing as Type 89 IFV
Armor.TPz_Fuchs, # Standing as Type 96 APC
Armor.IFV_LAV_25, # Standing as Type 16 or Type 87
Armor.APC_M1043_HMMWV_Armament,
Artillery.MLRS_M270,
Artillery.SPH_M109_Paladin, # Standing as Type 99 SPH
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Patriot_EPP_III,
LHA_1_Tarawa,
], "shorad": [
AirDefence.SPAAA_Gepard, # Type 87 SPAG
], "helicopter_carrier": [
LHA_1_Tarawa, # Standing as Hyuga-class helicopter carrier
], "destroyer": [
USS_Arleigh_Burke_IIa,
], "cruiser": [
Ticonderoga_class,
], "lhanames": [
"Hyuga",
"Ise",
], "boat":[
"ArleighBurkeGroupGenerator"
], "has_jtac": True
}

View File

@@ -2,8 +2,8 @@ from dcs.helicopters import *
from dcs.planes import *
from dcs.vehicles import *
Lybia_2011 = {
"country": "Russia",
Libya_2011 = {
"country": "Libya",
"side": "red",
"units": [

View File

@@ -34,5 +34,5 @@ Netherlands_1990 = {
AirDefence.SAM_Avenger_M1097
], "boat": [
"OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -36,5 +36,5 @@ Pakistan_2015 = {
AirDefence.AAA_ZU_23_Closed
], "boat": [
"Type54GroupGenerator", "OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -0,0 +1,91 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
from pydcs_extensions.mb339.mb339 import MB_339PAN
PMC_WESTERN_A = {
"country": "USA",
"side": "blue",
"units": [
C_101CC,
UH_1H,
Mi_8MT,
OH_58D,
SA342M,
Armor.APC_M1043_HMMWV_Armament,
Armor.IFV_MCV_80,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Avenger_M1097,
Armed_speedboat,
], "shorad":[
AirDefence.SAM_Avenger_M1097,
], "has_jtac": True
}
PMC_WESTERN_B = {
"country": "USA",
"side": "blue",
"units": [
MB_339PAN,
C_101CC,
UH_1H,
Mi_8MT,
OH_58D,
SA342M,
Armor.APC_M1043_HMMWV_Armament,
Armor.IFV_MCV_80,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Avenger_M1097,
Armed_speedboat,
], "shorad":[
AirDefence.SAM_Avenger_M1097,
], "has_jtac": True,
"requirements": {
"MB-339A": "http://www.freccetricolorivirtuali.net/",
}
}
PMC_RUSSIAN = {
"country": "Russia",
"side": "blue",
"units": [
L_39C,
L_39ZA,
Mi_8MT,
Mi_24V,
Ka_50,
Armor.APC_Cobra,
Armor.APC_BTR_80,
Armor.ARV_BRDM_2,
Unarmed.Transport_Ural_375,
Infantry.Paratrooper_AKS,
Infantry.Paratrooper_RPG_16,
AirDefence.AAA_ZU_23_on_Ural_375,
Armed_speedboat,
], "shorad":[
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_Closed,
], "has_jtac": True
}

View File

@@ -58,6 +58,9 @@ Russia_1990 = {
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_13_Strela_10M3_9A35M3,
AirDefence.SPAAA_ZSU_23_4_Shilka
], "carrier_names": [
"Admiral Kuznetov",
"Admiral Gorshkov"
], "aircraft_carrier": [
CV_1143_5_Admiral_Kuznetsov,
], "destroyer": [

View File

@@ -7,13 +7,14 @@ Russia_2010 = {
"country": "Russia",
"side": "red",
"units": [
AJS37,
MiG_23MLD,
Su_25,
Su_27,
Su_30,
Su_33,
MiG_29S,
MiG_31,
Su_25,
Su_25T,
Su_34,
Su_24M,
@@ -28,6 +29,8 @@ Russia_2010 = {
Ka_50,
Mi_8MT,
Mi_24V,
Mi_28N,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_11_Buk_LN_9A310M1,
@@ -37,6 +40,9 @@ Russia_2010 = {
Armor.MBT_T_90,
Armor.MBT_T_80U,
Armor.MBT_T_72B,
Armor.IFV_BMP_1,
Armor.IFV_BMP_2,
Armor.IFV_BMP_3,
Artillery.MLRS_9K57_Uragan_BM_27,
Artillery.SPH_2S19_Msta,
@@ -59,6 +65,8 @@ Russia_2010 = {
AirDefence.SAM_SA_13_Strela_10M3_9A35M3
], "aircraft_carrier": [
CV_1143_5_Admiral_Kuznetsov,
], "carrier_names": [
"Admiral Kuznetov"
], "destroyer": [
FF_1135M_Rezky,
], "cruiser": [

View File

@@ -46,5 +46,5 @@ Spain_1990 = {
"Juan Carlos I",
], "boat":[
"OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -27,5 +27,5 @@ Sweden_1990 = {
],
"shorad": [
AirDefence.SAM_Avenger_M1097
]
], "has_jtac": True
}

View File

@@ -38,5 +38,5 @@ Turkey_2005 = {
AirDefence.SPAAA_ZSU_23_4_Shilka
], "boat":[
"OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -32,5 +32,5 @@ UAE_2005 = {
Armed_speedboat,
], "boat":[
"OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

42
game/factions/uk_1944.py Normal file
View File

@@ -0,0 +1,42 @@
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
from game.data.building_data import WW2_ALLIES_BUILDINGS
from game.data.doctrine import WWII_DOCTRINE
UK_1944 = {
"country": "UK",
"side": "blue",
"units": [
P_51D,
P_51D_30_NA,
P_47D_30,
SpitfireLFMkIX,
SpitfireLFMkIXCW,
A_20G,
B_17G,
Armor.MT_M4A4_Sherman_Firefly,
Armor.MT_M4_Sherman,
Armor.APC_M2A1,
Armor.CT_Cromwell_IV,
Armor.ST_Centaur_IV,
Armor.HIT_Churchill_VII,
Infantry.Infantry_SMLE_No_4_Mk_1,
LS_Samuel_Chase,
LST_Mk_II,
LCVP__Higgins_boat,
Unarmed.CCKW_353,
AirDefence.AAA_Bofors_40mm,
], "shorad":[
AirDefence.AAA_Bofors_40mm,
],
"objects": WW2_ALLIES_BUILDINGS,
"doctrine": WWII_DOCTRINE,
"boat": ["WW2LSTGroupGenerator"],
"boat_count": 1
}

View File

@@ -16,7 +16,7 @@ UnitedKingdom_1990 = {
C_130,
E_3A,
SA342L,
SA342M,
AH_64A,
Armor.MBT_Challenger_II,
@@ -42,11 +42,11 @@ UnitedKingdom_1990 = {
Oliver_Hazzard_Perry_class,
], "cruiser": [
Ticonderoga_class,
], "lha_names": [
], "lhanames": [
"HMS Invincible",
"HMS Illustrious",
"HMS Ark Royal",
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -0,0 +1,72 @@
from dcs.helicopters import *
from dcs.planes import *
from dcs.ships import *
from dcs.vehicles import *
US_Aggressors = {
"country": "USAF Aggressors",
"side": "red",
"units": [
F_15C,
F_5E_3,
FA_18C_hornet,
F_16C_50,
Su_27,
KC_135,
KC130,
C_130,
E_3A,
UH_1H,
AH_64D,
Ka_50,
SA342M,
SA342L,
Armor.MBT_M1A2_Abrams,
Armor.MBT_Leopard_2,
Armor.ATGM_M1134_Stryker,
Armor.IFV_M2A2_Bradley,
Armor.APC_M1043_HMMWV_Armament,
Artillery.MLRS_M270,
Artillery.SPH_M109_Paladin,
Unarmed.Transport_M818,
Infantry.Infantry_M4,
Infantry.Soldier_M249,
AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Patriot_EPP_III,
CVN_74_John_C__Stennis,
LHA_1_Tarawa,
Armed_speedboat,
], "shorad": [
AirDefence.SAM_Avenger_M1097,
], "aircraft_carrier": [
CVN_74_John_C__Stennis,
], "helicopter_carrier": [
LHA_1_Tarawa,
], "destroyer": [
Oliver_Hazzard_Perry_class,
USS_Arleigh_Burke_IIa,
], "cruiser": [
Ticonderoga_class,
], "carrier_names": [
"CVN-71 Theodore Roosevelt",
"CVN-72 Abraham Lincoln",
"CVN-73 George Washington",
"CVN-74 John C. Stennis",
], "lhanames": [
"LHA-1 Tarawa",
"LHA-2 Saipan",
"LHA-3 Belleau Wood",
"LHA-4 Nassau",
"LHA-5 Peleliu"
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
]
}

View File

@@ -6,6 +6,40 @@ from game.data.building_data import WW2_ALLIES_BUILDINGS
from game.data.doctrine import WWII_DOCTRINE
USA_1944 = {
"country": "USA",
"side": "blue",
"units": [
P_51D,
P_51D_30_NA,
P_47D_30,
A_20G,
B_17G,
Armor.MT_M4_Sherman,
Armor.M30_Cargo_Carrier,
Armor.APC_M2A1,
Armor.LAC_M8_Greyhound,
Armor.TD_M10_GMC,
Artillery.M12_GMC,
Infantry.Infantry_M1_Garand,
LS_Samuel_Chase,
LST_Mk_II,
LCVP__Higgins_boat,
Unarmed.CCKW_353,
AirDefence.AAA_Bofors_40mm,
], "shorad":[
AirDefence.AAA_Bofors_40mm,
],
"objects": WW2_ALLIES_BUILDINGS,
"doctrine": WWII_DOCTRINE,
"boat": ["WW2LSTGroupGenerator"],
"boat_count": 2
}
ALLIES_1944 = {
"country": "USA",
"side": "blue",
"units": [

View File

@@ -37,6 +37,5 @@ USA_1965 = {
AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Chaparral_M48
], "boat":[
"OliverHazardPerryGroupGenerator"
]
}

View File

@@ -8,6 +8,7 @@ USA_1990 = {
"side": "blue",
"units": [
F_15C,
F_15E,
F_14B,
FA_18C_hornet,
@@ -23,6 +24,7 @@ USA_1990 = {
UH_1H,
AH_64A,
OH_58D,
Armor.MBT_M1A2_Abrams,
Armor.IFV_LAV_25,
@@ -61,5 +63,5 @@ USA_1990 = {
"LHA-5 Peleliu"
], "boat":[
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -8,10 +8,10 @@ USA_2005 = {
"side": "blue",
"units": [
F_15C,
F_15E,
F_14B,
FA_18C_hornet,
F_16C_50,
JF_17,
A_10C,
AV8BNA,
@@ -22,6 +22,7 @@ USA_2005 = {
UH_1H,
AH_64D,
OH_58D,
Armor.MBT_M1A2_Abrams,
Armor.ATGM_M1134_Stryker,
@@ -67,5 +68,5 @@ USA_2005 = {
"LHA-5 Peleliu"
], "boat":[
"ArleighBurkeGroupGenerator"
]
], "has_jtac": True
}

View File

@@ -1,7 +1,7 @@
from datetime import datetime, timedelta
from game.db import REWARDS, PLAYER_BUDGET_BASE, sys
from game.game_stats import GameStats
from game.models.game_stats import GameStats
from gen.flights.ai_flight_planner import FlightPlanner
from gen.ground_forces.ai_ground_planner import GroundPlanner
from .event import *
@@ -56,8 +56,8 @@ class Game:
current_unit_id = 0
current_group_id = 0
def __init__(self, player_name: str, enemy_name: str, theater: ConflictTheater, start_date: datetime):
self.settings = Settings()
def __init__(self, player_name: str, enemy_name: str, theater: ConflictTheater, start_date: datetime, settings):
self.settings = settings
self.events = []
self.theater = theater
self.player_name = player_name
@@ -73,7 +73,26 @@ class Game:
self.informations = []
self.informations.append(Information("Game Start", "-" * 40, 0))
self.__culling_points = self.compute_conflicts_position()
self.__frontlineData = []
self.__destroyed_units = []
self.jtacs = []
self.savepath = ""
self.sanitize_sides()
def sanitize_sides(self):
"""
Make sure the opposing factions are using different countries
:return:
"""
if self.player_country == self.enemy_country:
if self.player_country == "USA":
self.enemy_country = "USAF Aggressors"
elif self.player_country == "Russia":
self.enemy_country = "USSR"
else:
self.enemy_country = "Russia"
@property
def player_faction(self):
@@ -175,18 +194,6 @@ class Game:
else:
return event.name == self.player_name
def get_player_coalition_id(self):
if self.player_country in db.BLUEFOR_FACTIONS:
return 2
else:
return 1
def get_enemy_coalition_id(self):
if self.get_player_coalition_id() == 1:
return 2
else:
return 1
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint] = None):
logging.info("Pass turn")
@@ -237,6 +244,9 @@ class Game:
gplanner.plan_groundwar()
self.ground_planners[cp.id] = gplanner
# Autosave progress
persistency.autosave(self)
def _enemy_reinforcement(self):
"""
Compute and commision reinforcement for enemy bases
@@ -340,6 +350,8 @@ class Game:
# By default, use the existing frontline conflict position
for conflict in self.theater.conflicts():
points.append(Conflict.frontline_position(self.theater, conflict[0], conflict[1])[0])
points.append(conflict[0].position)
points.append(conflict[1].position)
# If there is no conflict take the center point between the two nearest opposing bases
if len(points) == 0:
@@ -351,6 +363,11 @@ class Game:
if d < min_distance:
min_distance = d
cpoint = Point((cp.position.x + cp2.position.x) / 2, (cp.position.y + cp2.position.y) / 2)
points.append(cp.position)
points.append(cp2.position)
break
if cpoint is not None:
break
if cpoint is not None:
points.append(cpoint)
@@ -361,6 +378,14 @@ class Game:
return points
def add_destroyed_units(self, data):
pos = Point(data["x"], data["z"])
if self.theater.is_on_land(pos):
self.__destroyed_units.append(data)
def get_destroyed_units(self):
return self.__destroyed_units
def position_culled(self, pos):
"""
Check if unit can be generated at given position depending on culling performance settings
@@ -375,3 +400,21 @@ class Game:
return False
return True
# 1 = red, 2 = blue
def get_player_coalition_id(self):
return 2
def get_enemy_coalition_id(self):
return 1
def get_player_coalition(self):
return dcs.action.Coalition.Blue
def get_enemy_coalition(self):
return dcs.action.Coalition.Red
def get_player_color(self):
return "blue"
def get_enemy_color(self):
return "red"

View File

@@ -0,0 +1,14 @@
class DestroyedUnit:
"""
Store info about a destroyed unit
"""
x: int
y: int
name: str
def __init__(self, x , y, name):
self.x = x
self.y = y
self.name = name

View File

@@ -0,0 +1,13 @@
from theater import ControlPoint
class FrontlineData:
"""
This Data structure will store information about an existing frontline
"""
def __init__(self, from_cp:ControlPoint, to_cp: ControlPoint):
self.to_cp = to_cp
self.from_cp = from_cp
self.enemy_units_position = []
self.blue_units_position = []

View File

@@ -14,19 +14,6 @@ class FrontlineAttackOperation(Operation):
attackers = None # type: db.ArmorDict
defenders = None # type: db.ArmorDict
def setup(self,
defenders: db.ArmorDict,
attackers: db.ArmorDict,
strikegroup: db.AssignedUnitsDict,
escort: db.AssignedUnitsDict,
interceptors: db.AssignedUnitsDict):
self.strikegroup = strikegroup
self.escort = escort
self.interceptors = interceptors
self.defenders = defenders
self.attackers = attackers
def prepare(self, terrain: Terrain, is_quick: bool):
super(FrontlineAttackOperation, self).prepare(terrain, is_quick)
if self.defender_name == self.game.player_name:
@@ -47,29 +34,6 @@ class FrontlineAttackOperation(Operation):
conflict=conflict)
def generate(self):
#if self.is_player_attack:
# self.prepare_carriers(db.unitdict_from(self.strikegroup))
# ground units
# self.armorgen.generate_vec(self.attackers, self.defenders)
## strike group w/ heli support
#planes_flights = {k: v for k, v in self.strikegroup.items() if k in plane_map.values()}
#self.airgen.generate_cas_strikegroup(*assigned_units_split(planes_flights), at=self.attackers_starting_position)
#heli_flights = {k: v for k, v in self.strikegroup.items() if k in helicopters.helicopter_map.values()}
#if heli_flights:
# self.briefinggen.append_frequency("FARP + Heli flights", "127.5 MHz AM")
# for farp, dict in zip(self.groundobjectgen.generate_farps(sum([x[0] for x in heli_flights.values()])),
# db.assignedunits_split_to_count(heli_flights, self.groundobjectgen.FARP_CAPACITY)):
# self.airgen.generate_cas_strikegroup(*assigned_units_split(dict),
# at=farp,
# escort=len(planes_flights) == 0)
#self.airgen.generate_attackers_escort(*assigned_units_split(self.escort), at=self.attackers_starting_position)
#self.airgen.generate_defense(*assigned_units_split(self.interceptors), at=self.defenders_starting_position)
self.briefinggen.title = "Frontline CAS"
self.briefinggen.description = "Provide CAS for the ground forces attacking enemy lines. Operation will be considered successful if total number of enemy units will be lower than your own by a factor of 1.5 (i.e. with 12 units from both sides, enemy forces need to be reduced to at least 8), meaning that you (and, probably, your wingmans) should concentrate on destroying the enemy units. Target base strength will be lowered as a result. Be advised that your flight will not attack anything until you explicitly tell them so by comms menu."
self.briefinggen.append_waypoint("CAS AREA IP")

View File

@@ -18,7 +18,6 @@ class Operation:
conflict = None # type: Conflict
armorgen = None # type: ArmorConflictGenerator
airgen = None # type: AircraftConflictGenerator
shipgen = None # type: ShipGenerator
triggersgen = None # type: TriggersGenerator
airsupportgen = None # type: AirSupportConflictGenerator
visualgen = None # type: VisualGenerator
@@ -65,7 +64,6 @@ class Operation:
self.current_mission = mission
self.conflict = conflict
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings, self.game)
self.shipgen = ShipGenerator(mission, conflict)
self.airsupportgen = AirSupportConflictGenerator(mission, conflict, self.game)
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
self.visualgen = VisualGenerator(mission, conflict, self.game)
@@ -74,9 +72,6 @@ class Operation:
self.groundobjectgen = GroundObjectsGenerator(mission, conflict, self.game)
self.briefinggen = BriefingGenerator(mission, conflict, self.game)
player_country = self.from_cp.captured and self.attacker_country or self.defender_country
enemy_country = self.from_cp.captured and self.defender_country or self.attacker_country
def prepare(self, terrain: Terrain, is_quick: bool):
with open("resources/default_options.lua", "r") as f:
options_dict = loads(f.read())["options"]
@@ -90,12 +85,12 @@ class Operation:
# Setup coalition :
self.current_mission.coalition["blue"] = Coalition("blue")
self.current_mission.coalition["red"] = Coalition("red")
if self.game.player_country and self.game.player_country in db.BLUEFOR_FACTIONS:
self.current_mission.coalition["blue"].add_country(country_dict[db.country_id_from_name(self.game.player_country)]())
self.current_mission.coalition["red"].add_country(country_dict[db.country_id_from_name(self.game.enemy_country)]())
else:
self.current_mission.coalition["blue"].add_country(country_dict[db.country_id_from_name(self.game.enemy_country)]())
self.current_mission.coalition["red"].add_country(country_dict[db.country_id_from_name(self.game.player_country)]())
p_country = self.game.player_country
e_country = self.game.enemy_country
self.current_mission.coalition["blue"].add_country(country_dict[db.country_id_from_name(p_country)]())
self.current_mission.coalition["red"].add_country(country_dict[db.country_id_from_name(e_country)]())
print([c for c in self.current_mission.coalition["blue"].countries.keys()])
print([c for c in self.current_mission.coalition["red"].countries.keys()])
@@ -125,6 +120,26 @@ class Operation:
# Generate ground object first
self.groundobjectgen.generate()
# Generate destroyed units
for d in self.game.get_destroyed_units():
try:
utype = db.unit_type_from_name(d["type"])
except KeyError:
continue
pos = Point(d["x"], d["z"])
if utype is not None and not self.game.position_culled(pos) and self.game.settings.perf_destroyed_units:
self.current_mission.static_group(
country=self.current_mission.country(self.game.player_country),
name="",
_type=utype,
hidden=True,
position=pos,
heading=d["orientation"],
dead=True,
)
# Air Support (Tanker & Awacs)
self.airsupportgen.generate(self.is_awacs_enabled)
@@ -139,6 +154,7 @@ class Operation:
self.airgen.generate_flights(cp, country, self.game.planners[cp.id])
# Generate ground units on frontline everywhere
self.game.jtacs = []
for player_cp, enemy_cp in self.game.theater.conflicts(True):
conflict = Conflict.frontline_cas_conflict(self.attacker_name, self.defender_name,
self.current_mission.country(self.attacker_country),
@@ -157,14 +173,14 @@ class Operation:
else:
self.current_mission.groundControl.red_tactical_commander = self.ca_slots
# triggers
# Triggers
if self.game.is_player_attack(self.conflict.attackers_country):
cp = self.conflict.from_cp
else:
cp = self.conflict.to_cp
self.triggersgen.generate()
# options
# Options
self.forcedoptionsgen.generate()
# Generate Visuals Smoke Effects
@@ -177,6 +193,24 @@ class Operation:
load_mist.add_action(DoScript(String(f.read())))
self.current_mission.triggerrules.triggers.append(load_mist)
# Load Ciribob's JTACAutoLase script
load_autolase = TriggerStart(comment="Load JTAC script")
with open("./resources/scripts/JTACAutoLase.lua") as f:
script = f.read()
script = script + "\n"
smoke = "true"
if hasattr(self.game.settings, "jtac_smoke_on"):
if not self.game.settings.jtac_smoke_on:
smoke = "false"
for jtac in self.game.jtacs:
script = script + "\n" + "JTACAutoLase('" + str(jtac[2]) + "', " + str(jtac[1]) + ", " + smoke + ", \"vehicle\")" + "\n"
load_autolase.add_action(DoScript(String(script)))
self.current_mission.triggerrules.triggers.append(load_autolase)
load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script")
with open("./resources/scripts/dcs_liberation.lua") as f:
script = f.read()
@@ -189,10 +223,10 @@ class Operation:
# Briefing Generation
for i, tanker_type in enumerate(self.airsupportgen.generated_tankers):
self.briefinggen.append_frequency("Tanker {} ({})".format(TANKER_CALLSIGNS[i], tanker_type), "{}X/{} MHz AM".format(97+i, 130+i))
self.briefinggen.append_frequency("Tanker {} ({})".format(TANKER_CALLSIGNS[i], tanker_type), "{}X/{} MHz AM".format(60+i, 130+i))
if self.is_awacs_enabled:
self.briefinggen.append_frequency("AWACS", "133 MHz AM")
self.briefinggen.append_frequency("AWACS", "233 MHz AM")
self.briefinggen.append_frequency("Flight", "251 MHz AM")

View File

@@ -1,32 +1,43 @@
class Settings:
# Difficulty settings
player_skill = "Good"
enemy_skill = "Average"
enemy_vehicle_skill = "Average"
map_coalition_visibility = "All Units"
labels = "Full"
only_player_takeoff = True # Legacy parameter do not use
night_disabled = False
external_views_allowed = True
supercarrier = False
multiplier = 1
generate_marks = True
sams = True # Legacy parameter do not use
cold_start = False # Legacy parameter do not use
version = None
def __init__(self):
# Generator settings
self.inverted = False
self.do_not_generate_carrier = False # TODO : implement
self.do_not_generate_lha = False # TODO : implement
self.do_not_generate_player_navy = True # TODO : implement
self.do_not_generate_enemy_navy = True # TODO : implement
# Performance oriented
perf_red_alert_state = True
perf_smoke_gen = True
perf_artillery = True
perf_moving_units = True
perf_infantry = True
perf_ai_parking_start = True
# Difficulty settings
self.player_skill = "Good"
self.enemy_skill = "Average"
self.enemy_vehicle_skill = "Average"
self.map_coalition_visibility = "All Units"
self.labels = "Full"
self.only_player_takeoff = True # Legacy parameter do not use
self.night_disabled = False
self.external_views_allowed = True
self.supercarrier = False
self.multiplier = 1
self.generate_marks = True
self.sams = True # Legacy parameter do not use
self.cold_start = False # Legacy parameter do not use
self.version = None
self.include_jtac_if_available = True
self.jtac_smoke_on = True
# Performance culling
perf_culling = False
perf_culling_distance = 100
# Performance oriented
self.perf_red_alert_state = True
self.perf_smoke_gen = True
self.perf_artillery = True
self.perf_moving_units = True
self.perf_infantry = True
self.perf_ai_parking_start = True
self.perf_destroyed_units = True
# Performance culling
self.perf_culling = False
self.perf_culling_distance = 100

View File

@@ -3,7 +3,6 @@ from .aircraft import *
from .armor import *
from .airsupportgen import *
from .conflictgen import *
from .shipgen import *
from .visualgen import *
from .triggergen import *
from .environmentgen import *

View File

@@ -1,10 +1,12 @@
from dcs.action import ActivateGroup, AITaskPush
from dcs.condition import TimeAfter, CoalitionHasAirdrome
from dcs.action import ActivateGroup, AITaskPush, MessageToCoalition, MessageToAll
from dcs.condition import TimeAfter, CoalitionHasAirdrome, PartOfCoalitionInZone
from dcs.helicopters import UH_1H
from dcs.terrain.terrain import NoParkingSlotError
from dcs.triggers import TriggerOnce, Event
from game.data.cap_capabilities_db import GUNFIGHTERS
from game.settings import Settings
from game.utils import nm_to_meter
from gen.flights.ai_flight_planner import FlightPlanner
from gen.flights.flight import Flight, FlightType, FlightWaypointType
from .conflictgen import *
@@ -36,7 +38,7 @@ class AircraftConflictGenerator:
return self.settings.cold_start and StartType.Cold or StartType.Warm
def _setup_group(self, group: FlyingGroup, for_task: typing.Type[Task], client_count: int):
def _setup_group(self, group: FlyingGroup, for_task: typing.Type[Task], flight: Flight):
did_load_loadout = False
unit_type = group.units[0].unit_type
@@ -70,8 +72,8 @@ class AircraftConflictGenerator:
for unit_instance in group.units:
unit_instance.livery_id = db.PLANE_LIVERY_OVERRIDES[unit_type]
single_client = client_count == 1
for idx in range(0, min(len(group.units), client_count)):
single_client = flight.client_count == 1
for idx in range(0, min(len(group.units), flight.client_count)):
if single_client:
group.units[idx].set_player()
else:
@@ -85,16 +87,32 @@ class AircraftConflictGenerator:
if unit_type is F_14B:
group.units[idx].set_property(F_14B.Properties.INSAlignmentStored.id, True)
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
# TODO : refactor this following bad specific special case code :(
if unit_type in helicopters.helicopter_map.values() and unit_type not in [UH_1H]:
group.set_frequency(127.5)
else:
if unit_type not in [P_51D_30_NA, P_51D, SpitfireLFMkIX, SpitfireLFMkIXCW, FW_190A8, FW_190D9, Bf_109K_4, P_47D_30]:
if unit_type not in [P_51D_30_NA, P_51D, SpitfireLFMkIX, SpitfireLFMkIXCW, P_47D_30, I_16, FW_190A8, FW_190D9, Bf_109K_4]:
group.set_frequency(251.0)
else:
# WW2
group.set_frequency(124.0)
if unit_type in [FW_190A8, FW_190D9, Bf_109K_4, Ju_88A4]:
group.set_frequency(40)
else:
group.set_frequency(124.0)
# Special case so Su 33 carrier take off
if unit_type is Su_33:
if task is not CAP:
for unit in group.units:
unit.fuel = Su_33.fuel_max / 2.2
else:
for unit in group.units:
unit.fuel = Su_33.fuel_max * 0.8
def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None, start_type = None) -> FlyingGroup:
assert count > 0
@@ -108,7 +126,7 @@ class AircraftConflictGenerator:
country=side,
name=name,
aircraft_type=unit_type,
airport=self.m.terrain.airport_by_id(airport.id),
airport=airport,
maintask=None,
start_type=start_type,
group_size=count,
@@ -143,10 +161,13 @@ class AircraftConflictGenerator:
group.points[0].alt_type = "RADIO"
return group
def _generate_at_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: typing.Union[ShipGroup, StaticGroup]) -> FlyingGroup:
def _generate_at_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: typing.Union[ShipGroup, StaticGroup], start_type=None) -> FlyingGroup:
assert count > 0
assert unit is not None
if start_type is None:
start_type = self._start_type()
logging.info("airgen: {} for {} at unit {}".format(unit_type, side.id, at))
return self.m.flight_group_from_unit(
country=side,
@@ -154,7 +175,7 @@ class AircraftConflictGenerator:
aircraft_type=unit_type,
pad_group=at,
maintask=None,
start_type=self._start_type(),
start_type=start_type,
group_size=count)
def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition):
@@ -233,6 +254,11 @@ class AircraftConflictGenerator:
def generate_flights(self, cp, country, flight_planner:FlightPlanner):
# Clear pydcs parking slots
if cp.airport is not None:
for ps in cp.airport.parking_slots:
ps.unit_id = None
for flight in flight_planner.flights:
if flight.client_count == 0 and self.game.position_culled(flight.from_cp.position):
@@ -240,11 +266,7 @@ class AircraftConflictGenerator:
continue
group = self.generate_planned_flight(cp, country, flight)
if flight.flight_type == FlightType.INTERCEPTION:
self.setup_group_as_intercept_flight(group, flight)
self._setup_custom_payload(flight, group)
else:
self.setup_flight_group(group, flight, flight.flight_type)
self.setup_flight_group(group, flight, flight.flight_type)
self.setup_group_activation_trigger(flight, group)
@@ -255,7 +277,7 @@ class AircraftConflictGenerator:
group.late_activation = False
group.uncontrolled = True
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationControlTriggerForGroup" + str(group.id))
activation_trigger = TriggerOnce(Event.NoEvent, "FlightStartTrigger" + str(group.id))
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in * 60))
if (flight.from_cp.cptype == ControlPointType.AIRBASE):
if flight.from_cp.captured:
@@ -265,12 +287,16 @@ class AircraftConflictGenerator:
activation_trigger.add_condition(
CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
if flight.flight_type == FlightType.INTERCEPTION:
self.setup_interceptor_triggers(group, flight, activation_trigger)
group.add_trigger_action(StartCommand())
activation_trigger.add_action(AITaskPush(group.id, len(group.tasks)))
self.m.triggerrules.triggers.append(activation_trigger)
else:
group.late_activation = True
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationActivationTriggerForGroup" + str(group.id))
activation_trigger = TriggerOnce(Event.NoEvent, "FlightLateActivationTrigger" + str(group.id))
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in*60))
if(flight.from_cp.cptype == ControlPointType.AIRBASE):
@@ -279,9 +305,22 @@ class AircraftConflictGenerator:
else:
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
if flight.flight_type == FlightType.INTERCEPTION:
self.setup_interceptor_triggers(group, flight, activation_trigger)
activation_trigger.add_action(ActivateGroup(group.id))
self.m.triggerrules.triggers.append(activation_trigger)
def setup_interceptor_triggers(self, group, flight, activation_trigger):
detection_zone = self.m.triggers.add_triggerzone(flight.from_cp.position, radius=25000, hidden=False, name="ITZ")
if flight.from_cp.captured:
activation_trigger.add_condition(PartOfCoalitionInZone(self.game.get_enemy_color(), detection_zone.id)) # TODO : support unit type in part of coalition
activation_trigger.add_action(MessageToAll(String("WARNING : Enemy aircrafts have been detected in the vicinity of " + flight.from_cp.name + ". Interceptors are taking off."), 20))
else:
activation_trigger.add_condition(PartOfCoalitionInZone(self.game.get_player_color(), detection_zone.id))
activation_trigger.add_action(MessageToAll(String("WARNING : We have detected that enemy aircrafts are scrambling for an interception on " + flight.from_cp.name + " airbase."), 20))
def generate_planned_flight(self, cp, country, flight:Flight):
try:
if flight.client_count == 0 and self.game.settings.perf_ai_parking_start:
@@ -310,7 +349,8 @@ class AircraftConflictGenerator:
unit_type=flight.unit_type,
count=flight.count,
client_count=0,
at=self.m.find_group(group_name),)
at=self.m.find_group(group_name),
start_type=st)
else:
group = self._generate_at_airport(
name=namegen.next_unit_name(country, cp.id, flight.unit_type),
@@ -318,7 +358,7 @@ class AircraftConflictGenerator:
unit_type=flight.unit_type,
count=flight.count,
client_count=0,
airport=self.m.terrain.airport_by_id(cp.at.id),
airport=cp.airport,
start_type=st)
except Exception:
# Generated when there is no place on Runway or on Parking Slots
@@ -332,56 +372,71 @@ class AircraftConflictGenerator:
at=cp.position)
group.points[0].alt = 1500
flight.group = group
return group
def setup_group_as_intercept_flight(self, group, flight):
group.points[0].ETA = 0
group.late_activation = True
self._setup_group(group, Intercept, flight.client_count)
self._setup_group(group, Intercept, flight)
for point in flight.points:
group.add_waypoint(Point(point.x,point.y), point.alt)
def setup_flight_group(self, group, flight, flight_type):
if flight_type in [FlightType.CAP, FlightType.BARCAP, FlightType.TARCAP]:
if flight_type in [FlightType.CAP, FlightType.BARCAP, FlightType.TARCAP, FlightType.INTERCEPTION]:
group.task = CAP.name
self._setup_group(group, CAP, flight.client_count)
self._setup_group(group, CAP, flight)
# group.points[0].tasks.clear()
# group.tasks.clear()
# group.tasks.append(EngageTargets(max_distance=40, targets=[Targets.All.Air]))
group.points[0].tasks.clear()
group.points[0].tasks.append(EngageTargets(max_distance=nm_to_meter(50), targets=[Targets.All.Air]))
# group.tasks.append(EngageTargets(max_distance=nm_to_meter(120), targets=[Targets.All.Air]))
pass
if flight.unit_type not in GUNFIGHTERS:
group.points[0].tasks.append(OptRTBOnOutOfAmmo(OptRTBOnOutOfAmmo.Values.AAM))
else:
group.points[0].tasks.append(OptRTBOnOutOfAmmo(OptRTBOnOutOfAmmo.Values.Cannon))
elif flight_type in [FlightType.CAS, FlightType.BAI]:
group.task = CAS.name
self._setup_group(group, CAS, flight.client_count)
self._setup_group(group, CAS, flight)
group.points[0].tasks.clear()
group.points[0].tasks.append(CASTaskAction())
group.points[0].tasks.append(EngageTargets(max_distance=nm_to_meter(10), targets=[Targets.All.GroundUnits.GroundVehicles]))
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree))
group.points[0].tasks.append(OptRTBOnOutOfAmmo(OptRTBOnOutOfAmmo.Values.Unguided))
group.points[0].tasks.append(OptRestrictJettison(True))
elif flight_type in [FlightType.SEAD, FlightType.DEAD]:
group.task = SEAD.name
self._setup_group(group, SEAD, flight.client_count)
self._setup_group(group, SEAD, flight)
group.points[0].tasks.clear()
group.points[0].tasks.append(NoTask())
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFire))
group.points[0].tasks.append(OptRestrictJettison(True))
group.points[0].tasks.append(OptRTBOnOutOfAmmo(OptRTBOnOutOfAmmo.Values.ASM))
elif flight_type in [FlightType.STRIKE]:
group.task = PinpointStrike.name
self._setup_group(group, GroundAttack, flight.client_count)
self._setup_group(group, GroundAttack, flight)
group.points[0].tasks.clear()
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFire))
group.points[0].tasks.append(OptRestrictJettison(True))
elif flight_type in [FlightType.ANTISHIP]:
group.task = AntishipStrike.name
self._setup_group(group, AntishipStrike, flight.client_count)
self._setup_group(group, AntishipStrike, flight)
group.points[0].tasks.clear()
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFire))
group.points[0].tasks.append(OptRestrictJettison(True))
group.points[0].tasks.append(OptRTBOnBingoFuel(True))
group.points[0].tasks.append(OptRestrictAfterburner(True))
if hasattr(flight.unit_type, 'eplrs'):
if flight.unit_type.eplrs:
group.points[0].tasks.append(EPLRS(group.id))
for i, point in enumerate(flight.points):
if not point.only_for_player or (point.only_for_player and flight.client_count > 0):
pt = group.add_waypoint(Point(point.x, point.y), point.alt)
@@ -420,6 +475,8 @@ class AircraftConflictGenerator:
group.add_nav_target_point(t.position, "PP" + str(j + 1))
if group.units[0].unit_type == F_14B and j == 0:
group.add_nav_target_point(t.position, "ST")
if group.units[0].unit_type == AJS37 and j < 9:
group.add_nav_target_point(t.position, "M" + str(j + 1))
elif point.waypoint_type == FlightWaypointType.INGRESS_SEAD:
tgroup = self.m.find_group(point.targetGroup.group_identifier)
@@ -438,6 +495,8 @@ class AircraftConflictGenerator:
group.add_nav_target_point(t.position, "PP" + str(j + 1))
if group.units[0].unit_type == F_14B and j == 0:
group.add_nav_target_point(t.position, "ST")
if group.units[0].unit_type == AJS37 and j < 9:
group.add_nav_target_point(t.position, "M" + str(j + 1))
if pt is not None:
pt.alt_type = point.alt_type
@@ -448,7 +507,7 @@ class AircraftConflictGenerator:
def setup_group_as_antiship_flight(self, group, flight):
group.task = AntishipStrike.name
self._setup_group(group, AntishipStrike, flight.client_count)
self._setup_group(group, AntishipStrike, flight)
group.points[0].tasks.clear()
group.points[0].tasks.append(AntishipStrikeTaskAction())

View File

@@ -32,6 +32,7 @@ class AirSupportConflictGenerator:
def generate(self, is_awacs_enabled):
player_cp = self.conflict.from_cp if self.conflict.from_cp.captured else self.conflict.to_cp
CALLSIGNS = ["TKR", "TEX", "FUL", "FUE", ""]
for i, tanker_unit_type in enumerate(db.find_unittype(Refueling, self.conflict.attackers_side)):
self.generated_tankers.append(db.unit_type_name(tanker_unit_type))
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position) + TANKER_HEADING_OFFSET * i
@@ -43,12 +44,17 @@ class AirSupportConflictGenerator:
plane_type=tanker_unit_type,
position=tanker_position,
altitude=TANKER_ALT,
race_distance=58000,
frequency=130 + i,
start_type=StartType.Warm,
tacanchannel="{}X".format(97 + i),
speed=574,
tacanchannel="{}X".format(60 + i),
)
tanker_group.points[0].tasks.append(ActivateBeaconCommand(channel=97 + i, unit_id=tanker_group.id, aa=False))
if tanker_unit_type != IL_78M:
tanker_group.points[0].tasks.pop() # Override PyDCS tacan channel
tanker_group.points[0].tasks.append(ActivateBeaconCommand(60 + i, "X", CALLSIGNS[i], True, tanker_group.units[0].id, True))
tanker_group.points[0].tasks.append(SetInvisibleCommand(True))
tanker_group.points[0].tasks.append(SetImmortalCommand(True))
@@ -62,7 +68,7 @@ class AirSupportConflictGenerator:
altitude=AWACS_ALT,
airport=None,
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
frequency=133,
frequency=233,
start_type=StartType.Warm,
)
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))

View File

@@ -1,4 +1,7 @@
from dcs.action import AITaskPush, AITaskSet
from dcs.condition import TimeAfter, UnitDamaged, Or, GroupLifeLess
from dcs.task import *
from dcs.triggers import TriggerOnce, Event
from gen import namegen
from gen.ground_forces.ai_ground_planner import CombatGroupRole, DISTANCE_FROM_FRONTLINE
@@ -17,10 +20,12 @@ AGGRESIVE_MOVE_DISTANCE = 16000
FIGHT_DISTANCE = 3500
RANDOM_OFFSET_ATTACK = 250
class GroundConflictGenerator:
def __init__(self, mission: Mission, conflict: Conflict, game, player_planned_combat_groups, enemy_planned_combat_groups, player_stance):
self.m = mission
self.mission = mission
self.conflict = conflict
self.enemy_planned_combat_groups = enemy_planned_combat_groups
self.player_planned_combat_groups = player_planned_combat_groups
@@ -58,7 +63,7 @@ class GroundConflictGenerator:
if final_position is not None:
g = self._generate_group(
side=self.m.country(self.game.player_country),
side=self.mission.country(self.game.player_country),
unit=group.units[0],
heading=self.conflict.heading+90,
count=len(group.units),
@@ -66,7 +71,7 @@ class GroundConflictGenerator:
g.set_skill(self.game.settings.player_skill)
player_groups.append((g,group))
self.gen_infantry_group_for_group(g, True, self.m.country(self.game.player_country), self.conflict.heading + 90)
self.gen_infantry_group_for_group(g, True, self.mission.country(self.game.player_country), self.conflict.heading + 90)
# Create enemy groups at random position
for group in self.enemy_planned_combat_groups:
@@ -78,7 +83,7 @@ class GroundConflictGenerator:
if final_position is not None:
g = self._generate_group(
side=self.m.country(self.game.enemy_country),
side=self.mission.country(self.game.enemy_country),
unit=group.units[0],
heading=self.conflict.heading - 90,
count=len(group.units),
@@ -86,14 +91,26 @@ class GroundConflictGenerator:
g.set_skill(self.game.settings.enemy_vehicle_skill)
enemy_groups.append((g, group))
self.gen_infantry_group_for_group(g, False, self.m.country(self.game.enemy_country), self.conflict.heading - 90)
self.gen_infantry_group_for_group(g, False, self.mission.country(self.game.enemy_country), self.conflict.heading - 90)
# Plan combat actions for groups
self.plan_action_for_groups(self.player_stance, player_groups, enemy_groups, self.conflict.heading + 90, self.conflict.from_cp, self.conflict.to_cp)
self.plan_action_for_groups(self.enemy_stance, enemy_groups, player_groups, self.conflict.heading - 90, self.conflict.to_cp, self.conflict.from_cp)
# Add JTAC
if "has_jtac" in self.game.player_faction and self.game.player_faction["has_jtac"] and self.game.settings.include_jtac_if_available:
n = "JTAC" + str(self.conflict.from_cp.id) + str(self.conflict.to_cp.id)
code = 1688 - len(self.game.jtacs)
jtac = self.mission.flight_group(country=self.mission.country(self.game.player_country),
name=n,
aircraft_type=MQ_9_Reaper,
position=position[0],
airport=None,
altitude=5000)
jtac.points[0].tasks.append(SetInvisibleCommand(True))
jtac.points[0].tasks.append(SetImmortalCommand(True))
jtac.points[0].tasks.append(OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle))
self.game.jtacs.append(("Frontline " + self.conflict.from_cp.name + "/" + self.conflict.to_cp.name, code, n))
def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading):
@@ -118,7 +135,7 @@ class GroundConflictGenerator:
return
u = random.choice(possible_infantry_units)
self.m.vehicle_group(
self.mission.vehicle_group(
side,
namegen.next_infantry_name(side, cp, u), u,
position=infantry_position,
@@ -129,7 +146,7 @@ class GroundConflictGenerator:
for i in range(randint(3, 10)):
u = random.choice(possible_infantry_units)
position = infantry_position.random_point_within(55, 5)
self.m.vehicle_group(
self.mission.vehicle_group(
side,
namegen.next_infantry_name(side, cp, u), u,
position=position,
@@ -149,14 +166,63 @@ class GroundConflictGenerator:
if self.game.settings.perf_artillery:
target = self.get_artillery_target_in_range(dcs_group, group, enemy_groups)
if target is not None:
dcs_group.points[0].tasks.append(FireAtPoint(target, len(group.units) * 10, 100))
if stance != CombatStance.RETREAT:
hold_task = Hold()
hold_task.number = 1
dcs_group.add_trigger_action(hold_task)
# Artillery strike random start
artillery_trigger = TriggerOnce(Event.NoEvent, "ArtilleryFireTask #" + str(dcs_group.id))
artillery_trigger.add_condition(TimeAfter(seconds=random.randint(1, 45)* 60))
fire_task = FireAtPoint(target, len(group.units) * 10, 100)
if stance != CombatStance.RETREAT:
fire_task.number = 2
else:
fire_task.number = 1
dcs_group.add_trigger_action(fire_task)
artillery_trigger.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
self.mission.triggerrules.triggers.append(artillery_trigger)
# Artillery will fall back when under attack
if stance != CombatStance.RETREAT:
# Hold position
dcs_group.points[0].tasks.append(Hold())
retreat = self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE/3))
dcs_group.add_waypoint(dcs_group.position.point_from_heading(forward_heading, 1), PointAction.OffRoad)
dcs_group.points[1].tasks.append(Hold())
dcs_group.add_waypoint(retreat, PointAction.OffRoad)
artillery_fallback = TriggerOnce(Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id))
for i, u in enumerate(dcs_group.units):
artillery_fallback.add_condition(UnitDamaged(u.id))
if i < len(dcs_group.units) - 1:
artillery_fallback.add_condition(Or())
hold_2 = Hold()
hold_2.number = 3
dcs_group.add_trigger_action(hold_2)
retreat_task = GoToWaypoint(toIndex=3)
retreat_task.number = 4
dcs_group.add_trigger_action(retreat_task)
artillery_fallback.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
self.mission.triggerrules.triggers.append(artillery_fallback)
for u in dcs_group.units:
u.initial = True
u.heading = forward_heading + random.randint(-5,5)
elif group.role in [CombatGroupRole.TANK, CombatGroupRole.IFV]:
if stance == CombatStance.AGGRESIVE:
# Attack nearest enemy if any
# Then move forward OR Attack enemy base if it is not too far away
target = self.find_nearest_enemy_group(dcs_group, enemy_groups)
if target is not None:
rand_offset = Point(random.randint(-50, 50), random.randint(-50, 50))
rand_offset = Point(random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK))
dcs_group.add_waypoint(target.points[0].position + rand_offset, PointAction.OffRoad)
dcs_group.points[1].tasks.append(AttackGroup(target.id))
@@ -179,13 +245,17 @@ class GroundConflictGenerator:
targets = self.find_n_nearest_enemy_groups(dcs_group, enemy_groups, 3)
i = 1
for target in targets:
rand_offset = Point(random.randint(-50, 50), random.randint(-50, 50))
dcs_group.add_waypoint(target.points[0].position+rand_offset,PointAction.OffRoad)
rand_offset = Point(random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK))
dcs_group.add_waypoint(target.points[0].position+rand_offset, PointAction.OffRoad)
dcs_group.points[i].tasks.append(AttackGroup(target.id))
i = i + 1
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
attack_point = to_cp.position.random_point_within(500, 0)
dcs_group.add_waypoint(attack_point)
if stance != CombatStance.RETREAT:
self.add_morale_trigger(dcs_group, forward_heading)
elif group.role in [CombatGroupRole.APC, CombatGroupRole.ATGM]:
if stance in [CombatStance.AGGRESIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
@@ -196,6 +266,9 @@ class GroundConflictGenerator:
attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
dcs_group.add_waypoint(attack_point, PointAction.OnRoad)
if stance != CombatStance.RETREAT:
self.add_morale_trigger(dcs_group, forward_heading)
if stance == CombatStance.RETREAT:
# In retreat mode, the units will fall back
# If the ally base is close enough, the units will even regroup there
@@ -208,14 +281,51 @@ class GroundConflictGenerator:
dcs_group.add_waypoint(reposition_point, PointAction.OffRoad)
def find_retreat_point(self, dcs_group, frontline_heading):
def add_morale_trigger(self, dcs_group, forward_heading):
"""
This add a trigger to manage units fleeing whenever their group is hit hard, or being engaged by CAS
"""
if len(dcs_group.units) == 1:
return
# Units should hold position on last waypoint
dcs_group.points[len(dcs_group.points) - 1].tasks.append(Hold())
# Force unit heading
for unit in dcs_group.units:
unit.heading = forward_heading
dcs_group.manualHeading = True
# We add a new retreat waypoint
dcs_group.add_waypoint(self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 8)), PointAction.OffRoad)
# Fallback task
fallback = ControlledTask(GoToWaypoint(toIndex=len(dcs_group.points)))
fallback.enabled = False
dcs_group.add_trigger_action(Hold())
dcs_group.add_trigger_action(fallback)
# Create trigger
fallback = TriggerOnce(Event.NoEvent, "Morale manager #" + str(dcs_group.id))
# Usually more than 50% casualties = RETREAT
fallback.add_condition(GroupLifeLess(dcs_group.id, random.randint(51, 76)))
# Do retreat to the configured retreat waypoint
fallback.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
self.mission.triggerrules.triggers.append(fallback)
def find_retreat_point(self, dcs_group, frontline_heading, distance=RETREAT_DISTANCE):
"""
Find a point to retreat to
:param dcs_group: DCS mission group we are searching a retreat point for
:param frontline_heading: Heading of the frontline
:return: dcs.mapping.Point object with the desired position
"""
return dcs_group.points[0].position.point_from_heading(frontline_heading-180, RETREAT_DISTANCE)
return dcs_group.points[0].position.point_from_heading(frontline_heading-180, distance)
def find_offensive_point(self, dcs_group, frontline_heading, distance):
"""
@@ -310,7 +420,7 @@ class GroundConflictGenerator:
cp = self.conflict.to_cp
logging.info("armorgen: {} for {}".format(unit, side.id))
group = self.m.vehicle_group(
group = self.mission.vehicle_group(
side,
namegen.next_unit_name(side, cp.id, unit), unit,
position=self._group_point(at),

View File

@@ -24,6 +24,8 @@ class BriefingGenerator:
self.targets = []
self.waypoints = []
self.jtacs = []
def append_frequency(self, name: str, frequency: str):
self.freqs.append((name, frequency))
@@ -45,8 +47,13 @@ class BriefingGenerator:
self.description += "#0 -- TAKEOFF : Take off from " + flight.from_cp.name + "\n"
for i, wpt in enumerate(flight.points):
self.description += "#" + str(1+i) + " -- " + wpt.name + " : " + wpt.description + "\n"
self.description += "#" + str(len(flight.points) + 1) + " -- RTB\n"
self.description += "#" + str(len(flight.points) + 1) + " -- RTB\n\n"
group = flight.group
if group is not None:
for i, nav_target in enumerate(group.nav_target_points):
self.description += nav_target.text_comment + "\n"
self.description += "\n"
self.description += "-" * 50 + "\n"
def add_ally_flight_description(self, flight):
@@ -54,7 +61,6 @@ class BriefingGenerator:
flight_unit_name = db.unit_type_name(flight.unit_type)
self.description += flight.flight_type.name + " " + flight_unit_name + " x " + str(flight.count) + ", departing in " + str(flight.scheduled_in) + " minutes \n"
def generate(self):
self.description = ""
@@ -62,8 +68,7 @@ class BriefingGenerator:
self.description += "DCS Liberation turn #" + str(self.game.turn) + "\n"
self.description += "=" * 15 + "\n\n"
self.description += "Current situation:\n"
self.description += "=" * 15 + "\n\n"
self.generate_ongoing_war_text()
self.description += "\n"*2
self.description += "Your flights:" + "\n"
@@ -89,11 +94,12 @@ class BriefingGenerator:
for name, freq in self.freqs:
self.description += "{}: {}\n".format(name, freq)
self.description += ("-" * 50) + "\n"
for cp in self.game.theater.controlpoints:
if cp.captured and cp.cptype in [ControlPointType.LHA_GROUP, ControlPointType.AIRCRAFT_CARRIER_GROUP]:
self.description += cp.name + "\n"
self.description += "RADIO : 127.5 Mhz AM\n"
self.description += "TACAN : "
self.description += str(cp.tacanN)
if cp.tacanY:
self.description += "Y"
@@ -105,6 +111,80 @@ class BriefingGenerator:
self.description += "ICLS Channel : " + str(cp.icls) + "\n"
self.description += "-" * 50 + "\n"
self.description += "JTACS [F-10 Menu] : \n"
self.description += "===================\n\n"
for jtac in self.game.jtacs:
self.description += str(jtac[0]) + " -- Code : " + str(jtac[1]) + "\n"
self.m.set_description_text(self.description)
self.m.add_picture_blue(os.path.abspath("./resources/ui/splash_screen.png"))
def generate_ongoing_war_text(self):
self.description += "Current situation:\n"
self.description += "=" * 15 + "\n\n"
conflict_number = 0
for c in self.game.theater.conflicts():
conflict_number = conflict_number + 1
if c[0].captured:
player_base = c[0]
enemy_base = c[1]
else:
player_base = c[1]
enemy_base = c[0]
has_numerical_superiority = player_base.base.total_armor > enemy_base.base.total_armor
self.description += self.__random_frontline_sentence(player_base.name, enemy_base.name)
if enemy_base.id in player_base.stances.keys():
stance = player_base.stances[enemy_base.id]
if player_base.base.total_armor == 0:
self.description += "We do not have a single vehicle available to hold our position, the situation is critical, and we will lose ground inevitably.\n"
elif enemy_base.base.total_armor == 0:
self.description += "The enemy forces have been crushed, we will be able to make significant progress toward " + enemy_base.name + ". \n"
if stance == CombatStance.AGGRESIVE:
if has_numerical_superiority:
self.description += "On this location, our ground forces will try to make progress against the enemy"
self.description += ". As the enemy is outnumbered, our forces should have no issue making progress.\n"
elif has_numerical_superiority:
self.description += "On this location, our ground forces will try an audacious assault against enemies in superior numbers. The operation is risky, and the enemy might counter attack.\n"
elif stance == CombatStance.ELIMINATION:
if has_numerical_superiority:
self.description += "On this location, our ground forces will focus on the destruction of enemy assets, before attempting to make progress toward " + enemy_base.name + ". "
self.description += "The enemy is already outnumbered, and this maneuver might draw a final blow to their forces.\n"
elif has_numerical_superiority:
self.description += "On this location, our ground forces will try an audacious assault against enemies in superior numbers. The operation is risky, and the enemy might counter attack.\n"
elif stance == CombatStance.BREAKTHROUGH:
if has_numerical_superiority:
self.description += "On this location, our ground forces will focus on progression toward " + enemy_base.name + ".\n"
elif has_numerical_superiority:
self.description += "On this location, our ground forces have been ordered to rush toward " + enemy_base.name + ". Wish them luck... We are also expecting a counter attack.\n"
elif stance in [CombatStance.DEFENSIVE, CombatStance.AMBUSH]:
if has_numerical_superiority:
self.description += "On this location, our ground forces will hold position. We are not expecting an enemy assault.\n"
elif has_numerical_superiority:
self.description += "On this location, our ground forces have been ordered to hold still, and defend against enemy attacks. An enemy assault might be iminent.\n"
if conflict_number == 0:
self.description += "There are currently no fights on the ground.\n"
self.description += "\n\n"
def __random_frontline_sentence(self, player_base_name, enemy_base_name):
templates = [
"There are combats between {} and {}. ",
"The war on the ground is still going on between {} an {}. ",
"Our ground forces in {} are opposed to enemy forces based in {}. ",
"Our forces from {} are fighting enemies based in {}. ",
"There is an active frontline between {} and {}. ",
]
return random.choice(templates).format(player_base_name, enemy_base_name)

View File

@@ -23,11 +23,12 @@ class CarrierGroupGenerator(GroupGenerator):
return
# Add destroyers escort
dd_type = random.choice(self.faction["destroyer"])
self.add_unit(dd_type, "DD1", self.position.x + 250, self.position.y + 450, self.heading)
self.add_unit(dd_type, "DD2", self.position.x + 250, self.position.y - 450, self.heading)
if "destroyer" in self.faction.keys():
dd_type = random.choice(self.faction["destroyer"])
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 + 450, self.position.y + 850, self.heading)
self.add_unit(dd_type, "DD4", self.position.x + 450, self.position.y - 850, 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

View File

@@ -31,7 +31,7 @@ class ChineseNavyGroupGenerator(GroupGenerator):
self.add_unit(dd_type, "FF2", self.position.x + 2400, self.position.y - 900, self.heading)
if include_cc:
cc_type = random.choice([Type_093, CGN_1144_2_Pyotr_Velikiy])
cc_type = random.choice([CGN_1144_2_Pyotr_Velikiy])
self.add_unit(cc_type, "CC1", self.position.x, self.position.y, self.heading)
self.get_generated_group().points[0].speed = 20

View File

@@ -19,7 +19,7 @@ class LHAGroupGenerator(GroupGenerator):
# Add destroyers escort
if "destroyer" in self.faction.keys():
dd_type = random.choice(self.faction["destroyer"])
self.add_unit(dd_type, "DD1", self.position.x + 250, self.position.y + 450, self.heading)
self.add_unit(dd_type, "DD2", self.position.x + 250, self.position.y - 450, self.heading)
self.add_unit(dd_type, "DD1", self.position.x + 1250, self.position.y + 1450, self.heading)
self.add_unit(dd_type, "DD2", self.position.x + 1250, self.position.y - 1450, self.heading)
self.get_generated_group().points[0].speed = 20

View File

@@ -56,7 +56,7 @@ class FlightPlanner:
self.compute_strike_targets()
# The priority is to assign air-superiority fighter or interceptor to interception roles, so they can scramble if there is an attacker
#self.commision_interceptors()
# self.commision_interceptors()
# Then some CAP patrol for the next 2 hours
self.commision_cap()
@@ -106,6 +106,7 @@ class FlightPlanner:
break
inventory[unit] = inventory[unit] - 2
flight = Flight(unit, 2, self.from_cp, FlightType.INTERCEPTION)
flight.scheduled_in = 1
flight.points = []
self.interceptor_flights.append(flight)

View File

@@ -3,13 +3,22 @@ from dcs.helicopters import *
# Interceptor are the aircraft prioritized for interception tasks
# If none is available, the AI will use regular CAP-capable aircraft instead
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M
INTERCEPT_CAPABLE = [
MiG_21Bis,
MiG_25PD,
MiG_31,
MiG_29S,
MiG_29A,
MiG_29G,
MiG_29K,
M_2000C,
Mirage_2000_5,
Rafale_M,
F_14B,
F_15C,
@@ -25,6 +34,7 @@ CAP_CAPABLE = [
MiG_29A,
MiG_29G,
MiG_29S,
MiG_31,
Su_27,
J_11A,
@@ -40,6 +50,7 @@ CAP_CAPABLE = [
F_5E_3,
F_14B,
F_15C,
F_15E,
F_16C_50,
FA_18C_hornet,
@@ -56,6 +67,9 @@ CAP_CAPABLE = [
Bf_109K_4,
FW_190D9,
FW_190A8,
A_4E_C,
Rafale_M,
]
# USed for CAS (Close air support) and BAI (Battlefield Interdiction)
@@ -85,15 +99,18 @@ CAS_CAPABLE = [
F_86F_Sabre,
F_5E_3,
F_14B,
F_15E,
F_16C_50,
FA_18C_hornet,
C_101CC,
MB_339PAN,
L_39ZA,
AJS37,
SA342M,
SA342L,
OH_58D,
AH_64A,
AH_64D,
@@ -116,12 +133,16 @@ CAS_CAPABLE = [
Bf_109K_4,
FW_190D9,
FW_190A8,
A_4E_C,
Rafale_A_S
]
# Aircraft used for SEAD / DEAD tasks
SEAD_CAPABLE = [
F_4E,
FA_18C_hornet,
F_15E,
# F_16C_50, Not yet
AV8BNA,
JF_17,
@@ -133,14 +154,16 @@ SEAD_CAPABLE = [
Su_30,
Su_34,
MiG_27K,
A_4E_C,
Rafale_A_S
]
# Aircraft used for Strike mission
STRIKE_CAPABLE = [
MiG_15bis,
MiG_29A,
MiG_27K,
MiG_29S,
MB_339PAN,
Su_17M4,
Su_24M,
@@ -160,6 +183,7 @@ STRIKE_CAPABLE = [
F_86F_Sabre,
F_5E_3,
F_14B,
F_15E,
F_16C_50,
FA_18C_hornet,
@@ -180,12 +204,16 @@ STRIKE_CAPABLE = [
FW_190D9,
FW_190A8,
A_4E_C,
Rafale_A_S
]
ANTISHIP_CAPABLE = [
Su_24M,
Su_17M4,
F_A_18C,
F_15E,
AV8BNA,
JF_17,
F_16C_50,
@@ -193,4 +221,5 @@ ANTISHIP_CAPABLE = [
A_10A,
Ju_88A4,
Rafale_A_S
]

View File

@@ -91,6 +91,7 @@ class Flight:
loadout = {}
preset_loadout_name = ""
start_type = "Runway"
group = False # Contains DCS Mission group data after mission has been generated
# How long before this flight should take off
scheduled_in = 0

View File

@@ -7,6 +7,8 @@ from gen import Conflict
from gen.ground_forces.combat_stance import CombatStance
from theater import ControlPoint
import pydcs_extensions.frenchpack.frenchpack as frenchpack
TYPE_TANKS = [
Armor.MBT_T_55,
Armor.MBT_T_72B,
@@ -32,6 +34,18 @@ TYPE_TANKS = [
Armor.ST_Centaur_IV,
Armor.CT_Cromwell_IV,
Armor.HIT_Churchill_VII,
# Mods
frenchpack.DIM__TOYOTA_BLUE,
frenchpack.DIM__TOYOTA_GREEN,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__KAMIKAZE,
frenchpack.AMX_10RCR,
frenchpack.AMX_10RCR_SEPAR,
frenchpack.AMX_30B2,
frenchpack.Leclerc_Serie_XXI,
]
TYPE_ATGM = [
@@ -44,6 +58,12 @@ TYPE_ATGM = [
Armor.TD_Jagdpanzer_IV,
Armor.TD_Jagdpanther_G1,
Armor.TD_M10_GMC,
# Mods
frenchpack.VBAE_CRAB_MMP,
frenchpack.VAB_MEPHISTO,
frenchpack.TRM_2000_PAMELA,
]
TYPE_IFV = [
@@ -61,6 +81,12 @@ TYPE_IFV = [
# WW2
Armor.IFV_Sd_Kfz_234_2_Puma,
Armor.LAC_M8_Greyhound,
# Mods
frenchpack.ERC_90,
frenchpack.VBAE_CRAB,
frenchpack.VAB_T20_13
]
TYPE_APC = [
@@ -81,6 +107,12 @@ TYPE_APC = [
# WW2
Armor.APC_M2A1,
Armor.APC_Sd_Kfz_251,
# Mods
frenchpack.VAB__50,
frenchpack.VBL__50,
frenchpack.VBL_AANF1,
]
TYPE_ARTILLERY = [
@@ -117,6 +149,11 @@ TYPE_LOGI = [
Unarmed.Willys_MB,
Unarmed.Land_Rover_109_S3,
Unarmed.Land_Rover_101_FC,
# Mods
frenchpack.VBL,
frenchpack.VAB,
]
TYPE_INFANTRY = [
@@ -148,14 +185,14 @@ class CombatGroupRole(Enum):
DISTANCE_FROM_FRONTLINE = {
CombatGroupRole.TANK:2800,
CombatGroupRole.APC:7000,
CombatGroupRole.IFV:3000,
CombatGroupRole.ARTILLERY:14000,
CombatGroupRole.SHORAD:12000,
CombatGroupRole.LOGI:18000,
CombatGroupRole.INFANTRY:2800,
CombatGroupRole.ATGM:5500
CombatGroupRole.TANK:3200,
CombatGroupRole.APC:8000,
CombatGroupRole.IFV:3700,
CombatGroupRole.ARTILLERY:18000,
CombatGroupRole.SHORAD:13000,
CombatGroupRole.LOGI:20000,
CombatGroupRole.INFANTRY:3000,
CombatGroupRole.ATGM:6200
}
GROUP_SIZES_BY_COMBAT_STANCE = {

View File

@@ -45,12 +45,6 @@ class GroundObjectsGenerator:
def generate(self):
cp = None # type: ControlPoint
if self.conflict.attackers_country.name == self.game.player_country:
cp = self.conflict.to_cp
else:
cp = self.conflict.from_cp
for cp in self.game.theater.controlpoints:
if cp.captured:
@@ -78,6 +72,7 @@ class GroundObjectsGenerator:
vehicle.position.x = u.position.x
vehicle.position.y = u.position.y
vehicle.heading = u.heading
vehicle.player_can_drive = True
vg.add_unit(vehicle)
else:
vg = self.m.ship_group(side, g.name, utype, position=g.position,
@@ -121,7 +116,7 @@ class GroundObjectsGenerator:
found_carrier_destination = False
attempt = 0
while not found_carrier_destination and attempt < 5:
point = sg.points[0].position.point_from_heading(self.m.weather.wind_at_ground.direction, 100000-attempt*20000)
point = sg.points[0].position.point_from_heading(self.m.weather.wind_at_ground.direction + 180, 100000-attempt*20000)
if self.game.theater.is_in_sea(point):
found_carrier_destination = True
sg.add_waypoint(point)

View File

@@ -20,6 +20,12 @@ class SA10Generator(GroupGenerator):
# Search radar for missiles (optionnal)
self.add_unit(AirDefence.SAM_SA_10_S_300PS_SR_64H6E, "SR2", self.position.x - 40, self.position.y, self.heading)
# 2 Tracking radars
self.add_unit(AirDefence.SAM_SA_10_S_300PS_TR_30N6, "TR1", self.position.x - 40, self.position.y - 40, self.heading)
self.add_unit(AirDefence.SAM_SA_10_S_300PS_TR_30N6, "TR2", self.position.x + 40, self.position.y - 40,
self.heading)
# 2 different launcher type (C & D)
num_launchers = random.randint(6, 8)
positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=360)
@@ -40,4 +46,4 @@ class SA10Generator(GroupGenerator):
num_launchers = random.randint(6, 8)
positions = self.get_circular_position(num_launchers, launcher_distance=350, coverage=360)
for i, position in enumerate(positions):
self.add_unit(AirDefence.AAA_ZU_23_Emplacement, "AA#" + str(i), position[0], position[1], position[2])
self.add_unit(AirDefence.SPAAA_ZSU_23_4_Shilka, "AA#" + str(i), position[0], position[1], position[2])

View File

@@ -1,53 +0,0 @@
import logging
from game import db
from .conflictgen import *
from .naming import *
from dcs.mission import *
from dcs.unitgroup import *
from dcs.task import *
SHIP_RANDOM_SPREAD = 300
class ShipGenerator:
def __init__(self, mission: Mission, conflict: Conflict):
self.m = mission
self.conflict = conflict
def generate_carrier(self, for_units: typing.Collection[UnitType], country: str, at: Point) -> ShipGroup:
type = db.find_unittype(Carriage, country)[0]
for unit_type in for_units:
if unit_type in db.CARRIER_TYPE_BY_PLANE:
type = db.CARRIER_TYPE_BY_PLANE[unit_type]
break
group = self.m.ship_group(
country=self.m.country(country),
name=namegen.next_carrier_name(self.m.country(country)),
_type=type,
position=at)
group.points[0].tasks.append(ActivateBeaconCommand(unit_id=group.id, channel=20, callsign="SHDW", aa=False))
group.points[0].tasks.append(ActivateICLSCommand(unit_id=group.id, channel=1))
return group
def generate_cargo(self, units: db.ShipDict) -> typing.Collection[ShipGroup]:
groups = []
offset = 0
for unit_type, unit_count in units.items():
for _ in range(unit_count):
offset += 1
logging.info("shipgen: {} ({}) for {}".format(unit_type, unit_count, self.conflict.defenders_side))
group = self.m.ship_group(
country=self.conflict.defenders_country,
name=namegen.next_unit_name(self.conflict.defenders_country, unit_type),
_type=unit_type,
position=self.conflict.ground_defenders_location.random_point_within(SHIP_RANDOM_SPREAD, SHIP_RANDOM_SPREAD).point_from_heading(0, offset * SHIP_RANDOM_SPREAD)
)
group.add_waypoint(self.conflict.to_cp.position)
groups.append(group)
return groups

View File

@@ -46,6 +46,22 @@ class TriggersGenerator:
"""
Set airbase initial coalition
"""
# Empty neutrals airports
cp_ids = [cp.id for cp in self.game.theater.controlpoints]
for airport in self.mission.terrain.airport_list():
if airport.id not in cp_ids:
airport.unlimited_fuel = False
airport.unlimited_munitions = False
airport.unlimited_aircrafts = False
airport.gasoline_init = 0
airport.methanol_mixture_init = 0
airport.diesel_init = 0
airport.jet_init = 0
airport.operating_level_air = 0
airport.operating_level_equipment = 0
airport.operating_level_fuel = 0
for cp in self.game.theater.controlpoints:
if cp.is_global:
continue
@@ -95,8 +111,8 @@ class TriggersGenerator:
self.mission.triggerrules.triggers.append(mark_trigger)
def generate(self):
player_coalition = self.game.player_country in db.BLUEFOR_FACTIONS and "blue" or "red"
enemy_coalition = player_coalition == "blue" and "red" or "blue"
player_coalition = "blue"
enemy_coalition = "red"
self.mission.coalition["blue"].bullseye = {"x": self.conflict.position.x,
"y": self.conflict.position.y}

1
liberation_theme.json Normal file
View File

@@ -0,0 +1 @@
{"theme_index": 1}

View File

@@ -0,0 +1,782 @@
from enum import Enum
from dcs import task
from dcs.planes import PlaneType
from dcs.weapons_data import Weapons
class WeaponsA4EC:
AN_M57__2__TER_ = {"clsid": "{AN-M57_TER_2_L}", "name": "AN-M57 *2 (TER)", "weight": 273.6}
AN_M57__2__TER__ = {"clsid": "{AN-M57_TER_2_R}", "name": "AN-M57 *2 (TER)", "weight": 273.6}
AN_M57__3__TER_ = {"clsid": "{AN-M57_TER_3_C}", "name": "AN-M57 *3 (TER)", "weight": 386.6}
AN_M57__5__MER_ = {"clsid": "{AN-M57_MER_5_L}", "name": "AN-M57 *5 (MER)", "weight": 664.8}
AN_M57__5__MER__ = {"clsid": "{AN-M57_MER_5_R}", "name": "AN-M57 *5 (MER)", "weight": 664.8}
AN_M57__6__MER_ = {"clsid": "{AN-M57_MER_6_C}", "name": "AN-M57 *6 (MER)", "weight": 777.8}
AN_M66A2 = {"clsid": "{AN-M66A2}", "name": "AN-M66A2", "weight": 970.68688}
AN_M81 = {"clsid": "{AN-M81}", "name": "AN-M81", "weight": 117.93392}
AN_M81__5__MER_ = {"clsid": "{AN-M81_MER_5_L}", "name": "AN-M81 *5 (MER)", "weight": 689.3}
AN_M81__5__MER__ = {"clsid": "{AN-M81_MER_5_R}", "name": "AN-M81 *5 (MER)", "weight": 689.3}
AN_M81__6__MER_ = {"clsid": "{AN-M81_MER_6_C}", "name": "AN-M81 *6 (MER)", "weight": 807.2}
AN_M88 = {"clsid": "{AN-M88}", "name": "AN-M88", "weight": 98.0665904}
AN_M88__5__MER_ = {"clsid": "{AN-M88_MER_5_L}", "name": "AN-M88 *5 (MER)", "weight": 589.8}
AN_M88__5__MER__ = {"clsid": "{AN-M88_MER_5_R}", "name": "AN-M88 *5 (MER)", "weight": 589.8}
AN_M88__6__MER_ = {"clsid": "{AN-M88_MER_6_C}", "name": "AN-M88 *6 (MER)", "weight": 687.8}
CBU_1_A = {"clsid": "{CBU-1/A}", "name": "CBU-1/A", "weight": 458.921706}
CBU_1_A__2 = {"clsid": "{CBU-1/A_TER_2_L}", "name": "CBU-1/A *2", "weight": 713.473056}
CBU_1_A__2_ = {"clsid": "{CBU-1/A_TER_2_R}", "name": "CBU-1/A *2", "weight": 713.473056}
CBU_2B_A = {"clsid": "{CBU-2B/A}", "name": "CBU-2B/A", "weight": 379.543106}
CBU_2B_A__2 = {"clsid": "{CBU-2B/A_TER_2_L}", "name": "CBU-2B/A *2", "weight": 806.686212}
CBU_2B_A__2_ = {"clsid": "{CBU-2B/A_TER_2_R}", "name": "CBU-2B/A *2", "weight": 806.686212}
CBU_2_A = {"clsid": "{CBU-2/A}", "name": "CBU-2/A", "weight": 343.822736}
CBU_2_A__2 = {"clsid": "{CBU-2/A_TER_2_L}", "name": "CBU-2/A *2", "weight": 735.245472}
CBU_2_A__2_ = {"clsid": "{CBU-2/A_TER_2_R}", "name": "CBU-2/A *2", "weight": 735.245472}
D_704_Refueling_Pod = {"clsid": "{D-704_BUDDY_POD}", "name": "D-704 Refueling Pod", "weight": 1234.532648}
Fuel_Tank_150_gallons = {"clsid": "{DFT-150gal}", "name": "Fuel Tank 150 gallons", "weight": 515.888512}
Fuel_Tank_300_gallons = {"clsid": "{DFT-300gal}", "name": "Fuel Tank 300 gallons", "weight": 991.407336}
Fuel_Tank_300_gallons_ = {"clsid": "{DFT-300gal_LR}", "name": "Fuel Tank 300 gallons", "weight": 998.664808}
Fuel_Tank_400_gallons = {"clsid": "{DFT-400gal}", "name": "Fuel Tank 400 gallons", "weight": 1320.06208}
LAU_10_2___4_ZUNI_MK_71 = {"clsid": "{LAU-10 ZUNI_TER_2_C}", "name": "LAU-10*2 - 4 ZUNI MK 71", "weight": 927.6}
LAU_10_2___4_ZUNI_MK_71_ = {"clsid": "{LAU-10 ZUNI_TER_2_L}", "name": "LAU-10*2 - 4 ZUNI MK 71", "weight": 927.6}
LAU_10_2___4_ZUNI_MK_71__ = {"clsid": "{LAU-10 ZUNI_TER_2_R}", "name": "LAU-10*2 - 4 ZUNI MK 71", "weight": 927.6}
LAU_10_3___4_ZUNI_MK_71 = {"clsid": "{LAU-10 ZUNI_TER_3_C}", "name": "LAU-10*3 - 4 ZUNI MK 71", "weight": 1367.6}
LAU_3_2___19_FFAR_M156_WP = {"clsid": "{LAU-3 FFAR WP156_TER_2_C}", "name": "LAU-3*2 - 19 FFAR M156 WP", "weight": 673.3414512}
LAU_3_2___19_FFAR_M156_WP_ = {"clsid": "{LAU-3 FFAR WP156_TER_2_L}", "name": "LAU-3*2 - 19 FFAR M156 WP", "weight": 673.3414512}
LAU_3_2___19_FFAR_M156_WP__ = {"clsid": "{LAU-3 FFAR WP156_TER_2_R}", "name": "LAU-3*2 - 19 FFAR M156 WP", "weight": 673.3414512}
LAU_3_2___19_FFAR_Mk1_HE = {"clsid": "{LAU-3 FFAR Mk1 HE_TER_2_C}", "name": "LAU-3*2 - 19 FFAR Mk1 HE", "weight": 618.184664}
LAU_3_2___19_FFAR_Mk1_HE_ = {"clsid": "{LAU-3 FFAR Mk1 HE_TER_2_L}", "name": "LAU-3*2 - 19 FFAR Mk1 HE", "weight": 618.184664}
LAU_3_2___19_FFAR_Mk1_HE__ = {"clsid": "{LAU-3 FFAR Mk1 HE_TER_2_R}", "name": "LAU-3*2 - 19 FFAR Mk1 HE", "weight": 618.184664}
LAU_3_2___19_FFAR_Mk5_HEAT = {"clsid": "{LAU-3 FFAR Mk5 HEAT_TER_2_C}", "name": "LAU-3*2 - 19 FFAR Mk5 HEAT", "weight": 619.9083136}
LAU_3_2___19_FFAR_Mk5_HEAT_ = {"clsid": "{LAU-3 FFAR Mk5 HEAT_TER_2_L}", "name": "LAU-3*2 - 19 FFAR Mk5 HEAT", "weight": 619.9083136}
LAU_3_2___19_FFAR_Mk5_HEAT__ = {"clsid": "{LAU-3 FFAR Mk5 HEAT_TER_2_R}", "name": "LAU-3*2 - 19 FFAR Mk5 HEAT", "weight": 619.9083136}
LAU_3_3___19_FFAR_M156_WP = {"clsid": "{LAU-3 FFAR WP156_TER_3_C}", "name": "LAU-3*3 - 19 FFAR M156 WP", "weight": 986.2121768}
LAU_3_3___19_FFAR_Mk1_HE = {"clsid": "{LAU-3 FFAR Mk1 HE_TER_3_C}", "name": "LAU-3*3 - 19 FFAR Mk1 HE", "weight": 903.476996}
LAU_3_3___19_FFAR_Mk5_HEAT = {"clsid": "{LAU-3 FFAR Mk5 HEAT_TER_3_C}", "name": "LAU-3*3 - 19 FFAR Mk5 HEAT", "weight": 906.0624704}
LAU_68_2___7_FFAR_M156_WP = {"clsid": "{LAU-68 FFAR WP156_TER_2_C}", "name": "LAU-68*2 - 7 FFAR M156 WP", "weight": 287.9121136}
LAU_68_2___7_FFAR_M156_WP_ = {"clsid": "{LAU-68 FFAR WP156_TER_2_L}", "name": "LAU-68*2 - 7 FFAR M156 WP", "weight": 287.9121136}
LAU_68_2___7_FFAR_M156_WP__ = {"clsid": "{LAU-68 FFAR WP156_TER_2_R}", "name": "LAU-68*2 - 7 FFAR M156 WP", "weight": 287.9121136}
LAU_68_2___7_FFAR_Mk1_HE = {"clsid": "{LAU-68 FFAR Mk1 HE_TER_2_C}", "name": "LAU-68*2 - 7 FFAR Mk1 HE", "weight": 267.591192}
LAU_68_2___7_FFAR_Mk1_HE_ = {"clsid": "{LAU-68 FFAR Mk1 HE_TER_2_L}", "name": "LAU-68*2 - 7 FFAR Mk1 HE", "weight": 267.591192}
LAU_68_2___7_FFAR_Mk1_HE__ = {"clsid": "{LAU-68 FFAR Mk1 HE_TER_2_R}", "name": "LAU-68*2 - 7 FFAR Mk1 HE", "weight": 267.591192}
LAU_68_2___7_FFAR_Mk5_HEAT = {"clsid": "{LAU-68 FFAR Mk5 HEAT_TER_2_C}", "name": "LAU-68*2 - 7 FFAR Mk5 HEAT", "weight": 268.2262208}
LAU_68_2___7_FFAR_Mk5_HEAT_ = {"clsid": "{LAU-68 FFAR Mk5 HEAT_TER_2_L}", "name": "LAU-68*2 - 7 FFAR Mk5 HEAT", "weight": 268.2262208}
LAU_68_2___7_FFAR_Mk5_HEAT__ = {"clsid": "{LAU-68 FFAR Mk5 HEAT_TER_2_R}", "name": "LAU-68*2 - 7 FFAR Mk5 HEAT", "weight": 268.2262208}
LAU_68_3___7_FFAR_M156_WP = {"clsid": "{LAU-68 FFAR WP156_TER_3_C}", "name": "LAU-68*3 - 7 FFAR M156 WP", "weight": 408.0681704}
LAU_68_3___7_FFAR_Mk1_HE = {"clsid": "{LAU-68 FFAR Mk1 HE_TER_3_C}", "name": "LAU-68*3 - 7 FFAR Mk1 HE", "weight": 377.586788}
LAU_68_3___7_FFAR_Mk5_HEAT = {"clsid": "{LAU-68 FFAR Mk5 HEAT_TER_3_C}", "name": "LAU-68*3 - 7 FFAR Mk5 HEAT", "weight": 378.5393312}
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_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}
Mk4_HIPEG = {"clsid": "{Mk4 HIPEG}", "name": "Mk4 HIPEG", "weight": 612.35}
Mk_20__2__TER_ = {"clsid": "{Mk-20_TER_2_L}", "name": "Mk-20 *2 (TER)", "weight": 491.6}
Mk_20__2__TER__ = {"clsid": "{Mk-20_TER_2_R}", "name": "Mk-20 *2 (TER)", "weight": 491.6}
Mk_20__2__TER___ = {"clsid": "{Mk-20_TER_2_C}", "name": "Mk-20 *2 (TER)", "weight": 491.6}
Mk_20__3__TER_ = {"clsid": "{Mk-20_TER_3_C}", "name": "Mk-20 *3 (TER)", "weight": 713.6}
Mk_77_mod_0 = {"clsid": "{mk77mod0}", "name": "Mk-77 mod 0", "weight": 340}
Mk_77_mod_1 = {"clsid": "{mk77mod1}", "name": "Mk-77 mod 1", "weight": 230}
Mk_77_mod_1__2__TER_ = {"clsid": "{Mk-77 mod 1_TER_2_L}", "name": "Mk-77 mod 1 *2 (TER)", "weight": 507.6}
Mk_77_mod_1__2__TER__ = {"clsid": "{Mk-77 mod 1_TER_2_R}", "name": "Mk-77 mod 1 *2 (TER)", "weight": 507.6}
Mk_77_mod_1__2__TER___ = {"clsid": "{Mk-77 mod 1_TER_2_C}", "name": "Mk-77 mod 1 *2 (TER)", "weight": 507.6}
Mk_77_mod_1__4__MER_ = {"clsid": "{Mk-77 mod 1_MER_4_C}", "name": "Mk-77 mod 1 *4 (MER)", "weight": 1019.8}
Mk_81SE = {"clsid": "{MK-81SE}", "name": "Mk-81SE", "weight": 113.398}
Mk_81SE__5__MER_ = {"clsid": "{Mk-81SE_MER_5_L}", "name": "Mk-81SE *5 (MER)", "weight": 689.8}
Mk_81SE__5__MER__ = {"clsid": "{Mk-81SE_MER_5_R}", "name": "Mk-81SE *5 (MER)", "weight": 689.8}
Mk_81SE__6__MER_ = {"clsid": "{Mk-81SE_MER_6_C}", "name": "Mk-81SE *6 (MER)", "weight": 807.8}
Mk_81__5__MER_ = {"clsid": "{Mk-81_MER_5_L}", "name": "Mk-81 *5 (MER)", "weight": 689.8}
Mk_81__5__MER__ = {"clsid": "{Mk-81_MER_5_R}", "name": "Mk-81 *5 (MER)", "weight": 689.8}
Mk_81__6__MER_ = {"clsid": "{Mk-81_MER_6_C}", "name": "Mk-81 *6 (MER)", "weight": 807.8}
Mk_82_Snakeye__2__TER_ = {"clsid": "{Mk-82 Snakeye_TER_2_L}", "name": "Mk-82 Snakeye *2 (TER)", "weight": 529.6}
Mk_82_Snakeye__2__TER__ = {"clsid": "{Mk-82 Snakeye_TER_2_R}", "name": "Mk-82 Snakeye *2 (TER)", "weight": 529.6}
Mk_82_Snakeye__3__TER_ = {"clsid": "{Mk-82 Snakeye_TER_3_C}", "name": "Mk-82 Snakeye *3 (TER)", "weight": 770.6}
Mk_82_Snakeye__4__MER_ = {"clsid": "{Mk-82 Snakeye_MER_4_C}", "name": "Mk-82 Snakeye *4 (MER)", "weight": 1063.8}
Mk_82_Snakeye__6__MER_ = {"clsid": "{Mk-82 Snakeye_MER_6_C}", "name": "Mk-82 Snakeye *6 (MER)", "weight": 1545.8}
Mk_82__2__TER_ = {"clsid": "{Mk-82_TER_2_L}", "name": "Mk-82 *2 (TER)", "weight": 529.6}
Mk_82__2__TER__ = {"clsid": "{Mk-82_TER_2_R}", "name": "Mk-82 *2 (TER)", "weight": 529.6}
Mk_82__3__TER_ = {"clsid": "{Mk-82_TER_3_C}", "name": "Mk-82 *3 (TER)", "weight": 770.6}
Mk_82__4__MER_ = {"clsid": "{Mk-82_MER_4_C}", "name": "Mk-82 *4 (MER)", "weight": 1063.8}
Mk_82__6__MER_ = {"clsid": "{Mk-82_MER_6_C}", "name": "Mk-82 *6 (MER)", "weight": 1545.8}
Mk_83__2__TER_ = {"clsid": "{Mk-83_TER_2_C}", "name": "Mk-83 *2 (TER)", "weight": 941.6}
Mk_83__3__TER_ = {"clsid": "{Mk-83_TER_3_C}", "name": "Mk-83 *3 (TER)", "weight": 1388.6}
_3_LAU_61 = {"clsid": "{TER,LAU-61*3}", "name": "3*LAU-61", "weight": 98}
class A_4E_C(PlaneType):
id = "A-4E-C"
flyable = True
height = 4.57
width = 8.38
length = 12.22
fuel_max = 2467.5454273299
max_speed = 1082.88
chaff = 30
flare = 30
charge_total = 60
chaff_charge_size = 1
flare_charge_size = 1
category = "Interceptor" #{78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
radio_frequency = 254
panel_radio = {
1: {
"channels": {
1: 264,
2: 265,
4: 254,
8: 258,
16: 267,
17: 251,
9: 262,
18: 253,
5: 250,
10: 259,
20: 252,
11: 268,
3: 256,
6: 270,
12: 269,
13: 260,
7: 257,
14: 263,
19: 266,
15: 261
},
},
}
property_defaults = {
"HideECMPanel": False,
"CBU2ATPP": 0,
"CBU2BATPP": 0,
"CMS_BURSTS": 1,
"CMS_BURST_INTERVAL": 1,
"CMS_SALVOS": 1,
"CMS_SALVO_INTERVAL": 1,
}
class Properties:
class HideECMPanel:
id = "HideECMPanel"
class CBU2ATPP:
id = "CBU2ATPP"
class Values:
_1_tube = 0
_2_tubes = 1
_3_tubes = 2
_4_tubes = 3
_6_tubes = 4
_17_tubes__salvo = 5
class CBU2BATPP:
id = "CBU2BATPP"
class Values:
_2_tubes = 0
_4_tubes = 1
_6_tubes = 2
class CMS_BURSTS:
id = "CMS_BURSTS"
class Values:
_1 = 1
_2 = 2
_3 = 3
_4 = 4
class CMS_BURST_INTERVAL:
id = "CMS_BURST_INTERVAL"
class Values:
_0_2_seconds = 1
_0_3_seconds = 2
_0_4_seconds = 3
_0_5_seconds = 4
class CMS_SALVOS:
id = "CMS_SALVOS"
class Values:
_8 = 1
_12 = 2
_16 = 3
_20 = 4
_24 = 5
_28 = 6
_32 = 7
class CMS_SALVO_INTERVAL:
id = "CMS_SALVO_INTERVAL"
class Values:
_2_seconds = 1
_4_seconds = 2
_6_seconds = 3
_8_seconds = 4
_10_seconds = 5
_12_seconds = 6
_14_seconds = 7
class Liveries:
class Georgia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Syria(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Finland(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Australia(Enum):
Unmarked = "Unmarked"
International_Australia = "International Australia"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
International_New_Zealand = "International New Zealand"
International_New_Zealand_Kiwi_Red = "International New Zealand Kiwi Red"
International_New_Zealand_Sqn_75 = "International New Zealand Sqn 75"
class Germany(Enum):
Unmarked = "Unmarked"
Trainer_BAE_Systems = "Trainer BAE Systems"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class SaudiArabia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Israel(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
International_Israel = "International Israel"
class Croatia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class CzechRepublic(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Norway(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Romania(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Spain(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Ukraine(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Belgium(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Slovakia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Greece(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class UK(Enum):
Unmarked = "Unmarked"
Trainer_BAE_Systems = "Trainer BAE Systems"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Insurgents(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Hungary(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class France(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Abkhazia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Russia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Sweden(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Austria(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Switzerland(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Italy(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class SouthOssetia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class SouthKorea(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Iran(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class China(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Pakistan(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Belarus(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class NorthKorea(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Iraq(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Kazakhstan(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Bulgaria(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Serbia(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class India(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class USAFAggressors(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
Aggressor_USMC_TopGun_MiG_17 = "Aggressor USMC TopGun MiG-17"
Aggressor_USN_TopGun = "Aggressor USN TopGun"
Aggressor_USN_VF_126_Bandits = "Aggressor USN VF-126 Bandits"
Aggressor_USN_VF_127_Royal_Blues = "Aggressor USN VF-127 Royal Blues"
Aggressor_USN_VFA_127_Cyclons__Forest = "Aggressor USN VFA-127 Cyclons (Forest)"
Aggressor_USN_VFA_127_Cyclons__Sea = "Aggressor USN VFA-127 Cyclons (Sea)"
class USA(Enum):
Unmarked = "Unmarked"
International_Argentina = "International Argentina"
International_Australia = "International Australia"
Trainer_BAE_Systems = "Trainer BAE Systems"
Blue_Angels_no_1 = "Blue Angels no 1"
Blue_Angels_no_2 = "Blue Angels no 2"
Blue_Angels_no_3 = "Blue Angels no 3"
Blue_Angels_no_4 = "Blue Angels no 4"
Blue_Angels_no_5 = "Blue Angels no 5"
Blue_Angels_no_6 = "Blue Angels no 6"
International_Brazil = "International Brazil"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
International_Israel = "International Israel"
International_Kuwait = "International Kuwait"
International_New_Zealand = "International New Zealand"
International_New_Zealand_Kiwi_Red = "International New Zealand Kiwi Red"
International_New_Zealand_Sqn_75 = "International New Zealand Sqn 75"
Trainer_USMC_PTMC = "Trainer USMC PTMC"
Aggressor_USMC_TopGun_MiG_17 = "Aggressor USMC TopGun MiG-17"
USMC_VMA_121_Green_Knights = "USMC VMA-121 Green Knights"
USMC_VMA_124_Memphis_Marines = "USMC VMA-124 Memphis Marines"
USMC_VMA_131_Diamondbacks = "USMC VMA-131 Diamondbacks"
USMC_VMA_142_Flying_Gators = "USMC VMA-142 Flying Gators"
USMC_VMA_211_Avengers = "USMC VMA-211 Avengers"
USMC_VMA_311_Tomcats = "USMC VMA-311 Tomcats"
USMC_VMA_322_Fighting_Gamecocks = "USMC VMA-322 Fighting Gamecocks"
Trainer_USMC_VMAT_102 = "Trainer USMC VMAT-102"
Trainer_USN_Bare_Metal_1956 = "Trainer USN Bare Metal 1956"
Trainer_USN_NFWS_Gray = "Trainer USN NFWS Gray"
Trainer_USN_NFWS_Green = "Trainer USN NFWS Green"
Aggressor_USN_TopGun = "Aggressor USN TopGun"
USN_VA_144_Roadrunners = "USN VA-144 Roadrunners"
USN_VA_153_Blue_Tail_Flies = "USN VA-153 Blue Tail Flies"
USN_VA_163_Saints = "USN VA-163 Saints"
USN_VA_164_Ghostriders = "USN VA-164 Ghostriders"
USN_VA_195_Dambusters = "USN VA-195 Dambusters"
USN_VA_212_Rampant_Raiders = "USN VA-212 Rampant Raiders"
USN_VA_45_Blackbirds = "USN VA-45 Blackbirds"
USN_VA_55_Warhorses = "USN VA-55 Warhorses"
USN_VA_64_Black_Lancers = "USN VA-64 Black Lancers"
Trainer_USN_VC_1_FLECOMPRON_One = "Trainer USN VC-1 FLECOMPRON One"
Trainer_USN_VC_5_Checkertails = "Trainer USN VC-5 Checkertails"
USN_VC_7_Tallyhoers = "USN VC-7 Tallyhoers"
Trainer_USN_VC_8_Redtails = "Trainer USN VC-8 Redtails"
Aggressor_USN_VF_126_Bandits = "Aggressor USN VF-126 Bandits"
Aggressor_USN_VF_127_Royal_Blues = "Aggressor USN VF-127 Royal Blues"
Aggressor_USN_VFA_127_Cyclons__Forest = "Aggressor USN VFA-127 Cyclons (Forest)"
Aggressor_USN_VFA_127_Cyclons__Sea = "Aggressor USN VFA-127 Cyclons (Sea)"
Trainer_USN_VT_7_Eagles = "Trainer USN VT-7 Eagles"
class Denmark(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Egypt(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Canada(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class TheNetherlands(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Turkey(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Japan(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Poland(Enum):
Unmarked = "Unmarked"
Community_A_4E = "Community A-4E"
Community_A_4E_II = "Community A-4E II"
class Pylon1:
LAU_10___4_ZUNI_MK_71 = (1, Weapons.LAU_10___4_ZUNI_MK_71)
LAU_3___19_FFAR_M156_WP = (1, Weapons.LAU_3___19_FFAR_M156_WP)
LAU_3___19_FFAR_Mk1_HE = (1, Weapons.LAU_3___19_FFAR_Mk1_HE)
LAU_3___19_FFAR_Mk5_HEAT = (1, Weapons.LAU_3___19_FFAR_Mk5_HEAT)
LAU_68___7_FFAR_M156_WP = (1, Weapons.LAU_68___7_FFAR_M156_WP)
LAU_68___7_FFAR_Mk1_HE = (1, Weapons.LAU_68___7_FFAR_Mk1_HE)
LAU_68___7_FFAR_Mk5_HEAT = (1, Weapons.LAU_68___7_FFAR_Mk5_HEAT)
AGM_45A = (1, Weapons.AGM_45A)
#ERRR {AGM12_B}
Mk_20 = (1, Weapons.Mk_20)
Mk_81 = (1, Weapons.Mk_81)
Mk_81SE = (1, WeaponsA4EC.Mk_81SE)
Mk_82 = (1, Weapons.Mk_82)
Mk_82_SnakeEye = (1, Weapons.Mk_82_SnakeEye)
Mk_77_mod_1 = (1, WeaponsA4EC.Mk_77_mod_1)
AN_M30A1 = (1, Weapons.AN_M30A1)
AN_M57 = (1, Weapons.AN_M57)
AN_M64 = (1, Weapons.AN_M64)
AN_M81 = (1, WeaponsA4EC.AN_M81)
AN_M88 = (1, WeaponsA4EC.AN_M88)
LAU_68___7_2_75__rockets_M257__Parachute_illumination_ = (1, Weapons.LAU_68___7_2_75__rockets_M257__Parachute_illumination_)
Smokewinder___red = (1, Weapons.Smokewinder___red)
Smokewinder___green = (1, Weapons.Smokewinder___green)
Smokewinder___blue = (1, Weapons.Smokewinder___blue)
Smokewinder___white = (1, Weapons.Smokewinder___white)
Smokewinder___yellow = (1, Weapons.Smokewinder___yellow)
Smokewinder___orange = (1, Weapons.Smokewinder___orange)
#ERRR <CLEAN>
class Pylon2:
Fuel_Tank_300_gallons_ = (2, WeaponsA4EC.Fuel_Tank_300_gallons_)
Fuel_Tank_150_gallons = (2, WeaponsA4EC.Fuel_Tank_150_gallons)
LAU_7_GAR_8_Sidewinder_IR_AAM = (2, Weapons.LAU_7_GAR_8_Sidewinder_IR_AAM)
LAU_7_AIM_9P_Sidewinder_IR_AAM = (2, Weapons.LAU_7_AIM_9P_Sidewinder_IR_AAM)
LAU_7_AIM_9P5_Sidewinder_IR_AAM = (2, Weapons.LAU_7_AIM_9P5_Sidewinder_IR_AAM)
LAU_10___4_ZUNI_MK_71 = (2, Weapons.LAU_10___4_ZUNI_MK_71)
LAU_10_2___4_ZUNI_MK_71_ = (2, WeaponsA4EC.LAU_10_2___4_ZUNI_MK_71_)
LAU_3___19_FFAR_M156_WP = (2, Weapons.LAU_3___19_FFAR_M156_WP)
LAU_3___19_FFAR_Mk1_HE = (2, Weapons.LAU_3___19_FFAR_Mk1_HE)
LAU_3___19_FFAR_Mk5_HEAT = (2, Weapons.LAU_3___19_FFAR_Mk5_HEAT)
LAU_3_2___19_FFAR_M156_WP_ = (2, WeaponsA4EC.LAU_3_2___19_FFAR_M156_WP_)
LAU_3_2___19_FFAR_Mk1_HE_ = (2, WeaponsA4EC.LAU_3_2___19_FFAR_Mk1_HE_)
LAU_3_2___19_FFAR_Mk5_HEAT_ = (2, WeaponsA4EC.LAU_3_2___19_FFAR_Mk5_HEAT_)
LAU_68___7_FFAR_M156_WP = (2, Weapons.LAU_68___7_FFAR_M156_WP)
LAU_68___7_FFAR_Mk1_HE = (2, Weapons.LAU_68___7_FFAR_Mk1_HE)
LAU_68___7_FFAR_Mk5_HEAT = (2, Weapons.LAU_68___7_FFAR_Mk5_HEAT)
LAU_68_2___7_FFAR_M156_WP_ = (2, WeaponsA4EC.LAU_68_2___7_FFAR_M156_WP_)
LAU_68_2___7_FFAR_Mk1_HE_ = (2, WeaponsA4EC.LAU_68_2___7_FFAR_Mk1_HE_)
LAU_68_2___7_FFAR_Mk5_HEAT_ = (2, WeaponsA4EC.LAU_68_2___7_FFAR_Mk5_HEAT_)
AGM_45A = (2, Weapons.AGM_45A)
#ERRR {AGM12_C}
#ERRR {AGM12_B}
AGM_62 = (2, Weapons.AGM_62)
Mk_20 = (2, Weapons.Mk_20)
Mk_81 = (2, Weapons.Mk_81)
Mk_81SE = (2, WeaponsA4EC.Mk_81SE)
Mk_82 = (2, Weapons.Mk_82)
Mk_82_SnakeEye = (2, Weapons.Mk_82_SnakeEye)
Mk_83 = (2, Weapons.Mk_83)
Mk_84 = (2, Weapons.Mk_84)
M117 = (2, Weapons.M117)
Mk_77_mod_0 = (2, WeaponsA4EC.Mk_77_mod_0)
Mk_77_mod_1 = (2, WeaponsA4EC.Mk_77_mod_1)
AN_M30A1 = (2, Weapons.AN_M30A1)
AN_M57 = (2, Weapons.AN_M57)
AN_M64 = (2, Weapons.AN_M64)
AN_M65 = (2, Weapons.AN_M65)
AN_M81 = (2, WeaponsA4EC.AN_M81)
AN_M88 = (2, WeaponsA4EC.AN_M88)
CBU_1_A = (2, WeaponsA4EC.CBU_1_A)
CBU_2_A = (2, WeaponsA4EC.CBU_2_A)
CBU_2B_A = (2, WeaponsA4EC.CBU_2B_A)
CBU_1_A__2 = (2, WeaponsA4EC.CBU_1_A__2)
CBU_2_A__2 = (2, WeaponsA4EC.CBU_2_A__2)
CBU_2B_A__2 = (2, WeaponsA4EC.CBU_2B_A__2)
Mk_20__2__TER_ = (2, WeaponsA4EC.Mk_20__2__TER_)
Mk_81__5__MER_ = (2, WeaponsA4EC.Mk_81__5__MER_)
Mk_81SE__5__MER_ = (2, WeaponsA4EC.Mk_81SE__5__MER_)
Mk_82__2__TER_ = (2, WeaponsA4EC.Mk_82__2__TER_)
Mk_82_Snakeye__2__TER_ = (2, WeaponsA4EC.Mk_82_Snakeye__2__TER_)
AN_M57__5__MER_ = (2, WeaponsA4EC.AN_M57__5__MER_)
AN_M57__2__TER_ = (2, WeaponsA4EC.AN_M57__2__TER_)
AN_M81__5__MER_ = (2, WeaponsA4EC.AN_M81__5__MER_)
AN_M88__5__MER_ = (2, WeaponsA4EC.AN_M88__5__MER_)
Mk4_HIPEG = (2, WeaponsA4EC.Mk4_HIPEG)
Smokewinder___red = (2, Weapons.Smokewinder___red)
Smokewinder___green = (2, Weapons.Smokewinder___green)
Smokewinder___blue = (2, Weapons.Smokewinder___blue)
Smokewinder___white = (2, Weapons.Smokewinder___white)
Smokewinder___yellow = (2, Weapons.Smokewinder___yellow)
Smokewinder___orange = (2, Weapons.Smokewinder___orange)
#ERRR <CLEAN>
class Pylon3:
Fuel_Tank_400_gallons = (3, WeaponsA4EC.Fuel_Tank_400_gallons)
Fuel_Tank_300_gallons = (3, WeaponsA4EC.Fuel_Tank_300_gallons)
Fuel_Tank_150_gallons = (3, WeaponsA4EC.Fuel_Tank_150_gallons)
D_704_Refueling_Pod = (3, WeaponsA4EC.D_704_Refueling_Pod)
#ERRR {3*LAU-61}
LAU_68_3___7_2_75__rockets_MK5__HE_ = (3, Weapons.LAU_68_3___7_2_75__rockets_MK5__HE_)
LAU_10___4_ZUNI_MK_71 = (3, Weapons.LAU_10___4_ZUNI_MK_71)
LAU_10_2___4_ZUNI_MK_71 = (3, WeaponsA4EC.LAU_10_2___4_ZUNI_MK_71)
LAU_10_3___4_ZUNI_MK_71 = (3, WeaponsA4EC.LAU_10_3___4_ZUNI_MK_71)
LAU_3___19_FFAR_M156_WP = (3, Weapons.LAU_3___19_FFAR_M156_WP)
LAU_3___19_FFAR_Mk1_HE = (3, Weapons.LAU_3___19_FFAR_Mk1_HE)
LAU_3___19_FFAR_Mk5_HEAT = (3, Weapons.LAU_3___19_FFAR_Mk5_HEAT)
LAU_3_2___19_FFAR_M156_WP = (3, WeaponsA4EC.LAU_3_2___19_FFAR_M156_WP)
LAU_3_2___19_FFAR_Mk1_HE = (3, WeaponsA4EC.LAU_3_2___19_FFAR_Mk1_HE)
LAU_3_2___19_FFAR_Mk5_HEAT = (3, WeaponsA4EC.LAU_3_2___19_FFAR_Mk5_HEAT)
LAU_3_3___19_FFAR_M156_WP = (3, WeaponsA4EC.LAU_3_3___19_FFAR_M156_WP)
LAU_3_3___19_FFAR_Mk1_HE = (3, WeaponsA4EC.LAU_3_3___19_FFAR_Mk1_HE)
LAU_3_3___19_FFAR_Mk5_HEAT = (3, WeaponsA4EC.LAU_3_3___19_FFAR_Mk5_HEAT)
LAU_68___7_FFAR_M156_WP = (3, Weapons.LAU_68___7_FFAR_M156_WP)
LAU_68___7_FFAR_Mk1_HE = (3, Weapons.LAU_68___7_FFAR_Mk1_HE)
LAU_68___7_FFAR_Mk5_HEAT = (3, Weapons.LAU_68___7_FFAR_Mk5_HEAT)
LAU_68_2___7_FFAR_M156_WP = (3, WeaponsA4EC.LAU_68_2___7_FFAR_M156_WP)
LAU_68_2___7_FFAR_Mk1_HE = (3, WeaponsA4EC.LAU_68_2___7_FFAR_Mk1_HE)
LAU_68_2___7_FFAR_Mk5_HEAT = (3, WeaponsA4EC.LAU_68_2___7_FFAR_Mk5_HEAT)
LAU_68_3___7_FFAR_M156_WP = (3, WeaponsA4EC.LAU_68_3___7_FFAR_M156_WP)
LAU_68_3___7_FFAR_Mk1_HE = (3, WeaponsA4EC.LAU_68_3___7_FFAR_Mk1_HE)
LAU_68_3___7_FFAR_Mk5_HEAT = (3, WeaponsA4EC.LAU_68_3___7_FFAR_Mk5_HEAT)
#ERRR {AGM12_B}
AGM_62 = (3, Weapons.AGM_62)
Mk_20 = (3, Weapons.Mk_20)
Mk_81 = (3, Weapons.Mk_81)
Mk_81SE = (3, WeaponsA4EC.Mk_81SE)
Mk_82 = (3, Weapons.Mk_82)
Mk_82_SnakeEye = (3, Weapons.Mk_82_SnakeEye)
Mk_83 = (3, Weapons.Mk_83)
Mk_84 = (3, Weapons.Mk_84)
M117 = (3, Weapons.M117)
Mk_77_mod_0 = (3, WeaponsA4EC.Mk_77_mod_0)
Mk_77_mod_1 = (3, WeaponsA4EC.Mk_77_mod_1)
AN_M30A1 = (3, Weapons.AN_M30A1)
AN_M57 = (3, Weapons.AN_M57)
AN_M64 = (3, Weapons.AN_M64)
AN_M65 = (3, Weapons.AN_M65)
AN_M66A2 = (3, WeaponsA4EC.AN_M66A2)
AN_M81 = (3, WeaponsA4EC.AN_M81)
AN_M88 = (3, WeaponsA4EC.AN_M88)
Mk_20__3__TER_ = (3, WeaponsA4EC.Mk_20__3__TER_)
Mk_20__2__TER___ = (3, WeaponsA4EC.Mk_20__2__TER___)
Mk_81__6__MER_ = (3, WeaponsA4EC.Mk_81__6__MER_)
Mk_81SE__6__MER_ = (3, WeaponsA4EC.Mk_81SE__6__MER_)
Mk_82__6__MER_ = (3, WeaponsA4EC.Mk_82__6__MER_)
Mk_82__4__MER_ = (3, WeaponsA4EC.Mk_82__4__MER_)
Mk_82__3__TER_ = (3, WeaponsA4EC.Mk_82__3__TER_)
Mk_82_Snakeye__6__MER_ = (3, WeaponsA4EC.Mk_82_Snakeye__6__MER_)
Mk_82_Snakeye__4__MER_ = (3, WeaponsA4EC.Mk_82_Snakeye__4__MER_)
Mk_82_Snakeye__3__TER_ = (3, WeaponsA4EC.Mk_82_Snakeye__3__TER_)
Mk_83__3__TER_ = (3, WeaponsA4EC.Mk_83__3__TER_)
Mk_83__2__TER_ = (3, WeaponsA4EC.Mk_83__2__TER_)
Mk_77_mod_1__2__TER___ = (3, WeaponsA4EC.Mk_77_mod_1__2__TER___)
AN_M57__6__MER_ = (3, WeaponsA4EC.AN_M57__6__MER_)
AN_M57__3__TER_ = (3, WeaponsA4EC.AN_M57__3__TER_)
AN_M81__6__MER_ = (3, WeaponsA4EC.AN_M81__6__MER_)
AN_M88__6__MER_ = (3, WeaponsA4EC.AN_M88__6__MER_)
Mk4_HIPEG = (3, WeaponsA4EC.Mk4_HIPEG)
Smokewinder___red = (3, Weapons.Smokewinder___red)
Smokewinder___green = (3, Weapons.Smokewinder___green)
Smokewinder___blue = (3, Weapons.Smokewinder___blue)
Smokewinder___white = (3, Weapons.Smokewinder___white)
Smokewinder___yellow = (3, Weapons.Smokewinder___yellow)
Smokewinder___orange = (3, Weapons.Smokewinder___orange)
#ERRR <CLEAN>
class Pylon4:
Fuel_Tank_300_gallons_ = (4, WeaponsA4EC.Fuel_Tank_300_gallons_)
Fuel_Tank_150_gallons = (4, WeaponsA4EC.Fuel_Tank_150_gallons)
LAU_7_GAR_8_Sidewinder_IR_AAM = (4, Weapons.LAU_7_GAR_8_Sidewinder_IR_AAM)
LAU_7_AIM_9P_Sidewinder_IR_AAM = (4, Weapons.LAU_7_AIM_9P_Sidewinder_IR_AAM)
LAU_7_AIM_9P5_Sidewinder_IR_AAM = (4, Weapons.LAU_7_AIM_9P5_Sidewinder_IR_AAM)
LAU_10___4_ZUNI_MK_71 = (4, Weapons.LAU_10___4_ZUNI_MK_71)
LAU_10_2___4_ZUNI_MK_71__ = (4, WeaponsA4EC.LAU_10_2___4_ZUNI_MK_71__)
LAU_3___19_FFAR_M156_WP = (4, Weapons.LAU_3___19_FFAR_M156_WP)
LAU_3___19_FFAR_Mk1_HE = (4, Weapons.LAU_3___19_FFAR_Mk1_HE)
LAU_3___19_FFAR_Mk5_HEAT = (4, Weapons.LAU_3___19_FFAR_Mk5_HEAT)
LAU_3_2___19_FFAR_M156_WP__ = (4, WeaponsA4EC.LAU_3_2___19_FFAR_M156_WP__)
LAU_3_2___19_FFAR_Mk1_HE__ = (4, WeaponsA4EC.LAU_3_2___19_FFAR_Mk1_HE__)
LAU_3_2___19_FFAR_Mk5_HEAT__ = (4, WeaponsA4EC.LAU_3_2___19_FFAR_Mk5_HEAT__)
LAU_68___7_FFAR_M156_WP = (4, Weapons.LAU_68___7_FFAR_M156_WP)
LAU_68___7_FFAR_Mk1_HE = (4, Weapons.LAU_68___7_FFAR_Mk1_HE)
LAU_68___7_FFAR_Mk5_HEAT = (4, Weapons.LAU_68___7_FFAR_Mk5_HEAT)
LAU_68_2___7_FFAR_M156_WP__ = (4, WeaponsA4EC.LAU_68_2___7_FFAR_M156_WP__)
LAU_68_2___7_FFAR_Mk1_HE__ = (4, WeaponsA4EC.LAU_68_2___7_FFAR_Mk1_HE__)
LAU_68_2___7_FFAR_Mk5_HEAT__ = (4, WeaponsA4EC.LAU_68_2___7_FFAR_Mk5_HEAT__)
AGM_45A = (4, Weapons.AGM_45A)
#ERRR {AGM12_C}
#ERRR {AGM12_B}
AGM_62 = (4, Weapons.AGM_62)
Mk_20 = (4, Weapons.Mk_20)
Mk_81 = (4, Weapons.Mk_81)
Mk_81SE = (4, WeaponsA4EC.Mk_81SE)
Mk_82 = (4, Weapons.Mk_82)
Mk_82_SnakeEye = (4, Weapons.Mk_82_SnakeEye)
Mk_83 = (4, Weapons.Mk_83)
Mk_84 = (4, Weapons.Mk_84)
M117 = (4, Weapons.M117)
Mk_77_mod_0 = (4, WeaponsA4EC.Mk_77_mod_0)
Mk_77_mod_1 = (4, WeaponsA4EC.Mk_77_mod_1)
AN_M30A1 = (4, Weapons.AN_M30A1)
AN_M57 = (4, Weapons.AN_M57)
AN_M64 = (4, Weapons.AN_M64)
AN_M65 = (4, Weapons.AN_M65)
AN_M81 = (4, WeaponsA4EC.AN_M81)
AN_M88 = (4, WeaponsA4EC.AN_M88)
CBU_1_A = (4, WeaponsA4EC.CBU_1_A)
CBU_2_A = (4, WeaponsA4EC.CBU_2_A)
CBU_2B_A = (4, WeaponsA4EC.CBU_2B_A)
CBU_1_A__2_ = (4, WeaponsA4EC.CBU_1_A__2_)
CBU_2_A__2_ = (4, WeaponsA4EC.CBU_2_A__2_)
CBU_2B_A__2_ = (4, WeaponsA4EC.CBU_2B_A__2_)
Mk_20__2__TER__ = (4, WeaponsA4EC.Mk_20__2__TER__)
Mk_81__5__MER__ = (4, WeaponsA4EC.Mk_81__5__MER__)
Mk_81SE__5__MER__ = (4, WeaponsA4EC.Mk_81SE__5__MER__)
Mk_82__2__TER__ = (4, WeaponsA4EC.Mk_82__2__TER__)
Mk_82_Snakeye__2__TER__ = (4, WeaponsA4EC.Mk_82_Snakeye__2__TER__)
AN_M57__5__MER__ = (4, WeaponsA4EC.AN_M57__5__MER__)
AN_M57__2__TER__ = (4, WeaponsA4EC.AN_M57__2__TER__)
AN_M81__5__MER__ = (4, WeaponsA4EC.AN_M81__5__MER__)
AN_M88__5__MER__ = (4, WeaponsA4EC.AN_M88__5__MER__)
Mk4_HIPEG = (4, WeaponsA4EC.Mk4_HIPEG)
Smokewinder___red = (4, Weapons.Smokewinder___red)
Smokewinder___green = (4, Weapons.Smokewinder___green)
Smokewinder___blue = (4, Weapons.Smokewinder___blue)
Smokewinder___white = (4, Weapons.Smokewinder___white)
Smokewinder___yellow = (4, Weapons.Smokewinder___yellow)
Smokewinder___orange = (4, Weapons.Smokewinder___orange)
#ERRR <CLEAN>
class Pylon5:
LAU_10___4_ZUNI_MK_71 = (5, Weapons.LAU_10___4_ZUNI_MK_71)
LAU_3___19_FFAR_M156_WP = (5, Weapons.LAU_3___19_FFAR_M156_WP)
LAU_3___19_FFAR_Mk1_HE = (5, Weapons.LAU_3___19_FFAR_Mk1_HE)
LAU_3___19_FFAR_Mk5_HEAT = (5, Weapons.LAU_3___19_FFAR_Mk5_HEAT)
LAU_68___7_FFAR_M156_WP = (5, Weapons.LAU_68___7_FFAR_M156_WP)
LAU_68___7_FFAR_Mk1_HE = (5, Weapons.LAU_68___7_FFAR_Mk1_HE)
LAU_68___7_FFAR_Mk5_HEAT = (5, Weapons.LAU_68___7_FFAR_Mk5_HEAT)
AGM_45A = (5, Weapons.AGM_45A)
#ERRR {AGM12_B}
Mk_20 = (5, Weapons.Mk_20)
Mk_81 = (5, Weapons.Mk_81)
Mk_81SE = (5, WeaponsA4EC.Mk_81SE)
Mk_82 = (5, Weapons.Mk_82)
Mk_82_SnakeEye = (5, Weapons.Mk_82_SnakeEye)
Mk_77_mod_1 = (5, WeaponsA4EC.Mk_77_mod_1)
AN_M30A1 = (5, Weapons.AN_M30A1)
AN_M57 = (5, Weapons.AN_M57)
AN_M64 = (5, Weapons.AN_M64)
AN_M81 = (5, WeaponsA4EC.AN_M81)
AN_M88 = (5, WeaponsA4EC.AN_M88)
LAU_68___7_2_75__rockets_M257__Parachute_illumination_ = (5, Weapons.LAU_68___7_2_75__rockets_M257__Parachute_illumination_)
Smokewinder___red = (5, Weapons.Smokewinder___red)
Smokewinder___green = (5, Weapons.Smokewinder___green)
Smokewinder___blue = (5, Weapons.Smokewinder___blue)
Smokewinder___white = (5, Weapons.Smokewinder___white)
Smokewinder___yellow = (5, Weapons.Smokewinder___yellow)
Smokewinder___orange = (5, Weapons.Smokewinder___orange)
#ERRR <CLEAN>
pylons = {1, 2, 3, 4, 5}
tasks = [task.CAP, task.CAS, task.SEAD, task.GroundAttack, task.AFAC, task.Refueling]
task_default = task.CAS

View File

@@ -0,0 +1,288 @@
# Requires French Pack mod :
# https://forums.eagle.ru/showthread.php?t=279974
#
from dcs import unittype
class AMX_10RCR(unittype.VehicleType):
id = "AMX10RCR"
name = "AMX-10RCR"
detection_range = 0
threat_range = 4000
air_weapon_dist = 4000
class AMX_10RCR_SEPAR(unittype.VehicleType):
id = "SEPAR"
name = "AMX-10RCR SEPAR"
detection_range = 0
threat_range = 4000
air_weapon_dist = 4000
class ERC_90(unittype.VehicleType):
id = "ERC"
name = "ERC-90"
detection_range = 0
threat_range = 4000
air_weapon_dist = 4000
eprls = True
class VAB__50(unittype.VehicleType):
id = "VAB_50"
name = "VAB .50"
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
class VAB_T20_13(unittype.VehicleType):
id = "VIB_VBR"
name = "VAB T20/13"
detection_range = 0
threat_range = 2000
air_weapon_dist = 2000
eprls = True
class VAB_MEPHISTO(unittype.VehicleType):
id = "VAB_HOT"
name = "VAB MEPHISTO"
detection_range = 0
threat_range = 4000
air_weapon_dist = 4000
eprls = True
class VBL__50(unittype.VehicleType):
id = "VBL50"
name = "VBL .50"
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
class VBL_AANF1(unittype.VehicleType):
id = "VBLANF1"
name = "VBL AANF1"
detection_range = 0
threat_range = 1000
air_weapon_dist = 1000
eprls = True
class VBAE_CRAB(unittype.VehicleType):
id = "VBAE"
name = "VBAE CRAB"
detection_range = 0
threat_range = 3500
air_weapon_dist = 3500
eprls = True
class VBAE_CRAB_MMP(unittype.VehicleType):
id = "VBAE_MMP"
name = "VBAE CRAB MMP"
detection_range = 0
threat_range = 3500
air_weapon_dist = 3500
eprls = True
class AMX_30B2(unittype.VehicleType):
id = "AMX-30B2"
name = "AMX-30B2"
detection_range = 0
threat_range = 3500
air_weapon_dist = 2500
class Char_M551_Sheridan(unittype.VehicleType):
id = "SHERIDAN"
name = "Char M551 Sheridan"
detection_range = 0
threat_range = 5000
air_weapon_dist = 5000
class Leclerc_Serie_XXI(unittype.VehicleType):
id = "Leclerc_XXI"
name = "Leclerc Série XXI"
detection_range = 0
threat_range = 5000
air_weapon_dist = 5000
class DIM__TOYOTA_BLUE(unittype.VehicleType):
id = "Toyota_bleu"
name = "DIM' TOYOTA BLUE"
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
class DIM__TOYOTA_GREEN(unittype.VehicleType):
id = "Toyota_vert"
name = "DIM' TOYOTA GREEN"
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
class DIM__TOYOTA_DESERT(unittype.VehicleType):
id = "Toyota_desert"
name = "DIM' TOYOTA DESERT"
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
class DIM__KAMIKAZE(unittype.VehicleType):
id = "Kamikaze"
name = "DIM' KAMIKAZE"
detection_range = 0
threat_range = 50
air_weapon_dist = 50
eprls = True
## FORTIFICATION
class _FIELD_HIDE(unittype.VehicleType):
id = "FieldHL"
name = "*FIELD HIDE"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
class _FIELD_HIDE_SMALL(unittype.VehicleType):
id = "HARRIERH"
name = "*FIELD HIDE SMALL"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
class SmokeD1(unittype.VehicleType):
id = "SmokeD1"
name = "SmokeD1"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
class SmokeD3(unittype.VehicleType):
id = "SmokeD3"
name = "SmokeD3"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
class TRM_2000(unittype.VehicleType):
id = "TRM2000"
name = "TRM-2000"
detection_range = 3500
threat_range = 0
air_weapon_dist = 0
eprls = True
class TRM_2000_Fuel(unittype.VehicleType):
id = "TRM2000_Citerne"
name = "TRM-2000 Fuel"
detection_range = 3500
threat_range = 0
air_weapon_dist = 0
eprls = True
class VAB_MEDICAL(unittype.VehicleType):
id = "VABH"
name = "VAB MEDICAL"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
eprls = True
class VAB(unittype.VehicleType):
id = "VAB_RADIO"
name = "VAB"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
eprls = True
class VBL(unittype.VehicleType):
id = "VBL-Radio"
name = "VBL"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
eprls = True
class Tracma_TD_1500(unittype.VehicleType):
id = "Tracma"
name = "Tracma TD 1500"
detection_range = 0
threat_range = 0
air_weapon_dist = 0
## AIRDEFENCE
class SMOKE_SAM_IR(unittype.VehicleType):
id = "SMOKESAM"
name = "SMOKE SAM IR"
detection_range = 20000
threat_range = 20000
air_weapon_dist = 20000
eprls = True
class _53T2(unittype.VehicleType):
id = "AA20"
name = "53T2"
detection_range = 5000
threat_range = 2000
air_weapon_dist = 2000
class TRM_2000_53T2(unittype.VehicleType):
id = "TRM2000_AA20"
name = "TRM-2000 53T2"
detection_range = 6000
threat_range = 2000
air_weapon_dist = 2000
eprls = True
class TRM_2000_PAMELA(unittype.VehicleType):
id = "TRMMISTRAL"
name = "TRM-2000 PAMELA"
detection_range = 8000
threat_range = 10000
air_weapon_dist = 10000
eprls = True
## INFANTRY
class Infantry_Soldier_JTAC(unittype.VehicleType):
id = "JTACFP"
name = "Infantry Soldier JTAC"
detection_range = 0
threat_range = 500
air_weapon_dist = 500
## ARTILERY
class MO_120_RT(unittype.VehicleType):
id = "M120"
name = "MO 120 RT"
detection_range = 0
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
eprls = True

View File

@@ -0,0 +1,446 @@
from enum import Enum
from dcs import task
from dcs.planes import PlaneType
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}
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}
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}
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_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}
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}
class MB_339PAN(PlaneType):
id = "MB-339PAN"
flyable = True
height = 4.77
width = 10.5
length = 12.13
fuel_max = 626
max_speed = 763.2
category = "Interceptor" #{78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
radio_frequency = 124
panel_radio = {
1: {
"channels": {
1: 225,
2: 258,
4: 270,
8: 257,
16: 252,
17: 268,
9: 253,
18: 269,
5: 255,
10: 263,
20: 269,
11: 267,
3: 260,
6: 259,
12: 254,
13: 264,
7: 262,
14: 266,
19: 268,
15: 265
},
},
2: {
"channels": {
1: 225,
2: 258,
4: 270,
8: 257,
16: 252,
17: 268,
9: 253,
18: 269,
5: 255,
10: 263,
20: 269,
30: 263,
21: 225,
11: 267,
22: 258,
3: 260,
6: 259,
12: 254,
24: 270,
19: 268,
25: 255,
13: 264,
26: 259,
27: 262,
7: 262,
14: 266,
28: 257,
23: 260,
29: 253,
15: 265
},
},
}
property_defaults = {
"SoloFlight": False,
"NetCrewControlPriority": 1,
}
class Properties:
class SoloFlight:
id = "SoloFlight"
class NetCrewControlPriority:
id = "NetCrewControlPriority"
class Values:
Pilot = 0
Instructor = 1
Ask_Always = -1
Equally_Responsible = -2
class Liveries:
class Georgia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Syria(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Finland(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Australia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Germany(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class SaudiArabia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Israel(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Croatia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class CzechRepublic(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Norway(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Romania(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Spain(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Ukraine(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Belgium(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Slovakia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Greece(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class UK(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Insurgents(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Hungary(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class France(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Abkhazia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Russia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Sweden(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Austria(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Switzerland(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Italy(Enum):
MB339PAN__Frecce_Tricolori = "MB339PAN 'Frecce Tricolori'"
MB339A__SVBIA____FACTORY = "MB339A 'SVBIA' - FACTORY"
MB339A__61BRIGATA____CAMO = "MB339A '61BRIGATA' - CAMO"
MB339A__61STORMO____CAMO = "MB339A '61STORMO' - CAMO"
MB339A__61STORMO____GREY = "MB339A '61STORMO' - GREY"
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class SouthOssetia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class SouthKorea(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Iran(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class China(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Pakistan(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Belarus(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class NorthKorea(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Iraq(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Kazakhstan(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Bulgaria(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Serbia(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class India(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class USAFAggressors(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class USA(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Denmark(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Egypt(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Canada(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class TheNetherlands(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Turkey(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Japan(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
class Poland(Enum):
MB339AA__ARMADA____Crippa = "MB339AA 'ARMADA' - Crippa"
MB339AA__ARMADA____Yellow_Band = "MB339AA 'ARMADA' - Yellow Band"
MB339__Factory = "MB339 'Factory'"
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)
class Pylon2:
Empty_Pylon = (2, MB_339PAN_Weapons.Empty_Pylon)
LR_25___25_ARF_8M3_HEI_ = (2, MB_339PAN_Weapons.LR_25___25_ARF_8M3_HEI_)
LR_25___25_ARF_8M3_API_ = (2, MB_339PAN_Weapons.LR_25___25_ARF_8M3_API_)
Mk_82 = (2, Weapons.Mk_82)
Matra_Type_155_Rocket_Pod = (2, Weapons.Matra_Type_155_Rocket_Pod)
class Pylon3:
Fuel_Tank_330lt = (3, MB_339PAN_Weapons.Fuel_Tank_330lt)
Empty_Pylon = (3, MB_339PAN_Weapons.Empty_Pylon)
LR_25___25_ARF_8M3_HEI_ = (3, MB_339PAN_Weapons.LR_25___25_ARF_8M3_HEI_)
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_)
Matra_Type_155_Rocket_Pod = (3, Weapons.Matra_Type_155_Rocket_Pod)
class Pylon4:
Color_Oil_Tank = (4, MB_339PAN_Weapons.Color_Oil_Tank)
Empty_Pylon = (4, MB_339PAN_Weapons.Empty_Pylon)
GunPod_AN_M3 = (4, MB_339PAN_Weapons.GunPod_AN_M3)
GunPod_DEFA553 = (4, MB_339PAN_Weapons.GunPod_DEFA553)
LR_25___25_ARF_8M3_HEI_ = (4, MB_339PAN_Weapons.LR_25___25_ARF_8M3_HEI_)
LR_25___25_ARF_8M3_API_ = (4, MB_339PAN_Weapons.LR_25___25_ARF_8M3_API_)
Mk_82 = (4, Weapons.Mk_82)
Matra_Type_155_Rocket_Pod = (4, Weapons.Matra_Type_155_Rocket_Pod)
class Pylon5:
MB339_Red_Smoke = (5, MB_339PAN_Weapons.MB339_Red_Smoke)
MB339_Green_Smoke = (5, MB_339PAN_Weapons.MB339_Green_Smoke)
MB339_YELLOW_Smoke = (5, MB_339PAN_Weapons.MB339_YELLOW_Smoke)
MB339_ORANGE_Smoke = (5, MB_339PAN_Weapons.MB339_ORANGE_Smoke)
MB339_Black_Smoke = (5, MB_339PAN_Weapons.MB339_Black_Smoke)
class Pylon6:
MB339_White_Smoke = (6, MB_339PAN_Weapons.MB339_White_Smoke)
class Pylon7:
Color_Oil_Tank = (7, MB_339PAN_Weapons.Color_Oil_Tank)
Empty_Pylon = (7, MB_339PAN_Weapons.Empty_Pylon)
GunPod_AN_M3_ = (7, MB_339PAN_Weapons.GunPod_AN_M3_)
GunPod_DEFA553_ = (7, MB_339PAN_Weapons.GunPod_DEFA553_)
LR_25___25_ARF_8M3_HEI_ = (7, MB_339PAN_Weapons.LR_25___25_ARF_8M3_HEI_)
LR_25___25_ARF_8M3_API_ = (7, MB_339PAN_Weapons.LR_25___25_ARF_8M3_API_)
Mk_82 = (7, Weapons.Mk_82)
Matra_Type_155_Rocket_Pod = (7, Weapons.Matra_Type_155_Rocket_Pod)
class Pylon8:
Fuel_Tank_330lt = (8, MB_339PAN_Weapons.Fuel_Tank_330lt)
Empty_Pylon = (8, MB_339PAN_Weapons.Empty_Pylon)
LR_25___25_ARF_8M3_HEI_ = (8, MB_339PAN_Weapons.LR_25___25_ARF_8M3_HEI_)
LR_25___25_ARF_8M3_API_ = (8, MB_339PAN_Weapons.LR_25___25_ARF_8M3_API_)
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_)
class Pylon9:
Empty_Pylon = (9, MB_339PAN_Weapons.Empty_Pylon)
LR_25___25_ARF_8M3_HEI_ = (9, MB_339PAN_Weapons.LR_25___25_ARF_8M3_HEI_)
LR_25___25_ARF_8M3_API_ = (9, MB_339PAN_Weapons.LR_25___25_ARF_8M3_API_)
Mk_82 = (9, Weapons.Mk_82)
Matra_Type_155_Rocket_Pod = (9, Weapons.Matra_Type_155_Rocket_Pod)
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_)
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
from userdata import logging_config
# Logging setup
VERSION_STRING = "2.0RC9"
VERSION_STRING = "2.0.10"
logging_config.init_logging(VERSION_STRING)
import logging
@@ -17,19 +17,19 @@ from qt_ui import uiconstants
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.QLiberationWindow import QLiberationWindow
from qt_ui.windows.preferences.QLiberationFirstStartWindow import QLiberationFirstStartWindow
from userdata import liberation_install, persistency
from userdata import liberation_install, persistency, liberation_theme
if __name__ == "__main__":
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" # Potential fix for 4K screens
app = QApplication(sys.argv)
# init the theme and load the stylesheet based on the theme index
liberation_theme.init()
css = ""
with open("./resources/stylesheets/style.css") as stylesheet:
with open("./resources/stylesheets/"+liberation_theme.get_theme_css_file()) as stylesheet:
app.setStyleSheet(stylesheet.read())
# Inject custom payload in pydcs framework
custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..\\resources\\customized_payloads")
if os.path.exists(custom_payloads):
@@ -84,6 +84,5 @@ if __name__ == "__main__":
logging.info("Attempt to restore original mission scripting file")
liberation_install.restore_original_mission_scripting()
logging.info("QT process exited with code : " + str(qt_execution_code))
sys.exit(0)

View File

@@ -6,11 +6,10 @@ from PySide2.QtGui import QColor, QFont, QPixmap
from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP
from userdata.liberation_theme import get_theme_icons
URLS : Dict[str, str] = {
"Manual": "https://github.com/khopa/dcs_liberation/wiki",
"Troubleshooting": "https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting",
"Modding": "https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial",
"Repository": "https://github.com/khopa/dcs_liberation",
"ForumThread": "https://forums.eagle.ru/showthread.php?t=214834",
"Issues": "https://github.com/khopa/dcs_liberation/issues"
@@ -19,26 +18,58 @@ URLS : Dict[str, str] = {
LABELS_OPTIONS = ["Full", "Abbreviated", "Dot Only", "Off"]
SKILL_OPTIONS = ["Average", "Good", "High", "Excellent"]
COLORS: Dict[str, QColor] = {
"dark_red": QColor(140, 20, 20),
"red": QColor(200, 80, 80),
"bright_red": QColor(150, 80, 80),
"super_red": QColor(200, 120, 120),
"blue": QColor(164, 164, 255),
"dark_blue": QColor(45, 62, 80),
"white": QColor(255, 255, 255),
"green": QColor(128, 186, 128),
"bright_green": QColor(64, 200, 64),
"black": QColor(0, 0, 0),
"black_transparent": QColor(0, 0, 0, 64),
"blue_transparent": QColor(164, 164, 255, 32),
"red_transparent": QColor(255, 125, 125, 32)
FONT_SIZE = 8
FONT_NAME = "Arial"
# FONT = QFont("Arial", 12, weight=5, italic=True)
FONT_PRIMARY = QFont(FONT_NAME, FONT_SIZE, weight=5, italic=False)
FONT_PRIMARY_I = QFont(FONT_NAME, FONT_SIZE, weight=5, italic=True)
FONT_PRIMARY_B = QFont(FONT_NAME, FONT_SIZE, weight=75, italic=False)
FONT_MAP = QFont(FONT_NAME, 10, weight=75, italic=False)
# new themes can be added here
THEMES: Dict[int, Dict[str, str]] = {
0: {'themeName': 'Vanilla',
'themeFile': 'windows-style.css',
'themeIcons': 'medium',
},
1: {'themeName': 'DCS World',
'themeFile': 'style-dcs.css',
'themeIcons': 'light',
},
}
COLORS: Dict[str, QColor] = {
"white": QColor(255, 255, 255),
"white_transparent": QColor(255, 255, 255, 35),
"grey_transparent": QColor(150, 150, 150, 30),
CP_SIZE = 25
FONT = QFont("Arial", 12, weight=5, italic=True)
"red": QColor(200, 80, 80),
"dark_red": QColor(140, 20, 20),
"red_transparent": QColor(227, 32, 0, 20),
"blue": QColor(0, 132, 255),
"dark_blue": QColor(45, 62, 80),
"blue_transparent": QColor(0, 132, 255, 20),
"bright_red": QColor(150, 80, 80),
"super_red": QColor(227, 32, 0),
"green": QColor(128, 186, 128),
"bright_green": QColor(64, 200, 64),
"black": QColor(0, 0, 0),
"black_transparent": QColor(0, 0, 0, 5),
"orange": QColor(254, 125, 10),
"night_overlay": QColor(12, 20, 69),
"dawn_dust_overlay": QColor(46, 38, 85),
}
CP_SIZE = 24
AIRCRAFT_ICONS: Dict[str, QPixmap] = {}
VEHICLES_ICONS: Dict[str, QPixmap] = {}
@@ -46,9 +77,9 @@ ICONS: Dict[str, QPixmap] = {}
def load_icons():
ICONS["New"] = QPixmap("./resources/ui/misc/new.png")
ICONS["Open"] = QPixmap("./resources/ui/misc/open.png")
ICONS["Save"] = QPixmap("./resources/ui/misc/save.png")
ICONS["New"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/new.png")
ICONS["Open"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/open.png")
ICONS["Save"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/save.png")
ICONS["Terrain_Caucasus"] = QPixmap("./resources/ui/terrain_caucasus.gif")
ICONS["Terrain_Persian_Gulf"] = QPixmap("./resources/ui/terrain_pg.gif")
@@ -61,12 +92,12 @@ def load_icons():
ICONS["Dusk"] = QPixmap("./resources/ui/daytime/dusk.png")
ICONS["Night"] = QPixmap("./resources/ui/daytime/night.png")
ICONS["Money"] = QPixmap("./resources/ui/misc/money_icon.png")
ICONS["PassTurn"] = QPixmap("./resources/ui/misc/hourglass.png")
ICONS["Proceed"] = QPixmap("./resources/ui/misc/proceed.png")
ICONS["Settings"] = QPixmap("./resources/ui/misc/settings.png")
ICONS["Statistics"] = QPixmap("./resources/ui/misc/statistics.png")
ICONS["Ordnance"] = QPixmap("./resources/ui/misc/ordnance_icon.png")
ICONS["Money"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/money_icon.png")
ICONS["PassTurn"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/hourglass.png")
ICONS["Proceed"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/proceed.png")
ICONS["Settings"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/settings.png")
ICONS["Statistics"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/statistics.png")
ICONS["Ordnance"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/ordnance_icon.png")
ICONS["target"] = QPixmap("./resources/ui/ground_assets/target.png")
ICONS["cleared"] = QPixmap("./resources/ui/ground_assets/cleared.png")
@@ -77,9 +108,9 @@ def load_icons():
ICONS["ship"] = QPixmap("./resources/ui/ground_assets/ship.png")
ICONS["ship_blue"] = QPixmap("./resources/ui/ground_assets/ship_blue.png")
ICONS["Generator"] = QPixmap("./resources/ui/misc/generator.png")
ICONS["Missile"] = QPixmap("./resources/ui/misc/missile.png")
ICONS["Cheat"] = QPixmap("./resources/ui/misc/cheat.png")
ICONS["Generator"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/generator.png")
ICONS["Missile"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/missile.png")
ICONS["Cheat"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/cheat.png")
ICONS["TaskCAS"] = QPixmap("./resources/ui/tasks/cas.png")
ICONS["TaskCAP"] = QPixmap("./resources/ui/tasks/cap.png")

View File

@@ -34,7 +34,7 @@ class QTopPanel(QFrame):
self.proceedButton = QPushButton("Mission Planning")
self.proceedButton.setIcon(CONST.ICONS["Proceed"])
self.proceedButton.setProperty("style", "btn-primary")
self.proceedButton.setProperty("style", "btn-success")
self.proceedButton.clicked.connect(self.proceed)
if self.game and self.game.turn == 0:
self.proceedButton.setEnabled(False)

View File

@@ -15,7 +15,6 @@ from game.event import UnitsDeliveryEvent, Event, ControlPointType
from gen import Conflict
from qt_ui.widgets.map.QLiberationScene import QLiberationScene
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint
from qt_ui.widgets.map.QMapEvent import QMapEvent
from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from theater import ControlPoint
@@ -71,7 +70,6 @@ class QLiberationMap(QGraphicsView):
"""
Uncomment to set up theather reference points
def keyPressEvent(self, event):
#super(QLiberationMap, self).keyPressEvent(event)
@@ -85,34 +83,36 @@ class QLiberationMap(QGraphicsView):
i = i + 1
if event.key() == QtCore.Qt.Key_Down:
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0] + 100, self.game.theater.reference_points[point_0][1]
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0] + 10, self.game.theater.reference_points[point_0][1]
if event.key() == QtCore.Qt.Key_Up:
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0] - 100, self.game.theater.reference_points[point_0][1]
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0] - 10, self.game.theater.reference_points[point_0][1]
if event.key() == QtCore.Qt.Key_Left:
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0], self.game.theater.reference_points[point_0][1] + 100
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0], self.game.theater.reference_points[point_0][1] + 10
if event.key() == QtCore.Qt.Key_Right:
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0], self.game.theater.reference_points[point_0][1] - 100
self.game.theater.reference_points[point_0] = self.game.theater.reference_points[point_0][0], self.game.theater.reference_points[point_0][1] - 10
if event.key() == QtCore.Qt.Key_2 and numpad_mod:
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0] + 100, self.game.theater.reference_points[point_1][1]
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0] + 10, self.game.theater.reference_points[point_1][1]
if event.key() == QtCore.Qt.Key_8 and numpad_mod:
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0] - 100, self.game.theater.reference_points[point_1][1]
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0] - 10, self.game.theater.reference_points[point_1][1]
if event.key() == QtCore.Qt.Key_4 and numpad_mod:
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0], self.game.theater.reference_points[point_1][1] + 100
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0], self.game.theater.reference_points[point_1][1] + 10
if event.key() == QtCore.Qt.Key_6 and numpad_mod:
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0], self.game.theater.reference_points[point_1][1] - 100
self.game.theater.reference_points[point_1] = self.game.theater.reference_points[point_1][0], self.game.theater.reference_points[point_1][1] - 10
print(self.game.theater.reference_points)
self.reload_scene()
"""
def reload_scene(self):
scene = self.scene()
scene.clear()
playerColor = self.game.get_player_color()
enemyColor = self.game.get_enemy_color()
self.addBackground()
# Uncomment below to help set up theater reference points
@@ -128,11 +128,11 @@ class QLiberationMap(QGraphicsView):
CONST.CP_SIZE, cp, self.game))
if cp.captured:
pen = QPen(brush=CONST.COLORS["blue"])
brush = CONST.COLORS["blue_transparent"]
pen = QPen(brush=CONST.COLORS[playerColor])
brush = CONST.COLORS[playerColor+"_transparent"]
else:
pen = QPen(brush=CONST.COLORS["red"])
brush = CONST.COLORS["red_transparent"]
pen = QPen(brush=CONST.COLORS[enemyColor])
brush = CONST.COLORS[enemyColor+"_transparent"]
added_objects = []
for ground_object in cp.ground_objects:
@@ -157,34 +157,35 @@ class QLiberationMap(QGraphicsView):
if unit.threat_range > max_range:
max_range = unit.threat_range
if has_radar:
scene.addEllipse(go_pos[0] - max_range/300.0 + 8, go_pos[1] - max_range/300.0 + 8, max_range/150.0, max_range/150.0, pen, brush)
scene.addEllipse(go_pos[0] - max_range/300.0 + 8, go_pos[1] - max_range/300.0 + 8, max_range/150.0, max_range/150.0, CONST.COLORS["white_transparent"], CONST.COLORS["grey_transparent"])
added_objects.append(ground_object.obj_name)
for cp in self.game.theater.enemy_points():
if self.get_display_rule("lines"):
self.scene_create_lines_for_cp(cp)
self.scene_create_lines_for_cp(cp, playerColor, enemyColor)
for cp in self.game.theater.player_points():
if self.get_display_rule("lines"):
self.scene_create_lines_for_cp(cp)
self.scene_create_lines_for_cp(cp, playerColor, enemyColor)
for cp in self.game.theater.controlpoints:
if cp.captured:
pen = QPen(brush=CONST.COLORS["blue"])
brush = CONST.COLORS["blue_transparent"]
pen = QPen(brush=CONST.COLORS[playerColor])
brush = CONST.COLORS[playerColor+"_transparent"]
flight_path_pen = QPen(brush=CONST.COLORS[playerColor])
flight_path_pen.setColor(CONST.COLORS[playerColor])
flight_path_pen = QPen(brush=CONST.COLORS["blue"])
flight_path_pen.setColor(CONST.COLORS["blue"])
flight_path_pen.setWidth(1)
flight_path_pen.setStyle(Qt.DashDotLine)
else:
pen = QPen(brush=CONST.COLORS["red"])
brush = CONST.COLORS["red_transparent"]
pen = QPen(brush=CONST.COLORS[enemyColor])
brush = CONST.COLORS[enemyColor+"_transparent"]
flight_path_pen = QPen(brush=CONST.COLORS["bright_red"])
flight_path_pen.setColor(CONST.COLORS["bright_red"])
flight_path_pen.setWidth(1)
flight_path_pen.setStyle(Qt.DashDotLine)
flight_path_pen = QPen(brush=CONST.COLORS[enemyColor])
flight_path_pen.setColor(CONST.COLORS[enemyColor])
flight_path_pen.setWidth(1)
flight_path_pen.setStyle(Qt.DashDotLine)
pos = self._transform_point(cp.position)
if self.get_display_rule("flight_paths"):
@@ -202,27 +203,27 @@ class QLiberationMap(QGraphicsView):
for cp in self.game.theater.controlpoints:
pos = self._transform_point(cp.position)
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
text = scene.addText(cp.name, font=CONST.FONT_MAP)
text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2)
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
text = scene.addText(cp.name, font=CONST.FONT_MAP)
text.setDefaultTextColor(Qt.white)
text.setPos(pos[0] + CONST.CP_SIZE + 1, pos[1] - CONST.CP_SIZE / 2 + 1)
def scene_create_lines_for_cp(self, cp: ControlPoint):
def scene_create_lines_for_cp(self, cp: ControlPoint, playerColor, enemyColor):
scene = self.scene()
pos = self._transform_point(cp.position)
for connected_cp in cp.connected_points:
pos2 = self._transform_point(connected_cp.position)
if not cp.captured:
color = CONST.COLORS["red"]
color = CONST.COLORS["dark_"+enemyColor]
elif cp.captured:
color = CONST.COLORS["blue"]
color = CONST.COLORS["dark_"+playerColor]
else:
color = CONST.COLORS["red"]
color = CONST.COLORS["dark_"+enemyColor]
pen = QPen(brush=color)
pen.setColor(color)
pen.setWidth(16)
pen.setWidth(6)
if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp):
if not cp.captured:
scene.addLine(pos[0], pos[1], pos2[0], pos2[1], pen=pen)
@@ -234,8 +235,8 @@ class QLiberationMap(QGraphicsView):
p1 = point_from_heading(pos2[0], pos2[1], h+180, 25)
p2 = point_from_heading(pos2[0], pos2[1], h, 25)
frontline_pen = QPen(brush=CONST.COLORS["bright_red"])
frontline_pen.setColor(CONST.COLORS["bright_red"])
frontline_pen.setWidth(18)
frontline_pen.setColor(CONST.COLORS["orange"])
frontline_pen.setWidth(8)
scene.addLine(p1[0], p1[1], p2[0], p2[1], pen=frontline_pen)
else:
@@ -318,14 +319,14 @@ class QLiberationMap(QGraphicsView):
pass
elif self.game.current_turn_daytime == "night":
ov = QPixmap(bg.width(), bg.height())
ov.fill(QColor(40, 40, 150))
ov.fill(CONST.COLORS["night_overlay"])
overlay = scene.addPixmap(ov)
effect = QGraphicsOpacityEffect()
effect.setOpacity(0.7)
overlay.setGraphicsEffect(effect)
else:
ov = QPixmap(bg.width(), bg.height())
ov.fill(QColor(165, 100, 100))
ov.fill(CONST.COLORS["dawn_dust_overlay"])
overlay = scene.addPixmap(ov)
effect = QGraphicsOpacityEffect()
effect.setOpacity(0.3)

View File

@@ -1,13 +1,13 @@
from PySide2.QtGui import QFont
from PySide2.QtWidgets import QGraphicsScene
from qt_ui.uiconstants import COLORS
import qt_ui.uiconstants as CONST
class QLiberationScene(QGraphicsScene):
def __init__(self, parent):
super().__init__(parent)
item = self.addText("No save file found. Go to \"File/New Game\" to setup a new campaign.",
QFont("Arial", 14, weight=5))
item.setDefaultTextColor(COLORS["white"])
item = self.addText("Go to \"File/New Game\" to setup a new campaign or go to \"File/Open\" to load an existing save game.",
CONST.FONT_PRIMARY)
item.setDefaultTextColor(CONST.COLORS["white"])

View File

@@ -5,7 +5,6 @@ from PySide2.QtWidgets import QGraphicsRectItem, QGraphicsSceneHoverEvent, QGrap
import qt_ui.uiconstants as CONST
from game import Game
from qt_ui.windows.basemenu.QBaseMenu import QBaseMenu
from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2
from theater import ControlPoint, db
@@ -71,7 +70,8 @@ class QMapControlPoint(QGraphicsRectItem):
self.update()
def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
self.contextMenuEvent(event)
self.openBaseMenu()
#self.contextMenuEvent(event)
def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
@@ -89,17 +89,11 @@ class QMapControlPoint(QGraphicsRectItem):
@property
def brush_color(self)->QColor:
if self.parent.game.player_country in db.BLUEFOR_FACTIONS:
return self.model.captured and CONST.COLORS["blue"] or CONST.COLORS["super_red"]
else:
return self.model.captured and CONST.COLORS["super_red"] or CONST.COLORS["blue"]
return self.model.captured and CONST.COLORS["blue"] or CONST.COLORS["super_red"]
@property
def pen_color(self) -> QColor:
if self.parent.game.player_country in db.BLUEFOR_FACTIONS:
return self.model.captured and CONST.COLORS["dark_blue"] or CONST.COLORS["bright_red"]
else:
return self.model.captured and CONST.COLORS["bright_red"] or CONST.COLORS["dark_blue"]
return self.model.captured and CONST.COLORS["white"] or CONST.COLORS["white"]
def openBaseMenu(self):
self.baseMenu = QBaseMenu2(self.window(), self.model, self.game)

View File

@@ -1,51 +0,0 @@
from PySide2.QtGui import QPen, Qt
from PySide2.QtWidgets import QGraphicsRectItem, QGraphicsSceneMouseEvent, QGraphicsSceneHoverEvent
import qt_ui.uiconstants as CONST
from game.event import Event, UnitsDeliveryEvent
from qt_ui.windows.QBriefingWindow import QBriefingWindow
class QMapEvent(QGraphicsRectItem):
def __init__(self, parent, x: float, y: float, w: float, h: float, gameEvent: Event):
super(QMapEvent, self).__init__(x, y, w, h)
self.gameEvent = gameEvent
self.parent = parent
self.setAcceptHoverEvents(True)
self.setZValue(2)
self.setToolTip(str(self.gameEvent))
self.playable = not isinstance(self.gameEvent, UnitsDeliveryEvent)
def paint(self, painter, option, widget=None):
if self.parent.get_display_rule("events"):
painter.save()
if self.gameEvent.is_player_attacking:
painter.setPen(QPen(brush=CONST.COLORS["blue"]))
painter.setBrush(CONST.COLORS["blue"])
else:
painter.setPen(QPen(brush=CONST.COLORS["red"]))
painter.setBrush(CONST.COLORS["red"])
if self.isUnderMouse() and self.playable:
painter.setBrush(CONST.COLORS["white"])
painter.drawRect(option.rect)
painter.drawPixmap(option.rect, CONST.EVENT_ICONS[self.gameEvent.__class__])
painter.restore()
def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
if self.parent.get_display_rule("events"):
self.openBriefing()
def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
self.update()
if self.playable:
self.setCursor(Qt.PointingHandCursor)
def openBriefing(self):
if self.playable:
self.briefing = QBriefingWindow(self.gameEvent)
self.briefing.show()

View File

@@ -42,6 +42,10 @@ class QMapGroundObject(QGraphicsRectItem):
def paint(self, painter, option, widget=None):
#super(QMapControlPoint, self).paint(painter, option, widget)
playerIcons = "_blue"
enemyIcons = ""
if self.parent.get_display_rule("go"):
painter.save()
@@ -50,9 +54,9 @@ class QMapGroundObject(QGraphicsRectItem):
cat = "ship"
if not self.model.is_dead and not self.cp.captured:
painter.drawPixmap(option.rect, CONST.ICONS[cat])
painter.drawPixmap(option.rect, CONST.ICONS[cat + enemyIcons])
elif not self.model.is_dead:
painter.drawPixmap(option.rect, CONST.ICONS[cat + "_blue"])
painter.drawPixmap(option.rect, CONST.ICONS[cat + playerIcons])
else:
painter.drawPixmap(option.rect, CONST.ICONS["destroyed"])
painter.restore()

View File

@@ -1,283 +0,0 @@
import os
from PySide2.QtGui import QWindow
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QVBoxLayout, QGridLayout, QGroupBox, QCheckBox, \
QSpinBox, QPushButton, QMessageBox, QComboBox
from pip._internal.utils import typing
from game.game import AWACS_BUDGET_COST, PinpointStrike, db, Event, FrontlineAttackEvent, Task, \
UnitType
from qt_ui.windows.QWaitingForMissionResultWindow import QWaitingForMissionResultWindow
from userdata.persistency import base_path
import qt_ui.uiconstants as CONST
class QBriefingWindow(QDialog):
def __init__(self, gameEvent: Event):
super(QBriefingWindow, self).__init__()
self.gameEvent = gameEvent
self.setWindowTitle("Briefing : " + str(gameEvent))
self.setMinimumSize(200,200)
self.setWindowIcon(CONST.EVENT_ICONS[self.gameEvent.__class__])
self.setModal(True)
self.game = self.gameEvent.game
if self.gameEvent.attacker_name == self.game.player_name:
self.base = self.gameEvent.from_cp.base
self.playerFromCp = self.gameEvent.from_cp
else:
self.base = self.gameEvent.to_cp.base
self.playerFromCp = self.gameEvent.to_cp
self.scramble_entries = {k: {} for k in self.gameEvent.tasks}
self.initUi()
def initUi(self):
self.layout = QVBoxLayout()
self.depart_box = QGroupBox("Departure")
self.depart_layout = QHBoxLayout()
self.depart_box.setLayout(self.depart_layout)
self.depart_from_label = QLabel("Depart from : ")
self.depart_from = QComboBox()
for i, cp in enumerate([b for b in self.game.theater.controlpoints if b.captured]):
self.depart_from.addItem(str(cp.name), cp)
if cp.name == self.playerFromCp.name:
self.depart_from.setCurrentIndex(i)
self.depart_from.currentTextChanged.connect(self.on_departure_cp_changed)
self.depart_layout.addWidget(self.depart_from_label)
self.depart_layout.addWidget(self.depart_from)
# Mission Description
self.gridLayout = QGridLayout()
self.initUnitRows()
self.scramble_box = QGroupBox("Units")
self.scramble_box.setLayout(self.gridLayout)
self.action_layout = QHBoxLayout()
self.commit_button = QPushButton("Commit")
self.back_button = QPushButton("Cancel")
self.commit_button.clicked.connect(self.start)
self.back_button.clicked.connect(self.close)
self.action_layout.addWidget(self.commit_button)
self.action_layout.addWidget(self.back_button)
self.support_box = self.initSupportBox()
self.layout.addWidget(QLabel("<h2>{} on {}</h2>".format(self.gameEvent, self.gameEvent.to_cp.name)))
self.layout.addWidget(self.depart_box)
self.layout.addWidget(self.scramble_box)
self.layout.addWidget(self.support_box)
self.layout.addWidget(QLabel("<b>Ready?</b>"))
self.layout.addLayout(self.action_layout)
self.setLayout(self.layout)
def initUnitRows(self):
row = 0
def header(text, row):
self.gridLayout.addWidget(QLabel("<b>" + text + "</b>"), row, 0, 1, 2)
def scramble_row(task_type, unit_type, unit_count, client_slots: bool, row: int):
unit_name = QLabel("{} ({})".format(db.unit_type_name(unit_type), unit_count))
self.gridLayout.addWidget(unit_name, row, 0)
scramble_entry = QSpinBox()
self.gridLayout.addWidget(scramble_entry, row, 1)
if client_slots:
client_entry = QSpinBox()
self.gridLayout.addWidget(client_entry, row, 2)
else:
client_entry = None
self.scramble_entries[task_type][unit_type] = scramble_entry, client_entry
# Table headers
self.gridLayout.addWidget(QLabel("Amount"), row, 1)
self.gridLayout.addWidget(QLabel("Client slots"), row, 2)
row += 1
for flight_task in self.gameEvent.tasks:
header("{}:".format(self.gameEvent.flight_name(flight_task)), row)
row += 1
if flight_task == PinpointStrike:
if not self.base.armor:
self.gridLayout.addWidget(QLabel("No units"), row, 1)
row += 1
for t, c in self.base.armor.items():
scramble_row(flight_task, t, c, False, row)
row += 1
else:
if not self.base.aircraft:
self.gridLayout.addWidget(QLabel("No units"), row, 1)
row += 1
for t, c in self.base.aircraft.items():
scramble_row(flight_task, t, c, t.flyable, row)
row += 1
return self.gridLayout
def initSupportBox(self):
self.support_box = QGroupBox("Support")
self.support_layout = QGridLayout()
self.support_box.setLayout(self.support_layout)
self.awacs_label = QLabel("AWACS ({}m)".format(AWACS_BUDGET_COST))
self.awacs_checkbox = QCheckBox()
self.ca_slot_label = QLabel("Combined Arms Slots")
self.ca_slot_entry = QSpinBox()
self.ca_slot_entry.setValue(0)
self.ca_slot_entry.setMinimum(0)
self.ca_slot_entry.setMaximum(32)
self.support_layout.addWidget(self.awacs_label, 0, 0)
self.support_layout.addWidget(self.awacs_checkbox, 0, 1)
self.support_layout.addWidget(self.ca_slot_label, 1, 0)
self.support_layout.addWidget(self.ca_slot_entry, 1, 1)
return self.support_box
def initWaitingForResults(self):
layout = QVBoxLayout()
layout.addWidget(QLabel("<b>You are clear for takeoff</b>"))
layout.addWidget(QLabel("In DCS open and play the mission : "))
layout.addWidget(QLabel("<i>liberation_nextturn</i>"))
layout.addWidget(QLabel("or"))
layout.addWidget(QLabel("<i>liberation_nextturn_quick</i>"))
layout.addWidget(QLabel("<b>Then save the debriefing to folder :</b>"))
layout.addWidget(QLabel("Then save the debriefing to the folder:"))
layout.addWidget(QLabel("<i>" + self.debriefing_directory_location() + "</i>"))
layout.addWidget(QLabel("Waiting for results..."))
# layout.addWidget(QLabel("In DCS open and play the mission : "))
# layout.addWidget(QLabel("<b>You are clear for takeoff</b>"))
self.setLayout(layout)
pass
def debriefing_directory_location(self) -> str:
return os.path.join(base_path(), "liberation_debriefings")
def start(self):
if self.awacs_checkbox.isChecked() == 1:
self.gameEvent.is_awacs_enabled = True
self.game.awacs_expense_commit()
else:
self.gameEvent.is_awacs_enabled = False
ca_slot_entry_value = self.ca_slot_entry.value()
try:
ca_slots = int(ca_slot_entry_value and ca_slot_entry_value or "0")
except:
ca_slots = 0
self.gameEvent.ca_slots = ca_slots
# Resolve Departure CP
self.gameEvent.departure_cp = self.depart_from.itemData(self.depart_from.currentIndex())
flights = {k: {} for k in self.gameEvent.tasks} # type: db.TaskForceDict
units_scramble_counts = {} # type: typing.Dict[typing.Type[UnitType], int]
tasks_scramble_counts = {} # type: typing.Dict[typing.Type[Task], int]
tasks_clients_counts = {} # type: typing.Dict[typing.Type[Task], int]
def dampen_count(unit_type, count: int) -> int:
nonlocal units_scramble_counts
total_count = self.base.total_units_of_type(unit_type)
total_scrambled = units_scramble_counts.get(unit_type, 0)
dampened_value = count if count + total_scrambled < total_count else total_count - total_scrambled
units_scramble_counts[unit_type] = units_scramble_counts.get(unit_type, 0) + dampened_value
return dampened_value
for task_type, dict in self.scramble_entries.items():
for unit_type, (count_entry, clients_entry) in dict.items():
try:
count = int(count_entry.value())
except:
count = 0
try:
clients_count = int(clients_entry and clients_entry.value() or 0)
except:
clients_count = 0
dampened_count = dampen_count(unit_type, count)
tasks_clients_counts[task_type] = tasks_clients_counts.get(task_type, 0) + clients_count
tasks_scramble_counts[task_type] = tasks_scramble_counts.get(task_type, 0) + dampened_count
flights[task_type][unit_type] = dampened_count, clients_count
for task in self.gameEvent.ai_banned_tasks:
if tasks_clients_counts.get(task, 0) == 0 and tasks_scramble_counts.get(task, 0) > 0:
self.showErrorMessage("Need at least one player in flight {}".format(self.gameEvent.flight_name(task)))
return
for task in self.gameEvent.player_banned_tasks:
if tasks_clients_counts.get(task, 0) != 0:
self.showErrorMessage("Players are not allowed on flight {}".format(self.gameEvent.flight_name(task)))
return
if self.game.is_player_attack(self.gameEvent):
if isinstance(self.gameEvent, FrontlineAttackEvent):
if self.base.total_armor == 0:
self.showErrorMessage("No ground vehicles available to attack!")
return
self.gameEvent.player_attacking(flights)
else:
if isinstance(self.gameEvent, FrontlineAttackEvent):
if self.gameEvent.to_cp.base.total_armor == 0:
self.showErrorMessage("No ground vehicles available to defend!")
return
self.gameEvent.player_defending(flights)
self.game.initiate_event(self.gameEvent)
waiting = QWaitingForMissionResultWindow(self.gameEvent, self.game)
waiting.show()
self.close()
def showErrorMessage(self, text):
about = QMessageBox()
about.setWindowTitle("Error")
about.setIcon(QMessageBox.Icon.Critical)
about.setText(text)
about.exec_()
def on_departure_cp_changed(self):
selectedBase = self.depart_from.itemData(self.depart_from.currentIndex())
for i, cp in enumerate([b for b in self.game.theater.controlpoints if b.captured]):
if cp.name == selectedBase.name:
self.base = cp.base
self.playerFromCp = cp
break
# Clear current selection
self.scramble_entries = {k: {} for k in self.gameEvent.tasks}
# Clear the grid layout
for i in reversed(range(self.gridLayout.count())):
self.gridLayout.itemAt(i).widget().setParent(None)
# Rebuild the grid layout, so that it correspond to the newly selected CP
self.initUnitRows()

View File

@@ -1,4 +1,4 @@
from PySide2.QtGui import QIcon
from PySide2.QtGui import QIcon, QPixmap
from PySide2.QtWidgets import QLabel, QDialog, QVBoxLayout, QGroupBox, QGridLayout, QPushButton
from game.game import Event, db, Game
@@ -25,14 +25,21 @@ class QDebriefingWindow(QDialog):
self.layout = QVBoxLayout()
# Result
header = QLabel(self)
header.setGeometry(0, 0, 655, 106)
pixmap = QPixmap("./resources/ui/debriefing.png")
header.setPixmap(pixmap)
self.layout.addWidget(header)
self.layout.addStretch()
if self.gameEvent.is_successfull(self.debriefing):
title = QLabel("<b>Operation Succesfull !</b>")
title.setProperty("style", "title-success")
else:
title = QLabel("<b>Operation failed !</b>")
title.setProperty("style", "title-danger")
# Result
#if self.gameEvent.is_successfull(self.debriefing):
# title = QLabel("<b>Operation end !</b>")
# title.setProperty("style", "title-success")
#else:
# title = QLabel("<b>Operation end !</b>")
# title.setProperty("style", "title-danger")
title = QLabel("<b>Casualty report</b>")
self.layout.addWidget(title)
# Player lost units

View File

@@ -5,7 +5,7 @@ import webbrowser
from PySide2.QtCore import Qt
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QWidget, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
QSplitter
QSplitter, QFileDialog
import qt_ui.uiconstants as CONST
from game import Game
@@ -54,6 +54,7 @@ class QLiberationWindow(QMainWindow):
hbox = QSplitter(Qt.Horizontal)
hbox.addWidget(self.info_panel)
hbox.addWidget(self.liberation_map)
hbox.setSizes([2, 8])
vbox = QVBoxLayout()
vbox.setMargin(0)
@@ -73,10 +74,18 @@ class QLiberationWindow(QMainWindow):
self.newGameAction.setIcon(QIcon(CONST.ICONS["New"]))
self.newGameAction.triggered.connect(self.newGame)
self.openAction = QAction("Open", self)
self.openAction.setIcon(QIcon(CONST.ICONS["Open"]))
self.openAction.triggered.connect(self.openFile)
self.saveGameAction = QAction("Save", self)
self.saveGameAction.setIcon(QIcon(CONST.ICONS["Save"]))
self.saveGameAction.triggered.connect(self.saveGame)
self.saveAsAction = QAction("Save As", self)
self.saveAsAction.setIcon(QIcon(CONST.ICONS["Save"]))
self.saveAsAction.triggered.connect(self.saveGameAs)
self.showAboutDialogAction = QAction("About DCS Liberation", self)
self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
self.showAboutDialogAction.triggered.connect(self.showAboutDialog)
@@ -88,7 +97,7 @@ class QLiberationWindow(QMainWindow):
def initToolbar(self):
self.tool_bar = self.addToolBar("File")
self.tool_bar.addAction(self.newGameAction)
#self.tool_bar.addAction(QIcon(CONST.ICONS["Open"]), "Open")
self.tool_bar.addAction(self.openAction)
self.tool_bar.addAction(self.saveGameAction)
def initMenuBar(self):
@@ -96,25 +105,23 @@ class QLiberationWindow(QMainWindow):
file_menu = self.menu.addMenu("File")
file_menu.addAction(self.newGameAction)
#file_menu.addAction(QIcon(CONST.ICONS["Open"]), "Open") # TODO : implement
file_menu.addAction(self.openAction)
file_menu.addAction(self.saveGameAction)
file_menu.addAction(self.saveAsAction)
file_menu.addSeparator()
file_menu.addAction(self.showLiberationPrefDialogAction)
file_menu.addSeparator()
#file_menu.addAction("Save As") # TODO : implement
#file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
file_menu.addAction("Exit" , lambda: self.exit())
help_menu = self.menu.addMenu("Help")
help_menu.addAction("Discord Server", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
help_menu.addAction("Github Repository", lambda: webbrowser.open_new_tab("https://github.com/khopa/dcs_liberation"))
help_menu.addAction("Releases", lambda: webbrowser.open_new_tab("https://github.com/Khopa/dcs_liberation/releases"))
help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
help_menu.addAction("Discord", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
#help_menu.addAction("Troubleshooting Guide", lambda: webbrowser.open_new_tab(URLS["Troubleshooting"]))
#help_menu.addAction("Modding Guide", lambda: webbrowser.open_new_tab(URLS["Modding"]))
#help_menu.addSeparator() ----> Note from Khopa : I disable these links since it's not up to date for this branch
#help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
help_menu.addAction("Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
help_menu.addAction("ED Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
help_menu.addAction("Report an issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))
help_menu.addSeparator()
help_menu.addAction(self.showAboutDialogAction)
@@ -163,10 +170,29 @@ class QLiberationWindow(QMainWindow):
wizard.show()
wizard.accepted.connect(lambda: self.onGameGenerated(wizard.generatedGame))
def openFile(self):
file = QFileDialog.getOpenFileName(self, "Select game file to open",
dir=persistency._dcs_saved_game_folder,
filter="*.liberation")
if file is not None:
game = persistency.load_game(file[0])
self.setGame(game)
GameUpdateSignal.get_instance().updateGame(self.game)
def saveGame(self):
logging.info("Saving game")
persistency.save_game(self.game)
GameUpdateSignal.get_instance().updateGame(self.game)
if self.game.savepath:
persistency.save_game(self.game)
GameUpdateSignal.get_instance().updateGame(self.game)
else:
self.saveGameAs()
def saveGameAs(self):
file = QFileDialog.getSaveFileName(self, "Save As", dir=persistency._dcs_saved_game_folder, filter="*.liberation")
if file is not None:
self.game.savepath = file[0]
persistency.save_game(self.game)
def onGameGenerated(self, game: Game):
logging.info("On Game generated")
@@ -187,13 +213,15 @@ class QLiberationWindow(QMainWindow):
def showAboutDialog(self):
text = "<h3>DCS Liberation</h3>" + \
"<h4>Repository</h4>" + \
"<b>Source code :</b> https://github.com/shdwp/dcs_liberation<br/>" + \
"<h4>Authors/Contributors</h4><br/>" + \
"<b>shdwp</b>, <b>Khopa</b>, <b>Wrycu</b>, <b>calvinmorrow</b>, <b>JohanAberg</b><br/>" + \
"<b>Source code :</b> https://github.com/khopa/dcs_liberation" + \
"<h4>Authors</h4>" + \
"<p>DCS Liberation was originally developed by <b>shdwp</b>, DCS Liberation 2.0 is a partial rewrite based on this work by <b>Khopa</b>." \
"<h4>Contributors</h4>" + \
"shdwp, Khopa, Wrycu, calvinmorrow, JohanAberg, Deus" + \
"<h4>Special Thanks :</h4>" \
"<b>rp-</b> <i>for the pydcs framework</i><br/>"\
"<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"
"<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"\
"<b>Ciribob </b> <i>for the JTACAutoLase.lua script</i><br/>"
about = QMessageBox()
about.setWindowTitle("About DCS Liberation")

View File

@@ -3,10 +3,12 @@ from __future__ import unicode_literals
import datetime
from PySide2 import QtGui, QtWidgets
from PySide2.QtWidgets import QHBoxLayout, QVBoxLayout
from dcs.task import CAP, CAS
import qt_ui.uiconstants as CONST
from game import db, Game
from game.settings import Settings
from gen import namegen
from theater import start_generator, persiangulf, nevada, caucasus, ConflictTheater, normandy, thechannel
@@ -30,13 +32,12 @@ class NewGameWizard(QtWidgets.QWizard):
def accept(self):
blueFaction = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "blue"][self.field("blueFaction")]
redFaction = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "red"][self.field("redFaction")]
playerIsBlue = self.field("playerIsBlue")
blueFaction = [c for c in db.FACTIONS][self.field("blueFaction")]
redFaction = [c for c in db.FACTIONS][self.field("redFaction")]
isTerrainPg = self.field("isTerrainPg")
isTerrainNttr = self.field("isTerrainNttr")
isTerrainCaucasusSmall = self.field("isTerrainCaucasusSmall")
isTerrainCaucasusSmallInverted = self.field("isTerrainCaucasusSmallInverted")
isTerrainRussia = self.field("isTerrainRussia")
isTerrainCaucasusNorth= self.field("isTerrainCaucasusNorth")
isIranianCampaignTheater = self.field("isIranianCampaignTheater")
isTerrainNormandy = self.field("isTerrainNormandy")
@@ -47,9 +48,15 @@ class NewGameWizard(QtWidgets.QWizard):
timePeriod = db.TIME_PERIODS[list(db.TIME_PERIODS.keys())[self.field("timePeriod")]]
midGame = self.field("midGame")
multiplier = self.field("multiplier")
no_carrier = self.field("no_carrier")
no_lha = self.field("no_lha")
supercarrier = self.field("supercarrier")
no_player_navy = self.field("no_player_navy")
no_enemy_navy = self.field("no_enemy_navy")
invertMap = self.field("invertMap")
player_name = playerIsBlue and blueFaction or redFaction
enemy_name = playerIsBlue and redFaction or blueFaction
player_name = blueFaction
enemy_name = redFaction
if isTerrainPg:
conflicttheater = persiangulf.PersianGulfTheater()
@@ -57,8 +64,8 @@ class NewGameWizard(QtWidgets.QWizard):
conflicttheater = nevada.NevadaTheater()
elif isTerrainCaucasusSmall:
conflicttheater = caucasus.WesternGeorgia()
elif isTerrainCaucasusSmallInverted:
conflicttheater = caucasus.WesternGeorgiaInverted()
elif isTerrainRussia:
conflicttheater = caucasus.RussiaSmall()
elif isTerrainCaucasusNorth:
conflicttheater = caucasus.NorthCaucasus()
elif isIranianCampaignTheater:
@@ -76,20 +83,25 @@ class NewGameWizard(QtWidgets.QWizard):
else:
conflicttheater = caucasus.CaucasusTheater()
settings = Settings()
settings.inverted = invertMap
settings.supercarrier = supercarrier
settings.do_not_generate_carrier = no_carrier
settings.do_not_generate_lha = no_lha
settings.do_not_generate_player_navy = no_player_navy
settings.do_not_generate_enemy_navy = no_enemy_navy
self.generatedGame = self.start_new_game(player_name, enemy_name, conflicttheater, midGame, multiplier,
timePeriod)
timePeriod, settings)
super(NewGameWizard, self).accept()
def start_new_game(self, player_name: str, enemy_name: str, conflicttheater: ConflictTheater,
midgame: bool, multiplier: float, period: datetime):
if midgame:
for i in range(0, int(len(conflicttheater.controlpoints) / 2)):
conflicttheater.controlpoints[i].captured = True
midgame: bool, multiplier: float, period: datetime, settings:Settings):
# Reset name generator
namegen.reset()
start_generator.prepare_theater(conflicttheater, settings, midgame)
print("-- Starting New Game Generator")
print("Enemy name : " + enemy_name)
@@ -101,14 +113,15 @@ class NewGameWizard(QtWidgets.QWizard):
game = Game(player_name=player_name,
enemy_name=enemy_name,
theater=conflicttheater,
start_date=period)
start_date=period,
settings=settings)
print("-- Game Object generated")
start_generator.generate_groundobjects(conflicttheater, game)
game.budget = int(game.budget * multiplier)
game.settings.multiplier = multiplier
game.settings.sams = True
game.settings.version = "2.0RC9"
game.settings.version = "2.0.10"
if midgame:
game.budget = game.budget * 4 * len(list(conflicttheater.conflicts()))
@@ -140,59 +153,59 @@ class FactionSelection(QtWidgets.QWizardPage):
self.setTitle("Faction selection")
self.setSubTitle("\nChoose the two opposing factions and select the player side.")
self.setPixmap(QtWidgets.QWizard.LogoPixmap,
QtGui.QPixmap('./resources/ui/wizard/logo1.png'))
QtGui.QPixmap('./resources/ui/misc/generator.png'))
self.setMinimumHeight(250)
blues = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "blue"]
reds = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "red"]
# Factions selection
self.factionsGroup = QtWidgets.QGroupBox("Factions")
self.factionsGroupLayout = QtWidgets.QGridLayout()
# Create form
blueFaction = QtWidgets.QLabel("Blue Faction :")
blueFaction = QtWidgets.QLabel("<b>Player Faction :</b>")
self.blueFactionSelect = QtWidgets.QComboBox()
for f in blues:
for f in db.FACTIONS:
self.blueFactionSelect.addItem(f)
blueFaction.setBuddy(self.blueFactionSelect)
redFaction = QtWidgets.QLabel("Red Faction :")
redFaction = QtWidgets.QLabel("<b>Enemy Faction :</b>")
self.redFactionSelect = QtWidgets.QComboBox()
for r in reds:
for i, r in enumerate(db.FACTIONS):
self.redFactionSelect.addItem(r)
if r == "Russia 1990": # Default ennemy
self.redFactionSelect.setCurrentIndex(i)
redFaction.setBuddy(self.redFactionSelect)
sideGroup = QtWidgets.QGroupBox("Player Side")
blueforRadioButton = QtWidgets.QRadioButton("BLUEFOR")
redforRadioButton = QtWidgets.QRadioButton("REDFOR")
blueforRadioButton.setChecked(True)
# Unit Preview
self.blueSideRecap = QtWidgets.QLabel("")
self.blueSideRecap.setFont(QtGui.QFont("Arial", italic=True))
self.blueSideRecap.setFont(CONST.FONT_PRIMARY_I)
self.blueSideRecap.setWordWrap(True)
self.redSideRecap = QtWidgets.QLabel("")
self.redSideRecap.setFont(QtGui.QFont("Arial", italic=True))
self.redSideRecap.setFont(CONST.FONT_PRIMARY_I)
self.redSideRecap.setWordWrap(True)
self.factionsGroupLayout.addWidget(blueFaction, 0, 0)
self.factionsGroupLayout.addWidget(self.blueFactionSelect, 0, 1)
self.factionsGroupLayout.addWidget(self.blueSideRecap, 1, 0, 1, 2)
self.factionsGroupLayout.addWidget(redFaction, 2, 0)
self.factionsGroupLayout.addWidget(self.redFactionSelect, 2, 1)
self.factionsGroupLayout.addWidget(self.redSideRecap, 3, 0, 1, 2)
self.factionsGroup.setLayout(self.factionsGroupLayout)
# Create required mod layout
self.requiredModsGroup = QtWidgets.QGroupBox("Required Mods")
self.requiredModsGroupLayout = QtWidgets.QHBoxLayout()
self.requiredMods = QtWidgets.QLabel("<ul><li>None</li></ul>")
self.requiredModsGroupLayout.addWidget(self.requiredMods)
self.requiredModsGroup.setLayout(self.requiredModsGroupLayout)
# Link form fields
self.registerField('blueFaction', self.blueFactionSelect)
self.registerField('redFaction', self.redFactionSelect)
self.registerField('playerIsBlue', blueforRadioButton)
self.registerField('playerIsRed', redforRadioButton)
# Build layout
sideGroupLayout = QtWidgets.QVBoxLayout()
sideGroupLayout.addWidget(blueforRadioButton)
sideGroupLayout.addWidget(redforRadioButton)
sideGroup.setLayout(sideGroupLayout)
layout = QtWidgets.QGridLayout()
layout.addWidget(blueFaction, 0, 0)
layout.addWidget(self.blueFactionSelect, 0, 1)
layout.addWidget(self.blueSideRecap, 1, 0, 1, 2)
layout.addWidget(redFaction, 2, 0)
layout.addWidget(self.redFactionSelect, 2, 1)
layout.addWidget(self.redSideRecap, 3, 0, 1, 2)
layout.addWidget(sideGroup, 4, 0, 1, 2)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.factionsGroup)
layout.addWidget(self.requiredModsGroup)
self.setLayout(layout)
self.updateUnitRecap()
@@ -200,8 +213,14 @@ class FactionSelection(QtWidgets.QWizardPage):
self.redFactionSelect.activated.connect(self.updateUnitRecap)
def updateUnitRecap(self):
red_units = db.FACTIONS[self.redFactionSelect.currentText()]["units"]
blue_units = db.FACTIONS[self.blueFactionSelect.currentText()]["units"]
self.requiredMods.setText("<ul>")
red_faction = db.FACTIONS[self.redFactionSelect.currentText()]
blue_faction = db.FACTIONS[self.blueFactionSelect.currentText()]
red_units = red_faction["units"]
blue_units = blue_faction["units"]
blue_txt = ""
for u in blue_units:
@@ -217,6 +236,23 @@ class FactionSelection(QtWidgets.QWizardPage):
red_txt = red_txt + "\n"
self.redSideRecap.setText(red_txt)
has_mod = False
if "requirements" in red_faction.keys():
has_mod = True
for mod in red_faction["requirements"].keys():
self.requiredMods.setText(self.requiredMods.text() + "\n<li>" + mod + ": <a href=\""+red_faction["requirements"][mod]+"\">" + red_faction["requirements"][mod] + "</a></li>")
if "requirements" in blue_faction.keys():
has_mod = True
for mod in blue_faction["requirements"].keys():
if not "requirements" in red_faction.keys() or mod not in red_faction["requirements"].keys():
self.requiredMods.setText(self.requiredMods.text() + "\n<li>" + mod + ": <a href=\""+blue_faction["requirements"][mod]+"\">" + blue_faction["requirements"][mod] + "</a></li>")
if has_mod:
self.requiredMods.setText(self.requiredMods.text() + "</ul>\n\n")
else:
self.requiredMods.setText(self.requiredMods.text() + "<li>None</li></ul>\n")
class TheaterConfiguration(QtWidgets.QWizardPage):
def __init__(self, parent=None):
@@ -227,24 +263,27 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
self.setPixmap(QtWidgets.QWizard.LogoPixmap,
QtGui.QPixmap('./resources/ui/wizard/logo1.png'))
self.setPixmap(QtWidgets.QWizard.WatermarkPixmap,
QtGui.QPixmap('./resources/ui/wizard/watermark3.png'))
# Terrain selection
terrainGroup = QtWidgets.QGroupBox("Terrain")
terrainCaucasusSmall = QtWidgets.QRadioButton("Caucasus - Western Georgia [RECOMMENDED - Early Cold War Era]")
terrainCaucasusSmall = QtWidgets.QRadioButton("Caucasus - Western Georgia")
terrainCaucasusSmall.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
terrainCaucasusSmallInverted = QtWidgets.QRadioButton("Caucasus - Western Georgia Inverted [RECOMMENDED - Early Cold War Era]")
terrainCaucasusSmallInverted.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
terrainCaucasus = QtWidgets.QRadioButton("Caucasus - Full map [NOT TESTED]")
terrainRussia = QtWidgets.QRadioButton("Caucasus - Russia Small")
terrainRussia.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
terrainCaucasus = QtWidgets.QRadioButton("Caucasus - Full map [NOT RECOMMENDED]")
terrainCaucasus.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
terrainCaucasusNorth = QtWidgets.QRadioButton("Caucasus - North - [RECOMMENDED - Modern Era]")
terrainCaucasusNorth = QtWidgets.QRadioButton("Caucasus - North")
terrainCaucasusNorth.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
terrainPg = QtWidgets.QRadioButton("Persian Gulf - Full Map [NOT TESTED]")
terrainPg = QtWidgets.QRadioButton("Persian Gulf - Full Map [NOT RECOMMENDED]")
terrainPg.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Persian_Gulf"]))
terrainIran = QtWidgets.QRadioButton("Persian Gulf - Invasion of Iran [RECOMMENDED]")
terrainIran = QtWidgets.QRadioButton("Persian Gulf - Invasion of Iran")
terrainIran.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Persian_Gulf"]))
terrainEmirates = QtWidgets.QRadioButton("Persian Gulf - Emirates [RECOMMENDED]")
terrainEmirates = QtWidgets.QRadioButton("Persian Gulf - Emirates")
terrainEmirates.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Persian_Gulf"]))
terrainNttr = QtWidgets.QRadioButton("Nevada - North Nevada [RECOMMENDED]")
terrainNttr = QtWidgets.QRadioButton("Nevada - North Nevada")
terrainNttr.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Nevada"]))
terrainNormandy = QtWidgets.QRadioButton("Normandy")
terrainNormandy.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Normandy"]))
@@ -256,6 +295,15 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
terrainChannelComplete.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Channel"]))
terrainCaucasusSmall.setChecked(True)
# Campaign settings
mapSettingsGroup = QtWidgets.QGroupBox("Map Settings")
invertMap = QtWidgets.QCheckBox()
self.registerField('invertMap', invertMap)
mapSettingsLayout = QtWidgets.QGridLayout()
mapSettingsLayout.addWidget(QtWidgets.QLabel("Invert Map"), 1, 0)
mapSettingsLayout.addWidget(invertMap, 1, 1)
mapSettingsGroup.setLayout(mapSettingsLayout)
# Time Period
timeGroup = QtWidgets.QGroupBox("Time Period")
timePeriod = QtWidgets.QLabel("Start date :")
@@ -268,7 +316,7 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
# Register fields
self.registerField('isTerrainCaucasus', terrainCaucasus)
self.registerField('isTerrainCaucasusSmall', terrainCaucasusSmall)
self.registerField('isTerrainCaucasusSmallInverted', terrainCaucasusSmallInverted)
self.registerField('isTerrainRussia', terrainRussia)
self.registerField('isTerrainCaucasusNorth', terrainCaucasusNorth)
self.registerField('isTerrainPg', terrainPg)
self.registerField('isIranianCampaignTheater', terrainIran)
@@ -283,7 +331,7 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
# Build layout
terrainGroupLayout = QtWidgets.QVBoxLayout()
terrainGroupLayout.addWidget(terrainCaucasusSmall)
terrainGroupLayout.addWidget(terrainCaucasusSmallInverted)
terrainGroupLayout.addWidget(terrainRussia)
terrainGroupLayout.addWidget(terrainCaucasusNorth)
terrainGroupLayout.addWidget(terrainCaucasus)
terrainGroupLayout.addWidget(terrainIran)
@@ -303,8 +351,9 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
layout = QtWidgets.QGridLayout()
layout.setColumnMinimumWidth(0, 20)
layout.addWidget(terrainGroup)
layout.addWidget(timeGroup)
layout.addWidget(terrainGroup, 0, 0, 3, 1)
layout.addWidget(mapSettingsGroup, 0, 1, 1, 1)
layout.addWidget(timeGroup, 1, 1, 1, 1)
self.setLayout(layout)
@@ -323,15 +372,47 @@ class MiscOptions(QtWidgets.QWizardPage):
multiplier.setMinimum(1)
multiplier.setMaximum(5)
miscSettingsGroup = QtWidgets.QGroupBox("Misc Settings")
self.registerField('midGame', midGame)
self.registerField('multiplier', multiplier)
# Campaign settings
generatorSettingsGroup = QtWidgets.QGroupBox("Generator Settings")
no_carrier = QtWidgets.QCheckBox()
self.registerField('no_carrier', no_carrier)
no_lha = QtWidgets.QCheckBox()
self.registerField('no_lha', no_lha)
supercarrier = QtWidgets.QCheckBox()
self.registerField('supercarrier', supercarrier)
no_player_navy= QtWidgets.QCheckBox()
self.registerField('no_player_navy', no_player_navy)
no_enemy_navy = QtWidgets.QCheckBox()
self.registerField('no_enemy_navy', no_enemy_navy)
generatorLayout = QtWidgets.QGridLayout()
generatorLayout.addWidget(QtWidgets.QLabel("No Aircraft Carriers"), 1, 0)
generatorLayout.addWidget(no_carrier, 1, 1)
generatorLayout.addWidget(QtWidgets.QLabel("No LHA"), 2, 0)
generatorLayout.addWidget(no_lha, 2, 1)
generatorLayout.addWidget(QtWidgets.QLabel("Use Supercarrier module"), 3, 0)
generatorLayout.addWidget(supercarrier, 3, 1)
generatorLayout.addWidget(QtWidgets.QLabel("No Player Navy"), 4, 0)
generatorLayout.addWidget(no_player_navy, 4, 1)
generatorLayout.addWidget(QtWidgets.QLabel("No Enemy Navy"), 5, 0)
generatorLayout.addWidget(no_enemy_navy, 5, 1)
generatorSettingsGroup.setLayout(generatorLayout)
layout = QtWidgets.QGridLayout()
layout.addWidget(QtWidgets.QLabel("Start at mid game"), 1, 0)
layout.addWidget(midGame, 1, 1)
layout.addWidget(QtWidgets.QLabel("Ennemy forces multiplier [Disabled for Now]"), 2, 0)
layout.addWidget(multiplier, 2, 1)
self.setLayout(layout)
miscSettingsGroup.setLayout(layout)
mlayout = QVBoxLayout()
mlayout.addWidget(miscSettingsGroup)
mlayout.addWidget(generatorSettingsGroup)
self.setLayout(mlayout)
class ConclusionPage(QtWidgets.QWizardPage):

View File

@@ -1,15 +1,18 @@
import json
import os
from PySide2 import QtCore
from PySide2.QtCore import QObject, Signal
from PySide2.QtGui import QMovie, QIcon
from PySide2.QtWidgets import QLabel, QDialog, QVBoxLayout, QGroupBox, QGridLayout, QPushButton
from PySide2.QtCore import QObject, Signal, Qt
from PySide2.QtGui import QMovie, QIcon, QPixmap
from PySide2.QtWidgets import QLabel, QDialog, QGroupBox, QGridLayout, QPushButton, QFileDialog, QMessageBox, QTextEdit, \
QHBoxLayout
from game.game import Event, Game
from game.game import Event, Game, logging
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from userdata.debriefing import wait_for_debriefing, Debriefing
from userdata.persistency import base_path
class DebriefingFileWrittenSignal(QObject):
instance = None
@@ -36,48 +39,87 @@ class QWaitingForMissionResultWindow(QDialog):
self.gameEvent = gameEvent
self.game = game
self.setWindowTitle("Waiting for mission completion.")
self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)
self.setWindowIcon(QIcon("./resources/icon.png"))
self.setMinimumHeight(570)
self.initUi()
DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect(self.updateLayout)
wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game)
self.wait_thread = wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game)
def initUi(self):
self.layout = QGridLayout()
header = QLabel(self)
header.setGeometry(0, 0, 655, 106)
pixmap = QPixmap("./resources/ui/conflict.png")
header.setPixmap(pixmap)
self.layout.addWidget(header, 0, 0)
self.gridLayout = QGridLayout()
self.gridLayout.addWidget(QLabel("<b>You are clear for takeoff</b>"), 1, 0)
self.gridLayout.addWidget(QLabel(""), 2, 0)
self.gridLayout.addWidget(QLabel("<h2>For Singleplayer :</h2>"), 3, 0)
self.gridLayout.addWidget(QLabel("In DCS, open the Mission Editor, and load the file : "), 4, 0)
self.gridLayout.addWidget(QLabel("<i>liberation_nextturn</i>"), 5, 0)
self.gridLayout.addWidget(QLabel("Then once the mission is loaded in ME, in menu \"Flight\", click on FLY Mission to launch"), 6, 0)
self.gridLayout.addWidget(QLabel(""), 7, 0)
self.gridLayout.addWidget(QLabel("<h2>For Multiplayer :</h2>"), 8, 0)
self.gridLayout.addWidget(QLabel("In DCS, open the Mission Editor, and load the file : "), 9, 0)
self.gridLayout.addWidget(QLabel("<i>liberation_nextturn</i>"), 10, 0)
self.gridLayout.addWidget(QLabel("Click on File/Save. Then exit the mission editor, and go to Multiplayer."), 11, 0)
self.gridLayout.addWidget(QLabel("Then host a server with the mission, and tell your friends to join !"), 12, 0)
self.gridLayout.addWidget(QLabel("(The step in the mission editor is important, and fix a game breaking bug.)"), 13, 0)
self.gridLayout.addWidget(QLabel(""), 14, 0)
TEXT = "" + \
"<b>You are clear for takeoff</b>" + \
"" + \
"<h2>For Singleplayer :</h2>\n" + \
"In DCS, open the Mission Editor, and load the file : \n" + \
"<i>liberation_nextturn</i>\n" + \
"<p>Then once the mission is loaded in ME, in menu \"Flight\",\n" + \
"click on FLY Mission to launch.</p>\n" + \
"" + \
"<h2>For Multiplayer :</h2>" + \
"In DCS, open the Mission Editor, and load the file : " + \
"<i>liberation_nextturn</i>" + \
"<p>Click on File/Save. Then exit the mission editor, and go to Multiplayer.</p>" + \
"<p>Then host a server with the mission, and tell your friends to join !</p>" + \
"<i>(The step in the mission editor is important, and fix a game breaking bug.)</i>" + \
"<h2>Finishing</h2>" + \
"<p>Once you have played the mission, click on the \"Accept Results\" button.</p>" + \
"<p>If DCS Liberation does not detect mission end, use the manually submit button, and choose the state.json file.</p>"
self.instructions_text = QTextEdit(TEXT)
self.instructions_text.setReadOnly(True)
self.gridLayout.addWidget(self.instructions_text, 1, 0)
progress = QLabel("")
progress.setAlignment(QtCore.Qt.AlignCenter)
progressBar = QMovie("./resources/ui/loader.gif")
progress.setMovie(progressBar)
self.gridLayout.addWidget(progress, 15, 0)
self.gridLayout.addWidget(QLabel(""), 16, 0)
self.gridLayout.addWidget(QLabel("Once you have played the mission, this window will dissapear."), 17, 0)
self.gridLayout.addWidget(QLabel("You will have to click on \"Accept Results\" to proceed"), 18, 0)
progress_bar = QMovie("./resources/ui/loader.gif")
progress.setMovie(progress_bar)
progressBar.start()
self.layout.addLayout(self.gridLayout,0,0)
self.actions = QGroupBox("Actions :")
self.actions_layout = QHBoxLayout()
self.actions.setLayout(self.actions_layout)
self.manually_submit = QPushButton("Manually Submit [Advanced users]")
self.manually_submit.clicked.connect(self.submit_manually)
self.actions_layout.addWidget(self.manually_submit)
self.cancel = QPushButton("Abort mission")
self.cancel.clicked.connect(self.close)
self.actions_layout.addWidget(self.cancel)
self.gridLayout.addWidget(self.actions, 2, 0)
self.actions2 = QGroupBox("Actions :")
self.actions2_layout = QHBoxLayout()
self.actions2.setLayout(self.actions2_layout)
self.manually_submit2 = QPushButton("Manually Submit [Advanced users]")
self.manually_submit2.clicked.connect(self.submit_manually)
self.actions2_layout.addWidget(self.manually_submit2)
self.cancel2 = QPushButton("Abort mission")
self.cancel2.clicked.connect(self.close)
self.actions2_layout.addWidget(self.cancel2)
self.proceed = QPushButton("Accept results")
self.proceed.setProperty("style", "btn-success")
self.proceed.clicked.connect(self.process_debriefing)
self.actions2_layout.addWidget(self.proceed)
progress_bar.start()
self.layout.addLayout(self.gridLayout, 1, 0)
self.setLayout(self.layout)
def updateLayout(self, debriefing):
updateBox = QGroupBox("Mission status")
updateLayout = QGridLayout()
updateBox.setLayout(updateLayout)
self.debriefing = debriefing
updateLayout.addWidget(QLabel("<b>Aircrafts destroyed</b>"), 0, 0)
updateLayout.addWidget(QLabel(str(len(debriefing.killed_aircrafts))), 0, 1)
@@ -85,40 +127,72 @@ class QWaitingForMissionResultWindow(QDialog):
updateLayout.addWidget(QLabel("<b>Ground units destroyed</b>"), 1, 0)
updateLayout.addWidget(QLabel(str(len(debriefing.killed_ground_units))), 1, 1)
updateLayout.addWidget(QLabel("<b>Weapons fired</b>"), 2, 0)
updateLayout.addWidget(QLabel(str(len(debriefing.weapons_fired))), 2, 1)
#updateLayout.addWidget(QLabel("<b>Weapons fired</b>"), 2, 0)
#updateLayout.addWidget(QLabel(str(len(debriefing.weapons_fired))), 2, 1)
updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 3, 0)
updateLayout.addWidget(QLabel(str(len(debriefing.base_capture_events))), 3, 1)
updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 2, 0)
updateLayout.addWidget(QLabel(str(len(debriefing.base_capture_events))), 2, 1)
# Clear previous content of the window
for i in reversed(range(self.gridLayout.count())):
self.gridLayout.itemAt(i).widget().setParent(None)
try:
self.gridLayout.itemAt(i).widget().setParent(None)
except:
pass
# Set new window content
self.gridLayout.addWidget(updateBox, 0, 0)
if not debriefing.mission_ended:
self.gridLayout.addWidget(QLabel("<b>Mission is being played</b>"), 1, 0)
self.gridLayout.addWidget(self.actions, 2, 0)
else:
#self.gridLayout.addWidget(QLabel("<b>Mission is over !</b>"), 1, 0)
proceed = QPushButton("Accept results")
proceed.setProperty("style", "btn-primary")
proceed.clicked.connect(lambda: self.process_debriefing(debriefing))
self.gridLayout.addWidget(proceed, 1, 0)
self.gridLayout.addWidget(QLabel("<b>Mission is over</b>"), 1, 0)
self.gridLayout.addWidget(self.actions2, 2, 0)
def on_debriefing_udpate(self, debriefing):
print("On Debriefing update")
print(debriefing)
DebriefingFileWrittenSignal.get_instance().sendDebriefing(debriefing)
wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game)
try:
logging.info("On Debriefing update")
print(debriefing)
DebriefingFileWrittenSignal.get_instance().sendDebriefing(debriefing)
except Exception as e:
logging.error("Got an error while sending debriefing")
logging.error(e)
self.wait_thread = wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game)
def process_debriefing(self, debriefing: Debriefing):
self.game.finish_event(event=self.gameEvent, debriefing=debriefing)
def process_debriefing(self):
self.game.finish_event(event=self.gameEvent, debriefing=self.debriefing)
self.game.pass_turn(ignored_cps=[self.gameEvent.to_cp, ])
GameUpdateSignal.get_instance().sendDebriefing(self.game, self.gameEvent, debriefing)
GameUpdateSignal.get_instance().sendDebriefing(self.game, self.gameEvent, self.debriefing)
self.close()
def debriefing_directory_location(self) -> str:
return os.path.join(base_path(), "liberation_debriefings")
def closeEvent(self, evt):
super(QWaitingForMissionResultWindow, self).closeEvent(evt)
if self.wait_thread is not None:
self.wait_thread.stop()
def submit_manually(self):
file = QFileDialog.getOpenFileName(self, "Select game file to open", filter="json(*.json)", dir=".")
print(file)
try:
with open(file[0], "r") as json_file:
json_data = json.load(json_file)
json_data["mission_ended"] = True
debriefing = Debriefing(json_data, self.game)
self.on_debriefing_udpate(debriefing)
except Exception as e:
logging.error(e)
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("Invalid file : " + file[0])
msg.setWindowTitle("Invalid file.")
msg.setStandardButtons(QMessageBox.Ok)
msg.setWindowFlags(Qt.WindowStaysOnTopHint)
msg.exec_()
return

View File

@@ -1,246 +0,0 @@
import traceback
from PySide2.QtCore import Qt
from PySide2.QtGui import QCloseEvent
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QVBoxLayout, QGridLayout, QPushButton, \
QGroupBox, QSizePolicy, QSpacerItem
from dcs.unittype import UnitType
from game.event import UnitsDeliveryEvent, ControlPointType
from qt_ui.widgets.QBudgetBox import QBudgetBox
from qt_ui.widgets.base.QAirportInformation import QAirportInformation
from qt_ui.windows.basemenu.base_defenses.QBaseInformation import QBaseInformation
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from theater import ControlPoint, CAP, Embarking, CAS, PinpointStrike, db
from game import Game
class QBaseMenu(QDialog):
def __init__(self, parent, controlPoint: ControlPoint, game: Game):
super(QBaseMenu, self).__init__(parent)
self.cp = controlPoint
self.game = game
self.is_carrier = self.cp.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]
try:
self.airport = game.theater.terrain.airport_by_id(self.cp.id)
except:
self.airport = None
if self.cp.captured:
self.deliveryEvent = None
for event in self.game.events:
print(event.__class__)
print(UnitsDeliveryEvent.__class__)
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
self.deliveryEvent = event
break
if not self.deliveryEvent:
print("Rebuild event")
self.deliveryEvent = self.game.units_delivery_event(self.cp)
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMinimumSize(300, 200)
self.setModal(True)
self.initUi()
def initUi(self):
self.setWindowTitle(self.cp.name)
self.topLayoutWidget = QWidget()
self.topLayout = QHBoxLayout()
title = QLabel("<b>" + self.cp.name + "</b>")
title.setAlignment(Qt.AlignLeft | Qt.AlignTop)
title.setProperty("style", "base-title")
unitsPower = QLabel("{} / {} / Runway : {}".format(self.cp.base.total_planes, self.cp.base.total_armor,
"Available" if self.cp.has_runway() else "Unavailable"))
self.topLayout.addWidget(title)
self.topLayout.addWidget(unitsPower)
self.topLayout.setAlignment(Qt.AlignTop)
self.topLayoutWidget.setProperty("style", "baseMenuHeader")
self.topLayoutWidget.setLayout(self.topLayout)
if self.cp.captured:
units = {
CAP: db.find_unittype(CAP, self.game.player_name),
Embarking: db.find_unittype(Embarking, self.game.player_name),
CAS: db.find_unittype(CAS, self.game.player_name),
PinpointStrike: db.find_unittype(PinpointStrike, self.game.player_name),
}
else:
units = {
CAP: db.find_unittype(CAP, self.game.enemy_name),
Embarking: db.find_unittype(Embarking, self.game.enemy_name),
CAS: db.find_unittype(CAS, self.game.enemy_name),
PinpointStrike: db.find_unittype(PinpointStrike, self.game.enemy_name),
}
self.mainLayout = QGridLayout()
self.leftLayout = QVBoxLayout()
self.unitLayout = QVBoxLayout()
self.bought_amount_labels = {}
self.existing_units_labels = {}
row = 0
if self.cp.captured:
self.recruitment = QGroupBox("Recruitment")
self.recruitmentLayout = QVBoxLayout()
self.budget = QBudgetBox()
self.budget.setBudget(self.game.budget, self.game.budget_reward_amount)
self.recruitmentLayout.addWidget(self.budget)
for task_type in units.keys():
if task_type == PinpointStrike and self.is_carrier:
continue
units_column = list(set(units[task_type]))
if len(units_column) == 0: continue
units_column.sort(key=lambda x: db.PRICES[x])
task_box = QGroupBox("{}".format(db.task_name(task_type)))
task_box_layout = QGridLayout()
task_box.setLayout(task_box_layout)
row = 0
for unit_type in units_column:
if self.is_carrier and not unit_type in db.CARRIER_CAPABLE:
continue
row = self.add_purchase_row(unit_type, task_box_layout, row)
stretch = QVBoxLayout()
stretch.addStretch()
task_box_layout.addLayout(stretch, row, 0)
self.recruitmentLayout.addWidget(task_box)
self.recruitmentLayout.addStretch()
self.recruitment.setLayout(self.recruitmentLayout)
self.leftLayout.addWidget(self.recruitment)
self.leftLayout.addStretch()
else:
intel = QGroupBox("Intel")
intelLayout = QVBoxLayout()
for task_type in units.keys():
units_column = list(set(units[task_type]))
if sum([self.cp.base.total_units_of_type(u) for u in units_column]) > 0:
group = QGroupBox(db.task_name(task_type))
groupLayout = QGridLayout()
group.setLayout(groupLayout)
row = 0
for unit_type in units_column:
existing_units = self.cp.base.total_units_of_type(unit_type)
if existing_units == 0:
continue
groupLayout.addWidget(QLabel("<b>" + db.unit_type_name(unit_type) + "</b>"), row, 0)
groupLayout.addWidget(QLabel(str(existing_units)), row, 1)
row += 1
intelLayout.addWidget(group)
intelLayout.addStretch()
intel.setLayout(intelLayout)
self.leftLayout.addWidget(intel)
self.mainLayout.addWidget(self.topLayoutWidget, 0, 0)
self.mainLayout.addLayout(self.leftLayout, 1, 0)
self.mainLayout.addWidget(QBaseInformation(self.cp, self.airport), 1, 1)
self.rightLayout = QVBoxLayout()
try:
self.rightLayout.addWidget(QPlannedFlightsView(self.game.planners[self.cp.id]))
except Exception:
traceback.print_exc()
if self.airport:
self.rightLayout.addWidget(QAirportInformation(self.cp, self.airport))
self.mainLayout.addLayout(self.rightLayout, 1, 2)
self.setLayout(self.mainLayout)
def add_purchase_row(self, unit_type, layout, row):
existing_units = self.cp.base.total_units_of_type(unit_type)
scheduled_units = self.deliveryEvent.units.get(unit_type, 0)
unitName = QLabel("<b>" + db.unit_type_name(unit_type) + "</b>")
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
existing_units = QLabel(str(existing_units))
existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
amount_bought = QLabel("[{}]".format(str(scheduled_units)))
amount_bought.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
self.existing_units_labels[unit_type] = existing_units
self.bought_amount_labels[unit_type] = amount_bought
price = QLabel("{}m".format(db.PRICES[unit_type]))
price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
buy = QPushButton("+")
buy.setProperty("style", "btn-success")
buy.setMinimumSize(24, 24)
buy.clicked.connect(lambda: self.buy(unit_type))
buy.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell = QPushButton("-")
sell.setProperty("style", "btn-danger")
sell.setMinimumSize(24, 24)
sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell.clicked.connect(lambda: self.sell(unit_type))
layout.addWidget(unitName, row, 0)
layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), row, 1)
layout.addWidget(existing_units, row, 2)
layout.addWidget(amount_bought, row, 3)
layout.addWidget(price, row, 4)
layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), row, 5)
layout.addWidget(buy, row, 6)
layout.addWidget(sell, row, 7)
return row + 1
def _update_count_label(self, unit_type: UnitType):
self.bought_amount_labels[unit_type].setText("[{}]".format(
unit_type in self.deliveryEvent.units and "{}".format(self.deliveryEvent.units[unit_type]) or "0"
))
self.existing_units_labels[unit_type].setText("{}".format(
self.cp.base.total_units_of_type(unit_type)
))
def buy(self, unit_type):
price = db.PRICES[unit_type]
if self.game.budget >= price:
self.deliveryEvent.deliver({unit_type: 1})
self.game.budget -= price
self.budget.setBudget(self.game.budget, self.game.budget_reward_amount)
self._update_count_label(unit_type)
def sell(self, unit_type):
if self.deliveryEvent.units.get(unit_type, 0) > 0:
price = db.PRICES[unit_type]
self.game.budget += price
self.deliveryEvent.units[unit_type] = self.deliveryEvent.units[unit_type] - 1
if self.deliveryEvent.units[unit_type] == 0:
del self.deliveryEvent.units[unit_type]
elif self.cp.base.total_units_of_type(unit_type) > 0:
price = db.PRICES[unit_type]
self.game.budget += price
self.cp.base.commit_losses({unit_type: 1})
self._update_count_label(unit_type)
def closeEvent(self, closeEvent:QCloseEvent):
GameUpdateSignal.get_instance().updateGame(self.game)

View File

@@ -1,5 +1,5 @@
from PySide2.QtCore import Qt
from PySide2.QtGui import QCloseEvent
from PySide2.QtGui import QCloseEvent, QPixmap
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QGridLayout
from game import Game
@@ -35,6 +35,8 @@ class QBaseMenu2(QDialog):
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMinimumSize(300, 200)
self.setMinimumWidth(800)
self.setMaximumWidth(800)
self.setModal(True)
self.initUi()
@@ -46,6 +48,11 @@ class QBaseMenu2(QDialog):
self.topLayoutWidget = QWidget()
self.topLayout = QHBoxLayout()
header = QLabel(self)
header.setGeometry(0, 0, 655, 106)
pixmap = QPixmap(self.get_base_image())
header.setPixmap(pixmap)
title = QLabel("<b>" + self.cp.name + "</b>")
title.setAlignment(Qt.AlignLeft | Qt.AlignTop)
title.setProperty("style", "base-title")
@@ -59,10 +66,19 @@ class QBaseMenu2(QDialog):
self.topLayoutWidget.setLayout(self.topLayout)
self.mainLayout = QGridLayout()
self.mainLayout.addWidget(self.topLayoutWidget, 0, 0)
self.mainLayout.addWidget(self.qbase_menu_tab, 1, 0)
self.mainLayout.addWidget(header, 0, 0)
self.mainLayout.addWidget(self.topLayoutWidget, 1, 0)
self.mainLayout.addWidget(self.qbase_menu_tab, 2, 0)
self.setLayout(self.mainLayout)
def closeEvent(self, closeEvent:QCloseEvent):
GameUpdateSignal.get_instance().updateGame(self.game)
GameUpdateSignal.get_instance().updateGame(self.game)
def get_base_image(self):
if self.cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP:
return "./resources/ui/carrier.png"
elif self.cp.cptype == ControlPointType.LHA_GROUP:
return "./resources/ui/lha.png"
else:
return "./resources/ui/airbase.png"

View File

@@ -1,5 +1,5 @@
from PySide2.QtWidgets import QLabel, QPushButton, \
QSizePolicy, QSpacerItem
QSizePolicy, QSpacerItem, QGroupBox, QHBoxLayout
from dcs.unittype import UnitType
from theater import db
@@ -19,54 +19,75 @@ class QRecruitBehaviour:
def add_purchase_row(self, unit_type, layout, row):
exist = QGroupBox()
exist.setProperty("style", "buy-box")
exist.setMaximumHeight(36)
exist.setMinimumHeight(36)
existLayout = QHBoxLayout()
exist.setLayout(existLayout)
existing_units = self.cp.base.total_units_of_type(unit_type)
scheduled_units = self.deliveryEvent.units.get(unit_type, 0)
unitName = QLabel("<b>" + db.unit_type_name(unit_type) + "</b>")
unitName = QLabel("<b>" + db.unit_type_name_2(unit_type) + "</b>")
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
existing_units = QLabel(str(existing_units))
existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
amount_bought = QLabel("[{}]".format(str(scheduled_units)))
amount_bought = QLabel("<b>{}</b>".format(str(scheduled_units)))
amount_bought.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
self.existing_units_labels[unit_type] = existing_units
self.bought_amount_labels[unit_type] = amount_bought
price = QLabel("{}m".format(db.PRICES[unit_type]))
price = QLabel("<b>$ {:02d}</b> m".format(db.PRICES[unit_type]))
price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
buysell = QGroupBox()
buysell.setProperty("style", "buy-box")
buysell.setMaximumHeight(36)
buysell.setMinimumHeight(36)
buysellayout = QHBoxLayout()
buysell.setLayout(buysellayout)
buy = QPushButton("+")
buy.setProperty("style", "btn-success")
buy.setMinimumSize(24, 24)
buy.setProperty("style", "btn-buy")
buy.setMinimumSize(16, 16)
buy.setMaximumSize(16, 16)
buy.clicked.connect(lambda: self.buy(unit_type))
buy.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell = QPushButton("-")
sell.setProperty("style", "btn-danger")
sell.setMinimumSize(24, 24)
sell.setProperty("style", "btn-sell")
sell.setMinimumSize(16, 16)
sell.setMaximumSize(16, 16)
sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell.clicked.connect(lambda: self.sell(unit_type))
layout.addWidget(unitName, row, 0)
layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), row, 1)
layout.addWidget(existing_units, row, 2)
layout.addWidget(amount_bought, row, 3)
layout.addWidget(price, row, 4)
layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), row, 5)
layout.addWidget(buy, row, 6)
layout.addWidget(sell, row, 7)
existLayout.addWidget(unitName)
existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
existLayout.addWidget(existing_units)
existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
existLayout.addWidget(price)
buysellayout.addWidget(sell)
buysellayout.addWidget(amount_bought)
buysellayout.addWidget(buy)
layout.addWidget(exist, row, 1)
layout.addWidget(buysell, row, 2)
return row + 1
def _update_count_label(self, unit_type: UnitType):
self.bought_amount_labels[unit_type].setText("[{}]".format(
self.bought_amount_labels[unit_type].setText("<b>{}</b>".format(
unit_type in self.deliveryEvent.units and "{}".format(self.deliveryEvent.units[unit_type]) or "0"
))
self.existing_units_labels[unit_type].setText("{}".format(
self.existing_units_labels[unit_type].setText("<b>{}</b>".format(
self.cp.base.total_units_of_type(unit_type)
))

View File

@@ -1,4 +1,5 @@
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox, QScrollArea, QFrame, QWidget
from game.event import UnitsDeliveryEvent
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
@@ -6,10 +7,10 @@ from theater import ControlPoint, CAP, CAS, db
from game import Game
class QAircraftRecruitmentMenu(QGroupBox, QRecruitBehaviour):
class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
def __init__(self, cp:ControlPoint, game:Game):
QGroupBox.__init__(self, "Recruitment")
QFrame.__init__(self)
self.cp = cp
self.game = game
@@ -25,13 +26,14 @@ class QAircraftRecruitmentMenu(QGroupBox, QRecruitBehaviour):
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
main_layout = QVBoxLayout()
units = {
CAP: db.find_unittype(CAP, self.game.player_name),
CAS: db.find_unittype(CAS, self.game.player_name),
}
scroll_content = QWidget()
task_box_layout = QGridLayout()
row = 0
@@ -49,6 +51,11 @@ class QAircraftRecruitmentMenu(QGroupBox, QRecruitBehaviour):
stretch.addStretch()
task_box_layout.addLayout(stretch, row, 0)
layout.addLayout(task_box_layout)
layout.addStretch()
self.setLayout(layout)
scroll_content.setLayout(task_box_layout)
scroll = QScrollArea()
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setWidgetResizable(True)
scroll.setWidget(scroll_content)
main_layout.addWidget(scroll)
self.setLayout(main_layout)

View File

@@ -1,4 +1,5 @@
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox, QFrame, QWidget, QScrollArea
from game import Game
from game.event import UnitsDeliveryEvent
@@ -6,10 +7,10 @@ from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
from theater import ControlPoint, PinpointStrike, db
class QArmorRecruitmentMenu(QGroupBox, QRecruitBehaviour):
class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
def __init__(self, cp:ControlPoint, game:Game):
QGroupBox.__init__(self, "Recruitment")
QFrame.__init__(self)
self.cp = cp
self.game = game
@@ -25,13 +26,15 @@ class QArmorRecruitmentMenu(QGroupBox, QRecruitBehaviour):
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
main_layout = QVBoxLayout()
units = {
PinpointStrike: db.find_unittype(PinpointStrike, self.game.player_name),
}
scroll_content = QWidget()
task_box_layout = QGridLayout()
scroll_content.setLayout(task_box_layout)
row = 0
for task_type in units.keys():
@@ -44,6 +47,11 @@ class QArmorRecruitmentMenu(QGroupBox, QRecruitBehaviour):
stretch.addStretch()
task_box_layout.addLayout(stretch, row, 0)
layout.addLayout(task_box_layout)
layout.addStretch()
self.setLayout(layout)
scroll_content.setLayout(task_box_layout)
scroll = QScrollArea()
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setWidgetResizable(True)
scroll.setWidget(scroll_content)
main_layout.addWidget(scroll)
self.setLayout(main_layout)

View File

@@ -22,7 +22,7 @@ class QInfoPanel(QGroupBox):
layout = QVBoxLayout()
layout.addWidget(self.informations_list)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
layout.setContentsMargins(0, 20, 0, 0)
self.setLayout(layout)

View File

@@ -16,7 +16,7 @@ class QMissionPlanning(QDialog):
super(QMissionPlanning, self).__init__()
self.game = game
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMinimumSize(1000, 420)
self.setMinimumSize(1000, 440)
self.setModal(True)
self.setWindowTitle("Mission Preparation")
self.setWindowIcon(EVENT_ICONS["strike"])
@@ -33,10 +33,12 @@ class QMissionPlanning(QDialog):
self.select_airbase = QChooseAirbase(self.game)
self.select_airbase.selected_airbase_changed.connect(self.on_departure_cp_changed)
self.planned_flight_view = QPlannedFlightsView(None)
self.available_aircraft_at_selected_location = {}
if self.captured_cp[0].id in self.game.planners.keys():
self.planner = self.game.planners[self.captured_cp[0].id]
self.planned_flight_view.set_flight_planner(self.planner)
self.selected_cp = self.captured_cp[0]
self.available_aircraft_at_selected_location = self.planner.get_available_aircraft()
self.planned_flight_view.selectionModel().setCurrentIndex(self.planned_flight_view.indexAt(QPoint(1, 1)), QItemSelectionModel.Rows)
self.planned_flight_view.selectionModel().selectionChanged.connect(self.on_flight_selection_change)
@@ -51,12 +53,13 @@ class QMissionPlanning(QDialog):
self.add_flight_button = QPushButton("Add Flight")
self.add_flight_button.clicked.connect(self.on_add_flight)
self.delete_flight_button = QPushButton("Delete Selected")
self.delete_flight_button.setProperty("style", "btn-danger")
self.delete_flight_button.clicked.connect(self.on_delete_flight)
self.button_layout = QHBoxLayout()
self.button_layout.addStretch()
self.button_layout.addWidget(self.add_flight_button)
self.button_layout.addWidget(self.delete_flight_button)
self.button_layout.addWidget(self.add_flight_button)
self.mission_start_button = QPushButton("Take Off")
self.mission_start_button.setProperty("style", "start-button")
@@ -81,8 +84,10 @@ class QMissionPlanning(QDialog):
if len(cps) == 1:
self.selected_cp = cps[0]
self.planner = self.game.planners[cps[0].id]
self.available_aircraft_at_selected_location = self.planner.get_available_aircraft()
self.planned_flight_view.set_flight_planner(self.planner)
else:
self.available_aircraft_at_selected_location = {}
self.planned_flight_view.set_flight_planner(None)
def on_flight_selection_change(self):

View File

@@ -40,7 +40,8 @@ class QFlightCreator(QDialog):
for aircraft_type in self.planner.get_available_aircraft().keys():
print(aircraft_type)
print(aircraft_type.name)
self.select_type_aircraft.addItem(aircraft_type.id, userData=aircraft_type)
if self.available[aircraft_type] > 0:
self.select_type_aircraft.addItem(aircraft_type.id, userData=aircraft_type)
self.select_type_aircraft.setCurrentIndex(0)
self.select_flight_type = QComboBox()
@@ -61,6 +62,11 @@ class QFlightCreator(QDialog):
self.select_count_of_aircraft.setMaximum(4)
self.select_count_of_aircraft.setValue(2)
aircraft_type = self.select_type_aircraft.currentData()
if aircraft_type is not None:
self.select_count_of_aircraft.setValue(min(self.available[aircraft_type], 2))
self.select_count_of_aircraft.setMaximum(min(self.available[aircraft_type], 4))
self.add_button = QPushButton("Add")
self.add_button.clicked.connect(self.create_flight)

View File

@@ -12,7 +12,7 @@ from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAb
class QSTRIKEMissionGenerator(QAbstractMissionGenerator):
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
super(QSTRIKEMissionGenerator, self).__init__(game, flight, flight_waypoint_list, "SEAD/DEAD Generator")
super(QSTRIKEMissionGenerator, self).__init__(game, flight, flight_waypoint_list, "Strike Generator")
self.tgt_selection_box = QStrikeTargetSelectionComboBox(self.game)
self.tgt_selection_box.setMinimumWidth(200)
@@ -33,7 +33,7 @@ class QSTRIKEMissionGenerator(QAbstractMissionGenerator):
layout = QVBoxLayout()
wpt_layout = QHBoxLayout()
wpt_layout.addWidget(QLabel("SEAD/DEAD target : "))
wpt_layout.addWidget(QLabel("Target : "))
wpt_layout.addStretch()
wpt_layout.addWidget(self.tgt_selection_box, alignment=Qt.AlignRight)

View File

@@ -38,9 +38,13 @@ class QFlightWaypointList(QTableView):
takeoff.description = "Take Off"
takeoff.name = takeoff.pretty_name = "Take Off from " + self.flight.from_cp.name
self.model.appendRow(QWaypointItem(takeoff, 0))
self.model.setItem(0, 1, QStandardItem("0 ft AGL"))
item = QStandardItem("0 feet AGL")
item.setEditable(False)
self.model.setItem(0, 1, item)
for i, point in enumerate(self.flight.points):
self.model.insertRow(self.model.rowCount())
self.model.setItem(self.model.rowCount()-1, 0, QWaypointItem(point, i + 1))
self.model.setItem(self.model.rowCount()-1, 1, QStandardItem(str(meter_to_feet(point.alt)) + " ft " + str(["AGL" if point.alt_type == "RADIO" else "MSL"][0])))
item = QStandardItem(str(meter_to_feet(point.alt)) + " ft " + str(["AGL" if point.alt_type == "RADIO" else "MSL"][0]))
item.setEditable(False)
self.model.setItem(self.model.rowCount()-1, 1, item)
self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)

View File

@@ -1,11 +1,16 @@
import os
from PySide2 import QtWidgets
from PySide2.QtCore import QFile
from PySide2.QtGui import Qt
from PySide2.QtWidgets import QFrame, QLineEdit, QGridLayout, QVBoxLayout, QLabel, QPushButton, \
QFileDialog, QMessageBox, QDialog
QFileDialog, QMessageBox, QDialog, QComboBox, QApplication
import qt_ui.uiconstants as CONST
import sys
from userdata import liberation_install
import userdata
from userdata import liberation_install, liberation_theme
from userdata.liberation_theme import get_theme_index, set_theme_index
class QLiberationPreferences(QFrame):
@@ -28,6 +33,8 @@ class QLiberationPreferences(QFrame):
self.browse_saved_game.clicked.connect(self.on_browse_saved_games)
self.browse_install_dir = QPushButton("Browse...")
self.browse_install_dir.clicked.connect(self.on_browse_installation_dir)
self.themeSelect = QComboBox()
[self.themeSelect.addItem(y['themeName']) for x, y in CONST.THEMES.items()]
self.initUi()
@@ -40,6 +47,9 @@ class QLiberationPreferences(QFrame):
layout.addWidget(QLabel("<strong>DCS installation directory:</strong>"), 2, 0, alignment=Qt.AlignLeft)
layout.addWidget(self.edit_dcs_install_dir, 3, 0, alignment=Qt.AlignRight)
layout.addWidget(self.browse_install_dir, 3, 1, alignment=Qt.AlignRight)
layout.addWidget(QLabel("<strong>Theme (Requires Restart)</strong>"), 4, 0)
layout.addWidget(self.themeSelect, 4, 1, alignment=Qt.AlignRight)
self.themeSelect.setCurrentIndex(get_theme_index())
main_layout.addLayout(layout)
main_layout.addStretch()
@@ -63,6 +73,7 @@ class QLiberationPreferences(QFrame):
print("Applying changes")
self.saved_game_dir = self.edit_saved_game_dir.text()
self.dcs_install_dir = self.edit_dcs_install_dir.text()
set_theme_index(self.themeSelect.currentIndex())
if not os.path.isdir(self.saved_game_dir):
error_dialog = QMessageBox.critical(self, "Wrong DCS Saved Games directory.",
@@ -78,7 +89,8 @@ class QLiberationPreferences(QFrame):
error_dialog.exec_()
return False
if not os.path.isdir(os.path.join(self.dcs_install_dir, "Scripts")) and os.path.isfile(os.path.join(self.dcs_install_dir, "bin", "DCS.exe")):
if not os.path.isdir(os.path.join(self.dcs_install_dir, "Scripts")) and os.path.isfile(
os.path.join(self.dcs_install_dir, "bin", "DCS.exe")):
error_dialog = QMessageBox.critical(self, "Wrong DCS installation directory.",
self.dcs_install_dir + " is not a valid DCS installation directory",
QMessageBox.StandardButton.Ok)
@@ -87,7 +99,5 @@ class QLiberationPreferences(QFrame):
liberation_install.setup(self.saved_game_dir, self.dcs_install_dir)
liberation_install.save_config()
liberation_theme.save_theme_config()
return True

View File

@@ -166,13 +166,31 @@ class QSettingsWindow(QDialog):
self.generate_marks.setChecked(self.game.settings.generate_marks)
self.generate_marks.toggled.connect(self.applySettings)
if not hasattr(self.game.settings, "include_jtac_if_available"):
self.game.settings.include_jtac_if_available = True
if not hasattr(self.game.settings, "jtac_smoke_on"):
self.game.settings.jtac_smoke_on= True
self.include_jtac_if_available = QCheckBox()
self.include_jtac_if_available.setChecked(self.game.settings.include_jtac_if_available)
self.include_jtac_if_available.toggled.connect(self.applySettings)
self.jtac_smoke_on = QCheckBox()
self.jtac_smoke_on.setChecked(self.game.settings.jtac_smoke_on)
self.jtac_smoke_on.toggled.connect(self.applySettings)
self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0)
self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight)
self.gameplayLayout.addWidget(QLabel("Include JTAC (If available)"), 2, 0)
self.gameplayLayout.addWidget(self.include_jtac_if_available, 2, 1, Qt.AlignRight)
self.gameplayLayout.addWidget(QLabel("Enable JTAC smoke markers"), 3, 0)
self.gameplayLayout.addWidget(self.jtac_smoke_on, 3, 1, Qt.AlignRight)
self.performance = QGroupBox("Performance")
self.performanceLayout = QGridLayout();
self.performanceLayout = QGridLayout()
self.performanceLayout.setAlignment(Qt.AlignTop)
self.performance.setLayout(self.performanceLayout)
@@ -200,6 +218,10 @@ class QSettingsWindow(QDialog):
self.ai_parking_start.setChecked(self.game.settings.perf_ai_parking_start)
self.ai_parking_start.toggled.connect(self.applySettings)
self.destroyed_units = QCheckBox()
self.destroyed_units.setChecked(self.game.settings.perf_destroyed_units)
self.destroyed_units.toggled.connect(self.applySettings)
self.culling = QCheckBox()
self.culling.setChecked(self.game.settings.perf_culling)
self.culling.toggled.connect(self.applySettings)
@@ -222,12 +244,14 @@ class QSettingsWindow(QDialog):
self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("AI planes parking start (AI starts in flight if disabled)"), 5, 0)
self.performanceLayout.addWidget(self.ai_parking_start, 5, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Include destroyed units carcass"), 6, 0)
self.performanceLayout.addWidget(self.destroyed_units, 6, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QHorizontalSeparationLine(), 6, 0, 1, 2)
self.performanceLayout.addWidget(QLabel("Culling of distant units enabled"), 7, 0)
self.performanceLayout.addWidget(self.culling, 7, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Culling distance (km)"), 8, 0)
self.performanceLayout.addWidget(self.culling_distance, 8, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QHorizontalSeparationLine(), 7, 0, 1, 2)
self.performanceLayout.addWidget(QLabel("Culling of distant units enabled"), 8, 0)
self.performanceLayout.addWidget(self.culling, 8, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Culling distance (km)"), 9, 0)
self.performanceLayout.addWidget(self.culling_distance, 9, 1, alignment=Qt.AlignRight)
self.generatorLayout.addWidget(self.gameplay)
self.generatorLayout.addWidget(QLabel("Disabling settings below may improve performance, but will impact the overall quality of the experience."))
@@ -282,6 +306,8 @@ class QSettingsWindow(QDialog):
self.game.settings.map_coalition_visibility = self.mapVisibiitySelection.currentData()
self.game.settings.external_views_allowed = self.ext_views.isChecked()
self.game.settings.generate_marks = self.generate_marks.isChecked()
self.game.settings.include_jtac_if_available = self.include_jtac_if_available.isChecked()
self.game.settings.jtac_smoke_on = self.jtac_smoke_on.isChecked()
print(self.game.settings.map_coalition_visibility)
@@ -293,6 +319,7 @@ class QSettingsWindow(QDialog):
self.game.settings.perf_moving_units = self.moving_units.isChecked()
self.game.settings.perf_infantry = self.infantry.isChecked()
self.game.settings.perf_ai_parking_start = self.ai_parking_start.isChecked()
self.game.settings.perf_destroyed_units = self.destroyed_units.isChecked()
self.game.settings.perf_culling = self.culling.isChecked()
self.game.settings.perf_culling_distance = int(self.culling_distance.value())

View File

@@ -1,4 +1,4 @@
pydcs>=0.9.4
pydcs>=0.9.9
Pyside2>=5.13.0
pyinstaller==3.6
pyproj==2.6.1.post1

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 800 KiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

View File

@@ -0,0 +1,72 @@
local unitPayloads = {
["name"] = "A-20G",
["payloads"] = {
[1] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
[2] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
[3] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
[4] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
[5] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
},
["tasks"] = {
[1] = 32,
[2] = 30,
[3] = 17,
},
["unitType"] = "A-20G",
}
return unitPayloads

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