Compare commits

..

53 Commits
2.1.1 ... 2.1.5

Author SHA1 Message Date
C. Perreau
41445c3092 Merge pull request #187 from Khopa/develop_2_1_x
2.1.5
2020-10-05 19:45:30 +02:00
Khopa
2a3bf9821b Fixed EPLRS cherry pick merge. 2020-10-05 19:33:48 +02:00
Khopa
819d775282 EPLRS for 2.1.5 2020-10-05 19:30:43 +02:00
Khopa
efbc6fe3ae Enable EPLRS for ground units that can use it. 2020-10-05 19:29:34 +02:00
Khopa
262ba6c113 Chery picked another fix for this release, so updated changelog 2020-10-05 19:28:55 +02:00
Khopa
c41ecb6735 Fix aircrafts landing point 2020-10-05 19:27:03 +02:00
Khopa
f5c32c6b98 Version 2.1.5 2020-10-05 19:26:07 +02:00
Dan Albert
a1886e37f8 Fix save issues after aborting mission.
When the mission is aborted the pending mission is still in the event
list, which is part of the game option. That event has a reference to
the operation, which in turn contains all the mission generator
objects. Two of these objects are the radio/TACAN allocators, which
use a generator to track the next free channel. Generators cannot be
picked, so because these are transitively part of the game object the
game cannot be saved.

Aside from the briefing generator, none of those objects are
actually needed outside the generation function itself, so just make
them locals instead.

This probably needs a larger refactor at some point. It doesn't look
like we need so many calls into the operation type (it has an
initialize, a prepare, and a generate, and it doesn't seem to need
anything but the last one). The only reason breifinggen needs to
remain a part of the class is because the briefing title and
description are filled in from the derived class, where title and
description should probably be overridden properties instead. I'm also
not sure if we need to make the event list a part of game at all, and
also don't think that the mission needs to be one of these events.
2020-10-05 19:20:57 +02:00
Khopa
7dd3367203 Version number for release 2.1.4 2020-10-03 16:50:56 +02:00
Khopa
e72c82521a Forgot the changelog for 2.1.4 2020-10-03 16:45:21 +02:00
C. Perreau
aca415db23 Merge pull request #179 from Khopa/develop
Release 2.1.4
2020-10-03 16:33:26 +02:00
David Pierron
98b2d8b3b9 typo in the generate_initial_units function name 2020-10-02 13:15:40 -07:00
David Pierron
f8ef5db5a3 bug when continuing an old campaign save 2020-10-02 13:15:40 -07:00
Dan Albert
a44cbe5972 Tone down failure message for missing plugin file.
This looked an awful lot like an error, but it's the common case.
2020-10-01 23:57:53 -07:00
C. Perreau
2066a2e9bc Merge pull request #167 from Khopa/develop
Release 2.1.3
2020-10-01 23:23:06 +02:00
Khopa
f381bf85a4 Fixed JTAC script not working after changes made to lua files 2020-10-01 23:17:32 +02:00
Khopa
44dcdcc8bb Changelog update 2020-10-01 23:17:08 +02:00
Khopa
01220800f3 Fixed Viggen icon 2020-10-01 22:47:58 +02:00
Khopa
8ecb4cdcf4 Added more ground vehicles icons. 2020-10-01 21:09:05 +02:00
Khopa
8402d108c0 Pydcs location 2020-10-01 20:22:11 +02:00
Khopa
75af2d468e Fix A-10C_II icon 2020-10-01 19:38:43 +02:00
Khopa
72ce37f008 Added custom payloads for A-10C II 2020-10-01 19:33:46 +02:00
Khopa
e48e884286 Added A-10C_2. Changed bluefor factions' country to "Combined Joint Task Forces Blue" instead of "USA" (support more units) 2020-10-01 19:20:25 +02:00
Khopa
f9d5c1f8de Update pydcs location 2020-10-01 19:07:06 +02:00
Khopa
0873dcab0a Gitmodule points to pydcs 2020-10-01 19:06:38 +02:00
C. Perreau
a1343c2849 Merge pull request #166 from DanAlbert/build-canaries
Build and archive binaries on push/PR.
2020-10-01 12:53:35 +02:00
Dan Albert
f732cc54d0 Build and archive binaries on push/PR.
Not building a full release, but this makes it easier to test someone
else's PR, or for players to get at pre-release builds.
2020-09-30 21:03:12 -07:00
David Pierron
473a7d5fa4 added a 'mkrelease' config for VS.Code 2020-09-30 19:47:02 -07:00
David Pierron
8054a0b62f removed useless link.cmd.sample file 2020-09-30 19:47:02 -07:00
Dan Albert
7f9cba5d37 Fix more None ATC bugs.
Fixes https://github.com/Khopa/dcs_liberation/issues/164
2020-09-30 19:20:50 -07:00
C. Perreau
f68e6387e6 Merge pull request #161 from VEAF/make-mission-portable
Make mission portable
2020-09-29 23:50:34 +02:00
Khopa
f032001bee Limit number of aircraft that can be bought at a Control Point. 2020-09-29 23:47:57 +02:00
David Pierron
3bae591c04 corrected and enhanced mission portability 2020-09-29 20:46:22 +02:00
Khopa
18a1f0af94 Added credits to new contributor to about dialog. 2020-09-29 20:03:07 +02:00
David Pierron
afbd4a4716 Make mission portable
use inline json.lua and write to %LIBERATION_EXPORT_DIR%, %TEMP%
or the DCS working directory
2020-09-29 17:27:35 +02:00
David Pierron
a98da14c6f Merge pull request #1 from Khopa/master
Merge from base
2020-09-29 15:14:55 +02:00
Khopa
a2a70213a7 Update pydcs location 2020-09-28 00:55:02 +02:00
Khopa
8b0f877041 Verrsion string updated to 2.1.2 2020-09-28 00:42:27 +02:00
Khopa
bf7ad4cad2 Merge remote-tracking branch 'khopa/master' into develop 2020-09-28 00:27:25 +02:00
C. Perreau
66b659c0af Merge pull request #152 from VEAF/introduced-scripts-plugins
Introduced LUA scripts plugins
2020-09-28 00:26:26 +02:00
Khopa
8709ea948f Merge remote-tracking branch 'khopa/master' into develop 2020-09-28 00:21:33 +02:00
Khopa
7236c10403 Changelog update 2020-09-28 00:21:12 +02:00
C. Perreau
dde703ec41 Merge pull request #154 from VEAF/add-tanker-type-to-tanker-name
add tanker type to tanker name
2020-09-28 00:06:49 +02:00
Khopa
aa2e9b123c Fix : AI is not planning flights for Tornado. 2020-09-28 00:03:01 +02:00
Khopa
737e04d09e Merge branch 'master' into develop 2020-09-27 19:16:34 +02:00
C. Perreau
0fe59efd72 Merge pull request #157 from DanAlbert/fix-none
Fix None dereference.
2020-09-27 19:10:31 +02:00
C. Perreau
ddb50e6254 Merge pull request #151 from VEAF/UHF-intraflight-frequency-for-Player-and-Clients-A-10C
UHF Intraflight Frequency for Player and Clients A-10C
2020-09-27 19:09:33 +02:00
Dan Albert
72e6ae4186 Fix None dereference. 2020-09-26 16:32:02 -07:00
David Pierron
4d510f643a add tanker type to tanker name 2020-09-25 17:11:17 +02:00
David Pierron
66f607b5e6 added a comment that links to my forum post 2020-09-25 11:33:07 +02:00
David Pierron
1a125c62e7 added sample __plugins.lst file 2020-09-25 11:21:23 +02:00
David Pierron
84da44a27b Introduced LUA scripts plugins
In order to be able to customize the scripts that can be injected in the
mission, a __plugin.lst file is read and the scripts mentionned in this
file are injected (through DoScriptFile and not DoScript).

A mechanism checks if a standard script (Mist, JTACAutolase) has
already been loaded, to avoid loading them twice.
2020-09-25 11:06:25 +02:00
David Pierron
5e35efcaef UHF Intraflight Frequency for Player and Clients A-10C
In the mission editor, using a VHF frequency for a Player or
Client A-10C results in an error. Changed the radio definitions
to use AN/ARC-164 for intraflight comms.
2020-09-25 10:36:18 +02:00
58 changed files with 710 additions and 132 deletions

39
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install environment
run: |
py -m venv ./venv
- name: Install dependencies
run: |
./venv/scripts/activate
pip install -r requirements.txt
# For some reason the shiboken2.abi3.dll is not found properly, so I copy it instead
Copy-Item .\venv\Lib\site-packages\shiboken2\shiboken2.abi3.dll .\venv\Lib\site-packages\PySide2\ -Force
- name: Build binaries
run: |
./venv/scripts/activate
$env:PYTHONPATH=".;./pydcs"
pyinstaller pyinstaller.spec
- uses: actions/upload-artifact@v2
with:
name: dcs_liberation
path: dist/

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@ logs/liberation.log
qt_ui/logs/liberation.log
*.psd
resources/scripts/plugins/*

4
.gitmodules vendored
View File

@@ -1,4 +1,4 @@
[submodule "pydcs"]
path = pydcs
url = https://github.com/khopa/dcs
branch = dataexport
url = https://github.com/pydcs/dcs
branch = master

11
.vscode/launch.json vendored
View File

@@ -14,6 +14,17 @@
"PYTHONPATH": ".;./pydcs"
},
"preLaunchTask": "Prepare Environment"
},
{
"name": "Python: Make Release",
"type": "python",
"request": "launch",
"program": "resources\\tools\\mkrelease.py",
"console": "integratedTerminal",
"env": {
"PYTHONPATH": ".;./pydcs"
},
"preLaunchTask": "Prepare Environment"
}
]
}

View File

@@ -1,3 +1,39 @@
# 2.1.5
## Features/Improvements :
* **[Units/Factions]** Enabled EPLRS for ground units that supports it (so they appear on A-10C II TAD and Helmet)
## Fixes :
* **[UI]** Fixed an issue that prevent saving after aborting a mission
* **[Mission Generator]** Fixed aircraft landing point type being wrong
# 2.1.4
## Fixes :
* **[UI]** Fixed an issue that prevent generating the mission (take off button no working) on old savegames.
# 2.1.3
## Features/Improvements :
* **[Units/Factions]** Added A-10C_2 to USA 2005 and Bluefor modern factions
* **[UI]** Limit number of aircraft that can be bought to the number of available parking slots.
* **[Mission Generator]** Use inline loading of the JSON.lua library, and save to either %LIBERATION_EXPORT_DIR%, or to DCS working directory
## Changes :
* **[Units/Factions]** Bluefor generic factions will now use the new "Combined Joint Task Forces Blue" country in the generated mission instead of "USA"
## Fixes :
* **[UI]** Fixed icon for Viggen
* **[UI]** Added icons for some ground units
* **[Misc]** Fixed issue with Chinese characters in pydcs preventing generating the mission. (Take Off button not working) (thanks to spark135246)
* **[Misc]** Fixed an error causing with ATC frequency preventing generating the mission. (Take Off button not working) (thanks to danalbert)
# 2.1.2
## Fixes :
* **[Mission Generator]** Fix mission generation issues with radio frequencies (Thanks to contributors davidp57 and danalbert)
* **[Mission Generator]** AI should now properly plan flights for Tornados
# 2.1.1
## Features/Improvements :
@@ -5,9 +41,9 @@
* **[Kneeboards]** Generate mission kneeboards for player flights. Kneeboards include
airfield/carrier information (ATC frequencies, ILS, TACAN, and runway
assignments), assigned radio channels, waypoint lists, and AWACS/JTAC/tanker
information.
information. (Thanks to contributor danalbert)
* **[Radios]** Allocate separate intra-flight channels for most aircraft to reduce global
chatter.
chatter. (Thanks to contributor danalbert)
* **[Radios]** Configure radio channel presets for most aircraft. Currently supported are:
* AJS37
* AV-8B
@@ -15,7 +51,7 @@
* F-16C
* F/A-18C
* JF-17
* M-2000C
* M-2000C (Thanks to contributor danalbert)
* **[Base Menu]** Added possibility to repair destroyed SAM and base defenses units for the player (Click on a SAM site to fix it)
* **[Base Menu]** Added possibility to buy/sell/replace SAM units
* **[Map]** Added recon images for buildings on strike targets, click on a Strike target to get detailled informations
@@ -25,7 +61,7 @@
* **[Cheat Menu]** Added buttons to remove money
## Fixed issues :
* **[UI/UX]** Spelling issues (Thanks to Github contributor steveveepee)
* **[UI/UX]** Spelling issues (Thanks to contributor steveveepee)
* **[Campaign Generator]** LHA was placed on land in Syrian Civil War campaign
* **[Campaign Generator]** Fixed inverted configuration for Syria full map
* **[Campaign Generator]** Syria "Inherent Resolve" campaign, added Incirlik Air Base

View File

@@ -192,6 +192,7 @@ PRICES = {
A_10A: 16,
A_10C: 22,
A_10C_2: 24,
# heli
Ka_50: 13,
@@ -498,6 +499,7 @@ UNIT_BY_TASK = {
AJS37,
A_10A,
A_10C,
A_10C_2,
Su_17M4,
Su_25,
Su_25T,
@@ -957,6 +959,7 @@ PLANE_PAYLOAD_OVERRIDES = {
},
A_10A: COMMON_OVERRIDE,
A_10C: COMMON_OVERRIDE,
A_10C_2: COMMON_OVERRIDE,
AV8BNA: COMMON_OVERRIDE,
C_101CC: COMMON_OVERRIDE,
F_5E_3: COMMON_OVERRIDE,

View File

@@ -4,7 +4,7 @@ from dcs.ships import *
from dcs.vehicles import *
BLUEFOR_COLDWAR = {
"country": "USA",
"country": "Combined Joint Task Forces Blue",
"side": "blue",
"units": [

View File

@@ -6,7 +6,7 @@ from dcs.vehicles import *
from pydcs_extensions.a4ec.a4ec import A_4E_C
BLUEFOR_COLDWAR_A4 = {
"country": "USA",
"country": "Combined Joint Task Forces Blue",
"side": "blue",
"units": [

View File

@@ -4,7 +4,7 @@ from dcs.ships import *
from dcs.vehicles import *
BLUEFOR_MODERN = {
"country": "USA",
"country": "Combined Joint Task Forces Blue",
"side": "blue",
"units": [
@@ -20,6 +20,7 @@ BLUEFOR_MODERN = {
Su_25T,
A_10A,
A_10C,
A_10C_2,
AV8BNA,
AJS37,

View File

@@ -13,6 +13,7 @@ USA_2005 = {
FA_18C_hornet,
F_16C_50,
A_10C,
A_10C_2,
AV8BNA,
MQ_9_Reaper,

View File

@@ -190,9 +190,9 @@ class Game:
def is_player_attack(self, event):
if isinstance(event, Event):
return event.attacker_name == self.player_name
return event and event.attacker_name and event.attacker_name == self.player_name
else:
return event.name == self.player_name
return event and event.name and event.name == self.player_name
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint] = None):

View File

@@ -68,26 +68,8 @@ class Operation:
def initialize(self, mission: Mission, conflict: Conflict):
self.current_mission = mission
self.conflict = conflict
self.radio_registry = RadioRegistry()
self.tacan_registry = TacanRegistry()
self.airgen = AircraftConflictGenerator(
mission, conflict, self.game.settings, self.game,
self.radio_registry)
self.airsupportgen = AirSupportConflictGenerator(
mission, conflict, self.game, self.radio_registry,
self.tacan_registry)
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
self.visualgen = VisualGenerator(mission, conflict, self.game)
self.envgen = EnviromentGenerator(mission, conflict, self.game)
self.forcedoptionsgen = ForcedOptionsGenerator(mission, conflict, self.game)
self.groundobjectgen = GroundObjectsGenerator(
mission,
conflict,
self.game,
self.radio_registry,
self.tacan_registry
)
self.briefinggen = BriefingGenerator(mission, conflict, self.game)
self.briefinggen = BriefingGenerator(self.current_mission,
self.conflict, self.game)
def prepare(self, terrain: Terrain, is_quick: bool):
with open("resources/default_options.lua", "r") as f:
@@ -127,6 +109,9 @@ class Operation:
self.defenders_starting_position = self.to_cp.at
def generate(self):
radio_registry = RadioRegistry()
tacan_registry = TacanRegistry()
# Dedup beacon/radio frequencies, since some maps have some frequencies
# used multiple times.
beacons = load_beacons_for_terrain(self.game.theater.terrain.name)
@@ -138,7 +123,7 @@ class Operation:
logging.error(
f"TACAN beacon has no channel: {beacon.callsign}")
else:
self.tacan_registry.reserve(beacon.tacan_channel)
tacan_registry.reserve(beacon.tacan_channel)
for airfield, data in AIRFIELD_DATA.items():
if data.theater == self.game.theater.terrain.name:
@@ -150,16 +135,26 @@ class Operation:
# beacon list.
for frequency in unique_map_frequencies:
self.radio_registry.reserve(frequency)
radio_registry.reserve(frequency)
# Generate meteo
envgen = EnviromentGenerator(self.current_mission, self.conflict,
self.game)
if self.environment_settings is None:
self.environment_settings = self.envgen.generate()
self.environment_settings = envgen.generate()
else:
self.envgen.load(self.environment_settings)
envgen.load(self.environment_settings)
# Generate ground object first
self.groundobjectgen.generate()
groundobjectgen = GroundObjectsGenerator(
self.current_mission,
self.conflict,
self.game,
radio_registry,
tacan_registry
)
groundobjectgen.generate()
# Generate destroyed units
for d in self.game.get_destroyed_units():
@@ -180,11 +175,16 @@ class Operation:
dead=True,
)
# Air Support (Tanker & Awacs)
self.airsupportgen.generate(self.is_awacs_enabled)
airsupportgen = AirSupportConflictGenerator(
self.current_mission, self.conflict, self.game, radio_registry,
tacan_registry)
airsupportgen.generate(self.is_awacs_enabled)
# Generate Activity on the map
airgen = AircraftConflictGenerator(
self.current_mission, self.conflict, self.game.settings, self.game,
radio_registry)
for cp in self.game.theater.controlpoints:
side = cp.captured
if side:
@@ -192,11 +192,11 @@ class Operation:
else:
country = self.current_mission.country(self.game.enemy_country)
if cp.id in self.game.planners.keys():
self.airgen.generate_flights(
airgen.generate_flights(
cp,
country,
self.game.planners[cp.id],
self.groundobjectgen.runways
groundobjectgen.runways
)
# Generate ground units on frontline everywhere
@@ -221,66 +221,128 @@ class Operation:
self.current_mission.groundControl.red_tactical_commander = self.ca_slots
# 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()
triggersgen = TriggersGenerator(self.current_mission, self.conflict,
self.game)
triggersgen.generate()
# Options
self.forcedoptionsgen.generate()
forcedoptionsgen = ForcedOptionsGenerator(self.current_mission,
self.conflict, self.game)
forcedoptionsgen.generate()
# Generate Visuals Smoke Effects
visualgen = VisualGenerator(self.current_mission, self.conflict,
self.game)
if self.game.settings.perf_smoke_gen:
self.visualgen.generate()
visualgen.generate()
# Inject Lua Scripts
load_mist = TriggerStart(comment="Load Mist Lua Framework")
with open("./resources/scripts/mist_4_3_74.lua") as f:
load_mist.add_action(DoScript(String(f.read())))
self.current_mission.triggerrules.triggers.append(load_mist)
# Inject Plugins Lua Scripts
listOfPluginsScripts = []
plugin_file_path = Path("./resources/scripts/plugins/__plugins.lst")
if plugin_file_path.exists():
for line in plugin_file_path.read_text().splitlines():
name = line.strip()
if not name.startswith( '#' ):
trigger = TriggerStart(comment="Load " + name)
listOfPluginsScripts.append(name)
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/plugins/" + name)
trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger)
else:
logging.info(
f"Not loading plugins, {plugin_file_path} does not exist")
# Load Ciribob's JTACAutoLase script
load_autolase = TriggerStart(comment="Load JTAC script")
with open("./resources/scripts/JTACAutoLase.lua") as f:
# Inject Mist Script if not done already in the plugins
if not "mist.lua" in listOfPluginsScripts and not "mist_4_3_74.lua" in listOfPluginsScripts: # don't load the script twice
trigger = TriggerStart(comment="Load Mist Lua framework")
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/mist_4_3_74.lua")
trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger)
script = f.read()
script = script + "\n"
# Inject JSON library if not done already in the plugins
if not "json.lua" in listOfPluginsScripts : # don't load the script twice
trigger = TriggerStart(comment="Load JSON Lua library")
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/json.lua")
trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger)
smoke = "true"
if hasattr(self.game.settings, "jtac_smoke_on"):
if not self.game.settings.jtac_smoke_on:
smoke = "false"
# Inject Ciribob's JTACAutoLase if not done already in the plugins
if not "JTACAutoLase.lua" in listOfPluginsScripts : # don't load the script twice
trigger = TriggerStart(comment="Load JTACAutoLase.lua script")
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/JTACAutoLase.lua")
trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger)
for jtac in jtacs:
script += f"\nJTACAutoLase('{jtac.unit_name}', {jtac.code}, {smoke}, 'vehicle')\n"
# set a LUA table with data from Liberation that we want to set
# at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function
# later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts
state_location = "[[" + os.path.abspath("state.json") + "]]"
lua = """
-- setting configuration table
env.info("DCSLiberation|: setting configuration table")
-- all data in this table is overridable.
dcsLiberation = {}
-- the base location for state.json; if non-existent, it'll be replaced with LIBERATION_EXPORT_DIR, TEMP, or DCS working directory
dcsLiberation.installPath=""" + state_location + """
-- you can override dcsLiberation.JTACAutoLase to make it use your own function ; it will be called with these parameters : ({jtac.unit_name}, {jtac.code}, {smoke}, 'vehicle') for all JTACs
if ctld then
dcsLiberation.JTACAutoLase=ctld.JTACAutoLase
elseif JTACAutoLase then
dcsLiberation.JTACAutoLase=JTACAutoLase
end
-- later, we'll add more data to the table
--dcsLiberation.POIs = {}
--dcsLiberation.BASEs = {}
--dcsLiberation.JTACs = {}
"""
load_autolase.add_action(DoScript(String(script)))
self.current_mission.triggerrules.triggers.append(load_autolase)
trigger = TriggerStart(comment="Set DCS Liberation data")
trigger.add_action(DoScript(String(lua)))
self.current_mission.triggerrules.triggers.append(trigger)
load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script")
with open("./resources/scripts/dcs_liberation.lua") as f:
script = f.read()
json_location = "[["+os.path.abspath("resources\\scripts\\json.lua")+"]]"
state_location = "[[" + os.path.abspath("state.json") + "]]"
script = script.replace("{{json_file_abs_location}}", json_location)
script = script.replace("{{debriefing_file_location}}", state_location)
load_dcs_libe.add_action(DoScript(String(script)))
self.current_mission.triggerrules.triggers.append(load_dcs_libe)
# Inject DCS-Liberation script if not done already in the plugins
if not "dcs_liberation.lua" in listOfPluginsScripts : # don't load the script twice
trigger = TriggerStart(comment="Load DCS Liberation script")
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/dcs_liberation.lua")
trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger)
self.assign_channels_to_flights()
# add a configuration for JTACAutoLase and start lasing for all JTACs
smoke = "true"
if hasattr(self.game.settings, "jtac_smoke_on"):
if not self.game.settings.jtac_smoke_on:
smoke = "false"
lua = """
-- setting and starting JTACs
env.info("DCSLiberation|: setting and starting JTACs")
"""
for jtac in jtacs:
lua += f"if dcsLiberation.JTACAutoLase then dcsLiberation.JTACAutoLase('{jtac.unit_name}', {jtac.code}, {smoke}, 'vehicle') end\n"
trigger = TriggerStart(comment="Start JTACs")
trigger.add_action(DoScript(String(lua)))
self.current_mission.triggerrules.triggers.append(trigger)
self.assign_channels_to_flights(airgen.flights,
airsupportgen.air_support)
kneeboard_generator = KneeboardGenerator(self.current_mission)
for dynamic_runway in self.groundobjectgen.runways.values():
for dynamic_runway in groundobjectgen.runways.values():
self.briefinggen.add_dynamic_runway(dynamic_runway)
for tanker in self.airsupportgen.air_support.tankers:
for tanker in airsupportgen.air_support.tankers:
self.briefinggen.add_tanker(tanker)
kneeboard_generator.add_tanker(tanker)
if self.is_awacs_enabled:
for awacs in self.airsupportgen.air_support.awacs:
for awacs in airsupportgen.air_support.awacs:
self.briefinggen.add_awacs(awacs)
kneeboard_generator.add_awacs(awacs)
@@ -288,21 +350,23 @@ class Operation:
self.briefinggen.add_jtac(jtac)
kneeboard_generator.add_jtac(jtac)
for flight in self.airgen.flights:
for flight in airgen.flights:
self.briefinggen.add_flight(flight)
kneeboard_generator.add_flight(flight)
self.briefinggen.generate()
kneeboard_generator.generate()
def assign_channels_to_flights(self) -> None:
def assign_channels_to_flights(self, flights: List[FlightData],
air_support: AirSupport) -> None:
"""Assigns preset radio channels for client flights."""
for flight in self.airgen.flights:
for flight in flights:
if not flight.client_units:
continue
self.assign_channels_to_flight(flight)
self.assign_channels_to_flight(flight, air_support)
def assign_channels_to_flight(self, flight: FlightData) -> None:
def assign_channels_to_flight(self, flight: FlightData,
air_support: AirSupport) -> None:
"""Assigns preset radio channels for a client flight."""
airframe = flight.aircraft_type
@@ -313,4 +377,5 @@ class Operation:
return
aircraft_data.channel_allocator.assign_channels_for_flight(
flight, self.airsupportgen.air_support)
flight, air_support
)

View File

@@ -279,13 +279,15 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
last_channel = flight.num_radio_channels(radio_id)
channel_alloc = iter(range(first_channel, last_channel + 1))
flight.assign_channel(radio_id, next(channel_alloc), flight.departure.atc)
if flight.departure.atc is not None:
flight.assign_channel(radio_id, next(channel_alloc),
flight.departure.atc)
# TODO: If there ever are multiple AWACS, limit to mission relevant.
for awacs in air_support.awacs:
flight.assign_channel(radio_id, next(channel_alloc), awacs.freq)
if flight.arrival != flight.departure:
if flight.arrival != flight.departure and flight.arrival.atc is not None:
flight.assign_channel(radio_id, next(channel_alloc),
flight.arrival.atc)
@@ -295,7 +297,7 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
flight.assign_channel(
radio_id, next(channel_alloc), tanker.freq)
if flight.divert is not None:
if flight.divert is not None and flight.divert.atc is not None:
flight.assign_channel(radio_id, next(channel_alloc),
flight.divert.atc)
except StopIteration:
@@ -374,7 +376,7 @@ class AircraftData:
AIRCRAFT_DATA: Dict[str, AircraftData] = {
"A-10C": AircraftData(
inter_flight_radio=get_radio("AN/ARC-164"),
intra_flight_radio=get_radio("AN/ARC-186(V) AM"),
intra_flight_radio=get_radio("AN/ARC-164"), # VHF for intraflight is not accepted anymore by DCS (see https://forums.eagle.ru/showthread.php?p=4499738)
channel_allocator=WarthogRadioChannelAllocator()
),
@@ -950,6 +952,7 @@ class AircraftConflictGenerator:
# pt.tasks.append(engagetgt)
elif point.waypoint_type == FlightWaypointType.LANDING_POINT:
pt.type = "Land"
pt.action = PointAction.Landing
elif point.waypoint_type == FlightWaypointType.INGRESS_STRIKE:
if group.units[0].unit_type == B_17G:

View File

@@ -1527,7 +1527,10 @@ class RunwayData:
ils: Optional[RadioFrequency] = None
try:
airfield = AIRFIELD_DATA[airport.name]
atc = airfield.atc.uhf
if airfield.atc is not None:
atc = airfield.atc.uhf
else:
atc = None
tacan = airfield.tacan
tacan_callsign = airfield.tacan_callsign
ils = airfield.ils_freq(runway)

View File

@@ -65,7 +65,7 @@ class AirSupportConflictGenerator:
tanker_position = player_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
tanker_group = self.mission.refuel_flight(
country=self.mission.country(self.game.player_country),
name=namegen.next_tanker_name(self.mission.country(self.game.player_country)),
name=namegen.next_tanker_name(self.mission.country(self.game.player_country), tanker_unit_type),
airport=None,
plane_type=tanker_unit_type,
position=tanker_position,

View File

@@ -183,6 +183,11 @@ class GroundConflictGenerator:
return
for dcs_group, group in ally_groups:
if hasattr(group.units[0], 'eplrs'):
if group.units[0].eplrs:
dcs_group.points[0].tasks.append(EPLRS(dcs_group.id))
if group.role == CombatGroupRole.ARTILLERY:
# Fire on any ennemy in range
if self.game.settings.perf_artillery:

View File

@@ -27,6 +27,7 @@ INTERCEPT_CAPABLE = [
# Used for CAP, Escort, and intercept if there is not a specialised aircraft available
CAP_CAPABLE = [
MiG_15bis,
MiG_19P,
MiG_21Bis,
@@ -98,6 +99,7 @@ CAS_CAPABLE = [
A_10A,
A_10C,
A_10C_2,
AV8BNA,
F_86F_Sabre,
@@ -108,6 +110,9 @@ CAS_CAPABLE = [
F_16C_50,
FA_18C_hornet,
Tornado_IDS,
Tornado_GR4,
C_101CC,
MB_339PAN,
L_39ZA,
@@ -121,7 +126,6 @@ CAS_CAPABLE = [
AH_64D,
AH_1W,
UH_1H,
Mi_8MT,
@@ -168,6 +172,9 @@ SEAD_CAPABLE = [
Su_34,
MiG_27K,
Tornado_IDS,
Tornado_GR4,
A_4E_C,
Rafale_A_S
]
@@ -191,6 +198,7 @@ STRIKE_CAPABLE = [
A_10A,
A_10C,
A_10C_2,
AV8BNA,
F_86F_Sabre,
@@ -201,6 +209,9 @@ STRIKE_CAPABLE = [
F_16C_50,
FA_18C_hornet,
Tornado_IDS,
Tornado_GR4,
C_101CC,
L_39ZA,
AJS37,
@@ -235,8 +246,12 @@ ANTISHIP_CAPABLE = [
F_16A,
F_16C_50,
A_10C,
A_10C_2,
A_10A,
Tornado_IDS,
Tornado_GR4,
Ju_88A4,
Rafale_A_S
]

View File

@@ -80,6 +80,10 @@ class GroundObjectsGenerator:
vehicle.heading = u.heading
vehicle.player_can_drive = True
vg.add_unit(vehicle)
if hasattr(utype, 'eplrs'):
if utype.eplrs:
vg.points[0].tasks.append(EPLRS(vg.id))
else:
vg = self.m.ship_group(side, g.name, utype, position=g.position,
heading=g.units[0].heading)

View File

@@ -61,9 +61,9 @@ class NameGenerator:
self.number += 1
return "awacs|{}|{}|0|".format(country.id, self.number)
def next_tanker_name(self, country):
def next_tanker_name(self, country, unit_type):
self.number += 1
return "tanker|{}|{}|0|".format(country.id, self.number)
return "tanker|{}|{}|0|{}".format(country.id, self.number, db.unit_type_name(unit_type))
def next_carrier_name(self, country):
self.number += 1

2
pydcs

Submodule pydcs updated: f46781b854...c203e5a1b8

View File

@@ -25,7 +25,7 @@ class ERC_90(unittype.VehicleType):
detection_range = 0
threat_range = 4000
air_weapon_dist = 4000
eprls = True
eplrs = True
class VAB__50(unittype.VehicleType):
@@ -34,7 +34,7 @@ class VAB__50(unittype.VehicleType):
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
eplrs = True
class VAB_T20_13(unittype.VehicleType):
@@ -43,7 +43,7 @@ class VAB_T20_13(unittype.VehicleType):
detection_range = 0
threat_range = 2000
air_weapon_dist = 2000
eprls = True
eplrs = True
class VAB_MEPHISTO(unittype.VehicleType):
@@ -52,7 +52,7 @@ class VAB_MEPHISTO(unittype.VehicleType):
detection_range = 0
threat_range = 4000
air_weapon_dist = 4000
eprls = True
eplrs = True
class VBL__50(unittype.VehicleType):
@@ -61,7 +61,7 @@ class VBL__50(unittype.VehicleType):
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
eplrs = True
class VBL_AANF1(unittype.VehicleType):
@@ -70,7 +70,7 @@ class VBL_AANF1(unittype.VehicleType):
detection_range = 0
threat_range = 1000
air_weapon_dist = 1000
eprls = True
eplrs = True
class VBAE_CRAB(unittype.VehicleType):
@@ -79,7 +79,7 @@ class VBAE_CRAB(unittype.VehicleType):
detection_range = 0
threat_range = 3500
air_weapon_dist = 3500
eprls = True
eplrs = True
class VBAE_CRAB_MMP(unittype.VehicleType):
@@ -88,7 +88,7 @@ class VBAE_CRAB_MMP(unittype.VehicleType):
detection_range = 0
threat_range = 3500
air_weapon_dist = 3500
eprls = True
eplrs = True
class AMX_30B2(unittype.VehicleType):
@@ -121,7 +121,7 @@ class DIM__TOYOTA_BLUE(unittype.VehicleType):
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
eplrs = True
class DIM__TOYOTA_GREEN(unittype.VehicleType):
@@ -130,7 +130,7 @@ class DIM__TOYOTA_GREEN(unittype.VehicleType):
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
eplrs = True
class DIM__TOYOTA_DESERT(unittype.VehicleType):
@@ -139,7 +139,7 @@ class DIM__TOYOTA_DESERT(unittype.VehicleType):
detection_range = 0
threat_range = 1200
air_weapon_dist = 1200
eprls = True
eplrs = True
class DIM__KAMIKAZE(unittype.VehicleType):
@@ -148,7 +148,7 @@ class DIM__KAMIKAZE(unittype.VehicleType):
detection_range = 0
threat_range = 50
air_weapon_dist = 50
eprls = True
eplrs = True
## FORTIFICATION
@@ -187,7 +187,7 @@ class TRM_2000(unittype.VehicleType):
detection_range = 3500
threat_range = 0
air_weapon_dist = 0
eprls = True
eplrs = True
class TRM_2000_Fuel(unittype.VehicleType):
id = "TRM2000_Citerne"
@@ -195,7 +195,7 @@ class TRM_2000_Fuel(unittype.VehicleType):
detection_range = 3500
threat_range = 0
air_weapon_dist = 0
eprls = True
eplrs = True
class VAB_MEDICAL(unittype.VehicleType):
id = "VABH"
@@ -203,7 +203,7 @@ class VAB_MEDICAL(unittype.VehicleType):
detection_range = 0
threat_range = 0
air_weapon_dist = 0
eprls = True
eplrs = True
class VAB(unittype.VehicleType):
id = "VAB_RADIO"
@@ -211,7 +211,7 @@ class VAB(unittype.VehicleType):
detection_range = 0
threat_range = 0
air_weapon_dist = 0
eprls = True
eplrs = True
class VBL(unittype.VehicleType):
id = "VBL-Radio"
@@ -219,7 +219,7 @@ class VBL(unittype.VehicleType):
detection_range = 0
threat_range = 0
air_weapon_dist = 0
eprls = True
eplrs = True
class Tracma_TD_1500(unittype.VehicleType):
id = "Tracma"
@@ -236,7 +236,7 @@ class SMOKE_SAM_IR(unittype.VehicleType):
detection_range = 20000
threat_range = 20000
air_weapon_dist = 20000
eprls = True
eplrs = True
class _53T2(unittype.VehicleType):
id = "AA20"
@@ -251,7 +251,7 @@ class TRM_2000_53T2(unittype.VehicleType):
detection_range = 6000
threat_range = 2000
air_weapon_dist = 2000
eprls = True
eplrs = True
class TRM_2000_PAMELA(unittype.VehicleType):
id = "TRMMISTRAL"
@@ -259,7 +259,7 @@ class TRM_2000_PAMELA(unittype.VehicleType):
detection_range = 8000
threat_range = 10000
air_weapon_dist = 10000
eprls = True
eplrs = True
## INFANTRY
@@ -285,4 +285,4 @@ class VAB_MORTIER(unittype.VehicleType):
detection_range = 0
threat_range = 15000
air_weapon_dist = 15000
eprls = True
eplrs = True

View File

@@ -8,7 +8,7 @@ from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP
from userdata.liberation_theme import get_theme_icons
VERSION_STRING = "2.1.1"
VERSION_STRING = "2.1.5"
URLS : Dict[str, str] = {
"Manual": "https://github.com/khopa/dcs_liberation/wiki",
@@ -82,6 +82,7 @@ def load_icons():
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["Hangar"] = QPixmap("./resources/ui/misc/hangar.png")
ICONS["Terrain_Caucasus"] = QPixmap("./resources/ui/terrain_caucasus.gif")
ICONS["Terrain_Persian_Gulf"] = QPixmap("./resources/ui/terrain_pg.gif")
@@ -138,6 +139,7 @@ def load_aircraft_icons():
AIRCRAFT_ICONS[aircraft[:-7]] = QPixmap(os.path.join("./resources/ui/units/aircrafts/", aircraft))
AIRCRAFT_ICONS["F-16C_50"] = AIRCRAFT_ICONS["F-16C"]
AIRCRAFT_ICONS["FA-18C_hornet"] = AIRCRAFT_ICONS["FA-18C"]
AIRCRAFT_ICONS["A-10C_2"] = AIRCRAFT_ICONS["A-10C"]
def load_vehicle_icons():

View File

@@ -221,7 +221,7 @@ class QLiberationWindow(QMainWindow):
"<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, ColonelPanic, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl" + \
"shdwp, Khopa, ColonelPanic, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl, davidp57" + \
"<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/>"\

View File

@@ -1,3 +1,5 @@
import logging
from PySide2.QtWidgets import QLabel, QPushButton, \
QSizePolicy, QSpacerItem, QGroupBox, QHBoxLayout
from dcs.unittype import UnitType
@@ -11,11 +13,14 @@ class QRecruitBehaviour:
deliveryEvent = None
existing_units_labels = None
bought_amount_labels = None
maximum_units = -1
recruitable_types = []
BUDGET_FORMAT = "Available Budget: <b>${}M</b>"
def __init__(self):
self.bought_amount_labels = {}
self.existing_units_labels = {}
self.recruitable_types = []
self.update_available_budget()
def add_purchase_row(self, unit_type, layout, row):
@@ -66,7 +71,6 @@ class QRecruitBehaviour:
sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell.clicked.connect(lambda: self.sell(unit_type))
existLayout.addWidget(unitName)
existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
existLayout.addWidget(existing_units)
@@ -102,10 +106,19 @@ class QRecruitBehaviour:
def buy(self, unit_type):
if self.maximum_units > 0:
if self.total_units + 1 > self.maximum_units:
logging.info("Not enough space left !")
# TODO : display modal warning
return
price = db.PRICES[unit_type]
if self.game.budget >= price:
self.deliveryEvent.deliver({unit_type: 1})
self.game.budget -= price
else:
# TODO : display modal warning
logging.info("Not enough money !")
self._update_count_label(unit_type)
self.update_available_budget()
@@ -123,3 +136,34 @@ class QRecruitBehaviour:
self._update_count_label(unit_type)
self.update_available_budget()
@property
def total_units(self):
total = 0
for unit_type in self.recruitables_types:
total += self.cp.base.total_units(unit_type)
print(unit_type, total, self.cp.base.total_units(unit_type))
print("--------------------------------")
if self.deliveryEvent:
for unit_bought in self.deliveryEvent.units:
if db.unit_task(unit_bought) in self.recruitables_types:
total += self.deliveryEvent.units[unit_bought]
print(unit_bought, total, self.deliveryEvent.units[unit_bought])
print("=============================")
return total
def set_maximum_units(self, maximum_units):
"""
Set the maximum number of units that can be bought
"""
self.maximum_units = maximum_units
def set_recruitable_types(self, recruitables_types):
"""
Set the maximum number of units that can be bought
"""
self.recruitables_types = recruitables_types

View File

@@ -1,28 +1,35 @@
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox, QScrollArea, QFrame, QWidget
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox, QScrollArea, QFrame, QWidget, QHBoxLayout, QLabel
from game.event import UnitsDeliveryEvent
from qt_ui.uiconstants import ICONS
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
from theater import ControlPoint, CAP, CAS, db
from theater import ControlPoint, CAP, CAS, db, ControlPointType
from game import Game
class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
def __init__(self, cp:ControlPoint, game:Game):
def __init__(self, cp: ControlPoint, game: Game):
QFrame.__init__(self)
self.cp = cp
self.game = game
self.bought_amount_labels = {}
self.existing_units_labels = {}
for event in self.game.events:
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
self.deliveryEvent = event
if not self.deliveryEvent:
self.deliveryEvent = self.game.units_delivery_event(self.cp)
# Determine maximum number of aircrafts that can be bought
self.set_maximum_units(self.cp.available_aircraft_slots)
self.set_recruitable_types([CAP, CAS])
self.bought_amount_labels = {}
self.existing_units_labels = {}
self.hangar_status = QHangarStatus(self.total_units, self.cp.available_aircraft_slots)
self.init_ui()
def init_ui(self):
@@ -57,5 +64,32 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setWidgetResizable(True)
scroll.setWidget(scroll_content)
main_layout.addLayout(self.hangar_status)
main_layout.addWidget(scroll)
self.setLayout(main_layout)
def buy(self, unit_type):
super().buy(unit_type)
self.hangar_status.update_label(self.total_units, self.cp.available_aircraft_slots)
def sell(self, unit_type):
super().sell(unit_type)
self.hangar_status.update_label(self.total_units, self.cp.available_aircraft_slots)
class QHangarStatus(QHBoxLayout):
def __init__(self, current_amount: int, max_amount: int):
super(QHangarStatus, self).__init__()
self.icon = QLabel()
self.icon.setPixmap(ICONS["Hangar"])
self.text = QLabel("")
self.update_label(current_amount, max_amount)
self.addWidget(self.icon, Qt.AlignLeft)
self.addWidget(self.text, Qt.AlignLeft)
self.addStretch(50)
self.setAlignment(Qt.AlignLeft)
def update_label(self, current_amount: int, max_amount: int):
self.text.setText("<strong>{}/{}</strong>".format(current_amount, max_amount))

View File

@@ -83,7 +83,7 @@ class NewGameWizard(QtWidgets.QWizard):
print("Enemy name : " + enemy_name)
print("Player name : " + player_name)
print("Midgame : " + str(midgame))
start_generator.generate_inital_units(conflictTheater, enemy_name, True, multiplier)
start_generator.generate_initial_units(conflictTheater, enemy_name, True, multiplier)
print("-- Initial units generated")
game = Game(player_name=player_name,

View File

@@ -0,0 +1,219 @@
local unitPayloads = {
["name"] = "A-10C II",
["payloads"] = {
[1] = {
["name"] = "New Payload",
["pylons"] = {
[1] = {
["CLSID"] = "{LAU-131x3 - 7 AGR-20A}",
["num"] = 8,
},
[2] = {
["CLSID"] = "{LAU-131x3 - 7 AGR-20 M282}",
["num"] = 9,
},
[3] = {
["CLSID"] = "{LAU-131x3 - 7 AGR-20A}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{LAU-131x3 - 7 AGR-20 M282}",
["num"] = 3,
},
[5] = {
["CLSID"] = "{LAU-131 - 7 AGR-20A}",
["num"] = 2,
},
[6] = {
["CLSID"] = "{LAU-131 - 7 AGR-20A}",
["num"] = 10,
},
},
["tasks"] = {
[1] = 31,
},
},
[2] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}",
["num"] = 11,
},
[2] = {
["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
[3] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "ALQ_184",
["num"] = 1,
},
[2] = {
["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}",
["num"] = 11,
},
[3] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 10,
},
[4] = {
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
["num"] = 8,
},
[5] = {
["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}",
["num"] = 9,
},
[6] = {
["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}",
["num"] = 3,
},
[7] = {
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
["num"] = 4,
},
[8] = {
["CLSID"] = "{LAU-131 - 7 AGR-20A}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
},
},
[4] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}",
["num"] = 11,
},
[2] = {
["CLSID"] = "ALQ_184",
["num"] = 1,
},
[3] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 10,
},
[4] = {
["CLSID"] = "{GBU-38}",
["num"] = 8,
},
[5] = {
["CLSID"] = "{GBU-38}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{GBU-38}",
["num"] = 4,
},
[7] = {
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}",
["num"] = 3,
},
[8] = {
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}",
["num"] = 9,
},
[9] = {
["CLSID"] = "{GBU-38}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 31,
},
},
[5] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}",
["num"] = 11,
},
[2] = {
["CLSID"] = "ALQ_184",
["num"] = 1,
},
[3] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 10,
},
[4] = {
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 9,
},
[5] = {
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 3,
},
[6] = {
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
},
},
[6] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}",
["num"] = 11,
},
[2] = {
["CLSID"] = "ALQ_184",
["num"] = 1,
},
[3] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 10,
},
[4] = {
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 9,
},
[5] = {
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 3,
},
[6] = {
["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
["num"] = 2,
},
[7] = {
["CLSID"] = "{GBU-38}",
["num"] = 7,
},
[8] = {
["CLSID"] = "{GBU-38}",
["num"] = 5,
},
[9] = {
["CLSID"] = "{GBU-38}",
["num"] = 8,
},
[10] = {
["CLSID"] = "{GBU-38}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
},
},
},
["unitType"] = "A-10C_2",
}
return unitPayloads

View File

@@ -1,9 +1,5 @@
local jsonlib = {{json_file_abs_location}}
json = loadfile(jsonlib)()
logger = mist.Logger:new("DCSLiberation", "info")
debriefing_file_location = {{debriefing_file_location}}
logger:info("Check that json.lua is loaded : json = "..tostring(json))
killed_aircrafts = {}
killed_ground_units = {}
@@ -32,12 +28,56 @@ write_state = function()
["mission_ended"] = mission_ended,
["destroyed_objects_positions"] = destroyed_objects_positions,
}
if not json then
local message = string.format("Unable to save DCS Liberation state to %s, JSON library is not loaded !",debriefing_file_location)
logger:error(message)
messageAll(message)
end
fp:write(json:encode(game_state))
fp:close()
-- logger.info("Done writing DCS Liberation state")
-- messageAll("Done writing DCS Liberation state.")
end
debriefing_file_location = nil
if dcsLiberation then
debriefing_file_location = dcsLiberation.installPath
end
if debriefing_file_location then
logger:info("Using DCS Liberation install folder for state.json")
else
if os then
debriefing_file_location = os.getenv("LIBERATION_EXPORT_DIR")
if debriefing_file_location then debriefing_file_location = debriefing_file_location .. "\\" end
end
if debriefing_file_location then
logger:info("Using LIBERATION_EXPORT_DIR environment variable for state.json")
else
if os then
debriefing_file_location = os.getenv("TEMP")
if debriefing_file_location then debriefing_file_location = debriefing_file_location .. "\\" end
end
if debriefing_file_location then
logger:info("Using TEMP environment variable for state.json")
else
if lfs then
debriefing_file_location = lfs.writedir()
end
if debriefing_file_location then
logger:info("Using DCS working directory for state.json")
end
end
end
end
if debriefing_file_location then
local filename = "state.json"
if not debriefing_file_location:sub(-#filename) == filename then
debriefing_file_location = debriefing_file_location .. filename
end
logger:info(string.format("DCS Liberation state will be written as json to [[%s]]",debriefing_file_location))
else
logger:error("No usable storage path for state.json")
end
write_state_error_handling = function()
if pcall(write_state) then

View File

@@ -968,7 +968,7 @@ function OBJDEF:new(args)
return setmetatable(new, OBJDEF)
end
return OBJDEF:new()
json = OBJDEF:new()
--
-- Version history:

View File

@@ -0,0 +1,29 @@
# this is a list of lua scripts that will be injected in the mission, in the same order
mist.lua
Moose.lua
CTLD.lua
NIOD.lua
WeatherMark.lua
veaf.lua
dcsUnits.lua
# JTACAutoLase is an empty file, only there to disable loading the official script (already included in CTLD)
JTACAutoLase.lua
veafAssets.lua
veafCarrierOperations.lua
veafCarrierOperations2.lua
veafCasMission.lua
veafCombatMission.lua
veafCombatZone.lua
veafGrass.lua
veafInterpreter.lua
veafMarkers.lua
veafMove.lua
veafNamedPoints.lua
veafRadio.lua
veafRemote.lua
veafSecurity.lua
veafShortcuts.lua
veafSpawn.lua
veafTransportMission.lua
veafUnits.lua
missionConfig.lua

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -102,14 +102,23 @@ class ControlPoint:
@property
def is_carrier(self):
"""
:return: Whether this control point is an aircraft carrier
"""
return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]
@property
def is_fleet(self):
"""
:return: Whether this control point is a boat (mobile)
"""
return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]
@property
def is_lha(self):
"""
:return: Whether this control point is an LHA
"""
return self.cptype in [ControlPointType.LHA_GROUP]
@property
@@ -122,6 +131,20 @@ class ControlPoint:
result.append(r)
return result
@property
def available_aircraft_slots(self):
"""
:return: The maximum number of aircraft that can be stored in this control point
"""
if self.cptype == ControlPointType.AIRBASE:
return len(self.airport.parking_slots)
elif self.is_lha:
return 20
elif self.is_carrier:
return 90
else:
return 0
def connect(self, to):
self.connected_points.append(to)
self.stances[to.id] = CombatStance.DEFENSIVE

View File

@@ -27,7 +27,7 @@ COUNT_BY_TASK = {
}
def generate_inital_units(theater: ConflictTheater, enemy_country: str, sams: bool, multiplier: float):
def generate_initial_units(theater: ConflictTheater, enemy_country: str, sams: bool, multiplier: float):
for cp in theater.enemy_points():
if cp.captured:
continue