diff --git a/README.md b/README.md index 1c01717c..800edb90 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,22 @@ ![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 -and [Mist](https://github.com/mrSkortch/MissionScriptingTools) for mission scripting +[![GitHub pull requests](https://img.shields.io/github/issues-pr/khopa/dcs_liberation)](https://github.com/Khopa/dcs_liberation) +[![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 @@ -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) -## Development Guide (WIP) +* [Developer/Contributor Guide]()(TODO) -Develop is the main development branch which is updated regularly. -Master branch will be updated less regularly and on release on new version. +* [Hosting DCS Liberation generated missions on a dedicated server]()(TODO) -Other branch might be used for feature development. - -**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. +## Special Thanks +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 ! \ No newline at end of file diff --git a/changelog.md b/changelog.md index 096caf61..ac729c8c 100644 --- a/changelog.md +++ b/changelog.md @@ -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 ## Features/Improvements : @@ -10,7 +32,7 @@ * **[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 "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]** 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. @@ -19,6 +41,7 @@ * **[Mission Generator]** The briefing will now contain the carrier ATC frequency * **[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]** Basic JTAC on Frontlines * **[Campaign Generator]** Added Tarawa in caucasus campaigns * **[Campaign Generator]** Tuned the various existing campaign parameters * **[Campaign Generator]** Added small campaign : "Russia" on Caucasus Theater diff --git a/game/db.py b/game/db.py index 9e2735b0..81193426 100644 --- a/game/db.py +++ b/game/db.py @@ -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_mb339 import Italy_1990_MB339 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.north_korea_2000 import NorthKorea_2000 from game.factions.pakistan_2015 import Pakistan_2015 @@ -166,13 +166,14 @@ PRICES = { AV8BNA: 14, M_2000C: 16, - Mirage_2000_5: 22, - FA_18C_hornet: 24, - F_15C: 26, + Mirage_2000_5: 20, + FA_18C_hornet: 22, + F_15C: 22, + F_15E: 24, F_16C_50: 20, - F_14B: 22, - Tornado_IDS: 24, - Tornado_GR4: 24, + F_14B: 24, + Tornado_IDS: 20, + Tornado_GR4: 20, # bomber Su_17M4: 10, @@ -396,6 +397,7 @@ UNIT_BY_TASK = { MiG_21Bis, MiG_29A, MiG_29S, + MiG_31, FA_18C_hornet, F_15C, F_14B, @@ -420,6 +422,7 @@ UNIT_BY_TASK = { SA342Mistral ], CAS: [ + F_15E, F_86F_Sabre, MiG_15bis, L_39ZA, @@ -756,7 +759,7 @@ FACTIONS = { "Netherlands 1990": Netherlands_1990, - "United Kingdown 1990": UnitedKingdom_1990, + "United Kingdom 1990": UnitedKingdom_1990, "Spain 1990": Spain_1990, @@ -783,7 +786,7 @@ FACTIONS = { "India 2010": India_2010, - "Lybia 2011": Lybia_2011, + "Libya 2011": Libya_2011, "Pakistan 2015": Pakistan_2015, @@ -872,6 +875,7 @@ PLANE_PAYLOAD_OVERRIDES = { F_5E_3: COMMON_OVERRIDE, F_14B: COMMON_OVERRIDE, F_15C: COMMON_OVERRIDE, + F_15E: COMMON_OVERRIDE, F_16C_50: COMMON_OVERRIDE, JF_17: COMMON_OVERRIDE, M_2000C: COMMON_OVERRIDE, @@ -899,6 +903,8 @@ PLANE_PAYLOAD_OVERRIDES = { SA342L:COMMON_OVERRIDE, SA342Mistral:COMMON_OVERRIDE, Mi_8MT:COMMON_OVERRIDE, + Mi_24V:COMMON_OVERRIDE, + Mi_28N:COMMON_OVERRIDE, Ka_50:COMMON_OVERRIDE, L_39ZA: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 } - - """ Possible time periods for new games diff --git a/game/event/event.py b/game/event/event.py index 01be1f59..6af3d6c9 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -65,25 +65,10 @@ class Event: else: 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 def tasks(self) -> typing.Collection[typing.Type[Task]]: 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 def global_cp_available(self) -> bool: return False @@ -255,7 +240,6 @@ class Event: # Destroyed units carcass # ------------------------- - for destroyed_unit in debriefing.destroyed_units: self.game.add_destroyed_units(destroyed_unit) diff --git a/game/event/frontlineattack.py b/game/event/frontlineattack.py index 9cd787d5..e548440f 100644 --- a/game/event/frontlineattack.py +++ b/game/event/frontlineattack.py @@ -4,16 +4,6 @@ from userdata.debriefing import Debriefing 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 def tasks(self) -> typing.Collection[typing.Type[Task]]: @@ -26,32 +16,11 @@ class FrontlineAttackEvent(Event): def global_cp_available(self) -> bool: 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): return "Frontline attack" 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 - if self.from_cp.captured: return attackers_success else: @@ -65,46 +34,20 @@ class FrontlineAttackEvent(Event): self.to_cp.base.affect_strength(-0.1) 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, attacker_name=self.attacker_name, defender_name=self.defender_name, from_cp=self.from_cp, departure_cp=self.departure_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 def player_defending(self, flights: db.TaskForceDict): - # assert CAP in flights and len(flights) == 1, "Invalid flights" - op = FrontlineAttackOperation(game=self.game, attacker_name=self.attacker_name, defender_name=self.defender_name, from_cp=self.from_cp, departure_cp=self.departure_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 diff --git a/game/factions/libya_2011.py b/game/factions/libya_2011.py index 9e14e0af..688b4877 100644 --- a/game/factions/libya_2011.py +++ b/game/factions/libya_2011.py @@ -2,8 +2,8 @@ from dcs.helicopters import * from dcs.planes import * from dcs.vehicles import * -Lybia_2011 = { - "country": "Lybia", +Libya_2011 = { + "country": "Libya", "side": "red", "units": [ diff --git a/game/factions/russia_2010.py b/game/factions/russia_2010.py index ee219fd4..cc45f062 100644 --- a/game/factions/russia_2010.py +++ b/game/factions/russia_2010.py @@ -7,12 +7,14 @@ Russia_2010 = { "country": "Russia", "side": "red", "units": [ - MiG_23MLD, - Su_25, + Su_27, + Su_30, Su_33, MiG_29S, + MiG_31, + Su_25, Su_25T, Su_34, Su_24M, @@ -27,6 +29,8 @@ Russia_2010 = { Ka_50, Mi_8MT, + Mi_24V, + Mi_28N, AirDefence.SAM_SA_19_Tunguska_2S6, AirDefence.SAM_SA_11_Buk_LN_9A310M1, diff --git a/game/factions/usa_1990.py b/game/factions/usa_1990.py index ae090e17..0eed7850 100644 --- a/game/factions/usa_1990.py +++ b/game/factions/usa_1990.py @@ -8,6 +8,7 @@ USA_1990 = { "side": "blue", "units": [ F_15C, + F_15E, F_14B, FA_18C_hornet, @@ -23,6 +24,7 @@ USA_1990 = { UH_1H, AH_64A, + OH_58D, Armor.MBT_M1A2_Abrams, Armor.IFV_LAV_25, diff --git a/game/factions/usa_2005.py b/game/factions/usa_2005.py index 5425aa92..19c8400e 100644 --- a/game/factions/usa_2005.py +++ b/game/factions/usa_2005.py @@ -8,6 +8,7 @@ USA_2005 = { "side": "blue", "units": [ F_15C, + F_15E, F_14B, FA_18C_hornet, F_16C_50, @@ -21,6 +22,7 @@ USA_2005 = { UH_1H, AH_64D, + OH_58D, Armor.MBT_M1A2_Abrams, Armor.ATGM_M1134_Stryker, diff --git a/game/game.py b/game/game.py index 1dbb397d..385261b8 100644 --- a/game/game.py +++ b/game/game.py @@ -378,8 +378,10 @@ class Game: return points - def add_destroyed_units(self, destroyed_unit_data): - self.__destroyed_units.append(destroyed_unit_data) + def add_destroyed_units(self, data): + pos = Point(data["x"], data["z"]) + if self.theater.is_on_land(pos): + self.__destroyed_units.append(data) def get_destroyed_units(self): return self.__destroyed_units diff --git a/game/operation/frontlineattack.py b/game/operation/frontlineattack.py index 53dc2d63..902ff6c9 100644 --- a/game/operation/frontlineattack.py +++ b/game/operation/frontlineattack.py @@ -14,19 +14,6 @@ class FrontlineAttackOperation(Operation): attackers = 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): super(FrontlineAttackOperation, self).prepare(terrain, is_quick) if self.defender_name == self.game.player_name: diff --git a/game/operation/operation.py b/game/operation/operation.py index d69c406d..033d3c34 100644 --- a/game/operation/operation.py +++ b/game/operation/operation.py @@ -72,9 +72,6 @@ class Operation: self.groundobjectgen = GroundObjectsGenerator(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): with open("resources/default_options.lua", "r") as f: options_dict = loads(f.read())["options"] @@ -202,8 +199,14 @@ class Operation: script = f.read() 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: - 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))) self.current_mission.triggerrules.triggers.append(load_autolase) diff --git a/game/settings.py b/game/settings.py index c42e727b..4566ad0f 100644 --- a/game/settings.py +++ b/game/settings.py @@ -25,6 +25,7 @@ class Settings: self.cold_start = False # Legacy parameter do not use self.version = None self.include_jtac_if_available = True + self.jtac_smoke_on = True # Performance oriented self.perf_red_alert_state = True diff --git a/gen/aircraft.py b/gen/aircraft.py index e26d74ef..62196edb 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -431,6 +431,7 @@ class AircraftConflictGenerator: group.points[0].tasks.append(OptRestrictJettison(True)) group.points[0].tasks.append(OptRTBOnBingoFuel(True)) + group.points[0].tasks.append(OptRestrictAfterburner(True)) if hasattr(flight.unit_type, 'eplrs'): if flight.unit_type.eplrs: diff --git a/gen/airsupportgen.py b/gen/airsupportgen.py index dabf7f48..2e0ef249 100644 --- a/gen/airsupportgen.py +++ b/gen/airsupportgen.py @@ -53,7 +53,7 @@ class AirSupportConflictGenerator: if tanker_unit_type != IL_78M: 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(SetImmortalCommand(True)) diff --git a/gen/armor.py b/gen/armor.py index 7c2e0f89..d2d74a91 100644 --- a/gen/armor.py +++ b/gen/armor.py @@ -100,16 +100,16 @@ class GroundConflictGenerator: # 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: 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), name=n, aircraft_type=MQ_9_Reaper, position=position[0], airport=None, 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(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)) def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading): diff --git a/gen/flights/ai_flight_planner_db.py b/gen/flights/ai_flight_planner_db.py index c73cece4..70e70e3a 100644 --- a/gen/flights/ai_flight_planner_db.py +++ b/gen/flights/ai_flight_planner_db.py @@ -34,6 +34,7 @@ CAP_CAPABLE = [ MiG_29A, MiG_29G, MiG_29S, + MiG_31, Su_27, J_11A, @@ -49,6 +50,7 @@ CAP_CAPABLE = [ F_5E_3, F_14B, F_15C, + F_15E, F_16C_50, FA_18C_hornet, @@ -97,6 +99,7 @@ CAS_CAPABLE = [ F_86F_Sabre, F_5E_3, F_14B, + F_15E, F_16C_50, FA_18C_hornet, @@ -107,6 +110,7 @@ CAS_CAPABLE = [ SA342M, SA342L, + OH_58D, AH_64A, AH_64D, @@ -138,6 +142,7 @@ CAS_CAPABLE = [ SEAD_CAPABLE = [ F_4E, FA_18C_hornet, + F_15E, # F_16C_50, Not yet AV8BNA, JF_17, @@ -178,6 +183,7 @@ STRIKE_CAPABLE = [ F_86F_Sabre, F_5E_3, F_14B, + F_15E, F_16C_50, FA_18C_hornet, @@ -207,6 +213,7 @@ ANTISHIP_CAPABLE = [ Su_24M, Su_17M4, F_A_18C, + F_15E, AV8BNA, JF_17, F_16C_50, diff --git a/gen/triggergen.py b/gen/triggergen.py index c62afe7b..fbd8062e 100644 --- a/gen/triggergen.py +++ b/gen/triggergen.py @@ -46,6 +46,22 @@ class TriggersGenerator: """ 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: if cp.is_global: continue diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index 80cce076..2e763071 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -15,7 +15,6 @@ from game.event import UnitsDeliveryEvent, Event, ControlPointType from gen import Conflict from qt_ui.widgets.map.QLiberationScene import QLiberationScene 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.windows.GameUpdateSignal import GameUpdateSignal from theater import ControlPoint diff --git a/qt_ui/widgets/map/QMapEvent.py b/qt_ui/widgets/map/QMapEvent.py deleted file mode 100644 index 5e24f35e..00000000 --- a/qt_ui/widgets/map/QMapEvent.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/qt_ui/windows/QBriefingWindow.py b/qt_ui/windows/QBriefingWindow.py deleted file mode 100644 index 7b4eec33..00000000 --- a/qt_ui/windows/QBriefingWindow.py +++ /dev/null @@ -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("

{} on {}

".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("Ready?")) - self.layout.addLayout(self.action_layout) - self.setLayout(self.layout) - - def initUnitRows(self): - - row = 0 - - def header(text, row): - self.gridLayout.addWidget(QLabel("" + text + ""), 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("You are clear for takeoff")) - layout.addWidget(QLabel("In DCS open and play the mission : ")) - layout.addWidget(QLabel("liberation_nextturn")) - layout.addWidget(QLabel("or")) - layout.addWidget(QLabel("liberation_nextturn_quick")) - - layout.addWidget(QLabel("Then save the debriefing to folder :")) - layout.addWidget(QLabel("Then save the debriefing to the folder:")) - layout.addWidget(QLabel("" + self.debriefing_directory_location() + "")) - layout.addWidget(QLabel("Waiting for results...")) - - # layout.addWidget(QLabel("In DCS open and play the mission : ")) - # layout.addWidget(QLabel("You are clear for takeoff")) - - 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() \ No newline at end of file diff --git a/qt_ui/windows/settings/QSettingsWindow.py b/qt_ui/windows/settings/QSettingsWindow.py index e6ba069a..d5c27b3b 100644 --- a/qt_ui/windows/settings/QSettingsWindow.py +++ b/qt_ui/windows/settings/QSettingsWindow.py @@ -169,17 +169,25 @@ class QSettingsWindow(QDialog): if not hasattr(self.game.settings, "include_jtac_if_available"): 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.setChecked(self.game.settings.include_jtac_if_available) 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(self.supercarrier, 0, 1, Qt.AlignRight) self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0) self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight) 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(QLabel("Enable JTAC smoke markers"), 3, 0) + self.gameplayLayout.addWidget(self.jtac_smoke_on, 3, 1, Qt.AlignRight) self.performance = QGroupBox("Performance") self.performanceLayout = QGridLayout() @@ -299,6 +307,7 @@ class QSettingsWindow(QDialog): self.game.settings.external_views_allowed = self.ext_views.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.jtac_smoke_on = self.jtac_smoke_on.isChecked() print(self.game.settings.map_coalition_visibility) diff --git a/resources/customized_payloads/F-15E.lua b/resources/customized_payloads/F-15E.lua new file mode 100644 index 00000000..77955c5f --- /dev/null +++ b/resources/customized_payloads/F-15E.lua @@ -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 diff --git a/resources/customized_payloads/Mi-24V.lua b/resources/customized_payloads/Mi-24V.lua new file mode 100644 index 00000000..c5cbd5ba --- /dev/null +++ b/resources/customized_payloads/Mi-24V.lua @@ -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 diff --git a/resources/customized_payloads/Mi-28.lua b/resources/customized_payloads/Mi-28.lua new file mode 100644 index 00000000..35d434ba --- /dev/null +++ b/resources/customized_payloads/Mi-28.lua @@ -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 diff --git a/resources/nevlandmap.p b/resources/nevlandmap.p index 111c24d4..1a9d8cc4 100644 Binary files a/resources/nevlandmap.p and b/resources/nevlandmap.p differ diff --git a/resources/scripts/JTACAutoLase.lua b/resources/scripts/JTACAutoLase.lua index f0af3ecb..05315574 100644 --- a/resources/scripts/JTACAutoLase.lua +++ b/resources/scripts/JTACAutoLase.lua @@ -554,7 +554,7 @@ function getJTACStatus() end end - notify(message, 10) + notify(message, 25) end diff --git a/resources/stylesheets/style-dcs.css b/resources/stylesheets/style-dcs.css index fb41fa21..47a8bee3 100644 --- a/resources/stylesheets/style-dcs.css +++ b/resources/stylesheets/style-dcs.css @@ -85,13 +85,11 @@ QPushButton { border: 1px solid #97A9A9; color:#fff; padding: 6px 10px; - cursor: pointer; border-radius:2px; } QPushButton:hover { background: #6c7b7f; - cursor:pointer; } /*btn-primary*/ @@ -101,7 +99,6 @@ QPushButton[style="btn-primary"]{ color:#fff; padding: 6px; border-radius:2px; - cursor: pointer; font-weight:bold; text-transform:uppercase; } @@ -114,7 +111,6 @@ QPushButton[style="btn-primary"]:hover{ QPushButton[style="btn-success"] , QPushButton[style="start-button"]{ background-color:#82A466; color: white; - cursor:pointer; border-radius:2px; font-weight:bold; text-transform:uppercase; @@ -134,7 +130,6 @@ QPushButton[style="btn-success"]:hover , QPushButton[style="start-button"]:hover QPushButton[style="btn-buy"]{ background-color:#82A466; color: white; - cursor:pointer; border-radius:2px; font-weight:bold; text-transform:uppercase; @@ -143,7 +138,6 @@ QPushButton[style="btn-buy"]{ } QPushButton[style="btn-buy"]:hover{ - cursor:pointer; background:#5C863F; } @@ -151,7 +145,6 @@ QPushButton[style="btn-buy"]:hover{ QPushButton[style="btn-sell"]{ background-color:#9E3232; color: white; - cursor:pointer; border-radius:2px; font-weight:bold; text-transform:uppercase; @@ -160,7 +153,6 @@ QPushButton[style="btn-sell"]{ } QPushButton[style="btn-sell"]:hover{ - cursor:pointer; background:#D84545; } @@ -169,7 +161,6 @@ QPushButton[style="btn-sell"]:hover{ QPushButton[style="btn-danger"]{ background-color:#9E3232; color: white; - cursor:pointer; padding: 6px; border-radius:2px; border: 1px solid #9E3232; @@ -191,7 +182,6 @@ QLabel{ QLabel[style="base-title"]{ font-size: 24px; - font-color: #ccc; } QLabel[style="icon-plane"]{ diff --git a/resources/stylesheets/style.css b/resources/stylesheets/style.css index 7a6f74cf..a8b65845 100644 --- a/resources/stylesheets/style.css +++ b/resources/stylesheets/style.css @@ -26,7 +26,6 @@ QTopPanel *{ QPushButton[style="btn-success"]{ background-color:#699245; color: white; - cursor:pointer; padding: 5px 5px 5px 5px; border-radius:5px; } @@ -35,13 +34,11 @@ QPushButton[style="btn-success"]:hover{ background-color:#8ABC5A; padding: 5px 5px 5px 5px; border-radius:5px; - cursor: pointer; } QPushButton[style="start-button"]{ background-color:#699245; color: white; - cursor:pointer; padding: 5px 5px 5px 5px; border-radius:5px; } @@ -50,14 +47,12 @@ QPushButton[style="start-button"]:hover{ background-color:#8ABC5A; padding: 15px 15px 15px 15px; border-radius:5px; - cursor: pointer; } /* Buy button */ QPushButton[style="btn-buy"]{ background-color:#82A466; color: white; - cursor:pointer; border-radius:2px; font-weight:bold; text-transform:uppercase; @@ -66,7 +61,6 @@ QPushButton[style="btn-buy"]{ } QPushButton[style="btn-buy"]:hover{ - cursor:pointer; background:#5C863F; } @@ -74,7 +68,6 @@ QPushButton[style="btn-buy"]:hover{ QPushButton[style="btn-sell"]{ background-color:#9E3232; color: white; - cursor:pointer; border-radius:2px; font-weight:bold; text-transform:uppercase; @@ -83,14 +76,12 @@ QPushButton[style="btn-sell"]{ } QPushButton[style="btn-sell"]:hover{ - cursor:pointer; background:#D84545; } QPushButton[style="btn-danger"]{ background-color:#9E3232; color: white; - cursor:pointer; padding: 5px 5px 5px 5px; border-radius:5px; } @@ -99,12 +90,10 @@ QPushButton[style="btn-danger"]:hover{ background-color:#D84545; padding: 5px 5px 5px 5px; border-radius:5px; - cursor: pointer; } QLabel[style="base-title"]{ font-size: 24px; - font-color: #ccc; border: 1px solid #ccc; } diff --git a/resources/tools/mkrelease.py b/resources/tools/mkrelease.py index e29e0fa1..f7dea204 100644 --- a/resources/tools/mkrelease.py +++ b/resources/tools/mkrelease.py @@ -46,9 +46,9 @@ def _mk_archieve(): except FileNotFoundError: pass os.system("pyinstaller.exe pyinstaller.spec") - archieve = ZipFile(path, "w") - archieve.writestr("dcs_liberation.bat", "cd dist\\dcs_liberation\r\nliberation_main \"%UserProfile%\\Saved Games\" \"{}\"".format(VERSION)) - _zip_dir(archieve, "./dist/dcs_liberation") + #archieve = ZipFile(path, "w") + #archieve.writestr("dcs_liberation.bat", "cd dist\\dcs_liberation\r\nliberation_main \"%UserProfile%\\Saved Games\" \"{}\"".format(VERSION)) + #_zip_dir(archieve, "./dist/dcs_liberation") _mk_archieve() diff --git a/resources/tools/nev_terrain.miz b/resources/tools/nev_terrain.miz index 4621f1f5..dec5094f 100644 Binary files a/resources/tools/nev_terrain.miz and b/resources/tools/nev_terrain.miz differ