Merge branch 'develop_mission_planner' into ato

This commit is contained in:
C. Perreau 2020-10-02 13:26:21 +02:00 committed by GitHub
commit 028292a023
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 991 additions and 169 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/*

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,22 +1,60 @@
# 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 :
* **[Other]** Added an installer option (thanks to contributor parithon)
* **[Cheat Menu]** Added possibility to replace destroyed SAM and base defenses units for the player (Click on a SAM site to fix it)
* **[Cheat Menu]** Added recon images for buildings on strike targets, click on a Strike target to get detailled informations
* **[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. (Thanks to contributor danalbert)
* **[Radios]** Allocate separate intra-flight channels for most aircraft to reduce global
chatter. (Thanks to contributor danalbert)
* **[Radios]** Configure radio channel presets for most aircraft. Currently supported are:
* AJS37
* AV-8B
* F-14B
* F-16C
* F/A-18C
* JF-17
* 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
* **[Units/Factions]** Added F-16C to USA 1990
* **[Units/Factions]** Added MQ-9 Reaper as CAS unit for USA 2005
* **[Units/Factions]** Added Mig-21, Mig-23, SA-342L to Syria 2011
* **[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
* **[Mission Generator]** AH-1W was not used by AI to generate CAS mission by default
* **[Mission Generator]** Fixed F-16C targeting pod not being added to payload
* **[Mission Generator]** AH-64A and AH-64D payloads fix.
* **[Units/Factions]** China will use KJ-2000 as awacs instead of A-50
# 2.1.0

View File

@ -192,6 +192,7 @@ PRICES = {
A_10A: 16,
A_10C: 22,
A_10C_2: 24,
# heli
Ka_50: 13,
@ -223,13 +224,16 @@ PRICES = {
KC130: 25,
A_50: 50,
KJ_2000: 50,
E_3A: 50,
C_130: 25,
# WW2
P_51D_30_NA: 18,
P_51D: 16,
P_47D_30: 18,
P_47D_30: 17,
P_47D_30bl1: 16,
P_47D_40: 18,
B_17G: 30,
# Drones
@ -495,6 +499,7 @@ UNIT_BY_TASK = {
AJS37,
A_10A,
A_10C,
A_10C_2,
Su_17M4,
Su_25,
Su_25T,
@ -519,6 +524,8 @@ UNIT_BY_TASK = {
MiG_27K,
A_20G,
P_47D_30,
P_47D_30bl1,
P_47D_40,
Ju_88A4,
B_17G,
MB_339PAN,
@ -542,7 +549,7 @@ UNIT_BY_TASK = {
KC130,
S_3B_Tanker,
],
AWACS: [E_3A, A_50, ],
AWACS: [E_3A, A_50, KJ_2000],
PinpointStrike: [
Armor.APC_MTLB,
Armor.APC_MTLB,
@ -952,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,
@ -993,6 +1001,8 @@ PLANE_PAYLOAD_OVERRIDES = {
Su_17M4: COMMON_OVERRIDE,
F_4E: COMMON_OVERRIDE,
P_47D_30:COMMON_OVERRIDE,
P_47D_30bl1:COMMON_OVERRIDE,
P_47D_40:COMMON_OVERRIDE,
B_17G: COMMON_OVERRIDE,
P_51D: COMMON_OVERRIDE,
P_51D_30_NA: COMMON_OVERRIDE,

View File

@ -267,7 +267,7 @@ class Event:
ratio = (1.0 + enemy_casualties) / (1.0 + ally_casualties)
player_aggresive = cp.stances[enemy_cp.id] in [CombatStance.AGGRESIVE, CombatStance.ELIMINATION, CombatStance.BREAKTHROUGH]
player_aggresive = cp.stances[enemy_cp.id] in [CombatStance.AGGRESSIVE, CombatStance.ELIMINATION, CombatStance.BREAKTHROUGH]
if ally_units_alive == 0:
player_won = False

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

@ -20,7 +20,7 @@ China_2010 = {
An_30M,
Yak_40,
A_50,
KJ_2000,
Mi_8MT,
Mi_28N,

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

@ -234,39 +234,97 @@ class Operation:
if self.game.settings.perf_smoke_gen:
self.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 = []
try:
with open("./resources/scripts/plugins/__plugins.lst", "r") as a_file:
for line in a_file:
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)
except Exception as e:
print(e)
# 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)
# 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()

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()
),

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

@ -43,7 +43,7 @@ class GroundConflictGenerator:
self.enemy_planned_combat_groups = enemy_planned_combat_groups
self.player_planned_combat_groups = player_planned_combat_groups
self.player_stance = CombatStance(player_stance)
self.enemy_stance = random.choice([CombatStance.AGGRESIVE, CombatStance.AGGRESIVE, CombatStance.AGGRESIVE, CombatStance.ELIMINATION, CombatStance.BREAKTHROUGH]) if len(enemy_planned_combat_groups) > len(player_planned_combat_groups) else random.choice([CombatStance.DEFENSIVE, CombatStance.DEFENSIVE, CombatStance.DEFENSIVE, CombatStance.AMBUSH, CombatStance.AGGRESIVE])
self.enemy_stance = random.choice([CombatStance.AGGRESSIVE, CombatStance.AGGRESSIVE, CombatStance.AGGRESSIVE, CombatStance.ELIMINATION, CombatStance.BREAKTHROUGH]) if len(enemy_planned_combat_groups) > len(player_planned_combat_groups) else random.choice([CombatStance.DEFENSIVE, CombatStance.DEFENSIVE, CombatStance.DEFENSIVE, CombatStance.AMBUSH, CombatStance.AGGRESSIVE])
self.game = game
self.jtacs: List[JtacInfo] = []
@ -239,7 +239,7 @@ class GroundConflictGenerator:
u.heading = forward_heading + random.randint(-5,5)
elif group.role in [CombatGroupRole.TANK, CombatGroupRole.IFV]:
if stance == CombatStance.AGGRESIVE:
if stance == CombatStance.AGGRESSIVE:
# Attack nearest enemy if any
# Then move forward OR Attack enemy base if it is not too far away
target = self.find_nearest_enemy_group(dcs_group, enemy_groups)
@ -280,7 +280,7 @@ class GroundConflictGenerator:
elif group.role in [CombatGroupRole.APC, CombatGroupRole.ATGM]:
if stance in [CombatStance.AGGRESIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
if stance in [CombatStance.AGGRESSIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
# APC & ATGM will never move too much forward, but will follow along any offensive
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
attack_point = to_cp.position.random_point_within(500, 0)

View File

@ -205,7 +205,7 @@ class BriefingGenerator(MissionInfoGenerator):
self.description += "We do not have a single vehicle available to hold our position, the situation is critical, and we will lose ground inevitably.\n"
elif enemy_base.base.total_armor == 0:
self.description += "The enemy forces have been crushed, we will be able to make significant progress toward " + enemy_base.name + ". \n"
if stance == CombatStance.AGGRESIVE:
if stance == CombatStance.AGGRESSIVE:
if has_numerical_superiority:
self.description += "On this location, our ground forces will try to make progress against the enemy"
self.description += ". As the enemy is outnumbered, our forces should have no issue making progress.\n"

View File

@ -3,22 +3,38 @@ import random
from dcs.vehicles import Armor
from game import db
from gen.defenses.armored_group_generator import ArmoredGroupGenerator
from gen.defenses.armored_group_generator import ArmoredGroupGenerator, FixedSizeArmorGroupGenerator
def generate_armor_group(faction:str, game, ground_object):
"""
This generate a group of ground units
:param parentCp: The parent control point
:param ground_object: The ground object which will own the group
:param country: Owner country
:return: Generated group
"""
possible_unit = [u for u in db.FACTIONS[faction]["units"] if u in Armor.__dict__.values()]
if len(possible_unit) > 0:
unit_type = random.choice(possible_unit)
generator = ArmoredGroupGenerator(game, ground_object, unit_type)
generator.generate()
return generator.get_generated_group()
return generate_armor_group_of_type(game, ground_object, unit_type)
return None
def generate_armor_group_of_type(game, ground_object, unit_type):
"""
This generate a group of ground units of given type
:return: Generated group
"""
generator = ArmoredGroupGenerator(game, ground_object, unit_type)
generator.generate()
return generator.get_generated_group()
def generate_armor_group_of_type_and_size(game, ground_object, unit_type, size: int):
"""
This generate a group of ground units of given type and size
:return: Generated group
"""
generator = FixedSizeArmorGroupGenerator(game, ground_object, unit_type, size)
generator.generate()
return generator.get_generated_group()

View File

@ -25,3 +25,20 @@ class ArmoredGroupGenerator(GroupGenerator):
self.position.y + spacing * j, self.heading)
class FixedSizeArmorGroupGenerator(GroupGenerator):
def __init__(self, game, ground_object, unit_type, size):
super(FixedSizeArmorGroupGenerator, self).__init__(game, ground_object)
self.unit_type = unit_type
self.size = size
def generate(self):
spacing = random.randint(20, 70)
index = 0
for i in range(self.size):
index = index + 1
self.add_unit(self.unit_type, "Armor#" + str(index),
self.position.x + spacing * i,
self.position.y, self.heading)

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,
@ -62,6 +63,8 @@ CAP_CAPABLE = [
P_51D_30_NA,
P_51D,
P_47D_30,
P_47D_30bl1,
P_47D_40,
SpitfireLFMkIXCW,
SpitfireLFMkIX,
@ -96,6 +99,7 @@ CAS_CAPABLE = [
A_10A,
A_10C,
A_10C_2,
AV8BNA,
F_86F_Sabre,
@ -106,6 +110,9 @@ CAS_CAPABLE = [
F_16C_50,
FA_18C_hornet,
Tornado_IDS,
Tornado_GR4,
C_101CC,
MB_339PAN,
L_39ZA,
@ -119,7 +126,6 @@ CAS_CAPABLE = [
AH_64D,
AH_1W,
UH_1H,
Mi_8MT,
@ -130,6 +136,8 @@ CAS_CAPABLE = [
P_51D_30_NA,
P_51D,
P_47D_30,
P_47D_30bl1,
P_47D_40,
A_20G,
SpitfireLFMkIXCW,
@ -164,6 +172,9 @@ SEAD_CAPABLE = [
Su_34,
MiG_27K,
Tornado_IDS,
Tornado_GR4,
A_4E_C,
Rafale_A_S
]
@ -187,6 +198,7 @@ STRIKE_CAPABLE = [
A_10A,
A_10C,
A_10C_2,
AV8BNA,
F_86F_Sabre,
@ -197,6 +209,9 @@ STRIKE_CAPABLE = [
F_16C_50,
FA_18C_hornet,
Tornado_IDS,
Tornado_GR4,
C_101CC,
L_39ZA,
AJS37,
@ -204,6 +219,8 @@ STRIKE_CAPABLE = [
P_51D_30_NA,
P_51D,
P_47D_30,
P_47D_30bl1,
P_47D_40,
A_20G,
B_17G,
@ -229,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

@ -197,7 +197,7 @@ DISTANCE_FROM_FRONTLINE = {
GROUP_SIZES_BY_COMBAT_STANCE = {
CombatStance.DEFENSIVE: [2, 4, 6],
CombatStance.AGGRESIVE: [2, 4, 6],
CombatStance.AGGRESSIVE: [2, 4, 6],
CombatStance.RETREAT: [2, 4, 6, 8],
CombatStance.BREAKTHROUGH: [4, 6, 6, 8],
CombatStance.ELIMINATION: [2, 4, 4, 4, 6],

View File

@ -3,7 +3,7 @@ from enum import Enum
class CombatStance(Enum):
DEFENSIVE = 0 # Unit will adopt defensive stance with medium group of units
AGGRESIVE = 1 # Unit will attempt to make progress with medium sized group of units
AGGRESSIVE = 1 # Unit will attempt to make progress with medium sized group of units
RETREAT = 2 # Unit will retreat
BREAKTHROUGH = 3 # Unit will attempt a breakthrough, rushing forward very aggresively with big group of armored units, and even less armored units will move aggresively
ELIMINATION = 4 # Unit will progress aggresively toward anemy units, attempting to eliminate the ennemy force

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

View File

@ -124,7 +124,7 @@ RADIOS: List[Radio] = [
# 4 preset channels (A/B/C/D)
Radio("SCR522", MHz(100), MHz(156), step=kHz(25)),
Radio("R&S M3AR VHF", MHz(108), MHz(174), step=MHz(1)),
Radio("R&S M3AR VHF", MHz(120), MHz(174), step=MHz(1)),
Radio("R&S M3AR UHF", MHz(225), MHz(400), step=MHz(1)),
]

2
pydcs

@ -1 +1 @@
Subproject commit f46781b854102a9f06948c8fb81a40331b78459e
Subproject commit ceea62a8e0731c21b3e1a3e90682aa0affc168f1

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.0"
VERSION_STRING = "2.1.3"
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

@ -243,7 +243,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, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody" + \
"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

@ -6,18 +6,28 @@ from PySide2.QtWidgets import (
QSizePolicy,
QSpacerItem,
)
import logging
from dcs.unittype import UnitType
from theater import db
class QRecruitBehaviour:
game = None
cp = None
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) -> None:
self.deliveryEvent = None
self.bought_amount_labels = {}
self.existing_units_labels = {}
self.recruitable_types = []
self.update_available_budget()
@property
@ -75,7 +85,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)
@ -112,10 +121,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.budget >= price:
self.deliveryEvent.deliver({unit_type: 1})
self.budget -= price
else:
# TODO : display modal warning
logging.info("Not enough money !")
self._update_count_label(unit_type)
self.update_available_budget()
@ -133,3 +151,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

@ -31,6 +31,15 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
if not self.deliveryEvent:
self.deliveryEvent = self.game_model.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):
@ -66,5 +75,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

@ -35,12 +35,12 @@ class QBaseDefenseGroupInfo(QGroupBox):
def buildLayout(self):
unit_dict = {}
for i in range(self.unit_layout.count()):
item = self.unit_layout.itemAt(i)
if item is not None and item.widget() is not None:
self.unit_layout.removeItem(item)
item.widget().setParent(None)
item.widget().deleteLater()
for i in range(self.unit_layout.rowCount()):
for j in range(self.unit_layout.columnCount()):
item = self.unit_layout.itemAtPosition(i, j)
if item is not None and item.widget() is not None:
item.widget().setParent(None)
print("Remove " + str(i) + ", " + str(j))
for g in self.ground_object.groups:
for u in g.units:
@ -60,6 +60,11 @@ class QBaseDefenseGroupInfo(QGroupBox):
self.unit_layout.addWidget(QLabel(str(v) + " x " + "<strong>" + k + "</strong>"), i, 1)
i = i + 1
if len(unit_dict.items()) == 0:
self.unit_layout.addWidget(QLabel("/"), 0, 0)
self.setLayout(self.main_layout)
def onManage(self):

View File

@ -1,7 +1,7 @@
import logging
from PySide2 import QtCore
from PySide2.QtGui import QCloseEvent, Qt
from PySide2.QtGui import Qt
from PySide2.QtWidgets import QHBoxLayout, QDialog, QGridLayout, QLabel, QGroupBox, QVBoxLayout, QPushButton, \
QComboBox, QSpinBox, QMessageBox
from dcs import Point
@ -9,7 +9,7 @@ from dcs import Point
from game import Game, db
from game.data.building_data import FORTIFICATION_BUILDINGS
from game.db import PRICES, unit_type_of, PinpointStrike
from gen.defenses.armor_group_generator import generate_armor_group
from gen.defenses.armor_group_generator import generate_armor_group_of_type_and_size
from gen.sam.sam_group_generator import get_faction_possible_sams_generator
from qt_ui.uiconstants import EVENT_ICONS
from qt_ui.widgets.QBudgetBox import QBudgetBox
@ -288,7 +288,9 @@ class QBuyGroupForGroundObjectDialog(QDialog):
self.buyArmorButton.setText("Buy [$" + str(db.PRICES[self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())] * self.amount.value()) + "M][-$" + str(self.current_group_value) + "M]")
def buyArmor(self):
print("Buy Armor ")
utype = self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())
print(utype)
price = db.PRICES[utype] * self.amount.value() - self.current_group_value
if price > self.game.budget:
self.error_money()
@ -298,7 +300,7 @@ class QBuyGroupForGroundObjectDialog(QDialog):
self.game.budget -= price
# Generate Armor
group = generate_armor_group(self.game.player_name, self.game, self.ground_object)
group = generate_armor_group_of_type_and_size(self.game, self.ground_object, utype, int(self.amount.value()))
self.ground_object.groups = [group]
GameUpdateSignal.get_instance().updateBudget(self.game)

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

@ -2,41 +2,84 @@ local unitPayloads = {
["name"] = "F-16C_50",
["payloads"] = {
[1] = {
["name"] = "ANTISHIP",
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "LAU3_HE5",
["num"] = 6,
["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}",
["num"] = 5,
},
[2] = {
["CLSID"] = "LAU3_HE5",
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 7,
},
[3] = {
["CLSID"] = "LAU3_HE5",
["num"] = 4,
},
[4] = {
["CLSID"] = "LAU3_HE5",
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 3,
},
[5] = {
[4] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 2,
},
[6] = {
[5] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 1,
},
[7] = {
[6] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 8,
},
[8] = {
[7] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 9,
},
[8] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
["num"] = 4,
},
[9] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
["num"] = 6,
},
[10] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 11,
},
},
["tasks"] = {
},
},
[2] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 7,
},
[2] = {
["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 1,
},
[5] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 8,
},
[6] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 9,
},
[7] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 11,
},
[8] = {
["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}",
["num"] = 5,
},
@ -44,7 +87,7 @@ local unitPayloads = {
["tasks"] = {
},
},
[2] = {
[3] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
@ -87,53 +130,6 @@ local unitPayloads = {
["tasks"] = {
},
},
[3] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}",
["num"] = 5,
},
[2] = {
["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}",
["num"] = 7,
},
[3] = {
["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 2,
},
[5] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 1,
},
[6] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}",
["num"] = 9,
},
[8] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
["num"] = 4,
},
[9] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
["num"] = 6,
},
[11] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 11,
},
},
["tasks"] = {
},
},
[4] = {
["name"] = "STRIKE",
["pylons"] = {
@ -142,11 +138,11 @@ local unitPayloads = {
["num"] = 7,
},
[2] = {
["CLSID"] = "{TER_9A_2L*MK-82}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 4,
},
[3] = {
["CLSID"] = "{TER_9A_2R*MK-82}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 6,
},
[4] = {
@ -173,7 +169,7 @@ local unitPayloads = {
["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}",
["num"] = 5,
},
[11] = {
[10] = {
["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
["num"] = 11,
},
@ -185,19 +181,19 @@ local unitPayloads = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}",
["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}",
["num"] = 6,
},
[2] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}",
["num"] = 7,
},
[3] = {
["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}",
["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}",
["num"] = 3,
},
[5] = {

View File

@ -2,26 +2,6 @@ local unitPayloads = {
["name"] = "P-47D-30",
["payloads"] = {
[1] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 11,
},
},
[2] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
@ -41,14 +21,34 @@ local unitPayloads = {
[1] = 11,
},
},
[3] = {
["name"] = "ANTISHIP",
[2] = {
["name"] = "ANTISTRIKE",
["pylons"] = {
},
["tasks"] = {
[1] = 11,
},
},
[3] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 11,
},
},
[4] = {
["name"] = "CAP",
["pylons"] = {
@ -77,6 +77,25 @@ local unitPayloads = {
[1] = 11,
},
},
[6] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
},
},
},
["tasks"] = {
},

View File

@ -0,0 +1,96 @@
local unitPayloads = {
["name"] = "P-47D-30bl1",
["payloads"] = {
[1] = {
["name"] = "CAP",
["pylons"] = {
},
["tasks"] = {
[1] = 11,
},
},
[2] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{AN_M57}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{AN_M57}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN_M57}",
["num"] = 3,
},
},
["tasks"] = {
[1] = 11,
},
},
[3] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 11,
},
},
[4] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 11,
},
},
[5] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
},
},
},
["tasks"] = {
},
["unitType"] = "P-47D-30bl1",
}
return unitPayloads

View File

@ -0,0 +1,88 @@
local unitPayloads = {
["name"] = "P-47D-40",
["payloads"] = {
[1] = {
["name"] = "CAP",
["pylons"] = {
},
["tasks"] = {
[1] = 11,
},
},
[2] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}",
["num"] = 4,
},
[2] = {
["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 11,
},
},
[3] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}",
["num"] = 4,
},
[2] = {
["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 11,
},
},
[4] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{AN-M64}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{AN-M64}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 11,
},
},
[5] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}",
["num"] = 5,
},
[2] = {
["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}",
["num"] = 4,
},
[3] = {
["CLSID"] = "{AN-M64}",
["num"] = 1,
},
},
["tasks"] = {
},
},
},
["tasks"] = {
},
["unitType"] = "P-47D-40",
}
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

@ -108,14 +108,23 @@ class ControlPoint(MissionTarget):
@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
@ -128,6 +137,20 @@ class ControlPoint(MissionTarget):
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