Merge pull request #167 from Khopa/develop

Release 2.1.3
This commit is contained in:
C. Perreau 2020-10-01 23:23:06 +02:00 committed by GitHub
commit 2066a2e9bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 528 additions and 79 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/

4
.gitmodules vendored
View File

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

11
.vscode/launch.json vendored
View File

@ -14,6 +14,17 @@
"PYTHONPATH": ".;./pydcs" "PYTHONPATH": ".;./pydcs"
}, },
"preLaunchTask": "Prepare Environment" "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,19 @@
# 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 # 2.1.2
## Fixes : ## Fixes :

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -250,41 +250,81 @@ class Operation:
print(e) print(e)
# Inject Mist Script if not done already in the plugins # 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 mist twice 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") trigger = TriggerStart(comment="Load Mist Lua framework")
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/mist_4_3_74.lua") fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/mist_4_3_74.lua")
trigger.add_action(DoScriptFile(fileref)) trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger) self.current_mission.triggerrules.triggers.append(trigger)
# Inject Liberation script # Inject JSON library if not done already in the plugins
load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script") if not "json.lua" in listOfPluginsScripts : # don't load the script twice
with open("./resources/scripts/dcs_liberation.lua") as f: trigger = TriggerStart(comment="Load JSON Lua library")
script = f.read() fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/json.lua")
json_location = "[["+os.path.abspath("resources\\scripts\\json.lua")+"]]" trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger)
# 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)
# 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") + "]]" state_location = "[[" + os.path.abspath("state.json") + "]]"
script = script.replace("{{json_file_abs_location}}", json_location) lua = """
script = script.replace("{{debriefing_file_location}}", state_location) -- setting configuration table
load_dcs_libe.add_action(DoScript(String(script))) env.info("DCSLiberation|: setting configuration table")
self.current_mission.triggerrules.triggers.append(load_dcs_libe)
# Load Ciribob's JTACAutoLase script if not done already in the plugins -- all data in this table is overridable.
if not "JTACAutoLase.lua" in listOfPluginsScripts: # don't load JTACAutoLase twice dcsLiberation = {}
load_autolase = TriggerStart(comment="Load JTAC script")
with open("./resources/scripts/JTACAutoLase.lua") as f:
script = f.read() -- the base location for state.json; if non-existent, it'll be replaced with LIBERATION_EXPORT_DIR, TEMP, or DCS working directory
script = script + "\n" 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 = {}
"""
trigger = TriggerStart(comment="Set DCS Liberation data")
trigger.add_action(DoScript(String(lua)))
self.current_mission.triggerrules.triggers.append(trigger)
# 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)
# add a configuration for JTACAutoLase and start lasing for all JTACs
smoke = "true" smoke = "true"
if hasattr(self.game.settings, "jtac_smoke_on"): if hasattr(self.game.settings, "jtac_smoke_on"):
if not self.game.settings.jtac_smoke_on: if not self.game.settings.jtac_smoke_on:
smoke = "false" smoke = "false"
for jtac in jtacs: lua = """
script += f"\nJTACAutoLase('{jtac.unit_name}', {jtac.code}, {smoke}, 'vehicle')\n" -- setting and starting JTACs
env.info("DCSLiberation|: setting and starting JTACs")
"""
load_autolase.add_action(DoScript(String(script))) for jtac in jtacs:
self.current_mission.triggerrules.triggers.append(load_autolase) 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() self.assign_channels_to_flights()

View File

@ -279,13 +279,15 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
last_channel = flight.num_radio_channels(radio_id) last_channel = flight.num_radio_channels(radio_id)
channel_alloc = iter(range(first_channel, last_channel + 1)) 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. # TODO: If there ever are multiple AWACS, limit to mission relevant.
for awacs in air_support.awacs: for awacs in air_support.awacs:
flight.assign_channel(radio_id, next(channel_alloc), awacs.freq) 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.assign_channel(radio_id, next(channel_alloc),
flight.arrival.atc) flight.arrival.atc)
@ -295,7 +297,7 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
flight.assign_channel( flight.assign_channel(
radio_id, next(channel_alloc), tanker.freq) 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.assign_channel(radio_id, next(channel_alloc),
flight.divert.atc) flight.divert.atc)
except StopIteration: except StopIteration:

View File

@ -99,6 +99,7 @@ CAS_CAPABLE = [
A_10A, A_10A,
A_10C, A_10C,
A_10C_2,
AV8BNA, AV8BNA,
F_86F_Sabre, F_86F_Sabre,
@ -197,6 +198,7 @@ STRIKE_CAPABLE = [
A_10A, A_10A,
A_10C, A_10C,
A_10C_2,
AV8BNA, AV8BNA,
F_86F_Sabre, F_86F_Sabre,
@ -244,6 +246,7 @@ ANTISHIP_CAPABLE = [
F_16A, F_16A,
F_16C_50, F_16C_50,
A_10C, A_10C,
A_10C_2,
A_10A, A_10A,
Tornado_IDS, Tornado_IDS,

2
pydcs

@ -1 +1 @@
Subproject commit 7b7c0322856c43ed8d1c7d29b2e30121129af048 Subproject commit ceea62a8e0731c21b3e1a3e90682aa0affc168f1

View File

@ -8,7 +8,7 @@ from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP from theater.theatergroundobject import CATEGORY_MAP
from userdata.liberation_theme import get_theme_icons from userdata.liberation_theme import get_theme_icons
VERSION_STRING = "2.1.2" VERSION_STRING = "2.1.3"
URLS : Dict[str, str] = { URLS : Dict[str, str] = {
"Manual": "https://github.com/khopa/dcs_liberation/wiki", "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["New"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/new.png")
ICONS["Open"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/open.png") ICONS["Open"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/open.png")
ICONS["Save"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/save.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_Caucasus"] = QPixmap("./resources/ui/terrain_caucasus.gif")
ICONS["Terrain_Persian_Gulf"] = QPixmap("./resources/ui/terrain_pg.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[aircraft[:-7]] = QPixmap(os.path.join("./resources/ui/units/aircrafts/", aircraft))
AIRCRAFT_ICONS["F-16C_50"] = AIRCRAFT_ICONS["F-16C"] AIRCRAFT_ICONS["F-16C_50"] = AIRCRAFT_ICONS["F-16C"]
AIRCRAFT_ICONS["FA-18C_hornet"] = AIRCRAFT_ICONS["FA-18C"] AIRCRAFT_ICONS["FA-18C_hornet"] = AIRCRAFT_ICONS["FA-18C"]
AIRCRAFT_ICONS["A-10C_2"] = AIRCRAFT_ICONS["A-10C"]
def load_vehicle_icons(): def load_vehicle_icons():

View File

@ -221,7 +221,7 @@ class QLiberationWindow(QMainWindow):
"<h4>Authors</h4>" + \ "<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>." \ "<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>" + \ "<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>" \ "<h4>Special Thanks :</h4>" \
"<b>rp-</b> <i>for the pydcs framework</i><br/>"\ "<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/>"\

View File

@ -1,3 +1,5 @@
import logging
from PySide2.QtWidgets import QLabel, QPushButton, \ from PySide2.QtWidgets import QLabel, QPushButton, \
QSizePolicy, QSpacerItem, QGroupBox, QHBoxLayout QSizePolicy, QSpacerItem, QGroupBox, QHBoxLayout
from dcs.unittype import UnitType from dcs.unittype import UnitType
@ -11,11 +13,14 @@ class QRecruitBehaviour:
deliveryEvent = None deliveryEvent = None
existing_units_labels = None existing_units_labels = None
bought_amount_labels = None bought_amount_labels = None
maximum_units = -1
recruitable_types = []
BUDGET_FORMAT = "Available Budget: <b>${}M</b>" BUDGET_FORMAT = "Available Budget: <b>${}M</b>"
def __init__(self): def __init__(self):
self.bought_amount_labels = {} self.bought_amount_labels = {}
self.existing_units_labels = {} self.existing_units_labels = {}
self.recruitable_types = []
self.update_available_budget() self.update_available_budget()
def add_purchase_row(self, unit_type, layout, row): def add_purchase_row(self, unit_type, layout, row):
@ -66,7 +71,6 @@ class QRecruitBehaviour:
sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell.clicked.connect(lambda: self.sell(unit_type)) sell.clicked.connect(lambda: self.sell(unit_type))
existLayout.addWidget(unitName) existLayout.addWidget(unitName)
existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)) existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
existLayout.addWidget(existing_units) existLayout.addWidget(existing_units)
@ -102,10 +106,19 @@ class QRecruitBehaviour:
def buy(self, unit_type): 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] price = db.PRICES[unit_type]
if self.game.budget >= price: if self.game.budget >= price:
self.deliveryEvent.deliver({unit_type: 1}) self.deliveryEvent.deliver({unit_type: 1})
self.game.budget -= price self.game.budget -= price
else:
# TODO : display modal warning
logging.info("Not enough money !")
self._update_count_label(unit_type) self._update_count_label(unit_type)
self.update_available_budget() self.update_available_budget()
@ -123,3 +136,34 @@ class QRecruitBehaviour:
self._update_count_label(unit_type) self._update_count_label(unit_type)
self.update_available_budget() 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,9 +1,10 @@
from PySide2.QtCore import Qt 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 game.event import UnitsDeliveryEvent
from qt_ui.uiconstants import ICONS
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour 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 from game import Game
@ -14,15 +15,21 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
self.cp = cp self.cp = cp
self.game = game self.game = game
self.bought_amount_labels = {}
self.existing_units_labels = {}
for event in self.game.events: for event in self.game.events:
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp: if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
self.deliveryEvent = event self.deliveryEvent = event
if not self.deliveryEvent: if not self.deliveryEvent:
self.deliveryEvent = self.game.units_delivery_event(self.cp) 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() self.init_ui()
def init_ui(self): def init_ui(self):
@ -57,5 +64,32 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setWidgetResizable(True) scroll.setWidgetResizable(True)
scroll.setWidget(scroll_content) scroll.setWidget(scroll_content)
main_layout.addLayout(self.hangar_status)
main_layout.addWidget(scroll) main_layout.addWidget(scroll)
self.setLayout(main_layout) 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

@ -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") logger = mist.Logger:new("DCSLiberation", "info")
logger:info("Check that json.lua is loaded : json = "..tostring(json))
debriefing_file_location = {{debriefing_file_location}}
killed_aircrafts = {} killed_aircrafts = {}
killed_ground_units = {} killed_ground_units = {}
@ -32,12 +28,56 @@ write_state = function()
["mission_ended"] = mission_ended, ["mission_ended"] = mission_ended,
["destroyed_objects_positions"] = destroyed_objects_positions, ["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:write(json:encode(game_state))
fp:close() fp:close()
-- logger.info("Done writing DCS Liberation state") -- logger.info("Done writing DCS Liberation state")
-- messageAll("Done writing DCS Liberation state.") -- messageAll("Done writing DCS Liberation state.")
end 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() write_state_error_handling = function()
if pcall(write_state) then if pcall(write_state) then

View File

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

View File

@ -1,29 +0,0 @@
rem this can be used to easily create hardlinks from your plugin development folder
mklink mist.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\community\mist.lua
mklink Moose.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\community\Moose.lua
mklink CTLD.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\community\CTLD.lua
mklink NIOD.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\community\NIOD.lua
mklink WeatherMark.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\community\WeatherMark.lua
mklink veaf.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veaf.lua
mklink dcsUnits.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\dcsUnits.lua
mklink JTACAutoLase.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\JTACAutoLase.lua
mklink veafAssets.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafAssets.lua
mklink veafCarrierOperations.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafCarrierOperations.lua
mklink veafCarrierOperations2.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafCarrierOperations2.lua
mklink veafCasMission.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafCasMission.lua
mklink veafCombatMission.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafCombatMission.lua
mklink veafCombatZone.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafCombatZone.lua
mklink veafGrass.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafGrass.lua
mklink veafInterpreter.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafInterpreter.lua
mklink veafMarkers.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafMarkers.lua
mklink veafMove.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafMove.lua
mklink veafNamedPoints.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafNamedPoints.lua
mklink veafRadio.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafRadio.lua
mklink veafRemote.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafRemote.lua
mklink veafSecurity.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafSecurity.lua
mklink veafShortcuts.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafShortcuts.lua
mklink veafSpawn.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafSpawn.lua
mklink veafTransportMission.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafTransportMission.lua
mklink veafUnits.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\veafUnits.lua
mklink missionConfig.lua d:\dev\_VEAF\VEAF-Mission-Creation-Tools\src\scripts\veaf\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 @property
def is_carrier(self): def is_carrier(self):
"""
:return: Whether this control point is an aircraft carrier
"""
return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP] return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]
@property @property
def is_fleet(self): def is_fleet(self):
"""
:return: Whether this control point is a boat (mobile)
"""
return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP] return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]
@property @property
def is_lha(self): def is_lha(self):
"""
:return: Whether this control point is an LHA
"""
return self.cptype in [ControlPointType.LHA_GROUP] return self.cptype in [ControlPointType.LHA_GROUP]
@property @property
@ -122,6 +131,20 @@ class ControlPoint:
result.append(r) result.append(r)
return result 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): def connect(self, to):
self.connected_points.append(to) self.connected_points.append(to)
self.stances[to.id] = CombatStance.DEFENSIVE self.stances[to.id] = CombatStance.DEFENSIVE