diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..5fad7bff --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,107 @@ +name: Release Pipeline + +on: + push: + tags: [ '*' ] + +jobs: + + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install environment + run: | + py -m venv ./venv + + - name: Install dependencies + run: | + ./venv/scripts/activate + pip install -r requirements.txt + # For some reason the shiboken2.abi3.dll is not found properly, so I copy it instead + Copy-Item .\venv\Lib\site-packages\shiboken2\shiboken2.abi3.dll .\venv\Lib\site-packages\PySide2\ -Force + + - name: Build binaries + run: | + ./venv/scripts/activate + $env:PYTHONPATH=".;./pydcs" + pyinstaller pyinstaller.spec + + - name: Create Installer + env: + TAG_NAME: ${{ github.ref }} + run: | + $version = ($env:TAG_NAME -split "/") | Select-Object -Last 1 + (Get-Content .\installer\dcs_liberation.iss) -replace "{{version}}",$version | Out-File .\build\installer.iss + cd .\installer + iscc.exe ..\build\installer.iss + cd .. + Copy-Item .\changelog.md .\dist + + - uses: actions/upload-artifact@v2 + with: + name: dcs_liberation + path: dist/ + + release: + needs: [ build ] + runs-on: windows-latest + steps: + - uses: actions/download-artifact@v2 + with: + name: dcs_liberation + + - name: "Get Version" + id: version + env: + TAG_NAME: ${{ github.ref }} + run: | + Get-ChildItem -Recurse -Depth 1 + $version = ($env:TAG_NAME -split "/") | Select-Object -Last 1 + $prerelease = ("2.1.1-alpha3" -match '[^\.\d]').ToString().ToLower() + Write-Host $version + Write-Host $prerelease + Write-Output "::set-output name=number::$version" + Write-Output "::set-output name=prerelease::$prerelease" + $changelog = Get-Content .\changelog.md + $last_change = ($changelog | Select-String -Pattern "^#\s" | Select-Object -Skip 1 -First 1).LineNumber - 2 + ($changelog | Select-Object -First $last_change) -join "`n" | Out-File .\releasenotes.md + Compress-Archive -Path .\dcs_liberation -DestinationPath "dcs_liberation.$version.zip" -Compression Optimal + + - uses: actions/create-release@v1 + id: create_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + body_path: releasenotes.md + draft: false + prerelease: ${{ steps.version.outputs.prerelease }} + + - uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./dcs_liberation.exe + asset_name: dcs_liberation.${{ steps.version.outputs.number }}.exe + asset_content_type: application/exe + + - uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./dcs_liberation.${{ steps.version.outputs.number }}.zip + asset_name: dcs_liberation.${{ steps.version.outputs.number }}.zip + asset_content_type: application/zip + \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..d8db9cf5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "pydcs"] + path = pydcs + url = https://github.com/pydcs/dcs + branch = master diff --git a/changelog.md b/changelog.md index 7d17b7f7..69a72793 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,23 @@ +# 2.1.1 + +## Features/Improvements : +* **[Other]** Added an installer option (thanks to contributor parithon) +* **[Cheat Menu]** Added possibility to replace destroyed SAM and base defenses units for the player (Click on a SAM site to fix it) +* **[Cheat Menu]** Added recon images for buildings on strike targets, click on a Strike target to get detailled informations +* **[Units/Factions]** Added F-16C to USA 1990 +* **[Units/Factions]** Added MQ-9 Reaper as CAS unit for USA 2005 +* **[Units/Factions]** Added Mig-21, Mig-23, SA-342L to Syria 2011 +* **[Cheat Menu]** Added buttons to remove money + +## Fixed issues : +* **[UI/UX]** Spelling issues (Thanks to Github contributor steveveepee) +* **[Campaign Generator]** LHA was placed on land in Syrian Civil War campaign +* **[Campaign Generator]** Fixed inverted configuration for Syria full map +* **[Campaign Generator]** Syria "Inherent Resolve" campaign, added Incirlik Air Base +* **[Mission Generator]** AH-1W was not used by AI to generate CAS mission by default +* **[Mission Generator]** Fixed F-16C targeting pod not being added to payload +* **[Mission Generator]** AH-64A and AH-64D payloads fix. + # 2.1.0 ## Features/Improvements : diff --git a/game/data/building_data.py b/game/data/building_data.py index 90d94cb2..f88415ce 100644 --- a/game/data/building_data.py +++ b/game/data/building_data.py @@ -1,12 +1,12 @@ import inspect -import dcs +from pydcs import dcs DEFAULT_AVAILABLE_BUILDINGS = ['fuel', 'ammo', 'comms', 'oil', 'ware', 'farp', 'fob', 'power', 'factory', 'derrick', 'aa'] WW2_GERMANY_BUILDINGS = ['fuel', 'factory', 'ww2bunker', 'ww2bunker', 'ww2bunker', 'allycamp', 'allycamp', 'aa'] WW2_ALLIES_BUILDINGS = ['fuel', 'factory', 'allycamp', 'allycamp', 'allycamp', 'allycamp', 'allycamp', 'aa'] -FORTIFICATION_BUILDINGS = ['Siegfried Line', 'Concertina Wire', 'Czech hedgehogs 1', 'Czech hedgehogs 2', +FORTIFICATION_BUILDINGS = ['Siegfried Line', 'Concertina wire', 'Concertina Wire', 'Czech hedgehogs 1', 'Czech hedgehogs 2', 'Dragonteeth 1', 'Dragonteeth 2', 'Dragonteeth 3', 'Dragonteeth 4', 'Dragonteeth 5', 'Haystack 1', 'Haystack 2', 'Haystack 3', 'Haystack 4', 'Hemmkurvenvenhindernis', 'Log posts 1', 'Log posts 2', 'Log posts 3', 'Log ramps 1', 'Log ramps 2', 'Log ramps 3', diff --git a/game/db.py b/game/db.py index 9c91cbda..a4cc3e4a 100644 --- a/game/db.py +++ b/game/db.py @@ -295,23 +295,6 @@ PRICES = { Unarmed.Transport_M818: 3, - AirDefence.AAA_Vulcan_M163: 5, - AirDefence.SAM_Linebacker_M6: 10, - - AirDefence.AAA_ZU_23_Closed: 2, - AirDefence.SPAAA_ZSU_23_4_Shilka: 4, - AirDefence.SAM_SA_9_Strela_1_9P31: 8, - AirDefence.SAM_SA_19_Tunguska_2S6: 15, - AirDefence.SAM_SA_6_Kub_LN_2P25: 22, - AirDefence.SAM_SA_8_Osa_9A33: 12, - AirDefence.SAM_SA_3_S_125_LN_5P73: 20, - AirDefence.SAM_SA_2_LN_SM_90: 15, - AirDefence.SAM_SA_11_Buk_LN_9A310M1: 25, - AirDefence.SAM_Hawk_PCP: 20, - AirDefence.SAM_Patriot_LN_M901: 60, - AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 60, - AirDefence.SAM_Chaparral_M48: 10, - # WW2 Armor.MT_Pz_Kpfw_V_Panther_Ausf_G:24, Armor.MT_Pz_Kpfw_IV_Ausf_H:16, @@ -332,9 +315,6 @@ PRICES = { Armor.LAC_M8_Greyhound: 8, Armor.TD_M10_GMC: 14, Armor.StuG_III_Ausf__G: 12, - AirDefence.AAA_Bofors_40mm: 8, - AirDefence.AAA_8_8cm_Flak_36: 8, - AirDefence.AAA_8_8cm_Flak_18: 12, Artillery.M12_GMC: 10, Artillery.Sturmpanzer_IV_Brummbär: 10, @@ -348,6 +328,79 @@ PRICES = { Dry_cargo_ship_Ivanov: 10, Tanker_Elnya_160: 10, + # Air Defence units + AirDefence.SAM_SA_19_Tunguska_2S6: 30, + AirDefence.SAM_SA_6_Kub_LN_2P25: 20, + AirDefence.SAM_SA_3_S_125_LN_5P73: 6, + AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 22, + AirDefence.SAM_SA_10_S_300PS_LN_5P85D: 22, + AirDefence.SAM_SA_11_Buk_LN_9A310M1: 30, + AirDefence.SAM_SA_8_Osa_9A33: 28, + AirDefence.SAM_SA_15_Tor_9A331: 40, + AirDefence.SAM_SA_13_Strela_10M3_9A35M3: 24, + AirDefence.SAM_SA_9_Strela_1_9P31: 16, + AirDefence.SAM_SA_11_Buk_CC_9S470M1: 25, + AirDefence.SAM_SA_8_Osa_LD_9T217: 22, + AirDefence.SAM_Patriot_AMG_AN_MRC_137: 35, + AirDefence.SAM_Patriot_ECS_AN_MSQ_104: 30, + AirDefence.SPAAA_Gepard: 24, + AirDefence.SAM_Hawk_PCP: 14, + AirDefence.AAA_Vulcan_M163: 12, + AirDefence.SAM_Hawk_LN_M192: 8, + AirDefence.SAM_Chaparral_M48: 16, + AirDefence.SAM_Linebacker_M6: 18, + AirDefence.SAM_Patriot_LN_M901: 15, + AirDefence.SAM_Avenger_M1097: 20, + AirDefence.SAM_Patriot_EPP_III: 15, + AirDefence.SAM_Patriot_ICC: 18, + AirDefence.SAM_Roland_ADS: 12, + AirDefence.SAM_SA_10_S_300PS_CP_54K6: 18, + AirDefence.Stinger_MANPADS: 6, + AirDefence.SAM_Stinger_comm_dsr: 4, + AirDefence.SAM_Stinger_comm: 4, + AirDefence.SPAAA_ZSU_23_4_Shilka: 12, + AirDefence.AAA_ZU_23_Closed: 6, + AirDefence.AAA_ZU_23_Emplacement: 6, + AirDefence.AAA_ZU_23_on_Ural_375: 8, + AirDefence.AAA_ZU_23_Insurgent_Closed: 6, + AirDefence.AAA_ZU_23_Insurgent_on_Ural_375: 8, + AirDefence.AAA_ZU_23_Insurgent: 6, + AirDefence.SAM_SA_18_Igla_MANPADS: 10, + AirDefence.SAM_SA_18_Igla_comm: 8, + AirDefence.SAM_SA_18_Igla_S_MANPADS: 12, + AirDefence.SAM_SA_18_Igla_S_comm: 8, + AirDefence.EWR_1L13: 30, + AirDefence.SAM_SA_6_Kub_STR_9S91: 22, + AirDefence.SAM_SA_10_S_300PS_TR_30N6: 24, + AirDefence.SAM_SA_10_S_300PS_SR_5N66M: 30, + AirDefence.EWR_55G6: 30, + AirDefence.SAM_SA_10_S_300PS_SR_64H6E: 30, + AirDefence.SAM_SA_11_Buk_SR_9S18M1: 28, + AirDefence.CP_9S80M1_Sborka: 10, + AirDefence.SAM_Hawk_TR_AN_MPQ_46: 14, + AirDefence.SAM_Hawk_SR_AN_MPQ_50: 18, + AirDefence.SAM_Patriot_STR_AN_MPQ_53: 22, + AirDefence.SAM_Hawk_CWAR_AN_MPQ_55: 20, + AirDefence.SAM_SR_P_19: 14, + AirDefence.SAM_Roland_EWR: 16, + AirDefence.SAM_SA_3_S_125_TR_SNR: 14, + AirDefence.SAM_SA_2_LN_SM_90: 8, + AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song: 12, + AirDefence.Rapier_FSA_Launcher: 6, + AirDefence.Rapier_FSA_Optical_Tracker: 12, + AirDefence.Rapier_FSA_Blindfire_Tracker: 16, + AirDefence.HQ_7_Self_Propelled_LN: 20, + AirDefence.HQ_7_Self_Propelled_STR: 24, + AirDefence.AAA_8_8cm_Flak_18: 6, + AirDefence.AAA_Flak_38: 6, + AirDefence.AAA_8_8cm_Flak_36: 8, + AirDefence.AAA_8_8cm_Flak_37: 10, + AirDefence.AAA_Flak_Vierling_38:6, + AirDefence.AAA_Kdo_G_40: 8, + AirDefence.Flak_Searchlight_37: 4, + AirDefence.Maschinensatz_33: 10, + AirDefence.AAA_8_8cm_Flak_41: 12, + AirDefence.AAA_Bofors_40mm: 8, # FRENCH PACK MOD frenchpack.AMX_10RCR: 10, @@ -959,10 +1012,8 @@ PLANE_PAYLOAD_OVERRIDES = { RQ_1A_Predator: COMMON_OVERRIDE, WingLoong_I: COMMON_OVERRIDE, AH_1W: COMMON_OVERRIDE, - - AH_64D:{ - CAS: "AGM-114K*16" - }, + AH_64D: COMMON_OVERRIDE, + AH_64A: COMMON_OVERRIDE, Su_25TM: { SEAD: "Kh-31P*2_Kh-25ML*4_R-73*2_L-081_MPS410", diff --git a/game/event/event.py b/game/event/event.py index 6af3d6c9..e064ad94 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -178,9 +178,12 @@ class Event: for i, ground_object in enumerate(cp.ground_objects): if ground_object.dcs_identifier in ["AA", "CARRIER", "LHA"]: for g in ground_object.groups: + if not hasattr(g, "units_losts"): + g.units_losts = [] for u in g.units: if u.name == destroyed_ground_unit_name: g.units.remove(u) + g.units_losts.append(u) destroyed_units = destroyed_units + 1 info.text = u.type ucount = sum([len(g.units) for g in ground_object.groups]) diff --git a/game/factions/syria.py b/game/factions/syria.py index b14df3db..de082320 100644 --- a/game/factions/syria.py +++ b/game/factions/syria.py @@ -7,14 +7,20 @@ Syria_2011 = { "side": "red", "units": [ - MiG_29S, + MiG_21Bis, + MiG_23MLD, MiG_25PD, - L_39ZA, - Su_24M, + MiG_29S, + Su_17M4, + Su_24M, + + L_39ZA, + Mi_24V, - SA342M, Mi_8MT, + SA342M, + SA342L, IL_76MD, IL_78M, diff --git a/game/factions/usa_1990.py b/game/factions/usa_1990.py index 0eed7850..df2b37df 100644 --- a/game/factions/usa_1990.py +++ b/game/factions/usa_1990.py @@ -11,12 +11,11 @@ USA_1990 = { F_15E, F_14B, FA_18C_hornet, + F_16C_50, A_10A, AV8BNA, - B_1B, - KC_135, KC130, C_130, @@ -24,7 +23,6 @@ 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 19c8400e..ddeccd0b 100644 --- a/game/factions/usa_2005.py +++ b/game/factions/usa_2005.py @@ -14,6 +14,7 @@ USA_2005 = { F_16C_50, A_10C, AV8BNA, + MQ_9_Reaper, KC_135, KC130, @@ -22,7 +23,6 @@ USA_2005 = { UH_1H, AH_64D, - OH_58D, Armor.MBT_M1A2_Abrams, Armor.ATGM_M1134_Stryker, diff --git a/gen/aircraft.py b/gen/aircraft.py index 70826ea5..118189ff 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -516,6 +516,10 @@ class AircraftConflictGenerator: group.points[0].tasks.append(OptRestrictJettison(True)) for point in flight.points: - group.add_waypoint(Point(point.x,point.y), point.alt) + group.add_waypoint(Point(point.x, point.y), point.alt) + + + def setup_radio_preset(self, flight, group): + pass diff --git a/gen/conflictgen.py b/gen/conflictgen.py index 9b83b51e..1a5dabdb 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -1,7 +1,7 @@ import logging import typing import pdb -import dcs +from pydcs import dcs from random import randint from dcs import Mission diff --git a/gen/flights/ai_flight_planner.py b/gen/flights/ai_flight_planner.py index 1582276d..90a91500 100644 --- a/gen/flights/ai_flight_planner.py +++ b/gen/flights/ai_flight_planner.py @@ -7,7 +7,8 @@ from game.data.doctrine import MODERN_DOCTRINE from game.data.radar_db import UNITS_WITH_RADAR from game.utils import meter_to_feet, nm_to_meter from gen import Conflict -from gen.flights.ai_flight_planner_db import INTERCEPT_CAPABLE, CAP_CAPABLE, CAS_CAPABLE, SEAD_CAPABLE, STRIKE_CAPABLE +from gen.flights.ai_flight_planner_db import INTERCEPT_CAPABLE, CAP_CAPABLE, CAS_CAPABLE, SEAD_CAPABLE, STRIKE_CAPABLE, \ + DRONES from gen.flights.flight import Flight, FlightType, FlightWaypoint, FlightWaypointType @@ -245,8 +246,13 @@ class FlightPlanner: except IndexError: break - inventory[unit] = inventory[unit] - 2 - flight = Flight(unit, 2, self.from_cp, FlightType.STRIKE) + if unit in DRONES: + count = 1 + else: + count = 2 + + inventory[unit] = inventory[unit] - count + flight = Flight(unit, count, self.from_cp, FlightType.STRIKE) flight.points = [] flight.scheduled_in = offset + i*random.randint(self.doctrine["STRIKE_EVERY_X_MINUTES"] - 5, self.doctrine["STRIKE_EVERY_X_MINUTES"] + 5) diff --git a/gen/flights/ai_flight_planner_db.py b/gen/flights/ai_flight_planner_db.py index ba989284..dd924f64 100644 --- a/gen/flights/ai_flight_planner_db.py +++ b/gen/flights/ai_flight_planner_db.py @@ -74,7 +74,7 @@ CAP_CAPABLE = [ Rafale_M, ] -# USed for CAS (Close air support) and BAI (Battlefield Interdiction) +# Used for CAS (Close air support) and BAI (Battlefield Interdiction) CAS_CAPABLE = [ MiG_15bis, @@ -117,6 +117,8 @@ CAS_CAPABLE = [ AH_64A, AH_64D, + AH_1W, + UH_1H, diff --git a/gen/flights/radio_generator.py b/gen/flights/radio_generator.py new file mode 100644 index 00000000..1e647287 --- /dev/null +++ b/gen/flights/radio_generator.py @@ -0,0 +1,4 @@ +from dcs.unitgroup import FlyingGroup + + + diff --git a/gen/sam/sam_group_generator.py b/gen/sam/sam_group_generator.py index c1c4c95d..7979cb16 100644 --- a/gen/sam/sam_group_generator.py +++ b/gen/sam/sam_group_generator.py @@ -65,6 +65,40 @@ SAM_MAP = { AirDefence.HQ_7_Self_Propelled_LN: HQ7Generator } +SAM_PRICES = { + AirDefence.SAM_Hawk_PCP: 35, + AirDefence.AAA_ZU_23_Emplacement: 10, + AirDefence.AAA_ZU_23_Closed: 10, + AirDefence.AAA_ZU_23_on_Ural_375: 10, + AirDefence.AAA_ZU_23_Insurgent_on_Ural_375: 10, + AirDefence.AAA_ZU_23_Insurgent_Closed: 10, + AirDefence.AAA_ZU_23_Insurgent: 10, + AirDefence.SPAAA_ZSU_23_4_Shilka: 10, + AirDefence.AAA_Vulcan_M163: 15, + AirDefence.SAM_Linebacker_M6: 20, + AirDefence.Rapier_FSA_Launcher: 20, + AirDefence.SAM_Avenger_M1097: 22, + AirDefence.SPAAA_Gepard: 24, + AirDefence.SAM_Roland_ADS: 40, + AirDefence.SAM_Patriot_LN_M901: 85, + AirDefence.SAM_Patriot_EPP_III: 85, + AirDefence.SAM_Chaparral_M48: 25, + AirDefence.AAA_Bofors_40mm: 15, + AirDefence.AAA_8_8cm_Flak_36: 15, + AirDefence.SAM_SA_2_LN_SM_90: 30, + AirDefence.SAM_SA_3_S_125_LN_5P73: 35, + AirDefence.SAM_SA_6_Kub_LN_2P25: 45, + AirDefence.SAM_SA_8_Osa_9A33: 30, + AirDefence.SAM_SA_9_Strela_1_9P31: 25, + AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 80, + AirDefence.SAM_SA_10_S_300PS_CP_54K6: 80, + AirDefence.SAM_SA_11_Buk_LN_9A310M1: 60, + AirDefence.SAM_SA_13_Strela_10M3_9A35M3: 30, + AirDefence.SAM_SA_15_Tor_9A331: 40, + AirDefence.SAM_SA_19_Tunguska_2S6: 35, + AirDefence.HQ_7_Self_Propelled_LN: 35 +} + def generate_anti_air_group(game, parent_cp, ground_object, faction:str): """ This generate a SAM group diff --git a/installer/ISCC.exe b/installer/ISCC.exe new file mode 100644 index 00000000..72a8c55b Binary files /dev/null and b/installer/ISCC.exe differ diff --git a/installer/dcs_liberation.iss b/installer/dcs_liberation.iss new file mode 100644 index 00000000..cd53dda3 --- /dev/null +++ b/installer/dcs_liberation.iss @@ -0,0 +1,51 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "DCS Liberation" +#define MyAppVersion "{{version}}" +#define MyAppPublisher "Khopa" +#define MyAppURL "https://github.com/Khopa/dcs_liberation/wiki" +#define MyAppExeName "liberation_main.exe" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{6753B352-D281-42CB-9AFA-5E93EB90AA5A} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +;AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={autopf}\{#MyAppName} +DefaultGroupName={#MyAppName} +AllowNoIcons=yes +; Remove the following line to run in administrative install mode (install for all users.) +PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed=dialog +OutputDir=..\dist +OutputBaseFilename=dcs_liberation +SetupIconFile=..\resources\icon.ico +UninstallDisplayIcon={app}\liberation_main.exe +Compression=lzma +SolidCompression=yes +WizardStyle=modern + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "..\dist\dcs_liberation\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + diff --git a/pydcs b/pydcs new file mode 160000 index 00000000..dcc3d846 --- /dev/null +++ b/pydcs @@ -0,0 +1 @@ +Subproject commit dcc3d846316af2925c93ae09840c3ab4a1150e59 diff --git a/qt_ui/main.py b/qt_ui/main.py index e019d32c..dff7e51b 100644 --- a/qt_ui/main.py +++ b/qt_ui/main.py @@ -4,7 +4,7 @@ import logging import os import sys -import dcs +from pydcs import dcs from PySide2 import QtWidgets from PySide2.QtGui import QPixmap from PySide2.QtWidgets import QApplication, QSplashScreen diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index 2e763071..41194ca0 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -143,7 +143,7 @@ class QLiberationMap(QGraphicsView): go_pos = self._transform_point(ground_object.position) if not ground_object.airbase_group: buildings = self.game.theater.find_ground_objects_by_obj_name(ground_object.obj_name) - scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 12, 12, cp, ground_object, buildings)) + scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 14, 12, cp, ground_object, self.game, buildings)) if ground_object.category == "aa" and self.get_display_rule("sam"): max_range = 0 diff --git a/qt_ui/widgets/map/QMapGroundObject.py b/qt_ui/widgets/map/QMapGroundObject.py index dbbf4d79..a79ce1ab 100644 --- a/qt_ui/widgets/map/QMapGroundObject.py +++ b/qt_ui/widgets/map/QMapGroundObject.py @@ -1,19 +1,22 @@ from PySide2.QtCore import QPoint, QRect, QPointF, Qt -from PySide2.QtGui import QPainter +from PySide2.QtGui import QPainter, QBrush from PySide2.QtWidgets import QGraphicsRectItem, QGraphicsItem, QGraphicsSceneHoverEvent, QGraphicsSceneMouseEvent import qt_ui.uiconstants as CONST -from game import db +from game import db, Game +from game.data.building_data import FORTIFICATION_BUILDINGS +from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu from theater import TheaterGroundObject, ControlPoint class QMapGroundObject(QGraphicsRectItem): - def __init__(self, parent, x: float, y: float, w: float, h: float, cp: ControlPoint, model: TheaterGroundObject, buildings=[]): + def __init__(self, parent, x: float, y: float, w: float, h: float, cp: ControlPoint, model: TheaterGroundObject, game:Game, buildings=[]): super(QMapGroundObject, self).__init__(x, y, w, h) self.model = model self.cp = cp self.parent = parent + self.game = game self.setAcceptHoverEvents(True) self.setZValue(2) self.buildings = buildings @@ -39,6 +42,8 @@ class QMapGroundObject(QGraphicsRectItem): tooltip = tooltip + str(building.dcs_identifier) + "\n" self.setToolTip(tooltip[:-1]) + def mousePressEvent(self, event:QGraphicsSceneMouseEvent): + self.openEditionMenu() def paint(self, painter, option, widget=None): #super(QMapControlPoint, self).paint(painter, option, widget) @@ -53,14 +58,49 @@ class QMapGroundObject(QGraphicsRectItem): if cat == "aa" and self.model.sea_object: cat = "ship" - if not self.model.is_dead and not self.cp.captured: - painter.drawPixmap(option.rect, CONST.ICONS[cat + enemyIcons]) - elif not self.model.is_dead: - painter.drawPixmap(option.rect, CONST.ICONS[cat + playerIcons]) + rect = QRect(option.rect.x()+2,option.rect.y(),option.rect.width()-2,option.rect.height()) + + is_dead = self.model.is_dead + for building in self.buildings: + if not building.is_dead: + is_dead = False + break + + if not is_dead and not self.cp.captured: + painter.drawPixmap(rect, CONST.ICONS[cat + enemyIcons]) + elif not is_dead: + painter.drawPixmap(rect, CONST.ICONS[cat + playerIcons]) else: - painter.drawPixmap(option.rect, CONST.ICONS["destroyed"]) + painter.drawPixmap(rect, CONST.ICONS["destroyed"]) + + self.drawHealthGauge(painter, option) painter.restore() + def drawHealthGauge(self, painter, option): + units_alive = 0 + units_dead = 0 + + if len(self.model.groups) == 0: + for building in self.buildings: + if building.dcs_identifier in FORTIFICATION_BUILDINGS: + continue + if building.is_dead: + units_dead += 1 + else: + units_alive += 1 + + for g in self.model.groups: + units_alive += len(g.units) + if hasattr(g, "units_losts"): + units_dead += len(g.units_losts) + + if units_dead + units_alive > 0: + ratio = float(units_alive)/(float(units_dead) + float(units_alive)) + bar_height = ratio * option.rect.height() + painter.fillRect(option.rect.x(), option.rect.y(), 2, option.rect.height(), QBrush(CONST.COLORS["dark_red"])) + painter.fillRect(option.rect.x(), option.rect.y(), 2, bar_height, QBrush(CONST.COLORS["green"])) + + def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent): self.update() self.setCursor(Qt.PointingHandCursor) @@ -72,3 +112,7 @@ class QMapGroundObject(QGraphicsRectItem): def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent): self.update() + def openEditionMenu(self): + self.editionMenu = QGroundObjectMenu(self.window(), self.model, self.buildings, self.cp, self.game) + self.editionMenu.show() + diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py b/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py index c3f3d454..2b2abb67 100644 --- a/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py +++ b/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py @@ -1,16 +1,22 @@ -from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox +from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox, QPushButton from qt_ui.uiconstants import VEHICLES_ICONS +from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu from theater import ControlPoint, TheaterGroundObject class QBaseDefenseGroupInfo(QGroupBox): - def __init__(self, cp:ControlPoint, ground_object: TheaterGroundObject): + def __init__(self, cp:ControlPoint, ground_object: TheaterGroundObject, game): super(QBaseDefenseGroupInfo, self).__init__("Group : " + ground_object.obj_name) self.ground_object = ground_object + self.cp = cp + self.game = game + self.buildings = game.theater.find_ground_objects_by_obj_name(self.ground_object.obj_name) self.init_ui() + + def init_ui(self): unit_dict = {} layout = QGridLayout() @@ -29,8 +35,18 @@ class QBaseDefenseGroupInfo(QGroupBox): # icon.setText("" + k[:6] + "") #icon.setProperty("style", "icon-plane") #layout.addWidget(icon, i, 0) - layout.addWidget(QLabel(str(v) + " x " + "" + k + ""), i, 1) + layout.addWidget(QLabel(str(v) + " x " + "" + k + ""), i, 0) i = i + 1 + + manage_button = QPushButton("Manage") + manage_button.setProperty("style", "btn-success") + manage_button.setMaximumWidth(180) + manage_button.clicked.connect(self.onManage) + layout.addWidget(manage_button, i+1, 0) self.setLayout(layout) + def onManage(self): + self.editionMenu = QGroundObjectMenu(self.window(), self.ground_object, self.buildings, self.cp, self.game) + self.editionMenu.show() + diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py b/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py index 77c53939..5ad1f6c9 100644 --- a/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py +++ b/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py @@ -15,6 +15,6 @@ class QBaseDefensesHQ(QFrame): def init_ui(self): airport = self.game.theater.terrain.airport_by_id(self.cp.id) layout = QGridLayout() - layout.addWidget(QBaseInformation(self.cp, airport)) + layout.addWidget(QBaseInformation(self.cp, airport, self.game)) self.setLayout(layout) diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py b/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py index 7ae07483..c98113b6 100644 --- a/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py +++ b/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py @@ -1,4 +1,5 @@ -from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox, QVBoxLayout, QFrame +from PySide2.QtGui import Qt +from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox, QVBoxLayout, QFrame, QWidget, QScrollArea from game import db from qt_ui.uiconstants import AIRCRAFT_ICONS, VEHICLES_ICONS @@ -8,17 +9,34 @@ from theater import ControlPoint, Airport class QBaseInformation(QFrame): - def __init__(self, cp:ControlPoint, airport:Airport): + def __init__(self, cp:ControlPoint, airport:Airport, game): super(QBaseInformation, self).__init__() self.cp = cp self.airport = airport + self.game = game self.setMinimumWidth(500) self.init_ui() def init_ui(self): - self.layout = QVBoxLayout() + self.mainLayout = QVBoxLayout() + + scroll_content = QWidget() + task_box_layout = QGridLayout() + scroll_content.setLayout(task_box_layout) + row = 0 + for g in self.cp.ground_objects: if g.airbase_group: - group_info = QBaseDefenseGroupInfo(self.cp, g) - self.layout.addWidget(group_info) - self.setLayout(self.layout) + group_info = QBaseDefenseGroupInfo(self.cp, g, self.game) + task_box_layout.addWidget(group_info) + + scroll_content.setLayout(task_box_layout) + scroll = QScrollArea() + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + scroll.setWidgetResizable(True) + scroll.setWidget(scroll_content) + + self.mainLayout.addWidget(scroll) + + self.setLayout(self.mainLayout) \ No newline at end of file diff --git a/qt_ui/windows/groundobject/QBuildingInfo.py b/qt_ui/windows/groundobject/QBuildingInfo.py new file mode 100644 index 00000000..e474a59f --- /dev/null +++ b/qt_ui/windows/groundobject/QBuildingInfo.py @@ -0,0 +1,33 @@ +import os + +from PySide2.QtGui import QPixmap +from PySide2.QtWidgets import QGroupBox, QHBoxLayout, QVBoxLayout, QLabel + + +class QBuildingInfo(QGroupBox): + + def __init__(self, building, ground_object): + super(QBuildingInfo, self).__init__() + self.building = building + self.ground_object = ground_object + self.init_ui() + + def init_ui(self): + self.header = QLabel() + path = os.path.join("./resources/ui/units/buildings/" + self.building.dcs_identifier + ".png") + if self.building.is_dead: + pixmap = QPixmap("./resources/ui/units/buildings/dead.png") + elif os.path.isfile(path): + pixmap = QPixmap(path) + else: + pixmap = QPixmap("./resources/ui/units/buildings/missing.png") + self.header.setPixmap(pixmap) + name = "{} {}".format(self.building.dcs_identifier[0:18], "[DEAD]" if self.building.is_dead else "") + self.name = QLabel(name) + self.name.setProperty("style", "small") + layout = QVBoxLayout() + layout.addWidget(self.header) + layout.addWidget(self.name) + footer = QHBoxLayout() + self.setLayout(layout) + diff --git a/qt_ui/windows/groundobject/QGroundObjectMenu.py b/qt_ui/windows/groundobject/QGroundObjectMenu.py new file mode 100644 index 00000000..b6c90027 --- /dev/null +++ b/qt_ui/windows/groundobject/QGroundObjectMenu.py @@ -0,0 +1,117 @@ +import logging + +from PySide2.QtGui import QCloseEvent +from PySide2.QtWidgets import QHBoxLayout, QWidget, QDialog, QGridLayout, QLabel, QGroupBox, QVBoxLayout, QPushButton +from dcs import Point + +from game import Game +from game.data.building_data import FORTIFICATION_BUILDINGS +from game.db import PRICES, unit_type_of +from qt_ui.uiconstants import EVENT_ICONS +from qt_ui.widgets.QBudgetBox import QBudgetBox +from qt_ui.windows.GameUpdateSignal import GameUpdateSignal +from qt_ui.windows.groundobject.QBuildingInfo import QBuildingInfo +from theater import ControlPoint, TheaterGroundObject + + +class QGroundObjectMenu(QDialog): + + def __init__(self, parent, ground_object: TheaterGroundObject, buildings:[], cp: ControlPoint, game: Game): + super(QGroundObjectMenu, self).__init__(parent) + self.setMinimumWidth(350) + self.ground_object = ground_object + self.buildings = buildings + self.cp = cp + self.game = game + self.setWindowTitle("Location " + self.ground_object.obj_name) + self.setWindowIcon(EVENT_ICONS["capture"]) + self.intelBox = QGroupBox("Units :") + self.buildingBox = QGroupBox("Buildings :") + self.intelLayout = QGridLayout() + self.buildingsLayout = QGridLayout() + self.init_ui() + + def init_ui(self): + + self.mainLayout = QVBoxLayout() + self.budget = QBudgetBox(self.game) + self.budget.setGame(self.game) + + self.doLayout() + + if len(self.ground_object.groups) > 0: + self.mainLayout.addWidget(self.intelBox) + else: + self.mainLayout.addWidget(self.buildingBox) + self.setLayout(self.mainLayout) + + def doLayout(self): + self.intelBox = QGroupBox("Units :") + self.intelLayout = QGridLayout() + i = 0 + for g in self.ground_object.groups: + if not hasattr(g, "units_losts"): + g.units_losts = [] + for u in g.units: + self.intelLayout.addWidget(QLabel("Unit #" + str(u.id) + " - " + str(u.type) + ""), i, 0) + i = i + 1 + + for u in g.units_losts: + + utype = unit_type_of(u) + if utype in PRICES: + price = PRICES[utype] + else: + price = 6 + + self.intelLayout.addWidget(QLabel("Unit #" + str(u.id) + " - " + str(u.type) + " [DEAD]"), i, 0) + if self.cp.captured: + repair = QPushButton("Repair [" + str(price) + "M]") + repair.setProperty("style", "btn-success") + repair.clicked.connect(lambda u=u, g=g, p=price: self.repair_unit(g, u, p)) + self.intelLayout.addWidget(repair, i, 1) + i = i + 1 + + self.buildingBox = QGroupBox("Buildings :") + self.buildingsLayout = QGridLayout() + j = 0 + for i, building in enumerate(self.buildings): + if building.dcs_identifier not in FORTIFICATION_BUILDINGS: + self.buildingsLayout.addWidget(QBuildingInfo(building, self.ground_object), j/3, j%3) + j = j + 1 + + self.buildingBox.setLayout(self.buildingsLayout) + self.intelBox.setLayout(self.intelLayout) + + def do_refresh_layout(self): + try: + for i in range(self.mainLayout.count()): + self.mainLayout.removeItem(self.mainLayout.itemAt(i)) + self.doLayout() + if len(self.ground_object.groups) > 0: + self.mainLayout.addWidget(self.intelBox) + else: + self.mainLayout.addWidget(self.buildingBox) + except Exception as e: + print(e) + + def repair_unit(self, group, unit, price): + if self.game.budget > price: + self.game.budget -= price + group.units_losts = [u for u in group.units_losts if u.id != unit.id] + group.units.append(unit) + GameUpdateSignal.get_instance().updateGame(self.game) + + # Remove destroyed units in the vicinity + destroyed_units = self.game.get_destroyed_units() + for d in destroyed_units: + p = Point(d["x"], d["z"]) + if p.distance_to_point(unit.position) < 15: + destroyed_units.remove(d) + logging.info("Removed destroyed units " + str(d)) + logging.info("Repaired unit : " + str(unit.id) + " " + str(unit.type)) + + self.do_refresh_layout() + + def closeEvent(self, closeEvent: QCloseEvent): + GameUpdateSignal.get_instance().updateGame(self.game) diff --git a/qt_ui/windows/groundobject/QGroundObjectReplacementMenu.py b/qt_ui/windows/groundobject/QGroundObjectReplacementMenu.py new file mode 100644 index 00000000..e69de29b diff --git a/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py b/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py index 4dac3bed..1f18c293 100644 --- a/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py +++ b/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py @@ -24,7 +24,11 @@ class QLoadoutEditor(QGroupBox): label = QLabel("{}".format(pylon.__name__[len("Pylon"):])) label.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) layout.addWidget(label, i, 0) - layout.addWidget(QPylonEditor(flight, pylon, i+1), i, 1) + try: + pylon_number = int(pylon.__name__.split("Pylon")[1]) + except: + pylon_number = i+1 + layout.addWidget(QPylonEditor(flight, pylon, pylon_number), i, 1) hboxLayout.addLayout(layout) hboxLayout.addStretch() diff --git a/qt_ui/windows/settings/QSettingsWindow.py b/qt_ui/windows/settings/QSettingsWindow.py index d5c27b3b..6ccdb226 100644 --- a/qt_ui/windows/settings/QSettingsWindow.py +++ b/qt_ui/windows/settings/QSettingsWindow.py @@ -1,3 +1,5 @@ +import logging + from PySide2.QtCore import QSize, Qt, QItemSelectionModel, QPoint from PySide2.QtGui import QStandardItemModel, QStandardItem from PySide2.QtWidgets import QLabel, QDialog, QGridLayout, QListView, QStackedLayout, QComboBox, QWidget, \ @@ -269,32 +271,28 @@ class QSettingsWindow(QDialog): self.moneyCheatBoxLayout = QGridLayout() self.moneyCheatBox.setLayout(self.moneyCheatBoxLayout) - self.cheat25M = QPushButton("Cheat +25M") - self.cheat50M = QPushButton("Cheat +50M") - self.cheat100M = QPushButton("Cheat +100M") - self.cheat200M = QPushButton("Cheat +200M") - self.cheat500M = QPushButton("Cheat +500M") - self.cheat1000M = QPushButton("Cheat +1000M") - - self.cheat25M.clicked.connect(lambda: self.cheatMoney(25)) - self.cheat50M.clicked.connect(lambda: self.cheatMoney(50)) - self.cheat100M.clicked.connect(lambda: self.cheatMoney(100)) - self.cheat200M.clicked.connect(lambda: self.cheatMoney(200)) - self.cheat500M.clicked.connect(lambda: self.cheatMoney(500)) - self.cheat1000M.clicked.connect(lambda: self.cheatMoney(1000)) - - self.moneyCheatBoxLayout.addWidget(self.cheat25M, 0, 0) - self.moneyCheatBoxLayout.addWidget(self.cheat50M, 0, 1) - self.moneyCheatBoxLayout.addWidget(self.cheat100M, 1, 0) - self.moneyCheatBoxLayout.addWidget(self.cheat200M, 1, 1) - self.moneyCheatBoxLayout.addWidget(self.cheat500M, 2, 0) - self.moneyCheatBoxLayout.addWidget(self.cheat1000M, 2, 1) - + cheats_amounts = [25, 50, 100, 200, 500, 1000, -25, -50, -100, -200] + for i, amount in enumerate(cheats_amounts): + if amount > 0: + btn = QPushButton("Cheat +" + str(amount) + "M") + btn.setProperty("style", "btn-success") + else: + btn = QPushButton("Cheat " + str(amount) + "M") + btn.setProperty("style", "btn-danger") + btn.clicked.connect(self.cheatLambda(amount)) + self.moneyCheatBoxLayout.addWidget(btn, i/2, i%2) self.cheatLayout.addWidget(self.moneyCheatBox, 0, 0) + def cheatLambda(self, amount): + return lambda: self.cheatMoney(amount) + def cheatMoney(self, amount): + logging.info("CHEATING FOR AMOUNT : " + str(amount) + "M") self.game.budget += amount - self.game.informations.append(Information("CHEATER", "You are a cheater and you should feel bad", self.game.turn)) + if amount > 0: + self.game.informations.append(Information("CHEATER", "You are a cheater and you should feel bad", self.game.turn)) + else: + self.game.informations.append(Information("CHEATER", "You are still a cheater !", self.game.turn)) GameUpdateSignal.get_instance().updateGame(self.game) def applySettings(self): diff --git a/requirements.txt b/requirements.txt index a7e3170e..6f314f97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pydcs>=0.9.10 +#pydcs>=0.9.10 Pyside2>=5.13.0 pyinstaller==3.6 pyproj==2.6.1.post1 diff --git a/resources/customized_payloads/AH-64A.lua b/resources/customized_payloads/AH-64A.lua new file mode 100644 index 00000000..80613b07 --- /dev/null +++ b/resources/customized_payloads/AH-64A.lua @@ -0,0 +1,118 @@ +local unitPayloads = { + ["name"] = "AH-64A", + ["payloads"] = { + [1] = { + ["name"] = "CAS", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + [3] = { + ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", + ["num"] = 3, + }, + [4] = { + ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", + ["num"] = 2, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [2] = { + ["name"] = "STRIKE", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [3] = { + ["name"] = "CAP", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [4] = { + ["name"] = "ANTISHIP", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 3, + }, + [3] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 2, + }, + [4] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [5] = { + ["name"] = "SEAD", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + }, + ["unitType"] = "AH-64A", +} +return unitPayloads diff --git a/resources/customized_payloads/AH-64D.lua b/resources/customized_payloads/AH-64D.lua new file mode 100644 index 00000000..f6ecce67 --- /dev/null +++ b/resources/customized_payloads/AH-64D.lua @@ -0,0 +1,110 @@ +local unitPayloads = { + ["name"] = "AH-64D", + ["payloads"] = { + [1] = { + ["name"] = "CAS", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [2] = { + ["name"] = "CAP", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [3] = { + ["name"] = "ANTISHIP", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + [3] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 3, + }, + [4] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 2, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [4] = { + ["name"] = "SEAD", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + [5] = { + ["name"] = "STRIKE", + ["pylons"] = { + [1] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 4, + }, + [2] = { + ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 18, + [2] = 31, + [3] = 32, + [4] = 30, + }, + }, + }, + ["unitType"] = "AH-64D", +} +return unitPayloads diff --git a/resources/customized_payloads/F-16C_50.lua b/resources/customized_payloads/F-16C_50.lua index e2868660..d48ad19e 100644 --- a/resources/customized_payloads/F-16C_50.lua +++ b/resources/customized_payloads/F-16C_50.lua @@ -2,53 +2,6 @@ local unitPayloads = { ["name"] = "F-16C_50", ["payloads"] = { [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - }, - ["tasks"] = { - }, - }, - [2] = { ["name"] = "ANTISHIP", ["pylons"] = { [1] = { @@ -91,7 +44,7 @@ local unitPayloads = { ["tasks"] = { }, }, - [3] = { + [2] = { ["name"] = "CAP", ["pylons"] = { [1] = { @@ -134,6 +87,53 @@ local unitPayloads = { ["tasks"] = { }, }, + [3] = { + ["name"] = "CAS", + ["pylons"] = { + [1] = { + ["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}", + ["num"] = 5, + }, + [2] = { + ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", + ["num"] = 7, + }, + [3] = { + ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", + ["num"] = 3, + }, + [4] = { + ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", + ["num"] = 2, + }, + [5] = { + ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", + ["num"] = 1, + }, + [6] = { + ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", + ["num"] = 8, + }, + [7] = { + ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", + ["num"] = 9, + }, + [8] = { + ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}", + ["num"] = 4, + }, + [9] = { + ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}", + ["num"] = 6, + }, + [11] = { + ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", + ["num"] = 11, + }, + }, + ["tasks"] = { + }, + }, [4] = { ["name"] = "STRIKE", ["pylons"] = { @@ -173,6 +173,10 @@ local unitPayloads = { ["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}", ["num"] = 5, }, + [11] = { + ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", + ["num"] = 11, + }, }, ["tasks"] = { }, diff --git a/resources/stylesheets/style-dcs.css b/resources/stylesheets/style-dcs.css index c01f398c..57b2478b 100644 --- a/resources/stylesheets/style-dcs.css +++ b/resources/stylesheets/style-dcs.css @@ -486,3 +486,7 @@ QWidget[style="baseMenuHeader"]{ font-weight: bold; color:white; }*/ + +QLabel[style="small"]{ + font-size: 8px; +} \ No newline at end of file diff --git a/resources/stylesheets/style.css b/resources/stylesheets/style.css index a8b65845..b382f642 100644 --- a/resources/stylesheets/style.css +++ b/resources/stylesheets/style.css @@ -178,4 +178,8 @@ QLabel[style="SEAD"]{ QWidget[style="baseMenuHeader"]{ font-size: 24px; font-weight: bold; -}*/ \ No newline at end of file +}*/ + +QLabel[style="small"]{ + font-size: 8px; +} \ No newline at end of file diff --git a/resources/tools/generate_loadout_check.py b/resources/tools/generate_loadout_check.py index 3d86d329..ae299a0f 100644 --- a/resources/tools/generate_loadout_check.py +++ b/resources/tools/generate_loadout_check.py @@ -1,6 +1,6 @@ import os import sys -import dcs +from pydcs import dcs from game import db from gen.aircraft import AircraftConflictGenerator diff --git a/resources/tools/mkrelease.py b/resources/tools/mkrelease.py index f7dea204..a76029b9 100644 --- a/resources/tools/mkrelease.py +++ b/resources/tools/mkrelease.py @@ -45,7 +45,7 @@ def _mk_archieve(): shutil.rmtree("./dist") except FileNotFoundError: pass - os.system("pyinstaller.exe pyinstaller.spec") + os.system("pyinstaller.exe --clean 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") diff --git a/resources/ui/units/buildings/.Ammunition depot.png b/resources/ui/units/buildings/.Ammunition depot.png new file mode 100644 index 00000000..3c17b0e2 Binary files /dev/null and b/resources/ui/units/buildings/.Ammunition depot.png differ diff --git a/resources/ui/units/buildings/.Command Center.png b/resources/ui/units/buildings/.Command Center.png new file mode 100644 index 00000000..4e309d13 Binary files /dev/null and b/resources/ui/units/buildings/.Command Center.png differ diff --git a/resources/ui/units/buildings/Barracks 2.png b/resources/ui/units/buildings/Barracks 2.png new file mode 100644 index 00000000..c25e5e01 Binary files /dev/null and b/resources/ui/units/buildings/Barracks 2.png differ diff --git a/resources/ui/units/buildings/Chemical Tank A.png b/resources/ui/units/buildings/Chemical Tank A.png new file mode 100644 index 00000000..1311207b Binary files /dev/null and b/resources/ui/units/buildings/Chemical Tank A.png differ diff --git a/resources/ui/units/buildings/Comms tower M.png b/resources/ui/units/buildings/Comms tower M.png new file mode 100644 index 00000000..388fafff Binary files /dev/null and b/resources/ui/units/buildings/Comms tower M.png differ diff --git a/resources/ui/units/buildings/Electric power box.png b/resources/ui/units/buildings/Electric power box.png new file mode 100644 index 00000000..830a6413 Binary files /dev/null and b/resources/ui/units/buildings/Electric power box.png differ diff --git a/resources/ui/units/buildings/FARP Ammo Dump Coating.png b/resources/ui/units/buildings/FARP Ammo Dump Coating.png new file mode 100644 index 00000000..95840b1c Binary files /dev/null and b/resources/ui/units/buildings/FARP Ammo Dump Coating.png differ diff --git a/resources/ui/units/buildings/FARP CP Blindage.png b/resources/ui/units/buildings/FARP CP Blindage.png new file mode 100644 index 00000000..0c7db6fb Binary files /dev/null and b/resources/ui/units/buildings/FARP CP Blindage.png differ diff --git a/resources/ui/units/buildings/FARP Fuel Depot.png b/resources/ui/units/buildings/FARP Fuel Depot.png new file mode 100644 index 00000000..d93a50c7 Binary files /dev/null and b/resources/ui/units/buildings/FARP Fuel Depot.png differ diff --git a/resources/ui/units/buildings/FARP Tent.png b/resources/ui/units/buildings/FARP Tent.png new file mode 100644 index 00000000..199af963 Binary files /dev/null and b/resources/ui/units/buildings/FARP Tent.png differ diff --git a/resources/ui/units/buildings/Farm A.png b/resources/ui/units/buildings/Farm A.png new file mode 100644 index 00000000..787e8117 Binary files /dev/null and b/resources/ui/units/buildings/Farm A.png differ diff --git a/resources/ui/units/buildings/Farm B.png b/resources/ui/units/buildings/Farm B.png new file mode 100644 index 00000000..c889a8c0 Binary files /dev/null and b/resources/ui/units/buildings/Farm B.png differ diff --git a/resources/ui/units/buildings/Fire Control Bunker.png b/resources/ui/units/buildings/Fire Control Bunker.png new file mode 100644 index 00000000..5294b680 Binary files /dev/null and b/resources/ui/units/buildings/Fire Control Bunker.png differ diff --git a/resources/ui/units/buildings/Garage B.png b/resources/ui/units/buildings/Garage B.png new file mode 100644 index 00000000..b495a4d4 Binary files /dev/null and b/resources/ui/units/buildings/Garage B.png differ diff --git a/resources/ui/units/buildings/Garage small B.png b/resources/ui/units/buildings/Garage small B.png new file mode 100644 index 00000000..f04794d2 Binary files /dev/null and b/resources/ui/units/buildings/Garage small B.png differ diff --git a/resources/ui/units/buildings/Hangar A.png b/resources/ui/units/buildings/Hangar A.png new file mode 100644 index 00000000..0eb1a301 Binary files /dev/null and b/resources/ui/units/buildings/Hangar A.png differ diff --git a/resources/ui/units/buildings/Hangar B.png b/resources/ui/units/buildings/Hangar B.png new file mode 100644 index 00000000..96a28496 Binary files /dev/null and b/resources/ui/units/buildings/Hangar B.png differ diff --git a/resources/ui/units/buildings/Oil derrick.png b/resources/ui/units/buildings/Oil derrick.png new file mode 100644 index 00000000..5a3c5cb4 Binary files /dev/null and b/resources/ui/units/buildings/Oil derrick.png differ diff --git a/resources/ui/units/buildings/Oil platform.png b/resources/ui/units/buildings/Oil platform.png new file mode 100644 index 00000000..c548fe7c Binary files /dev/null and b/resources/ui/units/buildings/Oil platform.png differ diff --git a/resources/ui/units/buildings/Pump station.png b/resources/ui/units/buildings/Pump station.png new file mode 100644 index 00000000..24bc23d8 Binary files /dev/null and b/resources/ui/units/buildings/Pump station.png differ diff --git a/resources/ui/units/buildings/Repair Workshop.png b/resources/ui/units/buildings/Repair Workshop.png new file mode 100644 index 00000000..273291c7 Binary files /dev/null and b/resources/ui/units/buildings/Repair Workshop.png differ diff --git a/resources/ui/units/buildings/SK_C_28_naval_gun.png b/resources/ui/units/buildings/SK_C_28_naval_gun.png new file mode 100644 index 00000000..909f6209 Binary files /dev/null and b/resources/ui/units/buildings/SK_C_28_naval_gun.png differ diff --git a/resources/ui/units/buildings/Subsidiary structure 2.png b/resources/ui/units/buildings/Subsidiary structure 2.png new file mode 100644 index 00000000..daa22d4d Binary files /dev/null and b/resources/ui/units/buildings/Subsidiary structure 2.png differ diff --git a/resources/ui/units/buildings/TV tower.png b/resources/ui/units/buildings/TV tower.png new file mode 100644 index 00000000..6b7f514a Binary files /dev/null and b/resources/ui/units/buildings/TV tower.png differ diff --git a/resources/ui/units/buildings/Tank 2.png b/resources/ui/units/buildings/Tank 2.png new file mode 100644 index 00000000..77faa07b Binary files /dev/null and b/resources/ui/units/buildings/Tank 2.png differ diff --git a/resources/ui/units/buildings/Tank 3.png b/resources/ui/units/buildings/Tank 3.png new file mode 100644 index 00000000..8d807877 Binary files /dev/null and b/resources/ui/units/buildings/Tank 3.png differ diff --git a/resources/ui/units/buildings/Tank.png b/resources/ui/units/buildings/Tank.png new file mode 100644 index 00000000..06dcaee2 Binary files /dev/null and b/resources/ui/units/buildings/Tank.png differ diff --git a/resources/ui/units/buildings/Tech combine.png b/resources/ui/units/buildings/Tech combine.png new file mode 100644 index 00000000..e58dfa56 Binary files /dev/null and b/resources/ui/units/buildings/Tech combine.png differ diff --git a/resources/ui/units/buildings/Tech hangar A.png b/resources/ui/units/buildings/Tech hangar A.png new file mode 100644 index 00000000..423ba0cf Binary files /dev/null and b/resources/ui/units/buildings/Tech hangar A.png differ diff --git a/resources/ui/units/buildings/Warehouse.png b/resources/ui/units/buildings/Warehouse.png new file mode 100644 index 00000000..dc74ede4 Binary files /dev/null and b/resources/ui/units/buildings/Warehouse.png differ diff --git a/resources/ui/units/buildings/Watch tower armed.png b/resources/ui/units/buildings/Watch tower armed.png new file mode 100644 index 00000000..dd0889eb Binary files /dev/null and b/resources/ui/units/buildings/Watch tower armed.png differ diff --git a/resources/ui/units/buildings/Workshop A.png b/resources/ui/units/buildings/Workshop A.png new file mode 100644 index 00000000..fcb202ab Binary files /dev/null and b/resources/ui/units/buildings/Workshop A.png differ diff --git a/resources/ui/units/buildings/dead.png b/resources/ui/units/buildings/dead.png new file mode 100644 index 00000000..7b218858 Binary files /dev/null and b/resources/ui/units/buildings/dead.png differ diff --git a/resources/ui/units/buildings/house2arm.png b/resources/ui/units/buildings/house2arm.png new file mode 100644 index 00000000..dd0889eb Binary files /dev/null and b/resources/ui/units/buildings/house2arm.png differ diff --git a/resources/ui/units/buildings/missing.png b/resources/ui/units/buildings/missing.png new file mode 100644 index 00000000..88bc2301 Binary files /dev/null and b/resources/ui/units/buildings/missing.png differ diff --git a/theater/conflicttheater.py b/theater/conflicttheater.py index 621f106a..2934f15e 100644 --- a/theater/conflicttheater.py +++ b/theater/conflicttheater.py @@ -1,6 +1,6 @@ import typing -import dcs +from pydcs import dcs from dcs.mapping import Point from .controlpoint import ControlPoint diff --git a/theater/syria.py b/theater/syria.py index ecdea405..1465f58e 100644 --- a/theater/syria.py +++ b/theater/syria.py @@ -110,7 +110,7 @@ class SyrianCivilWar(SyriaTheater): self.palmyra = ControlPoint.from_airport(syria.Palmyra, LAND, SIZE_REGULAR, IMPORTANCE_LOW) self.carrier = ControlPoint.carrier("Carrier", Point(18537, -52000), 1001) - self.lha = ControlPoint.lha("LHA", Point(116000, 30000), 1002) + self.lha = ControlPoint.lha("LHA", Point(116000, -30000), 1002) self.add_controlpoint(self.basselAlAssad, connected_to=[self.hama]) self.add_controlpoint(self.marjruhayyil, connected_to=[self.aldumayr]) @@ -140,6 +140,7 @@ class InherentResolve(SyriaTheater): super(InherentResolve, self).__init__() self.kinghussein = ControlPoint.from_airport(syria.King_Hussein_Air_College, LAND, SIZE_REGULAR, IMPORTANCE_HIGH) + self.incirlik = ControlPoint.from_airport(syria.Incirlik, LAND, SIZE_REGULAR, IMPORTANCE_HIGH) self.khalkhala = ControlPoint.from_airport(syria.Khalkhalah, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM) self.palmyra = ControlPoint.from_airport(syria.Palmyra, LAND, SIZE_REGULAR, IMPORTANCE_LOW) self.jirah = ControlPoint.from_airport(syria.Jirah, LAND, SIZE_REGULAR, IMPORTANCE_LOW) @@ -149,6 +150,7 @@ class InherentResolve(SyriaTheater): self.lha = ControlPoint.lha("LHA", Point(-131000, -161000), 1002) self.add_controlpoint(self.kinghussein, connected_to=[self.khalkhala]) + self.add_controlpoint(self.incirlik, connected_to=[self.incirlik]) self.add_controlpoint(self.khalkhala, connected_to=[self.kinghussein, self.palmyra]) self.add_controlpoint(self.palmyra, connected_to=[self.khalkhala, self.tabqa]) self.add_controlpoint(self.tabqa, connected_to=[self.palmyra, self.jirah]) @@ -158,10 +160,12 @@ class InherentResolve(SyriaTheater): self.add_controlpoint(self.lha) self.kinghussein.captured = True + self.incirlik.captured = True self.carrier.captured = True self.lha.captured = True self.jirah.captured_invert = True + self.incirlik.captured_invert = True self.carrier.captured_invert = True self.lha.captured_invert = True @@ -214,7 +218,7 @@ class SyriaFullMap(SyriaTheater): self.carrier.captured = True self.lha.captured = True - self.hatay.captured_invert = True + self.incirlik.captured_invert = True self.carrier.captured_invert = True self.lha.captured_invert = True diff --git a/userdata/liberation_install.py b/userdata/liberation_install.py index 5f19ec0a..440fe29f 100644 --- a/userdata/liberation_install.py +++ b/userdata/liberation_install.py @@ -2,7 +2,7 @@ import json import os from shutil import copyfile -import dcs +from pydcs import dcs from userdata import persistency