Merge pull request #60 from Khopa/develop

Develop
This commit is contained in:
C. Perreau 2020-08-16 15:22:10 +02:00 committed by GitHub
commit f61e23153b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 689 additions and 486 deletions

View File

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

View File

@ -1,3 +1,25 @@
# 2.0.11
## Features/Improvements :
* **[Units/Factions]** Added Mig-31, Su-30, Mi-24V, Mi-28N to Russia 2010 faction.
* **[Units/Factions]** Added F-15E to USA 2005 and USA 1990 factions.
* **[Mission Generator]** Added a parameter to choose whether the JTACs should use smoke markers or not
## Fixed issues :
* **[Units/Factions]** Fixed big performance issue in new release UI that occurred only when running the .exe
* **[Units/Factions]** Fixed mission generation not working with Libya faction
* **[Units/Factions]** Fixed OH-58D not being used by AI
* **[Units/Factions]** Fixed Tanker Tacan channel not being the same as the briefing one. (Sorry)
* **[Mission Generator]** Neutral airbases services will now be disabled. (Not possible to refuel or re-arm there)
* **[Mission Generator]** AI will be configured to limit afterburner usage
* **[Mission Generator]** JTAC will not use laser codes above 1688 anymore
* **[Mission Generator]** JTAC units were misconfigured and would not be invisible/immortal.
* **[Mission Generator]** Increased JTAC status message duration to 25s, so you have more time to enter coordinates;
* **[Mission Generator]** Destroyed units carcass will not appear on airfields to avoid having a destroyed vehicle blocking a runway or taxiway.
# 2.0.10 # 2.0.10
## Features/Improvements : ## Features/Improvements :
@ -10,7 +32,7 @@
* **[Units/Factions/Mods]** Added Rafale AI mod support * **[Units/Factions/Mods]** Added Rafale AI mod support
* **[Units/Factions/Mods]** Added faction "France Modded" with units from frenchpack v3.5 mod * **[Units/Factions/Mods]** Added faction "France Modded" with units from frenchpack v3.5 mod
* **[Units/Factions/Mods]** Added faction "Insurgent modded" with Insurgent units from frenchpack v3.5 mod (Toyota truck) * **[Units/Factions/Mods]** Added faction "Insurgent modded" with Insurgent units from frenchpack v3.5 mod (Toyota truck)
* **[Units/Factions/Mods]** Added factions Canada 2005, Australia 2005, Japan 2005, USA Aggressors * **[Units/Factions/Mods]** Added factions Canada 2005, Australia 2005, Japan 2005, USA Aggressors, PMC
* **[New Game Wizard]** Added the list of required mods for modded factions. * **[New Game Wizard]** Added the list of required mods for modded factions.
* **[New Game Wizard]** No more RED vs BLUE opposing faction restrictions. * **[New Game Wizard]** No more RED vs BLUE opposing faction restrictions.
* **[New Game Wizard]** New campaign generation settings added : No aircraft carrier, no lha, no navy, invert map starting positions. * **[New Game Wizard]** New campaign generation settings added : No aircraft carrier, no lha, no navy, invert map starting positions.
@ -19,6 +41,7 @@
* **[Mission Generator]** The briefing will now contain the carrier ATC frequency * **[Mission Generator]** The briefing will now contain the carrier ATC frequency
* **[Mission Generator]** The briefing contains a small situation update. * **[Mission Generator]** The briefing contains a small situation update.
* **[Mission Generator]** Previously destroyed units are visible in the mission. (And added a performance settings to disable this behaviour) * **[Mission Generator]** Previously destroyed units are visible in the mission. (And added a performance settings to disable this behaviour)
* **[Mission Generator]** Basic JTAC on Frontlines
* **[Campaign Generator]** Added Tarawa in caucasus campaigns * **[Campaign Generator]** Added Tarawa in caucasus campaigns
* **[Campaign Generator]** Tuned the various existing campaign parameters * **[Campaign Generator]** Tuned the various existing campaign parameters
* **[Campaign Generator]** Added small campaign : "Russia" on Caucasus Theater * **[Campaign Generator]** Added small campaign : "Russia" on Caucasus Theater

View File

@ -31,7 +31,7 @@ from game.factions.israel_2000 import Israel_2000
from game.factions.italy_1990 import Italy_1990 from game.factions.italy_1990 import Italy_1990
from game.factions.italy_1990_mb339 import Italy_1990_MB339 from game.factions.italy_1990_mb339 import Italy_1990_MB339
from game.factions.japan_2005 import Japan_2005 from game.factions.japan_2005 import Japan_2005
from game.factions.libya_2011 import Lybia_2011 from game.factions.libya_2011 import Libya_2011
from game.factions.netherlands_1990 import Netherlands_1990 from game.factions.netherlands_1990 import Netherlands_1990
from game.factions.north_korea_2000 import NorthKorea_2000 from game.factions.north_korea_2000 import NorthKorea_2000
from game.factions.pakistan_2015 import Pakistan_2015 from game.factions.pakistan_2015 import Pakistan_2015
@ -166,13 +166,14 @@ PRICES = {
AV8BNA: 14, AV8BNA: 14,
M_2000C: 16, M_2000C: 16,
Mirage_2000_5: 22, Mirage_2000_5: 20,
FA_18C_hornet: 24, FA_18C_hornet: 22,
F_15C: 26, F_15C: 22,
F_15E: 24,
F_16C_50: 20, F_16C_50: 20,
F_14B: 22, F_14B: 24,
Tornado_IDS: 24, Tornado_IDS: 20,
Tornado_GR4: 24, Tornado_GR4: 20,
# bomber # bomber
Su_17M4: 10, Su_17M4: 10,
@ -396,6 +397,7 @@ UNIT_BY_TASK = {
MiG_21Bis, MiG_21Bis,
MiG_29A, MiG_29A,
MiG_29S, MiG_29S,
MiG_31,
FA_18C_hornet, FA_18C_hornet,
F_15C, F_15C,
F_14B, F_14B,
@ -420,6 +422,7 @@ UNIT_BY_TASK = {
SA342Mistral SA342Mistral
], ],
CAS: [ CAS: [
F_15E,
F_86F_Sabre, F_86F_Sabre,
MiG_15bis, MiG_15bis,
L_39ZA, L_39ZA,
@ -756,7 +759,7 @@ FACTIONS = {
"Netherlands 1990": Netherlands_1990, "Netherlands 1990": Netherlands_1990,
"United Kingdown 1990": UnitedKingdom_1990, "United Kingdom 1990": UnitedKingdom_1990,
"Spain 1990": Spain_1990, "Spain 1990": Spain_1990,
@ -783,7 +786,7 @@ FACTIONS = {
"India 2010": India_2010, "India 2010": India_2010,
"Lybia 2011": Lybia_2011, "Libya 2011": Libya_2011,
"Pakistan 2015": Pakistan_2015, "Pakistan 2015": Pakistan_2015,
@ -872,6 +875,7 @@ PLANE_PAYLOAD_OVERRIDES = {
F_5E_3: COMMON_OVERRIDE, F_5E_3: COMMON_OVERRIDE,
F_14B: COMMON_OVERRIDE, F_14B: COMMON_OVERRIDE,
F_15C: COMMON_OVERRIDE, F_15C: COMMON_OVERRIDE,
F_15E: COMMON_OVERRIDE,
F_16C_50: COMMON_OVERRIDE, F_16C_50: COMMON_OVERRIDE,
JF_17: COMMON_OVERRIDE, JF_17: COMMON_OVERRIDE,
M_2000C: COMMON_OVERRIDE, M_2000C: COMMON_OVERRIDE,
@ -899,6 +903,8 @@ PLANE_PAYLOAD_OVERRIDES = {
SA342L:COMMON_OVERRIDE, SA342L:COMMON_OVERRIDE,
SA342Mistral:COMMON_OVERRIDE, SA342Mistral:COMMON_OVERRIDE,
Mi_8MT:COMMON_OVERRIDE, Mi_8MT:COMMON_OVERRIDE,
Mi_24V:COMMON_OVERRIDE,
Mi_28N:COMMON_OVERRIDE,
Ka_50:COMMON_OVERRIDE, Ka_50:COMMON_OVERRIDE,
L_39ZA:COMMON_OVERRIDE, L_39ZA:COMMON_OVERRIDE,
L_39C:COMMON_OVERRIDE, L_39C:COMMON_OVERRIDE,
@ -942,8 +948,6 @@ PLANE_LIVERY_OVERRIDES = {
FA_18C_hornet: "VFA-34", # default livery for the hornet is blue angels one FA_18C_hornet: "VFA-34", # default livery for the hornet is blue angels one
} }
""" """
Possible time periods for new games Possible time periods for new games

View File

@ -65,25 +65,10 @@ class Event:
else: else:
return self.departure_cp return self.departure_cp
@property
def threat_description(self) -> str:
return ""
def flight_name(self, for_task: typing.Type[typing.Type[Task]]) -> str:
return "Flight"
@property @property
def tasks(self) -> typing.Collection[typing.Type[Task]]: def tasks(self) -> typing.Collection[typing.Type[Task]]:
return [] return []
@property
def ai_banned_tasks(self) -> typing.Collection[typing.Type[Task]]:
return []
@property
def player_banned_tasks(self) -> typing.Collection[typing.Type[Task]]:
return []
@property @property
def global_cp_available(self) -> bool: def global_cp_available(self) -> bool:
return False return False
@ -255,7 +240,6 @@ class Event:
# Destroyed units carcass # Destroyed units carcass
# ------------------------- # -------------------------
for destroyed_unit in debriefing.destroyed_units: for destroyed_unit in debriefing.destroyed_units:
self.game.add_destroyed_units(destroyed_unit) self.game.add_destroyed_units(destroyed_unit)

View File

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

View File

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

View File

@ -7,12 +7,14 @@ Russia_2010 = {
"country": "Russia", "country": "Russia",
"side": "red", "side": "red",
"units": [ "units": [
MiG_23MLD,
Su_25,
Su_27, Su_27,
Su_30,
Su_33, Su_33,
MiG_29S, MiG_29S,
MiG_31,
Su_25,
Su_25T, Su_25T,
Su_34, Su_34,
Su_24M, Su_24M,
@ -27,6 +29,8 @@ Russia_2010 = {
Ka_50, Ka_50,
Mi_8MT, Mi_8MT,
Mi_24V,
Mi_28N,
AirDefence.SAM_SA_19_Tunguska_2S6, AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_11_Buk_LN_9A310M1, AirDefence.SAM_SA_11_Buk_LN_9A310M1,

View File

@ -8,6 +8,7 @@ USA_1990 = {
"side": "blue", "side": "blue",
"units": [ "units": [
F_15C, F_15C,
F_15E,
F_14B, F_14B,
FA_18C_hornet, FA_18C_hornet,
@ -23,6 +24,7 @@ USA_1990 = {
UH_1H, UH_1H,
AH_64A, AH_64A,
OH_58D,
Armor.MBT_M1A2_Abrams, Armor.MBT_M1A2_Abrams,
Armor.IFV_LAV_25, Armor.IFV_LAV_25,

View File

@ -8,6 +8,7 @@ USA_2005 = {
"side": "blue", "side": "blue",
"units": [ "units": [
F_15C, F_15C,
F_15E,
F_14B, F_14B,
FA_18C_hornet, FA_18C_hornet,
F_16C_50, F_16C_50,
@ -21,6 +22,7 @@ USA_2005 = {
UH_1H, UH_1H,
AH_64D, AH_64D,
OH_58D,
Armor.MBT_M1A2_Abrams, Armor.MBT_M1A2_Abrams,
Armor.ATGM_M1134_Stryker, Armor.ATGM_M1134_Stryker,

View File

@ -378,8 +378,10 @@ class Game:
return points return points
def add_destroyed_units(self, destroyed_unit_data): def add_destroyed_units(self, data):
self.__destroyed_units.append(destroyed_unit_data) pos = Point(data["x"], data["z"])
if self.theater.is_on_land(pos):
self.__destroyed_units.append(data)
def get_destroyed_units(self): def get_destroyed_units(self):
return self.__destroyed_units return self.__destroyed_units

View File

@ -14,19 +14,6 @@ class FrontlineAttackOperation(Operation):
attackers = None # type: db.ArmorDict attackers = None # type: db.ArmorDict
defenders = None # type: db.ArmorDict defenders = None # type: db.ArmorDict
def setup(self,
defenders: db.ArmorDict,
attackers: db.ArmorDict,
strikegroup: db.AssignedUnitsDict,
escort: db.AssignedUnitsDict,
interceptors: db.AssignedUnitsDict):
self.strikegroup = strikegroup
self.escort = escort
self.interceptors = interceptors
self.defenders = defenders
self.attackers = attackers
def prepare(self, terrain: Terrain, is_quick: bool): def prepare(self, terrain: Terrain, is_quick: bool):
super(FrontlineAttackOperation, self).prepare(terrain, is_quick) super(FrontlineAttackOperation, self).prepare(terrain, is_quick)
if self.defender_name == self.game.player_name: if self.defender_name == self.game.player_name:

View File

@ -72,9 +72,6 @@ class Operation:
self.groundobjectgen = GroundObjectsGenerator(mission, conflict, self.game) self.groundobjectgen = GroundObjectsGenerator(mission, conflict, self.game)
self.briefinggen = BriefingGenerator(mission, conflict, self.game) self.briefinggen = BriefingGenerator(mission, conflict, self.game)
player_country = self.from_cp.captured and self.attacker_country or self.defender_country
enemy_country = self.from_cp.captured and self.defender_country or self.attacker_country
def prepare(self, terrain: Terrain, is_quick: bool): def prepare(self, terrain: Terrain, is_quick: bool):
with open("resources/default_options.lua", "r") as f: with open("resources/default_options.lua", "r") as f:
options_dict = loads(f.read())["options"] options_dict = loads(f.read())["options"]
@ -202,8 +199,14 @@ class Operation:
script = f.read() script = f.read()
script = script + "\n" script = script + "\n"
smoke = "true"
if hasattr(self.game.settings, "jtac_smoke_on"):
if not self.game.settings.jtac_smoke_on:
smoke = "false"
for jtac in self.game.jtacs: for jtac in self.game.jtacs:
script = script + "\n" + "JTACAutoLase('" + str(jtac[2]) + "', " + str(jtac[1]) + ", true, \"vehicle\")" + "\n" script = script + "\n" + "JTACAutoLase('" + str(jtac[2]) + "', " + str(jtac[1]) + ", " + smoke + ", \"vehicle\")" + "\n"
load_autolase.add_action(DoScript(String(script))) load_autolase.add_action(DoScript(String(script)))
self.current_mission.triggerrules.triggers.append(load_autolase) self.current_mission.triggerrules.triggers.append(load_autolase)

View File

@ -25,6 +25,7 @@ class Settings:
self.cold_start = False # Legacy parameter do not use self.cold_start = False # Legacy parameter do not use
self.version = None self.version = None
self.include_jtac_if_available = True self.include_jtac_if_available = True
self.jtac_smoke_on = True
# Performance oriented # Performance oriented
self.perf_red_alert_state = True self.perf_red_alert_state = True

View File

@ -431,6 +431,7 @@ class AircraftConflictGenerator:
group.points[0].tasks.append(OptRestrictJettison(True)) group.points[0].tasks.append(OptRestrictJettison(True))
group.points[0].tasks.append(OptRTBOnBingoFuel(True)) group.points[0].tasks.append(OptRTBOnBingoFuel(True))
group.points[0].tasks.append(OptRestrictAfterburner(True))
if hasattr(flight.unit_type, 'eplrs'): if hasattr(flight.unit_type, 'eplrs'):
if flight.unit_type.eplrs: if flight.unit_type.eplrs:

View File

@ -53,7 +53,7 @@ class AirSupportConflictGenerator:
if tanker_unit_type != IL_78M: if tanker_unit_type != IL_78M:
tanker_group.points[0].tasks.pop() # Override PyDCS tacan channel tanker_group.points[0].tasks.pop() # Override PyDCS tacan channel
tanker_group.points[0].tasks.append(ActivateBeaconCommand(97+1, "X", CALLSIGNS[i], True, tanker_group.units[0].id, True)) tanker_group.points[0].tasks.append(ActivateBeaconCommand(60 + i, "X", CALLSIGNS[i], True, tanker_group.units[0].id, True))
tanker_group.points[0].tasks.append(SetInvisibleCommand(True)) tanker_group.points[0].tasks.append(SetInvisibleCommand(True))
tanker_group.points[0].tasks.append(SetImmortalCommand(True)) tanker_group.points[0].tasks.append(SetImmortalCommand(True))

View File

@ -100,16 +100,16 @@ class GroundConflictGenerator:
# Add JTAC # Add JTAC
if "has_jtac" in self.game.player_faction and self.game.player_faction["has_jtac"] and self.game.settings.include_jtac_if_available: if "has_jtac" in self.game.player_faction and self.game.player_faction["has_jtac"] and self.game.settings.include_jtac_if_available:
n = "JTAC" + str(self.conflict.from_cp.id) + str(self.conflict.to_cp.id) n = "JTAC" + str(self.conflict.from_cp.id) + str(self.conflict.to_cp.id)
code = 1688 + len(self.game.jtacs) code = 1688 - len(self.game.jtacs)
jtac = self.mission.flight_group(country=self.mission.country(self.game.player_country), jtac = self.mission.flight_group(country=self.mission.country(self.game.player_country),
name=n, name=n,
aircraft_type=MQ_9_Reaper, aircraft_type=MQ_9_Reaper,
position=position[0], position=position[0],
airport=None, airport=None,
altitude=5000) altitude=5000)
jtac.points[0].tasks.append(OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle))
jtac.points[0].tasks.append(SetInvisibleCommand(True)) jtac.points[0].tasks.append(SetInvisibleCommand(True))
jtac.points[0].tasks.append(SetImmortalCommand(True)) jtac.points[0].tasks.append(SetImmortalCommand(True))
jtac.points[0].tasks.append(OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle))
self.game.jtacs.append(("Frontline " + self.conflict.from_cp.name + "/" + self.conflict.to_cp.name, code, n)) self.game.jtacs.append(("Frontline " + self.conflict.from_cp.name + "/" + self.conflict.to_cp.name, code, n))
def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading): def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading):

View File

@ -34,6 +34,7 @@ CAP_CAPABLE = [
MiG_29A, MiG_29A,
MiG_29G, MiG_29G,
MiG_29S, MiG_29S,
MiG_31,
Su_27, Su_27,
J_11A, J_11A,
@ -49,6 +50,7 @@ CAP_CAPABLE = [
F_5E_3, F_5E_3,
F_14B, F_14B,
F_15C, F_15C,
F_15E,
F_16C_50, F_16C_50,
FA_18C_hornet, FA_18C_hornet,
@ -97,6 +99,7 @@ CAS_CAPABLE = [
F_86F_Sabre, F_86F_Sabre,
F_5E_3, F_5E_3,
F_14B, F_14B,
F_15E,
F_16C_50, F_16C_50,
FA_18C_hornet, FA_18C_hornet,
@ -107,6 +110,7 @@ CAS_CAPABLE = [
SA342M, SA342M,
SA342L, SA342L,
OH_58D,
AH_64A, AH_64A,
AH_64D, AH_64D,
@ -138,6 +142,7 @@ CAS_CAPABLE = [
SEAD_CAPABLE = [ SEAD_CAPABLE = [
F_4E, F_4E,
FA_18C_hornet, FA_18C_hornet,
F_15E,
# F_16C_50, Not yet # F_16C_50, Not yet
AV8BNA, AV8BNA,
JF_17, JF_17,
@ -178,6 +183,7 @@ STRIKE_CAPABLE = [
F_86F_Sabre, F_86F_Sabre,
F_5E_3, F_5E_3,
F_14B, F_14B,
F_15E,
F_16C_50, F_16C_50,
FA_18C_hornet, FA_18C_hornet,
@ -207,6 +213,7 @@ ANTISHIP_CAPABLE = [
Su_24M, Su_24M,
Su_17M4, Su_17M4,
F_A_18C, F_A_18C,
F_15E,
AV8BNA, AV8BNA,
JF_17, JF_17,
F_16C_50, F_16C_50,

View File

@ -46,6 +46,22 @@ class TriggersGenerator:
""" """
Set airbase initial coalition Set airbase initial coalition
""" """
# Empty neutrals airports
cp_ids = [cp.id for cp in self.game.theater.controlpoints]
for airport in self.mission.terrain.airport_list():
if airport.id not in cp_ids:
airport.unlimited_fuel = False
airport.unlimited_munitions = False
airport.unlimited_aircrafts = False
airport.gasoline_init = 0
airport.methanol_mixture_init = 0
airport.diesel_init = 0
airport.jet_init = 0
airport.operating_level_air = 0
airport.operating_level_equipment = 0
airport.operating_level_fuel = 0
for cp in self.game.theater.controlpoints: for cp in self.game.theater.controlpoints:
if cp.is_global: if cp.is_global:
continue continue

View File

@ -15,7 +15,6 @@ from game.event import UnitsDeliveryEvent, Event, ControlPointType
from gen import Conflict from gen import Conflict
from qt_ui.widgets.map.QLiberationScene import QLiberationScene from qt_ui.widgets.map.QLiberationScene import QLiberationScene
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint
from qt_ui.widgets.map.QMapEvent import QMapEvent
from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from theater import ControlPoint from theater import ControlPoint

View File

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

View File

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

View File

@ -169,17 +169,25 @@ class QSettingsWindow(QDialog):
if not hasattr(self.game.settings, "include_jtac_if_available"): if not hasattr(self.game.settings, "include_jtac_if_available"):
self.game.settings.include_jtac_if_available = True self.game.settings.include_jtac_if_available = True
if not hasattr(self.game.settings, "jtac_smoke_on"):
self.game.settings.jtac_smoke_on= True
self.include_jtac_if_available = QCheckBox() self.include_jtac_if_available = QCheckBox()
self.include_jtac_if_available.setChecked(self.game.settings.include_jtac_if_available) self.include_jtac_if_available.setChecked(self.game.settings.include_jtac_if_available)
self.include_jtac_if_available.toggled.connect(self.applySettings) self.include_jtac_if_available.toggled.connect(self.applySettings)
self.jtac_smoke_on = QCheckBox()
self.jtac_smoke_on.setChecked(self.game.settings.jtac_smoke_on)
self.jtac_smoke_on.toggled.connect(self.applySettings)
self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0) self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight) self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0) self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0)
self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight) self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight)
self.gameplayLayout.addWidget(QLabel("Include JTAC (If available)"), 2, 0) self.gameplayLayout.addWidget(QLabel("Include JTAC (If available)"), 2, 0)
self.gameplayLayout.addWidget(self.include_jtac_if_available, 2, 1, Qt.AlignRight) self.gameplayLayout.addWidget(self.include_jtac_if_available, 2, 1, Qt.AlignRight)
self.gameplayLayout.addWidget(QLabel("Enable JTAC smoke markers"), 3, 0)
self.gameplayLayout.addWidget(self.jtac_smoke_on, 3, 1, Qt.AlignRight)
self.performance = QGroupBox("Performance") self.performance = QGroupBox("Performance")
self.performanceLayout = QGridLayout() self.performanceLayout = QGridLayout()
@ -299,6 +307,7 @@ class QSettingsWindow(QDialog):
self.game.settings.external_views_allowed = self.ext_views.isChecked() self.game.settings.external_views_allowed = self.ext_views.isChecked()
self.game.settings.generate_marks = self.generate_marks.isChecked() self.game.settings.generate_marks = self.generate_marks.isChecked()
self.game.settings.include_jtac_if_available = self.include_jtac_if_available.isChecked() self.game.settings.include_jtac_if_available = self.include_jtac_if_available.isChecked()
self.game.settings.jtac_smoke_on = self.jtac_smoke_on.isChecked()
print(self.game.settings.map_coalition_visibility) print(self.game.settings.map_coalition_visibility)

View File

@ -0,0 +1,283 @@
local unitPayloads = {
["name"] = "F-15E",
["payloads"] = {
[1] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 6,
},
[5] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{GBU-38}",
["num"] = 9,
},
[7] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 10,
},
[8] = {
["CLSID"] = "{GBU-38}",
["num"] = 11,
},
[9] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 13,
},
[10] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 14,
},
[11] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 16,
},
[12] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 19,
},
[13] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 17,
},
[14] = {
["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}",
["num"] = 18,
},
[15] = {
["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 32,
},
},
[2] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{GBU-38}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{GBU-38}",
["num"] = 6,
},
[5] = {
["CLSID"] = "{GBU-38}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{GBU-38}",
["num"] = 9,
},
[7] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 10,
},
[8] = {
["CLSID"] = "{GBU-38}",
["num"] = 11,
},
[9] = {
["CLSID"] = "{GBU-38}",
["num"] = 13,
},
[10] = {
["CLSID"] = "{GBU-38}",
["num"] = 14,
},
[11] = {
["CLSID"] = "{GBU-38}",
["num"] = 16,
},
[12] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 19,
},
[13] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 17,
},
},
["tasks"] = {
[1] = 32,
},
},
[3] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 10,
},
[4] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 19,
},
[5] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 17,
},
[6] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 18,
},
[7] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 32,
},
},
[4] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{GBU-38}",
["num"] = 9,
},
[4] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 10,
},
[5] = {
["CLSID"] = "{GBU-38}",
["num"] = 11,
},
[6] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 19,
},
[7] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 17,
},
[8] = {
["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}",
["num"] = 18,
},
[9] = {
["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}",
["num"] = 2,
},
[10] = {
["CLSID"] = "{GBU-38}",
["num"] = 12,
},
[11] = {
["CLSID"] = "{GBU-38}",
["num"] = 8,
},
},
["tasks"] = {
[1] = 32,
},
},
[5] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{GBU-38}",
["num"] = 9,
},
[4] = {
["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}",
["num"] = 10,
},
[5] = {
["CLSID"] = "{GBU-38}",
["num"] = 11,
},
[6] = {
["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}",
["num"] = 19,
},
[7] = {
["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}",
["num"] = 17,
},
[8] = {
["CLSID"] = "{9BCC2A2B-5708-4860-B1F1-053A18442067}",
["num"] = 18,
},
[9] = {
["CLSID"] = "{9BCC2A2B-5708-4860-B1F1-053A18442067}",
["num"] = 2,
},
[10] = {
["CLSID"] = "{GBU-38}",
["num"] = 12,
},
[11] = {
["CLSID"] = "{GBU-38}",
["num"] = 8,
},
[12] = {
["CLSID"] = "{GBU-38}",
["num"] = 13,
},
[13] = {
["CLSID"] = "{GBU-38}",
["num"] = 7,
},
},
["tasks"] = {
[1] = 32,
},
},
},
["unitType"] = "F-15E",
}
return unitPayloads

View File

@ -0,0 +1,148 @@
local unitPayloads = {
["name"] = "Mi-24V",
["payloads"] = {
[1] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 5,
},
[6] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 6,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[2] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 6,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
[4] = 30,
},
},
[3] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 6,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
[4] = 30,
},
},
[4] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}",
["num"] = 6,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
[4] = 30,
},
},
[5] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 2,
},
[2] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 3,
},
[3] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
},
["unitType"] = "Mi-24V",
}
return unitPayloads

View File

@ -0,0 +1,131 @@
local unitPayloads = {
["name"] = "Mi-28",
["payloads"] = {
[1] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[2] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
[4] = 30,
},
},
[3] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
[4] = 30,
},
},
[4] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
[5] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 31,
[2] = 32,
[3] = 18,
},
},
},
["unitType"] = "Mi-28N",
}
return unitPayloads

Binary file not shown.

View File

@ -554,7 +554,7 @@ function getJTACStatus()
end end
end end
notify(message, 10) notify(message, 25)
end end

View File

@ -85,13 +85,11 @@ QPushButton {
border: 1px solid #97A9A9; border: 1px solid #97A9A9;
color:#fff; color:#fff;
padding: 6px 10px; padding: 6px 10px;
cursor: pointer;
border-radius:2px; border-radius:2px;
} }
QPushButton:hover { QPushButton:hover {
background: #6c7b7f; background: #6c7b7f;
cursor:pointer;
} }
/*btn-primary*/ /*btn-primary*/
@ -101,7 +99,6 @@ QPushButton[style="btn-primary"]{
color:#fff; color:#fff;
padding: 6px; padding: 6px;
border-radius:2px; border-radius:2px;
cursor: pointer;
font-weight:bold; font-weight:bold;
text-transform:uppercase; text-transform:uppercase;
} }
@ -114,7 +111,6 @@ QPushButton[style="btn-primary"]:hover{
QPushButton[style="btn-success"] , QPushButton[style="start-button"]{ QPushButton[style="btn-success"] , QPushButton[style="start-button"]{
background-color:#82A466; background-color:#82A466;
color: white; color: white;
cursor:pointer;
border-radius:2px; border-radius:2px;
font-weight:bold; font-weight:bold;
text-transform:uppercase; text-transform:uppercase;
@ -134,7 +130,6 @@ QPushButton[style="btn-success"]:hover , QPushButton[style="start-button"]:hover
QPushButton[style="btn-buy"]{ QPushButton[style="btn-buy"]{
background-color:#82A466; background-color:#82A466;
color: white; color: white;
cursor:pointer;
border-radius:2px; border-radius:2px;
font-weight:bold; font-weight:bold;
text-transform:uppercase; text-transform:uppercase;
@ -143,7 +138,6 @@ QPushButton[style="btn-buy"]{
} }
QPushButton[style="btn-buy"]:hover{ QPushButton[style="btn-buy"]:hover{
cursor:pointer;
background:#5C863F; background:#5C863F;
} }
@ -151,7 +145,6 @@ QPushButton[style="btn-buy"]:hover{
QPushButton[style="btn-sell"]{ QPushButton[style="btn-sell"]{
background-color:#9E3232; background-color:#9E3232;
color: white; color: white;
cursor:pointer;
border-radius:2px; border-radius:2px;
font-weight:bold; font-weight:bold;
text-transform:uppercase; text-transform:uppercase;
@ -160,7 +153,6 @@ QPushButton[style="btn-sell"]{
} }
QPushButton[style="btn-sell"]:hover{ QPushButton[style="btn-sell"]:hover{
cursor:pointer;
background:#D84545; background:#D84545;
} }
@ -169,7 +161,6 @@ QPushButton[style="btn-sell"]:hover{
QPushButton[style="btn-danger"]{ QPushButton[style="btn-danger"]{
background-color:#9E3232; background-color:#9E3232;
color: white; color: white;
cursor:pointer;
padding: 6px; padding: 6px;
border-radius:2px; border-radius:2px;
border: 1px solid #9E3232; border: 1px solid #9E3232;
@ -191,7 +182,6 @@ QLabel{
QLabel[style="base-title"]{ QLabel[style="base-title"]{
font-size: 24px; font-size: 24px;
font-color: #ccc;
} }
QLabel[style="icon-plane"]{ QLabel[style="icon-plane"]{

View File

@ -26,7 +26,6 @@ QTopPanel *{
QPushButton[style="btn-success"]{ QPushButton[style="btn-success"]{
background-color:#699245; background-color:#699245;
color: white; color: white;
cursor:pointer;
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
border-radius:5px; border-radius:5px;
} }
@ -35,13 +34,11 @@ QPushButton[style="btn-success"]:hover{
background-color:#8ABC5A; background-color:#8ABC5A;
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
border-radius:5px; border-radius:5px;
cursor: pointer;
} }
QPushButton[style="start-button"]{ QPushButton[style="start-button"]{
background-color:#699245; background-color:#699245;
color: white; color: white;
cursor:pointer;
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
border-radius:5px; border-radius:5px;
} }
@ -50,14 +47,12 @@ QPushButton[style="start-button"]:hover{
background-color:#8ABC5A; background-color:#8ABC5A;
padding: 15px 15px 15px 15px; padding: 15px 15px 15px 15px;
border-radius:5px; border-radius:5px;
cursor: pointer;
} }
/* Buy button */ /* Buy button */
QPushButton[style="btn-buy"]{ QPushButton[style="btn-buy"]{
background-color:#82A466; background-color:#82A466;
color: white; color: white;
cursor:pointer;
border-radius:2px; border-radius:2px;
font-weight:bold; font-weight:bold;
text-transform:uppercase; text-transform:uppercase;
@ -66,7 +61,6 @@ QPushButton[style="btn-buy"]{
} }
QPushButton[style="btn-buy"]:hover{ QPushButton[style="btn-buy"]:hover{
cursor:pointer;
background:#5C863F; background:#5C863F;
} }
@ -74,7 +68,6 @@ QPushButton[style="btn-buy"]:hover{
QPushButton[style="btn-sell"]{ QPushButton[style="btn-sell"]{
background-color:#9E3232; background-color:#9E3232;
color: white; color: white;
cursor:pointer;
border-radius:2px; border-radius:2px;
font-weight:bold; font-weight:bold;
text-transform:uppercase; text-transform:uppercase;
@ -83,14 +76,12 @@ QPushButton[style="btn-sell"]{
} }
QPushButton[style="btn-sell"]:hover{ QPushButton[style="btn-sell"]:hover{
cursor:pointer;
background:#D84545; background:#D84545;
} }
QPushButton[style="btn-danger"]{ QPushButton[style="btn-danger"]{
background-color:#9E3232; background-color:#9E3232;
color: white; color: white;
cursor:pointer;
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
border-radius:5px; border-radius:5px;
} }
@ -99,12 +90,10 @@ QPushButton[style="btn-danger"]:hover{
background-color:#D84545; background-color:#D84545;
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
border-radius:5px; border-radius:5px;
cursor: pointer;
} }
QLabel[style="base-title"]{ QLabel[style="base-title"]{
font-size: 24px; font-size: 24px;
font-color: #ccc;
border: 1px solid #ccc; border: 1px solid #ccc;
} }

View File

@ -46,9 +46,9 @@ def _mk_archieve():
except FileNotFoundError: except FileNotFoundError:
pass pass
os.system("pyinstaller.exe pyinstaller.spec") os.system("pyinstaller.exe pyinstaller.spec")
archieve = ZipFile(path, "w") #archieve = ZipFile(path, "w")
archieve.writestr("dcs_liberation.bat", "cd dist\\dcs_liberation\r\nliberation_main \"%UserProfile%\\Saved Games\" \"{}\"".format(VERSION)) #archieve.writestr("dcs_liberation.bat", "cd dist\\dcs_liberation\r\nliberation_main \"%UserProfile%\\Saved Games\" \"{}\"".format(VERSION))
_zip_dir(archieve, "./dist/dcs_liberation") #_zip_dir(archieve, "./dist/dcs_liberation")
_mk_archieve() _mk_archieve()

Binary file not shown.