Compare commits

...

29 Commits
2.1.2 ... 2.1.4

Author SHA1 Message Date
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
51 changed files with 550 additions and 95 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,24 @@
# 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 # 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

@@ -190,9 +190,9 @@ class Game:
def is_player_attack(self, event): def is_player_attack(self, event):
if isinstance(event, 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: 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): def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint] = None):

View File

@@ -236,55 +236,96 @@ class Operation:
# Inject Plugins Lua Scripts # Inject Plugins Lua Scripts
listOfPluginsScripts = [] listOfPluginsScripts = []
try: plugin_file_path = Path("./resources/scripts/plugins/__plugins.lst")
with open("./resources/scripts/plugins/__plugins.lst", "r") as a_file: if plugin_file_path.exists():
for line in a_file: for line in plugin_file_path.read_text().splitlines():
name = line.strip() name = line.strip()
if not name.startswith( '#' ): if not name.startswith( '#' ):
trigger = TriggerStart(comment="Load " + name) trigger = TriggerStart(comment="Load " + name)
listOfPluginsScripts.append(name) listOfPluginsScripts.append(name)
fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/plugins/" + name) fileref = self.current_mission.map_resource.add_resource_file("./resources/scripts/plugins/" + name)
trigger.add_action(DoScriptFile(fileref)) trigger.add_action(DoScriptFile(fileref))
self.current_mission.triggerrules.triggers.append(trigger) self.current_mission.triggerrules.triggers.append(trigger)
except Exception as e: else:
print(e) logging.info(
f"Not loading plugins, {plugin_file_path} does not exist")
# 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))
state_location = "[[" + os.path.abspath("state.json") + "]]" self.current_mission.triggerrules.triggers.append(trigger)
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)
# Load Ciribob's JTACAutoLase script if not done already in the plugins # Inject Ciribob's JTACAutoLase if not done already in the plugins
if not "JTACAutoLase.lua" in listOfPluginsScripts: # don't load JTACAutoLase twice if not "JTACAutoLase.lua" in listOfPluginsScripts : # don't load the script twice
load_autolase = TriggerStart(comment="Load JTAC script") trigger = TriggerStart(comment="Load JTACAutoLase.lua script")
with open("./resources/scripts/JTACAutoLase.lua") as f: 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)
script = f.read() # set a LUA table with data from Liberation that we want to set
script = script + "\n" # 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 = {}
"""
smoke = "true" trigger = TriggerStart(comment="Set DCS Liberation data")
if hasattr(self.game.settings, "jtac_smoke_on"): trigger.add_action(DoScript(String(lua)))
if not self.game.settings.jtac_smoke_on: self.current_mission.triggerrules.triggers.append(trigger)
smoke = "false"
for jtac in jtacs: # Inject DCS-Liberation script if not done already in the plugins
script += f"\nJTACAutoLase('{jtac.unit_name}', {jtac.code}, {smoke}, 'vehicle')\n" 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)
load_autolase.add_action(DoScript(String(script))) # add a configuration for JTACAutoLase and start lasing for all JTACs
self.current_mission.triggerrules.triggers.append(load_autolase) 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() 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

Submodule pydcs updated: f46781b854...ceea62a8e0

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.4"
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,28 +1,35 @@
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
class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour): class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
def __init__(self, cp:ControlPoint, game:Game): def __init__(self, cp: ControlPoint, game: Game):
QFrame.__init__(self) QFrame.__init__(self)
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

@@ -83,7 +83,7 @@ class NewGameWizard(QtWidgets.QWizard):
print("Enemy name : " + enemy_name) print("Enemy name : " + enemy_name)
print("Player name : " + player_name) print("Player name : " + player_name)
print("Midgame : " + str(midgame)) 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") print("-- Initial units generated")
game = Game(player_name=player_name, 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") 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

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(): for cp in theater.enemy_points():
if cp.captured: if cp.captured:
continue continue